root/trunk/Updater/ICSharpCode.SharpZipLib/GZip/GzipInputStream.cs @ 597

Wersja 597, 10.9 KB (wprowadzona przez marek, 17 years temu)

re #165

Line 
1// GzipInputStream.cs
2//
3// Copyright (C) 2001 Mike Krueger
4//
5// This file was translated from java, it was part of the GNU Classpath
6// Copyright (C) 2001 Free Software Foundation, Inc.
7//
8// This program is free software; you can redistribute it and/or
9// modify it under the terms of the GNU General Public License
10// as published by the Free Software Foundation; either version 2
11// of the License, or (at your option) any later version.
12//
13// This program is distributed in the hope that it will be useful,
14// but WITHOUT ANY WARRANTY; without even the implied warranty of
15// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16// GNU General Public License for more details.
17//
18// You should have received a copy of the GNU General Public License
19// along with this program; if not, write to the Free Software
20// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
21//
22// Linking this library statically or dynamically with other modules is
23// making a combined work based on this library.  Thus, the terms and
24// conditions of the GNU General Public License cover the whole
25// combination.
26//
27// As a special exception, the copyright holders of this library give you
28// permission to link this library with independent modules to produce an
29// executable, regardless of the license terms of these independent
30// modules, and to copy and distribute the resulting executable under
31// terms of your choice, provided that you also meet, for each linked
32// independent module, the terms and conditions of the license of that
33// module.  An independent module is a module which is not derived from
34// or based on this library.  If you modify this library, you may extend
35// this exception to your version of the library, but you are not
36// obligated to do so.  If you do not wish to do so, delete this
37// exception statement from your version.
38
39using System;
40using System.IO;
41
42using ICSharpCode.SharpZipLib.Checksums;
43using ICSharpCode.SharpZipLib.Zip.Compression;
44using ICSharpCode.SharpZipLib.Zip.Compression.Streams;
45
46namespace ICSharpCode.SharpZipLib.GZip
47{
48       
49        /// <summary>
50        /// This filter stream is used to decompress a "GZIP" format stream.
51        /// The "GZIP" format is described baseInputStream RFC 1952.
52        ///
53        /// author of the original java version : John Leuner
54        /// </summary>
55        /// <example> This sample shows how to unzip a gzipped file
56        /// <code>
57        /// using System;
58        /// using System.IO;
59        ///
60        /// using ICSharpCode.SharpZipLib.Core;
61        /// using ICSharpCode.SharpZipLib.GZip;
62        ///
63        /// class MainClass
64        /// {
65        ///     public static void Main(string[] args)
66        ///     {
67        ///                     using (Stream inStream = new GZipInputStream(File.OpenRead(args[0])))
68        ///                     using (FileStream outStream = File.Create(Path.GetFileNameWithoutExtension(args[0]))) {
69        ///                             byte[] buffer = new byte[4096];
70        ///                             StreamUtils.Copy(inStream, outStream, buffer);
71        ///             }
72        ///     }
73        /// }   
74        /// </code>
75        /// </example>
76        public class GZipInputStream : InflaterInputStream
77        {
78                #region Instance Fields
79                /// <summary>
80                /// CRC-32 value for uncompressed data
81                /// </summary>
82                protected Crc32 crc = new Crc32();
83               
84                /// <summary>
85                /// Indicates end of stream
86                /// </summary>
87                protected bool eos;
88               
89                // Have we read the GZIP header yet?
90                bool readGZIPHeader;
91                #endregion
92
93                #region Constructors
94                /// <summary>
95                /// Creates a GZipInputStream with the default buffer size
96                /// </summary>
97                /// <param name="baseInputStream">
98                /// The stream to read compressed data from (baseInputStream GZIP format)
99                /// </param>
100                public GZipInputStream(Stream baseInputStream)
101                        : this(baseInputStream, 4096)
102                {
103                }
104               
105                /// <summary>
106                /// Creates a GZIPInputStream with the specified buffer size
107                /// </summary>
108                /// <param name="baseInputStream">
109                /// The stream to read compressed data from (baseInputStream GZIP format)
110                /// </param>
111                /// <param name="size">
112                /// Size of the buffer to use
113                /// </param>
114                public GZipInputStream(Stream baseInputStream, int size)
115                        : base(baseInputStream, new Inflater(true), size)
116                {
117                }
118                #endregion     
119
120                #region Stream overrides
121                /// <summary>
122                /// Reads uncompressed data into an array of bytes
123                /// </summary>
124                /// <param name="buffer">
125                /// The buffer to read uncompressed data into
126                /// </param>
127                /// <param name="offset">
128                /// The offset indicating where the data should be placed
129                /// </param>
130                /// <param name="count">
131                /// The number of uncompressed bytes to be read
132                /// </param>
133                /// <returns>Returns the number of bytes actually read.</returns>
134                public override int Read(byte[] buffer, int offset, int count)
135                {
136                        // We first have to read the GZIP header, then we feed all the
137                        // rest of the data to the base class.
138                        //
139                        // As we do that we continually update the CRC32. Once the data is
140                        // finished, we check the CRC32
141                        //
142                        // This means we don't need our own buffer, as everything is done
143                        // in baseInputStream the superclass.
144                        if (!readGZIPHeader) {
145                                ReadHeader();
146                        }
147                       
148                        if (eos) {
149                                return 0;
150                        }
151                       
152                        // We don't have to read the header, so we just grab data from the superclass
153                        int bytesRead = base.Read(buffer, offset, count);
154                        if (bytesRead > 0) {
155                                crc.Update(buffer, offset, bytesRead);
156                        }
157                       
158                        if (inf.IsFinished) {
159                                ReadFooter();
160                        }
161                        return bytesRead;
162                }
163                #endregion     
164
165                #region Support routines
166                void ReadHeader()
167                {
168                        // 1. Check the two magic bytes
169                        Crc32 headCRC = new Crc32();
170                        int magic = baseInputStream.ReadByte();
171
172                        if (magic < 0) {
173                                throw new EndOfStreamException("EOS reading GZIP header");
174                        }
175
176                        headCRC.Update(magic);
177                        if (magic != (GZipConstants.GZIP_MAGIC >> 8)) {
178                                throw new GZipException("Error GZIP header, first magic byte doesn't match");
179                        }
180                               
181                        magic = baseInputStream.ReadByte();
182
183                        if (magic < 0) {
184                                throw new EndOfStreamException("EOS reading GZIP header");
185                        }
186                       
187                        if (magic != (GZipConstants.GZIP_MAGIC & 0xFF)) {
188                                throw new GZipException("Error GZIP header,  second magic byte doesn't match");
189                        }
190
191                        headCRC.Update(magic);
192                       
193                        // 2. Check the compression type (must be 8)
194                        int compressionType = baseInputStream.ReadByte();
195
196                        if ( compressionType < 0 ) {
197                                throw new EndOfStreamException("EOS reading GZIP header");
198                        }
199               
200                        if ( compressionType != 8 ) {
201                                throw new GZipException("Error GZIP header, data not in deflate format");
202                        }
203                        headCRC.Update(compressionType);
204                       
205                        // 3. Check the flags
206                        int flags = baseInputStream.ReadByte();
207                        if (flags < 0) {
208                                throw new EndOfStreamException("EOS reading GZIP header");
209                        }
210                        headCRC.Update(flags);
211                       
212                        /*    This flag byte is divided into individual bits as follows:
213                               
214                                bit 0   FTEXT
215                                bit 1   FHCRC
216                                bit 2   FEXTRA
217                                bit 3   FNAME
218                                bit 4   FCOMMENT
219                                bit 5   reserved
220                                bit 6   reserved
221                                bit 7   reserved
222                        */
223                               
224                        // 3.1 Check the reserved bits are zero
225                       
226                        if ((flags & 0xE0) != 0) {
227                                throw new GZipException("Reserved flag bits in GZIP header != 0");
228                        }
229                       
230                        // 4.-6. Skip the modification time, extra flags, and OS type
231                        for (int i=0; i< 6; i++) {
232                                int readByte = baseInputStream.ReadByte();
233                                if (readByte < 0) {
234                                        throw new EndOfStreamException("EOS reading GZIP header");
235                                }
236                                headCRC.Update(readByte);
237                        }
238                       
239                        // 7. Read extra field
240                        if ((flags & GZipConstants.FEXTRA) != 0) {
241                                // Skip subfield id
242                                for (int i=0; i< 2; i++) {
243                                        int readByte = baseInputStream.ReadByte();
244                                        if (readByte < 0) {
245                                                throw new EndOfStreamException("EOS reading GZIP header");
246                                        }
247                                        headCRC.Update(readByte);
248                                }
249
250                                if (baseInputStream.ReadByte() < 0 || baseInputStream.ReadByte() < 0) {
251                                        throw new EndOfStreamException("EOS reading GZIP header");
252                                }
253                               
254                                int len1, len2;
255                                len1 = baseInputStream.ReadByte();
256                                len2 = baseInputStream.ReadByte();
257                                if ((len1 < 0) || (len2 < 0)) {
258                                        throw new EndOfStreamException("EOS reading GZIP header");
259                                }
260                                headCRC.Update(len1);
261                                headCRC.Update(len2);
262                               
263                                int extraLen = (len1 << 8) | len2;
264                                for (int i = 0; i < extraLen;i++) {
265                                        int readByte = baseInputStream.ReadByte();
266                                        if (readByte < 0)
267                                        {
268                                                throw new EndOfStreamException("EOS reading GZIP header");
269                                        }
270                                        headCRC.Update(readByte);
271                                }
272                        }
273                       
274                        // 8. Read file name
275                        if ((flags & GZipConstants.FNAME) != 0) {
276                                int readByte;
277                                while ( (readByte = baseInputStream.ReadByte()) > 0) {
278                                        headCRC.Update(readByte);
279                                }
280                               
281                                if (readByte < 0) {
282                                        throw new EndOfStreamException("EOS reading GZIP header");
283                                }
284                                headCRC.Update(readByte);
285                        }
286                       
287                        // 9. Read comment
288                        if ((flags & GZipConstants.FCOMMENT) != 0) {
289                                int readByte;
290                                while ( (readByte = baseInputStream.ReadByte()) > 0) {
291                                        headCRC.Update(readByte);
292                                }
293                               
294                                if (readByte < 0) {
295                                        throw new EndOfStreamException("EOS reading GZIP header");
296                                }
297
298                                headCRC.Update(readByte);
299                        }
300                       
301                        // 10. Read header CRC
302                        if ((flags & GZipConstants.FHCRC) != 0) {
303                                int tempByte;
304                                int crcval = baseInputStream.ReadByte();
305                                if (crcval < 0) {
306                                        throw new EndOfStreamException("EOS reading GZIP header");
307                                }
308                               
309                                tempByte = baseInputStream.ReadByte();
310                                if (tempByte < 0) {
311                                        throw new EndOfStreamException("EOS reading GZIP header");
312                                }
313                               
314                                crcval = (crcval << 8) | tempByte;
315                                if (crcval != ((int) headCRC.Value & 0xffff)) {
316                                        throw new GZipException("Header CRC value mismatch");
317                                }
318                        }
319                       
320                        readGZIPHeader = true;
321                }
322               
323                void ReadFooter()
324                {
325                        byte[] footer = new byte[8];
326                        int avail = inf.RemainingInput;
327                       
328                        if (avail > 8) {
329                                avail = 8;
330                        }
331                       
332                        System.Array.Copy(inputBuffer.RawData, inputBuffer.RawLength - inf.RemainingInput, footer, 0, avail);
333                        int needed = 8 - avail;
334                       
335                        while (needed > 0) {
336                                int count = baseInputStream.Read(footer, 8 - needed, needed);
337                                if (count <= 0) {
338                                        throw new EndOfStreamException("EOS reading GZIP footer");
339                                }
340                                needed -= count; // Jewel Jan 16
341                        }
342
343                        int crcval = (footer[0] & 0xff) | ((footer[1] & 0xff) << 8) | ((footer[2] & 0xff) << 16) | (footer[3] << 24);
344                        if (crcval != (int) crc.Value) {
345                                throw new GZipException("GZIP crc sum mismatch, theirs \"" + crcval + "\" and ours \"" + (int) crc.Value);
346                        }
347                       
348                        // NOTE The total here is the original total modulo 2 ^ 32.
349                        uint total =
350                                (uint)((uint)footer[4] & 0xff) |
351                                (uint)(((uint)footer[5] & 0xff) << 8) |
352                                (uint)(((uint)footer[6] & 0xff) << 16) |
353                                (uint)((uint)footer[7] << 24);
354
355                        if ((inf.TotalOut & 0xffffffff) != total) {
356                                throw new GZipException("Number of bytes mismatch in footer");
357                        }
358                       
359                        // Should we support multiple gzip members.
360                        // Difficult, since there may be some bytes still in baseInputStream dataBuffer
361                        eos = true;
362                }
363                #endregion
364        }
365}
Notatka: Zobacz TracBrowser aby uzyskać więcej informacji.