// 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 backwards almost to the beginning of the EOCD, one byte after where the signature would be
// located if the EOCD had the minimum possible size (no file zip comment)
_archiveStream.Seek(-ZipEndOfCentralDirectoryBlock.SizeOfBlockWithoutSignature, SeekOrigin.End);
// If the EOCD has the minimum possible size (no zip file comment), then exactly the previous 4 bytes will contain the signature
// But if the EOCD has max possible size, the signature should be found somewhere in the previous 64K + 4 bytes
if (!ZipHelper.SeekBackwardsToSignature(_archiveStream,
ZipEndOfCentralDirectoryBlock.SignatureConstant,
ZipEndOfCentralDirectoryBlock.ZipFileCommentMaxLength + ZipEndOfCentralDirectoryBlock.SignatureSize))
{
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;
}
TryReadZip64EndOfCentralDirectory(eocd, eocdStart);
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);
}
}