Beispiel #1
0
 internal void SetEntry(ZipEntry entry)
 {
     entry_ = entry;
     entryValid_ = true;
     bytesTested_ = 0;
 }
Beispiel #2
0
        void ExtractEntry(ZipEntry entry)
        {
            bool doExtraction = entry.IsCompressionMethodSupported();
            string targetName = entry.Name;

            if (doExtraction)
            {
                if (entry.IsFile)
                {
                    targetName = extractNameTransform_.TransformFile(targetName);
                }
                else if (entry.IsDirectory)
                {
                    targetName = extractNameTransform_.TransformDirectory(targetName);
                }

                doExtraction = !((targetName == null) || (targetName.Length == 0));
            }

            // TODO: Fire delegate/throw exception were compression method not supported, or name is invalid?

            string dirName = null;

            if (doExtraction)
            {
                if (entry.IsDirectory)
                {
                    dirName = targetName;
                }
                else
                {
                    dirName = Path.GetDirectoryName(Path.GetFullPath(targetName));
                }
            }

            if (doExtraction && !Directory.Exists(dirName))
            {
                if (!entry.IsDirectory || CreateEmptyDirectories)
                {
                    try
                    {
                        Directory.CreateDirectory(dirName);
                    }
                    catch (Exception ex)
                    {
                        doExtraction = false;
                        if (events_ != null)
                        {
                            if (entry.IsDirectory)
                            {
                                continueRunning_ = events_.OnDirectoryFailure(targetName, ex);
                            }
                            else
                            {
                                continueRunning_ = events_.OnFileFailure(targetName, ex);
                            }
                        }
                        else
                        {
                            continueRunning_ = false;
                            throw;
                        }
                    }
                }
            }

            if (doExtraction && entry.IsFile)
            {
                ExtractFileEntry(entry, targetName);
            }
        }
        private static void AddExtraDataAES(ZipEntry entry, ZipExtraData extraData)
        {

            // Vendor Version: AE-1 IS 1. AE-2 is 2. With AE-2 no CRC is required and 0 is stored.
            const int VENDOR_VERSION = 2;
            // Vendor ID is the two ASCII characters "AE".
            const int VENDOR_ID = 0x4541; //not 6965;
            extraData.StartNewEntry();
            // Pack AES extra data field see http://www.winzip.com/aes_info.htm
            //extraData.AddLeShort(7);							// Data size (currently 7)
            extraData.AddLeShort(VENDOR_VERSION);				// 2 = AE-2
            extraData.AddLeShort(VENDOR_ID);					// "AE"
            extraData.AddData(entry.AESEncryptionStrength);		//  1 = 128, 2 = 192, 3 = 256
            extraData.AddLeShort((int)entry.CompressionMethod); // The actual compression method used to compress the file
            extraData.AddNewEntry(0x9901);
        }
        /// <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;
        }
        /// <summary>
        /// Closes the zip input stream
        /// </summary>
        public override void Close()
        {
            internalReader = new ReadDataHandler(ReadingNotAvailable);
            crc = null;
            entry = null;

            base.Close();
        }
Beispiel #6
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.Open(name, FileMode.Open, FileAccess.Read, FileShare.Read);
            }

            return result;
        }
Beispiel #7
0
 /// <summary>
 /// Initialises a default <see cref="ZipFile"/> instance with no entries and no file storage.
 /// </summary>
 internal ZipFile()
 {
     entries_ = new ZipEntry[0];
     isNewArchive_ = true;
 }
Beispiel #8
0
 public ZipUpdate(IStaticDataSource dataSource, ZipEntry entry)
 {
     command_ = UpdateCommand.Add;
     entry_ = entry;
     dataSource_ = dataSource;
 }
Beispiel #9
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();
     */
 }
Beispiel #10
0
 public ZipUpdate(string fileName, string entryName, CompressionMethod compressionMethod)
 {
     command_ = UpdateCommand.Add;
     entry_ = new ZipEntry(entryName);
     entry_.CompressionMethod = compressionMethod;
     filename_ = fileName;
 }
Beispiel #11
0
 public ZipUpdate(IStaticDataSource dataSource, string entryName, CompressionMethod compressionMethod)
 {
     command_ = UpdateCommand.Add;
     entry_ = new ZipEntry(entryName);
     entry_.CompressionMethod = compressionMethod;
     dataSource_ = dataSource;
 }
Beispiel #12
0
 public ZipUpdate(string fileName, ZipEntry entry)
 {
     command_ = UpdateCommand.Add;
     entry_ = entry;
     filename_ = fileName;
 }
Beispiel #13
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;
        }
Beispiel #14
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;
        }
Beispiel #15
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");
     }
 }
Beispiel #16
0
 public ZipUpdate(UpdateCommand command, ZipEntry entry)
 {
     command_ = command;
     entry_ = (ZipEntry)entry.Clone();
 }
Beispiel #17
0
 public ZipEntryEnumerator(ZipEntry[] entries)
 {
     array = entries;
 }
Beispiel #18
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.
 }
Beispiel #19
0
        /// <summary>
        /// Opens a Zip file reading the given <see cref="Stream"/>.
        /// </summary>
        /// <param name="stream">The <see cref="Stream"/> to read archive data from.</param>
        /// <exception cref="IOException">
        /// An i/o error occurs
        /// </exception>
        /// <exception cref="ZipException">
        /// The stream doesn't contain a valid zip archive.<br/>
        /// </exception>
        /// <exception cref="ArgumentException">
        /// The <see cref="Stream">stream</see> doesnt support seeking.
        /// </exception>
        /// <exception cref="ArgumentNullException">
        /// The <see cref="Stream">stream</see> argument is null.
        /// </exception>
        public ZipFile(Stream stream)
        {
            if (stream == null)
            {
                throw new ArgumentNullException("stream");
            }

            if (!stream.CanSeek)
            {
                throw new ArgumentException("Stream is not seekable", "stream");
            }

            baseStream_ = stream;
            isStreamOwner = true;

            if (baseStream_.Length > 0)
            {
                try
                {
                    ReadEntries();
                }
                catch
                {
                    DisposeInternal(true);
                    throw;
                }
            }
            else
            {
                entries_ = new ZipEntry[0];
                isNewArchive_ = true;
            }
        }
Beispiel #20
0
        void DisposeInternal(bool disposing)
        {
            if (!isDisposed_)
            {
                isDisposed_ = true;
                entries_ = new ZipEntry[0];

                if (IsStreamOwner && (baseStream_ != null))
                {
                    lock (baseStream_)
                    {
                        baseStream_.Close();
                    }
                }

                PostUpdateCleanup();
            }
        }
Beispiel #21
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="IExtendFramework.IO.Compression.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);
        }
Beispiel #22
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="IExtendFramework.IO.Compression.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 = 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;
            }
        }
        /// <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;
        }
Beispiel #24
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="IExtendFramework.IO.Compression.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);
 }
Beispiel #25
0
        void ExtractFileEntry(ZipEntry entry, string targetName)
        {
            bool proceed = true;
            if (overwrite_ != Overwrite.Always)
            {
                if (File.Exists(targetName))
                {
                    if ((overwrite_ == Overwrite.Prompt) && (confirmDelegate_ != null))
                    {
                        proceed = confirmDelegate_(targetName);
                    }
                    else
                    {
                        proceed = false;
                    }
                }
            }

            if (proceed)
            {
                if (events_ != null)
                {
                    continueRunning_ = events_.OnProcessFile(entry.Name);
                }

                if (continueRunning_)
                {
                    try
                    {
                        using (FileStream outputStream = File.Create(targetName))
                        {
                            if (buffer_ == null)
                            {
                                buffer_ = new byte[4096];
                            }
                            if ((events_ != null) && (events_.Progress != null))
                            {
                                StreamUtils.Copy(zipFile_.GetInputStream(entry), outputStream, buffer_,
                                    events_.Progress, events_.ProgressInterval, this, entry.Name, entry.Size);
                            }
                            else
                            {
                                StreamUtils.Copy(zipFile_.GetInputStream(entry), outputStream, buffer_);
                            }

                            if (events_ != null)
                            {
                                continueRunning_ = events_.OnCompletedFile(entry.Name);
                            }
                        }

#if !NETCF_1_0 && !NETCF_2_0
                        if (restoreDateTimeOnExtract_)
                        {
                            File.SetLastWriteTime(targetName, entry.DateTime);
                        }

                        if (RestoreAttributesOnExtract && entry.IsDOSEntry && (entry.ExternalFileAttributes != -1))
                        {
                            FileAttributes fileAttributes = (FileAttributes)entry.ExternalFileAttributes;
                            // TODO: FastZip - Setting of other file attributes on extraction is a little trickier.
                            fileAttributes &= (FileAttributes.Archive | FileAttributes.Normal | FileAttributes.ReadOnly | FileAttributes.Hidden);
                            File.SetAttributes(targetName, fileAttributes);
                        }
#endif
                    }
                    catch (Exception ex)
                    {
                        if (events_ != null)
                        {
                            continueRunning_ = events_.OnFileFailure(targetName, ex);
                        }
                        else
                        {
                            continueRunning_ = false;
                            throw;
                        }
                    }
                }
            }
        }
Beispiel #26
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
            {
#if !NET_1_1 && !NETCF_2_0
                if (entry.Version == ZipConstants.VERSION_AES)
                {
                    //
                    OnKeysRequired(entry.Name);
                    if (HaveKeys == false)
                    {
                        throw new ZipException("No password available for AES encrypted stream");
                    }
                    int saltLen = entry.AESSaltLen;
                    byte[] saltBytes = new byte[saltLen];
                    int saltIn = baseStream.Read(saltBytes, 0, saltLen);
                    if (saltIn != saltLen)
                        throw new ZipException("AES Salt expected " + saltLen + " got " + saltIn);
                    //
                    byte[] pwdVerifyRead = new byte[2];
                    baseStream.Read(pwdVerifyRead, 0, 2);
                    int blockSize = entry.AESKeySize / 8;	// bits to bytes

                    ZipAESTransform decryptor = new ZipAESTransform(rawPassword_, saltBytes, blockSize, false);
                    byte[] pwdVerifyCalc = decryptor.PwdVerifier;
                    if (pwdVerifyCalc[0] != pwdVerifyRead[0] || pwdVerifyCalc[1] != pwdVerifyRead[1])
                        throw new Exception("Invalid password for AES");
                    result = new ZipAESStream(baseStream, decryptor, CryptoStreamMode.Read);
                }
                else
#endif
                {
                    throw new ZipException("Decryption method not supported");
                }
            }

            return result;
        }
        /// <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)entry.CompressionMethodForHeader);
            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)
                {
                    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);
            }

#if !NET_1_1 && !NETCF_2_0
            if (entry.AESKeySize > 0)
            {
                AddExtraDataAES(entry, ed);
            }
#endif
            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;
            // Fix offsetOfCentraldir for AES
            if (entry.AESKeySize > 0)
                offset += entry.AESOverheadSize;

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

            if (entry.IsCrypted)
            {
#if !NET_1_1 && !NETCF_2_0
                if (entry.AESKeySize > 0)
                {
                    WriteAESHeader(entry);
                }
                else
#endif
                {
                    if (entry.Crc < 0)
                    {			// so testing Zip will says its ok
                        WriteEncryptionHeader(entry.DosTime << 16);
                    }
                    else
                    {
                        WriteEncryptionHeader(entry.Crc);
                    }
                }
            }
        }
Beispiel #28
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;
        }
 // Replaces WriteEncryptionHeader for AES
 //
 private void WriteAESHeader(ZipEntry entry)
 {
     byte[] salt;
     byte[] pwdVerifier;
     InitializeAESPassword(entry, Password, out salt, out pwdVerifier);
     // File format for AES:
     // Size (bytes)   Content
     // ------------   -------
     // Variable       Salt value
     // 2              Password verification value
     // Variable       Encrypted file data
     // 10             Authentication code
     //
     // Value in the "compressed size" fields of the local file header and the central directory entry
     // is the total size of all the items listed above. In other words, it is the total size of the
     // salt value, password verification value, encrypted data, and authentication code.
     baseOutputStream_.Write(salt, 0, salt.Length);
     baseOutputStream_.Write(pwdVerifier, 0, pwdVerifier.Length);
 }
Beispiel #30
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;
        }