~vanvugt/+junk/remmina-ppa

« back to all changes in this revision

Viewing changes to libvncserver/libvncclient/tight.c

  • Committer: Bazaar Package Importer
  • Author(s): Luca Falavigna
  • Date: 2010-07-11 23:40:47 UTC
  • mfrom: (1.2.1 upstream) (8.1.1 experimental)
  • Revision ID: james.westby@ubuntu.com-20100711234047-id2bdu1gb59e34n4
* New upstream release.
* debian/control:
  - Bump Standards-Version to 3.9.0, no changes required.

Show diffs side-by-side

added added

removed removed

Lines of Context:
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