blob: fbbb3a6883d34be5c707c3676de322cd82d090e6 [file] [log] [blame]
enikey27a239d2008-12-19 07:32:05 +00001package com.tightvnc.decoder;
2
enikey6aa2dbc2008-12-19 07:38:11 +00003import com.tightvnc.vncviewer.InStream;
enikey27a239d2008-12-19 07:32:05 +00004import com.tightvnc.vncviewer.RfbInputStream;
enikey6aa2dbc2008-12-19 07:38:11 +00005import com.tightvnc.vncviewer.ZlibInStream;
enikey27a239d2008-12-19 07:32:05 +00006import java.awt.Graphics;
enikey4f3dac92008-12-19 07:45:53 +00007import com.tightvnc.vncviewer.MemInStream;
8import java.awt.Color;
9import java.awt.Toolkit;
10import java.awt.image.MemoryImageSource;
11import java.io.IOException;
enikey27a239d2008-12-19 07:32:05 +000012
13//
14// Class that used for decoding ZRLE encoded data.
15//
16
enikey6aa2dbc2008-12-19 07:38:11 +000017public class ZRLEDecoder extends RawDecoder {
enikey27a239d2008-12-19 07:32:05 +000018
enikey6558a302008-12-24 05:14:30 +000019 final static int EncodingZRLE = 16;
20
enikey27a239d2008-12-19 07:32:05 +000021 public ZRLEDecoder(Graphics g, RfbInputStream is) {
22 super(g, is);
23 }
24
25 public ZRLEDecoder(Graphics g, RfbInputStream is, int frameBufferW,
26 int frameBufferH) {
27 super(g, is, frameBufferW, frameBufferH);
28 }
29
enikey6aa2dbc2008-12-19 07:38:11 +000030 //
enikey4f3dac92008-12-19 07:45:53 +000031 // Handle a ZRLE-encoded rectangle.
32 //
33 // FIXME: Currently, session recording is not fully supported for ZRLE.
34 //
35
36 public void handleRect(int x, int y, int w, int h) throws IOException, Exception {
enikey2f0294e2008-12-24 08:18:54 +000037
38 //
39 // Write encoding ID to record output stream
40 //
41
42 if (dos != null) {
43 dos.writeInt(ZRLEDecoder.EncodingZRLE);
44 }
45
enikey4f3dac92008-12-19 07:45:53 +000046 if (zrleInStream == null)
47 zrleInStream = new ZlibInStream();
48
49 int nBytes = rfbis.readU32();
50 if (nBytes > 64 * 1024 * 1024)
51 throw new Exception("ZRLE decoder: illegal compressed data size");
52
53 if (zrleBuf == null || zrleBufLen < nBytes) {
54 zrleBufLen = nBytes + 4096;
55 zrleBuf = new byte[zrleBufLen];
56 }
57
58 // FIXME: Do not wait for all the data before decompression.
59 rfbis.readFully(zrleBuf, 0, nBytes);
60
61 //
62 // Override handleRect method to decode RRE encoded data insted of
63 // raw pixel data.
64 //
65
66 if (rec.canWrite()) {
67 if (rec.isRecordFromBeginning()) {
68 rec.writeIntBE(nBytes);
69 rec.write(zrleBuf, 0, nBytes);
70 } else if (!zrleRecWarningShown) {
71 System.out.println("Warning: ZRLE session can be recorded" +
72 " only from the beginning");
73 System.out.println("Warning: Recorded file may be corrupted");
74 zrleRecWarningShown = true;
75 }
76 }
77
78 zrleInStream.setUnderlying(new MemInStream(zrleBuf, 0, nBytes), nBytes);
79
80 for (int ty = y; ty < y+h; ty += 64) {
81
82 int th = Math.min(y+h-ty, 64);
83
84 for (int tx = x; tx < x+w; tx += 64) {
85
86 int tw = Math.min(x+w-tx, 64);
87
88 int mode = zrleInStream.readU8();
89 boolean rle = (mode & 128) != 0;
90 int palSize = mode & 127;
91 int[] palette = new int[128];
92
93 readZrlePalette(palette, palSize);
94
95 if (palSize == 1) {
96 int pix = palette[0];
97 Color c = (bytesPerPixel == 1) ?
98 getColor256()[pix] : new Color(0xFF000000 | pix);
99 graphics.setColor(c);
100 graphics.fillRect(tx, ty, tw, th);
101 continue;
102 }
103
104 if (!rle) {
105 if (palSize == 0) {
106 readZrleRawPixels(tw, th);
107 } else {
108 readZrlePackedPixels(tw, th, palette, palSize);
109 }
110 } else {
111 if (palSize == 0) {
112 readZrlePlainRLEPixels(tw, th);
113 } else {
114 readZrlePackedRLEPixels(tw, th, palette);
115 }
116 }
117 handleUpdatedZrleTile(tx, ty, tw, th);
118 }
119 }
120 zrleInStream.reset();
121 }
122
123 //
124 // Override update() method cause we have own data that
125 // must be updated when framebuffer is resized or BPP is changed
126 //
127
128 public void update() {
129 // Images with raw pixels should be re-allocated on every change
130 // of geometry or pixel format.
131 int fbWidth = framebufferWidth;
132 int fbHeight = framebufferHeight;
133
134 if (bytesPerPixel == 1) {
135 RawDecoder.pixels24 = null;
136 RawDecoder.pixels8 = new byte[fbWidth * fbHeight];
137 RawDecoder.pixelsSource = new MemoryImageSource(fbWidth, fbHeight, getColorModel8(), pixels8, 0, fbWidth);
138 zrleTilePixels24 = null;
139 zrleTilePixels8 = new byte[64 * 64];
140 } else {
141 RawDecoder.pixels8 = null;
142 RawDecoder.pixels24 = new int[fbWidth * fbHeight];
143 RawDecoder.pixelsSource =
144 new MemoryImageSource(fbWidth, fbHeight, getColorModel24(), pixels24, 0, fbWidth);
145 zrleTilePixels8 = null;
146 zrleTilePixels24 = new int[64 * 64];
147 }
148 RawDecoder.pixelsSource.setAnimated(true);
149 RawDecoder.rawPixelsImage = Toolkit.getDefaultToolkit().createImage(pixelsSource);
150 }
151
152 //
153 // Copy pixels from zrleTilePixels8 or zrleTilePixels24, then update.
154 //
155
156 private void handleUpdatedZrleTile(int x, int y, int w, int h) {
157 Object src, dst;
158 if (bytesPerPixel == 1) {
159 src = zrleTilePixels8; dst = pixels8;
160 } else {
161 src = zrleTilePixels24; dst = pixels24;
162 }
163 int offsetSrc = 0;
164 int offsetDst = (y * framebufferWidth + x);
165 for (int j = 0; j < h; j++) {
166 System.arraycopy(src, offsetSrc, dst, offsetDst, w);
167 offsetSrc += w;
168 offsetDst += framebufferWidth;
169 }
170 handleUpdatedPixels(x, y, w, h);
171 }
172
173 //
enikey6aa2dbc2008-12-19 07:38:11 +0000174 // Private methods for reading ZRLE data
175 //
176
177 private int readPixel(InStream is) throws Exception {
178 int pix;
179 if (bytesPerPixel == 1) {
180 pix = is.readU8();
181 } else {
182 int p1 = is.readU8();
183 int p2 = is.readU8();
184 int p3 = is.readU8();
185 pix = (p3 & 0xFF) << 16 | (p2 & 0xFF) << 8 | (p1 & 0xFF);
186 }
187 return pix;
188 }
189
190 private void readPixels(InStream is, int[] dst, int count) throws Exception {
191 if (bytesPerPixel == 1) {
192 byte[] buf = new byte[count];
193 is.readBytes(buf, 0, count);
194 for (int i = 0; i < count; i++) {
195 dst[i] = (int)buf[i] & 0xFF;
196 }
197 } else {
198 byte[] buf = new byte[count * 3];
199 is.readBytes(buf, 0, count * 3);
200 for (int i = 0; i < count; i++) {
201 dst[i] = ((buf[i*3+2] & 0xFF) << 16 |
202 (buf[i*3+1] & 0xFF) << 8 |
203 (buf[i*3] & 0xFF));
204 }
205 }
206 }
207
208 private void readZrlePalette(int[] palette, int palSize) throws Exception {
209 readPixels(zrleInStream, palette, palSize);
210 }
211
212 private void readZrleRawPixels(int tw, int th) throws Exception {
213 if (bytesPerPixel == 1) {
214 zrleInStream.readBytes(zrleTilePixels8, 0, tw * th);
215 } else {
216 readPixels(zrleInStream, zrleTilePixels24, tw * th); ///
217 }
218 }
219
220 private void readZrlePackedPixels(int tw, int th, int[] palette, int palSize)
221 throws Exception {
222
223 int bppp = ((palSize > 16) ? 8 :
224 ((palSize > 4) ? 4 : ((palSize > 2) ? 2 : 1)));
225 int ptr = 0;
226
227 for (int i = 0; i < th; i++) {
228 int eol = ptr + tw;
229 int b = 0;
230 int nbits = 0;
231
232 while (ptr < eol) {
233 if (nbits == 0) {
234 b = zrleInStream.readU8();
235 nbits = 8;
236 }
237 nbits -= bppp;
238 int index = (b >> nbits) & ((1 << bppp) - 1) & 127;
239 if (bytesPerPixel == 1) {
240 zrleTilePixels8[ptr++] = (byte)palette[index];
241 } else {
242 zrleTilePixels24[ptr++] = palette[index];
243 }
244 }
245 }
246 }
247
248 private void readZrlePlainRLEPixels(int tw, int th) throws Exception {
249 int ptr = 0;
250 int end = ptr + tw * th;
251 while (ptr < end) {
252 int pix = readPixel(zrleInStream);
253 int len = 1;
254 int b;
255 do {
256 b = zrleInStream.readU8();
257 len += b;
258 } while (b == 255);
259
260 if (!(len <= end - ptr))
261 throw new Exception("ZRLE decoder: assertion failed" +
262 " (len <= end-ptr)");
263
264 if (bytesPerPixel == 1) {
265 while (len-- > 0) zrleTilePixels8[ptr++] = (byte)pix;
266 } else {
267 while (len-- > 0) zrleTilePixels24[ptr++] = pix;
268 }
269 }
270 }
271
272 private void readZrlePackedRLEPixels(int tw, int th, int[] palette)
273 throws Exception {
274
275 int ptr = 0;
276 int end = ptr + tw * th;
277 while (ptr < end) {
278 int index = zrleInStream.readU8();
279 int len = 1;
280 if ((index & 128) != 0) {
281 int b;
282 do {
283 b = zrleInStream.readU8();
284 len += b;
285 } while (b == 255);
286
287 if (!(len <= end - ptr))
288 throw new Exception("ZRLE decoder: assertion failed" +
289 " (len <= end - ptr)");
290 }
291
292 index &= 127;
293 int pix = palette[index];
294
295 if (bytesPerPixel == 1) {
296 while (len-- > 0) zrleTilePixels8[ptr++] = (byte)pix;
297 } else {
298 while (len-- > 0) zrleTilePixels24[ptr++] = pix;
299 }
300 }
301 }
302
303 //
304 // ZRLE encoder's data.
305 //
306
307 private byte[] zrleBuf;
308 private int zrleBufLen = 0;
309 private byte[] zrleTilePixels8;
310 private int[] zrleTilePixels24;
311 private ZlibInStream zrleInStream;
312 private boolean zrleRecWarningShown = false;
enikey27a239d2008-12-19 07:32:05 +0000313}