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.

TightDecoder.cxx 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507
  1. /* Copyright (C) 2000-2003 Constantin Kaplinsky. All Rights Reserved.
  2. * Copyright 2004-2005 Cendio AB.
  3. * Copyright 2009-2015 Pierre Ossman for Cendio AB
  4. * Copyright (C) 2011 D. R. Commander. All Rights Reserved.
  5. *
  6. * This is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation; either version 2 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This software is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this software; if not, write to the Free Software
  18. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
  19. * USA.
  20. */
  21. #include <assert.h>
  22. #include <rdr/InStream.h>
  23. #include <rdr/MemInStream.h>
  24. #include <rdr/OutStream.h>
  25. #include <rfb/ServerParams.h>
  26. #include <rfb/Exception.h>
  27. #include <rfb/PixelBuffer.h>
  28. #include <rfb/TightConstants.h>
  29. #include <rfb/TightDecoder.h>
  30. using namespace rfb;
  31. static const int TIGHT_MAX_WIDTH = 2048;
  32. static const int TIGHT_MIN_TO_COMPRESS = 12;
  33. #define BPP 8
  34. #include <rfb/tightDecode.h>
  35. #undef BPP
  36. #define BPP 16
  37. #include <rfb/tightDecode.h>
  38. #undef BPP
  39. #define BPP 32
  40. #include <rfb/tightDecode.h>
  41. #undef BPP
  42. TightDecoder::TightDecoder() : Decoder(DecoderPartiallyOrdered)
  43. {
  44. }
  45. TightDecoder::~TightDecoder()
  46. {
  47. }
  48. bool TightDecoder::readRect(const Rect& r, rdr::InStream* is,
  49. const ServerParams& server, rdr::OutStream* os)
  50. {
  51. rdr::U8 comp_ctl;
  52. if (!is->hasData(1))
  53. return false;
  54. is->setRestorePoint();
  55. comp_ctl = is->readU8();
  56. os->writeU8(comp_ctl);
  57. comp_ctl >>= 4;
  58. // "Fill" compression type.
  59. if (comp_ctl == tightFill) {
  60. if (server.pf().is888()) {
  61. if (!is->hasDataOrRestore(3))
  62. return false;
  63. os->copyBytes(is, 3);
  64. } else {
  65. if (!is->hasDataOrRestore(server.pf().bpp/8))
  66. return false;
  67. os->copyBytes(is, server.pf().bpp/8);
  68. }
  69. is->clearRestorePoint();
  70. return true;
  71. }
  72. // "JPEG" compression type.
  73. if (comp_ctl == tightJpeg) {
  74. rdr::U32 len;
  75. // FIXME: Might be less than 3 bytes
  76. if (!is->hasDataOrRestore(3))
  77. return false;
  78. len = readCompact(is);
  79. os->writeOpaque32(len);
  80. if (!is->hasDataOrRestore(len))
  81. return false;
  82. os->copyBytes(is, len);
  83. is->clearRestorePoint();
  84. return true;
  85. }
  86. // Quit on unsupported compression type.
  87. if (comp_ctl > tightMaxSubencoding)
  88. throw Exception("TightDecoder: bad subencoding value received");
  89. // "Basic" compression type.
  90. int palSize = 0;
  91. if (r.width() > TIGHT_MAX_WIDTH)
  92. throw Exception("TightDecoder: too large rectangle (%d pixels)", r.width());
  93. // Possible palette
  94. if ((comp_ctl & tightExplicitFilter) != 0) {
  95. rdr::U8 filterId;
  96. if (!is->hasDataOrRestore(1))
  97. return false;
  98. filterId = is->readU8();
  99. os->writeU8(filterId);
  100. switch (filterId) {
  101. case tightFilterPalette:
  102. if (!is->hasDataOrRestore(1))
  103. return false;
  104. palSize = is->readU8() + 1;
  105. os->writeU8(palSize - 1);
  106. if (server.pf().is888()) {
  107. if (!is->hasDataOrRestore(palSize * 3))
  108. return false;
  109. os->copyBytes(is, palSize * 3);
  110. } else {
  111. if (!is->hasDataOrRestore(palSize * server.pf().bpp/8))
  112. return false;
  113. os->copyBytes(is, palSize * server.pf().bpp/8);
  114. }
  115. break;
  116. case tightFilterGradient:
  117. if (server.pf().bpp == 8)
  118. throw Exception("TightDecoder: invalid BPP for gradient filter");
  119. break;
  120. case tightFilterCopy:
  121. break;
  122. default:
  123. throw Exception("TightDecoder: unknown filter code received");
  124. }
  125. }
  126. size_t rowSize, dataSize;
  127. if (palSize != 0) {
  128. if (palSize <= 2)
  129. rowSize = (r.width() + 7) / 8;
  130. else
  131. rowSize = r.width();
  132. } else if (server.pf().is888()) {
  133. rowSize = r.width() * 3;
  134. } else {
  135. rowSize = r.width() * server.pf().bpp/8;
  136. }
  137. dataSize = r.height() * rowSize;
  138. if (dataSize < TIGHT_MIN_TO_COMPRESS) {
  139. if (!is->hasDataOrRestore(dataSize))
  140. return false;
  141. os->copyBytes(is, dataSize);
  142. } else {
  143. rdr::U32 len;
  144. // FIXME: Might be less than 3 bytes
  145. if (!is->hasDataOrRestore(3))
  146. return false;
  147. len = readCompact(is);
  148. os->writeOpaque32(len);
  149. if (!is->hasDataOrRestore(len))
  150. return false;
  151. os->copyBytes(is, len);
  152. }
  153. is->clearRestorePoint();
  154. return true;
  155. }
  156. bool TightDecoder::doRectsConflict(const Rect& rectA,
  157. const void* bufferA,
  158. size_t buflenA,
  159. const Rect& rectB,
  160. const void* bufferB,
  161. size_t buflenB,
  162. const ServerParams& server)
  163. {
  164. rdr::U8 comp_ctl_a, comp_ctl_b;
  165. assert(buflenA >= 1);
  166. assert(buflenB >= 1);
  167. comp_ctl_a = *(const rdr::U8*)bufferA;
  168. comp_ctl_b = *(const rdr::U8*)bufferB;
  169. // Resets or use of zlib pose the same problem, so merge them
  170. if ((comp_ctl_a & 0x80) == 0x00)
  171. comp_ctl_a |= 1 << ((comp_ctl_a >> 4) & 0x03);
  172. if ((comp_ctl_b & 0x80) == 0x00)
  173. comp_ctl_b |= 1 << ((comp_ctl_b >> 4) & 0x03);
  174. if (((comp_ctl_a & 0x0f) & (comp_ctl_b & 0x0f)) != 0)
  175. return true;
  176. return false;
  177. }
  178. void TightDecoder::decodeRect(const Rect& r, const void* buffer,
  179. size_t buflen, const ServerParams& server,
  180. ModifiablePixelBuffer* pb)
  181. {
  182. const rdr::U8* bufptr;
  183. const PixelFormat& pf = server.pf();
  184. rdr::U8 comp_ctl;
  185. bufptr = (const rdr::U8*)buffer;
  186. assert(buflen >= 1);
  187. comp_ctl = *bufptr;
  188. bufptr += 1;
  189. buflen -= 1;
  190. // Reset zlib streams if we are told by the server to do so.
  191. for (int i = 0; i < 4; i++) {
  192. if (comp_ctl & 1) {
  193. zis[i].reset();
  194. }
  195. comp_ctl >>= 1;
  196. }
  197. // "Fill" compression type.
  198. if (comp_ctl == tightFill) {
  199. if (pf.is888()) {
  200. rdr::U8 pix[4];
  201. assert(buflen >= 3);
  202. pf.bufferFromRGB(pix, bufptr, 1);
  203. pb->fillRect(pf, r, pix);
  204. } else {
  205. assert(buflen >= (size_t)pf.bpp/8);
  206. pb->fillRect(pf, r, bufptr);
  207. }
  208. return;
  209. }
  210. // "JPEG" compression type.
  211. if (comp_ctl == tightJpeg) {
  212. rdr::U32 len;
  213. int stride;
  214. rdr::U8 *buf;
  215. JpegDecompressor jd;
  216. assert(buflen >= 4);
  217. memcpy(&len, bufptr, 4);
  218. bufptr += 4;
  219. buflen -= 4;
  220. // We always use direct decoding with JPEG images
  221. buf = pb->getBufferRW(r, &stride);
  222. jd.decompress(bufptr, len, buf, stride, r, pb->getPF());
  223. pb->commitBufferRW(r);
  224. return;
  225. }
  226. // Quit on unsupported compression type.
  227. assert(comp_ctl <= tightMaxSubencoding);
  228. // "Basic" compression type.
  229. int palSize = 0;
  230. rdr::U8 palette[256 * 4];
  231. bool useGradient = false;
  232. if ((comp_ctl & tightExplicitFilter) != 0) {
  233. rdr::U8 filterId;
  234. assert(buflen >= 1);
  235. filterId = *bufptr;
  236. bufptr += 1;
  237. buflen -= 1;
  238. switch (filterId) {
  239. case tightFilterPalette:
  240. assert(buflen >= 1);
  241. palSize = *bufptr + 1;
  242. bufptr += 1;
  243. buflen -= 1;
  244. if (pf.is888()) {
  245. size_t len = palSize * 3;
  246. rdr::U8Array tightPalette(len);
  247. assert(buflen >= len);
  248. memcpy(tightPalette.buf, bufptr, len);
  249. bufptr += len;
  250. buflen -= len;
  251. pf.bufferFromRGB(palette, tightPalette.buf, palSize);
  252. } else {
  253. size_t len;
  254. len = palSize * pf.bpp/8;
  255. assert(buflen >= len);
  256. memcpy(palette, bufptr, len);
  257. bufptr += len;
  258. buflen -= len;
  259. }
  260. break;
  261. case tightFilterGradient:
  262. useGradient = true;
  263. break;
  264. case tightFilterCopy:
  265. break;
  266. default:
  267. assert(false);
  268. }
  269. }
  270. // Determine if the data should be decompressed or just copied.
  271. size_t rowSize, dataSize;
  272. rdr::U8* netbuf;
  273. netbuf = NULL;
  274. if (palSize != 0) {
  275. if (palSize <= 2)
  276. rowSize = (r.width() + 7) / 8;
  277. else
  278. rowSize = r.width();
  279. } else if (pf.is888()) {
  280. rowSize = r.width() * 3;
  281. } else {
  282. rowSize = r.width() * pf.bpp/8;
  283. }
  284. dataSize = r.height() * rowSize;
  285. if (dataSize < TIGHT_MIN_TO_COMPRESS)
  286. assert(buflen >= dataSize);
  287. else {
  288. rdr::U32 len;
  289. int streamId;
  290. rdr::MemInStream* ms;
  291. assert(buflen >= 4);
  292. memcpy(&len, bufptr, 4);
  293. bufptr += 4;
  294. buflen -= 4;
  295. assert(buflen >= len);
  296. streamId = comp_ctl & 0x03;
  297. ms = new rdr::MemInStream(bufptr, len);
  298. zis[streamId].setUnderlying(ms, len);
  299. // Allocate buffer and decompress the data
  300. netbuf = new rdr::U8[dataSize];
  301. if (!zis[streamId].hasData(dataSize))
  302. throw Exception("Tight decode error");
  303. zis[streamId].readBytes(netbuf, dataSize);
  304. zis[streamId].flushUnderlying();
  305. zis[streamId].setUnderlying(NULL, 0);
  306. delete ms;
  307. bufptr = netbuf;
  308. buflen = dataSize;
  309. }
  310. // Time to decode the actual data
  311. bool directDecode;
  312. rdr::U8* outbuf;
  313. int stride;
  314. if (pb->getPF().equal(pf)) {
  315. // Decode directly into the framebuffer (fast path)
  316. directDecode = true;
  317. } else {
  318. // Decode into an intermediate buffer and use pixel translation
  319. directDecode = false;
  320. }
  321. if (directDecode)
  322. outbuf = pb->getBufferRW(r, &stride);
  323. else {
  324. outbuf = new rdr::U8[r.area() * (pf.bpp/8)];
  325. stride = r.width();
  326. }
  327. if (palSize == 0) {
  328. // Truecolor data
  329. if (useGradient) {
  330. if (pf.is888())
  331. FilterGradient24(bufptr, pf, (rdr::U32*)outbuf, stride, r);
  332. else {
  333. switch (pf.bpp) {
  334. case 8:
  335. assert(false);
  336. break;
  337. case 16:
  338. FilterGradient(bufptr, pf, (rdr::U16*)outbuf, stride, r);
  339. break;
  340. case 32:
  341. FilterGradient(bufptr, pf, (rdr::U32*)outbuf, stride, r);
  342. break;
  343. }
  344. }
  345. } else {
  346. // Copy
  347. rdr::U8* ptr = outbuf;
  348. const rdr::U8* srcPtr = bufptr;
  349. int w = r.width();
  350. int h = r.height();
  351. if (pf.is888()) {
  352. while (h > 0) {
  353. pf.bufferFromRGB(ptr, srcPtr, w);
  354. ptr += stride * pf.bpp/8;
  355. srcPtr += w * 3;
  356. h--;
  357. }
  358. } else {
  359. while (h > 0) {
  360. memcpy(ptr, srcPtr, w * pf.bpp/8);
  361. ptr += stride * pf.bpp/8;
  362. srcPtr += w * pf.bpp/8;
  363. h--;
  364. }
  365. }
  366. }
  367. } else {
  368. // Indexed color
  369. switch (pf.bpp) {
  370. case 8:
  371. FilterPalette((const rdr::U8*)palette, palSize,
  372. bufptr, (rdr::U8*)outbuf, stride, r);
  373. break;
  374. case 16:
  375. FilterPalette((const rdr::U16*)palette, palSize,
  376. bufptr, (rdr::U16*)outbuf, stride, r);
  377. break;
  378. case 32:
  379. FilterPalette((const rdr::U32*)palette, palSize,
  380. bufptr, (rdr::U32*)outbuf, stride, r);
  381. break;
  382. }
  383. }
  384. if (directDecode)
  385. pb->commitBufferRW(r);
  386. else {
  387. pb->imageRect(pf, r, outbuf);
  388. delete [] outbuf;
  389. }
  390. delete [] netbuf;
  391. }
  392. rdr::U32 TightDecoder::readCompact(rdr::InStream* is)
  393. {
  394. rdr::U8 b;
  395. rdr::U32 result;
  396. b = is->readU8();
  397. result = (int)b & 0x7F;
  398. if (b & 0x80) {
  399. b = is->readU8();
  400. result |= ((int)b & 0x7F) << 7;
  401. if (b & 0x80) {
  402. b = is->readU8();
  403. result |= ((int)b & 0xFF) << 14;
  404. }
  405. }
  406. return result;
  407. }