blob: 207a6c74174353c00e3f60a9bbd618f0ad9ed646 [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)
Pierre Ossman7b5c0692014-03-17 14:35:51 +010044#define READ_PIXEL(is) CONCAT2E(readOpaque,CPIXEL)(is)
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000045#define ZRLE_DECODE CONCAT2E(zrleDecode,CPIXEL)
46#else
47#define PIXEL_T rdr::CONCAT2E(U,BPP)
Pierre Ossman7b5c0692014-03-17 14:35:51 +010048#define READ_PIXEL(is) is->CONCAT2E(readOpaque,BPP)()
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000049#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++) {
Pierre Ossman7b5c0692014-03-17 14:35:51 +010077 palette[i] = READ_PIXEL(zis);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000078 }
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++) {
Pierre Ossman7b5c0692014-03-17 14:35:51 +010093 *ptr = READ_PIXEL(zis);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000094 }
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
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000124 } else {
125
126 if (palSize == 0) {
127
128 // plain RLE
129
130 PIXEL_T* ptr = buf;
131 PIXEL_T* end = ptr + t.area();
132 while (ptr < end) {
Pierre Ossman7b5c0692014-03-17 14:35:51 +0100133 PIXEL_T pix = READ_PIXEL(zis);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000134 int len = 1;
135 int b;
136 do {
137 b = zis->readU8();
138 len += b;
139 } while (b == 255);
140
Pierre Ossmanc1244c02014-03-19 12:16:48 +0000141 if (end - ptr < len) {
142 fprintf (stderr, "ZRLE decode error\n");
143 throw Exception ("ZRLE decode error");
144 }
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000145
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000146 while (len-- > 0) *ptr++ = pix;
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000147
148 }
149 } else {
150
151 // palette RLE
152
153 PIXEL_T* ptr = buf;
154 PIXEL_T* end = ptr + t.area();
155 while (ptr < end) {
156 int index = zis->readU8();
157 int len = 1;
158 if (index & 128) {
159 int b;
160 do {
161 b = zis->readU8();
162 len += b;
163 } while (b == 255);
164
Pierre Ossmanc1244c02014-03-19 12:16:48 +0000165 if (end - ptr < len) {
166 fprintf (stderr, "ZRLE decode error\n");
167 throw Exception ("ZRLE decode error");
168 }
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000169 }
170
171 index &= 127;
172
173 PIXEL_T pix = palette[index];
174
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000175 while (len-- > 0) *ptr++ = pix;
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000176 }
177 }
178 }
179
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000180 //fprintf(stderr,"copying data to screen %dx%d at %d,%d\n",
181 //t.width(),t.height(),t.tl.x,t.tl.y);
182 IMAGE_RECT(t,buf);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000183 }
184 }
185
186 zis->reset();
187}
188
189#undef ZRLE_DECODE
190#undef READ_PIXEL
191#undef PIXEL_T
192}