import com.tightvnc.vncviewer.RfbInputStream;
import com.tightvnc.vncviewer.ZlibInStream;
import java.awt.Graphics;
+import com.tightvnc.vncviewer.MemInStream;
+import java.awt.Color;
+import java.awt.Toolkit;
+import java.awt.image.MemoryImageSource;
+import java.io.IOException;
//
// Class that used for decoding ZRLE encoded data.
super(g, is, frameBufferW, frameBufferH);
}
+ //
+ // Handle a ZRLE-encoded rectangle.
+ //
+ // FIXME: Currently, session recording is not fully supported for ZRLE.
+ //
+
+ public void handleRect(int x, int y, int w, int h) throws IOException, Exception {
+ if (zrleInStream == null)
+ zrleInStream = new ZlibInStream();
+
+ int nBytes = rfbis.readU32();
+ if (nBytes > 64 * 1024 * 1024)
+ throw new Exception("ZRLE decoder: illegal compressed data size");
+
+ if (zrleBuf == null || zrleBufLen < nBytes) {
+ zrleBufLen = nBytes + 4096;
+ zrleBuf = new byte[zrleBufLen];
+ }
+
+ // FIXME: Do not wait for all the data before decompression.
+ rfbis.readFully(zrleBuf, 0, nBytes);
+
+ //
+ // Override handleRect method to decode RRE encoded data insted of
+ // raw pixel data.
+ //
+
+ if (rec.canWrite()) {
+ if (rec.isRecordFromBeginning()) {
+ rec.writeIntBE(nBytes);
+ rec.write(zrleBuf, 0, nBytes);
+ } else if (!zrleRecWarningShown) {
+ System.out.println("Warning: ZRLE session can be recorded" +
+ " only from the beginning");
+ System.out.println("Warning: Recorded file may be corrupted");
+ zrleRecWarningShown = true;
+ }
+ }
+
+ zrleInStream.setUnderlying(new MemInStream(zrleBuf, 0, nBytes), nBytes);
+
+ for (int ty = y; ty < y+h; ty += 64) {
+
+ int th = Math.min(y+h-ty, 64);
+
+ for (int tx = x; tx < x+w; tx += 64) {
+
+ int tw = Math.min(x+w-tx, 64);
+
+ int mode = zrleInStream.readU8();
+ boolean rle = (mode & 128) != 0;
+ int palSize = mode & 127;
+ int[] palette = new int[128];
+
+ readZrlePalette(palette, palSize);
+
+ if (palSize == 1) {
+ int pix = palette[0];
+ Color c = (bytesPerPixel == 1) ?
+ getColor256()[pix] : new Color(0xFF000000 | pix);
+ graphics.setColor(c);
+ graphics.fillRect(tx, ty, tw, th);
+ continue;
+ }
+
+ if (!rle) {
+ if (palSize == 0) {
+ readZrleRawPixels(tw, th);
+ } else {
+ readZrlePackedPixels(tw, th, palette, palSize);
+ }
+ } else {
+ if (palSize == 0) {
+ readZrlePlainRLEPixels(tw, th);
+ } else {
+ readZrlePackedRLEPixels(tw, th, palette);
+ }
+ }
+ handleUpdatedZrleTile(tx, ty, tw, th);
+ }
+ }
+ zrleInStream.reset();
+ }
+
+ //
+ // Override update() method cause we have own data that
+ // must be updated when framebuffer is resized or BPP is changed
+ //
+
+ public void update() {
+ // Images with raw pixels should be re-allocated on every change
+ // of geometry or pixel format.
+ int fbWidth = framebufferWidth;
+ int fbHeight = framebufferHeight;
+
+ if (bytesPerPixel == 1) {
+ RawDecoder.pixels24 = null;
+ RawDecoder.pixels8 = new byte[fbWidth * fbHeight];
+ RawDecoder.pixelsSource = new MemoryImageSource(fbWidth, fbHeight, getColorModel8(), pixels8, 0, fbWidth);
+ zrleTilePixels24 = null;
+ zrleTilePixels8 = new byte[64 * 64];
+ } else {
+ RawDecoder.pixels8 = null;
+ RawDecoder.pixels24 = new int[fbWidth * fbHeight];
+ RawDecoder.pixelsSource =
+ new MemoryImageSource(fbWidth, fbHeight, getColorModel24(), pixels24, 0, fbWidth);
+ zrleTilePixels8 = null;
+ zrleTilePixels24 = new int[64 * 64];
+ }
+ RawDecoder.pixelsSource.setAnimated(true);
+ RawDecoder.rawPixelsImage = Toolkit.getDefaultToolkit().createImage(pixelsSource);
+ }
+
+ //
+ // Copy pixels from zrleTilePixels8 or zrleTilePixels24, then update.
+ //
+
+ private void handleUpdatedZrleTile(int x, int y, int w, int h) {
+ Object src, dst;
+ if (bytesPerPixel == 1) {
+ src = zrleTilePixels8; dst = pixels8;
+ } else {
+ src = zrleTilePixels24; dst = pixels24;
+ }
+ int offsetSrc = 0;
+ int offsetDst = (y * framebufferWidth + x);
+ for (int j = 0; j < h; j++) {
+ System.arraycopy(src, offsetSrc, dst, offsetDst, w);
+ offsetSrc += w;
+ offsetDst += framebufferWidth;
+ }
+ handleUpdatedPixels(x, y, w, h);
+ }
+
//
// Private methods for reading ZRLE data
//