Beispiel #1
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();
            }

            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);
            }

            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);
        }