JDK-4109069 : java.util.zip.InflaterInputStream available() and read(byte[]) are broken
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.util
  • Affected Version: 1.2.0
  • Priority: P4
  • Status: Closed
  • Resolution: Fixed
  • OS: generic,solaris_2.5.1,windows_95
  • CPU: generic,x86,sparc
  • Submitted: 1998-02-03
  • Updated: 1999-01-15
  • Resolved: 1999-01-15
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
Other
1.2.0 1.2fcsFixed
Related Reports
Duplicate :  
Relates :  
Relates :  
Description

Name: rm29839			Date: 02/03/98


/*
java.util.zip.InflaterInputStream.available() 
doesn't return the correct number of bytes.
Also, java.util.zip.InflaterInputStream.read(byte[])
doesn't correctly read the file even if passed the
correct number of bytes.

The the test code to work, swing.jar and JFrame.class
must both be in the directory from which you run the 
code.
*/

import java.io.*;
import java.util.zip.*;

class JarInput {
   static final String JAR_FILE = "swing.jar";
   static final String CLASS_FILE = "com/sun/java/swing/JFrame.class";
   static final String DOS_FILE = "JFrame.class";
   static final String DEBUG_FILE = "debug.txt";
   static PrintWriter debugWriter;

   public static void main(String[] args) {
      try {
         ZipFile zipFile = new ZipFile(JAR_FILE);
         ZipEntry zipEntry = zipFile.getEntry(CLASS_FILE);
         int realFileSize;

         //Get InputStream from a class file...
         FileInputStream fis = new FileInputStream(DOS_FILE);
         //Print the size reported by available() and dump FileInputStream
         realFileSize = fis.available();
         print("From class file => " + fis + " available=" + realFileSize);
         print("Printing the FileInputStream from class file");
         print(fis);

         //Get InputStream from jar file...
         InputStream is = zipFile.getInputStream(zipEntry);
         int wrongFileSize = is.available();
         byte[] buff = new byte[realFileSize]; //Don't rely on InflaterInputStream.available()
         is.read(buff);
         ByteArrayInputStream bis = new ByteArrayInputStream(buff);
         //Print the size reported by available() and dump ByteArrayInputStream
         print("From Jar => " + is + " available=" + wrongFileSize);
         print("Printing the ByteArrayInputStream from jar file");
         print(bis);
      }
      catch(IOException ex) {
        System.out.println(ex);
      }
   }

   static final void print(InputStream is)
      throws IOException
   {
      int aByte;
      StringBuffer strBuf = new StringBuffer();
      int colPos = 0;
      int colMax = 16;
      while((aByte = is.read()) != -1) {
         strBuf.append(" " + int2Hex(aByte));
         colPos++;
         if (colPos == 8) {
            strBuf.append(" ");
         }
         else if(colPos == colMax) {
            strBuf.append("\n");
            colPos = 0;
         }
      }
      print(strBuf.toString());
   }

   static String int2Hex(int i) {
      int j = i / 16;
      int k = i % 16;
      return digit2Hex(j) + digit2Hex(k);
   }

   static String digit2Hex(int i) {
      switch(i) {
         case 0 : return "0";
         case 1 : return "1";
         case 2 : return "2";
         case 3 : return "3";
         case 4 : return "4";
         case 5 : return "5";
         case 6 : return "6";
         case 7 : return "7";
         case 8 : return "8";
         case 9 : return "9";
         case 10 : return "A";
         case 11 : return "B";
         case 12 : return "C";
         case 13 : return "D";
         case 14 : return "E";
         case 15 : return "F";
         default:
               throw new RuntimeException(i + " can't be translated to a hex digit");
      }
   }

   static {
     try {
        debugWriter = new PrintWriter(new FileOutputStream(DEBUG_FILE), true);
     }
     catch(IOException e) {
        System.err.println(DEBUG_FILE + " : " + e);
        System.exit(1);
        debugWriter = new PrintWriter(System.err, true);
     }
   }

   static final void print(String string) {
      debugWriter.println(string);
   }
}
(Review ID: 24345)
======================================================================

Comments
CONVERTED DATA BugTraq+ Release Management Values COMMIT TO FIX: generic FIXED IN: 1.2fcs INTEGRATED IN: 1.2fcs
14-06-2004

WORK AROUND Name: rm29839 Date: 02/03/98 Read the InflaterInputStream one byte at a time. ======================================================================
11-06-2004

EVALUATION Programs should never expect read to read all the available bytes from the underlying stream. According to JLS 22.3.2,f or read(b), "the number of bytes read is, at most, equal to the length of b", so the right way to do is to check the return value of read to see how much data was actually read. In general, an InflaterInputStream available is not able to return the exact number of bytes that are available from the compressed file. With the fix to bug 4028605, ZipInputStream and InflaterInputStream available will always return 1 before EOF and 0 otherwise. So available can be used to see whether EOF has reached of not, and the return value of read() needs to be checked. ###@###.### 1998-07-21
21-07-1998