Beispiel #1
0
        /// <summary>
        /// Write a data descriptor.
        /// </summary>
        /// <param name="entry">The entry to write a descriptor for.</param>
        /// <returns>Returns the number of descriptor bytes written.</returns>
        public int WriteDataDescriptor(ZipEntryM entry)
        {
            if (entry == null)
            {
                //throw new ArgumentNullException(//nameof//(entry));
            }

            int result = 0;

            // Add data descriptor if flagged as required
            if ((entry.Flags & (int)GeneralBitFlags.Descriptor) != 0)
            {
                // The signature is not PKZIP originally but is now described as optional
                // in the PKZIP Appnote documenting trhe format.
                WriteLEInt(ZipConstants.DataDescriptorSignature);
                WriteLEInt(unchecked ((int)(entry.Crc)));

                result += 8;

                if (entry.LocalHeaderRequiresZip64)
                {
                    WriteLELong(entry.CompressedSize);
                    WriteLELong(entry.Size);
                    result += 16;
                }
                else
                {
                    WriteLEInt((int)entry.CompressedSize);
                    WriteLEInt((int)entry.Size);
                    result += 8;
                }
            }

            return(result);
        }
Beispiel #2
0
        public ZipEntryM(ZipEntryM entry)
        {
            if (entry == null)
            {
                //throw new ArgumentNullException(//nameof//(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);
            }
        }
        /// <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;
        }
        void ProcessFile(object sender, ScanEventArgs e)
        {
            if ((events_ != null) && (events_.ProcessFile != null))
            {
                events_.ProcessFile(sender, e);
            }

            if (e.ContinueRunning)
            {
                try {
                    // The open below is equivalent to OpenRead which gaurantees that if opened the
                    // file will not be changed by subsequent openers, but precludes opening in some cases
                    // were it could succeed. ie the open may fail as its already open for writing and the share mode should reflect that.
                    using (FileStream stream = File.Open(e.Name, FileMode.Open, FileAccess.Read, FileShare.Read)) {
                        ZipEntryM entry = entryFactory_.MakeFileEntry(e.Name);
                        outputStream_.PutNextEntry(entry);
                        AddFileContents(e.Name, stream);
                    }
                } catch (Exception ex) {
                    if (events_ != null)
                    {
                        continueRunning_ = events_.OnFileFailure(e.Name, ex);
                    }
                    else
                    {
                        continueRunning_ = false;
                        throw;
                    }
                }
            }
        }
        /// <summary>
        /// Closes the zip input stream
        /// </summary>
        protected override void Dispose(bool disposing)
        {
            internalReader = new ReadDataHandler(ReadingNotAvailable);
            crc            = null;
            entry          = null;

            base.Dispose(disposing);
        }
        private static void AddExtraDataAES(ZipEntryM 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);
        }
 // Replaces WriteEncryptionHeader for AES
 //
 private void WriteAESHeader(ZipEntryM 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);
 }
        void ProcessDirectory(object sender, DirectoryEventArgs e)
        {
            if (!e.HasMatchingFiles && CreateEmptyDirectories)
            {
                if (events_ != null)
                {
                    events_.OnProcessDirectory(e.Name, e.HasMatchingFiles);
                }

                if (e.ContinueRunning)
                {
                    if (e.Name != sourceDirectory_)
                    {
                        ZipEntryM entry = entryFactory_.MakeDirectoryEntry(e.Name);
                        outputStream_.PutNextEntry(entry);
                    }
                }
            }
        }
        /// <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(ZipEntryM entry)
        {
            if (entry == null)
            {
                //throw new ArgumentNullException(//nameof//(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 && entry.CompressedSize >= 0;

                // 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)
            {
                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.");
            }

            var 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 (entry.AESKeySize > 0)
            {
                AddExtraDataAES(entry, ed);
            }
            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 (entry.AESKeySize > 0)
                {
                    WriteAESHeader(entry);
                }
                else
                {
                    if (entry.Crc < 0)                                  // so testing Zip will says its ok
                    {
                        WriteEncryptionHeader(entry.DosTime << 16);
                    }
                    else
                    {
                        WriteEncryptionHeader(entry.Crc);
                    }
                }
            }
        }
Beispiel #10
0
        // Write the local file header
        // TODO: ZipHelperStream.WriteLocalHeader is not yet used and needs checking for ZipFile and ZipOuptutStream usage
        void WriteLocalHeader(ZipEntryM entry, EntryPatchData patchData)
        {
            CompressionMethod method = entry.CompressionMethod;
            bool headerInfoAvailable = true;             // How to get this?
            bool patchEntryHeader    = false;

            WriteLEInt(ZipConstants.LocalHeaderSignature);

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

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

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

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

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

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

            var ed = new ZipExtraData(entry.ExtraData);

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

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

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

            byte[] extra = ed.GetEntryData();

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

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

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

            if (extra.Length > 0)
            {
                stream_.Write(extra, 0, extra.Length);
            }
        }
Beispiel #11
0
        /// <summary>
        /// Make a new <see cref="ZipEntryM"></see> for a directory.
        /// </summary>
        /// <param name="directoryName">The raw untransformed name for the new directory</param>
        /// <param name="useFileSystem">If true entry detail is retrieved from the file system if the file exists.</param>
        /// <returns>Returns a new <see cref="ZipEntryM"></see> representing a directory.</returns>
        public ZipEntryM MakeDirectoryEntry(string directoryName, bool useFileSystem)
        {
            var result = new ZipEntryM(nameTransform_.TransformDirectory(directoryName));

            result.IsUnicodeText = isUnicodeText_;
            result.Size          = 0;

            int externalAttributes = 0;

            DirectoryInfo di = null;

            if (useFileSystem)
            {
                di = new DirectoryInfo(directoryName);
            }


            if ((di != null) && di.Exists)
            {
                switch (timeSetting_)
                {
                case TimeSetting.CreateTime:
                    result.DateTime = di.CreationTime;
                    break;

                case TimeSetting.CreateTimeUtc:
                    result.DateTime = di.CreationTimeUtc;
                    break;

                case TimeSetting.LastAccessTime:
                    result.DateTime = di.LastAccessTime;
                    break;

                case TimeSetting.LastAccessTimeUtc:
                    result.DateTime = di.LastAccessTimeUtc;
                    break;

                case TimeSetting.LastWriteTime:
                    result.DateTime = di.LastWriteTime;
                    break;

                case TimeSetting.LastWriteTimeUtc:
                    result.DateTime = di.LastWriteTimeUtc;
                    break;

                case TimeSetting.Fixed:
                    result.DateTime = fixedDateTime_;
                    break;

//					default:
                    //throw new ZipException("Unhandled time setting in MakeDirectoryEntry");
                }

                externalAttributes = ((int)di.Attributes & getAttributes_);
            }
            else
            {
                if (timeSetting_ == TimeSetting.Fixed)
                {
                    result.DateTime = fixedDateTime_;
                }
            }

            // Always set directory attribute on.
            externalAttributes           |= (setAttributes_ | 16);
            result.ExternalFileAttributes = externalAttributes;

            return(result);
        }
Beispiel #12
0
        /// <summary>
        /// Make a new <see cref="ZipEntryM"/> from a name.
        /// </summary>
        /// <param name="fileName">The name of the file to create a new entry for.</param>
        /// <param name="entryName">An alternative name to be used for the new entry. Null if not applicable.</param>
        /// <param name="useFileSystem">If true entry detail is retrieved from the file system if the file exists.</param>
        /// <returns>Returns a new <see cref="ZipEntryM"/> based on the <paramref name="fileName"/>.</returns>
        public ZipEntryM MakeFileEntry(string fileName, string entryName, bool useFileSystem)
        {
            var result = new ZipEntryM(nameTransform_.TransformFile(!string.IsNullOrEmpty(entryName) ? entryName : fileName));

            result.IsUnicodeText = isUnicodeText_;

            int  externalAttributes = 0;
            bool useAttributes      = (setAttributes_ != 0);

            FileInfo fi = null;

            if (useFileSystem)
            {
                fi = new FileInfo(fileName);
            }

            if ((fi != null) && fi.Exists)
            {
                switch (timeSetting_)
                {
                case TimeSetting.CreateTime:
                    result.DateTime = fi.CreationTime;
                    break;

                case TimeSetting.CreateTimeUtc:
                    result.DateTime = fi.CreationTimeUtc;
                    break;

                case TimeSetting.LastAccessTime:
                    result.DateTime = fi.LastAccessTime;
                    break;

                case TimeSetting.LastAccessTimeUtc:
                    result.DateTime = fi.LastAccessTimeUtc;
                    break;

                case TimeSetting.LastWriteTime:
                    result.DateTime = fi.LastWriteTime;
                    break;

                case TimeSetting.LastWriteTimeUtc:
                    result.DateTime = fi.LastWriteTimeUtc;
                    break;

                case TimeSetting.Fixed:
                    result.DateTime = fixedDateTime_;
                    break;

//					default:
                    //throw new ZipException("Unhandled time setting in MakeFileEntry");
                }

                result.Size = fi.Length;

                useAttributes      = true;
                externalAttributes = ((int)fi.Attributes & getAttributes_);
            }
            else
            {
                if (timeSetting_ == TimeSetting.Fixed)
                {
                    result.DateTime = fixedDateTime_;
                }
            }

            if (useAttributes)
            {
                externalAttributes           |= setAttributes_;
                result.ExternalFileAttributes = externalAttributes;
            }

            return(result);
        }
        /// <summary>
        /// Advances to the next entry in the archive
        /// </summary>
        /// <returns>
        /// The next <see cref="ZipEntryM">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 ZipEntryM 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
                Dispose();
                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));
            }

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

            flags  = inputBuffer.ReadLeShort();
            method = inputBuffer.ReadLeShort();
            var 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 ZipEntryM(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);
        }
        void ExtractEntry(ZipEntryM 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 = !(string.IsNullOrEmpty(targetName));
            }

            // 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);
            }
        }
        void ExtractFileEntry(ZipEntryM 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 (restoreDateTimeOnExtract_)
                        {
                            File.SetLastWriteTime(targetName, entry.DateTime);
                        }

                        if (RestoreAttributesOnExtract && entry.IsDOSEntry && (entry.ExternalFileAttributes != -1))
                        {
                            var 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);
                        }
                    } catch (Exception ex) {
                        if (events_ != null)
                        {
                            continueRunning_ = events_.OnFileFailure(targetName, ex);
                        }
                        else
                        {
                            continueRunning_ = false;
                            throw;
                        }
                    }
                }
            }
        }