]> source.dussan.org Git - tigervnc.git/commitdiff
Fixes for erros in java hextile/zrle decoders
authorBrian P. Hinz <bphinz@users.sf.net>
Mon, 1 Jan 2018 22:24:20 +0000 (17:24 -0500)
committerBrian P. Hinz <bphinz@users.sf.net>
Wed, 17 Jan 2018 04:28:37 +0000 (23:28 -0500)
Various errors exposed when connecting to RealVNC servers
on alternative platforms (ARM, SPARC).  SSLEngineManager
was also cleaned up but most of the changes are cosmetic.

16 files changed:
java/com/tigervnc/network/FileDescriptor.java
java/com/tigervnc/network/SSLEngineManager.java
java/com/tigervnc/network/SocketDescriptor.java
java/com/tigervnc/rdr/FdInStream.java
java/com/tigervnc/rdr/FdOutStream.java
java/com/tigervnc/rdr/InStream.java
java/com/tigervnc/rdr/OutStream.java
java/com/tigervnc/rdr/TLSInStream.java
java/com/tigervnc/rdr/TLSOutStream.java
java/com/tigervnc/rdr/ZlibInStream.java
java/com/tigervnc/rfb/CMsgReader.java
java/com/tigervnc/rfb/CSecurityVncAuth.java
java/com/tigervnc/rfb/HextileDecoder.java
java/com/tigervnc/rfb/PixelFormat.java
java/com/tigervnc/rfb/TightDecoder.java
java/com/tigervnc/rfb/ZRLEDecoder.java

index 8a4f693d4e296d63dce60c907c714d1c4ca3e29a..d8a91735d1cb05f5c37ef162fd2e8e04c94841e8 100644 (file)
 package com.tigervnc.network;
 
 import java.io.IOException;
+import java.nio.ByteBuffer;
 import com.tigervnc.rdr.Exception;
 
 public interface FileDescriptor {
 
-  public int read(byte[] buf, int bufPtr, int length) throws Exception;
-  public int write(byte[] buf, int bufPtr, int length) throws Exception;
+  public int read(ByteBuffer buf, int length) throws Exception;
+  public int write(ByteBuffer buf, int length) throws Exception;
   public int select(int interestOps, Integer timeout) throws Exception;
   public void close() throws IOException;
 
index e6abe3e9798db700f46288cdf1878e71facfeb85..27a9a3ea1951e98f336fef68fc743aebc11db0c2 100644 (file)
@@ -32,12 +32,7 @@ public class SSLEngineManager {
 
   private SSLEngine engine = null;
 
-  private int appBufSize;
-  private int pktBufSize;
-
-  private ByteBuffer myAppData;
   private ByteBuffer myNetData;
-  private ByteBuffer peerAppData;
   private ByteBuffer peerNetData;
 
   private Executor executor;
@@ -53,13 +48,8 @@ public class SSLEngineManager {
 
     executor = Executors.newSingleThreadExecutor();
 
-    pktBufSize = engine.getSession().getPacketBufferSize();
-    appBufSize = engine.getSession().getApplicationBufferSize();
-
-    myAppData =
-      ByteBuffer.allocate(Math.max(appBufSize, os.getBufSize()));
+    int pktBufSize = engine.getSession().getPacketBufferSize();
     myNetData = ByteBuffer.allocate(pktBufSize);
-    peerAppData = ByteBuffer.allocate(appBufSize);
     peerNetData = ByteBuffer.allocate(pktBufSize);
   }
 
@@ -70,6 +60,10 @@ public class SSLEngineManager {
     SSLEngineResult.HandshakeStatus hs = engine.getHandshakeStatus();
 
     // Process handshaking message
+    SSLEngineResult res = null;
+    int appBufSize = engine.getSession().getApplicationBufferSize();
+    ByteBuffer peerAppData = ByteBuffer.allocate(appBufSize);
+    ByteBuffer myAppData = ByteBuffer.allocate(appBufSize);
     while (hs != SSLEngineResult.HandshakeStatus.FINISHED &&
            hs != SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING) {
 
@@ -78,36 +72,26 @@ public class SSLEngineManager {
       case NEED_UNWRAP:
         // Receive handshaking data from peer
         peerNetData.flip();
-        SSLEngineResult res = engine.unwrap(peerNetData, peerAppData);
+        res = engine.unwrap(peerNetData, peerAppData);
         peerNetData.compact();
         hs = res.getHandshakeStatus();
+
         // Check status
         switch (res.getStatus()) {
           case BUFFER_UNDERFLOW:
-            int max = Math.min(peerNetData.remaining(), in.getBufSize());
-            int m = in.check(1, max, true);
-            int pos = peerNetData.position();
-            in.readBytes(peerNetData.array(), pos, m);
-            peerNetData.position(pos+m);
-            peerNetData.flip();
-            peerNetData.compact();
+            int avail = in.check(1, peerNetData.remaining(), false);
+            in.readBytes(peerNetData, avail);
             break;
-
           case OK:
             // Process incoming handshaking data
             break;
-
           case CLOSED:
             engine.closeInbound();
             break;
-
         }
         break;
 
       case NEED_WRAP:
-        // Empty the local network packet buffer.
-        myNetData.clear();
-
         // Generate handshaking data
         res = engine.wrap(myAppData, myNetData);
         hs = res.getHandshakeStatus();
@@ -115,21 +99,14 @@ public class SSLEngineManager {
         // Check status
         switch (res.getStatus()) {
           case OK:
-            myAppData.compact();
             myNetData.flip();
-            os.writeBytes(myNetData.array(), 0, myNetData.remaining());
+            os.writeBytes(myNetData, myNetData.remaining());
             os.flush();
-            myNetData.clear();
+            myNetData.compact();
             break;
-
-          case BUFFER_OVERFLOW:
-            // FIXME: How much larger should the buffer be?
-            break;
-
           case CLOSED:
             engine.closeOutbound();
             break;
-
         }
         break;
 
@@ -149,30 +126,19 @@ public class SSLEngineManager {
     }
   }
 
-  public int read(byte[] data, int dataPtr, int length) throws IOException {
+  public int read(ByteBuffer data, int length) throws IOException {
     // Read SSL/TLS encoded data from peer
-    int bytesRead = 0;
     peerNetData.flip();
-    SSLEngineResult res = engine.unwrap(peerNetData, peerAppData);
+    SSLEngineResult res = engine.unwrap(peerNetData, data);
     peerNetData.compact();
     switch (res.getStatus()) {
       case OK :
-        bytesRead = Math.min(length, res.bytesProduced());
-        peerAppData.flip();
-        peerAppData.get(data, dataPtr, bytesRead);
-        peerAppData.compact();
-        break;
+        return res.bytesProduced();
 
       case BUFFER_UNDERFLOW:
-        // need more net data
-        int pos = peerNetData.position();
         // attempt to drain the underlying buffer first
         int need = peerNetData.remaining();
-        int avail = in.check(1, in.getBufSize(), false);
-        if (avail < need)
-          avail = in.check(1, Math.min(need, in.getBufSize()), true);
-        in.readBytes(peerNetData.array(), pos, Math.min(need, avail));
-        peerNetData.position(pos+Math.min(need, avail));
+        in.readBytes(peerNetData, in.check(1, need, true));
         break;
 
       case CLOSED:
@@ -180,26 +146,27 @@ public class SSLEngineManager {
         break;
 
     }
-    return bytesRead;
+    return 0;
   }
 
-  public int write(byte[] data, int dataPtr, int length) throws IOException {
+  public int write(ByteBuffer data, int length) throws IOException {
     int n = 0;
-    myAppData.put(data, dataPtr, length);
-    myAppData.flip();
-    while (myAppData.hasRemaining()) {
-      SSLEngineResult res = engine.wrap(myAppData, myNetData);
+    while (data.hasRemaining()) {
+      SSLEngineResult res = engine.wrap(data, myNetData);
       n += res.bytesConsumed();
       switch (res.getStatus()) {
         case OK:
+          myNetData.flip();
+          os.writeBytes(myNetData, myNetData.remaining());
+          os.flush();
+          myNetData.compact();
           break;
 
         case BUFFER_OVERFLOW:
           // Make room in the buffer by flushing the outstream
           myNetData.flip();
-          os.writeBytes(myNetData.array(), 0, myNetData.remaining());
-          os.flush();
-          myNetData.clear();
+          os.writeBytes(myNetData, myNetData.remaining());
+          myNetData.compact();
           break;
 
         case CLOSED:
@@ -207,11 +174,6 @@ public class SSLEngineManager {
           break;
       }
     }
-    myAppData.clear();
-    myNetData.flip();
-    os.writeBytes(myNetData.array(), 0, myNetData.remaining());
-    os.flush();
-    myNetData.clear();
     return n;
   }
 
index 3cbe5ab2e4baa6242001cbe62112430240b7df9f..b4c99c74b499312ef7e9cf4ed7afc4ed7ac69c45 100644 (file)
@@ -74,37 +74,6 @@ public class SocketDescriptor implements FileDescriptor {
     return SelectorProvider.provider();
   }
 
-  synchronized public int read(byte[] buf, int bufPtr, int length) throws Exception {
-    int n;
-    ByteBuffer b = ByteBuffer.allocate(length);
-    try {
-      n = channel.read(b);
-    } catch (java.io.IOException e) {
-      throw new Exception(e.getMessage());
-    }
-    if (n <= 0)
-      return (n == 0) ? -1 : 0;
-    b.flip();
-    b.get(buf, bufPtr, n);
-    b.clear();
-    return n;
-
-  }
-
-  synchronized public int write(byte[] buf, int bufPtr, int length) throws Exception {
-    int n;
-    ByteBuffer b = ByteBuffer.allocate(length);
-    b.put(buf, bufPtr, length);
-    b.flip();
-    try {
-      n = channel.write(b);
-    } catch (java.io.IOException e) {
-      throw new Exception(e.getMessage());
-    }
-    b.clear();
-    return n;
-  }
-
   synchronized public int select(int interestOps, Integer timeout) throws Exception {
     int n;
     Selector selector;
@@ -134,48 +103,24 @@ public class SocketDescriptor implements FileDescriptor {
     return n;
   }
 
-  public int write(ByteBuffer buf) throws Exception {
-    int n = 0;
-    try {
-      n = channel.write(buf);
-    } catch (java.io.IOException e) {
-      throw new Exception(e.getMessage());
-    }
-    return n;
-  }
-
-  public long write(ByteBuffer[] buf, int offset, int length)
-        throws IOException
-  {
-    long n = 0;
+  public int write(ByteBuffer buf, int len) throws Exception {
     try {
-      n = channel.write(buf, offset, length);
+      int n = channel.write((ByteBuffer)buf.slice().limit(len));
+      buf.position(buf.position()+n);
+      return n;
     } catch (java.io.IOException e) {
       throw new Exception(e.getMessage());
     }
-    return n;
   }
 
-  public int read(ByteBuffer buf) throws IOException {
-    int n = 0;
+  public int read(ByteBuffer buf, int len) throws Exception {
     try {
-      n = channel.read(buf);
-    } catch (java.io.IOException e) {
+      int n = channel.read((ByteBuffer)buf.slice().limit(len));
+      buf.position(buf.position()+n);
+      return (n < 0) ? 0 : n;
+    } catch (java.lang.Exception e) {
       throw new Exception(e.getMessage());
     }
-    return n;
-  }
-
-  public long read(ByteBuffer[] buf, int offset, int length)
-        throws IOException
-  {
-    long n = 0;
-    try {
-      n = channel.read(buf, offset, length);
-    } catch (java.io.IOException e) {
-      throw new Exception(e.getMessage());
-    }
-    return n;
   }
 
   public java.net.Socket socket() {
@@ -210,15 +155,6 @@ public class SocketDescriptor implements FileDescriptor {
     return channel.isConnected();
   }
 
-  protected void implConfigureBlocking(boolean block) throws IOException {
-    channel.configureBlocking(block);
-  }
-
-  protected synchronized void implCloseSelectableChannel() throws IOException {
-    channel.close();
-    notifyAll();
-  }
-
   protected void setChannel(SocketChannel channel_) {
     try {
       if (channel != null)
index b782f74aaf07bc60154b53c605adf701145f7908..8b3c7e2c1c7d06bfd998276f734e763788d5321d 100644 (file)
 
 package com.tigervnc.rdr;
 
-import com.tigervnc.network.*;
+import java.nio.*;
 import java.nio.channels.Selector;
 import java.nio.channels.SelectionKey;
 import java.util.Set;
 import java.util.Iterator;
 
+import com.tigervnc.network.*;
+
 public class FdInStream extends InStream {
 
   static final int DEFAULT_BUF_SIZE = 16384;
@@ -58,22 +60,24 @@ public class FdInStream extends InStream {
     this(fd_, blockCallback_, 0);
   }
 
-  public final void readBytes(byte[] data, int dataPtr, int length) {
+  public final void readBytes(ByteBuffer data, int length) {
     if (length < minBulkSize) {
-      super.readBytes(data, dataPtr, length);
+      super.readBytes(data, length);
       return;
     }
 
+    int dataPtr = data.position();
+
     int n = end - ptr;
     if (n > length) n = length;
 
-    System.arraycopy(b, ptr, data, dataPtr, n);
+    data.put(b, ptr, n);
     dataPtr += n;
     length -= n;
     ptr += n;
 
     while (length > 0) {
-      n = readWithTimeoutOrCallback(data, dataPtr, length);
+      n = readWithTimeoutOrCallback(data, length);
       dataPtr += n;
       length -= n;
       offset += n;
@@ -139,7 +143,8 @@ public class FdInStream extends InStream {
         // bytes is ineffecient.
         bytes_to_read = Math.min(bytes_to_read, Math.max(itemSize*nItems, 8));
       }
-      int n = readWithTimeoutOrCallback(b, end, bytes_to_read, wait);
+      Buffer buf = ByteBuffer.wrap(b).position(end);
+      int n = readWithTimeoutOrCallback((ByteBuffer)buf, bytes_to_read, wait);
       if (n == 0) return 0;
       end += n;
     }
@@ -150,7 +155,7 @@ public class FdInStream extends InStream {
     return nItems;
   }
 
-  protected int readWithTimeoutOrCallback(byte[] buf, int bufPtr, int len, boolean wait) {
+  protected int readWithTimeoutOrCallback(ByteBuffer buf, int len, boolean wait) {
     long before = 0;
     if (timing)
       before = System.nanoTime();
@@ -184,7 +189,7 @@ public class FdInStream extends InStream {
     }
 
     try {
-      n = fd.read(buf, bufPtr, len);
+      n = fd.read(buf, len);
     } catch (Exception e) {
       throw new SystemException("read:"+e.toString());
     }
@@ -211,8 +216,8 @@ public class FdInStream extends InStream {
     return n;
   }
 
-  private int readWithTimeoutOrCallback(byte[] buf, int bufPtr, int len) {
-    return readWithTimeoutOrCallback(buf, bufPtr, len, true);
+  private int readWithTimeoutOrCallback(ByteBuffer buf, int len) {
+    return readWithTimeoutOrCallback(buf, len, true);
   }
 
   public FileDescriptor getFd() {
index a9dea781c7075f205dc007bda608d950a804f631..acb03a29bf265c926338c8de09db47fc0f1bcaed 100644 (file)
 
 package com.tigervnc.rdr;
 
-import com.tigervnc.network.*;
+import java.nio.ByteBuffer;
 import java.nio.channels.SelectionKey;
 
+import com.tigervnc.network.*;
+
 public class FdOutStream extends OutStream {
 
   static final int DEFAULT_BUF_SIZE = 16384;
@@ -36,6 +38,8 @@ public class FdOutStream extends OutStream {
     offset = 0;
     ptr = sentUpTo = start = 0;
     end = start + bufSize;
+
+    lastWrite = System.currentTimeMillis();
   }
 
   public FdOutStream(FileDescriptor fd_) { this(fd_, true, -1, 0); }
@@ -53,17 +57,22 @@ public class FdOutStream extends OutStream {
     return offset + ptr - sentUpTo;
   }
 
-  public void flush()
+  int bufferUsage()
   {
-    int timeoutms_;
+    return ptr - sentUpTo;
+  }
 
-    if (blocking)
-      timeoutms_ = timeoutms;
-    else
-      timeoutms_ = 0;
+  long getIdleTime()
+  {
+    return System.currentTimeMillis()-lastWrite;
+  }
 
+  public void flush()
+  {
     while (sentUpTo < ptr) {
-      int n = writeWithTimeout(b, sentUpTo, ptr - sentUpTo, timeoutms_);
+      int n = writeWithTimeout(b, sentUpTo,
+                               ptr - sentUpTo,
+                               blocking ? timeoutms : 0);
 
       // Timeout?
       if (n == 0) {
@@ -71,13 +80,6 @@ public class FdOutStream extends OutStream {
         if (!blocking)
           break;
 
-        // Otherwise try blocking (with possible timeout)
-        if ((timeoutms_ == 0) && (timeoutms != 0)) {
-          timeoutms_ = timeoutms;
-          break;
-        }
-
-        // Proper timeout
         throw new TimedOut();
       }
 
@@ -90,39 +92,6 @@ public class FdOutStream extends OutStream {
       ptr = sentUpTo = start;
   }
 
-  private int writeWithTimeout(byte[] data, int dataPtr, int length, int timeoutms)
-  {
-    int n;
-
-    do {
-
-      Integer tv;
-      if (timeoutms != -1) {
-        tv = new Integer(timeoutms);
-      } else {
-        tv = null;
-      }
-
-      try {
-        n = fd.select(SelectionKey.OP_WRITE, tv);
-      } catch (java.lang.Exception e) {
-        System.out.println(e.toString());
-        throw new Exception(e.getMessage());
-      }
-
-    } while (n < 0);
-
-    if (n == 0) return 0;
-
-    try {
-      n = fd.write(data, dataPtr, length);
-    } catch (java.lang.Exception e) {
-      throw new Exception(e.getMessage());
-    }
-
-    return n;
-  }
-
   protected int overrun(int itemSize, int nItems)
   {
     if (itemSize > bufSize)
@@ -159,6 +128,41 @@ public class FdOutStream extends OutStream {
     return nItems;
   }
 
+  private int writeWithTimeout(byte[] data, int dataPtr, int length, int timeoutms)
+  {
+    int n;
+
+    do {
+
+      Integer tv;
+      if (timeoutms != -1) {
+        tv = new Integer(timeoutms);
+      } else {
+        tv = null;
+      }
+
+      try {
+        n = fd.select(SelectionKey.OP_WRITE, tv);
+      } catch (java.lang.Exception e) {
+        System.out.println(e.toString());
+        throw new Exception(e.getMessage());
+      }
+
+    } while (n < 0);
+
+    if (n == 0) return 0;
+
+    try {
+      n = fd.write(ByteBuffer.wrap(data, dataPtr, length), length);
+    } catch (java.lang.Exception e) {
+      throw new Exception(e.getMessage());
+    }
+
+    lastWrite = System.currentTimeMillis();
+
+    return n;
+  }
+
   public FileDescriptor getFd() {
     return fd;
   }
@@ -178,4 +182,5 @@ public class FdOutStream extends OutStream {
   protected int sentUpTo;
   protected int offset;
   protected int bufSize;
+  private long lastWrite;
 }
index 0906d326e812799321a3a60add48676ba7882e11..58afcfb67be6829784c6e209c1e4e7579ae29e18 100644 (file)
@@ -74,11 +74,11 @@ abstract public class InStream {
     if (len > maxStringLength)
       throw new Exception("InStream max string length exceeded");
 
-    byte[] str = new byte[len];
-    readBytes(str, 0, len);
+    ByteBuffer str = ByteBuffer.allocate(len);
+    readBytes(str, len);
     String utf8string = new String();
     try {
-      utf8string = new String(str,"UTF8");
+      utf8string = new String(str.array(),"UTF8");
     } catch(java.io.UnsupportedEncodingException e) {
       e.printStackTrace();
     }
@@ -98,26 +98,16 @@ abstract public class InStream {
     }
   }
 
-  // readBytes() reads an exact number of bytes into an array at an offset.
+  // readBytes() reads an exact number of bytes
 
   public void readBytes(ByteBuffer data, int length) {
-    int dataEnd = data.mark().position() + length;
-    while (data.position() < dataEnd) {
-      int n = check(1, dataEnd - data.position());
-      data.put(b, ptr, n);
+    ByteBuffer dataPtr = data;
+    int dataEnd = dataPtr.position() + length;
+    while (dataPtr.position() < dataEnd) {
+      int n = check(1, dataEnd - dataPtr.position());
+      dataPtr.put(b, ptr, n);
       ptr += n;
     }
-    data.reset();
-  }
-
-  public void readBytes(byte[] data, int dataPtr, int length) {
-    int dataEnd = dataPtr + length;
-    while (dataPtr < dataEnd) {
-      int n = check(1, dataEnd - dataPtr);
-      System.arraycopy(b, ptr, data, dataPtr, n);
-      ptr += n;
-      dataPtr += n;
-    }
   }
 
   // readOpaqueN() reads a quantity "without byte-swapping".  Because java has
@@ -126,38 +116,6 @@ abstract public class InStream {
   public final int readOpaque8()  { return readU8(); }
   public final int readOpaque16() { return readU16(); }
   public final int readOpaque32() { return readU32(); }
-  public final int readOpaque24A() { check(3); int b0 = b[ptr++];
-                                     int b1 = b[ptr++]; int b2 = b[ptr++];
-                                     return b0 << 24 | b1 << 16 | b2 << 8; }
-  public final int readOpaque24B() { check(3); int b0 = b[ptr++];
-                                     int b1 = b[ptr++]; int b2 = b[ptr++];
-                                     return b0 << 16 | b1 << 8 | b2; }
-
-  public final int readPixel(int bytesPerPixel, boolean bigEndian) {
-    byte[] pix = new byte[4];
-    readBytes(pix, 0, bytesPerPixel);
-
-    if (bigEndian) {
-      return 0xff000000 | (pix[0] & 0xff)<<16 | (pix[1] & 0xff)<<8 | (pix[2] & 0xff);
-    } else {
-      return 0xff000000 | (pix[2] & 0xff)<<16 | (pix[1] & 0xff)<<8 | (pix[0] & 0xff);
-    }
-  }
-
-  public final void readPixels(int[] buf, int length, int bytesPerPixel, boolean bigEndian) {
-    int npixels = length*bytesPerPixel;
-    byte[] pixels = new byte[npixels];
-    readBytes(pixels, 0, npixels);
-    for (int i = 0; i < length; i++) {
-      byte[] pix = new byte[4];
-      System.arraycopy(pixels, i*bytesPerPixel, pix, 0, bytesPerPixel);
-      if (bigEndian) {
-        buf[i] = 0xff000000 | (pix[0] & 0xff)<<16 | (pix[1] & 0xff)<<8 | (pix[2] & 0xff);
-      } else {
-        buf[i] = 0xff000000 | (pix[2] & 0xff)<<16 | (pix[1] & 0xff)<<8 | (pix[0] & 0xff);
-      }
-    }
-  }
 
   // pos() returns the position in the stream.
 
@@ -184,6 +142,9 @@ abstract public class InStream {
   // is supposed to be "small" (a few bytes).
 
   abstract protected int overrun(int itemSize, int nItems, boolean wait);
+  protected int overrun(int itemSize, int nItems) {
+    return overrun(itemSize, nItems, true);
+  }
 
   protected InStream() {}
   protected byte[] b;
index a3b1a6c0f6c4779c8839204937e8c158c046fd95..0e2013394cb80feee50236414b1c9c9a4cac9459 100644 (file)
@@ -23,6 +23,8 @@
 
 package com.tigervnc.rdr;
 
+import java.nio.*;
+
 import com.tigervnc.network.*;
 
 abstract public class OutStream {
@@ -116,12 +118,22 @@ abstract public class OutStream {
     }
   }
 
+  public void writeBytes(ByteBuffer data, int length) {
+    ByteBuffer dataPtr = data;
+    int dataEnd = dataPtr.position() + length;
+    while (dataPtr.position() < dataEnd) {
+      int n = check(1, dataEnd - dataPtr.position());
+      dataPtr.get(b, ptr, n);
+      ptr += n;
+    }
+  }
+
   // copyBytes() efficiently transfers data between streams
 
   public void copyBytes(InStream is, int length) {
     while (length > 0) {
       int n = check(1, length);
-      is.readBytes(b, ptr, n);
+      is.readBytes(ByteBuffer.wrap(b, ptr, n), n);
       ptr += n;
       length -= n;
     }
index 0cdc4d9dfbeb5061f75e5d2555f2e8b6171a84be..c0e57a6118dd6938ea60593bc03b25df66028892 100644 (file)
@@ -89,12 +89,8 @@ public class TLSInStream extends InStream {
   {
     int n = -1;
 
-    //n = in.check(1, 1, wait);
-    //if (n == 0)
-    //  return 0;
-
     try {
-      n = manager.read(buf, bufPtr, len);
+      n = manager.read(ByteBuffer.wrap(buf, bufPtr, len), len);
     } catch (java.io.IOException e) {
       e.printStackTrace();
     }
index 80514b277019e751b8618f061f2e6d630332ffb1..f5685d5bbc6c1f4908fdd49bc661b1b313b1e691 100644 (file)
@@ -77,7 +77,7 @@ public class TLSOutStream extends OutStream {
     int n = 0;
 
     try {
-      n = manager.write(data, dataPtr, length);
+      n = manager.write(ByteBuffer.wrap(data, dataPtr, length), length);
     } catch (java.io.IOException e) {
       throw new Exception(e.getMessage());
     }
index 151633ecca87bac53c41e4718451be88c663f69c..12de0e8b3e48172f464b15f04d6c6f9112e64e2d 100644 (file)
@@ -33,28 +33,12 @@ public class ZlibInStream extends InStream {
     bufSize = bufSize_;
     b = new byte[bufSize];
     bytesIn = offset = 0;
-    zs = new ZStream();
-    zs.next_in = null;
-    zs.next_in_index = 0;
-    zs.avail_in = 0;
-    if (zs.inflateInit() != JZlib.Z_OK) {
-      zs = null;
-      throw new Exception("ZlinInStream: inflateInit failed");
-    }
     ptr = end = start = 0;
+    init();
   }
 
   public ZlibInStream() { this(defaultBufSize); }
 
-  protected void finalize() throws Throwable {
-    try {
-      b = null;
-      zs.inflateEnd();
-    } finally {
-      super.finalize();
-    }
-  }
-
   public void setUnderlying(InStream is, int bytesIn_)
   {
     underlying = is;
@@ -62,6 +46,11 @@ public class ZlibInStream extends InStream {
     ptr = end = start;
   }
 
+  public int pos()
+  {
+    return offset + ptr - start;
+  }
+
   public void removeUnderlying()
   {
     ptr = end = start;
@@ -74,21 +63,32 @@ public class ZlibInStream extends InStream {
     underlying = null;
   }
 
-  public int pos()
+  public void reset()
   {
-    return offset + ptr - start;
+    deinit();
+    init();
   }
 
-  public void reset()
+  public void init()
   {
-    ptr = end = start;
-    if (underlying == null) return;
+    assert(zs == null);
 
-    while (bytesIn > 0) {
-      decompress(true);
-      end = start; // throw away any data
+    zs = new ZStream();
+    zs.next_in = null;
+    zs.next_in_index = 0;
+    zs.avail_in = 0;
+    if (zs.inflateInit() != JZlib.Z_OK) {
+      zs = null;
+      throw new Exception("ZlinInStream: inflateInit failed");
     }
-    underlying = null;
+  }
+
+  public void deinit()
+  {
+    assert(zs != null);
+    removeUnderlying();
+    zs.inflateEnd();
+    zs = null;
   }
 
   protected int overrun(int itemSize, int nItems, boolean wait)
index a79cf84285f8096ecb975212794884fb58290cb2..e65db8c67a942c2399aa4f733c8d69f479ff1768 100644 (file)
@@ -153,10 +153,10 @@ public class CMsgReader {
       vlog.error("cut text too long ("+len+" bytes) - ignoring");
       return;
     }
-    byte[] buf = new byte[len];
-    is.readBytes(buf, 0, len);
+    ByteBuffer buf = ByteBuffer.allocate(len);
+    is.readBytes(buf, len);
     Charset latin1 = Charset.forName("ISO-8859-1");
-    CharBuffer chars = latin1.decode(ByteBuffer.wrap(buf));
+    CharBuffer chars = latin1.decode(buf.compact());
     handler.serverCutText(chars.toString(), len);
   }
 
@@ -164,22 +164,22 @@ public class CMsgReader {
   {
     int flags;
     int len;
-    byte[] data = new byte[64];
+    ByteBuffer data = ByteBuffer.allocate(64);
 
     is.skip(3);
 
     flags = is.readU32();
 
     len = is.readU8();
-    if (len > data.length) {
+    if (len > data.capacity()) {
       System.out.println("Ignoring fence with too large payload\n");
       is.skip(len);
       return;
     }
 
-    is.readBytes(data, 0, len);
+    is.readBytes(data, len);
 
-    handler.fence(flags, len, data);
+    handler.fence(flags, len, data.array());
   }
 
   protected void readEndOfContinuousUpdates()
@@ -243,6 +243,12 @@ public class CMsgReader {
         int byte_ = y * maskBytesPerRow + x / 8;
         int bit = 7 - x % 8;
 
+        // NOTE: BufferedImage needs ARGB, rather than RGBA
+        if ((mask.get(byte_) & (1 << bit)) > 0)
+          out.put(out.position(), (byte)255);
+        else
+          out.put(out.position(), (byte)0);
+
         if ((data.get(byte_) & (1 << bit)) > 0) {
           out.put(out.position() + 1, pr);
           out.put(out.position() + 2, pg);
@@ -253,11 +259,6 @@ public class CMsgReader {
           out.put(out.position() + 3, sb);
         }
 
-        if ((mask.get(byte_) & (1 << bit)) > 0)
-          out.put(out.position() + 0, (byte)255);
-        else
-          out.put(out.position() + 0, (byte)0);
-
         out.position(out.position() + 4);
       }
     }
@@ -281,8 +282,8 @@ public class CMsgReader {
     is.readBytes(mask, mask_len);
 
     int maskBytesPerRow = (width+7)/8;
-    in = (ByteBuffer)data.duplicate().mark();
-    out = (ByteBuffer)ByteBuffer.wrap(buf).mark();
+    in = ByteBuffer.wrap(data.array());
+    out = ByteBuffer.wrap(buf);
     for (y = 0;y < height;y++) {
       for (x = 0;x < width;x++) {
         int byte_ = y * maskBytesPerRow + x / 8;
@@ -294,10 +295,10 @@ public class CMsgReader {
         else
           out.put((byte)0);
 
-        handler.cp.pf().rgbFromBuffer(out, in.duplicate(), 1);
+        handler.cp.pf().rgbFromBuffer(out.duplicate(), in.duplicate(), 1);
 
         in.position(in.position() + handler.cp.pf().bpp/8);
-        out.position(out.reset().position() + 4).mark();
+        out.position(out.position() + 3);
       }
     }
 
index 06154953726406ed5dbe9faa707d9468da807522..b1859f11a96827509a268311aab8bda4c1726479 100644 (file)
@@ -18,6 +18,8 @@
 
 package com.tigervnc.rfb;
 
+import java.nio.*;
+
 import com.tigervnc.rdr.*;
 import com.tigervnc.vncviewer.*;
 
@@ -33,8 +35,8 @@ public class CSecurityVncAuth extends CSecurity {
     OutStream os = cc.getOutStream();
 
     // Read the challenge & obtain the user's password
-    byte[] challenge = new byte[vncAuthChallengeSize];
-    is.readBytes(challenge, 0, vncAuthChallengeSize);
+    ByteBuffer challenge = ByteBuffer.allocate(vncAuthChallengeSize);
+    is.readBytes(challenge, vncAuthChallengeSize);
     StringBuffer passwd = new StringBuffer();
     upg.getUserPasswd(cc.isSecure(), null, passwd);
 
@@ -51,10 +53,10 @@ public class CSecurityVncAuth extends CSecurity {
       key[i] = i<pwdLen ? utf8str[i] : 0;
     DesCipher des = new DesCipher(key);
     for (int j = 0; j < vncAuthChallengeSize; j += 8)
-      des.encrypt(challenge,j,challenge,j);
+      des.encrypt(challenge.array(),j,challenge.array(),j);
 
     // Return the response to the server
-    os.writeBytes(challenge, 0, vncAuthChallengeSize);
+    os.writeBytes(challenge.array(), 0, vncAuthChallengeSize);
     os.flush();
     return true;
   }
index b0744cad06961bba4ce7ad1ff4e1e3ee7b2d6a15..4c99deebe33ee2fbbbd5eaea28570419a011c39e 100644 (file)
@@ -51,8 +51,8 @@ public class HextileDecoder extends Decoder {
 
         t.br.x = Math.min(r.br.x, t.tl.x + 16);
 
-        tileType = is.readU8() & 0xff;
-        os.writeU32(tileType);
+        tileType = is.readU8();
+        os.writeU8(tileType);
 
         if ((tileType & hextileRaw) != 0) {
           os.copyBytes(is, t.area() * bytesPerPixel);
@@ -68,8 +68,8 @@ public class HextileDecoder extends Decoder {
         if ((tileType & hextileAnySubrects) != 0) {
           int nSubrects;
 
-          nSubrects = is.readU8() & 0xff;
-          os.writeU32(nSubrects);
+          nSubrects = is.readU8();
+          os.writeU8(nSubrects);
 
           if ((tileType & hextileSubrectsColoured) != 0)
             os.copyBytes(is, nSubrects * (bytesPerPixel + 2));
@@ -115,29 +115,24 @@ public class HextileDecoder extends Decoder {
   }
 
   private static ByteBuffer READ_PIXEL(InStream is, PixelFormat pf) {
-    ByteBuffer b = ByteBuffer.allocate(4);
     switch (pf.bpp) {
     case 8:
-      b.putInt(is.readOpaque8());
-      return ByteBuffer.allocate(1).put(b.get(3));
+      return ByteBuffer.allocate(1).put(0, (byte)is.readOpaque8());
     case 16:
-      b.putInt(is.readOpaque16());
-      return ByteBuffer.allocate(2).put(b.array(), 2, 2);
-    case 32:
+      return ByteBuffer.allocate(2).putShort(0, (short)is.readOpaque16());
     default:
-      b.putInt(is.readOpaque32());
-      return b;
+      return ByteBuffer.allocate(4).putInt(0, is.readOpaque32());
     }
   }
 
   private void HEXTILE_DECODE(Rect r, InStream is,
-                                     PixelFormat pf,
-                                     ModifiablePixelBuffer pb)
+                              PixelFormat pf,
+                              ModifiablePixelBuffer pb)
   {
     Rect t = new Rect();
     ByteBuffer bg = ByteBuffer.allocate(pf.bpp/8);
     ByteBuffer fg = ByteBuffer.allocate(pf.bpp/8);
-    ByteBuffer buf = ByteBuffer.allocate(16 * 16 * 4);
+    ByteBuffer buf = ByteBuffer.allocate(16 * 16 * pf.bpp/8);
 
     for (t.tl.y = r.tl.y; t.tl.y < r.br.y; t.tl.y += 16) {
 
@@ -147,10 +142,10 @@ public class HextileDecoder extends Decoder {
 
         t.br.x = Math.min(r.br.x, t.tl.x + 16);
 
-        int tileType = is.readU32();
+        int tileType = is.readU8();
 
         if ((tileType & hextileRaw) != 0) {
-          is.readBytes(buf, t.area() * (pf.bpp/8));
+          is.readBytes(buf.duplicate(), t.area() * (pf.bpp/8));
           pb.imageRect(pf, t, buf.array());
           continue;
         }
@@ -166,7 +161,7 @@ public class HextileDecoder extends Decoder {
           fg = READ_PIXEL(is, pf);
 
         if ((tileType & hextileAnySubrects) != 0) {
-          int nSubrects = is.readU32();
+          int nSubrects = is.readU8();
 
           for (int i = 0; i < nSubrects; i++) {
 
@@ -180,13 +175,16 @@ public class HextileDecoder extends Decoder {
             int y = (xy & 15);
             int w = ((wh >> 4) & 15) + 1;
             int h = (wh & 15) + 1;
+            if (x + w > 16 || y + h > 16) {
+              throw new Exception("HEXTILE_DECODE: Hextile out of bounds");
+            }
             ptr = buf.duplicate();
             ptr.position((y * t.width() + x)*pf.bpp/8);
             int rowAdd = (t.width() - w)*pf.bpp/8;
             while (h-- > 0) {
               len = w;
               while (len-- > 0) ptr.put(fg.array());
-              ptr.position(ptr.position()+Math.min(rowAdd,ptr.remaining()));
+              if (h > 0) ptr.position(ptr.position()+rowAdd);
             }
           }
         }
index 9a2699928ebefb672619e54496681c2cbada7a0e..593b7804c5052aede87cfa6592703de71762d564 100644 (file)
@@ -204,11 +204,13 @@ public class PixelFormat {
     return 0;
   }
 
+  // This method should be invoked with duplicates of dst/src Buffers
   public void bufferFromRGB(ByteBuffer dst, ByteBuffer src, int pixels)
   {
     bufferFromRGB(dst, src, pixels, pixels, 1);
   }
 
+  // This method should be invoked with duplicates of dst/src Buffers
   public void bufferFromRGB(ByteBuffer dst, ByteBuffer src,
                             int w, int stride, int h)
   {
@@ -269,11 +271,13 @@ public class PixelFormat {
     }
   }
 
+  // This method should be invoked with duplicates of dst/src Buffers
   public void rgbFromBuffer(ByteBuffer dst, ByteBuffer src, int pixels)
   {
     rgbFromBuffer(dst, src, pixels, pixels, 1);
   }
 
+  // This method should be invoked with duplicates of dst/src Buffers
   public void rgbFromBuffer(ByteBuffer dst, ByteBuffer src,
                             int w, int stride, int h)
   {
@@ -326,7 +330,7 @@ public class PixelFormat {
           dst.put(b);
           src.position(src.position() + bpp/8);
         }
-        src.reset().position(src.position() + srcPad).mark();
+        src.position(src.position() + srcPad);
       }
     }
   }
@@ -345,6 +349,7 @@ public class PixelFormat {
     }
   }
 
+  // This method should be invoked with a duplicates of buffer
   public int pixelFromBuffer(ByteBuffer buffer)
   {
     int p;
index b180707d67b6679ecc3fdffa5ab7a12602e71e1c..262fcc342c1f5367f423a8c77a600bab602fd974 100644 (file)
@@ -211,7 +211,7 @@ public class TightDecoder extends Decoder {
 
         assert(buflen >= 3);
 
-        pf.bufferFromRGB(pix, bufptr, 1);
+        pf.bufferFromRGB(pix.duplicate(), bufptr, 1);
         pb.fillRect(pf, r, pix.array());
       } else {
         assert(buflen >= pf.bpp/8);
@@ -296,7 +296,7 @@ public class TightDecoder extends Decoder {
 
     // Determine if the data should be decompressed or just copied.
     int rowSize, dataSize;
-    byte[] netbuf;
+    ByteBuffer netbuf;
 
     if (palSize != 0) {
       if (palSize <= 2)
@@ -330,14 +330,14 @@ public class TightDecoder extends Decoder {
       zis[streamId].setUnderlying(ms, len);
 
       // Allocate netbuf and read in data
-      netbuf = new byte[dataSize];
+      netbuf = ByteBuffer.allocate(dataSize);
 
-      zis[streamId].readBytes(netbuf, 0, dataSize);
+      zis[streamId].readBytes(netbuf, dataSize);
 
       zis[streamId].removeUnderlying();
       ms = null;
 
-      bufptr = ByteBuffer.wrap(netbuf);
+      bufptr = (ByteBuffer)netbuf.flip();
       buflen = dataSize;
     }
 
@@ -426,7 +426,7 @@ public class TightDecoder extends Decoder {
         pix.put(c, (byte)(inbuf.get(y*rectWidth*3+c) + prevRow[c]));
         thisRow[c] = pix.get(c);
       }
-      pf.bufferFromRGB((ByteBuffer)outbuf.position(y*stride), pix, 1);
+      pf.bufferFromRGB((ByteBuffer)outbuf.duplicate().position(y*stride), pix, 1);
 
       /* Remaining pixels of a row */
       for (x = 1; x < rectWidth; x++) {
@@ -440,7 +440,7 @@ public class TightDecoder extends Decoder {
           pix.put(c, (byte)(inbuf.get((y*rectWidth+x)*3+c) + est[c]));
           thisRow[x*3+c] = pix.get(c);
         }
-        pf.bufferFromRGB((ByteBuffer)outbuf.position(y*stride+x), pix, 1);
+        pf.bufferFromRGB((ByteBuffer)outbuf.duplicate().position(y*stride+x), pix, 1);
       }
 
       System.arraycopy(thisRow, 0, prevRow, 0, prevRow.length);
@@ -463,13 +463,13 @@ public class TightDecoder extends Decoder {
 
     for (y = 0; y < rectHeight; y++) {
       /* First pixel in a row */
-      pf.rgbFromBuffer(pix, (ByteBuffer)inbuf.position(y*rectWidth), 1);
+      pf.rgbFromBuffer(pix.duplicate(), (ByteBuffer)inbuf.position(y*rectWidth), 1);
       for (c = 0; c < 3; c++)
         pix.put(c, (byte)(pix.get(c) + prevRow[c]));
 
       System.arraycopy(pix.array(), 0, thisRow, 0, pix.capacity());
 
-      pf.bufferFromRGB((ByteBuffer)outbuf.position(y*stride), pix, 1);
+      pf.bufferFromRGB((ByteBuffer)outbuf.duplicate().position(y*stride), pix, 1);
 
       /* Remaining pixels of a row */
       for (x = 1; x < rectWidth; x++) {
@@ -482,13 +482,13 @@ public class TightDecoder extends Decoder {
           }
         }
 
-        pf.rgbFromBuffer(pix, (ByteBuffer)inbuf.position(y*rectWidth+x), 1);
+        pf.rgbFromBuffer(pix.duplicate(), (ByteBuffer)inbuf.position(y*rectWidth+x), 1);
         for (c = 0; c < 3; c++)
           pix.put(c, (byte)(pix.get(c) + est[c]));
 
         System.arraycopy(pix.array(), 0, thisRow, x*3, pix.capacity());
 
-        pf.bufferFromRGB((ByteBuffer)outbuf.position(y*stride+x), pix, 1);
+        pf.bufferFromRGB((ByteBuffer)outbuf.duplicate().position(y*stride+x), pix, 1);
       }
 
       System.arraycopy(thisRow, 0, prevRow, 0, prevRow.length);
index c1f908abaa354cb88e9a40b25ddfc59ae00ba9dc..03692b96771a514d300c889f4df5b07fd2004c3e 100644 (file)
@@ -26,24 +26,24 @@ import com.tigervnc.rdr.*;
 
 public class ZRLEDecoder extends Decoder {
 
-  private static int readOpaque24A(InStream is)
+  private static ByteBuffer readOpaque24A(InStream is)
   {
     is.check(3);
     ByteBuffer r = ByteBuffer.allocate(4);
     r.put(0, (byte)is.readU8());
     r.put(1, (byte)is.readU8());
     r.put(2, (byte)is.readU8());
-    return ((ByteBuffer)r.rewind()).getInt();
+    return r;
   }
 
-  private static int readOpaque24B(InStream is)
+  private static ByteBuffer readOpaque24B(InStream is)
   {
     is.check(3);
     ByteBuffer r = ByteBuffer.allocate(4);
-    r.put(2, (byte)is.readU8());
     r.put(1, (byte)is.readU8());
-    r.put(0, (byte)is.readU8());
-    return ((ByteBuffer)r.rewind()).getInt();
+    r.put(2, (byte)is.readU8());
+    r.put(3, (byte)is.readU8());
+    return r;
   }
 
   public ZRLEDecoder() {
@@ -67,97 +67,98 @@ public class ZRLEDecoder extends Decoder {
   {
     MemInStream is = new MemInStream((byte[])buffer, 0, buflen);
     PixelFormat pf = cp.pf();
-    ByteBuffer buf = ByteBuffer.allocate(64 * 64 * 4);
     switch (pf.bpp) {
-    case 8:  zrleDecode8(r, is, zis, buf, pf, pb); break;
-    case 16: zrleDecode16(r, is, zis, buf, pf, pb); break;
+    case 8:  zrleDecode8(r, is, zis, pf, pb); break;
+    case 16: zrleDecode16(r, is, zis, pf, pb); break;
     case 32:
-        int maxPixel = pf.pixelFromRGB(-1, -1, -1, pf.getColorModel());
-        boolean fitsInLS3Bytes = maxPixel < (1<<24);
-        boolean fitsInMS3Bytes = (maxPixel & 0xff) == 0;
-
-        if ((fitsInLS3Bytes && pf.isLittleEndian()) ||
-            (fitsInMS3Bytes && pf.isBigEndian()))
-        {
-          zrleDecode24A(r, is, zis, buf, pf, pb);
-        }
-        else if ((fitsInLS3Bytes && pf.isBigEndian()) ||
-                (fitsInMS3Bytes && pf.isLittleEndian()))
-        {
-          zrleDecode24B(r, is, zis, buf, pf, pb);
-        }
-        else
-        {
-          zrleDecode32(r, is, zis, buf, pf, pb);
+      {
+        if (pf.depth <= 24) {
+          int maxPixel = pf.pixelFromRGB(-1, -1, -1, pf.getColorModel());
+          boolean fitsInLS3Bytes = maxPixel < (1<<24);
+          boolean fitsInMS3Bytes = (maxPixel & 0xff) == 0;
+
+          if ((fitsInLS3Bytes && pf.isLittleEndian()) ||
+              (fitsInMS3Bytes && pf.isBigEndian()))
+          {
+            zrleDecode24A(r, is, zis, pf, pb);
+            break;
+          }
+
+          if ((fitsInLS3Bytes && pf.isBigEndian()) ||
+              (fitsInMS3Bytes && pf.isLittleEndian()))
+          {
+            zrleDecode24B(r, is, zis, pf, pb);
+            break;
+          }
         }
+
+        zrleDecode32(r, is, zis, pf, pb);
         break;
+      }
     }
   }
 
   private static enum PIXEL_T { U8, U16, U24A, U24B, U32 };
 
   private static ByteBuffer READ_PIXEL(InStream is, PIXEL_T type) {
-    ByteBuffer b = ByteBuffer.allocate(4);
     switch (type) {
     case U8:
-      b.putInt(is.readOpaque8());
-      return (ByteBuffer)ByteBuffer.allocate(1).put(b.get(3)).rewind();
+      return ByteBuffer.allocate(1).put(0, (byte)is.readOpaque8());
     case U16:
-      b.putInt(is.readOpaque16());
-      return (ByteBuffer)ByteBuffer.allocate(2).put(b.array(), 2, 2).rewind();
+      return ByteBuffer.allocate(2).putShort(0, (short)is.readOpaque16());
     case U24A:
-      return (ByteBuffer)b.putInt(readOpaque24A(is)).rewind();
+      return readOpaque24A(is);
     case U24B:
-      return (ByteBuffer)b.putInt(readOpaque24B(is)).rewind();
-    case U32:
+      return readOpaque24B(is);
     default:
-      return (ByteBuffer)b.putInt(is.readOpaque32()).rewind();
+      return ByteBuffer.allocate(4).putInt(0, is.readOpaque32());
     }
   }
 
   private void zrleDecode8(Rect r, InStream is,
-                           ZlibInStream zis, ByteBuffer buf,
+                           ZlibInStream zis,
                            PixelFormat pf, ModifiablePixelBuffer pb)
   {
-    ZRLE_DECODE(r, is, zis, buf, pf, pb, PIXEL_T.U8);
+    ZRLE_DECODE(r, is, zis, pf, pb, PIXEL_T.U8);
   }
 
   private void zrleDecode16(Rect r, InStream is,
-                            ZlibInStream zis, ByteBuffer buf,
+                            ZlibInStream zis,
                             PixelFormat pf, ModifiablePixelBuffer pb)
   {
-    ZRLE_DECODE(r, is, zis, buf, pf, pb, PIXEL_T.U16);
+    ZRLE_DECODE(r, is, zis, pf, pb, PIXEL_T.U16);
   }
 
   private void zrleDecode24A(Rect r, InStream is,
-                             ZlibInStream zis, ByteBuffer buf,
+                             ZlibInStream zis,
                              PixelFormat pf, ModifiablePixelBuffer pb)
   {
-    ZRLE_DECODE(r, is, zis, buf, pf, pb, PIXEL_T.U24A);
+    ZRLE_DECODE(r, is, zis, pf, pb, PIXEL_T.U24A);
   }
 
   private void zrleDecode24B(Rect r, InStream is,
-                             ZlibInStream zis, ByteBuffer buf,
+                             ZlibInStream zis,
                              PixelFormat pf, ModifiablePixelBuffer pb)
   {
-    ZRLE_DECODE(r, is, zis, buf, pf, pb, PIXEL_T.U24B);
+    ZRLE_DECODE(r, is, zis, pf, pb, PIXEL_T.U24B);
   }
 
   private void zrleDecode32(Rect r, InStream is,
-                            ZlibInStream zis, ByteBuffer buf,
+                            ZlibInStream zis,
                             PixelFormat pf, ModifiablePixelBuffer pb)
   {
-    ZRLE_DECODE(r, is, zis, buf, pf, pb, PIXEL_T.U32);
+    ZRLE_DECODE(r, is, zis, pf, pb, PIXEL_T.U32);
   }
 
   private void ZRLE_DECODE(Rect r, InStream is,
-                           ZlibInStream zis, ByteBuffer buf,
+                           ZlibInStream zis,
                            PixelFormat pf, ModifiablePixelBuffer pb,
                            PIXEL_T pix_t)
   {
     int length = is.readU32();
     zis.setUnderlying(is, length);
     Rect t = new Rect();
+    ByteBuffer buf = ByteBuffer.allocate(64 * 64 * pf.bpp/8);
 
     for (t.tl.y = r.tl.y; t.tl.y < r.br.y; t.tl.y += 64) {
 
@@ -175,11 +176,12 @@ public class ZRLEDecoder extends Decoder {
         for (int i = 0; i < palSize; i++) {
           palette.put(READ_PIXEL(zis, pix_t));
         }
+        palette.flip();
 
         if (palSize == 1) {
-          ByteBuffer pix = 
-            ByteBuffer.allocate(pf.bpp/8).put(palette.array(), 0, pf.bpp/8);
-          pb.fillRect(pf, t, pix.array());
+          byte[] pix = new byte[pf.bpp/8];
+          palette.get(pix);
+          pb.fillRect(pf, t, pix);
           continue;
         }
 
@@ -191,12 +193,12 @@ public class ZRLEDecoder extends Decoder {
             case U24A:
             case U24B:
               ByteBuffer ptr = buf.duplicate();
-              for (int iptr=0; iptr < t.area(); iptr++) {
+              for (int i=0; i < t.area(); i++) {
                 ptr.put(READ_PIXEL(zis, pix_t));
               }
               break;
             default:
-              zis.readBytes(buf, t.area() * (pf.bpp/8));
+              zis.readBytes(buf.duplicate(), t.area() * (pf.bpp/8));
             }
 
           } else {
@@ -241,12 +243,12 @@ public class ZRLEDecoder extends Decoder {
                 len += b;
               } while (b == 255);
 
-              if (end - ptr.position() < len*(pf.bpp/8)) {
+              if (end - ptr.position() < len*pf.bpp/8) {
                 System.err.println("ZRLE decode error\n");
                 throw new Exception("ZRLE decode error");
               }
 
-              while (len-- > 0) ptr.put(pix);
+              while (len-- > 0) ptr.put(pix.array());
 
             }
           } else {
@@ -265,7 +267,7 @@ public class ZRLEDecoder extends Decoder {
                   len += b;
                 } while (b == 255);
 
-                if (end - ptr.position() < len*(pf.bpp/8)) {
+                if (end - ptr.position() < len*pf.bpp/8) {
                   System.err.println("ZRLE decode error\n");
                   throw new Exception("ZRLE decode error");
                 }
@@ -273,8 +275,10 @@ public class ZRLEDecoder extends Decoder {
 
               index &= 127;
 
-              while (len-- > 0) ptr.put(palette.array(), index*pf.bpp/8, pf.bpp/8);
+              ByteBuffer pix = ByteBuffer.allocate(pf.bpp/8);
+              pix.put(palette.array(), index*pf.bpp/8, pf.bpp/8);
 
+              while (len-- > 0) ptr.put(pix.array());
             }
           }
         }