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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617
  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. #include <assert.h>
  20. #include <stdio.h>
  21. #include <rdr/InStream.h>
  22. #include <rdr/ZlibInStream.h>
  23. #include <rfb/msgTypes.h>
  24. #include <rfb/clipboardTypes.h>
  25. #include <rfb/Exception.h>
  26. #include <rfb/LogWriter.h>
  27. #include <rfb/util.h>
  28. #include <rfb/CMsgHandler.h>
  29. #include <rfb/CMsgReader.h>
  30. static rfb::LogWriter vlog("CMsgReader");
  31. static rfb::IntParameter maxCutText("MaxCutText", "Maximum permitted length of an incoming clipboard update", 256*1024);
  32. using namespace rfb;
  33. CMsgReader::CMsgReader(CMsgHandler* handler_, rdr::InStream* is_)
  34. : imageBufIdealSize(0), handler(handler_), is(is_),
  35. nUpdateRectsLeft(0)
  36. {
  37. }
  38. CMsgReader::~CMsgReader()
  39. {
  40. }
  41. void CMsgReader::readServerInit()
  42. {
  43. int width = is->readU16();
  44. int height = is->readU16();
  45. PixelFormat pf;
  46. pf.read(is);
  47. rdr::U32 len = is->readU32();
  48. CharArray name(len + 1);
  49. is->readBytes(name.buf, len);
  50. name.buf[len] = '\0';
  51. handler->serverInit(width, height, pf, name.buf);
  52. }
  53. void CMsgReader::readMsg()
  54. {
  55. if (nUpdateRectsLeft == 0) {
  56. int type = is->readU8();
  57. switch (type) {
  58. case msgTypeSetColourMapEntries:
  59. readSetColourMapEntries();
  60. break;
  61. case msgTypeBell:
  62. readBell();
  63. break;
  64. case msgTypeServerCutText:
  65. readServerCutText();
  66. break;
  67. case msgTypeFramebufferUpdate:
  68. readFramebufferUpdate();
  69. break;
  70. case msgTypeServerFence:
  71. readFence();
  72. break;
  73. case msgTypeEndOfContinuousUpdates:
  74. readEndOfContinuousUpdates();
  75. break;
  76. default:
  77. vlog.error("unknown message type %d", type);
  78. throw Exception("unknown message type");
  79. }
  80. } else {
  81. int x = is->readU16();
  82. int y = is->readU16();
  83. int w = is->readU16();
  84. int h = is->readU16();
  85. int encoding = is->readS32();
  86. switch (encoding) {
  87. case pseudoEncodingLastRect:
  88. nUpdateRectsLeft = 1; // this rectangle is the last one
  89. break;
  90. case pseudoEncodingXCursor:
  91. readSetXCursor(w, h, Point(x,y));
  92. break;
  93. case pseudoEncodingCursor:
  94. readSetCursor(w, h, Point(x,y));
  95. break;
  96. case pseudoEncodingCursorWithAlpha:
  97. readSetCursorWithAlpha(w, h, Point(x,y));
  98. break;
  99. case pseudoEncodingVMwareCursor:
  100. readSetVMwareCursor(w, h, Point(x,y));
  101. break;
  102. case pseudoEncodingDesktopName:
  103. readSetDesktopName(x, y, w, h);
  104. break;
  105. case pseudoEncodingDesktopSize:
  106. handler->setDesktopSize(w, h);
  107. break;
  108. case pseudoEncodingExtendedDesktopSize:
  109. readExtendedDesktopSize(x, y, w, h);
  110. break;
  111. case pseudoEncodingLEDState:
  112. readLEDState();
  113. break;
  114. case pseudoEncodingVMwareLEDState:
  115. readVMwareLEDState();
  116. break;
  117. case pseudoEncodingQEMUKeyEvent:
  118. handler->supportsQEMUKeyEvent();
  119. break;
  120. default:
  121. readRect(Rect(x, y, x+w, y+h), encoding);
  122. break;
  123. };
  124. nUpdateRectsLeft--;
  125. if (nUpdateRectsLeft == 0)
  126. handler->framebufferUpdateEnd();
  127. }
  128. }
  129. void CMsgReader::readSetColourMapEntries()
  130. {
  131. is->skip(1);
  132. int firstColour = is->readU16();
  133. int nColours = is->readU16();
  134. rdr::U16Array rgbs(nColours * 3);
  135. for (int i = 0; i < nColours * 3; i++)
  136. rgbs.buf[i] = is->readU16();
  137. handler->setColourMapEntries(firstColour, nColours, rgbs.buf);
  138. }
  139. void CMsgReader::readBell()
  140. {
  141. handler->bell();
  142. }
  143. void CMsgReader::readServerCutText()
  144. {
  145. is->skip(3);
  146. rdr::U32 len = is->readU32();
  147. if (len & 0x80000000) {
  148. rdr::S32 slen = len;
  149. slen = -slen;
  150. readExtendedClipboard(slen);
  151. return;
  152. }
  153. if (len > (size_t)maxCutText) {
  154. is->skip(len);
  155. vlog.error("cut text too long (%d bytes) - ignoring",len);
  156. return;
  157. }
  158. CharArray ca(len);
  159. is->readBytes(ca.buf, len);
  160. CharArray filtered(convertLF(ca.buf, len));
  161. handler->serverCutText(filtered.buf);
  162. }
  163. void CMsgReader::readExtendedClipboard(rdr::S32 len)
  164. {
  165. rdr::U32 flags;
  166. rdr::U32 action;
  167. if (len < 4)
  168. throw Exception("Invalid extended clipboard message");
  169. if (len > maxCutText) {
  170. vlog.error("Extended clipboard message too long (%d bytes) - ignoring", len);
  171. is->skip(len);
  172. return;
  173. }
  174. flags = is->readU32();
  175. action = flags & clipboardActionMask;
  176. if (action & clipboardCaps) {
  177. int i;
  178. size_t num;
  179. rdr::U32 lengths[16];
  180. num = 0;
  181. for (i = 0;i < 16;i++) {
  182. if (flags & (1 << i))
  183. num++;
  184. }
  185. if (len < (rdr::S32)(4 + 4*num))
  186. throw Exception("Invalid extended clipboard message");
  187. num = 0;
  188. for (i = 0;i < 16;i++) {
  189. if (flags & (1 << i))
  190. lengths[num++] = is->readU32();
  191. }
  192. handler->handleClipboardCaps(flags, lengths);
  193. } else if (action == clipboardProvide) {
  194. rdr::ZlibInStream zis;
  195. int i;
  196. size_t num;
  197. size_t lengths[16];
  198. rdr::U8* buffers[16];
  199. zis.setUnderlying(is, len - 4);
  200. num = 0;
  201. for (i = 0;i < 16;i++) {
  202. if (!(flags & 1 << i))
  203. continue;
  204. lengths[num] = zis.readU32();
  205. if (lengths[num] > (size_t)maxCutText) {
  206. vlog.error("Extended clipboard data too long (%d bytes) - ignoring",
  207. (unsigned)lengths[num]);
  208. zis.skip(lengths[num]);
  209. flags &= ~(1 << i);
  210. continue;
  211. }
  212. buffers[num] = new rdr::U8[lengths[num]];
  213. zis.readBytes(buffers[num], lengths[num]);
  214. num++;
  215. }
  216. zis.flushUnderlying();
  217. zis.setUnderlying(NULL, 0);
  218. handler->handleClipboardProvide(flags, lengths, buffers);
  219. num = 0;
  220. for (i = 0;i < 16;i++) {
  221. if (!(flags & 1 << i))
  222. continue;
  223. delete [] buffers[num++];
  224. }
  225. } else {
  226. switch (action) {
  227. case clipboardRequest:
  228. handler->handleClipboardRequest(flags);
  229. break;
  230. case clipboardPeek:
  231. handler->handleClipboardPeek(flags);
  232. break;
  233. case clipboardNotify:
  234. handler->handleClipboardNotify(flags);
  235. break;
  236. default:
  237. throw Exception("Invalid extended clipboard action");
  238. }
  239. }
  240. }
  241. void CMsgReader::readFence()
  242. {
  243. rdr::U32 flags;
  244. rdr::U8 len;
  245. char data[64];
  246. is->skip(3);
  247. flags = is->readU32();
  248. len = is->readU8();
  249. if (len > sizeof(data)) {
  250. vlog.error("Ignoring fence with too large payload");
  251. is->skip(len);
  252. return;
  253. }
  254. is->readBytes(data, len);
  255. handler->fence(flags, len, data);
  256. }
  257. void CMsgReader::readEndOfContinuousUpdates()
  258. {
  259. handler->endOfContinuousUpdates();
  260. }
  261. void CMsgReader::readFramebufferUpdate()
  262. {
  263. is->skip(1);
  264. nUpdateRectsLeft = is->readU16();
  265. handler->framebufferUpdateStart();
  266. }
  267. void CMsgReader::readRect(const Rect& r, int encoding)
  268. {
  269. if ((r.br.x > handler->server.width()) ||
  270. (r.br.y > handler->server.height())) {
  271. vlog.error("Rect too big: %dx%d at %d,%d exceeds %dx%d",
  272. r.width(), r.height(), r.tl.x, r.tl.y,
  273. handler->server.width(), handler->server.height());
  274. throw Exception("Rect too big");
  275. }
  276. if (r.is_empty())
  277. vlog.error("zero size rect");
  278. handler->dataRect(r, encoding);
  279. }
  280. void CMsgReader::readSetXCursor(int width, int height, const Point& hotspot)
  281. {
  282. if (width > maxCursorSize || height > maxCursorSize)
  283. throw Exception("Too big cursor");
  284. rdr::U8Array rgba(width*height*4);
  285. if (width * height > 0) {
  286. rdr::U8 pr, pg, pb;
  287. rdr::U8 sr, sg, sb;
  288. int data_len = ((width+7)/8) * height;
  289. int mask_len = ((width+7)/8) * height;
  290. rdr::U8Array data(data_len);
  291. rdr::U8Array mask(mask_len);
  292. int x, y;
  293. rdr::U8* out;
  294. pr = is->readU8();
  295. pg = is->readU8();
  296. pb = is->readU8();
  297. sr = is->readU8();
  298. sg = is->readU8();
  299. sb = is->readU8();
  300. is->readBytes(data.buf, data_len);
  301. is->readBytes(mask.buf, mask_len);
  302. int maskBytesPerRow = (width+7)/8;
  303. out = rgba.buf;
  304. for (y = 0;y < height;y++) {
  305. for (x = 0;x < width;x++) {
  306. int byte = y * maskBytesPerRow + x / 8;
  307. int bit = 7 - x % 8;
  308. if (data.buf[byte] & (1 << bit)) {
  309. out[0] = pr;
  310. out[1] = pg;
  311. out[2] = pb;
  312. } else {
  313. out[0] = sr;
  314. out[1] = sg;
  315. out[2] = sb;
  316. }
  317. if (mask.buf[byte] & (1 << bit))
  318. out[3] = 255;
  319. else
  320. out[3] = 0;
  321. out += 4;
  322. }
  323. }
  324. }
  325. handler->setCursor(width, height, hotspot, rgba.buf);
  326. }
  327. void CMsgReader::readSetCursor(int width, int height, const Point& hotspot)
  328. {
  329. if (width > maxCursorSize || height > maxCursorSize)
  330. throw Exception("Too big cursor");
  331. int data_len = width * height * (handler->server.pf().bpp/8);
  332. int mask_len = ((width+7)/8) * height;
  333. rdr::U8Array data(data_len);
  334. rdr::U8Array mask(mask_len);
  335. int x, y;
  336. rdr::U8Array rgba(width*height*4);
  337. rdr::U8* in;
  338. rdr::U8* out;
  339. is->readBytes(data.buf, data_len);
  340. is->readBytes(mask.buf, mask_len);
  341. int maskBytesPerRow = (width+7)/8;
  342. in = data.buf;
  343. out = rgba.buf;
  344. for (y = 0;y < height;y++) {
  345. for (x = 0;x < width;x++) {
  346. int byte = y * maskBytesPerRow + x / 8;
  347. int bit = 7 - x % 8;
  348. handler->server.pf().rgbFromBuffer(out, in, 1);
  349. if (mask.buf[byte] & (1 << bit))
  350. out[3] = 255;
  351. else
  352. out[3] = 0;
  353. in += handler->server.pf().bpp/8;
  354. out += 4;
  355. }
  356. }
  357. handler->setCursor(width, height, hotspot, rgba.buf);
  358. }
  359. void CMsgReader::readSetCursorWithAlpha(int width, int height, const Point& hotspot)
  360. {
  361. if (width > maxCursorSize || height > maxCursorSize)
  362. throw Exception("Too big cursor");
  363. int encoding;
  364. const PixelFormat rgbaPF(32, 32, false, true, 255, 255, 255, 16, 8, 0);
  365. ManagedPixelBuffer pb(rgbaPF, width, height);
  366. PixelFormat origPF;
  367. rdr::U8* buf;
  368. int stride;
  369. encoding = is->readS32();
  370. origPF = handler->server.pf();
  371. handler->server.setPF(rgbaPF);
  372. handler->readAndDecodeRect(pb.getRect(), encoding, &pb);
  373. handler->server.setPF(origPF);
  374. // On-wire data has pre-multiplied alpha, but we store it
  375. // non-pre-multiplied
  376. buf = pb.getBufferRW(pb.getRect(), &stride);
  377. assert(stride == width);
  378. for (int i = 0;i < pb.area();i++) {
  379. rdr::U8 alpha;
  380. alpha = buf[3];
  381. if (alpha == 0)
  382. alpha = 1; // Avoid division by zero
  383. buf[0] = (unsigned)buf[0] * 255/alpha;
  384. buf[1] = (unsigned)buf[1] * 255/alpha;
  385. buf[2] = (unsigned)buf[2] * 255/alpha;
  386. buf += 4;
  387. }
  388. pb.commitBufferRW(pb.getRect());
  389. handler->setCursor(width, height, hotspot,
  390. pb.getBuffer(pb.getRect(), &stride));
  391. }
  392. void CMsgReader::readSetVMwareCursor(int width, int height, const Point& hotspot)
  393. {
  394. if (width > maxCursorSize || height > maxCursorSize)
  395. throw Exception("Too big cursor");
  396. rdr::U8 type;
  397. type = is->readU8();
  398. is->skip(1);
  399. if (type == 0) {
  400. int len = width * height * (handler->server.pf().bpp/8);
  401. rdr::U8Array andMask(len);
  402. rdr::U8Array xorMask(len);
  403. rdr::U8Array data(width*height*4);
  404. rdr::U8* andIn;
  405. rdr::U8* xorIn;
  406. rdr::U8* out;
  407. int Bpp;
  408. is->readBytes(andMask.buf, len);
  409. is->readBytes(xorMask.buf, len);
  410. andIn = andMask.buf;
  411. xorIn = xorMask.buf;
  412. out = data.buf;
  413. Bpp = handler->server.pf().bpp/8;
  414. for (int y = 0;y < height;y++) {
  415. for (int x = 0;x < width;x++) {
  416. Pixel andPixel, xorPixel;
  417. andPixel = handler->server.pf().pixelFromBuffer(andIn);
  418. xorPixel = handler->server.pf().pixelFromBuffer(xorIn);
  419. andIn += Bpp;
  420. xorIn += Bpp;
  421. if (andPixel == 0) {
  422. rdr::U8 r, g, b;
  423. // Opaque pixel
  424. handler->server.pf().rgbFromPixel(xorPixel, &r, &g, &b);
  425. *out++ = r;
  426. *out++ = g;
  427. *out++ = b;
  428. *out++ = 0xff;
  429. } else if (xorPixel == 0) {
  430. // Fully transparent pixel
  431. *out++ = 0;
  432. *out++ = 0;
  433. *out++ = 0;
  434. *out++ = 0;
  435. } else if (andPixel == xorPixel) {
  436. // Inverted pixel
  437. // We don't really support this, so just turn the pixel black
  438. // FIXME: Do an outline like WinVNC does?
  439. *out++ = 0;
  440. *out++ = 0;
  441. *out++ = 0;
  442. *out++ = 0xff;
  443. } else {
  444. // Partially transparent/inverted pixel
  445. // We _really_ can't handle this, just make it black
  446. *out++ = 0;
  447. *out++ = 0;
  448. *out++ = 0;
  449. *out++ = 0xff;
  450. }
  451. }
  452. }
  453. handler->setCursor(width, height, hotspot, data.buf);
  454. } else if (type == 1) {
  455. rdr::U8Array data(width*height*4);
  456. // FIXME: Is alpha premultiplied?
  457. is->readBytes(data.buf, width*height*4);
  458. handler->setCursor(width, height, hotspot, data.buf);
  459. } else {
  460. throw Exception("Unknown cursor type");
  461. }
  462. }
  463. void CMsgReader::readSetDesktopName(int x, int y, int w, int h)
  464. {
  465. rdr::U32 len = is->readU32();
  466. CharArray name(len + 1);
  467. is->readBytes(name.buf, len);
  468. name.buf[len] = '\0';
  469. if (x || y || w || h) {
  470. vlog.error("Ignoring DesktopName rect with non-zero position/size");
  471. } else {
  472. handler->setName(name.buf);
  473. }
  474. }
  475. void CMsgReader::readExtendedDesktopSize(int x, int y, int w, int h)
  476. {
  477. unsigned int screens, i;
  478. rdr::U32 id, flags;
  479. int sx, sy, sw, sh;
  480. ScreenSet layout;
  481. screens = is->readU8();
  482. is->skip(3);
  483. for (i = 0;i < screens;i++) {
  484. id = is->readU32();
  485. sx = is->readU16();
  486. sy = is->readU16();
  487. sw = is->readU16();
  488. sh = is->readU16();
  489. flags = is->readU32();
  490. layout.add_screen(Screen(id, sx, sy, sw, sh, flags));
  491. }
  492. handler->setExtendedDesktopSize(x, y, w, h, layout);
  493. }
  494. void CMsgReader::readLEDState()
  495. {
  496. rdr::U8 state;
  497. state = is->readU8();
  498. handler->setLEDState(state);
  499. }
  500. void CMsgReader::readVMwareLEDState()
  501. {
  502. rdr::U32 state;
  503. state = is->readU32();
  504. // As luck has it, this extension uses the same bit definitions,
  505. // so no conversion required
  506. handler->setLEDState(state);
  507. }