This is the mail archive of the java-patches@gcc.gnu.org mailing list for the Java project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[4.1] Patch: FYI: fix PR libgcj/27271


I'm checking this in on the 4.1 branch.
I have a different patch for the trunk (and classpath) which I will
submit shortly.

This fixes PR 27271.  My patch for PR 24461 revealed a latent bug
which affects some programs, notably RSSOwl.  The problem is that
Inflater requires an extra dummy byte when created with the "no
header" flag.  This patch arranges to pass in this byte when reading
from a zip file.

I looked at other creations of Inflater and, apparently, this
treatment is not required there.  (Meaning, I could not write a
failing test case for those cases.)

I think this is an interesting example of how an API mistake (the
extra byte oddity originates in zlib) can propagate outward, making
more and more things uglier and harder to maintain.

Tom

Index: classpath/ChangeLog.gcj
from  Tom Tromey  <tromey@redhat.com>

	* java/util/zip/ZipFile.java (getInputStream): Call addDummyByte
	on PartialInputStream.
	(PartialInputStream.addDummyByte): New field.
	(PartialInputStream.singleByte): Likewise.
	(PartialInputStream): Initialize new fields.
	(PartialInputStream.read()): Rewrote.
	(PartialInputStream.read(byte[],int,int)): Handle dummy byte, if
	added.
	(PartialInputStream.addDummyByte): New method.

Index: classpath/java/util/zip/ZipFile.java
===================================================================
--- classpath/java/util/zip/ZipFile.java	(revision 115034)
+++ classpath/java/util/zip/ZipFile.java	(working copy)
@@ -497,13 +497,15 @@
 
     long start = checkLocalHeader(zipEntry);
     int method = zipEntry.getMethod();
-    InputStream is = new BufferedInputStream(new PartialInputStream
-      (raf, start, zipEntry.getCompressedSize()));
+    PartialInputStream pIn
+      = new PartialInputStream(raf, start, zipEntry.getCompressedSize());
+    InputStream is = new BufferedInputStream(pIn);
     switch (method)
       {
       case ZipOutputStream.STORED:
 	return is;
       case ZipOutputStream.DEFLATED:
+	pIn.addDummyByte();
 	return new InflaterInputStream(is, new Inflater(true));
       default:
 	throw new ZipException("Unknown compression method " + method);
@@ -564,12 +566,16 @@
   {
     private final RandomAccessFile raf;
     long filepos, end;
+    boolean addDummyByte;
+    byte[] singleByte;
 
     public PartialInputStream(RandomAccessFile raf, long start, long len)
     {
       this.raf = raf;
       filepos = start;
       end = start + len;
+      addDummyByte = false;
+      singleByte = new byte[1];
     }
     
     public int available()
@@ -579,20 +585,27 @@
 	return Integer.MAX_VALUE;
       return (int) amount;
     }
-    
+
     public int read() throws IOException
     {
-      if (filepos == end)
-	return -1;
-      synchronized (raf)
-	{
-	  raf.seek(filepos++);
-	  return raf.read();
-	}
+      int r = read(singleByte, 0, 1);
+      if (r != 1)
+	return r;
+      return singleByte[0] & 0xff;
     }
 
     public int read(byte[] b, int off, int len) throws IOException
     {
+      if (end - filepos == 0)
+	{
+	  if (len > 0 && addDummyByte)
+	    {
+	      addDummyByte = false;
+	      b[0] = 0;
+	      return 1;
+	    }
+	}
+
       if (len > end - filepos)
 	{
 	  len = (int) (end - filepos);
@@ -618,5 +631,10 @@
       filepos += amount;
       return amount;
     }
+
+    public void addDummyByte()
+    {
+      addDummyByte = true;
+    }
   }
 }


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]