Home | History | Annotate | Download | only in libvncclient
      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 
    689