Crisis.Ionic.Zip.ZipEntry.InternalExtract C# (CSharp) Method

InternalExtract() private method

private InternalExtract ( string baseDir, Stream outstream, string password ) : void
baseDir string
outstream Stream
password string
return void
        private void InternalExtract(string baseDir, Stream outstream, string password)
        {
            // workitem 7958
            if (_container == null)
                throw new BadStateException("This entry is an orphan");

            // workitem 10355
            if (_container.ZipFile == null)
                throw new InvalidOperationException("Use Extract() only with ZipFile.");

            _container.ZipFile.Reset(false);

            if (this._Source != ZipEntrySource.ZipFile)
                throw new BadStateException("You must call ZipFile.Save before calling any Extract method");

            OnBeforeExtract(baseDir);
            _ioOperationCanceled = false;
            string targetFileName = null;
            Stream output = null;
            bool fileExistsBeforeExtraction = false;
            bool checkLaterForResetDirTimes = false;
            try
            {
                ValidateCompression();
                ValidateEncryption();

                if (ValidateOutput(baseDir, outstream, out targetFileName))
                {
                    WriteStatus("extract dir {0}...", targetFileName);
                    // if true, then the entry was a directory and has been created.
                    // We need to fire the Extract Event.
                    OnAfterExtract(baseDir);
                    return;
                }

                // workitem 10639
                // do we want to extract to a regular filesystem file?
                if (targetFileName != null)
                {
                    // Check for extracting to a previously extant file. The user
                    // can specify bejavior for that case: overwrite, don't
                    // overwrite, and throw.  Also, if the file exists prior to
                    // extraction, it affects exception handling: whether to delete
                    // the target of extraction or not.  This check needs to be done
                    // before the password check is done, because password check may
                    // throw a BadPasswordException, which triggers the catch,
                    // wherein the extant file may be deleted if not flagged as
                    // pre-existing.
                    if (File.Exists(targetFileName))
                    {
                        fileExistsBeforeExtraction = true;
                        int rc = CheckExtractExistingFile(baseDir, targetFileName);
                        if (rc == 2) goto ExitTry; // cancel
                        if (rc == 1) return; // do not overwrite
                    }
                }

                // If no password explicitly specified, use the password on the entry itself,
                // or on the zipfile itself.
                string p = password ?? this._Password ?? this._container.Password;
                if (_Encryption_FromZipFile != EncryptionAlgorithm.None)
                {
                    if (p == null)
                        throw new BadPasswordException();
                    SetupCryptoForExtract(p);
                }


                // set up the output stream
                if (targetFileName != null)
                {
                    WriteStatus("extract file {0}...", targetFileName);
                    targetFileName += ".tmp";
                    var dirName = Path.GetDirectoryName(targetFileName);
                    // ensure the target path exists
                    if (!Directory.Exists(dirName))
                    {
                        // we create the directory here, but we do not set the
                        // create/modified/accessed times on it because it is being
                        // created implicitly, not explcitly. There's no entry in the
                        // zip archive for the directory.
                        Directory.CreateDirectory(dirName);
                    }
                    else
                    {
                        // workitem 8264
                        if (_container.ZipFile != null)
                            checkLaterForResetDirTimes = _container.ZipFile._inExtractAll;
                    }

                    // File.Create(CreateNew) will overwrite any existing file.
                    output = new FileStream(targetFileName, FileMode.CreateNew);
                }
                else
                {
                    WriteStatus("extract entry {0} to stream...", FileName);
                    output = outstream;
                }


                if (_ioOperationCanceled)
                    goto ExitTry;

                Int32 ActualCrc32 = ExtractOne(output);

                if (_ioOperationCanceled)
                    goto ExitTry;

                VerifyCrcAfterExtract(ActualCrc32);

                if (targetFileName != null)
                {
                    output.Close();
                    output = null;

                    // workitem 10639
                    // move file to permanent home
                    string tmpName = targetFileName;
                    string zombie = null;
                    targetFileName = tmpName.Substring(0,tmpName.Length-4);

                    if (fileExistsBeforeExtraction)
                    {
                        // An AV program may hold the target file open, which means
                        // File.Delete() will succeed, though the actual deletion
                        // remains pending. This will prevent a subsequent
                        // File.Move() from succeeding. To avoid this, when the file
                        // already exists, we need to replace it in 3 steps:
                        //
                        //     1. rename the existing file to a zombie name;
                        //     2. rename the extracted file from the temp name to
                        //        the target file name;
                        //     3. delete the zombie.
                        //
                        zombie = targetFileName + ".PendingOverwrite";
                        File.Move(targetFileName, zombie);
                    }

                    File.Move(tmpName, targetFileName);
                    _SetTimes(targetFileName, true);

                    if (zombie != null && File.Exists(zombie))
                        ReallyDelete(zombie);

                    // workitem 8264
                    if (checkLaterForResetDirTimes)
                    {
                        // This is sort of a hack.  What I do here is set the time on
                        // the parent directory, every time a file is extracted into
                        // it.  If there is a directory with 1000 files, then I set
                        // the time on the dir, 1000 times. This allows the directory
                        // to have times that reflect the actual time on the entry in
                        // the zip archive.

                        // String.Contains is not available on .NET CF 2.0
                        if (this.FileName.IndexOf('/') != -1)
                        {
                            string dirname = Path.GetDirectoryName(this.FileName);
                            if (this._container.ZipFile[dirname] == null)
                            {
                                _SetTimes(Path.GetDirectoryName(targetFileName), false);
                            }
                        }
                    }

#if NETCF
                    // workitem 7926 - version made by OS can be zero or 10
                    if ((_VersionMadeBy & 0xFF00) == 0x0a00 || (_VersionMadeBy & 0xFF00) == 0x0000)
                        NetCfFile.SetAttributes(targetFileName, (uint)_ExternalFileAttrs);

#else
                    // workitem 7071
                    //
                    // We can only apply attributes if they are relevant to the NTFS
                    // OS.  Must do this LAST because it may involve a ReadOnly bit,
                    // which would prevent us from setting the time, etc.
                    //
                    // workitem 7926 - version made by OS can be zero (FAT) or 10
                    // (NTFS)
                    if ((_VersionMadeBy & 0xFF00) == 0x0a00 || (_VersionMadeBy & 0xFF00) == 0x0000)
                        File.SetAttributes(targetFileName, (FileAttributes)_ExternalFileAttrs);
#endif
                }

                OnAfterExtract(baseDir);

                ExitTry: ;
            }
            catch (Exception)
            {
                _ioOperationCanceled = true;
                throw;
            }
            finally
            {
                if (_ioOperationCanceled)
                {
                    if (targetFileName != null)
                    {
                        try
                        {
                            if (output != null) output.Close();
                            // An exception has occurred. If the file exists, check
                            // to see if it existed before we tried extracting.  If
                            // it did not, attempt to remove the target file. There
                            // is a small possibility that the existing file has
                            // been extracted successfully, overwriting a previously
                            // existing file, and an exception was thrown after that
                            // but before final completion (setting times, etc). In
                            // that case the file will remain, even though some
                            // error occurred.  Nothing to be done about it.
                            if (File.Exists(targetFileName) && !fileExistsBeforeExtraction)
                                File.Delete(targetFileName);

                        }
                        finally { }
                    }
                }
            }
        }
ZipEntry