1 /*
2  * Copyright (C) 2002 RealVNC Ltd.  All Rights Reserved.
3  * Copyright (C) 2003 Sun Microsystems, Inc.
4  *
5  * This is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This software is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this software; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
18  * USA.
19  */
20 
21 /*
22  * zrle.c
23  *
24  * Routines to implement Zlib Run-length Encoding (ZRLE).
25  */
26 
27 #include "rfb/rfb.h"
28 #include "private.h"
29 #include "zrleoutstream.h"
30 
31 
32 #define GET_IMAGE_INTO_BUF(tx,ty,tw,th,buf)                                \
33 {  char *fbptr = (cl->scaledScreen->frameBuffer                                   \
34 		 + (cl->scaledScreen->paddedWidthInBytes * ty)                   \
35                  + (tx * (cl->scaledScreen->bitsPerPixel / 8)));                 \
36                                                                            \
37   (*cl->translateFn)(cl->translateLookupTable, &cl->screen->serverFormat,\
38                      &cl->format, fbptr, (char*)buf,                       \
39                      cl->scaledScreen->paddedWidthInBytes, tw, th); }
40 
41 #define EXTRA_ARGS , rfbClientPtr cl
42 
43 #define ENDIAN_LITTLE 0
44 #define ENDIAN_BIG 1
45 #define ENDIAN_NO 2
46 #define BPP 8
47 #define ZYWRLE_ENDIAN ENDIAN_NO
48 #include <zrleencodetemplate.c>
49 #undef BPP
50 #define BPP 15
51 #undef ZYWRLE_ENDIAN
52 #define ZYWRLE_ENDIAN ENDIAN_LITTLE
53 #include <zrleencodetemplate.c>
54 #undef ZYWRLE_ENDIAN
55 #define ZYWRLE_ENDIAN ENDIAN_BIG
56 #include <zrleencodetemplate.c>
57 #undef BPP
58 #define BPP 16
59 #undef ZYWRLE_ENDIAN
60 #define ZYWRLE_ENDIAN ENDIAN_LITTLE
61 #include <zrleencodetemplate.c>
62 #undef ZYWRLE_ENDIAN
63 #define ZYWRLE_ENDIAN ENDIAN_BIG
64 #include <zrleencodetemplate.c>
65 #undef BPP
66 #define BPP 32
67 #undef ZYWRLE_ENDIAN
68 #define ZYWRLE_ENDIAN ENDIAN_LITTLE
69 #include <zrleencodetemplate.c>
70 #undef ZYWRLE_ENDIAN
71 #define ZYWRLE_ENDIAN ENDIAN_BIG
72 #include <zrleencodetemplate.c>
73 #define CPIXEL 24A
74 #undef ZYWRLE_ENDIAN
75 #define ZYWRLE_ENDIAN ENDIAN_LITTLE
76 #include <zrleencodetemplate.c>
77 #undef ZYWRLE_ENDIAN
78 #define ZYWRLE_ENDIAN ENDIAN_BIG
79 #include <zrleencodetemplate.c>
80 #undef CPIXEL
81 #define CPIXEL 24B
82 #undef ZYWRLE_ENDIAN
83 #define ZYWRLE_ENDIAN ENDIAN_LITTLE
84 #include <zrleencodetemplate.c>
85 #undef ZYWRLE_ENDIAN
86 #define ZYWRLE_ENDIAN ENDIAN_BIG
87 #include <zrleencodetemplate.c>
88 #undef CPIXEL
89 #undef BPP
90 
91 
92 /*
93  * zrleBeforeBuf contains pixel data in the client's format.  It must be at
94  * least one pixel bigger than the largest tile of pixel data, since the
95  * ZRLE encoding algorithm writes to the position one past the end of the pixel
96  * data.
97  */
98 
99 
100 /*
101  * rfbSendRectEncodingZRLE - send a given rectangle using ZRLE encoding.
102  */
103 
rfbSendRectEncodingZRLE(rfbClientPtr cl,int x,int y,int w,int h)104 rfbBool rfbSendRectEncodingZRLE(rfbClientPtr cl, int x, int y, int w, int h)
105 {
106   zrleOutStream* zos;
107   rfbFramebufferUpdateRectHeader rect;
108   rfbZRLEHeader hdr;
109   int i;
110   char *zrleBeforeBuf;
111 
112   if (cl->zrleBeforeBuf == NULL) {
113 	cl->zrleBeforeBuf = (char *) malloc(rfbZRLETileWidth * rfbZRLETileHeight * 4 + 4);
114   }
115   zrleBeforeBuf = cl->zrleBeforeBuf;
116 
117   if (cl->preferredEncoding == rfbEncodingZYWRLE) {
118 	  if (cl->tightQualityLevel < 0) {
119 		  cl->zywrleLevel = 1;
120 	  } else if (cl->tightQualityLevel < 3) {
121 		  cl->zywrleLevel = 3;
122 	  } else if (cl->tightQualityLevel < 6) {
123 		  cl->zywrleLevel = 2;
124 	  } else {
125 		  cl->zywrleLevel = 1;
126 	  }
127   } else
128 	  cl->zywrleLevel = 0;
129 
130   if (!cl->zrleData)
131     cl->zrleData = zrleOutStreamNew();
132   zos = cl->zrleData;
133   zos->in.ptr = zos->in.start;
134   zos->out.ptr = zos->out.start;
135 
136   switch (cl->format.bitsPerPixel) {
137 
138   case 8:
139     zrleEncode8NE(x, y, w, h, zos, zrleBeforeBuf, cl);
140     break;
141 
142   case 16:
143 	if (cl->format.greenMax > 0x1F) {
144 		if (cl->format.bigEndian)
145 		  zrleEncode16BE(x, y, w, h, zos, zrleBeforeBuf, cl);
146 		else
147 		  zrleEncode16LE(x, y, w, h, zos, zrleBeforeBuf, cl);
148 	} else {
149 		if (cl->format.bigEndian)
150 		  zrleEncode15BE(x, y, w, h, zos, zrleBeforeBuf, cl);
151 		else
152 		  zrleEncode15LE(x, y, w, h, zos, zrleBeforeBuf, cl);
153 	}
154     break;
155 
156   case 32: {
157     rfbBool fitsInLS3Bytes
158       = ((cl->format.redMax   << cl->format.redShift)   < (1<<24) &&
159          (cl->format.greenMax << cl->format.greenShift) < (1<<24) &&
160          (cl->format.blueMax  << cl->format.blueShift)  < (1<<24));
161 
162     rfbBool fitsInMS3Bytes = (cl->format.redShift   > 7  &&
163                            cl->format.greenShift > 7  &&
164                            cl->format.blueShift  > 7);
165 
166     if ((fitsInLS3Bytes && !cl->format.bigEndian) ||
167         (fitsInMS3Bytes && cl->format.bigEndian)) {
168 	if (cl->format.bigEndian)
169 		zrleEncode24ABE(x, y, w, h, zos, zrleBeforeBuf, cl);
170 	else
171 		zrleEncode24ALE(x, y, w, h, zos, zrleBeforeBuf, cl);
172     }
173     else if ((fitsInLS3Bytes && cl->format.bigEndian) ||
174              (fitsInMS3Bytes && !cl->format.bigEndian)) {
175 	if (cl->format.bigEndian)
176 		zrleEncode24BBE(x, y, w, h, zos, zrleBeforeBuf, cl);
177 	else
178 		zrleEncode24BLE(x, y, w, h, zos, zrleBeforeBuf, cl);
179     }
180     else {
181 	if (cl->format.bigEndian)
182 		zrleEncode32BE(x, y, w, h, zos, zrleBeforeBuf, cl);
183 	else
184 		zrleEncode32LE(x, y, w, h, zos, zrleBeforeBuf, cl);
185     }
186   }
187     break;
188   }
189 
190   rfbStatRecordEncodingSent(cl, rfbEncodingZRLE, sz_rfbFramebufferUpdateRectHeader + sz_rfbZRLEHeader + ZRLE_BUFFER_LENGTH(&zos->out),
191       + w * (cl->format.bitsPerPixel / 8) * h);
192 
193   if (cl->ublen + sz_rfbFramebufferUpdateRectHeader + sz_rfbZRLEHeader
194       > UPDATE_BUF_SIZE)
195     {
196       if (!rfbSendUpdateBuf(cl))
197         return FALSE;
198     }
199 
200   rect.r.x = Swap16IfLE(x);
201   rect.r.y = Swap16IfLE(y);
202   rect.r.w = Swap16IfLE(w);
203   rect.r.h = Swap16IfLE(h);
204   rect.encoding = Swap32IfLE(cl->preferredEncoding);
205 
206   memcpy(cl->updateBuf+cl->ublen, (char *)&rect,
207          sz_rfbFramebufferUpdateRectHeader);
208   cl->ublen += sz_rfbFramebufferUpdateRectHeader;
209 
210   hdr.length = Swap32IfLE(ZRLE_BUFFER_LENGTH(&zos->out));
211 
212   memcpy(cl->updateBuf+cl->ublen, (char *)&hdr, sz_rfbZRLEHeader);
213   cl->ublen += sz_rfbZRLEHeader;
214 
215   /* copy into updateBuf and send from there.  Maybe should send directly? */
216 
217   for (i = 0; i < ZRLE_BUFFER_LENGTH(&zos->out);) {
218 
219     int bytesToCopy = UPDATE_BUF_SIZE - cl->ublen;
220 
221     if (i + bytesToCopy > ZRLE_BUFFER_LENGTH(&zos->out)) {
222       bytesToCopy = ZRLE_BUFFER_LENGTH(&zos->out) - i;
223     }
224 
225     memcpy(cl->updateBuf+cl->ublen, (uint8_t*)zos->out.start + i, bytesToCopy);
226 
227     cl->ublen += bytesToCopy;
228     i += bytesToCopy;
229 
230     if (cl->ublen == UPDATE_BUF_SIZE) {
231       if (!rfbSendUpdateBuf(cl))
232         return FALSE;
233     }
234   }
235 
236   return TRUE;
237 }
238 
239 
rfbFreeZrleData(rfbClientPtr cl)240 void rfbFreeZrleData(rfbClientPtr cl)
241 {
242 	if (cl->zrleData) {
243 		zrleOutStreamFree(cl->zrleData);
244 	}
245 	cl->zrleData = NULL;
246 
247 	if (cl->zrleBeforeBuf) {
248 		free(cl->zrleBeforeBuf);
249 	}
250 	cl->zrleBeforeBuf = NULL;
251 
252 	if (cl->paletteHelper) {
253 		free(cl->paletteHelper);
254 	}
255 	cl->paletteHelper = NULL;
256 }
257 
258