internal static Zip64ExtraField GetJustZip64Block(Stream extraFieldStream, bool readUncompressedSize, bool readCompressedSize, bool readLocalHeaderOffset, bool readStartDiskNumber) { Zip64ExtraField zip64Field; using (var reader = new BinaryReader(extraFieldStream, _utf8EncodingNoBOM)) { while (ZipGenericExtraField.TryReadBlock(reader, extraFieldStream.Length, out var currentExtraField)) { if (TryGetZip64BlockFromGenericExtraField(currentExtraField, readUncompressedSize, readCompressedSize, readLocalHeaderOffset, readStartDiskNumber, out zip64Field)) { return(zip64Field); } } } zip64Field = new Zip64ExtraField { CompressedSize = null, UncompressedSize = null, LocalHeaderOffset = null, StartDiskNumber = null }; return(zip64Field); }
// shouldn't ever read the byte at position endExtraField // assumes we are positioned at the beginning of an extra field subfield internal static bool TryReadBlock(BinaryReader reader, long endExtraField, out ZipGenericExtraField field) { field = new ZipGenericExtraField(); // not enough bytes to read tag + size if (endExtraField - reader.BaseStream.Position < 4) { return(false); } field.Tag = reader.ReadUInt16(); field.Size = reader.ReadUInt16(); // not enough bytes to read the data 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 { CompressedSize = null, UncompressedSize = null, LocalHeaderOffset = null, 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 var reader = new BinaryReader(ms); // Why did they do this and how does it still work?! 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 InvalidDataException(SR.FieldTooBigUncompressedSize); } if (zip64Block.CompressedSize < 0) { throw new InvalidDataException(SR.FieldTooBigCompressedSize); } if (zip64Block.LocalHeaderOffset < 0) { throw new InvalidDataException(SR.FieldTooBigLocalHeaderOffset); } if (zip64Block.StartDiskNumber < 0) { throw new InvalidDataException(SR.FieldTooBigStartDiskNumber); } return(true); } finally { ms?.Dispose(); } }