|  | // 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 | 
|  | { | 
|  |  | 
|  | /// <summary> | 
|  | /// Extracts all of the items in the zip archive, to the specified path in the | 
|  | /// filesystem.  The path can be relative or fully-qualified. | 
|  | /// </summary> | 
|  | /// | 
|  | /// <remarks> | 
|  | /// <para> | 
|  | ///   This method will extract all entries in the <c>ZipFile</c> to the | 
|  | ///   specified path. | 
|  | /// </para> | 
|  | /// | 
|  | /// <para> | 
|  | ///   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 <c>ZipFile</c> 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 | 
|  | ///   <see cref="ZipFile.ExtractAll(string, | 
|  | ///   Ionic.Zip.ExtractExistingFileAction)" /> overload that allows you to | 
|  | ///   specify an ExtractExistingFileAction parameter. | 
|  | /// </para> | 
|  | /// | 
|  | /// <para> | 
|  | ///   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 <see | 
|  | ///   cref="ZipEntry.Extract()">ZipEntry.Extract</see> methods. | 
|  | /// </para> | 
|  | /// | 
|  | /// <para> | 
|  | ///   This method will send verbose output messages to the <see | 
|  | ///   cref="StatusMessageTextWriter"/>, if it is set on the <c>ZipFile</c> | 
|  | ///   instance. | 
|  | /// </para> | 
|  | /// | 
|  | /// <para> | 
|  | /// You may wish to take advantage of the <c>ExtractProgress</c> event. | 
|  | /// </para> | 
|  | /// | 
|  | /// <para> | 
|  | ///   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 <c>ZipEntry</c>, then the extracted file will also get | 
|  | ///   these times. | 
|  | /// </para> | 
|  | /// | 
|  | /// <para> | 
|  | ///   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. | 
|  | /// </para> | 
|  | /// | 
|  | /// <para> | 
|  | ///   To compensate, when extracting an archive with <c>ExtractAll</c>, | 
|  | ///   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. | 
|  | /// </para> | 
|  | /// | 
|  | /// <para> | 
|  | ///   This compensation is performed only within the context of an | 
|  | ///   <c>ExtractAll</c>. If you call <c>ZipEntry.Extract</c> on a directory | 
|  | ///   entry, the timestamps on directory in the filesystem will reflect the | 
|  | ///   times stored in the zip.  If you then call <c>ZipEntry.Extract</c> on | 
|  | ///   a file entry, which is extracted into the directory, the timestamps on | 
|  | ///   the directory will be updated to the current time. | 
|  | /// </para> | 
|  | /// </remarks> | 
|  | /// | 
|  | /// <example> | 
|  | ///   This example extracts all the entries in a zip archive file, to the | 
|  | ///   specified target directory.  The extraction will overwrite any | 
|  | ///   existing files silently. | 
|  | /// | 
|  | /// <code> | 
|  | /// String TargetDirectory= "unpack"; | 
|  | /// using(ZipFile zip= ZipFile.Read(ZipFileToExtract)) | 
|  | /// { | 
|  | ///     zip.ExtractExistingFile= ExtractExistingFileAction.OverwriteSilently; | 
|  | ///     zip.ExtractAll(TargetDirectory); | 
|  | /// } | 
|  | /// </code> | 
|  | /// | 
|  | /// <code lang="VB"> | 
|  | /// Dim TargetDirectory As String = "unpack" | 
|  | /// Using zip As ZipFile = ZipFile.Read(ZipFileToExtract) | 
|  | ///     zip.ExtractExistingFile= ExtractExistingFileAction.OverwriteSilently | 
|  | ///     zip.ExtractAll(TargetDirectory) | 
|  | /// End Using | 
|  | /// </code> | 
|  | /// </example> | 
|  | /// | 
|  | /// <seealso cref="Ionic.Zip.ZipFile.ExtractProgress"/> | 
|  | /// <seealso cref="Ionic.Zip.ZipFile.ExtractExistingFile"/> | 
|  | /// | 
|  | /// <param name="path"> | 
|  | ///   The path to which the contents of the zipfile will be extracted. | 
|  | ///   The path can be relative or fully-qualified. | 
|  | /// </param> | 
|  | /// | 
|  | public void ExtractAll(string path) | 
|  | { | 
|  | _InternalExtractAll(path, true); | 
|  | } | 
|  |  | 
|  |  | 
|  |  | 
|  | /// <summary> | 
|  | /// 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. | 
|  | /// </summary> | 
|  | /// | 
|  | /// <remarks> | 
|  | /// | 
|  | /// <para> | 
|  | /// This method will extract all entries in the <c>ZipFile</c> to the specified | 
|  | /// path.  For an extraction that would overwrite an existing file, the behavior | 
|  | /// is dictated by <paramref name="extractExistingFile"/>, which overrides any | 
|  | /// setting you may have made on individual ZipEntry instances. | 
|  | /// </para> | 
|  | /// | 
|  | /// <para> | 
|  | /// 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 <see cref="ZipEntry.Extract(String, | 
|  | /// ExtractExistingFileAction)" /> or one of the similar methods. | 
|  | /// </para> | 
|  | /// | 
|  | /// <para> | 
|  | /// Calling this method is equivalent to setting the <see | 
|  | /// cref="ExtractExistingFile"/> property and then calling <see | 
|  | /// cref="ExtractAll(String)"/>. | 
|  | /// </para> | 
|  | /// | 
|  | /// <para> | 
|  | /// This method will send verbose output messages to the | 
|  | /// <see cref="StatusMessageTextWriter"/>, if it is set on the <c>ZipFile</c> instance. | 
|  | /// </para> | 
|  | /// </remarks> | 
|  | /// | 
|  | /// <example> | 
|  | /// This example extracts all the entries in a zip archive file, to the | 
|  | /// specified target directory.  It does not overwrite any existing files. | 
|  | /// <code> | 
|  | /// String TargetDirectory= "c:\\unpack"; | 
|  | /// using(ZipFile zip= ZipFile.Read(ZipFileToExtract)) | 
|  | /// { | 
|  | ///   zip.ExtractAll(TargetDirectory, ExtractExistingFileAction.DontOverwrite); | 
|  | /// } | 
|  | /// </code> | 
|  | /// | 
|  | /// <code lang="VB"> | 
|  | /// Dim TargetDirectory As String = "c:\unpack" | 
|  | /// Using zip As ZipFile = ZipFile.Read(ZipFileToExtract) | 
|  | ///     zip.ExtractAll(TargetDirectory, ExtractExistingFileAction.DontOverwrite) | 
|  | /// End Using | 
|  | /// </code> | 
|  | /// </example> | 
|  | /// | 
|  | /// <param name="path"> | 
|  | /// The path to which the contents of the zipfile will be extracted. | 
|  | /// The path can be relative or fully-qualified. | 
|  | /// </param> | 
|  | /// | 
|  | /// <param name="extractExistingFile"> | 
|  | /// The action to take if extraction would overwrite an existing file. | 
|  | /// </param> | 
|  | /// <seealso cref="ExtractSelectedEntries(String,ExtractExistingFileAction)"/> | 
|  | 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; | 
|  | } | 
|  | } | 
|  |  | 
|  |  | 
|  | } | 
|  | } |