You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
296 lines
8.3 KiB
296 lines
8.3 KiB
/* |
|
* 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
|
|
|