blob: 2f9fbabaabff0b8010678db1d93a93593de2f132 [file] [log] [blame]
San Mehata430b2b2014-09-23 08:30:51 -07001/*
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