diff options
Diffstat (limited to 'java/com/tigervnc/rfb/ZRLEDecoder.java')
-rw-r--r-- | java/com/tigervnc/rfb/ZRLEDecoder.java | 210 |
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; } |