1 | // ZipFile.cs
|
---|
2 | //
|
---|
3 | // Copyright (c) 2006-2010 Dino Chiesa
|
---|
4 | // All rights reserved.
|
---|
5 | //
|
---|
6 | // This module is part of DotNetZip, a zipfile class library.
|
---|
7 | // The class library reads and writes zip files, according to the format
|
---|
8 | // described by PKware, at:
|
---|
9 | // http://www.pkware.com/business_and_developers/developer/popups/appnote.txt
|
---|
10 | //
|
---|
11 | //
|
---|
12 | // There are other Zip class libraries available.
|
---|
13 | //
|
---|
14 | // - it is possible to read and write zip files within .NET via the J# runtime.
|
---|
15 | // But some people don't like to install the extra DLL, which is no longer
|
---|
16 | // supported by MS. And also, the J# libraries don't support advanced zip
|
---|
17 | // features, like ZIP64, spanned archives, or AES encryption.
|
---|
18 | //
|
---|
19 | // - There are third-party GPL and LGPL libraries available. Some people don't
|
---|
20 | // like the license, and some of them don't support all the ZIP features, like AES.
|
---|
21 | //
|
---|
22 | // - Finally, there are commercial tools (From ComponentOne, XCeed, etc). But
|
---|
23 | // some people don't want to incur the cost.
|
---|
24 | //
|
---|
25 | // This alternative implementation is **not** GPL licensed. It is free of cost, and
|
---|
26 | // does not require J#. It does require .NET 2.0. It balances a good set of
|
---|
27 | // features, with ease of use and speed of performance.
|
---|
28 | //
|
---|
29 | // This code is released under the Microsoft Public License .
|
---|
30 | // See the License.txt for details.
|
---|
31 | //
|
---|
32 | //
|
---|
33 | // NB: This implementation originally relied on the
|
---|
34 | // System.IO.Compression.DeflateStream base class in the .NET Framework
|
---|
35 | // v2.0 base class library, but now includes a managed-code port of Zlib.
|
---|
36 | //
|
---|
37 | // Thu, 08 Oct 2009 17:04
|
---|
38 | //
|
---|
39 |
|
---|
40 |
|
---|
41 | using System;
|
---|
42 | using System.IO;
|
---|
43 | using System.Collections.Generic;
|
---|
44 | using Interop = System.Runtime.InteropServices;
|
---|
45 | using OfficeOpenXml.Packaging.Ionic.Zlib;
|
---|
46 | namespace OfficeOpenXml.Packaging.Ionic.Zip
|
---|
47 | {
|
---|
48 | /// <summary>
|
---|
49 | /// The ZipFile type represents a zip archive file.
|
---|
50 | /// </summary>
|
---|
51 | ///
|
---|
52 | /// <remarks>
|
---|
53 | /// <para>
|
---|
54 | /// This is the main type in the DotNetZip class library. This class reads and
|
---|
55 | /// writes zip files, as defined in the <see
|
---|
56 | /// href="http://www.pkware.com/documents/casestudies/APPNOTE.TXT">specification
|
---|
57 | /// for zip files described by PKWare</see>. The compression for this
|
---|
58 | /// implementation is provided by a managed-code version of Zlib, included with
|
---|
59 | /// DotNetZip in the classes in the Ionic.Zlib namespace.
|
---|
60 | /// </para>
|
---|
61 | ///
|
---|
62 | /// <para>
|
---|
63 | /// This class provides a general purpose zip file capability. Use it to read,
|
---|
64 | /// create, or update zip files. When you want to create zip files using a
|
---|
65 | /// <c>Stream</c> type to write the zip file, you may want to consider the <see
|
---|
66 | /// cref="ZipOutputStream"/> class.
|
---|
67 | /// </para>
|
---|
68 | ///
|
---|
69 | /// <para>
|
---|
70 | /// Both the <c>ZipOutputStream</c> class and the <c>ZipFile</c> class can
|
---|
71 | /// be used to create zip files. Both of them support many of the common zip
|
---|
72 | /// features, including Unicode, different compression methods and levels,
|
---|
73 | /// and ZIP64. They provide very similar performance when creating zip
|
---|
74 | /// files.
|
---|
75 | /// </para>
|
---|
76 | ///
|
---|
77 | /// <para>
|
---|
78 | /// The <c>ZipFile</c> class is generally easier to use than
|
---|
79 | /// <c>ZipOutputStream</c> and should be considered a higher-level interface. For
|
---|
80 | /// example, when creating a zip file via calls to the <c>PutNextEntry()</c> and
|
---|
81 | /// <c>Write()</c> methods on the <c>ZipOutputStream</c> class, the caller is
|
---|
82 | /// responsible for opening the file, reading the bytes from the file, writing
|
---|
83 | /// those bytes into the <c>ZipOutputStream</c>, setting the attributes on the
|
---|
84 | /// <c>ZipEntry</c>, and setting the created, last modified, and last accessed
|
---|
85 | /// timestamps on the zip entry. All of these things are done automatically by a
|
---|
86 | /// call to <see cref="ZipFile.AddFile(string,string)">ZipFile.AddFile()</see>.
|
---|
87 | /// For this reason, the <c>ZipOutputStream</c> is generally recommended for use
|
---|
88 | /// only when your application emits arbitrary data, not necessarily data from a
|
---|
89 | /// filesystem file, directly into a zip file, and does so using a <c>Stream</c>
|
---|
90 | /// metaphor.
|
---|
91 | /// </para>
|
---|
92 | ///
|
---|
93 | /// <para>
|
---|
94 | /// Aside from the differences in programming model, there are other
|
---|
95 | /// differences in capability between the two classes.
|
---|
96 | /// </para>
|
---|
97 | ///
|
---|
98 | /// <list type="bullet">
|
---|
99 | /// <item>
|
---|
100 | /// <c>ZipFile</c> can be used to read and extract zip files, in addition to
|
---|
101 | /// creating zip files. <c>ZipOutputStream</c> cannot read zip files. If you want
|
---|
102 | /// to use a stream to read zip files, check out the ZipInputStream class.
|
---|
103 | /// </item>
|
---|
104 | ///
|
---|
105 | /// <item>
|
---|
106 | /// <c>ZipOutputStream</c> does not support the creation of segmented or spanned
|
---|
107 | /// zip files.
|
---|
108 | /// </item>
|
---|
109 | ///
|
---|
110 | /// <item>
|
---|
111 | /// <c>ZipOutputStream</c> cannot produce a self-extracting archive.
|
---|
112 | /// </item>
|
---|
113 | /// </list>
|
---|
114 | ///
|
---|
115 | /// <para>
|
---|
116 | /// Be aware that the <c>ZipFile</c> class implements the <see
|
---|
117 | /// cref="System.IDisposable"/> interface. In order for <c>ZipFile</c> to
|
---|
118 | /// produce a valid zip file, you use use it within a using clause (<c>Using</c>
|
---|
119 | /// in VB), or call the <c>Dispose()</c> method explicitly. See the examples
|
---|
120 | /// for how to employ a using clause.
|
---|
121 | /// </para>
|
---|
122 | ///
|
---|
123 | /// </remarks>
|
---|
124 | [Interop.GuidAttribute("ebc25cf6-9120-4283-b972-0e5520d00005")]
|
---|
125 | [Interop.ComVisible(true)]
|
---|
126 | #if !NETCF
|
---|
127 | [Interop.ClassInterface(Interop.ClassInterfaceType.AutoDispatch)]
|
---|
128 | #endif
|
---|
129 | internal partial class ZipFile :
|
---|
130 | System.Collections.IEnumerable,
|
---|
131 | System.Collections.Generic.IEnumerable<ZipEntry>,
|
---|
132 | IDisposable
|
---|
133 | {
|
---|
134 |
|
---|
135 | #region public properties
|
---|
136 |
|
---|
137 | /// <summary>
|
---|
138 | /// Indicates whether to perform a full scan of the zip file when reading it.
|
---|
139 | /// </summary>
|
---|
140 | ///
|
---|
141 | /// <remarks>
|
---|
142 | ///
|
---|
143 | /// <para>
|
---|
144 | /// You almost never want to use this property.
|
---|
145 | /// </para>
|
---|
146 | ///
|
---|
147 | /// <para>
|
---|
148 | /// When reading a zip file, if this flag is <c>true</c> (<c>True</c> in
|
---|
149 | /// VB), the entire zip archive will be scanned and searched for entries.
|
---|
150 | /// For large archives, this can take a very, long time. The much more
|
---|
151 | /// efficient default behavior is to read the zip directory, which is
|
---|
152 | /// stored at the end of the zip file. But, in some cases the directory is
|
---|
153 | /// corrupted and you need to perform a full scan of the zip file to
|
---|
154 | /// determine the contents of the zip file. This property lets you do
|
---|
155 | /// that, when necessary.
|
---|
156 | /// </para>
|
---|
157 | ///
|
---|
158 | /// <para>
|
---|
159 | /// This flag is effective only when calling <see
|
---|
160 | /// cref="Initialize(string)"/>. Normally you would read a ZipFile with the
|
---|
161 | /// static <see cref="ZipFile.Read(String)">ZipFile.Read</see>
|
---|
162 | /// method. But you can't set the <c>FullScan</c> property on the
|
---|
163 | /// <c>ZipFile</c> instance when you use a static factory method like
|
---|
164 | /// <c>ZipFile.Read</c>.
|
---|
165 | /// </para>
|
---|
166 | ///
|
---|
167 | /// </remarks>
|
---|
168 | ///
|
---|
169 | /// <example>
|
---|
170 | ///
|
---|
171 | /// This example shows how to read a zip file using the full scan approach,
|
---|
172 | /// and then save it, thereby producing a corrected zip file.
|
---|
173 | ///
|
---|
174 | /// <code lang="C#">
|
---|
175 | /// using (var zip = new ZipFile())
|
---|
176 | /// {
|
---|
177 | /// zip.FullScan = true;
|
---|
178 | /// zip.Initialize(zipFileName);
|
---|
179 | /// zip.Save(newName);
|
---|
180 | /// }
|
---|
181 | /// </code>
|
---|
182 | ///
|
---|
183 | /// <code lang="VB">
|
---|
184 | /// Using zip As New ZipFile
|
---|
185 | /// zip.FullScan = True
|
---|
186 | /// zip.Initialize(zipFileName)
|
---|
187 | /// zip.Save(newName)
|
---|
188 | /// End Using
|
---|
189 | /// </code>
|
---|
190 | /// </example>
|
---|
191 | ///
|
---|
192 | public bool FullScan
|
---|
193 | {
|
---|
194 | get;
|
---|
195 | set;
|
---|
196 | }
|
---|
197 |
|
---|
198 |
|
---|
199 | /// <summary>
|
---|
200 | /// Whether to sort the ZipEntries before saving the file.
|
---|
201 | /// </summary>
|
---|
202 | ///
|
---|
203 | /// <remarks>
|
---|
204 | /// The default is false. If you have a large number of zip entries, the sort
|
---|
205 | /// alone can consume significant time.
|
---|
206 | /// </remarks>
|
---|
207 | ///
|
---|
208 | /// <example>
|
---|
209 | /// <code lang="C#">
|
---|
210 | /// using (var zip = new ZipFile())
|
---|
211 | /// {
|
---|
212 | /// zip.AddFiles(filesToAdd);
|
---|
213 | /// zip.SortEntriesBeforeSaving = true;
|
---|
214 | /// zip.Save(name);
|
---|
215 | /// }
|
---|
216 | /// </code>
|
---|
217 | ///
|
---|
218 | /// <code lang="VB">
|
---|
219 | /// Using zip As New ZipFile
|
---|
220 | /// zip.AddFiles(filesToAdd)
|
---|
221 | /// zip.SortEntriesBeforeSaving = True
|
---|
222 | /// zip.Save(name)
|
---|
223 | /// End Using
|
---|
224 | /// </code>
|
---|
225 | /// </example>
|
---|
226 | ///
|
---|
227 | public bool SortEntriesBeforeSaving
|
---|
228 | {
|
---|
229 | get;
|
---|
230 | set;
|
---|
231 | }
|
---|
232 |
|
---|
233 |
|
---|
234 |
|
---|
235 | /// <summary>
|
---|
236 | /// Indicates whether NTFS Reparse Points, like junctions, should be
|
---|
237 | /// traversed during calls to <c>AddDirectory()</c>.
|
---|
238 | /// </summary>
|
---|
239 | ///
|
---|
240 | /// <remarks>
|
---|
241 | /// By default, calls to AddDirectory() will traverse NTFS reparse
|
---|
242 | /// points, like mounted volumes, and directory junctions. An example
|
---|
243 | /// of a junction is the "My Music" directory in Windows Vista. In some
|
---|
244 | /// cases you may not want DotNetZip to traverse those directories. In
|
---|
245 | /// that case, set this property to false.
|
---|
246 | /// </remarks>
|
---|
247 | ///
|
---|
248 | /// <example>
|
---|
249 | /// <code lang="C#">
|
---|
250 | /// using (var zip = new ZipFile())
|
---|
251 | /// {
|
---|
252 | /// zip.AddDirectoryWillTraverseReparsePoints = false;
|
---|
253 | /// zip.AddDirectory(dirToZip,"fodder");
|
---|
254 | /// zip.Save(zipFileToCreate);
|
---|
255 | /// }
|
---|
256 | /// </code>
|
---|
257 | /// </example>
|
---|
258 | public bool AddDirectoryWillTraverseReparsePoints { get; set; }
|
---|
259 |
|
---|
260 |
|
---|
261 | /// <summary>
|
---|
262 | /// Size of the IO buffer used while saving.
|
---|
263 | /// </summary>
|
---|
264 | ///
|
---|
265 | /// <remarks>
|
---|
266 | ///
|
---|
267 | /// <para>
|
---|
268 | /// First, let me say that you really don't need to bother with this. It is
|
---|
269 | /// here to allow for optimizations that you probably won't make! It will work
|
---|
270 | /// fine if you don't set or get this property at all. Ok?
|
---|
271 | /// </para>
|
---|
272 | ///
|
---|
273 | /// <para>
|
---|
274 | /// Now that we have <em>that</em> out of the way, the fine print: This
|
---|
275 | /// property affects the size of the buffer that is used for I/O for each
|
---|
276 | /// entry contained in the zip file. When a file is read in to be compressed,
|
---|
277 | /// it uses a buffer given by the size here. When you update a zip file, the
|
---|
278 | /// data for unmodified entries is copied from the first zip file to the
|
---|
279 | /// other, through a buffer given by the size here.
|
---|
280 | /// </para>
|
---|
281 | ///
|
---|
282 | /// <para>
|
---|
283 | /// Changing the buffer size affects a few things: first, for larger buffer
|
---|
284 | /// sizes, the memory used by the <c>ZipFile</c>, obviously, will be larger
|
---|
285 | /// during I/O operations. This may make operations faster for very much
|
---|
286 | /// larger files. Last, for any given entry, when you use a larger buffer
|
---|
287 | /// there will be fewer progress events during I/O operations, because there's
|
---|
288 | /// one progress event generated for each time the buffer is filled and then
|
---|
289 | /// emptied.
|
---|
290 | /// </para>
|
---|
291 | ///
|
---|
292 | /// <para>
|
---|
293 | /// The default buffer size is 8k. Increasing the buffer size may speed
|
---|
294 | /// things up as you compress larger files. But there are no hard-and-fast
|
---|
295 | /// rules here, eh? You won't know til you test it. And there will be a
|
---|
296 | /// limit where ever larger buffers actually slow things down. So as I said
|
---|
297 | /// in the beginning, it's probably best if you don't set or get this property
|
---|
298 | /// at all.
|
---|
299 | /// </para>
|
---|
300 | ///
|
---|
301 | /// </remarks>
|
---|
302 | ///
|
---|
303 | /// <example>
|
---|
304 | /// This example shows how you might set a large buffer size for efficiency when
|
---|
305 | /// dealing with zip entries that are larger than 1gb.
|
---|
306 | /// <code lang="C#">
|
---|
307 | /// using (ZipFile zip = new ZipFile())
|
---|
308 | /// {
|
---|
309 | /// zip.SaveProgress += this.zip1_SaveProgress;
|
---|
310 | /// zip.AddDirectory(directoryToZip, "");
|
---|
311 | /// zip.UseZip64WhenSaving = Zip64Option.Always;
|
---|
312 | /// zip.BufferSize = 65536*8; // 65536 * 8 = 512k
|
---|
313 | /// zip.Save(ZipFileToCreate);
|
---|
314 | /// }
|
---|
315 | /// </code>
|
---|
316 | /// </example>
|
---|
317 |
|
---|
318 | public int BufferSize
|
---|
319 | {
|
---|
320 | get { return _BufferSize; }
|
---|
321 | set { _BufferSize = value; }
|
---|
322 | }
|
---|
323 |
|
---|
324 | /// <summary>
|
---|
325 | /// Size of the work buffer to use for the ZLIB codec during compression.
|
---|
326 | /// </summary>
|
---|
327 | ///
|
---|
328 | /// <remarks>
|
---|
329 | /// <para>
|
---|
330 | /// When doing ZLIB or Deflate compression, the library fills a buffer,
|
---|
331 | /// then passes it to the compressor for compression. Then the library
|
---|
332 | /// reads out the compressed bytes. This happens repeatedly until there
|
---|
333 | /// is no more uncompressed data to compress. This property sets the
|
---|
334 | /// size of the buffer that will be used for chunk-wise compression. In
|
---|
335 | /// order for the setting to take effect, your application needs to set
|
---|
336 | /// this property before calling one of the <c>ZipFile.Save()</c>
|
---|
337 | /// overloads.
|
---|
338 | /// </para>
|
---|
339 | /// <para>
|
---|
340 | /// Setting this affects the performance and memory efficiency of
|
---|
341 | /// compression and decompression. For larger files, setting this to a
|
---|
342 | /// larger size may improve compression performance, but the exact
|
---|
343 | /// numbers vary depending on available memory, the size of the streams
|
---|
344 | /// you are compressing, and a bunch of other variables. I don't have
|
---|
345 | /// good firm recommendations on how to set it. You'll have to test it
|
---|
346 | /// yourself. Or just leave it alone and accept the default.
|
---|
347 | /// </para>
|
---|
348 | /// </remarks>
|
---|
349 | public int CodecBufferSize
|
---|
350 | {
|
---|
351 | get;
|
---|
352 | set;
|
---|
353 | }
|
---|
354 |
|
---|
355 | /// <summary>
|
---|
356 | /// Indicates whether extracted files should keep their paths as
|
---|
357 | /// stored in the zip archive.
|
---|
358 | /// </summary>
|
---|
359 | ///
|
---|
360 | /// <remarks>
|
---|
361 | /// <para>
|
---|
362 | /// This property affects Extraction. It is not used when creating zip
|
---|
363 | /// archives.
|
---|
364 | /// </para>
|
---|
365 | ///
|
---|
366 | /// <para>
|
---|
367 | /// With this property set to <c>false</c>, the default, extracting entries
|
---|
368 | /// from a zip file will create files in the filesystem that have the full
|
---|
369 | /// path associated to the entry within the zip file. With this property set
|
---|
370 | /// to <c>true</c>, extracting entries from the zip file results in files
|
---|
371 | /// with no path: the folders are "flattened."
|
---|
372 | /// </para>
|
---|
373 | ///
|
---|
374 | /// <para>
|
---|
375 | /// An example: suppose the zip file contains entries /directory1/file1.txt and
|
---|
376 | /// /directory2/file2.txt. With <c>FlattenFoldersOnExtract</c> set to false,
|
---|
377 | /// the files created will be \directory1\file1.txt and \directory2\file2.txt.
|
---|
378 | /// With the property set to true, the files created are file1.txt and file2.txt.
|
---|
379 | /// </para>
|
---|
380 | ///
|
---|
381 | /// </remarks>
|
---|
382 | public bool FlattenFoldersOnExtract
|
---|
383 | {
|
---|
384 | get;
|
---|
385 | set;
|
---|
386 | }
|
---|
387 |
|
---|
388 |
|
---|
389 | /// <summary>
|
---|
390 | /// The compression strategy to use for all entries.
|
---|
391 | /// </summary>
|
---|
392 | ///
|
---|
393 | /// <remarks>
|
---|
394 | /// Set the Strategy used by the ZLIB-compatible compressor, when
|
---|
395 | /// compressing entries using the DEFLATE method. Different compression
|
---|
396 | /// strategies work better on different sorts of data. The strategy
|
---|
397 | /// parameter can affect the compression ratio and the speed of
|
---|
398 | /// compression but not the correctness of the compresssion. For more
|
---|
399 | /// information see <see
|
---|
400 | /// cref="Ionic.Zlib.CompressionStrategy">Ionic.Zlib.CompressionStrategy</see>.
|
---|
401 | /// </remarks>
|
---|
402 | public CompressionStrategy Strategy
|
---|
403 | {
|
---|
404 | get { return _Strategy; }
|
---|
405 | set { _Strategy = value; }
|
---|
406 | }
|
---|
407 |
|
---|
408 |
|
---|
409 | /// <summary>
|
---|
410 | /// The name of the <c>ZipFile</c>, on disk.
|
---|
411 | /// </summary>
|
---|
412 | ///
|
---|
413 | /// <remarks>
|
---|
414 | ///
|
---|
415 | /// <para>
|
---|
416 | /// When the <c>ZipFile</c> instance was created by reading an archive using
|
---|
417 | /// one of the <c>ZipFile.Read</c> methods, this property represents the name
|
---|
418 | /// of the zip file that was read. When the <c>ZipFile</c> instance was
|
---|
419 | /// created by using the no-argument constructor, this value is <c>null</c>
|
---|
420 | /// (<c>Nothing</c> in VB).
|
---|
421 | /// </para>
|
---|
422 | ///
|
---|
423 | /// <para>
|
---|
424 | /// If you use the no-argument constructor, and you then explicitly set this
|
---|
425 | /// property, when you call <see cref="ZipFile.Save()"/>, this name will
|
---|
426 | /// specify the name of the zip file created. Doing so is equivalent to
|
---|
427 | /// calling <see cref="ZipFile.Save(String)"/>. When instantiating a
|
---|
428 | /// <c>ZipFile</c> by reading from a stream or byte array, the <c>Name</c>
|
---|
429 | /// property remains <c>null</c>. When saving to a stream, the <c>Name</c>
|
---|
430 | /// property is implicitly set to <c>null</c>.
|
---|
431 | /// </para>
|
---|
432 | /// </remarks>
|
---|
433 | public string Name
|
---|
434 | {
|
---|
435 | get { return _name; }
|
---|
436 | set { _name = value; }
|
---|
437 | }
|
---|
438 |
|
---|
439 |
|
---|
440 | /// <summary>
|
---|
441 | /// Sets the compression level to be used for entries subsequently added to
|
---|
442 | /// the zip archive.
|
---|
443 | /// </summary>
|
---|
444 | ///
|
---|
445 | /// <remarks>
|
---|
446 | /// <para>
|
---|
447 | /// Varying the compression level used on entries can affect the
|
---|
448 | /// size-vs-speed tradeoff when compression and decompressing data streams
|
---|
449 | /// or files.
|
---|
450 | /// </para>
|
---|
451 | ///
|
---|
452 | /// <para>
|
---|
453 | /// As with some other properties on the <c>ZipFile</c> class, like <see
|
---|
454 | /// cref="Password"/>, <see cref="Encryption"/>, and <see
|
---|
455 | /// cref="ZipErrorAction"/>, setting this property on a <c>ZipFile</c>
|
---|
456 | /// instance will cause the specified <c>CompressionLevel</c> to be used on all
|
---|
457 | /// <see cref="ZipEntry"/> items that are subsequently added to the
|
---|
458 | /// <c>ZipFile</c> instance. If you set this property after you have added
|
---|
459 | /// items to the <c>ZipFile</c>, but before you have called <c>Save()</c>,
|
---|
460 | /// those items will not use the specified compression level.
|
---|
461 | /// </para>
|
---|
462 | ///
|
---|
463 | /// <para>
|
---|
464 | /// If you do not set this property, the default compression level is used,
|
---|
465 | /// which normally gives a good balance of compression efficiency and
|
---|
466 | /// compression speed. In some tests, using <c>BestCompression</c> can
|
---|
467 | /// double the time it takes to compress, while delivering just a small
|
---|
468 | /// increase in compression efficiency. This behavior will vary with the
|
---|
469 | /// type of data you compress. If you are in doubt, just leave this setting
|
---|
470 | /// alone, and accept the default.
|
---|
471 | /// </para>
|
---|
472 | /// </remarks>
|
---|
473 | public OfficeOpenXml.Packaging.Ionic.Zlib.CompressionLevel CompressionLevel
|
---|
474 | {
|
---|
475 | get;
|
---|
476 | set;
|
---|
477 | }
|
---|
478 |
|
---|
479 | /// <summary>
|
---|
480 | /// The compression method for the zipfile.
|
---|
481 | /// </summary>
|
---|
482 | /// <remarks>
|
---|
483 | /// <para>
|
---|
484 | /// By default, the compression method is <c>CompressionMethod.Deflate.</c>
|
---|
485 | /// </para>
|
---|
486 | /// </remarks>
|
---|
487 | /// <seealso cref="Ionic.Zip.CompressionMethod" />
|
---|
488 | internal Ionic.Zip.CompressionMethod CompressionMethod
|
---|
489 | {
|
---|
490 | get
|
---|
491 | {
|
---|
492 | return _compressionMethod;
|
---|
493 | }
|
---|
494 | set
|
---|
495 | {
|
---|
496 | _compressionMethod = value;
|
---|
497 | }
|
---|
498 | }
|
---|
499 |
|
---|
500 |
|
---|
501 |
|
---|
502 | /// <summary>
|
---|
503 | /// A comment attached to the zip archive.
|
---|
504 | /// </summary>
|
---|
505 | ///
|
---|
506 | /// <remarks>
|
---|
507 | ///
|
---|
508 | /// <para>
|
---|
509 | /// This property is read/write. It allows the application to specify a
|
---|
510 | /// comment for the <c>ZipFile</c>, or read the comment for the
|
---|
511 | /// <c>ZipFile</c>. After setting this property, changes are only made
|
---|
512 | /// permanent when you call a <c>Save()</c> method.
|
---|
513 | /// </para>
|
---|
514 | ///
|
---|
515 | /// <para>
|
---|
516 | /// According to <see
|
---|
517 | /// href="http://www.pkware.com/documents/casestudies/APPNOTE.TXT">PKWARE's
|
---|
518 | /// zip specification</see>, the comment is not encrypted, even if there is a
|
---|
519 | /// password set on the zip file.
|
---|
520 | /// </para>
|
---|
521 | ///
|
---|
522 | /// <para>
|
---|
523 | /// The specification does not describe how to indicate the encoding used
|
---|
524 | /// on a comment string. Many "compliant" zip tools and libraries use
|
---|
525 | /// IBM437 as the code page for comments; DotNetZip, too, follows that
|
---|
526 | /// practice. On the other hand, there are situations where you want a
|
---|
527 | /// Comment to be encoded with something else, for example using code page
|
---|
528 | /// 950 "Big-5 Chinese". To fill that need, DotNetZip will encode the
|
---|
529 | /// comment following the same procedure it follows for encoding
|
---|
530 | /// filenames: (a) if <see cref="AlternateEncodingUsage"/> is
|
---|
531 | /// <c>Never</c>, it uses the default encoding (IBM437). (b) if <see
|
---|
532 | /// cref="AlternateEncodingUsage"/> is <c>Always</c>, it always uses the
|
---|
533 | /// alternate encoding (<see cref="AlternateEncoding"/>). (c) if <see
|
---|
534 | /// cref="AlternateEncodingUsage"/> is <c>AsNecessary</c>, it uses the
|
---|
535 | /// alternate encoding only if the default encoding is not sufficient for
|
---|
536 | /// encoding the comment - in other words if decoding the result does not
|
---|
537 | /// produce the original string. This decision is taken at the time of
|
---|
538 | /// the call to <c>ZipFile.Save()</c>.
|
---|
539 | /// </para>
|
---|
540 | ///
|
---|
541 | /// <para>
|
---|
542 | /// When creating a zip archive using this library, it is possible to change
|
---|
543 | /// the value of <see cref="AlternateEncoding" /> between each
|
---|
544 | /// entry you add, and between adding entries and the call to
|
---|
545 | /// <c>Save()</c>. Don't do this. It will likely result in a zip file that is
|
---|
546 | /// not readable by any tool or application. For best interoperability, leave
|
---|
547 | /// <see cref="AlternateEncoding"/> alone, or specify it only
|
---|
548 | /// once, before adding any entries to the <c>ZipFile</c> instance.
|
---|
549 | /// </para>
|
---|
550 | ///
|
---|
551 | /// </remarks>
|
---|
552 | public string Comment
|
---|
553 | {
|
---|
554 | get { return _Comment; }
|
---|
555 | set
|
---|
556 | {
|
---|
557 | _Comment = value;
|
---|
558 | _contentsChanged = true;
|
---|
559 | }
|
---|
560 | }
|
---|
561 |
|
---|
562 |
|
---|
563 |
|
---|
564 |
|
---|
565 | /// <summary>
|
---|
566 | /// Specifies whether the Creation, Access, and Modified times for entries
|
---|
567 | /// added to the zip file will be emitted in “Windows format”
|
---|
568 | /// when the zip archive is saved.
|
---|
569 | /// </summary>
|
---|
570 | ///
|
---|
571 | /// <remarks>
|
---|
572 | /// <para>
|
---|
573 | /// An application creating a zip archive can use this flag to explicitly
|
---|
574 | /// specify that the file times for the entries should or should not be stored
|
---|
575 | /// in the zip archive in the format used by Windows. By default this flag is
|
---|
576 | /// <c>true</c>, meaning the Windows-format times are stored in the zip
|
---|
577 | /// archive.
|
---|
578 | /// </para>
|
---|
579 | ///
|
---|
580 | /// <para>
|
---|
581 | /// When adding an entry from a file or directory, the Creation (<see
|
---|
582 | /// cref="ZipEntry.CreationTime"/>), Access (<see
|
---|
583 | /// cref="ZipEntry.AccessedTime"/>), and Modified (<see
|
---|
584 | /// cref="ZipEntry.ModifiedTime"/>) times for the given entry are
|
---|
585 | /// automatically set from the filesystem values. When adding an entry from a
|
---|
586 | /// stream or string, all three values are implicitly set to
|
---|
587 | /// <c>DateTime.Now</c>. Applications can also explicitly set those times by
|
---|
588 | /// calling <see cref="ZipEntry.SetEntryTimes(DateTime, DateTime,
|
---|
589 | /// DateTime)"/>.
|
---|
590 | /// </para>
|
---|
591 | ///
|
---|
592 | /// <para>
|
---|
593 | /// <see
|
---|
594 | /// href="http://www.pkware.com/documents/casestudies/APPNOTE.TXT">PKWARE's
|
---|
595 | /// zip specification</see> describes multiple ways to format these times in a
|
---|
596 | /// zip file. One is the format Windows applications normally use: 100ns ticks
|
---|
597 | /// since January 1, 1601 UTC. The other is a format Unix applications typically
|
---|
598 | /// use: seconds since January 1, 1970 UTC. Each format can be stored in an
|
---|
599 | /// "extra field" in the zip entry when saving the zip archive. The former
|
---|
600 | /// uses an extra field with a Header Id of 0x000A, while the latter uses a
|
---|
601 | /// header ID of 0x5455, although you probably don't need to know that.
|
---|
602 | /// </para>
|
---|
603 | ///
|
---|
604 | /// <para>
|
---|
605 | /// Not all tools and libraries can interpret these fields. Windows
|
---|
606 | /// compressed folders is one that can read the Windows Format timestamps,
|
---|
607 | /// while I believe <see href="http://www.info-zip.org/">the Infozip
|
---|
608 | /// tools</see> can read the Unix format timestamps. Some tools and libraries
|
---|
609 | /// may be able to read only one or the other. DotNetZip can read or write
|
---|
610 | /// times in either or both formats.
|
---|
611 | /// </para>
|
---|
612 | ///
|
---|
613 | /// <para>
|
---|
614 | /// The times stored are taken from <see cref="ZipEntry.ModifiedTime"/>, <see
|
---|
615 | /// cref="ZipEntry.AccessedTime"/>, and <see cref="ZipEntry.CreationTime"/>.
|
---|
616 | /// </para>
|
---|
617 | ///
|
---|
618 | /// <para>
|
---|
619 | /// The value set here applies to all entries subsequently added to the
|
---|
620 | /// <c>ZipFile</c>.
|
---|
621 | /// </para>
|
---|
622 | ///
|
---|
623 | /// <para>
|
---|
624 | /// This property is not mutually exclusive of the <see
|
---|
625 | /// cref="EmitTimesInUnixFormatWhenSaving" /> property. It is possible and
|
---|
626 | /// legal and valid to produce a zip file that contains timestamps encoded in
|
---|
627 | /// the Unix format as well as in the Windows format, in addition to the <see
|
---|
628 | /// cref="ZipEntry.LastModified">LastModified</see> time attached to each
|
---|
629 | /// entry in the archive, a time that is always stored in "DOS format". And,
|
---|
630 | /// notwithstanding the names PKWare uses for these time formats, any of them
|
---|
631 | /// can be read and written by any computer, on any operating system. But,
|
---|
632 | /// there are no guarantees that a program running on Mac or Linux will
|
---|
633 | /// gracefully handle a zip file with "Windows" formatted times, or that an
|
---|
634 | /// application that does not use DotNetZip but runs on Windows will be able to
|
---|
635 | /// handle file times in Unix format.
|
---|
636 | /// </para>
|
---|
637 | ///
|
---|
638 | /// <para>
|
---|
639 | /// When in doubt, test. Sorry, I haven't got a complete list of tools and
|
---|
640 | /// which sort of timestamps they can use and will tolerate. If you get any
|
---|
641 | /// good information and would like to pass it on, please do so and I will
|
---|
642 | /// include that information in this documentation.
|
---|
643 | /// </para>
|
---|
644 | /// </remarks>
|
---|
645 | ///
|
---|
646 | /// <example>
|
---|
647 | /// This example shows how to save a zip file that contains file timestamps
|
---|
648 | /// in a format normally used by Unix.
|
---|
649 | /// <code lang="C#">
|
---|
650 | /// using (var zip = new ZipFile())
|
---|
651 | /// {
|
---|
652 | /// // produce a zip file the Mac will like
|
---|
653 | /// zip.EmitTimesInWindowsFormatWhenSaving = false;
|
---|
654 | /// zip.EmitTimesInUnixFormatWhenSaving = true;
|
---|
655 | /// zip.AddDirectory(directoryToZip, "files");
|
---|
656 | /// zip.Save(outputFile);
|
---|
657 | /// }
|
---|
658 | /// </code>
|
---|
659 | ///
|
---|
660 | /// <code lang="VB">
|
---|
661 | /// Using zip As New ZipFile
|
---|
662 | /// '' produce a zip file the Mac will like
|
---|
663 | /// zip.EmitTimesInWindowsFormatWhenSaving = False
|
---|
664 | /// zip.EmitTimesInUnixFormatWhenSaving = True
|
---|
665 | /// zip.AddDirectory(directoryToZip, "files")
|
---|
666 | /// zip.Save(outputFile)
|
---|
667 | /// End Using
|
---|
668 | /// </code>
|
---|
669 | /// </example>
|
---|
670 | ///
|
---|
671 | /// <seealso cref="ZipEntry.EmitTimesInWindowsFormatWhenSaving" />
|
---|
672 | /// <seealso cref="EmitTimesInUnixFormatWhenSaving" />
|
---|
673 | public bool EmitTimesInWindowsFormatWhenSaving
|
---|
674 | {
|
---|
675 | get
|
---|
676 | {
|
---|
677 | return _emitNtfsTimes;
|
---|
678 | }
|
---|
679 | set
|
---|
680 | {
|
---|
681 | _emitNtfsTimes = value;
|
---|
682 | }
|
---|
683 | }
|
---|
684 |
|
---|
685 |
|
---|
686 | /// <summary>
|
---|
687 | /// Specifies whether the Creation, Access, and Modified times
|
---|
688 | /// for entries added to the zip file will be emitted in "Unix(tm)
|
---|
689 | /// format" when the zip archive is saved.
|
---|
690 | /// </summary>
|
---|
691 | ///
|
---|
692 | /// <remarks>
|
---|
693 | /// <para>
|
---|
694 | /// An application creating a zip archive can use this flag to explicitly
|
---|
695 | /// specify that the file times for the entries should or should not be stored
|
---|
696 | /// in the zip archive in the format used by Unix. By default this flag is
|
---|
697 | /// <c>false</c>, meaning the Unix-format times are not stored in the zip
|
---|
698 | /// archive.
|
---|
699 | /// </para>
|
---|
700 | ///
|
---|
701 | /// <para>
|
---|
702 | /// When adding an entry from a file or directory, the Creation (<see
|
---|
703 | /// cref="ZipEntry.CreationTime"/>), Access (<see
|
---|
704 | /// cref="ZipEntry.AccessedTime"/>), and Modified (<see
|
---|
705 | /// cref="ZipEntry.ModifiedTime"/>) times for the given entry are
|
---|
706 | /// automatically set from the filesystem values. When adding an entry from a
|
---|
707 | /// stream or string, all three values are implicitly set to DateTime.Now.
|
---|
708 | /// Applications can also explicitly set those times by calling <see
|
---|
709 | /// cref="ZipEntry.SetEntryTimes(DateTime, DateTime, DateTime)"/>.
|
---|
710 | /// </para>
|
---|
711 | ///
|
---|
712 | /// <para>
|
---|
713 | /// <see
|
---|
714 | /// href="http://www.pkware.com/documents/casestudies/APPNOTE.TXT">PKWARE's
|
---|
715 | /// zip specification</see> describes multiple ways to format these times in a
|
---|
716 | /// zip file. One is the format Windows applications normally use: 100ns ticks
|
---|
717 | /// since January 1, 1601 UTC. The other is a format Unix applications
|
---|
718 | /// typically use: seconds since January 1, 1970 UTC. Each format can be
|
---|
719 | /// stored in an "extra field" in the zip entry when saving the zip
|
---|
720 | /// archive. The former uses an extra field with a Header Id of 0x000A, while
|
---|
721 | /// the latter uses a header ID of 0x5455, although you probably don't need to
|
---|
722 | /// know that.
|
---|
723 | /// </para>
|
---|
724 | ///
|
---|
725 | /// <para>
|
---|
726 | /// Not all tools and libraries can interpret these fields. Windows
|
---|
727 | /// compressed folders is one that can read the Windows Format timestamps,
|
---|
728 | /// while I believe the <see href="http://www.info-zip.org/">Infozip</see>
|
---|
729 | /// tools can read the Unix format timestamps. Some tools and libraries may be
|
---|
730 | /// able to read only one or the other. DotNetZip can read or write times in
|
---|
731 | /// either or both formats.
|
---|
732 | /// </para>
|
---|
733 | ///
|
---|
734 | /// <para>
|
---|
735 | /// The times stored are taken from <see cref="ZipEntry.ModifiedTime"/>, <see
|
---|
736 | /// cref="ZipEntry.AccessedTime"/>, and <see cref="ZipEntry.CreationTime"/>.
|
---|
737 | /// </para>
|
---|
738 | ///
|
---|
739 | /// <para>
|
---|
740 | /// This property is not mutually exclusive of the <see
|
---|
741 | /// cref="EmitTimesInWindowsFormatWhenSaving" /> property. It is possible and
|
---|
742 | /// legal and valid to produce a zip file that contains timestamps encoded in
|
---|
743 | /// the Unix format as well as in the Windows format, in addition to the <see
|
---|
744 | /// cref="ZipEntry.LastModified">LastModified</see> time attached to each
|
---|
745 | /// entry in the zip archive, a time that is always stored in "DOS
|
---|
746 | /// format". And, notwithstanding the names PKWare uses for these time
|
---|
747 | /// formats, any of them can be read and written by any computer, on any
|
---|
748 | /// operating system. But, there are no guarantees that a program running on
|
---|
749 | /// Mac or Linux will gracefully handle a zip file with "Windows" formatted
|
---|
750 | /// times, or that an application that does not use DotNetZip but runs on
|
---|
751 | /// Windows will be able to handle file times in Unix format.
|
---|
752 | /// </para>
|
---|
753 | ///
|
---|
754 | /// <para>
|
---|
755 | /// When in doubt, test. Sorry, I haven't got a complete list of tools and
|
---|
756 | /// which sort of timestamps they can use and will tolerate. If you get any
|
---|
757 | /// good information and would like to pass it on, please do so and I will
|
---|
758 | /// include that information in this documentation.
|
---|
759 | /// </para>
|
---|
760 | /// </remarks>
|
---|
761 | ///
|
---|
762 | /// <seealso cref="ZipEntry.EmitTimesInUnixFormatWhenSaving" />
|
---|
763 | /// <seealso cref="EmitTimesInWindowsFormatWhenSaving" />
|
---|
764 | public bool EmitTimesInUnixFormatWhenSaving
|
---|
765 | {
|
---|
766 | get
|
---|
767 | {
|
---|
768 | return _emitUnixTimes;
|
---|
769 | }
|
---|
770 | set
|
---|
771 | {
|
---|
772 | _emitUnixTimes = value;
|
---|
773 | }
|
---|
774 | }
|
---|
775 |
|
---|
776 |
|
---|
777 |
|
---|
778 | /// <summary>
|
---|
779 | /// Indicates whether verbose output is sent to the <see
|
---|
780 | /// cref="StatusMessageTextWriter"/> during <c>AddXxx()</c> and
|
---|
781 | /// <c>ReadXxx()</c> operations.
|
---|
782 | /// </summary>
|
---|
783 | ///
|
---|
784 | /// <remarks>
|
---|
785 | /// This is a <em>synthetic</em> property. It returns true if the <see
|
---|
786 | /// cref="StatusMessageTextWriter"/> is non-null.
|
---|
787 | /// </remarks>
|
---|
788 | internal bool Verbose
|
---|
789 | {
|
---|
790 | get { return (_StatusMessageTextWriter != null); }
|
---|
791 | }
|
---|
792 |
|
---|
793 |
|
---|
794 | /// <summary>
|
---|
795 | /// Returns true if an entry by the given name exists in the ZipFile.
|
---|
796 | /// </summary>
|
---|
797 | ///
|
---|
798 | /// <param name='name'>the name of the entry to find</param>
|
---|
799 | /// <returns>true if an entry with the given name exists; otherwise false.
|
---|
800 | /// </returns>
|
---|
801 | public bool ContainsEntry(string name)
|
---|
802 | {
|
---|
803 | // workitem 12534
|
---|
804 | return _entries.ContainsKey(SharedUtilities.NormalizePathForUseInZipFile(name));
|
---|
805 | }
|
---|
806 |
|
---|
807 |
|
---|
808 |
|
---|
809 | /// <summary>
|
---|
810 | /// Indicates whether to perform case-sensitive matching on the filename when
|
---|
811 | /// retrieving entries in the zipfile via the string-based indexer.
|
---|
812 | /// </summary>
|
---|
813 | ///
|
---|
814 | /// <remarks>
|
---|
815 | /// The default value is <c>false</c>, which means don't do case-sensitive
|
---|
816 | /// matching. In other words, retrieving zip["ReadMe.Txt"] is the same as
|
---|
817 | /// zip["readme.txt"]. It really makes sense to set this to <c>true</c> only
|
---|
818 | /// if you are not running on Windows, which has case-insensitive
|
---|
819 | /// filenames. But since this library is not built for non-Windows platforms,
|
---|
820 | /// in most cases you should just leave this property alone.
|
---|
821 | /// </remarks>
|
---|
822 | public bool CaseSensitiveRetrieval
|
---|
823 | {
|
---|
824 | get
|
---|
825 | {
|
---|
826 | return _CaseSensitiveRetrieval;
|
---|
827 | }
|
---|
828 |
|
---|
829 | set
|
---|
830 | {
|
---|
831 | // workitem 9868
|
---|
832 | if (value != _CaseSensitiveRetrieval)
|
---|
833 | {
|
---|
834 | _CaseSensitiveRetrieval = value;
|
---|
835 | _initEntriesDictionary();
|
---|
836 | }
|
---|
837 | }
|
---|
838 | }
|
---|
839 |
|
---|
840 |
|
---|
841 | /// <summary>
|
---|
842 | /// Indicates whether to encode entry filenames and entry comments using Unicode
|
---|
843 | /// (UTF-8).
|
---|
844 | /// </summary>
|
---|
845 | ///
|
---|
846 | /// <remarks>
|
---|
847 | /// <para>
|
---|
848 | /// <see href="http://www.pkware.com/documents/casestudies/APPNOTE.TXT">The
|
---|
849 | /// PKWare zip specification</see> provides for encoding file names and file
|
---|
850 | /// comments in either the IBM437 code page, or in UTF-8. This flag selects
|
---|
851 | /// the encoding according to that specification. By default, this flag is
|
---|
852 | /// false, and filenames and comments are encoded into the zip file in the
|
---|
853 | /// IBM437 codepage. Setting this flag to true will specify that filenames
|
---|
854 | /// and comments that cannot be encoded with IBM437 will be encoded with
|
---|
855 | /// UTF-8.
|
---|
856 | /// </para>
|
---|
857 | ///
|
---|
858 | /// <para>
|
---|
859 | /// Zip files created with strict adherence to the PKWare specification with
|
---|
860 | /// respect to UTF-8 encoding can contain entries with filenames containing
|
---|
861 | /// any combination of Unicode characters, including the full range of
|
---|
862 | /// characters from Chinese, Latin, Hebrew, Greek, Cyrillic, and many other
|
---|
863 | /// alphabets. However, because at this time, the UTF-8 portion of the PKWare
|
---|
864 | /// specification is not broadly supported by other zip libraries and
|
---|
865 | /// utilities, such zip files may not be readable by your favorite zip tool or
|
---|
866 | /// archiver. In other words, interoperability will decrease if you set this
|
---|
867 | /// flag to true.
|
---|
868 | /// </para>
|
---|
869 | ///
|
---|
870 | /// <para>
|
---|
871 | /// In particular, Zip files created with strict adherence to the PKWare
|
---|
872 | /// specification with respect to UTF-8 encoding will not work well with
|
---|
873 | /// Explorer in Windows XP or Windows Vista, because Windows compressed
|
---|
874 | /// folders, as far as I know, do not support UTF-8 in zip files. Vista can
|
---|
875 | /// read the zip files, but shows the filenames incorrectly. Unpacking from
|
---|
876 | /// Windows Vista Explorer will result in filenames that have rubbish
|
---|
877 | /// characters in place of the high-order UTF-8 bytes.
|
---|
878 | /// </para>
|
---|
879 | ///
|
---|
880 | /// <para>
|
---|
881 | /// Also, zip files that use UTF-8 encoding will not work well with Java
|
---|
882 | /// applications that use the java.util.zip classes, as of v5.0 of the Java
|
---|
883 | /// runtime. The Java runtime does not correctly implement the PKWare
|
---|
884 | /// specification in this regard.
|
---|
885 | /// </para>
|
---|
886 | ///
|
---|
887 | /// <para>
|
---|
888 | /// As a result, we have the unfortunate situation that "correct" behavior by
|
---|
889 | /// the DotNetZip library with regard to Unicode encoding of filenames during
|
---|
890 | /// zip creation will result in zip files that are readable by strictly
|
---|
891 | /// compliant and current tools (for example the most recent release of the
|
---|
892 | /// commercial WinZip tool); but these zip files will not be readable by
|
---|
893 | /// various other tools or libraries, including Windows Explorer.
|
---|
894 | /// </para>
|
---|
895 | ///
|
---|
896 | /// <para>
|
---|
897 | /// The DotNetZip library can read and write zip files with UTF8-encoded
|
---|
898 | /// entries, according to the PKware spec. If you use DotNetZip for both
|
---|
899 | /// creating and reading the zip file, and you use UTF-8, there will be no
|
---|
900 | /// loss of information in the filenames. For example, using a self-extractor
|
---|
901 | /// created by this library will allow you to unpack files correctly with no
|
---|
902 | /// loss of information in the filenames.
|
---|
903 | /// </para>
|
---|
904 | ///
|
---|
905 | /// <para>
|
---|
906 | /// If you do not set this flag, it will remain false. If this flag is false,
|
---|
907 | /// your <c>ZipFile</c> will encode all filenames and comments using the
|
---|
908 | /// IBM437 codepage. This can cause "loss of information" on some filenames,
|
---|
909 | /// but the resulting zipfile will be more interoperable with other
|
---|
910 | /// utilities. As an example of the loss of information, diacritics can be
|
---|
911 | /// lost. The o-tilde character will be down-coded to plain o. The c with a
|
---|
912 | /// cedilla (Unicode 0xE7) used in Portugese will be downcoded to a c.
|
---|
913 | /// Likewise, the O-stroke character (Unicode 248), used in Danish and
|
---|
914 | /// Norwegian, will be down-coded to plain o. Chinese characters cannot be
|
---|
915 | /// represented in codepage IBM437; when using the default encoding, Chinese
|
---|
916 | /// characters in filenames will be represented as ?. These are all examples
|
---|
917 | /// of "information loss".
|
---|
918 | /// </para>
|
---|
919 | ///
|
---|
920 | /// <para>
|
---|
921 | /// The loss of information associated to the use of the IBM437 encoding is
|
---|
922 | /// inconvenient, and can also lead to runtime errors. For example, using
|
---|
923 | /// IBM437, any sequence of 4 Chinese characters will be encoded as ????. If
|
---|
924 | /// your application creates a <c>ZipFile</c>, then adds two files, each with
|
---|
925 | /// names of four Chinese characters each, this will result in a duplicate
|
---|
926 | /// filename exception. In the case where you add a single file with a name
|
---|
927 | /// containing four Chinese characters, calling Extract() on the entry that
|
---|
928 | /// has question marks in the filename will result in an exception, because
|
---|
929 | /// the question mark is not legal for use within filenames on Windows. These
|
---|
930 | /// are just a few examples of the problems associated to loss of information.
|
---|
931 | /// </para>
|
---|
932 | ///
|
---|
933 | /// <para>
|
---|
934 | /// This flag is independent of the encoding of the content within the entries
|
---|
935 | /// in the zip file. Think of the zip file as a container - it supports an
|
---|
936 | /// encoding. Within the container are other "containers" - the file entries
|
---|
937 | /// themselves. The encoding within those entries is independent of the
|
---|
938 | /// encoding of the zip archive container for those entries.
|
---|
939 | /// </para>
|
---|
940 | ///
|
---|
941 | /// <para>
|
---|
942 | /// Rather than specify the encoding in a binary fashion using this flag, an
|
---|
943 | /// application can specify an arbitrary encoding via the <see
|
---|
944 | /// cref="ProvisionalAlternateEncoding"/> property. Setting the encoding
|
---|
945 | /// explicitly when creating zip archives will result in non-compliant zip
|
---|
946 | /// files that, curiously, are fairly interoperable. The challenge is, the
|
---|
947 | /// PKWare specification does not provide for a way to specify that an entry
|
---|
948 | /// in a zip archive uses a code page that is neither IBM437 nor UTF-8.
|
---|
949 | /// Therefore if you set the encoding explicitly when creating a zip archive,
|
---|
950 | /// you must take care upon reading the zip archive to use the same code page.
|
---|
951 | /// If you get it wrong, the behavior is undefined and may result in incorrect
|
---|
952 | /// filenames, exceptions, stomach upset, hair loss, and acne.
|
---|
953 | /// </para>
|
---|
954 | /// </remarks>
|
---|
955 | /// <seealso cref="ProvisionalAlternateEncoding"/>
|
---|
956 | [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.")]
|
---|
957 | public bool UseUnicodeAsNecessary
|
---|
958 | {
|
---|
959 | get
|
---|
960 | {
|
---|
961 | return (_alternateEncoding == System.Text.Encoding.GetEncoding("UTF-8")) &&
|
---|
962 | (_alternateEncodingUsage == ZipOption.AsNecessary);
|
---|
963 | }
|
---|
964 | set
|
---|
965 | {
|
---|
966 | if (value)
|
---|
967 | {
|
---|
968 | _alternateEncoding = System.Text.Encoding.GetEncoding("UTF-8");
|
---|
969 | _alternateEncodingUsage = ZipOption.AsNecessary;
|
---|
970 |
|
---|
971 | }
|
---|
972 | else
|
---|
973 | {
|
---|
974 | _alternateEncoding = Ionic.Zip.ZipFile.DefaultEncoding;
|
---|
975 | _alternateEncodingUsage = ZipOption.Never;
|
---|
976 | }
|
---|
977 | }
|
---|
978 | }
|
---|
979 |
|
---|
980 |
|
---|
981 | /// <summary>
|
---|
982 | /// Specify whether to use ZIP64 extensions when saving a zip archive.
|
---|
983 | /// </summary>
|
---|
984 | ///
|
---|
985 | /// <remarks>
|
---|
986 | ///
|
---|
987 | /// <para>
|
---|
988 | /// When creating a zip file, the default value for the property is <see
|
---|
989 | /// cref="Zip64Option.Never"/>. <see cref="Zip64Option.AsNecessary"/> is
|
---|
990 | /// safest, in the sense that you will not get an Exception if a pre-ZIP64
|
---|
991 | /// limit is exceeded.
|
---|
992 | /// </para>
|
---|
993 | ///
|
---|
994 | /// <para>
|
---|
995 | /// You may set the property at any time before calling Save().
|
---|
996 | /// </para>
|
---|
997 | ///
|
---|
998 | /// <para>
|
---|
999 | /// When reading a zip file via the <c>Zipfile.Read()</c> method, DotNetZip
|
---|
1000 | /// will properly read ZIP64-endowed zip archives, regardless of the value of
|
---|
1001 | /// this property. DotNetZip will always read ZIP64 archives. This property
|
---|
1002 | /// governs only whether DotNetZip will write them. Therefore, when updating
|
---|
1003 | /// archives, be careful about setting this property after reading an archive
|
---|
1004 | /// that may use ZIP64 extensions.
|
---|
1005 | /// </para>
|
---|
1006 | ///
|
---|
1007 | /// <para>
|
---|
1008 | /// An interesting question is, if you have set this property to
|
---|
1009 | /// <c>AsNecessary</c>, and then successfully saved, does the resulting
|
---|
1010 | /// archive use ZIP64 extensions or not? To learn this, check the <see
|
---|
1011 | /// cref="OutputUsedZip64"/> property, after calling <c>Save()</c>.
|
---|
1012 | /// </para>
|
---|
1013 | ///
|
---|
1014 | /// <para>
|
---|
1015 | /// Have you thought about
|
---|
1016 | /// <see href="http://cheeso.members.winisp.net/DotNetZipDonate.aspx">donating</see>?
|
---|
1017 | /// </para>
|
---|
1018 | ///
|
---|
1019 | /// </remarks>
|
---|
1020 | /// <seealso cref="RequiresZip64"/>
|
---|
1021 | internal Zip64Option UseZip64WhenSaving
|
---|
1022 | {
|
---|
1023 | get
|
---|
1024 | {
|
---|
1025 | return _zip64;
|
---|
1026 | }
|
---|
1027 | set
|
---|
1028 | {
|
---|
1029 | _zip64 = value;
|
---|
1030 | }
|
---|
1031 | }
|
---|
1032 |
|
---|
1033 |
|
---|
1034 |
|
---|
1035 | /// <summary>
|
---|
1036 | /// Indicates whether the archive requires ZIP64 extensions.
|
---|
1037 | /// </summary>
|
---|
1038 | ///
|
---|
1039 | /// <remarks>
|
---|
1040 | ///
|
---|
1041 | /// <para>
|
---|
1042 | /// This property is <c>null</c> (or <c>Nothing</c> in VB) if the archive has
|
---|
1043 | /// not been saved, and there are fewer than 65334 <c>ZipEntry</c> items
|
---|
1044 | /// contained in the archive.
|
---|
1045 | /// </para>
|
---|
1046 | ///
|
---|
1047 | /// <para>
|
---|
1048 | /// The <c>Value</c> is true if any of the following four conditions holds:
|
---|
1049 | /// the uncompressed size of any entry is larger than 0xFFFFFFFF; the
|
---|
1050 | /// compressed size of any entry is larger than 0xFFFFFFFF; the relative
|
---|
1051 | /// offset of any entry within the zip archive is larger than 0xFFFFFFFF; or
|
---|
1052 | /// there are more than 65534 entries in the archive. (0xFFFFFFFF =
|
---|
1053 | /// 4,294,967,295). The result may not be known until a <c>Save()</c> is attempted
|
---|
1054 | /// on the zip archive. The Value of this <see cref="System.Nullable"/>
|
---|
1055 | /// property may be set only AFTER one of the Save() methods has been called.
|
---|
1056 | /// </para>
|
---|
1057 | ///
|
---|
1058 | /// <para>
|
---|
1059 | /// If none of the four conditions holds, and the archive has been saved, then
|
---|
1060 | /// the <c>Value</c> is false.
|
---|
1061 | /// </para>
|
---|
1062 | ///
|
---|
1063 | /// <para>
|
---|
1064 | /// A <c>Value</c> of false does not indicate that the zip archive, as saved,
|
---|
1065 | /// does not use ZIP64. It merely indicates that ZIP64 is not required. An
|
---|
1066 | /// archive may use ZIP64 even when not required if the <see
|
---|
1067 | /// cref="ZipFile.UseZip64WhenSaving"/> property is set to <see
|
---|
1068 | /// cref="Zip64Option.Always"/>, or if the <see
|
---|
1069 | /// cref="ZipFile.UseZip64WhenSaving"/> property is set to <see
|
---|
1070 | /// cref="Zip64Option.AsNecessary"/> and the output stream was not
|
---|
1071 | /// seekable. Use the <see cref="OutputUsedZip64"/> property to determine if
|
---|
1072 | /// the most recent <c>Save()</c> method resulted in an archive that utilized
|
---|
1073 | /// the ZIP64 extensions.
|
---|
1074 | /// </para>
|
---|
1075 | ///
|
---|
1076 | /// </remarks>
|
---|
1077 | /// <seealso cref="UseZip64WhenSaving"/>
|
---|
1078 | /// <seealso cref="OutputUsedZip64"/>
|
---|
1079 | public Nullable<bool> RequiresZip64
|
---|
1080 | {
|
---|
1081 | get
|
---|
1082 | {
|
---|
1083 | if (_entries.Count > 65534)
|
---|
1084 | return new Nullable<bool>(true);
|
---|
1085 |
|
---|
1086 | // If the <c>ZipFile</c> has not been saved or if the contents have changed, then
|
---|
1087 | // it is not known if ZIP64 is required.
|
---|
1088 | if (!_hasBeenSaved || _contentsChanged) return null;
|
---|
1089 |
|
---|
1090 | // Whether ZIP64 is required is knowable.
|
---|
1091 | foreach (ZipEntry e in _entries.Values)
|
---|
1092 | {
|
---|
1093 | if (e.RequiresZip64.Value) return new Nullable<bool>(true);
|
---|
1094 | }
|
---|
1095 |
|
---|
1096 | return new Nullable<bool>(false);
|
---|
1097 | }
|
---|
1098 | }
|
---|
1099 |
|
---|
1100 |
|
---|
1101 | /// <summary>
|
---|
1102 | /// Indicates whether the most recent <c>Save()</c> operation used ZIP64 extensions.
|
---|
1103 | /// </summary>
|
---|
1104 | ///
|
---|
1105 | /// <remarks>
|
---|
1106 | /// <para>
|
---|
1107 | /// The use of ZIP64 extensions within an archive is not always necessary, and
|
---|
1108 | /// for interoperability concerns, it may be desired to NOT use ZIP64 if
|
---|
1109 | /// possible. The <see cref="ZipFile.UseZip64WhenSaving"/> property can be
|
---|
1110 | /// set to use ZIP64 extensions only when necessary. In those cases,
|
---|
1111 | /// Sometimes applications want to know whether a Save() actually used ZIP64
|
---|
1112 | /// extensions. Applications can query this read-only property to learn
|
---|
1113 | /// whether ZIP64 has been used in a just-saved <c>ZipFile</c>.
|
---|
1114 | /// </para>
|
---|
1115 | ///
|
---|
1116 | /// <para>
|
---|
1117 | /// The value is <c>null</c> (or <c>Nothing</c> in VB) if the archive has not
|
---|
1118 | /// been saved.
|
---|
1119 | /// </para>
|
---|
1120 | ///
|
---|
1121 | /// <para>
|
---|
1122 | /// Non-null values (<c>HasValue</c> is true) indicate whether ZIP64
|
---|
1123 | /// extensions were used during the most recent <c>Save()</c> operation. The
|
---|
1124 | /// ZIP64 extensions may have been used as required by any particular entry
|
---|
1125 | /// because of its uncompressed or compressed size, or because the archive is
|
---|
1126 | /// larger than 4294967295 bytes, or because there are more than 65534 entries
|
---|
1127 | /// in the archive, or because the <c>UseZip64WhenSaving</c> property was set
|
---|
1128 | /// to <see cref="Zip64Option.Always"/>, or because the
|
---|
1129 | /// <c>UseZip64WhenSaving</c> property was set to <see
|
---|
1130 | /// cref="Zip64Option.AsNecessary"/> and the output stream was not seekable.
|
---|
1131 | /// The value of this property does not indicate the reason the ZIP64
|
---|
1132 | /// extensions were used.
|
---|
1133 | /// </para>
|
---|
1134 | ///
|
---|
1135 | /// </remarks>
|
---|
1136 | /// <seealso cref="UseZip64WhenSaving"/>
|
---|
1137 | /// <seealso cref="RequiresZip64"/>
|
---|
1138 | public Nullable<bool> OutputUsedZip64
|
---|
1139 | {
|
---|
1140 | get
|
---|
1141 | {
|
---|
1142 | return _OutputUsesZip64;
|
---|
1143 | }
|
---|
1144 | }
|
---|
1145 |
|
---|
1146 |
|
---|
1147 | /// <summary>
|
---|
1148 | /// Indicates whether the most recent <c>Read()</c> operation read a zip file that uses
|
---|
1149 | /// ZIP64 extensions.
|
---|
1150 | /// </summary>
|
---|
1151 | ///
|
---|
1152 | /// <remarks>
|
---|
1153 | /// This property will return null (Nothing in VB) if you've added an entry after reading
|
---|
1154 | /// the zip file.
|
---|
1155 | /// </remarks>
|
---|
1156 | public Nullable<bool> InputUsesZip64
|
---|
1157 | {
|
---|
1158 | get
|
---|
1159 | {
|
---|
1160 | if (_entries.Count > 65534)
|
---|
1161 | return true;
|
---|
1162 |
|
---|
1163 | foreach (ZipEntry e in this)
|
---|
1164 | {
|
---|
1165 | // if any entry was added after reading the zip file, then the result is null
|
---|
1166 | if (e.Source != ZipEntrySource.ZipFile) return null;
|
---|
1167 |
|
---|
1168 | // if any entry read from the zip used zip64, then the result is true
|
---|
1169 | if (e._InputUsesZip64) return true;
|
---|
1170 | }
|
---|
1171 | return false;
|
---|
1172 | }
|
---|
1173 | }
|
---|
1174 |
|
---|
1175 |
|
---|
1176 | /// <summary>
|
---|
1177 | /// The text encoding to use when writing new entries to the <c>ZipFile</c>,
|
---|
1178 | /// for those entries that cannot be encoded with the default (IBM437)
|
---|
1179 | /// encoding; or, the text encoding that was used when reading the entries
|
---|
1180 | /// from the <c>ZipFile</c>.
|
---|
1181 | /// </summary>
|
---|
1182 | ///
|
---|
1183 | /// <remarks>
|
---|
1184 | /// <para>
|
---|
1185 | /// In <see href="http://www.pkware.com/documents/casestudies/APPNOTE.TXT">its
|
---|
1186 | /// zip specification</see>, PKWare describes two options for encoding
|
---|
1187 | /// filenames and comments: using IBM437 or UTF-8. But, some archiving tools
|
---|
1188 | /// or libraries do not follow the specification, and instead encode
|
---|
1189 | /// characters using the system default code page. For example, WinRAR when
|
---|
1190 | /// run on a machine in Shanghai may encode filenames with the Big-5 Chinese
|
---|
1191 | /// (950) code page. This behavior is contrary to the Zip specification, but
|
---|
1192 | /// it occurs anyway.
|
---|
1193 | /// </para>
|
---|
1194 | ///
|
---|
1195 | /// <para>
|
---|
1196 | /// When using DotNetZip to write zip archives that will be read by one of
|
---|
1197 | /// these other archivers, set this property to specify the code page to use
|
---|
1198 | /// when encoding the <see cref="ZipEntry.FileName"/> and <see
|
---|
1199 | /// cref="ZipEntry.Comment"/> for each <c>ZipEntry</c> in the zip file, for
|
---|
1200 | /// values that cannot be encoded with the default codepage for zip files,
|
---|
1201 | /// IBM437. This is why this property is "provisional". In all cases, IBM437
|
---|
1202 | /// is used where possible, in other words, where no loss of data would
|
---|
1203 | /// result. It is possible, therefore, to have a given entry with a
|
---|
1204 | /// <c>Comment</c> encoded in IBM437 and a <c>FileName</c> encoded with the
|
---|
1205 | /// specified "provisional" codepage.
|
---|
1206 | /// </para>
|
---|
1207 | ///
|
---|
1208 | /// <para>
|
---|
1209 | /// Be aware that a zip file created after you've explicitly set the <see
|
---|
1210 | /// cref="ProvisionalAlternateEncoding" /> property to a value other than
|
---|
1211 | /// IBM437 may not be compliant to the PKWare specification, and may not be
|
---|
1212 | /// readable by compliant archivers. On the other hand, many (most?)
|
---|
1213 | /// archivers are non-compliant and can read zip files created in arbitrary
|
---|
1214 | /// code pages. The trick is to use or specify the proper codepage when
|
---|
1215 | /// reading the zip.
|
---|
1216 | /// </para>
|
---|
1217 | ///
|
---|
1218 | /// <para>
|
---|
1219 | /// When creating a zip archive using this library, it is possible to change
|
---|
1220 | /// the value of <see cref="ProvisionalAlternateEncoding" /> between each
|
---|
1221 | /// entry you add, and between adding entries and the call to
|
---|
1222 | /// <c>Save()</c>. Don't do this. It will likely result in a zipfile that is
|
---|
1223 | /// not readable. For best interoperability, either leave <see
|
---|
1224 | /// cref="ProvisionalAlternateEncoding" /> alone, or specify it only once,
|
---|
1225 | /// before adding any entries to the <c>ZipFile</c> instance. There is one
|
---|
1226 | /// exception to this recommendation, described later.
|
---|
1227 | /// </para>
|
---|
1228 | ///
|
---|
1229 | /// <para>
|
---|
1230 | /// When using an arbitrary, non-UTF8 code page for encoding, there is no
|
---|
1231 | /// standard way for the creator application - whether DotNetZip, WinZip,
|
---|
1232 | /// WinRar, or something else - to formally specify in the zip file which
|
---|
1233 | /// codepage has been used for the entries. As a result, readers of zip files
|
---|
1234 | /// are not able to inspect the zip file and determine the codepage that was
|
---|
1235 | /// used for the entries contained within it. It is left to the application
|
---|
1236 | /// or user to determine the necessary codepage when reading zip files encoded
|
---|
1237 | /// this way. In other words, if you explicitly specify the codepage when you
|
---|
1238 | /// create the zipfile, you must explicitly specify the same codepage when
|
---|
1239 | /// reading the zipfile.
|
---|
1240 | /// </para>
|
---|
1241 | ///
|
---|
1242 | /// <para>
|
---|
1243 | /// The way you specify the code page to use when reading a zip file varies
|
---|
1244 | /// depending on the tool or library you use to read the zip. In DotNetZip,
|
---|
1245 | /// you use a ZipFile.Read() method that accepts an encoding parameter. It
|
---|
1246 | /// isn't possible with Windows Explorer, as far as I know, to specify an
|
---|
1247 | /// explicit codepage to use when reading a zip. If you use an incorrect
|
---|
1248 | /// codepage when reading a zipfile, you will get entries with filenames that
|
---|
1249 | /// are incorrect, and the incorrect filenames may even contain characters
|
---|
1250 | /// that are not legal for use within filenames in Windows. Extracting entries
|
---|
1251 | /// with illegal characters in the filenames will lead to exceptions. It's too
|
---|
1252 | /// bad, but this is just the way things are with code pages in zip
|
---|
1253 | /// files. Caveat Emptor.
|
---|
1254 | /// </para>
|
---|
1255 | ///
|
---|
1256 | /// <para>
|
---|
1257 | /// Example: Suppose you create a zipfile that contains entries with
|
---|
1258 | /// filenames that have Danish characters. If you use <see
|
---|
1259 | /// cref="ProvisionalAlternateEncoding" /> equal to "iso-8859-1" (cp 28591),
|
---|
1260 | /// the filenames will be correctly encoded in the zip. But, to read that
|
---|
1261 | /// zipfile correctly, you have to specify the same codepage at the time you
|
---|
1262 | /// read it. If try to read that zip file with Windows Explorer or another
|
---|
1263 | /// application that is not flexible with respect to the codepage used to
|
---|
1264 | /// decode filenames in zipfiles, you will get a filename like "Infᅵ.txt".
|
---|
1265 | /// </para>
|
---|
1266 | ///
|
---|
1267 | /// <para>
|
---|
1268 | /// When using DotNetZip to read a zip archive, and the zip archive uses an
|
---|
1269 | /// arbitrary code page, you must specify the encoding to use before or when
|
---|
1270 | /// the <c>Zipfile</c> is READ. This means you must use a <c>ZipFile.Read()</c>
|
---|
1271 | /// method that allows you to specify a System.Text.Encoding parameter. Setting
|
---|
1272 | /// the ProvisionalAlternateEncoding property after your application has read in
|
---|
1273 | /// the zip archive will not affect the entry names of entries that have already
|
---|
1274 | /// been read in.
|
---|
1275 | /// </para>
|
---|
1276 | ///
|
---|
1277 | /// <para>
|
---|
1278 | /// And now, the exception to the rule described above. One strategy for
|
---|
1279 | /// specifying the code page for a given zip file is to describe the code page
|
---|
1280 | /// in a human-readable form in the Zip comment. For example, the comment may
|
---|
1281 | /// read "Entries in this archive are encoded in the Big5 code page". For
|
---|
1282 | /// maximum interoperability, the zip comment in this case should be encoded
|
---|
1283 | /// in the default, IBM437 code page. In this case, the zip comment is
|
---|
1284 | /// encoded using a different page than the filenames. To do this, Specify
|
---|
1285 | /// <c>ProvisionalAlternateEncoding</c> to your desired region-specific code
|
---|
1286 | /// page, once before adding any entries, and then reset
|
---|
1287 | /// <c>ProvisionalAlternateEncoding</c> to IBM437 before setting the <see
|
---|
1288 | /// cref="Comment"/> property and calling Save().
|
---|
1289 | /// </para>
|
---|
1290 | /// </remarks>
|
---|
1291 | ///
|
---|
1292 | /// <example>
|
---|
1293 | /// This example shows how to read a zip file using the Big-5 Chinese code page
|
---|
1294 | /// (950), and extract each entry in the zip file. For this code to work as
|
---|
1295 | /// desired, the <c>Zipfile</c> must have been created using the big5 code page
|
---|
1296 | /// (CP950). This is typical, for example, when using WinRar on a machine with
|
---|
1297 | /// CP950 set as the default code page. In that case, the names of entries
|
---|
1298 | /// within the Zip archive will be stored in that code page, and reading the zip
|
---|
1299 | /// archive must be done using that code page. If the application did not use
|
---|
1300 | /// the correct code page in <c>ZipFile.Read()</c>, then names of entries within the
|
---|
1301 | /// zip archive would not be correctly retrieved.
|
---|
1302 | /// <code>
|
---|
1303 | /// using (var zip = ZipFile.Read(zipFileName, System.Text.Encoding.GetEncoding("big5")))
|
---|
1304 | /// {
|
---|
1305 | /// // retrieve and extract an entry using a name encoded with CP950
|
---|
1306 | /// zip[MyDesiredEntry].Extract("unpack");
|
---|
1307 | /// }
|
---|
1308 | /// </code>
|
---|
1309 | ///
|
---|
1310 | /// <code lang="VB">
|
---|
1311 | /// Using zip As ZipFile = ZipFile.Read(ZipToExtract, System.Text.Encoding.GetEncoding("big5"))
|
---|
1312 | /// ' retrieve and extract an entry using a name encoded with CP950
|
---|
1313 | /// zip(MyDesiredEntry).Extract("unpack")
|
---|
1314 | /// End Using
|
---|
1315 | /// </code>
|
---|
1316 | /// </example>
|
---|
1317 | ///
|
---|
1318 | /// <seealso cref="Ionic.Zip.ZipFile.DefaultEncoding">DefaultEncoding</seealso>
|
---|
1319 | [Obsolete("use AlternateEncoding instead.")]
|
---|
1320 | public System.Text.Encoding ProvisionalAlternateEncoding
|
---|
1321 | {
|
---|
1322 | get
|
---|
1323 | {
|
---|
1324 | if (_alternateEncodingUsage == ZipOption.AsNecessary)
|
---|
1325 | return _alternateEncoding;
|
---|
1326 | return null;
|
---|
1327 | }
|
---|
1328 | set
|
---|
1329 | {
|
---|
1330 | _alternateEncoding = value;
|
---|
1331 | _alternateEncodingUsage = ZipOption.AsNecessary;
|
---|
1332 | }
|
---|
1333 | }
|
---|
1334 |
|
---|
1335 |
|
---|
1336 | /// <summary>
|
---|
1337 | /// A Text Encoding to use when encoding the filenames and comments for
|
---|
1338 | /// all the ZipEntry items, during a ZipFile.Save() operation.
|
---|
1339 | /// </summary>
|
---|
1340 | /// <remarks>
|
---|
1341 | /// <para>
|
---|
1342 | /// Whether the encoding specified here is used during the save depends
|
---|
1343 | /// on <see cref="AlternateEncodingUsage"/>.
|
---|
1344 | /// </para>
|
---|
1345 | /// </remarks>
|
---|
1346 | public System.Text.Encoding AlternateEncoding
|
---|
1347 | {
|
---|
1348 | get
|
---|
1349 | {
|
---|
1350 | return _alternateEncoding;
|
---|
1351 | }
|
---|
1352 | set
|
---|
1353 | {
|
---|
1354 | _alternateEncoding = value;
|
---|
1355 | }
|
---|
1356 | }
|
---|
1357 |
|
---|
1358 |
|
---|
1359 | /// <summary>
|
---|
1360 | /// A flag that tells if and when this instance should apply
|
---|
1361 | /// AlternateEncoding to encode the filenames and comments associated to
|
---|
1362 | /// of ZipEntry objects contained within this instance.
|
---|
1363 | /// </summary>
|
---|
1364 | internal ZipOption AlternateEncodingUsage
|
---|
1365 | {
|
---|
1366 | get
|
---|
1367 | {
|
---|
1368 | return _alternateEncodingUsage;
|
---|
1369 | }
|
---|
1370 | set
|
---|
1371 | {
|
---|
1372 | _alternateEncodingUsage = value;
|
---|
1373 | }
|
---|
1374 | }
|
---|
1375 |
|
---|
1376 |
|
---|
1377 | /// <summary>
|
---|
1378 | /// The default text encoding used in zip archives. It is numeric 437, also
|
---|
1379 | /// known as IBM437.
|
---|
1380 | /// </summary>
|
---|
1381 | /// <seealso cref="Ionic.Zip.ZipFile.ProvisionalAlternateEncoding"/>
|
---|
1382 | public static System.Text.Encoding DefaultEncoding
|
---|
1383 | {
|
---|
1384 | get
|
---|
1385 | {
|
---|
1386 | return _defaultEncoding;
|
---|
1387 | }
|
---|
1388 | }
|
---|
1389 |
|
---|
1390 |
|
---|
1391 | /// <summary>
|
---|
1392 | /// Gets or sets the <c>TextWriter</c> to which status messages are delivered
|
---|
1393 | /// for the instance.
|
---|
1394 | /// </summary>
|
---|
1395 | ///
|
---|
1396 | /// <remarks>
|
---|
1397 | /// If the TextWriter is set to a non-null value, then verbose output is sent
|
---|
1398 | /// to the <c>TextWriter</c> during <c>Add</c><c>, Read</c><c>, Save</c> and
|
---|
1399 | /// <c>Extract</c> operations. Typically, console applications might use
|
---|
1400 | /// <c>Console.Out</c> and graphical or headless applications might use a
|
---|
1401 | /// <c>System.IO.StringWriter</c>. The output of this is suitable for viewing
|
---|
1402 | /// by humans.
|
---|
1403 | /// </remarks>
|
---|
1404 | ///
|
---|
1405 | /// <example>
|
---|
1406 | /// <para>
|
---|
1407 | /// In this example, a console application instantiates a <c>ZipFile</c>, then
|
---|
1408 | /// sets the <c>StatusMessageTextWriter</c> to <c>Console.Out</c>. At that
|
---|
1409 | /// point, all verbose status messages for that <c>ZipFile</c> are sent to the
|
---|
1410 | /// console.
|
---|
1411 | /// </para>
|
---|
1412 | ///
|
---|
1413 | /// <code lang="C#">
|
---|
1414 | /// using (ZipFile zip= ZipFile.Read(FilePath))
|
---|
1415 | /// {
|
---|
1416 | /// zip.StatusMessageTextWriter= System.Console.Out;
|
---|
1417 | /// // messages are sent to the console during extraction
|
---|
1418 | /// zip.ExtractAll();
|
---|
1419 | /// }
|
---|
1420 | /// </code>
|
---|
1421 | ///
|
---|
1422 | /// <code lang="VB">
|
---|
1423 | /// Using zip As ZipFile = ZipFile.Read(FilePath)
|
---|
1424 | /// zip.StatusMessageTextWriter= System.Console.Out
|
---|
1425 | /// 'Status Messages will be sent to the console during extraction
|
---|
1426 | /// zip.ExtractAll()
|
---|
1427 | /// End Using
|
---|
1428 | /// </code>
|
---|
1429 | ///
|
---|
1430 | /// <para>
|
---|
1431 | /// In this example, a Windows Forms application instantiates a
|
---|
1432 | /// <c>ZipFile</c>, then sets the <c>StatusMessageTextWriter</c> to a
|
---|
1433 | /// <c>StringWriter</c>. At that point, all verbose status messages for that
|
---|
1434 | /// <c>ZipFile</c> are sent to the <c>StringWriter</c>.
|
---|
1435 | /// </para>
|
---|
1436 | ///
|
---|
1437 | /// <code lang="C#">
|
---|
1438 | /// var sw = new System.IO.StringWriter();
|
---|
1439 | /// using (ZipFile zip= ZipFile.Read(FilePath))
|
---|
1440 | /// {
|
---|
1441 | /// zip.StatusMessageTextWriter= sw;
|
---|
1442 | /// zip.ExtractAll();
|
---|
1443 | /// }
|
---|
1444 | /// Console.WriteLine("{0}", sw.ToString());
|
---|
1445 | /// </code>
|
---|
1446 | ///
|
---|
1447 | /// <code lang="VB">
|
---|
1448 | /// Dim sw as New System.IO.StringWriter
|
---|
1449 | /// Using zip As ZipFile = ZipFile.Read(FilePath)
|
---|
1450 | /// zip.StatusMessageTextWriter= sw
|
---|
1451 | /// zip.ExtractAll()
|
---|
1452 | /// End Using
|
---|
1453 | /// 'Status Messages are now available in sw
|
---|
1454 | ///
|
---|
1455 | /// </code>
|
---|
1456 | /// </example>
|
---|
1457 | public TextWriter StatusMessageTextWriter
|
---|
1458 | {
|
---|
1459 | get { return _StatusMessageTextWriter; }
|
---|
1460 | set { _StatusMessageTextWriter = value; }
|
---|
1461 | }
|
---|
1462 |
|
---|
1463 |
|
---|
1464 |
|
---|
1465 |
|
---|
1466 | /// <summary>
|
---|
1467 | /// Gets or sets the name for the folder to store the temporary file
|
---|
1468 | /// this library writes when saving a zip archive.
|
---|
1469 | /// </summary>
|
---|
1470 | ///
|
---|
1471 | /// <remarks>
|
---|
1472 | /// <para>
|
---|
1473 | /// This library will create a temporary file when saving a Zip archive to a
|
---|
1474 | /// file. This file is written when calling one of the <c>Save()</c> methods
|
---|
1475 | /// that does not save to a stream, or one of the <c>SaveSelfExtractor()</c>
|
---|
1476 | /// methods.
|
---|
1477 | /// </para>
|
---|
1478 | ///
|
---|
1479 | /// <para>
|
---|
1480 | /// By default, the library will create the temporary file in the directory
|
---|
1481 | /// specified for the file itself, via the <see cref="Name"/> property or via
|
---|
1482 | /// the <see cref="ZipFile.Save(String)"/> method.
|
---|
1483 | /// </para>
|
---|
1484 | ///
|
---|
1485 | /// <para>
|
---|
1486 | /// Setting this property allows applications to override this default
|
---|
1487 | /// behavior, so that the library will create the temporary file in the
|
---|
1488 | /// specified folder. For example, to have the library create the temporary
|
---|
1489 | /// file in the current working directory, regardless where the <c>ZipFile</c>
|
---|
1490 | /// is saved, specfy ".". To revert to the default behavior, set this
|
---|
1491 | /// property to <c>null</c> (<c>Nothing</c> in VB).
|
---|
1492 | /// </para>
|
---|
1493 | ///
|
---|
1494 | /// <para>
|
---|
1495 | /// When setting the property to a non-null value, the folder specified must
|
---|
1496 | /// exist; if it does not an exception is thrown. The application should have
|
---|
1497 | /// write and delete permissions on the folder. The permissions are not
|
---|
1498 | /// explicitly checked ahead of time; if the application does not have the
|
---|
1499 | /// appropriate rights, an exception will be thrown at the time <c>Save()</c>
|
---|
1500 | /// is called.
|
---|
1501 | /// </para>
|
---|
1502 | ///
|
---|
1503 | /// <para>
|
---|
1504 | /// There is no temporary file created when reading a zip archive. When
|
---|
1505 | /// saving to a Stream, there is no temporary file created. For example, if
|
---|
1506 | /// the application is an ASP.NET application and calls <c>Save()</c>
|
---|
1507 | /// specifying the <c>Response.OutputStream</c> as the output stream, there is
|
---|
1508 | /// no temporary file created.
|
---|
1509 | /// </para>
|
---|
1510 | /// </remarks>
|
---|
1511 | ///
|
---|
1512 | /// <exception cref="System.IO.FileNotFoundException">
|
---|
1513 | /// Thrown when setting the property if the directory does not exist.
|
---|
1514 | /// </exception>
|
---|
1515 | ///
|
---|
1516 | public String TempFileFolder
|
---|
1517 | {
|
---|
1518 | get { return _TempFileFolder; }
|
---|
1519 |
|
---|
1520 | set
|
---|
1521 | {
|
---|
1522 | _TempFileFolder = value;
|
---|
1523 | if (value == null) return;
|
---|
1524 |
|
---|
1525 | if (!Directory.Exists(value))
|
---|
1526 | throw new FileNotFoundException(String.Format("That directory ({0}) does not exist.", value));
|
---|
1527 |
|
---|
1528 | }
|
---|
1529 | }
|
---|
1530 |
|
---|
1531 | /// <summary>
|
---|
1532 | /// Sets the password to be used on the <c>ZipFile</c> instance.
|
---|
1533 | /// </summary>
|
---|
1534 | ///
|
---|
1535 | /// <remarks>
|
---|
1536 | ///
|
---|
1537 | /// <para>
|
---|
1538 | /// When writing a zip archive, this password is applied to the entries, not
|
---|
1539 | /// to the zip archive itself. It applies to any <c>ZipEntry</c> subsequently
|
---|
1540 | /// added to the <c>ZipFile</c>, using one of the <c>AddFile</c>,
|
---|
1541 | /// <c>AddDirectory</c>, <c>AddEntry</c>, or <c>AddItem</c> methods, etc.
|
---|
1542 | /// When reading a zip archive, this property applies to any entry
|
---|
1543 | /// subsequently extracted from the <c>ZipFile</c> using one of the Extract
|
---|
1544 | /// methods on the <c>ZipFile</c> class.
|
---|
1545 | /// </para>
|
---|
1546 | ///
|
---|
1547 | /// <para>
|
---|
1548 | /// When writing a zip archive, keep this in mind: though the password is set
|
---|
1549 | /// on the ZipFile object, according to the Zip spec, the "directory" of the
|
---|
1550 | /// archive - in other words the list of entries or files contained in the archive - is
|
---|
1551 | /// not encrypted with the password, or protected in any way. If you set the
|
---|
1552 | /// Password property, the password actually applies to individual entries
|
---|
1553 | /// that are added to the archive, subsequent to the setting of this property.
|
---|
1554 | /// The list of filenames in the archive that is eventually created will
|
---|
1555 | /// appear in clear text, but the contents of the individual files are
|
---|
1556 | /// encrypted. This is how Zip encryption works.
|
---|
1557 | /// </para>
|
---|
1558 | ///
|
---|
1559 | /// <para>
|
---|
1560 | /// One simple way around this limitation is to simply double-wrap sensitive
|
---|
1561 | /// filenames: Store the files in a zip file, and then store that zip file
|
---|
1562 | /// within a second, "outer" zip file. If you apply a password to the outer
|
---|
1563 | /// zip file, then readers will be able to see that the outer zip file
|
---|
1564 | /// contains an inner zip file. But readers will not be able to read the
|
---|
1565 | /// directory or file list of the inner zip file.
|
---|
1566 | /// </para>
|
---|
1567 | ///
|
---|
1568 | /// <para>
|
---|
1569 | /// If you set the password on the <c>ZipFile</c>, and then add a set of files
|
---|
1570 | /// to the archive, then each entry is encrypted with that password. You may
|
---|
1571 | /// also want to change the password between adding different entries. If you
|
---|
1572 | /// set the password, add an entry, then set the password to <c>null</c>
|
---|
1573 | /// (<c>Nothing</c> in VB), and add another entry, the first entry is
|
---|
1574 | /// encrypted and the second is not. If you call <c>AddFile()</c>, then set
|
---|
1575 | /// the <c>Password</c> property, then call <c>ZipFile.Save</c>, the file
|
---|
1576 | /// added will not be password-protected, and no warning will be generated.
|
---|
1577 | /// </para>
|
---|
1578 | ///
|
---|
1579 | /// <para>
|
---|
1580 | /// When setting the Password, you may also want to explicitly set the <see
|
---|
1581 | /// cref="Encryption"/> property, to specify how to encrypt the entries added
|
---|
1582 | /// to the ZipFile. If you set the Password to a non-null value and do not
|
---|
1583 | /// set <see cref="Encryption"/>, then PKZip 2.0 ("Weak") encryption is used.
|
---|
1584 | /// This encryption is relatively weak but is very interoperable. If you set
|
---|
1585 | /// the password to a <c>null</c> value (<c>Nothing</c> in VB), Encryption is
|
---|
1586 | /// reset to None.
|
---|
1587 | /// </para>
|
---|
1588 | ///
|
---|
1589 | /// <para>
|
---|
1590 | /// All of the preceding applies to writing zip archives, in other words when
|
---|
1591 | /// you use one of the Save methods. To use this property when reading or an
|
---|
1592 | /// existing ZipFile, do the following: set the Password property on the
|
---|
1593 | /// <c>ZipFile</c>, then call one of the Extract() overloads on the <see
|
---|
1594 | /// cref="ZipEntry" />. In this case, the entry is extracted using the
|
---|
1595 | /// <c>Password</c> that is specified on the <c>ZipFile</c> instance. If you
|
---|
1596 | /// have not set the <c>Password</c> property, then the password is
|
---|
1597 | /// <c>null</c>, and the entry is extracted with no password.
|
---|
1598 | /// </para>
|
---|
1599 | ///
|
---|
1600 | /// <para>
|
---|
1601 | /// If you set the Password property on the <c>ZipFile</c>, then call
|
---|
1602 | /// <c>Extract()</c> an entry that has not been encrypted with a password, the
|
---|
1603 | /// password is not used for that entry, and the <c>ZipEntry</c> is extracted
|
---|
1604 | /// as normal. In other words, the password is used only if necessary.
|
---|
1605 | /// </para>
|
---|
1606 | ///
|
---|
1607 | /// <para>
|
---|
1608 | /// The <see cref="ZipEntry"/> class also has a <see
|
---|
1609 | /// cref="ZipEntry.Password">Password</see> property. It takes precedence
|
---|
1610 | /// over this property on the <c>ZipFile</c>. Typically, you would use the
|
---|
1611 | /// per-entry Password when most entries in the zip archive use one password,
|
---|
1612 | /// and a few entries use a different password. If all entries in the zip
|
---|
1613 | /// file use the same password, then it is simpler to just set this property
|
---|
1614 | /// on the <c>ZipFile</c> itself, whether creating a zip archive or extracting
|
---|
1615 | /// a zip archive.
|
---|
1616 | /// </para>
|
---|
1617 | ///
|
---|
1618 | /// </remarks>
|
---|
1619 | ///
|
---|
1620 | /// <example>
|
---|
1621 | /// <para>
|
---|
1622 | /// This example creates a zip file, using password protection for the
|
---|
1623 | /// entries, and then extracts the entries from the zip file. When creating
|
---|
1624 | /// the zip file, the Readme.txt file is not protected with a password, but
|
---|
1625 | /// the other two are password-protected as they are saved. During extraction,
|
---|
1626 | /// each file is extracted with the appropriate password.
|
---|
1627 | /// </para>
|
---|
1628 | /// <code>
|
---|
1629 | /// // create a file with encryption
|
---|
1630 | /// using (ZipFile zip = new ZipFile())
|
---|
1631 | /// {
|
---|
1632 | /// zip.AddFile("ReadMe.txt");
|
---|
1633 | /// zip.Password= "!Secret1";
|
---|
1634 | /// zip.AddFile("MapToTheSite-7440-N49th.png");
|
---|
1635 | /// zip.AddFile("2008-Regional-Sales-Report.pdf");
|
---|
1636 | /// zip.Save("EncryptedArchive.zip");
|
---|
1637 | /// }
|
---|
1638 | ///
|
---|
1639 | /// // extract entries that use encryption
|
---|
1640 | /// using (ZipFile zip = ZipFile.Read("EncryptedArchive.zip"))
|
---|
1641 | /// {
|
---|
1642 | /// zip.Password= "!Secret1";
|
---|
1643 | /// zip.ExtractAll("extractDir");
|
---|
1644 | /// }
|
---|
1645 | ///
|
---|
1646 | /// </code>
|
---|
1647 | ///
|
---|
1648 | /// <code lang="VB">
|
---|
1649 | /// Using zip As New ZipFile
|
---|
1650 | /// zip.AddFile("ReadMe.txt")
|
---|
1651 | /// zip.Password = "123456!"
|
---|
1652 | /// zip.AddFile("MapToTheSite-7440-N49th.png")
|
---|
1653 | /// zip.Password= "!Secret1";
|
---|
1654 | /// zip.AddFile("2008-Regional-Sales-Report.pdf")
|
---|
1655 | /// zip.Save("EncryptedArchive.zip")
|
---|
1656 | /// End Using
|
---|
1657 | ///
|
---|
1658 | ///
|
---|
1659 | /// ' extract entries that use encryption
|
---|
1660 | /// Using (zip as ZipFile = ZipFile.Read("EncryptedArchive.zip"))
|
---|
1661 | /// zip.Password= "!Secret1"
|
---|
1662 | /// zip.ExtractAll("extractDir")
|
---|
1663 | /// End Using
|
---|
1664 | ///
|
---|
1665 | /// </code>
|
---|
1666 | ///
|
---|
1667 | /// </example>
|
---|
1668 | ///
|
---|
1669 | /// <seealso cref="Ionic.Zip.ZipFile.Encryption">ZipFile.Encryption</seealso>
|
---|
1670 | /// <seealso cref="ZipEntry.Password">ZipEntry.Password</seealso>
|
---|
1671 | public String Password
|
---|
1672 | {
|
---|
1673 | set
|
---|
1674 | {
|
---|
1675 | _Password = value;
|
---|
1676 | if (_Password == null)
|
---|
1677 | {
|
---|
1678 | Encryption = EncryptionAlgorithm.None;
|
---|
1679 | }
|
---|
1680 | else if (Encryption == EncryptionAlgorithm.None)
|
---|
1681 | {
|
---|
1682 | Encryption = EncryptionAlgorithm.PkzipWeak;
|
---|
1683 | }
|
---|
1684 | }
|
---|
1685 | private get
|
---|
1686 | {
|
---|
1687 | return _Password;
|
---|
1688 | }
|
---|
1689 | }
|
---|
1690 |
|
---|
1691 |
|
---|
1692 |
|
---|
1693 |
|
---|
1694 |
|
---|
1695 | /// <summary>
|
---|
1696 | /// The action the library should take when extracting a file that already
|
---|
1697 | /// exists.
|
---|
1698 | /// </summary>
|
---|
1699 | ///
|
---|
1700 | /// <remarks>
|
---|
1701 | /// <para>
|
---|
1702 | /// This property affects the behavior of the Extract methods (one of the
|
---|
1703 | /// <c>Extract()</c> or <c>ExtractWithPassword()</c> overloads), when
|
---|
1704 | /// extraction would would overwrite an existing filesystem file. If you do
|
---|
1705 | /// not set this property, the library throws an exception when extracting an
|
---|
1706 | /// entry would overwrite an existing file.
|
---|
1707 | /// </para>
|
---|
1708 | ///
|
---|
1709 | /// <para>
|
---|
1710 | /// This property has no effect when extracting to a stream, or when the file
|
---|
1711 | /// to be extracted does not already exist.
|
---|
1712 | /// </para>
|
---|
1713 | /// </remarks>
|
---|
1714 | /// <seealso cref="ZipEntry.ExtractExistingFile"/>
|
---|
1715 | internal ExtractExistingFileAction ExtractExistingFile
|
---|
1716 | {
|
---|
1717 | get;
|
---|
1718 | set;
|
---|
1719 | }
|
---|
1720 |
|
---|
1721 |
|
---|
1722 | /// <summary>
|
---|
1723 | /// The action the library should take when an error is encountered while
|
---|
1724 | /// opening or reading files as they are saved into a zip archive.
|
---|
1725 | /// </summary>
|
---|
1726 | ///
|
---|
1727 | /// <remarks>
|
---|
1728 | /// <para>
|
---|
1729 | /// Errors can occur as a file is being saved to the zip archive. For
|
---|
1730 | /// example, the File.Open may fail, or a File.Read may fail, because of
|
---|
1731 | /// lock conflicts or other reasons.
|
---|
1732 | /// </para>
|
---|
1733 | ///
|
---|
1734 | /// <para>
|
---|
1735 | /// The first problem might occur after having called AddDirectory() on a
|
---|
1736 | /// directory that contains a Clipper .dbf file; the file is locked by
|
---|
1737 | /// Clipper and cannot be opened for read by another process. An example of
|
---|
1738 | /// the second problem might occur when trying to zip a .pst file that is in
|
---|
1739 | /// use by Microsoft Outlook. Outlook locks a range on the file, which allows
|
---|
1740 | /// other processes to open the file, but not read it in its entirety.
|
---|
1741 | /// </para>
|
---|
1742 | ///
|
---|
1743 | /// <para>
|
---|
1744 | /// This property tells DotNetZip what you would like to do in the case of
|
---|
1745 | /// these errors. The primary options are: <c>ZipErrorAction.Throw</c> to
|
---|
1746 | /// throw an exception (this is the default behavior if you don't set this
|
---|
1747 | /// property); <c>ZipErrorAction.Skip</c> to Skip the file for which there
|
---|
1748 | /// was an error and continue saving; <c>ZipErrorAction.Retry</c> to Retry
|
---|
1749 | /// the entry that caused the problem; or
|
---|
1750 | /// <c>ZipErrorAction.InvokeErrorEvent</c> to invoke an event handler.
|
---|
1751 | /// </para>
|
---|
1752 | ///
|
---|
1753 | /// <para>
|
---|
1754 | /// This property is implicitly set to <c>ZipErrorAction.InvokeErrorEvent</c>
|
---|
1755 | /// if you add a handler to the <see cref="ZipError" /> event. If you set
|
---|
1756 | /// this property to something other than
|
---|
1757 | /// <c>ZipErrorAction.InvokeErrorEvent</c>, then the <c>ZipError</c>
|
---|
1758 | /// event is implicitly cleared. What it means is you can set one or the
|
---|
1759 | /// other (or neither), depending on what you want, but you never need to set
|
---|
1760 | /// both.
|
---|
1761 | /// </para>
|
---|
1762 | ///
|
---|
1763 | /// <para>
|
---|
1764 | /// As with some other properties on the <c>ZipFile</c> class, like <see
|
---|
1765 | /// cref="Password"/>, <see cref="Encryption"/>, and <see
|
---|
1766 | /// cref="CompressionLevel"/>, setting this property on a <c>ZipFile</c>
|
---|
1767 | /// instance will cause the specified <c>ZipErrorAction</c> to be used on all
|
---|
1768 | /// <see cref="ZipEntry"/> items that are subsequently added to the
|
---|
1769 | /// <c>ZipFile</c> instance. If you set this property after you have added
|
---|
1770 | /// items to the <c>ZipFile</c>, but before you have called <c>Save()</c>,
|
---|
1771 | /// those items will not use the specified error handling action.
|
---|
1772 | /// </para>
|
---|
1773 | ///
|
---|
1774 | /// <para>
|
---|
1775 | /// If you want to handle any errors that occur with any entry in the zip
|
---|
1776 | /// file in the same way, then set this property once, before adding any
|
---|
1777 | /// entries to the zip archive.
|
---|
1778 | /// </para>
|
---|
1779 | ///
|
---|
1780 | /// <para>
|
---|
1781 | /// If you set this property to <c>ZipErrorAction.Skip</c> and you'd like to
|
---|
1782 | /// learn which files may have been skipped after a <c>Save()</c>, you can
|
---|
1783 | /// set the <see cref="StatusMessageTextWriter" /> on the ZipFile before
|
---|
1784 | /// calling <c>Save()</c>. A message will be emitted into that writer for
|
---|
1785 | /// each skipped file, if any.
|
---|
1786 | /// </para>
|
---|
1787 | ///
|
---|
1788 | /// </remarks>
|
---|
1789 | ///
|
---|
1790 | /// <example>
|
---|
1791 | /// This example shows how to tell DotNetZip to skip any files for which an
|
---|
1792 | /// error is generated during the Save().
|
---|
1793 | /// <code lang="VB">
|
---|
1794 | /// Public Sub SaveZipFile()
|
---|
1795 | /// Dim SourceFolder As String = "fodder"
|
---|
1796 | /// Dim DestFile As String = "eHandler.zip"
|
---|
1797 | /// Dim sw as New StringWriter
|
---|
1798 | /// Using zipArchive As ZipFile = New ZipFile
|
---|
1799 | /// ' Tell DotNetZip to skip any files for which it encounters an error
|
---|
1800 | /// zipArchive.ZipErrorAction = ZipErrorAction.Skip
|
---|
1801 | /// zipArchive.StatusMessageTextWriter = sw
|
---|
1802 | /// zipArchive.AddDirectory(SourceFolder)
|
---|
1803 | /// zipArchive.Save(DestFile)
|
---|
1804 | /// End Using
|
---|
1805 | /// ' examine sw here to see any messages
|
---|
1806 | /// End Sub
|
---|
1807 | ///
|
---|
1808 | /// </code>
|
---|
1809 | /// </example>
|
---|
1810 | ///
|
---|
1811 | /// <seealso cref="ZipEntry.ZipErrorAction"/>
|
---|
1812 | /// <seealso cref="Ionic.Zip.ZipFile.ZipError"/>
|
---|
1813 |
|
---|
1814 | internal ZipErrorAction ZipErrorAction
|
---|
1815 | {
|
---|
1816 | get
|
---|
1817 | {
|
---|
1818 | if (ZipError != null)
|
---|
1819 | _zipErrorAction = ZipErrorAction.InvokeErrorEvent;
|
---|
1820 | return _zipErrorAction;
|
---|
1821 | }
|
---|
1822 | set
|
---|
1823 | {
|
---|
1824 | _zipErrorAction = value;
|
---|
1825 | if (_zipErrorAction != ZipErrorAction.InvokeErrorEvent && ZipError != null)
|
---|
1826 | ZipError = null;
|
---|
1827 | }
|
---|
1828 | }
|
---|
1829 |
|
---|
1830 |
|
---|
1831 | /// <summary>
|
---|
1832 | /// The Encryption to use for entries added to the <c>ZipFile</c>.
|
---|
1833 | /// </summary>
|
---|
1834 | ///
|
---|
1835 | /// <remarks>
|
---|
1836 | /// <para>
|
---|
1837 | /// Set this when creating a zip archive, or when updating a zip archive. The
|
---|
1838 | /// specified Encryption is applied to the entries subsequently added to the
|
---|
1839 | /// <c>ZipFile</c> instance. Applications do not need to set the
|
---|
1840 | /// <c>Encryption</c> property when reading or extracting a zip archive.
|
---|
1841 | /// </para>
|
---|
1842 | ///
|
---|
1843 | /// <para>
|
---|
1844 | /// If you set this to something other than EncryptionAlgorithm.None, you
|
---|
1845 | /// will also need to set the <see cref="Password"/>.
|
---|
1846 | /// </para>
|
---|
1847 | ///
|
---|
1848 | /// <para>
|
---|
1849 | /// As with some other properties on the <c>ZipFile</c> class, like <see
|
---|
1850 | /// cref="Password"/> and <see cref="CompressionLevel"/>, setting this
|
---|
1851 | /// property on a <c>ZipFile</c> instance will cause the specified
|
---|
1852 | /// <c>EncryptionAlgorithm</c> to be used on all <see cref="ZipEntry"/> items
|
---|
1853 | /// that are subsequently added to the <c>ZipFile</c> instance. In other
|
---|
1854 | /// words, if you set this property after you have added items to the
|
---|
1855 | /// <c>ZipFile</c>, but before you have called <c>Save()</c>, those items will
|
---|
1856 | /// not be encrypted or protected with a password in the resulting zip
|
---|
1857 | /// archive. To get a zip archive with encrypted entries, set this property,
|
---|
1858 | /// along with the <see cref="Password"/> property, before calling
|
---|
1859 | /// <c>AddFile</c>, <c>AddItem</c>, or <c>AddDirectory</c> (etc.) on the
|
---|
1860 | /// <c>ZipFile</c> instance.
|
---|
1861 | /// </para>
|
---|
1862 | ///
|
---|
1863 | /// <para>
|
---|
1864 | /// If you read a <c>ZipFile</c>, you can modify the <c>Encryption</c> on an
|
---|
1865 | /// encrypted entry, only by setting the <c>Encryption</c> property on the
|
---|
1866 | /// <c>ZipEntry</c> itself. Setting the <c>Encryption</c> property on the
|
---|
1867 | /// <c>ZipFile</c>, once it has been created via a call to
|
---|
1868 | /// <c>ZipFile.Read()</c>, does not affect entries that were previously read.
|
---|
1869 | /// </para>
|
---|
1870 | ///
|
---|
1871 | /// <para>
|
---|
1872 | /// For example, suppose you read a <c>ZipFile</c>, and there is an encrypted
|
---|
1873 | /// entry. Setting the <c>Encryption</c> property on that <c>ZipFile</c> and
|
---|
1874 | /// then calling <c>Save()</c> on the <c>ZipFile</c> does not update the
|
---|
1875 | /// <c>Encryption</c> used for the entries in the archive. Neither is an
|
---|
1876 | /// exception thrown. Instead, what happens during the <c>Save()</c> is that
|
---|
1877 | /// all previously existing entries are copied through to the new zip archive,
|
---|
1878 | /// with whatever encryption and password that was used when originally
|
---|
1879 | /// creating the zip archive. Upon re-reading that archive, to extract
|
---|
1880 | /// entries, applications should use the original password or passwords, if
|
---|
1881 | /// any.
|
---|
1882 | /// </para>
|
---|
1883 | ///
|
---|
1884 | /// <para>
|
---|
1885 | /// Suppose an application reads a <c>ZipFile</c>, and there is an encrypted
|
---|
1886 | /// entry. Setting the <c>Encryption</c> property on that <c>ZipFile</c> and
|
---|
1887 | /// then adding new entries (via <c>AddFile()</c>, <c>AddEntry()</c>, etc)
|
---|
1888 | /// and then calling <c>Save()</c> on the <c>ZipFile</c> does not update the
|
---|
1889 | /// <c>Encryption</c> on any of the entries that had previously been in the
|
---|
1890 | /// <c>ZipFile</c>. The <c>Encryption</c> property applies only to the
|
---|
1891 | /// newly-added entries.
|
---|
1892 | /// </para>
|
---|
1893 | ///
|
---|
1894 | /// </remarks>
|
---|
1895 | ///
|
---|
1896 | /// <example>
|
---|
1897 | /// <para>
|
---|
1898 | /// This example creates a zip archive that uses encryption, and then extracts
|
---|
1899 | /// entries from the archive. When creating the zip archive, the ReadMe.txt
|
---|
1900 | /// file is zipped without using a password or encryption. The other files
|
---|
1901 | /// use encryption.
|
---|
1902 | /// </para>
|
---|
1903 | ///
|
---|
1904 | /// <code>
|
---|
1905 | /// // Create a zip archive with AES Encryption.
|
---|
1906 | /// using (ZipFile zip = new ZipFile())
|
---|
1907 | /// {
|
---|
1908 | /// zip.AddFile("ReadMe.txt");
|
---|
1909 | /// zip.Encryption= EncryptionAlgorithm.WinZipAes256;
|
---|
1910 | /// zip.Password= "Top.Secret.No.Peeking!";
|
---|
1911 | /// zip.AddFile("7440-N49th.png");
|
---|
1912 | /// zip.AddFile("2008-Regional-Sales-Report.pdf");
|
---|
1913 | /// zip.Save("EncryptedArchive.zip");
|
---|
1914 | /// }
|
---|
1915 | ///
|
---|
1916 | /// // Extract a zip archive that uses AES Encryption.
|
---|
1917 | /// // You do not need to specify the algorithm during extraction.
|
---|
1918 | /// using (ZipFile zip = ZipFile.Read("EncryptedArchive.zip"))
|
---|
1919 | /// {
|
---|
1920 | /// zip.Password= "Top.Secret.No.Peeking!";
|
---|
1921 | /// zip.ExtractAll("extractDirectory");
|
---|
1922 | /// }
|
---|
1923 | /// </code>
|
---|
1924 | ///
|
---|
1925 | /// <code lang="VB">
|
---|
1926 | /// ' Create a zip that uses Encryption.
|
---|
1927 | /// Using zip As New ZipFile()
|
---|
1928 | /// zip.Encryption= EncryptionAlgorithm.WinZipAes256
|
---|
1929 | /// zip.Password= "Top.Secret.No.Peeking!"
|
---|
1930 | /// zip.AddFile("ReadMe.txt")
|
---|
1931 | /// zip.AddFile("7440-N49th.png")
|
---|
1932 | /// zip.AddFile("2008-Regional-Sales-Report.pdf")
|
---|
1933 | /// zip.Save("EncryptedArchive.zip")
|
---|
1934 | /// End Using
|
---|
1935 | ///
|
---|
1936 | /// ' Extract a zip archive that uses AES Encryption.
|
---|
1937 | /// ' You do not need to specify the algorithm during extraction.
|
---|
1938 | /// Using (zip as ZipFile = ZipFile.Read("EncryptedArchive.zip"))
|
---|
1939 | /// zip.Password= "Top.Secret.No.Peeking!"
|
---|
1940 | /// zip.ExtractAll("extractDirectory")
|
---|
1941 | /// End Using
|
---|
1942 | /// </code>
|
---|
1943 | ///
|
---|
1944 | /// </example>
|
---|
1945 | ///
|
---|
1946 | /// <seealso cref="Ionic.Zip.ZipFile.Password">ZipFile.Password</seealso>
|
---|
1947 | /// <seealso cref="ZipEntry.Encryption">ZipEntry.Encryption</seealso>
|
---|
1948 | internal EncryptionAlgorithm Encryption
|
---|
1949 | {
|
---|
1950 | get
|
---|
1951 | {
|
---|
1952 | return _Encryption;
|
---|
1953 | }
|
---|
1954 | set
|
---|
1955 | {
|
---|
1956 | if (value == EncryptionAlgorithm.Unsupported)
|
---|
1957 | throw new InvalidOperationException("You may not set Encryption to that value.");
|
---|
1958 | _Encryption = value;
|
---|
1959 | }
|
---|
1960 | }
|
---|
1961 |
|
---|
1962 |
|
---|
1963 |
|
---|
1964 | /// <summary>
|
---|
1965 | /// A callback that allows the application to specify the compression level
|
---|
1966 | /// to use for entries subsequently added to the zip archive.
|
---|
1967 | /// </summary>
|
---|
1968 | ///
|
---|
1969 | /// <remarks>
|
---|
1970 | ///
|
---|
1971 | /// <para>
|
---|
1972 | /// With this callback, the DotNetZip library allows the application to
|
---|
1973 | /// determine whether compression will be used, at the time of the
|
---|
1974 | /// <c>Save</c>. This may be useful if the application wants to favor
|
---|
1975 | /// speed over size, and wants to defer the decision until the time of
|
---|
1976 | /// <c>Save</c>.
|
---|
1977 | /// </para>
|
---|
1978 | ///
|
---|
1979 | /// <para>
|
---|
1980 | /// Typically applications set the <see cref="CompressionLevel"/> property on
|
---|
1981 | /// the <c>ZipFile</c> or on each <c>ZipEntry</c> to determine the level of
|
---|
1982 | /// compression used. This is done at the time the entry is added to the
|
---|
1983 | /// <c>ZipFile</c>. Setting the property to
|
---|
1984 | /// <c>Ionic.Zlib.CompressionLevel.None</c> means no compression will be used.
|
---|
1985 | /// </para>
|
---|
1986 | ///
|
---|
1987 | /// <para>
|
---|
1988 | /// This callback allows the application to defer the decision on the
|
---|
1989 | /// <c>CompressionLevel</c> to use, until the time of the call to
|
---|
1990 | /// <c>ZipFile.Save()</c>. The callback is invoked once per <c>ZipEntry</c>,
|
---|
1991 | /// at the time the data for the entry is being written out as part of a
|
---|
1992 | /// <c>Save()</c> operation. The application can use whatever criteria it
|
---|
1993 | /// likes in determining the level to return. For example, an application may
|
---|
1994 | /// wish that no .mp3 files should be compressed, because they are already
|
---|
1995 | /// compressed and the extra compression is not worth the CPU time incurred,
|
---|
1996 | /// and so can return <c>None</c> for all .mp3 entries.
|
---|
1997 | /// </para>
|
---|
1998 | ///
|
---|
1999 | /// <para>
|
---|
2000 | /// The library determines whether compression will be attempted for an entry
|
---|
2001 | /// this way: If the entry is a zero length file, or a directory, no
|
---|
2002 | /// compression is used. Otherwise, if this callback is set, it is invoked
|
---|
2003 | /// and the <c>CompressionLevel</c> is set to the return value. If this
|
---|
2004 | /// callback has not been set, then the previously set value for
|
---|
2005 | /// <c>CompressionLevel</c> is used.
|
---|
2006 | /// </para>
|
---|
2007 | ///
|
---|
2008 | /// </remarks>
|
---|
2009 | public SetCompressionCallback SetCompression
|
---|
2010 | {
|
---|
2011 | get;
|
---|
2012 | set;
|
---|
2013 | }
|
---|
2014 |
|
---|
2015 |
|
---|
2016 | /// <summary>
|
---|
2017 | /// The maximum size of an output segment, when saving a split Zip file.
|
---|
2018 | /// </summary>
|
---|
2019 | /// <remarks>
|
---|
2020 | /// <para>
|
---|
2021 | /// Set this to a non-zero value before calling <see cref="Save()"/> or <see
|
---|
2022 | /// cref="Save(String)"/> to specify that the ZipFile should be saved as a
|
---|
2023 | /// split archive, also sometimes called a spanned archive. Some also
|
---|
2024 | /// call them multi-file archives.
|
---|
2025 | /// </para>
|
---|
2026 | ///
|
---|
2027 | /// <para>
|
---|
2028 | /// A split zip archive is saved in a set of discrete filesystem files,
|
---|
2029 | /// rather than in a single file. This is handy when transmitting the
|
---|
2030 | /// archive in email or some other mechanism that has a limit to the size of
|
---|
2031 | /// each file. The first file in a split archive will be named
|
---|
2032 | /// <c>basename.z01</c>, the second will be named <c>basename.z02</c>, and
|
---|
2033 | /// so on. The final file is named <c>basename.zip</c>. According to the zip
|
---|
2034 | /// specification from PKWare, the minimum value is 65536, for a 64k segment
|
---|
2035 | /// size. The maximum number of segments allows in a split archive is 99.
|
---|
2036 | /// </para>
|
---|
2037 | ///
|
---|
2038 | /// <para>
|
---|
2039 | /// The value of this property determines the maximum size of a split
|
---|
2040 | /// segment when writing a split archive. For example, suppose you have a
|
---|
2041 | /// <c>ZipFile</c> that would save to a single file of 200k. If you set the
|
---|
2042 | /// <c>MaxOutputSegmentSize</c> to 65536 before calling <c>Save()</c>, you
|
---|
2043 | /// will get four distinct output files. On the other hand if you set this
|
---|
2044 | /// property to 256k, then you will get a single-file archive for that
|
---|
2045 | /// <c>ZipFile</c>.
|
---|
2046 | /// </para>
|
---|
2047 | ///
|
---|
2048 | /// <para>
|
---|
2049 | /// The size of each split output file will be as large as possible, up to
|
---|
2050 | /// the maximum size set here. The zip specification requires that some data
|
---|
2051 | /// fields in a zip archive may not span a split boundary, and an output
|
---|
2052 | /// segment may be smaller than the maximum if necessary to avoid that
|
---|
2053 | /// problem. Also, obviously the final segment of the archive may be smaller
|
---|
2054 | /// than the maximum segment size. Segments will never be larger than the
|
---|
2055 | /// value set with this property.
|
---|
2056 | /// </para>
|
---|
2057 | ///
|
---|
2058 | /// <para>
|
---|
2059 | /// You can save a split Zip file only when saving to a regular filesystem
|
---|
2060 | /// file. It's not possible to save a split zip file as a self-extracting
|
---|
2061 | /// archive, nor is it possible to save a split zip file to a stream. When
|
---|
2062 | /// saving to a SFX or to a Stream, this property is ignored.
|
---|
2063 | /// </para>
|
---|
2064 | ///
|
---|
2065 | /// <para>
|
---|
2066 | /// About interoperability: Split or spanned zip files produced by DotNetZip
|
---|
2067 | /// can be read by WinZip or PKZip, and vice-versa. Segmented zip files may
|
---|
2068 | /// not be readable by other tools, if those other tools don't support zip
|
---|
2069 | /// spanning or splitting. When in doubt, test. I don't believe Windows
|
---|
2070 | /// Explorer can extract a split archive.
|
---|
2071 | /// </para>
|
---|
2072 | ///
|
---|
2073 | /// <para>
|
---|
2074 | /// This property has no effect when reading a split archive. You can read
|
---|
2075 | /// a split archive in the normal way with DotNetZip.
|
---|
2076 | /// </para>
|
---|
2077 | ///
|
---|
2078 | /// <para>
|
---|
2079 | /// When saving a zip file, if you want a regular zip file rather than a
|
---|
2080 | /// split zip file, don't set this property, or set it to Zero.
|
---|
2081 | /// </para>
|
---|
2082 | ///
|
---|
2083 | /// <para>
|
---|
2084 | /// If you read a split archive, with <see cref="ZipFile.Read(string)"/> and
|
---|
2085 | /// then subsequently call <c>ZipFile.Save()</c>, unless you set this
|
---|
2086 | /// property before calling <c>Save()</c>, you will get a normal,
|
---|
2087 | /// single-file archive.
|
---|
2088 | /// </para>
|
---|
2089 | /// </remarks>
|
---|
2090 | ///
|
---|
2091 | /// <seealso cref="NumberOfSegmentsForMostRecentSave"/>
|
---|
2092 | public Int32 MaxOutputSegmentSize
|
---|
2093 | {
|
---|
2094 | get
|
---|
2095 | {
|
---|
2096 | return _maxOutputSegmentSize;
|
---|
2097 | }
|
---|
2098 | set
|
---|
2099 | {
|
---|
2100 | if (value < 65536 && value != 0)
|
---|
2101 | throw new ZipException("The minimum acceptable segment size is 65536.");
|
---|
2102 | _maxOutputSegmentSize = value;
|
---|
2103 | }
|
---|
2104 | }
|
---|
2105 |
|
---|
2106 |
|
---|
2107 | /// <summary>
|
---|
2108 | /// Returns the number of segments used in the most recent Save() operation.
|
---|
2109 | /// </summary>
|
---|
2110 | /// <remarks>
|
---|
2111 | /// <para>
|
---|
2112 | /// This is normally zero, unless you have set the <see
|
---|
2113 | /// cref="MaxOutputSegmentSize"/> property. If you have set <see
|
---|
2114 | /// cref="MaxOutputSegmentSize"/>, and then you save a file, after the call to
|
---|
2115 | /// Save() completes, you can read this value to learn the number of segments that
|
---|
2116 | /// were created.
|
---|
2117 | /// </para>
|
---|
2118 | /// <para>
|
---|
2119 | /// If you call Save("Archive.zip"), and it creates 5 segments, then you
|
---|
2120 | /// will have filesystem files named Archive.z01, Archive.z02, Archive.z03,
|
---|
2121 | /// Archive.z04, and Archive.zip, and the value of this property will be 5.
|
---|
2122 | /// </para>
|
---|
2123 | /// </remarks>
|
---|
2124 | /// <seealso cref="MaxOutputSegmentSize"/>
|
---|
2125 | public Int32 NumberOfSegmentsForMostRecentSave
|
---|
2126 | {
|
---|
2127 | get
|
---|
2128 | {
|
---|
2129 | return unchecked((Int32)_numberOfSegmentsForMostRecentSave + 1);
|
---|
2130 | }
|
---|
2131 | }
|
---|
2132 |
|
---|
2133 |
|
---|
2134 | #if !NETCF
|
---|
2135 | /// <summary>
|
---|
2136 | /// The size threshold for an entry, above which a parallel deflate is used.
|
---|
2137 | /// </summary>
|
---|
2138 | ///
|
---|
2139 | /// <remarks>
|
---|
2140 | ///
|
---|
2141 | /// <para>
|
---|
2142 | /// DotNetZip will use multiple threads to compress any ZipEntry,
|
---|
2143 | /// if the entry is larger than the given size. Zero means "always
|
---|
2144 | /// use parallel deflate", while -1 means "never use parallel
|
---|
2145 | /// deflate". The default value for this property is 512k. Aside
|
---|
2146 | /// from the special values of 0 and 1, the minimum value is 65536.
|
---|
2147 | /// </para>
|
---|
2148 | ///
|
---|
2149 | /// <para>
|
---|
2150 | /// If the entry size cannot be known before compression, as with a
|
---|
2151 | /// read-forward stream, then Parallel deflate will never be
|
---|
2152 | /// performed, unless the value of this property is zero.
|
---|
2153 | /// </para>
|
---|
2154 | ///
|
---|
2155 | /// <para>
|
---|
2156 | /// A parallel deflate operations will speed up the compression of
|
---|
2157 | /// large files, on computers with multiple CPUs or multiple CPU
|
---|
2158 | /// cores. For files above 1mb, on a dual core or dual-cpu (2p)
|
---|
2159 | /// machine, the time required to compress the file can be 70% of the
|
---|
2160 | /// single-threaded deflate. For very large files on 4p machines the
|
---|
2161 | /// compression can be done in 30% of the normal time. The downside
|
---|
2162 | /// is that parallel deflate consumes extra memory during the deflate,
|
---|
2163 | /// and the deflation is not as effective.
|
---|
2164 | /// </para>
|
---|
2165 | ///
|
---|
2166 | /// <para>
|
---|
2167 | /// Parallel deflate tends to yield slightly less compression when
|
---|
2168 | /// compared to as single-threaded deflate; this is because the original
|
---|
2169 | /// data stream is split into multiple independent buffers, each of which
|
---|
2170 | /// is compressed in parallel. But because they are treated
|
---|
2171 | /// independently, there is no opportunity to share compression
|
---|
2172 | /// dictionaries. For that reason, a deflated stream may be slightly
|
---|
2173 | /// larger when compressed using parallel deflate, as compared to a
|
---|
2174 | /// traditional single-threaded deflate. Sometimes the increase over the
|
---|
2175 | /// normal deflate is as much as 5% of the total compressed size. For
|
---|
2176 | /// larger files it can be as small as 0.1%.
|
---|
2177 | /// </para>
|
---|
2178 | ///
|
---|
2179 | /// <para>
|
---|
2180 | /// Multi-threaded compression does not give as much an advantage when
|
---|
2181 | /// using Encryption. This is primarily because encryption tends to slow
|
---|
2182 | /// down the entire pipeline. Also, multi-threaded compression gives less
|
---|
2183 | /// of an advantage when using lower compression levels, for example <see
|
---|
2184 | /// cref="Ionic.Zlib.CompressionLevel.BestSpeed"/>. You may have to
|
---|
2185 | /// perform some tests to determine the best approach for your situation.
|
---|
2186 | /// </para>
|
---|
2187 | ///
|
---|
2188 | /// </remarks>
|
---|
2189 | ///
|
---|
2190 | /// <seealso cref="ParallelDeflateMaxBufferPairs"/>
|
---|
2191 | ///
|
---|
2192 | public long ParallelDeflateThreshold
|
---|
2193 | {
|
---|
2194 | set
|
---|
2195 | {
|
---|
2196 | if ((value != 0) && (value != -1) && (value < 64 * 1024))
|
---|
2197 | throw new ArgumentOutOfRangeException("ParallelDeflateThreshold should be -1, 0, or > 65536");
|
---|
2198 | _ParallelDeflateThreshold = value;
|
---|
2199 | }
|
---|
2200 | get
|
---|
2201 | {
|
---|
2202 | return _ParallelDeflateThreshold;
|
---|
2203 | }
|
---|
2204 | }
|
---|
2205 |
|
---|
2206 | /// <summary>
|
---|
2207 | /// The maximum number of buffer pairs to use when performing
|
---|
2208 | /// parallel compression.
|
---|
2209 | /// </summary>
|
---|
2210 | ///
|
---|
2211 | /// <remarks>
|
---|
2212 | /// <para>
|
---|
2213 | /// This property sets an upper limit on the number of memory
|
---|
2214 | /// buffer pairs to create when performing parallel
|
---|
2215 | /// compression. The implementation of the parallel
|
---|
2216 | /// compression stream allocates multiple buffers to
|
---|
2217 | /// facilitate parallel compression. As each buffer fills up,
|
---|
2218 | /// the stream uses <see
|
---|
2219 | /// cref="System.Threading.ThreadPool.QueueUserWorkItem(System.Threading.WaitCallback)">
|
---|
2220 | /// ThreadPool.QueueUserWorkItem()</see> to compress those
|
---|
2221 | /// buffers in a background threadpool thread. After a buffer
|
---|
2222 | /// is compressed, it is re-ordered and written to the output
|
---|
2223 | /// stream.
|
---|
2224 | /// </para>
|
---|
2225 | ///
|
---|
2226 | /// <para>
|
---|
2227 | /// A higher number of buffer pairs enables a higher degree of
|
---|
2228 | /// parallelism, which tends to increase the speed of compression on
|
---|
2229 | /// multi-cpu computers. On the other hand, a higher number of buffer
|
---|
2230 | /// pairs also implies a larger memory consumption, more active worker
|
---|
2231 | /// threads, and a higher cpu utilization for any compression. This
|
---|
2232 | /// property enables the application to limit its memory consumption and
|
---|
2233 | /// CPU utilization behavior depending on requirements.
|
---|
2234 | /// </para>
|
---|
2235 | ///
|
---|
2236 | /// <para>
|
---|
2237 | /// For each compression "task" that occurs in parallel, there are 2
|
---|
2238 | /// buffers allocated: one for input and one for output. This property
|
---|
2239 | /// sets a limit for the number of pairs. The total amount of storage
|
---|
2240 | /// space allocated for buffering will then be (N*S*2), where N is the
|
---|
2241 | /// number of buffer pairs, S is the size of each buffer (<see
|
---|
2242 | /// cref="BufferSize"/>). By default, DotNetZip allocates 4 buffer
|
---|
2243 | /// pairs per CPU core, so if your machine has 4 cores, and you retain
|
---|
2244 | /// the default buffer size of 128k, then the
|
---|
2245 | /// ParallelDeflateOutputStream will use 4 * 4 * 2 * 128kb of buffer
|
---|
2246 | /// memory in total, or 4mb, in blocks of 128kb. If you then set this
|
---|
2247 | /// property to 8, then the number will be 8 * 2 * 128kb of buffer
|
---|
2248 | /// memory, or 2mb.
|
---|
2249 | /// </para>
|
---|
2250 | ///
|
---|
2251 | /// <para>
|
---|
2252 | /// CPU utilization will also go up with additional buffers, because a
|
---|
2253 | /// larger number of buffer pairs allows a larger number of background
|
---|
2254 | /// threads to compress in parallel. If you find that parallel
|
---|
2255 | /// compression is consuming too much memory or CPU, you can adjust this
|
---|
2256 | /// value downward.
|
---|
2257 | /// </para>
|
---|
2258 | ///
|
---|
2259 | /// <para>
|
---|
2260 | /// The default value is 16. Different values may deliver better or
|
---|
2261 | /// worse results, depending on your priorities and the dynamic
|
---|
2262 | /// performance characteristics of your storage and compute resources.
|
---|
2263 | /// </para>
|
---|
2264 | ///
|
---|
2265 | /// <para>
|
---|
2266 | /// This property is not the number of buffer pairs to use; it is an
|
---|
2267 | /// upper limit. An illustration: Suppose you have an application that
|
---|
2268 | /// uses the default value of this property (which is 16), and it runs
|
---|
2269 | /// on a machine with 2 CPU cores. In that case, DotNetZip will allocate
|
---|
2270 | /// 4 buffer pairs per CPU core, for a total of 8 pairs. The upper
|
---|
2271 | /// limit specified by this property has no effect.
|
---|
2272 | /// </para>
|
---|
2273 | ///
|
---|
2274 | /// <para>
|
---|
2275 | /// The application can set this value at any time
|
---|
2276 | /// before calling <c>ZipFile.Save()</c>.
|
---|
2277 | /// </para>
|
---|
2278 | /// </remarks>
|
---|
2279 | ///
|
---|
2280 | /// <seealso cref="ParallelDeflateThreshold"/>
|
---|
2281 | ///
|
---|
2282 | public int ParallelDeflateMaxBufferPairs
|
---|
2283 | {
|
---|
2284 | get
|
---|
2285 | {
|
---|
2286 | return _maxBufferPairs;
|
---|
2287 | }
|
---|
2288 | set
|
---|
2289 | {
|
---|
2290 | if (value < 4)
|
---|
2291 | throw new ArgumentOutOfRangeException("ParallelDeflateMaxBufferPairs",
|
---|
2292 | "Value must be 4 or greater.");
|
---|
2293 | _maxBufferPairs = value;
|
---|
2294 | }
|
---|
2295 | }
|
---|
2296 | #endif
|
---|
2297 |
|
---|
2298 |
|
---|
2299 | /// <summary>Provides a string representation of the instance.</summary>
|
---|
2300 | /// <returns>a string representation of the instance.</returns>
|
---|
2301 | public override String ToString()
|
---|
2302 | {
|
---|
2303 | return String.Format("ZipFile::{0}", Name);
|
---|
2304 | }
|
---|
2305 |
|
---|
2306 |
|
---|
2307 | /// <summary>
|
---|
2308 | /// Returns the version number on the DotNetZip assembly.
|
---|
2309 | /// </summary>
|
---|
2310 | ///
|
---|
2311 | /// <remarks>
|
---|
2312 | /// <para>
|
---|
2313 | /// This property is exposed as a convenience. Callers could also get the
|
---|
2314 | /// version value by retrieving GetName().Version on the
|
---|
2315 | /// System.Reflection.Assembly object pointing to the DotNetZip
|
---|
2316 | /// assembly. But sometimes it is not clear which assembly is being loaded.
|
---|
2317 | /// This property makes it clear.
|
---|
2318 | /// </para>
|
---|
2319 | /// <para>
|
---|
2320 | /// This static property is primarily useful for diagnostic purposes.
|
---|
2321 | /// </para>
|
---|
2322 | /// </remarks>
|
---|
2323 | public static System.Version LibraryVersion
|
---|
2324 | {
|
---|
2325 | get
|
---|
2326 | {
|
---|
2327 | return System.Reflection.Assembly.GetExecutingAssembly().GetName().Version;
|
---|
2328 | }
|
---|
2329 | }
|
---|
2330 |
|
---|
2331 | internal void NotifyEntryChanged()
|
---|
2332 | {
|
---|
2333 | _contentsChanged = true;
|
---|
2334 | }
|
---|
2335 |
|
---|
2336 |
|
---|
2337 | internal Stream StreamForDiskNumber(uint diskNumber)
|
---|
2338 | {
|
---|
2339 | if (diskNumber + 1 == this._diskNumberWithCd ||
|
---|
2340 | (diskNumber == 0 && this._diskNumberWithCd == 0))
|
---|
2341 | {
|
---|
2342 | //return (this.ReadStream as FileStream);
|
---|
2343 | return this.ReadStream;
|
---|
2344 | }
|
---|
2345 | return ZipSegmentedStream.ForReading(this._readName ?? this._name,
|
---|
2346 | diskNumber, _diskNumberWithCd);
|
---|
2347 | }
|
---|
2348 |
|
---|
2349 |
|
---|
2350 |
|
---|
2351 | // called by ZipEntry in ZipEntry.Extract(), when there is no stream set for the
|
---|
2352 | // ZipEntry.
|
---|
2353 | internal void Reset(bool whileSaving)
|
---|
2354 | {
|
---|
2355 | if (_JustSaved)
|
---|
2356 | {
|
---|
2357 | // read in the just-saved zip archive
|
---|
2358 | using (ZipFile x = new ZipFile())
|
---|
2359 | {
|
---|
2360 | // workitem 10735
|
---|
2361 | x._readName = x._name = whileSaving
|
---|
2362 | ? (this._readName ?? this._name)
|
---|
2363 | : this._name;
|
---|
2364 | x.AlternateEncoding = this.AlternateEncoding;
|
---|
2365 | x.AlternateEncodingUsage = this.AlternateEncodingUsage;
|
---|
2366 | ReadIntoInstance(x);
|
---|
2367 | // copy the contents of the entries.
|
---|
2368 | // cannot just replace the entries - the app may be holding them
|
---|
2369 | foreach (ZipEntry e1 in x)
|
---|
2370 | {
|
---|
2371 | foreach (ZipEntry e2 in this)
|
---|
2372 | {
|
---|
2373 | if (e1.FileName == e2.FileName)
|
---|
2374 | {
|
---|
2375 | e2.CopyMetaData(e1);
|
---|
2376 | break;
|
---|
2377 | }
|
---|
2378 | }
|
---|
2379 | }
|
---|
2380 | }
|
---|
2381 | _JustSaved = false;
|
---|
2382 | }
|
---|
2383 | }
|
---|
2384 |
|
---|
2385 |
|
---|
2386 | #endregion
|
---|
2387 |
|
---|
2388 | #region Constructors
|
---|
2389 |
|
---|
2390 | /// <summary>
|
---|
2391 | /// Creates a new <c>ZipFile</c> instance, using the specified filename.
|
---|
2392 | /// </summary>
|
---|
2393 | ///
|
---|
2394 | /// <remarks>
|
---|
2395 | /// <para>
|
---|
2396 | /// Applications can use this constructor to create a new ZipFile for writing,
|
---|
2397 | /// or to slurp in an existing zip archive for read and update purposes.
|
---|
2398 | /// </para>
|
---|
2399 | ///
|
---|
2400 | /// <para>
|
---|
2401 | /// To create a new zip archive, an application can call this constructor,
|
---|
2402 | /// passing the name of a file that does not exist. The name may be a fully
|
---|
2403 | /// qualified path. Then the application can add directories or files to the
|
---|
2404 | /// <c>ZipFile</c> via <c>AddDirectory()</c>, <c>AddFile()</c>, <c>AddItem()</c>
|
---|
2405 | /// and then write the zip archive to the disk by calling <c>Save()</c>. The
|
---|
2406 | /// zip file is not actually opened and written to the disk until the
|
---|
2407 | /// application calls <c>ZipFile.Save()</c>. At that point the new zip file
|
---|
2408 | /// with the given name is created.
|
---|
2409 | /// </para>
|
---|
2410 | ///
|
---|
2411 | /// <para>
|
---|
2412 | /// If you won't know the name of the <c>Zipfile</c> until the time you call
|
---|
2413 | /// <c>ZipFile.Save()</c>, or if you plan to save to a stream (which has no
|
---|
2414 | /// name), then you should use the no-argument constructor.
|
---|
2415 | /// </para>
|
---|
2416 | ///
|
---|
2417 | /// <para>
|
---|
2418 | /// The application can also call this constructor to read an existing zip
|
---|
2419 | /// archive. passing the name of a valid zip file that does exist. But, it's
|
---|
2420 | /// better form to use the static <see cref="ZipFile.Read(String)"/> method,
|
---|
2421 | /// passing the name of the zip file, because using <c>ZipFile.Read()</c> in
|
---|
2422 | /// your code communicates very clearly what you are doing. In either case,
|
---|
2423 | /// the file is then read into the <c>ZipFile</c> instance. The app can then
|
---|
2424 | /// enumerate the entries or can modify the zip file, for example adding
|
---|
2425 | /// entries, removing entries, changing comments, and so on.
|
---|
2426 | /// </para>
|
---|
2427 | ///
|
---|
2428 | /// <para>
|
---|
2429 | /// One advantage to this parameterized constructor: it allows applications to
|
---|
2430 | /// use the same code to add items to a zip archive, regardless of whether the
|
---|
2431 | /// zip file exists.
|
---|
2432 | /// </para>
|
---|
2433 | ///
|
---|
2434 | /// <para>
|
---|
2435 | /// Instances of the <c>ZipFile</c> class are not multi-thread safe. You may
|
---|
2436 | /// not party on a single instance with multiple threads. You may have
|
---|
2437 | /// multiple threads that each use a distinct <c>ZipFile</c> instance, or you
|
---|
2438 | /// can synchronize multi-thread access to a single instance.
|
---|
2439 | /// </para>
|
---|
2440 | ///
|
---|
2441 | /// <para>
|
---|
2442 | /// By the way, since DotNetZip is so easy to use, don't you think <see
|
---|
2443 | /// href="http://cheeso.members.winisp.net/DotNetZipDonate.aspx">you should
|
---|
2444 | /// donate $5 or $10</see>?
|
---|
2445 | /// </para>
|
---|
2446 | ///
|
---|
2447 | /// </remarks>
|
---|
2448 | ///
|
---|
2449 | /// <exception cref="Ionic.Zip.ZipException">
|
---|
2450 | /// Thrown if name refers to an existing file that is not a valid zip file.
|
---|
2451 | /// </exception>
|
---|
2452 | ///
|
---|
2453 | /// <example>
|
---|
2454 | /// This example shows how to create a zipfile, and add a few files into it.
|
---|
2455 | /// <code>
|
---|
2456 | /// String ZipFileToCreate = "archive1.zip";
|
---|
2457 | /// String DirectoryToZip = "c:\\reports";
|
---|
2458 | /// using (ZipFile zip = new ZipFile())
|
---|
2459 | /// {
|
---|
2460 | /// // Store all files found in the top level directory, into the zip archive.
|
---|
2461 | /// String[] filenames = System.IO.Directory.GetFiles(DirectoryToZip);
|
---|
2462 | /// zip.AddFiles(filenames, "files");
|
---|
2463 | /// zip.Save(ZipFileToCreate);
|
---|
2464 | /// }
|
---|
2465 | /// </code>
|
---|
2466 | ///
|
---|
2467 | /// <code lang="VB">
|
---|
2468 | /// Dim ZipFileToCreate As String = "archive1.zip"
|
---|
2469 | /// Dim DirectoryToZip As String = "c:\reports"
|
---|
2470 | /// Using zip As ZipFile = New ZipFile()
|
---|
2471 | /// Dim filenames As String() = System.IO.Directory.GetFiles(DirectoryToZip)
|
---|
2472 | /// zip.AddFiles(filenames, "files")
|
---|
2473 | /// zip.Save(ZipFileToCreate)
|
---|
2474 | /// End Using
|
---|
2475 | /// </code>
|
---|
2476 | /// </example>
|
---|
2477 | ///
|
---|
2478 | /// <param name="fileName">The filename to use for the new zip archive.</param>
|
---|
2479 | ///
|
---|
2480 | public ZipFile(string fileName)
|
---|
2481 | {
|
---|
2482 | try
|
---|
2483 | {
|
---|
2484 | _InitInstance(fileName, null);
|
---|
2485 | }
|
---|
2486 | catch (Exception e1)
|
---|
2487 | {
|
---|
2488 | throw new ZipException(String.Format("Could not read {0} as a zip file", fileName), e1);
|
---|
2489 | }
|
---|
2490 | }
|
---|
2491 |
|
---|
2492 |
|
---|
2493 | /// <summary>
|
---|
2494 | /// Creates a new <c>ZipFile</c> instance, using the specified name for the
|
---|
2495 | /// filename, and the specified Encoding.
|
---|
2496 | /// </summary>
|
---|
2497 | ///
|
---|
2498 | /// <remarks>
|
---|
2499 | /// <para>
|
---|
2500 | /// See the documentation on the <see cref="ZipFile(String)">ZipFile
|
---|
2501 | /// constructor that accepts a single string argument</see> for basic
|
---|
2502 | /// information on all the <c>ZipFile</c> constructors.
|
---|
2503 | /// </para>
|
---|
2504 | ///
|
---|
2505 | /// <para>
|
---|
2506 | /// The Encoding is used as the default alternate encoding for entries with
|
---|
2507 | /// filenames or comments that cannot be encoded with the IBM437 code page.
|
---|
2508 | /// This is equivalent to setting the <see
|
---|
2509 | /// cref="ProvisionalAlternateEncoding"/> property on the <c>ZipFile</c>
|
---|
2510 | /// instance after construction.
|
---|
2511 | /// </para>
|
---|
2512 | ///
|
---|
2513 | /// <para>
|
---|
2514 | /// Instances of the <c>ZipFile</c> class are not multi-thread safe. You may
|
---|
2515 | /// not party on a single instance with multiple threads. You may have
|
---|
2516 | /// multiple threads that each use a distinct <c>ZipFile</c> instance, or you
|
---|
2517 | /// can synchronize multi-thread access to a single instance.
|
---|
2518 | /// </para>
|
---|
2519 | ///
|
---|
2520 | /// </remarks>
|
---|
2521 | ///
|
---|
2522 | /// <exception cref="Ionic.Zip.ZipException">
|
---|
2523 | /// Thrown if name refers to an existing file that is not a valid zip file.
|
---|
2524 | /// </exception>
|
---|
2525 | ///
|
---|
2526 | /// <param name="fileName">The filename to use for the new zip archive.</param>
|
---|
2527 | /// <param name="encoding">The Encoding is used as the default alternate
|
---|
2528 | /// encoding for entries with filenames or comments that cannot be encoded
|
---|
2529 | /// with the IBM437 code page. </param>
|
---|
2530 | public ZipFile(string fileName, System.Text.Encoding encoding)
|
---|
2531 | {
|
---|
2532 | try
|
---|
2533 | {
|
---|
2534 | AlternateEncoding = encoding;
|
---|
2535 | AlternateEncodingUsage = ZipOption.Always;
|
---|
2536 | _InitInstance(fileName, null);
|
---|
2537 | }
|
---|
2538 | catch (Exception e1)
|
---|
2539 | {
|
---|
2540 | throw new ZipException(String.Format("{0} is not a valid zip file", fileName), e1);
|
---|
2541 | }
|
---|
2542 | }
|
---|
2543 |
|
---|
2544 |
|
---|
2545 |
|
---|
2546 | /// <summary>
|
---|
2547 | /// Create a zip file, without specifying a target filename or stream to save to.
|
---|
2548 | /// </summary>
|
---|
2549 | ///
|
---|
2550 | /// <remarks>
|
---|
2551 | /// <para>
|
---|
2552 | /// See the documentation on the <see cref="ZipFile(String)">ZipFile
|
---|
2553 | /// constructor that accepts a single string argument</see> for basic
|
---|
2554 | /// information on all the <c>ZipFile</c> constructors.
|
---|
2555 | /// </para>
|
---|
2556 | ///
|
---|
2557 | /// <para>
|
---|
2558 | /// After instantiating with this constructor and adding entries to the
|
---|
2559 | /// archive, the application should call <see cref="ZipFile.Save(String)"/> or
|
---|
2560 | /// <see cref="ZipFile.Save(System.IO.Stream)"/> to save to a file or a
|
---|
2561 | /// stream, respectively. The application can also set the <see cref="Name"/>
|
---|
2562 | /// property and then call the no-argument <see cref="Save()"/> method. (This
|
---|
2563 | /// is the preferred approach for applications that use the library through
|
---|
2564 | /// COM interop.) If you call the no-argument <see cref="Save()"/> method
|
---|
2565 | /// without having set the <c>Name</c> of the <c>ZipFile</c>, either through
|
---|
2566 | /// the parameterized constructor or through the explicit property , the
|
---|
2567 | /// Save() will throw, because there is no place to save the file. </para>
|
---|
2568 | ///
|
---|
2569 | /// <para>
|
---|
2570 | /// Instances of the <c>ZipFile</c> class are not multi-thread safe. You may
|
---|
2571 | /// have multiple threads that each use a distinct <c>ZipFile</c> instance, or
|
---|
2572 | /// you can synchronize multi-thread access to a single instance. </para>
|
---|
2573 | ///
|
---|
2574 | /// </remarks>
|
---|
2575 | ///
|
---|
2576 | /// <example>
|
---|
2577 | /// This example creates a Zip archive called Backup.zip, containing all the files
|
---|
2578 | /// in the directory DirectoryToZip. Files within subdirectories are not zipped up.
|
---|
2579 | /// <code>
|
---|
2580 | /// using (ZipFile zip = new ZipFile())
|
---|
2581 | /// {
|
---|
2582 | /// // Store all files found in the top level directory, into the zip archive.
|
---|
2583 | /// // note: this code does not recurse subdirectories!
|
---|
2584 | /// String[] filenames = System.IO.Directory.GetFiles(DirectoryToZip);
|
---|
2585 | /// zip.AddFiles(filenames, "files");
|
---|
2586 | /// zip.Save("Backup.zip");
|
---|
2587 | /// }
|
---|
2588 | /// </code>
|
---|
2589 | ///
|
---|
2590 | /// <code lang="VB">
|
---|
2591 | /// Using zip As New ZipFile
|
---|
2592 | /// ' Store all files found in the top level directory, into the zip archive.
|
---|
2593 | /// ' note: this code does not recurse subdirectories!
|
---|
2594 | /// Dim filenames As String() = System.IO.Directory.GetFiles(DirectoryToZip)
|
---|
2595 | /// zip.AddFiles(filenames, "files")
|
---|
2596 | /// zip.Save("Backup.zip")
|
---|
2597 | /// End Using
|
---|
2598 | /// </code>
|
---|
2599 | /// </example>
|
---|
2600 | public ZipFile()
|
---|
2601 | {
|
---|
2602 | _InitInstance(null, null);
|
---|
2603 | }
|
---|
2604 |
|
---|
2605 |
|
---|
2606 | /// <summary>
|
---|
2607 | /// Create a zip file, specifying a text Encoding, but without specifying a
|
---|
2608 | /// target filename or stream to save to.
|
---|
2609 | /// </summary>
|
---|
2610 | ///
|
---|
2611 | /// <remarks>
|
---|
2612 | /// <para>
|
---|
2613 | /// See the documentation on the <see cref="ZipFile(String)">ZipFile
|
---|
2614 | /// constructor that accepts a single string argument</see> for basic
|
---|
2615 | /// information on all the <c>ZipFile</c> constructors.
|
---|
2616 | /// </para>
|
---|
2617 | ///
|
---|
2618 | /// </remarks>
|
---|
2619 | ///
|
---|
2620 | /// <param name="encoding">
|
---|
2621 | /// The Encoding is used as the default alternate encoding for entries with
|
---|
2622 | /// filenames or comments that cannot be encoded with the IBM437 code page.
|
---|
2623 | /// </param>
|
---|
2624 | public ZipFile(System.Text.Encoding encoding)
|
---|
2625 | {
|
---|
2626 | AlternateEncoding = encoding;
|
---|
2627 | AlternateEncodingUsage = ZipOption.Always;
|
---|
2628 | _InitInstance(null, null);
|
---|
2629 | }
|
---|
2630 |
|
---|
2631 |
|
---|
2632 | /// <summary>
|
---|
2633 | /// Creates a new <c>ZipFile</c> instance, using the specified name for the
|
---|
2634 | /// filename, and the specified status message writer.
|
---|
2635 | /// </summary>
|
---|
2636 | ///
|
---|
2637 | /// <remarks>
|
---|
2638 | /// <para>
|
---|
2639 | /// See the documentation on the <see cref="ZipFile(String)">ZipFile
|
---|
2640 | /// constructor that accepts a single string argument</see> for basic
|
---|
2641 | /// information on all the <c>ZipFile</c> constructors.
|
---|
2642 | /// </para>
|
---|
2643 | ///
|
---|
2644 | /// <para>
|
---|
2645 | /// This version of the constructor allows the caller to pass in a TextWriter,
|
---|
2646 | /// to which verbose messages will be written during extraction or creation of
|
---|
2647 | /// the zip archive. A console application may wish to pass
|
---|
2648 | /// System.Console.Out to get messages on the Console. A graphical or headless
|
---|
2649 | /// application may wish to capture the messages in a different
|
---|
2650 | /// <c>TextWriter</c>, for example, a <c>StringWriter</c>, and then display
|
---|
2651 | /// the messages in a TextBox, or generate an audit log of ZipFile operations.
|
---|
2652 | /// </para>
|
---|
2653 | ///
|
---|
2654 | /// <para>
|
---|
2655 | /// To encrypt the data for the files added to the <c>ZipFile</c> instance,
|
---|
2656 | /// set the Password property after creating the <c>ZipFile</c> instance.
|
---|
2657 | /// </para>
|
---|
2658 | ///
|
---|
2659 | /// <para>
|
---|
2660 | /// Instances of the <c>ZipFile</c> class are not multi-thread safe. You may
|
---|
2661 | /// not party on a single instance with multiple threads. You may have
|
---|
2662 | /// multiple threads that each use a distinct <c>ZipFile</c> instance, or you
|
---|
2663 | /// can synchronize multi-thread access to a single instance.
|
---|
2664 | /// </para>
|
---|
2665 | ///
|
---|
2666 | /// </remarks>
|
---|
2667 | ///
|
---|
2668 | /// <exception cref="Ionic.Zip.ZipException">
|
---|
2669 | /// Thrown if name refers to an existing file that is not a valid zip file.
|
---|
2670 | /// </exception>
|
---|
2671 | ///
|
---|
2672 | /// <example>
|
---|
2673 | /// <code>
|
---|
2674 | /// using (ZipFile zip = new ZipFile("Backup.zip", Console.Out))
|
---|
2675 | /// {
|
---|
2676 | /// // Store all files found in the top level directory, into the zip archive.
|
---|
2677 | /// // note: this code does not recurse subdirectories!
|
---|
2678 | /// // Status messages will be written to Console.Out
|
---|
2679 | /// String[] filenames = System.IO.Directory.GetFiles(DirectoryToZip);
|
---|
2680 | /// zip.AddFiles(filenames);
|
---|
2681 | /// zip.Save();
|
---|
2682 | /// }
|
---|
2683 | /// </code>
|
---|
2684 | ///
|
---|
2685 | /// <code lang="VB">
|
---|
2686 | /// Using zip As New ZipFile("Backup.zip", Console.Out)
|
---|
2687 | /// ' Store all files found in the top level directory, into the zip archive.
|
---|
2688 | /// ' note: this code does not recurse subdirectories!
|
---|
2689 | /// ' Status messages will be written to Console.Out
|
---|
2690 | /// Dim filenames As String() = System.IO.Directory.GetFiles(DirectoryToZip)
|
---|
2691 | /// zip.AddFiles(filenames)
|
---|
2692 | /// zip.Save()
|
---|
2693 | /// End Using
|
---|
2694 | /// </code>
|
---|
2695 | /// </example>
|
---|
2696 | ///
|
---|
2697 | /// <param name="fileName">The filename to use for the new zip archive.</param>
|
---|
2698 | /// <param name="statusMessageWriter">A TextWriter to use for writing
|
---|
2699 | /// verbose status messages.</param>
|
---|
2700 | public ZipFile(string fileName, TextWriter statusMessageWriter)
|
---|
2701 | {
|
---|
2702 | try
|
---|
2703 | {
|
---|
2704 | _InitInstance(fileName, statusMessageWriter);
|
---|
2705 | }
|
---|
2706 | catch (Exception e1)
|
---|
2707 | {
|
---|
2708 | throw new ZipException(String.Format("{0} is not a valid zip file", fileName), e1);
|
---|
2709 | }
|
---|
2710 | }
|
---|
2711 |
|
---|
2712 |
|
---|
2713 | /// <summary>
|
---|
2714 | /// Creates a new <c>ZipFile</c> instance, using the specified name for the
|
---|
2715 | /// filename, the specified status message writer, and the specified Encoding.
|
---|
2716 | /// </summary>
|
---|
2717 | ///
|
---|
2718 | /// <remarks>
|
---|
2719 | /// <para>
|
---|
2720 | /// This constructor works like the <see cref="ZipFile(String)">ZipFile
|
---|
2721 | /// constructor that accepts a single string argument.</see> See that
|
---|
2722 | /// reference for detail on what this constructor does.
|
---|
2723 | /// </para>
|
---|
2724 | ///
|
---|
2725 | /// <para>
|
---|
2726 | /// This version of the constructor allows the caller to pass in a
|
---|
2727 | /// <c>TextWriter</c>, and an Encoding. The <c>TextWriter</c> will collect
|
---|
2728 | /// verbose messages that are generated by the library during extraction or
|
---|
2729 | /// creation of the zip archive. A console application may wish to pass
|
---|
2730 | /// <c>System.Console.Out</c> to get messages on the Console. A graphical or
|
---|
2731 | /// headless application may wish to capture the messages in a different
|
---|
2732 | /// <c>TextWriter</c>, for example, a <c>StringWriter</c>, and then display
|
---|
2733 | /// the messages in a <c>TextBox</c>, or generate an audit log of
|
---|
2734 | /// <c>ZipFile</c> operations.
|
---|
2735 | /// </para>
|
---|
2736 | ///
|
---|
2737 | /// <para>
|
---|
2738 | /// The <c>Encoding</c> is used as the default alternate encoding for entries
|
---|
2739 | /// with filenames or comments that cannot be encoded with the IBM437 code
|
---|
2740 | /// page. This is a equivalent to setting the <see
|
---|
2741 | /// cref="ProvisionalAlternateEncoding"/> property on the <c>ZipFile</c>
|
---|
2742 | /// instance after construction.
|
---|
2743 | /// </para>
|
---|
2744 | ///
|
---|
2745 | /// <para>
|
---|
2746 | /// To encrypt the data for the files added to the <c>ZipFile</c> instance,
|
---|
2747 | /// set the <c>Password</c> property after creating the <c>ZipFile</c>
|
---|
2748 | /// instance.
|
---|
2749 | /// </para>
|
---|
2750 | ///
|
---|
2751 | /// <para>
|
---|
2752 | /// Instances of the <c>ZipFile</c> class are not multi-thread safe. You may
|
---|
2753 | /// not party on a single instance with multiple threads. You may have
|
---|
2754 | /// multiple threads that each use a distinct <c>ZipFile</c> instance, or you
|
---|
2755 | /// can synchronize multi-thread access to a single instance.
|
---|
2756 | /// </para>
|
---|
2757 | ///
|
---|
2758 | /// </remarks>
|
---|
2759 | ///
|
---|
2760 | /// <exception cref="Ionic.Zip.ZipException">
|
---|
2761 | /// Thrown if <c>fileName</c> refers to an existing file that is not a valid zip file.
|
---|
2762 | /// </exception>
|
---|
2763 | ///
|
---|
2764 | /// <param name="fileName">The filename to use for the new zip archive.</param>
|
---|
2765 | /// <param name="statusMessageWriter">A TextWriter to use for writing verbose
|
---|
2766 | /// status messages.</param>
|
---|
2767 | /// <param name="encoding">
|
---|
2768 | /// The Encoding is used as the default alternate encoding for entries with
|
---|
2769 | /// filenames or comments that cannot be encoded with the IBM437 code page.
|
---|
2770 | /// </param>
|
---|
2771 | public ZipFile(string fileName, TextWriter statusMessageWriter,
|
---|
2772 | System.Text.Encoding encoding)
|
---|
2773 | {
|
---|
2774 | try
|
---|
2775 | {
|
---|
2776 | AlternateEncoding = encoding;
|
---|
2777 | AlternateEncodingUsage = ZipOption.Always;
|
---|
2778 | _InitInstance(fileName, statusMessageWriter);
|
---|
2779 | }
|
---|
2780 | catch (Exception e1)
|
---|
2781 | {
|
---|
2782 | throw new ZipException(String.Format("{0} is not a valid zip file", fileName), e1);
|
---|
2783 | }
|
---|
2784 | }
|
---|
2785 |
|
---|
2786 |
|
---|
2787 |
|
---|
2788 |
|
---|
2789 | /// <summary>
|
---|
2790 | /// Initialize a <c>ZipFile</c> instance by reading in a zip file.
|
---|
2791 | /// </summary>
|
---|
2792 | ///
|
---|
2793 | /// <remarks>
|
---|
2794 | ///
|
---|
2795 | /// <para>
|
---|
2796 | /// This method is primarily useful from COM Automation environments, when
|
---|
2797 | /// reading or extracting zip files. In COM, it is not possible to invoke
|
---|
2798 | /// parameterized constructors for a class. A COM Automation application can
|
---|
2799 | /// update a zip file by using the <see cref="ZipFile()">default (no argument)
|
---|
2800 | /// constructor</see>, then calling <c>Initialize()</c> to read the contents
|
---|
2801 | /// of an on-disk zip archive into the <c>ZipFile</c> instance.
|
---|
2802 | /// </para>
|
---|
2803 | ///
|
---|
2804 | /// <para>
|
---|
2805 | /// .NET applications are encouraged to use the <c>ZipFile.Read()</c> methods
|
---|
2806 | /// for better clarity.
|
---|
2807 | /// </para>
|
---|
2808 | ///
|
---|
2809 | /// </remarks>
|
---|
2810 | /// <param name="fileName">the name of the existing zip file to read in.</param>
|
---|
2811 | public void Initialize(string fileName)
|
---|
2812 | {
|
---|
2813 | try
|
---|
2814 | {
|
---|
2815 | _InitInstance(fileName, null);
|
---|
2816 | }
|
---|
2817 | catch (Exception e1)
|
---|
2818 | {
|
---|
2819 | throw new ZipException(String.Format("{0} is not a valid zip file", fileName), e1);
|
---|
2820 | }
|
---|
2821 | }
|
---|
2822 |
|
---|
2823 |
|
---|
2824 |
|
---|
2825 | private void _initEntriesDictionary()
|
---|
2826 | {
|
---|
2827 | // workitem 9868
|
---|
2828 | StringComparer sc = (CaseSensitiveRetrieval) ? StringComparer.Ordinal : StringComparer.OrdinalIgnoreCase;
|
---|
2829 | _entries = (_entries == null)
|
---|
2830 | ? new Dictionary<String, ZipEntry>(sc)
|
---|
2831 | : new Dictionary<String, ZipEntry>(_entries, sc);
|
---|
2832 | }
|
---|
2833 |
|
---|
2834 |
|
---|
2835 | private void _InitInstance(string zipFileName, TextWriter statusMessageWriter)
|
---|
2836 | {
|
---|
2837 | // create a new zipfile
|
---|
2838 | _name = zipFileName;
|
---|
2839 | _StatusMessageTextWriter = statusMessageWriter;
|
---|
2840 | _contentsChanged = true;
|
---|
2841 | AddDirectoryWillTraverseReparsePoints = true; // workitem 8617
|
---|
2842 | CompressionLevel = OfficeOpenXml.Packaging.Ionic.Zlib.CompressionLevel.Default;
|
---|
2843 | #if !NETCF
|
---|
2844 | ParallelDeflateThreshold = 512 * 1024;
|
---|
2845 | #endif
|
---|
2846 | // workitem 7685, 9868
|
---|
2847 | _initEntriesDictionary();
|
---|
2848 |
|
---|
2849 | if (File.Exists(_name))
|
---|
2850 | {
|
---|
2851 | if (FullScan)
|
---|
2852 | ReadIntoInstance_Orig(this);
|
---|
2853 | else
|
---|
2854 | ReadIntoInstance(this);
|
---|
2855 | this._fileAlreadyExists = true;
|
---|
2856 | }
|
---|
2857 |
|
---|
2858 | return;
|
---|
2859 | }
|
---|
2860 | #endregion
|
---|
2861 |
|
---|
2862 |
|
---|
2863 |
|
---|
2864 | #region Indexers and Collections
|
---|
2865 |
|
---|
2866 | private List<ZipEntry> ZipEntriesAsList
|
---|
2867 | {
|
---|
2868 | get
|
---|
2869 | {
|
---|
2870 | if (_zipEntriesAsList == null)
|
---|
2871 | _zipEntriesAsList = new List<ZipEntry>(_entries.Values);
|
---|
2872 | return _zipEntriesAsList;
|
---|
2873 | }
|
---|
2874 | }
|
---|
2875 |
|
---|
2876 | /// <summary>
|
---|
2877 | /// This is an integer indexer into the Zip archive.
|
---|
2878 | /// </summary>
|
---|
2879 | ///
|
---|
2880 | /// <remarks>
|
---|
2881 | /// <para>
|
---|
2882 | /// This property is read-only.
|
---|
2883 | /// </para>
|
---|
2884 | ///
|
---|
2885 | /// <para>
|
---|
2886 | /// Internally, the <c>ZipEntry</c> instances that belong to the
|
---|
2887 | /// <c>ZipFile</c> are stored in a Dictionary. When you use this
|
---|
2888 | /// indexer the first time, it creates a read-only
|
---|
2889 | /// <c>List<ZipEntry></c> from the Dictionary.Values Collection.
|
---|
2890 | /// If at any time you modify the set of entries in the <c>ZipFile</c>,
|
---|
2891 | /// either by adding an entry, removing an entry, or renaming an
|
---|
2892 | /// entry, a new List will be created, and the numeric indexes for the
|
---|
2893 | /// remaining entries may be different.
|
---|
2894 | /// </para>
|
---|
2895 | ///
|
---|
2896 | /// <para>
|
---|
2897 | /// This means you cannot rename any ZipEntry from
|
---|
2898 | /// inside an enumeration of the zip file.
|
---|
2899 | /// </para>
|
---|
2900 | ///
|
---|
2901 | /// <param name="ix">
|
---|
2902 | /// The index value.
|
---|
2903 | /// </param>
|
---|
2904 | ///
|
---|
2905 | /// </remarks>
|
---|
2906 | ///
|
---|
2907 | /// <returns>
|
---|
2908 | /// The <c>ZipEntry</c> within the Zip archive at the specified index. If the
|
---|
2909 | /// entry does not exist in the archive, this indexer throws.
|
---|
2910 | /// </returns>
|
---|
2911 | ///
|
---|
2912 | public ZipEntry this[int ix]
|
---|
2913 | {
|
---|
2914 | // workitem 6402
|
---|
2915 | get
|
---|
2916 | {
|
---|
2917 | return ZipEntriesAsList[ix];
|
---|
2918 | }
|
---|
2919 | }
|
---|
2920 |
|
---|
2921 |
|
---|
2922 | /// <summary>
|
---|
2923 | /// This is a name-based indexer into the Zip archive.
|
---|
2924 | /// </summary>
|
---|
2925 | ///
|
---|
2926 | /// <remarks>
|
---|
2927 | /// <para>
|
---|
2928 | /// This property is read-only.
|
---|
2929 | /// </para>
|
---|
2930 | ///
|
---|
2931 | /// <para>
|
---|
2932 | /// The <see cref="CaseSensitiveRetrieval"/> property on the <c>ZipFile</c>
|
---|
2933 | /// determines whether retrieval via this indexer is done via case-sensitive
|
---|
2934 | /// comparisons. By default, retrieval is not case sensitive. This makes
|
---|
2935 | /// sense on Windows, in which filesystems are not case sensitive.
|
---|
2936 | /// </para>
|
---|
2937 | ///
|
---|
2938 | /// <para>
|
---|
2939 | /// Regardless of case-sensitivity, it is not always the case that
|
---|
2940 | /// <c>this[value].FileName == value</c>. In other words, the <c>FileName</c>
|
---|
2941 | /// property of the <c>ZipEntry</c> retrieved with this indexer, may or may
|
---|
2942 | /// not be equal to the index value.
|
---|
2943 | /// </para>
|
---|
2944 | ///
|
---|
2945 | /// <para>
|
---|
2946 | /// This is because DotNetZip performs a normalization of filenames passed to
|
---|
2947 | /// this indexer, before attempting to retrieve the item. That normalization
|
---|
2948 | /// includes: removal of a volume letter and colon, swapping backward slashes
|
---|
2949 | /// for forward slashes. So, <c>zip["dir1\\entry1.txt"].FileName ==
|
---|
2950 | /// "dir1/entry.txt"</c>.
|
---|
2951 | /// </para>
|
---|
2952 | ///
|
---|
2953 | /// <para>
|
---|
2954 | /// Directory entries in the zip file may be retrieved via this indexer only
|
---|
2955 | /// with names that have a trailing slash. DotNetZip automatically appends a
|
---|
2956 | /// trailing slash to the names of any directory entries added to a zip.
|
---|
2957 | /// </para>
|
---|
2958 | ///
|
---|
2959 | /// </remarks>
|
---|
2960 | ///
|
---|
2961 | /// <example>
|
---|
2962 | /// This example extracts only the entries in a zip file that are .txt files.
|
---|
2963 | /// <code>
|
---|
2964 | /// using (ZipFile zip = ZipFile.Read("PackedDocuments.zip"))
|
---|
2965 | /// {
|
---|
2966 | /// foreach (string s1 in zip.EntryFilenames)
|
---|
2967 | /// {
|
---|
2968 | /// if (s1.EndsWith(".txt"))
|
---|
2969 | /// zip[s1].Extract("textfiles");
|
---|
2970 | /// }
|
---|
2971 | /// }
|
---|
2972 | /// </code>
|
---|
2973 | /// <code lang="VB">
|
---|
2974 | /// Using zip As ZipFile = ZipFile.Read("PackedDocuments.zip")
|
---|
2975 | /// Dim s1 As String
|
---|
2976 | /// For Each s1 In zip.EntryFilenames
|
---|
2977 | /// If s1.EndsWith(".txt") Then
|
---|
2978 | /// zip(s1).Extract("textfiles")
|
---|
2979 | /// End If
|
---|
2980 | /// Next
|
---|
2981 | /// End Using
|
---|
2982 | /// </code>
|
---|
2983 | /// </example>
|
---|
2984 | /// <seealso cref="Ionic.Zip.ZipFile.RemoveEntry(string)"/>
|
---|
2985 | ///
|
---|
2986 | /// <exception cref="System.ArgumentException">
|
---|
2987 | /// Thrown if the caller attempts to assign a non-null value to the indexer.
|
---|
2988 | /// </exception>
|
---|
2989 | ///
|
---|
2990 | /// <param name="fileName">
|
---|
2991 | /// The name of the file, including any directory path, to retrieve from the
|
---|
2992 | /// zip. The filename match is not case-sensitive by default; you can use the
|
---|
2993 | /// <see cref="CaseSensitiveRetrieval"/> property to change this behavior. The
|
---|
2994 | /// pathname can use forward-slashes or backward slashes.
|
---|
2995 | /// </param>
|
---|
2996 | ///
|
---|
2997 | /// <returns>
|
---|
2998 | /// The <c>ZipEntry</c> within the Zip archive, given by the specified
|
---|
2999 | /// filename. If the named entry does not exist in the archive, this indexer
|
---|
3000 | /// returns <c>null</c> (<c>Nothing</c> in VB).
|
---|
3001 | /// </returns>
|
---|
3002 | ///
|
---|
3003 | public ZipEntry this[String fileName]
|
---|
3004 | {
|
---|
3005 | get
|
---|
3006 | {
|
---|
3007 | var key = SharedUtilities.NormalizePathForUseInZipFile(fileName);
|
---|
3008 | if (_entries.ContainsKey(key))
|
---|
3009 | return _entries[key];
|
---|
3010 | // workitem 11056
|
---|
3011 | key = key.Replace("/", "\\");
|
---|
3012 | if (_entries.ContainsKey(key))
|
---|
3013 | return _entries[key];
|
---|
3014 | return null;
|
---|
3015 |
|
---|
3016 | #if MESSY
|
---|
3017 | foreach (ZipEntry e in _entries.Values)
|
---|
3018 | {
|
---|
3019 | if (this.CaseSensitiveRetrieval)
|
---|
3020 | {
|
---|
3021 | // check for the file match with a case-sensitive comparison.
|
---|
3022 | if (e.FileName == fileName) return e;
|
---|
3023 | // also check for equivalence
|
---|
3024 | if (fileName.Replace("\\", "/") == e.FileName) return e;
|
---|
3025 | if (e.FileName.Replace("\\", "/") == fileName) return e;
|
---|
3026 |
|
---|
3027 | // check for a difference only in trailing slash
|
---|
3028 | if (e.FileName.EndsWith("/"))
|
---|
3029 | {
|
---|
3030 | var fileNameNoSlash = e.FileName.Trim("/".ToCharArray());
|
---|
3031 | if (fileNameNoSlash == fileName) return e;
|
---|
3032 | // also check for equivalence
|
---|
3033 | if (fileName.Replace("\\", "/") == fileNameNoSlash) return e;
|
---|
3034 | if (fileNameNoSlash.Replace("\\", "/") == fileName) return e;
|
---|
3035 | }
|
---|
3036 |
|
---|
3037 | }
|
---|
3038 | else
|
---|
3039 | {
|
---|
3040 | // check for the file match in a case-insensitive manner.
|
---|
3041 | if (String.Compare(e.FileName, fileName, StringComparison.CurrentCultureIgnoreCase) == 0) return e;
|
---|
3042 | // also check for equivalence
|
---|
3043 | if (String.Compare(fileName.Replace("\\", "/"), e.FileName, StringComparison.CurrentCultureIgnoreCase) == 0) return e;
|
---|
3044 | if (String.Compare(e.FileName.Replace("\\", "/"), fileName, StringComparison.CurrentCultureIgnoreCase) == 0) return e;
|
---|
3045 |
|
---|
3046 | // check for a difference only in trailing slash
|
---|
3047 | if (e.FileName.EndsWith("/"))
|
---|
3048 | {
|
---|
3049 | var fileNameNoSlash = e.FileName.Trim("/".ToCharArray());
|
---|
3050 |
|
---|
3051 | if (String.Compare(fileNameNoSlash, fileName, StringComparison.CurrentCultureIgnoreCase) == 0) return e;
|
---|
3052 | // also check for equivalence
|
---|
3053 | if (String.Compare(fileName.Replace("\\", "/"), fileNameNoSlash, StringComparison.CurrentCultureIgnoreCase) == 0) return e;
|
---|
3054 | if (String.Compare(fileNameNoSlash.Replace("\\", "/"), fileName, StringComparison.CurrentCultureIgnoreCase) == 0) return e;
|
---|
3055 |
|
---|
3056 | }
|
---|
3057 |
|
---|
3058 | }
|
---|
3059 |
|
---|
3060 | }
|
---|
3061 | return null;
|
---|
3062 |
|
---|
3063 | #endif
|
---|
3064 | }
|
---|
3065 | }
|
---|
3066 |
|
---|
3067 |
|
---|
3068 | /// <summary>
|
---|
3069 | /// The list of filenames for the entries contained within the zip archive.
|
---|
3070 | /// </summary>
|
---|
3071 | ///
|
---|
3072 | /// <remarks>
|
---|
3073 | /// According to the ZIP specification, the names of the entries use forward
|
---|
3074 | /// slashes in pathnames. If you are scanning through the list, you may have
|
---|
3075 | /// to swap forward slashes for backslashes.
|
---|
3076 | /// </remarks>
|
---|
3077 | ///
|
---|
3078 | /// <seealso cref="Ionic.Zip.ZipFile.this[string]"/>
|
---|
3079 | ///
|
---|
3080 | /// <example>
|
---|
3081 | /// This example shows one way to test if a filename is already contained
|
---|
3082 | /// within a zip archive.
|
---|
3083 | /// <code>
|
---|
3084 | /// String zipFileToRead= "PackedDocuments.zip";
|
---|
3085 | /// string candidate = "DatedMaterial.xps";
|
---|
3086 | /// using (ZipFile zip = new ZipFile(zipFileToRead))
|
---|
3087 | /// {
|
---|
3088 | /// if (zip.EntryFilenames.Contains(candidate))
|
---|
3089 | /// Console.WriteLine("The file '{0}' exists in the zip archive '{1}'",
|
---|
3090 | /// candidate,
|
---|
3091 | /// zipFileName);
|
---|
3092 | /// else
|
---|
3093 | /// Console.WriteLine("The file, '{0}', does not exist in the zip archive '{1}'",
|
---|
3094 | /// candidate,
|
---|
3095 | /// zipFileName);
|
---|
3096 | /// Console.WriteLine();
|
---|
3097 | /// }
|
---|
3098 | /// </code>
|
---|
3099 | /// <code lang="VB">
|
---|
3100 | /// Dim zipFileToRead As String = "PackedDocuments.zip"
|
---|
3101 | /// Dim candidate As String = "DatedMaterial.xps"
|
---|
3102 | /// Using zip As ZipFile.Read(ZipFileToRead)
|
---|
3103 | /// If zip.EntryFilenames.Contains(candidate) Then
|
---|
3104 | /// Console.WriteLine("The file '{0}' exists in the zip archive '{1}'", _
|
---|
3105 | /// candidate, _
|
---|
3106 | /// zipFileName)
|
---|
3107 | /// Else
|
---|
3108 | /// Console.WriteLine("The file, '{0}', does not exist in the zip archive '{1}'", _
|
---|
3109 | /// candidate, _
|
---|
3110 | /// zipFileName)
|
---|
3111 | /// End If
|
---|
3112 | /// Console.WriteLine
|
---|
3113 | /// End Using
|
---|
3114 | /// </code>
|
---|
3115 | /// </example>
|
---|
3116 | ///
|
---|
3117 | /// <returns>
|
---|
3118 | /// The list of strings for the filenames contained within the Zip archive.
|
---|
3119 | /// </returns>
|
---|
3120 | ///
|
---|
3121 | public System.Collections.Generic.ICollection<String> EntryFileNames
|
---|
3122 | {
|
---|
3123 | get
|
---|
3124 | {
|
---|
3125 | return _entries.Keys;
|
---|
3126 | }
|
---|
3127 | }
|
---|
3128 |
|
---|
3129 |
|
---|
3130 | /// <summary>
|
---|
3131 | /// Returns the readonly collection of entries in the Zip archive.
|
---|
3132 | /// </summary>
|
---|
3133 | ///
|
---|
3134 | /// <remarks>
|
---|
3135 | ///
|
---|
3136 | /// <para>
|
---|
3137 | /// If there are no entries in the current <c>ZipFile</c>, the value returned is a
|
---|
3138 | /// non-null zero-element collection. If there are entries in the zip file,
|
---|
3139 | /// the elements are returned in no particular order.
|
---|
3140 | /// </para>
|
---|
3141 | /// <para>
|
---|
3142 | /// This is the implied enumerator on the <c>ZipFile</c> class. If you use a
|
---|
3143 | /// <c>ZipFile</c> instance in a context that expects an enumerator, you will
|
---|
3144 | /// get this collection.
|
---|
3145 | /// </para>
|
---|
3146 | /// </remarks>
|
---|
3147 | /// <seealso cref="EntriesSorted"/>
|
---|
3148 | public System.Collections.Generic.ICollection<ZipEntry> Entries
|
---|
3149 | {
|
---|
3150 | get
|
---|
3151 | {
|
---|
3152 | return _entries.Values;
|
---|
3153 | }
|
---|
3154 | }
|
---|
3155 |
|
---|
3156 |
|
---|
3157 | /// <summary>
|
---|
3158 | /// Returns a readonly collection of entries in the Zip archive, sorted by FileName.
|
---|
3159 | /// </summary>
|
---|
3160 | ///
|
---|
3161 | /// <remarks>
|
---|
3162 | /// If there are no entries in the current <c>ZipFile</c>, the value returned
|
---|
3163 | /// is a non-null zero-element collection. If there are entries in the zip
|
---|
3164 | /// file, the elements are returned sorted by the name of the entry.
|
---|
3165 | /// </remarks>
|
---|
3166 | ///
|
---|
3167 | /// <example>
|
---|
3168 | ///
|
---|
3169 | /// This example fills a Windows Forms ListView with the entries in a zip file.
|
---|
3170 | ///
|
---|
3171 | /// <code lang="C#">
|
---|
3172 | /// using (ZipFile zip = ZipFile.Read(zipFile))
|
---|
3173 | /// {
|
---|
3174 | /// foreach (ZipEntry entry in zip.EntriesSorted)
|
---|
3175 | /// {
|
---|
3176 | /// ListViewItem item = new ListViewItem(n.ToString());
|
---|
3177 | /// n++;
|
---|
3178 | /// string[] subitems = new string[] {
|
---|
3179 | /// entry.FileName.Replace("/","\\"),
|
---|
3180 | /// entry.LastModified.ToString("yyyy-MM-dd HH:mm:ss"),
|
---|
3181 | /// entry.UncompressedSize.ToString(),
|
---|
3182 | /// String.Format("{0,5:F0}%", entry.CompressionRatio),
|
---|
3183 | /// entry.CompressedSize.ToString(),
|
---|
3184 | /// (entry.UsesEncryption) ? "Y" : "N",
|
---|
3185 | /// String.Format("{0:X8}", entry.Crc)};
|
---|
3186 | ///
|
---|
3187 | /// foreach (String s in subitems)
|
---|
3188 | /// {
|
---|
3189 | /// ListViewItem.ListViewSubItem subitem = new ListViewItem.ListViewSubItem();
|
---|
3190 | /// subitem.Text = s;
|
---|
3191 | /// item.SubItems.Add(subitem);
|
---|
3192 | /// }
|
---|
3193 | ///
|
---|
3194 | /// this.listView1.Items.Add(item);
|
---|
3195 | /// }
|
---|
3196 | /// }
|
---|
3197 | /// </code>
|
---|
3198 | /// </example>
|
---|
3199 | ///
|
---|
3200 | /// <seealso cref="Entries"/>
|
---|
3201 | public System.Collections.Generic.ICollection<ZipEntry> EntriesSorted
|
---|
3202 | {
|
---|
3203 | get
|
---|
3204 | {
|
---|
3205 | var coll = new System.Collections.Generic.List<ZipEntry>();
|
---|
3206 | foreach (var e in this.Entries)
|
---|
3207 | {
|
---|
3208 | coll.Add(e);
|
---|
3209 | }
|
---|
3210 | StringComparison sc = (CaseSensitiveRetrieval) ? StringComparison.Ordinal : StringComparison.OrdinalIgnoreCase;
|
---|
3211 |
|
---|
3212 | coll.Sort((x, y) => { return String.Compare(x.FileName, y.FileName, sc); });
|
---|
3213 | return coll.AsReadOnly();
|
---|
3214 | }
|
---|
3215 | }
|
---|
3216 |
|
---|
3217 |
|
---|
3218 | /// <summary>
|
---|
3219 | /// Returns the number of entries in the Zip archive.
|
---|
3220 | /// </summary>
|
---|
3221 | public int Count
|
---|
3222 | {
|
---|
3223 | get
|
---|
3224 | {
|
---|
3225 | return _entries.Count;
|
---|
3226 | }
|
---|
3227 | }
|
---|
3228 |
|
---|
3229 |
|
---|
3230 |
|
---|
3231 | /// <summary>
|
---|
3232 | /// Removes the given <c>ZipEntry</c> from the zip archive.
|
---|
3233 | /// </summary>
|
---|
3234 | ///
|
---|
3235 | /// <remarks>
|
---|
3236 | /// <para>
|
---|
3237 | /// After calling <c>RemoveEntry</c>, the application must call <c>Save</c> to
|
---|
3238 | /// make the changes permanent.
|
---|
3239 | /// </para>
|
---|
3240 | /// </remarks>
|
---|
3241 | ///
|
---|
3242 | /// <exception cref="System.ArgumentException">
|
---|
3243 | /// Thrown if the specified <c>ZipEntry</c> does not exist in the <c>ZipFile</c>.
|
---|
3244 | /// </exception>
|
---|
3245 | ///
|
---|
3246 | /// <example>
|
---|
3247 | /// In this example, all entries in the zip archive dating from before
|
---|
3248 | /// December 31st, 2007, are removed from the archive. This is actually much
|
---|
3249 | /// easier if you use the RemoveSelectedEntries method. But I needed an
|
---|
3250 | /// example for RemoveEntry, so here it is.
|
---|
3251 | /// <code>
|
---|
3252 | /// String ZipFileToRead = "ArchiveToModify.zip";
|
---|
3253 | /// System.DateTime Threshold = new System.DateTime(2007,12,31);
|
---|
3254 | /// using (ZipFile zip = ZipFile.Read(ZipFileToRead))
|
---|
3255 | /// {
|
---|
3256 | /// var EntriesToRemove = new System.Collections.Generic.List<ZipEntry>();
|
---|
3257 | /// foreach (ZipEntry e in zip)
|
---|
3258 | /// {
|
---|
3259 | /// if (e.LastModified < Threshold)
|
---|
3260 | /// {
|
---|
3261 | /// // We cannot remove the entry from the list, within the context of
|
---|
3262 | /// // an enumeration of said list.
|
---|
3263 | /// // So we add the doomed entry to a list to be removed later.
|
---|
3264 | /// EntriesToRemove.Add(e);
|
---|
3265 | /// }
|
---|
3266 | /// }
|
---|
3267 | ///
|
---|
3268 | /// // actually remove the doomed entries.
|
---|
3269 | /// foreach (ZipEntry zombie in EntriesToRemove)
|
---|
3270 | /// zip.RemoveEntry(zombie);
|
---|
3271 | ///
|
---|
3272 | /// zip.Comment= String.Format("This zip archive was updated at {0}.",
|
---|
3273 | /// System.DateTime.Now.ToString("G"));
|
---|
3274 | ///
|
---|
3275 | /// // save with a different name
|
---|
3276 | /// zip.Save("Archive-Updated.zip");
|
---|
3277 | /// }
|
---|
3278 | /// </code>
|
---|
3279 | ///
|
---|
3280 | /// <code lang="VB">
|
---|
3281 | /// Dim ZipFileToRead As String = "ArchiveToModify.zip"
|
---|
3282 | /// Dim Threshold As New DateTime(2007, 12, 31)
|
---|
3283 | /// Using zip As ZipFile = ZipFile.Read(ZipFileToRead)
|
---|
3284 | /// Dim EntriesToRemove As New System.Collections.Generic.List(Of ZipEntry)
|
---|
3285 | /// Dim e As ZipEntry
|
---|
3286 | /// For Each e In zip
|
---|
3287 | /// If (e.LastModified < Threshold) Then
|
---|
3288 | /// ' We cannot remove the entry from the list, within the context of
|
---|
3289 | /// ' an enumeration of said list.
|
---|
3290 | /// ' So we add the doomed entry to a list to be removed later.
|
---|
3291 | /// EntriesToRemove.Add(e)
|
---|
3292 | /// End If
|
---|
3293 | /// Next
|
---|
3294 | ///
|
---|
3295 | /// ' actually remove the doomed entries.
|
---|
3296 | /// Dim zombie As ZipEntry
|
---|
3297 | /// For Each zombie In EntriesToRemove
|
---|
3298 | /// zip.RemoveEntry(zombie)
|
---|
3299 | /// Next
|
---|
3300 | /// zip.Comment = String.Format("This zip archive was updated at {0}.", DateTime.Now.ToString("G"))
|
---|
3301 | /// 'save as a different name
|
---|
3302 | /// zip.Save("Archive-Updated.zip")
|
---|
3303 | /// End Using
|
---|
3304 | /// </code>
|
---|
3305 | /// </example>
|
---|
3306 | ///
|
---|
3307 | /// <param name="entry">
|
---|
3308 | /// The <c>ZipEntry</c> to remove from the zip.
|
---|
3309 | /// </param>
|
---|
3310 | ///
|
---|
3311 | /// <seealso cref="Ionic.Zip.ZipFile.RemoveSelectedEntries(string)"/>
|
---|
3312 | ///
|
---|
3313 | public void RemoveEntry(ZipEntry entry)
|
---|
3314 | {
|
---|
3315 | //if (!_entries.Values.Contains(entry))
|
---|
3316 | // throw new ArgumentException("The entry you specified does not exist in the zip archive.");
|
---|
3317 | if (entry == null)
|
---|
3318 | throw new ArgumentNullException("entry");
|
---|
3319 |
|
---|
3320 | _entries.Remove(SharedUtilities.NormalizePathForUseInZipFile(entry.FileName));
|
---|
3321 | _zipEntriesAsList = null;
|
---|
3322 |
|
---|
3323 | #if NOTNEEDED
|
---|
3324 | if (_direntries != null)
|
---|
3325 | {
|
---|
3326 | bool FoundAndRemovedDirEntry = false;
|
---|
3327 | foreach (ZipDirEntry de1 in _direntries)
|
---|
3328 | {
|
---|
3329 | if (entry.FileName == de1.FileName)
|
---|
3330 | {
|
---|
3331 | _direntries.Remove(de1);
|
---|
3332 | FoundAndRemovedDirEntry = true;
|
---|
3333 | break;
|
---|
3334 | }
|
---|
3335 | }
|
---|
3336 |
|
---|
3337 | if (!FoundAndRemovedDirEntry)
|
---|
3338 | throw new BadStateException("The entry to be removed was not found in the directory.");
|
---|
3339 | }
|
---|
3340 | #endif
|
---|
3341 | _contentsChanged = true;
|
---|
3342 | }
|
---|
3343 |
|
---|
3344 |
|
---|
3345 |
|
---|
3346 |
|
---|
3347 | /// <summary>
|
---|
3348 | /// Removes the <c>ZipEntry</c> with the given filename from the zip archive.
|
---|
3349 | /// </summary>
|
---|
3350 | ///
|
---|
3351 | /// <remarks>
|
---|
3352 | /// <para>
|
---|
3353 | /// After calling <c>RemoveEntry</c>, the application must call <c>Save</c> to
|
---|
3354 | /// make the changes permanent.
|
---|
3355 | /// </para>
|
---|
3356 | ///
|
---|
3357 | /// </remarks>
|
---|
3358 | ///
|
---|
3359 | /// <exception cref="System.InvalidOperationException">
|
---|
3360 | /// Thrown if the <c>ZipFile</c> is not updatable.
|
---|
3361 | /// </exception>
|
---|
3362 | ///
|
---|
3363 | /// <exception cref="System.ArgumentException">
|
---|
3364 | /// Thrown if a <c>ZipEntry</c> with the specified filename does not exist in
|
---|
3365 | /// the <c>ZipFile</c>.
|
---|
3366 | /// </exception>
|
---|
3367 | ///
|
---|
3368 | /// <example>
|
---|
3369 | ///
|
---|
3370 | /// This example shows one way to remove an entry with a given filename from
|
---|
3371 | /// an existing zip archive.
|
---|
3372 | ///
|
---|
3373 | /// <code>
|
---|
3374 | /// String zipFileToRead= "PackedDocuments.zip";
|
---|
3375 | /// string candidate = "DatedMaterial.xps";
|
---|
3376 | /// using (ZipFile zip = ZipFile.Read(zipFileToRead))
|
---|
3377 | /// {
|
---|
3378 | /// if (zip.EntryFilenames.Contains(candidate))
|
---|
3379 | /// {
|
---|
3380 | /// zip.RemoveEntry(candidate);
|
---|
3381 | /// zip.Comment= String.Format("The file '{0}' has been removed from this archive.",
|
---|
3382 | /// Candidate);
|
---|
3383 | /// zip.Save();
|
---|
3384 | /// }
|
---|
3385 | /// }
|
---|
3386 | /// </code>
|
---|
3387 | /// <code lang="VB">
|
---|
3388 | /// Dim zipFileToRead As String = "PackedDocuments.zip"
|
---|
3389 | /// Dim candidate As String = "DatedMaterial.xps"
|
---|
3390 | /// Using zip As ZipFile = ZipFile.Read(zipFileToRead)
|
---|
3391 | /// If zip.EntryFilenames.Contains(candidate) Then
|
---|
3392 | /// zip.RemoveEntry(candidate)
|
---|
3393 | /// zip.Comment = String.Format("The file '{0}' has been removed from this archive.", Candidate)
|
---|
3394 | /// zip.Save
|
---|
3395 | /// End If
|
---|
3396 | /// End Using
|
---|
3397 | /// </code>
|
---|
3398 | /// </example>
|
---|
3399 | ///
|
---|
3400 | /// <param name="fileName">
|
---|
3401 | /// The name of the file, including any directory path, to remove from the zip.
|
---|
3402 | /// The filename match is not case-sensitive by default; you can use the
|
---|
3403 | /// <c>CaseSensitiveRetrieval</c> property to change this behavior. The
|
---|
3404 | /// pathname can use forward-slashes or backward slashes.
|
---|
3405 | /// </param>
|
---|
3406 | ///
|
---|
3407 | public void RemoveEntry(String fileName)
|
---|
3408 | {
|
---|
3409 | string modifiedName = ZipEntry.NameInArchive(fileName, null);
|
---|
3410 | ZipEntry e = this[modifiedName];
|
---|
3411 | if (e == null)
|
---|
3412 | throw new ArgumentException("The entry you specified was not found in the zip archive.");
|
---|
3413 |
|
---|
3414 | RemoveEntry(e);
|
---|
3415 | }
|
---|
3416 |
|
---|
3417 |
|
---|
3418 | #endregion
|
---|
3419 |
|
---|
3420 | #region Destructors and Disposers
|
---|
3421 |
|
---|
3422 | // /// <summary>
|
---|
3423 | // /// This is the class Destructor, which gets called implicitly when the instance
|
---|
3424 | // /// is destroyed. Because the <c>ZipFile</c> type implements IDisposable, this
|
---|
3425 | // /// method calls Dispose(false).
|
---|
3426 | // /// </summary>
|
---|
3427 | // ~ZipFile()
|
---|
3428 | // {
|
---|
3429 | // // call Dispose with false. Since we're in the
|
---|
3430 | // // destructor call, the managed resources will be
|
---|
3431 | // // disposed of anyways.
|
---|
3432 | // Dispose(false);
|
---|
3433 | // }
|
---|
3434 |
|
---|
3435 | /// <summary>
|
---|
3436 | /// Closes the read and write streams associated
|
---|
3437 | /// to the <c>ZipFile</c>, if necessary.
|
---|
3438 | /// </summary>
|
---|
3439 | ///
|
---|
3440 | /// <remarks>
|
---|
3441 | /// The Dispose() method is generally employed implicitly, via a <c>using(..) {..}</c>
|
---|
3442 | /// statement. (<c>Using...End Using</c> in VB) If you do not employ a using
|
---|
3443 | /// statement, insure that your application calls Dispose() explicitly. For
|
---|
3444 | /// example, in a Powershell application, or an application that uses the COM
|
---|
3445 | /// interop interface, you must call Dispose() explicitly.
|
---|
3446 | /// </remarks>
|
---|
3447 | ///
|
---|
3448 | /// <example>
|
---|
3449 | /// This example extracts an entry selected by name, from the Zip file to the
|
---|
3450 | /// Console.
|
---|
3451 | /// <code>
|
---|
3452 | /// using (ZipFile zip = ZipFile.Read(zipfile))
|
---|
3453 | /// {
|
---|
3454 | /// foreach (ZipEntry e in zip)
|
---|
3455 | /// {
|
---|
3456 | /// if (WantThisEntry(e.FileName))
|
---|
3457 | /// zip.Extract(e.FileName, Console.OpenStandardOutput());
|
---|
3458 | /// }
|
---|
3459 | /// } // Dispose() is called implicitly here.
|
---|
3460 | /// </code>
|
---|
3461 | ///
|
---|
3462 | /// <code lang="VB">
|
---|
3463 | /// Using zip As ZipFile = ZipFile.Read(zipfile)
|
---|
3464 | /// Dim e As ZipEntry
|
---|
3465 | /// For Each e In zip
|
---|
3466 | /// If WantThisEntry(e.FileName) Then
|
---|
3467 | /// zip.Extract(e.FileName, Console.OpenStandardOutput())
|
---|
3468 | /// End If
|
---|
3469 | /// Next
|
---|
3470 | /// End Using ' Dispose is implicity called here
|
---|
3471 | /// </code>
|
---|
3472 | /// </example>
|
---|
3473 | public void Dispose()
|
---|
3474 | {
|
---|
3475 | // dispose of the managed and unmanaged resources
|
---|
3476 | Dispose(true);
|
---|
3477 |
|
---|
3478 | // tell the GC that the Finalize process no longer needs
|
---|
3479 | // to be run for this object.
|
---|
3480 | GC.SuppressFinalize(this);
|
---|
3481 | }
|
---|
3482 |
|
---|
3483 | /// <summary>
|
---|
3484 | /// Disposes any managed resources, if the flag is set, then marks the
|
---|
3485 | /// instance disposed. This method is typically not called explicitly from
|
---|
3486 | /// application code.
|
---|
3487 | /// </summary>
|
---|
3488 | ///
|
---|
3489 | /// <remarks>
|
---|
3490 | /// Applications should call <see cref="Dispose()">the no-arg Dispose method</see>.
|
---|
3491 | /// </remarks>
|
---|
3492 | ///
|
---|
3493 | /// <param name="disposeManagedResources">
|
---|
3494 | /// indicates whether the method should dispose streams or not.
|
---|
3495 | /// </param>
|
---|
3496 | protected virtual void Dispose(bool disposeManagedResources)
|
---|
3497 | {
|
---|
3498 | if (!this._disposed)
|
---|
3499 | {
|
---|
3500 | if (disposeManagedResources)
|
---|
3501 | {
|
---|
3502 | // dispose managed resources
|
---|
3503 | if (_ReadStreamIsOurs)
|
---|
3504 | {
|
---|
3505 | if (_readstream != null)
|
---|
3506 | {
|
---|
3507 | // workitem 7704
|
---|
3508 | #if NETCF
|
---|
3509 | _readstream.Close();
|
---|
3510 | #else
|
---|
3511 | _readstream.Dispose();
|
---|
3512 | #endif
|
---|
3513 | _readstream = null;
|
---|
3514 | }
|
---|
3515 | }
|
---|
3516 | // only dispose the writestream if there is a backing file
|
---|
3517 | if ((_temporaryFileName != null) && (_name != null))
|
---|
3518 | if (_writestream != null)
|
---|
3519 | {
|
---|
3520 | // workitem 7704
|
---|
3521 | #if NETCF
|
---|
3522 | _writestream.Close();
|
---|
3523 | #else
|
---|
3524 | _writestream.Dispose();
|
---|
3525 | #endif
|
---|
3526 | _writestream = null;
|
---|
3527 | }
|
---|
3528 |
|
---|
3529 | #if !NETCF
|
---|
3530 | // workitem 10030
|
---|
3531 | if (this.ParallelDeflater != null)
|
---|
3532 | {
|
---|
3533 | this.ParallelDeflater.Dispose();
|
---|
3534 | this.ParallelDeflater = null;
|
---|
3535 | }
|
---|
3536 | #endif
|
---|
3537 | }
|
---|
3538 | this._disposed = true;
|
---|
3539 | }
|
---|
3540 | }
|
---|
3541 | #endregion
|
---|
3542 |
|
---|
3543 |
|
---|
3544 | #region private properties
|
---|
3545 |
|
---|
3546 | internal Stream ReadStream
|
---|
3547 | {
|
---|
3548 | get
|
---|
3549 | {
|
---|
3550 | if (_readstream == null)
|
---|
3551 | {
|
---|
3552 | if (_readName != null || _name !=null)
|
---|
3553 | {
|
---|
3554 | _readstream = File.Open(_readName ?? _name,
|
---|
3555 | FileMode.Open,
|
---|
3556 | FileAccess.Read,
|
---|
3557 | FileShare.Read | FileShare.Write);
|
---|
3558 | _ReadStreamIsOurs = true;
|
---|
3559 | }
|
---|
3560 | }
|
---|
3561 | return _readstream;
|
---|
3562 | }
|
---|
3563 | }
|
---|
3564 |
|
---|
3565 |
|
---|
3566 |
|
---|
3567 | private Stream WriteStream
|
---|
3568 | {
|
---|
3569 | // workitem 9763
|
---|
3570 | get
|
---|
3571 | {
|
---|
3572 | if (_writestream != null) return _writestream;
|
---|
3573 | if (_name == null) return _writestream;
|
---|
3574 |
|
---|
3575 | if (_maxOutputSegmentSize != 0)
|
---|
3576 | {
|
---|
3577 | _writestream = ZipSegmentedStream.ForWriting(this._name, _maxOutputSegmentSize);
|
---|
3578 | return _writestream;
|
---|
3579 | }
|
---|
3580 |
|
---|
3581 | SharedUtilities.CreateAndOpenUniqueTempFile(TempFileFolder ?? Path.GetDirectoryName(_name),
|
---|
3582 | out _writestream,
|
---|
3583 | out _temporaryFileName);
|
---|
3584 | return _writestream;
|
---|
3585 | }
|
---|
3586 | set
|
---|
3587 | {
|
---|
3588 | if (value != null)
|
---|
3589 | throw new ZipException("Cannot set the stream to a non-null value.");
|
---|
3590 | _writestream = null;
|
---|
3591 | }
|
---|
3592 | }
|
---|
3593 | #endregion
|
---|
3594 |
|
---|
3595 | #region private fields
|
---|
3596 | private TextWriter _StatusMessageTextWriter;
|
---|
3597 | private bool _CaseSensitiveRetrieval;
|
---|
3598 | private Stream _readstream;
|
---|
3599 | private Stream _writestream;
|
---|
3600 | private UInt16 _versionMadeBy;
|
---|
3601 | private UInt16 _versionNeededToExtract;
|
---|
3602 | private UInt32 _diskNumberWithCd;
|
---|
3603 | private Int32 _maxOutputSegmentSize;
|
---|
3604 | private UInt32 _numberOfSegmentsForMostRecentSave;
|
---|
3605 | private ZipErrorAction _zipErrorAction;
|
---|
3606 | private bool _disposed;
|
---|
3607 | //private System.Collections.Generic.List<ZipEntry> _entries;
|
---|
3608 | private System.Collections.Generic.Dictionary<String, ZipEntry> _entries;
|
---|
3609 | private List<ZipEntry> _zipEntriesAsList;
|
---|
3610 | private string _name;
|
---|
3611 | private string _readName;
|
---|
3612 | private string _Comment;
|
---|
3613 | internal string _Password;
|
---|
3614 | private bool _emitNtfsTimes = true;
|
---|
3615 | private bool _emitUnixTimes;
|
---|
3616 | private Ionic.Zlib.CompressionStrategy _Strategy = Ionic.Zlib.CompressionStrategy.Default;
|
---|
3617 | private Ionic.Zip.CompressionMethod _compressionMethod = Ionic.Zip.CompressionMethod.Deflate;
|
---|
3618 | private bool _fileAlreadyExists;
|
---|
3619 | private string _temporaryFileName;
|
---|
3620 | private bool _contentsChanged;
|
---|
3621 | private bool _hasBeenSaved;
|
---|
3622 | private String _TempFileFolder;
|
---|
3623 | private bool _ReadStreamIsOurs = true;
|
---|
3624 | private object LOCK = new object();
|
---|
3625 | private bool _saveOperationCanceled;
|
---|
3626 | private bool _extractOperationCanceled;
|
---|
3627 | private bool _addOperationCanceled;
|
---|
3628 | private EncryptionAlgorithm _Encryption;
|
---|
3629 | private bool _JustSaved;
|
---|
3630 | private long _locEndOfCDS = -1;
|
---|
3631 | private uint _OffsetOfCentralDirectory;
|
---|
3632 | private Int64 _OffsetOfCentralDirectory64;
|
---|
3633 | private Nullable<bool> _OutputUsesZip64;
|
---|
3634 | internal bool _inExtractAll;
|
---|
3635 | private System.Text.Encoding _alternateEncoding = System.Text.Encoding.GetEncoding("IBM437"); // UTF-8
|
---|
3636 | private ZipOption _alternateEncodingUsage = ZipOption.Never;
|
---|
3637 | private static System.Text.Encoding _defaultEncoding = System.Text.Encoding.GetEncoding("IBM437");
|
---|
3638 |
|
---|
3639 | private int _BufferSize = BufferSizeDefault;
|
---|
3640 |
|
---|
3641 | #if !NETCF
|
---|
3642 | internal Ionic.Zlib.ParallelDeflateOutputStream ParallelDeflater;
|
---|
3643 | private long _ParallelDeflateThreshold;
|
---|
3644 | private int _maxBufferPairs = 16;
|
---|
3645 | #endif
|
---|
3646 |
|
---|
3647 | internal Zip64Option _zip64 = Zip64Option.Default;
|
---|
3648 | #pragma warning disable 649
|
---|
3649 | private bool _SavingSfx;
|
---|
3650 | #pragma warning restore 649
|
---|
3651 |
|
---|
3652 | /// <summary>
|
---|
3653 | /// Default size of the buffer used for IO.
|
---|
3654 | /// </summary>
|
---|
3655 | public static readonly int BufferSizeDefault = 32768;
|
---|
3656 |
|
---|
3657 | #endregion
|
---|
3658 | }
|
---|
3659 |
|
---|
3660 | /// <summary>
|
---|
3661 | /// Options for using ZIP64 extensions when saving zip archives.
|
---|
3662 | /// </summary>
|
---|
3663 | ///
|
---|
3664 | /// <remarks>
|
---|
3665 | ///
|
---|
3666 | /// <para>
|
---|
3667 | /// Designed many years ago, the <see
|
---|
3668 | /// href="http://www.pkware.com/documents/casestudies/APPNOTE.TXT">original zip
|
---|
3669 | /// specification from PKWARE</see> allowed for 32-bit quantities for the
|
---|
3670 | /// compressed and uncompressed sizes of zip entries, as well as a 32-bit quantity
|
---|
3671 | /// for specifying the length of the zip archive itself, and a maximum of 65535
|
---|
3672 | /// entries. These limits are now regularly exceeded in many backup and archival
|
---|
3673 | /// scenarios. Recently, PKWare added extensions to the original zip spec, called
|
---|
3674 | /// "ZIP64 extensions", to raise those limitations. This property governs whether
|
---|
3675 | /// DotNetZip will use those extensions when writing zip archives. The use of
|
---|
3676 | /// these extensions is optional and explicit in DotNetZip because, despite the
|
---|
3677 | /// status of ZIP64 as a bona fide standard, many other zip tools and libraries do
|
---|
3678 | /// not support ZIP64, and therefore a zip file with ZIP64 extensions may be
|
---|
3679 | /// unreadable by some of those other tools.
|
---|
3680 | /// </para>
|
---|
3681 | ///
|
---|
3682 | /// <para>
|
---|
3683 | /// Set this property to <see cref="Zip64Option.Always"/> to always use ZIP64
|
---|
3684 | /// extensions when saving, regardless of whether your zip archive needs it.
|
---|
3685 | /// Suppose you add 5 files, each under 100k, to a ZipFile. If you specify Always
|
---|
3686 | /// for this flag, you will get a ZIP64 archive, though the archive does not need
|
---|
3687 | /// to use ZIP64 because none of the original zip limits had been exceeded.
|
---|
3688 | /// </para>
|
---|
3689 | ///
|
---|
3690 | /// <para>
|
---|
3691 | /// Set this property to <see cref="Zip64Option.Never"/> to tell the DotNetZip
|
---|
3692 | /// library to never use ZIP64 extensions. This is useful for maximum
|
---|
3693 | /// compatibility and interoperability, at the expense of the capability of
|
---|
3694 | /// handling large files or large archives. NB: Windows Explorer in Windows XP
|
---|
3695 | /// and Windows Vista cannot currently extract files from a zip64 archive, so if
|
---|
3696 | /// you want to guarantee that a zip archive produced by this library will work in
|
---|
3697 | /// Windows Explorer, use <c>Never</c>. If you set this property to <see
|
---|
3698 | /// cref="Zip64Option.Never"/>, and your application creates a zip that would
|
---|
3699 | /// exceed one of the Zip limits, the library will throw an exception while saving
|
---|
3700 | /// the zip file.
|
---|
3701 | /// </para>
|
---|
3702 | ///
|
---|
3703 | /// <para>
|
---|
3704 | /// Set this property to <see cref="Zip64Option.AsNecessary"/> to tell the
|
---|
3705 | /// DotNetZip library to use the ZIP64 extensions when required by the
|
---|
3706 | /// entry. After the file is compressed, the original and compressed sizes are
|
---|
3707 | /// checked, and if they exceed the limits described above, then zip64 can be
|
---|
3708 | /// used. That is the general idea, but there is an additional wrinkle when saving
|
---|
3709 | /// to a non-seekable device, like the ASP.NET <c>Response.OutputStream</c>, or
|
---|
3710 | /// <c>Console.Out</c>. When using non-seekable streams for output, the entry
|
---|
3711 | /// header - which indicates whether zip64 is in use - is emitted before it is
|
---|
3712 | /// known if zip64 is necessary. It is only after all entries have been saved
|
---|
3713 | /// that it can be known if ZIP64 will be required. On seekable output streams,
|
---|
3714 | /// after saving all entries, the library can seek backward and re-emit the zip
|
---|
3715 | /// file header to be consistent with the actual ZIP64 requirement. But using a
|
---|
3716 | /// non-seekable output stream, the library cannot seek backward, so the header
|
---|
3717 | /// can never be changed. In other words, the archive's use of ZIP64 extensions is
|
---|
3718 | /// not alterable after the header is emitted. Therefore, when saving to
|
---|
3719 | /// non-seekable streams, using <see cref="Zip64Option.AsNecessary"/> is the same
|
---|
3720 | /// as using <see cref="Zip64Option.Always"/>: it will always produce a zip
|
---|
3721 | /// archive that uses ZIP64 extensions.
|
---|
3722 | /// </para>
|
---|
3723 | ///
|
---|
3724 | /// </remarks>
|
---|
3725 | internal enum Zip64Option
|
---|
3726 | {
|
---|
3727 | /// <summary>
|
---|
3728 | /// The default behavior, which is "Never".
|
---|
3729 | /// (For COM clients, this is a 0 (zero).)
|
---|
3730 | /// </summary>
|
---|
3731 | Default = 0,
|
---|
3732 | /// <summary>
|
---|
3733 | /// Do not use ZIP64 extensions when writing zip archives.
|
---|
3734 | /// (For COM clients, this is a 0 (zero).)
|
---|
3735 | /// </summary>
|
---|
3736 | Never = 0,
|
---|
3737 | /// <summary>
|
---|
3738 | /// Use ZIP64 extensions when writing zip archives, as necessary.
|
---|
3739 | /// For example, when a single entry exceeds 0xFFFFFFFF in size, or when the archive as a whole
|
---|
3740 | /// exceeds 0xFFFFFFFF in size, or when there are more than 65535 entries in an archive.
|
---|
3741 | /// (For COM clients, this is a 1.)
|
---|
3742 | /// </summary>
|
---|
3743 | AsNecessary = 1,
|
---|
3744 | /// <summary>
|
---|
3745 | /// Always use ZIP64 extensions when writing zip archives, even when unnecessary.
|
---|
3746 | /// (For COM clients, this is a 2.)
|
---|
3747 | /// </summary>
|
---|
3748 | Always
|
---|
3749 | }
|
---|
3750 |
|
---|
3751 |
|
---|
3752 | /// <summary>
|
---|
3753 | /// An enum representing the values on a three-way toggle switch
|
---|
3754 | /// for various options in the library. This might be used to
|
---|
3755 | /// specify whether to employ a particular text encoding, or to use
|
---|
3756 | /// ZIP64 extensions, or some other option.
|
---|
3757 | /// </summary>
|
---|
3758 | internal enum ZipOption
|
---|
3759 | {
|
---|
3760 | /// <summary>
|
---|
3761 | /// The default behavior. This is the same as "Never".
|
---|
3762 | /// (For COM clients, this is a 0 (zero).)
|
---|
3763 | /// </summary>
|
---|
3764 | Default = 0,
|
---|
3765 | /// <summary>
|
---|
3766 | /// Never use the associated option.
|
---|
3767 | /// (For COM clients, this is a 0 (zero).)
|
---|
3768 | /// </summary>
|
---|
3769 | Never = 0,
|
---|
3770 | /// <summary>
|
---|
3771 | /// Use the associated behavior "as necessary."
|
---|
3772 | /// (For COM clients, this is a 1.)
|
---|
3773 | /// </summary>
|
---|
3774 | AsNecessary = 1,
|
---|
3775 | /// <summary>
|
---|
3776 | /// Use the associated behavior Always, whether necessary or not.
|
---|
3777 | /// (For COM clients, this is a 2.)
|
---|
3778 | /// </summary>
|
---|
3779 | Always
|
---|
3780 | }
|
---|
3781 |
|
---|
3782 |
|
---|
3783 | enum AddOrUpdateAction
|
---|
3784 | {
|
---|
3785 | AddOnly = 0,
|
---|
3786 | AddOrUpdate
|
---|
3787 | }
|
---|
3788 |
|
---|
3789 | }
|
---|
3790 |
|
---|
3791 |
|
---|
3792 |
|
---|
3793 | // ==================================================================
|
---|
3794 | //
|
---|
3795 | // Information on the ZIP format:
|
---|
3796 | //
|
---|
3797 | // From
|
---|
3798 | // http://www.pkware.com/documents/casestudies/APPNOTE.TXT
|
---|
3799 | //
|
---|
3800 | // Overall .ZIP file format:
|
---|
3801 | //
|
---|
3802 | // [local file header 1]
|
---|
3803 | // [file data 1]
|
---|
3804 | // [data descriptor 1] ** sometimes
|
---|
3805 | // .
|
---|
3806 | // .
|
---|
3807 | // .
|
---|
3808 | // [local file header n]
|
---|
3809 | // [file data n]
|
---|
3810 | // [data descriptor n] ** sometimes
|
---|
3811 | // [archive decryption header]
|
---|
3812 | // [archive extra data record]
|
---|
3813 | // [central directory]
|
---|
3814 | // [zip64 end of central directory record]
|
---|
3815 | // [zip64 end of central directory locator]
|
---|
3816 | // [end of central directory record]
|
---|
3817 | //
|
---|
3818 | // Local File Header format:
|
---|
3819 | // local file header signature ... 4 bytes (0x04034b50)
|
---|
3820 | // version needed to extract ..... 2 bytes
|
---|
3821 | // general purpose bit field ..... 2 bytes
|
---|
3822 | // compression method ............ 2 bytes
|
---|
3823 | // last mod file time ............ 2 bytes
|
---|
3824 | // last mod file date............. 2 bytes
|
---|
3825 | // crc-32 ........................ 4 bytes
|
---|
3826 | // compressed size................ 4 bytes
|
---|
3827 | // uncompressed size.............. 4 bytes
|
---|
3828 | // file name length............... 2 bytes
|
---|
3829 | // extra field length ............ 2 bytes
|
---|
3830 | // file name varies
|
---|
3831 | // extra field varies
|
---|
3832 | //
|
---|
3833 | //
|
---|
3834 | // Data descriptor: (used only when bit 3 of the general purpose bitfield is set)
|
---|
3835 | // (although, I have found zip files where bit 3 is not set, yet this descriptor is present!)
|
---|
3836 | // local file header signature 4 bytes (0x08074b50) ** sometimes!!! Not always
|
---|
3837 | // crc-32 4 bytes
|
---|
3838 | // compressed size 4 bytes
|
---|
3839 | // uncompressed size 4 bytes
|
---|
3840 | //
|
---|
3841 | //
|
---|
3842 | // Central directory structure:
|
---|
3843 | //
|
---|
3844 | // [file header 1]
|
---|
3845 | // .
|
---|
3846 | // .
|
---|
3847 | // .
|
---|
3848 | // [file header n]
|
---|
3849 | // [digital signature]
|
---|
3850 | //
|
---|
3851 | //
|
---|
3852 | // File header: (This is a ZipDirEntry)
|
---|
3853 | // central file header signature 4 bytes (0x02014b50)
|
---|
3854 | // version made by 2 bytes
|
---|
3855 | // version needed to extract 2 bytes
|
---|
3856 | // general purpose bit flag 2 bytes
|
---|
3857 | // compression method 2 bytes
|
---|
3858 | // last mod file time 2 bytes
|
---|
3859 | // last mod file date 2 bytes
|
---|
3860 | // crc-32 4 bytes
|
---|
3861 | // compressed size 4 bytes
|
---|
3862 | // uncompressed size 4 bytes
|
---|
3863 | // file name length 2 bytes
|
---|
3864 | // extra field length 2 bytes
|
---|
3865 | // file comment length 2 bytes
|
---|
3866 | // disk number start 2 bytes
|
---|
3867 | // internal file attributes ** 2 bytes
|
---|
3868 | // external file attributes *** 4 bytes
|
---|
3869 | // relative offset of local header 4 bytes
|
---|
3870 | // file name (variable size)
|
---|
3871 | // extra field (variable size)
|
---|
3872 | // file comment (variable size)
|
---|
3873 | //
|
---|
3874 | // ** The internal file attributes, near as I can tell,
|
---|
3875 | // uses 0x01 for a file and a 0x00 for a directory.
|
---|
3876 | //
|
---|
3877 | // ***The external file attributes follows the MS-DOS file attribute byte, described here:
|
---|
3878 | // at http://support.microsoft.com/kb/q125019/
|
---|
3879 | // 0x0010 => directory
|
---|
3880 | // 0x0020 => file
|
---|
3881 | //
|
---|
3882 | //
|
---|
3883 | // End of central directory record:
|
---|
3884 | //
|
---|
3885 | // end of central dir signature 4 bytes (0x06054b50)
|
---|
3886 | // number of this disk 2 bytes
|
---|
3887 | // number of the disk with the
|
---|
3888 | // start of the central directory 2 bytes
|
---|
3889 | // total number of entries in the
|
---|
3890 | // central directory on this disk 2 bytes
|
---|
3891 | // total number of entries in
|
---|
3892 | // the central directory 2 bytes
|
---|
3893 | // size of the central directory 4 bytes
|
---|
3894 | // offset of start of central
|
---|
3895 | // directory with respect to
|
---|
3896 | // the starting disk number 4 bytes
|
---|
3897 | // .ZIP file comment length 2 bytes
|
---|
3898 | // .ZIP file comment (variable size)
|
---|
3899 | //
|
---|
3900 | // date and time are packed values, as MSDOS did them
|
---|
3901 | // time: bits 0-4 : seconds (divided by 2)
|
---|
3902 | // 5-10: minute
|
---|
3903 | // 11-15: hour
|
---|
3904 | // date bits 0-4 : day
|
---|
3905 | // 5-8: month
|
---|
3906 | // 9-15 year (since 1980)
|
---|
3907 | //
|
---|
3908 | // see http://msdn.microsoft.com/en-us/library/ms724274(VS.85).aspx
|
---|
3909 |
|
---|