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