Free cookie consent management tool by TermsFeed Policy Generator

source: branches/2389-EpsLexicase/HeuristicLab.ExtLibs/HeuristicLab.EPPlus/4.0.3/EPPlus-4.0.3/Packaging/DotNetZip/Zlib/GZipStream.cs @ 15945

Last change on this file since 15945 was 12074, checked in by sraggl, 10 years ago

#2341: Added EPPlus-4.0.3 to ExtLibs

File size: 41.5 KB
Line 
1// GZipStream.cs
2// ------------------------------------------------------------------
3//
4// Copyright (c) 2009 Dino Chiesa and Microsoft Corporation.
5// All rights reserved.
6//
7// This code module is part of DotNetZip, a zipfile class library.
8//
9// ------------------------------------------------------------------
10//
11// This code is licensed under the Microsoft Public License.
12// See the file License.txt for the license details.
13// More info on: http://dotnetzip.codeplex.com
14//
15// ------------------------------------------------------------------
16//
17// last saved (in emacs):
18// Time-stamp: <2011-August-08 18:14:39>
19//
20// ------------------------------------------------------------------
21//
22// This module defines the GZipStream class, which can be used as a replacement for
23// the System.IO.Compression.GZipStream class in the .NET BCL.  NB: The design is not
24// completely OO clean: there is some intelligence in the ZlibBaseStream that reads the
25// GZip header.
26//
27// ------------------------------------------------------------------
28
29
30using System;
31using System.IO;
32
33namespace OfficeOpenXml.Packaging.Ionic.Zlib
34{
35    /// <summary>
36    ///   A class for compressing and decompressing GZIP streams.
37    /// </summary>
38    /// <remarks>
39    ///
40    /// <para>
41    ///   The <c>GZipStream</c> is a <see
42    ///   href="http://en.wikipedia.org/wiki/Decorator_pattern">Decorator</see> on a
43    ///   <see cref="Stream"/>. It adds GZIP compression or decompression to any
44    ///   stream.
45    /// </para>
46    ///
47    /// <para>
48    ///   Like the <c>System.IO.Compression.GZipStream</c> in the .NET Base Class Library, the
49    ///   <c>Ionic.Zlib.GZipStream</c> can compress while writing, or decompress while
50    ///   reading, but not vice versa.  The compression method used is GZIP, which is
51    ///   documented in <see href="http://www.ietf.org/rfc/rfc1952.txt">IETF RFC
52    ///   1952</see>, "GZIP file format specification version 4.3".</para>
53    ///
54    /// <para>
55    ///   A <c>GZipStream</c> can be used to decompress data (through <c>Read()</c>) or
56    ///   to compress data (through <c>Write()</c>), but not both.
57    /// </para>
58    ///
59    /// <para>
60    ///   If you wish to use the <c>GZipStream</c> to compress data, you must wrap it
61    ///   around a write-able stream. As you call <c>Write()</c> on the <c>GZipStream</c>, the
62    ///   data will be compressed into the GZIP format.  If you want to decompress data,
63    ///   you must wrap the <c>GZipStream</c> around a readable stream that contains an
64    ///   IETF RFC 1952-compliant stream.  The data will be decompressed as you call
65    ///   <c>Read()</c> on the <c>GZipStream</c>.
66    /// </para>
67    ///
68    /// <para>
69    ///   Though the GZIP format allows data from multiple files to be concatenated
70    ///   together, this stream handles only a single segment of GZIP format, typically
71    ///   representing a single file.
72    /// </para>
73    ///
74    /// <para>
75    ///   This class is similar to <see cref="ZlibStream"/> and <see cref="DeflateStream"/>.
76    ///   <c>ZlibStream</c> handles RFC1950-compliant streams.  <see cref="DeflateStream"/>
77    ///   handles RFC1951-compliant streams. This class handles RFC1952-compliant streams.
78    /// </para>
79    ///
80    /// </remarks>
81    ///
82    /// <seealso cref="DeflateStream" />
83    /// <seealso cref="ZlibStream" />
84    public class GZipStream : System.IO.Stream
85    {
86        // GZip format
87        // source: http://tools.ietf.org/html/rfc1952
88        //
89        //  header id:           2 bytes    1F 8B
90        //  compress method      1 byte     8= DEFLATE (none other supported)
91        //  flag                 1 byte     bitfield (See below)
92        //  mtime                4 bytes    time_t (seconds since jan 1, 1970 UTC of the file.
93        //  xflg                 1 byte     2 = max compress used , 4 = max speed (can be ignored)
94        //  OS                   1 byte     OS for originating archive. set to 0xFF in compression.
95        //  extra field length   2 bytes    optional - only if FEXTRA is set.
96        //  extra field          varies
97        //  filename             varies     optional - if FNAME is set.  zero terminated. ISO-8859-1.
98        //  file comment         varies     optional - if FCOMMENT is set. zero terminated. ISO-8859-1.
99        //  crc16                1 byte     optional - present only if FHCRC bit is set
100        //  compressed data      varies
101        //  CRC32                4 bytes
102        //  isize                4 bytes    data size modulo 2^32
103        //
104        //     FLG (FLaGs)
105        //                bit 0   FTEXT - indicates file is ASCII text (can be safely ignored)
106        //                bit 1   FHCRC - there is a CRC16 for the header immediately following the header
107        //                bit 2   FEXTRA - extra fields are present
108        //                bit 3   FNAME - the zero-terminated filename is present. encoding; ISO-8859-1.
109        //                bit 4   FCOMMENT  - a zero-terminated file comment is present. encoding: ISO-8859-1
110        //                bit 5   reserved
111        //                bit 6   reserved
112        //                bit 7   reserved
113        //
114        // On consumption:
115        // Extra field is a bunch of nonsense and can be safely ignored.
116        // Header CRC and OS, likewise.
117        //
118        // on generation:
119        // all optional fields get 0, except for the OS, which gets 255.
120        //
121
122
123
124        /// <summary>
125        ///   The comment on the GZIP stream.
126        /// </summary>
127        ///
128        /// <remarks>
129        /// <para>
130        ///   The GZIP format allows for each file to optionally have an associated
131        ///   comment stored with the file.  The comment is encoded with the ISO-8859-1
132        ///   code page.  To include a comment in a GZIP stream you create, set this
133        ///   property before calling <c>Write()</c> for the first time on the
134        ///   <c>GZipStream</c>.
135        /// </para>
136        ///
137        /// <para>
138        ///   When using <c>GZipStream</c> to decompress, you can retrieve this property
139        ///   after the first call to <c>Read()</c>.  If no comment has been set in the
140        ///   GZIP bytestream, the Comment property will return <c>null</c>
141        ///   (<c>Nothing</c> in VB).
142        /// </para>
143        /// </remarks>
144        public String Comment
145        {
146            get
147            {
148                return _Comment;
149            }
150            set
151            {
152                if (_disposed) throw new ObjectDisposedException("GZipStream");
153                _Comment = value;
154            }
155        }
156
157        /// <summary>
158        ///   The FileName for the GZIP stream.
159        /// </summary>
160        ///
161        /// <remarks>
162        ///
163        /// <para>
164        ///   The GZIP format optionally allows each file to have an associated
165        ///   filename.  When compressing data (through <c>Write()</c>), set this
166        ///   FileName before calling <c>Write()</c> the first time on the <c>GZipStream</c>.
167        ///   The actual filename is encoded into the GZIP bytestream with the
168        ///   ISO-8859-1 code page, according to RFC 1952. It is the application's
169        ///   responsibility to insure that the FileName can be encoded and decoded
170        ///   correctly with this code page.
171        /// </para>
172        ///
173        /// <para>
174        ///   When decompressing (through <c>Read()</c>), you can retrieve this value
175        ///   any time after the first <c>Read()</c>.  In the case where there was no filename
176        ///   encoded into the GZIP bytestream, the property will return <c>null</c> (<c>Nothing</c>
177        ///   in VB).
178        /// </para>
179        /// </remarks>
180        public String FileName
181        {
182            get { return _FileName; }
183            set
184            {
185                if (_disposed) throw new ObjectDisposedException("GZipStream");
186                _FileName = value;
187                if (_FileName == null) return;
188                if (_FileName.IndexOf("/") != -1)
189                {
190                    _FileName = _FileName.Replace("/", "\\");
191                }
192                if (_FileName.EndsWith("\\"))
193                    throw new Exception("Illegal filename");
194                if (_FileName.IndexOf("\\") != -1)
195                {
196                    // trim any leading path
197                    _FileName = Path.GetFileName(_FileName);
198                }
199            }
200        }
201
202        /// <summary>
203        ///   The last modified time for the GZIP stream.
204        /// </summary>
205        ///
206        /// <remarks>
207        ///   GZIP allows the storage of a last modified time with each GZIP entry.
208        ///   When compressing data, you can set this before the first call to
209        ///   <c>Write()</c>.  When decompressing, you can retrieve this value any time
210        ///   after the first call to <c>Read()</c>.
211        /// </remarks>
212        public DateTime? LastModified;
213
214        /// <summary>
215        /// The CRC on the GZIP stream.
216        /// </summary>
217        /// <remarks>
218        /// This is used for internal error checking. You probably don't need to look at this property.
219        /// </remarks>
220        public int Crc32 { get { return _Crc32; } }
221
222        private int _headerByteCount;
223        internal ZlibBaseStream _baseStream;
224        bool _disposed;
225        bool _firstReadDone;
226        string _FileName;
227        string _Comment;
228        int _Crc32;
229
230
231        /// <summary>
232        ///   Create a <c>GZipStream</c> using the specified <c>CompressionMode</c>.
233        /// </summary>
234        /// <remarks>
235        ///
236        /// <para>
237        ///   When mode is <c>CompressionMode.Compress</c>, the <c>GZipStream</c> will use the
238        ///   default compression level.
239        /// </para>
240        ///
241        /// <para>
242        ///   As noted in the class documentation, the <c>CompressionMode</c> (Compress
243        ///   or Decompress) also establishes the "direction" of the stream.  A
244        ///   <c>GZipStream</c> with <c>CompressionMode.Compress</c> works only through
245        ///   <c>Write()</c>.  A <c>GZipStream</c> with
246        ///   <c>CompressionMode.Decompress</c> works only through <c>Read()</c>.
247        /// </para>
248        ///
249        /// </remarks>
250        ///
251        /// <example>
252        ///   This example shows how to use a GZipStream to compress data.
253        /// <code>
254        /// using (System.IO.Stream input = System.IO.File.OpenRead(fileToCompress))
255        /// {
256        ///     using (var raw = System.IO.File.Create(outputFile))
257        ///     {
258        ///         using (Stream compressor = new GZipStream(raw, CompressionMode.Compress))
259        ///         {
260        ///             byte[] buffer = new byte[WORKING_BUFFER_SIZE];
261        ///             int n;
262        ///             while ((n= input.Read(buffer, 0, buffer.Length)) != 0)
263        ///             {
264        ///                 compressor.Write(buffer, 0, n);
265        ///             }
266        ///         }
267        ///     }
268        /// }
269        /// </code>
270        /// <code lang="VB">
271        /// Dim outputFile As String = (fileToCompress &amp; ".compressed")
272        /// Using input As Stream = File.OpenRead(fileToCompress)
273        ///     Using raw As FileStream = File.Create(outputFile)
274        ///     Using compressor As Stream = New GZipStream(raw, CompressionMode.Compress)
275        ///         Dim buffer As Byte() = New Byte(4096) {}
276        ///         Dim n As Integer = -1
277        ///         Do While (n &lt;&gt; 0)
278        ///             If (n &gt; 0) Then
279        ///                 compressor.Write(buffer, 0, n)
280        ///             End If
281        ///             n = input.Read(buffer, 0, buffer.Length)
282        ///         Loop
283        ///     End Using
284        ///     End Using
285        /// End Using
286        /// </code>
287        /// </example>
288        ///
289        /// <example>
290        /// This example shows how to use a GZipStream to uncompress a file.
291        /// <code>
292        /// private void GunZipFile(string filename)
293        /// {
294        ///     if (!filename.EndsWith(".gz))
295        ///         throw new ArgumentException("filename");
296        ///     var DecompressedFile = filename.Substring(0,filename.Length-3);
297        ///     byte[] working = new byte[WORKING_BUFFER_SIZE];
298        ///     int n= 1;
299        ///     using (System.IO.Stream input = System.IO.File.OpenRead(filename))
300        ///     {
301        ///         using (Stream decompressor= new Ionic.Zlib.GZipStream(input, CompressionMode.Decompress, true))
302        ///         {
303        ///             using (var output = System.IO.File.Create(DecompressedFile))
304        ///             {
305        ///                 while (n !=0)
306        ///                 {
307        ///                     n= decompressor.Read(working, 0, working.Length);
308        ///                     if (n > 0)
309        ///                     {
310        ///                         output.Write(working, 0, n);
311        ///                     }
312        ///                 }
313        ///             }
314        ///         }
315        ///     }
316        /// }
317        /// </code>
318        ///
319        /// <code lang="VB">
320        /// Private Sub GunZipFile(ByVal filename as String)
321        ///     If Not (filename.EndsWith(".gz)) Then
322        ///         Throw New ArgumentException("filename")
323        ///     End If
324        ///     Dim DecompressedFile as String = filename.Substring(0,filename.Length-3)
325        ///     Dim working(WORKING_BUFFER_SIZE) as Byte
326        ///     Dim n As Integer = 1
327        ///     Using input As Stream = File.OpenRead(filename)
328        ///         Using decompressor As Stream = new Ionic.Zlib.GZipStream(input, CompressionMode.Decompress, True)
329        ///             Using output As Stream = File.Create(UncompressedFile)
330        ///                 Do
331        ///                     n= decompressor.Read(working, 0, working.Length)
332        ///                     If n > 0 Then
333        ///                         output.Write(working, 0, n)
334        ///                     End IF
335        ///                 Loop While (n  > 0)
336        ///             End Using
337        ///         End Using
338        ///     End Using
339        /// End Sub
340        /// </code>
341        /// </example>
342        ///
343        /// <param name="stream">The stream which will be read or written.</param>
344        /// <param name="mode">Indicates whether the GZipStream will compress or decompress.</param>
345        public GZipStream(Stream stream, CompressionMode mode)
346            : this(stream, mode, CompressionLevel.Default, false)
347        {
348        }
349
350        /// <summary>
351        ///   Create a <c>GZipStream</c> using the specified <c>CompressionMode</c> and
352        ///   the specified <c>CompressionLevel</c>.
353        /// </summary>
354        /// <remarks>
355        ///
356        /// <para>
357        ///   The <c>CompressionMode</c> (Compress or Decompress) also establishes the
358        ///   "direction" of the stream.  A <c>GZipStream</c> with
359        ///   <c>CompressionMode.Compress</c> works only through <c>Write()</c>.  A
360        ///   <c>GZipStream</c> with <c>CompressionMode.Decompress</c> works only
361        ///   through <c>Read()</c>.
362        /// </para>
363        ///
364        /// </remarks>
365        ///
366        /// <example>
367        ///
368        /// This example shows how to use a <c>GZipStream</c> to compress a file into a .gz file.
369        ///
370        /// <code>
371        /// using (System.IO.Stream input = System.IO.File.OpenRead(fileToCompress))
372        /// {
373        ///     using (var raw = System.IO.File.Create(fileToCompress + ".gz"))
374        ///     {
375        ///         using (Stream compressor = new GZipStream(raw,
376        ///                                                   CompressionMode.Compress,
377        ///                                                   CompressionLevel.BestCompression))
378        ///         {
379        ///             byte[] buffer = new byte[WORKING_BUFFER_SIZE];
380        ///             int n;
381        ///             while ((n= input.Read(buffer, 0, buffer.Length)) != 0)
382        ///             {
383        ///                 compressor.Write(buffer, 0, n);
384        ///             }
385        ///         }
386        ///     }
387        /// }
388        /// </code>
389        ///
390        /// <code lang="VB">
391        /// Using input As Stream = File.OpenRead(fileToCompress)
392        ///     Using raw As FileStream = File.Create(fileToCompress &amp; ".gz")
393        ///         Using compressor As Stream = New GZipStream(raw, CompressionMode.Compress, CompressionLevel.BestCompression)
394        ///             Dim buffer As Byte() = New Byte(4096) {}
395        ///             Dim n As Integer = -1
396        ///             Do While (n &lt;&gt; 0)
397        ///                 If (n &gt; 0) Then
398        ///                     compressor.Write(buffer, 0, n)
399        ///                 End If
400        ///                 n = input.Read(buffer, 0, buffer.Length)
401        ///             Loop
402        ///         End Using
403        ///     End Using
404        /// End Using
405        /// </code>
406        /// </example>
407        /// <param name="stream">The stream to be read or written while deflating or inflating.</param>
408        /// <param name="mode">Indicates whether the <c>GZipStream</c> will compress or decompress.</param>
409        /// <param name="level">A tuning knob to trade speed for effectiveness.</param>
410        public GZipStream(Stream stream, CompressionMode mode, CompressionLevel level)
411            : this(stream, mode, level, false)
412        {
413        }
414
415        /// <summary>
416        ///   Create a <c>GZipStream</c> using the specified <c>CompressionMode</c>, and
417        ///   explicitly specify whether the stream should be left open after Deflation
418        ///   or Inflation.
419        /// </summary>
420        ///
421        /// <remarks>
422        /// <para>
423        ///   This constructor allows the application to request that the captive stream
424        ///   remain open after the deflation or inflation occurs.  By default, after
425        ///   <c>Close()</c> is called on the stream, the captive stream is also
426        ///   closed. In some cases this is not desired, for example if the stream is a
427        ///   memory stream that will be re-read after compressed data has been written
428        ///   to it.  Specify true for the <paramref name="leaveOpen"/> parameter to leave
429        ///   the stream open.
430        /// </para>
431        ///
432        /// <para>
433        ///   The <see cref="CompressionMode"/> (Compress or Decompress) also
434        ///   establishes the "direction" of the stream.  A <c>GZipStream</c> with
435        ///   <c>CompressionMode.Compress</c> works only through <c>Write()</c>.  A <c>GZipStream</c>
436        ///   with <c>CompressionMode.Decompress</c> works only through <c>Read()</c>.
437        /// </para>
438        ///
439        /// <para>
440        ///   The <c>GZipStream</c> will use the default compression level. If you want
441        ///   to specify the compression level, see <see cref="GZipStream(Stream,
442        ///   CompressionMode, CompressionLevel, bool)"/>.
443        /// </para>
444        ///
445        /// <para>
446        ///   See the other overloads of this constructor for example code.
447        /// </para>
448        ///
449        /// </remarks>
450        ///
451        /// <param name="stream">
452        ///   The stream which will be read or written. This is called the "captive"
453        ///   stream in other places in this documentation.
454        /// </param>
455        ///
456        /// <param name="mode">Indicates whether the GZipStream will compress or decompress.
457        /// </param>
458        ///
459        /// <param name="leaveOpen">
460        ///   true if the application would like the base stream to remain open after
461        ///   inflation/deflation.
462        /// </param>
463        public GZipStream(Stream stream, CompressionMode mode, bool leaveOpen)
464            : this(stream, mode, CompressionLevel.Default, leaveOpen)
465        {
466        }
467
468        /// <summary>
469        ///   Create a <c>GZipStream</c> using the specified <c>CompressionMode</c> and the
470        ///   specified <c>CompressionLevel</c>, and explicitly specify whether the
471        ///   stream should be left open after Deflation or Inflation.
472        /// </summary>
473        ///
474        /// <remarks>
475        ///
476        /// <para>
477        ///   This constructor allows the application to request that the captive stream
478        ///   remain open after the deflation or inflation occurs.  By default, after
479        ///   <c>Close()</c> is called on the stream, the captive stream is also
480        ///   closed. In some cases this is not desired, for example if the stream is a
481        ///   memory stream that will be re-read after compressed data has been written
482        ///   to it.  Specify true for the <paramref name="leaveOpen"/> parameter to
483        ///   leave the stream open.
484        /// </para>
485        ///
486        /// <para>
487        ///   As noted in the class documentation, the <c>CompressionMode</c> (Compress
488        ///   or Decompress) also establishes the "direction" of the stream.  A
489        ///   <c>GZipStream</c> with <c>CompressionMode.Compress</c> works only through
490        ///   <c>Write()</c>.  A <c>GZipStream</c> with <c>CompressionMode.Decompress</c> works only
491        ///   through <c>Read()</c>.
492        /// </para>
493        ///
494        /// </remarks>
495        ///
496        /// <example>
497        ///   This example shows how to use a <c>GZipStream</c> to compress data.
498        /// <code>
499        /// using (System.IO.Stream input = System.IO.File.OpenRead(fileToCompress))
500        /// {
501        ///     using (var raw = System.IO.File.Create(outputFile))
502        ///     {
503        ///         using (Stream compressor = new GZipStream(raw, CompressionMode.Compress, CompressionLevel.BestCompression, true))
504        ///         {
505        ///             byte[] buffer = new byte[WORKING_BUFFER_SIZE];
506        ///             int n;
507        ///             while ((n= input.Read(buffer, 0, buffer.Length)) != 0)
508        ///             {
509        ///                 compressor.Write(buffer, 0, n);
510        ///             }
511        ///         }
512        ///     }
513        /// }
514        /// </code>
515        /// <code lang="VB">
516        /// Dim outputFile As String = (fileToCompress &amp; ".compressed")
517        /// Using input As Stream = File.OpenRead(fileToCompress)
518        ///     Using raw As FileStream = File.Create(outputFile)
519        ///     Using compressor As Stream = New GZipStream(raw, CompressionMode.Compress, CompressionLevel.BestCompression, True)
520        ///         Dim buffer As Byte() = New Byte(4096) {}
521        ///         Dim n As Integer = -1
522        ///         Do While (n &lt;&gt; 0)
523        ///             If (n &gt; 0) Then
524        ///                 compressor.Write(buffer, 0, n)
525        ///             End If
526        ///             n = input.Read(buffer, 0, buffer.Length)
527        ///         Loop
528        ///     End Using
529        ///     End Using
530        /// End Using
531        /// </code>
532        /// </example>
533        /// <param name="stream">The stream which will be read or written.</param>
534        /// <param name="mode">Indicates whether the GZipStream will compress or decompress.</param>
535        /// <param name="leaveOpen">true if the application would like the stream to remain open after inflation/deflation.</param>
536        /// <param name="level">A tuning knob to trade speed for effectiveness.</param>
537        public GZipStream(Stream stream, CompressionMode mode, CompressionLevel level, bool leaveOpen)
538        {
539            _baseStream = new ZlibBaseStream(stream, mode, level, ZlibStreamFlavor.GZIP, leaveOpen);
540        }
541
542        #region Zlib properties
543
544        /// <summary>
545        /// This property sets the flush behavior on the stream.
546        /// </summary>
547        virtual public FlushType FlushMode
548        {
549            get { return (this._baseStream._flushMode); }
550            set {
551                if (_disposed) throw new ObjectDisposedException("GZipStream");
552                this._baseStream._flushMode = value;
553            }
554        }
555
556        /// <summary>
557        ///   The size of the working buffer for the compression codec.
558        /// </summary>
559        ///
560        /// <remarks>
561        /// <para>
562        ///   The working buffer is used for all stream operations.  The default size is
563        ///   1024 bytes.  The minimum size is 128 bytes. You may get better performance
564        ///   with a larger buffer.  Then again, you might not.  You would have to test
565        ///   it.
566        /// </para>
567        ///
568        /// <para>
569        ///   Set this before the first call to <c>Read()</c> or <c>Write()</c> on the
570        ///   stream. If you try to set it afterwards, it will throw.
571        /// </para>
572        /// </remarks>
573        public int BufferSize
574        {
575            get
576            {
577                return this._baseStream._bufferSize;
578            }
579            set
580            {
581                if (_disposed) throw new ObjectDisposedException("GZipStream");
582                if (this._baseStream._workingBuffer != null)
583                    throw new ZlibException("The working buffer is already set.");
584                if (value < ZlibConstants.WorkingBufferSizeMin)
585                    throw new ZlibException(String.Format("Don't be silly. {0} bytes?? Use a bigger buffer, at least {1}.", value, ZlibConstants.WorkingBufferSizeMin));
586                this._baseStream._bufferSize = value;
587            }
588        }
589
590
591        /// <summary> Returns the total number of bytes input so far.</summary>
592        virtual public long TotalIn
593        {
594            get
595            {
596                return this._baseStream._z.TotalBytesIn;
597            }
598        }
599
600        /// <summary> Returns the total number of bytes output so far.</summary>
601        virtual public long TotalOut
602        {
603            get
604            {
605                return this._baseStream._z.TotalBytesOut;
606            }
607        }
608
609        #endregion
610
611        #region Stream methods
612
613        /// <summary>
614        ///   Dispose the stream.
615        /// </summary>
616        /// <remarks>
617        ///   <para>
618        ///     This may or may not result in a <c>Close()</c> call on the captive
619        ///     stream.  See the constructors that have a <c>leaveOpen</c> parameter
620        ///     for more information.
621        ///   </para>
622        ///   <para>
623        ///     This method may be invoked in two distinct scenarios.  If disposing
624        ///     == true, the method has been called directly or indirectly by a
625        ///     user's code, for example via the public Dispose() method. In this
626        ///     case, both managed and unmanaged resources can be referenced and
627        ///     disposed.  If disposing == false, the method has been called by the
628        ///     runtime from inside the object finalizer and this method should not
629        ///     reference other objects; in that case only unmanaged resources must
630        ///     be referenced or disposed.
631        ///   </para>
632        /// </remarks>
633        /// <param name="disposing">
634        ///   indicates whether the Dispose method was invoked by user code.
635        /// </param>
636        protected override void Dispose(bool disposing)
637        {
638            try
639            {
640                if (!_disposed)
641                {
642                    if (disposing && (this._baseStream != null))
643                    {
644                        this._baseStream.Close();
645                        this._Crc32 = _baseStream.Crc32;
646                    }
647                    _disposed = true;
648                }
649            }
650            finally
651            {
652                base.Dispose(disposing);
653            }
654        }
655
656
657        /// <summary>
658        /// Indicates whether the stream can be read.
659        /// </summary>
660        /// <remarks>
661        /// The return value depends on whether the captive stream supports reading.
662        /// </remarks>
663        public override bool CanRead
664        {
665            get
666            {
667                if (_disposed) throw new ObjectDisposedException("GZipStream");
668                return _baseStream._stream.CanRead;
669            }
670        }
671
672        /// <summary>
673        /// Indicates whether the stream supports Seek operations.
674        /// </summary>
675        /// <remarks>
676        /// Always returns false.
677        /// </remarks>
678        public override bool CanSeek
679        {
680            get { return false; }
681        }
682
683
684        /// <summary>
685        /// Indicates whether the stream can be written.
686        /// </summary>
687        /// <remarks>
688        /// The return value depends on whether the captive stream supports writing.
689        /// </remarks>
690        public override bool CanWrite
691        {
692            get
693            {
694                if (_disposed) throw new ObjectDisposedException("GZipStream");
695                return _baseStream._stream.CanWrite;
696            }
697        }
698
699        /// <summary>
700        /// Flush the stream.
701        /// </summary>
702        public override void Flush()
703        {
704            if (_disposed) throw new ObjectDisposedException("GZipStream");
705            _baseStream.Flush();
706        }
707
708        /// <summary>
709        /// Reading this property always throws a <see cref="NotImplementedException"/>.
710        /// </summary>
711        public override long Length
712        {
713            get { throw new NotImplementedException(); }
714        }
715
716        /// <summary>
717        ///   The position of the stream pointer.
718        /// </summary>
719        ///
720        /// <remarks>
721        ///   Setting this property always throws a <see
722        ///   cref="NotImplementedException"/>. Reading will return the total bytes
723        ///   written out, if used in writing, or the total bytes read in, if used in
724        ///   reading.  The count may refer to compressed bytes or uncompressed bytes,
725        ///   depending on how you've used the stream.
726        /// </remarks>
727        public override long Position
728        {
729            get
730            {
731                if (this._baseStream._streamMode == Ionic.Zlib.ZlibBaseStream.StreamMode.Writer)
732                    return this._baseStream._z.TotalBytesOut + _headerByteCount;
733                if (this._baseStream._streamMode == Ionic.Zlib.ZlibBaseStream.StreamMode.Reader)
734                    return this._baseStream._z.TotalBytesIn + this._baseStream._gzipHeaderByteCount;
735                return 0;
736            }
737
738            set { throw new NotImplementedException(); }
739        }
740
741        /// <summary>
742        ///   Read and decompress data from the source stream.
743        /// </summary>
744        ///
745        /// <remarks>
746        ///   With a <c>GZipStream</c>, decompression is done through reading.
747        /// </remarks>
748        ///
749        /// <example>
750        /// <code>
751        /// byte[] working = new byte[WORKING_BUFFER_SIZE];
752        /// using (System.IO.Stream input = System.IO.File.OpenRead(_CompressedFile))
753        /// {
754        ///     using (Stream decompressor= new Ionic.Zlib.GZipStream(input, CompressionMode.Decompress, true))
755        ///     {
756        ///         using (var output = System.IO.File.Create(_DecompressedFile))
757        ///         {
758        ///             int n;
759        ///             while ((n= decompressor.Read(working, 0, working.Length)) !=0)
760        ///             {
761        ///                 output.Write(working, 0, n);
762        ///             }
763        ///         }
764        ///     }
765        /// }
766        /// </code>
767        /// </example>
768        /// <param name="buffer">The buffer into which the decompressed data should be placed.</param>
769        /// <param name="offset">the offset within that data array to put the first byte read.</param>
770        /// <param name="count">the number of bytes to read.</param>
771        /// <returns>the number of bytes actually read</returns>
772        public override int Read(byte[] buffer, int offset, int count)
773        {
774            if (_disposed) throw new ObjectDisposedException("GZipStream");
775            int n = _baseStream.Read(buffer, offset, count);
776
777            // Console.WriteLine("GZipStream::Read(buffer, off({0}), c({1}) = {2}", offset, count, n);
778            // Console.WriteLine( Util.FormatByteArray(buffer, offset, n) );
779
780            if (!_firstReadDone)
781            {
782                _firstReadDone = true;
783                FileName = _baseStream._GzipFileName;
784                Comment = _baseStream._GzipComment;
785            }
786            return n;
787        }
788
789
790
791        /// <summary>
792        ///   Calling this method always throws a <see cref="NotImplementedException"/>.
793        /// </summary>
794        /// <param name="offset">irrelevant; it will always throw!</param>
795        /// <param name="origin">irrelevant; it will always throw!</param>
796        /// <returns>irrelevant!</returns>
797        public override long Seek(long offset, SeekOrigin origin)
798        {
799            throw new NotImplementedException();
800        }
801
802        /// <summary>
803        ///   Calling this method always throws a <see cref="NotImplementedException"/>.
804        /// </summary>
805        /// <param name="value">irrelevant; this method will always throw!</param>
806        public override void SetLength(long value)
807        {
808            throw new NotImplementedException();
809        }
810
811        /// <summary>
812        ///   Write data to the stream.
813        /// </summary>
814        ///
815        /// <remarks>
816        /// <para>
817        ///   If you wish to use the <c>GZipStream</c> to compress data while writing,
818        ///   you can create a <c>GZipStream</c> with <c>CompressionMode.Compress</c>, and a
819        ///   writable output stream.  Then call <c>Write()</c> on that <c>GZipStream</c>,
820        ///   providing uncompressed data as input.  The data sent to the output stream
821        ///   will be the compressed form of the data written.
822        /// </para>
823        ///
824        /// <para>
825        ///   A <c>GZipStream</c> can be used for <c>Read()</c> or <c>Write()</c>, but not
826        ///   both. Writing implies compression.  Reading implies decompression.
827        /// </para>
828        ///
829        /// </remarks>
830        /// <param name="buffer">The buffer holding data to write to the stream.</param>
831        /// <param name="offset">the offset within that data array to find the first byte to write.</param>
832        /// <param name="count">the number of bytes to write.</param>
833        public override void Write(byte[] buffer, int offset, int count)
834        {
835            if (_disposed) throw new ObjectDisposedException("GZipStream");
836            if (_baseStream._streamMode == Ionic.Zlib.ZlibBaseStream.StreamMode.Undefined)
837            {
838                //Console.WriteLine("GZipStream: First write");
839                if (_baseStream._wantCompress)
840                {
841                    // first write in compression, therefore, emit the GZIP header
842                    _headerByteCount = EmitHeader();
843                }
844                else
845                {
846                    throw new InvalidOperationException();
847                }
848            }
849
850            _baseStream.Write(buffer, offset, count);
851        }
852        #endregion
853
854
855        internal static readonly System.DateTime _unixEpoch = new System.DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
856#if SILVERLIGHT || NETCF
857        internal static readonly System.Text.Encoding iso8859dash1 = new Ionic.Encoding.Iso8859Dash1Encoding();
858#else
859        internal static readonly System.Text.Encoding iso8859dash1 = System.Text.Encoding.GetEncoding("iso-8859-1");
860#endif
861
862
863        private int EmitHeader()
864        {
865            byte[] commentBytes = (Comment == null) ? null : iso8859dash1.GetBytes(Comment);
866            byte[] filenameBytes = (FileName == null) ? null : iso8859dash1.GetBytes(FileName);
867
868            int cbLength = (Comment == null) ? 0 : commentBytes.Length + 1;
869            int fnLength = (FileName == null) ? 0 : filenameBytes.Length + 1;
870
871            int bufferLength = 10 + cbLength + fnLength;
872            byte[] header = new byte[bufferLength];
873            int i = 0;
874            // ID
875            header[i++] = 0x1F;
876            header[i++] = 0x8B;
877
878            // compression method
879            header[i++] = 8;
880            byte flag = 0;
881            if (Comment != null)
882                flag ^= 0x10;
883            if (FileName != null)
884                flag ^= 0x8;
885
886            // flag
887            header[i++] = flag;
888
889            // mtime
890            if (!LastModified.HasValue) LastModified = DateTime.Now;
891            System.TimeSpan delta = LastModified.Value - _unixEpoch;
892            Int32 timet = (Int32)delta.TotalSeconds;
893            Array.Copy(BitConverter.GetBytes(timet), 0, header, i, 4);
894            i += 4;
895
896            // xflg
897            header[i++] = 0;    // this field is totally useless
898            // OS
899            header[i++] = 0xFF; // 0xFF == unspecified
900
901            // extra field length - only if FEXTRA is set, which it is not.
902            //header[i++]= 0;
903            //header[i++]= 0;
904
905            // filename
906            if (fnLength != 0)
907            {
908                Array.Copy(filenameBytes, 0, header, i, fnLength - 1);
909                i += fnLength - 1;
910                header[i++] = 0; // terminate
911            }
912
913            // comment
914            if (cbLength != 0)
915            {
916                Array.Copy(commentBytes, 0, header, i, cbLength - 1);
917                i += cbLength - 1;
918                header[i++] = 0; // terminate
919            }
920
921            _baseStream._stream.Write(header, 0, header.Length);
922
923            return header.Length; // bytes written
924        }
925
926
927
928        /// <summary>
929        ///   Compress a string into a byte array using GZip.
930        /// </summary>
931        ///
932        /// <remarks>
933        ///   Uncompress it with <see cref="GZipStream.UncompressString(byte[])"/>.
934        /// </remarks>
935        ///
936        /// <seealso cref="GZipStream.UncompressString(byte[])"/>
937        /// <seealso cref="GZipStream.CompressBuffer(byte[])"/>
938        ///
939        /// <param name="s">
940        ///   A string to compress. The string will first be encoded
941        ///   using UTF8, then compressed.
942        /// </param>
943        ///
944        /// <returns>The string in compressed form</returns>
945        public static byte[] CompressString(String s)
946        {
947            using (var ms = new MemoryStream())
948            {
949                System.IO.Stream compressor =
950                    new GZipStream(ms, CompressionMode.Compress, CompressionLevel.BestCompression);
951                ZlibBaseStream.CompressString(s, compressor);
952                return ms.ToArray();
953            }
954        }
955
956
957        /// <summary>
958        ///   Compress a byte array into a new byte array using GZip.
959        /// </summary>
960        ///
961        /// <remarks>
962        ///   Uncompress it with <see cref="GZipStream.UncompressBuffer(byte[])"/>.
963        /// </remarks>
964        ///
965        /// <seealso cref="GZipStream.CompressString(string)"/>
966        /// <seealso cref="GZipStream.UncompressBuffer(byte[])"/>
967        ///
968        /// <param name="b">
969        ///   A buffer to compress.
970        /// </param>
971        ///
972        /// <returns>The data in compressed form</returns>
973        public static byte[] CompressBuffer(byte[] b)
974        {
975            using (var ms = new MemoryStream())
976            {
977                System.IO.Stream compressor =
978                    new GZipStream( ms, CompressionMode.Compress, CompressionLevel.BestCompression );
979
980                ZlibBaseStream.CompressBuffer(b, compressor);
981                return ms.ToArray();
982            }
983        }
984
985
986        /// <summary>
987        ///   Uncompress a GZip'ed byte array into a single string.
988        /// </summary>
989        ///
990        /// <seealso cref="GZipStream.CompressString(String)"/>
991        /// <seealso cref="GZipStream.UncompressBuffer(byte[])"/>
992        ///
993        /// <param name="compressed">
994        ///   A buffer containing GZIP-compressed data.
995        /// </param>
996        ///
997        /// <returns>The uncompressed string</returns>
998        public static String UncompressString(byte[] compressed)
999        {
1000            using (var input = new MemoryStream(compressed))
1001            {
1002                Stream decompressor = new GZipStream(input, CompressionMode.Decompress);
1003                return ZlibBaseStream.UncompressString(compressed, decompressor);
1004            }
1005        }
1006
1007
1008        /// <summary>
1009        ///   Uncompress a GZip'ed byte array into a byte array.
1010        /// </summary>
1011        ///
1012        /// <seealso cref="GZipStream.CompressBuffer(byte[])"/>
1013        /// <seealso cref="GZipStream.UncompressString(byte[])"/>
1014        ///
1015        /// <param name="compressed">
1016        ///   A buffer containing data that has been compressed with GZip.
1017        /// </param>
1018        ///
1019        /// <returns>The data in uncompressed form</returns>
1020        public static byte[] UncompressBuffer(byte[] compressed)
1021        {
1022            using (var input = new System.IO.MemoryStream(compressed))
1023            {
1024                System.IO.Stream decompressor =
1025                    new GZipStream( input, CompressionMode.Decompress );
1026
1027                return ZlibBaseStream.UncompressBuffer(compressed, decompressor);
1028            }
1029        }
1030
1031
1032    }
1033}
Note: See TracBrowser for help on using the repository browser.