changeset 539:cb7c23cca231

fix ZRLEDecoder
author riono
date Thu, 17 Oct 2019 18:12:27 +0900
parents 6620e04f994c
children 5812a47e293a
files src/main/java/com/glavsoft/rfb/encoding/decoder/ZRLEDecoder.java src/viewer_swing/java/com/glavsoft/viewer/swing/SwingViewerWindow.java
diffstat 2 files changed, 138 insertions(+), 117 deletions(-) [+]
line wrap: on
line diff
--- a/src/main/java/com/glavsoft/rfb/encoding/decoder/ZRLEDecoder.java	Thu Jun 13 18:19:53 2019 +0900
+++ b/src/main/java/com/glavsoft/rfb/encoding/decoder/ZRLEDecoder.java	Thu Oct 17 18:12:27 2019 +0900
@@ -38,10 +38,10 @@
 
 public class ZRLEDecoder extends ZlibDecoder {
 	private static final int MAX_TILE_SIZE = 64;
-    private int[] decodedBitmap;
-    private int[] palette;
+	private int[] decodedBitmap;
+	private int[] palette;
 
-    class TileLoop {
+	class TileLoop {
 		private final boolean blocking;
 		private final int half;
 		private int deflate_size = 55507;
@@ -53,7 +53,6 @@
 		private int prevC1Offset;
 		private int prevoffset;
 		private Deflater deflater;
-		private int rectPos;
 		private int ztileInLine;
 		private int hwidth;
 		private int hc1width;
@@ -65,31 +64,33 @@
 		 * Multicast framebufferUpdate to children.
 		 * read FrameBuffferUpdate. If it is ZLE, make it ZLEE which is self contained compressed packet.
 		 * put the packet to the multicastqueue. Then normal rendering engine read the same stream using is.reset().
-		 *
+		 * <p>
 		 * Haeder
-		 *    messageID  ( FrameBuffer Update
-		 *    1 byte padding
-		 *    2 byte numberofrectangle
-		 *      2 - U16 - x-position
-		 *      2 - U16 - y-position
-		 *      2 - U16 - width
-		 *      2 - U16 - height
-		 *      4 - S32 - encoding-type
-		 *      4 byte datalengths
-		 *      datalengths databyte
+		 * messageID  ( FrameBuffer Update
+		 * 1 byte padding
+		 * 2 byte numberofrectangle
+		 * 2 - U16 - x-position
+		 * 2 - U16 - y-position
+		 * 2 - U16 - width
+		 * 2 - U16 - height
+		 * 4 - S32 - encoding-type
+		 * 4 byte datalengths
+		 * datalengths databyte
 		 *
 		 * @throws TransportException
 		 * @throws UnsupportedEncodingException
 		 */
 
 		public TileLoop(int offset) {
-			prevoffset = prevLineOffset = prevC1Offset = offset;
-			if (offset < deflate_size+spanGap) {
+			prevoffset = prevLineOffset = offset;
+			prevC1Offset = 0;
+			if (offset < deflate_size + spanGap) {
 				// packet size fit in broadcast send it all at once
 				blocking = false;
 			} else
 				blocking = true;
-			discard = 0; half = 0;
+			discard = 0;
+			half = 0;
 		}
 
 		private void zrleeBlocking(TreeRFBProto rfb, ByteBuffer header, FramebufferUpdateRectangle rect, byte bytes[]) {
@@ -99,7 +100,7 @@
 			c1.put(header.get(0));
 			c1rect = new FramebufferUpdateRectangle(rect.x, rect.y, 0, 0);
 			if (!blocking) {
-				deflater.setInput(bytes,0,prevoffset);
+				deflater.setInput(bytes, 0, prevoffset);
 				deflater.deflate(c1);
 				flushMuticast(rfb);
 			}
@@ -107,7 +108,8 @@
 		}
 
 		private void newMulticastPacket(TreeRFBProto rfb, FramebufferUpdateRectangle rect) {
-			c1 = rfb.multicastqueue.allocate(deflate_size);
+			c1 = rfb.multicastqueue.allocate(deflate_size + 20);
+			c1.limit(c1.limit() - 20);
 			if (rfb.addSerialNum)
 				c1.putLong(rfb.counter++);
 			if (rfb.checkDelay)
@@ -116,39 +118,38 @@
 			c1.put((byte) 0);
 			c1.put((byte) 0);
 			c1.putShort((short) 0);
-			c1.position(c1.position()+16);
+			c1.position(c1.position() + 16);
 			c1.putInt(0);     // should be data length
+			prevC1Offset = c1.position();
 			width = 0;
-			rectPos = 4;
 			ztileInLine = 0;
 		}
 
 		int spanGap = 128;
 		/**
-		 *
 		 * Series of tiles compose at most three rectangles. SYNC_FLUSH is necessary on
 		 * rectangle boundaries.
-		 *
-		 *                +----+
-		 *                |  | |   phase 0
-		 *     +---------------+
-		 *     |       |       |   phase 1
-		 *     +----+----------+
-		 *     |  | |              phase 2
-		 *     +----+
-		 *
+		 * <p>
+		 * +----+
+		 * |  | |   phase 0
+		 * +---------------+
+		 * |       |       |   phase 1
+		 * +----+----------+
+		 * |  | |              phase 2
+		 * +----+
+		 * <p>
 		 * Broadcast packet have to less than 64kbytes
-		 *     A tile 64x64x3 11288byte, a packet can contain 5 raw tiles, when these are
-		 *     compressed 10 to 100 tiles can be stored. It is impossible to predict the
-		 *     compression rate. To check the compressed capacity, Deflate.needsInputs() can
-		 *     be used. If needsInputs() is false on SYNC_FLUSH, smaller input is necessary.
-		 *
-		 *     We'll try 512 tiles before SYNC_FLUSH in a phase, if it fails try flush former 256 tiles.
-		 *     If it will failed again, flush the previous line and do flush 512 tiles in new Packet.
-		 *     If it failed again try former 256 tiles flushed, if this failes again dicard the former half.
-		 *     The last case cannot happen but former 256 tiles have to be flushed, because the next 256 lines
-		 *     may failed again and restart the from this point.
-		 *     The next packet start with later 256 tiles filled and unflushed.
+		 * A tile 64x64x3 11288byte, a packet can contain 5 raw tiles, when these are
+		 * compressed 10 to 100 tiles can be stored. It is impossible to predict the
+		 * compression rate. To check the compressed capacity, Deflate.needsInputs() can
+		 * be used. If needsInputs() is false on SYNC_FLUSH, smaller input is necessary.
+		 * <p>
+		 * We'll try 512 tiles before SYNC_FLUSH in a phase, if it fails try flush former 256 tiles.
+		 * If it will failed again, flush the previous line and do flush 512 tiles in new Packet.
+		 * If it failed again try former 256 tiles flushed, if this failes again dicard the former half.
+		 * The last case cannot happen but former 256 tiles have to be flushed, because the next 256 lines
+		 * may failed again and restart the from this point.
+		 * The next packet start with later 256 tiles filled and unflushed.
 		 *
 		 * @param rfb
 		 * @param last
@@ -158,22 +159,23 @@
 		 * @param tileW
 		 * @param tileH
 		 */
-		
+
 		int MAX_ZTILE = 512;
 
 		public void multicastPut(TreeRFBProto rfb, boolean last, FramebufferUpdateRectangle rect, byte[] bytes, int offset, int tileW, int tileH) {
 			if (!blocking) return;
 			int span = offset - prevoffset;
-			deflater.setInput(bytes,prevoffset,span);
+			deflater.setInput(bytes, prevoffset, span);
 			prevoffset = offset;
-			c1rect.width  += tileW; width += tileW;
+			c1rect.width += tileW;
+			width += tileW;
 			if (c1rect.x > rect.x) {  // phase 0
-				if (c1rect.x+c1rect.width < rect.x+rect.width) {
-					compressAndCheckFlush(rfb, rect, bytes, offset,false, last);
+				if (c1rect.x + c1rect.width < rect.x + rect.width) {
+					compressAndCheckFlush(rfb, rect, bytes, offset, false, last);
 				} else {
-					c1rect.width = rect.x+rect.width-c1rect.x ;
+					c1rect.width = rect.x + rect.width - c1rect.x;
 					c1rect.height += tileH;
-					compressAndCheckFlush(rfb,rect,bytes,offset,true, last);
+					compressAndCheckFlush(rfb, rect, bytes, offset, true, last);
 				}
 			} else {  // phase 1
 				if (width >= rect.width) {
@@ -181,8 +183,7 @@
 					width = 0;
 					c1rect.height += tileH;
 					prevLineOffset = offset;
-					prevC1Offset = c1.position();
-					compressAndCheckFlush(rfb,rect,bytes,offset,true, last);
+					compressAndCheckFlush(rfb, rect, bytes, offset, true, last);
 				} else {
 					compressAndCheckFlush(rfb, rect, bytes, offset, false, last);
 				}
@@ -196,28 +197,39 @@
 			int headerLength = 20;
 			if (!deflater.needsInput()) {
 				deflater.finish();
-				if (offset != prevLineOffset) {  // phase 2
-					c1.limit(c1.limit() + headerLength);
-					// to make rectangle header shift last bytes
-					for (int i = 0; i < c1.position() - prevC1Offset; i++) {
-						c1.array()[prevC1Offset + headerLength - i] = c1.array() [prevC1Offset - i];
+				if (offset != prevLineOffset) {
+					prevC1Offset++;
+					// fix phase1 rectangle header
+					c1.putShort(prevC1Offset + 0, (short) c1rect.x);
+					c1.putShort(prevC1Offset + 2, (short) c1rect.y);
+					c1.putShort(prevC1Offset + 4, (short) c1rect.width);
+					c1.putShort(prevC1Offset + 6, (short) c1rect.height);
+					c1.putInt(prevC1Offset + 8, EncodingType.ZRLEE.getId());
+					c1.putInt(prevC1Offset + 12, c1.position() - prevC1Offset - 12); // data length
+					c1.putShort(2, (short) (c1.getShort(2) + 1));    // increment rectangle count
+
+					if (c1rect.x == rect.x) {  // phase0 needs no phase1
+						// make header space for phase2
+						c1.limit(c1.limit() + headerLength);
+						// to make rectangle header shift last bytes
+						for (int i = 0; i < c1.position() - prevC1Offset; i++) {
+							c1.array()[prevC1Offset + headerLength - i] = c1.array()[prevC1Offset - i];
+						}
 					}
-					c1.putShort(prevC1Offset + 1,  (short)c1rect.x);
-					c1.putShort(rectPos + 3,  (short)c1rect.y);
-					c1.putShort(rectPos + 5,  (short)c1rect.width);
-					c1.putShort(rectPos + 7, (short)c1rect.height);
-					c1.putInt(rectPos + 9,EncodingType.ZRLEE.getId());
-					c1.putInt(rectPos + 13, c1.position()-rectPos-12); // data length
-					c1.putShort(2,(short)(c1.getShort(2)+1));    // increment rectangle count
 				}
+				flushRectangle(rect);
 				flushMuticast(rfb);
 				newMulticastPacket(rfb, rect);
 				deflater.deflate(c1, Deflater.NO_FLUSH);
+			} else if (last) {
+				flushRectangle(rect);
+				flushMuticast(rfb);
+				return;
+			} else {
+				nextBlock(rect);
 			}
-			nextRectangle(rect);
 		}
 
-
 		/**
 		 * fix rectangle header
 		 * create next rectangle header
@@ -225,20 +237,19 @@
 		 * send muticast pacate if nessesally
 		 */
 		private void flushRectangle(FramebufferUpdateRectangle rect) {
-			c1.putShort(rectPos + 0,  (short)c1rect.x);
-			c1.putShort(rectPos + 2,  (short)c1rect.y);
-			c1.putShort(rectPos + 4,  (short)c1rect.width);
-			c1.putShort(rectPos + 6, (short)c1rect.height);
-			c1.putInt(rectPos + 8,EncodingType.ZRLEE.getId());
-			c1.putInt(rectPos + 12, c1.position()-rectPos-12); // data length
-			rectPos = c1.position();
-			c1.putShort(2,(short)(c1.getShort(2)+1));    // increment rectangle count
-			nextRectangle(rect);
+			c1.putShort(prevC1Offset + 0, (short) c1rect.x);
+			c1.putShort(prevC1Offset + 2, (short) c1rect.y);
+			c1.putShort(prevC1Offset + 4, (short) c1rect.width);
+			c1.putShort(prevC1Offset + 6, (short) c1rect.height);
+			c1.putInt(prevC1Offset + 8, EncodingType.ZRLEE.getId());
+			c1.putInt(prevC1Offset + 12, c1.position() - prevC1Offset - 12); // data length
+			c1.putShort(2, (short) (c1.getShort(2) + 1));    // increment rectangle count
 			ztileInLine = 0;
+			prevC1Offset = c1.position();
 		}
 
-		private void nextRectangle(FramebufferUpdateRectangle rect) {
-			if (c1rect.x+c1rect.width < rect.x+rect.width) {
+		private void nextBlock(FramebufferUpdateRectangle rect) {
+			if (c1rect.x + c1rect.width < rect.x + rect.width) {
 				c1rect.x = c1rect.width;   // next rectangle is phase 1
 			} else {
 				c1rect.x = rect.x;
@@ -271,19 +282,19 @@
 
 	@Override
 	public void decode(Reader reader, Renderer renderer,
-                       FramebufferUpdateRectangle rect) throws TransportException {
+					   FramebufferUpdateRectangle rect) throws TransportException {
 		int zippedLength = (int) reader.readUInt32();
 		if (0 == zippedLength) return;
 		int length = rect.width * rect.height * renderer.getBytesPerPixel();
 		byte[] bytes = unzip(reader, zippedLength, length, rect.getEncodingType());
 		decode1(renderer, null, rect, bytes, zippedLength, null);
-    }
+	}
 
 
 	public void multicastDecode(Reader reader, Renderer renderer,
-					   FramebufferUpdateRectangle rect, TreeRFBProto rfb) throws TransportException {
-    	ByteBuffer header = ByteBuffer.allocate(16);
-    	reader.read(header.array());
+								FramebufferUpdateRectangle rect, TreeRFBProto rfb) throws TransportException {
+		ByteBuffer header = ByteBuffer.allocate(16);
+		reader.read(header.array());
 		int zippedLength = (int) reader.readUInt32();
 		if (0 == zippedLength) return;
 		int length = rect.width * rect.height * renderer.getBytesPerPixel();
@@ -298,51 +309,61 @@
 
 		TileLoop tileloop = new TileLoop(zippedLength);
 		//System.out.println("decode1: "+rect);
-        if (null == palette) {
-            palette = new int [128];
-        }
-        if (null == decodedBitmap) {
-            decodedBitmap = new int[MAX_TILE_SIZE * MAX_TILE_SIZE];
-        }
+		if (null == palette) {
+			palette = new int[128];
+		}
+		if (null == decodedBitmap) {
+			decodedBitmap = new int[MAX_TILE_SIZE * MAX_TILE_SIZE];
+		}
 
-		if (rfbProto.multicastBlocking)  {
-			tileloop.zrleeBlocking(rfbProto, header, rect,bytes);
+		if (rfbProto.multicastBlocking) {
+			tileloop.zrleeBlocking(rfbProto, header, rect, bytes);
 		}
-		for (int tileY = rect.y; tileY < maxY; tileY += MAX_TILE_SIZE) {
-			int tileHeight = Math.min(maxY - tileY, MAX_TILE_SIZE);
+		try {
+			for (int tileY = rect.y; tileY < maxY; tileY += MAX_TILE_SIZE) {
+				int tileHeight = Math.min(maxY - tileY, MAX_TILE_SIZE);
 
-			for (int tileX = rect.x; tileX < maxX; tileX += MAX_TILE_SIZE) {
-				int tileWidth = Math.min(maxX - tileX, MAX_TILE_SIZE);
-				int subencoding = bytes[offset++] & 0x0ff;
-				if(subencoding!=0)
-					System.out.println("----------------"+subencoding);
-				// 128 -plain RLE, 130-255 - Palette RLE
-				boolean isRle = (subencoding & 128) != 0;
-				// 2 to 16 for raw packed palette data, 130 to 255 for Palette RLE (subencoding - 128)
-				int paletteSize = subencoding & 127;
-				offset += readPalette(bytes, offset, renderer, paletteSize);
-				if (1 == subencoding) { // A solid tile consisting of a single colour
-					renderer.fillRect(palette[0], tileX, tileY, tileWidth, tileHeight);
-				} else if (isRle) {
-					if (0 == paletteSize) { // subencoding == 128 (or paletteSize == 0) - Plain RLE
-						offset += decodePlainRle(bytes, offset, renderer, tileX, tileY, tileWidth, tileHeight);
+				for (int tileX = rect.x; tileX < maxX; tileX += MAX_TILE_SIZE) {
+					int tileWidth = Math.min(maxX - tileX, MAX_TILE_SIZE);
+					int subencoding = bytes[offset++] & 0x0ff;
+					if (subencoding != 0)
+						System.out.println("----------------" + subencoding);
+					// 128 -plain RLE, 130-255 - Palette RLE
+					boolean isRle = (subencoding & 128) != 0;
+					// 2 to 16 for raw packed palette data, 130 to 255 for Palette RLE (subencoding - 128)
+					int paletteSize = subencoding & 127;
+					offset += readPalette(bytes, offset, renderer, paletteSize);
+					if (1 == subencoding) { // A solid tile consisting of a single colour
+						renderer.fillRect(palette[0], tileX, tileY, tileWidth, tileHeight);
+					} else if (isRle) {
+						if (0 == paletteSize) { // subencoding == 128 (or paletteSize == 0) - Plain RLE
+							offset += decodePlainRle(bytes, offset, renderer, tileX, tileY, tileWidth, tileHeight);
+						} else {
+							offset += decodePaletteRle(bytes, offset, renderer, tileX, tileY, tileWidth, tileHeight);
+						}
 					} else {
-						offset += decodePaletteRle(bytes, offset, renderer, tileX, tileY, tileWidth, tileHeight);
-					}
-				} else {
-					if (0 == paletteSize) { // subencoding == 0 (or paletteSize == 0) - raw CPIXEL data
-						offset += decodeRaw(bytes, offset, renderer, tileX, tileY, tileWidth, tileHeight);
+						if (0 == paletteSize) { // subencoding == 0 (or paletteSize == 0) - raw CPIXEL data
+							offset += decodeRaw(bytes, offset, renderer, tileX, tileY, tileWidth, tileHeight);
 //						System.out.println("offset:"+offset);
-					} else {
-						offset += decodePacked(bytes, offset, renderer, paletteSize, tileX, tileY, tileWidth, tileHeight);
+						} else {
+							offset += decodePacked(bytes, offset, renderer, paletteSize, tileX, tileY, tileWidth, tileHeight);
+						}
 					}
+					if (rfbProto != null && rfbProto.multicastBlocking)
+						tileloop.multicastPut(rfbProto, false, rect, bytes, offset, tileWidth, tileHeight);
 				}
-				if (rfbProto != null && rfbProto.multicastBlocking) tileloop.multicastPut(rfbProto, false, rect, bytes,  offset, tileWidth, tileHeight);
 			}
+			if (rfbProto != null && rfbProto.multicastBlocking)
+				tileloop.multicastPut(rfbProto, true, rect, bytes, offset, 0, 0);
+		} catch (Exception e) {
+			if (rfbProto != null && rfbProto.multicastBlocking)
+				tileloop.multicastPut(rfbProto, true, rect, bytes, offset, 0, 0);
+			throw e;
 		}
-		if (rfbProto != null && rfbProto.multicastBlocking) tileloop.multicastPut(rfbProto, true, rect, bytes,  offset, 0, 0);
 	}
 
+
+
 	private int decodePlainRle(byte[] bytes, int offset, Renderer renderer,
 			int tileX, int tileY, int tileWidth, int tileHeight) {
 		int bytesPerCPixel = renderer.getBytesPerCPixel();
--- a/src/viewer_swing/java/com/glavsoft/viewer/swing/SwingViewerWindow.java	Thu Jun 13 18:19:53 2019 +0900
+++ b/src/viewer_swing/java/com/glavsoft/viewer/swing/SwingViewerWindow.java	Thu Oct 17 18:12:27 2019 +0900
@@ -627,7 +627,7 @@
                 processButtonsBarVisibility();
 
                 boolean needScrolling = processVScroll() || processHScroll();
-                oldMousePoint = mousePoint;
+                // oldMousePoint = mousePoint;
                 if (needScrolling) {
                     cancelShowExecutor();
                     setButtonsBarVisibleFS(false);