2 // Copyright (C) 2001 Mike Krueger
4 // This file was translated from java, it was part of the GNU Classpath
5 // Copyright (C) 2001 Free Software Foundation, Inc.
7 // This program is free software; you can redistribute it and/or
8 // modify it under the terms of the GNU General Public License
9 // as published by the Free Software Foundation; either version 2
10 // of the License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU General Public License for more details.
17 // You should have received a copy of the GNU General Public License
18 // along with this program; if not, write to the Free Software
19 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21 // Linking this library statically or dynamically with other modules is
22 // making a combined work based on this library. Thus, the terms and
23 // conditions of the GNU General Public License cover the whole
26 // As a special exception, the copyright holders of this library give you
27 // permission to link this library with independent modules to produce an
28 // executable, regardless of the license terms of these independent
29 // modules, and to copy and distribute the resulting executable under
30 // terms of your choice, provided that you also meet, for each linked
31 // independent module, the terms and conditions of the license of that
32 // module. An independent module is a module which is not derived from
33 // or based on this library. If you modify this library, you may extend
34 // this exception to your version of the library, but you are not
35 // obligated to do so. If you do not wish to do so, delete this
36 // exception statement from your version.
41 using ICSharpCode
.SharpZipLib
.Checksums
;
42 using ICSharpCode
.SharpZipLib
.Zip
.Compression
;
43 using ICSharpCode
.SharpZipLib
.Zip
.Compression
.Streams
;
45 namespace ICSharpCode
.SharpZipLib
.GZip
49 /// This filter stream is used to decompress a "GZIP" format stream.
50 /// The "GZIP" format is described baseInputStream RFC 1952.
52 /// author of the original java version : John Leuner
54 /// <example> This sample shows how to unzip a gzipped file
63 /// public static void Main(string[] args)
65 /// Stream s = new GZipInputStream(File.OpenRead(args[0]));
66 /// FileStream fs = File.Create(Path.GetFileNameWithoutExtension(args[0]));
68 /// byte[] writeData = new byte[2048];
70 /// size = s.Read(writeData, 0, size);
72 /// fs.Write(writeData, 0, size);
82 public class GZipInputStream
: InflaterInputStream
85 /// CRC-32 value for uncompressed data
87 protected Crc32 crc
= new Crc32();
90 /// Indicates end of stream
94 // Have we read the GZIP header yet?
98 /// Creates a GzipInputStream with the default buffer size
100 /// <param name="baseInputStream">
101 /// The stream to read compressed data from (baseInputStream GZIP format)
103 public GZipInputStream(Stream baseInputStream
) : this(baseInputStream
, 4096)
108 /// Creates a GZIPInputStream with the specified buffer size
110 /// <param name="baseInputStream">
111 /// The stream to read compressed data from (baseInputStream GZIP format)
113 /// <param name="size">
114 /// Size of the buffer to use
116 public GZipInputStream(Stream baseInputStream
, int size
) : base(baseInputStream
, new Inflater(true), size
)
121 /// Reads uncompressed data into an array of bytes
123 /// <param name="buf">
124 /// the buffer to read uncompressed data into
126 /// <param name="offset">
127 /// the offset indicating where the data should be placed
129 /// <param name="len">
130 /// the number of uncompressed bytes to be read
132 public override int Read(byte[] buf
, int offset
, int len
)
134 // We first have to slurp baseInputStream the GZIP header, then we feed all the
135 // rest of the data to the superclass.
137 // As we do that we continually update the CRC32. Once the data is
138 // finished, we check the CRC32
140 // This means we don't need our own buffer, as everything is done
141 // baseInputStream the superclass.
142 if (!readGZIPHeader
) {
150 // System.err.println("GZIPIS.read(byte[], off, len ... " + offset + " and len " + len);
151 //We don't have to read the header, so we just grab data from the superclass
152 int numRead
= base.Read(buf
, offset
, len
);
154 crc
.Update(buf
, offset
, numRead
);
157 if (inf
.IsFinished
) {
163 private void ReadHeader()
165 /* 1. Check the two magic bytes */
166 Crc32 headCRC
= new Crc32();
167 int magic
= baseInputStream
.ReadByte();
172 headCRC
.Update(magic
);
173 if (magic
!= (GZipConstants
.GZIP_MAGIC
>> 8)) {
174 throw new IOException("Error baseInputStream GZIP header, first byte doesn't match");
177 magic
= baseInputStream
.ReadByte();
178 if (magic
!= (GZipConstants
.GZIP_MAGIC
& 0xFF)) {
179 throw new IOException("Error baseInputStream GZIP header, second byte doesn't match");
181 headCRC
.Update(magic
);
183 /* 2. Check the compression type (must be 8) */
184 int CM
= baseInputStream
.ReadByte();
186 throw new IOException("Error baseInputStream GZIP header, data not baseInputStream deflate format");
190 /* 3. Check the flags */
191 int flags
= baseInputStream
.ReadByte();
193 throw new Exception("Early EOF baseInputStream GZIP header");
195 headCRC
.Update(flags
);
197 /* This flag byte is divided into individual bits as follows:
209 /* 3.1 Check the reserved bits are zero */
211 if ((flags
& 0xd0) != 0) {
212 throw new IOException("Reserved flag bits baseInputStream GZIP header != 0");
215 /* 4.-6. Skip the modification time, extra flags, and OS type */
216 for (int i
=0; i
< 6; i
++) {
217 int readByte
= baseInputStream
.ReadByte();
219 throw new Exception("Early EOF baseInputStream GZIP header");
221 headCRC
.Update(readByte
);
224 /* 7. Read extra field */
225 if ((flags
& GZipConstants
.FEXTRA
) != 0) {
226 /* Skip subfield id */
227 for (int i
=0; i
< 2; i
++) {
228 int readByte
= baseInputStream
.ReadByte();
230 throw new Exception("Early EOF baseInputStream GZIP header");
232 headCRC
.Update(readByte
);
234 if (baseInputStream
.ReadByte() < 0 || baseInputStream
.ReadByte() < 0) {
235 throw new Exception("Early EOF baseInputStream GZIP header");
238 int len1
, len2
, extraLen
;
239 len1
= baseInputStream
.ReadByte();
240 len2
= baseInputStream
.ReadByte();
241 if ((len1
< 0) || (len2
< 0)) {
242 throw new Exception("Early EOF baseInputStream GZIP header");
244 headCRC
.Update(len1
);
245 headCRC
.Update(len2
);
247 extraLen
= (len1
<< 8) | len2
;
248 for (int i
= 0; i
< extraLen
;i
++) {
249 int readByte
= baseInputStream
.ReadByte();
252 throw new Exception("Early EOF baseInputStream GZIP header");
254 headCRC
.Update(readByte
);
258 /* 8. Read file name */
259 if ((flags
& GZipConstants
.FNAME
) != 0) {
261 while ( (readByte
= baseInputStream
.ReadByte()) > 0) {
262 headCRC
.Update(readByte
);
265 throw new Exception("Early EOF baseInputStream GZIP file name");
267 headCRC
.Update(readByte
);
270 /* 9. Read comment */
271 if ((flags
& GZipConstants
.FCOMMENT
) != 0) {
273 while ( (readByte
= baseInputStream
.ReadByte()) > 0) {
274 headCRC
.Update(readByte
);
278 throw new Exception("Early EOF baseInputStream GZIP comment");
280 headCRC
.Update(readByte
);
283 /* 10. Read header CRC */
284 if ((flags
& GZipConstants
.FHCRC
) != 0) {
286 int crcval
= baseInputStream
.ReadByte();
288 throw new Exception("Early EOF baseInputStream GZIP header");
291 tempByte
= baseInputStream
.ReadByte();
293 throw new Exception("Early EOF baseInputStream GZIP header");
296 crcval
= (crcval
<< 8) | tempByte
;
297 if (crcval
!= ((int) headCRC
.Value
& 0xffff)) {
298 throw new IOException("Header CRC value mismatch");
302 readGZIPHeader
= true;
303 //System.err.println("Read GZIP header");
306 private void ReadFooter()
308 byte[] footer
= new byte[8];
309 int avail
= inf
.RemainingInput
;
313 System
.Array
.Copy(buf
, len
- inf
.RemainingInput
, footer
, 0, avail
);
314 int needed
= 8 - avail
;
316 int count
= baseInputStream
.Read(footer
, 8-needed
, needed
);
318 throw new Exception("Early EOF baseInputStream GZIP footer");
320 needed
-= count
; //Jewel Jan 16
322 int crcval
= (footer
[0] & 0xff) | ((footer
[1] & 0xff) << 8) | ((footer
[2] & 0xff) << 16) | (footer
[3] << 24);
323 if (crcval
!= (int) crc
.Value
) {
324 throw new IOException("GZIP crc sum mismatch, theirs \"" + crcval
+ "\" and ours \"" + (int) crc
.Value
);
326 int total
= (footer
[4] & 0xff) | ((footer
[5] & 0xff) << 8) | ((footer
[6] & 0xff) << 16) | (footer
[7] << 24);
327 if (total
!= inf
.TotalOut
) {
328 throw new IOException("Number of bytes mismatch");
330 /* XXX Should we support multiple members.
331 * Difficult, since there may be some bytes still baseInputStream buf