LibVNCServer/LibVNCClient
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
tight.c
Go to the documentation of this file.
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