San Mehat | a430b2b | 2014-09-23 08:30:51 -0700 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2000, 2001 Const Kaplinsky. All Rights Reserved. |
| 3 | * |
| 4 | * This is free software; you can redistribute it and/or modify |
| 5 | * it under the terms of the GNU General Public License as published by |
| 6 | * the Free Software Foundation; either version 2 of the License, or |
| 7 | * (at your option) any later version. |
| 8 | * |
| 9 | * This software is distributed in the hope that it will be useful, |
| 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 12 | * GNU General Public License for more details. |
| 13 | * |
| 14 | * You should have received a copy of the GNU General Public License |
| 15 | * along with this software; if not, write to the Free Software |
| 16 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, |
| 17 | * USA. |
| 18 | */ |
| 19 | |
| 20 | #ifdef LIBVNCSERVER_HAVE_LIBZ |
| 21 | #ifdef LIBVNCSERVER_HAVE_LIBJPEG |
| 22 | |
| 23 | /* |
| 24 | * tight.c - handle ``tight'' encoding. |
| 25 | * |
| 26 | * This file shouldn't be compiled directly. It is included multiple |
| 27 | * times by rfbproto.c, each time with a different definition of the |
| 28 | * macro BPP. For each value of BPP, this file defines a function |
| 29 | * which handles a tight-encoded rectangle with BPP bits per pixel. |
| 30 | * |
| 31 | */ |
| 32 | |
| 33 | #define TIGHT_MIN_TO_COMPRESS 12 |
| 34 | |
| 35 | #define CARDBPP CONCAT3E(uint,BPP,_t) |
| 36 | #define filterPtrBPP CONCAT2E(filterPtr,BPP) |
| 37 | |
| 38 | #define HandleTightBPP CONCAT2E(HandleTight,BPP) |
| 39 | #define InitFilterCopyBPP CONCAT2E(InitFilterCopy,BPP) |
| 40 | #define InitFilterPaletteBPP CONCAT2E(InitFilterPalette,BPP) |
| 41 | #define InitFilterGradientBPP CONCAT2E(InitFilterGradient,BPP) |
| 42 | #define FilterCopyBPP CONCAT2E(FilterCopy,BPP) |
| 43 | #define FilterPaletteBPP CONCAT2E(FilterPalette,BPP) |
| 44 | #define FilterGradientBPP CONCAT2E(FilterGradient,BPP) |
| 45 | |
| 46 | #if BPP != 8 |
| 47 | #define DecompressJpegRectBPP CONCAT2E(DecompressJpegRect,BPP) |
| 48 | #endif |
| 49 | |
| 50 | #ifndef RGB_TO_PIXEL |
| 51 | |
| 52 | #define RGB_TO_PIXEL(bpp,r,g,b) \ |
| 53 | (((CARD##bpp)(r) & client->format.redMax) << client->format.redShift | \ |
| 54 | ((CARD##bpp)(g) & client->format.greenMax) << client->format.greenShift | \ |
| 55 | ((CARD##bpp)(b) & client->format.blueMax) << client->format.blueShift) |
| 56 | |
| 57 | #define RGB24_TO_PIXEL(bpp,r,g,b) \ |
| 58 | ((((CARD##bpp)(r) & 0xFF) * client->format.redMax + 127) / 255 \ |
| 59 | << client->format.redShift | \ |
| 60 | (((CARD##bpp)(g) & 0xFF) * client->format.greenMax + 127) / 255 \ |
| 61 | << client->format.greenShift | \ |
| 62 | (((CARD##bpp)(b) & 0xFF) * client->format.blueMax + 127) / 255 \ |
| 63 | << client->format.blueShift) |
| 64 | |
| 65 | #define RGB24_TO_PIXEL32(r,g,b) \ |
| 66 | (((uint32_t)(r) & 0xFF) << client->format.redShift | \ |
| 67 | ((uint32_t)(g) & 0xFF) << client->format.greenShift | \ |
| 68 | ((uint32_t)(b) & 0xFF) << client->format.blueShift) |
| 69 | |
| 70 | #endif |
| 71 | |
| 72 | /* Type declarations */ |
| 73 | |
| 74 | typedef void (*filterPtrBPP)(rfbClient* client, int, CARDBPP *); |
| 75 | |
| 76 | /* Prototypes */ |
| 77 | |
| 78 | static int InitFilterCopyBPP (rfbClient* client, int rw, int rh); |
| 79 | static int InitFilterPaletteBPP (rfbClient* client, int rw, int rh); |
| 80 | static int InitFilterGradientBPP (rfbClient* client, int rw, int rh); |
| 81 | static void FilterCopyBPP (rfbClient* client, int numRows, CARDBPP *destBuffer); |
| 82 | static void FilterPaletteBPP (rfbClient* client, int numRows, CARDBPP *destBuffer); |
| 83 | static void FilterGradientBPP (rfbClient* client, int numRows, CARDBPP *destBuffer); |
| 84 | |
| 85 | #if BPP != 8 |
| 86 | static rfbBool DecompressJpegRectBPP(rfbClient* client, int x, int y, int w, int h); |
| 87 | #endif |
| 88 | |
| 89 | /* Definitions */ |
| 90 | |
| 91 | static rfbBool |
| 92 | HandleTightBPP (rfbClient* client, int rx, int ry, int rw, int rh) |
| 93 | { |
| 94 | CARDBPP fill_colour; |
| 95 | uint8_t comp_ctl; |
| 96 | uint8_t filter_id; |
| 97 | filterPtrBPP filterFn; |
| 98 | z_streamp zs; |
| 99 | char *buffer2; |
| 100 | int err, stream_id, compressedLen, bitsPixel; |
| 101 | int bufferSize, rowSize, numRows, portionLen, rowsProcessed, extraBytes; |
| 102 | |
| 103 | if (!ReadFromRFBServer(client, (char *)&comp_ctl, 1)) |
| 104 | return FALSE; |
| 105 | |
| 106 | /* Flush zlib streams if we are told by the server to do so. */ |
| 107 | for (stream_id = 0; stream_id < 4; stream_id++) { |
| 108 | if ((comp_ctl & 1) && client->zlibStreamActive[stream_id]) { |
| 109 | if (inflateEnd (&client->zlibStream[stream_id]) != Z_OK && |
| 110 | client->zlibStream[stream_id].msg != NULL) |
| 111 | rfbClientLog("inflateEnd: %s\n", client->zlibStream[stream_id].msg); |
| 112 | client->zlibStreamActive[stream_id] = FALSE; |
| 113 | } |
| 114 | comp_ctl >>= 1; |
| 115 | } |
| 116 | |
| 117 | /* Handle solid rectangles. */ |
| 118 | if (comp_ctl == rfbTightFill) { |
| 119 | #if BPP == 32 |
| 120 | if (client->format.depth == 24 && client->format.redMax == 0xFF && |
| 121 | client->format.greenMax == 0xFF && client->format.blueMax == 0xFF) { |
| 122 | if (!ReadFromRFBServer(client, client->buffer, 3)) |
| 123 | return FALSE; |
| 124 | fill_colour = RGB24_TO_PIXEL32(client->buffer[0], client->buffer[1], client->buffer[2]); |
| 125 | } else { |
| 126 | if (!ReadFromRFBServer(client, (char*)&fill_colour, sizeof(fill_colour))) |
| 127 | return FALSE; |
| 128 | } |
| 129 | #else |
| 130 | if (!ReadFromRFBServer(client, (char*)&fill_colour, sizeof(fill_colour))) |
| 131 | return FALSE; |
| 132 | #endif |
| 133 | |
| 134 | FillRectangle(client, rx, ry, rw, rh, fill_colour); |
| 135 | |
| 136 | return TRUE; |
| 137 | } |
| 138 | |
| 139 | #if BPP == 8 |
| 140 | if (comp_ctl == rfbTightJpeg) { |
| 141 | rfbClientLog("Tight encoding: JPEG is not supported in 8 bpp mode.\n"); |
| 142 | return FALSE; |
| 143 | } |
| 144 | #else |
| 145 | if (comp_ctl == rfbTightJpeg) { |
| 146 | return DecompressJpegRectBPP(client, rx, ry, rw, rh); |
| 147 | } |
| 148 | #endif |
| 149 | |
| 150 | /* Quit on unsupported subencoding value. */ |
| 151 | if (comp_ctl > rfbTightMaxSubencoding) { |
| 152 | rfbClientLog("Tight encoding: bad subencoding value received.\n"); |
| 153 | return FALSE; |
| 154 | } |
| 155 | |
| 156 | /* |
| 157 | * Here primary compression mode handling begins. |
| 158 | * Data was processed with optional filter + zlib compression. |
| 159 | */ |
| 160 | |
| 161 | /* First, we should identify a filter to use. */ |
| 162 | if ((comp_ctl & rfbTightExplicitFilter) != 0) { |
| 163 | if (!ReadFromRFBServer(client, (char*)&filter_id, 1)) |
| 164 | return FALSE; |
| 165 | |
| 166 | switch (filter_id) { |
| 167 | case rfbTightFilterCopy: |
| 168 | filterFn = FilterCopyBPP; |
| 169 | bitsPixel = InitFilterCopyBPP(client, rw, rh); |
| 170 | break; |
| 171 | case rfbTightFilterPalette: |
| 172 | filterFn = FilterPaletteBPP; |
| 173 | bitsPixel = InitFilterPaletteBPP(client, rw, rh); |
| 174 | break; |
| 175 | case rfbTightFilterGradient: |
| 176 | filterFn = FilterGradientBPP; |
| 177 | bitsPixel = InitFilterGradientBPP(client, rw, rh); |
| 178 | break; |
| 179 | default: |
| 180 | rfbClientLog("Tight encoding: unknown filter code received.\n"); |
| 181 | return FALSE; |
| 182 | } |
| 183 | } else { |
| 184 | filterFn = FilterCopyBPP; |
| 185 | bitsPixel = InitFilterCopyBPP(client, rw, rh); |
| 186 | } |
| 187 | if (bitsPixel == 0) { |
| 188 | rfbClientLog("Tight encoding: error receiving palette.\n"); |
| 189 | return FALSE; |
| 190 | } |
| 191 | |
| 192 | /* Determine if the data should be decompressed or just copied. */ |
| 193 | rowSize = (rw * bitsPixel + 7) / 8; |
| 194 | if (rh * rowSize < TIGHT_MIN_TO_COMPRESS) { |
| 195 | if (!ReadFromRFBServer(client, (char*)client->buffer, rh * rowSize)) |
| 196 | return FALSE; |
| 197 | |
| 198 | buffer2 = &client->buffer[TIGHT_MIN_TO_COMPRESS * 4]; |
| 199 | filterFn(client, rh, (CARDBPP *)buffer2); |
| 200 | |
| 201 | CopyRectangle(client, (uint8_t *)buffer2, rx, ry, rw, rh); |
| 202 | |
| 203 | return TRUE; |
| 204 | } |
| 205 | |
| 206 | /* Read the length (1..3 bytes) of compressed data following. */ |
| 207 | compressedLen = (int)ReadCompactLen(client); |
| 208 | if (compressedLen <= 0) { |
| 209 | rfbClientLog("Incorrect data received from the server.\n"); |
| 210 | return FALSE; |
| 211 | } |
| 212 | |
| 213 | /* Now let's initialize compression stream if needed. */ |
| 214 | stream_id = comp_ctl & 0x03; |
| 215 | zs = &client->zlibStream[stream_id]; |
| 216 | if (!client->zlibStreamActive[stream_id]) { |
| 217 | zs->zalloc = Z_NULL; |
| 218 | zs->zfree = Z_NULL; |
| 219 | zs->opaque = Z_NULL; |
| 220 | err = inflateInit(zs); |
| 221 | if (err != Z_OK) { |
| 222 | if (zs->msg != NULL) |
| 223 | rfbClientLog("InflateInit error: %s.\n", zs->msg); |
| 224 | return FALSE; |
| 225 | } |
| 226 | client->zlibStreamActive[stream_id] = TRUE; |
| 227 | } |
| 228 | |
| 229 | /* Read, decode and draw actual pixel data in a loop. */ |
| 230 | |
| 231 | bufferSize = RFB_BUFFER_SIZE * bitsPixel / (bitsPixel + BPP) & 0xFFFFFFFC; |
| 232 | buffer2 = &client->buffer[bufferSize]; |
| 233 | if (rowSize > bufferSize) { |
| 234 | /* Should be impossible when RFB_BUFFER_SIZE >= 16384 */ |
| 235 | rfbClientLog("Internal error: incorrect buffer size.\n"); |
| 236 | return FALSE; |
| 237 | } |
| 238 | |
| 239 | rowsProcessed = 0; |
| 240 | extraBytes = 0; |
| 241 | |
| 242 | while (compressedLen > 0) { |
| 243 | if (compressedLen > ZLIB_BUFFER_SIZE) |
| 244 | portionLen = ZLIB_BUFFER_SIZE; |
| 245 | else |
| 246 | portionLen = compressedLen; |
| 247 | |
| 248 | if (!ReadFromRFBServer(client, (char*)client->zlib_buffer, portionLen)) |
| 249 | return FALSE; |
| 250 | |
| 251 | compressedLen -= portionLen; |
| 252 | |
| 253 | zs->next_in = (Bytef *)client->zlib_buffer; |
| 254 | zs->avail_in = portionLen; |
| 255 | |
| 256 | do { |
| 257 | zs->next_out = (Bytef *)&client->buffer[extraBytes]; |
| 258 | zs->avail_out = bufferSize - extraBytes; |
| 259 | |
| 260 | err = inflate(zs, Z_SYNC_FLUSH); |
| 261 | if (err == Z_BUF_ERROR) /* Input exhausted -- no problem. */ |
| 262 | break; |
| 263 | if (err != Z_OK && err != Z_STREAM_END) { |
| 264 | if (zs->msg != NULL) { |
| 265 | rfbClientLog("Inflate error: %s.\n", zs->msg); |
| 266 | } else { |
| 267 | rfbClientLog("Inflate error: %d.\n", err); |
| 268 | } |
| 269 | return FALSE; |
| 270 | } |
| 271 | |
| 272 | numRows = (bufferSize - zs->avail_out) / rowSize; |
| 273 | |
| 274 | filterFn(client, numRows, (CARDBPP *)buffer2); |
| 275 | |
| 276 | extraBytes = bufferSize - zs->avail_out - numRows * rowSize; |
| 277 | if (extraBytes > 0) |
| 278 | memcpy(client->buffer, &client->buffer[numRows * rowSize], extraBytes); |
| 279 | |
| 280 | CopyRectangle(client, (uint8_t *)buffer2, rx, ry+rowsProcessed, rw, numRows); |
| 281 | |
| 282 | rowsProcessed += numRows; |
| 283 | } |
| 284 | while (zs->avail_out == 0); |
| 285 | } |
| 286 | |
| 287 | if (rowsProcessed != rh) { |
| 288 | rfbClientLog("Incorrect number of scan lines after decompression.\n"); |
| 289 | return FALSE; |
| 290 | } |
| 291 | |
| 292 | return TRUE; |
| 293 | } |
| 294 | |
| 295 | /*---------------------------------------------------------------------------- |
| 296 | * |
| 297 | * Filter stuff. |
| 298 | * |
| 299 | */ |
| 300 | |
| 301 | static int |
| 302 | InitFilterCopyBPP (rfbClient* client, int rw, int rh) |
| 303 | { |
| 304 | client->rectWidth = rw; |
| 305 | |
| 306 | #if BPP == 32 |
| 307 | if (client->format.depth == 24 && client->format.redMax == 0xFF && |
| 308 | client->format.greenMax == 0xFF && client->format.blueMax == 0xFF) { |
| 309 | client->cutZeros = TRUE; |
| 310 | return 24; |
| 311 | } else { |
| 312 | client->cutZeros = FALSE; |
| 313 | } |
| 314 | #endif |
| 315 | |
| 316 | return BPP; |
| 317 | } |
| 318 | |
| 319 | static void |
| 320 | FilterCopyBPP (rfbClient* client, int numRows, CARDBPP *dst) |
| 321 | { |
| 322 | |
| 323 | #if BPP == 32 |
| 324 | int x, y; |
| 325 | |
| 326 | if (client->cutZeros) { |
| 327 | for (y = 0; y < numRows; y++) { |
| 328 | for (x = 0; x < client->rectWidth; x++) { |
| 329 | dst[y*client->rectWidth+x] = |
| 330 | RGB24_TO_PIXEL32(client->buffer[(y*client->rectWidth+x)*3], |
| 331 | client->buffer[(y*client->rectWidth+x)*3+1], |
| 332 | client->buffer[(y*client->rectWidth+x)*3+2]); |
| 333 | } |
| 334 | } |
| 335 | return; |
| 336 | } |
| 337 | #endif |
| 338 | |
| 339 | memcpy (dst, client->buffer, numRows * client->rectWidth * (BPP / 8)); |
| 340 | } |
| 341 | |
| 342 | static int |
| 343 | InitFilterGradientBPP (rfbClient* client, int rw, int rh) |
| 344 | { |
| 345 | int bits; |
| 346 | |
| 347 | bits = InitFilterCopyBPP(client, rw, rh); |
| 348 | if (client->cutZeros) |
| 349 | memset(client->tightPrevRow, 0, rw * 3); |
| 350 | else |
| 351 | memset(client->tightPrevRow, 0, rw * 3 * sizeof(uint16_t)); |
| 352 | |
| 353 | return bits; |
| 354 | } |
| 355 | |
| 356 | #if BPP == 32 |
| 357 | |
| 358 | static void |
| 359 | FilterGradient24 (rfbClient* client, int numRows, uint32_t *dst) |
| 360 | { |
| 361 | int x, y, c; |
| 362 | uint8_t thisRow[2048*3]; |
| 363 | uint8_t pix[3]; |
| 364 | int est[3]; |
| 365 | |
| 366 | for (y = 0; y < numRows; y++) { |
| 367 | |
| 368 | /* First pixel in a row */ |
| 369 | for (c = 0; c < 3; c++) { |
| 370 | pix[c] = client->tightPrevRow[c] + client->buffer[y*client->rectWidth*3+c]; |
| 371 | thisRow[c] = pix[c]; |
| 372 | } |
| 373 | dst[y*client->rectWidth] = RGB24_TO_PIXEL32(pix[0], pix[1], pix[2]); |
| 374 | |
| 375 | /* Remaining pixels of a row */ |
| 376 | for (x = 1; x < client->rectWidth; x++) { |
| 377 | for (c = 0; c < 3; c++) { |
| 378 | est[c] = (int)client->tightPrevRow[x*3+c] + (int)pix[c] - |
| 379 | (int)client->tightPrevRow[(x-1)*3+c]; |
| 380 | if (est[c] > 0xFF) { |
| 381 | est[c] = 0xFF; |
| 382 | } else if (est[c] < 0x00) { |
| 383 | est[c] = 0x00; |
| 384 | } |
| 385 | pix[c] = (uint8_t)est[c] + client->buffer[(y*client->rectWidth+x)*3+c]; |
| 386 | thisRow[x*3+c] = pix[c]; |
| 387 | } |
| 388 | dst[y*client->rectWidth+x] = RGB24_TO_PIXEL32(pix[0], pix[1], pix[2]); |
| 389 | } |
| 390 | |
| 391 | memcpy(client->tightPrevRow, thisRow, client->rectWidth * 3); |
| 392 | } |
| 393 | } |
| 394 | |
| 395 | #endif |
| 396 | |
| 397 | static void |
| 398 | FilterGradientBPP (rfbClient* client, int numRows, CARDBPP *dst) |
| 399 | { |
| 400 | int x, y, c; |
| 401 | CARDBPP *src = (CARDBPP *)client->buffer; |
| 402 | uint16_t *thatRow = (uint16_t *)client->tightPrevRow; |
| 403 | uint16_t thisRow[2048*3]; |
| 404 | uint16_t pix[3]; |
| 405 | uint16_t max[3]; |
| 406 | int shift[3]; |
| 407 | int est[3]; |
| 408 | |
| 409 | #if BPP == 32 |
| 410 | if (client->cutZeros) { |
| 411 | FilterGradient24(client, numRows, dst); |
| 412 | return; |
| 413 | } |
| 414 | #endif |
| 415 | |
| 416 | max[0] = client->format.redMax; |
| 417 | max[1] = client->format.greenMax; |
| 418 | max[2] = client->format.blueMax; |
| 419 | |
| 420 | shift[0] = client->format.redShift; |
| 421 | shift[1] = client->format.greenShift; |
| 422 | shift[2] = client->format.blueShift; |
| 423 | |
| 424 | for (y = 0; y < numRows; y++) { |
| 425 | |
| 426 | /* First pixel in a row */ |
| 427 | for (c = 0; c < 3; c++) { |
| 428 | pix[c] = (uint16_t)(((src[y*client->rectWidth] >> shift[c]) + thatRow[c]) & max[c]); |
| 429 | thisRow[c] = pix[c]; |
| 430 | } |
| 431 | dst[y*client->rectWidth] = RGB_TO_PIXEL(BPP, pix[0], pix[1], pix[2]); |
| 432 | |
| 433 | /* Remaining pixels of a row */ |
| 434 | for (x = 1; x < client->rectWidth; x++) { |
| 435 | for (c = 0; c < 3; c++) { |
| 436 | est[c] = (int)thatRow[x*3+c] + (int)pix[c] - (int)thatRow[(x-1)*3+c]; |
| 437 | if (est[c] > (int)max[c]) { |
| 438 | est[c] = (int)max[c]; |
| 439 | } else if (est[c] < 0) { |
| 440 | est[c] = 0; |
| 441 | } |
| 442 | pix[c] = (uint16_t)(((src[y*client->rectWidth+x] >> shift[c]) + est[c]) & max[c]); |
| 443 | thisRow[x*3+c] = pix[c]; |
| 444 | } |
| 445 | dst[y*client->rectWidth+x] = RGB_TO_PIXEL(BPP, pix[0], pix[1], pix[2]); |
| 446 | } |
| 447 | memcpy(thatRow, thisRow, client->rectWidth * 3 * sizeof(uint16_t)); |
| 448 | } |
| 449 | } |
| 450 | |
| 451 | static int |
| 452 | InitFilterPaletteBPP (rfbClient* client, int rw, int rh) |
| 453 | { |
| 454 | uint8_t numColors; |
| 455 | #if BPP == 32 |
| 456 | int i; |
| 457 | CARDBPP *palette = (CARDBPP *)client->tightPalette; |
| 458 | #endif |
| 459 | |
| 460 | client->rectWidth = rw; |
| 461 | |
| 462 | if (!ReadFromRFBServer(client, (char*)&numColors, 1)) |
| 463 | return 0; |
| 464 | |
| 465 | client->rectColors = (int)numColors; |
| 466 | if (++client->rectColors < 2) |
| 467 | return 0; |
| 468 | |
| 469 | #if BPP == 32 |
| 470 | if (client->format.depth == 24 && client->format.redMax == 0xFF && |
| 471 | client->format.greenMax == 0xFF && client->format.blueMax == 0xFF) { |
| 472 | if (!ReadFromRFBServer(client, (char*)&client->tightPalette, client->rectColors * 3)) |
| 473 | return 0; |
| 474 | for (i = client->rectColors - 1; i >= 0; i--) { |
| 475 | palette[i] = RGB24_TO_PIXEL32(client->tightPalette[i*3], |
| 476 | client->tightPalette[i*3+1], |
| 477 | client->tightPalette[i*3+2]); |
| 478 | } |
| 479 | return (client->rectColors == 2) ? 1 : 8; |
| 480 | } |
| 481 | #endif |
| 482 | |
| 483 | if (!ReadFromRFBServer(client, (char*)&client->tightPalette, client->rectColors * (BPP / 8))) |
| 484 | return 0; |
| 485 | |
| 486 | return (client->rectColors == 2) ? 1 : 8; |
| 487 | } |
| 488 | |
| 489 | static void |
| 490 | FilterPaletteBPP (rfbClient* client, int numRows, CARDBPP *dst) |
| 491 | { |
| 492 | int x, y, b, w; |
| 493 | uint8_t *src = (uint8_t *)client->buffer; |
| 494 | CARDBPP *palette = (CARDBPP *)client->tightPalette; |
| 495 | |
| 496 | if (client->rectColors == 2) { |
| 497 | w = (client->rectWidth + 7) / 8; |
| 498 | for (y = 0; y < numRows; y++) { |
| 499 | for (x = 0; x < client->rectWidth / 8; x++) { |
| 500 | for (b = 7; b >= 0; b--) |
| 501 | dst[y*client->rectWidth+x*8+7-b] = palette[src[y*w+x] >> b & 1]; |
| 502 | } |
| 503 | for (b = 7; b >= 8 - client->rectWidth % 8; b--) { |
| 504 | dst[y*client->rectWidth+x*8+7-b] = palette[src[y*w+x] >> b & 1]; |
| 505 | } |
| 506 | } |
| 507 | } else { |
| 508 | for (y = 0; y < numRows; y++) |
| 509 | for (x = 0; x < client->rectWidth; x++) |
| 510 | dst[y*client->rectWidth+x] = palette[(int)src[y*client->rectWidth+x]]; |
| 511 | } |
| 512 | } |
| 513 | |
| 514 | #if BPP != 8 |
| 515 | |
| 516 | /*---------------------------------------------------------------------------- |
| 517 | * |
| 518 | * JPEG decompression. |
| 519 | * |
| 520 | */ |
| 521 | |
| 522 | static rfbBool |
| 523 | DecompressJpegRectBPP(rfbClient* client, int x, int y, int w, int h) |
| 524 | { |
| 525 | struct jpeg_decompress_struct cinfo; |
| 526 | struct jpeg_error_mgr jerr; |
| 527 | int compressedLen; |
| 528 | uint8_t *compressedData; |
| 529 | CARDBPP *pixelPtr; |
| 530 | JSAMPROW rowPointer[1]; |
| 531 | int dx, dy; |
| 532 | |
| 533 | compressedLen = (int)ReadCompactLen(client); |
| 534 | if (compressedLen <= 0) { |
| 535 | rfbClientLog("Incorrect data received from the server.\n"); |
| 536 | return FALSE; |
| 537 | } |
| 538 | |
| 539 | compressedData = malloc(compressedLen); |
| 540 | if (compressedData == NULL) { |
| 541 | rfbClientLog("Memory allocation error.\n"); |
| 542 | return FALSE; |
| 543 | } |
| 544 | |
| 545 | if (!ReadFromRFBServer(client, (char*)compressedData, compressedLen)) { |
| 546 | free(compressedData); |
| 547 | return FALSE; |
| 548 | } |
| 549 | |
| 550 | cinfo.err = jpeg_std_error(&jerr); |
| 551 | cinfo.client_data = client; |
| 552 | jpeg_create_decompress(&cinfo); |
| 553 | |
| 554 | JpegSetSrcManager(&cinfo, compressedData, compressedLen); |
| 555 | |
| 556 | jpeg_read_header(&cinfo, TRUE); |
| 557 | cinfo.out_color_space = JCS_RGB; |
| 558 | |
| 559 | jpeg_start_decompress(&cinfo); |
| 560 | if (cinfo.output_width != w || cinfo.output_height != h || |
| 561 | cinfo.output_components != 3) { |
| 562 | rfbClientLog("Tight Encoding: Wrong JPEG data received.\n"); |
| 563 | jpeg_destroy_decompress(&cinfo); |
| 564 | free(compressedData); |
| 565 | return FALSE; |
| 566 | } |
| 567 | |
| 568 | rowPointer[0] = (JSAMPROW)client->buffer; |
| 569 | dy = 0; |
| 570 | while (cinfo.output_scanline < cinfo.output_height) { |
| 571 | jpeg_read_scanlines(&cinfo, rowPointer, 1); |
| 572 | if (client->jpegError) { |
| 573 | break; |
| 574 | } |
| 575 | pixelPtr = (CARDBPP *)&client->buffer[RFB_BUFFER_SIZE / 2]; |
| 576 | for (dx = 0; dx < w; dx++) { |
| 577 | *pixelPtr++ = |
| 578 | RGB24_TO_PIXEL(BPP, client->buffer[dx*3], client->buffer[dx*3+1], client->buffer[dx*3+2]); |
| 579 | } |
| 580 | CopyRectangle(client, (uint8_t *)&client->buffer[RFB_BUFFER_SIZE / 2], x, y + dy, w, 1); |
| 581 | dy++; |
| 582 | } |
| 583 | |
| 584 | if (!client->jpegError) |
| 585 | jpeg_finish_decompress(&cinfo); |
| 586 | |
| 587 | jpeg_destroy_decompress(&cinfo); |
| 588 | free(compressedData); |
| 589 | |
| 590 | return !client->jpegError; |
| 591 | } |
| 592 | |
| 593 | #else |
| 594 | |
| 595 | static long |
| 596 | ReadCompactLen (rfbClient* client) |
| 597 | { |
| 598 | long len; |
| 599 | uint8_t b; |
| 600 | |
| 601 | if (!ReadFromRFBServer(client, (char *)&b, 1)) |
| 602 | return -1; |
| 603 | len = (int)b & 0x7F; |
| 604 | if (b & 0x80) { |
| 605 | if (!ReadFromRFBServer(client, (char *)&b, 1)) |
| 606 | return -1; |
| 607 | len |= ((int)b & 0x7F) << 7; |
| 608 | if (b & 0x80) { |
| 609 | if (!ReadFromRFBServer(client, (char *)&b, 1)) |
| 610 | return -1; |
| 611 | len |= ((int)b & 0xFF) << 14; |
| 612 | } |
| 613 | } |
| 614 | return len; |
| 615 | } |
| 616 | |
| 617 | /* |
| 618 | * JPEG source manager functions for JPEG decompression in Tight decoder. |
| 619 | */ |
| 620 | |
| 621 | static void |
| 622 | JpegInitSource(j_decompress_ptr cinfo) |
| 623 | { |
| 624 | rfbClient* client=(rfbClient*)cinfo->client_data; |
| 625 | client->jpegError = FALSE; |
| 626 | } |
| 627 | |
| 628 | static boolean |
| 629 | JpegFillInputBuffer(j_decompress_ptr cinfo) |
| 630 | { |
| 631 | rfbClient* client=(rfbClient*)cinfo->client_data; |
| 632 | client->jpegError = TRUE; |
| 633 | client->jpegSrcManager->bytes_in_buffer = client->jpegBufferLen; |
| 634 | client->jpegSrcManager->next_input_byte = (JOCTET *)client->jpegBufferPtr; |
| 635 | |
| 636 | return TRUE; |
| 637 | } |
| 638 | |
| 639 | static void |
| 640 | JpegSkipInputData(j_decompress_ptr cinfo, long num_bytes) |
| 641 | { |
| 642 | rfbClient* client=(rfbClient*)cinfo->client_data; |
| 643 | if (num_bytes < 0 || num_bytes > client->jpegSrcManager->bytes_in_buffer) { |
| 644 | client->jpegError = TRUE; |
| 645 | client->jpegSrcManager->bytes_in_buffer = client->jpegBufferLen; |
| 646 | client->jpegSrcManager->next_input_byte = (JOCTET *)client->jpegBufferPtr; |
| 647 | } else { |
| 648 | client->jpegSrcManager->next_input_byte += (size_t) num_bytes; |
| 649 | client->jpegSrcManager->bytes_in_buffer -= (size_t) num_bytes; |
| 650 | } |
| 651 | } |
| 652 | |
| 653 | static void |
| 654 | JpegTermSource(j_decompress_ptr cinfo) |
| 655 | { |
| 656 | /* nothing to do here. */ |
| 657 | } |
| 658 | |
| 659 | static void |
| 660 | JpegSetSrcManager(j_decompress_ptr cinfo, |
| 661 | uint8_t *compressedData, |
| 662 | int compressedLen) |
| 663 | { |
| 664 | rfbClient* client=(rfbClient*)cinfo->client_data; |
| 665 | client->jpegBufferPtr = compressedData; |
| 666 | client->jpegBufferLen = (size_t)compressedLen; |
| 667 | |
| 668 | if(client->jpegSrcManager == NULL) |
| 669 | client->jpegSrcManager = malloc(sizeof(struct jpeg_source_mgr)); |
| 670 | client->jpegSrcManager->init_source = JpegInitSource; |
| 671 | client->jpegSrcManager->fill_input_buffer = JpegFillInputBuffer; |
| 672 | client->jpegSrcManager->skip_input_data = JpegSkipInputData; |
| 673 | client->jpegSrcManager->resync_to_restart = jpeg_resync_to_restart; |
| 674 | client->jpegSrcManager->term_source = JpegTermSource; |
| 675 | client->jpegSrcManager->next_input_byte = (JOCTET*)client->jpegBufferPtr; |
| 676 | client->jpegSrcManager->bytes_in_buffer = client->jpegBufferLen; |
| 677 | |
| 678 | cinfo->src = client->jpegSrcManager; |
| 679 | } |
| 680 | |
| 681 | #endif |
| 682 | |
| 683 | #undef CARDBPP |
| 684 | |
| 685 | /* LIBVNCSERVER_HAVE_LIBZ and LIBVNCSERVER_HAVE_LIBJPEG */ |
| 686 | #endif |
| 687 | #endif |
| 688 | |