| // 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; |
| } |
| } |
| |
| |
| } |
| } |