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