public static void ReadEndOfCentralDirectory(Stream stream, BinaryReader reader, out long expectedNumberOfEntries, out long centralDirectoryStart) { try { // this seeks to the start of the end of central directory record stream.Seek(-ZipEndOfCentralDirectoryBlock.SizeOfBlockWithoutSignature, SeekOrigin.End); if (!ZipHelper.SeekBackwardsToSignature(stream, ZipEndOfCentralDirectoryBlock.SignatureConstant)) { throw new ZipArchiveException("SignatureConstant"); } long eocdStart = stream.Position; // read the EOCD ZipEndOfCentralDirectoryBlock eocd; bool eocdProper = ZipEndOfCentralDirectoryBlock.TryReadBlock(reader, out eocd); Debug.Assert(eocdProper); // we just found this using the signature finder, so it should be okay if (eocd.NumberOfThisDisk != eocd.NumberOfTheDiskWithTheStartOfTheCentralDirectory) { throw new ZipArchiveException("SplitSpanned"); } centralDirectoryStart = eocd.OffsetOfStartOfCentralDirectoryWithRespectToTheStartingDiskNumber; if (eocd.NumberOfEntriesInTheCentralDirectory != eocd.NumberOfEntriesInTheCentralDirectoryOnThisDisk) { throw new ZipArchiveException("SplitSpanned"); } expectedNumberOfEntries = eocd.NumberOfEntriesInTheCentralDirectory; // only bother looking for zip64 EOCD stuff if we suspect it is needed because some value is FFFFFFFFF // because these are the only two values we need, we only worry about these // if we don't find the zip64 EOCD, we just give up and try to use the original values if (eocd.NumberOfThisDisk == ZipHelper.Mask16Bit || eocd.OffsetOfStartOfCentralDirectoryWithRespectToTheStartingDiskNumber == ZipHelper.Mask32Bit || eocd.NumberOfEntriesInTheCentralDirectory == ZipHelper.Mask16Bit) { // we need to look for zip 64 EOCD stuff // seek to the zip 64 EOCD locator stream.Seek(eocdStart - Zip64EndOfCentralDirectoryLocator.SizeOfBlockWithoutSignature, SeekOrigin.Begin); // if we don't find it, assume it doesn't exist and use data from normal eocd if (ZipHelper.SeekBackwardsToSignature(stream, Zip64EndOfCentralDirectoryLocator.SignatureConstant)) { // use locator to get to Zip64EOCD Zip64EndOfCentralDirectoryLocator locator; bool zip64eocdLocatorProper = Zip64EndOfCentralDirectoryLocator.TryReadBlock(reader, out locator); Debug.Assert(zip64eocdLocatorProper); // we just found this using the signature finder, so it should be okay if (locator.OffsetOfZip64EOCD > long.MaxValue) { throw new ZipArchiveException("FieldTooBigOffsetToZip64EOCD"); } long zip64EOCDOffset = (long)locator.OffsetOfZip64EOCD; stream.Seek(zip64EOCDOffset, SeekOrigin.Begin); // read Zip64EOCD Zip64EndOfCentralDirectoryRecord record; if (!Zip64EndOfCentralDirectoryRecord.TryReadBlock(reader, out record)) { throw new ZipArchiveException("Zip64EOCDNotWhereExpected"); } if (record.NumberOfEntriesTotal > long.MaxValue) { throw new ZipArchiveException("FieldTooBigNumEntries"); } if (record.OffsetOfCentralDirectory > long.MaxValue) { throw new ZipArchiveException("FieldTooBigOffsetToCD"); } if (record.NumberOfEntriesTotal != record.NumberOfEntriesOnThisDisk) { throw new ZipArchiveException("SplitSpanned"); } expectedNumberOfEntries = (long)record.NumberOfEntriesTotal; centralDirectoryStart = (long)record.OffsetOfCentralDirectory; } } if (centralDirectoryStart > stream.Length) { throw new ZipArchiveException("FieldTooBigOffsetToCD"); } } catch (EndOfStreamException ex) { throw new ZipArchiveException("CDCorrupt", ex); } catch (IOException ex) { throw new ZipArchiveException("CDCorrupt", ex); } }
public static void ReadEndOfCentralDirectory(Stream stream, BinaryReader reader, out long expectedNumberOfEntries, out long centralDirectoryStart) { try { stream.Seek(-ZipEndOfCentralDirectoryBlock.SizeOfBlockWithoutSignature, SeekOrigin.End); if (!ZipHelper.SeekBackwardsToSignature(stream, ZipEndOfCentralDirectoryBlock.SignatureConstant)) { throw new ZipArchiveException("SignatureConstant"); } long eocdStart = stream.Position; ZipEndOfCentralDirectoryBlock eocd; bool eocdProper = ZipEndOfCentralDirectoryBlock.TryReadBlock(reader, out eocd); Debug.Assert(eocdProper); if (eocd.NumberOfThisDisk != eocd.NumberOfTheDiskWithTheStartOfTheCentralDirectory) { throw new ZipArchiveException("SplitSpanned"); } centralDirectoryStart = eocd.OffsetOfStartOfCentralDirectoryWithRespectToTheStartingDiskNumber; if (eocd.NumberOfEntriesInTheCentralDirectory != eocd.NumberOfEntriesInTheCentralDirectoryOnThisDisk) { throw new ZipArchiveException("SplitSpanned"); } expectedNumberOfEntries = eocd.NumberOfEntriesInTheCentralDirectory; if (eocd.NumberOfThisDisk == ZipHelper.Mask16Bit || eocd.OffsetOfStartOfCentralDirectoryWithRespectToTheStartingDiskNumber == ZipHelper.Mask32Bit || eocd.NumberOfEntriesInTheCentralDirectory == ZipHelper.Mask16Bit) { stream.Seek(eocdStart - Zip64EndOfCentralDirectoryLocator.SizeOfBlockWithoutSignature, SeekOrigin.Begin); if (ZipHelper.SeekBackwardsToSignature(stream, Zip64EndOfCentralDirectoryLocator.SignatureConstant)) { Zip64EndOfCentralDirectoryLocator locator; bool zip64eocdLocatorProper = Zip64EndOfCentralDirectoryLocator.TryReadBlock(reader, out locator); Debug.Assert(zip64eocdLocatorProper); if (locator.OffsetOfZip64EOCD > long.MaxValue) { throw new ZipArchiveException("FieldTooBigOffsetToZip64EOCD"); } long zip64EOCDOffset = (long)locator.OffsetOfZip64EOCD; stream.Seek(zip64EOCDOffset, SeekOrigin.Begin); Zip64EndOfCentralDirectoryRecord record; if (!Zip64EndOfCentralDirectoryRecord.TryReadBlock(reader, out record)) { throw new ZipArchiveException("Zip64EOCDNotWhereExpected"); } if (record.NumberOfEntriesTotal > long.MaxValue) { throw new ZipArchiveException("FieldTooBigNumEntries"); } if (record.OffsetOfCentralDirectory > long.MaxValue) { throw new ZipArchiveException("FieldTooBigOffsetToCD"); } if (record.NumberOfEntriesTotal != record.NumberOfEntriesOnThisDisk) { throw new ZipArchiveException("SplitSpanned"); } expectedNumberOfEntries = (long)record.NumberOfEntriesTotal; centralDirectoryStart = (long)record.OffsetOfCentralDirectory; } } if (centralDirectoryStart > stream.Length) { throw new ZipArchiveException("FieldTooBigOffsetToCD"); } } catch (EndOfStreamException ex) { throw new ZipArchiveException("CDCorrupt", ex); } catch (IOException ex) { throw new ZipArchiveException("CDCorrupt", ex); } }