update about dialog
[presencevnc] / libvnc / libvncclient / tight.c
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