1 | // ZipOutputStream.cs
|
---|
2 | //
|
---|
3 | // ------------------------------------------------------------------
|
---|
4 | //
|
---|
5 | // Copyright (c) 2009 Dino Chiesa.
|
---|
6 | // All rights reserved.
|
---|
7 | //
|
---|
8 | // This code module is part of DotNetZip, a zipfile class library.
|
---|
9 | //
|
---|
10 | // ------------------------------------------------------------------
|
---|
11 | //
|
---|
12 | // This code is licensed under the Microsoft Public License.
|
---|
13 | // See the file License.txt for the license details.
|
---|
14 | // More info on: http://dotnetzip.codeplex.com
|
---|
15 | //
|
---|
16 | // ------------------------------------------------------------------
|
---|
17 | //
|
---|
18 | // last saved (in emacs):
|
---|
19 | // Time-stamp: <2011-July-28 06:34:30>
|
---|
20 | //
|
---|
21 | // ------------------------------------------------------------------
|
---|
22 | //
|
---|
23 | // This module defines the ZipOutputStream class, which is a stream metaphor for
|
---|
24 | // generating zip files. This class does not depend on Ionic.Zip.ZipFile, but rather
|
---|
25 | // stands alongside it as an alternative "container" for ZipEntry. It replicates a
|
---|
26 | // subset of the properties, including these:
|
---|
27 | //
|
---|
28 | // - Comment
|
---|
29 | // - Encryption
|
---|
30 | // - Password
|
---|
31 | // - CodecBufferSize
|
---|
32 | // - CompressionLevel
|
---|
33 | // - CompressionMethod
|
---|
34 | // - EnableZip64 (UseZip64WhenSaving)
|
---|
35 | // - IgnoreCase (!CaseSensitiveRetrieval)
|
---|
36 | //
|
---|
37 | // It adds these novel methods:
|
---|
38 | //
|
---|
39 | // - PutNextEntry
|
---|
40 | //
|
---|
41 | //
|
---|
42 | // ------------------------------------------------------------------
|
---|
43 | //
|
---|
44 |
|
---|
45 | using System;
|
---|
46 | using System.Threading;
|
---|
47 | using System.Collections.Generic;
|
---|
48 | using System.IO;
|
---|
49 | using Ionic.Zip;
|
---|
50 | using OfficeOpenXml.Packaging.Ionic.Zlib;
|
---|
51 |
|
---|
52 | namespace OfficeOpenXml.Packaging.Ionic.Zip
|
---|
53 | {
|
---|
54 | /// <summary>
|
---|
55 | /// Provides a stream metaphor for generating zip files.
|
---|
56 | /// </summary>
|
---|
57 | ///
|
---|
58 | /// <remarks>
|
---|
59 | /// <para>
|
---|
60 | /// This class writes zip files, as defined in the <see
|
---|
61 | /// href="http://www.pkware.com/documents/casestudies/APPNOTE.TXT">specification
|
---|
62 | /// for zip files described by PKWare</see>. The compression for this
|
---|
63 | /// implementation is provided by a managed-code version of Zlib, included with
|
---|
64 | /// DotNetZip in the classes in the Ionic.Zlib namespace.
|
---|
65 | /// </para>
|
---|
66 | ///
|
---|
67 | /// <para>
|
---|
68 | /// This class provides an alternative programming model to the one enabled by the
|
---|
69 | /// <see cref="ZipFile"/> class. Use this when creating zip files, as an
|
---|
70 | /// alternative to the <see cref="ZipFile"/> class, when you would like to use a
|
---|
71 | /// <c>Stream</c> type to write the zip file.
|
---|
72 | /// </para>
|
---|
73 | ///
|
---|
74 | /// <para>
|
---|
75 | /// Both the <c>ZipOutputStream</c> class and the <c>ZipFile</c> class can be used
|
---|
76 | /// to create zip files. Both of them support many of the common zip features,
|
---|
77 | /// including Unicode, different compression levels, and ZIP64. They provide
|
---|
78 | /// very similar performance when creating zip files.
|
---|
79 | /// </para>
|
---|
80 | ///
|
---|
81 | /// <para>
|
---|
82 | /// The <c>ZipFile</c> class is generally easier to use than
|
---|
83 | /// <c>ZipOutputStream</c> and should be considered a higher-level interface. For
|
---|
84 | /// example, when creating a zip file via calls to the <c>PutNextEntry()</c> and
|
---|
85 | /// <c>Write()</c> methods on the <c>ZipOutputStream</c> class, the caller is
|
---|
86 | /// responsible for opening the file, reading the bytes from the file, writing
|
---|
87 | /// those bytes into the <c>ZipOutputStream</c>, setting the attributes on the
|
---|
88 | /// <c>ZipEntry</c>, and setting the created, last modified, and last accessed
|
---|
89 | /// timestamps on the zip entry. All of these things are done automatically by a
|
---|
90 | /// call to <see cref="ZipFile.AddFile(string,string)">ZipFile.AddFile()</see>.
|
---|
91 | /// For this reason, the <c>ZipOutputStream</c> is generally recommended for use
|
---|
92 | /// only when your application emits arbitrary data, not necessarily data from a
|
---|
93 | /// filesystem file, directly into a zip file, and does so using a <c>Stream</c>
|
---|
94 | /// metaphor.
|
---|
95 | /// </para>
|
---|
96 | ///
|
---|
97 | /// <para>
|
---|
98 | /// Aside from the differences in programming model, there are other
|
---|
99 | /// differences in capability between the two classes.
|
---|
100 | /// </para>
|
---|
101 | ///
|
---|
102 | /// <list type="bullet">
|
---|
103 | /// <item>
|
---|
104 | /// <c>ZipFile</c> can be used to read and extract zip files, in addition to
|
---|
105 | /// creating zip files. <c>ZipOutputStream</c> cannot read zip files. If you want
|
---|
106 | /// to use a stream to read zip files, check out the <see cref="ZipInputStream"/> class.
|
---|
107 | /// </item>
|
---|
108 | ///
|
---|
109 | /// <item>
|
---|
110 | /// <c>ZipOutputStream</c> does not support the creation of segmented or spanned
|
---|
111 | /// zip files.
|
---|
112 | /// </item>
|
---|
113 | ///
|
---|
114 | /// <item>
|
---|
115 | /// <c>ZipOutputStream</c> cannot produce a self-extracting archive.
|
---|
116 | /// </item>
|
---|
117 | /// </list>
|
---|
118 | ///
|
---|
119 | /// <para>
|
---|
120 | /// Be aware that the <c>ZipOutputStream</c> class implements the <see
|
---|
121 | /// cref="System.IDisposable"/> interface. In order for
|
---|
122 | /// <c>ZipOutputStream</c> to produce a valid zip file, you use use it within
|
---|
123 | /// a using clause (<c>Using</c> in VB), or call the <c>Dispose()</c> method
|
---|
124 | /// explicitly. See the examples for how to employ a using clause.
|
---|
125 | /// </para>
|
---|
126 | ///
|
---|
127 | /// <para>
|
---|
128 | /// Also, a note regarding compression performance: On the desktop .NET
|
---|
129 | /// Framework, DotNetZip can use a multi-threaded compression implementation
|
---|
130 | /// that provides significant speed increases on large files, over 300k or so,
|
---|
131 | /// at the cost of increased memory use at runtime. (The output of the
|
---|
132 | /// compression is almost exactly the same size). But, the multi-threaded
|
---|
133 | /// approach incurs a performance hit on smaller files. There's no way for the
|
---|
134 | /// ZipOutputStream to know whether parallel compression will be beneficial,
|
---|
135 | /// because the ZipOutputStream does not know how much data you will write
|
---|
136 | /// through the stream. You may wish to set the <see
|
---|
137 | /// cref="ParallelDeflateThreshold"/> property to zero, if you are compressing
|
---|
138 | /// large files through <c>ZipOutputStream</c>. This will cause parallel
|
---|
139 | /// compression to be used, always.
|
---|
140 | /// </para>
|
---|
141 | /// </remarks>
|
---|
142 | internal class ZipOutputStream : Stream
|
---|
143 | {
|
---|
144 | /// <summary>
|
---|
145 | /// Create a ZipOutputStream, wrapping an existing stream.
|
---|
146 | /// </summary>
|
---|
147 | ///
|
---|
148 | /// <remarks>
|
---|
149 | /// <para>
|
---|
150 | /// The <see cref="ZipFile"/> class is generally easier to use when creating
|
---|
151 | /// zip files. The ZipOutputStream offers a different metaphor for creating a
|
---|
152 | /// zip file, based on the <see cref="System.IO.Stream"/> class.
|
---|
153 | /// </para>
|
---|
154 | ///
|
---|
155 | /// </remarks>
|
---|
156 | ///
|
---|
157 | /// <param name="stream">
|
---|
158 | /// The stream to wrap. It must be writable. This stream will be closed at
|
---|
159 | /// the time the ZipOutputStream is closed.
|
---|
160 | /// </param>
|
---|
161 | ///
|
---|
162 | /// <example>
|
---|
163 | ///
|
---|
164 | /// This example shows how to create a zip file, using the
|
---|
165 | /// ZipOutputStream class.
|
---|
166 | ///
|
---|
167 | /// <code lang="C#">
|
---|
168 | /// private void Zipup()
|
---|
169 | /// {
|
---|
170 | /// if (filesToZip.Count == 0)
|
---|
171 | /// {
|
---|
172 | /// System.Console.WriteLine("Nothing to do.");
|
---|
173 | /// return;
|
---|
174 | /// }
|
---|
175 | ///
|
---|
176 | /// using (var raw = File.Open(_outputFileName, FileMode.Create, FileAccess.ReadWrite ))
|
---|
177 | /// {
|
---|
178 | /// using (var output= new ZipOutputStream(raw))
|
---|
179 | /// {
|
---|
180 | /// output.Password = "VerySecret!";
|
---|
181 | /// output.Encryption = EncryptionAlgorithm.WinZipAes256;
|
---|
182 | ///
|
---|
183 | /// foreach (string inputFileName in filesToZip)
|
---|
184 | /// {
|
---|
185 | /// System.Console.WriteLine("file: {0}", inputFileName);
|
---|
186 | ///
|
---|
187 | /// output.PutNextEntry(inputFileName);
|
---|
188 | /// using (var input = File.Open(inputFileName, FileMode.Open, FileAccess.Read, FileShare.Read | FileShare.Write ))
|
---|
189 | /// {
|
---|
190 | /// byte[] buffer= new byte[2048];
|
---|
191 | /// int n;
|
---|
192 | /// while ((n= input.Read(buffer,0,buffer.Length)) > 0)
|
---|
193 | /// {
|
---|
194 | /// output.Write(buffer,0,n);
|
---|
195 | /// }
|
---|
196 | /// }
|
---|
197 | /// }
|
---|
198 | /// }
|
---|
199 | /// }
|
---|
200 | /// }
|
---|
201 | /// </code>
|
---|
202 | ///
|
---|
203 | /// <code lang="VB">
|
---|
204 | /// Private Sub Zipup()
|
---|
205 | /// Dim outputFileName As String = "XmlData.zip"
|
---|
206 | /// Dim filesToZip As String() = Directory.GetFiles(".", "*.xml")
|
---|
207 | /// If (filesToZip.Length = 0) Then
|
---|
208 | /// Console.WriteLine("Nothing to do.")
|
---|
209 | /// Else
|
---|
210 | /// Using raw As FileStream = File.Open(outputFileName, FileMode.Create, FileAccess.ReadWrite)
|
---|
211 | /// Using output As ZipOutputStream = New ZipOutputStream(raw)
|
---|
212 | /// output.Password = "VerySecret!"
|
---|
213 | /// output.Encryption = EncryptionAlgorithm.WinZipAes256
|
---|
214 | /// Dim inputFileName As String
|
---|
215 | /// For Each inputFileName In filesToZip
|
---|
216 | /// Console.WriteLine("file: {0}", inputFileName)
|
---|
217 | /// output.PutNextEntry(inputFileName)
|
---|
218 | /// Using input As FileStream = File.Open(inputFileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)
|
---|
219 | /// Dim n As Integer
|
---|
220 | /// Dim buffer As Byte() = New Byte(2048) {}
|
---|
221 | /// Do While (n = input.Read(buffer, 0, buffer.Length) > 0)
|
---|
222 | /// output.Write(buffer, 0, n)
|
---|
223 | /// Loop
|
---|
224 | /// End Using
|
---|
225 | /// Next
|
---|
226 | /// End Using
|
---|
227 | /// End Using
|
---|
228 | /// End If
|
---|
229 | /// End Sub
|
---|
230 | /// </code>
|
---|
231 | /// </example>
|
---|
232 | public ZipOutputStream(Stream stream) : this(stream, false) { }
|
---|
233 |
|
---|
234 |
|
---|
235 | /// <summary>
|
---|
236 | /// Create a ZipOutputStream that writes to a filesystem file.
|
---|
237 | /// </summary>
|
---|
238 | ///
|
---|
239 | /// <remarks>
|
---|
240 | /// The <see cref="ZipFile"/> class is generally easier to use when creating
|
---|
241 | /// zip files. The ZipOutputStream offers a different metaphor for creating a
|
---|
242 | /// zip file, based on the <see cref="System.IO.Stream"/> class.
|
---|
243 | /// </remarks>
|
---|
244 | ///
|
---|
245 | /// <param name="fileName">
|
---|
246 | /// The name of the zip file to create.
|
---|
247 | /// </param>
|
---|
248 | ///
|
---|
249 | /// <example>
|
---|
250 | ///
|
---|
251 | /// This example shows how to create a zip file, using the
|
---|
252 | /// ZipOutputStream class.
|
---|
253 | ///
|
---|
254 | /// <code lang="C#">
|
---|
255 | /// private void Zipup()
|
---|
256 | /// {
|
---|
257 | /// if (filesToZip.Count == 0)
|
---|
258 | /// {
|
---|
259 | /// System.Console.WriteLine("Nothing to do.");
|
---|
260 | /// return;
|
---|
261 | /// }
|
---|
262 | ///
|
---|
263 | /// using (var output= new ZipOutputStream(outputFileName))
|
---|
264 | /// {
|
---|
265 | /// output.Password = "VerySecret!";
|
---|
266 | /// output.Encryption = EncryptionAlgorithm.WinZipAes256;
|
---|
267 | ///
|
---|
268 | /// foreach (string inputFileName in filesToZip)
|
---|
269 | /// {
|
---|
270 | /// System.Console.WriteLine("file: {0}", inputFileName);
|
---|
271 | ///
|
---|
272 | /// output.PutNextEntry(inputFileName);
|
---|
273 | /// using (var input = File.Open(inputFileName, FileMode.Open, FileAccess.Read,
|
---|
274 | /// FileShare.Read | FileShare.Write ))
|
---|
275 | /// {
|
---|
276 | /// byte[] buffer= new byte[2048];
|
---|
277 | /// int n;
|
---|
278 | /// while ((n= input.Read(buffer,0,buffer.Length)) > 0)
|
---|
279 | /// {
|
---|
280 | /// output.Write(buffer,0,n);
|
---|
281 | /// }
|
---|
282 | /// }
|
---|
283 | /// }
|
---|
284 | /// }
|
---|
285 | /// }
|
---|
286 | /// </code>
|
---|
287 | ///
|
---|
288 | /// <code lang="VB">
|
---|
289 | /// Private Sub Zipup()
|
---|
290 | /// Dim outputFileName As String = "XmlData.zip"
|
---|
291 | /// Dim filesToZip As String() = Directory.GetFiles(".", "*.xml")
|
---|
292 | /// If (filesToZip.Length = 0) Then
|
---|
293 | /// Console.WriteLine("Nothing to do.")
|
---|
294 | /// Else
|
---|
295 | /// Using output As ZipOutputStream = New ZipOutputStream(outputFileName)
|
---|
296 | /// output.Password = "VerySecret!"
|
---|
297 | /// output.Encryption = EncryptionAlgorithm.WinZipAes256
|
---|
298 | /// Dim inputFileName As String
|
---|
299 | /// For Each inputFileName In filesToZip
|
---|
300 | /// Console.WriteLine("file: {0}", inputFileName)
|
---|
301 | /// output.PutNextEntry(inputFileName)
|
---|
302 | /// Using input As FileStream = File.Open(inputFileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)
|
---|
303 | /// Dim n As Integer
|
---|
304 | /// Dim buffer As Byte() = New Byte(2048) {}
|
---|
305 | /// Do While (n = input.Read(buffer, 0, buffer.Length) > 0)
|
---|
306 | /// output.Write(buffer, 0, n)
|
---|
307 | /// Loop
|
---|
308 | /// End Using
|
---|
309 | /// Next
|
---|
310 | /// End Using
|
---|
311 | /// End If
|
---|
312 | /// End Sub
|
---|
313 | /// </code>
|
---|
314 | /// </example>
|
---|
315 | public ZipOutputStream(String fileName)
|
---|
316 | {
|
---|
317 | Stream stream = File.Open(fileName, FileMode.Create, FileAccess.ReadWrite, FileShare.None);
|
---|
318 | _Init(stream, false, fileName);
|
---|
319 | }
|
---|
320 |
|
---|
321 |
|
---|
322 | /// <summary>
|
---|
323 | /// Create a ZipOutputStream.
|
---|
324 | /// </summary>
|
---|
325 | ///
|
---|
326 | /// <remarks>
|
---|
327 | /// See the documentation for the <see
|
---|
328 | /// cref="ZipOutputStream(Stream)">ZipOutputStream(Stream)</see>
|
---|
329 | /// constructor for an example.
|
---|
330 | /// </remarks>
|
---|
331 | ///
|
---|
332 | /// <param name="stream">
|
---|
333 | /// The stream to wrap. It must be writable.
|
---|
334 | /// </param>
|
---|
335 | ///
|
---|
336 | /// <param name="leaveOpen">
|
---|
337 | /// true if the application would like the stream
|
---|
338 | /// to remain open after the <c>ZipOutputStream</c> has been closed.
|
---|
339 | /// </param>
|
---|
340 | public ZipOutputStream(Stream stream, bool leaveOpen)
|
---|
341 | {
|
---|
342 | _Init(stream, leaveOpen, null);
|
---|
343 | }
|
---|
344 |
|
---|
345 | private void _Init(Stream stream, bool leaveOpen, string name)
|
---|
346 | {
|
---|
347 | // workitem 9307
|
---|
348 | _outputStream = stream.CanRead ? stream : new CountingStream(stream);
|
---|
349 | CompressionLevel = OfficeOpenXml.Packaging.Ionic.Zlib.CompressionLevel.Default;
|
---|
350 | CompressionMethod = OfficeOpenXml.Packaging.Ionic.Zip.CompressionMethod.Deflate;
|
---|
351 | _encryption = EncryptionAlgorithm.None;
|
---|
352 | _entriesWritten = new Dictionary<String, ZipEntry>(StringComparer.Ordinal);
|
---|
353 | _zip64 = Zip64Option.Never;
|
---|
354 | _leaveUnderlyingStreamOpen = leaveOpen;
|
---|
355 | Strategy = Ionic.Zlib.CompressionStrategy.Default;
|
---|
356 | _name = name ?? "(stream)";
|
---|
357 | #if !NETCF
|
---|
358 | ParallelDeflateThreshold = -1L;
|
---|
359 | #endif
|
---|
360 | }
|
---|
361 |
|
---|
362 |
|
---|
363 | /// <summary>Provides a string representation of the instance.</summary>
|
---|
364 | /// <remarks>
|
---|
365 | /// <para>
|
---|
366 | /// This can be useful for debugging purposes.
|
---|
367 | /// </para>
|
---|
368 | /// </remarks>
|
---|
369 | /// <returns>a string representation of the instance.</returns>
|
---|
370 | public override String ToString()
|
---|
371 | {
|
---|
372 | return String.Format ("ZipOutputStream::{0}(leaveOpen({1})))", _name, _leaveUnderlyingStreamOpen);
|
---|
373 | }
|
---|
374 |
|
---|
375 |
|
---|
376 | /// <summary>
|
---|
377 | /// Sets the password to be used on the <c>ZipOutputStream</c> instance.
|
---|
378 | /// </summary>
|
---|
379 | ///
|
---|
380 | /// <remarks>
|
---|
381 | ///
|
---|
382 | /// <para>
|
---|
383 | /// When writing a zip archive, this password is applied to the entries, not
|
---|
384 | /// to the zip archive itself. It applies to any <c>ZipEntry</c> subsequently
|
---|
385 | /// written to the <c>ZipOutputStream</c>.
|
---|
386 | /// </para>
|
---|
387 | ///
|
---|
388 | /// <para>
|
---|
389 | /// Using a password does not encrypt or protect the "directory" of the
|
---|
390 | /// archive - the list of entries contained in the archive. If you set the
|
---|
391 | /// <c>Password</c> property, the password actually applies to individual
|
---|
392 | /// entries that are added to the archive, subsequent to the setting of this
|
---|
393 | /// property. The list of filenames in the archive that is eventually created
|
---|
394 | /// will appear in clear text, but the contents of the individual files are
|
---|
395 | /// encrypted. This is how Zip encryption works.
|
---|
396 | /// </para>
|
---|
397 | ///
|
---|
398 | /// <para>
|
---|
399 | /// If you set this property, and then add a set of entries to the archive via
|
---|
400 | /// calls to <c>PutNextEntry</c>, then each entry is encrypted with that
|
---|
401 | /// password. You may also want to change the password between adding
|
---|
402 | /// different entries. If you set the password, add an entry, then set the
|
---|
403 | /// password to <c>null</c> (<c>Nothing</c> in VB), and add another entry, the
|
---|
404 | /// first entry is encrypted and the second is not.
|
---|
405 | /// </para>
|
---|
406 | ///
|
---|
407 | /// <para>
|
---|
408 | /// When setting the <c>Password</c>, you may also want to explicitly set the <see
|
---|
409 | /// cref="Encryption"/> property, to specify how to encrypt the entries added
|
---|
410 | /// to the ZipFile. If you set the <c>Password</c> to a non-null value and do not
|
---|
411 | /// set <see cref="Encryption"/>, then PKZip 2.0 ("Weak") encryption is used.
|
---|
412 | /// This encryption is relatively weak but is very interoperable. If
|
---|
413 | /// you set the password to a <c>null</c> value (<c>Nothing</c> in VB),
|
---|
414 | /// <c>Encryption</c> is reset to None.
|
---|
415 | /// </para>
|
---|
416 | ///
|
---|
417 | /// <para>
|
---|
418 | /// Special case: if you wrap a ZipOutputStream around a non-seekable stream,
|
---|
419 | /// and use encryption, and emit an entry of zero bytes, the <c>Close()</c> or
|
---|
420 | /// <c>PutNextEntry()</c> following the entry will throw an exception.
|
---|
421 | /// </para>
|
---|
422 | ///
|
---|
423 | /// </remarks>
|
---|
424 | public String Password
|
---|
425 | {
|
---|
426 | set
|
---|
427 | {
|
---|
428 | if (_disposed)
|
---|
429 | {
|
---|
430 | _exceptionPending = true;
|
---|
431 | throw new System.InvalidOperationException("The stream has been closed.");
|
---|
432 | }
|
---|
433 |
|
---|
434 | _password = value;
|
---|
435 | if (_password == null)
|
---|
436 | {
|
---|
437 | _encryption = EncryptionAlgorithm.None;
|
---|
438 | }
|
---|
439 | else if (_encryption == EncryptionAlgorithm.None)
|
---|
440 | {
|
---|
441 | _encryption = EncryptionAlgorithm.PkzipWeak;
|
---|
442 | }
|
---|
443 | }
|
---|
444 | }
|
---|
445 |
|
---|
446 |
|
---|
447 | /// <summary>
|
---|
448 | /// The Encryption to use for entries added to the <c>ZipOutputStream</c>.
|
---|
449 | /// </summary>
|
---|
450 | ///
|
---|
451 | /// <remarks>
|
---|
452 | /// <para>
|
---|
453 | /// The specified Encryption is applied to the entries subsequently
|
---|
454 | /// written to the <c>ZipOutputStream</c> instance.
|
---|
455 | /// </para>
|
---|
456 | ///
|
---|
457 | /// <para>
|
---|
458 | /// If you set this to something other than
|
---|
459 | /// EncryptionAlgorithm.None, you will also need to set the
|
---|
460 | /// <see cref="Password"/> to a non-null, non-empty value in
|
---|
461 | /// order to actually get encryption on the entry.
|
---|
462 | /// </para>
|
---|
463 | ///
|
---|
464 | /// </remarks>
|
---|
465 | ///
|
---|
466 | /// <seealso cref="Password">ZipOutputStream.Password</seealso>
|
---|
467 | /// <seealso cref="ZipEntry.Encryption">ZipEntry.Encryption</seealso>
|
---|
468 | public EncryptionAlgorithm Encryption
|
---|
469 | {
|
---|
470 | get
|
---|
471 | {
|
---|
472 | return _encryption;
|
---|
473 | }
|
---|
474 | set
|
---|
475 | {
|
---|
476 | if (_disposed)
|
---|
477 | {
|
---|
478 | _exceptionPending = true;
|
---|
479 | throw new System.InvalidOperationException("The stream has been closed.");
|
---|
480 | }
|
---|
481 | if (value == EncryptionAlgorithm.Unsupported)
|
---|
482 | {
|
---|
483 | _exceptionPending = true;
|
---|
484 | throw new InvalidOperationException("You may not set Encryption to that value.");
|
---|
485 | }
|
---|
486 | _encryption = value;
|
---|
487 | }
|
---|
488 | }
|
---|
489 |
|
---|
490 |
|
---|
491 | /// <summary>
|
---|
492 | /// Size of the work buffer to use for the ZLIB codec during compression.
|
---|
493 | /// </summary>
|
---|
494 | ///
|
---|
495 | /// <remarks>
|
---|
496 | /// Setting this may affect performance. For larger files, setting this to a
|
---|
497 | /// larger size may improve performance, but I'm not sure. Sorry, I don't
|
---|
498 | /// currently have good recommendations on how to set it. You can test it if
|
---|
499 | /// you like.
|
---|
500 | /// </remarks>
|
---|
501 | public int CodecBufferSize
|
---|
502 | {
|
---|
503 | get;
|
---|
504 | set;
|
---|
505 | }
|
---|
506 |
|
---|
507 |
|
---|
508 | /// <summary>
|
---|
509 | /// The compression strategy to use for all entries.
|
---|
510 | /// </summary>
|
---|
511 | ///
|
---|
512 | /// <remarks>
|
---|
513 | /// Set the Strategy used by the ZLIB-compatible compressor, when compressing
|
---|
514 | /// data for the entries in the zip archive. Different compression strategies
|
---|
515 | /// work better on different sorts of data. The strategy parameter can affect
|
---|
516 | /// the compression ratio and the speed of compression but not the correctness
|
---|
517 | /// of the compresssion. For more information see <see
|
---|
518 | /// cref="Ionic.Zlib.CompressionStrategy "/>.
|
---|
519 | /// </remarks>
|
---|
520 | public CompressionStrategy Strategy
|
---|
521 | {
|
---|
522 | get;
|
---|
523 | set;
|
---|
524 | }
|
---|
525 |
|
---|
526 |
|
---|
527 | /// <summary>
|
---|
528 | /// The type of timestamp attached to the ZipEntry.
|
---|
529 | /// </summary>
|
---|
530 | ///
|
---|
531 | /// <remarks>
|
---|
532 | /// Set this in order to specify the kind of timestamp that should be emitted
|
---|
533 | /// into the zip file for each entry.
|
---|
534 | /// </remarks>
|
---|
535 | public ZipEntryTimestamp Timestamp
|
---|
536 | {
|
---|
537 | get
|
---|
538 | {
|
---|
539 | return _timestamp;
|
---|
540 | }
|
---|
541 | set
|
---|
542 | {
|
---|
543 | if (_disposed)
|
---|
544 | {
|
---|
545 | _exceptionPending = true;
|
---|
546 | throw new System.InvalidOperationException("The stream has been closed.");
|
---|
547 | }
|
---|
548 | _timestamp = value;
|
---|
549 | }
|
---|
550 | }
|
---|
551 |
|
---|
552 |
|
---|
553 | /// <summary>
|
---|
554 | /// Sets the compression level to be used for entries subsequently added to
|
---|
555 | /// the zip archive.
|
---|
556 | /// </summary>
|
---|
557 | ///
|
---|
558 | /// <remarks>
|
---|
559 | /// <para>
|
---|
560 | /// Varying the compression level used on entries can affect the
|
---|
561 | /// size-vs-speed tradeoff when compression and decompressing data streams
|
---|
562 | /// or files.
|
---|
563 | /// </para>
|
---|
564 | ///
|
---|
565 | /// <para>
|
---|
566 | /// As with some other properties on the <c>ZipOutputStream</c> class, like <see
|
---|
567 | /// cref="Password"/>, and <see cref="Encryption"/>,
|
---|
568 | /// setting this property on a <c>ZipOutputStream</c>
|
---|
569 | /// instance will cause the specified <c>CompressionLevel</c> to be used on all
|
---|
570 | /// <see cref="ZipEntry"/> items that are subsequently added to the
|
---|
571 | /// <c>ZipOutputStream</c> instance.
|
---|
572 | /// </para>
|
---|
573 | ///
|
---|
574 | /// <para>
|
---|
575 | /// If you do not set this property, the default compression level is used,
|
---|
576 | /// which normally gives a good balance of compression efficiency and
|
---|
577 | /// compression speed. In some tests, using <c>BestCompression</c> can
|
---|
578 | /// double the time it takes to compress, while delivering just a small
|
---|
579 | /// increase in compression efficiency. This behavior will vary with the
|
---|
580 | /// type of data you compress. If you are in doubt, just leave this setting
|
---|
581 | /// alone, and accept the default.
|
---|
582 | /// </para>
|
---|
583 | /// </remarks>
|
---|
584 | public OfficeOpenXml.Packaging.Ionic.Zlib.CompressionLevel CompressionLevel
|
---|
585 | {
|
---|
586 | get;
|
---|
587 | set;
|
---|
588 | }
|
---|
589 |
|
---|
590 | /// <summary>
|
---|
591 | /// The compression method used on each entry added to the ZipOutputStream.
|
---|
592 | /// </summary>
|
---|
593 | public CompressionMethod CompressionMethod
|
---|
594 | {
|
---|
595 | get;
|
---|
596 | set;
|
---|
597 | }
|
---|
598 |
|
---|
599 |
|
---|
600 | /// <summary>
|
---|
601 | /// A comment attached to the zip archive.
|
---|
602 | /// </summary>
|
---|
603 | ///
|
---|
604 | /// <remarks>
|
---|
605 | ///
|
---|
606 | /// <para>
|
---|
607 | /// The application sets this property to specify a comment to be embedded
|
---|
608 | /// into the generated zip archive.
|
---|
609 | /// </para>
|
---|
610 | ///
|
---|
611 | /// <para>
|
---|
612 | /// According to <see
|
---|
613 | /// href="http://www.pkware.com/documents/casestudies/APPNOTE.TXT">PKWARE's
|
---|
614 | /// zip specification</see>, the comment is not encrypted, even if there is a
|
---|
615 | /// password set on the zip file.
|
---|
616 | /// </para>
|
---|
617 | ///
|
---|
618 | /// <para>
|
---|
619 | /// The specification does not describe how to indicate the encoding used
|
---|
620 | /// on a comment string. Many "compliant" zip tools and libraries use
|
---|
621 | /// IBM437 as the code page for comments; DotNetZip, too, follows that
|
---|
622 | /// practice. On the other hand, there are situations where you want a
|
---|
623 | /// Comment to be encoded with something else, for example using code page
|
---|
624 | /// 950 "Big-5 Chinese". To fill that need, DotNetZip will encode the
|
---|
625 | /// comment following the same procedure it follows for encoding
|
---|
626 | /// filenames: (a) if <see cref="AlternateEncodingUsage"/> is
|
---|
627 | /// <c>Never</c>, it uses the default encoding (IBM437). (b) if <see
|
---|
628 | /// cref="AlternateEncodingUsage"/> is <c>Always</c>, it always uses the
|
---|
629 | /// alternate encoding (<see cref="AlternateEncoding"/>). (c) if <see
|
---|
630 | /// cref="AlternateEncodingUsage"/> is <c>AsNecessary</c>, it uses the
|
---|
631 | /// alternate encoding only if the default encoding is not sufficient for
|
---|
632 | /// encoding the comment - in other words if decoding the result does not
|
---|
633 | /// produce the original string. This decision is taken at the time of
|
---|
634 | /// the call to <c>ZipFile.Save()</c>.
|
---|
635 | /// </para>
|
---|
636 | ///
|
---|
637 | /// </remarks>
|
---|
638 | public string Comment
|
---|
639 | {
|
---|
640 | get { return _comment; }
|
---|
641 | set
|
---|
642 | {
|
---|
643 | if (_disposed)
|
---|
644 | {
|
---|
645 | _exceptionPending = true;
|
---|
646 | throw new System.InvalidOperationException("The stream has been closed.");
|
---|
647 | }
|
---|
648 | _comment = value;
|
---|
649 | }
|
---|
650 | }
|
---|
651 |
|
---|
652 |
|
---|
653 |
|
---|
654 | /// <summary>
|
---|
655 | /// Specify whether to use ZIP64 extensions when saving a zip archive.
|
---|
656 | /// </summary>
|
---|
657 | ///
|
---|
658 | /// <remarks>
|
---|
659 | /// <para>
|
---|
660 | /// The default value for the property is <see
|
---|
661 | /// cref="Zip64Option.Never"/>. <see cref="Zip64Option.AsNecessary"/> is
|
---|
662 | /// safest, in the sense that you will not get an Exception if a
|
---|
663 | /// pre-ZIP64 limit is exceeded.
|
---|
664 | /// </para>
|
---|
665 | ///
|
---|
666 | /// <para>
|
---|
667 | /// You must set this property before calling <c>Write()</c>.
|
---|
668 | /// </para>
|
---|
669 | ///
|
---|
670 | /// </remarks>
|
---|
671 | public Zip64Option EnableZip64
|
---|
672 | {
|
---|
673 | get
|
---|
674 | {
|
---|
675 | return _zip64;
|
---|
676 | }
|
---|
677 | set
|
---|
678 | {
|
---|
679 | if (_disposed)
|
---|
680 | {
|
---|
681 | _exceptionPending = true;
|
---|
682 | throw new System.InvalidOperationException("The stream has been closed.");
|
---|
683 | }
|
---|
684 | _zip64 = value;
|
---|
685 | }
|
---|
686 | }
|
---|
687 |
|
---|
688 |
|
---|
689 | /// <summary>
|
---|
690 | /// Indicates whether ZIP64 extensions were used when saving the zip archive.
|
---|
691 | /// </summary>
|
---|
692 | ///
|
---|
693 | /// <remarks>
|
---|
694 | /// The value is defined only after the <c>ZipOutputStream</c> has been closed.
|
---|
695 | /// </remarks>
|
---|
696 | public bool OutputUsedZip64
|
---|
697 | {
|
---|
698 | get
|
---|
699 | {
|
---|
700 | return _anyEntriesUsedZip64 || _directoryNeededZip64;
|
---|
701 | }
|
---|
702 | }
|
---|
703 |
|
---|
704 |
|
---|
705 | /// <summary>
|
---|
706 | /// Whether the ZipOutputStream should use case-insensitive comparisons when
|
---|
707 | /// checking for uniqueness of zip entries.
|
---|
708 | /// </summary>
|
---|
709 | ///
|
---|
710 | /// <remarks>
|
---|
711 | /// <para>
|
---|
712 | /// Though the zip specification doesn't prohibit zipfiles with duplicate
|
---|
713 | /// entries, Sane zip files have no duplicates, and the DotNetZip library
|
---|
714 | /// cannot create zip files with duplicate entries. If an application attempts
|
---|
715 | /// to call <see cref="PutNextEntry(String)"/> with a name that duplicates one
|
---|
716 | /// already used within the archive, the library will throw an Exception.
|
---|
717 | /// </para>
|
---|
718 | /// <para>
|
---|
719 | /// This property allows the application to specify whether the
|
---|
720 | /// ZipOutputStream instance considers ordinal case when checking for
|
---|
721 | /// uniqueness of zip entries.
|
---|
722 | /// </para>
|
---|
723 | /// </remarks>
|
---|
724 | public bool IgnoreCase
|
---|
725 | {
|
---|
726 | get
|
---|
727 | {
|
---|
728 | return !_DontIgnoreCase;
|
---|
729 | }
|
---|
730 |
|
---|
731 | set
|
---|
732 | {
|
---|
733 | _DontIgnoreCase = !value;
|
---|
734 | }
|
---|
735 |
|
---|
736 | }
|
---|
737 |
|
---|
738 |
|
---|
739 | /// <summary>
|
---|
740 | /// Indicates whether to encode entry filenames and entry comments using
|
---|
741 | /// Unicode (UTF-8).
|
---|
742 | /// </summary>
|
---|
743 | ///
|
---|
744 | /// <remarks>
|
---|
745 | /// <para>
|
---|
746 | /// <see href="http://www.pkware.com/documents/casestudies/APPNOTE.TXT">The
|
---|
747 | /// PKWare zip specification</see> provides for encoding file names and file
|
---|
748 | /// comments in either the IBM437 code page, or in UTF-8. This flag selects
|
---|
749 | /// the encoding according to that specification. By default, this flag is
|
---|
750 | /// false, and filenames and comments are encoded into the zip file in the
|
---|
751 | /// IBM437 codepage. Setting this flag to true will specify that filenames
|
---|
752 | /// and comments that cannot be encoded with IBM437 will be encoded with
|
---|
753 | /// UTF-8.
|
---|
754 | /// </para>
|
---|
755 | ///
|
---|
756 | /// <para>
|
---|
757 | /// Zip files created with strict adherence to the PKWare specification with
|
---|
758 | /// respect to UTF-8 encoding can contain entries with filenames containing
|
---|
759 | /// any combination of Unicode characters, including the full range of
|
---|
760 | /// characters from Chinese, Latin, Hebrew, Greek, Cyrillic, and many other
|
---|
761 | /// alphabets. However, because at this time, the UTF-8 portion of the PKWare
|
---|
762 | /// specification is not broadly supported by other zip libraries and
|
---|
763 | /// utilities, such zip files may not be readable by your favorite zip tool or
|
---|
764 | /// archiver. In other words, interoperability will decrease if you set this
|
---|
765 | /// flag to true.
|
---|
766 | /// </para>
|
---|
767 | ///
|
---|
768 | /// <para>
|
---|
769 | /// In particular, Zip files created with strict adherence to the PKWare
|
---|
770 | /// specification with respect to UTF-8 encoding will not work well with
|
---|
771 | /// Explorer in Windows XP or Windows Vista, because Windows compressed
|
---|
772 | /// folders, as far as I know, do not support UTF-8 in zip files. Vista can
|
---|
773 | /// read the zip files, but shows the filenames incorrectly. Unpacking from
|
---|
774 | /// Windows Vista Explorer will result in filenames that have rubbish
|
---|
775 | /// characters in place of the high-order UTF-8 bytes.
|
---|
776 | /// </para>
|
---|
777 | ///
|
---|
778 | /// <para>
|
---|
779 | /// Also, zip files that use UTF-8 encoding will not work well with Java
|
---|
780 | /// applications that use the java.util.zip classes, as of v5.0 of the Java
|
---|
781 | /// runtime. The Java runtime does not correctly implement the PKWare
|
---|
782 | /// specification in this regard.
|
---|
783 | /// </para>
|
---|
784 | ///
|
---|
785 | /// <para>
|
---|
786 | /// As a result, we have the unfortunate situation that "correct" behavior by
|
---|
787 | /// the DotNetZip library with regard to Unicode encoding of filenames during
|
---|
788 | /// zip creation will result in zip files that are readable by strictly
|
---|
789 | /// compliant and current tools (for example the most recent release of the
|
---|
790 | /// commercial WinZip tool); but these zip files will not be readable by
|
---|
791 | /// various other tools or libraries, including Windows Explorer.
|
---|
792 | /// </para>
|
---|
793 | ///
|
---|
794 | /// <para>
|
---|
795 | /// The DotNetZip library can read and write zip files with UTF8-encoded
|
---|
796 | /// entries, according to the PKware spec. If you use DotNetZip for both
|
---|
797 | /// creating and reading the zip file, and you use UTF-8, there will be no
|
---|
798 | /// loss of information in the filenames. For example, using a self-extractor
|
---|
799 | /// created by this library will allow you to unpack files correctly with no
|
---|
800 | /// loss of information in the filenames.
|
---|
801 | /// </para>
|
---|
802 | ///
|
---|
803 | /// <para>
|
---|
804 | /// If you do not set this flag, it will remain false. If this flag is false,
|
---|
805 | /// the <c>ZipOutputStream</c> will encode all filenames and comments using
|
---|
806 | /// the IBM437 codepage. This can cause "loss of information" on some
|
---|
807 | /// filenames, but the resulting zipfile will be more interoperable with other
|
---|
808 | /// utilities. As an example of the loss of information, diacritics can be
|
---|
809 | /// lost. The o-tilde character will be down-coded to plain o. The c with a
|
---|
810 | /// cedilla (Unicode 0xE7) used in Portugese will be downcoded to a c.
|
---|
811 | /// Likewise, the O-stroke character (Unicode 248), used in Danish and
|
---|
812 | /// Norwegian, will be down-coded to plain o. Chinese characters cannot be
|
---|
813 | /// represented in codepage IBM437; when using the default encoding, Chinese
|
---|
814 | /// characters in filenames will be represented as ?. These are all examples
|
---|
815 | /// of "information loss".
|
---|
816 | /// </para>
|
---|
817 | ///
|
---|
818 | /// <para>
|
---|
819 | /// The loss of information associated to the use of the IBM437 encoding is
|
---|
820 | /// inconvenient, and can also lead to runtime errors. For example, using
|
---|
821 | /// IBM437, any sequence of 4 Chinese characters will be encoded as ????. If
|
---|
822 | /// your application creates a <c>ZipOutputStream</c>, does not set the
|
---|
823 | /// encoding, then adds two files, each with names of four Chinese characters
|
---|
824 | /// each, this will result in a duplicate filename exception. In the case
|
---|
825 | /// where you add a single file with a name containing four Chinese
|
---|
826 | /// characters, the zipfile will save properly, but extracting that file
|
---|
827 | /// later, with any zip tool, will result in an error, because the question
|
---|
828 | /// mark is not legal for use within filenames on Windows. These are just a
|
---|
829 | /// few examples of the problems associated to loss of information.
|
---|
830 | /// </para>
|
---|
831 | ///
|
---|
832 | /// <para>
|
---|
833 | /// This flag is independent of the encoding of the content within the entries
|
---|
834 | /// in the zip file. Think of the zip file as a container - it supports an
|
---|
835 | /// encoding. Within the container are other "containers" - the file entries
|
---|
836 | /// themselves. The encoding within those entries is independent of the
|
---|
837 | /// encoding of the zip archive container for those entries.
|
---|
838 | /// </para>
|
---|
839 | ///
|
---|
840 | /// <para>
|
---|
841 | /// Rather than specify the encoding in a binary fashion using this flag, an
|
---|
842 | /// application can specify an arbitrary encoding via the <see
|
---|
843 | /// cref="ProvisionalAlternateEncoding"/> property. Setting the encoding
|
---|
844 | /// explicitly when creating zip archives will result in non-compliant zip
|
---|
845 | /// files that, curiously, are fairly interoperable. The challenge is, the
|
---|
846 | /// PKWare specification does not provide for a way to specify that an entry
|
---|
847 | /// in a zip archive uses a code page that is neither IBM437 nor UTF-8.
|
---|
848 | /// Therefore if you set the encoding explicitly when creating a zip archive,
|
---|
849 | /// you must take care upon reading the zip archive to use the same code page.
|
---|
850 | /// If you get it wrong, the behavior is undefined and may result in incorrect
|
---|
851 | /// filenames, exceptions, stomach upset, hair loss, and acne.
|
---|
852 | /// </para>
|
---|
853 | /// </remarks>
|
---|
854 | /// <seealso cref="ProvisionalAlternateEncoding"/>
|
---|
855 | [Obsolete("Beginning with v1.9.1.6 of DotNetZip, this property is obsolete. It will be removed in a future version of the library. Use AlternateEncoding and AlternateEncodingUsage instead.")]
|
---|
856 | public bool UseUnicodeAsNecessary
|
---|
857 | {
|
---|
858 | get
|
---|
859 | {
|
---|
860 | return (_alternateEncoding == System.Text.Encoding.UTF8) &&
|
---|
861 | (AlternateEncodingUsage == ZipOption.AsNecessary);
|
---|
862 | }
|
---|
863 | set
|
---|
864 | {
|
---|
865 | if (value)
|
---|
866 | {
|
---|
867 | _alternateEncoding = System.Text.Encoding.UTF8;
|
---|
868 | _alternateEncodingUsage = ZipOption.AsNecessary;
|
---|
869 |
|
---|
870 | }
|
---|
871 | else
|
---|
872 | {
|
---|
873 | _alternateEncoding = Ionic.Zip.ZipOutputStream.DefaultEncoding;
|
---|
874 | _alternateEncodingUsage = ZipOption.Never;
|
---|
875 | }
|
---|
876 | }
|
---|
877 | }
|
---|
878 |
|
---|
879 |
|
---|
880 | /// <summary>
|
---|
881 | /// The text encoding to use when emitting entries into the zip archive, for
|
---|
882 | /// those entries whose filenames or comments cannot be encoded with the
|
---|
883 | /// default (IBM437) encoding.
|
---|
884 | /// </summary>
|
---|
885 | ///
|
---|
886 | /// <remarks>
|
---|
887 | /// <para>
|
---|
888 | /// In <see href="http://www.pkware.com/documents/casestudies/APPNOTE.TXT">its
|
---|
889 | /// zip specification</see>, PKWare describes two options for encoding
|
---|
890 | /// filenames and comments: using IBM437 or UTF-8. But, some archiving tools
|
---|
891 | /// or libraries do not follow the specification, and instead encode
|
---|
892 | /// characters using the system default code page. For example, WinRAR when
|
---|
893 | /// run on a machine in Shanghai may encode filenames with the Big-5 Chinese
|
---|
894 | /// (950) code page. This behavior is contrary to the Zip specification, but
|
---|
895 | /// it occurs anyway.
|
---|
896 | /// </para>
|
---|
897 | ///
|
---|
898 | /// <para>
|
---|
899 | /// When using DotNetZip to write zip archives that will be read by one of
|
---|
900 | /// these other archivers, set this property to specify the code page to use
|
---|
901 | /// when encoding the <see cref="ZipEntry.FileName"/> and <see
|
---|
902 | /// cref="ZipEntry.Comment"/> for each <c>ZipEntry</c> in the zip file, for
|
---|
903 | /// values that cannot be encoded with the default codepage for zip files,
|
---|
904 | /// IBM437. This is why this property is "provisional". In all cases, IBM437
|
---|
905 | /// is used where possible, in other words, where no loss of data would
|
---|
906 | /// result. It is possible, therefore, to have a given entry with a
|
---|
907 | /// <c>Comment</c> encoded in IBM437 and a <c>FileName</c> encoded with the
|
---|
908 | /// specified "provisional" codepage.
|
---|
909 | /// </para>
|
---|
910 | ///
|
---|
911 | /// <para>
|
---|
912 | /// Be aware that a zip file created after you've explicitly set the
|
---|
913 | /// <c>ProvisionalAlternateEncoding</c> property to a value other than
|
---|
914 | /// IBM437 may not be compliant to the PKWare specification, and may not be
|
---|
915 | /// readable by compliant archivers. On the other hand, many (most?)
|
---|
916 | /// archivers are non-compliant and can read zip files created in arbitrary
|
---|
917 | /// code pages. The trick is to use or specify the proper codepage when
|
---|
918 | /// reading the zip.
|
---|
919 | /// </para>
|
---|
920 | ///
|
---|
921 | /// <para>
|
---|
922 | /// When creating a zip archive using this library, it is possible to change
|
---|
923 | /// the value of <c>ProvisionalAlternateEncoding</c> between each entry you
|
---|
924 | /// add, and between adding entries and the call to <c>Close()</c>. Don't do
|
---|
925 | /// this. It will likely result in a zipfile that is not readable. For best
|
---|
926 | /// interoperability, either leave <c>ProvisionalAlternateEncoding</c>
|
---|
927 | /// alone, or specify it only once, before adding any entries to the
|
---|
928 | /// <c>ZipOutputStream</c> instance. There is one exception to this
|
---|
929 | /// recommendation, described later.
|
---|
930 | /// </para>
|
---|
931 | ///
|
---|
932 | /// <para>
|
---|
933 | /// When using an arbitrary, non-UTF8 code page for encoding, there is no
|
---|
934 | /// standard way for the creator application - whether DotNetZip, WinZip,
|
---|
935 | /// WinRar, or something else - to formally specify in the zip file which
|
---|
936 | /// codepage has been used for the entries. As a result, readers of zip files
|
---|
937 | /// are not able to inspect the zip file and determine the codepage that was
|
---|
938 | /// used for the entries contained within it. It is left to the application
|
---|
939 | /// or user to determine the necessary codepage when reading zip files encoded
|
---|
940 | /// this way. If you use an incorrect codepage when reading a zipfile, you
|
---|
941 | /// will get entries with filenames that are incorrect, and the incorrect
|
---|
942 | /// filenames may even contain characters that are not legal for use within
|
---|
943 | /// filenames in Windows. Extracting entries with illegal characters in the
|
---|
944 | /// filenames will lead to exceptions. It's too bad, but this is just the way
|
---|
945 | /// things are with code pages in zip files. Caveat Emptor.
|
---|
946 | /// </para>
|
---|
947 | ///
|
---|
948 | /// <para>
|
---|
949 | /// One possible approach for specifying the code page for a given zip file is
|
---|
950 | /// to describe the code page in a human-readable form in the Zip comment. For
|
---|
951 | /// example, the comment may read "Entries in this archive are encoded in the
|
---|
952 | /// Big5 code page". For maximum interoperability, the zip comment in this
|
---|
953 | /// case should be encoded in the default, IBM437 code page. In this case,
|
---|
954 | /// the zip comment is encoded using a different page than the filenames. To
|
---|
955 | /// do this, Specify <c>ProvisionalAlternateEncoding</c> to your desired
|
---|
956 | /// region-specific code page, once before adding any entries, and then set
|
---|
957 | /// the <see cref="Comment"/> property and reset
|
---|
958 | /// <c>ProvisionalAlternateEncoding</c> to IBM437 before calling <c>Close()</c>.
|
---|
959 | /// </para>
|
---|
960 | /// </remarks>
|
---|
961 | [Obsolete("use AlternateEncoding and AlternateEncodingUsage instead.")]
|
---|
962 | public System.Text.Encoding ProvisionalAlternateEncoding
|
---|
963 | {
|
---|
964 | get
|
---|
965 | {
|
---|
966 | if (_alternateEncodingUsage == ZipOption.AsNecessary)
|
---|
967 | return _alternateEncoding;
|
---|
968 | return null;
|
---|
969 | }
|
---|
970 | set
|
---|
971 | {
|
---|
972 | _alternateEncoding = value;
|
---|
973 | _alternateEncodingUsage = ZipOption.AsNecessary;
|
---|
974 | }
|
---|
975 | }
|
---|
976 |
|
---|
977 | /// <summary>
|
---|
978 | /// A Text Encoding to use when encoding the filenames and comments for
|
---|
979 | /// all the ZipEntry items, during a ZipFile.Save() operation.
|
---|
980 | /// </summary>
|
---|
981 | /// <remarks>
|
---|
982 | /// <para>
|
---|
983 | /// Whether the encoding specified here is used during the save depends
|
---|
984 | /// on <see cref="AlternateEncodingUsage"/>.
|
---|
985 | /// </para>
|
---|
986 | /// </remarks>
|
---|
987 | public System.Text.Encoding AlternateEncoding
|
---|
988 | {
|
---|
989 | get
|
---|
990 | {
|
---|
991 | return _alternateEncoding;
|
---|
992 | }
|
---|
993 | set
|
---|
994 | {
|
---|
995 | _alternateEncoding = value;
|
---|
996 | }
|
---|
997 | }
|
---|
998 |
|
---|
999 | /// <summary>
|
---|
1000 | /// A flag that tells if and when this instance should apply
|
---|
1001 | /// AlternateEncoding to encode the filenames and comments associated to
|
---|
1002 | /// of ZipEntry objects contained within this instance.
|
---|
1003 | /// </summary>
|
---|
1004 | public ZipOption AlternateEncodingUsage
|
---|
1005 | {
|
---|
1006 | get
|
---|
1007 | {
|
---|
1008 | return _alternateEncodingUsage;
|
---|
1009 | }
|
---|
1010 | set
|
---|
1011 | {
|
---|
1012 | _alternateEncodingUsage = value;
|
---|
1013 | }
|
---|
1014 | }
|
---|
1015 |
|
---|
1016 | /// <summary>
|
---|
1017 | /// The default text encoding used in zip archives. It is numeric 437, also
|
---|
1018 | /// known as IBM437.
|
---|
1019 | /// </summary>
|
---|
1020 | /// <seealso cref="Ionic.Zip.ZipFile.ProvisionalAlternateEncoding"/>
|
---|
1021 | public static System.Text.Encoding DefaultEncoding
|
---|
1022 | {
|
---|
1023 | get
|
---|
1024 | {
|
---|
1025 | return System.Text.Encoding.GetEncoding("IBM437");
|
---|
1026 | }
|
---|
1027 | }
|
---|
1028 |
|
---|
1029 |
|
---|
1030 | #if !NETCF
|
---|
1031 | /// <summary>
|
---|
1032 | /// The size threshold for an entry, above which a parallel deflate is used.
|
---|
1033 | /// </summary>
|
---|
1034 | ///
|
---|
1035 | /// <remarks>
|
---|
1036 | ///
|
---|
1037 | /// <para>
|
---|
1038 | /// DotNetZip will use multiple threads to compress any ZipEntry, when
|
---|
1039 | /// the <c>CompressionMethod</c> is Deflate, and if the entry is
|
---|
1040 | /// larger than the given size. Zero means "always use parallel
|
---|
1041 | /// deflate", while -1 means "never use parallel deflate".
|
---|
1042 | /// </para>
|
---|
1043 | ///
|
---|
1044 | /// <para>
|
---|
1045 | /// If the entry size cannot be known before compression, as with any entry
|
---|
1046 | /// added via a ZipOutputStream, then Parallel deflate will never be
|
---|
1047 | /// performed, unless the value of this property is zero.
|
---|
1048 | /// </para>
|
---|
1049 | ///
|
---|
1050 | /// <para>
|
---|
1051 | /// A parallel deflate operations will speed up the compression of
|
---|
1052 | /// large files, on computers with multiple CPUs or multiple CPU
|
---|
1053 | /// cores. For files above 1mb, on a dual core or dual-cpu (2p)
|
---|
1054 | /// machine, the time required to compress the file can be 70% of the
|
---|
1055 | /// single-threaded deflate. For very large files on 4p machines the
|
---|
1056 | /// compression can be done in 30% of the normal time. The downside
|
---|
1057 | /// is that parallel deflate consumes extra memory during the deflate,
|
---|
1058 | /// and the deflation is slightly less effective.
|
---|
1059 | /// </para>
|
---|
1060 | ///
|
---|
1061 | /// <para>
|
---|
1062 | /// Parallel deflate tends to not be as effective as single-threaded deflate
|
---|
1063 | /// because the original data stream is split into multiple independent
|
---|
1064 | /// buffers, each of which is compressed in parallel. But because they are
|
---|
1065 | /// treated independently, there is no opportunity to share compression
|
---|
1066 | /// dictionaries, and additional framing bytes must be added to the output
|
---|
1067 | /// stream. For that reason, a deflated stream may be slightly larger when
|
---|
1068 | /// compressed using parallel deflate, as compared to a traditional
|
---|
1069 | /// single-threaded deflate. For files of about 512k, the increase over the
|
---|
1070 | /// normal deflate is as much as 5% of the total compressed size. For larger
|
---|
1071 | /// files, the difference can be as small as 0.1%.
|
---|
1072 | /// </para>
|
---|
1073 | ///
|
---|
1074 | /// <para>
|
---|
1075 | /// Multi-threaded compression does not give as much an advantage when using
|
---|
1076 | /// Encryption. This is primarily because encryption tends to slow down
|
---|
1077 | /// the entire pipeline. Also, multi-threaded compression gives less of an
|
---|
1078 | /// advantage when using lower compression levels, for example <see
|
---|
1079 | /// cref="Ionic.Zlib.CompressionLevel.BestSpeed"/>. You may have to perform
|
---|
1080 | /// some tests to determine the best approach for your situation.
|
---|
1081 | /// </para>
|
---|
1082 | ///
|
---|
1083 | /// <para>
|
---|
1084 | /// The default value for this property is -1, which means parallel
|
---|
1085 | /// compression will not be performed unless you set it to zero.
|
---|
1086 | /// </para>
|
---|
1087 | ///
|
---|
1088 | /// </remarks>
|
---|
1089 | public long ParallelDeflateThreshold
|
---|
1090 | {
|
---|
1091 | set
|
---|
1092 | {
|
---|
1093 | if ((value != 0) && (value != -1) && (value < 64 * 1024))
|
---|
1094 | throw new ArgumentOutOfRangeException("value must be greater than 64k, or 0, or -1");
|
---|
1095 | _ParallelDeflateThreshold = value;
|
---|
1096 | }
|
---|
1097 | get
|
---|
1098 | {
|
---|
1099 | return _ParallelDeflateThreshold;
|
---|
1100 | }
|
---|
1101 | }
|
---|
1102 |
|
---|
1103 |
|
---|
1104 | /// <summary>
|
---|
1105 | /// The maximum number of buffer pairs to use when performing
|
---|
1106 | /// parallel compression.
|
---|
1107 | /// </summary>
|
---|
1108 | ///
|
---|
1109 | /// <remarks>
|
---|
1110 | /// <para>
|
---|
1111 | /// This property sets an upper limit on the number of memory
|
---|
1112 | /// buffer pairs to create when performing parallel
|
---|
1113 | /// compression. The implementation of the parallel
|
---|
1114 | /// compression stream allocates multiple buffers to
|
---|
1115 | /// facilitate parallel compression. As each buffer fills up,
|
---|
1116 | /// the stream uses <see
|
---|
1117 | /// cref="System.Threading.ThreadPool.QueueUserWorkItem(WaitCallback)">
|
---|
1118 | /// ThreadPool.QueueUserWorkItem()</see> to compress those
|
---|
1119 | /// buffers in a background threadpool thread. After a buffer
|
---|
1120 | /// is compressed, it is re-ordered and written to the output
|
---|
1121 | /// stream.
|
---|
1122 | /// </para>
|
---|
1123 | ///
|
---|
1124 | /// <para>
|
---|
1125 | /// A higher number of buffer pairs enables a higher degree of
|
---|
1126 | /// parallelism, which tends to increase the speed of compression on
|
---|
1127 | /// multi-cpu computers. On the other hand, a higher number of buffer
|
---|
1128 | /// pairs also implies a larger memory consumption, more active worker
|
---|
1129 | /// threads, and a higher cpu utilization for any compression. This
|
---|
1130 | /// property enables the application to limit its memory consumption and
|
---|
1131 | /// CPU utilization behavior depending on requirements.
|
---|
1132 | /// </para>
|
---|
1133 | ///
|
---|
1134 | /// <para>
|
---|
1135 | /// For each compression "task" that occurs in parallel, there are 2
|
---|
1136 | /// buffers allocated: one for input and one for output. This property
|
---|
1137 | /// sets a limit for the number of pairs. The total amount of storage
|
---|
1138 | /// space allocated for buffering will then be (N*S*2), where N is the
|
---|
1139 | /// number of buffer pairs, S is the size of each buffer (<see
|
---|
1140 | /// cref="CodecBufferSize"/>). By default, DotNetZip allocates 4 buffer
|
---|
1141 | /// pairs per CPU core, so if your machine has 4 cores, and you retain
|
---|
1142 | /// the default buffer size of 128k, then the
|
---|
1143 | /// ParallelDeflateOutputStream will use 4 * 4 * 2 * 128kb of buffer
|
---|
1144 | /// memory in total, or 4mb, in blocks of 128kb. If you then set this
|
---|
1145 | /// property to 8, then the number will be 8 * 2 * 128kb of buffer
|
---|
1146 | /// memory, or 2mb.
|
---|
1147 | /// </para>
|
---|
1148 | ///
|
---|
1149 | /// <para>
|
---|
1150 | /// CPU utilization will also go up with additional buffers, because a
|
---|
1151 | /// larger number of buffer pairs allows a larger number of background
|
---|
1152 | /// threads to compress in parallel. If you find that parallel
|
---|
1153 | /// compression is consuming too much memory or CPU, you can adjust this
|
---|
1154 | /// value downward.
|
---|
1155 | /// </para>
|
---|
1156 | ///
|
---|
1157 | /// <para>
|
---|
1158 | /// The default value is 16. Different values may deliver better or
|
---|
1159 | /// worse results, depending on your priorities and the dynamic
|
---|
1160 | /// performance characteristics of your storage and compute resources.
|
---|
1161 | /// </para>
|
---|
1162 | ///
|
---|
1163 | /// <para>
|
---|
1164 | /// This property is not the number of buffer pairs to use; it is an
|
---|
1165 | /// upper limit. An illustration: Suppose you have an application that
|
---|
1166 | /// uses the default value of this property (which is 16), and it runs
|
---|
1167 | /// on a machine with 2 CPU cores. In that case, DotNetZip will allocate
|
---|
1168 | /// 4 buffer pairs per CPU core, for a total of 8 pairs. The upper
|
---|
1169 | /// limit specified by this property has no effect.
|
---|
1170 | /// </para>
|
---|
1171 | ///
|
---|
1172 | /// <para>
|
---|
1173 | /// The application can set this value at any time, but it is
|
---|
1174 | /// effective only if set before calling
|
---|
1175 | /// <c>ZipOutputStream.Write()</c> for the first time.
|
---|
1176 | /// </para>
|
---|
1177 | /// </remarks>
|
---|
1178 | ///
|
---|
1179 | /// <seealso cref="ParallelDeflateThreshold"/>
|
---|
1180 | ///
|
---|
1181 | public int ParallelDeflateMaxBufferPairs
|
---|
1182 | {
|
---|
1183 | get
|
---|
1184 | {
|
---|
1185 | return _maxBufferPairs;
|
---|
1186 | }
|
---|
1187 | set
|
---|
1188 | {
|
---|
1189 | if (value < 4)
|
---|
1190 | throw new ArgumentOutOfRangeException("ParallelDeflateMaxBufferPairs",
|
---|
1191 | "Value must be 4 or greater.");
|
---|
1192 | _maxBufferPairs = value;
|
---|
1193 | }
|
---|
1194 | }
|
---|
1195 | #endif
|
---|
1196 |
|
---|
1197 |
|
---|
1198 | private void InsureUniqueEntry(ZipEntry ze1)
|
---|
1199 | {
|
---|
1200 | if (_entriesWritten.ContainsKey(ze1.FileName))
|
---|
1201 | {
|
---|
1202 | _exceptionPending = true;
|
---|
1203 | throw new ArgumentException(String.Format("The entry '{0}' already exists in the zip archive.", ze1.FileName));
|
---|
1204 | }
|
---|
1205 | }
|
---|
1206 |
|
---|
1207 |
|
---|
1208 | internal Stream OutputStream
|
---|
1209 | {
|
---|
1210 | get
|
---|
1211 | {
|
---|
1212 | return _outputStream;
|
---|
1213 | }
|
---|
1214 | }
|
---|
1215 |
|
---|
1216 | internal String Name
|
---|
1217 | {
|
---|
1218 | get
|
---|
1219 | {
|
---|
1220 | return _name;
|
---|
1221 | }
|
---|
1222 | }
|
---|
1223 |
|
---|
1224 | /// <summary>
|
---|
1225 | /// Returns true if an entry by the given name has already been written
|
---|
1226 | /// to the ZipOutputStream.
|
---|
1227 | /// </summary>
|
---|
1228 | ///
|
---|
1229 | /// <param name="name">
|
---|
1230 | /// The name of the entry to scan for.
|
---|
1231 | /// </param>
|
---|
1232 | ///
|
---|
1233 | /// <returns>
|
---|
1234 | /// true if an entry by the given name has already been written.
|
---|
1235 | /// </returns>
|
---|
1236 | public bool ContainsEntry(string name)
|
---|
1237 | {
|
---|
1238 | return _entriesWritten.ContainsKey(SharedUtilities.NormalizePathForUseInZipFile(name));
|
---|
1239 | }
|
---|
1240 |
|
---|
1241 |
|
---|
1242 | /// <summary>
|
---|
1243 | /// Write the data from the buffer to the stream.
|
---|
1244 | /// </summary>
|
---|
1245 | ///
|
---|
1246 | /// <remarks>
|
---|
1247 | /// As the application writes data into this stream, the data may be
|
---|
1248 | /// compressed and encrypted before being written out to the underlying
|
---|
1249 | /// stream, depending on the settings of the <see cref="CompressionLevel"/>
|
---|
1250 | /// and the <see cref="Encryption"/> properties.
|
---|
1251 | /// </remarks>
|
---|
1252 | ///
|
---|
1253 | /// <param name="buffer">The buffer holding data to write to the stream.</param>
|
---|
1254 | /// <param name="offset">the offset within that data array to find the first byte to write.</param>
|
---|
1255 | /// <param name="count">the number of bytes to write.</param>
|
---|
1256 | public override void Write(byte[] buffer, int offset, int count)
|
---|
1257 | {
|
---|
1258 | if (_disposed)
|
---|
1259 | {
|
---|
1260 | _exceptionPending = true;
|
---|
1261 | throw new System.InvalidOperationException("The stream has been closed.");
|
---|
1262 | }
|
---|
1263 |
|
---|
1264 | if (buffer==null)
|
---|
1265 | {
|
---|
1266 | _exceptionPending = true;
|
---|
1267 | throw new System.ArgumentNullException("buffer");
|
---|
1268 | }
|
---|
1269 |
|
---|
1270 | if (_currentEntry == null)
|
---|
1271 | {
|
---|
1272 | _exceptionPending = true;
|
---|
1273 | throw new System.InvalidOperationException("You must call PutNextEntry() before calling Write().");
|
---|
1274 | }
|
---|
1275 |
|
---|
1276 | if (_currentEntry.IsDirectory)
|
---|
1277 | {
|
---|
1278 | _exceptionPending = true;
|
---|
1279 | throw new System.InvalidOperationException("You cannot Write() data for an entry that is a directory.");
|
---|
1280 | }
|
---|
1281 |
|
---|
1282 | if (_needToWriteEntryHeader)
|
---|
1283 | _InitiateCurrentEntry(false);
|
---|
1284 |
|
---|
1285 | if (count != 0)
|
---|
1286 | _entryOutputStream.Write(buffer, offset, count);
|
---|
1287 | }
|
---|
1288 |
|
---|
1289 |
|
---|
1290 |
|
---|
1291 | /// <summary>
|
---|
1292 | /// Specify the name of the next entry that will be written to the zip file.
|
---|
1293 | /// </summary>
|
---|
1294 | ///
|
---|
1295 | /// <remarks>
|
---|
1296 | /// <para>
|
---|
1297 | /// Call this method just before calling <see cref="Write(byte[], int, int)"/>, to
|
---|
1298 | /// specify the name of the entry that the next set of bytes written to
|
---|
1299 | /// the <c>ZipOutputStream</c> belongs to. All subsequent calls to <c>Write</c>,
|
---|
1300 | /// until the next call to <c>PutNextEntry</c>,
|
---|
1301 | /// will be inserted into the named entry in the zip file.
|
---|
1302 | /// </para>
|
---|
1303 | ///
|
---|
1304 | /// <para>
|
---|
1305 | /// If the <paramref name="entryName"/> used in <c>PutNextEntry()</c> ends in
|
---|
1306 | /// a slash, then the entry added is marked as a directory. Because directory
|
---|
1307 | /// entries do not contain data, a call to <c>Write()</c>, before an
|
---|
1308 | /// intervening additional call to <c>PutNextEntry()</c>, will throw an
|
---|
1309 | /// exception.
|
---|
1310 | /// </para>
|
---|
1311 | ///
|
---|
1312 | /// <para>
|
---|
1313 | /// If you don't call <c>Write()</c> between two calls to
|
---|
1314 | /// <c>PutNextEntry()</c>, the first entry is inserted into the zip file as a
|
---|
1315 | /// file of zero size. This may be what you want.
|
---|
1316 | /// </para>
|
---|
1317 | ///
|
---|
1318 | /// <para>
|
---|
1319 | /// Because <c>PutNextEntry()</c> closes out the prior entry, if any, this
|
---|
1320 | /// method may throw if there is a problem with the prior entry.
|
---|
1321 | /// </para>
|
---|
1322 | ///
|
---|
1323 | /// <para>
|
---|
1324 | /// This method returns the <c>ZipEntry</c>. You can modify public properties
|
---|
1325 | /// on the <c>ZipEntry</c>, such as <see cref="ZipEntry.Encryption"/>, <see
|
---|
1326 | /// cref="ZipEntry.Password"/>, and so on, until the first call to
|
---|
1327 | /// <c>ZipOutputStream.Write()</c>, or until the next call to
|
---|
1328 | /// <c>PutNextEntry()</c>. If you modify the <c>ZipEntry</c> <em>after</em>
|
---|
1329 | /// having called <c>Write()</c>, you may get a runtime exception, or you may
|
---|
1330 | /// silently get an invalid zip archive.
|
---|
1331 | /// </para>
|
---|
1332 | ///
|
---|
1333 | /// </remarks>
|
---|
1334 | ///
|
---|
1335 | /// <example>
|
---|
1336 | ///
|
---|
1337 | /// This example shows how to create a zip file, using the
|
---|
1338 | /// <c>ZipOutputStream</c> class.
|
---|
1339 | ///
|
---|
1340 | /// <code>
|
---|
1341 | /// private void Zipup()
|
---|
1342 | /// {
|
---|
1343 | /// using (FileStream fs raw = File.Open(_outputFileName, FileMode.Create, FileAccess.ReadWrite ))
|
---|
1344 | /// {
|
---|
1345 | /// using (var output= new ZipOutputStream(fs))
|
---|
1346 | /// {
|
---|
1347 | /// output.Password = "VerySecret!";
|
---|
1348 | /// output.Encryption = EncryptionAlgorithm.WinZipAes256;
|
---|
1349 | /// output.PutNextEntry("entry1.txt");
|
---|
1350 | /// byte[] buffer= System.Text.Encoding.ASCII.GetBytes("This is the content for entry #1.");
|
---|
1351 | /// output.Write(buffer,0,buffer.Length);
|
---|
1352 | /// output.PutNextEntry("entry2.txt"); // this will be zero length
|
---|
1353 | /// output.PutNextEntry("entry3.txt");
|
---|
1354 | /// buffer= System.Text.Encoding.ASCII.GetBytes("This is the content for entry #3.");
|
---|
1355 | /// output.Write(buffer,0,buffer.Length);
|
---|
1356 | /// }
|
---|
1357 | /// }
|
---|
1358 | /// }
|
---|
1359 | /// </code>
|
---|
1360 | /// </example>
|
---|
1361 | ///
|
---|
1362 | /// <param name="entryName">
|
---|
1363 | /// The name of the entry to be added, including any path to be used
|
---|
1364 | /// within the zip file.
|
---|
1365 | /// </param>
|
---|
1366 | ///
|
---|
1367 | /// <returns>
|
---|
1368 | /// The ZipEntry created.
|
---|
1369 | /// </returns>
|
---|
1370 | ///
|
---|
1371 | public ZipEntry PutNextEntry(String entryName)
|
---|
1372 | {
|
---|
1373 | if (String.IsNullOrEmpty(entryName))
|
---|
1374 | throw new ArgumentNullException("entryName");
|
---|
1375 |
|
---|
1376 | if (_disposed)
|
---|
1377 | {
|
---|
1378 | _exceptionPending = true;
|
---|
1379 | throw new System.InvalidOperationException("The stream has been closed.");
|
---|
1380 | }
|
---|
1381 |
|
---|
1382 | _FinishCurrentEntry();
|
---|
1383 | _currentEntry = ZipEntry.CreateForZipOutputStream(entryName);
|
---|
1384 | _currentEntry._container = new ZipContainer(this);
|
---|
1385 | _currentEntry._BitField |= 0x0008; // workitem 8932
|
---|
1386 | _currentEntry.SetEntryTimes(DateTime.Now, DateTime.Now, DateTime.Now);
|
---|
1387 | _currentEntry.CompressionLevel = this.CompressionLevel;
|
---|
1388 | _currentEntry.CompressionMethod = this.CompressionMethod;
|
---|
1389 | _currentEntry.Password = _password; // workitem 13909
|
---|
1390 | _currentEntry.Encryption = this.Encryption;
|
---|
1391 | // workitem 12634
|
---|
1392 | _currentEntry.AlternateEncoding = this.AlternateEncoding;
|
---|
1393 | _currentEntry.AlternateEncodingUsage = this.AlternateEncodingUsage;
|
---|
1394 |
|
---|
1395 | if (entryName.EndsWith("/")) _currentEntry.MarkAsDirectory();
|
---|
1396 |
|
---|
1397 | _currentEntry.EmitTimesInWindowsFormatWhenSaving = ((_timestamp & ZipEntryTimestamp.Windows) != 0);
|
---|
1398 | _currentEntry.EmitTimesInUnixFormatWhenSaving = ((_timestamp & ZipEntryTimestamp.Unix) != 0);
|
---|
1399 | InsureUniqueEntry(_currentEntry);
|
---|
1400 | _needToWriteEntryHeader = true;
|
---|
1401 |
|
---|
1402 | return _currentEntry;
|
---|
1403 | }
|
---|
1404 |
|
---|
1405 |
|
---|
1406 |
|
---|
1407 | private void _InitiateCurrentEntry(bool finishing)
|
---|
1408 | {
|
---|
1409 | // If finishing==true, this means we're initiating the entry at the time of
|
---|
1410 | // Close() or PutNextEntry(). If this happens, it means no data was written
|
---|
1411 | // for the entry - Write() was never called. (The usual case us to call
|
---|
1412 | // _InitiateCurrentEntry(bool) from within Write().) If finishing==true,
|
---|
1413 | // the entry could be either a zero-byte file or a directory.
|
---|
1414 |
|
---|
1415 | _entriesWritten.Add(_currentEntry.FileName,_currentEntry);
|
---|
1416 | _entryCount++; // could use _entriesWritten.Count, but I don't want to incur
|
---|
1417 | // the cost.
|
---|
1418 |
|
---|
1419 | if (_entryCount > 65534 && _zip64 == Zip64Option.Never)
|
---|
1420 | {
|
---|
1421 | _exceptionPending = true;
|
---|
1422 | throw new System.InvalidOperationException("Too many entries. Consider setting ZipOutputStream.EnableZip64.");
|
---|
1423 | }
|
---|
1424 |
|
---|
1425 | // Write out the header.
|
---|
1426 | //
|
---|
1427 | // If finishing, and encryption is in use, then we don't want to emit the
|
---|
1428 | // normal encryption header. Signal that with a cycle=99 to turn off
|
---|
1429 | // encryption for zero-byte entries or directories.
|
---|
1430 | //
|
---|
1431 | // If finishing, then we know the stream length is zero. Else, unknown
|
---|
1432 | // stream length. Passing stream length == 0 allows an optimization so as
|
---|
1433 | // not to setup an encryption or deflation stream, when stream length is
|
---|
1434 | // zero.
|
---|
1435 |
|
---|
1436 | _currentEntry.WriteHeader(_outputStream, finishing ? 99 : 0);
|
---|
1437 | _currentEntry.StoreRelativeOffset();
|
---|
1438 |
|
---|
1439 | if (!_currentEntry.IsDirectory)
|
---|
1440 | {
|
---|
1441 | _currentEntry.WriteSecurityMetadata(_outputStream);
|
---|
1442 | _currentEntry.PrepOutputStream(_outputStream,
|
---|
1443 | finishing ? 0 : -1,
|
---|
1444 | out _outputCounter,
|
---|
1445 | out _encryptor,
|
---|
1446 | out _deflater,
|
---|
1447 | out _entryOutputStream);
|
---|
1448 | }
|
---|
1449 | _needToWriteEntryHeader = false;
|
---|
1450 | }
|
---|
1451 |
|
---|
1452 |
|
---|
1453 |
|
---|
1454 | private void _FinishCurrentEntry()
|
---|
1455 | {
|
---|
1456 | if (_currentEntry != null)
|
---|
1457 | {
|
---|
1458 | if (_needToWriteEntryHeader)
|
---|
1459 | _InitiateCurrentEntry(true); // an empty entry - no writes
|
---|
1460 |
|
---|
1461 | _currentEntry.FinishOutputStream(_outputStream, _outputCounter, _encryptor, _deflater, _entryOutputStream);
|
---|
1462 | _currentEntry.PostProcessOutput(_outputStream);
|
---|
1463 | // workitem 12964
|
---|
1464 | if (_currentEntry.OutputUsedZip64!=null)
|
---|
1465 | _anyEntriesUsedZip64 |= _currentEntry.OutputUsedZip64.Value;
|
---|
1466 |
|
---|
1467 | // reset all the streams
|
---|
1468 | _outputCounter = null; _encryptor = _deflater = null; _entryOutputStream = null;
|
---|
1469 | }
|
---|
1470 | }
|
---|
1471 |
|
---|
1472 |
|
---|
1473 |
|
---|
1474 | /// <summary>
|
---|
1475 | /// Dispose the stream
|
---|
1476 | /// </summary>
|
---|
1477 | ///
|
---|
1478 | /// <remarks>
|
---|
1479 | /// <para>
|
---|
1480 | /// This method writes the Zip Central directory, then closes the stream. The
|
---|
1481 | /// application must call Dispose() (or Close) in order to produce a valid zip file.
|
---|
1482 | /// </para>
|
---|
1483 | ///
|
---|
1484 | /// <para>
|
---|
1485 | /// Typically the application will call <c>Dispose()</c> implicitly, via a <c>using</c>
|
---|
1486 | /// statement in C#, or a <c>Using</c> statement in VB.
|
---|
1487 | /// </para>
|
---|
1488 | ///
|
---|
1489 | /// </remarks>
|
---|
1490 | ///
|
---|
1491 | /// <param name="disposing">set this to true, always.</param>
|
---|
1492 | protected override void Dispose(bool disposing)
|
---|
1493 | {
|
---|
1494 | if (_disposed) return;
|
---|
1495 |
|
---|
1496 | if (disposing) // not called from finalizer
|
---|
1497 | {
|
---|
1498 | // handle pending exceptions
|
---|
1499 | if (!_exceptionPending)
|
---|
1500 | {
|
---|
1501 | _FinishCurrentEntry();
|
---|
1502 | _directoryNeededZip64 = ZipOutput.WriteCentralDirectoryStructure(_outputStream,
|
---|
1503 | _entriesWritten.Values,
|
---|
1504 | 1, // _numberOfSegmentsForMostRecentSave,
|
---|
1505 | _zip64,
|
---|
1506 | Comment,
|
---|
1507 | new ZipContainer(this));
|
---|
1508 | Stream wrappedStream = null;
|
---|
1509 | CountingStream cs = _outputStream as CountingStream;
|
---|
1510 | if (cs != null)
|
---|
1511 | {
|
---|
1512 | wrappedStream = cs.WrappedStream;
|
---|
1513 | #if NETCF
|
---|
1514 | cs.Close();
|
---|
1515 | #else
|
---|
1516 | cs.Dispose();
|
---|
1517 | #endif
|
---|
1518 | }
|
---|
1519 | else
|
---|
1520 | {
|
---|
1521 | wrappedStream = _outputStream;
|
---|
1522 | }
|
---|
1523 |
|
---|
1524 | if (!_leaveUnderlyingStreamOpen)
|
---|
1525 | {
|
---|
1526 | #if NETCF
|
---|
1527 | wrappedStream.Close();
|
---|
1528 | #else
|
---|
1529 | wrappedStream.Dispose();
|
---|
1530 | #endif
|
---|
1531 | }
|
---|
1532 | _outputStream = null;
|
---|
1533 | }
|
---|
1534 | }
|
---|
1535 | _disposed = true;
|
---|
1536 | }
|
---|
1537 |
|
---|
1538 |
|
---|
1539 |
|
---|
1540 | /// <summary>
|
---|
1541 | /// Always returns false.
|
---|
1542 | /// </summary>
|
---|
1543 | public override bool CanRead { get { return false; } }
|
---|
1544 |
|
---|
1545 | /// <summary>
|
---|
1546 | /// Always returns false.
|
---|
1547 | /// </summary>
|
---|
1548 | public override bool CanSeek { get { return false; } }
|
---|
1549 |
|
---|
1550 | /// <summary>
|
---|
1551 | /// Always returns true.
|
---|
1552 | /// </summary>
|
---|
1553 | public override bool CanWrite { get { return true; } }
|
---|
1554 |
|
---|
1555 | /// <summary>
|
---|
1556 | /// Always returns a NotSupportedException.
|
---|
1557 | /// </summary>
|
---|
1558 | public override long Length { get { throw new NotSupportedException(); } }
|
---|
1559 |
|
---|
1560 | /// <summary>
|
---|
1561 | /// Setting this property always returns a NotSupportedException. Getting it
|
---|
1562 | /// returns the value of the Position on the underlying stream.
|
---|
1563 | /// </summary>
|
---|
1564 | public override long Position
|
---|
1565 | {
|
---|
1566 | get { return _outputStream.Position; }
|
---|
1567 | set { throw new NotSupportedException(); }
|
---|
1568 | }
|
---|
1569 |
|
---|
1570 | /// <summary>
|
---|
1571 | /// This is a no-op.
|
---|
1572 | /// </summary>
|
---|
1573 | public override void Flush() { }
|
---|
1574 |
|
---|
1575 | /// <summary>
|
---|
1576 | /// This method always throws a NotSupportedException.
|
---|
1577 | /// </summary>
|
---|
1578 | /// <param name="buffer">ignored</param>
|
---|
1579 | /// <param name="offset">ignored</param>
|
---|
1580 | /// <param name="count">ignored</param>
|
---|
1581 | /// <returns>nothing</returns>
|
---|
1582 | public override int Read(byte[] buffer, int offset, int count)
|
---|
1583 | {
|
---|
1584 | throw new NotSupportedException("Read");
|
---|
1585 | }
|
---|
1586 |
|
---|
1587 | /// <summary>
|
---|
1588 | /// This method always throws a NotSupportedException.
|
---|
1589 | /// </summary>
|
---|
1590 | /// <param name="offset">ignored</param>
|
---|
1591 | /// <param name="origin">ignored</param>
|
---|
1592 | /// <returns>nothing</returns>
|
---|
1593 | public override long Seek(long offset, SeekOrigin origin)
|
---|
1594 | {
|
---|
1595 | throw new NotSupportedException("Seek");
|
---|
1596 | }
|
---|
1597 |
|
---|
1598 | /// <summary>
|
---|
1599 | /// This method always throws a NotSupportedException.
|
---|
1600 | /// </summary>
|
---|
1601 | /// <param name="value">ignored</param>
|
---|
1602 | public override void SetLength(long value)
|
---|
1603 | {
|
---|
1604 | throw new NotSupportedException();
|
---|
1605 | }
|
---|
1606 |
|
---|
1607 |
|
---|
1608 | private EncryptionAlgorithm _encryption;
|
---|
1609 | private ZipEntryTimestamp _timestamp;
|
---|
1610 | internal String _password;
|
---|
1611 | private String _comment;
|
---|
1612 | private Stream _outputStream;
|
---|
1613 | private ZipEntry _currentEntry;
|
---|
1614 | internal Zip64Option _zip64;
|
---|
1615 | private Dictionary<String, ZipEntry> _entriesWritten;
|
---|
1616 | private int _entryCount;
|
---|
1617 | private ZipOption _alternateEncodingUsage = ZipOption.Never;
|
---|
1618 | private System.Text.Encoding _alternateEncoding
|
---|
1619 | = System.Text.Encoding.GetEncoding("IBM437"); // default = IBM437
|
---|
1620 |
|
---|
1621 | private bool _leaveUnderlyingStreamOpen;
|
---|
1622 | private bool _disposed;
|
---|
1623 | private bool _exceptionPending; // **see note below
|
---|
1624 | private bool _anyEntriesUsedZip64, _directoryNeededZip64;
|
---|
1625 | private CountingStream _outputCounter;
|
---|
1626 | private Stream _encryptor;
|
---|
1627 | private Stream _deflater;
|
---|
1628 | private Ionic.Crc.CrcCalculatorStream _entryOutputStream;
|
---|
1629 | private bool _needToWriteEntryHeader;
|
---|
1630 | private string _name;
|
---|
1631 | private bool _DontIgnoreCase;
|
---|
1632 | #if !NETCF
|
---|
1633 | internal ParallelDeflateOutputStream ParallelDeflater;
|
---|
1634 | private long _ParallelDeflateThreshold;
|
---|
1635 | private int _maxBufferPairs = 16;
|
---|
1636 | #endif
|
---|
1637 |
|
---|
1638 | // **Note regarding exceptions:
|
---|
1639 |
|
---|
1640 | // When ZipOutputStream is employed within a using clause, which
|
---|
1641 | // is the typical scenario, and an exception is thrown within
|
---|
1642 | // the scope of the using, Close()/Dispose() is invoked
|
---|
1643 | // implicitly before processing the initial exception. In that
|
---|
1644 | // case, _exceptionPending is true, and we don't want to try to
|
---|
1645 | // write anything in the Close/Dispose logic. Doing so can
|
---|
1646 | // cause additional exceptions that mask the original one. So,
|
---|
1647 | // the _exceptionPending flag is used to track that, and to
|
---|
1648 | // allow the original exception to be propagated to the
|
---|
1649 | // application without extra "noise."
|
---|
1650 |
|
---|
1651 | }
|
---|
1652 |
|
---|
1653 |
|
---|
1654 |
|
---|
1655 | internal class ZipContainer
|
---|
1656 | {
|
---|
1657 | private ZipFile _zf;
|
---|
1658 | private ZipOutputStream _zos;
|
---|
1659 | private ZipInputStream _zis;
|
---|
1660 |
|
---|
1661 | public ZipContainer(Object o)
|
---|
1662 | {
|
---|
1663 | _zf = (o as ZipFile);
|
---|
1664 | _zos = (o as ZipOutputStream);
|
---|
1665 | _zis = (o as ZipInputStream);
|
---|
1666 | }
|
---|
1667 |
|
---|
1668 | public ZipFile ZipFile
|
---|
1669 | {
|
---|
1670 | get { return _zf; }
|
---|
1671 | }
|
---|
1672 |
|
---|
1673 | public ZipOutputStream ZipOutputStream
|
---|
1674 | {
|
---|
1675 | get { return _zos; }
|
---|
1676 | }
|
---|
1677 |
|
---|
1678 | public string Name
|
---|
1679 | {
|
---|
1680 | get
|
---|
1681 | {
|
---|
1682 | if (_zf != null) return _zf.Name;
|
---|
1683 | if (_zis != null) throw new NotSupportedException();
|
---|
1684 | return _zos.Name;
|
---|
1685 | }
|
---|
1686 | }
|
---|
1687 |
|
---|
1688 | public string Password
|
---|
1689 | {
|
---|
1690 | get
|
---|
1691 | {
|
---|
1692 | if (_zf != null) return _zf._Password;
|
---|
1693 | if (_zis != null) return _zis._Password;
|
---|
1694 | return _zos._password;
|
---|
1695 | }
|
---|
1696 | }
|
---|
1697 |
|
---|
1698 | public Zip64Option Zip64
|
---|
1699 | {
|
---|
1700 | get
|
---|
1701 | {
|
---|
1702 | if (_zf != null) return _zf._zip64;
|
---|
1703 | if (_zis != null) throw new NotSupportedException();
|
---|
1704 | return _zos._zip64;
|
---|
1705 | }
|
---|
1706 | }
|
---|
1707 |
|
---|
1708 | public int BufferSize
|
---|
1709 | {
|
---|
1710 | get
|
---|
1711 | {
|
---|
1712 | if (_zf != null) return _zf.BufferSize;
|
---|
1713 | if (_zis != null) throw new NotSupportedException();
|
---|
1714 | return 0;
|
---|
1715 | }
|
---|
1716 | }
|
---|
1717 |
|
---|
1718 | #if !NETCF
|
---|
1719 | public Ionic.Zlib.ParallelDeflateOutputStream ParallelDeflater
|
---|
1720 | {
|
---|
1721 | get
|
---|
1722 | {
|
---|
1723 | if (_zf != null) return _zf.ParallelDeflater;
|
---|
1724 | if (_zis != null) return null;
|
---|
1725 | return _zos.ParallelDeflater;
|
---|
1726 | }
|
---|
1727 | set
|
---|
1728 | {
|
---|
1729 | if (_zf != null) _zf.ParallelDeflater = value;
|
---|
1730 | else if (_zos != null) _zos.ParallelDeflater = value;
|
---|
1731 | }
|
---|
1732 | }
|
---|
1733 |
|
---|
1734 | public long ParallelDeflateThreshold
|
---|
1735 | {
|
---|
1736 | get
|
---|
1737 | {
|
---|
1738 | if (_zf != null) return _zf.ParallelDeflateThreshold;
|
---|
1739 | return _zos.ParallelDeflateThreshold;
|
---|
1740 | }
|
---|
1741 | }
|
---|
1742 | public int ParallelDeflateMaxBufferPairs
|
---|
1743 | {
|
---|
1744 | get
|
---|
1745 | {
|
---|
1746 | if (_zf != null) return _zf.ParallelDeflateMaxBufferPairs;
|
---|
1747 | return _zos.ParallelDeflateMaxBufferPairs;
|
---|
1748 | }
|
---|
1749 | }
|
---|
1750 | #endif
|
---|
1751 |
|
---|
1752 | public int CodecBufferSize
|
---|
1753 | {
|
---|
1754 | get
|
---|
1755 | {
|
---|
1756 | if (_zf != null) return _zf.CodecBufferSize;
|
---|
1757 | if (_zis != null) return _zis.CodecBufferSize;
|
---|
1758 | return _zos.CodecBufferSize;
|
---|
1759 | }
|
---|
1760 | }
|
---|
1761 |
|
---|
1762 | public Ionic.Zlib.CompressionStrategy Strategy
|
---|
1763 | {
|
---|
1764 | get
|
---|
1765 | {
|
---|
1766 | if (_zf != null) return _zf.Strategy;
|
---|
1767 | return _zos.Strategy;
|
---|
1768 | }
|
---|
1769 | }
|
---|
1770 |
|
---|
1771 | public Zip64Option UseZip64WhenSaving
|
---|
1772 | {
|
---|
1773 | get
|
---|
1774 | {
|
---|
1775 | if (_zf != null) return _zf.UseZip64WhenSaving;
|
---|
1776 | return _zos.EnableZip64;
|
---|
1777 | }
|
---|
1778 | }
|
---|
1779 |
|
---|
1780 | public System.Text.Encoding AlternateEncoding
|
---|
1781 | {
|
---|
1782 | get
|
---|
1783 | {
|
---|
1784 | if (_zf != null) return _zf.AlternateEncoding;
|
---|
1785 | if (_zos!=null) return _zos.AlternateEncoding;
|
---|
1786 | return null;
|
---|
1787 | }
|
---|
1788 | }
|
---|
1789 | public System.Text.Encoding DefaultEncoding
|
---|
1790 | {
|
---|
1791 | get
|
---|
1792 | {
|
---|
1793 | if (_zf != null) return ZipFile.DefaultEncoding;
|
---|
1794 | if (_zos!=null) return ZipOutputStream.DefaultEncoding;
|
---|
1795 | return null;
|
---|
1796 | }
|
---|
1797 | }
|
---|
1798 | public ZipOption AlternateEncodingUsage
|
---|
1799 | {
|
---|
1800 | get
|
---|
1801 | {
|
---|
1802 | if (_zf != null) return _zf.AlternateEncodingUsage;
|
---|
1803 | if (_zos!=null) return _zos.AlternateEncodingUsage;
|
---|
1804 | return ZipOption.Never; // n/a
|
---|
1805 | }
|
---|
1806 | }
|
---|
1807 |
|
---|
1808 | public Stream ReadStream
|
---|
1809 | {
|
---|
1810 | get
|
---|
1811 | {
|
---|
1812 | if (_zf != null) return _zf.ReadStream;
|
---|
1813 | return _zis.ReadStream;
|
---|
1814 | }
|
---|
1815 | }
|
---|
1816 | }
|
---|
1817 |
|
---|
1818 | } |
---|