This class contains constants used for Zip format files
Example #1
0
        public ZipEntry GetNextEntry()
        {
            if (this.crc == null)
            {
                throw new InvalidOperationException("Closed.");
            }
            if (this.entry != null)
            {
                this.CloseEntry();
            }
            int num = this.inputBuffer.ReadLeInt();

            if (num == 33639248 || num == 101010256 || num == 84233040 || num == 117853008 || num == 101075792)
            {
                this.Close();
                return(null);
            }
            if (num == 808471376 || num == 134695760)
            {
                num = this.inputBuffer.ReadLeInt();
            }
            if (num != 67324752)
            {
                throw new ZipException("Wrong Local header signature: 0x" + string.Format("{0:X}", num));
            }
            short versionRequiredToExtract = (short)this.inputBuffer.ReadLeShort();

            this.flags  = this.inputBuffer.ReadLeShort();
            this.method = this.inputBuffer.ReadLeShort();
            uint num2 = (uint)this.inputBuffer.ReadLeInt();
            int  num3 = this.inputBuffer.ReadLeInt();

            this.csize = (long)this.inputBuffer.ReadLeInt();
            this.size  = (long)this.inputBuffer.ReadLeInt();
            int  num4 = this.inputBuffer.ReadLeShort();
            int  num5 = this.inputBuffer.ReadLeShort();
            bool flag = (this.flags & 1) == 1;

            byte[] array = new byte[num4];
            this.inputBuffer.ReadRawBuffer(array);
            string name = ZipConstants.ConvertToStringExt(this.flags, array);

            this.entry                   = new ZipEntry(name, (int)versionRequiredToExtract);
            this.entry.Flags             = this.flags;
            this.entry.CompressionMethod = (CompressionMethod)this.method;
            if ((this.flags & 8) == 0)
            {
                this.entry.Crc              = ((long)num3 & 0xFFFFFFFFL);
                this.entry.Size             = (this.size & 0xFFFFFFFFL);
                this.entry.CompressedSize   = (this.csize & 0xFFFFFFFFL);
                this.entry.CryptoCheckValue = (byte)(num3 >> 24 & 255);
            }
            else
            {
                if (num3 != 0)
                {
                    this.entry.Crc = ((long)num3 & 0xFFFFFFFFL);
                }
                if (this.size != 0L)
                {
                    this.entry.Size = (this.size & 0xFFFFFFFFL);
                }
                if (this.csize != 0L)
                {
                    this.entry.CompressedSize = (this.csize & 0xFFFFFFFFL);
                }
                this.entry.CryptoCheckValue = (byte)(num2 >> 8 & 255u);
            }
            this.entry.DosTime = (long)((ulong)num2);
            if (num5 > 0)
            {
                byte[] array2 = new byte[num5];
                this.inputBuffer.ReadRawBuffer(array2);
                this.entry.ExtraData = array2;
            }
            this.entry.ProcessExtraData(true);
            if (this.entry.CompressedSize >= 0L)
            {
                this.csize = this.entry.CompressedSize;
            }
            if (this.entry.Size >= 0L)
            {
                this.size = this.entry.Size;
            }
            if (this.method == 0 && ((!flag && this.csize != this.size) || (flag && this.csize - 12L != this.size)))
            {
                throw new ZipException("Stored, but compressed != uncompressed");
            }
            if (this.entry.IsCompressionMethodSupported())
            {
                this.internalReader = new ZipInputStream.ReadDataHandler(this.InitialRead);
            }
            else
            {
                this.internalReader = new ZipInputStream.ReadDataHandler(this.ReadingNotSupported);
            }
            return(this.entry);
        }
Example #2
0
        /// <summary>
        /// Advances to the next entry in the archive
        /// </summary>
        /// <returns>
        /// The next <see cref="ZipEntry">entry</see> in the archive or null if there are no more entries.
        /// </returns>
        /// <remarks>
        /// If the previous entry is still open <see cref="CloseEntry">CloseEntry</see> is called.
        /// </remarks>
        /// <exception cref="InvalidOperationException">
        /// Input stream is closed
        /// </exception>
        /// <exception cref="ZipException">
        /// Password is not set, password is invalid, compression method is invalid,
        /// version required to extract is not supported
        /// </exception>
        public ZipEntry GetNextEntry()
        {
            if (crc == null)
            {
                throw new InvalidOperationException("Closed.");
            }

            if (entry != null)
            {
                CloseEntry();
            }

            int header = inputBuffer.ReadLeInt();

            if (header == ZipConstants.CentralHeaderSignature ||
                header == ZipConstants.EndOfCentralDirectorySignature ||
                header == ZipConstants.CentralHeaderDigitalSignature ||
                header == ZipConstants.ArchiveExtraDataSignature ||
                header == ZipConstants.Zip64CentralFileHeaderSignature)
            {
                // No more individual entries exist
                Close();
                return(null);
            }

            // -jr- 07-Dec-2003 Ignore spanning temporary signatures if found
            // Spanning signature is same as descriptor signature and is untested as yet.
            if ((header == ZipConstants.SpanningTempSignature) || (header == ZipConstants.SpanningSignature))
            {
                header = inputBuffer.ReadLeInt();
            }

            if (header != ZipConstants.LocalHeaderSignature)
            {
                throw new ZipException("Wrong Local header signature: 0x" + String.Format("{0:X}", header));
            }

            short versionRequiredToExtract = (short)inputBuffer.ReadLeShort();

            flags  = inputBuffer.ReadLeShort();
            method = inputBuffer.ReadLeShort();
            uint dostime = (uint)inputBuffer.ReadLeInt();
            int  crc2    = inputBuffer.ReadLeInt();

            csize = inputBuffer.ReadLeInt();
            size  = inputBuffer.ReadLeInt();
            int nameLen  = inputBuffer.ReadLeShort();
            int extraLen = inputBuffer.ReadLeShort();

            bool isCrypted = (flags & 1) == 1;

            byte[] buffer = new byte[nameLen];
            inputBuffer.ReadRawBuffer(buffer);

            string name = ZipConstants.ConvertToStringExt(flags, buffer);

            entry       = new ZipEntry(name, versionRequiredToExtract);
            entry.Flags = flags;

            entry.CompressionMethod = (CompressionMethod)method;

            if ((flags & 8) == 0)
            {
                entry.Crc            = crc2 & 0xFFFFFFFFL;
                entry.Size           = size & 0xFFFFFFFFL;
                entry.CompressedSize = csize & 0xFFFFFFFFL;

                entry.CryptoCheckValue = (byte)((crc2 >> 24) & 0xff);
            }
            else
            {
                // This allows for GNU, WinZip and possibly other archives, the PKZIP spec
                // says these values are zero under these circumstances.
                if (crc2 != 0)
                {
                    entry.Crc = crc2 & 0xFFFFFFFFL;
                }

                if (size != 0)
                {
                    entry.Size = size & 0xFFFFFFFFL;
                }

                if (csize != 0)
                {
                    entry.CompressedSize = csize & 0xFFFFFFFFL;
                }

                entry.CryptoCheckValue = (byte)((dostime >> 8) & 0xff);
            }

            entry.DosTime = dostime;

            // If local header requires Zip64 is true then the extended header should contain
            // both values.

            // Handle extra data if present.  This can set/alter some fields of the entry.
            if (extraLen > 0)
            {
                byte[] extra = new byte[extraLen];
                inputBuffer.ReadRawBuffer(extra);
                entry.ExtraData = extra;
            }

            entry.ProcessExtraData(true);
            if (entry.CompressedSize >= 0)
            {
                csize = entry.CompressedSize;
            }

            if (entry.Size >= 0)
            {
                size = entry.Size;
            }

            if (method == (int)CompressionMethod.Stored && (!isCrypted && csize != size || (isCrypted && csize - ZipConstants.CryptoHeaderSize != size)))
            {
                throw new ZipException("Stored, but compressed != uncompressed");
            }

            // Determine how to handle reading of data if this is attempted.
            if (entry.IsCompressionMethodSupported())
            {
                internalReader = new ReadDataHandler(InitialRead);
            }
            else
            {
                internalReader = new ReadDataHandler(ReadingNotSupported);
            }

            return(entry);
        }
Example #3
0
        private void WriteLocalHeader(ZipEntry entry, EntryPatchData patchData)
        {
            CompressionMethod compressionMethod = entry.CompressionMethod;
            bool flag  = true;
            bool flag2 = false;

            this.WriteLEInt(67324752);
            this.WriteLEShort(entry.Version);
            this.WriteLEShort(entry.Flags);
            this.WriteLEShort((int)((byte)compressionMethod));
            this.WriteLEInt((int)entry.DosTime);
            if (flag)
            {
                this.WriteLEInt((int)entry.Crc);
                if (entry.LocalHeaderRequiresZip64)
                {
                    this.WriteLEInt(-1);
                    this.WriteLEInt(-1);
                }
                else
                {
                    this.WriteLEInt((!entry.IsCrypted) ? ((int)entry.CompressedSize) : ((int)entry.CompressedSize + 12));
                    this.WriteLEInt((int)entry.Size);
                }
            }
            else
            {
                if (patchData != null)
                {
                    patchData.CrcPatchOffset = this.stream_.Position;
                }
                this.WriteLEInt(0);
                if (patchData != null)
                {
                    patchData.SizePatchOffset = this.stream_.Position;
                }
                if (entry.LocalHeaderRequiresZip64 && flag2)
                {
                    this.WriteLEInt(-1);
                    this.WriteLEInt(-1);
                }
                else
                {
                    this.WriteLEInt(0);
                    this.WriteLEInt(0);
                }
            }
            byte[] array = ZipConstants.ConvertToArray(entry.Flags, entry.Name);
            if (array.Length > 65535)
            {
                throw new Exception("Entry name too long.");
            }
            ZipExtraData zipExtraData = new ZipExtraData(entry.ExtraData);

            if (entry.LocalHeaderRequiresZip64 && (flag || flag2))
            {
                zipExtraData.StartNewEntry();
                if (flag)
                {
                    zipExtraData.AddLeLong(entry.Size);
                    zipExtraData.AddLeLong(entry.CompressedSize);
                }
                else
                {
                    zipExtraData.AddLeLong(-1L);
                    zipExtraData.AddLeLong(-1L);
                }
                zipExtraData.AddNewEntry(1);
                if (!zipExtraData.Find(1))
                {
                    throw new Exception("Internal error cant find extra data");
                }
                if (patchData != null)
                {
                    patchData.SizePatchOffset = (long)zipExtraData.CurrentReadIndex;
                }
            }
            else
            {
                zipExtraData.Delete(1);
            }
            byte[] entryData = zipExtraData.GetEntryData();
            this.WriteLEShort(array.Length);
            this.WriteLEShort(entryData.Length);
            if (array.Length > 0)
            {
                this.stream_.Write(array, 0, array.Length);
            }
            if (entry.LocalHeaderRequiresZip64 && flag2)
            {
                patchData.SizePatchOffset += this.stream_.Position;
            }
            if (entryData.Length > 0)
            {
                this.stream_.Write(entryData, 0, entryData.Length);
            }
        }
Example #4
0
        // Write the local file header
        // TODO: ZipHelperStream.WriteLocalHeader is not yet used and needs checking for ZipFile and ZipOuptutStream usage
        void WriteLocalHeader(ZipEntry entry, EntryPatchData patchData)
        {
            CompressionMethod method = entry.CompressionMethod;
            bool headerInfoAvailable = true;             // How to get this?
            bool patchEntryHeader    = false;

            WriteLEInt(ZipConstants.LocalHeaderSignature);

            WriteLEShort(entry.Version);
            WriteLEShort(entry.Flags);
            WriteLEShort((byte)method);
            WriteLEInt((int)entry.DosTime);

            if (headerInfoAvailable == true)
            {
                WriteLEInt((int)entry.Crc);
                if (entry.LocalHeaderRequiresZip64)
                {
                    WriteLEInt(-1);
                    WriteLEInt(-1);
                }
                else
                {
                    WriteLEInt(entry.IsCrypted ? (int)entry.CompressedSize + ZipConstants.CryptoHeaderSize : (int)entry.CompressedSize);
                    WriteLEInt((int)entry.Size);
                }
            }
            else
            {
                if (patchData != null)
                {
                    patchData.CrcPatchOffset = stream_.Position;
                }
                WriteLEInt(0);                  // Crc

                if (patchData != null)
                {
                    patchData.SizePatchOffset = stream_.Position;
                }

                // For local header both sizes appear in Zip64 Extended Information
                if (entry.LocalHeaderRequiresZip64 && patchEntryHeader)
                {
                    WriteLEInt(-1);
                    WriteLEInt(-1);
                }
                else
                {
                    WriteLEInt(0);                      // Compressed size
                    WriteLEInt(0);                      // Uncompressed size
                }
            }

            byte[] name = ZipConstants.ConvertToArray(entry.Flags, entry.Name);

            if (name.Length > 0xFFFF)
            {
                throw new ZipException("Entry name too long.");
            }

            var ed = new ZipExtraData(entry.ExtraData);

            if (entry.LocalHeaderRequiresZip64 && (headerInfoAvailable || patchEntryHeader))
            {
                ed.StartNewEntry();
                if (headerInfoAvailable)
                {
                    ed.AddLeLong(entry.Size);
                    ed.AddLeLong(entry.CompressedSize);
                }
                else
                {
                    ed.AddLeLong(-1);
                    ed.AddLeLong(-1);
                }
                ed.AddNewEntry(1);

                if (!ed.Find(1))
                {
                    throw new ZipException("Internal error cant find extra data");
                }

                if (patchData != null)
                {
                    patchData.SizePatchOffset = ed.CurrentReadIndex;
                }
            }
            else
            {
                ed.Delete(1);
            }

            byte[] extra = ed.GetEntryData();

            WriteLEShort(name.Length);
            WriteLEShort(extra.Length);

            if (name.Length > 0)
            {
                stream_.Write(name, 0, name.Length);
            }

            if (entry.LocalHeaderRequiresZip64 && patchEntryHeader)
            {
                patchData.SizePatchOffset += stream_.Position;
            }

            if (extra.Length > 0)
            {
                stream_.Write(extra, 0, extra.Length);
            }
        }
Example #5
0
        /// <summary>
        /// Starts a new Zip entry. It automatically closes the previous
        /// entry if present.
        /// All entry elements bar name are optional, but must be correct if present.
        /// If the compression method is stored and the output is not patchable
        /// the compression for that entry is automatically changed to deflate level 0
        /// </summary>
        /// <param name="entry">
        /// the entry.
        /// </param>
        /// <exception cref="System.ArgumentNullException">
        /// if entry passed is null.
        /// </exception>
        /// <exception cref="System.IO.IOException">
        /// if an I/O error occured.
        /// </exception>
        /// <exception cref="System.InvalidOperationException">
        /// if stream was finished
        /// </exception>
        /// <exception cref="ZipException">
        /// Too many entries in the Zip file<br/>
        /// Entry name is too long<br/>
        /// Finish has already been called<br/>
        /// </exception>
        public void PutNextEntry(ZipEntry entry)
        {
            if (entry == null)
            {
                throw new ArgumentNullException("entry");
            }

            if (entries == null)
            {
                throw new InvalidOperationException("ZipOutputStream was finished");
            }

            if (curEntry != null)
            {
                CloseEntry();
            }

            if (entries.Count == int.MaxValue)
            {
                throw new ZipException("Too many entries for Zip file");
            }

            CompressionMethod method = entry.CompressionMethod;
            int compressionLevel     = defaultCompressionLevel;

            // Clear flags that the library manages internally
            entry.Flags     &= (int)GeneralBitFlags.UnicodeText;
            patchEntryHeader = false;
            bool headerInfoAvailable = true;

            if (method == CompressionMethod.Stored)
            {
                // Cant store values in a data descriptor as you cant extract stored files
                // if the length isnt known.
                entry.Flags &= ~8;
                if (entry.CompressedSize >= 0)
                {
                    if (entry.Size < 0)
                    {
                        entry.Size = entry.CompressedSize;
                    }
                    else if (entry.Size != entry.CompressedSize)
                    {
                        throw new ZipException("Method STORED, but compressed size != size");
                    }
                }
                else
                {
                    if (entry.Size >= 0)
                    {
                        entry.CompressedSize = entry.Size;
                    }
                }

                if (entry.Size < 0 || entry.Crc < 0)
                {
                    if (CanPatchEntries == true)
                    {
                        headerInfoAvailable = false;
                    }
                    else
                    {
                        // Can't patch entries so storing is not possible.
                        method           = CompressionMethod.Deflated;
                        compressionLevel = 0;
                    }
                }
            }

            if (method == CompressionMethod.Deflated)
            {
                if (entry.Size == 0)
                {
                    // No need to compress - no data.
                    entry.CompressedSize = entry.Size;
                    entry.Crc            = 0;
                    method = CompressionMethod.Stored;
                }
                else if ((entry.CompressedSize < 0) || (entry.Size < 0) || (entry.Crc < 0))
                {
                    headerInfoAvailable = false;
                }
            }

            if (headerInfoAvailable == false)
            {
                if (CanPatchEntries == false)
                {
                    // Only way to record size and compressed size is to append a data descriptor
                    // after compressed data.
                    entry.Flags |= 8;
                }
                else
                {
                    patchEntryHeader = true;
                }
            }

            if (Password != null)
            {
                entry.IsCrypted = true;
                if (entry.Crc < 0)
                {
                    // Need to append a data descriptor as the crc isnt available for use
                    // with encryption, the date is used instead.  Setting the flag
                    // indicates this to the decompressor.
                    entry.Flags |= 8;
                }
            }

            entry.Offset            = offset;
            entry.CompressionMethod = (CompressionMethod)method;

            curMethod    = method;
            sizePatchPos = -1;

            if ((useZip64_ == UseZip64.On) || ((entry.Size < 0) && (useZip64_ == UseZip64.Dynamic)))
            {
                entry.ForceZip64();
            }

            // Write the local file header
            WriteLeInt(ZipConstants.LocalHeaderSignature);

            WriteLeShort(entry.Version);
            WriteLeShort(entry.Flags);
            WriteLeShort((byte)method);
            WriteLeInt((int)entry.DosTime);

            // TODO: Refactor header writing.  Its done in several places.
            if (headerInfoAvailable == true)
            {
                WriteLeInt((int)entry.Crc);
                if (entry.LocalHeaderRequiresZip64)
                {
                    WriteLeInt(-1);
                    WriteLeInt(-1);
                }
                else
                {
                    WriteLeInt(entry.IsCrypted ? (int)entry.CompressedSize + ZipConstants.CryptoHeaderSize : (int)entry.CompressedSize);
                    WriteLeInt((int)entry.Size);
                }
            }
            else
            {
                if (patchEntryHeader == true)
                {
                    crcPatchPos = baseOutputStream_.Position;
                }
                WriteLeInt(0);                  // Crc

                if (patchEntryHeader)
                {
                    sizePatchPos = baseOutputStream_.Position;
                }

                // For local header both sizes appear in Zip64 Extended Information
                if (entry.LocalHeaderRequiresZip64 && patchEntryHeader)
                {
                    WriteLeInt(-1);
                    WriteLeInt(-1);
                }
                else
                {
                    WriteLeInt(0);                      // Compressed size
                    WriteLeInt(0);                      // Uncompressed size
                }
            }

            byte[] name = ZipConstants.ConvertToArray(entry.Flags, entry.Name);

            if (name.Length > 0xFFFF)
            {
                throw new ZipException("Entry name too long.");
            }

            ZipExtraData ed = new ZipExtraData(entry.ExtraData);

            if (entry.LocalHeaderRequiresZip64 && (headerInfoAvailable || patchEntryHeader))
            {
                ed.StartNewEntry();
                if (headerInfoAvailable)
                {
                    ed.AddLeLong(entry.Size);
                    ed.AddLeLong(entry.CompressedSize);
                }
                else
                {
                    ed.AddLeLong(-1);
                    ed.AddLeLong(-1);
                }
                ed.AddNewEntry(1);

                if (!ed.Find(1))
                {
                    throw new ZipException("Internal error cant find extra data");
                }

                if (patchEntryHeader)
                {
                    sizePatchPos = ed.CurrentReadIndex;
                }
            }
            else
            {
                ed.Delete(1);
            }

            byte[] extra = ed.GetEntryData();

            WriteLeShort(name.Length);
            WriteLeShort(extra.Length);

            if (name.Length > 0)
            {
                baseOutputStream_.Write(name, 0, name.Length);
            }

            if (entry.LocalHeaderRequiresZip64 && patchEntryHeader)
            {
                sizePatchPos += baseOutputStream_.Position;
            }

            if (extra.Length > 0)
            {
                baseOutputStream_.Write(extra, 0, extra.Length);
            }

            offset += ZipConstants.LocalHeaderBaseSize + name.Length + extra.Length;

            // Activate the entry.
            curEntry = entry;
            crc.Reset();
            if (method == CompressionMethod.Deflated)
            {
                deflater_.Reset();
                deflater_.SetLevel(compressionLevel);
            }
            size = 0;

            if (entry.IsCrypted == true)
            {
                if (entry.Crc < 0)                                      // so testing Zip will says its ok
                {
                    WriteEncryptionHeader(entry.DosTime << 16);
                }
                else
                {
                    WriteEncryptionHeader(entry.Crc);
                }
            }
        }
Example #6
0
        /// <summary>
        /// Finishes the stream.  This will write the central directory at the
        /// end of the zip file and flush the stream.
        /// </summary>
        /// <remarks>
        /// This is automatically called when the stream is closed.
        /// </remarks>
        /// <exception cref="System.IO.IOException">
        /// An I/O error occurs.
        /// </exception>
        /// <exception cref="ZipException">
        /// Comment exceeds the maximum length<br/>
        /// Entry name exceeds the maximum length
        /// </exception>
        public override void Finish()
        {
            if (entries == null)
            {
                return;
            }

            if (curEntry != null)
            {
                CloseEntry();
            }

            long numEntries  = entries.Count;
            long sizeEntries = 0;

            foreach (ZipEntry entry in entries)
            {
                WriteLeInt(ZipConstants.CentralHeaderSignature);
                WriteLeShort(ZipConstants.VersionMadeBy);
                WriteLeShort(entry.Version);
                WriteLeShort(entry.Flags);
                WriteLeShort((short)entry.CompressionMethod);
                WriteLeInt((int)entry.DosTime);
                WriteLeInt((int)entry.Crc);

                if (entry.IsZip64Forced() ||
                    (entry.CompressedSize >= uint.MaxValue))
                {
                    WriteLeInt(-1);
                }
                else
                {
                    WriteLeInt((int)entry.CompressedSize);
                }

                if (entry.IsZip64Forced() ||
                    (entry.Size >= uint.MaxValue))
                {
                    WriteLeInt(-1);
                }
                else
                {
                    WriteLeInt((int)entry.Size);
                }

                byte[] name = ZipConstants.ConvertToArray(entry.Flags, entry.Name);

                if (name.Length > 0xffff)
                {
                    throw new ZipException("Name too long.");
                }

                ZipExtraData ed = new ZipExtraData(entry.ExtraData);

                if (entry.CentralHeaderRequiresZip64)
                {
                    ed.StartNewEntry();
                    if (entry.IsZip64Forced() ||
                        (entry.Size >= 0xffffffff))
                    {
                        ed.AddLeLong(entry.Size);
                    }

                    if (entry.IsZip64Forced() ||
                        (entry.CompressedSize >= 0xffffffff))
                    {
                        ed.AddLeLong(entry.CompressedSize);
                    }

                    if (entry.Offset >= 0xffffffff)
                    {
                        ed.AddLeLong(entry.Offset);
                    }

                    ed.AddNewEntry(1);
                }
                else
                {
                    ed.Delete(1);
                }

                byte[] extra = ed.GetEntryData();

                byte[] entryComment =
                    (entry.Comment != null) ?
                    ZipConstants.ConvertToArray(entry.Flags, entry.Comment) :
                    new byte[0];

                if (entryComment.Length > 0xffff)
                {
                    throw new ZipException("Comment too long.");
                }

                WriteLeShort(name.Length);
                WriteLeShort(extra.Length);
                WriteLeShort(entryComment.Length);
                WriteLeShort(0);                        // disk number
                WriteLeShort(0);                        // internal file attributes
                // external file attributes

                if (entry.ExternalFileAttributes != -1)
                {
                    WriteLeInt(entry.ExternalFileAttributes);
                }
                else
                {
                    if (entry.IsDirectory)                                               // mark entry as directory (from nikolam.AT.perfectinfo.com)
                    {
                        WriteLeInt(16);
                    }
                    else
                    {
                        WriteLeInt(0);
                    }
                }

                if (entry.Offset >= uint.MaxValue)
                {
                    WriteLeInt(-1);
                }
                else
                {
                    WriteLeInt((int)entry.Offset);
                }

                if (name.Length > 0)
                {
                    baseOutputStream_.Write(name, 0, name.Length);
                }

                if (extra.Length > 0)
                {
                    baseOutputStream_.Write(extra, 0, extra.Length);
                }

                if (entryComment.Length > 0)
                {
                    baseOutputStream_.Write(entryComment, 0, entryComment.Length);
                }

                sizeEntries += ZipConstants.CentralHeaderBaseSize + name.Length + extra.Length + entryComment.Length;
            }

            using (ZipHelperStream zhs = new ZipHelperStream(baseOutputStream_)) {
                zhs.WriteEndOfCentralDirectory(numEntries, sizeEntries, offset, zipComment);
            }

            entries = null;
        }
        /// <summary>
        /// Advances to the next entry in the archive
        /// </summary>
        /// <returns>
        /// The next <see cref="ZipEntry">entry</see> in the archive or null if there are no more entries.
        /// </returns>
        /// <remarks>
        /// If the previous entry is still open <see cref="CloseEntry">CloseEntry</see> is called.
        /// </remarks>
        /// <exception cref="InvalidOperationException">
        /// Input stream is closed
        /// </exception>
        /// <exception cref="ZipException">
        /// Password is not set, password is invalid, compression method is invalid,
        /// version required to extract is not supported
        /// </exception>
        public ZipEntry GetNextEntry()
        {
            if (crc == null)
            {
                throw new InvalidOperationException("Closed.");
            }

            if (entry != null)
            {
                CloseEntry();
            }

            if (this.cryptbuffer != null)
            {
                if (inf.IsFinished == false && (entry.Flags & 8) != 0)
                {
                    throw new ZipException("NextEntry location not known");
                }

                if (avail == 0 && inf.RemainingInput != 0)
                {
                    avail = inf.RemainingInput - 16;
                    inf.Reset();
                }
                baseInputStream.Position -= this.len;
                baseInputStream.Read(this.buf, 0, this.len);
            }

            if (avail <= 0)
            {
                FillBuf(ZipConstants.LOCHDR);
            }

            int header = ReadLeInt();

            if (header == ZipConstants.CENSIG ||
                header == ZipConstants.ENDSIG ||
                header == ZipConstants.CENDIGITALSIG ||
                header == ZipConstants.CENSIG64)
            {
                // No more individual entries exist
                Close();
                return(null);
            }

            // -jr- 07-Dec-2003 Ignore spanning temporary signatures if found
            // SPANNINGSIG is same as descriptor signature and is untested as yet.
            if (header == ZipConstants.SPANTEMPSIG || header == ZipConstants.SPANNINGSIG)
            {
                header = ReadLeInt();
            }

            if (header != ZipConstants.LOCSIG)
            {
                throw new ZipException("Wrong Local header signature: 0x" + String.Format("{0:X}", header));
            }

            short versionRequiredToExtract = (short)ReadLeShort();

            flags  = ReadLeShort();
            method = ReadLeShort();
            uint dostime = (uint)ReadLeInt();
            int  crc2    = ReadLeInt();

            csize = ReadLeInt();
            size  = ReadLeInt();
            int nameLen  = ReadLeShort();
            int extraLen = ReadLeShort();

            bool isCrypted = (flags & 1) == 1;

            byte[] buffer = new byte[nameLen];
            ReadFully(buffer);

            string name = ZipConstants.ConvertToString(buffer);

            entry       = new ZipEntry(name, versionRequiredToExtract);
            entry.Flags = flags;

            if (method == (int)CompressionMethod.Stored && (!isCrypted && csize != size || (isCrypted && csize - ZipConstants.CRYPTO_HEADER_SIZE != size)))
            {
                throw new ZipException("Stored, but compressed != uncompressed");
            }

            if (method != (int)CompressionMethod.Stored && method != (int)CompressionMethod.Deflated)
            {
                throw new ZipException("unknown compression method " + method);
            }

            entry.CompressionMethod = (CompressionMethod)method;

            if ((flags & 8) == 0)
            {
                entry.Crc            = crc2 & 0xFFFFFFFFL;
                entry.Size           = size & 0xFFFFFFFFL;
                entry.CompressedSize = csize & 0xFFFFFFFFL;
                BufferReadSize       = 0;
            }
            else
            {
                if (isCrypted)
                {
                    BufferReadSize = 1;
                }
                else
                {
                    BufferReadSize = 0;
                }

                // This allows for GNU, WinZip and possibly other archives, the PKZIP spec says these are zero
                // under these circumstances.
                if (crc2 != 0)
                {
                    entry.Crc = crc2 & 0xFFFFFFFFL;
                }

                if (size != 0)
                {
                    entry.Size = size & 0xFFFFFFFFL;
                }
                if (csize != 0)
                {
                    entry.CompressedSize = csize & 0xFFFFFFFFL;
                }
            }


            entry.DosTime = dostime;

            if (extraLen > 0)
            {
                byte[] extra = new byte[extraLen];
                ReadFully(extra);
                entry.ExtraData = extra;
            }

            // TODO How to handle this?
            // This library cannot handle versions greater than 20
            // Throwing an exception precludes getting at later possibly useable entries.
            // Could also skip this entry entirely
            // Letting it slip past here isnt so great as it wont work
            if (versionRequiredToExtract > 20)
            {
                throw new ZipException("Libray cannot extract this entry version required (" + versionRequiredToExtract.ToString() + ")");
            }

            // test for encryption
            if (isCrypted)
            {
                if (password == null)
                {
                    throw new ZipException("No password set.");
                }
                InitializePassword(password);
                cryptbuffer = new byte[ZipConstants.CRYPTO_HEADER_SIZE];
                ReadFully(cryptbuffer);
                DecryptBlock(cryptbuffer, 0, cryptbuffer.Length);

                if ((flags & 8) == 0)
                {
                    if (cryptbuffer[ZipConstants.CRYPTO_HEADER_SIZE - 1] != (byte)(crc2 >> 24))
                    {
                        throw new ZipException("Invalid password");
                    }
                }
                else
                {
                    if (cryptbuffer[ZipConstants.CRYPTO_HEADER_SIZE - 1] != (byte)((dostime >> 8) & 0xff))
                    {
                        throw new ZipException("Invalid password");
                    }
                }

                if (csize >= ZipConstants.CRYPTO_HEADER_SIZE)
                {
                    csize -= ZipConstants.CRYPTO_HEADER_SIZE;
                }
            }
            else
            {
                cryptbuffer = null;
            }

            if (method == (int)CompressionMethod.Deflated && avail > 0)
            {
                System.Array.Copy(buf, len - (int)avail, buf, 0, (int)avail);
                len   = (int)avail;
                avail = 0;
                if (isCrypted)
                {
                    DecryptBlock(buf, 0, Math.Min((int)csize, len));
                }
                inf.SetInput(buf, 0, len);
            }

            return(entry);
        }
        /// <summary>
        /// Perform the initial read on an entry which may include
        /// reading encryption headers and setting up inflation.
        /// </summary>
        /// <param name="destination">The destination to fill with data read.</param>
        /// <param name="offset">The offset to start reading at.</param>
        /// <param name="count">The maximum number of bytes to read.</param>
        /// <returns>The actual number of bytes read.</returns>
        int InitialRead(byte[] destination, int offset, int count)
        {
            if (!CanDecompressEntry)
            {
                throw new ZipException("Library cannot extract this entry. Version required is (" + entry.Version.ToString() + ")");
            }

            // Handle encryption if required.
            if (entry.IsCrypted)
            {
#if NETCF_1_0
                throw new ZipException("Encryption not supported for Compact Framework 1.0");
#else
                if (password == null)
                {
                    throw new ZipException("No password set.");
                }

                // Generate and set crypto transform...
                PkzipClassicManaged managed = new PkzipClassicManaged();
                byte[] key = PkzipClassic.GenerateKeys(ZipConstants.ConvertToArray(password));

                inputBuffer.CryptoTransform = managed.CreateDecryptor(key, null);

                byte[] cryptbuffer = new byte[ZipConstants.CryptoHeaderSize];
                inputBuffer.ReadClearTextBuffer(cryptbuffer, 0, ZipConstants.CryptoHeaderSize);

                if (cryptbuffer[ZipConstants.CryptoHeaderSize - 1] != entry.CryptoCheckValue)
                {
                    throw new ZipException("Invalid password");
                }

                if (csize >= ZipConstants.CryptoHeaderSize)
                {
                    csize -= ZipConstants.CryptoHeaderSize;
                }
                else if ((entry.Flags & (int)GeneralBitFlags.Descriptor) == 0)
                {
                    throw new ZipException(string.Format("Entry compressed size {0} too small for encryption", csize));
                }
#endif
            }
            else
            {
#if !NETCF_1_0
                inputBuffer.CryptoTransform = null;
#endif
            }

            if ((csize > 0) || ((flags & (int)GeneralBitFlags.Descriptor) != 0))
            {
                if ((method == (int)CompressionMethod.Deflated) && (inputBuffer.Available > 0))
                {
                    inputBuffer.SetInflaterInput(inf);
                }

                internalReader = new ReadDataHandler(BodyRead);
                return(BodyRead(destination, offset, count));
            }
            else
            {
                internalReader = new ReadDataHandler(ReadingNotAvailable);
                return(0);
            }
        }
Example #9
0
        public ZipEntry GetNextEntry()
        {
            if (this.crc == null)
            {
                throw new InvalidOperationException("Closed.");
            }
            if (this.entry != null)
            {
                this.CloseEntry();
            }
            int num = base.inputBuffer.ReadLeInt();

            switch (num)
            {
            case 0x2014b50:
            case 0x6054b50:
            case 0x5054b50:
            case 0x7064b50:
            case 0x6064b50:
                this.Close();
                return(null);

            case 0x30304b50:
            case 0x8074b50:
                num = base.inputBuffer.ReadLeInt();
                break;
            }
            if (num != 0x4034b50)
            {
                throw new ZipException("Wrong Local header signature: 0x" + $"{num:X}");
            }
            short versionRequiredToExtract = (short)base.inputBuffer.ReadLeShort();

            this.flags  = base.inputBuffer.ReadLeShort();
            this.method = base.inputBuffer.ReadLeShort();
            uint num3 = (uint)base.inputBuffer.ReadLeInt();
            int  num4 = base.inputBuffer.ReadLeInt();

            base.csize = base.inputBuffer.ReadLeInt();
            this.size  = base.inputBuffer.ReadLeInt();
            int  num5 = base.inputBuffer.ReadLeShort();
            int  num6 = base.inputBuffer.ReadLeShort();
            bool flag = (this.flags & 1) == 1;

            byte[] buffer = new byte[num5];
            base.inputBuffer.ReadRawBuffer(buffer);
            string name = ZipConstants.ConvertToStringExt(this.flags, buffer);

            this.entry                   = new ZipEntry(name, versionRequiredToExtract);
            this.entry.Flags             = this.flags;
            this.entry.CompressionMethod = (CompressionMethod)this.method;
            if ((this.flags & 8) == 0)
            {
                this.entry.Crc              = num4 & ((long)0xffffffffL);
                this.entry.Size             = this.size & ((long)0xffffffffL);
                this.entry.CompressedSize   = base.csize & ((long)0xffffffffL);
                this.entry.CryptoCheckValue = (byte)((num4 >> 0x18) & 0xff);
            }
            else
            {
                if (num4 != 0)
                {
                    this.entry.Crc = num4 & ((long)0xffffffffL);
                }
                if (this.size != 0L)
                {
                    this.entry.Size = this.size & ((long)0xffffffffL);
                }
                if (base.csize != 0L)
                {
                    this.entry.CompressedSize = base.csize & ((long)0xffffffffL);
                }
                this.entry.CryptoCheckValue = (byte)((num3 >> 8) & 0xff);
            }
            this.entry.DosTime = num3;
            if (num6 > 0)
            {
                byte[] buffer2 = new byte[num6];
                base.inputBuffer.ReadRawBuffer(buffer2);
                this.entry.ExtraData = buffer2;
            }
            this.entry.ProcessExtraData(true);
            if (this.entry.CompressedSize >= 0L)
            {
                base.csize = this.entry.CompressedSize;
            }
            if (this.entry.Size >= 0L)
            {
                this.size = this.entry.Size;
            }
            if ((this.method == 0) && ((!flag && (base.csize != this.size)) || (flag && ((base.csize - 12L) != this.size))))
            {
                throw new ZipException("Stored, but compressed != uncompressed");
            }
            if (this.entry.IsCompressionMethodSupported())
            {
                this.internalReader = new ReaderDelegate(this.InitialRead);
            }
            else
            {
                this.internalReader = new ReaderDelegate(this.ReadingNotSupported);
            }
            return(this.entry);
        }
Example #10
0
        public ZipEntry GetNextEntry()
        {
            if (crc == null)
            {
                throw new InvalidOperationException("Closed.");
            }
            if (entry != null)
            {
                CloseEntry();
            }
            int num = inputBuffer.ReadLeInt();

            switch (num)
            {
            case 33639248:
            case 84233040:
            case 101010256:
            case 101075792:
            case 117853008:
                Close();
                return(null);

            case 134695760:
            case 808471376:
                num = inputBuffer.ReadLeInt();
                break;
            }
            if (num != 67324752)
            {
                throw new ZipException("Wrong Local header signature: 0x" + $"{num:X}");
            }
            short versionRequiredToExtract = (short)inputBuffer.ReadLeShort();

            flags  = inputBuffer.ReadLeShort();
            method = inputBuffer.ReadLeShort();
            uint num2 = (uint)inputBuffer.ReadLeInt();
            int  num3 = inputBuffer.ReadLeInt();

            csize = inputBuffer.ReadLeInt();
            size  = inputBuffer.ReadLeInt();
            int  num4 = inputBuffer.ReadLeShort();
            int  num5 = inputBuffer.ReadLeShort();
            bool flag = (flags & 1) == 1;

            byte[] array = new byte[num4];
            inputBuffer.ReadRawBuffer(array);
            string name = ZipConstants.ConvertToStringExt(flags, array);

            entry                   = new ZipEntry(name, versionRequiredToExtract);
            entry.Flags             = flags;
            entry.CompressionMethod = (CompressionMethod)method;
            if ((flags & 8) == 0)
            {
                entry.Crc              = (num3 & uint.MaxValue);
                entry.Size             = (size & uint.MaxValue);
                entry.CompressedSize   = (csize & uint.MaxValue);
                entry.CryptoCheckValue = (byte)((num3 >> 24) & 0xFF);
            }
            else
            {
                if (num3 != 0)
                {
                    entry.Crc = (num3 & uint.MaxValue);
                }
                if (size != 0)
                {
                    entry.Size = (size & uint.MaxValue);
                }
                if (csize != 0)
                {
                    entry.CompressedSize = (csize & uint.MaxValue);
                }
                entry.CryptoCheckValue = (byte)((num2 >> 8) & 0xFF);
            }
            entry.DosTime = num2;
            if (num5 > 0)
            {
                byte[] array2 = new byte[num5];
                inputBuffer.ReadRawBuffer(array2);
                entry.ExtraData = array2;
            }
            entry.ProcessExtraData(localHeader: true);
            if (entry.CompressedSize >= 0)
            {
                csize = entry.CompressedSize;
            }
            if (entry.Size >= 0)
            {
                size = entry.Size;
            }
            if (method == 0 && ((!flag && csize != size) || (flag && csize - 12 != size)))
            {
                throw new ZipException("Stored, but compressed != uncompressed");
            }
            if (entry.IsCompressionMethodSupported())
            {
                internalReader = InitialRead;
            }
            else
            {
                internalReader = ReadingNotSupported;
            }
            return(entry);
        }
Example #11
0
 public override void Finish()
 {
     if (entries != null)
     {
         if (curEntry != null)
         {
             CloseEntry();
         }
         long noOfEntries = entries.Count;
         long num         = 0L;
         foreach (ZipEntry entry in entries)
         {
             WriteLeInt(33639248);
             WriteLeShort(51);
             WriteLeShort(entry.Version);
             WriteLeShort(entry.Flags);
             WriteLeShort((short)entry.CompressionMethodForHeader);
             WriteLeInt((int)entry.DosTime);
             WriteLeInt((int)entry.Crc);
             if (entry.IsZip64Forced() || entry.CompressedSize >= uint.MaxValue)
             {
                 WriteLeInt(-1);
             }
             else
             {
                 WriteLeInt((int)entry.CompressedSize);
             }
             if (entry.IsZip64Forced() || entry.Size >= uint.MaxValue)
             {
                 WriteLeInt(-1);
             }
             else
             {
                 WriteLeInt((int)entry.Size);
             }
             byte[] array = ZipConstants.ConvertToArray(entry.Flags, entry.Name);
             if (array.Length > 65535)
             {
                 throw new ZipException("Name too long.");
             }
             ZipExtraData zipExtraData = new ZipExtraData(entry.ExtraData);
             if (entry.CentralHeaderRequiresZip64)
             {
                 zipExtraData.StartNewEntry();
                 if (entry.IsZip64Forced() || entry.Size >= uint.MaxValue)
                 {
                     zipExtraData.AddLeLong(entry.Size);
                 }
                 if (entry.IsZip64Forced() || entry.CompressedSize >= uint.MaxValue)
                 {
                     zipExtraData.AddLeLong(entry.CompressedSize);
                 }
                 if (entry.Offset >= uint.MaxValue)
                 {
                     zipExtraData.AddLeLong(entry.Offset);
                 }
                 zipExtraData.AddNewEntry(1);
             }
             else
             {
                 zipExtraData.Delete(1);
             }
             if (entry.AESKeySize > 0)
             {
                 AddExtraDataAES(entry, zipExtraData);
             }
             byte[] entryData = zipExtraData.GetEntryData();
             byte[] array2    = (entry.Comment != null) ? ZipConstants.ConvertToArray(entry.Flags, entry.Comment) : new byte[0];
             if (array2.Length > 65535)
             {
                 throw new ZipException("Comment too long.");
             }
             WriteLeShort(array.Length);
             WriteLeShort(entryData.Length);
             WriteLeShort(array2.Length);
             WriteLeShort(0);
             WriteLeShort(0);
             if (entry.ExternalFileAttributes != -1)
             {
                 WriteLeInt(entry.ExternalFileAttributes);
             }
             else if (entry.IsDirectory)
             {
                 WriteLeInt(16);
             }
             else
             {
                 WriteLeInt(0);
             }
             if (entry.Offset >= uint.MaxValue)
             {
                 WriteLeInt(-1);
             }
             else
             {
                 WriteLeInt((int)entry.Offset);
             }
             if (array.Length > 0)
             {
                 baseOutputStream_.Write(array, 0, array.Length);
             }
             if (entryData.Length > 0)
             {
                 baseOutputStream_.Write(entryData, 0, entryData.Length);
             }
             if (array2.Length > 0)
             {
                 baseOutputStream_.Write(array2, 0, array2.Length);
             }
             num += 46 + array.Length + entryData.Length + array2.Length;
         }
         using (ZipHelperStream zipHelperStream = new ZipHelperStream(baseOutputStream_))
         {
             zipHelperStream.WriteEndOfCentralDirectory(noOfEntries, num, offset, zipComment);
         }
         entries = null;
     }
 }
Example #12
0
        public void PutNextEntry(ZipEntry entry)
        {
            if (entry == null)
            {
                throw new ArgumentNullException("entry");
            }
            if (entries == null)
            {
                throw new InvalidOperationException("ZipOutputStream was finished");
            }
            if (curEntry != null)
            {
                CloseEntry();
            }
            if (entries.Count == int.MaxValue)
            {
                throw new ZipException("Too many entries for Zip file");
            }
            CompressionMethod compressionMethod = entry.CompressionMethod;
            int level = defaultCompressionLevel;

            entry.Flags     &= 2048;
            patchEntryHeader = false;
            bool flag;

            if (entry.Size == 0)
            {
                entry.CompressedSize = entry.Size;
                entry.Crc            = 0L;
                compressionMethod    = CompressionMethod.Stored;
                flag = true;
            }
            else
            {
                flag = (entry.Size >= 0 && entry.HasCrc);
                if (compressionMethod == CompressionMethod.Stored)
                {
                    if (!flag)
                    {
                        if (!base.CanPatchEntries)
                        {
                            compressionMethod = CompressionMethod.Deflated;
                            level             = 0;
                        }
                    }
                    else
                    {
                        entry.CompressedSize = entry.Size;
                        flag = entry.HasCrc;
                    }
                }
            }
            if (!flag)
            {
                if (!base.CanPatchEntries)
                {
                    entry.Flags |= 8;
                }
                else
                {
                    patchEntryHeader = true;
                }
            }
            if (base.Password != null)
            {
                entry.IsCrypted = true;
                if (entry.Crc < 0)
                {
                    entry.Flags |= 8;
                }
            }
            entry.Offset            = offset;
            entry.CompressionMethod = compressionMethod;
            curMethod    = compressionMethod;
            sizePatchPos = -1L;
            if (useZip64_ == UseZip64.On || (entry.Size < 0 && useZip64_ == UseZip64.Dynamic))
            {
                entry.ForceZip64();
            }
            WriteLeInt(67324752);
            WriteLeShort(entry.Version);
            WriteLeShort(entry.Flags);
            WriteLeShort((byte)entry.CompressionMethodForHeader);
            WriteLeInt((int)entry.DosTime);
            if (flag)
            {
                WriteLeInt((int)entry.Crc);
                if (entry.LocalHeaderRequiresZip64)
                {
                    WriteLeInt(-1);
                    WriteLeInt(-1);
                }
                else
                {
                    WriteLeInt((int)(entry.IsCrypted ? ((int)entry.CompressedSize + 12) : entry.CompressedSize));
                    WriteLeInt((int)entry.Size);
                }
            }
            else
            {
                if (patchEntryHeader)
                {
                    crcPatchPos = baseOutputStream_.Position;
                }
                WriteLeInt(0);
                if (patchEntryHeader)
                {
                    sizePatchPos = baseOutputStream_.Position;
                }
                if (entry.LocalHeaderRequiresZip64 || patchEntryHeader)
                {
                    WriteLeInt(-1);
                    WriteLeInt(-1);
                }
                else
                {
                    WriteLeInt(0);
                    WriteLeInt(0);
                }
            }
            byte[] array = ZipConstants.ConvertToArray(entry.Flags, entry.Name);
            if (array.Length > 65535)
            {
                throw new ZipException("Entry name too long.");
            }
            ZipExtraData zipExtraData = new ZipExtraData(entry.ExtraData);

            if (entry.LocalHeaderRequiresZip64)
            {
                zipExtraData.StartNewEntry();
                if (flag)
                {
                    zipExtraData.AddLeLong(entry.Size);
                    zipExtraData.AddLeLong(entry.CompressedSize);
                }
                else
                {
                    zipExtraData.AddLeLong(-1L);
                    zipExtraData.AddLeLong(-1L);
                }
                zipExtraData.AddNewEntry(1);
                if (!zipExtraData.Find(1))
                {
                    throw new ZipException("Internal error cant find extra data");
                }
                if (patchEntryHeader)
                {
                    sizePatchPos = zipExtraData.CurrentReadIndex;
                }
            }
            else
            {
                zipExtraData.Delete(1);
            }
            if (entry.AESKeySize > 0)
            {
                AddExtraDataAES(entry, zipExtraData);
            }
            byte[] entryData = zipExtraData.GetEntryData();
            WriteLeShort(array.Length);
            WriteLeShort(entryData.Length);
            if (array.Length > 0)
            {
                baseOutputStream_.Write(array, 0, array.Length);
            }
            if (entry.LocalHeaderRequiresZip64 && patchEntryHeader)
            {
                sizePatchPos += baseOutputStream_.Position;
            }
            if (entryData.Length > 0)
            {
                baseOutputStream_.Write(entryData, 0, entryData.Length);
            }
            offset += 30 + array.Length + entryData.Length;
            if (entry.AESKeySize > 0)
            {
                offset += entry.AESOverheadSize;
            }
            curEntry = entry;
            crc.Reset();
            if (compressionMethod == CompressionMethod.Deflated)
            {
                deflater_.Reset();
                deflater_.SetLevel(level);
            }
            size = 0L;
            if (entry.IsCrypted)
            {
                if (entry.AESKeySize > 0)
                {
                    WriteAESHeader(entry);
                }
                else if (entry.Crc < 0)
                {
                    WriteEncryptionHeader(entry.DosTime << 16);
                }
                else
                {
                    WriteEncryptionHeader(entry.Crc);
                }
            }
        }
Example #13
0
        /// <summary>
        /// Open the next entry from the zip archive, and return its description.
        /// If the previous entry wasn't closed, this method will close it.
        /// </summary>
        public ZipEntry GetNextEntry()
        {
            if (crc == null)
            {
                throw new InvalidOperationException("Closed.");
            }
            if (entry != null)
            {
                CloseEntry();
            }

            if (this.cryptbuffer != null)
            {
                if (avail == 0 && inf.RemainingInput != 0)
                {
                    avail = inf.RemainingInput - 16;
                    inf.Reset();
                }
                baseInputStream.Position -= this.len;
                baseInputStream.Read(this.buf, 0, this.len);
            }

            int header = ReadLeInt();

            // -jr- added end sig for empty zip files, Zip64 end sig and digital sig for files that have them...
            if (header == ZipConstants.CENSIG ||
                header == ZipConstants.ENDSIG ||
                header == ZipConstants.CENDIGITALSIG ||
                header == ZipConstants.CENSIG64)
            {
                // Central Header reached or end of empty zip file
                Close();
                return(null);
            }
            // -jr- 07-Dec-2003 ignore spanning temporary signatures if found
            // SPANNINGSIG is same as descriptor signature and is untested as yet.
            if (header == ZipConstants.SPANTEMPSIG || header == ZipConstants.SPANNINGSIG)
            {
                header = ReadLeInt();
            }

            if (header != ZipConstants.LOCSIG)
            {
                throw new ZipException("Wrong Local header signature: 0x" + String.Format("{0:X}", header));
            }

            short version = (short)ReadLeShort();

            flags  = ReadLeShort();
            method = ReadLeShort();
            uint dostime = (uint)ReadLeInt();
            int  crc2    = ReadLeInt();

            csize = ReadLeInt();
            size  = ReadLeInt();
            int  nameLen   = ReadLeShort();
            int  extraLen  = ReadLeShort();
            bool isCrypted = (flags & 1) == 1;

            if (method == ZipOutputStream.STORED && (!isCrypted && csize != size || (isCrypted && csize - 12 != size)))
            {
                throw new ZipException("Stored, but compressed != uncompressed");
            }

            byte[] buffer = new byte[nameLen];
            ReadFully(buffer);

            string name = ZipConstants.ConvertToString(buffer);

            entry           = new ZipEntry(name);
            entry.IsCrypted = isCrypted;
            entry.Version   = (ushort)version;
            if (method != 0 && method != 8)
            {
                throw new ZipException("unknown compression method " + method);
            }
            entry.CompressionMethod = (CompressionMethod)method;

            if ((flags & 8) == 0)
            {
                entry.Crc            = crc2 & 0xFFFFFFFFL;
                entry.Size           = size & 0xFFFFFFFFL;
                entry.CompressedSize = csize & 0xFFFFFFFFL;
            }

            entry.DosTime = dostime;

            if (extraLen > 0)
            {
                byte[] extra = new byte[extraLen];
                ReadFully(extra);
                entry.ExtraData = extra;
            }

            // test for encryption
            if (isCrypted)
            {
                if (password == null)
                {
                    throw new ZipException("No password set.");
                }
                InitializePassword(password);
                cryptbuffer = new byte[12];
                ReadFully(cryptbuffer);
                DecryptBlock(cryptbuffer, 0, cryptbuffer.Length);
                if ((flags & 8) == 0)                  // -jr- 10-Feb-2004 Dont yet know correct size here....
                {
                    csize -= 12;
                }
            }
            else
            {
                cryptbuffer = null;
            }

            if (method == ZipOutputStream.DEFLATED && avail > 0)
            {
                System.Array.Copy(buf, len - (int)avail, buf, 0, (int)avail);
                len   = (int)avail;
                avail = 0;
                if (isCrypted)
                {
                    DecryptBlock(buf, 0, Math.Min((int)csize, len));
                }
                inf.SetInput(buf, 0, len);
            }

            return(entry);
        }