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);
long eocdStart = _archiveStream.Position;
//read the EOCD
ZipEndOfCentralDirectoryBlock eocd;
bool 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;
bool 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 > (ulong)long.MaxValue)
throw new InvalidDataException(SR.FieldTooBigOffsetToZip64EOCD);
long zip64EOCDOffset = (long)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 > (ulong)long.MaxValue)
throw new InvalidDataException(SR.FieldTooBigNumEntries);
if (record.OffsetOfCentralDirectory > (ulong)long.MaxValue)
throw new InvalidDataException(SR.FieldTooBigOffsetToCD);
if (record.NumberOfEntriesTotal != record.NumberOfEntriesOnThisDisk)
throw new InvalidDataException(SR.SplitSpanned);
_expectedNumberOfEntries = (long)record.NumberOfEntriesTotal;
_centralDirectoryStart = (long)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);
}
}