OSDN Git Service

PR libgcj/14446:
[pf3gnuchains/gcc-fork.git] / libjava / java / util / zip / GZIPInputStream.java
1 /* GZIPInputStream.java - Input filter for reading gzip file
2    Copyright (C) 1999, 2000, 2001, 2002, 2004 Free Software Foundation, Inc.
3
4 This file is part of GNU Classpath.
5
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10  
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING.  If not, write to the
18 Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19 02111-1307 USA.
20
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
24 combination.
25
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. */
37
38 package java.util.zip;
39
40 import java.io.InputStream;
41 import java.io.IOException;
42
43 /**
44  * This filter stream is used to decompress a "GZIP" format stream. 
45  * The "GZIP" format is described in RFC 1952.
46  *
47  * @author John Leuner
48  * @author Tom Tromey
49  * @since JDK 1.1
50  */
51 public class GZIPInputStream
52   extends InflaterInputStream
53 {
54   /**
55    * The magic number found at the start of a GZIP stream.
56    */
57   public static final int GZIP_MAGIC = 0x8b1f;
58
59   static final int Z_DEFLATED = 8;
60
61   /**
62    * The mask for bit 1 of the flag byte.
63    */
64   static final int HEAD_CRC = 0x02;
65
66   /**
67    * The mask for bit 2 of the flag byte.
68    */
69   static final int EXTRA_FIELD = 0x04;
70
71   /**
72    * The mask for bit 3 of the flag byte.
73    */
74   static final int ORIG_NAME = 0x08;
75
76   /**
77    * The mask for bit 4 of the flag byte.
78    */
79   static final int COMMENT = 0x10;
80
81   /**
82    * The mask for all reserved bits of the flag byte.
83    */
84   static final int RESERVED = 0xe0;
85   
86   /**
87    * The CRC-32 checksum value for uncompressed data.
88    */
89   protected CRC32 crc; 
90
91   /**
92    * Indicates whether or not the end of the stream has been reached.
93    */  
94   protected boolean eos;
95
96   /**
97    * Creates a GZIPInputStream with the default buffer size.
98    *
99    * @param in The stream to read compressed data from 
100    *           (in GZIP format).
101    *
102    * @throws IOException if an error occurs during an I/O operation.
103    */
104   public GZIPInputStream(InputStream in)
105     throws IOException
106   {
107     this(in, 4096);
108   }
109
110   /**
111    * Creates a GZIPInputStream with the specified buffer size.
112    *
113    * @param in The stream to read compressed data from 
114    *           (in GZIP format).
115    * @param size The size of the buffer to use.
116    *
117    * @throws IOException if an error occurs during an I/O operation.
118    * @throws IllegalArgumentException if <code>size</code>
119    * is less than or equal to 0.
120    */
121   public GZIPInputStream(InputStream in, int size)
122     throws IOException
123   {
124     super(in, new Inflater(true), size);
125
126     // NOTE: header reading code taken from zlib's gzio.c.
127
128     // Read the magic number.
129     int magic = eof_read() | (eof_read() << 8);
130     if (magic != GZIP_MAGIC)
131       throw new ZipException("gzip header corrupted");
132
133     int method = eof_read();
134     int flags = eof_read();
135     // Test from zlib.
136     if (method != Z_DEFLATED || (flags & RESERVED) != 0)
137       throw new ZipException("gzip header corrupted");
138
139     // Discard time, xflags, OS code.
140     for (int i = 0; i < 6; ++i)
141       eof_read();
142
143     // Skip the extra field.
144     if ((flags & EXTRA_FIELD) != 0)
145       {
146         int len = eof_read() | (eof_read() << 8);
147         while (len-- != 0)
148           eof_read();
149       }
150
151     if ((flags & ORIG_NAME) != 0)
152       {
153         while (true)
154           {
155             int c = eof_read();
156             if (c == 0)
157               break;
158           }
159       }
160
161     if ((flags & COMMENT) != 0)
162       {
163         while (true)
164           {
165             int c = eof_read();
166             if (c == 0)
167               break;
168           }
169       }
170
171     if ((flags & HEAD_CRC) != 0)
172       {
173         // FIXME: consider checking CRC of the header.
174         eof_read();
175         eof_read();
176       }
177
178     crc = new CRC32();
179   }
180
181   /**
182    * Closes the input stream.
183    *
184    * @throws IOException if an error occurs during an I/O operation.
185    */
186   public void close()
187     throws IOException
188   {
189     // Nothing to do here.
190     super.close();
191   }
192
193   private final int eof_read() throws IOException
194   {
195     int r = in.read();
196     if (r == -1)
197       throw new ZipException("gzip header corrupted");
198     return r & 0xff;
199   }
200
201   /**
202    * Reads in GZIP-compressed data and stores it in uncompressed form
203    * into an array of bytes.  The method will block until either
204    * enough input data becomes available or the compressed stream
205    * reaches its end.
206    *
207    * @param buf the buffer into which the uncompressed data will
208    *            be stored.
209    * @param offset the offset indicating where in <code>buf</code>
210    *               the uncompressed data should be placed.
211    * @param len the number of uncompressed bytes to be read.
212    */
213   public int read(byte[] buf, int offset, int len) throws IOException
214   {
215     if (eos)
216       return -1;
217     int r = super.read(buf, offset, len);
218     if (r == -1)
219       {
220         eos = true;
221
222         byte[] tmp = new byte[8];
223         // First copy remaining bytes from inflater input buffer.
224         int avail = inf.getRemaining();
225         System.arraycopy(this.buf, this.len - avail, tmp, 0, avail);
226
227         // Now read remaining bytes from wrapped input stream.
228         for (int i = avail; i < 8; ++i)
229           {
230             tmp[i] = (byte) eof_read();
231           }
232
233         // Be careful to avoid sign extension here; CRC32.getValue()
234         // returns a long.
235         long header_crc = read4(tmp, 0) & 0xffffffffL;
236         if (crc.getValue() != header_crc)
237           throw new ZipException("corrupted gzip file - crc mismatch");
238         int isize = read4(tmp, 4);
239         if (inf.getTotalOut() != isize)
240           throw new ZipException("corrupted gzip file - size mismatch");
241         return -1;
242       }
243     crc.update(buf, offset, r);
244     return r;
245   }
246
247   private final int read4(byte[] buf, int offset) throws IOException
248   {
249     return (((buf[offset + 3] & 0xFF) << 24) + ((buf[offset + 2] & 0xFF) << 16)
250             + ((buf[offset + 1] & 0xFF) << 8) + (buf[offset] & 0xFF));
251   }
252 }