blob: 8f6f7927e895c94afd98d712097f2e8d34a476bd [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//
22// This file is #included after having set the following macros:
23// BPP - 8, 16 or 32
24// EXTRA_ARGS - optional extra arguments
25// FILL_RECT - fill a rectangle with a single colour
26// IMAGE_RECT - draw a rectangle of pixel data from a buffer
27
Pierre Ossmanc1244c02014-03-19 12:16:48 +000028#include <stdio.h>
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000029#include <rdr/InStream.h>
30#include <rdr/ZlibInStream.h>
Pierre Ossmanc1244c02014-03-19 12:16:48 +000031#include <rfb/Exception.h>
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000032
33namespace rfb {
34
35// CONCAT2E concatenates its arguments, expanding them if they are macros
36
37#ifndef CONCAT2E
38#define CONCAT2(a,b) a##b
39#define CONCAT2E(a,b) CONCAT2(a,b)
40#endif
41
42#ifdef CPIXEL
43#define PIXEL_T rdr::CONCAT2E(U,BPP)
44#define READ_PIXEL CONCAT2E(readOpaque,CPIXEL)
45#define ZRLE_DECODE CONCAT2E(zrleDecode,CPIXEL)
46#else
47#define PIXEL_T rdr::CONCAT2E(U,BPP)
48#define READ_PIXEL CONCAT2E(readOpaque,BPP)
49#define ZRLE_DECODE CONCAT2E(zrleDecode,BPP)
50#endif
51
52void ZRLE_DECODE (const Rect& r, rdr::InStream* is,
53 rdr::ZlibInStream* zis, PIXEL_T* buf
54#ifdef EXTRA_ARGS
55 , EXTRA_ARGS
56#endif
57 )
58{
59 int length = is->readU32();
60 zis->setUnderlying(is, length);
61 Rect t;
62
63 for (t.tl.y = r.tl.y; t.tl.y < r.br.y; t.tl.y += 64) {
64
65 t.br.y = __rfbmin(r.br.y, t.tl.y + 64);
66
67 for (t.tl.x = r.tl.x; t.tl.x < r.br.x; t.tl.x += 64) {
68
69 t.br.x = __rfbmin(r.br.x, t.tl.x + 64);
70
71 int mode = zis->readU8();
72 bool rle = mode & 128;
73 int palSize = mode & 127;
74 PIXEL_T palette[128];
75
76 for (int i = 0; i < palSize; i++) {
77 palette[i] = zis->READ_PIXEL();
78 }
79
80 if (palSize == 1) {
81 PIXEL_T pix = palette[0];
82 FILL_RECT(t,pix);
83 continue;
84 }
85
86 if (!rle) {
87 if (palSize == 0) {
88
89 // raw
90
91#ifdef CPIXEL
92 for (PIXEL_T* ptr = buf; ptr < buf+t.area(); ptr++) {
93 *ptr = zis->READ_PIXEL();
94 }
95#else
96 zis->readBytes(buf, t.area() * (BPP / 8));
97#endif
98
99 } else {
100
101 // packed pixels
102 int bppp = ((palSize > 16) ? 8 :
103 ((palSize > 4) ? 4 : ((palSize > 2) ? 2 : 1)));
104
105 PIXEL_T* ptr = buf;
106
107 for (int i = 0; i < t.height(); i++) {
108 PIXEL_T* eol = ptr + t.width();
109 rdr::U8 byte = 0;
110 rdr::U8 nbits = 0;
111
112 while (ptr < eol) {
113 if (nbits == 0) {
114 byte = zis->readU8();
115 nbits = 8;
116 }
117 nbits -= bppp;
118 rdr::U8 index = (byte >> nbits) & ((1 << bppp) - 1) & 127;
119 *ptr++ = palette[index];
120 }
121 }
122 }
123
124#ifdef FAVOUR_FILL_RECT
125 //fprintf(stderr,"copying data to screen %dx%d at %d,%d\n",
126 //t.width(),t.height(),t.tl.x,t.tl.y);
127 IMAGE_RECT(t,buf);
128#endif
129
130 } else {
131
132 if (palSize == 0) {
133
134 // plain RLE
135
136 PIXEL_T* ptr = buf;
137 PIXEL_T* end = ptr + t.area();
138 while (ptr < end) {
139 PIXEL_T pix = zis->READ_PIXEL();
140 int len = 1;
141 int b;
142 do {
143 b = zis->readU8();
144 len += b;
145 } while (b == 255);
146
Pierre Ossmanc1244c02014-03-19 12:16:48 +0000147 if (end - ptr < len) {
148 fprintf (stderr, "ZRLE decode error\n");
149 throw Exception ("ZRLE decode error");
150 }
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000151
152#ifdef FAVOUR_FILL_RECT
153 int i = ptr - buf;
154 ptr += len;
155
156 int runX = i % t.width();
157 int runY = i / t.width();
158
159 if (runX + len > t.width()) {
160 if (runX != 0) {
161 FILL_RECT(Rect(t.tl.x+runX, t.tl.y+runY, t.width()-runX, 1),
162 pix);
163 len -= t.width()-runX;
164 runX = 0;
165 runY++;
166 }
167
168 if (len > t.width()) {
169 FILL_RECT(Rect(t.tl.x, t.tl.y+runY, t.width(), len/t.width()),
170 pix);
171 runY += len / t.width();
172 len = len % t.width();
173 }
174 }
175
176 if (len != 0) {
177 FILL_RECT(Rect(t.tl.x+runX, t.tl.y+runY, len, 1), pix);
178 }
179#else
180 while (len-- > 0) *ptr++ = pix;
181#endif
182
183 }
184 } else {
185
186 // palette RLE
187
188 PIXEL_T* ptr = buf;
189 PIXEL_T* end = ptr + t.area();
190 while (ptr < end) {
191 int index = zis->readU8();
192 int len = 1;
193 if (index & 128) {
194 int b;
195 do {
196 b = zis->readU8();
197 len += b;
198 } while (b == 255);
199
Pierre Ossmanc1244c02014-03-19 12:16:48 +0000200 if (end - ptr < len) {
201 fprintf (stderr, "ZRLE decode error\n");
202 throw Exception ("ZRLE decode error");
203 }
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000204 }
205
206 index &= 127;
207
208 PIXEL_T pix = palette[index];
209
210#ifdef FAVOUR_FILL_RECT
211 int i = ptr - buf;
212 ptr += len;
213
214 int runX = i % t.width();
215 int runY = i / t.width();
216
217 if (runX + len > t.width()) {
218 if (runX != 0) {
219 FILL_RECT(Rect(t.tl.x+runX, t.tl.y+runY, t.width()-runX, 1),
220 pix);
221 len -= t.width()-runX;
222 runX = 0;
223 runY++;
224 }
225
226 if (len > t.width()) {
227 FILL_RECT(Rect(t.tl.x, t.tl.y+runY, t.width(), len/t.width()),
228 pix);
229 runY += len / t.width();
230 len = len % t.width();
231 }
232 }
233
234 if (len != 0) {
235 FILL_RECT(Rect(t.tl.x+runX, t.tl.y+runY, len, 1), pix);
236 }
237#else
238 while (len-- > 0) *ptr++ = pix;
239#endif
240 }
241 }
242 }
243
244#ifndef FAVOUR_FILL_RECT
245 //fprintf(stderr,"copying data to screen %dx%d at %d,%d\n",
246 //t.width(),t.height(),t.tl.x,t.tl.y);
247 IMAGE_RECT(t,buf);
248#endif
249 }
250 }
251
252 zis->reset();
253}
254
255#undef ZRLE_DECODE
256#undef READ_PIXEL
257#undef PIXEL_T
258}