You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

CMsgReader.cxx 18KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840
  1. /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
  2. * Copyright 2009-2019 Pierre Ossman for Cendio AB
  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., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
  17. * USA.
  18. */
  19. #ifdef HAVE_CONFIG_H
  20. #include <config.h>
  21. #endif
  22. #include <assert.h>
  23. #include <stdio.h>
  24. #include <rdr/InStream.h>
  25. #include <rdr/ZlibInStream.h>
  26. #include <rfb/msgTypes.h>
  27. #include <rfb/clipboardTypes.h>
  28. #include <rfb/Exception.h>
  29. #include <rfb/LogWriter.h>
  30. #include <rfb/util.h>
  31. #include <rfb/CMsgHandler.h>
  32. #include <rfb/CMsgReader.h>
  33. static rfb::LogWriter vlog("CMsgReader");
  34. static rfb::IntParameter maxCutText("MaxCutText", "Maximum permitted length of an incoming clipboard update", 256*1024);
  35. using namespace rfb;
  36. CMsgReader::CMsgReader(CMsgHandler* handler_, rdr::InStream* is_)
  37. : imageBufIdealSize(0), handler(handler_), is(is_),
  38. state(MSGSTATE_IDLE), cursorEncoding(-1)
  39. {
  40. }
  41. CMsgReader::~CMsgReader()
  42. {
  43. }
  44. bool CMsgReader::readServerInit()
  45. {
  46. int width, height;
  47. rdr::U32 len;
  48. if (!is->hasData(2 + 2 + 16 + 4))
  49. return false;
  50. is->setRestorePoint();
  51. width = is->readU16();
  52. height = is->readU16();
  53. PixelFormat pf;
  54. pf.read(is);
  55. len = is->readU32();
  56. if (!is->hasDataOrRestore(len))
  57. return false;
  58. is->clearRestorePoint();
  59. CharArray name(len + 1);
  60. is->readBytes(name.buf, len);
  61. name.buf[len] = '\0';
  62. handler->serverInit(width, height, pf, name.buf);
  63. return true;
  64. }
  65. bool CMsgReader::readMsg()
  66. {
  67. if (state == MSGSTATE_IDLE) {
  68. if (!is->hasData(1))
  69. return false;
  70. currentMsgType = is->readU8();
  71. state = MSGSTATE_MESSAGE;
  72. }
  73. if (currentMsgType != msgTypeFramebufferUpdate) {
  74. bool ret;
  75. switch (currentMsgType) {
  76. case msgTypeSetColourMapEntries:
  77. ret = readSetColourMapEntries();
  78. break;
  79. case msgTypeBell:
  80. ret = readBell();
  81. break;
  82. case msgTypeServerCutText:
  83. ret = readServerCutText();
  84. break;
  85. case msgTypeFramebufferUpdate:
  86. ret = readFramebufferUpdate();
  87. break;
  88. case msgTypeServerFence:
  89. ret = readFence();
  90. break;
  91. case msgTypeEndOfContinuousUpdates:
  92. ret = readEndOfContinuousUpdates();
  93. break;
  94. default:
  95. throw Exception("Unknown message type %d", currentMsgType);
  96. }
  97. if (ret)
  98. state = MSGSTATE_IDLE;
  99. return ret;
  100. } else {
  101. if (state == MSGSTATE_MESSAGE) {
  102. if (!readFramebufferUpdate())
  103. return false;
  104. // Empty update?
  105. if (nUpdateRectsLeft == 0) {
  106. state = MSGSTATE_IDLE;
  107. handler->framebufferUpdateEnd();
  108. return true;
  109. }
  110. state = MSGSTATE_RECT_HEADER;
  111. }
  112. if (state == MSGSTATE_RECT_HEADER) {
  113. if (!is->hasData(2 + 2 + 2 + 2 + 4))
  114. return false;
  115. int x = is->readU16();
  116. int y = is->readU16();
  117. int w = is->readU16();
  118. int h = is->readU16();
  119. dataRect.setXYWH(x, y, w, h);
  120. rectEncoding = is->readS32();
  121. state = MSGSTATE_RECT_DATA;
  122. }
  123. bool ret;
  124. switch (rectEncoding) {
  125. case pseudoEncodingLastRect:
  126. nUpdateRectsLeft = 1; // this rectangle is the last one
  127. ret = true;
  128. break;
  129. case pseudoEncodingXCursor:
  130. ret = readSetXCursor(dataRect.width(), dataRect.height(), dataRect.tl);
  131. break;
  132. case pseudoEncodingCursor:
  133. ret = readSetCursor(dataRect.width(), dataRect.height(), dataRect.tl);
  134. break;
  135. case pseudoEncodingCursorWithAlpha:
  136. ret = readSetCursorWithAlpha(dataRect.width(), dataRect.height(), dataRect.tl);
  137. break;
  138. case pseudoEncodingVMwareCursor:
  139. ret = readSetVMwareCursor(dataRect.width(), dataRect.height(), dataRect.tl);
  140. break;
  141. case pseudoEncodingVMwareCursorPosition:
  142. handler->setCursorPos(dataRect.tl);
  143. ret = true;
  144. break;
  145. case pseudoEncodingDesktopName:
  146. ret = readSetDesktopName(dataRect.tl.x, dataRect.tl.y,
  147. dataRect.width(), dataRect.height());
  148. break;
  149. case pseudoEncodingDesktopSize:
  150. handler->setDesktopSize(dataRect.width(), dataRect.height());
  151. ret = true;
  152. break;
  153. case pseudoEncodingExtendedDesktopSize:
  154. ret = readExtendedDesktopSize(dataRect.tl.x, dataRect.tl.y,
  155. dataRect.width(), dataRect.height());
  156. break;
  157. case pseudoEncodingLEDState:
  158. ret = readLEDState();
  159. break;
  160. case pseudoEncodingVMwareLEDState:
  161. ret = readVMwareLEDState();
  162. break;
  163. case pseudoEncodingQEMUKeyEvent:
  164. handler->supportsQEMUKeyEvent();
  165. ret = true;
  166. break;
  167. default:
  168. ret = readRect(dataRect, rectEncoding);
  169. break;
  170. };
  171. if (ret) {
  172. state = MSGSTATE_RECT_HEADER;
  173. nUpdateRectsLeft--;
  174. if (nUpdateRectsLeft == 0) {
  175. state = MSGSTATE_IDLE;
  176. handler->framebufferUpdateEnd();
  177. }
  178. }
  179. return ret;
  180. }
  181. }
  182. bool CMsgReader::readSetColourMapEntries()
  183. {
  184. if (!is->hasData(1 + 2 + 2))
  185. return false;
  186. is->setRestorePoint();
  187. is->skip(1);
  188. int firstColour = is->readU16();
  189. int nColours = is->readU16();
  190. if (!is->hasDataOrRestore(nColours * 3 * 2))
  191. return false;
  192. is->clearRestorePoint();
  193. rdr::U16Array rgbs(nColours * 3);
  194. for (int i = 0; i < nColours * 3; i++)
  195. rgbs.buf[i] = is->readU16();
  196. handler->setColourMapEntries(firstColour, nColours, rgbs.buf);
  197. return true;
  198. }
  199. bool CMsgReader::readBell()
  200. {
  201. handler->bell();
  202. return true;
  203. }
  204. bool CMsgReader::readServerCutText()
  205. {
  206. if (!is->hasData(3 + 4))
  207. return false;
  208. is->setRestorePoint();
  209. is->skip(3);
  210. rdr::U32 len = is->readU32();
  211. if (len & 0x80000000) {
  212. rdr::S32 slen = len;
  213. slen = -slen;
  214. if (readExtendedClipboard(slen)) {
  215. is->clearRestorePoint();
  216. return true;
  217. } else {
  218. is->gotoRestorePoint();
  219. return false;
  220. }
  221. }
  222. if (!is->hasDataOrRestore(len))
  223. return false;
  224. is->clearRestorePoint();
  225. if (len > (size_t)maxCutText) {
  226. is->skip(len);
  227. vlog.error("cut text too long (%d bytes) - ignoring",len);
  228. return true;
  229. }
  230. CharArray ca(len);
  231. is->readBytes(ca.buf, len);
  232. CharArray filtered(convertLF(ca.buf, len));
  233. handler->serverCutText(filtered.buf);
  234. return true;
  235. }
  236. bool CMsgReader::readExtendedClipboard(rdr::S32 len)
  237. {
  238. rdr::U32 flags;
  239. rdr::U32 action;
  240. if (!is->hasData(len))
  241. return false;
  242. if (len < 4)
  243. throw Exception("Invalid extended clipboard message");
  244. if (len > maxCutText) {
  245. vlog.error("Extended clipboard message too long (%d bytes) - ignoring", len);
  246. is->skip(len);
  247. return true;
  248. }
  249. flags = is->readU32();
  250. action = flags & clipboardActionMask;
  251. if (action & clipboardCaps) {
  252. int i;
  253. size_t num;
  254. rdr::U32 lengths[16];
  255. num = 0;
  256. for (i = 0;i < 16;i++) {
  257. if (flags & (1 << i))
  258. num++;
  259. }
  260. if (len < (rdr::S32)(4 + 4*num))
  261. throw Exception("Invalid extended clipboard message");
  262. num = 0;
  263. for (i = 0;i < 16;i++) {
  264. if (flags & (1 << i))
  265. lengths[num++] = is->readU32();
  266. }
  267. handler->handleClipboardCaps(flags, lengths);
  268. } else if (action == clipboardProvide) {
  269. rdr::ZlibInStream zis;
  270. int i;
  271. size_t num;
  272. size_t lengths[16];
  273. rdr::U8* buffers[16];
  274. zis.setUnderlying(is, len - 4);
  275. num = 0;
  276. for (i = 0;i < 16;i++) {
  277. if (!(flags & 1 << i))
  278. continue;
  279. if (!zis.hasData(4))
  280. throw Exception("Extended clipboard decode error");
  281. lengths[num] = zis.readU32();
  282. if (lengths[num] > (size_t)maxCutText) {
  283. vlog.error("Extended clipboard data too long (%d bytes) - ignoring",
  284. (unsigned)lengths[num]);
  285. // Slowly (safely) drain away the data
  286. while (lengths[num] > 0) {
  287. size_t chunk;
  288. if (!zis.hasData(1))
  289. throw Exception("Extended clipboard decode error");
  290. chunk = zis.avail();
  291. if (chunk > lengths[num])
  292. chunk = lengths[num];
  293. zis.skip(chunk);
  294. lengths[num] -= chunk;
  295. }
  296. flags &= ~(1 << i);
  297. continue;
  298. }
  299. if (!zis.hasData(lengths[num]))
  300. throw Exception("Extended clipboard decode error");
  301. buffers[num] = new rdr::U8[lengths[num]];
  302. zis.readBytes(buffers[num], lengths[num]);
  303. num++;
  304. }
  305. zis.flushUnderlying();
  306. zis.setUnderlying(NULL, 0);
  307. handler->handleClipboardProvide(flags, lengths, buffers);
  308. num = 0;
  309. for (i = 0;i < 16;i++) {
  310. if (!(flags & 1 << i))
  311. continue;
  312. delete [] buffers[num++];
  313. }
  314. } else {
  315. switch (action) {
  316. case clipboardRequest:
  317. handler->handleClipboardRequest(flags);
  318. break;
  319. case clipboardPeek:
  320. handler->handleClipboardPeek(flags);
  321. break;
  322. case clipboardNotify:
  323. handler->handleClipboardNotify(flags);
  324. break;
  325. default:
  326. throw Exception("Invalid extended clipboard action");
  327. }
  328. }
  329. return true;
  330. }
  331. bool CMsgReader::readFence()
  332. {
  333. rdr::U32 flags;
  334. rdr::U8 len;
  335. char data[64];
  336. if (!is->hasData(3 + 4 + 1))
  337. return false;
  338. is->setRestorePoint();
  339. is->skip(3);
  340. flags = is->readU32();
  341. len = is->readU8();
  342. if (!is->hasDataOrRestore(len))
  343. return false;
  344. is->clearRestorePoint();
  345. if (len > sizeof(data)) {
  346. vlog.error("Ignoring fence with too large payload");
  347. is->skip(len);
  348. return true;
  349. }
  350. is->readBytes(data, len);
  351. handler->fence(flags, len, data);
  352. return true;
  353. }
  354. bool CMsgReader::readEndOfContinuousUpdates()
  355. {
  356. handler->endOfContinuousUpdates();
  357. return true;
  358. }
  359. bool CMsgReader::readFramebufferUpdate()
  360. {
  361. if (!is->hasData(1 + 2))
  362. return false;
  363. is->skip(1);
  364. nUpdateRectsLeft = is->readU16();
  365. handler->framebufferUpdateStart();
  366. return true;
  367. }
  368. bool CMsgReader::readRect(const Rect& r, int encoding)
  369. {
  370. if ((r.br.x > handler->server.width()) ||
  371. (r.br.y > handler->server.height())) {
  372. vlog.error("Rect too big: %dx%d at %d,%d exceeds %dx%d",
  373. r.width(), r.height(), r.tl.x, r.tl.y,
  374. handler->server.width(), handler->server.height());
  375. throw Exception("Rect too big");
  376. }
  377. if (r.is_empty())
  378. vlog.error("zero size rect");
  379. return handler->dataRect(r, encoding);
  380. }
  381. bool CMsgReader::readSetXCursor(int width, int height, const Point& hotspot)
  382. {
  383. if (width > maxCursorSize || height > maxCursorSize)
  384. throw Exception("Too big cursor");
  385. rdr::U8Array rgba(width*height*4);
  386. if (width * height > 0) {
  387. rdr::U8 pr, pg, pb;
  388. rdr::U8 sr, sg, sb;
  389. int data_len = ((width+7)/8) * height;
  390. int mask_len = ((width+7)/8) * height;
  391. rdr::U8Array data(data_len);
  392. rdr::U8Array mask(mask_len);
  393. int x, y;
  394. rdr::U8* out;
  395. if (!is->hasData(3 + 3 + data_len + mask_len))
  396. return false;
  397. pr = is->readU8();
  398. pg = is->readU8();
  399. pb = is->readU8();
  400. sr = is->readU8();
  401. sg = is->readU8();
  402. sb = is->readU8();
  403. is->readBytes(data.buf, data_len);
  404. is->readBytes(mask.buf, mask_len);
  405. int maskBytesPerRow = (width+7)/8;
  406. out = rgba.buf;
  407. for (y = 0;y < height;y++) {
  408. for (x = 0;x < width;x++) {
  409. int byte = y * maskBytesPerRow + x / 8;
  410. int bit = 7 - x % 8;
  411. if (data.buf[byte] & (1 << bit)) {
  412. out[0] = pr;
  413. out[1] = pg;
  414. out[2] = pb;
  415. } else {
  416. out[0] = sr;
  417. out[1] = sg;
  418. out[2] = sb;
  419. }
  420. if (mask.buf[byte] & (1 << bit))
  421. out[3] = 255;
  422. else
  423. out[3] = 0;
  424. out += 4;
  425. }
  426. }
  427. }
  428. handler->setCursor(width, height, hotspot, rgba.buf);
  429. return true;
  430. }
  431. bool CMsgReader::readSetCursor(int width, int height, const Point& hotspot)
  432. {
  433. if (width > maxCursorSize || height > maxCursorSize)
  434. throw Exception("Too big cursor");
  435. int data_len = width * height * (handler->server.pf().bpp/8);
  436. int mask_len = ((width+7)/8) * height;
  437. rdr::U8Array data(data_len);
  438. rdr::U8Array mask(mask_len);
  439. int x, y;
  440. rdr::U8Array rgba(width*height*4);
  441. rdr::U8* in;
  442. rdr::U8* out;
  443. if (!is->hasData(data_len + mask_len))
  444. return false;
  445. is->readBytes(data.buf, data_len);
  446. is->readBytes(mask.buf, mask_len);
  447. int maskBytesPerRow = (width+7)/8;
  448. in = data.buf;
  449. out = rgba.buf;
  450. for (y = 0;y < height;y++) {
  451. for (x = 0;x < width;x++) {
  452. int byte = y * maskBytesPerRow + x / 8;
  453. int bit = 7 - x % 8;
  454. handler->server.pf().rgbFromBuffer(out, in, 1);
  455. if (mask.buf[byte] & (1 << bit))
  456. out[3] = 255;
  457. else
  458. out[3] = 0;
  459. in += handler->server.pf().bpp/8;
  460. out += 4;
  461. }
  462. }
  463. handler->setCursor(width, height, hotspot, rgba.buf);
  464. return true;
  465. }
  466. bool CMsgReader::readSetCursorWithAlpha(int width, int height, const Point& hotspot)
  467. {
  468. if (width > maxCursorSize || height > maxCursorSize)
  469. throw Exception("Too big cursor");
  470. const PixelFormat rgbaPF(32, 32, false, true, 255, 255, 255, 16, 8, 0);
  471. ManagedPixelBuffer pb(rgbaPF, width, height);
  472. PixelFormat origPF;
  473. bool ret;
  474. rdr::U8* buf;
  475. int stride;
  476. // We can't use restore points as the decoder likely wants to as well, so
  477. // we need to keep track of the read encoding
  478. if (cursorEncoding == -1) {
  479. if (!is->hasData(4))
  480. return false;
  481. cursorEncoding = is->readS32();
  482. }
  483. origPF = handler->server.pf();
  484. handler->server.setPF(rgbaPF);
  485. ret = handler->readAndDecodeRect(pb.getRect(), cursorEncoding, &pb);
  486. handler->server.setPF(origPF);
  487. if (!ret)
  488. return false;
  489. cursorEncoding = -1;
  490. // On-wire data has pre-multiplied alpha, but we store it
  491. // non-pre-multiplied
  492. buf = pb.getBufferRW(pb.getRect(), &stride);
  493. assert(stride == width);
  494. for (int i = 0;i < pb.area();i++) {
  495. rdr::U8 alpha;
  496. alpha = buf[3];
  497. if (alpha == 0)
  498. alpha = 1; // Avoid division by zero
  499. buf[0] = (unsigned)buf[0] * 255/alpha;
  500. buf[1] = (unsigned)buf[1] * 255/alpha;
  501. buf[2] = (unsigned)buf[2] * 255/alpha;
  502. buf += 4;
  503. }
  504. pb.commitBufferRW(pb.getRect());
  505. handler->setCursor(width, height, hotspot,
  506. pb.getBuffer(pb.getRect(), &stride));
  507. return true;
  508. }
  509. bool CMsgReader::readSetVMwareCursor(int width, int height, const Point& hotspot)
  510. {
  511. if (width > maxCursorSize || height > maxCursorSize)
  512. throw Exception("Too big cursor");
  513. rdr::U8 type;
  514. if (!is->hasData(1 + 1))
  515. return false;
  516. is->setRestorePoint();
  517. type = is->readU8();
  518. is->skip(1);
  519. if (type == 0) {
  520. int len = width * height * (handler->server.pf().bpp/8);
  521. rdr::U8Array andMask(len);
  522. rdr::U8Array xorMask(len);
  523. rdr::U8Array data(width*height*4);
  524. rdr::U8* andIn;
  525. rdr::U8* xorIn;
  526. rdr::U8* out;
  527. int Bpp;
  528. if (!is->hasDataOrRestore(len + len))
  529. return false;
  530. is->clearRestorePoint();
  531. is->readBytes(andMask.buf, len);
  532. is->readBytes(xorMask.buf, len);
  533. andIn = andMask.buf;
  534. xorIn = xorMask.buf;
  535. out = data.buf;
  536. Bpp = handler->server.pf().bpp/8;
  537. for (int y = 0;y < height;y++) {
  538. for (int x = 0;x < width;x++) {
  539. Pixel andPixel, xorPixel;
  540. andPixel = handler->server.pf().pixelFromBuffer(andIn);
  541. xorPixel = handler->server.pf().pixelFromBuffer(xorIn);
  542. andIn += Bpp;
  543. xorIn += Bpp;
  544. if (andPixel == 0) {
  545. rdr::U8 r, g, b;
  546. // Opaque pixel
  547. handler->server.pf().rgbFromPixel(xorPixel, &r, &g, &b);
  548. *out++ = r;
  549. *out++ = g;
  550. *out++ = b;
  551. *out++ = 0xff;
  552. } else if (xorPixel == 0) {
  553. // Fully transparent pixel
  554. *out++ = 0;
  555. *out++ = 0;
  556. *out++ = 0;
  557. *out++ = 0;
  558. } else if (andPixel == xorPixel) {
  559. // Inverted pixel
  560. // We don't really support this, so just turn the pixel black
  561. // FIXME: Do an outline like WinVNC does?
  562. *out++ = 0;
  563. *out++ = 0;
  564. *out++ = 0;
  565. *out++ = 0xff;
  566. } else {
  567. // Partially transparent/inverted pixel
  568. // We _really_ can't handle this, just make it black
  569. *out++ = 0;
  570. *out++ = 0;
  571. *out++ = 0;
  572. *out++ = 0xff;
  573. }
  574. }
  575. }
  576. handler->setCursor(width, height, hotspot, data.buf);
  577. } else if (type == 1) {
  578. rdr::U8Array data(width*height*4);
  579. if (!is->hasDataOrRestore(width*height*4))
  580. return false;
  581. is->clearRestorePoint();
  582. // FIXME: Is alpha premultiplied?
  583. is->readBytes(data.buf, width*height*4);
  584. handler->setCursor(width, height, hotspot, data.buf);
  585. } else {
  586. throw Exception("Unknown cursor type");
  587. }
  588. return true;
  589. }
  590. bool CMsgReader::readSetDesktopName(int x, int y, int w, int h)
  591. {
  592. rdr::U32 len;
  593. if (!is->hasData(4))
  594. return false;
  595. is->setRestorePoint();
  596. len = is->readU32();
  597. if (!is->hasDataOrRestore(len))
  598. return false;
  599. is->clearRestorePoint();
  600. CharArray name(len + 1);
  601. is->readBytes(name.buf, len);
  602. name.buf[len] = '\0';
  603. if (x || y || w || h) {
  604. vlog.error("Ignoring DesktopName rect with non-zero position/size");
  605. } else {
  606. handler->setName(name.buf);
  607. }
  608. return true;
  609. }
  610. bool CMsgReader::readExtendedDesktopSize(int x, int y, int w, int h)
  611. {
  612. unsigned int screens, i;
  613. rdr::U32 id, flags;
  614. int sx, sy, sw, sh;
  615. ScreenSet layout;
  616. if (!is->hasData(1 + 3))
  617. return false;
  618. is->setRestorePoint();
  619. screens = is->readU8();
  620. is->skip(3);
  621. if (!is->hasDataOrRestore(16 * screens))
  622. return false;
  623. is->clearRestorePoint();
  624. for (i = 0;i < screens;i++) {
  625. id = is->readU32();
  626. sx = is->readU16();
  627. sy = is->readU16();
  628. sw = is->readU16();
  629. sh = is->readU16();
  630. flags = is->readU32();
  631. layout.add_screen(Screen(id, sx, sy, sw, sh, flags));
  632. }
  633. handler->setExtendedDesktopSize(x, y, w, h, layout);
  634. return true;
  635. }
  636. bool CMsgReader::readLEDState()
  637. {
  638. rdr::U8 state;
  639. if (!is->hasData(1))
  640. return false;
  641. state = is->readU8();
  642. handler->setLEDState(state);
  643. return true;
  644. }
  645. bool CMsgReader::readVMwareLEDState()
  646. {
  647. rdr::U32 state;
  648. if (!is->hasData(4))
  649. return false;
  650. state = is->readU32();
  651. // As luck has it, this extension uses the same bit definitions,
  652. // so no conversion required
  653. handler->setLEDState(state);
  654. return true;
  655. }