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