blob: 4bcbf1f08e35bdb2f16b4e72409f8c7e224269e1 [file] [log] [blame]
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +00001/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
2 *
3 * This is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This software is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this software; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
16 * USA.
17 */
18
19//
20// ZRLE decoding function.
21//
Pierre Ossmanbcc295e2014-02-12 13:16:43 +010022// This file is #included after having set the following macro:
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000023// BPP - 8, 16 or 32
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000024
Pierre Ossmanc1244c02014-03-19 12:16:48 +000025#include <stdio.h>
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000026#include <rdr/InStream.h>
27#include <rdr/ZlibInStream.h>
Pierre Ossmanc1244c02014-03-19 12:16:48 +000028#include <rfb/Exception.h>
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000029
30namespace rfb {
31
32// CONCAT2E concatenates its arguments, expanding them if they are macros
33
34#ifndef CONCAT2E
35#define CONCAT2(a,b) a##b
36#define CONCAT2E(a,b) CONCAT2(a,b)
37#endif
38
39#ifdef CPIXEL
40#define PIXEL_T rdr::CONCAT2E(U,BPP)
Pierre Ossman7b5c0692014-03-17 14:35:51 +010041#define READ_PIXEL(is) CONCAT2E(readOpaque,CPIXEL)(is)
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000042#define ZRLE_DECODE CONCAT2E(zrleDecode,CPIXEL)
43#else
44#define PIXEL_T rdr::CONCAT2E(U,BPP)
Pierre Ossman7b5c0692014-03-17 14:35:51 +010045#define READ_PIXEL(is) is->CONCAT2E(readOpaque,BPP)()
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000046#define ZRLE_DECODE CONCAT2E(zrleDecode,BPP)
47#endif
48
49void ZRLE_DECODE (const Rect& r, rdr::InStream* is,
Pierre Ossmanbcc295e2014-02-12 13:16:43 +010050 rdr::ZlibInStream* zis, PIXEL_T* buf,
51 CMsgHandler* handler)
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000052{
53 int length = is->readU32();
54 zis->setUnderlying(is, length);
55 Rect t;
56
57 for (t.tl.y = r.tl.y; t.tl.y < r.br.y; t.tl.y += 64) {
58
59 t.br.y = __rfbmin(r.br.y, t.tl.y + 64);
60
61 for (t.tl.x = r.tl.x; t.tl.x < r.br.x; t.tl.x += 64) {
62
63 t.br.x = __rfbmin(r.br.x, t.tl.x + 64);
64
65 int mode = zis->readU8();
66 bool rle = mode & 128;
67 int palSize = mode & 127;
68 PIXEL_T palette[128];
69
70 for (int i = 0; i < palSize; i++) {
Pierre Ossman7b5c0692014-03-17 14:35:51 +010071 palette[i] = READ_PIXEL(zis);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000072 }
73
74 if (palSize == 1) {
75 PIXEL_T pix = palette[0];
Pierre Ossmanbcc295e2014-02-12 13:16:43 +010076 handler->fillRect(t, pix);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000077 continue;
78 }
79
80 if (!rle) {
81 if (palSize == 0) {
82
83 // raw
84
85#ifdef CPIXEL
86 for (PIXEL_T* ptr = buf; ptr < buf+t.area(); ptr++) {
Pierre Ossman7b5c0692014-03-17 14:35:51 +010087 *ptr = READ_PIXEL(zis);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000088 }
89#else
90 zis->readBytes(buf, t.area() * (BPP / 8));
91#endif
92
93 } else {
94
95 // packed pixels
96 int bppp = ((palSize > 16) ? 8 :
97 ((palSize > 4) ? 4 : ((palSize > 2) ? 2 : 1)));
98
99 PIXEL_T* ptr = buf;
100
101 for (int i = 0; i < t.height(); i++) {
102 PIXEL_T* eol = ptr + t.width();
103 rdr::U8 byte = 0;
104 rdr::U8 nbits = 0;
105
106 while (ptr < eol) {
107 if (nbits == 0) {
108 byte = zis->readU8();
109 nbits = 8;
110 }
111 nbits -= bppp;
112 rdr::U8 index = (byte >> nbits) & ((1 << bppp) - 1) & 127;
113 *ptr++ = palette[index];
114 }
115 }
116 }
117
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000118 } else {
119
120 if (palSize == 0) {
121
122 // plain RLE
123
124 PIXEL_T* ptr = buf;
125 PIXEL_T* end = ptr + t.area();
126 while (ptr < end) {
Pierre Ossman7b5c0692014-03-17 14:35:51 +0100127 PIXEL_T pix = READ_PIXEL(zis);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000128 int len = 1;
129 int b;
130 do {
131 b = zis->readU8();
132 len += b;
133 } while (b == 255);
134
Pierre Ossmanc1244c02014-03-19 12:16:48 +0000135 if (end - ptr < len) {
136 fprintf (stderr, "ZRLE decode error\n");
137 throw Exception ("ZRLE decode error");
138 }
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000139
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000140 while (len-- > 0) *ptr++ = pix;
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000141
142 }
143 } else {
144
145 // palette RLE
146
147 PIXEL_T* ptr = buf;
148 PIXEL_T* end = ptr + t.area();
149 while (ptr < end) {
150 int index = zis->readU8();
151 int len = 1;
152 if (index & 128) {
153 int b;
154 do {
155 b = zis->readU8();
156 len += b;
157 } while (b == 255);
158
Pierre Ossmanc1244c02014-03-19 12:16:48 +0000159 if (end - ptr < len) {
160 fprintf (stderr, "ZRLE decode error\n");
161 throw Exception ("ZRLE decode error");
162 }
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000163 }
164
165 index &= 127;
166
167 PIXEL_T pix = palette[index];
168
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000169 while (len-- > 0) *ptr++ = pix;
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000170 }
171 }
172 }
173
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000174 //fprintf(stderr,"copying data to screen %dx%d at %d,%d\n",
175 //t.width(),t.height(),t.tl.x,t.tl.y);
Pierre Ossmanbcc295e2014-02-12 13:16:43 +0100176 handler->imageRect(t, buf);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000177 }
178 }
179
180 zis->reset();
181}
182
183#undef ZRLE_DECODE
184#undef READ_PIXEL
185#undef PIXEL_T
186}