| // ZipFile.cs | |
| // | |
| // Copyright (c) 2006-2010 Dino Chiesa | |
| // All rights reserved. | |
| // | |
| // This module is part of DotNetZip, a zipfile class library. | |
| // The class library reads and writes zip files, according to the format | |
| // described by PKware, at: | |
| // http://www.pkware.com/business_and_developers/developer/popups/appnote.txt | |
| // | |
| // | |
| // There are other Zip class libraries available. | |
| // | |
| // - it is possible to read and write zip files within .NET via the J# runtime. | |
| // But some people don't like to install the extra DLL, which is no longer | |
| // supported by MS. And also, the J# libraries don't support advanced zip | |
| // features, like ZIP64, spanned archives, or AES encryption. | |
| // | |
| // - There are third-party GPL and LGPL libraries available. Some people don't | |
| // like the license, and some of them don't support all the ZIP features, like AES. | |
| // | |
| // - Finally, there are commercial tools (From ComponentOne, XCeed, etc). But | |
| // some people don't want to incur the cost. | |
| // | |
| // This alternative implementation is **not** GPL licensed. It is free of cost, and | |
| // does not require J#. It does require .NET 2.0. It balances a good set of | |
| // features, with ease of use and speed of performance. | |
| // | |
| // This code is released under the Microsoft Public License . | |
| // See the License.txt for details. | |
| // | |
| // | |
| // NB: This implementation originally relied on the | |
| // System.IO.Compression.DeflateStream base class in the .NET Framework | |
| // v2.0 base class library, but now includes a managed-code port of Zlib. | |
| // | |
| // Thu, 08 Oct 2009 17:04 | |
| // | |
| using System; | |
| using System.IO; | |
| using System.Collections.Generic; | |
| using Interop = System.Runtime.InteropServices; | |
| using OfficeOpenXml.Packaging.Ionic.Zlib; | |
| namespace OfficeOpenXml.Packaging.Ionic.Zip | |
| { | |
| /// <summary> | |
| /// The ZipFile type represents a zip archive file. | |
| /// </summary> | |
| /// | |
| /// <remarks> | |
| /// <para> | |
| /// This is the main type in the DotNetZip class library. This class reads and | |
| /// writes zip files, as defined in the <see | |
| /// href="http://www.pkware.com/documents/casestudies/APPNOTE.TXT">specification | |
| /// for zip files described by PKWare</see>. The compression for this | |
| /// implementation is provided by a managed-code version of Zlib, included with | |
| /// DotNetZip in the classes in the Ionic.Zlib namespace. | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// This class provides a general purpose zip file capability. Use it to read, | |
| /// create, or update zip files. When you want to create zip files using a | |
| /// <c>Stream</c> type to write the zip file, you may want to consider the <see | |
| /// cref="ZipOutputStream"/> class. | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// Both the <c>ZipOutputStream</c> class and the <c>ZipFile</c> class can | |
| /// be used to create zip files. Both of them support many of the common zip | |
| /// features, including Unicode, different compression methods and levels, | |
| /// and ZIP64. They provide very similar performance when creating zip | |
| /// files. | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// The <c>ZipFile</c> class is generally easier to use than | |
| /// <c>ZipOutputStream</c> and should be considered a higher-level interface. For | |
| /// example, when creating a zip file via calls to the <c>PutNextEntry()</c> and | |
| /// <c>Write()</c> methods on the <c>ZipOutputStream</c> class, the caller is | |
| /// responsible for opening the file, reading the bytes from the file, writing | |
| /// those bytes into the <c>ZipOutputStream</c>, setting the attributes on the | |
| /// <c>ZipEntry</c>, and setting the created, last modified, and last accessed | |
| /// timestamps on the zip entry. All of these things are done automatically by a | |
| /// call to <see cref="ZipFile.AddFile(string,string)">ZipFile.AddFile()</see>. | |
| /// For this reason, the <c>ZipOutputStream</c> is generally recommended for use | |
| /// only when your application emits arbitrary data, not necessarily data from a | |
| /// filesystem file, directly into a zip file, and does so using a <c>Stream</c> | |
| /// metaphor. | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// Aside from the differences in programming model, there are other | |
| /// differences in capability between the two classes. | |
| /// </para> | |
| /// | |
| /// <list type="bullet"> | |
| /// <item> | |
| /// <c>ZipFile</c> can be used to read and extract zip files, in addition to | |
| /// creating zip files. <c>ZipOutputStream</c> cannot read zip files. If you want | |
| /// to use a stream to read zip files, check out the ZipInputStream class. | |
| /// </item> | |
| /// | |
| /// <item> | |
| /// <c>ZipOutputStream</c> does not support the creation of segmented or spanned | |
| /// zip files. | |
| /// </item> | |
| /// | |
| /// <item> | |
| /// <c>ZipOutputStream</c> cannot produce a self-extracting archive. | |
| /// </item> | |
| /// </list> | |
| /// | |
| /// <para> | |
| /// Be aware that the <c>ZipFile</c> class implements the <see | |
| /// cref="System.IDisposable"/> interface. In order for <c>ZipFile</c> to | |
| /// produce a valid zip file, you use use it within a using clause (<c>Using</c> | |
| /// in VB), or call the <c>Dispose()</c> method explicitly. See the examples | |
| /// for how to employ a using clause. | |
| /// </para> | |
| /// | |
| /// </remarks> | |
| [Interop.GuidAttribute("ebc25cf6-9120-4283-b972-0e5520d00005")] | |
| [Interop.ComVisible(true)] | |
| #if !NETCF | |
| [Interop.ClassInterface(Interop.ClassInterfaceType.AutoDispatch)] | |
| #endif | |
| internal partial class ZipFile : | |
| System.Collections.IEnumerable, | |
| System.Collections.Generic.IEnumerable<ZipEntry>, | |
| IDisposable | |
| { | |
| #region public properties | |
| /// <summary> | |
| /// Indicates whether to perform a full scan of the zip file when reading it. | |
| /// </summary> | |
| /// | |
| /// <remarks> | |
| /// | |
| /// <para> | |
| /// You almost never want to use this property. | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// When reading a zip file, if this flag is <c>true</c> (<c>True</c> in | |
| /// VB), the entire zip archive will be scanned and searched for entries. | |
| /// For large archives, this can take a very, long time. The much more | |
| /// efficient default behavior is to read the zip directory, which is | |
| /// stored at the end of the zip file. But, in some cases the directory is | |
| /// corrupted and you need to perform a full scan of the zip file to | |
| /// determine the contents of the zip file. This property lets you do | |
| /// that, when necessary. | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// This flag is effective only when calling <see | |
| /// cref="Initialize(string)"/>. Normally you would read a ZipFile with the | |
| /// static <see cref="ZipFile.Read(String)">ZipFile.Read</see> | |
| /// method. But you can't set the <c>FullScan</c> property on the | |
| /// <c>ZipFile</c> instance when you use a static factory method like | |
| /// <c>ZipFile.Read</c>. | |
| /// </para> | |
| /// | |
| /// </remarks> | |
| /// | |
| /// <example> | |
| /// | |
| /// This example shows how to read a zip file using the full scan approach, | |
| /// and then save it, thereby producing a corrected zip file. | |
| /// | |
| /// <code lang="C#"> | |
| /// using (var zip = new ZipFile()) | |
| /// { | |
| /// zip.FullScan = true; | |
| /// zip.Initialize(zipFileName); | |
| /// zip.Save(newName); | |
| /// } | |
| /// </code> | |
| /// | |
| /// <code lang="VB"> | |
| /// Using zip As New ZipFile | |
| /// zip.FullScan = True | |
| /// zip.Initialize(zipFileName) | |
| /// zip.Save(newName) | |
| /// End Using | |
| /// </code> | |
| /// </example> | |
| /// | |
| public bool FullScan | |
| { | |
| get; | |
| set; | |
| } | |
| /// <summary> | |
| /// Whether to sort the ZipEntries before saving the file. | |
| /// </summary> | |
| /// | |
| /// <remarks> | |
| /// The default is false. If you have a large number of zip entries, the sort | |
| /// alone can consume significant time. | |
| /// </remarks> | |
| /// | |
| /// <example> | |
| /// <code lang="C#"> | |
| /// using (var zip = new ZipFile()) | |
| /// { | |
| /// zip.AddFiles(filesToAdd); | |
| /// zip.SortEntriesBeforeSaving = true; | |
| /// zip.Save(name); | |
| /// } | |
| /// </code> | |
| /// | |
| /// <code lang="VB"> | |
| /// Using zip As New ZipFile | |
| /// zip.AddFiles(filesToAdd) | |
| /// zip.SortEntriesBeforeSaving = True | |
| /// zip.Save(name) | |
| /// End Using | |
| /// </code> | |
| /// </example> | |
| /// | |
| public bool SortEntriesBeforeSaving | |
| { | |
| get; | |
| set; | |
| } | |
| /// <summary> | |
| /// Indicates whether NTFS Reparse Points, like junctions, should be | |
| /// traversed during calls to <c>AddDirectory()</c>. | |
| /// </summary> | |
| /// | |
| /// <remarks> | |
| /// By default, calls to AddDirectory() will traverse NTFS reparse | |
| /// points, like mounted volumes, and directory junctions. An example | |
| /// of a junction is the "My Music" directory in Windows Vista. In some | |
| /// cases you may not want DotNetZip to traverse those directories. In | |
| /// that case, set this property to false. | |
| /// </remarks> | |
| /// | |
| /// <example> | |
| /// <code lang="C#"> | |
| /// using (var zip = new ZipFile()) | |
| /// { | |
| /// zip.AddDirectoryWillTraverseReparsePoints = false; | |
| /// zip.AddDirectory(dirToZip,"fodder"); | |
| /// zip.Save(zipFileToCreate); | |
| /// } | |
| /// </code> | |
| /// </example> | |
| public bool AddDirectoryWillTraverseReparsePoints { get; set; } | |
| /// <summary> | |
| /// Size of the IO buffer used while saving. | |
| /// </summary> | |
| /// | |
| /// <remarks> | |
| /// | |
| /// <para> | |
| /// First, let me say that you really don't need to bother with this. It is | |
| /// here to allow for optimizations that you probably won't make! It will work | |
| /// fine if you don't set or get this property at all. Ok? | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// Now that we have <em>that</em> out of the way, the fine print: This | |
| /// property affects the size of the buffer that is used for I/O for each | |
| /// entry contained in the zip file. When a file is read in to be compressed, | |
| /// it uses a buffer given by the size here. When you update a zip file, the | |
| /// data for unmodified entries is copied from the first zip file to the | |
| /// other, through a buffer given by the size here. | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// Changing the buffer size affects a few things: first, for larger buffer | |
| /// sizes, the memory used by the <c>ZipFile</c>, obviously, will be larger | |
| /// during I/O operations. This may make operations faster for very much | |
| /// larger files. Last, for any given entry, when you use a larger buffer | |
| /// there will be fewer progress events during I/O operations, because there's | |
| /// one progress event generated for each time the buffer is filled and then | |
| /// emptied. | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// The default buffer size is 8k. Increasing the buffer size may speed | |
| /// things up as you compress larger files. But there are no hard-and-fast | |
| /// rules here, eh? You won't know til you test it. And there will be a | |
| /// limit where ever larger buffers actually slow things down. So as I said | |
| /// in the beginning, it's probably best if you don't set or get this property | |
| /// at all. | |
| /// </para> | |
| /// | |
| /// </remarks> | |
| /// | |
| /// <example> | |
| /// This example shows how you might set a large buffer size for efficiency when | |
| /// dealing with zip entries that are larger than 1gb. | |
| /// <code lang="C#"> | |
| /// using (ZipFile zip = new ZipFile()) | |
| /// { | |
| /// zip.SaveProgress += this.zip1_SaveProgress; | |
| /// zip.AddDirectory(directoryToZip, ""); | |
| /// zip.UseZip64WhenSaving = Zip64Option.Always; | |
| /// zip.BufferSize = 65536*8; // 65536 * 8 = 512k | |
| /// zip.Save(ZipFileToCreate); | |
| /// } | |
| /// </code> | |
| /// </example> | |
| public int BufferSize | |
| { | |
| get { return _BufferSize; } | |
| set { _BufferSize = value; } | |
| } | |
| /// <summary> | |
| /// Size of the work buffer to use for the ZLIB codec during compression. | |
| /// </summary> | |
| /// | |
| /// <remarks> | |
| /// <para> | |
| /// When doing ZLIB or Deflate compression, the library fills a buffer, | |
| /// then passes it to the compressor for compression. Then the library | |
| /// reads out the compressed bytes. This happens repeatedly until there | |
| /// is no more uncompressed data to compress. This property sets the | |
| /// size of the buffer that will be used for chunk-wise compression. In | |
| /// order for the setting to take effect, your application needs to set | |
| /// this property before calling one of the <c>ZipFile.Save()</c> | |
| /// overloads. | |
| /// </para> | |
| /// <para> | |
| /// Setting this affects the performance and memory efficiency of | |
| /// compression and decompression. For larger files, setting this to a | |
| /// larger size may improve compression performance, but the exact | |
| /// numbers vary depending on available memory, the size of the streams | |
| /// you are compressing, and a bunch of other variables. I don't have | |
| /// good firm recommendations on how to set it. You'll have to test it | |
| /// yourself. Or just leave it alone and accept the default. | |
| /// </para> | |
| /// </remarks> | |
| public int CodecBufferSize | |
| { | |
| get; | |
| set; | |
| } | |
| /// <summary> | |
| /// Indicates whether extracted files should keep their paths as | |
| /// stored in the zip archive. | |
| /// </summary> | |
| /// | |
| /// <remarks> | |
| /// <para> | |
| /// This property affects Extraction. It is not used when creating zip | |
| /// archives. | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// With this property set to <c>false</c>, the default, extracting entries | |
| /// from a zip file will create files in the filesystem that have the full | |
| /// path associated to the entry within the zip file. With this property set | |
| /// to <c>true</c>, extracting entries from the zip file results in files | |
| /// with no path: the folders are "flattened." | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// An example: suppose the zip file contains entries /directory1/file1.txt and | |
| /// /directory2/file2.txt. With <c>FlattenFoldersOnExtract</c> set to false, | |
| /// the files created will be \directory1\file1.txt and \directory2\file2.txt. | |
| /// With the property set to true, the files created are file1.txt and file2.txt. | |
| /// </para> | |
| /// | |
| /// </remarks> | |
| public bool FlattenFoldersOnExtract | |
| { | |
| get; | |
| set; | |
| } | |
| /// <summary> | |
| /// The compression strategy to use for all entries. | |
| /// </summary> | |
| /// | |
| /// <remarks> | |
| /// Set the Strategy used by the ZLIB-compatible compressor, when | |
| /// compressing entries using the DEFLATE method. Different compression | |
| /// strategies work better on different sorts of data. The strategy | |
| /// parameter can affect the compression ratio and the speed of | |
| /// compression but not the correctness of the compresssion. For more | |
| /// information see <see | |
| /// cref="Ionic.Zlib.CompressionStrategy">Ionic.Zlib.CompressionStrategy</see>. | |
| /// </remarks> | |
| public CompressionStrategy Strategy | |
| { | |
| get { return _Strategy; } | |
| set { _Strategy = value; } | |
| } | |
| /// <summary> | |
| /// The name of the <c>ZipFile</c>, on disk. | |
| /// </summary> | |
| /// | |
| /// <remarks> | |
| /// | |
| /// <para> | |
| /// When the <c>ZipFile</c> instance was created by reading an archive using | |
| /// one of the <c>ZipFile.Read</c> methods, this property represents the name | |
| /// of the zip file that was read. When the <c>ZipFile</c> instance was | |
| /// created by using the no-argument constructor, this value is <c>null</c> | |
| /// (<c>Nothing</c> in VB). | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// If you use the no-argument constructor, and you then explicitly set this | |
| /// property, when you call <see cref="ZipFile.Save()"/>, this name will | |
| /// specify the name of the zip file created. Doing so is equivalent to | |
| /// calling <see cref="ZipFile.Save(String)"/>. When instantiating a | |
| /// <c>ZipFile</c> by reading from a stream or byte array, the <c>Name</c> | |
| /// property remains <c>null</c>. When saving to a stream, the <c>Name</c> | |
| /// property is implicitly set to <c>null</c>. | |
| /// </para> | |
| /// </remarks> | |
| public string Name | |
| { | |
| get { return _name; } | |
| set { _name = value; } | |
| } | |
| /// <summary> | |
| /// Sets the compression level to be used for entries subsequently added to | |
| /// the zip archive. | |
| /// </summary> | |
| /// | |
| /// <remarks> | |
| /// <para> | |
| /// Varying the compression level used on entries can affect the | |
| /// size-vs-speed tradeoff when compression and decompressing data streams | |
| /// or files. | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// As with some other properties on the <c>ZipFile</c> class, like <see | |
| /// cref="Password"/>, <see cref="Encryption"/>, and <see | |
| /// cref="ZipErrorAction"/>, setting this property on a <c>ZipFile</c> | |
| /// instance will cause the specified <c>CompressionLevel</c> to be used on all | |
| /// <see cref="ZipEntry"/> items that are subsequently added to the | |
| /// <c>ZipFile</c> instance. If you set this property after you have added | |
| /// items to the <c>ZipFile</c>, but before you have called <c>Save()</c>, | |
| /// those items will not use the specified compression level. | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// If you do not set this property, the default compression level is used, | |
| /// which normally gives a good balance of compression efficiency and | |
| /// compression speed. In some tests, using <c>BestCompression</c> can | |
| /// double the time it takes to compress, while delivering just a small | |
| /// increase in compression efficiency. This behavior will vary with the | |
| /// type of data you compress. If you are in doubt, just leave this setting | |
| /// alone, and accept the default. | |
| /// </para> | |
| /// </remarks> | |
| public OfficeOpenXml.Packaging.Ionic.Zlib.CompressionLevel CompressionLevel | |
| { | |
| get; | |
| set; | |
| } | |
| /// <summary> | |
| /// The compression method for the zipfile. | |
| /// </summary> | |
| /// <remarks> | |
| /// <para> | |
| /// By default, the compression method is <c>CompressionMethod.Deflate.</c> | |
| /// </para> | |
| /// </remarks> | |
| /// <seealso cref="Ionic.Zip.CompressionMethod" /> | |
| internal Ionic.Zip.CompressionMethod CompressionMethod | |
| { | |
| get | |
| { | |
| return _compressionMethod; | |
| } | |
| set | |
| { | |
| _compressionMethod = value; | |
| } | |
| } | |
| /// <summary> | |
| /// A comment attached to the zip archive. | |
| /// </summary> | |
| /// | |
| /// <remarks> | |
| /// | |
| /// <para> | |
| /// This property is read/write. It allows the application to specify a | |
| /// comment for the <c>ZipFile</c>, or read the comment for the | |
| /// <c>ZipFile</c>. After setting this property, changes are only made | |
| /// permanent when you call a <c>Save()</c> method. | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// According to <see | |
| /// href="http://www.pkware.com/documents/casestudies/APPNOTE.TXT">PKWARE's | |
| /// zip specification</see>, the comment is not encrypted, even if there is a | |
| /// password set on the zip file. | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// The specification does not describe how to indicate the encoding used | |
| /// on a comment string. Many "compliant" zip tools and libraries use | |
| /// IBM437 as the code page for comments; DotNetZip, too, follows that | |
| /// practice. On the other hand, there are situations where you want a | |
| /// Comment to be encoded with something else, for example using code page | |
| /// 950 "Big-5 Chinese". To fill that need, DotNetZip will encode the | |
| /// comment following the same procedure it follows for encoding | |
| /// filenames: (a) if <see cref="AlternateEncodingUsage"/> is | |
| /// <c>Never</c>, it uses the default encoding (IBM437). (b) if <see | |
| /// cref="AlternateEncodingUsage"/> is <c>Always</c>, it always uses the | |
| /// alternate encoding (<see cref="AlternateEncoding"/>). (c) if <see | |
| /// cref="AlternateEncodingUsage"/> is <c>AsNecessary</c>, it uses the | |
| /// alternate encoding only if the default encoding is not sufficient for | |
| /// encoding the comment - in other words if decoding the result does not | |
| /// produce the original string. This decision is taken at the time of | |
| /// the call to <c>ZipFile.Save()</c>. | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// When creating a zip archive using this library, it is possible to change | |
| /// the value of <see cref="AlternateEncoding" /> between each | |
| /// entry you add, and between adding entries and the call to | |
| /// <c>Save()</c>. Don't do this. It will likely result in a zip file that is | |
| /// not readable by any tool or application. For best interoperability, leave | |
| /// <see cref="AlternateEncoding"/> alone, or specify it only | |
| /// once, before adding any entries to the <c>ZipFile</c> instance. | |
| /// </para> | |
| /// | |
| /// </remarks> | |
| public string Comment | |
| { | |
| get { return _Comment; } | |
| set | |
| { | |
| _Comment = value; | |
| _contentsChanged = true; | |
| } | |
| } | |
| /// <summary> | |
| /// Specifies whether the Creation, Access, and Modified times for entries | |
| /// added to the zip file will be emitted in “Windows format” | |
| /// when the zip archive is saved. | |
| /// </summary> | |
| /// | |
| /// <remarks> | |
| /// <para> | |
| /// An application creating a zip archive can use this flag to explicitly | |
| /// specify that the file times for the entries should or should not be stored | |
| /// in the zip archive in the format used by Windows. By default this flag is | |
| /// <c>true</c>, meaning the Windows-format times are stored in the zip | |
| /// archive. | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// When adding an entry from a file or directory, the Creation (<see | |
| /// cref="ZipEntry.CreationTime"/>), Access (<see | |
| /// cref="ZipEntry.AccessedTime"/>), and Modified (<see | |
| /// cref="ZipEntry.ModifiedTime"/>) times for the given entry are | |
| /// automatically set from the filesystem values. When adding an entry from a | |
| /// stream or string, all three values are implicitly set to | |
| /// <c>DateTime.Now</c>. Applications can also explicitly set those times by | |
| /// calling <see cref="ZipEntry.SetEntryTimes(DateTime, DateTime, | |
| /// DateTime)"/>. | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// <see | |
| /// href="http://www.pkware.com/documents/casestudies/APPNOTE.TXT">PKWARE's | |
| /// zip specification</see> describes multiple ways to format these times in a | |
| /// zip file. One is the format Windows applications normally use: 100ns ticks | |
| /// since January 1, 1601 UTC. The other is a format Unix applications typically | |
| /// use: seconds since January 1, 1970 UTC. Each format can be stored in an | |
| /// "extra field" in the zip entry when saving the zip archive. The former | |
| /// uses an extra field with a Header Id of 0x000A, while the latter uses a | |
| /// header ID of 0x5455, although you probably don't need to know that. | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// Not all tools and libraries can interpret these fields. Windows | |
| /// compressed folders is one that can read the Windows Format timestamps, | |
| /// while I believe <see href="http://www.info-zip.org/">the Infozip | |
| /// tools</see> can read the Unix format timestamps. Some tools and libraries | |
| /// may be able to read only one or the other. DotNetZip can read or write | |
| /// times in either or both formats. | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// The times stored are taken from <see cref="ZipEntry.ModifiedTime"/>, <see | |
| /// cref="ZipEntry.AccessedTime"/>, and <see cref="ZipEntry.CreationTime"/>. | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// The value set here applies to all entries subsequently added to the | |
| /// <c>ZipFile</c>. | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// This property is not mutually exclusive of the <see | |
| /// cref="EmitTimesInUnixFormatWhenSaving" /> property. It is possible and | |
| /// legal and valid to produce a zip file that contains timestamps encoded in | |
| /// the Unix format as well as in the Windows format, in addition to the <see | |
| /// cref="ZipEntry.LastModified">LastModified</see> time attached to each | |
| /// entry in the archive, a time that is always stored in "DOS format". And, | |
| /// notwithstanding the names PKWare uses for these time formats, any of them | |
| /// can be read and written by any computer, on any operating system. But, | |
| /// there are no guarantees that a program running on Mac or Linux will | |
| /// gracefully handle a zip file with "Windows" formatted times, or that an | |
| /// application that does not use DotNetZip but runs on Windows will be able to | |
| /// handle file times in Unix format. | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// When in doubt, test. Sorry, I haven't got a complete list of tools and | |
| /// which sort of timestamps they can use and will tolerate. If you get any | |
| /// good information and would like to pass it on, please do so and I will | |
| /// include that information in this documentation. | |
| /// </para> | |
| /// </remarks> | |
| /// | |
| /// <example> | |
| /// This example shows how to save a zip file that contains file timestamps | |
| /// in a format normally used by Unix. | |
| /// <code lang="C#"> | |
| /// using (var zip = new ZipFile()) | |
| /// { | |
| /// // produce a zip file the Mac will like | |
| /// zip.EmitTimesInWindowsFormatWhenSaving = false; | |
| /// zip.EmitTimesInUnixFormatWhenSaving = true; | |
| /// zip.AddDirectory(directoryToZip, "files"); | |
| /// zip.Save(outputFile); | |
| /// } | |
| /// </code> | |
| /// | |
| /// <code lang="VB"> | |
| /// Using zip As New ZipFile | |
| /// '' produce a zip file the Mac will like | |
| /// zip.EmitTimesInWindowsFormatWhenSaving = False | |
| /// zip.EmitTimesInUnixFormatWhenSaving = True | |
| /// zip.AddDirectory(directoryToZip, "files") | |
| /// zip.Save(outputFile) | |
| /// End Using | |
| /// </code> | |
| /// </example> | |
| /// | |
| /// <seealso cref="ZipEntry.EmitTimesInWindowsFormatWhenSaving" /> | |
| /// <seealso cref="EmitTimesInUnixFormatWhenSaving" /> | |
| public bool EmitTimesInWindowsFormatWhenSaving | |
| { | |
| get | |
| { | |
| return _emitNtfsTimes; | |
| } | |
| set | |
| { | |
| _emitNtfsTimes = value; | |
| } | |
| } | |
| /// <summary> | |
| /// Specifies whether the Creation, Access, and Modified times | |
| /// for entries added to the zip file will be emitted in "Unix(tm) | |
| /// format" when the zip archive is saved. | |
| /// </summary> | |
| /// | |
| /// <remarks> | |
| /// <para> | |
| /// An application creating a zip archive can use this flag to explicitly | |
| /// specify that the file times for the entries should or should not be stored | |
| /// in the zip archive in the format used by Unix. By default this flag is | |
| /// <c>false</c>, meaning the Unix-format times are not stored in the zip | |
| /// archive. | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// When adding an entry from a file or directory, the Creation (<see | |
| /// cref="ZipEntry.CreationTime"/>), Access (<see | |
| /// cref="ZipEntry.AccessedTime"/>), and Modified (<see | |
| /// cref="ZipEntry.ModifiedTime"/>) times for the given entry are | |
| /// automatically set from the filesystem values. When adding an entry from a | |
| /// stream or string, all three values are implicitly set to DateTime.Now. | |
| /// Applications can also explicitly set those times by calling <see | |
| /// cref="ZipEntry.SetEntryTimes(DateTime, DateTime, DateTime)"/>. | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// <see | |
| /// href="http://www.pkware.com/documents/casestudies/APPNOTE.TXT">PKWARE's | |
| /// zip specification</see> describes multiple ways to format these times in a | |
| /// zip file. One is the format Windows applications normally use: 100ns ticks | |
| /// since January 1, 1601 UTC. The other is a format Unix applications | |
| /// typically use: seconds since January 1, 1970 UTC. Each format can be | |
| /// stored in an "extra field" in the zip entry when saving the zip | |
| /// archive. The former uses an extra field with a Header Id of 0x000A, while | |
| /// the latter uses a header ID of 0x5455, although you probably don't need to | |
| /// know that. | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// Not all tools and libraries can interpret these fields. Windows | |
| /// compressed folders is one that can read the Windows Format timestamps, | |
| /// while I believe the <see href="http://www.info-zip.org/">Infozip</see> | |
| /// tools can read the Unix format timestamps. Some tools and libraries may be | |
| /// able to read only one or the other. DotNetZip can read or write times in | |
| /// either or both formats. | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// The times stored are taken from <see cref="ZipEntry.ModifiedTime"/>, <see | |
| /// cref="ZipEntry.AccessedTime"/>, and <see cref="ZipEntry.CreationTime"/>. | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// This property is not mutually exclusive of the <see | |
| /// cref="EmitTimesInWindowsFormatWhenSaving" /> property. It is possible and | |
| /// legal and valid to produce a zip file that contains timestamps encoded in | |
| /// the Unix format as well as in the Windows format, in addition to the <see | |
| /// cref="ZipEntry.LastModified">LastModified</see> time attached to each | |
| /// entry in the zip archive, a time that is always stored in "DOS | |
| /// format". And, notwithstanding the names PKWare uses for these time | |
| /// formats, any of them can be read and written by any computer, on any | |
| /// operating system. But, there are no guarantees that a program running on | |
| /// Mac or Linux will gracefully handle a zip file with "Windows" formatted | |
| /// times, or that an application that does not use DotNetZip but runs on | |
| /// Windows will be able to handle file times in Unix format. | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// When in doubt, test. Sorry, I haven't got a complete list of tools and | |
| /// which sort of timestamps they can use and will tolerate. If you get any | |
| /// good information and would like to pass it on, please do so and I will | |
| /// include that information in this documentation. | |
| /// </para> | |
| /// </remarks> | |
| /// | |
| /// <seealso cref="ZipEntry.EmitTimesInUnixFormatWhenSaving" /> | |
| /// <seealso cref="EmitTimesInWindowsFormatWhenSaving" /> | |
| public bool EmitTimesInUnixFormatWhenSaving | |
| { | |
| get | |
| { | |
| return _emitUnixTimes; | |
| } | |
| set | |
| { | |
| _emitUnixTimes = value; | |
| } | |
| } | |
| /// <summary> | |
| /// Indicates whether verbose output is sent to the <see | |
| /// cref="StatusMessageTextWriter"/> during <c>AddXxx()</c> and | |
| /// <c>ReadXxx()</c> operations. | |
| /// </summary> | |
| /// | |
| /// <remarks> | |
| /// This is a <em>synthetic</em> property. It returns true if the <see | |
| /// cref="StatusMessageTextWriter"/> is non-null. | |
| /// </remarks> | |
| internal bool Verbose | |
| { | |
| get { return (_StatusMessageTextWriter != null); } | |
| } | |
| /// <summary> | |
| /// Returns true if an entry by the given name exists in the ZipFile. | |
| /// </summary> | |
| /// | |
| /// <param name='name'>the name of the entry to find</param> | |
| /// <returns>true if an entry with the given name exists; otherwise false. | |
| /// </returns> | |
| public bool ContainsEntry(string name) | |
| { | |
| // workitem 12534 | |
| return _entries.ContainsKey(SharedUtilities.NormalizePathForUseInZipFile(name)); | |
| } | |
| /// <summary> | |
| /// Indicates whether to perform case-sensitive matching on the filename when | |
| /// retrieving entries in the zipfile via the string-based indexer. | |
| /// </summary> | |
| /// | |
| /// <remarks> | |
| /// The default value is <c>false</c>, which means don't do case-sensitive | |
| /// matching. In other words, retrieving zip["ReadMe.Txt"] is the same as | |
| /// zip["readme.txt"]. It really makes sense to set this to <c>true</c> only | |
| /// if you are not running on Windows, which has case-insensitive | |
| /// filenames. But since this library is not built for non-Windows platforms, | |
| /// in most cases you should just leave this property alone. | |
| /// </remarks> | |
| public bool CaseSensitiveRetrieval | |
| { | |
| get | |
| { | |
| return _CaseSensitiveRetrieval; | |
| } | |
| set | |
| { | |
| // workitem 9868 | |
| if (value != _CaseSensitiveRetrieval) | |
| { | |
| _CaseSensitiveRetrieval = value; | |
| _initEntriesDictionary(); | |
| } | |
| } | |
| } | |
| /// <summary> | |
| /// Indicates whether to encode entry filenames and entry comments using Unicode | |
| /// (UTF-8). | |
| /// </summary> | |
| /// | |
| /// <remarks> | |
| /// <para> | |
| /// <see href="http://www.pkware.com/documents/casestudies/APPNOTE.TXT">The | |
| /// PKWare zip specification</see> provides for encoding file names and file | |
| /// comments in either the IBM437 code page, or in UTF-8. This flag selects | |
| /// the encoding according to that specification. By default, this flag is | |
| /// false, and filenames and comments are encoded into the zip file in the | |
| /// IBM437 codepage. Setting this flag to true will specify that filenames | |
| /// and comments that cannot be encoded with IBM437 will be encoded with | |
| /// UTF-8. | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// Zip files created with strict adherence to the PKWare specification with | |
| /// respect to UTF-8 encoding can contain entries with filenames containing | |
| /// any combination of Unicode characters, including the full range of | |
| /// characters from Chinese, Latin, Hebrew, Greek, Cyrillic, and many other | |
| /// alphabets. However, because at this time, the UTF-8 portion of the PKWare | |
| /// specification is not broadly supported by other zip libraries and | |
| /// utilities, such zip files may not be readable by your favorite zip tool or | |
| /// archiver. In other words, interoperability will decrease if you set this | |
| /// flag to true. | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// In particular, Zip files created with strict adherence to the PKWare | |
| /// specification with respect to UTF-8 encoding will not work well with | |
| /// Explorer in Windows XP or Windows Vista, because Windows compressed | |
| /// folders, as far as I know, do not support UTF-8 in zip files. Vista can | |
| /// read the zip files, but shows the filenames incorrectly. Unpacking from | |
| /// Windows Vista Explorer will result in filenames that have rubbish | |
| /// characters in place of the high-order UTF-8 bytes. | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// Also, zip files that use UTF-8 encoding will not work well with Java | |
| /// applications that use the java.util.zip classes, as of v5.0 of the Java | |
| /// runtime. The Java runtime does not correctly implement the PKWare | |
| /// specification in this regard. | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// As a result, we have the unfortunate situation that "correct" behavior by | |
| /// the DotNetZip library with regard to Unicode encoding of filenames during | |
| /// zip creation will result in zip files that are readable by strictly | |
| /// compliant and current tools (for example the most recent release of the | |
| /// commercial WinZip tool); but these zip files will not be readable by | |
| /// various other tools or libraries, including Windows Explorer. | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// The DotNetZip library can read and write zip files with UTF8-encoded | |
| /// entries, according to the PKware spec. If you use DotNetZip for both | |
| /// creating and reading the zip file, and you use UTF-8, there will be no | |
| /// loss of information in the filenames. For example, using a self-extractor | |
| /// created by this library will allow you to unpack files correctly with no | |
| /// loss of information in the filenames. | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// If you do not set this flag, it will remain false. If this flag is false, | |
| /// your <c>ZipFile</c> will encode all filenames and comments using the | |
| /// IBM437 codepage. This can cause "loss of information" on some filenames, | |
| /// but the resulting zipfile will be more interoperable with other | |
| /// utilities. As an example of the loss of information, diacritics can be | |
| /// lost. The o-tilde character will be down-coded to plain o. The c with a | |
| /// cedilla (Unicode 0xE7) used in Portugese will be downcoded to a c. | |
| /// Likewise, the O-stroke character (Unicode 248), used in Danish and | |
| /// Norwegian, will be down-coded to plain o. Chinese characters cannot be | |
| /// represented in codepage IBM437; when using the default encoding, Chinese | |
| /// characters in filenames will be represented as ?. These are all examples | |
| /// of "information loss". | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// The loss of information associated to the use of the IBM437 encoding is | |
| /// inconvenient, and can also lead to runtime errors. For example, using | |
| /// IBM437, any sequence of 4 Chinese characters will be encoded as ????. If | |
| /// your application creates a <c>ZipFile</c>, then adds two files, each with | |
| /// names of four Chinese characters each, this will result in a duplicate | |
| /// filename exception. In the case where you add a single file with a name | |
| /// containing four Chinese characters, calling Extract() on the entry that | |
| /// has question marks in the filename will result in an exception, because | |
| /// the question mark is not legal for use within filenames on Windows. These | |
| /// are just a few examples of the problems associated to loss of information. | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// This flag is independent of the encoding of the content within the entries | |
| /// in the zip file. Think of the zip file as a container - it supports an | |
| /// encoding. Within the container are other "containers" - the file entries | |
| /// themselves. The encoding within those entries is independent of the | |
| /// encoding of the zip archive container for those entries. | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// Rather than specify the encoding in a binary fashion using this flag, an | |
| /// application can specify an arbitrary encoding via the <see | |
| /// cref="ProvisionalAlternateEncoding"/> property. Setting the encoding | |
| /// explicitly when creating zip archives will result in non-compliant zip | |
| /// files that, curiously, are fairly interoperable. The challenge is, the | |
| /// PKWare specification does not provide for a way to specify that an entry | |
| /// in a zip archive uses a code page that is neither IBM437 nor UTF-8. | |
| /// Therefore if you set the encoding explicitly when creating a zip archive, | |
| /// you must take care upon reading the zip archive to use the same code page. | |
| /// If you get it wrong, the behavior is undefined and may result in incorrect | |
| /// filenames, exceptions, stomach upset, hair loss, and acne. | |
| /// </para> | |
| /// </remarks> | |
| /// <seealso cref="ProvisionalAlternateEncoding"/> | |
| [Obsolete("Beginning with v1.9.1.6 of DotNetZip, this property is obsolete. It will be removed in a future version of the library. Your applications should use AlternateEncoding and AlternateEncodingUsage instead.")] | |
| public bool UseUnicodeAsNecessary | |
| { | |
| get | |
| { | |
| return (_alternateEncoding == System.Text.Encoding.GetEncoding("UTF-8")) && | |
| (_alternateEncodingUsage == ZipOption.AsNecessary); | |
| } | |
| set | |
| { | |
| if (value) | |
| { | |
| _alternateEncoding = System.Text.Encoding.GetEncoding("UTF-8"); | |
| _alternateEncodingUsage = ZipOption.AsNecessary; | |
| } | |
| else | |
| { | |
| _alternateEncoding = Ionic.Zip.ZipFile.DefaultEncoding; | |
| _alternateEncodingUsage = ZipOption.Never; | |
| } | |
| } | |
| } | |
| /// <summary> | |
| /// Specify whether to use ZIP64 extensions when saving a zip archive. | |
| /// </summary> | |
| /// | |
| /// <remarks> | |
| /// | |
| /// <para> | |
| /// When creating a zip file, the default value for the property is <see | |
| /// cref="Zip64Option.Never"/>. <see cref="Zip64Option.AsNecessary"/> is | |
| /// safest, in the sense that you will not get an Exception if a pre-ZIP64 | |
| /// limit is exceeded. | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// You may set the property at any time before calling Save(). | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// When reading a zip file via the <c>Zipfile.Read()</c> method, DotNetZip | |
| /// will properly read ZIP64-endowed zip archives, regardless of the value of | |
| /// this property. DotNetZip will always read ZIP64 archives. This property | |
| /// governs only whether DotNetZip will write them. Therefore, when updating | |
| /// archives, be careful about setting this property after reading an archive | |
| /// that may use ZIP64 extensions. | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// An interesting question is, if you have set this property to | |
| /// <c>AsNecessary</c>, and then successfully saved, does the resulting | |
| /// archive use ZIP64 extensions or not? To learn this, check the <see | |
| /// cref="OutputUsedZip64"/> property, after calling <c>Save()</c>. | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// Have you thought about | |
| /// <see href="http://cheeso.members.winisp.net/DotNetZipDonate.aspx">donating</see>? | |
| /// </para> | |
| /// | |
| /// </remarks> | |
| /// <seealso cref="RequiresZip64"/> | |
| internal Zip64Option UseZip64WhenSaving | |
| { | |
| get | |
| { | |
| return _zip64; | |
| } | |
| set | |
| { | |
| _zip64 = value; | |
| } | |
| } | |
| /// <summary> | |
| /// Indicates whether the archive requires ZIP64 extensions. | |
| /// </summary> | |
| /// | |
| /// <remarks> | |
| /// | |
| /// <para> | |
| /// This property is <c>null</c> (or <c>Nothing</c> in VB) if the archive has | |
| /// not been saved, and there are fewer than 65334 <c>ZipEntry</c> items | |
| /// contained in the archive. | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// The <c>Value</c> is true if any of the following four conditions holds: | |
| /// the uncompressed size of any entry is larger than 0xFFFFFFFF; the | |
| /// compressed size of any entry is larger than 0xFFFFFFFF; the relative | |
| /// offset of any entry within the zip archive is larger than 0xFFFFFFFF; or | |
| /// there are more than 65534 entries in the archive. (0xFFFFFFFF = | |
| /// 4,294,967,295). The result may not be known until a <c>Save()</c> is attempted | |
| /// on the zip archive. The Value of this <see cref="System.Nullable"/> | |
| /// property may be set only AFTER one of the Save() methods has been called. | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// If none of the four conditions holds, and the archive has been saved, then | |
| /// the <c>Value</c> is false. | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// A <c>Value</c> of false does not indicate that the zip archive, as saved, | |
| /// does not use ZIP64. It merely indicates that ZIP64 is not required. An | |
| /// archive may use ZIP64 even when not required if the <see | |
| /// cref="ZipFile.UseZip64WhenSaving"/> property is set to <see | |
| /// cref="Zip64Option.Always"/>, or if the <see | |
| /// cref="ZipFile.UseZip64WhenSaving"/> property is set to <see | |
| /// cref="Zip64Option.AsNecessary"/> and the output stream was not | |
| /// seekable. Use the <see cref="OutputUsedZip64"/> property to determine if | |
| /// the most recent <c>Save()</c> method resulted in an archive that utilized | |
| /// the ZIP64 extensions. | |
| /// </para> | |
| /// | |
| /// </remarks> | |
| /// <seealso cref="UseZip64WhenSaving"/> | |
| /// <seealso cref="OutputUsedZip64"/> | |
| public Nullable<bool> RequiresZip64 | |
| { | |
| get | |
| { | |
| if (_entries.Count > 65534) | |
| return new Nullable<bool>(true); | |
| // If the <c>ZipFile</c> has not been saved or if the contents have changed, then | |
| // it is not known if ZIP64 is required. | |
| if (!_hasBeenSaved || _contentsChanged) return null; | |
| // Whether ZIP64 is required is knowable. | |
| foreach (ZipEntry e in _entries.Values) | |
| { | |
| if (e.RequiresZip64.Value) return new Nullable<bool>(true); | |
| } | |
| return new Nullable<bool>(false); | |
| } | |
| } | |
| /// <summary> | |
| /// Indicates whether the most recent <c>Save()</c> operation used ZIP64 extensions. | |
| /// </summary> | |
| /// | |
| /// <remarks> | |
| /// <para> | |
| /// The use of ZIP64 extensions within an archive is not always necessary, and | |
| /// for interoperability concerns, it may be desired to NOT use ZIP64 if | |
| /// possible. The <see cref="ZipFile.UseZip64WhenSaving"/> property can be | |
| /// set to use ZIP64 extensions only when necessary. In those cases, | |
| /// Sometimes applications want to know whether a Save() actually used ZIP64 | |
| /// extensions. Applications can query this read-only property to learn | |
| /// whether ZIP64 has been used in a just-saved <c>ZipFile</c>. | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// The value is <c>null</c> (or <c>Nothing</c> in VB) if the archive has not | |
| /// been saved. | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// Non-null values (<c>HasValue</c> is true) indicate whether ZIP64 | |
| /// extensions were used during the most recent <c>Save()</c> operation. The | |
| /// ZIP64 extensions may have been used as required by any particular entry | |
| /// because of its uncompressed or compressed size, or because the archive is | |
| /// larger than 4294967295 bytes, or because there are more than 65534 entries | |
| /// in the archive, or because the <c>UseZip64WhenSaving</c> property was set | |
| /// to <see cref="Zip64Option.Always"/>, or because the | |
| /// <c>UseZip64WhenSaving</c> property was set to <see | |
| /// cref="Zip64Option.AsNecessary"/> and the output stream was not seekable. | |
| /// The value of this property does not indicate the reason the ZIP64 | |
| /// extensions were used. | |
| /// </para> | |
| /// | |
| /// </remarks> | |
| /// <seealso cref="UseZip64WhenSaving"/> | |
| /// <seealso cref="RequiresZip64"/> | |
| public Nullable<bool> OutputUsedZip64 | |
| { | |
| get | |
| { | |
| return _OutputUsesZip64; | |
| } | |
| } | |
| /// <summary> | |
| /// Indicates whether the most recent <c>Read()</c> operation read a zip file that uses | |
| /// ZIP64 extensions. | |
| /// </summary> | |
| /// | |
| /// <remarks> | |
| /// This property will return null (Nothing in VB) if you've added an entry after reading | |
| /// the zip file. | |
| /// </remarks> | |
| public Nullable<bool> InputUsesZip64 | |
| { | |
| get | |
| { | |
| if (_entries.Count > 65534) | |
| return true; | |
| foreach (ZipEntry e in this) | |
| { | |
| // if any entry was added after reading the zip file, then the result is null | |
| if (e.Source != ZipEntrySource.ZipFile) return null; | |
| // if any entry read from the zip used zip64, then the result is true | |
| if (e._InputUsesZip64) return true; | |
| } | |
| return false; | |
| } | |
| } | |
| /// <summary> | |
| /// The text encoding to use when writing new entries to the <c>ZipFile</c>, | |
| /// for those entries that cannot be encoded with the default (IBM437) | |
| /// encoding; or, the text encoding that was used when reading the entries | |
| /// from the <c>ZipFile</c>. | |
| /// </summary> | |
| /// | |
| /// <remarks> | |
| /// <para> | |
| /// In <see href="http://www.pkware.com/documents/casestudies/APPNOTE.TXT">its | |
| /// zip specification</see>, PKWare describes two options for encoding | |
| /// filenames and comments: using IBM437 or UTF-8. But, some archiving tools | |
| /// or libraries do not follow the specification, and instead encode | |
| /// characters using the system default code page. For example, WinRAR when | |
| /// run on a machine in Shanghai may encode filenames with the Big-5 Chinese | |
| /// (950) code page. This behavior is contrary to the Zip specification, but | |
| /// it occurs anyway. | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// When using DotNetZip to write zip archives that will be read by one of | |
| /// these other archivers, set this property to specify the code page to use | |
| /// when encoding the <see cref="ZipEntry.FileName"/> and <see | |
| /// cref="ZipEntry.Comment"/> for each <c>ZipEntry</c> in the zip file, for | |
| /// values that cannot be encoded with the default codepage for zip files, | |
| /// IBM437. This is why this property is "provisional". In all cases, IBM437 | |
| /// is used where possible, in other words, where no loss of data would | |
| /// result. It is possible, therefore, to have a given entry with a | |
| /// <c>Comment</c> encoded in IBM437 and a <c>FileName</c> encoded with the | |
| /// specified "provisional" codepage. | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// Be aware that a zip file created after you've explicitly set the <see | |
| /// cref="ProvisionalAlternateEncoding" /> property to a value other than | |
| /// IBM437 may not be compliant to the PKWare specification, and may not be | |
| /// readable by compliant archivers. On the other hand, many (most?) | |
| /// archivers are non-compliant and can read zip files created in arbitrary | |
| /// code pages. The trick is to use or specify the proper codepage when | |
| /// reading the zip. | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// When creating a zip archive using this library, it is possible to change | |
| /// the value of <see cref="ProvisionalAlternateEncoding" /> between each | |
| /// entry you add, and between adding entries and the call to | |
| /// <c>Save()</c>. Don't do this. It will likely result in a zipfile that is | |
| /// not readable. For best interoperability, either leave <see | |
| /// cref="ProvisionalAlternateEncoding" /> alone, or specify it only once, | |
| /// before adding any entries to the <c>ZipFile</c> instance. There is one | |
| /// exception to this recommendation, described later. | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// When using an arbitrary, non-UTF8 code page for encoding, there is no | |
| /// standard way for the creator application - whether DotNetZip, WinZip, | |
| /// WinRar, or something else - to formally specify in the zip file which | |
| /// codepage has been used for the entries. As a result, readers of zip files | |
| /// are not able to inspect the zip file and determine the codepage that was | |
| /// used for the entries contained within it. It is left to the application | |
| /// or user to determine the necessary codepage when reading zip files encoded | |
| /// this way. In other words, if you explicitly specify the codepage when you | |
| /// create the zipfile, you must explicitly specify the same codepage when | |
| /// reading the zipfile. | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// The way you specify the code page to use when reading a zip file varies | |
| /// depending on the tool or library you use to read the zip. In DotNetZip, | |
| /// you use a ZipFile.Read() method that accepts an encoding parameter. It | |
| /// isn't possible with Windows Explorer, as far as I know, to specify an | |
| /// explicit codepage to use when reading a zip. If you use an incorrect | |
| /// codepage when reading a zipfile, you will get entries with filenames that | |
| /// are incorrect, and the incorrect filenames may even contain characters | |
| /// that are not legal for use within filenames in Windows. Extracting entries | |
| /// with illegal characters in the filenames will lead to exceptions. It's too | |
| /// bad, but this is just the way things are with code pages in zip | |
| /// files. Caveat Emptor. | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// Example: Suppose you create a zipfile that contains entries with | |
| /// filenames that have Danish characters. If you use <see | |
| /// cref="ProvisionalAlternateEncoding" /> equal to "iso-8859-1" (cp 28591), | |
| /// the filenames will be correctly encoded in the zip. But, to read that | |
| /// zipfile correctly, you have to specify the same codepage at the time you | |
| /// read it. If try to read that zip file with Windows Explorer or another | |
| /// application that is not flexible with respect to the codepage used to | |
| /// decode filenames in zipfiles, you will get a filename like "Inf�.txt". | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// When using DotNetZip to read a zip archive, and the zip archive uses an | |
| /// arbitrary code page, you must specify the encoding to use before or when | |
| /// the <c>Zipfile</c> is READ. This means you must use a <c>ZipFile.Read()</c> | |
| /// method that allows you to specify a System.Text.Encoding parameter. Setting | |
| /// the ProvisionalAlternateEncoding property after your application has read in | |
| /// the zip archive will not affect the entry names of entries that have already | |
| /// been read in. | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// And now, the exception to the rule described above. One strategy for | |
| /// specifying the code page for a given zip file is to describe the code page | |
| /// in a human-readable form in the Zip comment. For example, the comment may | |
| /// read "Entries in this archive are encoded in the Big5 code page". For | |
| /// maximum interoperability, the zip comment in this case should be encoded | |
| /// in the default, IBM437 code page. In this case, the zip comment is | |
| /// encoded using a different page than the filenames. To do this, Specify | |
| /// <c>ProvisionalAlternateEncoding</c> to your desired region-specific code | |
| /// page, once before adding any entries, and then reset | |
| /// <c>ProvisionalAlternateEncoding</c> to IBM437 before setting the <see | |
| /// cref="Comment"/> property and calling Save(). | |
| /// </para> | |
| /// </remarks> | |
| /// | |
| /// <example> | |
| /// This example shows how to read a zip file using the Big-5 Chinese code page | |
| /// (950), and extract each entry in the zip file. For this code to work as | |
| /// desired, the <c>Zipfile</c> must have been created using the big5 code page | |
| /// (CP950). This is typical, for example, when using WinRar on a machine with | |
| /// CP950 set as the default code page. In that case, the names of entries | |
| /// within the Zip archive will be stored in that code page, and reading the zip | |
| /// archive must be done using that code page. If the application did not use | |
| /// the correct code page in <c>ZipFile.Read()</c>, then names of entries within the | |
| /// zip archive would not be correctly retrieved. | |
| /// <code> | |
| /// using (var zip = ZipFile.Read(zipFileName, System.Text.Encoding.GetEncoding("big5"))) | |
| /// { | |
| /// // retrieve and extract an entry using a name encoded with CP950 | |
| /// zip[MyDesiredEntry].Extract("unpack"); | |
| /// } | |
| /// </code> | |
| /// | |
| /// <code lang="VB"> | |
| /// Using zip As ZipFile = ZipFile.Read(ZipToExtract, System.Text.Encoding.GetEncoding("big5")) | |
| /// ' retrieve and extract an entry using a name encoded with CP950 | |
| /// zip(MyDesiredEntry).Extract("unpack") | |
| /// End Using | |
| /// </code> | |
| /// </example> | |
| /// | |
| /// <seealso cref="Ionic.Zip.ZipFile.DefaultEncoding">DefaultEncoding</seealso> | |
| [Obsolete("use AlternateEncoding instead.")] | |
| public System.Text.Encoding ProvisionalAlternateEncoding | |
| { | |
| get | |
| { | |
| if (_alternateEncodingUsage == ZipOption.AsNecessary) | |
| return _alternateEncoding; | |
| return null; | |
| } | |
| set | |
| { | |
| _alternateEncoding = value; | |
| _alternateEncodingUsage = ZipOption.AsNecessary; | |
| } | |
| } | |
| /// <summary> | |
| /// A Text Encoding to use when encoding the filenames and comments for | |
| /// all the ZipEntry items, during a ZipFile.Save() operation. | |
| /// </summary> | |
| /// <remarks> | |
| /// <para> | |
| /// Whether the encoding specified here is used during the save depends | |
| /// on <see cref="AlternateEncodingUsage"/>. | |
| /// </para> | |
| /// </remarks> | |
| public System.Text.Encoding AlternateEncoding | |
| { | |
| get | |
| { | |
| return _alternateEncoding; | |
| } | |
| set | |
| { | |
| _alternateEncoding = value; | |
| } | |
| } | |
| /// <summary> | |
| /// A flag that tells if and when this instance should apply | |
| /// AlternateEncoding to encode the filenames and comments associated to | |
| /// of ZipEntry objects contained within this instance. | |
| /// </summary> | |
| internal ZipOption AlternateEncodingUsage | |
| { | |
| get | |
| { | |
| return _alternateEncodingUsage; | |
| } | |
| set | |
| { | |
| _alternateEncodingUsage = value; | |
| } | |
| } | |
| /// <summary> | |
| /// The default text encoding used in zip archives. It is numeric 437, also | |
| /// known as IBM437. | |
| /// </summary> | |
| /// <seealso cref="Ionic.Zip.ZipFile.ProvisionalAlternateEncoding"/> | |
| public static System.Text.Encoding DefaultEncoding | |
| { | |
| get | |
| { | |
| return _defaultEncoding; | |
| } | |
| } | |
| /// <summary> | |
| /// Gets or sets the <c>TextWriter</c> to which status messages are delivered | |
| /// for the instance. | |
| /// </summary> | |
| /// | |
| /// <remarks> | |
| /// If the TextWriter is set to a non-null value, then verbose output is sent | |
| /// to the <c>TextWriter</c> during <c>Add</c><c>, Read</c><c>, Save</c> and | |
| /// <c>Extract</c> operations. Typically, console applications might use | |
| /// <c>Console.Out</c> and graphical or headless applications might use a | |
| /// <c>System.IO.StringWriter</c>. The output of this is suitable for viewing | |
| /// by humans. | |
| /// </remarks> | |
| /// | |
| /// <example> | |
| /// <para> | |
| /// In this example, a console application instantiates a <c>ZipFile</c>, then | |
| /// sets the <c>StatusMessageTextWriter</c> to <c>Console.Out</c>. At that | |
| /// point, all verbose status messages for that <c>ZipFile</c> are sent to the | |
| /// console. | |
| /// </para> | |
| /// | |
| /// <code lang="C#"> | |
| /// using (ZipFile zip= ZipFile.Read(FilePath)) | |
| /// { | |
| /// zip.StatusMessageTextWriter= System.Console.Out; | |
| /// // messages are sent to the console during extraction | |
| /// zip.ExtractAll(); | |
| /// } | |
| /// </code> | |
| /// | |
| /// <code lang="VB"> | |
| /// Using zip As ZipFile = ZipFile.Read(FilePath) | |
| /// zip.StatusMessageTextWriter= System.Console.Out | |
| /// 'Status Messages will be sent to the console during extraction | |
| /// zip.ExtractAll() | |
| /// End Using | |
| /// </code> | |
| /// | |
| /// <para> | |
| /// In this example, a Windows Forms application instantiates a | |
| /// <c>ZipFile</c>, then sets the <c>StatusMessageTextWriter</c> to a | |
| /// <c>StringWriter</c>. At that point, all verbose status messages for that | |
| /// <c>ZipFile</c> are sent to the <c>StringWriter</c>. | |
| /// </para> | |
| /// | |
| /// <code lang="C#"> | |
| /// var sw = new System.IO.StringWriter(); | |
| /// using (ZipFile zip= ZipFile.Read(FilePath)) | |
| /// { | |
| /// zip.StatusMessageTextWriter= sw; | |
| /// zip.ExtractAll(); | |
| /// } | |
| /// Console.WriteLine("{0}", sw.ToString()); | |
| /// </code> | |
| /// | |
| /// <code lang="VB"> | |
| /// Dim sw as New System.IO.StringWriter | |
| /// Using zip As ZipFile = ZipFile.Read(FilePath) | |
| /// zip.StatusMessageTextWriter= sw | |
| /// zip.ExtractAll() | |
| /// End Using | |
| /// 'Status Messages are now available in sw | |
| /// | |
| /// </code> | |
| /// </example> | |
| public TextWriter StatusMessageTextWriter | |
| { | |
| get { return _StatusMessageTextWriter; } | |
| set { _StatusMessageTextWriter = value; } | |
| } | |
| /// <summary> | |
| /// Gets or sets the name for the folder to store the temporary file | |
| /// this library writes when saving a zip archive. | |
| /// </summary> | |
| /// | |
| /// <remarks> | |
| /// <para> | |
| /// This library will create a temporary file when saving a Zip archive to a | |
| /// file. This file is written when calling one of the <c>Save()</c> methods | |
| /// that does not save to a stream, or one of the <c>SaveSelfExtractor()</c> | |
| /// methods. | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// By default, the library will create the temporary file in the directory | |
| /// specified for the file itself, via the <see cref="Name"/> property or via | |
| /// the <see cref="ZipFile.Save(String)"/> method. | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// Setting this property allows applications to override this default | |
| /// behavior, so that the library will create the temporary file in the | |
| /// specified folder. For example, to have the library create the temporary | |
| /// file in the current working directory, regardless where the <c>ZipFile</c> | |
| /// is saved, specfy ".". To revert to the default behavior, set this | |
| /// property to <c>null</c> (<c>Nothing</c> in VB). | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// When setting the property to a non-null value, the folder specified must | |
| /// exist; if it does not an exception is thrown. The application should have | |
| /// write and delete permissions on the folder. The permissions are not | |
| /// explicitly checked ahead of time; if the application does not have the | |
| /// appropriate rights, an exception will be thrown at the time <c>Save()</c> | |
| /// is called. | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// There is no temporary file created when reading a zip archive. When | |
| /// saving to a Stream, there is no temporary file created. For example, if | |
| /// the application is an ASP.NET application and calls <c>Save()</c> | |
| /// specifying the <c>Response.OutputStream</c> as the output stream, there is | |
| /// no temporary file created. | |
| /// </para> | |
| /// </remarks> | |
| /// | |
| /// <exception cref="System.IO.FileNotFoundException"> | |
| /// Thrown when setting the property if the directory does not exist. | |
| /// </exception> | |
| /// | |
| public String TempFileFolder | |
| { | |
| get { return _TempFileFolder; } | |
| set | |
| { | |
| _TempFileFolder = value; | |
| if (value == null) return; | |
| if (!Directory.Exists(value)) | |
| throw new FileNotFoundException(String.Format("That directory ({0}) does not exist.", value)); | |
| } | |
| } | |
| /// <summary> | |
| /// Sets the password to be used on the <c>ZipFile</c> instance. | |
| /// </summary> | |
| /// | |
| /// <remarks> | |
| /// | |
| /// <para> | |
| /// When writing a zip archive, this password is applied to the entries, not | |
| /// to the zip archive itself. It applies to any <c>ZipEntry</c> subsequently | |
| /// added to the <c>ZipFile</c>, using one of the <c>AddFile</c>, | |
| /// <c>AddDirectory</c>, <c>AddEntry</c>, or <c>AddItem</c> methods, etc. | |
| /// When reading a zip archive, this property applies to any entry | |
| /// subsequently extracted from the <c>ZipFile</c> using one of the Extract | |
| /// methods on the <c>ZipFile</c> class. | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// When writing a zip archive, keep this in mind: though the password is set | |
| /// on the ZipFile object, according to the Zip spec, the "directory" of the | |
| /// archive - in other words the list of entries or files contained in the archive - is | |
| /// not encrypted with the password, or protected in any way. If you set the | |
| /// Password property, the password actually applies to individual entries | |
| /// that are added to the archive, subsequent to the setting of this property. | |
| /// The list of filenames in the archive that is eventually created will | |
| /// appear in clear text, but the contents of the individual files are | |
| /// encrypted. This is how Zip encryption works. | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// One simple way around this limitation is to simply double-wrap sensitive | |
| /// filenames: Store the files in a zip file, and then store that zip file | |
| /// within a second, "outer" zip file. If you apply a password to the outer | |
| /// zip file, then readers will be able to see that the outer zip file | |
| /// contains an inner zip file. But readers will not be able to read the | |
| /// directory or file list of the inner zip file. | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// If you set the password on the <c>ZipFile</c>, and then add a set of files | |
| /// to the archive, then each entry is encrypted with that password. You may | |
| /// also want to change the password between adding different entries. If you | |
| /// set the password, add an entry, then set the password to <c>null</c> | |
| /// (<c>Nothing</c> in VB), and add another entry, the first entry is | |
| /// encrypted and the second is not. If you call <c>AddFile()</c>, then set | |
| /// the <c>Password</c> property, then call <c>ZipFile.Save</c>, the file | |
| /// added will not be password-protected, and no warning will be generated. | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// When setting the Password, you may also want to explicitly set the <see | |
| /// cref="Encryption"/> property, to specify how to encrypt the entries added | |
| /// to the ZipFile. If you set the Password to a non-null value and do not | |
| /// set <see cref="Encryption"/>, then PKZip 2.0 ("Weak") encryption is used. | |
| /// This encryption is relatively weak but is very interoperable. If you set | |
| /// the password to a <c>null</c> value (<c>Nothing</c> in VB), Encryption is | |
| /// reset to None. | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// All of the preceding applies to writing zip archives, in other words when | |
| /// you use one of the Save methods. To use this property when reading or an | |
| /// existing ZipFile, do the following: set the Password property on the | |
| /// <c>ZipFile</c>, then call one of the Extract() overloads on the <see | |
| /// cref="ZipEntry" />. In this case, the entry is extracted using the | |
| /// <c>Password</c> that is specified on the <c>ZipFile</c> instance. If you | |
| /// have not set the <c>Password</c> property, then the password is | |
| /// <c>null</c>, and the entry is extracted with no password. | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// If you set the Password property on the <c>ZipFile</c>, then call | |
| /// <c>Extract()</c> an entry that has not been encrypted with a password, the | |
| /// password is not used for that entry, and the <c>ZipEntry</c> is extracted | |
| /// as normal. In other words, the password is used only if necessary. | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// The <see cref="ZipEntry"/> class also has a <see | |
| /// cref="ZipEntry.Password">Password</see> property. It takes precedence | |
| /// over this property on the <c>ZipFile</c>. Typically, you would use the | |
| /// per-entry Password when most entries in the zip archive use one password, | |
| /// and a few entries use a different password. If all entries in the zip | |
| /// file use the same password, then it is simpler to just set this property | |
| /// on the <c>ZipFile</c> itself, whether creating a zip archive or extracting | |
| /// a zip archive. | |
| /// </para> | |
| /// | |
| /// </remarks> | |
| /// | |
| /// <example> | |
| /// <para> | |
| /// This example creates a zip file, using password protection for the | |
| /// entries, and then extracts the entries from the zip file. When creating | |
| /// the zip file, the Readme.txt file is not protected with a password, but | |
| /// the other two are password-protected as they are saved. During extraction, | |
| /// each file is extracted with the appropriate password. | |
| /// </para> | |
| /// <code> | |
| /// // create a file with encryption | |
| /// using (ZipFile zip = new ZipFile()) | |
| /// { | |
| /// zip.AddFile("ReadMe.txt"); | |
| /// zip.Password= "!Secret1"; | |
| /// zip.AddFile("MapToTheSite-7440-N49th.png"); | |
| /// zip.AddFile("2008-Regional-Sales-Report.pdf"); | |
| /// zip.Save("EncryptedArchive.zip"); | |
| /// } | |
| /// | |
| /// // extract entries that use encryption | |
| /// using (ZipFile zip = ZipFile.Read("EncryptedArchive.zip")) | |
| /// { | |
| /// zip.Password= "!Secret1"; | |
| /// zip.ExtractAll("extractDir"); | |
| /// } | |
| /// | |
| /// </code> | |
| /// | |
| /// <code lang="VB"> | |
| /// Using zip As New ZipFile | |
| /// zip.AddFile("ReadMe.txt") | |
| /// zip.Password = "123456!" | |
| /// zip.AddFile("MapToTheSite-7440-N49th.png") | |
| /// zip.Password= "!Secret1"; | |
| /// zip.AddFile("2008-Regional-Sales-Report.pdf") | |
| /// zip.Save("EncryptedArchive.zip") | |
| /// End Using | |
| /// | |
| /// | |
| /// ' extract entries that use encryption | |
| /// Using (zip as ZipFile = ZipFile.Read("EncryptedArchive.zip")) | |
| /// zip.Password= "!Secret1" | |
| /// zip.ExtractAll("extractDir") | |
| /// End Using | |
| /// | |
| /// </code> | |
| /// | |
| /// </example> | |
| /// | |
| /// <seealso cref="Ionic.Zip.ZipFile.Encryption">ZipFile.Encryption</seealso> | |
| /// <seealso cref="ZipEntry.Password">ZipEntry.Password</seealso> | |
| public String Password | |
| { | |
| set | |
| { | |
| _Password = value; | |
| if (_Password == null) | |
| { | |
| Encryption = EncryptionAlgorithm.None; | |
| } | |
| else if (Encryption == EncryptionAlgorithm.None) | |
| { | |
| Encryption = EncryptionAlgorithm.PkzipWeak; | |
| } | |
| } | |
| private get | |
| { | |
| return _Password; | |
| } | |
| } | |
| /// <summary> | |
| /// The action the library should take when extracting a file that already | |
| /// exists. | |
| /// </summary> | |
| /// | |
| /// <remarks> | |
| /// <para> | |
| /// This property affects the behavior of the Extract methods (one of the | |
| /// <c>Extract()</c> or <c>ExtractWithPassword()</c> overloads), when | |
| /// extraction would would overwrite an existing filesystem file. If you do | |
| /// not set this property, the library throws an exception when extracting an | |
| /// entry would overwrite an existing file. | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// This property has no effect when extracting to a stream, or when the file | |
| /// to be extracted does not already exist. | |
| /// </para> | |
| /// </remarks> | |
| /// <seealso cref="ZipEntry.ExtractExistingFile"/> | |
| internal ExtractExistingFileAction ExtractExistingFile | |
| { | |
| get; | |
| set; | |
| } | |
| /// <summary> | |
| /// The action the library should take when an error is encountered while | |
| /// opening or reading files as they are saved into a zip archive. | |
| /// </summary> | |
| /// | |
| /// <remarks> | |
| /// <para> | |
| /// Errors can occur as a file is being saved to the zip archive. For | |
| /// example, the File.Open may fail, or a File.Read may fail, because of | |
| /// lock conflicts or other reasons. | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// The first problem might occur after having called AddDirectory() on a | |
| /// directory that contains a Clipper .dbf file; the file is locked by | |
| /// Clipper and cannot be opened for read by another process. An example of | |
| /// the second problem might occur when trying to zip a .pst file that is in | |
| /// use by Microsoft Outlook. Outlook locks a range on the file, which allows | |
| /// other processes to open the file, but not read it in its entirety. | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// This property tells DotNetZip what you would like to do in the case of | |
| /// these errors. The primary options are: <c>ZipErrorAction.Throw</c> to | |
| /// throw an exception (this is the default behavior if you don't set this | |
| /// property); <c>ZipErrorAction.Skip</c> to Skip the file for which there | |
| /// was an error and continue saving; <c>ZipErrorAction.Retry</c> to Retry | |
| /// the entry that caused the problem; or | |
| /// <c>ZipErrorAction.InvokeErrorEvent</c> to invoke an event handler. | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// This property is implicitly set to <c>ZipErrorAction.InvokeErrorEvent</c> | |
| /// if you add a handler to the <see cref="ZipError" /> event. If you set | |
| /// this property to something other than | |
| /// <c>ZipErrorAction.InvokeErrorEvent</c>, then the <c>ZipError</c> | |
| /// event is implicitly cleared. What it means is you can set one or the | |
| /// other (or neither), depending on what you want, but you never need to set | |
| /// both. | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// As with some other properties on the <c>ZipFile</c> class, like <see | |
| /// cref="Password"/>, <see cref="Encryption"/>, and <see | |
| /// cref="CompressionLevel"/>, setting this property on a <c>ZipFile</c> | |
| /// instance will cause the specified <c>ZipErrorAction</c> to be used on all | |
| /// <see cref="ZipEntry"/> items that are subsequently added to the | |
| /// <c>ZipFile</c> instance. If you set this property after you have added | |
| /// items to the <c>ZipFile</c>, but before you have called <c>Save()</c>, | |
| /// those items will not use the specified error handling action. | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// If you want to handle any errors that occur with any entry in the zip | |
| /// file in the same way, then set this property once, before adding any | |
| /// entries to the zip archive. | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// If you set this property to <c>ZipErrorAction.Skip</c> and you'd like to | |
| /// learn which files may have been skipped after a <c>Save()</c>, you can | |
| /// set the <see cref="StatusMessageTextWriter" /> on the ZipFile before | |
| /// calling <c>Save()</c>. A message will be emitted into that writer for | |
| /// each skipped file, if any. | |
| /// </para> | |
| /// | |
| /// </remarks> | |
| /// | |
| /// <example> | |
| /// This example shows how to tell DotNetZip to skip any files for which an | |
| /// error is generated during the Save(). | |
| /// <code lang="VB"> | |
| /// Public Sub SaveZipFile() | |
| /// Dim SourceFolder As String = "fodder" | |
| /// Dim DestFile As String = "eHandler.zip" | |
| /// Dim sw as New StringWriter | |
| /// Using zipArchive As ZipFile = New ZipFile | |
| /// ' Tell DotNetZip to skip any files for which it encounters an error | |
| /// zipArchive.ZipErrorAction = ZipErrorAction.Skip | |
| /// zipArchive.StatusMessageTextWriter = sw | |
| /// zipArchive.AddDirectory(SourceFolder) | |
| /// zipArchive.Save(DestFile) | |
| /// End Using | |
| /// ' examine sw here to see any messages | |
| /// End Sub | |
| /// | |
| /// </code> | |
| /// </example> | |
| /// | |
| /// <seealso cref="ZipEntry.ZipErrorAction"/> | |
| /// <seealso cref="Ionic.Zip.ZipFile.ZipError"/> | |
| internal ZipErrorAction ZipErrorAction | |
| { | |
| get | |
| { | |
| if (ZipError != null) | |
| _zipErrorAction = ZipErrorAction.InvokeErrorEvent; | |
| return _zipErrorAction; | |
| } | |
| set | |
| { | |
| _zipErrorAction = value; | |
| if (_zipErrorAction != ZipErrorAction.InvokeErrorEvent && ZipError != null) | |
| ZipError = null; | |
| } | |
| } | |
| /// <summary> | |
| /// The Encryption to use for entries added to the <c>ZipFile</c>. | |
| /// </summary> | |
| /// | |
| /// <remarks> | |
| /// <para> | |
| /// Set this when creating a zip archive, or when updating a zip archive. The | |
| /// specified Encryption is applied to the entries subsequently added to the | |
| /// <c>ZipFile</c> instance. Applications do not need to set the | |
| /// <c>Encryption</c> property when reading or extracting a zip archive. | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// If you set this to something other than EncryptionAlgorithm.None, you | |
| /// will also need to set the <see cref="Password"/>. | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// As with some other properties on the <c>ZipFile</c> class, like <see | |
| /// cref="Password"/> and <see cref="CompressionLevel"/>, setting this | |
| /// property on a <c>ZipFile</c> instance will cause the specified | |
| /// <c>EncryptionAlgorithm</c> to be used on all <see cref="ZipEntry"/> items | |
| /// that are subsequently added to the <c>ZipFile</c> instance. In other | |
| /// words, if you set this property after you have added items to the | |
| /// <c>ZipFile</c>, but before you have called <c>Save()</c>, those items will | |
| /// not be encrypted or protected with a password in the resulting zip | |
| /// archive. To get a zip archive with encrypted entries, set this property, | |
| /// along with the <see cref="Password"/> property, before calling | |
| /// <c>AddFile</c>, <c>AddItem</c>, or <c>AddDirectory</c> (etc.) on the | |
| /// <c>ZipFile</c> instance. | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// If you read a <c>ZipFile</c>, you can modify the <c>Encryption</c> on an | |
| /// encrypted entry, only by setting the <c>Encryption</c> property on the | |
| /// <c>ZipEntry</c> itself. Setting the <c>Encryption</c> property on the | |
| /// <c>ZipFile</c>, once it has been created via a call to | |
| /// <c>ZipFile.Read()</c>, does not affect entries that were previously read. | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// For example, suppose you read a <c>ZipFile</c>, and there is an encrypted | |
| /// entry. Setting the <c>Encryption</c> property on that <c>ZipFile</c> and | |
| /// then calling <c>Save()</c> on the <c>ZipFile</c> does not update the | |
| /// <c>Encryption</c> used for the entries in the archive. Neither is an | |
| /// exception thrown. Instead, what happens during the <c>Save()</c> is that | |
| /// all previously existing entries are copied through to the new zip archive, | |
| /// with whatever encryption and password that was used when originally | |
| /// creating the zip archive. Upon re-reading that archive, to extract | |
| /// entries, applications should use the original password or passwords, if | |
| /// any. | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// Suppose an application reads a <c>ZipFile</c>, and there is an encrypted | |
| /// entry. Setting the <c>Encryption</c> property on that <c>ZipFile</c> and | |
| /// then adding new entries (via <c>AddFile()</c>, <c>AddEntry()</c>, etc) | |
| /// and then calling <c>Save()</c> on the <c>ZipFile</c> does not update the | |
| /// <c>Encryption</c> on any of the entries that had previously been in the | |
| /// <c>ZipFile</c>. The <c>Encryption</c> property applies only to the | |
| /// newly-added entries. | |
| /// </para> | |
| /// | |
| /// </remarks> | |
| /// | |
| /// <example> | |
| /// <para> | |
| /// This example creates a zip archive that uses encryption, and then extracts | |
| /// entries from the archive. When creating the zip archive, the ReadMe.txt | |
| /// file is zipped without using a password or encryption. The other files | |
| /// use encryption. | |
| /// </para> | |
| /// | |
| /// <code> | |
| /// // Create a zip archive with AES Encryption. | |
| /// using (ZipFile zip = new ZipFile()) | |
| /// { | |
| /// zip.AddFile("ReadMe.txt"); | |
| /// zip.Encryption= EncryptionAlgorithm.WinZipAes256; | |
| /// zip.Password= "Top.Secret.No.Peeking!"; | |
| /// zip.AddFile("7440-N49th.png"); | |
| /// zip.AddFile("2008-Regional-Sales-Report.pdf"); | |
| /// zip.Save("EncryptedArchive.zip"); | |
| /// } | |
| /// | |
| /// // Extract a zip archive that uses AES Encryption. | |
| /// // You do not need to specify the algorithm during extraction. | |
| /// using (ZipFile zip = ZipFile.Read("EncryptedArchive.zip")) | |
| /// { | |
| /// zip.Password= "Top.Secret.No.Peeking!"; | |
| /// zip.ExtractAll("extractDirectory"); | |
| /// } | |
| /// </code> | |
| /// | |
| /// <code lang="VB"> | |
| /// ' Create a zip that uses Encryption. | |
| /// Using zip As New ZipFile() | |
| /// zip.Encryption= EncryptionAlgorithm.WinZipAes256 | |
| /// zip.Password= "Top.Secret.No.Peeking!" | |
| /// zip.AddFile("ReadMe.txt") | |
| /// zip.AddFile("7440-N49th.png") | |
| /// zip.AddFile("2008-Regional-Sales-Report.pdf") | |
| /// zip.Save("EncryptedArchive.zip") | |
| /// End Using | |
| /// | |
| /// ' Extract a zip archive that uses AES Encryption. | |
| /// ' You do not need to specify the algorithm during extraction. | |
| /// Using (zip as ZipFile = ZipFile.Read("EncryptedArchive.zip")) | |
| /// zip.Password= "Top.Secret.No.Peeking!" | |
| /// zip.ExtractAll("extractDirectory") | |
| /// End Using | |
| /// </code> | |
| /// | |
| /// </example> | |
| /// | |
| /// <seealso cref="Ionic.Zip.ZipFile.Password">ZipFile.Password</seealso> | |
| /// <seealso cref="ZipEntry.Encryption">ZipEntry.Encryption</seealso> | |
| internal EncryptionAlgorithm Encryption | |
| { | |
| get | |
| { | |
| return _Encryption; | |
| } | |
| set | |
| { | |
| if (value == EncryptionAlgorithm.Unsupported) | |
| throw new InvalidOperationException("You may not set Encryption to that value."); | |
| _Encryption = value; | |
| } | |
| } | |
| /// <summary> | |
| /// A callback that allows the application to specify the compression level | |
| /// to use for entries subsequently added to the zip archive. | |
| /// </summary> | |
| /// | |
| /// <remarks> | |
| /// | |
| /// <para> | |
| /// With this callback, the DotNetZip library allows the application to | |
| /// determine whether compression will be used, at the time of the | |
| /// <c>Save</c>. This may be useful if the application wants to favor | |
| /// speed over size, and wants to defer the decision until the time of | |
| /// <c>Save</c>. | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// Typically applications set the <see cref="CompressionLevel"/> property on | |
| /// the <c>ZipFile</c> or on each <c>ZipEntry</c> to determine the level of | |
| /// compression used. This is done at the time the entry is added to the | |
| /// <c>ZipFile</c>. Setting the property to | |
| /// <c>Ionic.Zlib.CompressionLevel.None</c> means no compression will be used. | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// This callback allows the application to defer the decision on the | |
| /// <c>CompressionLevel</c> to use, until the time of the call to | |
| /// <c>ZipFile.Save()</c>. The callback is invoked once per <c>ZipEntry</c>, | |
| /// at the time the data for the entry is being written out as part of a | |
| /// <c>Save()</c> operation. The application can use whatever criteria it | |
| /// likes in determining the level to return. For example, an application may | |
| /// wish that no .mp3 files should be compressed, because they are already | |
| /// compressed and the extra compression is not worth the CPU time incurred, | |
| /// and so can return <c>None</c> for all .mp3 entries. | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// The library determines whether compression will be attempted for an entry | |
| /// this way: If the entry is a zero length file, or a directory, no | |
| /// compression is used. Otherwise, if this callback is set, it is invoked | |
| /// and the <c>CompressionLevel</c> is set to the return value. If this | |
| /// callback has not been set, then the previously set value for | |
| /// <c>CompressionLevel</c> is used. | |
| /// </para> | |
| /// | |
| /// </remarks> | |
| public SetCompressionCallback SetCompression | |
| { | |
| get; | |
| set; | |
| } | |
| /// <summary> | |
| /// The maximum size of an output segment, when saving a split Zip file. | |
| /// </summary> | |
| /// <remarks> | |
| /// <para> | |
| /// Set this to a non-zero value before calling <see cref="Save()"/> or <see | |
| /// cref="Save(String)"/> to specify that the ZipFile should be saved as a | |
| /// split archive, also sometimes called a spanned archive. Some also | |
| /// call them multi-file archives. | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// A split zip archive is saved in a set of discrete filesystem files, | |
| /// rather than in a single file. This is handy when transmitting the | |
| /// archive in email or some other mechanism that has a limit to the size of | |
| /// each file. The first file in a split archive will be named | |
| /// <c>basename.z01</c>, the second will be named <c>basename.z02</c>, and | |
| /// so on. The final file is named <c>basename.zip</c>. According to the zip | |
| /// specification from PKWare, the minimum value is 65536, for a 64k segment | |
| /// size. The maximum number of segments allows in a split archive is 99. | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// The value of this property determines the maximum size of a split | |
| /// segment when writing a split archive. For example, suppose you have a | |
| /// <c>ZipFile</c> that would save to a single file of 200k. If you set the | |
| /// <c>MaxOutputSegmentSize</c> to 65536 before calling <c>Save()</c>, you | |
| /// will get four distinct output files. On the other hand if you set this | |
| /// property to 256k, then you will get a single-file archive for that | |
| /// <c>ZipFile</c>. | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// The size of each split output file will be as large as possible, up to | |
| /// the maximum size set here. The zip specification requires that some data | |
| /// fields in a zip archive may not span a split boundary, and an output | |
| /// segment may be smaller than the maximum if necessary to avoid that | |
| /// problem. Also, obviously the final segment of the archive may be smaller | |
| /// than the maximum segment size. Segments will never be larger than the | |
| /// value set with this property. | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// You can save a split Zip file only when saving to a regular filesystem | |
| /// file. It's not possible to save a split zip file as a self-extracting | |
| /// archive, nor is it possible to save a split zip file to a stream. When | |
| /// saving to a SFX or to a Stream, this property is ignored. | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// About interoperability: Split or spanned zip files produced by DotNetZip | |
| /// can be read by WinZip or PKZip, and vice-versa. Segmented zip files may | |
| /// not be readable by other tools, if those other tools don't support zip | |
| /// spanning or splitting. When in doubt, test. I don't believe Windows | |
| /// Explorer can extract a split archive. | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// This property has no effect when reading a split archive. You can read | |
| /// a split archive in the normal way with DotNetZip. | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// When saving a zip file, if you want a regular zip file rather than a | |
| /// split zip file, don't set this property, or set it to Zero. | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// If you read a split archive, with <see cref="ZipFile.Read(string)"/> and | |
| /// then subsequently call <c>ZipFile.Save()</c>, unless you set this | |
| /// property before calling <c>Save()</c>, you will get a normal, | |
| /// single-file archive. | |
| /// </para> | |
| /// </remarks> | |
| /// | |
| /// <seealso cref="NumberOfSegmentsForMostRecentSave"/> | |
| public Int32 MaxOutputSegmentSize | |
| { | |
| get | |
| { | |
| return _maxOutputSegmentSize; | |
| } | |
| set | |
| { | |
| if (value < 65536 && value != 0) | |
| throw new ZipException("The minimum acceptable segment size is 65536."); | |
| _maxOutputSegmentSize = value; | |
| } | |
| } | |
| /// <summary> | |
| /// Returns the number of segments used in the most recent Save() operation. | |
| /// </summary> | |
| /// <remarks> | |
| /// <para> | |
| /// This is normally zero, unless you have set the <see | |
| /// cref="MaxOutputSegmentSize"/> property. If you have set <see | |
| /// cref="MaxOutputSegmentSize"/>, and then you save a file, after the call to | |
| /// Save() completes, you can read this value to learn the number of segments that | |
| /// were created. | |
| /// </para> | |
| /// <para> | |
| /// If you call Save("Archive.zip"), and it creates 5 segments, then you | |
| /// will have filesystem files named Archive.z01, Archive.z02, Archive.z03, | |
| /// Archive.z04, and Archive.zip, and the value of this property will be 5. | |
| /// </para> | |
| /// </remarks> | |
| /// <seealso cref="MaxOutputSegmentSize"/> | |
| public Int32 NumberOfSegmentsForMostRecentSave | |
| { | |
| get | |
| { | |
| return unchecked((Int32)_numberOfSegmentsForMostRecentSave + 1); | |
| } | |
| } | |
| #if !NETCF | |
| /// <summary> | |
| /// The size threshold for an entry, above which a parallel deflate is used. | |
| /// </summary> | |
| /// | |
| /// <remarks> | |
| /// | |
| /// <para> | |
| /// DotNetZip will use multiple threads to compress any ZipEntry, | |
| /// if the entry is larger than the given size. Zero means "always | |
| /// use parallel deflate", while -1 means "never use parallel | |
| /// deflate". The default value for this property is 512k. Aside | |
| /// from the special values of 0 and 1, the minimum value is 65536. | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// If the entry size cannot be known before compression, as with a | |
| /// read-forward stream, then Parallel deflate will never be | |
| /// performed, unless the value of this property is zero. | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// A parallel deflate operations will speed up the compression of | |
| /// large files, on computers with multiple CPUs or multiple CPU | |
| /// cores. For files above 1mb, on a dual core or dual-cpu (2p) | |
| /// machine, the time required to compress the file can be 70% of the | |
| /// single-threaded deflate. For very large files on 4p machines the | |
| /// compression can be done in 30% of the normal time. The downside | |
| /// is that parallel deflate consumes extra memory during the deflate, | |
| /// and the deflation is not as effective. | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// Parallel deflate tends to yield slightly less compression when | |
| /// compared to as single-threaded deflate; this is because the original | |
| /// data stream is split into multiple independent buffers, each of which | |
| /// is compressed in parallel. But because they are treated | |
| /// independently, there is no opportunity to share compression | |
| /// dictionaries. For that reason, a deflated stream may be slightly | |
| /// larger when compressed using parallel deflate, as compared to a | |
| /// traditional single-threaded deflate. Sometimes the increase over the | |
| /// normal deflate is as much as 5% of the total compressed size. For | |
| /// larger files it can be as small as 0.1%. | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// Multi-threaded compression does not give as much an advantage when | |
| /// using Encryption. This is primarily because encryption tends to slow | |
| /// down the entire pipeline. Also, multi-threaded compression gives less | |
| /// of an advantage when using lower compression levels, for example <see | |
| /// cref="Ionic.Zlib.CompressionLevel.BestSpeed"/>. You may have to | |
| /// perform some tests to determine the best approach for your situation. | |
| /// </para> | |
| /// | |
| /// </remarks> | |
| /// | |
| /// <seealso cref="ParallelDeflateMaxBufferPairs"/> | |
| /// | |
| public long ParallelDeflateThreshold | |
| { | |
| set | |
| { | |
| if ((value != 0) && (value != -1) && (value < 64 * 1024)) | |
| throw new ArgumentOutOfRangeException("ParallelDeflateThreshold should be -1, 0, or > 65536"); | |
| _ParallelDeflateThreshold = value; | |
| } | |
| get | |
| { | |
| return _ParallelDeflateThreshold; | |
| } | |
| } | |
| /// <summary> | |
| /// The maximum number of buffer pairs to use when performing | |
| /// parallel compression. | |
| /// </summary> | |
| /// | |
| /// <remarks> | |
| /// <para> | |
| /// This property sets an upper limit on the number of memory | |
| /// buffer pairs to create when performing parallel | |
| /// compression. The implementation of the parallel | |
| /// compression stream allocates multiple buffers to | |
| /// facilitate parallel compression. As each buffer fills up, | |
| /// the stream uses <see | |
| /// cref="System.Threading.ThreadPool.QueueUserWorkItem(System.Threading.WaitCallback)"> | |
| /// ThreadPool.QueueUserWorkItem()</see> to compress those | |
| /// buffers in a background threadpool thread. After a buffer | |
| /// is compressed, it is re-ordered and written to the output | |
| /// stream. | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// A higher number of buffer pairs enables a higher degree of | |
| /// parallelism, which tends to increase the speed of compression on | |
| /// multi-cpu computers. On the other hand, a higher number of buffer | |
| /// pairs also implies a larger memory consumption, more active worker | |
| /// threads, and a higher cpu utilization for any compression. This | |
| /// property enables the application to limit its memory consumption and | |
| /// CPU utilization behavior depending on requirements. | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// For each compression "task" that occurs in parallel, there are 2 | |
| /// buffers allocated: one for input and one for output. This property | |
| /// sets a limit for the number of pairs. The total amount of storage | |
| /// space allocated for buffering will then be (N*S*2), where N is the | |
| /// number of buffer pairs, S is the size of each buffer (<see | |
| /// cref="BufferSize"/>). By default, DotNetZip allocates 4 buffer | |
| /// pairs per CPU core, so if your machine has 4 cores, and you retain | |
| /// the default buffer size of 128k, then the | |
| /// ParallelDeflateOutputStream will use 4 * 4 * 2 * 128kb of buffer | |
| /// memory in total, or 4mb, in blocks of 128kb. If you then set this | |
| /// property to 8, then the number will be 8 * 2 * 128kb of buffer | |
| /// memory, or 2mb. | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// CPU utilization will also go up with additional buffers, because a | |
| /// larger number of buffer pairs allows a larger number of background | |
| /// threads to compress in parallel. If you find that parallel | |
| /// compression is consuming too much memory or CPU, you can adjust this | |
| /// value downward. | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// The default value is 16. Different values may deliver better or | |
| /// worse results, depending on your priorities and the dynamic | |
| /// performance characteristics of your storage and compute resources. | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// This property is not the number of buffer pairs to use; it is an | |
| /// upper limit. An illustration: Suppose you have an application that | |
| /// uses the default value of this property (which is 16), and it runs | |
| /// on a machine with 2 CPU cores. In that case, DotNetZip will allocate | |
| /// 4 buffer pairs per CPU core, for a total of 8 pairs. The upper | |
| /// limit specified by this property has no effect. | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// The application can set this value at any time | |
| /// before calling <c>ZipFile.Save()</c>. | |
| /// </para> | |
| /// </remarks> | |
| /// | |
| /// <seealso cref="ParallelDeflateThreshold"/> | |
| /// | |
| public int ParallelDeflateMaxBufferPairs | |
| { | |
| get | |
| { | |
| return _maxBufferPairs; | |
| } | |
| set | |
| { | |
| if (value < 4) | |
| throw new ArgumentOutOfRangeException("ParallelDeflateMaxBufferPairs", | |
| "Value must be 4 or greater."); | |
| _maxBufferPairs = value; | |
| } | |
| } | |
| #endif | |
| /// <summary>Provides a string representation of the instance.</summary> | |
| /// <returns>a string representation of the instance.</returns> | |
| public override String ToString() | |
| { | |
| return String.Format("ZipFile::{0}", Name); | |
| } | |
| /// <summary> | |
| /// Returns the version number on the DotNetZip assembly. | |
| /// </summary> | |
| /// | |
| /// <remarks> | |
| /// <para> | |
| /// This property is exposed as a convenience. Callers could also get the | |
| /// version value by retrieving GetName().Version on the | |
| /// System.Reflection.Assembly object pointing to the DotNetZip | |
| /// assembly. But sometimes it is not clear which assembly is being loaded. | |
| /// This property makes it clear. | |
| /// </para> | |
| /// <para> | |
| /// This static property is primarily useful for diagnostic purposes. | |
| /// </para> | |
| /// </remarks> | |
| public static System.Version LibraryVersion | |
| { | |
| get | |
| { | |
| return System.Reflection.Assembly.GetExecutingAssembly().GetName().Version; | |
| } | |
| } | |
| internal void NotifyEntryChanged() | |
| { | |
| _contentsChanged = true; | |
| } | |
| internal Stream StreamForDiskNumber(uint diskNumber) | |
| { | |
| if (diskNumber + 1 == this._diskNumberWithCd || | |
| (diskNumber == 0 && this._diskNumberWithCd == 0)) | |
| { | |
| //return (this.ReadStream as FileStream); | |
| return this.ReadStream; | |
| } | |
| return ZipSegmentedStream.ForReading(this._readName ?? this._name, | |
| diskNumber, _diskNumberWithCd); | |
| } | |
| // called by ZipEntry in ZipEntry.Extract(), when there is no stream set for the | |
| // ZipEntry. | |
| internal void Reset(bool whileSaving) | |
| { | |
| if (_JustSaved) | |
| { | |
| // read in the just-saved zip archive | |
| using (ZipFile x = new ZipFile()) | |
| { | |
| // workitem 10735 | |
| x._readName = x._name = whileSaving | |
| ? (this._readName ?? this._name) | |
| : this._name; | |
| x.AlternateEncoding = this.AlternateEncoding; | |
| x.AlternateEncodingUsage = this.AlternateEncodingUsage; | |
| ReadIntoInstance(x); | |
| // copy the contents of the entries. | |
| // cannot just replace the entries - the app may be holding them | |
| foreach (ZipEntry e1 in x) | |
| { | |
| foreach (ZipEntry e2 in this) | |
| { | |
| if (e1.FileName == e2.FileName) | |
| { | |
| e2.CopyMetaData(e1); | |
| break; | |
| } | |
| } | |
| } | |
| } | |
| _JustSaved = false; | |
| } | |
| } | |
| #endregion | |
| #region Constructors | |
| /// <summary> | |
| /// Creates a new <c>ZipFile</c> instance, using the specified filename. | |
| /// </summary> | |
| /// | |
| /// <remarks> | |
| /// <para> | |
| /// Applications can use this constructor to create a new ZipFile for writing, | |
| /// or to slurp in an existing zip archive for read and update purposes. | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// To create a new zip archive, an application can call this constructor, | |
| /// passing the name of a file that does not exist. The name may be a fully | |
| /// qualified path. Then the application can add directories or files to the | |
| /// <c>ZipFile</c> via <c>AddDirectory()</c>, <c>AddFile()</c>, <c>AddItem()</c> | |
| /// and then write the zip archive to the disk by calling <c>Save()</c>. The | |
| /// zip file is not actually opened and written to the disk until the | |
| /// application calls <c>ZipFile.Save()</c>. At that point the new zip file | |
| /// with the given name is created. | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// If you won't know the name of the <c>Zipfile</c> until the time you call | |
| /// <c>ZipFile.Save()</c>, or if you plan to save to a stream (which has no | |
| /// name), then you should use the no-argument constructor. | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// The application can also call this constructor to read an existing zip | |
| /// archive. passing the name of a valid zip file that does exist. But, it's | |
| /// better form to use the static <see cref="ZipFile.Read(String)"/> method, | |
| /// passing the name of the zip file, because using <c>ZipFile.Read()</c> in | |
| /// your code communicates very clearly what you are doing. In either case, | |
| /// the file is then read into the <c>ZipFile</c> instance. The app can then | |
| /// enumerate the entries or can modify the zip file, for example adding | |
| /// entries, removing entries, changing comments, and so on. | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// One advantage to this parameterized constructor: it allows applications to | |
| /// use the same code to add items to a zip archive, regardless of whether the | |
| /// zip file exists. | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// Instances of the <c>ZipFile</c> class are not multi-thread safe. You may | |
| /// not party on a single instance with multiple threads. You may have | |
| /// multiple threads that each use a distinct <c>ZipFile</c> instance, or you | |
| /// can synchronize multi-thread access to a single instance. | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// By the way, since DotNetZip is so easy to use, don't you think <see | |
| /// href="http://cheeso.members.winisp.net/DotNetZipDonate.aspx">you should | |
| /// donate $5 or $10</see>? | |
| /// </para> | |
| /// | |
| /// </remarks> | |
| /// | |
| /// <exception cref="Ionic.Zip.ZipException"> | |
| /// Thrown if name refers to an existing file that is not a valid zip file. | |
| /// </exception> | |
| /// | |
| /// <example> | |
| /// This example shows how to create a zipfile, and add a few files into it. | |
| /// <code> | |
| /// String ZipFileToCreate = "archive1.zip"; | |
| /// String DirectoryToZip = "c:\\reports"; | |
| /// using (ZipFile zip = new ZipFile()) | |
| /// { | |
| /// // Store all files found in the top level directory, into the zip archive. | |
| /// String[] filenames = System.IO.Directory.GetFiles(DirectoryToZip); | |
| /// zip.AddFiles(filenames, "files"); | |
| /// zip.Save(ZipFileToCreate); | |
| /// } | |
| /// </code> | |
| /// | |
| /// <code lang="VB"> | |
| /// Dim ZipFileToCreate As String = "archive1.zip" | |
| /// Dim DirectoryToZip As String = "c:\reports" | |
| /// Using zip As ZipFile = New ZipFile() | |
| /// Dim filenames As String() = System.IO.Directory.GetFiles(DirectoryToZip) | |
| /// zip.AddFiles(filenames, "files") | |
| /// zip.Save(ZipFileToCreate) | |
| /// End Using | |
| /// </code> | |
| /// </example> | |
| /// | |
| /// <param name="fileName">The filename to use for the new zip archive.</param> | |
| /// | |
| public ZipFile(string fileName) | |
| { | |
| try | |
| { | |
| _InitInstance(fileName, null); | |
| } | |
| catch (Exception e1) | |
| { | |
| throw new ZipException(String.Format("Could not read {0} as a zip file", fileName), e1); | |
| } | |
| } | |
| /// <summary> | |
| /// Creates a new <c>ZipFile</c> instance, using the specified name for the | |
| /// filename, and the specified Encoding. | |
| /// </summary> | |
| /// | |
| /// <remarks> | |
| /// <para> | |
| /// See the documentation on the <see cref="ZipFile(String)">ZipFile | |
| /// constructor that accepts a single string argument</see> for basic | |
| /// information on all the <c>ZipFile</c> constructors. | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// The Encoding is used as the default alternate encoding for entries with | |
| /// filenames or comments that cannot be encoded with the IBM437 code page. | |
| /// This is equivalent to setting the <see | |
| /// cref="ProvisionalAlternateEncoding"/> property on the <c>ZipFile</c> | |
| /// instance after construction. | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// Instances of the <c>ZipFile</c> class are not multi-thread safe. You may | |
| /// not party on a single instance with multiple threads. You may have | |
| /// multiple threads that each use a distinct <c>ZipFile</c> instance, or you | |
| /// can synchronize multi-thread access to a single instance. | |
| /// </para> | |
| /// | |
| /// </remarks> | |
| /// | |
| /// <exception cref="Ionic.Zip.ZipException"> | |
| /// Thrown if name refers to an existing file that is not a valid zip file. | |
| /// </exception> | |
| /// | |
| /// <param name="fileName">The filename to use for the new zip archive.</param> | |
| /// <param name="encoding">The Encoding is used as the default alternate | |
| /// encoding for entries with filenames or comments that cannot be encoded | |
| /// with the IBM437 code page. </param> | |
| public ZipFile(string fileName, System.Text.Encoding encoding) | |
| { | |
| try | |
| { | |
| AlternateEncoding = encoding; | |
| AlternateEncodingUsage = ZipOption.Always; | |
| _InitInstance(fileName, null); | |
| } | |
| catch (Exception e1) | |
| { | |
| throw new ZipException(String.Format("{0} is not a valid zip file", fileName), e1); | |
| } | |
| } | |
| /// <summary> | |
| /// Create a zip file, without specifying a target filename or stream to save to. | |
| /// </summary> | |
| /// | |
| /// <remarks> | |
| /// <para> | |
| /// See the documentation on the <see cref="ZipFile(String)">ZipFile | |
| /// constructor that accepts a single string argument</see> for basic | |
| /// information on all the <c>ZipFile</c> constructors. | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// After instantiating with this constructor and adding entries to the | |
| /// archive, the application should call <see cref="ZipFile.Save(String)"/> or | |
| /// <see cref="ZipFile.Save(System.IO.Stream)"/> to save to a file or a | |
| /// stream, respectively. The application can also set the <see cref="Name"/> | |
| /// property and then call the no-argument <see cref="Save()"/> method. (This | |
| /// is the preferred approach for applications that use the library through | |
| /// COM interop.) If you call the no-argument <see cref="Save()"/> method | |
| /// without having set the <c>Name</c> of the <c>ZipFile</c>, either through | |
| /// the parameterized constructor or through the explicit property , the | |
| /// Save() will throw, because there is no place to save the file. </para> | |
| /// | |
| /// <para> | |
| /// Instances of the <c>ZipFile</c> class are not multi-thread safe. You may | |
| /// have multiple threads that each use a distinct <c>ZipFile</c> instance, or | |
| /// you can synchronize multi-thread access to a single instance. </para> | |
| /// | |
| /// </remarks> | |
| /// | |
| /// <example> | |
| /// This example creates a Zip archive called Backup.zip, containing all the files | |
| /// in the directory DirectoryToZip. Files within subdirectories are not zipped up. | |
| /// <code> | |
| /// using (ZipFile zip = new ZipFile()) | |
| /// { | |
| /// // Store all files found in the top level directory, into the zip archive. | |
| /// // note: this code does not recurse subdirectories! | |
| /// String[] filenames = System.IO.Directory.GetFiles(DirectoryToZip); | |
| /// zip.AddFiles(filenames, "files"); | |
| /// zip.Save("Backup.zip"); | |
| /// } | |
| /// </code> | |
| /// | |
| /// <code lang="VB"> | |
| /// Using zip As New ZipFile | |
| /// ' Store all files found in the top level directory, into the zip archive. | |
| /// ' note: this code does not recurse subdirectories! | |
| /// Dim filenames As String() = System.IO.Directory.GetFiles(DirectoryToZip) | |
| /// zip.AddFiles(filenames, "files") | |
| /// zip.Save("Backup.zip") | |
| /// End Using | |
| /// </code> | |
| /// </example> | |
| public ZipFile() | |
| { | |
| _InitInstance(null, null); | |
| } | |
| /// <summary> | |
| /// Create a zip file, specifying a text Encoding, but without specifying a | |
| /// target filename or stream to save to. | |
| /// </summary> | |
| /// | |
| /// <remarks> | |
| /// <para> | |
| /// See the documentation on the <see cref="ZipFile(String)">ZipFile | |
| /// constructor that accepts a single string argument</see> for basic | |
| /// information on all the <c>ZipFile</c> constructors. | |
| /// </para> | |
| /// | |
| /// </remarks> | |
| /// | |
| /// <param name="encoding"> | |
| /// The Encoding is used as the default alternate encoding for entries with | |
| /// filenames or comments that cannot be encoded with the IBM437 code page. | |
| /// </param> | |
| public ZipFile(System.Text.Encoding encoding) | |
| { | |
| AlternateEncoding = encoding; | |
| AlternateEncodingUsage = ZipOption.Always; | |
| _InitInstance(null, null); | |
| } | |
| /// <summary> | |
| /// Creates a new <c>ZipFile</c> instance, using the specified name for the | |
| /// filename, and the specified status message writer. | |
| /// </summary> | |
| /// | |
| /// <remarks> | |
| /// <para> | |
| /// See the documentation on the <see cref="ZipFile(String)">ZipFile | |
| /// constructor that accepts a single string argument</see> for basic | |
| /// information on all the <c>ZipFile</c> constructors. | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// This version of the constructor allows the caller to pass in a TextWriter, | |
| /// to which verbose messages will be written during extraction or creation of | |
| /// the zip archive. A console application may wish to pass | |
| /// System.Console.Out to get messages on the Console. A graphical or headless | |
| /// application may wish to capture the messages in a different | |
| /// <c>TextWriter</c>, for example, a <c>StringWriter</c>, and then display | |
| /// the messages in a TextBox, or generate an audit log of ZipFile operations. | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// To encrypt the data for the files added to the <c>ZipFile</c> instance, | |
| /// set the Password property after creating the <c>ZipFile</c> instance. | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// Instances of the <c>ZipFile</c> class are not multi-thread safe. You may | |
| /// not party on a single instance with multiple threads. You may have | |
| /// multiple threads that each use a distinct <c>ZipFile</c> instance, or you | |
| /// can synchronize multi-thread access to a single instance. | |
| /// </para> | |
| /// | |
| /// </remarks> | |
| /// | |
| /// <exception cref="Ionic.Zip.ZipException"> | |
| /// Thrown if name refers to an existing file that is not a valid zip file. | |
| /// </exception> | |
| /// | |
| /// <example> | |
| /// <code> | |
| /// using (ZipFile zip = new ZipFile("Backup.zip", Console.Out)) | |
| /// { | |
| /// // Store all files found in the top level directory, into the zip archive. | |
| /// // note: this code does not recurse subdirectories! | |
| /// // Status messages will be written to Console.Out | |
| /// String[] filenames = System.IO.Directory.GetFiles(DirectoryToZip); | |
| /// zip.AddFiles(filenames); | |
| /// zip.Save(); | |
| /// } | |
| /// </code> | |
| /// | |
| /// <code lang="VB"> | |
| /// Using zip As New ZipFile("Backup.zip", Console.Out) | |
| /// ' Store all files found in the top level directory, into the zip archive. | |
| /// ' note: this code does not recurse subdirectories! | |
| /// ' Status messages will be written to Console.Out | |
| /// Dim filenames As String() = System.IO.Directory.GetFiles(DirectoryToZip) | |
| /// zip.AddFiles(filenames) | |
| /// zip.Save() | |
| /// End Using | |
| /// </code> | |
| /// </example> | |
| /// | |
| /// <param name="fileName">The filename to use for the new zip archive.</param> | |
| /// <param name="statusMessageWriter">A TextWriter to use for writing | |
| /// verbose status messages.</param> | |
| public ZipFile(string fileName, TextWriter statusMessageWriter) | |
| { | |
| try | |
| { | |
| _InitInstance(fileName, statusMessageWriter); | |
| } | |
| catch (Exception e1) | |
| { | |
| throw new ZipException(String.Format("{0} is not a valid zip file", fileName), e1); | |
| } | |
| } | |
| /// <summary> | |
| /// Creates a new <c>ZipFile</c> instance, using the specified name for the | |
| /// filename, the specified status message writer, and the specified Encoding. | |
| /// </summary> | |
| /// | |
| /// <remarks> | |
| /// <para> | |
| /// This constructor works like the <see cref="ZipFile(String)">ZipFile | |
| /// constructor that accepts a single string argument.</see> See that | |
| /// reference for detail on what this constructor does. | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// This version of the constructor allows the caller to pass in a | |
| /// <c>TextWriter</c>, and an Encoding. The <c>TextWriter</c> will collect | |
| /// verbose messages that are generated by the library during extraction or | |
| /// creation of the zip archive. A console application may wish to pass | |
| /// <c>System.Console.Out</c> to get messages on the Console. A graphical or | |
| /// headless application may wish to capture the messages in a different | |
| /// <c>TextWriter</c>, for example, a <c>StringWriter</c>, and then display | |
| /// the messages in a <c>TextBox</c>, or generate an audit log of | |
| /// <c>ZipFile</c> operations. | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// The <c>Encoding</c> is used as the default alternate encoding for entries | |
| /// with filenames or comments that cannot be encoded with the IBM437 code | |
| /// page. This is a equivalent to setting the <see | |
| /// cref="ProvisionalAlternateEncoding"/> property on the <c>ZipFile</c> | |
| /// instance after construction. | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// To encrypt the data for the files added to the <c>ZipFile</c> instance, | |
| /// set the <c>Password</c> property after creating the <c>ZipFile</c> | |
| /// instance. | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// Instances of the <c>ZipFile</c> class are not multi-thread safe. You may | |
| /// not party on a single instance with multiple threads. You may have | |
| /// multiple threads that each use a distinct <c>ZipFile</c> instance, or you | |
| /// can synchronize multi-thread access to a single instance. | |
| /// </para> | |
| /// | |
| /// </remarks> | |
| /// | |
| /// <exception cref="Ionic.Zip.ZipException"> | |
| /// Thrown if <c>fileName</c> refers to an existing file that is not a valid zip file. | |
| /// </exception> | |
| /// | |
| /// <param name="fileName">The filename to use for the new zip archive.</param> | |
| /// <param name="statusMessageWriter">A TextWriter to use for writing verbose | |
| /// status messages.</param> | |
| /// <param name="encoding"> | |
| /// The Encoding is used as the default alternate encoding for entries with | |
| /// filenames or comments that cannot be encoded with the IBM437 code page. | |
| /// </param> | |
| public ZipFile(string fileName, TextWriter statusMessageWriter, | |
| System.Text.Encoding encoding) | |
| { | |
| try | |
| { | |
| AlternateEncoding = encoding; | |
| AlternateEncodingUsage = ZipOption.Always; | |
| _InitInstance(fileName, statusMessageWriter); | |
| } | |
| catch (Exception e1) | |
| { | |
| throw new ZipException(String.Format("{0} is not a valid zip file", fileName), e1); | |
| } | |
| } | |
| /// <summary> | |
| /// Initialize a <c>ZipFile</c> instance by reading in a zip file. | |
| /// </summary> | |
| /// | |
| /// <remarks> | |
| /// | |
| /// <para> | |
| /// This method is primarily useful from COM Automation environments, when | |
| /// reading or extracting zip files. In COM, it is not possible to invoke | |
| /// parameterized constructors for a class. A COM Automation application can | |
| /// update a zip file by using the <see cref="ZipFile()">default (no argument) | |
| /// constructor</see>, then calling <c>Initialize()</c> to read the contents | |
| /// of an on-disk zip archive into the <c>ZipFile</c> instance. | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// .NET applications are encouraged to use the <c>ZipFile.Read()</c> methods | |
| /// for better clarity. | |
| /// </para> | |
| /// | |
| /// </remarks> | |
| /// <param name="fileName">the name of the existing zip file to read in.</param> | |
| public void Initialize(string fileName) | |
| { | |
| try | |
| { | |
| _InitInstance(fileName, null); | |
| } | |
| catch (Exception e1) | |
| { | |
| throw new ZipException(String.Format("{0} is not a valid zip file", fileName), e1); | |
| } | |
| } | |
| private void _initEntriesDictionary() | |
| { | |
| // workitem 9868 | |
| StringComparer sc = (CaseSensitiveRetrieval) ? StringComparer.Ordinal : StringComparer.OrdinalIgnoreCase; | |
| _entries = (_entries == null) | |
| ? new Dictionary<String, ZipEntry>(sc) | |
| : new Dictionary<String, ZipEntry>(_entries, sc); | |
| } | |
| private void _InitInstance(string zipFileName, TextWriter statusMessageWriter) | |
| { | |
| // create a new zipfile | |
| _name = zipFileName; | |
| _StatusMessageTextWriter = statusMessageWriter; | |
| _contentsChanged = true; | |
| AddDirectoryWillTraverseReparsePoints = true; // workitem 8617 | |
| CompressionLevel = OfficeOpenXml.Packaging.Ionic.Zlib.CompressionLevel.Default; | |
| #if !NETCF | |
| ParallelDeflateThreshold = 512 * 1024; | |
| #endif | |
| // workitem 7685, 9868 | |
| _initEntriesDictionary(); | |
| if (File.Exists(_name)) | |
| { | |
| if (FullScan) | |
| ReadIntoInstance_Orig(this); | |
| else | |
| ReadIntoInstance(this); | |
| this._fileAlreadyExists = true; | |
| } | |
| return; | |
| } | |
| #endregion | |
| #region Indexers and Collections | |
| private List<ZipEntry> ZipEntriesAsList | |
| { | |
| get | |
| { | |
| if (_zipEntriesAsList == null) | |
| _zipEntriesAsList = new List<ZipEntry>(_entries.Values); | |
| return _zipEntriesAsList; | |
| } | |
| } | |
| /// <summary> | |
| /// This is an integer indexer into the Zip archive. | |
| /// </summary> | |
| /// | |
| /// <remarks> | |
| /// <para> | |
| /// This property is read-only. | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// Internally, the <c>ZipEntry</c> instances that belong to the | |
| /// <c>ZipFile</c> are stored in a Dictionary. When you use this | |
| /// indexer the first time, it creates a read-only | |
| /// <c>List<ZipEntry></c> from the Dictionary.Values Collection. | |
| /// If at any time you modify the set of entries in the <c>ZipFile</c>, | |
| /// either by adding an entry, removing an entry, or renaming an | |
| /// entry, a new List will be created, and the numeric indexes for the | |
| /// remaining entries may be different. | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// This means you cannot rename any ZipEntry from | |
| /// inside an enumeration of the zip file. | |
| /// </para> | |
| /// | |
| /// <param name="ix"> | |
| /// The index value. | |
| /// </param> | |
| /// | |
| /// </remarks> | |
| /// | |
| /// <returns> | |
| /// The <c>ZipEntry</c> within the Zip archive at the specified index. If the | |
| /// entry does not exist in the archive, this indexer throws. | |
| /// </returns> | |
| /// | |
| public ZipEntry this[int ix] | |
| { | |
| // workitem 6402 | |
| get | |
| { | |
| return ZipEntriesAsList[ix]; | |
| } | |
| } | |
| /// <summary> | |
| /// This is a name-based indexer into the Zip archive. | |
| /// </summary> | |
| /// | |
| /// <remarks> | |
| /// <para> | |
| /// This property is read-only. | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// The <see cref="CaseSensitiveRetrieval"/> property on the <c>ZipFile</c> | |
| /// determines whether retrieval via this indexer is done via case-sensitive | |
| /// comparisons. By default, retrieval is not case sensitive. This makes | |
| /// sense on Windows, in which filesystems are not case sensitive. | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// Regardless of case-sensitivity, it is not always the case that | |
| /// <c>this[value].FileName == value</c>. In other words, the <c>FileName</c> | |
| /// property of the <c>ZipEntry</c> retrieved with this indexer, may or may | |
| /// not be equal to the index value. | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// This is because DotNetZip performs a normalization of filenames passed to | |
| /// this indexer, before attempting to retrieve the item. That normalization | |
| /// includes: removal of a volume letter and colon, swapping backward slashes | |
| /// for forward slashes. So, <c>zip["dir1\\entry1.txt"].FileName == | |
| /// "dir1/entry.txt"</c>. | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// Directory entries in the zip file may be retrieved via this indexer only | |
| /// with names that have a trailing slash. DotNetZip automatically appends a | |
| /// trailing slash to the names of any directory entries added to a zip. | |
| /// </para> | |
| /// | |
| /// </remarks> | |
| /// | |
| /// <example> | |
| /// This example extracts only the entries in a zip file that are .txt files. | |
| /// <code> | |
| /// using (ZipFile zip = ZipFile.Read("PackedDocuments.zip")) | |
| /// { | |
| /// foreach (string s1 in zip.EntryFilenames) | |
| /// { | |
| /// if (s1.EndsWith(".txt")) | |
| /// zip[s1].Extract("textfiles"); | |
| /// } | |
| /// } | |
| /// </code> | |
| /// <code lang="VB"> | |
| /// Using zip As ZipFile = ZipFile.Read("PackedDocuments.zip") | |
| /// Dim s1 As String | |
| /// For Each s1 In zip.EntryFilenames | |
| /// If s1.EndsWith(".txt") Then | |
| /// zip(s1).Extract("textfiles") | |
| /// End If | |
| /// Next | |
| /// End Using | |
| /// </code> | |
| /// </example> | |
| /// <seealso cref="Ionic.Zip.ZipFile.RemoveEntry(string)"/> | |
| /// | |
| /// <exception cref="System.ArgumentException"> | |
| /// Thrown if the caller attempts to assign a non-null value to the indexer. | |
| /// </exception> | |
| /// | |
| /// <param name="fileName"> | |
| /// The name of the file, including any directory path, to retrieve from the | |
| /// zip. The filename match is not case-sensitive by default; you can use the | |
| /// <see cref="CaseSensitiveRetrieval"/> property to change this behavior. The | |
| /// pathname can use forward-slashes or backward slashes. | |
| /// </param> | |
| /// | |
| /// <returns> | |
| /// The <c>ZipEntry</c> within the Zip archive, given by the specified | |
| /// filename. If the named entry does not exist in the archive, this indexer | |
| /// returns <c>null</c> (<c>Nothing</c> in VB). | |
| /// </returns> | |
| /// | |
| public ZipEntry this[String fileName] | |
| { | |
| get | |
| { | |
| var key = SharedUtilities.NormalizePathForUseInZipFile(fileName); | |
| if (_entries.ContainsKey(key)) | |
| return _entries[key]; | |
| // workitem 11056 | |
| key = key.Replace("/", "\\"); | |
| if (_entries.ContainsKey(key)) | |
| return _entries[key]; | |
| return null; | |
| #if MESSY | |
| foreach (ZipEntry e in _entries.Values) | |
| { | |
| if (this.CaseSensitiveRetrieval) | |
| { | |
| // check for the file match with a case-sensitive comparison. | |
| if (e.FileName == fileName) return e; | |
| // also check for equivalence | |
| if (fileName.Replace("\\", "/") == e.FileName) return e; | |
| if (e.FileName.Replace("\\", "/") == fileName) return e; | |
| // check for a difference only in trailing slash | |
| if (e.FileName.EndsWith("/")) | |
| { | |
| var fileNameNoSlash = e.FileName.Trim("/".ToCharArray()); | |
| if (fileNameNoSlash == fileName) return e; | |
| // also check for equivalence | |
| if (fileName.Replace("\\", "/") == fileNameNoSlash) return e; | |
| if (fileNameNoSlash.Replace("\\", "/") == fileName) return e; | |
| } | |
| } | |
| else | |
| { | |
| // check for the file match in a case-insensitive manner. | |
| if (String.Compare(e.FileName, fileName, StringComparison.CurrentCultureIgnoreCase) == 0) return e; | |
| // also check for equivalence | |
| if (String.Compare(fileName.Replace("\\", "/"), e.FileName, StringComparison.CurrentCultureIgnoreCase) == 0) return e; | |
| if (String.Compare(e.FileName.Replace("\\", "/"), fileName, StringComparison.CurrentCultureIgnoreCase) == 0) return e; | |
| // check for a difference only in trailing slash | |
| if (e.FileName.EndsWith("/")) | |
| { | |
| var fileNameNoSlash = e.FileName.Trim("/".ToCharArray()); | |
| if (String.Compare(fileNameNoSlash, fileName, StringComparison.CurrentCultureIgnoreCase) == 0) return e; | |
| // also check for equivalence | |
| if (String.Compare(fileName.Replace("\\", "/"), fileNameNoSlash, StringComparison.CurrentCultureIgnoreCase) == 0) return e; | |
| if (String.Compare(fileNameNoSlash.Replace("\\", "/"), fileName, StringComparison.CurrentCultureIgnoreCase) == 0) return e; | |
| } | |
| } | |
| } | |
| return null; | |
| #endif | |
| } | |
| } | |
| /// <summary> | |
| /// The list of filenames for the entries contained within the zip archive. | |
| /// </summary> | |
| /// | |
| /// <remarks> | |
| /// According to the ZIP specification, the names of the entries use forward | |
| /// slashes in pathnames. If you are scanning through the list, you may have | |
| /// to swap forward slashes for backslashes. | |
| /// </remarks> | |
| /// | |
| /// <seealso cref="Ionic.Zip.ZipFile.this[string]"/> | |
| /// | |
| /// <example> | |
| /// This example shows one way to test if a filename is already contained | |
| /// within a zip archive. | |
| /// <code> | |
| /// String zipFileToRead= "PackedDocuments.zip"; | |
| /// string candidate = "DatedMaterial.xps"; | |
| /// using (ZipFile zip = new ZipFile(zipFileToRead)) | |
| /// { | |
| /// if (zip.EntryFilenames.Contains(candidate)) | |
| /// Console.WriteLine("The file '{0}' exists in the zip archive '{1}'", | |
| /// candidate, | |
| /// zipFileName); | |
| /// else | |
| /// Console.WriteLine("The file, '{0}', does not exist in the zip archive '{1}'", | |
| /// candidate, | |
| /// zipFileName); | |
| /// Console.WriteLine(); | |
| /// } | |
| /// </code> | |
| /// <code lang="VB"> | |
| /// Dim zipFileToRead As String = "PackedDocuments.zip" | |
| /// Dim candidate As String = "DatedMaterial.xps" | |
| /// Using zip As ZipFile.Read(ZipFileToRead) | |
| /// If zip.EntryFilenames.Contains(candidate) Then | |
| /// Console.WriteLine("The file '{0}' exists in the zip archive '{1}'", _ | |
| /// candidate, _ | |
| /// zipFileName) | |
| /// Else | |
| /// Console.WriteLine("The file, '{0}', does not exist in the zip archive '{1}'", _ | |
| /// candidate, _ | |
| /// zipFileName) | |
| /// End If | |
| /// Console.WriteLine | |
| /// End Using | |
| /// </code> | |
| /// </example> | |
| /// | |
| /// <returns> | |
| /// The list of strings for the filenames contained within the Zip archive. | |
| /// </returns> | |
| /// | |
| public System.Collections.Generic.ICollection<String> EntryFileNames | |
| { | |
| get | |
| { | |
| return _entries.Keys; | |
| } | |
| } | |
| /// <summary> | |
| /// Returns the readonly collection of entries in the Zip archive. | |
| /// </summary> | |
| /// | |
| /// <remarks> | |
| /// | |
| /// <para> | |
| /// If there are no entries in the current <c>ZipFile</c>, the value returned is a | |
| /// non-null zero-element collection. If there are entries in the zip file, | |
| /// the elements are returned in no particular order. | |
| /// </para> | |
| /// <para> | |
| /// This is the implied enumerator on the <c>ZipFile</c> class. If you use a | |
| /// <c>ZipFile</c> instance in a context that expects an enumerator, you will | |
| /// get this collection. | |
| /// </para> | |
| /// </remarks> | |
| /// <seealso cref="EntriesSorted"/> | |
| public System.Collections.Generic.ICollection<ZipEntry> Entries | |
| { | |
| get | |
| { | |
| return _entries.Values; | |
| } | |
| } | |
| /// <summary> | |
| /// Returns a readonly collection of entries in the Zip archive, sorted by FileName. | |
| /// </summary> | |
| /// | |
| /// <remarks> | |
| /// If there are no entries in the current <c>ZipFile</c>, the value returned | |
| /// is a non-null zero-element collection. If there are entries in the zip | |
| /// file, the elements are returned sorted by the name of the entry. | |
| /// </remarks> | |
| /// | |
| /// <example> | |
| /// | |
| /// This example fills a Windows Forms ListView with the entries in a zip file. | |
| /// | |
| /// <code lang="C#"> | |
| /// using (ZipFile zip = ZipFile.Read(zipFile)) | |
| /// { | |
| /// foreach (ZipEntry entry in zip.EntriesSorted) | |
| /// { | |
| /// ListViewItem item = new ListViewItem(n.ToString()); | |
| /// n++; | |
| /// string[] subitems = new string[] { | |
| /// entry.FileName.Replace("/","\\"), | |
| /// entry.LastModified.ToString("yyyy-MM-dd HH:mm:ss"), | |
| /// entry.UncompressedSize.ToString(), | |
| /// String.Format("{0,5:F0}%", entry.CompressionRatio), | |
| /// entry.CompressedSize.ToString(), | |
| /// (entry.UsesEncryption) ? "Y" : "N", | |
| /// String.Format("{0:X8}", entry.Crc)}; | |
| /// | |
| /// foreach (String s in subitems) | |
| /// { | |
| /// ListViewItem.ListViewSubItem subitem = new ListViewItem.ListViewSubItem(); | |
| /// subitem.Text = s; | |
| /// item.SubItems.Add(subitem); | |
| /// } | |
| /// | |
| /// this.listView1.Items.Add(item); | |
| /// } | |
| /// } | |
| /// </code> | |
| /// </example> | |
| /// | |
| /// <seealso cref="Entries"/> | |
| public System.Collections.Generic.ICollection<ZipEntry> EntriesSorted | |
| { | |
| get | |
| { | |
| var coll = new System.Collections.Generic.List<ZipEntry>(); | |
| foreach (var e in this.Entries) | |
| { | |
| coll.Add(e); | |
| } | |
| StringComparison sc = (CaseSensitiveRetrieval) ? StringComparison.Ordinal : StringComparison.OrdinalIgnoreCase; | |
| coll.Sort((x, y) => { return String.Compare(x.FileName, y.FileName, sc); }); | |
| return coll.AsReadOnly(); | |
| } | |
| } | |
| /// <summary> | |
| /// Returns the number of entries in the Zip archive. | |
| /// </summary> | |
| public int Count | |
| { | |
| get | |
| { | |
| return _entries.Count; | |
| } | |
| } | |
| /// <summary> | |
| /// Removes the given <c>ZipEntry</c> from the zip archive. | |
| /// </summary> | |
| /// | |
| /// <remarks> | |
| /// <para> | |
| /// After calling <c>RemoveEntry</c>, the application must call <c>Save</c> to | |
| /// make the changes permanent. | |
| /// </para> | |
| /// </remarks> | |
| /// | |
| /// <exception cref="System.ArgumentException"> | |
| /// Thrown if the specified <c>ZipEntry</c> does not exist in the <c>ZipFile</c>. | |
| /// </exception> | |
| /// | |
| /// <example> | |
| /// In this example, all entries in the zip archive dating from before | |
| /// December 31st, 2007, are removed from the archive. This is actually much | |
| /// easier if you use the RemoveSelectedEntries method. But I needed an | |
| /// example for RemoveEntry, so here it is. | |
| /// <code> | |
| /// String ZipFileToRead = "ArchiveToModify.zip"; | |
| /// System.DateTime Threshold = new System.DateTime(2007,12,31); | |
| /// using (ZipFile zip = ZipFile.Read(ZipFileToRead)) | |
| /// { | |
| /// var EntriesToRemove = new System.Collections.Generic.List<ZipEntry>(); | |
| /// foreach (ZipEntry e in zip) | |
| /// { | |
| /// if (e.LastModified < Threshold) | |
| /// { | |
| /// // We cannot remove the entry from the list, within the context of | |
| /// // an enumeration of said list. | |
| /// // So we add the doomed entry to a list to be removed later. | |
| /// EntriesToRemove.Add(e); | |
| /// } | |
| /// } | |
| /// | |
| /// // actually remove the doomed entries. | |
| /// foreach (ZipEntry zombie in EntriesToRemove) | |
| /// zip.RemoveEntry(zombie); | |
| /// | |
| /// zip.Comment= String.Format("This zip archive was updated at {0}.", | |
| /// System.DateTime.Now.ToString("G")); | |
| /// | |
| /// // save with a different name | |
| /// zip.Save("Archive-Updated.zip"); | |
| /// } | |
| /// </code> | |
| /// | |
| /// <code lang="VB"> | |
| /// Dim ZipFileToRead As String = "ArchiveToModify.zip" | |
| /// Dim Threshold As New DateTime(2007, 12, 31) | |
| /// Using zip As ZipFile = ZipFile.Read(ZipFileToRead) | |
| /// Dim EntriesToRemove As New System.Collections.Generic.List(Of ZipEntry) | |
| /// Dim e As ZipEntry | |
| /// For Each e In zip | |
| /// If (e.LastModified < Threshold) Then | |
| /// ' We cannot remove the entry from the list, within the context of | |
| /// ' an enumeration of said list. | |
| /// ' So we add the doomed entry to a list to be removed later. | |
| /// EntriesToRemove.Add(e) | |
| /// End If | |
| /// Next | |
| /// | |
| /// ' actually remove the doomed entries. | |
| /// Dim zombie As ZipEntry | |
| /// For Each zombie In EntriesToRemove | |
| /// zip.RemoveEntry(zombie) | |
| /// Next | |
| /// zip.Comment = String.Format("This zip archive was updated at {0}.", DateTime.Now.ToString("G")) | |
| /// 'save as a different name | |
| /// zip.Save("Archive-Updated.zip") | |
| /// End Using | |
| /// </code> | |
| /// </example> | |
| /// | |
| /// <param name="entry"> | |
| /// The <c>ZipEntry</c> to remove from the zip. | |
| /// </param> | |
| /// | |
| /// <seealso cref="Ionic.Zip.ZipFile.RemoveSelectedEntries(string)"/> | |
| /// | |
| public void RemoveEntry(ZipEntry entry) | |
| { | |
| //if (!_entries.Values.Contains(entry)) | |
| // throw new ArgumentException("The entry you specified does not exist in the zip archive."); | |
| if (entry == null) | |
| throw new ArgumentNullException("entry"); | |
| _entries.Remove(SharedUtilities.NormalizePathForUseInZipFile(entry.FileName)); | |
| _zipEntriesAsList = null; | |
| #if NOTNEEDED | |
| if (_direntries != null) | |
| { | |
| bool FoundAndRemovedDirEntry = false; | |
| foreach (ZipDirEntry de1 in _direntries) | |
| { | |
| if (entry.FileName == de1.FileName) | |
| { | |
| _direntries.Remove(de1); | |
| FoundAndRemovedDirEntry = true; | |
| break; | |
| } | |
| } | |
| if (!FoundAndRemovedDirEntry) | |
| throw new BadStateException("The entry to be removed was not found in the directory."); | |
| } | |
| #endif | |
| _contentsChanged = true; | |
| } | |
| /// <summary> | |
| /// Removes the <c>ZipEntry</c> with the given filename from the zip archive. | |
| /// </summary> | |
| /// | |
| /// <remarks> | |
| /// <para> | |
| /// After calling <c>RemoveEntry</c>, the application must call <c>Save</c> to | |
| /// make the changes permanent. | |
| /// </para> | |
| /// | |
| /// </remarks> | |
| /// | |
| /// <exception cref="System.InvalidOperationException"> | |
| /// Thrown if the <c>ZipFile</c> is not updatable. | |
| /// </exception> | |
| /// | |
| /// <exception cref="System.ArgumentException"> | |
| /// Thrown if a <c>ZipEntry</c> with the specified filename does not exist in | |
| /// the <c>ZipFile</c>. | |
| /// </exception> | |
| /// | |
| /// <example> | |
| /// | |
| /// This example shows one way to remove an entry with a given filename from | |
| /// an existing zip archive. | |
| /// | |
| /// <code> | |
| /// String zipFileToRead= "PackedDocuments.zip"; | |
| /// string candidate = "DatedMaterial.xps"; | |
| /// using (ZipFile zip = ZipFile.Read(zipFileToRead)) | |
| /// { | |
| /// if (zip.EntryFilenames.Contains(candidate)) | |
| /// { | |
| /// zip.RemoveEntry(candidate); | |
| /// zip.Comment= String.Format("The file '{0}' has been removed from this archive.", | |
| /// Candidate); | |
| /// zip.Save(); | |
| /// } | |
| /// } | |
| /// </code> | |
| /// <code lang="VB"> | |
| /// Dim zipFileToRead As String = "PackedDocuments.zip" | |
| /// Dim candidate As String = "DatedMaterial.xps" | |
| /// Using zip As ZipFile = ZipFile.Read(zipFileToRead) | |
| /// If zip.EntryFilenames.Contains(candidate) Then | |
| /// zip.RemoveEntry(candidate) | |
| /// zip.Comment = String.Format("The file '{0}' has been removed from this archive.", Candidate) | |
| /// zip.Save | |
| /// End If | |
| /// End Using | |
| /// </code> | |
| /// </example> | |
| /// | |
| /// <param name="fileName"> | |
| /// The name of the file, including any directory path, to remove from the zip. | |
| /// The filename match is not case-sensitive by default; you can use the | |
| /// <c>CaseSensitiveRetrieval</c> property to change this behavior. The | |
| /// pathname can use forward-slashes or backward slashes. | |
| /// </param> | |
| /// | |
| public void RemoveEntry(String fileName) | |
| { | |
| string modifiedName = ZipEntry.NameInArchive(fileName, null); | |
| ZipEntry e = this[modifiedName]; | |
| if (e == null) | |
| throw new ArgumentException("The entry you specified was not found in the zip archive."); | |
| RemoveEntry(e); | |
| } | |
| #endregion | |
| #region Destructors and Disposers | |
| // /// <summary> | |
| // /// This is the class Destructor, which gets called implicitly when the instance | |
| // /// is destroyed. Because the <c>ZipFile</c> type implements IDisposable, this | |
| // /// method calls Dispose(false). | |
| // /// </summary> | |
| // ~ZipFile() | |
| // { | |
| // // call Dispose with false. Since we're in the | |
| // // destructor call, the managed resources will be | |
| // // disposed of anyways. | |
| // Dispose(false); | |
| // } | |
| /// <summary> | |
| /// Closes the read and write streams associated | |
| /// to the <c>ZipFile</c>, if necessary. | |
| /// </summary> | |
| /// | |
| /// <remarks> | |
| /// The Dispose() method is generally employed implicitly, via a <c>using(..) {..}</c> | |
| /// statement. (<c>Using...End Using</c> in VB) If you do not employ a using | |
| /// statement, insure that your application calls Dispose() explicitly. For | |
| /// example, in a Powershell application, or an application that uses the COM | |
| /// interop interface, you must call Dispose() explicitly. | |
| /// </remarks> | |
| /// | |
| /// <example> | |
| /// This example extracts an entry selected by name, from the Zip file to the | |
| /// Console. | |
| /// <code> | |
| /// using (ZipFile zip = ZipFile.Read(zipfile)) | |
| /// { | |
| /// foreach (ZipEntry e in zip) | |
| /// { | |
| /// if (WantThisEntry(e.FileName)) | |
| /// zip.Extract(e.FileName, Console.OpenStandardOutput()); | |
| /// } | |
| /// } // Dispose() is called implicitly here. | |
| /// </code> | |
| /// | |
| /// <code lang="VB"> | |
| /// Using zip As ZipFile = ZipFile.Read(zipfile) | |
| /// Dim e As ZipEntry | |
| /// For Each e In zip | |
| /// If WantThisEntry(e.FileName) Then | |
| /// zip.Extract(e.FileName, Console.OpenStandardOutput()) | |
| /// End If | |
| /// Next | |
| /// End Using ' Dispose is implicity called here | |
| /// </code> | |
| /// </example> | |
| public void Dispose() | |
| { | |
| // dispose of the managed and unmanaged resources | |
| Dispose(true); | |
| // tell the GC that the Finalize process no longer needs | |
| // to be run for this object. | |
| GC.SuppressFinalize(this); | |
| } | |
| /// <summary> | |
| /// Disposes any managed resources, if the flag is set, then marks the | |
| /// instance disposed. This method is typically not called explicitly from | |
| /// application code. | |
| /// </summary> | |
| /// | |
| /// <remarks> | |
| /// Applications should call <see cref="Dispose()">the no-arg Dispose method</see>. | |
| /// </remarks> | |
| /// | |
| /// <param name="disposeManagedResources"> | |
| /// indicates whether the method should dispose streams or not. | |
| /// </param> | |
| protected virtual void Dispose(bool disposeManagedResources) | |
| { | |
| if (!this._disposed) | |
| { | |
| if (disposeManagedResources) | |
| { | |
| // dispose managed resources | |
| if (_ReadStreamIsOurs) | |
| { | |
| if (_readstream != null) | |
| { | |
| // workitem 7704 | |
| #if NETCF | |
| _readstream.Close(); | |
| #else | |
| _readstream.Dispose(); | |
| #endif | |
| _readstream = null; | |
| } | |
| } | |
| // only dispose the writestream if there is a backing file | |
| if ((_temporaryFileName != null) && (_name != null)) | |
| if (_writestream != null) | |
| { | |
| // workitem 7704 | |
| #if NETCF | |
| _writestream.Close(); | |
| #else | |
| _writestream.Dispose(); | |
| #endif | |
| _writestream = null; | |
| } | |
| #if !NETCF | |
| // workitem 10030 | |
| if (this.ParallelDeflater != null) | |
| { | |
| this.ParallelDeflater.Dispose(); | |
| this.ParallelDeflater = null; | |
| } | |
| #endif | |
| } | |
| this._disposed = true; | |
| } | |
| } | |
| #endregion | |
| #region private properties | |
| internal Stream ReadStream | |
| { | |
| get | |
| { | |
| if (_readstream == null) | |
| { | |
| if (_readName != null || _name !=null) | |
| { | |
| _readstream = File.Open(_readName ?? _name, | |
| FileMode.Open, | |
| FileAccess.Read, | |
| FileShare.Read | FileShare.Write); | |
| _ReadStreamIsOurs = true; | |
| } | |
| } | |
| return _readstream; | |
| } | |
| } | |
| private Stream WriteStream | |
| { | |
| // workitem 9763 | |
| get | |
| { | |
| if (_writestream != null) return _writestream; | |
| if (_name == null) return _writestream; | |
| if (_maxOutputSegmentSize != 0) | |
| { | |
| _writestream = ZipSegmentedStream.ForWriting(this._name, _maxOutputSegmentSize); | |
| return _writestream; | |
| } | |
| SharedUtilities.CreateAndOpenUniqueTempFile(TempFileFolder ?? Path.GetDirectoryName(_name), | |
| out _writestream, | |
| out _temporaryFileName); | |
| return _writestream; | |
| } | |
| set | |
| { | |
| if (value != null) | |
| throw new ZipException("Cannot set the stream to a non-null value."); | |
| _writestream = null; | |
| } | |
| } | |
| #endregion | |
| #region private fields | |
| private TextWriter _StatusMessageTextWriter; | |
| private bool _CaseSensitiveRetrieval; | |
| private Stream _readstream; | |
| private Stream _writestream; | |
| private UInt16 _versionMadeBy; | |
| private UInt16 _versionNeededToExtract; | |
| private UInt32 _diskNumberWithCd; | |
| private Int32 _maxOutputSegmentSize; | |
| private UInt32 _numberOfSegmentsForMostRecentSave; | |
| private ZipErrorAction _zipErrorAction; | |
| private bool _disposed; | |
| //private System.Collections.Generic.List<ZipEntry> _entries; | |
| private System.Collections.Generic.Dictionary<String, ZipEntry> _entries; | |
| private List<ZipEntry> _zipEntriesAsList; | |
| private string _name; | |
| private string _readName; | |
| private string _Comment; | |
| internal string _Password; | |
| private bool _emitNtfsTimes = true; | |
| private bool _emitUnixTimes; | |
| private Ionic.Zlib.CompressionStrategy _Strategy = Ionic.Zlib.CompressionStrategy.Default; | |
| private Ionic.Zip.CompressionMethod _compressionMethod = Ionic.Zip.CompressionMethod.Deflate; | |
| private bool _fileAlreadyExists; | |
| private string _temporaryFileName; | |
| private bool _contentsChanged; | |
| private bool _hasBeenSaved; | |
| private String _TempFileFolder; | |
| private bool _ReadStreamIsOurs = true; | |
| private object LOCK = new object(); | |
| private bool _saveOperationCanceled; | |
| private bool _extractOperationCanceled; | |
| private bool _addOperationCanceled; | |
| private EncryptionAlgorithm _Encryption; | |
| private bool _JustSaved; | |
| private long _locEndOfCDS = -1; | |
| private uint _OffsetOfCentralDirectory; | |
| private Int64 _OffsetOfCentralDirectory64; | |
| private Nullable<bool> _OutputUsesZip64; | |
| internal bool _inExtractAll; | |
| private System.Text.Encoding _alternateEncoding = System.Text.Encoding.GetEncoding("IBM437"); // UTF-8 | |
| private ZipOption _alternateEncodingUsage = ZipOption.Never; | |
| private static System.Text.Encoding _defaultEncoding = System.Text.Encoding.GetEncoding("IBM437"); | |
| private int _BufferSize = BufferSizeDefault; | |
| #if !NETCF | |
| internal Ionic.Zlib.ParallelDeflateOutputStream ParallelDeflater; | |
| private long _ParallelDeflateThreshold; | |
| private int _maxBufferPairs = 16; | |
| #endif | |
| internal Zip64Option _zip64 = Zip64Option.Default; | |
| #pragma warning disable 649 | |
| private bool _SavingSfx; | |
| #pragma warning restore 649 | |
| /// <summary> | |
| /// Default size of the buffer used for IO. | |
| /// </summary> | |
| public static readonly int BufferSizeDefault = 32768; | |
| #endregion | |
| } | |
| /// <summary> | |
| /// Options for using ZIP64 extensions when saving zip archives. | |
| /// </summary> | |
| /// | |
| /// <remarks> | |
| /// | |
| /// <para> | |
| /// Designed many years ago, the <see | |
| /// href="http://www.pkware.com/documents/casestudies/APPNOTE.TXT">original zip | |
| /// specification from PKWARE</see> allowed for 32-bit quantities for the | |
| /// compressed and uncompressed sizes of zip entries, as well as a 32-bit quantity | |
| /// for specifying the length of the zip archive itself, and a maximum of 65535 | |
| /// entries. These limits are now regularly exceeded in many backup and archival | |
| /// scenarios. Recently, PKWare added extensions to the original zip spec, called | |
| /// "ZIP64 extensions", to raise those limitations. This property governs whether | |
| /// DotNetZip will use those extensions when writing zip archives. The use of | |
| /// these extensions is optional and explicit in DotNetZip because, despite the | |
| /// status of ZIP64 as a bona fide standard, many other zip tools and libraries do | |
| /// not support ZIP64, and therefore a zip file with ZIP64 extensions may be | |
| /// unreadable by some of those other tools. | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// Set this property to <see cref="Zip64Option.Always"/> to always use ZIP64 | |
| /// extensions when saving, regardless of whether your zip archive needs it. | |
| /// Suppose you add 5 files, each under 100k, to a ZipFile. If you specify Always | |
| /// for this flag, you will get a ZIP64 archive, though the archive does not need | |
| /// to use ZIP64 because none of the original zip limits had been exceeded. | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// Set this property to <see cref="Zip64Option.Never"/> to tell the DotNetZip | |
| /// library to never use ZIP64 extensions. This is useful for maximum | |
| /// compatibility and interoperability, at the expense of the capability of | |
| /// handling large files or large archives. NB: Windows Explorer in Windows XP | |
| /// and Windows Vista cannot currently extract files from a zip64 archive, so if | |
| /// you want to guarantee that a zip archive produced by this library will work in | |
| /// Windows Explorer, use <c>Never</c>. If you set this property to <see | |
| /// cref="Zip64Option.Never"/>, and your application creates a zip that would | |
| /// exceed one of the Zip limits, the library will throw an exception while saving | |
| /// the zip file. | |
| /// </para> | |
| /// | |
| /// <para> | |
| /// Set this property to <see cref="Zip64Option.AsNecessary"/> to tell the | |
| /// DotNetZip library to use the ZIP64 extensions when required by the | |
| /// entry. After the file is compressed, the original and compressed sizes are | |
| /// checked, and if they exceed the limits described above, then zip64 can be | |
| /// used. That is the general idea, but there is an additional wrinkle when saving | |
| /// to a non-seekable device, like the ASP.NET <c>Response.OutputStream</c>, or | |
| /// <c>Console.Out</c>. When using non-seekable streams for output, the entry | |
| /// header - which indicates whether zip64 is in use - is emitted before it is | |
| /// known if zip64 is necessary. It is only after all entries have been saved | |
| /// that it can be known if ZIP64 will be required. On seekable output streams, | |
| /// after saving all entries, the library can seek backward and re-emit the zip | |
| /// file header to be consistent with the actual ZIP64 requirement. But using a | |
| /// non-seekable output stream, the library cannot seek backward, so the header | |
| /// can never be changed. In other words, the archive's use of ZIP64 extensions is | |
| /// not alterable after the header is emitted. Therefore, when saving to | |
| /// non-seekable streams, using <see cref="Zip64Option.AsNecessary"/> is the same | |
| /// as using <see cref="Zip64Option.Always"/>: it will always produce a zip | |
| /// archive that uses ZIP64 extensions. | |
| /// </para> | |
| /// | |
| /// </remarks> | |
| internal enum Zip64Option | |
| { | |
| /// <summary> | |
| /// The default behavior, which is "Never". | |
| /// (For COM clients, this is a 0 (zero).) | |
| /// </summary> | |
| Default = 0, | |
| /// <summary> | |
| /// Do not use ZIP64 extensions when writing zip archives. | |
| /// (For COM clients, this is a 0 (zero).) | |
| /// </summary> | |
| Never = 0, | |
| /// <summary> | |
| /// Use ZIP64 extensions when writing zip archives, as necessary. | |
| /// For example, when a single entry exceeds 0xFFFFFFFF in size, or when the archive as a whole | |
| /// exceeds 0xFFFFFFFF in size, or when there are more than 65535 entries in an archive. | |
| /// (For COM clients, this is a 1.) | |
| /// </summary> | |
| AsNecessary = 1, | |
| /// <summary> | |
| /// Always use ZIP64 extensions when writing zip archives, even when unnecessary. | |
| /// (For COM clients, this is a 2.) | |
| /// </summary> | |
| Always | |
| } | |
| /// <summary> | |
| /// An enum representing the values on a three-way toggle switch | |
| /// for various options in the library. This might be used to | |
| /// specify whether to employ a particular text encoding, or to use | |
| /// ZIP64 extensions, or some other option. | |
| /// </summary> | |
| internal enum ZipOption | |
| { | |
| /// <summary> | |
| /// The default behavior. This is the same as "Never". | |
| /// (For COM clients, this is a 0 (zero).) | |
| /// </summary> | |
| Default = 0, | |
| /// <summary> | |
| /// Never use the associated option. | |
| /// (For COM clients, this is a 0 (zero).) | |
| /// </summary> | |
| Never = 0, | |
| /// <summary> | |
| /// Use the associated behavior "as necessary." | |
| /// (For COM clients, this is a 1.) | |
| /// </summary> | |
| AsNecessary = 1, | |
| /// <summary> | |
| /// Use the associated behavior Always, whether necessary or not. | |
| /// (For COM clients, this is a 2.) | |
| /// </summary> | |
| Always | |
| } | |
| enum AddOrUpdateAction | |
| { | |
| AddOnly = 0, | |
| AddOrUpdate | |
| } | |
| } | |
| // ================================================================== | |
| // | |
| // Information on the ZIP format: | |
| // | |
| // From | |
| // http://www.pkware.com/documents/casestudies/APPNOTE.TXT | |
| // | |
| // Overall .ZIP file format: | |
| // | |
| // [local file header 1] | |
| // [file data 1] | |
| // [data descriptor 1] ** sometimes | |
| // . | |
| // . | |
| // . | |
| // [local file header n] | |
| // [file data n] | |
| // [data descriptor n] ** sometimes | |
| // [archive decryption header] | |
| // [archive extra data record] | |
| // [central directory] | |
| // [zip64 end of central directory record] | |
| // [zip64 end of central directory locator] | |
| // [end of central directory record] | |
| // | |
| // Local File Header format: | |
| // local file header signature ... 4 bytes (0x04034b50) | |
| // version needed to extract ..... 2 bytes | |
| // general purpose bit field ..... 2 bytes | |
| // compression method ............ 2 bytes | |
| // last mod file time ............ 2 bytes | |
| // last mod file date............. 2 bytes | |
| // crc-32 ........................ 4 bytes | |
| // compressed size................ 4 bytes | |
| // uncompressed size.............. 4 bytes | |
| // file name length............... 2 bytes | |
| // extra field length ............ 2 bytes | |
| // file name varies | |
| // extra field varies | |
| // | |
| // | |
| // Data descriptor: (used only when bit 3 of the general purpose bitfield is set) | |
| // (although, I have found zip files where bit 3 is not set, yet this descriptor is present!) | |
| // local file header signature 4 bytes (0x08074b50) ** sometimes!!! Not always | |
| // crc-32 4 bytes | |
| // compressed size 4 bytes | |
| // uncompressed size 4 bytes | |
| // | |
| // | |
| // Central directory structure: | |
| // | |
| // [file header 1] | |
| // . | |
| // . | |
| // . | |
| // [file header n] | |
| // [digital signature] | |
| // | |
| // | |
| // File header: (This is a ZipDirEntry) | |
| // central file header signature 4 bytes (0x02014b50) | |
| // version made by 2 bytes | |
| // version needed to extract 2 bytes | |
| // general purpose bit flag 2 bytes | |
| // compression method 2 bytes | |
| // last mod file time 2 bytes | |
| // last mod file date 2 bytes | |
| // crc-32 4 bytes | |
| // compressed size 4 bytes | |
| // uncompressed size 4 bytes | |
| // file name length 2 bytes | |
| // extra field length 2 bytes | |
| // file comment length 2 bytes | |
| // disk number start 2 bytes | |
| // internal file attributes ** 2 bytes | |
| // external file attributes *** 4 bytes | |
| // relative offset of local header 4 bytes | |
| // file name (variable size) | |
| // extra field (variable size) | |
| // file comment (variable size) | |
| // | |
| // ** The internal file attributes, near as I can tell, | |
| // uses 0x01 for a file and a 0x00 for a directory. | |
| // | |
| // ***The external file attributes follows the MS-DOS file attribute byte, described here: | |
| // at http://support.microsoft.com/kb/q125019/ | |
| // 0x0010 => directory | |
| // 0x0020 => file | |
| // | |
| // | |
| // End of central directory record: | |
| // | |
| // end of central dir signature 4 bytes (0x06054b50) | |
| // number of this disk 2 bytes | |
| // number of the disk with the | |
| // start of the central directory 2 bytes | |
| // total number of entries in the | |
| // central directory on this disk 2 bytes | |
| // total number of entries in | |
| // the central directory 2 bytes | |
| // size of the central directory 4 bytes | |
| // offset of start of central | |
| // directory with respect to | |
| // the starting disk number 4 bytes | |
| // .ZIP file comment length 2 bytes | |
| // .ZIP file comment (variable size) | |
| // | |
| // date and time are packed values, as MSDOS did them | |
| // time: bits 0-4 : seconds (divided by 2) | |
| // 5-10: minute | |
| // 11-15: hour | |
| // date bits 0-4 : day | |
| // 5-8: month | |
| // 9-15 year (since 1980) | |
| // | |
| // see http://msdn.microsoft.com/en-us/library/ms724274(VS.85).aspx | |