fix disconnect bug in libvncserver
[presencevnc] / libvnc / libvncserver / zrle.c
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 /* TODO: put into rfbClient struct */
100 static char zrleBeforeBuf[rfbZRLETileWidth * rfbZRLETileHeight * 4 + 4];
101
102
103
104 /*
105  * rfbSendRectEncodingZRLE - send a given rectangle using ZRLE encoding.
106  */
107
108
109 rfbBool rfbSendRectEncodingZRLE(rfbClientPtr cl, int x, int y, int w, int h)
110 {
111   zrleOutStream* zos;
112   rfbFramebufferUpdateRectHeader rect;
113   rfbZRLEHeader hdr;
114   int i;
115
116   if (cl->preferredEncoding == rfbEncodingZYWRLE) {
117           if (cl->tightQualityLevel < 0) {
118                   cl->zywrleLevel = 1;
119           } else if (cl->tightQualityLevel < 3) {
120                   cl->zywrleLevel = 3;
121           } else if (cl->tightQualityLevel < 6) {
122                   cl->zywrleLevel = 2;
123           } else {
124                   cl->zywrleLevel = 1;
125           }
126   } else
127           cl->zywrleLevel = 0;
128
129   if (!cl->zrleData)
130     cl->zrleData = zrleOutStreamNew();
131   zos = cl->zrleData;
132   zos->in.ptr = zos->in.start;
133   zos->out.ptr = zos->out.start;
134
135   switch (cl->format.bitsPerPixel) {
136
137   case 8:
138     zrleEncode8NE(x, y, w, h, zos, zrleBeforeBuf, cl);
139     break;
140
141   case 16:
142         if (cl->format.greenMax > 0x1F) {
143                 if (cl->format.bigEndian)
144                   zrleEncode16BE(x, y, w, h, zos, zrleBeforeBuf, cl);
145                 else
146                   zrleEncode16LE(x, y, w, h, zos, zrleBeforeBuf, cl);
147         } else {
148                 if (cl->format.bigEndian)
149                   zrleEncode15BE(x, y, w, h, zos, zrleBeforeBuf, cl);
150                 else
151                   zrleEncode15LE(x, y, w, h, zos, zrleBeforeBuf, cl);
152         }
153     break;
154
155   case 32: {
156     rfbBool fitsInLS3Bytes
157       = ((cl->format.redMax   << cl->format.redShift)   < (1<<24) &&
158          (cl->format.greenMax << cl->format.greenShift) < (1<<24) &&
159          (cl->format.blueMax  << cl->format.blueShift)  < (1<<24));
160
161     rfbBool fitsInMS3Bytes = (cl->format.redShift   > 7  &&
162                            cl->format.greenShift > 7  &&
163                            cl->format.blueShift  > 7);
164
165     if ((fitsInLS3Bytes && !cl->format.bigEndian) ||
166         (fitsInMS3Bytes && cl->format.bigEndian)) {
167         if (cl->format.bigEndian)
168                 zrleEncode24ABE(x, y, w, h, zos, zrleBeforeBuf, cl);
169         else
170                 zrleEncode24ALE(x, y, w, h, zos, zrleBeforeBuf, cl);
171     }
172     else if ((fitsInLS3Bytes && cl->format.bigEndian) ||
173              (fitsInMS3Bytes && !cl->format.bigEndian)) {
174         if (cl->format.bigEndian)
175                 zrleEncode24BBE(x, y, w, h, zos, zrleBeforeBuf, cl);
176         else
177                 zrleEncode24BLE(x, y, w, h, zos, zrleBeforeBuf, cl);
178     }
179     else {
180         if (cl->format.bigEndian)
181                 zrleEncode32BE(x, y, w, h, zos, zrleBeforeBuf, cl);
182         else
183                 zrleEncode32LE(x, y, w, h, zos, zrleBeforeBuf, cl);
184     }
185   }
186     break;
187   }
188
189   rfbStatRecordEncodingSent(cl, rfbEncodingZRLE, sz_rfbFramebufferUpdateRectHeader + sz_rfbZRLEHeader + ZRLE_BUFFER_LENGTH(&zos->out),
190       + w * (cl->format.bitsPerPixel / 8) * h);
191
192   if (cl->ublen + sz_rfbFramebufferUpdateRectHeader + sz_rfbZRLEHeader
193       > UPDATE_BUF_SIZE)
194     {
195       if (!rfbSendUpdateBuf(cl))
196         return FALSE;
197     }
198
199   rect.r.x = Swap16IfLE(x);
200   rect.r.y = Swap16IfLE(y);
201   rect.r.w = Swap16IfLE(w);
202   rect.r.h = Swap16IfLE(h);
203   rect.encoding = Swap32IfLE(cl->preferredEncoding);
204
205   memcpy(cl->updateBuf+cl->ublen, (char *)&rect,
206          sz_rfbFramebufferUpdateRectHeader);
207   cl->ublen += sz_rfbFramebufferUpdateRectHeader;
208
209   hdr.length = Swap32IfLE(ZRLE_BUFFER_LENGTH(&zos->out));
210
211   memcpy(cl->updateBuf+cl->ublen, (char *)&hdr, sz_rfbZRLEHeader);
212   cl->ublen += sz_rfbZRLEHeader;
213
214   /* copy into updateBuf and send from there.  Maybe should send directly? */
215
216   for (i = 0; i < ZRLE_BUFFER_LENGTH(&zos->out);) {
217
218     int bytesToCopy = UPDATE_BUF_SIZE - cl->ublen;
219
220     if (i + bytesToCopy > ZRLE_BUFFER_LENGTH(&zos->out)) {
221       bytesToCopy = ZRLE_BUFFER_LENGTH(&zos->out) - i;
222     }
223
224     memcpy(cl->updateBuf+cl->ublen, (uint8_t*)zos->out.start + i, bytesToCopy);
225
226     cl->ublen += bytesToCopy;
227     i += bytesToCopy;
228
229     if (cl->ublen == UPDATE_BUF_SIZE) {
230       if (!rfbSendUpdateBuf(cl))
231         return FALSE;
232     }
233   }
234
235   return TRUE;
236 }
237
238
239 void rfbFreeZrleData(rfbClientPtr cl)
240 {
241   if (cl->zrleData)
242     zrleOutStreamFree(cl->zrleData);
243   cl->zrleData = NULL;
244 }
245