Frames | No Frames |
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., 51 Franklin Street, Fifth Floor, Boston, MA 19: 02110-1301 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: }