diff options
Diffstat (limited to 'src/share/classes/java/util/zip/GZIPInputStream.java')
-rw-r--r-- | src/share/classes/java/util/zip/GZIPInputStream.java | 87 |
1 files changed, 63 insertions, 24 deletions
diff --git a/src/share/classes/java/util/zip/GZIPInputStream.java b/src/share/classes/java/util/zip/GZIPInputStream.java index 1140c38b3..8d60d1996 100644 --- a/src/share/classes/java/util/zip/GZIPInputStream.java +++ b/src/share/classes/java/util/zip/GZIPInputStream.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2010, 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 @@ -66,19 +66,24 @@ class GZIPInputStream extends InflaterInputStream { * Creates a new input stream with the specified buffer size. * @param in the input stream * @param size the input buffer size + * + * @exception ZipException if a GZIP format error has occurred or the + * compression method used is unsupported * @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(); + readHeader(in); } /** * Creates a new input stream with a default buffer size. * @param in the input stream + * + * @exception ZipException if a GZIP format error has occurred or the + * compression method used is unsupported * @exception IOException if an I/O error has occurred */ public GZIPInputStream(InputStream in) throws IOException { @@ -94,26 +99,30 @@ class GZIPInputStream extends InflaterInputStream { * @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 + * @exception ZipException if the compressed input data is corrupt. + * @exception IOException if an I/O error has occurred. + * */ 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; + int n = super.read(buf, off, len); + if (n == -1) { + if (readTrailer()) + eos = true; + else + return this.read(buf, off, len); } else { - crc.update(buf, off, len); + crc.update(buf, off, n); } - return len; + return n; } /** @@ -144,48 +153,61 @@ class GZIPInputStream extends InflaterInputStream { private final static int FCOMMENT = 16; // File comment /* - * Reads GZIP member header. + * Reads GZIP member header and returns the total byte number + * of this member header. */ - private void readHeader() throws IOException { - CheckedInputStream in = new CheckedInputStream(this.in, crc); + private int readHeader(InputStream this_in) 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"); + throw new ZipException("Not in GZIP format"); } // Check compression method if (readUByte(in) != 8) { - throw new IOException("Unsupported compression method"); + throw new ZipException("Unsupported compression method"); } // Read flags int flg = readUByte(in); // Skip MTIME, XFL, and OS fields skipBytes(in, 6); + int n = 2 + 2 + 6; // Skip optional extra field if ((flg & FEXTRA) == FEXTRA) { - skipBytes(in, readUShort(in)); + int m = readUShort(in); + skipBytes(in, m); + n += m + 2; } // Skip optional file name if ((flg & FNAME) == FNAME) { - while (readUByte(in) != 0) ; + do { + n++; + } while (readUByte(in) != 0); } // Skip optional file comment if ((flg & FCOMMENT) == FCOMMENT) { - while (readUByte(in) != 0) ; + do { + n++; + } 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"); + throw new ZipException("Corrupt GZIP header"); } + n += 2; } + crc.reset(); + return n; } /* - * Reads GZIP member trailer. + * Reads GZIP member trailer and returns true if the eos + * reached, false if there are more (concatenated gzip + * data set) */ - private void readTrailer() throws IOException { + private boolean readTrailer() throws IOException { InputStream in = this.in; int n = inf.getRemaining(); if (n > 0) { @@ -196,7 +218,25 @@ class GZIPInputStream extends InflaterInputStream { 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"); + throw new ZipException("Corrupt GZIP trailer"); + + // If there are more bytes available in "in" or + // the leftover in the "inf" is > 26 bytes: + // this.trailer(8) + next.header.min(10) + next.trailer(8) + // try concatenated case + if (this.in.available() > 0 || n > 26) { + int m = 8; // this.trailer + try { + m += readHeader(in); // next.header + } catch (IOException ze) { + return true; // ignore any malformed, do nothing + } + inf.reset(); + if (n > m) + inf.setInput(buf, len - n + m, n - m); + return false; + } + return true; } /* @@ -231,7 +271,6 @@ class GZIPInputStream extends InflaterInputStream { return b; } - private byte[] tmpbuf = new byte[128]; /* |