| // 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.ASCII; // UTF-8 |
| private ZipOption _alternateEncodingUsage = ZipOption.Never; |
| private static System.Text.Encoding _defaultEncoding = System.Text.Encoding.ASCII; |
| |
| 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 |
| |