diff options
| author | John Leuner <jewel@pixie.co.za> | 2001-09-07 12:44:14 +0000 |
|---|---|---|
| committer | John Leuner <jewel@pixie.co.za> | 2001-09-07 12:44:14 +0000 |
| commit | 07283c734f54cf1ff1952da9167f2eccddb85c47 (patch) | |
| tree | b965581614a9c892d2d276240a1c59e124aec7ff /java/util/zip/GZIPInputStream.java | |
| parent | 242fb218cfca462a5955ab4a9d323fc50a268e26 (diff) | |
| download | classpath-07283c734f54cf1ff1952da9167f2eccddb85c47.tar.gz | |
including jazzlib into classpath tree
Diffstat (limited to 'java/util/zip/GZIPInputStream.java')
| -rw-r--r-- | java/util/zip/GZIPInputStream.java | 301 |
1 files changed, 301 insertions, 0 deletions
diff --git a/java/util/zip/GZIPInputStream.java b/java/util/zip/GZIPInputStream.java new file mode 100644 index 000000000..99132ea54 --- /dev/null +++ b/java/util/zip/GZIPInputStream.java @@ -0,0 +1,301 @@ +/* java.util.zip.GZIPInputStream + Copyright (C) 2001 Free Software Foundation, Inc. + +This file is part of Jazzlib. + +Jazzlib is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +Jazzlib 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +02111-1307 USA. + +As a special exception, if you link this library with other files to +produce an executable, this library does not by itself cause the +resulting executable to be covered by the GNU General Public License. +This exception does not however invalidate any other reasons why the +executable file might be covered by the GNU General Public License. */ + +package java.util.zip; + +import java.io.InputStream; +import java.io.IOException; +import java.io.EOFException; + + +/** + * This filter stream is used to decompress a "GZIP" format stream. + * The "GZIP" format is described in RFC 1952. + * + * @author John Leuner + * @since JDK 1.1 + */ + +public class GZIPInputStream extends InflaterInputStream implements GZIPConstants { + + //Variables + + /** CRC-32 value for uncompressed data + */ + + protected CRC32 crc; + + /** Indicates end of stream */ + + protected boolean eos; + + /** + * Creates a GZIPInputStream with the default buffer size + * + * + * @param in The stream to read compressed data from + * (in GZIP format) + */ + + public GZIPInputStream(InputStream in) throws IOException + { + this(in, 4096); + } + + /** + * Creates a GZIPInputStream with the specified buffer size + * + * + * @param in The stream to read compressed data from + * (in GZIP format) + * @param size Size of the buffer to use + */ + + public GZIPInputStream(InputStream in, int size) throws IOException + { + super(in, new Inflater(true), size); + crc = new CRC32(); + } + + /** + * Closes the input stream + * + */ + public void close() throws IOException + { + super.close(); + } + + /** + * Reads uncompressed data into an array of bytes + * + * + * @param buf the buffer to read uncompressed data into + * @param offset the offset indicating where the data should be placed + * @param len the number of uncompressed bytes to be read + */ + + public int read(byte[] buf, int offset, int len) throws IOException + { + // We first have to slurp in the GZIP header, then we feed all the + // rest of the data to the superclass. + // + // As we do that we continually update the CRC32. Once the data is + // finished, we check the CRC32 + // + // This means we don't need our own buffer, as everything is done + // in the superclass. + if (!readGZIPHeader) + readHeader(); + + if (eos) + return -1; + + // System.err.println("GZIPIS.read(byte[], off, len ... " + offset + " and len " + len); + //We don't have to read the header, so we just grab data from the superclass + int numRead = super.read(buf, offset, len); + if (numRead > 0) + crc.update(buf, offset, numRead); + + if (inf.finished()) + readFooter(); + return numRead; + } + + private void readHeader() throws IOException + { + /* 1. Check the two magic bytes */ + CRC32 headCRC = new CRC32(); + int magic = in.read(); + if (magic < 0) + { + eos = true; + return; + } + headCRC.update(magic); + if (magic != (GZIP_MAGIC >> 8)) + { + throw new IOException("Error in GZIP header, first byte doesn't match"); + } + + magic = in.read(); + if (magic != (GZIP_MAGIC & 0xff)) + { + throw new IOException("Error in GZIP header, second byte doesn't match"); + } + headCRC.update(magic); + + /* 2. Check the compression type (must be 8) */ + int CM = in.read(); + if (CM != 8) + { + throw new IOException("Error in GZIP header, data not in deflate format"); + } + headCRC.update(CM); + + /* 3. Check the flags */ + int flags = in.read(); + if (flags < 0) + throw new EOFException("Early EOF in GZIP header"); + headCRC.update(flags); + + /* This flag byte is divided into individual bits as follows: + + bit 0 FTEXT + bit 1 FHCRC + bit 2 FEXTRA + bit 3 FNAME + bit 4 FCOMMENT + bit 5 reserved + bit 6 reserved + bit 7 reserved + */ + + /* 3.1 Check the reserved bits are zero */ + + if ((flags & 0xd0) != 0) + { + throw new IOException("Reserved flag bits in GZIP header != 0"); + } + + /* 4.-6. Skip the modification time, extra flags, and OS type */ + for (int i=0; i< 6; i++) + { + int readByte = in.read(); + if (readByte < 0) + throw new EOFException("Early EOF in GZIP header"); + headCRC.update(readByte); + } + + /* 7. Read extra field */ + if ((flags & FEXTRA) != 0) + { + /* Skip subfield id */ + for (int i=0; i< 2; i++) + { + int readByte = in.read(); + if (readByte < 0) + throw new EOFException("Early EOF in GZIP header"); + headCRC.update(readByte); + } + if (in.read() < 0 || in.read() < 0) + throw new EOFException("Early EOF in GZIP header"); + + int len1, len2, extraLen; + len1 = in.read(); + len2 = in.read(); + if ((len1 < 0) || (len2 < 0)) + throw new EOFException("Early EOF in GZIP header"); + headCRC.update(len1); + headCRC.update(len2); + + extraLen = (len1 << 8) | len2; + for (int i = 0; i < extraLen;i++) + { + int readByte = in.read(); + if (readByte < 0) + throw new EOFException("Early EOF in GZIP header"); + headCRC.update(readByte); + } + } + + /* 8. Read file name */ + if ((flags & FNAME) != 0) + { + int readByte; + while ( (readByte = in.read()) > 0) + headCRC.update(readByte); + if (readByte < 0) + throw new EOFException("Early EOF in GZIP file name"); + headCRC.update(readByte); + } + + /* 9. Read comment */ + if ((flags & FCOMMENT) != 0) + { + int readByte; + while ( (readByte = in.read()) > 0) + headCRC.update(readByte); + + if (readByte < 0) + throw new EOFException("Early EOF in GZIP comment"); + headCRC.update(readByte); + } + + /* 10. Read header CRC */ + if ((flags & FHCRC) != 0) + { + int tempByte; + int crcval = in.read(); + if (crcval < 0) + throw new EOFException("Early EOF in GZIP header"); + + tempByte = in.read(); + if (tempByte < 0) + throw new EOFException("Early EOF in GZIP header"); + + crcval = (crcval << 8) | tempByte; + if (crcval != ((int) headCRC.getValue() & 0xffff)) + throw new IOException("Header CRC value mismatch"); + } + + readGZIPHeader = true; + //System.err.println("Read GZIP header"); + } + + private void readFooter() throws IOException + { + byte[] footer = new byte[8]; + int avail = inf.getRemaining(); + if (avail > 8) + avail = 8; + System.arraycopy(buf, len - inf.getRemaining(), footer, 0, avail); + int needed = 8 - avail; + while (needed > 0) + { + int count = in.read(footer, 8-needed, needed); + if (count <= 0) + throw new EOFException("Early EOF in GZIP footer"); + needed -= count; //Jewel Jan 16 + } + int crcval = (footer[0] & 0xff) | ((footer[1] & 0xff) << 8) + | ((footer[2] & 0xff) << 16) | (footer[3] << 24); + if (crcval != (int) crc.getValue()) + throw new IOException("GZIP crc sum mismatch, theirs \"" + Integer.toHexString(crcval) + "\" and ours \"" + Integer.toHexString( (int) crc.getValue())); + int total = (footer[4] & 0xff) | ((footer[5] & 0xff) << 8) + | ((footer[6] & 0xff) << 16) | (footer[7] << 24); + if (total != inf.getTotalOut()) + throw new IOException("Number of bytes mismatch"); + /* XXX Should we support multiple members. + * Difficult, since there may be some bytes still in buf + */ + eos = true; + } + + + /* Have we read the GZIP header yet? */ + private boolean readGZIPHeader; +} |
