Hi,

I completed ImageInputStreamImpl and MemoryCacheImageInputStream. Though all but one of the methods had implementations, they were very buggy. I've committed a new test case to Mauve to ensure that these classes are now correct. This patch brings the pure Java JPEG decoder closer to a working state.

Tom

2006-05-18  Thomas Fitzsimmons  <[EMAIL PROTECTED]>

        * javax/imageio/stream/ImageInputStreamImpl.java: Complete.
        * javax/imageio/stream/MemoryCacheImageInputStream.java: Likewise.
Index: javax/imageio/stream/ImageInputStreamImpl.java
===================================================================
RCS file: /sources/classpath/classpath/javax/imageio/stream/ImageInputStreamImpl.java,v
retrieving revision 1.6
diff -u -r1.6 ImageInputStreamImpl.java
--- javax/imageio/stream/ImageInputStreamImpl.java	25 Mar 2006 00:15:10 -0000	1.6
+++ javax/imageio/stream/ImageInputStreamImpl.java	19 May 2006 03:59:53 -0000
@@ -81,7 +81,8 @@
   protected void finalize()
     throws Throwable
   {
-    close();
+    if (!closed)
+      close();
   }
 
   public void flush()
@@ -154,38 +155,43 @@
       }
     catch (IOException e)
       {
-	// Ignored.
+        throw new RuntimeException(e);
       }
   }
 
   public abstract int read()
     throws IOException;
 
+  public abstract int read(byte[] data, int offset, int len)
+    throws IOException;
+
   public int read(byte[] data)
     throws IOException
   {
     return read(data, 0, data.length);
   }
 
-  public abstract int read(byte[] data, int offset, int len)
-    throws IOException;
-
   public int readBit()
     throws IOException
   {
     checkClosed();
 
-    // Calc new bit offset here, readByte resets it.
+    // Calculate new bit offset here as readByte clears it.
     int newOffset = (bitOffset + 1) & 0x7;
 
+    // Clears bitOffset.
     byte data = readByte();
-    
-    if (bitOffset != 0)
+
+    // If newOffset is 0 it means we just read the 8th bit in a byte
+    // and therefore we want to advance to the next byte.  Otherwise
+    // we want to roll back the stream one byte so that future readBit
+    // calls read bits from the same current byte.
+    if (newOffset != 0)
       {
-	seek(getStreamPosition() - 1);
-	data = (byte) (data >> (8 - newOffset));
+        seek(getStreamPosition() - 1);
+        data = (byte) (data >> (8 - newOffset));
       }
-
+    
     bitOffset = newOffset;
     return data & 0x1;
   }
@@ -198,17 +204,13 @@
     if (numBits < 0 || numBits > 64)
       throw new IllegalArgumentException();
 
-    if (numBits == 0)
-      return 0L;
-
     long bits = 0L;
-    
+
     for (int i = 0; i < numBits; i++)
       {
 	bits <<= 1;
 	bits |= readBit();
       }
-
     return bits;
   }
 
@@ -216,12 +218,15 @@
     throws IOException
   {
     byte data = readByte();
+
     return data != 0;
   }
 
   public byte readByte()
     throws IOException
   {
+    checkClosed();
+
     int data = read();
 
     if (data == -1)
@@ -233,10 +238,7 @@
   public void readBytes(IIOByteBuffer buffer, int len)
     throws IOException
   {
-    int result = read(buffer.getData(), buffer.getOffset(), len);
-    
-    if (result == -1 || result < len)
-      throw new EOFException();
+    readFullyPrivate(buffer.getData(), buffer.getOffset(), len);
 
     buffer.setLength(len);
   }
@@ -250,13 +252,13 @@
   public double readDouble()
     throws IOException
   {
-    return (double) readLong();
+    return Double.longBitsToDouble(readLong());
   }
 
   public float readFloat()
     throws IOException
   {
-    return (float) readInt();
+    return Float.intBitsToFloat(readInt());
   }
 
   public void readFully(byte[] data)
@@ -268,8 +270,7 @@
   public void readFully(byte[] data, int offset, int len)
     throws IOException
   {
-    for (int i = 0; i < len; ++i)
-      data[offset + i] = readByte();
+    readFullyPrivate(data, offset, len);
   }
 
   public void readFully(char[] data, int offset, int len)
@@ -317,23 +318,20 @@
   public int readInt()
     throws IOException
   {
-    int result = read(buffer, 0, 4);
+    readFullyPrivate(buffer, 0, 4);
 
-    if (result == -1)
-      throw new EOFException();
-    
     if (getByteOrder() == ByteOrder.LITTLE_ENDIAN)
-      {
-	return ((buffer[0] & 0xff)
-		+ (buffer[1] << 8)
-		+ (buffer[2] << 16)
-		+ (buffer[3] << 24));
-      }
-
-    return ((buffer[4] << 24)
-	    + (buffer[3] << 16)
-	    + (buffer[2] << 8)
-	    + (buffer[1] & 0xff));
+      return (int)
+        (((int) (buffer[0] & 0xff) << 0)
+         | ((int) (buffer[1] & 0xff) << 8)
+         | ((int) (buffer[2] & 0xff) << 16)
+         | ((int) (buffer[3] & 0xff) << 24));
+
+    return (int)
+      (((int) (buffer[0] & 0xff) << 24)
+       + ((int) (buffer[1] & 0xff) << 16)
+       + ((int) (buffer[2] & 0xff) << 8)
+       + ((int) (buffer[3] & 0xff) << 0));
   }
 
   public String readLine()
@@ -345,94 +343,101 @@
     boolean eol = false;
     StringBuffer buffer = new StringBuffer();
 
-    while (!eol && (c = read()) != -1)
+    c = read();
+    if (c == -1)
+      return null;
+
+    while (!eol)
       {
 	switch(c)
 	  {
 	  case '\r':
-	    // Consume following \n'
-	    long oldPosition = getStreamPosition();
-	    if (read() != '\n')
-	       seek(oldPosition);
+            // Check for following '\n'.
+            long oldPosition = getStreamPosition();
+            c = read();
+            if (c == -1 || c == '\n')
+              eol = true;
+            else
+              {
+                seek(oldPosition);
+                eol = true;
+              }
+            continue;
+
 	  case '\n':
 	    eol = true;
-	    break;
+            continue;
+
 	  default:
 	    buffer.append((char) c);
 	    break;
 	  }
+        c = read();
+        if (c == -1)
+          eol = true;
       }
 
-    if (c == -1 && buffer.length() == 0)
-      return null;
-
     return buffer.toString();
   }
 
   public long readLong()
     throws IOException
   {
-    int result = read(buffer, 0, 8);
+    readFullyPrivate(buffer, 0, 8);
 
-    if (result == -1)
-      throw new EOFException();
-    
     if (getByteOrder() == ByteOrder.LITTLE_ENDIAN)
-      {
-        return ((buffer[0] & 0xff)
-                + (((buffer[1] & 0xff)) << 8)
-                + (((buffer[2] & 0xff)) << 16)
-                + (((buffer[3] & 0xffL)) << 24)
-                + (((buffer[4] & 0xffL)) << 32)
-                + (((buffer[5] & 0xffL)) << 40)
-                + (((buffer[6] & 0xffL)) << 48)
-                + (((long) buffer[7]) << 56));
-      }
-
-    return ((((long) buffer[7]) << 56)
-            + ((buffer[6] & 0xffL) << 48)
-            + ((buffer[5] & 0xffL) << 40)
-            + ((buffer[4] & 0xffL) << 32)
-            + ((buffer[3] & 0xffL) << 24)
-            + ((buffer[2] & 0xff) << 16)
-            + ((buffer[1] & 0xff) << 8)
-            + (buffer[0] & 0xff));
+      return (long)
+        (((long) (buffer[0] & 0xff) << 0)
+         | ((long) (buffer[1] & 0xff) << 8)
+         | ((long) (buffer[2] & 0xff) << 16)
+         | ((long) (buffer[3] & 0xff) << 24)
+         | ((long) (buffer[4] & 0xff) << 32)
+         | ((long) (buffer[5] & 0xff) << 40)
+         | ((long) (buffer[6] & 0xff) << 48)
+         | ((long) (buffer[7] & 0xff) << 56));
+
+    return  (long)
+      (((long) (buffer[0] & 0xff) << 56)
+       | ((long) (buffer[1] & 0xff) << 48)
+       | ((long) (buffer[2] & 0xff) << 40)
+       | ((long) (buffer[3] & 0xff) << 32)
+       | ((long) (buffer[4] & 0xff) << 24)
+       | ((long) (buffer[5] & 0xff) << 16)
+       | ((long) (buffer[6] & 0xff) << 8)
+       | ((long) (buffer[7] & 0xff) << 0));
   }
 
   public short readShort()
     throws IOException
   {
-    int result = read(buffer, 0, 2);
+    readFullyPrivate(buffer, 0, 2);
 
-    if (result == -1)
-      throw new EOFException();
-    
     if (getByteOrder() == ByteOrder.LITTLE_ENDIAN)
-      {
-	return (short) ((buffer[0] & 0xff)
-			+ (buffer[1] << 8));
-      }
-
-    return (short) ((buffer[0] << 8)
-		    + (buffer[1] & 0xff));
+      return (short)
+        (((short) (buffer[0] & 0xff) << 0)
+         | ((short) (buffer[1] & 0xff) << 8));
+
+    return (short)
+      (((short) (buffer[0] & 0xff) << 8)
+       | ((short) (buffer[1] & 0xff) << 0));
   }
 
   public int readUnsignedByte()
     throws IOException
   {
-    return readByte() & 0xff;
+    return (int) readByte() & 0xff;
   }
 
   public long readUnsignedInt()
     throws IOException
   {
-    return readInt() & 0xffffffff;
+    return (long) readInt() & 0xffffffffL;
   }
 
   public int readUnsignedShort()
     throws IOException
   {
-    return readShort() & 0xffff;
+    return (int) readShort() & 0xffff;
   }
 
   public String readUTF()
@@ -442,7 +447,8 @@
 
     String data;
     ByteOrder old = getByteOrder();
-    setByteOrder(ByteOrder.BIG_ENDIAN); // Strings are always big endian.
+    // Strings are always big endian.
+    setByteOrder(ByteOrder.BIG_ENDIAN);
 
     try
       {
@@ -483,7 +489,7 @@
     checkClosed();
     
     if (bitOffset < 0 || bitOffset > 7)
-      throw new IllegalArgumentException();
+      throw new IllegalArgumentException("bitOffset not between 0 and 7 inclusive");
 
     this.bitOffset = bitOffset;
   }
@@ -512,4 +518,23 @@
     bitOffset = 0;
     return num;
   }
+
+  private void readFullyPrivate (byte[] buf, int offset, int len) throws IOException
+  {
+    checkClosed();
+
+    if (len < 0)
+      throw new IndexOutOfBoundsException("Negative length: " + len);
+
+    while (len > 0)
+      {
+	// read will block until some data is available.
+	int numread = read (buf, offset, len);
+	if (numread < 0)
+	  throw new EOFException ();
+	len -= numread;
+	offset += numread;
+      }
+    bitOffset = 0;
+  }
 }
Index: javax/imageio/stream/MemoryCacheImageInputStream.java
===================================================================
RCS file: /sources/classpath/classpath/javax/imageio/stream/MemoryCacheImageInputStream.java,v
retrieving revision 1.5
diff -u -r1.5 MemoryCacheImageInputStream.java
--- javax/imageio/stream/MemoryCacheImageInputStream.java	22 Mar 2006 19:15:24 -0000	1.5
+++ javax/imageio/stream/MemoryCacheImageInputStream.java	19 May 2006 03:59:53 -0000
@@ -38,10 +38,11 @@
 
 package javax.imageio.stream;
 
-import gnu.classpath.NotImplementedException;
-
+import java.io.BufferedInputStream;
+import java.io.BufferedReader;
 import java.io.IOException;
 import java.io.InputStream;
+import java.io.InputStreamReader;
 
 /**
  * @author Michael Koch ([EMAIL PROTECTED])
@@ -49,10 +50,15 @@
 public class MemoryCacheImageInputStream extends ImageInputStreamImpl
 {
   private InputStream stream;
+  private BufferedInputStream buffer;
+
+  private int READLIMIT = 2048;
   
   public MemoryCacheImageInputStream(InputStream stream)
   {
     this.stream = stream;
+    buffer = new BufferedInputStream(stream);
+    buffer.mark(READLIMIT);
   }
 
   public void close()
@@ -63,10 +69,13 @@
   }
 
   public void flushBefore(long position)
-    throws IOException, NotImplementedException
+    throws IOException
   {
-    // FIXME: Implement me.
-    throw new Error("not implemented");
+    long prevFlushedPosition = getFlushedPosition();
+    super.flushBefore(position);
+    buffer.reset();
+    buffer.skip(getFlushedPosition() - prevFlushedPosition);
+    buffer.mark(READLIMIT);
   }
 
   public boolean isCached()
@@ -88,13 +97,33 @@
     throws IOException
   {
     setBitOffset(0);
-    return stream.read();
+    int retval = buffer.read();
+    
+    if (retval != -1)
+      streamPos++;
+
+    return retval;
   }
 
   public int read(byte[] data, int offset, int len)
     throws IOException
   {
     setBitOffset(0);
-    return stream.read(data, offset, len);
+    int retval = buffer.read(data, offset, len);
+
+    if (retval != -1)
+      {
+        streamPos += retval;
+      }
+
+    return retval; 
+  }
+  
+  public void seek(long position)
+  throws IOException
+  {
+    super.seek(position);
+    buffer.reset();
+    buffer.skip(position - getFlushedPosition());
   }
 }

Reply via email to