KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > caucho > quercus > lib > zlib > GZInputStream


1 /*
2  * Copyright (c) 1998-2006 Caucho Technology -- all rights reserved
3  *
4  * This file is part of Resin(R) Open Source
5  *
6  * Each copy or derived work must preserve the copyright notice and this
7  * notice unmodified.
8  *
9  * Resin Open Source is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * Resin Open Source is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
17  * of NON-INFRINGEMENT. See the GNU General Public License for more
18  * details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with Resin Open Source; if not, write to the
22  *
23  * Free Software Foundation, Inc.
24  * 59 Temple Place, Suite 330
25  * Boston, MA 02111-1307 USA
26  *
27  * @author Nam Nguyen
28  */

29
30 package com.caucho.quercus.lib.zlib;
31
32 import java.io.IOException JavaDoc;
33 import java.io.InputStream JavaDoc;
34 import java.io.PushbackInputStream JavaDoc;
35 import java.util.zip.CRC32 JavaDoc;
36 import java.util.zip.DataFormatException JavaDoc;
37 import java.util.zip.Inflater JavaDoc;
38
39 /**
40  * Similar to GZIPInputStream but with ability to read appended gzip.
41  */

42 public class GZInputStream extends InputStream JavaDoc
43 {
44   private PushbackInputStream JavaDoc _in;
45   private Inflater JavaDoc _inflater;
46
47   private CRC32 JavaDoc _crc;
48   private boolean _eof;
49   private boolean _isGzip;
50
51   private byte[] _readBuffer; //raw input data buffer
52
private byte[] _tbuffer; //temporary buffer
53

54   private int _readBufferSize; //amount of raw data read into _readBuffer
55
private int _inputSize; //decompressed bytes read so far
56
// for the current 'append' stream
57

58   private long _totalInputSize; //total decompressed bytes read
59

60   public GZInputStream(InputStream JavaDoc in)
61     throws IOException JavaDoc
62   {
63     this(in, 512);
64   }
65
66   public GZInputStream(InputStream JavaDoc in, int size)
67     throws IOException JavaDoc
68   {
69     // Need to use same buffer size for pushback and _readBuffer
70
// because will need to unread <= _readBuffer.length.
71
_in = new PushbackInputStream JavaDoc(in, size);
72
73     _inflater = new Inflater JavaDoc(true);
74     _crc = new CRC32 JavaDoc();
75     _eof = false;
76
77     _readBuffer = new byte[size];
78     _tbuffer = new byte[128];
79
80     _totalInputSize = 0;
81
82     init();
83   }
84
85   /**
86    * Returns 0 if gzip EOF has been reached, 1 otherwise
87    */

88   public int available()
89     throws IOException JavaDoc
90   {
91     if (!_isGzip)
92       return _in.available();
93
94     if (_eof == true)
95       return 0;
96     return 1;
97   }
98
99   public void close()
100     throws IOException JavaDoc
101   {
102     _inflater.end();
103   }
104
105   /**
106    * mark() and reset() are not supported by this class.
107    * @return false always
108    */

109   public boolean markSupported()
110   {
111     return false;
112   }
113
114   /**
115    * Returns the byte read, -1 if EOF
116    * @return number of bytes read, or -1 if EOF
117    */

118   public int read() throws IOException JavaDoc
119   {
120     byte[] b = new byte[1];
121     int n = read(b);
122     if (n < 0)
123       return -1;
124     return b[0];
125   }
126
127   /**
128    * Reads from the compressed stream and
129    * stores the resulting uncompressed data into the byte array.
130    * @return number of bytes read, or -1 upon EOF
131    */

132   public int read(byte[] b)
133     throws IOException JavaDoc
134   {
135     return read(b, 0, b.length);
136   }
137
138   /**
139    * Reads from the compressed stream and
140    * stores the resulting uncompressed data into the byte array.
141    * @return number of bytes read, or -1 upon EOF
142    */

143   public int read(byte[] b, int off, int len)
144     throws IOException JavaDoc
145   {
146     if (len <= 0 || off < 0 || off + len > b.length)
147       return 0;
148
149     if (_eof)
150       return -1;
151
152     // Read from uncompressed stream
153
if (! _isGzip)
154       return _in.read(b, off, len);
155
156     try {
157       int sublen;
158       int length = 0;
159       while(length < len) {
160         if (_inflater.needsInput()) {
161           _readBufferSize = _in.read(_readBuffer, 0, _readBuffer.length);
162           if (_readBufferSize < 0)
163             break;
164
165           _inflater.setInput(_readBuffer, 0, _readBufferSize);
166         }
167
168        sublen = _inflater.inflate(b, off + length, len - length);
169         _crc.update(b, off + length, sublen);
170        _inputSize += sublen;
171        _totalInputSize += sublen;
172        length += sublen;
173
174         // Unread gzip trailer and possibly beginning of appended gzip data.
175
if (_inflater.finished()) {
176           int remaining = _inflater.getRemaining();
177           _in.unread(_readBuffer, _readBufferSize - remaining, remaining);
178           readTrailer();
179           break;
180         }
181       }
182
183       return length;
184     }
185     catch (DataFormatException JavaDoc e) {
186       throw new IOException JavaDoc(e.getMessage());
187     }
188   }
189
190   /**
191    * Skips over and discards n bytes.
192    * @param n number of bytes to skip
193    * @return actual number of bytes skipped
194    */

195   public long skip(long n)
196     throws IOException JavaDoc
197   {
198     if (_eof || n <= 0)
199       return 0;
200     
201     long remaining = n;
202     while (remaining > 0) {
203       int length = (int)Math.min(_tbuffer.length, remaining);
204       int sublen = read(_tbuffer, 0, length);
205       if (sublen < 0)
206         break;
207       remaining -= sublen;
208     }
209     return (n - remaining);
210   }
211
212   /**
213    * Inits/resets this class to be ready to read the start of a gzip stream.
214    */

215   private void init()
216     throws IOException JavaDoc
217   {
218     _inflater.reset();
219     _crc.reset();
220     _inputSize = 0;
221     _readBufferSize = 0;
222
223     byte flg;
224
225     int length = _in.read(_tbuffer, 0, 10);
226     if (length != 10) {
227       _isGzip = false;
228       _in.unread(_tbuffer, 0, length);
229       return;
230     }
231     if (_tbuffer[0] != (byte)0x1f || _tbuffer[1] != (byte)0x8b) {
232       _isGzip = false;
233       _in.unread(_tbuffer, 0, length);
234       return;
235     }
236
237     flg = _tbuffer[3];
238
239     // Skip optional field
240
if ((flg & (byte)0x04) > 0) {
241       length = _in.read(_tbuffer, 0, 2);
242       if (length != 2)
243         throw new IOException JavaDoc("Bad GZIP (FEXTRA) header.");
244       length = (((int)_tbuffer[1]) << 4) | _tbuffer[0];
245       _in.skip(length);
246     }
247
248     int c;
249
250     // Skip optional field
251
if ((flg & (byte)0x08) > 0) {
252       c = _in.read();
253       while (c != 0) {
254         if (c < 0)
255           throw new IOException JavaDoc("Bad GZIP (FNAME) header.");
256         c = _in.read();
257       }
258     }
259
260     // Skip optional field
261
if ((flg & 0x10) > 0) {
262       c = _in.read();
263       while (c != 0) {
264         if (c < 0)
265           throw new IOException JavaDoc("Bad GZIP (FCOMMENT) header.");
266         c = _in.read();
267       }
268     }
269
270     // Skip optional field
271
if ((flg & 0x02) > 0) {
272       length = _in.read(_tbuffer, 0, 2);
273       if (length != 2)
274         throw new IOException JavaDoc("Bad GZIP (FHCRC) header.");
275     }
276
277     _isGzip = true;
278   }
279
280   /**
281    * Reads the trailer and prepare this class for the possibility
282    * of an appended gzip stream.
283    */

284   private void readTrailer()
285     throws IOException JavaDoc
286   {
287     int length = _in.read(_tbuffer, 0, 8);
288     if (length != 8)
289       throw new IOException JavaDoc("Bad GZIP trailer.");
290
291     int refValue = _tbuffer[3] & 0xff;
292     refValue <<= 8;
293     refValue |= _tbuffer[2] & 0xff;
294     refValue <<= 8;
295     refValue |= _tbuffer[1] & 0xff;
296     refValue <<= 8;
297     refValue |= _tbuffer[0] & 0xff;
298
299     int value = (int)_crc.getValue();
300
301     if (refValue != value)
302       throw new IOException JavaDoc("Bad GZIP trailer (CRC32).");
303
304     refValue = _tbuffer[7] & 0xff;
305     refValue <<= 8;
306     refValue |= _tbuffer[6] & 0xff;
307     refValue <<= 8;
308     refValue |= _tbuffer[5] & 0xff;
309     refValue <<= 8;
310     refValue |= _tbuffer[4] & 0xff;
311
312     if (refValue != _inputSize)
313       throw new IOException JavaDoc("Bad GZIP trailer (LENGTH).");
314
315     // Check to see if this gzip stream is appended with a valid gzip stream.
316
// If it is appended, then can continue reading from stream.
317
int c = _in.read();
318     if (c < 0)
319       _eof = true;
320     else {
321       _in.unread(c);
322       init();
323       if (!_isGzip)
324         _eof = true;
325     }
326   }
327
328   /*
329    * Returns true if stream is in gzip format.
330    */

331   public boolean isGzip()
332   {
333     return _isGzip;
334   }
335 }
336
Popular Tags