/*
 * Copyright (c) 1996, 2006, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

package java.util.zip;

import java.io.SequenceInputStream;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.IOException;
import java.io.EOFException;

This class implements a stream filter for reading compressed data in the GZIP file format.
Author: David Connelly
See Also:
  • InflaterInputStream
/** * This class implements a stream filter for reading compressed data in * the GZIP file format. * * @see InflaterInputStream * @author David Connelly * */
public class GZIPInputStream extends InflaterInputStream {
CRC-32 for uncompressed data.
/** * CRC-32 for uncompressed data. */
protected CRC32 crc = new CRC32();
Indicates end of input stream.
/** * Indicates end of input stream. */
protected boolean eos; private boolean closed = false;
Check to make sure that this stream has not been closed
/** * Check to make sure that this stream has not been closed */
private void ensureOpen() throws IOException { if (closed) { throw new IOException("Stream closed"); } }
Creates a new input stream with the specified buffer size.
Params:
  • in – the input stream
  • size – the input buffer size
Throws:
/** * Creates a new input stream with the specified buffer size. * @param in the input stream * @param size the input buffer size * @exception IOException if an I/O error has occurred * @exception IllegalArgumentException if size is <= 0 */
public GZIPInputStream(InputStream in, int size) throws IOException { super(in, new Inflater(true), size); usesDefaultInflater = true; readHeader(); crc.reset(); }
Creates a new input stream with a default buffer size.
Params:
  • in – the input stream
Throws:
/** * Creates a new input stream with a default buffer size. * @param in the input stream * @exception IOException if an I/O error has occurred */
public GZIPInputStream(InputStream in) throws IOException { this(in, 512); }
Reads uncompressed data into an array of bytes. If len is not zero, the method will block until some input can be decompressed; otherwise, no bytes are read and 0 is returned.
Params:
  • buf – the buffer into which the data is read
  • off – the start offset in the destination array b
  • len – the maximum number of bytes read
Throws:
Returns: the actual number of bytes read, or -1 if the end of the compressed input stream is reached
/** * Reads uncompressed data into an array of bytes. If <code>len</code> is not * zero, the method will block until some input can be decompressed; otherwise, * no bytes are read and <code>0</code> is returned. * @param buf the buffer into which the data is read * @param off the start offset in the destination array <code>b</code> * @param len the maximum number of bytes read * @return the actual number of bytes read, or -1 if the end of the * compressed input stream is reached * @exception NullPointerException If <code>buf</code> is <code>null</code>. * @exception IndexOutOfBoundsException If <code>off</code> is negative, * <code>len</code> is negative, or <code>len</code> is greater than * <code>buf.length - off</code> * @exception IOException if an I/O error has occurred or the compressed * input data is corrupt */
public int read(byte[] buf, int off, int len) throws IOException { ensureOpen(); if (eos) { return -1; } len = super.read(buf, off, len); if (len == -1) { readTrailer(); eos = true; } else { crc.update(buf, off, len); } return len; }
Closes this input stream and releases any system resources associated with the stream.
Throws:
  • IOException – if an I/O error has occurred
/** * Closes this input stream and releases any system resources associated * with the stream. * @exception IOException if an I/O error has occurred */
public void close() throws IOException { if (!closed) { super.close(); eos = true; closed = true; } }
GZIP header magic number.
/** * GZIP header magic number. */
public final static int GZIP_MAGIC = 0x8b1f; /* * File header flags. */ private final static int FTEXT = 1; // Extra text private final static int FHCRC = 2; // Header CRC private final static int FEXTRA = 4; // Extra field private final static int FNAME = 8; // File name private final static int FCOMMENT = 16; // File comment /* * Reads GZIP member header. */ private void readHeader() throws IOException { CheckedInputStream in = new CheckedInputStream(this.in, crc); crc.reset(); // Check header magic if (readUShort(in) != GZIP_MAGIC) { throw new IOException("Not in GZIP format"); } // Check compression method if (readUByte(in) != 8) { throw new IOException("Unsupported compression method"); } // Read flags int flg = readUByte(in); // Skip MTIME, XFL, and OS fields skipBytes(in, 6); // Skip optional extra field if ((flg & FEXTRA) == FEXTRA) { skipBytes(in, readUShort(in)); } // Skip optional file name if ((flg & FNAME) == FNAME) { while (readUByte(in) != 0) ; } // Skip optional file comment if ((flg & FCOMMENT) == FCOMMENT) { while (readUByte(in) != 0) ; } // Check optional header CRC if ((flg & FHCRC) == FHCRC) { int v = (int)crc.getValue() & 0xffff; if (readUShort(in) != v) { throw new IOException("Corrupt GZIP header"); } } } /* * Reads GZIP member trailer. */ private void readTrailer() throws IOException { InputStream in = this.in; int n = inf.getRemaining(); if (n > 0) { in = new SequenceInputStream( new ByteArrayInputStream(buf, len - n, n), in); } // Uses left-to-right evaluation order if ((readUInt(in) != crc.getValue()) || // rfc1952; ISIZE is the input size modulo 2^32 (readUInt(in) != (inf.getBytesWritten() & 0xffffffffL))) throw new IOException("Corrupt GZIP trailer"); } /* * Reads unsigned integer in Intel byte order. */ private long readUInt(InputStream in) throws IOException { long s = readUShort(in); return ((long)readUShort(in) << 16) | s; } /* * Reads unsigned short in Intel byte order. */ private int readUShort(InputStream in) throws IOException { int b = readUByte(in); return ((int)readUByte(in) << 8) | b; } /* * Reads unsigned byte. */ private int readUByte(InputStream in) throws IOException { int b = in.read(); if (b == -1) { throw new EOFException(); } if (b < -1 || b > 255) { // Report on this.in, not argument in; see read{Header, Trailer}. throw new IOException(this.in.getClass().getName() + ".read() returned value out of range -1..255: " + b); } return b; } private byte[] tmpbuf = new byte[128]; /* * Skips bytes of input data blocking until all bytes are skipped. * Does not assume that the input stream is capable of seeking. */ private void skipBytes(InputStream in, int n) throws IOException { while (n > 0) { int len = in.read(tmpbuf, 0, n < tmpbuf.length ? n : tmpbuf.length); if (len == -1) { throw new EOFException(); } n -= len; } } }