Beispiel #1
0
        /// <summary>
        /// Compress the specified byte[] and return the compressed byte[]
        /// </summary>
        /// <param name="uncompressedBytes"></param>
        /// <param name="entryName"></param>
        /// <returns></returns>
        public static byte[] CompressStream( byte[] uncompressedValue, string entryExtension )
        {
            byte[] compressedBytes;
            using ( MemoryStream compressedStream = new MemoryStream() )
            {
                // Compress the raw bytes into the compressed stream
                using ( ZipOutputStream outStream = new ZipOutputStream( compressedStream ) )
                {
                    outStream.SetLevel( 9 ); // 0 - store only to 9 - means best compression

                    ZipEntry entry = new ZipEntry( string.Concat( "report.", entryExtension ) );
                    outStream.PutNextEntry( entry );
                    outStream.Write( uncompressedValue, 0, uncompressedValue.Length );
                    outStream.Flush();
                    outStream.Finish();

                    // Check the length for this ZipOutputStream
                    long streamLength = outStream.Length;

                    // read the compressed stream's buffer
                    compressedBytes = new byte[ streamLength ];
                    compressedStream.Seek( 0, SeekOrigin.Begin );
                    // Note: There is potential data loss here.  If the compressed stream length
                    //       is > 2Gig, we will have an invalid length, and the file will be
                    //       corrupt.  Rather than adding complexity for that corner case, I'm
                    //       just noting the possibility, and using the cast.
                    compressedStream.Read( compressedBytes, 0, (int)streamLength );
                }
            }

            return compressedBytes;
        }
        /// <summary>
        /// Starts a new Zip entry. It automatically closes the previous
        /// entry if present.  If the compression method is stored, the entry
        /// must have a valid size and crc, otherwise all elements (except
        /// name) are optional, but must be correct if present.  If the time
        /// is not set in the entry, the current time is used.
        /// </summary>
        /// <param name="entry">
        /// the entry.
        /// </param>
        /// <exception cref="System.IO.IOException">
        /// if an I/O error occured.
        /// </exception>
        /// <exception cref="System.InvalidOperationException">
        /// if stream was finished
        /// </exception>
        public void PutNextEntry(ZipEntry entry)
        {
            if (entries == null) {
                throw new InvalidOperationException("ZipOutputStream was finished");
            }

            CompressionMethod method = entry.CompressionMethod;
            int flags = 0;
            entry.IsCrypted = Password != null;
            switch (method) {
                case CompressionMethod.Stored:
                    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 {
                        entry.CompressedSize = entry.Size;
                    }

                    if (entry.IsCrypted) {
                        entry.CompressedSize += 12;
                    }

                    if (entry.Size < 0) {
                        throw new ZipException("Method STORED, but size not set");
                    } else if (entry.Crc < 0) {
                        throw new ZipException("Method STORED, but crc not set");
                    }
                    break;
                case CompressionMethod.Deflated:
                    if (entry.CompressedSize < 0 || entry.Size < 0 || entry.Crc < 0) {
                        flags |= 8;
                    }
                    break;
            }

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

            //			if (entry.DosTime < 0) {
            //				entry.Time = System.Environment.TickCount;
            //			}
            if (entry.IsCrypted) {
                flags |= 1;
            }
            entry.Flags  = flags;
            entry.Offset = offset;
            entry.CompressionMethod = (CompressionMethod)method;

            curMethod    = method;
            // Write the local file header
            WriteLeInt(ZipConstants.LOCSIG);

            // write ZIP version
            WriteLeShort(method == CompressionMethod.Stored ? ZIP_STORED_VERSION : ZIP_DEFLATED_VERSION);
            if ((flags & 8) == 0) {
                WriteLeShort(flags);
                WriteLeShort((byte)method);
                WriteLeInt((int)entry.DosTime);
                WriteLeInt((int)entry.Crc);
                WriteLeInt((int)entry.CompressedSize);
                WriteLeInt((int)entry.Size);
            } else {
                if (baseOutputStream.CanSeek) {
                    shouldWriteBack = true;
                    WriteLeShort((short)(flags & ~8));
                } else {
                    shouldWriteBack = false;
                    WriteLeShort(flags);
                }
                WriteLeShort((byte)method);
                WriteLeInt((int)entry.DosTime);
                if (baseOutputStream.CanSeek) {
                    seekPos = baseOutputStream.Position;
                }
                WriteLeInt(0);
                WriteLeInt(0);
                WriteLeInt(0);
            }
            byte[] name = ZipConstants.ConvertToArray(entry.Name);

            if (name.Length > 0xFFFF) {
                throw new ZipException("Name too long.");
            }
            byte[] extra = entry.ExtraData;
            if (extra == null) {
                extra = new byte[0];
            }
            if (extra.Length > 0xFFFF) {
                throw new ZipException("Extra data too long.");
            }

            WriteLeShort(name.Length);
            WriteLeShort(extra.Length);
            baseOutputStream.Write(name, 0, name.Length);
            baseOutputStream.Write(extra, 0, extra.Length);

            if (Password != null) {
                InitializePassword(Password);
                byte[] cryptbuffer = new byte[12];
                Random rnd = new Random();
                for (int i = 0; i < cryptbuffer.Length; ++i) {
                    cryptbuffer[i] = (byte)rnd.Next();
                }
                EncryptBlock(cryptbuffer, 0, cryptbuffer.Length);
                baseOutputStream.Write(cryptbuffer, 0, cryptbuffer.Length);
            }
            offset += ZipConstants.LOCHDR + name.Length + extra.Length;

            /* Activate the entry. */
            curEntry = entry;
            crc.Reset();
            if (method == CompressionMethod.Deflated) {
                def.Reset();
            }
            size = 0;
        }
        /// <summary>
        /// Closes the current entry.
        /// </summary>
        /// <exception cref="System.IO.IOException">
        /// if an I/O error occured.
        /// </exception>
        /// <exception cref="System.InvalidOperationException">
        /// if no entry is active.
        /// </exception>
        public void CloseEntry()
        {
            if (curEntry == null) {
                throw new InvalidOperationException("No open entry");
            }

            /* First finish the deflater, if appropriate */
            if (curMethod == CompressionMethod.Deflated) {
                base.Finish();
            }

            int csize = curMethod == CompressionMethod.Deflated ? def.TotalOut : size;

            if (curEntry.Size < 0) {
                curEntry.Size = size;
            } else if (curEntry.Size != size) {
                throw new ZipException("size was " + size + ", but I expected " + curEntry.Size);
            }

            if (curEntry.IsCrypted) {
                csize += 12;
            }

            if (curEntry.CompressedSize < 0) {
                curEntry.CompressedSize = csize;
            } else if (curEntry.CompressedSize != csize) {
                throw new ZipException("compressed size was " + csize + ", but I expected " + curEntry.CompressedSize);
            }

            if (curEntry.Crc < 0) {
                curEntry.Crc = crc.Value;
            } else if (curEntry.Crc != crc.Value) {
                throw new ZipException("crc was " + crc.Value +
                    ", but I expected " +
                    curEntry.Crc);
            }

            offset += csize;

            /* Now write the data descriptor entry if needed. */
            if (curMethod == CompressionMethod.Deflated && (curEntry.Flags & 8) != 0) {
                if (shouldWriteBack) {
                    curEntry.Flags &= ~8;
                    long curPos = baseOutputStream.Position;
                    baseOutputStream.Seek(seekPos, SeekOrigin.Begin);
                    WriteLeInt((int)curEntry.Crc);
                    WriteLeInt((int)curEntry.CompressedSize);
                    WriteLeInt((int)curEntry.Size);
                    baseOutputStream.Seek(curPos, SeekOrigin.Begin);
                    shouldWriteBack = false;
                } else {
                    WriteLeInt(ZipConstants.EXTSIG);
                    WriteLeInt((int)curEntry.Crc);
                    WriteLeInt((int)curEntry.CompressedSize);
                    WriteLeInt((int)curEntry.Size);
                    offset += ZipConstants.EXTHDR;
                }
            }

            entries.Add(curEntry);
            curEntry = null;
        }
Beispiel #4
0
 public ZipEntryEnumeration(ZipEntry[] arr)
 {
     array = arr;
 }
Beispiel #5
0
        /// <summary>
        /// Read the central directory of a zip file and fill the entries
        /// array.  This is called exactly once by the constructors.
        /// </summary>
        /// <exception name="System.IO.IOException">
        /// if a i/o error occured.
        /// </exception>
        /// <exception name="Tools.FileCompressionUtilities.ZipException">
        /// if the central directory is malformed
        /// </exception>
        void ReadEntries()
        {
            /* Search for the End Of Central Directory.  When a zip comment is
            * present the directory may start earlier.
            * FIXME: This searches the whole file in a very slow manner if the
            * file isn't a zip file.
            */
            long pos = baseStream.Length - ZipConstants.ENDHDR;
            do {
                if (pos < 0) {
                    throw new ZipException("central directory not found, probably not a zip file");
                }
                baseStream.Seek(pos--, SeekOrigin.Begin);
            } while (ReadLeInt() != ZipConstants.ENDSIG);

            long oldPos = baseStream.Position;
            baseStream.Position += ZipConstants.ENDTOT - ZipConstants.ENDNRD;

            if (baseStream.Position - oldPos != ZipConstants.ENDTOT - ZipConstants.ENDNRD) {
                throw new EndOfStreamException();
            }
            int count = ReadLeShort();

            oldPos = baseStream.Position;
            baseStream.Position += ZipConstants.ENDOFF - ZipConstants.ENDSIZ;

            if (baseStream.Position - oldPos != ZipConstants.ENDOFF - ZipConstants.ENDSIZ) {
                throw new EndOfStreamException();
            }

            int centralOffset = ReadLeInt();

            // GET COMMENT SIZE (COMES AFTER CENTRALOFFSET)
            int commentSize = ReadLeShort();
            byte[] zipComment = new byte[commentSize];
            baseStream.Read(zipComment, 0, zipComment.Length);
            comment = ZipConstants.ConvertToString(zipComment);

            entries = new ZipEntry[count];
            baseStream.Seek(centralOffset, SeekOrigin.Begin);
            for (int i = 0; i < count; i++) {
                if (ReadLeInt() != ZipConstants.CENSIG) {
                    throw new ZipException("Wrong Central Directory signature");
                }

                oldPos = baseStream.Position;
                baseStream.Position += ZipConstants.CENHOW - ZipConstants.CENVEM;

                if (baseStream.Position - oldPos != ZipConstants.CENHOW - ZipConstants.CENVEM) {
                    throw new EndOfStreamException();
                }
                int method = ReadLeShort();
                int dostime = ReadLeInt();
                int crc = ReadLeInt();
                int csize = ReadLeInt();
                int size = ReadLeInt();
                int nameLen = ReadLeShort();
                int extraLen = ReadLeShort();
                int commentLen = ReadLeShort();

                oldPos = baseStream.Position;
                baseStream.Position += ZipConstants.CENOFF - ZipConstants.CENDSK;
                if (baseStream.Position - oldPos != ZipConstants.CENOFF - ZipConstants.CENDSK) {
                    throw new EndOfStreamException();
                }
                int offset = ReadLeInt();

                byte[] buffer = new byte[Math.Max(nameLen, commentLen)];

                baseStream.Read(buffer, 0, nameLen);
                string name = ZipConstants.ConvertToString(buffer);

                ZipEntry entry = new ZipEntry(name);
                entry.CompressionMethod = (CompressionMethod)method;
                entry.Crc = crc & 0xffffffffL;
                entry.Size = size & 0xffffffffL;
                entry.CompressedSize = csize & 0xffffffffL;
                entry.DosTime = (uint)dostime;
                if (extraLen > 0) {
                    byte[] extra = new byte[extraLen];
                    baseStream.Read(extra, 0, extraLen);
                    entry.ExtraData = extra;
                }
                if (commentLen > 0) {
                    baseStream.Read(buffer, 0, commentLen);
                    entry.Comment = ZipConstants.ConvertToString(buffer);
                }
                entry.ZipFileIndex = i;
                entry.Offset = offset;
                entries[i] = entry;
            }
        }
Beispiel #6
0
        /// <summary>
        /// Checks, if the local header of the entry at index i matches the
        /// central directory, and returns the offset to the data.
        /// </summary>
        /// <returns>
        /// the start offset of the (compressed) data.
        /// </returns>
        /// <exception name="System.IO.IOException">
        /// if a i/o error occured.
        /// </exception>
        /// <exception name="Tools.FileCompressionUtilities.ZipException">
        /// if the local header doesn't match the central directory header
        /// </exception>
        long CheckLocalHeader(ZipEntry entry)
        {
            lock(baseStream) {
                baseStream.Seek(entry.Offset, SeekOrigin.Begin);
                if (ReadLeInt() != ZipConstants.LOCSIG) {
                    throw new ZipException("Wrong Local header signature");
                }

                /* skip version and flags */
                long oldPos = baseStream.Position;
                baseStream.Position += ZipConstants.LOCHOW - ZipConstants.LOCVER;
                if (baseStream.Position - oldPos != ZipConstants.LOCHOW - ZipConstants.LOCVER) {
                    throw new EndOfStreamException();
                }

                if (entry.CompressionMethod != (CompressionMethod)ReadLeShort()) {
                    throw new ZipException("Compression method mismatch");
                }

                /* Skip time, crc, size and csize */
                oldPos = baseStream.Position;
                baseStream.Position += ZipConstants.LOCNAM - ZipConstants.LOCTIM;

                if (baseStream.Position - oldPos != ZipConstants.LOCNAM - ZipConstants.LOCTIM) {
                    throw new EndOfStreamException();
                }

                if (entry.Name.Length != ReadLeShort()) {
                    throw new ZipException("file name length mismatch");
                }

                int extraLen = entry.Name.Length + ReadLeShort();
                return entry.Offset + ZipConstants.LOCHDR + extraLen;
            }
        }
Beispiel #7
0
        /// <summary>
        /// Creates an input stream reading the given zip entry as
        /// uncompressed data.  Normally zip entry should be an entry
        /// returned by GetEntry().
        /// </summary>
        /// <returns>
        /// the input stream.
        /// </returns>
        /// <exception name="System.IO.IOException">
        /// if a i/o error occured.
        /// </exception>
        /// <exception name="Tools.FileCompressionUtilities.ZipException">
        /// if the Zip archive is malformed.
        /// </exception>
        public Stream GetInputStream(ZipEntry entry)
        {
            if (entries == null) {
                throw new InvalidOperationException("ZipFile has closed");
            }

            int index = entry.ZipFileIndex;
            if (index < 0 || index >= entries.Length || entries[index].Name != entry.Name) {
                index = GetEntryIndex(entry.Name);
                if (index < 0) {
                    throw new IndexOutOfRangeException();
                }
            }

            long start = CheckLocalHeader(entries[index]);
            CompressionMethod method = entries[index].CompressionMethod;
            Stream istr = new PartialInputStream(baseStream, start, entries[index].CompressedSize);
            switch (method) {
                case CompressionMethod.Stored:
                    return istr;
                case CompressionMethod.Deflated:
                    return new InflaterInputStream(istr, new Inflater(true));
                default:
                    throw new ZipException("Unknown compression method " + method);
            }
        }
Beispiel #8
0
 /// <summary>
 /// Creates a copy of the given zip entry.
 /// </summary>
 /// <param name="e">
 /// the entry to copy.
 /// </param>
 public ZipEntry(ZipEntry e)
 {
     name           = e.name;
     known          = e.known;
     size           = e.size;
     compressedSize = e.compressedSize;
     crc            = e.crc;
     dosTime        = e.dosTime;
     method         = e.method;
     extra          = e.extra;
     comment        = e.comment;
 }
        /// <summary>
        /// Reads a block of bytes from the current zip entry.
        /// </summary>
        /// <returns>
        /// the number of bytes read (may be smaller, even before EOF), or -1 on EOF.
        /// </returns>
        /// <exception name="Exception">
        /// IOException if a i/o error occured.
        /// ZipException if the deflated stream is corrupted.
        /// </exception>
        public override int Read(byte[] b, int off, int len)
        {
            if (crc == null) {
                throw new InvalidOperationException("Closed.");
            }

            if (entry == null) {
                return 0;
            }
            bool finished = false;

            switch (method) {
                case ZipOutputStream.DEFLATED:
                    len = base.Read(b, off, len);
                    if (len <= 0) { // TODO BUG1 -jr- Check this was < 0 but avail was not adjusted causing failure in later calls
                        if (!inf.IsFinished) {
                            throw new ZipException("Inflater not finished!?");
                        }
                        avail = inf.RemainingInput;

                        // BUG1 -jr- With bit 3 set you dont yet know the size
                        if ((flags & 8) == 0 && (inf.TotalIn != csize || inf.TotalOut != size)) {
                            throw new ZipException("size mismatch: " + csize + ";" + size + " <-> " + inf.TotalIn + ";" + inf.TotalOut);
                        }
                        inf.Reset();
                        finished = true;
                    }
                    break;

                case ZipOutputStream.STORED:
                    if (len > csize && csize >= 0) {
                        len = (int)csize;
                    }
                    len = ReadBuf(b, off, len);
                    if (len > 0) {
                        csize -= len;
                        size -= len;
                    }

                    if (csize == 0) {
                        finished = true;
                    } else {
                        if (len < 0) {
                            throw new ZipException("EOF in stored block");
                        }
                    }

                    // decrypting crypted data
                    if (cryptbuffer != null) {
                        DecryptBlock(b, off, len);
                    }

                    break;
            }

            if (len > 0) {
                crc.Update(b, off, len);
            }

            if (finished) {
                if ((flags & 8) != 0) {
                    ReadDataDescr();
                }

                if ((crc.Value & 0xFFFFFFFFL) != entry.Crc && entry.Crc != -1) {
                    throw new ZipException("CRC mismatch");
                }
                crc.Reset();
                entry = null;
            }
            return len;
        }
        /// <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;
        }
        /// <summary>
        /// Closes the current zip entry and moves to the next one.
        /// </summary>
        public void CloseEntry()
        {
            if (crc == null) {
                throw new InvalidOperationException("Closed.");
            }

            if (entry == null) {
                return;
            }

            if (method == ZipOutputStream.DEFLATED) {
                if ((flags & 8) != 0) {
                    /* We don't know how much we must skip, read until end. */
                    byte[] tmp = new byte[2048];
                    while (Read(tmp, 0, tmp.Length) > 0)
                        ;
                    /* read will close this entry */
                    return;
                }
                csize -= inf.TotalIn;
                avail = inf.RemainingInput;
            }
            if (avail > csize && csize >= 0) {
                avail -= csize;
            } else {
                csize -= avail;
                avail = 0;
                while (csize != 0) {
                    int skipped = (int)base.Skip(csize & 0xFFFFFFFFL);

                    if (skipped <= 0) {
                        throw new ZipException("zip archive ends early.");
                    }

                    csize -= skipped;
                }
            }

            size = 0;
            crc.Reset();
            if (method == ZipOutputStream.DEFLATED) {
                inf.Reset();
            }
            entry = null;
        }
 /// <summary>
 /// Closes the zip file.
 /// </summary>
 /// <exception name="Exception">
 /// if a i/o error occured.
 /// </exception>
 public override void Close()
 {
     base.Close();
     crc = null;
     entry = null;
 }