//This function reads all the EOCD stuff it needs to find the offset to the start of the central directory //This offset gets put in _centralDirectoryStart and the number of this disk gets put in _numberOfThisDisk //Also does some verification that this isn't a split/spanned archive //Also checks that offset to CD isn't out of bounds private void ReadEndOfCentralDirectory() { try { //this seeks to the start of the end of central directory record _archiveStream.Seek(-ZipEndOfCentralDirectoryBlock.SizeOfBlockWithoutSignature, SeekOrigin.End); if (!ZipHelper.SeekBackwardsToSignature(_archiveStream, ZipEndOfCentralDirectoryBlock.SignatureConstant)) { throw new InvalidDataException(SR.EOCDNotFound); } Int64 eocdStart = _archiveStream.Position; //read the EOCD ZipEndOfCentralDirectoryBlock eocd; Boolean eocdProper = ZipEndOfCentralDirectoryBlock.TryReadBlock(_archiveReader, 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 InvalidDataException(SR.SplitSpanned); } _numberOfThisDisk = eocd.NumberOfThisDisk; _centralDirectoryStart = eocd.OffsetOfStartOfCentralDirectoryWithRespectToTheStartingDiskNumber; if (eocd.NumberOfEntriesInTheCentralDirectory != eocd.NumberOfEntriesInTheCentralDirectoryOnThisDisk) { throw new InvalidDataException(SR.SplitSpanned); } _expectedNumberOfEntries = eocd.NumberOfEntriesInTheCentralDirectory; //only bother saving the comment if we are in update mode if (_mode == ZipArchiveMode.Update) { _archiveComment = eocd.ArchiveComment; } //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 _archiveStream.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(_archiveStream, Zip64EndOfCentralDirectoryLocator.SignatureConstant)) { //use locator to get to Zip64EOCD Zip64EndOfCentralDirectoryLocator locator; Boolean zip64eocdLocatorProper = Zip64EndOfCentralDirectoryLocator.TryReadBlock(_archiveReader, out locator); Debug.Assert(zip64eocdLocatorProper); //we just found this using the signature finder, so it should be okay if (locator.OffsetOfZip64EOCD > (UInt64)Int64.MaxValue) { throw new InvalidDataException(SR.FieldTooBigOffsetToZip64EOCD); } Int64 zip64EOCDOffset = (Int64)locator.OffsetOfZip64EOCD; _archiveStream.Seek(zip64EOCDOffset, SeekOrigin.Begin); //read Zip64EOCD Zip64EndOfCentralDirectoryRecord record; if (!Zip64EndOfCentralDirectoryRecord.TryReadBlock(_archiveReader, out record)) { throw new InvalidDataException(SR.Zip64EOCDNotWhereExpected); } _numberOfThisDisk = record.NumberOfThisDisk; if (record.NumberOfEntriesTotal > (UInt64)Int64.MaxValue) { throw new InvalidDataException(SR.FieldTooBigNumEntries); } if (record.OffsetOfCentralDirectory > (UInt64)Int64.MaxValue) { throw new InvalidDataException(SR.FieldTooBigOffsetToCD); } if (record.NumberOfEntriesTotal != record.NumberOfEntriesOnThisDisk) { throw new InvalidDataException(SR.SplitSpanned); } _expectedNumberOfEntries = (Int64)record.NumberOfEntriesTotal; _centralDirectoryStart = (Int64)record.OffsetOfCentralDirectory; } } if (_centralDirectoryStart > _archiveStream.Length) { throw new InvalidDataException(SR.FieldTooBigOffsetToCD); } } catch (EndOfStreamException ex) { throw new InvalidDataException(SR.CDCorrupt, ex); } catch (IOException ex) { throw new InvalidDataException(SR.CDCorrupt, ex); } }