private static void ReadCentralDirectoryFooter(ZipFile zf)
        {
            Stream s         = zf.ReadStream;
            int    signature = SharedUtilities.ReadSignature(s);

            byte[] block = null;
            int    j     = 0;

            if (signature == ZipConstants.Zip64EndOfCentralDirectoryRecordSignature)
            {
                // We have a ZIP64 EOCD
                // This data block is 4 bytes sig, 8 bytes size, 44 bytes fixed data,
                // followed by a variable-sized extension block.  We have read the sig already.
                // 8 - datasize (64 bits)
                // 2 - version made by
                // 2 - version needed to extract
                // 4 - number of this disk
                // 4 - number of the disk with the start of the CD
                // 8 - total number of entries in the CD on this disk
                // 8 - total number of entries in the CD
                // 8 - size of the CD
                // 8 - offset of the CD
                // -----------------------
                // 52 bytes

                block = new byte[8 + 44];
                s.Read(block, 0, block.Length);

                Int64 DataSize = BitConverter.ToInt64(block, 0);  // == 44 + the variable length

                if (DataSize < 44)
                {
                    throw new ZipException("Bad size in the ZIP64 Central Directory.");
                }

                zf._versionMadeBy = BitConverter.ToUInt16(block, j);
                j += 2;
                zf._versionNeededToExtract = BitConverter.ToUInt16(block, j);
                j += 2;
                zf._diskNumberWithCd = BitConverter.ToUInt32(block, j);
                j += 2;

                //zf._diskNumberWithCd++; // hack!!

                // read the extended block
                block = new byte[DataSize - 44];
                s.Read(block, 0, block.Length);
                // discard the result

                signature = SharedUtilities.ReadSignature(s);
                if (signature != ZipConstants.Zip64EndOfCentralDirectoryLocatorSignature)
                {
                    throw new ZipException("Inconsistent metadata in the ZIP64 Central Directory.");
                }

                block = new byte[16];
                s.Read(block, 0, block.Length);
                // discard the result

                signature = SharedUtilities.ReadSignature(s);
            }

            // Throw if this is not a signature for "end of central directory record"
            // This is a sanity check.
            if (signature != ZipConstants.EndOfCentralDirectorySignature)
            {
                s.Seek(-4, SeekOrigin.Current);
                throw new BadReadException(String.Format("Bad signature ({0:X8}) at position 0x{1:X8}",
                                                         signature, s.Position));
            }

            // read the End-of-Central-Directory-Record
            block = new byte[16];
            zf.ReadStream.Read(block, 0, block.Length);

            // off sz  data
            // -------------------------------------------------------
            //  0   4  end of central dir signature (0x06054b50)
            //  4   2  number of this disk
            //  6   2  number of the disk with start of the central directory
            //  8   2  total number of entries in the  central directory on this disk
            // 10   2  total number of entries in  the central directory
            // 12   4  size of the central directory
            // 16   4  offset of start of central directory with respect to the starting disk number
            // 20   2  ZIP file comment length
            // 22  ??  ZIP file comment

            if (zf._diskNumberWithCd == 0)
            {
                zf._diskNumberWithCd = BitConverter.ToUInt16(block, 2);
                //zf._diskNumberWithCd++; // hack!!
            }

            // read the comment here
            ReadZipFileComment(zf);
        }
        // build the TOC by reading each entry in the file.
        private static void ReadIntoInstance_Orig(ZipFile zf)
        {
            zf.OnReadStarted();
            //zf._entries = new System.Collections.Generic.List<ZipEntry>();
            zf._entries = new System.Collections.Generic.Dictionary <String, ZipEntry>();

            ZipEntry e;

            if (zf.Verbose)
            {
                if (zf.Name == null)
                {
                    zf.StatusMessageTextWriter.WriteLine("Reading zip from stream...");
                }
                else
                {
                    zf.StatusMessageTextWriter.WriteLine("Reading zip {0}...", zf.Name);
                }
            }

            // work item 6647:  PK00 (packed to removable disk)
            bool         firstEntry = true;
            ZipContainer zc         = new ZipContainer(zf);

            while ((e = ZipEntry.ReadEntry(zc, firstEntry)) != null)
            {
                if (zf.Verbose)
                {
                    zf.StatusMessageTextWriter.WriteLine("  {0}", e.FileName);
                }

                zf._entries.Add(e.FileName, e);
                firstEntry = false;
            }

            // read the zipfile's central directory structure here.
            // workitem 9912
            // But, because it may be corrupted, ignore errors.
            try
            {
                ZipEntry de;
                // in lieu of hashset, use a dictionary
                var previouslySeen = new Dictionary <String, Object>();
                while ((de = ZipEntry.ReadDirEntry(zf, previouslySeen)) != null)
                {
                    // Housekeeping: Since ZipFile exposes ZipEntry elements in the enumerator,
                    // we need to copy the comment that we grab from the ZipDirEntry
                    // into the ZipEntry, so the application can access the comment.
                    // Also since ZipEntry is used to Write zip files, we need to copy the
                    // file attributes to the ZipEntry as appropriate.
                    ZipEntry e1 = zf._entries[de.FileName];
                    if (e1 != null)
                    {
                        e1._Comment = de.Comment;
                        if (de.IsDirectory)
                        {
                            e1.MarkAsDirectory();
                        }
                    }
                    previouslySeen.Add(de.FileName, null); // to prevent dupes
                }

                // workitem 8299
                if (zf._locEndOfCDS > 0)
                {
                    zf.ReadStream.Seek(zf._locEndOfCDS, SeekOrigin.Begin);
                }

                ReadCentralDirectoryFooter(zf);

                if (zf.Verbose && !String.IsNullOrEmpty(zf.Comment))
                {
                    zf.StatusMessageTextWriter.WriteLine("Zip file Comment: {0}", zf.Comment);
                }
            }
            catch (ZipException) { }
            catch (IOException) { }

            zf.OnReadCompleted();
        }
        private static void ReadIntoInstance(ZipFile zf)
        {
            Stream s = zf.ReadStream;

            try
            {
                zf._readName = zf._name; // workitem 13915
                if (!s.CanSeek)
                {
                    ReadIntoInstance_Orig(zf);
                    return;
                }

                zf.OnReadStarted();

                // change for workitem 8098
                //zf._originPosition = s.Position;

                // Try reading the central directory, rather than scanning the file.

                uint datum = ReadFirstFourBytes(s);

                if (datum == ZipConstants.EndOfCentralDirectorySignature)
                {
                    return;
                }


                // start at the end of the file...
                // seek backwards a bit, then look for the EoCD signature.
                int  nTries  = 0;
                bool success = false;

                // The size of the end-of-central-directory-footer plus 2 bytes is 18.
                // This implies an archive comment length of 0.  We'll add a margin of
                // safety and start "in front" of that, when looking for the
                // EndOfCentralDirectorySignature
                long posn        = s.Length - 64;
                long maxSeekback = Math.Max(s.Length - 0x4000, 10);
                do
                {
                    if (posn < 0)
                    {
                        posn = 0;            // BOF
                    }
                    s.Seek(posn, SeekOrigin.Begin);
                    long bytesRead = SharedUtilities.FindSignature(s, (int)ZipConstants.EndOfCentralDirectorySignature);
                    if (bytesRead != -1)
                    {
                        success = true;
                    }
                    else
                    {
                        if (posn == 0)
                        {
                            break;          // started at the BOF and found nothing
                        }
                        nTries++;
                        // Weird: with NETCF, negative offsets from SeekOrigin.End DO
                        // NOT WORK. So rather than seek a negative offset, we seek
                        // from SeekOrigin.Begin using a smaller number.
                        posn -= (32 * (nTries + 1) * nTries);
                    }
                }while (!success && posn > maxSeekback);

                if (success)
                {
                    // workitem 8299
                    zf._locEndOfCDS = s.Position - 4;

                    byte[] block = new byte[16];
                    s.Read(block, 0, block.Length);

                    zf._diskNumberWithCd = BitConverter.ToUInt16(block, 2);

                    if (zf._diskNumberWithCd == 0xFFFF)
                    {
                        throw new ZipException("Spanned archives with more than 65534 segments are not supported at this time.");
                    }

                    zf._diskNumberWithCd++; // I think the number in the file differs from reality by 1

                    int i = 12;

                    uint offset32 = (uint)BitConverter.ToUInt32(block, i);
                    if (offset32 == 0xFFFFFFFF)
                    {
                        Zip64SeekToCentralDirectory(zf);
                    }
                    else
                    {
                        zf._OffsetOfCentralDirectory = offset32;
                        // change for workitem 8098
                        s.Seek(offset32, SeekOrigin.Begin);
                    }

                    ReadCentralDirectory(zf);
                }
                else
                {
                    // Could not find the central directory.
                    // Fallback to the old method.
                    // workitem 8098: ok
                    //s.Seek(zf._originPosition, SeekOrigin.Begin);
                    s.Seek(0L, SeekOrigin.Begin);
                    ReadIntoInstance_Orig(zf);
                }
            }
            catch (Exception ex1)
            {
                if (zf._ReadStreamIsOurs && zf._readstream != null)
                {
                    try
                    {
#if NETCF
                        zf._readstream.Close();
#else
                        zf._readstream.Dispose();
#endif
                        zf._readstream = null;
                    }
                    finally { }
                }

                throw new ZipException("Cannot read that as a ZipFile", ex1);
            }

            // the instance has been read in
            zf._contentsChanged = false;
        }
        private static void ReadCentralDirectory(ZipFile zf)
        {
            // We must have the central directory footer record, in order to properly
            // read zip dir entries from the central directory.  This because the logic
            // knows when to open a spanned file when the volume number for the central
            // directory differs from the volume number for the zip entry.  The
            // _diskNumberWithCd was set when originally finding the offset for the
            // start of the Central Directory.

            // workitem 9214
            bool     inputUsesZip64 = false;
            ZipEntry de;
            // in lieu of hashset, use a dictionary
            var previouslySeen = new Dictionary <String, object>();

            while ((de = ZipEntry.ReadDirEntry(zf, previouslySeen)) != null)
            {
                de.ResetDirEntry();
                zf.OnReadEntry(true, null);

                if (zf.Verbose)
                {
                    zf.StatusMessageTextWriter.WriteLine("entry {0}", de.FileName);
                }

                zf._entries.Add(de.FileName, de);

                // workitem 9214
                if (de._InputUsesZip64)
                {
                    inputUsesZip64 = true;
                }
                previouslySeen.Add(de.FileName, null); // to prevent dupes
            }

            // workitem 9214; auto-set the zip64 flag
            if (inputUsesZip64)
            {
                zf.UseZip64WhenSaving = Zip64Option.Always;
            }

            // workitem 8299
            if (zf._locEndOfCDS > 0)
            {
                zf.ReadStream.Seek(zf._locEndOfCDS, SeekOrigin.Begin);
            }

            ReadCentralDirectoryFooter(zf);

            if (zf.Verbose && !String.IsNullOrEmpty(zf.Comment))
            {
                zf.StatusMessageTextWriter.WriteLine("Zip file Comment: {0}", zf.Comment);
            }

            // We keep the read stream open after reading.

            if (zf.Verbose)
            {
                zf.StatusMessageTextWriter.WriteLine("read in {0} entries.", zf._entries.Count);
            }

            zf.OnReadCompleted();
        }
 /// <summary>
 /// Reads a zip file archive and returns the instance.
 /// </summary>
 ///
 /// <remarks>
 /// <para>
 /// The stream is read using the default <c>System.Text.Encoding</c>, which is the
 /// <c>IBM437</c> codepage.
 /// </para>
 /// </remarks>
 ///
 /// <exception cref="System.Exception">
 /// Thrown if the <c>ZipFile</c> cannot be read. The implementation of this method
 /// relies on <c>System.IO.File.OpenRead</c>, which can throw a variety of exceptions,
 /// including specific exceptions if a file is not found, an unauthorized access
 /// exception, exceptions for poorly formatted filenames, and so on.
 /// </exception>
 ///
 /// <param name="fileName">
 /// The name of the zip archive to open.  This can be a fully-qualified or relative
 /// pathname.
 /// </param>
 ///
 /// <seealso cref="ZipFile.Read(String, ReadOptions)"/>.
 ///
 /// <returns>The instance read from the zip archive.</returns>
 ///
 internal static ZipFile Read(string fileName)
 {
     return(ZipFile.Read(fileName, null, null, null));
 }