3 // ------------------------------------------------------------------
5 // Copyright (c) 2009 Dino Chiesa.
6 // All rights reserved.
8 // This code module is part of DotNetZip, a zipfile class library.
10 // ------------------------------------------------------------------
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
16 // ------------------------------------------------------------------
18 // last saved (in emacs):
19 // Time-stamp: <2011-July-28 06:34:30>
21 // ------------------------------------------------------------------
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:
33 // - CompressionMethod
34 // - EnableZip64 (UseZip64WhenSaving)
35 // - IgnoreCase (!CaseSensitiveRetrieval)
37 // It adds these novel methods:
42 // ------------------------------------------------------------------
46 using System.Threading;
47 using System.Collections.Generic;
54 /// Provides a stream metaphor for generating zip files.
59 /// This class writes zip files, as defined in the <see
60 /// href="http://www.pkware.com/documents/casestudies/APPNOTE.TXT">specification
61 /// for zip files described by PKWare</see>. The compression for this
62 /// implementation is provided by a managed-code version of Zlib, included with
63 /// DotNetZip in the classes in the Ionic.Zlib namespace.
67 /// This class provides an alternative programming model to the one enabled by the
68 /// <see cref="ZipFile"/> class. Use this when creating zip files, as an
69 /// alternative to the <see cref="ZipFile"/> class, when you would like to use a
70 /// <c>Stream</c> type to write the zip file.
74 /// Both the <c>ZipOutputStream</c> class and the <c>ZipFile</c> class can be used
75 /// to create zip files. Both of them support many of the common zip features,
76 /// including Unicode, different compression levels, and ZIP64. They provide
77 /// very similar performance when creating zip files.
81 /// The <c>ZipFile</c> class is generally easier to use than
82 /// <c>ZipOutputStream</c> and should be considered a higher-level interface. For
83 /// example, when creating a zip file via calls to the <c>PutNextEntry()</c> and
84 /// <c>Write()</c> methods on the <c>ZipOutputStream</c> class, the caller is
85 /// responsible for opening the file, reading the bytes from the file, writing
86 /// those bytes into the <c>ZipOutputStream</c>, setting the attributes on the
87 /// <c>ZipEntry</c>, and setting the created, last modified, and last accessed
88 /// timestamps on the zip entry. All of these things are done automatically by a
89 /// call to <see cref="ZipFile.AddFile(string,string)">ZipFile.AddFile()</see>.
90 /// For this reason, the <c>ZipOutputStream</c> is generally recommended for use
91 /// only when your application emits arbitrary data, not necessarily data from a
92 /// filesystem file, directly into a zip file, and does so using a <c>Stream</c>
97 /// Aside from the differences in programming model, there are other
98 /// differences in capability between the two classes.
101 /// <list type="bullet">
103 /// <c>ZipFile</c> can be used to read and extract zip files, in addition to
104 /// creating zip files. <c>ZipOutputStream</c> cannot read zip files. If you want
105 /// to use a stream to read zip files, check out the <see cref="ZipInputStream"/> class.
109 /// <c>ZipOutputStream</c> does not support the creation of segmented or spanned
114 /// <c>ZipOutputStream</c> cannot produce a self-extracting archive.
119 /// Be aware that the <c>ZipOutputStream</c> class implements the <see
120 /// cref="System.IDisposable"/> interface. In order for
121 /// <c>ZipOutputStream</c> to produce a valid zip file, you use use it within
122 /// a using clause (<c>Using</c> in VB), or call the <c>Dispose()</c> method
123 /// explicitly. See the examples for how to employ a using clause.
127 /// Also, a note regarding compression performance: On the desktop .NET
128 /// Framework, DotNetZip can use a multi-threaded compression implementation
129 /// that provides significant speed increases on large files, over 300k or so,
130 /// at the cost of increased memory use at runtime. (The output of the
131 /// compression is almost exactly the same size). But, the multi-threaded
132 /// approach incurs a performance hit on smaller files. There's no way for the
133 /// ZipOutputStream to know whether parallel compression will be beneficial,
134 /// because the ZipOutputStream does not know how much data you will write
135 /// through the stream. You may wish to set the <see
136 /// cref="ParallelDeflateThreshold"/> property to zero, if you are compressing
137 /// large files through <c>ZipOutputStream</c>. This will cause parallel
138 /// compression to be used, always.
141 internal class ZipOutputStream : Stream
144 /// Create a ZipOutputStream, wrapping an existing stream.
149 /// The <see cref="ZipFile"/> class is generally easier to use when creating
150 /// zip files. The ZipOutputStream offers a different metaphor for creating a
151 /// zip file, based on the <see cref="System.IO.Stream"/> class.
156 /// <param name="stream">
157 /// The stream to wrap. It must be writable. This stream will be closed at
158 /// the time the ZipOutputStream is closed.
163 /// This example shows how to create a zip file, using the
164 /// ZipOutputStream class.
167 /// private void Zipup()
169 /// if (filesToZip.Count == 0)
171 /// System.Console.WriteLine("Nothing to do.");
175 /// using (var raw = File.Open(_outputFileName, FileMode.Create, FileAccess.ReadWrite ))
177 /// using (var output= new ZipOutputStream(raw))
179 /// output.Password = "VerySecret!";
180 /// output.Encryption = EncryptionAlgorithm.WinZipAes256;
182 /// foreach (string inputFileName in filesToZip)
184 /// System.Console.WriteLine("file: {0}", inputFileName);
186 /// output.PutNextEntry(inputFileName);
187 /// using (var input = File.Open(inputFileName, FileMode.Open, FileAccess.Read, FileShare.Read | FileShare.Write ))
189 /// byte[] buffer= new byte[2048];
191 /// while ((n= input.Read(buffer,0,buffer.Length)) > 0)
193 /// output.Write(buffer,0,n);
203 /// Private Sub Zipup()
204 /// Dim outputFileName As String = "XmlData.zip"
205 /// Dim filesToZip As String() = Directory.GetFiles(".", "*.xml")
206 /// If (filesToZip.Length = 0) Then
207 /// Console.WriteLine("Nothing to do.")
209 /// Using raw As FileStream = File.Open(outputFileName, FileMode.Create, FileAccess.ReadWrite)
210 /// Using output As ZipOutputStream = New ZipOutputStream(raw)
211 /// output.Password = "VerySecret!"
212 /// output.Encryption = EncryptionAlgorithm.WinZipAes256
213 /// Dim inputFileName As String
214 /// For Each inputFileName In filesToZip
215 /// Console.WriteLine("file: {0}", inputFileName)
216 /// output.PutNextEntry(inputFileName)
217 /// Using input As FileStream = File.Open(inputFileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)
219 /// Dim buffer As Byte() = New Byte(2048) {}
220 /// Do While (n = input.Read(buffer, 0, buffer.Length) > 0)
221 /// output.Write(buffer, 0, n)
231 public ZipOutputStream(Stream stream) : this(stream, false) { }
235 /// Create a ZipOutputStream that writes to a filesystem file.
239 /// The <see cref="ZipFile"/> class is generally easier to use when creating
240 /// zip files. The ZipOutputStream offers a different metaphor for creating a
241 /// zip file, based on the <see cref="System.IO.Stream"/> class.
244 /// <param name="fileName">
245 /// The name of the zip file to create.
250 /// This example shows how to create a zip file, using the
251 /// ZipOutputStream class.
254 /// private void Zipup()
256 /// if (filesToZip.Count == 0)
258 /// System.Console.WriteLine("Nothing to do.");
262 /// using (var output= new ZipOutputStream(outputFileName))
264 /// output.Password = "VerySecret!";
265 /// output.Encryption = EncryptionAlgorithm.WinZipAes256;
267 /// foreach (string inputFileName in filesToZip)
269 /// System.Console.WriteLine("file: {0}", inputFileName);
271 /// output.PutNextEntry(inputFileName);
272 /// using (var input = File.Open(inputFileName, FileMode.Open, FileAccess.Read,
273 /// FileShare.Read | FileShare.Write ))
275 /// byte[] buffer= new byte[2048];
277 /// while ((n= input.Read(buffer,0,buffer.Length)) > 0)
279 /// output.Write(buffer,0,n);
288 /// Private Sub Zipup()
289 /// Dim outputFileName As String = "XmlData.zip"
290 /// Dim filesToZip As String() = Directory.GetFiles(".", "*.xml")
291 /// If (filesToZip.Length = 0) Then
292 /// Console.WriteLine("Nothing to do.")
294 /// Using output As ZipOutputStream = New ZipOutputStream(outputFileName)
295 /// output.Password = "VerySecret!"
296 /// output.Encryption = EncryptionAlgorithm.WinZipAes256
297 /// Dim inputFileName As String
298 /// For Each inputFileName In filesToZip
299 /// Console.WriteLine("file: {0}", inputFileName)
300 /// output.PutNextEntry(inputFileName)
301 /// Using input As FileStream = File.Open(inputFileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)
303 /// Dim buffer As Byte() = New Byte(2048) {}
304 /// Do While (n = input.Read(buffer, 0, buffer.Length) > 0)
305 /// output.Write(buffer, 0, n)
314 public ZipOutputStream(String fileName)
316 Stream stream = File.Open(fileName, FileMode.Create, FileAccess.ReadWrite, FileShare.None);
317 _Init(stream, false, fileName);
322 /// Create a ZipOutputStream.
326 /// See the documentation for the <see
327 /// cref="ZipOutputStream(Stream)">ZipOutputStream(Stream)</see>
328 /// constructor for an example.
331 /// <param name="stream">
332 /// The stream to wrap. It must be writable.
335 /// <param name="leaveOpen">
336 /// true if the application would like the stream
337 /// to remain open after the <c>ZipOutputStream</c> has been closed.
339 public ZipOutputStream(Stream stream, bool leaveOpen)
341 _Init(stream, leaveOpen, null);
344 private void _Init(Stream stream, bool leaveOpen, string name)
347 _outputStream = stream.CanRead ? stream : new CountingStream(stream);
348 CompressionLevel = Ionic.Zlib.CompressionLevel.Default;
349 CompressionMethod = Ionic.Zip.CompressionMethod.Deflate;
350 _encryption = EncryptionAlgorithm.None;
351 _entriesWritten = new Dictionary<String, ZipEntry>(StringComparer.Ordinal);
352 _zip64 = Zip64Option.Never;
353 _leaveUnderlyingStreamOpen = leaveOpen;
354 Strategy = Ionic.Zlib.CompressionStrategy.Default;
355 _name = name ?? "(stream)";
357 ParallelDeflateThreshold = -1L;
362 /// <summary>Provides a string representation of the instance.</summary>
365 /// This can be useful for debugging purposes.
368 /// <returns>a string representation of the instance.</returns>
369 public override String ToString()
371 return String.Format ("ZipOutputStream::{0}(leaveOpen({1})))", _name, _leaveUnderlyingStreamOpen);
376 /// Sets the password to be used on the <c>ZipOutputStream</c> instance.
382 /// When writing a zip archive, this password is applied to the entries, not
383 /// to the zip archive itself. It applies to any <c>ZipEntry</c> subsequently
384 /// written to the <c>ZipOutputStream</c>.
388 /// Using a password does not encrypt or protect the "directory" of the
389 /// archive - the list of entries contained in the archive. If you set the
390 /// <c>Password</c> property, the password actually applies to individual
391 /// entries that are added to the archive, subsequent to the setting of this
392 /// property. The list of filenames in the archive that is eventually created
393 /// will appear in clear text, but the contents of the individual files are
394 /// encrypted. This is how Zip encryption works.
398 /// If you set this property, and then add a set of entries to the archive via
399 /// calls to <c>PutNextEntry</c>, then each entry is encrypted with that
400 /// password. You may also want to change the password between adding
401 /// different entries. If you set the password, add an entry, then set the
402 /// password to <c>null</c> (<c>Nothing</c> in VB), and add another entry, the
403 /// first entry is encrypted and the second is not.
407 /// When setting the <c>Password</c>, you may also want to explicitly set the <see
408 /// cref="Encryption"/> property, to specify how to encrypt the entries added
409 /// to the ZipFile. If you set the <c>Password</c> to a non-null value and do not
410 /// set <see cref="Encryption"/>, then PKZip 2.0 ("Weak") encryption is used.
411 /// This encryption is relatively weak but is very interoperable. If
412 /// you set the password to a <c>null</c> value (<c>Nothing</c> in VB),
413 /// <c>Encryption</c> is reset to None.
417 /// Special case: if you wrap a ZipOutputStream around a non-seekable stream,
418 /// and use encryption, and emit an entry of zero bytes, the <c>Close()</c> or
419 /// <c>PutNextEntry()</c> following the entry will throw an exception.
423 public String Password
429 _exceptionPending = true;
430 throw new System.InvalidOperationException("The stream has been closed.");
434 if (_password == null)
436 _encryption = EncryptionAlgorithm.None;
438 else if (_encryption == EncryptionAlgorithm.None)
440 _encryption = EncryptionAlgorithm.PkzipWeak;
447 /// The Encryption to use for entries added to the <c>ZipOutputStream</c>.
452 /// The specified Encryption is applied to the entries subsequently
453 /// written to the <c>ZipOutputStream</c> instance.
457 /// If you set this to something other than
458 /// EncryptionAlgorithm.None, you will also need to set the
459 /// <see cref="Password"/> to a non-null, non-empty value in
460 /// order to actually get encryption on the entry.
465 /// <seealso cref="Password">ZipOutputStream.Password</seealso>
466 /// <seealso cref="Ionic.Zip.ZipEntry.Encryption">ZipEntry.Encryption</seealso>
467 public EncryptionAlgorithm Encryption
477 _exceptionPending = true;
478 throw new System.InvalidOperationException("The stream has been closed.");
480 if (value == EncryptionAlgorithm.Unsupported)
482 _exceptionPending = true;
483 throw new InvalidOperationException("You may not set Encryption to that value.");
491 /// Size of the work buffer to use for the ZLIB codec during compression.
495 /// Setting this may affect performance. For larger files, setting this to a
496 /// larger size may improve performance, but I'm not sure. Sorry, I don't
497 /// currently have good recommendations on how to set it. You can test it if
500 public int CodecBufferSize
508 /// The compression strategy to use for all entries.
512 /// Set the Strategy used by the ZLIB-compatible compressor, when compressing
513 /// data for the entries in the zip archive. Different compression strategies
514 /// work better on different sorts of data. The strategy parameter can affect
515 /// the compression ratio and the speed of compression but not the correctness
516 /// of the compresssion. For more information see <see
517 /// cref="Ionic.Zlib.CompressionStrategy "/>.
519 public Ionic.Zlib.CompressionStrategy Strategy
527 /// The type of timestamp attached to the ZipEntry.
531 /// Set this in order to specify the kind of timestamp that should be emitted
532 /// into the zip file for each entry.
534 public ZipEntryTimestamp Timestamp
544 _exceptionPending = true;
545 throw new System.InvalidOperationException("The stream has been closed.");
553 /// Sets the compression level to be used for entries subsequently added to
559 /// Varying the compression level used on entries can affect the
560 /// size-vs-speed tradeoff when compression and decompressing data streams
565 /// As with some other properties on the <c>ZipOutputStream</c> class, like <see
566 /// cref="Password"/>, and <see cref="Encryption"/>,
567 /// setting this property on a <c>ZipOutputStream</c>
568 /// instance will cause the specified <c>CompressionLevel</c> to be used on all
569 /// <see cref="ZipEntry"/> items that are subsequently added to the
570 /// <c>ZipOutputStream</c> instance.
574 /// If you do not set this property, the default compression level is used,
575 /// which normally gives a good balance of compression efficiency and
576 /// compression speed. In some tests, using <c>BestCompression</c> can
577 /// double the time it takes to compress, while delivering just a small
578 /// increase in compression efficiency. This behavior will vary with the
579 /// type of data you compress. If you are in doubt, just leave this setting
580 /// alone, and accept the default.
583 public Ionic.Zlib.CompressionLevel CompressionLevel
590 /// The compression method used on each entry added to the ZipOutputStream.
592 public Ionic.Zip.CompressionMethod CompressionMethod
600 /// A comment attached to the zip archive.
606 /// The application sets this property to specify a comment to be embedded
607 /// into the generated zip archive.
611 /// According to <see
612 /// href="http://www.pkware.com/documents/casestudies/APPNOTE.TXT">PKWARE's
613 /// zip specification</see>, the comment is not encrypted, even if there is a
614 /// password set on the zip file.
618 /// The specification does not describe how to indicate the encoding used
619 /// on a comment string. Many "compliant" zip tools and libraries use
620 /// IBM437 as the code page for comments; DotNetZip, too, follows that
621 /// practice. On the other hand, there are situations where you want a
622 /// Comment to be encoded with something else, for example using code page
623 /// 950 "Big-5 Chinese". To fill that need, DotNetZip will encode the
624 /// comment following the same procedure it follows for encoding
625 /// filenames: (a) if <see cref="AlternateEncodingUsage"/> is
626 /// <c>Never</c>, it uses the default encoding (IBM437). (b) if <see
627 /// cref="AlternateEncodingUsage"/> is <c>Always</c>, it always uses the
628 /// alternate encoding (<see cref="AlternateEncoding"/>). (c) if <see
629 /// cref="AlternateEncodingUsage"/> is <c>AsNecessary</c>, it uses the
630 /// alternate encoding only if the default encoding is not sufficient for
631 /// encoding the comment - in other words if decoding the result does not
632 /// produce the original string. This decision is taken at the time of
633 /// the call to <c>ZipFile.Save()</c>.
637 public string Comment
639 get { return _comment; }
644 _exceptionPending = true;
645 throw new System.InvalidOperationException("The stream has been closed.");
654 /// Specify whether to use ZIP64 extensions when saving a zip archive.
659 /// The default value for the property is <see
660 /// cref="Zip64Option.Never"/>. <see cref="Zip64Option.AsNecessary"/> is
661 /// safest, in the sense that you will not get an Exception if a
662 /// pre-ZIP64 limit is exceeded.
666 /// You must set this property before calling <c>Write()</c>.
670 public Zip64Option EnableZip64
680 _exceptionPending = true;
681 throw new System.InvalidOperationException("The stream has been closed.");
689 /// Indicates whether ZIP64 extensions were used when saving the zip archive.
693 /// The value is defined only after the <c>ZipOutputStream</c> has been closed.
695 public bool OutputUsedZip64
699 return _anyEntriesUsedZip64 || _directoryNeededZip64;
705 /// Whether the ZipOutputStream should use case-insensitive comparisons when
706 /// checking for uniqueness of zip entries.
711 /// Though the zip specification doesn't prohibit zipfiles with duplicate
712 /// entries, Sane zip files have no duplicates, and the DotNetZip library
713 /// cannot create zip files with duplicate entries. If an application attempts
714 /// to call <see cref="PutNextEntry(String)"/> with a name that duplicates one
715 /// already used within the archive, the library will throw an Exception.
718 /// This property allows the application to specify whether the
719 /// ZipOutputStream instance considers ordinal case when checking for
720 /// uniqueness of zip entries.
723 public bool IgnoreCase
727 return !_DontIgnoreCase;
732 _DontIgnoreCase = !value;
739 /// Indicates whether to encode entry filenames and entry comments using
745 /// <see href="http://www.pkware.com/documents/casestudies/APPNOTE.TXT">The
746 /// PKWare zip specification</see> provides for encoding file names and file
747 /// comments in either the IBM437 code page, or in UTF-8. This flag selects
748 /// the encoding according to that specification. By default, this flag is
749 /// false, and filenames and comments are encoded into the zip file in the
750 /// IBM437 codepage. Setting this flag to true will specify that filenames
751 /// and comments that cannot be encoded with IBM437 will be encoded with
756 /// Zip files created with strict adherence to the PKWare specification with
757 /// respect to UTF-8 encoding can contain entries with filenames containing
758 /// any combination of Unicode characters, including the full range of
759 /// characters from Chinese, Latin, Hebrew, Greek, Cyrillic, and many other
760 /// alphabets. However, because at this time, the UTF-8 portion of the PKWare
761 /// specification is not broadly supported by other zip libraries and
762 /// utilities, such zip files may not be readable by your favorite zip tool or
763 /// archiver. In other words, interoperability will decrease if you set this
768 /// In particular, Zip files created with strict adherence to the PKWare
769 /// specification with respect to UTF-8 encoding will not work well with
770 /// Explorer in Windows XP or Windows Vista, because Windows compressed
771 /// folders, as far as I know, do not support UTF-8 in zip files. Vista can
772 /// read the zip files, but shows the filenames incorrectly. Unpacking from
773 /// Windows Vista Explorer will result in filenames that have rubbish
774 /// characters in place of the high-order UTF-8 bytes.
778 /// Also, zip files that use UTF-8 encoding will not work well with Java
779 /// applications that use the java.util.zip classes, as of v5.0 of the Java
780 /// runtime. The Java runtime does not correctly implement the PKWare
781 /// specification in this regard.
785 /// As a result, we have the unfortunate situation that "correct" behavior by
786 /// the DotNetZip library with regard to Unicode encoding of filenames during
787 /// zip creation will result in zip files that are readable by strictly
788 /// compliant and current tools (for example the most recent release of the
789 /// commercial WinZip tool); but these zip files will not be readable by
790 /// various other tools or libraries, including Windows Explorer.
794 /// The DotNetZip library can read and write zip files with UTF8-encoded
795 /// entries, according to the PKware spec. If you use DotNetZip for both
796 /// creating and reading the zip file, and you use UTF-8, there will be no
797 /// loss of information in the filenames. For example, using a self-extractor
798 /// created by this library will allow you to unpack files correctly with no
799 /// loss of information in the filenames.
803 /// If you do not set this flag, it will remain false. If this flag is false,
804 /// the <c>ZipOutputStream</c> will encode all filenames and comments using
805 /// the IBM437 codepage. This can cause "loss of information" on some
806 /// filenames, but the resulting zipfile will be more interoperable with other
807 /// utilities. As an example of the loss of information, diacritics can be
808 /// lost. The o-tilde character will be down-coded to plain o. The c with a
809 /// cedilla (Unicode 0xE7) used in Portugese will be downcoded to a c.
810 /// Likewise, the O-stroke character (Unicode 248), used in Danish and
811 /// Norwegian, will be down-coded to plain o. Chinese characters cannot be
812 /// represented in codepage IBM437; when using the default encoding, Chinese
813 /// characters in filenames will be represented as ?. These are all examples
814 /// of "information loss".
818 /// The loss of information associated to the use of the IBM437 encoding is
819 /// inconvenient, and can also lead to runtime errors. For example, using
820 /// IBM437, any sequence of 4 Chinese characters will be encoded as ????. If
821 /// your application creates a <c>ZipOutputStream</c>, does not set the
822 /// encoding, then adds two files, each with names of four Chinese characters
823 /// each, this will result in a duplicate filename exception. In the case
824 /// where you add a single file with a name containing four Chinese
825 /// characters, the zipfile will save properly, but extracting that file
826 /// later, with any zip tool, will result in an error, because the question
827 /// mark is not legal for use within filenames on Windows. These are just a
828 /// few examples of the problems associated to loss of information.
832 /// This flag is independent of the encoding of the content within the entries
833 /// in the zip file. Think of the zip file as a container - it supports an
834 /// encoding. Within the container are other "containers" - the file entries
835 /// themselves. The encoding within those entries is independent of the
836 /// encoding of the zip archive container for those entries.
840 /// Rather than specify the encoding in a binary fashion using this flag, an
841 /// application can specify an arbitrary encoding via the <see
842 /// cref="ProvisionalAlternateEncoding"/> property. Setting the encoding
843 /// explicitly when creating zip archives will result in non-compliant zip
844 /// files that, curiously, are fairly interoperable. The challenge is, the
845 /// PKWare specification does not provide for a way to specify that an entry
846 /// in a zip archive uses a code page that is neither IBM437 nor UTF-8.
847 /// Therefore if you set the encoding explicitly when creating a zip archive,
848 /// you must take care upon reading the zip archive to use the same code page.
849 /// If you get it wrong, the behavior is undefined and may result in incorrect
850 /// filenames, exceptions, stomach upset, hair loss, and acne.
853 /// <seealso cref="ProvisionalAlternateEncoding"/>
854 [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.")]
855 public bool UseUnicodeAsNecessary
859 return (_alternateEncoding == System.Text.Encoding.UTF8) &&
860 (AlternateEncodingUsage == ZipOption.AsNecessary);
866 _alternateEncoding = System.Text.Encoding.UTF8;
867 _alternateEncodingUsage = ZipOption.AsNecessary;
872 _alternateEncoding = Ionic.Zip.ZipOutputStream.DefaultEncoding;
873 _alternateEncodingUsage = ZipOption.Never;
880 /// The text encoding to use when emitting entries into the zip archive, for
881 /// those entries whose filenames or comments cannot be encoded with the
882 /// default (IBM437) encoding.
887 /// In <see href="http://www.pkware.com/documents/casestudies/APPNOTE.TXT">its
888 /// zip specification</see>, PKWare describes two options for encoding
889 /// filenames and comments: using IBM437 or UTF-8. But, some archiving tools
890 /// or libraries do not follow the specification, and instead encode
891 /// characters using the system default code page. For example, WinRAR when
892 /// run on a machine in Shanghai may encode filenames with the Big-5 Chinese
893 /// (950) code page. This behavior is contrary to the Zip specification, but
894 /// it occurs anyway.
898 /// When using DotNetZip to write zip archives that will be read by one of
899 /// these other archivers, set this property to specify the code page to use
900 /// when encoding the <see cref="ZipEntry.FileName"/> and <see
901 /// cref="ZipEntry.Comment"/> for each <c>ZipEntry</c> in the zip file, for
902 /// values that cannot be encoded with the default codepage for zip files,
903 /// IBM437. This is why this property is "provisional". In all cases, IBM437
904 /// is used where possible, in other words, where no loss of data would
905 /// result. It is possible, therefore, to have a given entry with a
906 /// <c>Comment</c> encoded in IBM437 and a <c>FileName</c> encoded with the
907 /// specified "provisional" codepage.
911 /// Be aware that a zip file created after you've explicitly set the
912 /// <c>ProvisionalAlternateEncoding</c> property to a value other than
913 /// IBM437 may not be compliant to the PKWare specification, and may not be
914 /// readable by compliant archivers. On the other hand, many (most?)
915 /// archivers are non-compliant and can read zip files created in arbitrary
916 /// code pages. The trick is to use or specify the proper codepage when
921 /// When creating a zip archive using this library, it is possible to change
922 /// the value of <c>ProvisionalAlternateEncoding</c> between each entry you
923 /// add, and between adding entries and the call to <c>Close()</c>. Don't do
924 /// this. It will likely result in a zipfile that is not readable. For best
925 /// interoperability, either leave <c>ProvisionalAlternateEncoding</c>
926 /// alone, or specify it only once, before adding any entries to the
927 /// <c>ZipOutputStream</c> instance. There is one exception to this
928 /// recommendation, described later.
932 /// When using an arbitrary, non-UTF8 code page for encoding, there is no
933 /// standard way for the creator application - whether DotNetZip, WinZip,
934 /// WinRar, or something else - to formally specify in the zip file which
935 /// codepage has been used for the entries. As a result, readers of zip files
936 /// are not able to inspect the zip file and determine the codepage that was
937 /// used for the entries contained within it. It is left to the application
938 /// or user to determine the necessary codepage when reading zip files encoded
939 /// this way. If you use an incorrect codepage when reading a zipfile, you
940 /// will get entries with filenames that are incorrect, and the incorrect
941 /// filenames may even contain characters that are not legal for use within
942 /// filenames in Windows. Extracting entries with illegal characters in the
943 /// filenames will lead to exceptions. It's too bad, but this is just the way
944 /// things are with code pages in zip files. Caveat Emptor.
948 /// One possible approach for specifying the code page for a given zip file is
949 /// to describe the code page in a human-readable form in the Zip comment. For
950 /// example, the comment may read "Entries in this archive are encoded in the
951 /// Big5 code page". For maximum interoperability, the zip comment in this
952 /// case should be encoded in the default, IBM437 code page. In this case,
953 /// the zip comment is encoded using a different page than the filenames. To
954 /// do this, Specify <c>ProvisionalAlternateEncoding</c> to your desired
955 /// region-specific code page, once before adding any entries, and then set
956 /// the <see cref="Comment"/> property and reset
957 /// <c>ProvisionalAlternateEncoding</c> to IBM437 before calling <c>Close()</c>.
960 [Obsolete("use AlternateEncoding and AlternateEncodingUsage instead.")]
961 public System.Text.Encoding ProvisionalAlternateEncoding
965 if (_alternateEncodingUsage == ZipOption.AsNecessary)
966 return _alternateEncoding;
971 _alternateEncoding = value;
972 _alternateEncodingUsage = ZipOption.AsNecessary;
977 /// A Text Encoding to use when encoding the filenames and comments for
978 /// all the ZipEntry items, during a ZipFile.Save() operation.
982 /// Whether the encoding specified here is used during the save depends
983 /// on <see cref="AlternateEncodingUsage"/>.
986 public System.Text.Encoding AlternateEncoding
990 return _alternateEncoding;
994 _alternateEncoding = value;
999 /// A flag that tells if and when this instance should apply
1000 /// AlternateEncoding to encode the filenames and comments associated to
1001 /// of ZipEntry objects contained within this instance.
1003 public ZipOption AlternateEncodingUsage
1007 return _alternateEncodingUsage;
1011 _alternateEncodingUsage = value;
1016 /// The default text encoding used in zip archives. It is numeric 437, also
1017 /// known as IBM437.
1019 /// <seealso cref="Ionic.Zip.ZipFile.ProvisionalAlternateEncoding"/>
1020 internal static System.Text.Encoding DefaultEncoding
1024 return System.Text.Encoding.GetEncoding("IBM437");
1031 /// The size threshold for an entry, above which a parallel deflate is used.
1037 /// DotNetZip will use multiple threads to compress any ZipEntry, when
1038 /// the <c>CompressionMethod</c> is Deflate, and if the entry is
1039 /// larger than the given size. Zero means "always use parallel
1040 /// deflate", while -1 means "never use parallel deflate".
1044 /// If the entry size cannot be known before compression, as with any entry
1045 /// added via a ZipOutputStream, then Parallel deflate will never be
1046 /// performed, unless the value of this property is zero.
1050 /// A parallel deflate operations will speed up the compression of
1051 /// large files, on computers with multiple CPUs or multiple CPU
1052 /// cores. For files above 1mb, on a dual core or dual-cpu (2p)
1053 /// machine, the time required to compress the file can be 70% of the
1054 /// single-threaded deflate. For very large files on 4p machines the
1055 /// compression can be done in 30% of the normal time. The downside
1056 /// is that parallel deflate consumes extra memory during the deflate,
1057 /// and the deflation is slightly less effective.
1061 /// Parallel deflate tends to not be as effective as single-threaded deflate
1062 /// because the original data stream is split into multiple independent
1063 /// buffers, each of which is compressed in parallel. But because they are
1064 /// treated independently, there is no opportunity to share compression
1065 /// dictionaries, and additional framing bytes must be added to the output
1066 /// stream. For that reason, a deflated stream may be slightly larger when
1067 /// compressed using parallel deflate, as compared to a traditional
1068 /// single-threaded deflate. For files of about 512k, the increase over the
1069 /// normal deflate is as much as 5% of the total compressed size. For larger
1070 /// files, the difference can be as small as 0.1%.
1074 /// Multi-threaded compression does not give as much an advantage when using
1075 /// Encryption. This is primarily because encryption tends to slow down
1076 /// the entire pipeline. Also, multi-threaded compression gives less of an
1077 /// advantage when using lower compression levels, for example <see
1078 /// cref="Ionic.Zlib.CompressionLevel.BestSpeed"/>. You may have to perform
1079 /// some tests to determine the best approach for your situation.
1083 /// The default value for this property is -1, which means parallel
1084 /// compression will not be performed unless you set it to zero.
1088 public long ParallelDeflateThreshold
1092 if ((value != 0) && (value != -1) && (value < 64 * 1024))
1093 throw new ArgumentOutOfRangeException("value must be greater than 64k, or 0, or -1");
1094 _ParallelDeflateThreshold = value;
1098 return _ParallelDeflateThreshold;
1104 /// The maximum number of buffer pairs to use when performing
1105 /// parallel compression.
1110 /// This property sets an upper limit on the number of memory
1111 /// buffer pairs to create when performing parallel
1112 /// compression. The implementation of the parallel
1113 /// compression stream allocates multiple buffers to
1114 /// facilitate parallel compression. As each buffer fills up,
1115 /// the stream uses <see
1116 /// cref="System.Threading.ThreadPool.QueueUserWorkItem(WaitCallback)">
1117 /// ThreadPool.QueueUserWorkItem()</see> to compress those
1118 /// buffers in a background threadpool thread. After a buffer
1119 /// is compressed, it is re-ordered and written to the output
1124 /// A higher number of buffer pairs enables a higher degree of
1125 /// parallelism, which tends to increase the speed of compression on
1126 /// multi-cpu computers. On the other hand, a higher number of buffer
1127 /// pairs also implies a larger memory consumption, more active worker
1128 /// threads, and a higher cpu utilization for any compression. This
1129 /// property enables the application to limit its memory consumption and
1130 /// CPU utilization behavior depending on requirements.
1134 /// For each compression "task" that occurs in parallel, there are 2
1135 /// buffers allocated: one for input and one for output. This property
1136 /// sets a limit for the number of pairs. The total amount of storage
1137 /// space allocated for buffering will then be (N*S*2), where N is the
1138 /// number of buffer pairs, S is the size of each buffer (<see
1139 /// cref="CodecBufferSize"/>). By default, DotNetZip allocates 4 buffer
1140 /// pairs per CPU core, so if your machine has 4 cores, and you retain
1141 /// the default buffer size of 128k, then the
1142 /// ParallelDeflateOutputStream will use 4 * 4 * 2 * 128kb of buffer
1143 /// memory in total, or 4mb, in blocks of 128kb. If you then set this
1144 /// property to 8, then the number will be 8 * 2 * 128kb of buffer
1149 /// CPU utilization will also go up with additional buffers, because a
1150 /// larger number of buffer pairs allows a larger number of background
1151 /// threads to compress in parallel. If you find that parallel
1152 /// compression is consuming too much memory or CPU, you can adjust this
1157 /// The default value is 16. Different values may deliver better or
1158 /// worse results, depending on your priorities and the dynamic
1159 /// performance characteristics of your storage and compute resources.
1163 /// This property is not the number of buffer pairs to use; it is an
1164 /// upper limit. An illustration: Suppose you have an application that
1165 /// uses the default value of this property (which is 16), and it runs
1166 /// on a machine with 2 CPU cores. In that case, DotNetZip will allocate
1167 /// 4 buffer pairs per CPU core, for a total of 8 pairs. The upper
1168 /// limit specified by this property has no effect.
1172 /// The application can set this value at any time, but it is
1173 /// effective only if set before calling
1174 /// <c>ZipOutputStream.Write()</c> for the first time.
1178 /// <seealso cref="ParallelDeflateThreshold"/>
1180 public int ParallelDeflateMaxBufferPairs
1184 return _maxBufferPairs;
1189 throw new ArgumentOutOfRangeException("ParallelDeflateMaxBufferPairs",
1190 "Value must be 4 or greater.");
1191 _maxBufferPairs = value;
1197 private void InsureUniqueEntry(ZipEntry ze1)
1199 if (_entriesWritten.ContainsKey(ze1.FileName))
1201 _exceptionPending = true;
1202 throw new ArgumentException(String.Format("The entry '{0}' already exists in the zip archive.", ze1.FileName));
1207 internal Stream OutputStream
1211 return _outputStream;
1215 internal String Name
1224 /// Returns true if an entry by the given name has already been written
1225 /// to the ZipOutputStream.
1228 /// <param name="name">
1229 /// The name of the entry to scan for.
1233 /// true if an entry by the given name has already been written.
1235 public bool ContainsEntry(string name)
1237 return _entriesWritten.ContainsKey(SharedUtilities.NormalizePathForUseInZipFile(name));
1242 /// Write the data from the buffer to the stream.
1246 /// As the application writes data into this stream, the data may be
1247 /// compressed and encrypted before being written out to the underlying
1248 /// stream, depending on the settings of the <see cref="CompressionLevel"/>
1249 /// and the <see cref="Encryption"/> properties.
1252 /// <param name="buffer">The buffer holding data to write to the stream.</param>
1253 /// <param name="offset">the offset within that data array to find the first byte to write.</param>
1254 /// <param name="count">the number of bytes to write.</param>
1255 public override void Write(byte[] buffer, int offset, int count)
1259 _exceptionPending = true;
1260 throw new System.InvalidOperationException("The stream has been closed.");
1265 _exceptionPending = true;
1266 throw new System.ArgumentNullException("buffer");
1269 if (_currentEntry == null)
1271 _exceptionPending = true;
1272 throw new System.InvalidOperationException("You must call PutNextEntry() before calling Write().");
1275 if (_currentEntry.IsDirectory)
1277 _exceptionPending = true;
1278 throw new System.InvalidOperationException("You cannot Write() data for an entry that is a directory.");
1281 if (_needToWriteEntryHeader)
1282 _InitiateCurrentEntry(false);
1285 _entryOutputStream.Write(buffer, offset, count);
1291 /// Specify the name of the next entry that will be written to the zip file.
1296 /// Call this method just before calling <see cref="Write(byte[], int, int)"/>, to
1297 /// specify the name of the entry that the next set of bytes written to
1298 /// the <c>ZipOutputStream</c> belongs to. All subsequent calls to <c>Write</c>,
1299 /// until the next call to <c>PutNextEntry</c>,
1300 /// will be inserted into the named entry in the zip file.
1304 /// If the <paramref name="entryName"/> used in <c>PutNextEntry()</c> ends in
1305 /// a slash, then the entry added is marked as a directory. Because directory
1306 /// entries do not contain data, a call to <c>Write()</c>, before an
1307 /// intervening additional call to <c>PutNextEntry()</c>, will throw an
1312 /// If you don't call <c>Write()</c> between two calls to
1313 /// <c>PutNextEntry()</c>, the first entry is inserted into the zip file as a
1314 /// file of zero size. This may be what you want.
1318 /// Because <c>PutNextEntry()</c> closes out the prior entry, if any, this
1319 /// method may throw if there is a problem with the prior entry.
1323 /// This method returns the <c>ZipEntry</c>. You can modify public properties
1324 /// on the <c>ZipEntry</c>, such as <see cref="ZipEntry.Encryption"/>, <see
1325 /// cref="ZipEntry.Password"/>, and so on, until the first call to
1326 /// <c>ZipOutputStream.Write()</c>, or until the next call to
1327 /// <c>PutNextEntry()</c>. If you modify the <c>ZipEntry</c> <em>after</em>
1328 /// having called <c>Write()</c>, you may get a runtime exception, or you may
1329 /// silently get an invalid zip archive.
1336 /// This example shows how to create a zip file, using the
1337 /// <c>ZipOutputStream</c> class.
1340 /// private void Zipup()
1342 /// using (FileStream fs raw = File.Open(_outputFileName, FileMode.Create, FileAccess.ReadWrite ))
1344 /// using (var output= new ZipOutputStream(fs))
1346 /// output.Password = "VerySecret!";
1347 /// output.Encryption = EncryptionAlgorithm.WinZipAes256;
1348 /// output.PutNextEntry("entry1.txt");
1349 /// byte[] buffer= System.Text.Encoding.ASCII.GetBytes("This is the content for entry #1.");
1350 /// output.Write(buffer,0,buffer.Length);
1351 /// output.PutNextEntry("entry2.txt"); // this will be zero length
1352 /// output.PutNextEntry("entry3.txt");
1353 /// buffer= System.Text.Encoding.ASCII.GetBytes("This is the content for entry #3.");
1354 /// output.Write(buffer,0,buffer.Length);
1361 /// <param name="entryName">
1362 /// The name of the entry to be added, including any path to be used
1363 /// within the zip file.
1367 /// The ZipEntry created.
1370 public ZipEntry PutNextEntry(String entryName)
1372 if (String.IsNullOrEmpty(entryName))
1373 throw new ArgumentNullException("entryName");
1377 _exceptionPending = true;
1378 throw new System.InvalidOperationException("The stream has been closed.");
1381 _FinishCurrentEntry();
1382 _currentEntry = ZipEntry.CreateForZipOutputStream(entryName);
1383 _currentEntry._container = new ZipContainer(this);
1384 _currentEntry._BitField |= 0x0008; // workitem 8932
1385 _currentEntry.SetEntryTimes(DateTime.Now, DateTime.Now, DateTime.Now);
1386 _currentEntry.CompressionLevel = this.CompressionLevel;
1387 _currentEntry.CompressionMethod = this.CompressionMethod;
1388 _currentEntry.Password = _password; // workitem 13909
1389 _currentEntry.Encryption = this.Encryption;
1391 _currentEntry.AlternateEncoding = this.AlternateEncoding;
1392 _currentEntry.AlternateEncodingUsage = this.AlternateEncodingUsage;
1394 if (entryName.EndsWith("/")) _currentEntry.MarkAsDirectory();
1396 _currentEntry.EmitTimesInWindowsFormatWhenSaving = ((_timestamp & ZipEntryTimestamp.Windows) != 0);
1397 _currentEntry.EmitTimesInUnixFormatWhenSaving = ((_timestamp & ZipEntryTimestamp.Unix) != 0);
1398 InsureUniqueEntry(_currentEntry);
1399 _needToWriteEntryHeader = true;
1401 return _currentEntry;
1406 private void _InitiateCurrentEntry(bool finishing)
1408 // If finishing==true, this means we're initiating the entry at the time of
1409 // Close() or PutNextEntry(). If this happens, it means no data was written
1410 // for the entry - Write() was never called. (The usual case us to call
1411 // _InitiateCurrentEntry(bool) from within Write().) If finishing==true,
1412 // the entry could be either a zero-byte file or a directory.
1414 _entriesWritten.Add(_currentEntry.FileName,_currentEntry);
1415 _entryCount++; // could use _entriesWritten.Count, but I don't want to incur
1418 if (_entryCount > 65534 && _zip64 == Zip64Option.Never)
1420 _exceptionPending = true;
1421 throw new System.InvalidOperationException("Too many entries. Consider setting ZipOutputStream.EnableZip64.");
1424 // Write out the header.
1426 // If finishing, and encryption is in use, then we don't want to emit the
1427 // normal encryption header. Signal that with a cycle=99 to turn off
1428 // encryption for zero-byte entries or directories.
1430 // If finishing, then we know the stream length is zero. Else, unknown
1431 // stream length. Passing stream length == 0 allows an optimization so as
1432 // not to setup an encryption or deflation stream, when stream length is
1435 _currentEntry.WriteHeader(_outputStream, finishing ? 99 : 0);
1436 _currentEntry.StoreRelativeOffset();
1438 if (!_currentEntry.IsDirectory)
1440 _currentEntry.WriteSecurityMetadata(_outputStream);
1441 _currentEntry.PrepOutputStream(_outputStream,
1446 out _entryOutputStream);
1448 _needToWriteEntryHeader = false;
1453 private void _FinishCurrentEntry()
1455 if (_currentEntry != null)
1457 if (_needToWriteEntryHeader)
1458 _InitiateCurrentEntry(true); // an empty entry - no writes
1460 _currentEntry.FinishOutputStream(_outputStream, _outputCounter, _encryptor, _deflater, _entryOutputStream);
1461 _currentEntry.PostProcessOutput(_outputStream);
1463 if (_currentEntry.OutputUsedZip64!=null)
1464 _anyEntriesUsedZip64 |= _currentEntry.OutputUsedZip64.Value;
1466 // reset all the streams
1467 _outputCounter = null; _encryptor = _deflater = null; _entryOutputStream = null;
1474 /// Dispose the stream
1479 /// This method writes the Zip Central directory, then closes the stream. The
1480 /// application must call Dispose() (or Close) in order to produce a valid zip file.
1484 /// Typically the application will call <c>Dispose()</c> implicitly, via a <c>using</c>
1485 /// statement in C#, or a <c>Using</c> statement in VB.
1490 /// <param name="disposing">set this to true, always.</param>
1491 protected override void Dispose(bool disposing)
1493 if (_disposed) return;
1495 if (disposing) // not called from finalizer
1497 // handle pending exceptions
1498 if (!_exceptionPending)
1500 _FinishCurrentEntry();
1501 _directoryNeededZip64 = ZipOutput.WriteCentralDirectoryStructure(_outputStream,
1502 _entriesWritten.Values,
1503 1, // _numberOfSegmentsForMostRecentSave,
1506 new ZipContainer(this));
1507 Stream wrappedStream = null;
1508 CountingStream cs = _outputStream as CountingStream;
1511 wrappedStream = cs.WrappedStream;
1520 wrappedStream = _outputStream;
1523 if (!_leaveUnderlyingStreamOpen)
1526 wrappedStream.Close();
1528 wrappedStream.Dispose();
1531 _outputStream = null;
1540 /// Always returns false.
1542 public override bool CanRead { get { return false; } }
1545 /// Always returns false.
1547 public override bool CanSeek { get { return false; } }
1550 /// Always returns true.
1552 public override bool CanWrite { get { return true; } }
1555 /// Always returns a NotSupportedException.
1557 public override long Length { get { throw new NotSupportedException(); } }
1560 /// Setting this property always returns a NotSupportedException. Getting it
1561 /// returns the value of the Position on the underlying stream.
1563 public override long Position
1565 get { return _outputStream.Position; }
1566 set { throw new NotSupportedException(); }
1570 /// This is a no-op.
1572 public override void Flush() { }
1575 /// This method always throws a NotSupportedException.
1577 /// <param name="buffer">ignored</param>
1578 /// <param name="offset">ignored</param>
1579 /// <param name="count">ignored</param>
1580 /// <returns>nothing</returns>
1581 public override int Read(byte[] buffer, int offset, int count)
1583 throw new NotSupportedException("Read");
1587 /// This method always throws a NotSupportedException.
1589 /// <param name="offset">ignored</param>
1590 /// <param name="origin">ignored</param>
1591 /// <returns>nothing</returns>
1592 public override long Seek(long offset, SeekOrigin origin)
1594 throw new NotSupportedException("Seek");
1598 /// This method always throws a NotSupportedException.
1600 /// <param name="value">ignored</param>
1601 public override void SetLength(long value)
1603 throw new NotSupportedException();
1607 private EncryptionAlgorithm _encryption;
1608 private ZipEntryTimestamp _timestamp;
1609 internal String _password;
1610 private String _comment;
1611 private Stream _outputStream;
1612 private ZipEntry _currentEntry;
1613 internal Zip64Option _zip64;
1614 private Dictionary<String, ZipEntry> _entriesWritten;
1615 private int _entryCount;
1616 private ZipOption _alternateEncodingUsage = ZipOption.Never;
1617 private System.Text.Encoding _alternateEncoding
1618 = System.Text.Encoding.GetEncoding("IBM437"); // default = IBM437
1620 private bool _leaveUnderlyingStreamOpen;
1621 private bool _disposed;
1622 private bool _exceptionPending; // **see note below
1623 private bool _anyEntriesUsedZip64, _directoryNeededZip64;
1624 private CountingStream _outputCounter;
1625 private Stream _encryptor;
1626 private Stream _deflater;
1627 private Ionic.Crc.CrcCalculatorStream _entryOutputStream;
1628 private bool _needToWriteEntryHeader;
1629 private string _name;
1630 private bool _DontIgnoreCase;
1632 internal Ionic.Zlib.ParallelDeflateOutputStream ParallelDeflater;
1633 private long _ParallelDeflateThreshold;
1634 private int _maxBufferPairs = 16;
1637 // **Note regarding exceptions:
1639 // When ZipOutputStream is employed within a using clause, which
1640 // is the typical scenario, and an exception is thrown within
1641 // the scope of the using, Close()/Dispose() is invoked
1642 // implicitly before processing the initial exception. In that
1643 // case, _exceptionPending is true, and we don't want to try to
1644 // write anything in the Close/Dispose logic. Doing so can
1645 // cause additional exceptions that mask the original one. So,
1646 // the _exceptionPending flag is used to track that, and to
1647 // allow the original exception to be propagated to the
1648 // application without extra "noise."
1654 internal class ZipContainer
1656 private ZipFile _zf;
1657 private ZipOutputStream _zos;
1658 private ZipInputStream _zis;
1660 public ZipContainer(Object o)
1662 _zf = (o as ZipFile);
1663 _zos = (o as ZipOutputStream);
1664 _zis = (o as ZipInputStream);
1667 public ZipFile ZipFile
1672 public ZipOutputStream ZipOutputStream
1674 get { return _zos; }
1681 if (_zf != null) return _zf.Name;
1682 if (_zis != null) throw new NotSupportedException();
1687 public string Password
1691 if (_zf != null) return _zf._Password;
1692 if (_zis != null) return _zis._Password;
1693 return _zos._password;
1697 public Zip64Option Zip64
1701 if (_zf != null) return _zf._zip64;
1702 if (_zis != null) throw new NotSupportedException();
1707 public int BufferSize
1711 if (_zf != null) return _zf.BufferSize;
1712 if (_zis != null) throw new NotSupportedException();
1718 public Ionic.Zlib.ParallelDeflateOutputStream ParallelDeflater
1722 if (_zf != null) return _zf.ParallelDeflater;
1723 if (_zis != null) return null;
1724 return _zos.ParallelDeflater;
1728 if (_zf != null) _zf.ParallelDeflater = value;
1729 else if (_zos != null) _zos.ParallelDeflater = value;
1733 public long ParallelDeflateThreshold
1737 if (_zf != null) return _zf.ParallelDeflateThreshold;
1738 return _zos.ParallelDeflateThreshold;
1741 public int ParallelDeflateMaxBufferPairs
1745 if (_zf != null) return _zf.ParallelDeflateMaxBufferPairs;
1746 return _zos.ParallelDeflateMaxBufferPairs;
1751 public int CodecBufferSize
1755 if (_zf != null) return _zf.CodecBufferSize;
1756 if (_zis != null) return _zis.CodecBufferSize;
1757 return _zos.CodecBufferSize;
1761 public Ionic.Zlib.CompressionStrategy Strategy
1765 if (_zf != null) return _zf.Strategy;
1766 return _zos.Strategy;
1770 public Zip64Option UseZip64WhenSaving
1774 if (_zf != null) return _zf.UseZip64WhenSaving;
1775 return _zos.EnableZip64;
1779 public System.Text.Encoding AlternateEncoding
1783 if (_zf != null) return _zf.AlternateEncoding;
1784 if (_zos!=null) return _zos.AlternateEncoding;
1788 public System.Text.Encoding DefaultEncoding
1792 if (_zf != null) return ZipFile.DefaultEncoding;
1793 if (_zos!=null) return ZipOutputStream.DefaultEncoding;
1797 public ZipOption AlternateEncodingUsage
1801 if (_zf != null) return _zf.AlternateEncodingUsage;
1802 if (_zos!=null) return _zos.AlternateEncodingUsage;
1803 return ZipOption.Never; // n/a
1807 public Stream ReadStream
1811 if (_zf != null) return _zf.ReadStream;
1812 return _zis.ReadStream;