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

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