blob: afc759945e1036e05379473ba01767dc0bf8c54b [file] [log] [blame]
Peter Åstrand462753d2004-11-16 15:23:25 +00001/* Copyright (C) 2000-2003 Constantin Kaplinsky. 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// Tight decoding functions.
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
28#include <rdr/InStream.h>
29#include <rdr/ZlibInStream.h>
30#include <rfb/Exception.h>
31#include <assert.h>
32
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#define PIXEL_T rdr::CONCAT2E(U,BPP)
43#define READ_PIXEL CONCAT2E(readOpaque,BPP)
44#define TIGHT_DECODE CONCAT2E(tightDecode,BPP)
45
46#define TIGHT_MIN_TO_COMPRESS 12
47
48// Main function implementing Tight decoder
49
50void TIGHT_DECODE (const Rect& r, rdr::InStream* is,
51 rdr::ZlibInStream zis[], PIXEL_T* buf
52#ifdef EXTRA_ARGS
53 , EXTRA_ARGS
54#endif
55 )
56{
57 rdr::U8 comp_ctl = is->readU8();
58
59 // Flush zlib streams if we are told by the server to do so.
60 for (int i = 0; i < 4; i++) {
61 /* FIXME: Implement flushing
62 if ((comp_ctl & 1) && m_tightZlibStreamActive[i]) {
63 int err = inflateEnd (&m_tightZlibStream[i]);
64 if (err != Z_OK) {
65 if (m_tightZlibStream[i].msg != NULL) {
66 vnclog.Print(0, _T("zlib inflateEnd() error: %s\n"),
67 m_tightZlibStream[i].msg);
68 } else {
69 vnclog.Print(0, _T("zlib inflateEnd() error: %d\n"), err);
70 }
71 return;
72 }
73 m_tightZlibStreamActive[i] = FALSE;
74 }
75 */
76 comp_ctl >>= 1;
77 }
78
79 // "Fill" compression type.
80 if (comp_ctl == 0x08) {
81 PIXEL_T pix = is->READ_PIXEL();
82 FILL_RECT(r, pix);
83 return;
84 }
85
86 // "JPEG" compression type.
87 if (comp_ctl == 0x09) {
88 throw Exception("TightDecoder: FIXME: JPEG compression is not supported yet");
89 return;
90 }
91
92 // Quit on unsupported compression type.
93 if (comp_ctl > 0x09) {
94 throw Exception("TightDecoder: bad subencoding value received");
95 return;
96 }
97
98 // "Basic" compression type.
99 int palSize = 0;
100 PIXEL_T palette[256];
101 bool useGradient = false;
102
103 if ((comp_ctl & 0x04) != 0) {
104 rdr::U8 filterId = is->readU8();
105
106 switch (filterId) {
107 case 0x01: // "palette" filter
108 palSize = is->readU8() + 1;
109 {
110 for (int i = 0; i < palSize; i++)
111 palette[i] = is->READ_PIXEL();
112 }
113 break;
114 case 0x02: // "gradient" filter
115 useGradient = true;
116 break;
117 case 0x00: // no filter
118 break;
119 default:
120 throw Exception("TightDecoder: unknown filter code received");
121 return;
122 }
123 }
124
125 int bppp = BPP;
126 if (palSize != 0) {
127 bppp = (palSize <= 2) ? 1 : 8;
128 }
129
130 // Determine if the data should be decompressed or just copied.
131 int rowSize = (r.width() * bppp + 7) / 8;
132 int dataSize = r.height() * rowSize;
133 rdr::InStream *input;
134 if (dataSize < TIGHT_MIN_TO_COMPRESS) {
135 input = is;
136 } else {
137 int length = is->readCompactLength();
138 int streamId = comp_ctl & 0x03;
139 zis[streamId].setUnderlying(is, length);
140 input = &zis[streamId];
141 }
142
143 if (palSize == 0) {
144 // Truecolor data
145 input->readBytes(buf, dataSize);
146 if (useGradient) {
147 // FIXME: Implement the "gradient" filter.
148 }
149 } else {
150 int x, y, b, w;
151 PIXEL_T *ptr = buf;
152 rdr::U8 bits;
153 if (palSize <= 2) {
154 // 2-color palette
155 w = (r.width() + 7) / 8;
156 for (y = 0; y < r.height(); y++) {
157 for (x = 0; x < r.width() / 8; x++) {
158 bits = input->readU8();
159 for (b = 7; b >= 0; b--)
160 *ptr++ = palette[bits >> b & 1];
161 }
162 if (r.width() % 8 != 0) {
163 bits = input->readU8();
164 for (b = 7; b >= 8 - r.width() % 8; b--) {
165 *ptr++ = palette[bits >> b & 1];
166 }
167 }
168 }
169 } else {
170 // 256-color palette
171 for (y = 0; y < r.height(); y++)
172 for (x = 0; x < r.width(); x++)
173 *ptr++ = palette[input->readU8()];
174 }
175 }
176
177 IMAGE_RECT(r, buf);
178
179 // zis->reset(); // FIXME: Is that needed?
180}
181
182#undef TIGHT_DECODE
183#undef READ_PIXEL
184#undef PIXEL_T
185}