blob: 37612ea33f6129b02f6dd4f9243d49bdcfb630d1 [file] [log] [blame]
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +00001/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
Pierre Ossman7638e9c2014-01-16 13:12:40 +01002 * Copyright 2009-2014 Pierre Ossman for Cendio AB
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +00003 *
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., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
17 * USA.
18 */
19#include <stdio.h>
Pierre Ossman7638e9c2014-01-16 13:12:40 +010020#include <rfb/msgTypes.h>
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000021#include <rdr/InStream.h>
22#include <rfb/Exception.h>
23#include <rfb/util.h>
24#include <rfb/CMsgHandler.h>
25#include <rfb/CMsgReader.h>
Pierre Ossman7638e9c2014-01-16 13:12:40 +010026#include <rfb/Decoder.h>
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000027
28using namespace rfb;
29
30CMsgReader::CMsgReader(CMsgHandler* handler_, rdr::InStream* is_)
31 : imageBufIdealSize(0), handler(handler_), is(is_),
Pierre Ossman7638e9c2014-01-16 13:12:40 +010032 imageBuf(0), imageBufSize(0), nUpdateRectsLeft(0)
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000033{
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000034}
35
36CMsgReader::~CMsgReader()
37{
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000038 delete [] imageBuf;
39}
40
Pierre Ossman7638e9c2014-01-16 13:12:40 +010041void CMsgReader::readServerInit()
42{
43 int width = is->readU16();
44 int height = is->readU16();
45 handler->setDesktopSize(width, height);
46 PixelFormat pf;
47 pf.read(is);
48 handler->setPixelFormat(pf);
49 CharArray name(is->readString());
50 handler->setName(name.buf);
51 handler->serverInit();
52}
53
54void CMsgReader::readMsg()
55{
56 if (nUpdateRectsLeft == 0) {
57 int type = is->readU8();
58
59 switch (type) {
60 case msgTypeSetColourMapEntries:
61 readSetColourMapEntries();
62 break;
63 case msgTypeBell:
64 readBell();
65 break;
66 case msgTypeServerCutText:
67 readServerCutText();
68 break;
69 case msgTypeFramebufferUpdate:
70 readFramebufferUpdate();
71 break;
72 case msgTypeServerFence:
73 readFence();
74 break;
75 case msgTypeEndOfContinuousUpdates:
76 readEndOfContinuousUpdates();
77 break;
78 default:
79 fprintf(stderr, "unknown message type %d\n", type);
80 throw Exception("unknown message type");
81 }
82 } else {
83 int x = is->readU16();
84 int y = is->readU16();
85 int w = is->readU16();
86 int h = is->readU16();
87 int encoding = is->readS32();
88
89 switch (encoding) {
90 case pseudoEncodingLastRect:
91 nUpdateRectsLeft = 1; // this rectangle is the last one
92 break;
93 case pseudoEncodingCursor:
94 readSetCursor(w, h, Point(x,y));
95 break;
96 case pseudoEncodingDesktopName:
97 readSetDesktopName(x, y, w, h);
98 break;
99 case pseudoEncodingDesktopSize:
100 handler->setDesktopSize(w, h);
101 break;
102 case pseudoEncodingExtendedDesktopSize:
103 readExtendedDesktopSize(x, y, w, h);
104 break;
105 default:
106 readRect(Rect(x, y, x+w, y+h), encoding);
107 break;
108 };
109
110 nUpdateRectsLeft--;
111 if (nUpdateRectsLeft == 0)
112 handler->framebufferUpdateEnd();
113 }
114}
115
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000116void CMsgReader::readSetColourMapEntries()
117{
118 is->skip(1);
119 int firstColour = is->readU16();
120 int nColours = is->readU16();
121 rdr::U16Array rgbs(nColours * 3);
122 for (int i = 0; i < nColours * 3; i++)
123 rgbs.buf[i] = is->readU16();
124 handler->setColourMapEntries(firstColour, nColours, rgbs.buf);
125}
126
127void CMsgReader::readBell()
128{
129 handler->bell();
130}
131
132void CMsgReader::readServerCutText()
133{
134 is->skip(3);
Adam Tkacacf6c6b2009-02-13 12:42:05 +0000135 rdr::U32 len = is->readU32();
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000136 if (len > 256*1024) {
137 is->skip(len);
138 fprintf(stderr,"cut text too long (%d bytes) - ignoring\n",len);
139 return;
140 }
141 CharArray ca(len+1);
142 ca.buf[len] = 0;
143 is->readBytes(ca.buf, len);
144 handler->serverCutText(ca.buf, len);
145}
146
Pierre Ossman7638e9c2014-01-16 13:12:40 +0100147void CMsgReader::readFence()
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000148{
Pierre Ossman7638e9c2014-01-16 13:12:40 +0100149 rdr::U32 flags;
150 rdr::U8 len;
151 char data[64];
152
153 is->skip(3);
154
155 flags = is->readU32();
156
157 len = is->readU8();
158 if (len > sizeof(data)) {
159 fprintf(stderr, "Ignoring fence with too large payload\n");
160 is->skip(len);
161 return;
162 }
163
164 is->readBytes(data, len);
165
166 handler->fence(flags, len, data);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000167}
168
Pierre Ossman7638e9c2014-01-16 13:12:40 +0100169void CMsgReader::readEndOfContinuousUpdates()
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000170{
Pierre Ossman7638e9c2014-01-16 13:12:40 +0100171 handler->endOfContinuousUpdates();
172}
173
174void CMsgReader::readFramebufferUpdate()
175{
176 is->skip(1);
177 nUpdateRectsLeft = is->readU16();
178 handler->framebufferUpdateStart();
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000179}
180
Peter Åstrand98fe98c2010-02-10 07:43:02 +0000181void CMsgReader::readRect(const Rect& r, int encoding)
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000182{
183 if ((r.br.x > handler->cp.width) || (r.br.y > handler->cp.height)) {
184 fprintf(stderr, "Rect too big: %dx%d at %d,%d exceeds %dx%d\n",
185 r.width(), r.height(), r.tl.x, r.tl.y,
186 handler->cp.width, handler->cp.height);
187 throw Exception("Rect too big");
188 }
189
190 if (r.is_empty())
191 fprintf(stderr, "Warning: zero size rect\n");
192
Pierre Ossmanfdba3fe2014-01-31 13:12:18 +0100193 handler->dataRect(r, encoding);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000194}
195
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000196void CMsgReader::readSetCursor(int width, int height, const Point& hotspot)
197{
198 int data_len = width * height * (handler->cp.pf().bpp/8);
199 int mask_len = ((width+7)/8) * height;
200 rdr::U8Array data(data_len);
201 rdr::U8Array mask(mask_len);
202
203 is->readBytes(data.buf, data_len);
204 is->readBytes(mask.buf, mask_len);
205
206 handler->setCursor(width, height, hotspot, data.buf, mask.buf);
207}
208
Pierre Ossman7638e9c2014-01-16 13:12:40 +0100209void CMsgReader::readSetDesktopName(int x, int y, int w, int h)
210{
211 char* name = is->readString();
212
213 if (x || y || w || h) {
214 fprintf(stderr, "Ignoring DesktopName rect with non-zero position/size\n");
215 } else {
216 handler->setName(name);
217 }
218
219 delete [] name;
220}
221
222void CMsgReader::readExtendedDesktopSize(int x, int y, int w, int h)
223{
224 unsigned int screens, i;
225 rdr::U32 id, flags;
226 int sx, sy, sw, sh;
227 ScreenSet layout;
228
229 screens = is->readU8();
230 is->skip(3);
231
232 for (i = 0;i < screens;i++) {
233 id = is->readU32();
234 sx = is->readU16();
235 sy = is->readU16();
236 sw = is->readU16();
237 sh = is->readU16();
238 flags = is->readU32();
239
240 layout.add_screen(Screen(id, sx, sy, sw, sh, flags));
241 }
242
243 handler->setExtendedDesktopSize(x, y, w, h, layout);
244}
245
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000246rdr::U8* CMsgReader::getImageBuf(int required, int requested, int* nPixels)
247{
248 int requiredBytes = required * (handler->cp.pf().bpp / 8);
249 int requestedBytes = requested * (handler->cp.pf().bpp / 8);
250 int size = requestedBytes;
251 if (size > imageBufIdealSize) size = imageBufIdealSize;
252
253 if (size < requiredBytes)
254 size = requiredBytes;
255
256 if (imageBufSize < size) {
257 imageBufSize = size;
258 delete [] imageBuf;
259 imageBuf = new rdr::U8[imageBufSize];
260 }
261 if (nPixels)
262 *nPixels = imageBufSize / (handler->cp.pf().bpp / 8);
263 return imageBuf;
264}
265
266int CMsgReader::bpp()
267{
268 return handler->cp.pf().bpp;
269}