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 19KB

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