// There is a small chance that something very weird could happen here. The code calling into this function // will ask for a value from the extra field if the field was masked with FF's. It's theoretically possible // that a field was FF's legitimately, and the writer didn't decide to write the corresponding extra field. // Also, at the same time, other fields were masked with FF's to indicate looking in the zip64 record. // Then, the search for the zip64 record will fail because the expected size is wrong, // and a nulled out Zip64ExtraField will be returned. Thus, even though there was Zip64 data, // it will not be used. It is questionable whether this situation is possible to detect // unlike the other functions that have try-pattern semantics, these functions always return a // Zip64ExtraField. If a Zip64 extra field actually doesn't exist, all of the fields in the // returned struct will be null // // If there are more than one Zip64 extra fields, we take the first one that has the expected size // public static Zip64ExtraField GetJustZip64Block(Stream extraFieldStream, bool readUncompressedSize, bool readCompressedSize, bool readLocalHeaderOffset, bool readStartDiskNumber) { Zip64ExtraField zip64Field; using (BinaryReader reader = new BinaryReader(extraFieldStream)) { ZipGenericExtraField currentExtraField; while (ZipGenericExtraField.TryReadBlock(reader, extraFieldStream.Length, out currentExtraField)) { if (TryGetZip64BlockFromGenericExtraField(currentExtraField, readUncompressedSize, readCompressedSize, readLocalHeaderOffset, readStartDiskNumber, out zip64Field)) { return(zip64Field); } } } zip64Field = new Zip64ExtraField(); zip64Field._compressedSize = null; zip64Field._uncompressedSize = null; zip64Field._localHeaderOffset = null; zip64Field._startDiskNumber = null; return(zip64Field); }
public static bool TryReadBlock(BinaryReader reader, long endExtraField, out ZipGenericExtraField field) { field = new ZipGenericExtraField(); if (endExtraField - reader.BaseStream.Position < 4) { return(false); } field._tag = reader.ReadUInt16(); field._size = reader.ReadUInt16(); if (endExtraField - reader.BaseStream.Position < field._size) { return(false); } field._data = reader.ReadBytes(field._size); return(true); }
private static bool TryGetZip64BlockFromGenericExtraField(ZipGenericExtraField extraField, bool readUncompressedSize, bool readCompressedSize, bool readLocalHeaderOffset, bool readStartDiskNumber, out Zip64ExtraField zip64Block) { zip64Block = new Zip64ExtraField(); zip64Block._compressedSize = null; zip64Block._uncompressedSize = null; zip64Block._localHeaderOffset = null; zip64Block._startDiskNumber = null; if (extraField.Tag != TagConstant) { return(false); } // this pattern needed because nested using blocks trigger CA2202 MemoryStream ms = null; try { ms = new MemoryStream(extraField.Data); using (BinaryReader reader = new BinaryReader(ms)) { ms = null; zip64Block._size = extraField.Size; ushort expectedSize = 0; if (readUncompressedSize) { expectedSize += 8; } if (readCompressedSize) { expectedSize += 8; } if (readLocalHeaderOffset) { expectedSize += 8; } if (readStartDiskNumber) { expectedSize += 4; } // if it is not the expected size, perhaps there is another extra field that matches if (expectedSize != zip64Block._size) { return(false); } if (readUncompressedSize) { zip64Block._uncompressedSize = reader.ReadInt64(); } if (readCompressedSize) { zip64Block._compressedSize = reader.ReadInt64(); } if (readLocalHeaderOffset) { zip64Block._localHeaderOffset = reader.ReadInt64(); } if (readStartDiskNumber) { zip64Block._startDiskNumber = reader.ReadInt32(); } // original values are unsigned, so implies value is too big to fit in signed integer if (zip64Block._uncompressedSize < 0) { throw new ZipArchiveException("FieldTooBigUncompressedSize"); } if (zip64Block._compressedSize < 0) { throw new ZipArchiveException("FieldTooBigCompressedSize"); } if (zip64Block._localHeaderOffset < 0) { throw new ZipArchiveException("FieldTooBigLocalHeaderOffset"); } if (zip64Block._startDiskNumber < 0) { throw new ZipArchiveException("FieldTooBigStartDiskNumber"); } return(true); } } finally { if (ms != null) { ms.Dispose(); } } }
private static bool TryGetZip64BlockFromGenericExtraField(ZipGenericExtraField extraField, bool readUncompressedSize, bool readCompressedSize, bool readLocalHeaderOffset, bool readStartDiskNumber, out Zip64ExtraField zip64Block) { zip64Block = new Zip64ExtraField(); zip64Block._compressedSize = null; zip64Block._uncompressedSize = null; zip64Block._localHeaderOffset = null; zip64Block._startDiskNumber = null; if (extraField.Tag != TagConstant) { return(false); } MemoryStream ms = null; try { ms = new MemoryStream(extraField.Data); using (BinaryReader reader = new BinaryReader(ms)) { ms = null; zip64Block._size = extraField.Size; ushort expectedSize = 0; if (readUncompressedSize) { expectedSize += 8; } if (readCompressedSize) { expectedSize += 8; } if (readLocalHeaderOffset) { expectedSize += 8; } if (readStartDiskNumber) { expectedSize += 4; } if (expectedSize != zip64Block._size) { return(false); } if (readUncompressedSize) { zip64Block._uncompressedSize = reader.ReadInt64(); } if (readCompressedSize) { zip64Block._compressedSize = reader.ReadInt64(); } if (readLocalHeaderOffset) { zip64Block._localHeaderOffset = reader.ReadInt64(); } if (readStartDiskNumber) { zip64Block._startDiskNumber = reader.ReadInt32(); } if (zip64Block._uncompressedSize < 0) { throw new ZipArchiveException("FieldTooBigUncompressedSize"); } if (zip64Block._compressedSize < 0) { throw new ZipArchiveException("FieldTooBigCompressedSize"); } if (zip64Block._localHeaderOffset < 0) { throw new ZipArchiveException("FieldTooBigLocalHeaderOffset"); } if (zip64Block._startDiskNumber < 0) { throw new ZipArchiveException("FieldTooBigStartDiskNumber"); } return(true); } } finally { if (ms != null) { ms.Dispose(); } } }