summaryrefslogtreecommitdiffstats
path: root/libvncclient/trle.c
diff options
context:
space:
mode:
Diffstat (limited to 'libvncclient/trle.c')
-rw-r--r--libvncclient/trle.c296
1 files changed, 296 insertions, 0 deletions
diff --git a/libvncclient/trle.c b/libvncclient/trle.c
new file mode 100644
index 0000000..b8d6e5c
--- /dev/null
+++ b/libvncclient/trle.c
@@ -0,0 +1,296 @@
+/*
+ * Copyright (C) 2017 Wiki Wang <wikiwang@live.com>. All Rights Reserved.
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+
+/*
+ * trle.c - handle trle encoding.
+ *
+ * This file shouldn't be compiled directly. It is included multiple times by
+ * rfbproto.c, each time with a different definition of the macro BPP. For
+ * each value of BPP, this file defines a function which handles a trle
+ * encoded rectangle with BPP bits per pixel.
+ */
+
+#ifndef REALBPP
+#define REALBPP BPP
+#endif
+
+#if !defined(UNCOMP) || UNCOMP == 0
+#define HandleTRLE CONCAT2E(HandleTRLE, REALBPP)
+#elif UNCOMP > 0
+#define HandleTRLE CONCAT3E(HandleTRLE, REALBPP, Down)
+#else
+#define HandleTRLE CONCAT3E(HandleTRLE, REALBPP, Up)
+#endif
+#define CARDBPP CONCAT3E(uint, BPP, _t)
+#define CARDREALBPP CONCAT3E(uint, REALBPP, _t)
+
+#if REALBPP != BPP && defined(UNCOMP) && UNCOMP != 0
+#if UNCOMP > 0
+#define UncompressCPixel(pointer) ((*(CARDBPP *)pointer) >> UNCOMP)
+#else
+#define UncompressCPixel(pointer) ((*(CARDBPP *)pointer) << (-(UNCOMP)))
+#endif
+#else
+#define UncompressCPixel(pointer) (*(CARDBPP *)pointer)
+#endif
+
+static rfbBool HandleTRLE(rfbClient *client, int rx, int ry, int rw, int rh) {
+ int x, y, w, h;
+ uint8_t type, last_type;
+ int min_buffer_size = 16 * 16 * (REALBPP / 8) * 2;
+ uint8_t *buffer;
+ CARDBPP palette[128];
+ int bpp, mask, divider;
+ CARDBPP color;
+
+ /* First make sure we have a large enough raw buffer to hold the
+ * decompressed data. In practice, with a fixed REALBPP, fixed frame
+ * buffer size and the first update containing the entire frame
+ * buffer, this buffer allocation should only happen once, on the
+ * first update.
+ */
+ if (client->raw_buffer_size < min_buffer_size) {
+
+ if (client->raw_buffer != NULL) {
+
+ free(client->raw_buffer);
+ }
+
+ client->raw_buffer_size = min_buffer_size;
+ client->raw_buffer = (char *)malloc(client->raw_buffer_size);
+ }
+
+ rfbClientLog("Update %d %d %d %d\n", rx, ry, rw, rh);
+
+ for (y = ry; y < ry + rh; y += 16) {
+ for (x = rx; x < rx + rw; x += 16) {
+ w = h = 16;
+ if (rx + rw - x < 16)
+ w = rx + rw - x;
+ if (ry + rh - y < 16)
+ h = ry + rh - y;
+
+ if (!ReadFromRFBServer(client, &type, 1))
+ return FALSE;
+
+ buffer = client->raw_buffer;
+
+ switch (type) {
+ case_0:
+ case 0: {
+ if (!ReadFromRFBServer(client, buffer, w * h * REALBPP / 8))
+ return FALSE;
+#if REALBPP != BPP
+ int i, j;
+
+ for (j = y * client->width; j < (y + h) * client->width;
+ j += client->width)
+ for (i = x; i < x + w; i++, buffer += REALBPP / 8)
+ ((CARDBPP *)client->frameBuffer)[j + i] = UncompressCPixel(buffer);
+#else
+ client->GotBitmap(client, buffer, x, y, w, h);
+#endif
+ type = last_type;
+ break;
+ }
+ case 1: {
+ if (!ReadFromRFBServer(client, buffer, REALBPP / 8))
+ return FALSE;
+
+ color = UncompressCPixel(buffer);
+
+ client->GotFillRect(client, x, y, w, h, color);
+
+ last_type = type;
+ break;
+ }
+ case_127:
+ case 127:
+ switch (last_type) {
+ case 0:
+ return FALSE;
+ case 1:
+ client->GotFillRect(client, x, y, w, h, color);
+ type = last_type;
+ break;
+ case 128:
+ return FALSE;
+ default:
+ if (last_type >= 130) {
+ last_type = last_type & 0x7f;
+
+ bpp = (last_type > 4 ? (last_type > 16 ? 8 : 4)
+ : (last_type > 2 ? 2 : 1)),
+ mask = (1 << bpp) - 1, divider = (8 / bpp);
+ }
+ if (last_type <= 16) {
+ int i, j, shift;
+
+ if (!ReadFromRFBServer(client, buffer,
+ (w + divider - 1) / divider * h))
+ return FALSE;
+
+ /* read palettized pixels */
+ for (j = y * client->width; j < (y + h) * client->width;
+ j += client->width) {
+ for (i = x, shift = 8 - bpp; i < x + w; i++) {
+ ((CARDBPP *)client->frameBuffer)[j + i] =
+ palette[((*buffer) >> shift) & mask];
+ shift -= bpp;
+ if (shift < 0) {
+ shift = 8 - bpp;
+ buffer++;
+ }
+ }
+ if (shift < 8 - bpp)
+ buffer++;
+
+ type = last_type;
+ }
+ } else
+ return FALSE;
+ }
+ break;
+ case 128: {
+ int i = 0, j = 0;
+ while (j < h) {
+ int color, length;
+ /* read color */
+ if (!ReadFromRFBServer(client, buffer, REALBPP / 8 + 1))
+ return FALSE;
+ color = UncompressCPixel(buffer);
+ buffer += REALBPP / 8;
+ /* read run length */
+ length = 1;
+ while (*buffer == 0xff) {
+ if (!ReadFromRFBServer(client, buffer + 1, 1))
+ return FALSE;
+ length += *buffer;
+ buffer++;
+ }
+ length += *buffer;
+ buffer++;
+ while (j < h && length > 0) {
+ ((CARDBPP *)client->frameBuffer)[(y + j) * client->width + x + i] =
+ color;
+ length--;
+ i++;
+ if (i >= w) {
+ i = 0;
+ j++;
+ }
+ }
+ if (length > 0)
+ rfbClientLog("Warning: possible TRLE corruption\n");
+ }
+
+ type = last_type;
+
+ break;
+ }
+ case_129:
+ case 129: {
+ int i, j;
+ /* read palettized pixels */
+ i = j = 0;
+ while (j < h) {
+ int color, length;
+ /* read color */
+ if (!ReadFromRFBServer(client, buffer, 1))
+ return FALSE;
+ color = palette[(*buffer) & 0x7f];
+ length = 1;
+ if (*buffer & 0x80) {
+ if (!ReadFromRFBServer(client, buffer + 1, 1))
+ return FALSE;
+ buffer++;
+ /* read run length */
+ while (*buffer == 0xff) {
+ if (!ReadFromRFBServer(client, buffer + 1, 1))
+ return FALSE;
+ length += *buffer;
+ buffer++;
+ }
+ length += *buffer;
+ }
+ buffer++;
+ while (j < h && length > 0) {
+ ((CARDBPP *)client->frameBuffer)[(y + j) * client->width + x + i] =
+ color;
+ length--;
+ i++;
+ if (i >= w) {
+ i = 0;
+ j++;
+ }
+ }
+ if (length > 0)
+ rfbClientLog("Warning: possible TRLE corruption\n");
+ }
+
+ if (type == 129) {
+ type = last_type;
+ }
+
+ break;
+ }
+ default:
+ if (type <= 16) {
+ int i;
+
+ bpp = (type > 4 ? (type > 16 ? 8 : 4) : (type > 2 ? 2 : 1)),
+ mask = (1 << bpp) - 1, divider = (8 / bpp);
+
+ if (!ReadFromRFBServer(client, buffer, type * REALBPP / 8))
+ return FALSE;
+
+ /* read palette */
+ for (i = 0; i < type; i++, buffer += REALBPP / 8)
+ palette[i] = UncompressCPixel(buffer);
+
+ last_type = type;
+ goto case_127;
+ } else if (type >= 130) {
+ int i;
+
+ if (!ReadFromRFBServer(client, buffer, (type - 128) * REALBPP / 8))
+ return FALSE;
+
+ /* read palette */
+ for (i = 0; i < type - 128; i++, buffer += REALBPP / 8)
+ palette[i] = UncompressCPixel(buffer);
+
+ last_type = type;
+ goto case_129;
+ } else
+ return FALSE;
+ }
+ last_type = type;
+ }
+ }
+
+ return TRUE;
+}
+
+#undef CARDBPP
+#undef CARDREALBPP
+#undef HandleTRLE
+#undef UncompressCPixel
+#undef REALBPP
+#undef UNCOMP