blob: 0bfbbe152dd443ede674001572ddbbe18ae05dce [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 Ossman1349e422016-10-05 11:00:37 +020050 rdr::ZlibInStream* zis,
Pierre Ossman0c9bd4b2014-07-09 16:44:11 +020051 const PixelFormat& pf, ModifiablePixelBuffer* pb)
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000052{
53 int length = is->readU32();
54 zis->setUnderlying(is, length);
55 Rect t;
Pierre Ossman1349e422016-10-05 11:00:37 +020056 PIXEL_T buf[64 * 64];
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000057
58 for (t.tl.y = r.tl.y; t.tl.y < r.br.y; t.tl.y += 64) {
59
60 t.br.y = __rfbmin(r.br.y, t.tl.y + 64);
61
62 for (t.tl.x = r.tl.x; t.tl.x < r.br.x; t.tl.x += 64) {
63
64 t.br.x = __rfbmin(r.br.x, t.tl.x + 64);
65
66 int mode = zis->readU8();
67 bool rle = mode & 128;
68 int palSize = mode & 127;
69 PIXEL_T palette[128];
70
71 for (int i = 0; i < palSize; i++) {
Pierre Ossman7b5c0692014-03-17 14:35:51 +010072 palette[i] = READ_PIXEL(zis);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000073 }
74
75 if (palSize == 1) {
76 PIXEL_T pix = palette[0];
Pierre Ossman56f99d62015-06-05 12:57:02 +020077 pb->fillRect(pf, t, &pix);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000078 continue;
79 }
80
81 if (!rle) {
82 if (palSize == 0) {
83
84 // raw
85
86#ifdef CPIXEL
87 for (PIXEL_T* ptr = buf; ptr < buf+t.area(); ptr++) {
Pierre Ossman7b5c0692014-03-17 14:35:51 +010088 *ptr = READ_PIXEL(zis);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000089 }
90#else
91 zis->readBytes(buf, t.area() * (BPP / 8));
92#endif
93
94 } else {
95
96 // packed pixels
97 int bppp = ((palSize > 16) ? 8 :
98 ((palSize > 4) ? 4 : ((palSize > 2) ? 2 : 1)));
99
100 PIXEL_T* ptr = buf;
101
102 for (int i = 0; i < t.height(); i++) {
103 PIXEL_T* eol = ptr + t.width();
104 rdr::U8 byte = 0;
105 rdr::U8 nbits = 0;
106
107 while (ptr < eol) {
108 if (nbits == 0) {
109 byte = zis->readU8();
110 nbits = 8;
111 }
112 nbits -= bppp;
113 rdr::U8 index = (byte >> nbits) & ((1 << bppp) - 1) & 127;
114 *ptr++ = palette[index];
115 }
116 }
117 }
118
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000119 } else {
120
121 if (palSize == 0) {
122
123 // plain RLE
124
125 PIXEL_T* ptr = buf;
126 PIXEL_T* end = ptr + t.area();
127 while (ptr < end) {
Pierre Ossman7b5c0692014-03-17 14:35:51 +0100128 PIXEL_T pix = READ_PIXEL(zis);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000129 int len = 1;
130 int b;
131 do {
132 b = zis->readU8();
133 len += b;
134 } while (b == 255);
135
Pierre Ossmanc1244c02014-03-19 12:16:48 +0000136 if (end - ptr < len) {
137 fprintf (stderr, "ZRLE decode error\n");
138 throw Exception ("ZRLE decode error");
139 }
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000140
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000141 while (len-- > 0) *ptr++ = pix;
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000142
143 }
144 } else {
145
146 // palette RLE
147
148 PIXEL_T* ptr = buf;
149 PIXEL_T* end = ptr + t.area();
150 while (ptr < end) {
151 int index = zis->readU8();
152 int len = 1;
153 if (index & 128) {
154 int b;
155 do {
156 b = zis->readU8();
157 len += b;
158 } while (b == 255);
159
Pierre Ossmanc1244c02014-03-19 12:16:48 +0000160 if (end - ptr < len) {
161 fprintf (stderr, "ZRLE decode error\n");
162 throw Exception ("ZRLE decode error");
163 }
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000164 }
165
166 index &= 127;
167
168 PIXEL_T pix = palette[index];
169
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000170 while (len-- > 0) *ptr++ = pix;
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000171 }
172 }
173 }
174
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000175 //fprintf(stderr,"copying data to screen %dx%d at %d,%d\n",
176 //t.width(),t.height(),t.tl.x,t.tl.y);
Pierre Ossman0c9bd4b2014-07-09 16:44:11 +0200177 pb->imageRect(pf, t, buf);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000178 }
179 }
180
Pierre Ossman6f318e42015-11-11 13:11:09 +0100181 zis->removeUnderlying();
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000182}
183
184#undef ZRLE_DECODE
185#undef READ_PIXEL
186#undef PIXEL_T
187}