src/share/classes/java/util/zip/GZIPInputStream.java

Print this page

        

@@ -1,7 +1,7 @@
 /*
- * Copyright 1996-2006 Sun Microsystems, Inc.  All Rights Reserved.
+ * Copyright 1996-2010 Sun Microsystems, Inc.  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.  Sun designates this

@@ -73,12 +73,11 @@
      * @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

@@ -112,18 +111,20 @@
     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();
+        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;
     }
 
     /**
      * Closes this input stream and releases any system resources associated
      * with the stream.

@@ -150,14 +151,15 @@
     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.
+     * 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 ZipException("Not in GZIP format");
         }

@@ -167,35 +169,47 @@
         }
         // 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 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) {
             in = new SequenceInputStream(
                         new ByteArrayInputStream(buf, len - n, n), in);

@@ -203,11 +217,29 @@
         // 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 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;
+    }
 
     /*
      * Reads unsigned integer in Intel byte order.
      */
     private long readUInt(InputStream in) throws IOException {

@@ -237,11 +269,10 @@
                 + ".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.