Example #1
0
        /// <summary>
        /// 压缩文件
        /// </summary>
        /// <param name="fileToZip">要压缩的文件路径</param>
        /// <param name="zipedFile">压缩后的文件路径</param>
        public void ZipFile(string fileToZip, string zipedFile)
        {
            if (!File.Exists(fileToZip))
            {
                throw new FileNotFoundException("The specified file " + fileToZip + " could not be found.");
            }

            if (!string.IsNullOrEmpty(zipedFile))
            {
                zipedFile = Path.GetFileNameWithoutExtension(zipedFile) + ".zip";
            }

            if (Path.GetExtension(zipedFile) != ".zip")
            {
                zipedFile = zipedFile + ".zip";
            }

            string zipedDir = zipedFile.Substring(0, zipedFile.LastIndexOf("\\"));
            if (!Directory.Exists(zipedDir))
            {
                Directory.CreateDirectory(zipedDir);
            }

            using (ZipOutputStream zipStream = new ZipOutputStream(File.Create(zipedFile)))
            {
                string fileName = Path.GetFileName(fileToZip);
                ZipEntry zipEntry = new ZipEntry(fileName);
                zipStream.PutNextEntry(zipEntry);
                zipStream.SetLevel(compressionLevel);

                using (FileStream streamToZip = new FileStream(fileToZip, FileMode.Open, FileAccess.Read))
                {
                    int size = streamToZip.Read(buffer, 0, buffer.Length);
                    zipStream.Write(buffer, 0, size);

                    while (size < streamToZip.Length)
                    {
                        int sizeRead = streamToZip.Read(buffer, 0, buffer.Length);
                        zipStream.Write(buffer, 0, sizeRead);
                        size += sizeRead;
                    }
                }
            }
        }
Example #2
0
 internal void SetEntry(ZipEntry entry)
 {
     entry_ = entry;
     entryValid_ = true;
     bytesTested_ = 0;
 }
Example #3
0
        /// <summary>
        /// Closes the current entry, updating header and footer information as required
        /// </summary>
        /// <exception cref="System.IO.IOException">
        /// An I/O error occurs.
        /// </exception>
        /// <exception cref="System.InvalidOperationException">
        /// No entry is active.
        /// </exception>
        public void CloseEntry()
        {
            if (curEntry == null) {
                throw new InvalidOperationException("No open entry");
            }

            long csize = size;

            // First finish the deflater, if appropriate
            if (curMethod == CompressionMethod.Deflated) {
                if (size > 0) {
                    base.Finish();
                    csize = deflater_.TotalOut;
                }
                else {
                    deflater_.Reset();
                }
            }

            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.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;

            if (curEntry.IsCrypted == true) {
                curEntry.CompressedSize += ZipConstants.CryptoHeaderSize;
            }

            // Patch the header if possible
            if (patchEntryHeader == true) {
                patchEntryHeader = false;

                long curPos = baseOutputStream_.Position;
                baseOutputStream_.Seek(crcPatchPos, SeekOrigin.Begin);
                WriteLeInt((int)curEntry.Crc);

                if ( curEntry.LocalHeaderRequiresZip64 ) {

                    if ( sizePatchPos == -1 ) {
                        throw new ZipException("Entry requires zip64 but this has been turned off");
                    }

                    baseOutputStream_.Seek(sizePatchPos, SeekOrigin.Begin);
                    WriteLeLong(curEntry.Size);
                    WriteLeLong(curEntry.CompressedSize);
                }
                else {
                    WriteLeInt((int)curEntry.CompressedSize);
                    WriteLeInt((int)curEntry.Size);
                }
                baseOutputStream_.Seek(curPos, SeekOrigin.Begin);
            }

            // Add data descriptor if flagged as required
            if ((curEntry.Flags & 8) != 0) {
                WriteLeInt(ZipConstants.DataDescriptorSignature);
                WriteLeInt(unchecked((int)curEntry.Crc));

                if ( curEntry.LocalHeaderRequiresZip64 ) {
                    WriteLeLong(curEntry.CompressedSize);
                    WriteLeLong(curEntry.Size);
                    offset += ZipConstants.Zip64DataDescriptorSize;
                }
                else {
                    WriteLeInt((int)curEntry.CompressedSize);
                    WriteLeInt((int)curEntry.Size);
                    offset += ZipConstants.DataDescriptorSize;
                }
            }

            entries.Add(curEntry);
            curEntry = null;
        }
Example #4
0
        //        TBD: Direct form of updating
        //
        //        public void Update(IEntryMatcher deleteMatcher)
        //        {
        //        }
        //
        //        public void Update(IScanner addScanner)
        //        {
        //        }
        /* Modify not yet ready for public consumption.
           Direct modification of an entry should not overwrite original data before its read.
           Safe mode is trivial in this sense.
        public void Modify(ZipEntry original, ZipEntry updated)
        {
            if ( original == null ) {
                throw new ArgumentNullException("original");
            }

            if ( updated == null ) {
                throw new ArgumentNullException("updated");
            }

            CheckUpdating();
            contentsEdited_ = true;
            updates_.Add(new ZipUpdate(original, updated));
        }
        */

        #endregion Other

        #if !NETCF_1_0

        static void CheckClassicPassword(CryptoStream classicCryptoStream, ZipEntry entry)
        {
            byte[] cryptbuffer = new byte[ZipConstants.CryptoHeaderSize];
            StreamUtils.ReadFully(classicCryptoStream, cryptbuffer);
            if (cryptbuffer[ZipConstants.CryptoHeaderSize - 1] != entry.CryptoCheckValue) {
                throw new ZipException("Invalid password");
            }
        }
Example #5
0
        Stream CreateAndInitEncryptionStream(Stream baseStream, ZipEntry entry)
        {
            CryptoStream result = null;
            if ( (entry.Version < ZipConstants.VersionStrongEncryption)
                || (entry.Flags & (int)GeneralBitFlags.StrongEncryption) == 0) {
                PkzipClassicManaged classicManaged = new PkzipClassicManaged();

                OnKeysRequired(entry.Name);
                if (HaveKeys == false) {
                    throw new ZipException("No password available for encrypted stream");
                }

                // Closing a CryptoStream will close the base stream as well so wrap it in an UncompressedStream
                // which doesnt do this.
                result = new CryptoStream(new UncompressedStream(baseStream),
                    classicManaged.CreateEncryptor(key, null), CryptoStreamMode.Write);

                if ( (entry.Crc < 0) || (entry.Flags & 8) != 0) {
                    WriteEncryptionHeader(result, entry.DosTime << 16);
                }
                else {
                    WriteEncryptionHeader(result, entry.Crc);
                }
            }
            return result;
        }
Example #6
0
 public ZipUpdate(IStaticDataSource dataSource, ZipEntry entry)
 {
     command_ = UpdateCommand.Add;
     entry_ = entry;
     dataSource_ = dataSource;
 }
Example #7
0
 public ZipUpdate(UpdateCommand command, ZipEntry entry)
 {
     command_ = command;
     entry_ = ( ZipEntry )entry.Clone();
 }
Example #8
0
        /// <summary>
        /// Gets an input stream for reading the given zip entry data in an uncompressed form.
        /// Normally the <see cref="ZipEntry"/> should be an entry returned by GetEntry().
        /// </summary>
        /// <param name="entry">The <see cref="ZipEntry"/> to obtain a data <see cref="Stream"/> for</param>
        /// <returns>An input <see cref="Stream"/> containing data for this <see cref="ZipEntry"/></returns>
        /// <exception cref="ObjectDisposedException">
        /// The ZipFile has already been closed
        /// </exception>
        /// <exception cref="DME.Zip.Zip.ZipException">
        /// The compression method for the entry is unknown
        /// </exception>
        /// <exception cref="IndexOutOfRangeException">
        /// The entry is not found in the ZipFile
        /// </exception>
        public Stream GetInputStream(ZipEntry entry)
        {
            if ( entry == null ) {
                throw new ArgumentNullException("entry");
            }

            if ( isDisposed_ ) {
                throw new ObjectDisposedException("ZipFile");
            }

            long index = entry.ZipFileIndex;
            if ( (index < 0) || (index >= entries_.Length) || (entries_[index].Name != entry.Name) ) {
                index = FindEntry(entry.Name, true);
                if (index < 0) {
                    throw new ZipException("Entry cannot be found");
                }
            }
            return GetInputStream(index);
        }
Example #9
0
        int FindExistingUpdate(ZipEntry entry)
        {
            int result = -1;
            string convertedName = GetTransformedFileName(entry.Name);

            if (updateIndex_.ContainsKey(convertedName)) {
                result = (int)updateIndex_[convertedName];
            }
            /*
            // This is slow like the coming of the next ice age but takes less storage and may be useful
            // for CF?
            for (int index = 0; index < updates_.Count; ++index)
            {
                ZipUpdate zu = ( ZipUpdate )updates_[index];
                if ( (zu.Entry.ZipFileIndex == entry.ZipFileIndex) &&
                    (string.Compare(convertedName, zu.Entry.Name, true, CultureInfo.InvariantCulture) == 0) ) {
                    result = index;
                    break;
                }
            }
             */
            return result;
        }
Example #10
0
        /// <summary>
        /// Add a <see cref="ZipEntry"/> that contains no data.
        /// </summary>
        /// <param name="entry">The entry to add.</param>
        /// <remarks>This can be used to add directories, volume labels, or empty file entries.</remarks>
        public void Add(ZipEntry entry)
        {
            if ( entry == null ) {
                throw new ArgumentNullException("entry");
            }

            CheckUpdating();

            if ( (entry.Size != 0) || (entry.CompressedSize != 0) ) {
                throw new ZipException("Entry cannot have any data");
            }

            AddUpdate(new ZipUpdate(UpdateCommand.Add, entry));
        }
Example #11
0
        /// <summary>
        /// Delete a <see cref="ZipEntry"/> from the archive.
        /// </summary>
        /// <param name="entry">The entry to delete.</param>
        public void Delete(ZipEntry entry)
        {
            if ( entry == null ) {
                throw new ArgumentNullException("entry");
            }

            CheckUpdating();

            int index = FindExistingUpdate(entry);
            if ( index >= 0 ) {
                contentsEdited_ = true;
                updates_[index] = null;
                updateCount_ -= 1;
            }
            else {
                throw new ZipException("Cannot find entry to delete");
            }
        }
Example #12
0
        /// <summary>
        /// Complete cleanup as the final part of closing.
        /// </summary>
        /// <param name="testCrc">True if the crc value should be tested</param>
        void CompleteCloseEntry(bool testCrc)
        {
            StopDecrypting();

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

            size = 0;

            if ( testCrc &&
                ((crc.Value & 0xFFFFFFFFL) != entry.Crc) && (entry.Crc != -1)) {
                throw new ZipException("CRC mismatch");
            }

            crc.Reset();

            if (method == (int)CompressionMethod.Deflated) {
                inf.Reset();
            }
            entry = null;
        }
Example #13
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 #14
0
        /// <summary>
        /// Closes the zip input stream
        /// </summary>
        public override void Close()
        {
            internalReader = new ReadDataHandler(ReadingNotAvailable);
            crc = null;
            entry = null;

            base.Close();
        }
Example #15
0
 public ZipUpdate(string fileName, string entryName, CompressionMethod compressionMethod)
 {
     command_ = UpdateCommand.Add;
     entry_ = new ZipEntry(entryName);
     entry_.CompressionMethod = compressionMethod;
     filename_ = fileName;
 }
Example #16
0
        /// <summary>
        /// Get an output stream for the specified <see cref="ZipEntry"/>
        /// </summary>
        /// <param name="entry">The entry to get an output stream for.</param>
        /// <returns>The output stream obtained for the entry.</returns>
        Stream GetOutputStream(ZipEntry entry)
        {
            Stream result = baseStream_;

            if ( entry.IsCrypted == true ) {
            #if NETCF_1_0
                throw new ZipException("Encryption not supported for Compact Framework 1.0");
            #else
                result = CreateAndInitEncryptionStream(result, entry);
            #endif
            }

            switch ( entry.CompressionMethod ) {
                case CompressionMethod.Stored:
                    result = new UncompressedStream(result);
                    break;

                case CompressionMethod.Deflated:
                    DeflaterOutputStream dos = new DeflaterOutputStream(result, new Deflater(9, true));
                    dos.IsStreamOwner = false;
                    result = dos;
                    break;

                default:
                    throw new ZipException("Unknown compression method " + entry.CompressionMethod);
            }
            return result;
        }
Example #17
0
 public ZipUpdate(IStaticDataSource dataSource, string entryName, CompressionMethod compressionMethod)
 {
     command_ = UpdateCommand.Add;
     entry_ = new ZipEntry(entryName);
     entry_.CompressionMethod = compressionMethod;
     dataSource_ = dataSource;
 }
Example #18
0
 /// <summary>
 /// Locate the data for a given entry.
 /// </summary>
 /// <returns>
 /// The start offset of the data.
 /// </returns>
 /// <exception cref="System.IO.EndOfStreamException">
 /// The stream ends prematurely
 /// </exception>
 /// <exception cref="DME.Zip.Zip.ZipException">
 /// The local header signature is invalid, the entry and central header file name lengths are different
 /// or the local and entry compression methods dont match
 /// </exception>
 long LocateEntry(ZipEntry entry)
 {
     return TestLocalHeader(entry, HeaderTest.Extract);
 }
Example #19
0
 public ZipUpdate(ZipEntry original, ZipEntry updated)
 {
     throw new ZipException("Modify not currently supported");
     /*
     command_ = UpdateCommand.Modify;
     entry_ = ( ZipEntry )original.Clone();
     outEntry_ = ( ZipEntry )updated.Clone();
     */
 }
Example #20
0
        /// <summary>
        /// Search for and read the central directory of a zip file filling the entries array.
        /// </summary>
        /// <exception cref="System.IO.IOException">
        /// An i/o error occurs.
        /// </exception>
        /// <exception cref="DME.Zip.Zip.ZipException">
        /// The central directory is malformed or cannot be found
        /// </exception>
        void ReadEntries()
        {
            // Search for the End Of Central Directory.  When a zip comment is
            // present the directory will start earlier
            //
            // The search is limited to 64K which is the maximum size of a trailing comment field to aid speed.
            // This should be compatible with both SFX and ZIP files but has only been tested for Zip files
            // If a SFX file has the Zip data attached as a resource and there are other resources occuring later then
            // this could be invalid.
            // Could also speed this up by reading memory in larger blocks.

            if (baseStream_.CanSeek == false) {
                throw new ZipException("ZipFile stream must be seekable");
            }

            long locatedEndOfCentralDir = LocateBlockWithSignature(ZipConstants.EndOfCentralDirectorySignature,
                baseStream_.Length, ZipConstants.EndOfCentralRecordBaseSize, 0xffff);

            if (locatedEndOfCentralDir < 0) {
                throw new ZipException("Cannot find central directory");
            }

            // Read end of central directory record
            ushort thisDiskNumber           = ReadLEUshort();
            ushort startCentralDirDisk      = ReadLEUshort();
            ulong entriesForThisDisk        = ReadLEUshort();
            ulong entriesForWholeCentralDir = ReadLEUshort();
            ulong centralDirSize            = ReadLEUint();
            long offsetOfCentralDir         = ReadLEUint();
            uint commentSize                = ReadLEUshort();

            if ( commentSize > 0 ) {
                byte[] comment = new byte[commentSize];

                StreamUtils.ReadFully(baseStream_, comment);
                comment_ = ZipConstants.ConvertToString(comment);
            }
            else {
                comment_ = string.Empty;
            }

            bool isZip64 = false;

            // Check if zip64 header information is required.
            if ( (thisDiskNumber == 0xffff) ||
                (startCentralDirDisk == 0xffff) ||
                (entriesForThisDisk == 0xffff) ||
                (entriesForWholeCentralDir == 0xffff) ||
                (centralDirSize == 0xffffffff) ||
                (offsetOfCentralDir == 0xffffffff) ) {
                isZip64 = true;

                long offset = LocateBlockWithSignature(ZipConstants.Zip64CentralDirLocatorSignature, locatedEndOfCentralDir, 0, 0x1000);
                if ( offset < 0 ) {
                    throw new ZipException("Cannot find Zip64 locator");
                }

                // number of the disk with the start of the zip64 end of central directory 4 bytes
                // relative offset of the zip64 end of central directory record 8 bytes
                // total number of disks 4 bytes
                ReadLEUint(); // startDisk64 is not currently used
                ulong offset64 = ReadLEUlong();
                uint totalDisks = ReadLEUint();

                baseStream_.Position = (long)offset64;
                long sig64 = ReadLEUint();

                if ( sig64 != ZipConstants.Zip64CentralFileHeaderSignature ) {
                    throw new ZipException(string.Format("Invalid Zip64 Central directory signature at {0:X}", offset64));
                }

                // NOTE: Record size = SizeOfFixedFields + SizeOfVariableData - 12.
                ulong recordSize = ( ulong )ReadLEUlong();
                int versionMadeBy = ReadLEUshort();
                int versionToExtract = ReadLEUshort();
                uint thisDisk = ReadLEUint();
                uint centralDirDisk = ReadLEUint();
                entriesForThisDisk = ReadLEUlong();
                entriesForWholeCentralDir = ReadLEUlong();
                centralDirSize = ReadLEUlong();
                offsetOfCentralDir = (long)ReadLEUlong();

                // NOTE: zip64 extensible data sector (variable size) is ignored.
            }

            entries_ = new ZipEntry[entriesForThisDisk];

            // SFX/embedded support, find the offset of the first entry vis the start of the stream
            // This applies to Zip files that are appended to the end of an SFX stub.
            // Or are appended as a resource to an executable.
            // Zip files created by some archivers have the offsets altered to reflect the true offsets
            // and so dont require any adjustment here...
            // TODO: Difficulty with Zip64 and SFX offset handling needs resolution - maths?
            if ( !isZip64 && (offsetOfCentralDir < locatedEndOfCentralDir - (4 + (long)centralDirSize)) ) {
                offsetOfFirstEntry = locatedEndOfCentralDir - (4 + (long)centralDirSize + offsetOfCentralDir);
                if (offsetOfFirstEntry <= 0) {
                    throw new ZipException("Invalid embedded zip archive");
                }
            }

            baseStream_.Seek(offsetOfFirstEntry + offsetOfCentralDir, SeekOrigin.Begin);

            for (ulong i = 0; i < entriesForThisDisk; i++) {
                if (ReadLEUint() != ZipConstants.CentralHeaderSignature) {
                    throw new ZipException("Wrong Central Directory signature");
                }

                int versionMadeBy      = ReadLEUshort();
                int versionToExtract   = ReadLEUshort();
                int bitFlags           = ReadLEUshort();
                int method             = ReadLEUshort();
                uint dostime           = ReadLEUint();
                uint crc               = ReadLEUint();
                long csize             = (long)ReadLEUint();
                long size              = (long)ReadLEUint();
                int nameLen            = ReadLEUshort();
                int extraLen           = ReadLEUshort();
                int commentLen         = ReadLEUshort();

                int diskStartNo        = ReadLEUshort();  // Not currently used
                int internalAttributes = ReadLEUshort();  // Not currently used

                uint externalAttributes = ReadLEUint();
                long offset             = ReadLEUint();

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

                StreamUtils.ReadFully(baseStream_, buffer, 0, nameLen);
                string name = ZipConstants.ConvertToStringExt(bitFlags, buffer, nameLen);

                ZipEntry entry = new ZipEntry(name, versionToExtract, versionMadeBy, (CompressionMethod)method);
                entry.Crc = crc & 0xffffffffL;
                entry.Size = size & 0xffffffffL;
                entry.CompressedSize = csize & 0xffffffffL;
                entry.Flags = bitFlags;
                entry.DosTime = (uint)dostime;
                entry.ZipFileIndex = (long)i;
                entry.Offset = offset;
                entry.ExternalFileAttributes = (int)externalAttributes;

                if ((bitFlags & 8) == 0) {
                    entry.CryptoCheckValue = (byte)(crc >> 24);
                }
                else {
                    entry.CryptoCheckValue = (byte)((dostime >> 8) & 0xff);
                }

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

                entry.ProcessExtraData(false);

                if (commentLen > 0) {
                    StreamUtils.ReadFully(baseStream_, buffer, 0, commentLen);
                    entry.Comment = ZipConstants.ConvertToStringExt(bitFlags, buffer, commentLen);
                }

                entries_[i] = entry;
            }
        }
Example #21
0
 /// <summary>
 /// Copy an existing entry.
 /// </summary>
 /// <param name="entry">The existing entry to copy.</param>
 public ZipUpdate(ZipEntry entry)
     : this(UpdateCommand.Copy, entry)
 {
     // Do nothing.
 }
Example #22
0
        /// <summary>
        /// Test a local header against that provided from the central directory
        /// </summary>
        /// <param name="entry">
        /// The entry to test against
        /// </param>
        /// <param name="tests">The type of <see cref="HeaderTest">tests</see> to carry out.</param>
        /// <returns>The offset of the entries data in the file</returns>
        long TestLocalHeader(ZipEntry entry, HeaderTest tests)
        {
            lock(baseStream_)
            {
                bool testHeader = (tests & HeaderTest.Header) != 0;
                bool testData = (tests & HeaderTest.Extract) != 0;

                baseStream_.Seek(offsetOfFirstEntry + entry.Offset, SeekOrigin.Begin);
                if ((int)ReadLEUint() != ZipConstants.LocalHeaderSignature) {
                    throw new ZipException(string.Format("Wrong local header signature @{0:X}", offsetOfFirstEntry + entry.Offset));
                }

                short extractVersion = ( short )ReadLEUshort();
                short localFlags = ( short )ReadLEUshort();
                short compressionMethod = ( short )ReadLEUshort();
                short fileTime = ( short )ReadLEUshort();
                short fileDate = ( short )ReadLEUshort();
                uint crcValue = ReadLEUint();
                long compressedSize = ReadLEUint();
                long size = ReadLEUint();
                int storedNameLength = ReadLEUshort();
                int extraDataLength = ReadLEUshort();

                byte[] nameData = new byte[storedNameLength];
                StreamUtils.ReadFully(baseStream_, nameData);

                byte[] extraData = new byte[extraDataLength];
                StreamUtils.ReadFully(baseStream_, extraData);

                ZipExtraData localExtraData = new ZipExtraData(extraData);

                // Extra data / zip64 checks
                if (localExtraData.Find(1))
                {
                    // TODO Check for tag values being distinct..  Multiple zip64 tags means what?

                    // Zip64 extra data but 'extract version' is too low
                    if (extractVersion < ZipConstants.VersionZip64)
                    {
                        throw new ZipException(
                            string.Format("Extra data contains Zip64 information but version {0}.{1} is not high enough",
                            extractVersion / 10, extractVersion % 10));
                    }

                    // Zip64 extra data but size fields dont indicate its required.
                    if (((uint)size != uint.MaxValue) && ((uint)compressedSize != uint.MaxValue))
                    {
                        throw new ZipException("Entry sizes not correct for Zip64");
                    }

                    size = localExtraData.ReadLong();
                    compressedSize = localExtraData.ReadLong();

                    if ((localFlags & (int)GeneralBitFlags.Descriptor) != 0)
                    {
                        // These may be valid if patched later
                        if ( (size != -1) && (size != entry.Size)) {
                            throw new ZipException("Size invalid for descriptor");
                        }

                        if ((compressedSize != -1) && (compressedSize != entry.CompressedSize)) {
                            throw new ZipException("Compressed size invalid for descriptor");
                        }
                    }
                }
                else
                {
                    // No zip64 extra data but entry requires it.
                    if ((extractVersion >= ZipConstants.VersionZip64) &&
                        (((uint)size == uint.MaxValue) || ((uint)compressedSize == uint.MaxValue)))
                    {
                        throw new ZipException("Required Zip64 extended information missing");
                    }
                }

                if ( testData ) {
                    if ( entry.IsFile ) {
                        if ( !entry.IsCompressionMethodSupported() ) {
                            throw new ZipException("Compression method not supported");
                        }

                        if ( (extractVersion > ZipConstants.VersionMadeBy)
                            || ((extractVersion > 20) && (extractVersion < ZipConstants.VersionZip64)) ) {
                            throw new ZipException(string.Format("Version required to extract this entry not supported ({0})", extractVersion));
                        }

                        if ( (localFlags & ( int )(GeneralBitFlags.Patched | GeneralBitFlags.StrongEncryption | GeneralBitFlags.EnhancedCompress | GeneralBitFlags.HeaderMasked)) != 0 ) {
                            throw new ZipException("The library does not support the zip version required to extract this entry");
                        }
                    }
                }

                if (testHeader)
                {
                    if ((extractVersion <= 63) &&	// Ignore later versions as we dont know about them..
                        (extractVersion != 10) &&
                        (extractVersion != 11) &&
                        (extractVersion != 20) &&
                        (extractVersion != 21) &&
                        (extractVersion != 25) &&
                        (extractVersion != 27) &&
                        (extractVersion != 45) &&
                        (extractVersion != 46) &&
                        (extractVersion != 50) &&
                        (extractVersion != 51) &&
                        (extractVersion != 52) &&
                        (extractVersion != 61) &&
                        (extractVersion != 62) &&
                        (extractVersion != 63)
                        )
                    {
                        throw new ZipException(string.Format("Version required to extract this entry is invalid ({0})", extractVersion));
                    }

                    // Local entry flags dont have reserved bit set on.
                    if ((localFlags & (int)(GeneralBitFlags.ReservedPKware4 | GeneralBitFlags.ReservedPkware14 | GeneralBitFlags.ReservedPkware15)) != 0)
                    {
                        throw new ZipException("Reserved bit flags cannot be set.");
                    }

                    // Encryption requires extract version >= 20
                    if (((localFlags & (int)GeneralBitFlags.Encrypted) != 0) && (extractVersion < 20))
                    {
                        throw new ZipException(string.Format("Version required to extract this entry is too low for encryption ({0})", extractVersion));
                    }

                    // Strong encryption requires encryption flag to be set and extract version >= 50.
                    if ((localFlags & (int)GeneralBitFlags.StrongEncryption) != 0)
                    {
                        if ((localFlags & (int)GeneralBitFlags.Encrypted) == 0)
                        {
                            throw new ZipException("Strong encryption flag set but encryption flag is not set");
                        }

                        if (extractVersion < 50)
                        {
                            throw new ZipException(string.Format("Version required to extract this entry is too low for encryption ({0})", extractVersion));
                        }
                    }

                    // Patched entries require extract version >= 27
                    if (((localFlags & (int)GeneralBitFlags.Patched) != 0) && (extractVersion < 27))
                    {
                        throw new ZipException(string.Format("Patched data requires higher version than ({0})", extractVersion));
                    }

                    // Central header flags match local entry flags.
                    if (localFlags != entry.Flags)
                    {
                        throw new ZipException("Central header/local header flags mismatch");
                    }

                    // Central header compression method matches local entry
                    if (entry.CompressionMethod != (CompressionMethod)compressionMethod)
                    {
                        throw new ZipException("Central header/local header compression method mismatch");
                    }

                    if (entry.Version != extractVersion)
                    {
                        throw new ZipException("Extract version mismatch");
                    }

                    // Strong encryption and extract version match
                    if ((localFlags & (int)GeneralBitFlags.StrongEncryption) != 0)
                    {
                        if (extractVersion < 62)
                        {
                            throw new ZipException("Strong encryption flag set but version not high enough");
                        }
                    }

                    if ((localFlags & (int)GeneralBitFlags.HeaderMasked) != 0)
                    {
                        if ((fileTime != 0) || (fileDate != 0))
                        {
                            throw new ZipException("Header masked set but date/time values non-zero");
                        }
                    }

                    if ((localFlags & (int)GeneralBitFlags.Descriptor) == 0)
                    {
                        if (crcValue != (uint)entry.Crc)
                        {
                            throw new ZipException("Central header/local header crc mismatch");
                        }
                    }

                    // Crc valid for empty entry.
                    // This will also apply to streamed entries where size isnt known and the header cant be patched
                    if ((size == 0) && (compressedSize == 0))
                    {
                        if (crcValue != 0)
                        {
                            throw new ZipException("Invalid CRC for empty entry");
                        }
                    }

                    // TODO: make test more correct...  can't compare lengths as was done originally as this can fail for MBCS strings
                    // Assuming a code page at this point is not valid?  Best is to store the name length in the ZipEntry probably
                    if (entry.Name.Length > storedNameLength)
                    {
                        throw new ZipException("File name length mismatch");
                    }

                    // Name data has already been read convert it and compare.
                    string localName = ZipConstants.ConvertToStringExt(localFlags, nameData);

                    // Central directory and local entry name match
                    if (localName != entry.Name)
                    {
                        throw new ZipException("Central header and local header file name mismatch");
                    }

                    // Directories have zero actual size but can have compressed size
                    if (entry.IsDirectory)
                    {
                        if (size > 0)
                        {
                            throw new ZipException("Directory cannot have size");
                        }

                        // There may be other cases where the compressed size can be greater than this?
                        // If so until details are known we will be strict.
                        if (entry.IsCrypted)
                        {
                            if (compressedSize > ZipConstants.CryptoHeaderSize + 2)
                            {
                                throw new ZipException("Directory compressed size invalid");
                            }
                        }
                        else if (compressedSize > 2)
                        {
                            // When not compressed the directory size can validly be 2 bytes
                            // if the true size wasnt known when data was originally being written.
                            // NOTE: Versions of the library 0.85.4 and earlier always added 2 bytes
                            throw new ZipException("Directory compressed size invalid");
                        }
                    }

                    if (!ZipNameTransform.IsValidName(localName, true))
                    {
                        throw new ZipException("Name is invalid");
                    }
                }

                // Tests that apply to both data and header.

                // Size can be verified only if it is known in the local header.
                // it will always be known in the central header.
                if (((localFlags & (int)GeneralBitFlags.Descriptor) == 0) ||
                    ((size > 0) || (compressedSize > 0))) {

                    if (size != entry.Size) {
                        throw new ZipException(
                            string.Format("Size mismatch between central header({0}) and local header({1})",
                                entry.Size, size));
                    }

                    if (compressedSize != entry.CompressedSize) {
                        throw new ZipException(
                            string.Format("Compressed size mismatch between central header({0}) and local header({1})",
                            entry.CompressedSize, compressedSize));
                    }
                }

                int extraLength = storedNameLength + extraDataLength;
                return offsetOfFirstEntry + entry.Offset + ZipConstants.LocalHeaderBaseSize + extraLength;
            }
        }
Example #23
0
        Stream CreateAndInitDecryptionStream(Stream baseStream, ZipEntry entry)
        {
            CryptoStream result = null;

            if ( (entry.Version < ZipConstants.VersionStrongEncryption)
                || (entry.Flags & (int)GeneralBitFlags.StrongEncryption) == 0) {
                PkzipClassicManaged classicManaged = new PkzipClassicManaged();

                OnKeysRequired(entry.Name);
                if (HaveKeys == false) {
                    throw new ZipException("No password available for encrypted stream");
                }

                result = new CryptoStream(baseStream, classicManaged.CreateDecryptor(key, null), CryptoStreamMode.Read);
                CheckClassicPassword(result, entry);
            }
            else {
                throw new ZipException("Decryption method not supported");
            }

            return result;
        }
Example #24
0
        int WriteCentralDirectoryHeader(ZipEntry entry)
        {
            if ( entry.CompressedSize < 0 ) {
                throw new ZipException("Attempt to write central directory entry with unknown csize");
            }

            if ( entry.Size < 0 ) {
                throw new ZipException("Attempt to write central directory entry with unknown size");
            }

            if ( entry.Crc < 0 ) {
                throw new ZipException("Attempt to write central directory entry with unknown crc");
            }

            // Write the central file header
            WriteLEInt(ZipConstants.CentralHeaderSignature);

            // Version made by
            WriteLEShort(ZipConstants.VersionMadeBy);

            // Version required to extract
            WriteLEShort(entry.Version);

            WriteLEShort(entry.Flags);

            unchecked {
                WriteLEShort((byte)entry.CompressionMethod);
                WriteLEInt((int)entry.DosTime);
                WriteLEInt((int)entry.Crc);
            }

            if ( (entry.IsZip64Forced()) || (entry.CompressedSize >= 0xffffffff) ) {
                WriteLEInt(-1);
            }
            else {
                WriteLEInt((int)(entry.CompressedSize & 0xffffffff));
            }

            if ( (entry.IsZip64Forced()) || (entry.Size >= 0xffffffff) ) {
                WriteLEInt(-1);
            }
            else {
                WriteLEInt((int)entry.Size);
            }

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

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

            WriteLEShort(name.Length);

            // Central header extra data is different to local header version so regenerate.
            ZipExtraData ed = new ZipExtraData(entry.ExtraData);

            if ( entry.CentralHeaderRequiresZip64 ) {
                ed.StartNewEntry();

                if ( (entry.Size >= 0xffffffff) || (useZip64_ == UseZip64.On) )
                {
                    ed.AddLeLong(entry.Size);
                }

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

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

                // Number of disk on which this file starts isnt supported and is never written here.
                ed.AddNewEntry(1);
            }
            else {
                // Should have already be done when local header was added.
                ed.Delete(1);
            }

            byte[] centralExtraData = ed.GetEntryData();

            WriteLEShort(centralExtraData.Length);
            WriteLEShort(entry.Comment != null ? entry.Comment.Length : 0);

            WriteLEShort(0);	// disk number
            WriteLEShort(0);	// internal file attributes

            // External file attributes...
            if ( entry.ExternalFileAttributes != -1 ) {
                WriteLEInt(entry.ExternalFileAttributes);
            }
            else {
                if ( entry.IsDirectory ) {
                    WriteLEUint(16);
                }
                else {
                    WriteLEUint(0);
                }
            }

            if ( entry.Offset >= 0xffffffff ) {
                WriteLEUint(0xffffffff);
            }
            else {
                WriteLEUint((uint)(int)entry.Offset);
            }

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

            if ( centralExtraData.Length > 0 ) {
                baseStream_.Write(centralExtraData, 0, centralExtraData.Length);
            }

            byte[] rawComment = (entry.Comment != null) ? Encoding.ASCII.GetBytes(entry.Comment) : new byte[0];

            if ( rawComment.Length > 0 ) {
                baseStream_.Write(rawComment, 0, rawComment.Length);
            }

            return ZipConstants.CentralHeaderBaseSize + name.Length + centralExtraData.Length + rawComment.Length;
        }
Example #25
0
        /// <summary>
        /// Get a <see cref="Stream"/> providing data for an entry.
        /// </summary>
        /// <param name="entry">The entry to provide data for.</param>
        /// <param name="name">The file name for data if known.</param>
        /// <returns>Returns a stream providing data; or null if not available</returns>
        public Stream GetSource(ZipEntry entry, string name)
        {
            Stream result = null;

            if ( name != null ) {
                result = File.OpenRead(name);
            }

            return result;
        }
Example #26
0
 public ZipEntryEnumerator(ZipEntry[] entries)
 {
     array = entries;
 }
Example #27
0
        public ZipEntry(ZipEntry entry)
        {
            if ( entry == null ) {
                throw new ArgumentNullException("entry");
            }

            known                  = entry.known;
            name                   = entry.name;
            size                   = entry.size;
            compressedSize         = entry.compressedSize;
            crc                    = entry.crc;
            dosTime                = entry.dosTime;
            method                 = entry.method;
            comment                = entry.comment;
            versionToExtract       = entry.versionToExtract;
            versionMadeBy          = entry.versionMadeBy;
            externalFileAttributes = entry.externalFileAttributes;
            flags                  = entry.flags;

            zipFileIndex           = entry.zipFileIndex;
            offset                 = entry.offset;

            forceZip64_			   = entry.forceZip64_;

            if ( entry.extra != null ) {
                extra = new byte[entry.extra.Length];
                Array.Copy(entry.extra, 0, extra, 0, entry.extra.Length);
            }
        }
Example #28
0
 public ZipUpdate(string fileName, ZipEntry entry)
 {
     command_ = UpdateCommand.Add;
     entry_ = entry;
     filename_ = fileName;
 }
Example #29
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;

            // No need to compress - definitely no data.
            if (entry.Size == 0)
            {
                entry.CompressedSize = entry.Size;
                entry.Crc = 0;
                method = CompressionMethod.Stored;
                headerInfoAvailable = true;
            }
            else
            {
                headerInfoAvailable = (entry.Size >= 0) && entry.HasCrc;

                // Switch to deflation if storing isnt possible.
                if (method == CompressionMethod.Stored)
                {
                    if (!headerInfoAvailable)
                    {
                        if (!CanPatchEntries)
                        {
                            // Can't patch entries so storing is not possible.
                            method = CompressionMethod.Deflated;
                            compressionLevel = 0;
                        }
                    }
                    else // entry.size must be > 0
                    {
                        entry.CompressedSize = entry.Size;
                        headerInfoAvailable = entry.HasCrc;
                    }
                }
            }

            if (headerInfoAvailable == false) {
                if (CanPatchEntries == false) {
                    // Only way to record size and compressed size is to append a data descriptor
                    // after compressed data.

                    // Stored entries of this form have already been converted to deflating.
                    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) {
                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 #30
0
        /// <summary>
        /// 压缩文件夹
        /// </summary>
        /// <param name="directoryToZip">要压缩的文件夹路径</param>
        /// <param name="zipedFile">压缩后的文件路径</param>
        public void ZipDerctory(string directoryToZip, string zipedFile)
        {
            if (string.IsNullOrEmpty(zipedFile))
            {
                zipedFile = directoryToZip.Substring(directoryToZip.LastIndexOf("\\") + 1);
                zipedFile = directoryToZip.Substring(0, directoryToZip.LastIndexOf("\\")) + "\\" + zipedFile + ".zip";
            }

            if (Path.GetExtension(zipedFile) != ".zip")
            {
                zipedFile = zipedFile + ".zip";
            }

            using (ZipOutputStream zipStream = new ZipOutputStream(File.Create(zipedFile)))
            {
                ArrayList fileList = GetFileList(directoryToZip);
                int directoryNameLength = (Directory.GetParent(directoryToZip)).ToString().Length;

                zipStream.SetLevel(compressionLevel);
                ZipEntry zipEntry = null;
                FileStream fileStream = null;

                foreach (string fileName in fileList)
                {
                    zipEntry = new ZipEntry(fileName.Remove(0, directoryNameLength));
                    zipStream.PutNextEntry(zipEntry);

                    if (!fileName.EndsWith(@"/"))
                    {
                        fileStream = File.OpenRead(fileName);
                        fileStream.Read(buffer, 0, buffer.Length);
                        zipStream.Write(buffer, 0, buffer.Length);
                    }
                }
            }
        }