aboutsummaryrefslogtreecommitdiffstats
path: root/java/com/tigervnc/rfb/ZRLEDecoder.java
diff options
context:
space:
mode:
Diffstat (limited to 'java/com/tigervnc/rfb/ZRLEDecoder.java')
-rw-r--r--java/com/tigervnc/rfb/ZRLEDecoder.java210
1 files changed, 172 insertions, 38 deletions
diff --git a/java/com/tigervnc/rfb/ZRLEDecoder.java b/java/com/tigervnc/rfb/ZRLEDecoder.java
index e706510f..c1f908ab 100644
--- a/java/com/tigervnc/rfb/ZRLEDecoder.java
+++ b/java/com/tigervnc/rfb/ZRLEDecoder.java
@@ -18,22 +18,143 @@
package com.tigervnc.rfb;
+import java.awt.image.*;
+import java.nio.*;
+import java.util.*;
+
import com.tigervnc.rdr.*;
public class ZRLEDecoder extends Decoder {
- public ZRLEDecoder(CMsgReader reader_) {
- reader = reader_;
+ private static int 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();
+ }
+
+ private static int 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();
+ }
+
+ public ZRLEDecoder() {
+ super(DecoderFlags.DecoderOrdered);
zis = new ZlibInStream();
}
- public void readRect(Rect r, CMsgHandler handler) {
- InStream is = reader.getInStream();
- int[] buf = reader.getImageBuf(64 * 64 * 4);
- int bpp = handler.cp.pf().bpp;
- int bytesPerPixel = (bpp > 24 ? 3 : bpp / 8);
- boolean bigEndian = handler.cp.pf().bigEndian;
+ public void readRect(Rect r, InStream is,
+ ConnParams cp, OutStream os)
+ {
+ int len;
+ len = is.readU32();
+ os.writeU32(len);
+ os.copyBytes(is, len);
+ }
+
+ public void decodeRect(Rect r, Object buffer,
+ int buflen, ConnParams cp,
+ ModifiablePixelBuffer pb)
+ {
+ 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 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);
+ }
+ 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();
+ case U16:
+ b.putInt(is.readOpaque16());
+ return (ByteBuffer)ByteBuffer.allocate(2).put(b.array(), 2, 2).rewind();
+ case U24A:
+ return (ByteBuffer)b.putInt(readOpaque24A(is)).rewind();
+ case U24B:
+ return (ByteBuffer)b.putInt(readOpaque24B(is)).rewind();
+ case U32:
+ default:
+ return (ByteBuffer)b.putInt(is.readOpaque32()).rewind();
+ }
+ }
+
+ private void zrleDecode8(Rect r, InStream is,
+ ZlibInStream zis, ByteBuffer buf,
+ PixelFormat pf, ModifiablePixelBuffer pb)
+ {
+ ZRLE_DECODE(r, is, zis, buf, pf, pb, PIXEL_T.U8);
+ }
+
+ private void zrleDecode16(Rect r, InStream is,
+ ZlibInStream zis, ByteBuffer buf,
+ PixelFormat pf, ModifiablePixelBuffer pb)
+ {
+ ZRLE_DECODE(r, is, zis, buf, pf, pb, PIXEL_T.U16);
+ }
+
+ private void zrleDecode24A(Rect r, InStream is,
+ ZlibInStream zis, ByteBuffer buf,
+ PixelFormat pf, ModifiablePixelBuffer pb)
+ {
+ ZRLE_DECODE(r, is, zis, buf, pf, pb, PIXEL_T.U24A);
+ }
+
+ private void zrleDecode24B(Rect r, InStream is,
+ ZlibInStream zis, ByteBuffer buf,
+ PixelFormat pf, ModifiablePixelBuffer pb)
+ {
+ ZRLE_DECODE(r, is, zis, buf, pf, pb, PIXEL_T.U24B);
+ }
+
+ private void zrleDecode32(Rect r, InStream is,
+ ZlibInStream zis, ByteBuffer buf,
+ PixelFormat pf, ModifiablePixelBuffer pb)
+ {
+ ZRLE_DECODE(r, is, zis, buf, pf, pb, PIXEL_T.U32);
+ }
+
+ private void ZRLE_DECODE(Rect r, InStream is,
+ ZlibInStream zis, ByteBuffer buf,
+ PixelFormat pf, ModifiablePixelBuffer pb,
+ PIXEL_T pix_t)
+ {
int length = is.readU32();
zis.setUnderlying(is, length);
Rect t = new Rect();
@@ -49,13 +170,16 @@ public class ZRLEDecoder extends Decoder {
int mode = zis.readU8();
boolean rle = (mode & 128) != 0;
int palSize = mode & 127;
- int[] palette = new int[128];
+ ByteBuffer palette = ByteBuffer.allocate(128 * pf.bpp/8);
- zis.readPixels(palette, palSize, bytesPerPixel, bigEndian);
+ for (int i = 0; i < palSize; i++) {
+ palette.put(READ_PIXEL(zis, pix_t));
+ }
if (palSize == 1) {
- int pix = palette[0];
- handler.fillRect(t, pix);
+ ByteBuffer pix =
+ ByteBuffer.allocate(pf.bpp/8).put(palette.array(), 0, pf.bpp/8);
+ pb.fillRect(pf, t, pix.array());
continue;
}
@@ -63,8 +187,17 @@ public class ZRLEDecoder extends Decoder {
if (palSize == 0) {
// raw
-
- zis.readPixels(buf, t.area(), bytesPerPixel, bigEndian);
+ switch (pix_t) {
+ case U24A:
+ case U24B:
+ ByteBuffer ptr = buf.duplicate();
+ for (int iptr=0; iptr < t.area(); iptr++) {
+ ptr.put(READ_PIXEL(zis, pix_t));
+ }
+ break;
+ default:
+ zis.readBytes(buf, t.area() * (pf.bpp/8));
+ }
} else {
@@ -72,21 +205,21 @@ public class ZRLEDecoder extends Decoder {
int bppp = ((palSize > 16) ? 8 :
((palSize > 4) ? 4 : ((palSize > 2) ? 2 : 1)));
- int ptr = 0;
+ ByteBuffer ptr = buf.duplicate();
for (int i = 0; i < t.height(); i++) {
- int eol = ptr + t.width();
+ int eol = ptr.position() + t.width()*pf.bpp/8;
int b = 0;
int nbits = 0;
- while (ptr < eol) {
+ while (ptr.position() < eol) {
if (nbits == 0) {
b = zis.readU8();
nbits = 8;
}
nbits -= bppp;
int index = (b >> nbits) & ((1 << bppp) - 1) & 127;
- buf[ptr++] = palette[index];
+ ptr.put(palette.array(), index*pf.bpp/8, pf.bpp/8);
}
}
}
@@ -97,10 +230,10 @@ public class ZRLEDecoder extends Decoder {
// plain RLE
- int ptr = 0;
- int end = ptr + t.area();
- while (ptr < end) {
- int pix = zis.readPixel(bytesPerPixel, bigEndian);
+ ByteBuffer ptr = buf.duplicate();
+ int end = ptr.position() + t.area()*pf.bpp/8;
+ while (ptr.position() < end) {
+ ByteBuffer pix = READ_PIXEL(zis, pix_t);
int len = 1;
int b;
do {
@@ -108,19 +241,21 @@ public class ZRLEDecoder extends Decoder {
len += b;
} while (b == 255);
- if (!(len <= end - ptr))
- throw new Exception("ZRLEDecoder: assertion (len <= end - ptr)"
- +" failed");
+ 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) buf[ptr++] = pix;
}
} else {
// palette RLE
- int ptr = 0;
- int end = ptr + t.area();
- while (ptr < end) {
+ ByteBuffer ptr = buf.duplicate();
+ int end = ptr.position() + t.area()*pf.bpp/8;
+ while (ptr.position() < end) {
int index = zis.readU8();
int len = 1;
if ((index & 128) != 0) {
@@ -130,27 +265,26 @@ public class ZRLEDecoder extends Decoder {
len += b;
} while (b == 255);
- if (!(len <= end - ptr))
- throw new Exception("ZRLEDecoder: assertion "
- +"(len <= end - ptr) failed");
+ if (end - ptr.position() < len*(pf.bpp/8)) {
+ System.err.println("ZRLE decode error\n");
+ throw new Exception("ZRLE decode error");
+ }
}
index &= 127;
- int pix = palette[index];
+ while (len-- > 0) ptr.put(palette.array(), index*pf.bpp/8, pf.bpp/8);
- while (len-- > 0) buf[ptr++] = pix;
}
}
}
- handler.imageRect(t, buf);
+ pb.imageRect(pf, t, buf.array());
}
}
- zis.reset();
+ zis.removeUnderlying();
}
- CMsgReader reader;
- ZlibInStream zis;
+ private ZlibInStream zis;
}