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 74typedef void (*filterPtrBPP)(rfbClient* client, int, CARDBPP *); 75 76/* Prototypes */ 77 78static int InitFilterCopyBPP (rfbClient* client, int rw, int rh); 79static int InitFilterPaletteBPP (rfbClient* client, int rw, int rh); 80static int InitFilterGradientBPP (rfbClient* client, int rw, int rh); 81static void FilterCopyBPP (rfbClient* client, int numRows, CARDBPP *destBuffer); 82static void FilterPaletteBPP (rfbClient* client, int numRows, CARDBPP *destBuffer); 83static void FilterGradientBPP (rfbClient* client, int numRows, CARDBPP *destBuffer); 84 85#if BPP != 8 86static rfbBool DecompressJpegRectBPP(rfbClient* client, int x, int y, int w, int h); 87#endif 88 89/* Definitions */ 90 91static rfbBool 92HandleTightBPP (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 301static int 302InitFilterCopyBPP (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 319static void 320FilterCopyBPP (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 342static int 343InitFilterGradientBPP (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 358static void 359FilterGradient24 (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 397static void 398FilterGradientBPP (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 451static int 452InitFilterPaletteBPP (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 489static void 490FilterPaletteBPP (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 522static rfbBool 523DecompressJpegRectBPP(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 595static long 596ReadCompactLen (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 621static void 622JpegInitSource(j_decompress_ptr cinfo) 623{ 624 rfbClient* client=(rfbClient*)cinfo->client_data; 625 client->jpegError = FALSE; 626} 627 628static boolean 629JpegFillInputBuffer(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 639static void 640JpegSkipInputData(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 653static void 654JpegTermSource(j_decompress_ptr cinfo) 655{ 656 /* nothing to do here. */ 657} 658 659static void 660JpegSetSrcManager(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 689