// ZipFile.Extract.cs
// ------------------------------------------------------------------
//
// Copyright (c) 2009 Dino Chiesa.
// All rights reserved.
//
// This code module is part of DotNetZip, a zipfile class library.
//
// ------------------------------------------------------------------
//
// This code is licensed under the Microsoft Public License.
// See the file License.txt for the license details.
// More info on: http://dotnetzip.codeplex.com
//
// ------------------------------------------------------------------
//
// last saved (in emacs):
// Time-stamp: <2011-July-31 14:45:18>
//
// ------------------------------------------------------------------
//
// This module defines the methods for Extract operations on zip files.
//
// ------------------------------------------------------------------
//
using System;
using System.IO;
using System.Collections.Generic;
namespace OfficeOpenXml.Packaging.Ionic.Zip
{
internal partial class ZipFile
{
///
/// Extracts all of the items in the zip archive, to the specified path in the
/// filesystem. The path can be relative or fully-qualified.
///
///
///
///
/// This method will extract all entries in the ZipFile to the
/// specified path.
///
///
///
/// If an extraction of a file from the zip archive would overwrite an
/// existing file in the filesystem, the action taken is dictated by the
/// ExtractExistingFile property, which overrides any setting you may have
/// made on individual ZipEntry instances. By default, if you have not
/// set that property on the ZipFile instance, the entry will not
/// be extracted, the existing file will not be overwritten and an
/// exception will be thrown. To change this, set the property, or use the
/// overload that allows you to
/// specify an ExtractExistingFileAction parameter.
///
///
///
/// The action to take when an extract would overwrite an existing file
/// applies to all entries. If you want to set this on a per-entry basis,
/// then you must use one of the ZipEntry.Extract methods.
///
///
///
/// This method will send verbose output messages to the , if it is set on the ZipFile
/// instance.
///
///
///
/// You may wish to take advantage of the ExtractProgress event.
///
///
///
/// About timestamps: When extracting a file entry from a zip archive, the
/// extracted file gets the last modified time of the entry as stored in
/// the archive. The archive may also store extended file timestamp
/// information, including last accessed and created times. If these are
/// present in the ZipEntry, then the extracted file will also get
/// these times.
///
///
///
/// A Directory entry is somewhat different. It will get the times as
/// described for a file entry, but, if there are file entries in the zip
/// archive that, when extracted, appear in the just-created directory,
/// then when those file entries are extracted, the last modified and last
/// accessed times of the directory will change, as a side effect. The
/// result is that after an extraction of a directory and a number of
/// files within the directory, the last modified and last accessed
/// timestamps on the directory will reflect the time that the last file
/// was extracted into the directory, rather than the time stored in the
/// zip archive for the directory.
///
///
///
/// To compensate, when extracting an archive with ExtractAll,
/// DotNetZip will extract all the file and directory entries as described
/// above, but it will then make a second pass on the directories, and
/// reset the times on the directories to reflect what is stored in the
/// zip archive.
///
///
///
/// This compensation is performed only within the context of an
/// ExtractAll. If you call ZipEntry.Extract on a directory
/// entry, the timestamps on directory in the filesystem will reflect the
/// times stored in the zip. If you then call ZipEntry.Extract on
/// a file entry, which is extracted into the directory, the timestamps on
/// the directory will be updated to the current time.
///
///
///
///
/// This example extracts all the entries in a zip archive file, to the
/// specified target directory. The extraction will overwrite any
/// existing files silently.
///
///
/// String TargetDirectory= "unpack";
/// using(ZipFile zip= ZipFile.Read(ZipFileToExtract))
/// {
/// zip.ExtractExistingFile= ExtractExistingFileAction.OverwriteSilently;
/// zip.ExtractAll(TargetDirectory);
/// }
///
///
///
/// Dim TargetDirectory As String = "unpack"
/// Using zip As ZipFile = ZipFile.Read(ZipFileToExtract)
/// zip.ExtractExistingFile= ExtractExistingFileAction.OverwriteSilently
/// zip.ExtractAll(TargetDirectory)
/// End Using
///
///
///
///
///
///
///
/// The path to which the contents of the zipfile will be extracted.
/// The path can be relative or fully-qualified.
///
///
public void ExtractAll(string path)
{
_InternalExtractAll(path, true);
}
///
/// Extracts all of the items in the zip archive, to the specified path in the
/// filesystem, using the specified behavior when extraction would overwrite an
/// existing file.
///
///
///
///
///
/// This method will extract all entries in the ZipFile to the specified
/// path. For an extraction that would overwrite an existing file, the behavior
/// is dictated by , which overrides any
/// setting you may have made on individual ZipEntry instances.
///
///
///
/// The action to take when an extract would overwrite an existing file
/// applies to all entries. If you want to set this on a per-entry basis,
/// then you must use or one of the similar methods.
///
///
///
/// Calling this method is equivalent to setting the property and then calling .
///
///
///
/// This method will send verbose output messages to the
/// , if it is set on the ZipFile instance.
///
///
///
///
/// This example extracts all the entries in a zip archive file, to the
/// specified target directory. It does not overwrite any existing files.
///
/// String TargetDirectory= "c:\\unpack";
/// using(ZipFile zip= ZipFile.Read(ZipFileToExtract))
/// {
/// zip.ExtractAll(TargetDirectory, ExtractExistingFileAction.DontOverwrite);
/// }
///
///
///
/// Dim TargetDirectory As String = "c:\unpack"
/// Using zip As ZipFile = ZipFile.Read(ZipFileToExtract)
/// zip.ExtractAll(TargetDirectory, ExtractExistingFileAction.DontOverwrite)
/// End Using
///
///
///
///
/// The path to which the contents of the zipfile will be extracted.
/// The path can be relative or fully-qualified.
///
///
///
/// The action to take if extraction would overwrite an existing file.
///
///
internal void ExtractAll(string path, ExtractExistingFileAction extractExistingFile)
{
ExtractExistingFile = extractExistingFile;
_InternalExtractAll(path, true);
}
private void _InternalExtractAll(string path, bool overrideExtractExistingProperty)
{
bool header = Verbose;
_inExtractAll = true;
try
{
OnExtractAllStarted(path);
int n = 0;
foreach (ZipEntry e in _entries.Values)
{
if (header)
{
StatusMessageTextWriter.WriteLine("\n{1,-22} {2,-8} {3,4} {4,-8} {0}",
"Name", "Modified", "Size", "Ratio", "Packed");
StatusMessageTextWriter.WriteLine(new System.String('-', 72));
header = false;
}
if (Verbose)
{
StatusMessageTextWriter.WriteLine("{1,-22} {2,-8} {3,4:F0}% {4,-8} {0}",
e.FileName,
e.LastModified.ToString("yyyy-MM-dd HH:mm:ss"),
e.UncompressedSize,
e.CompressionRatio,
e.CompressedSize);
if (!String.IsNullOrEmpty(e.Comment))
StatusMessageTextWriter.WriteLine(" Comment: {0}", e.Comment);
}
e.Password = _Password; // this may be null
OnExtractEntry(n, true, e, path);
if (overrideExtractExistingProperty)
e.ExtractExistingFile = this.ExtractExistingFile;
e.Extract(path);
n++;
OnExtractEntry(n, false, e, path);
if (_extractOperationCanceled)
break;
}
if (!_extractOperationCanceled)
{
// workitem 8264:
// now, set times on directory entries, again.
// The problem is, extracting a file changes the times on the parent
// directory. So after all files have been extracted, we have to
// run through the directories again.
foreach (ZipEntry e in _entries.Values)
{
// check if it is a directory
if ((e.IsDirectory) || (e.FileName.EndsWith("/")))
{
string outputFile = (e.FileName.StartsWith("/"))
? Path.Combine(path, e.FileName.Substring(1))
: Path.Combine(path, e.FileName);
e._SetTimes(outputFile, false);
}
}
OnExtractAllCompleted(path);
}
}
finally
{
_inExtractAll = false;
}
}
}
}