public static bool TryReadBlock(BinaryReader reader, out ZipEndOfCentralDirectoryBlock eocdBlock)
        {
            eocdBlock = new ZipEndOfCentralDirectoryBlock();
            if (reader.ReadUInt32() != SignatureConstant)
            {
                return(false);
            }

            eocdBlock.Signature        = SignatureConstant;
            eocdBlock.NumberOfThisDisk = reader.ReadUInt16();
            eocdBlock.NumberOfTheDiskWithTheStartOfTheCentralDirectory = reader.ReadUInt16();
            eocdBlock.NumberOfEntriesInTheCentralDirectoryOnThisDisk   = reader.ReadUInt16();
            eocdBlock.NumberOfEntriesInTheCentralDirectory             = reader.ReadUInt16();
            eocdBlock.SizeOfCentralDirectory = reader.ReadUInt32();
            eocdBlock.OffsetOfStartOfCentralDirectoryWithRespectToTheStartingDiskNumber = reader.ReadUInt32();

            ushort commentLength = reader.ReadUInt16();

            eocdBlock.ArchiveComment = reader.ReadBytes(commentLength);

            return(true);
        }
        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);
            }
        }