1 /* Copyright (C) 2002-2005 RealVNC Ltd.  All Rights Reserved.
2  * Copyright (C) 2019 Brian P. Hinz
3  *
4  * This is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This software is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this software; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
17  * USA.
18  */
19 
20 package com.tigervnc.rfb;
21 
22 import java.awt.image.*;
23 import java.nio.*;
24 import java.util.*;
25 
26 import com.tigervnc.rdr.*;
27 
28 public class ZRLEDecoder extends Decoder {
29 
readOpaque24A(InStream is)30   private static ByteBuffer readOpaque24A(InStream is)
31   {
32     is.check(3);
33     ByteBuffer r = ByteBuffer.allocate(4);
34     r.put(0, (byte)is.readU8());
35     r.put(1, (byte)is.readU8());
36     r.put(2, (byte)is.readU8());
37     return r;
38   }
39 
readOpaque24B(InStream is)40   private static ByteBuffer readOpaque24B(InStream is)
41   {
42     is.check(3);
43     ByteBuffer r = ByteBuffer.allocate(4);
44     r.put(1, (byte)is.readU8());
45     r.put(2, (byte)is.readU8());
46     r.put(3, (byte)is.readU8());
47     return r;
48   }
49 
ZRLEDecoder()50   public ZRLEDecoder() {
51     super(DecoderFlags.DecoderOrdered);
52     zis = new ZlibInStream();
53   }
54 
readRect(Rect r, InStream is, ServerParams server, OutStream os)55   public void readRect(Rect r, InStream is,
56                       ServerParams server, OutStream os)
57   {
58     int len;
59 
60     len = is.readU32();
61     os.writeU32(len);
62     os.copyBytes(is, len);
63   }
64 
decodeRect(Rect r, Object buffer, int buflen, ServerParams server, ModifiablePixelBuffer pb)65   public void decodeRect(Rect r, Object buffer,
66                          int buflen, ServerParams server,
67                          ModifiablePixelBuffer pb)
68   {
69     MemInStream is = new MemInStream((byte[])buffer, 0, buflen);
70     PixelFormat pf = server.pf();
71     switch (pf.bpp) {
72     case 8:  zrleDecode8(r, is, zis, pf, pb); break;
73     case 16: zrleDecode16(r, is, zis, pf, pb); break;
74     case 32:
75       {
76         if (pf.depth <= 24) {
77           int maxPixel = pf.pixelFromRGB(-1, -1, -1, pf.getColorModel());
78           boolean fitsInLS3Bytes = maxPixel < (1<<24);
79           boolean fitsInMS3Bytes = (maxPixel & 0xff) == 0;
80 
81           if ((fitsInLS3Bytes && pf.isLittleEndian()) ||
82               (fitsInMS3Bytes && pf.isBigEndian()))
83           {
84             zrleDecode24A(r, is, zis, pf, pb);
85             break;
86           }
87 
88           if ((fitsInLS3Bytes && pf.isBigEndian()) ||
89               (fitsInMS3Bytes && pf.isLittleEndian()))
90           {
91             zrleDecode24B(r, is, zis, pf, pb);
92             break;
93           }
94         }
95 
96         zrleDecode32(r, is, zis, pf, pb);
97         break;
98       }
99     }
100   }
101 
102   private static enum PIXEL_T { U8, U16, U24A, U24B, U32 };
103 
104   private static ByteBuffer READ_PIXEL(InStream is, PIXEL_T type) {
105     switch (type) {
106     case U8:
107       return ByteBuffer.allocate(1).put(0, (byte)is.readOpaque8());
108     case U16:
109       return ByteBuffer.allocate(2).putShort(0, (short)is.readOpaque16());
110     case U24A:
111       return readOpaque24A(is);
112     case U24B:
113       return readOpaque24B(is);
114     default:
115       return ByteBuffer.allocate(4).putInt(0, is.readOpaque32());
116     }
117   }
118 
119   private void zrleDecode8(Rect r, InStream is,
120                            ZlibInStream zis,
121                            PixelFormat pf, ModifiablePixelBuffer pb)
122   {
123     ZRLE_DECODE(r, is, zis, pf, pb, PIXEL_T.U8);
124   }
125 
126   private void zrleDecode16(Rect r, InStream is,
127                             ZlibInStream zis,
128                             PixelFormat pf, ModifiablePixelBuffer pb)
129   {
130     ZRLE_DECODE(r, is, zis, pf, pb, PIXEL_T.U16);
131   }
132 
133   private void zrleDecode24A(Rect r, InStream is,
134                              ZlibInStream zis,
135                              PixelFormat pf, ModifiablePixelBuffer pb)
136   {
137     ZRLE_DECODE(r, is, zis, pf, pb, PIXEL_T.U24A);
138   }
139 
140   private void zrleDecode24B(Rect r, InStream is,
141                              ZlibInStream zis,
142                              PixelFormat pf, ModifiablePixelBuffer pb)
143   {
144     ZRLE_DECODE(r, is, zis, pf, pb, PIXEL_T.U24B);
145   }
146 
147   private void zrleDecode32(Rect r, InStream is,
148                             ZlibInStream zis,
149                             PixelFormat pf, ModifiablePixelBuffer pb)
150   {
151     ZRLE_DECODE(r, is, zis, pf, pb, PIXEL_T.U32);
152   }
153 
154   private void ZRLE_DECODE(Rect r, InStream is,
155                            ZlibInStream zis,
156                            PixelFormat pf, ModifiablePixelBuffer pb,
157                            PIXEL_T pix_t)
158   {
159     int length = is.readU32();
160     zis.setUnderlying(is, length);
161     Rect t = new Rect();
162     ByteBuffer buf = ByteBuffer.allocate(64 * 64 * pf.bpp/8);
163 
164     for (t.tl.y = r.tl.y; t.tl.y < r.br.y; t.tl.y += 64) {
165 
166       t.br.y = Math.min(r.br.y, t.tl.y + 64);
167 
168       for (t.tl.x = r.tl.x; t.tl.x < r.br.x; t.tl.x += 64) {
169 
170         t.br.x = Math.min(r.br.x, t.tl.x + 64);
171 
172         int mode = zis.readU8();
173         boolean rle = (mode & 128) != 0;
174         int palSize = mode & 127;
175         ByteBuffer palette = ByteBuffer.allocate(128 * pf.bpp/8);
176 
177         for (int i = 0; i < palSize; i++) {
178           palette.put(READ_PIXEL(zis, pix_t));
179         }
180         palette.flip();
181 
182         if (palSize == 1) {
183           byte[] pix = new byte[pf.bpp/8];
184           palette.get(pix);
185           pb.fillRect(pf, t, pix);
186           continue;
187         }
188 
189         if (!rle) {
190           if (palSize == 0) {
191 
192             // raw
193             switch (pix_t) {
194             case U24A:
195             case U24B:
196               ByteBuffer ptr = buf.duplicate();
197               for (int i=0; i < t.area(); i++) {
198                 ptr.put(READ_PIXEL(zis, pix_t));
199               }
200               break;
201             default:
202               zis.readBytes(buf.duplicate(), t.area() * (pf.bpp/8));
203             }
204 
205           } else {
206 
207             // packed pixels
208             int bppp = ((palSize > 16) ? 8 :
209                         ((palSize > 4) ? 4 : ((palSize > 2) ? 2 : 1)));
210 
211             ByteBuffer ptr = buf.duplicate();
212 
213             for (int i = 0; i < t.height(); i++) {
214               int eol = ptr.position() + t.width()*pf.bpp/8;
215               int b = 0;
216               int nbits = 0;
217 
218               while (ptr.position() < eol) {
219                 if (nbits == 0) {
220                   b = zis.readU8();
221                   nbits = 8;
222                 }
223                 nbits -= bppp;
224                 int index = (b >> nbits) & ((1 << bppp) - 1) & 127;
225                 ptr.put(palette.array(), index*pf.bpp/8, pf.bpp/8);
226               }
227             }
228           }
229 
230         } else {
231 
232           if (palSize == 0) {
233 
234             // plain RLE
235 
236             ByteBuffer ptr = buf.duplicate();
237             int end = ptr.position() + t.area()*pf.bpp/8;
238             while (ptr.position() < end) {
239               ByteBuffer pix = READ_PIXEL(zis, pix_t);
240               int len = 1;
241               int b;
242               do {
243                 b = zis.readU8();
244                 len += b;
245               } while (b == 255);
246 
247               if (end - ptr.position() < len*pf.bpp/8) {
248                 System.err.println("ZRLE decode error\n");
249                 throw new Exception("ZRLE decode error");
250               }
251 
252               while (len-- > 0) ptr.put(pix.array());
253 
254             }
255           } else {
256 
257             // palette RLE
258 
259             ByteBuffer ptr = buf.duplicate();
260             int end = ptr.position() + t.area()*pf.bpp/8;
261             while (ptr.position() < end) {
262               int index = zis.readU8();
263               int len = 1;
264               if ((index & 128) != 0) {
265                 int b;
266                 do {
267                   b = zis.readU8();
268                   len += b;
269                 } while (b == 255);
270 
271                 if (end - ptr.position() < len*pf.bpp/8) {
272                   System.err.println("ZRLE decode error\n");
273                   throw new Exception("ZRLE decode error");
274                 }
275               }
276 
277               index &= 127;
278 
279               ByteBuffer pix = ByteBuffer.allocate(pf.bpp/8);
280               pix.put(palette.array(), index*pf.bpp/8, pf.bpp/8);
281 
282               while (len-- > 0) ptr.put(pix.array());
283             }
284           }
285         }
286 
287         pb.imageRect(pf, t, buf.array());
288       }
289     }
290 
291     zis.flushUnderlying();
292     zis.setUnderlying(null, 0);
293   }
294 
295   private ZlibInStream zis;
296 }
297