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.

util.cxx 14KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673
  1. /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
  2. * Copyright 2011-2022 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 <ctype.h>
  24. #include <stdarg.h>
  25. #include <stdio.h>
  26. #include <sys/time.h>
  27. #include <rfb/util.h>
  28. namespace rfb {
  29. void CharArray::format(const char *fmt, ...) {
  30. va_list ap;
  31. int len;
  32. va_start(ap, fmt);
  33. len = vsnprintf(NULL, 0, fmt, ap);
  34. va_end(ap);
  35. delete [] buf;
  36. if (len < 0) {
  37. buf = new char[1];
  38. buf[0] = '\0';
  39. return;
  40. }
  41. buf = new char[len+1];
  42. va_start(ap, fmt);
  43. vsnprintf(buf, len+1, fmt, ap);
  44. va_end(ap);
  45. }
  46. char* strDup(const char* s) {
  47. if (!s) return 0;
  48. int l = strlen(s);
  49. char* r = new char[l+1];
  50. memcpy(r, s, l+1);
  51. return r;
  52. };
  53. void strFree(char* s) {
  54. delete [] s;
  55. }
  56. bool strSplit(const char* src, const char limiter, char** out1, char** out2, bool fromEnd) {
  57. CharArray out1old, out2old;
  58. if (out1) out1old.buf = *out1;
  59. if (out2) out2old.buf = *out2;
  60. int len = strlen(src);
  61. int i=0, increment=1, limit=len;
  62. if (fromEnd) {
  63. i=len-1; increment = -1; limit = -1;
  64. }
  65. while (i!=limit) {
  66. if (src[i] == limiter) {
  67. if (out1) {
  68. *out1 = new char[i+1];
  69. if (i) memcpy(*out1, src, i);
  70. (*out1)[i] = 0;
  71. }
  72. if (out2) {
  73. *out2 = new char[len-i];
  74. if (len-i-1) memcpy(*out2, &src[i+1], len-i-1);
  75. (*out2)[len-i-1] = 0;
  76. }
  77. return true;
  78. }
  79. i+=increment;
  80. }
  81. if (out1) *out1 = strDup(src);
  82. if (out2) *out2 = 0;
  83. return false;
  84. }
  85. bool strContains(const char* src, char c) {
  86. int l=strlen(src);
  87. for (int i=0; i<l; i++)
  88. if (src[i] == c) return true;
  89. return false;
  90. }
  91. void strCopy(char* dest, const char* src, int destlen) {
  92. if (src)
  93. strncpy(dest, src, destlen-1);
  94. dest[src ? destlen-1 : 0] = 0;
  95. }
  96. static char intToHex(uint8_t i) {
  97. if (i<=9)
  98. return '0'+i;
  99. else if ((i>=10) && (i<=15))
  100. return 'a'+(i-10);
  101. assert(false);
  102. return '\0';
  103. }
  104. void binToHex(const uint8_t* in, size_t inlen,
  105. char* out, size_t outlen) {
  106. if (inlen > outlen/2)
  107. inlen = outlen/2;
  108. if (inlen > 0) {
  109. assert(in);
  110. assert(out);
  111. }
  112. for (size_t i=0; i<inlen; i++) {
  113. out[i*2] = intToHex((in[i] >> 4) & 15);
  114. out[i*2+1] = intToHex((in[i] & 15));
  115. }
  116. }
  117. std::string binToHex(const uint8_t* in, size_t inlen) {
  118. char* buffer = new char[inlen*2+1]();
  119. std::string out;
  120. binToHex(in, inlen, buffer, inlen*2);
  121. out = buffer;
  122. delete [] buffer;
  123. return out;
  124. }
  125. static bool readHexAndShift(char c, uint8_t* v) {
  126. c=tolower(c);
  127. if ((c >= '0') && (c <= '9'))
  128. *v = (*v << 4) + (c - '0');
  129. else if ((c >= 'a') && (c <= 'f'))
  130. *v = (*v << 4) + (c - 'a' + 10);
  131. else
  132. return false;
  133. return true;
  134. }
  135. bool hexToBin(const char* in, size_t inlen,
  136. uint8_t* out, size_t outlen) {
  137. assert(in);
  138. assert(out);
  139. if (inlen & 1)
  140. return false;
  141. if (inlen > outlen*2)
  142. inlen = outlen*2;
  143. for(size_t i=0; i<inlen; i+=2) {
  144. uint8_t byte = 0;
  145. if (!readHexAndShift(in[i], &byte) ||
  146. !readHexAndShift(in[i+1], &byte))
  147. return false;
  148. out[i/2] = byte;
  149. }
  150. return true;
  151. }
  152. std::vector<uint8_t> hexToBin(const char* in, size_t inlen) {
  153. std::vector<uint8_t> out(inlen/2);
  154. if (!hexToBin(in, inlen, out.data(), inlen/2))
  155. return std::vector<uint8_t>();
  156. return out;
  157. }
  158. std::string convertLF(const char* src, size_t bytes)
  159. {
  160. size_t sz;
  161. std::string out;
  162. const char* in;
  163. size_t in_len;
  164. // Compute output size
  165. sz = 0;
  166. in = src;
  167. in_len = bytes;
  168. while ((in_len > 0) && (*in != '\0')) {
  169. if (*in != '\r') {
  170. sz++;
  171. in++;
  172. in_len--;
  173. continue;
  174. }
  175. if ((in_len < 2) || (*(in+1) != '\n'))
  176. sz++;
  177. in++;
  178. in_len--;
  179. }
  180. // Reserve space
  181. out.reserve(sz);
  182. // And convert
  183. in = src;
  184. in_len = bytes;
  185. while ((in_len > 0) && (*in != '\0')) {
  186. if (*in != '\r') {
  187. out += *in++;
  188. in_len--;
  189. continue;
  190. }
  191. if ((in_len < 2) || (*(in+1) != '\n'))
  192. out += '\n';
  193. in++;
  194. in_len--;
  195. }
  196. return out;
  197. }
  198. std::string convertCRLF(const char* src, size_t bytes)
  199. {
  200. std::string out;
  201. size_t sz;
  202. const char* in;
  203. size_t in_len;
  204. // Compute output size
  205. sz = 0;
  206. in = src;
  207. in_len = bytes;
  208. while ((in_len > 0) && (*in != '\0')) {
  209. sz++;
  210. if (*in == '\r') {
  211. if ((in_len < 2) || (*(in+1) != '\n'))
  212. sz++;
  213. } else if (*in == '\n') {
  214. if ((in == src) || (*(in-1) != '\r'))
  215. sz++;
  216. }
  217. in++;
  218. in_len--;
  219. }
  220. // Reserve space
  221. out.reserve(sz);
  222. // And convert
  223. in = src;
  224. in_len = bytes;
  225. while ((in_len > 0) && (*in != '\0')) {
  226. if (*in == '\n') {
  227. if ((in == src) || (*(in-1) != '\r'))
  228. out += '\r';
  229. }
  230. out += *in;
  231. if (*in == '\r') {
  232. if ((in_len < 2) || (*(in+1) != '\n'))
  233. out += '\n';
  234. }
  235. in++;
  236. in_len--;
  237. }
  238. return out;
  239. }
  240. size_t ucs4ToUTF8(unsigned src, char dst[5]) {
  241. if (src < 0x80) {
  242. *dst++ = src;
  243. *dst++ = '\0';
  244. return 1;
  245. } else if (src < 0x800) {
  246. *dst++ = 0xc0 | (src >> 6);
  247. *dst++ = 0x80 | (src & 0x3f);
  248. *dst++ = '\0';
  249. return 2;
  250. } else if (src < 0x10000) {
  251. *dst++ = 0xe0 | (src >> 12);
  252. *dst++ = 0x80 | ((src >> 6) & 0x3f);
  253. *dst++ = 0x80 | (src & 0x3f);
  254. *dst++ = '\0';
  255. return 3;
  256. } else if (src < 0x110000) {
  257. *dst++ = 0xf0 | (src >> 18);
  258. *dst++ = 0x80 | ((src >> 12) & 0x3f);
  259. *dst++ = 0x80 | ((src >> 6) & 0x3f);
  260. *dst++ = 0x80 | (src & 0x3f);
  261. *dst++ = '\0';
  262. return 4;
  263. } else {
  264. return ucs4ToUTF8(0xfffd, dst);
  265. }
  266. }
  267. size_t utf8ToUCS4(const char* src, size_t max, unsigned* dst) {
  268. size_t count, consumed;
  269. *dst = 0xfffd;
  270. if (max == 0)
  271. return 0;
  272. consumed = 1;
  273. if ((*src & 0x80) == 0) {
  274. *dst = *src;
  275. count = 0;
  276. } else if ((*src & 0xe0) == 0xc0) {
  277. *dst = *src & 0x1f;
  278. count = 1;
  279. } else if ((*src & 0xf0) == 0xe0) {
  280. *dst = *src & 0x0f;
  281. count = 2;
  282. } else if ((*src & 0xf8) == 0xf0) {
  283. *dst = *src & 0x07;
  284. count = 3;
  285. } else {
  286. // Invalid sequence, consume all continuation characters
  287. src++;
  288. max--;
  289. while ((max-- > 0) && ((*src++ & 0xc0) == 0x80))
  290. consumed++;
  291. return consumed;
  292. }
  293. src++;
  294. max--;
  295. while (count--) {
  296. consumed++;
  297. // Invalid or truncated sequence?
  298. if ((max == 0) || ((*src & 0xc0) != 0x80)) {
  299. *dst = 0xfffd;
  300. return consumed;
  301. }
  302. *dst <<= 6;
  303. *dst |= *src & 0x3f;
  304. src++;
  305. max--;
  306. }
  307. return consumed;
  308. }
  309. size_t ucs4ToUTF16(unsigned src, wchar_t dst[3]) {
  310. if ((src < 0xd800) || ((src >= 0xe000) && (src < 0x10000))) {
  311. *dst++ = src;
  312. *dst++ = L'\0';
  313. return 1;
  314. } else if ((src >= 0x10000) && (src < 0x110000)) {
  315. src -= 0x10000;
  316. *dst++ = 0xd800 | ((src >> 10) & 0x03ff);
  317. *dst++ = 0xdc00 | (src & 0x03ff);
  318. *dst++ = L'\0';
  319. return 2;
  320. } else {
  321. return ucs4ToUTF16(0xfffd, dst);
  322. }
  323. }
  324. size_t utf16ToUCS4(const wchar_t* src, size_t max, unsigned* dst) {
  325. *dst = 0xfffd;
  326. if (max == 0)
  327. return 0;
  328. if ((*src < 0xd800) || (*src >= 0xe000)) {
  329. *dst = *src;
  330. return 1;
  331. }
  332. if (*src & 0x0400) {
  333. size_t consumed;
  334. // Invalid sequence, consume all continuation characters
  335. consumed = 0;
  336. while ((max > 0) && (*src & 0x0400)) {
  337. src++;
  338. max--;
  339. consumed++;
  340. }
  341. return consumed;
  342. }
  343. *dst = *src++;
  344. max--;
  345. // Invalid or truncated sequence?
  346. if ((max == 0) || ((*src & 0xfc00) != 0xdc00)) {
  347. *dst = 0xfffd;
  348. return 1;
  349. }
  350. *dst = 0x10000 + ((*dst & 0x03ff) << 10);
  351. *dst |= *src & 0x3ff;
  352. return 2;
  353. }
  354. std::string latin1ToUTF8(const char* src, size_t bytes) {
  355. std::string out;
  356. size_t sz;
  357. const char* in;
  358. size_t in_len;
  359. // Compute output size
  360. sz = 0;
  361. in = src;
  362. in_len = bytes;
  363. while ((in_len > 0) && (*in != '\0')) {
  364. char buf[5];
  365. sz += ucs4ToUTF8(*(const unsigned char*)in, buf);
  366. in++;
  367. in_len--;
  368. }
  369. // Reserve space
  370. out.reserve(sz);
  371. // And convert
  372. in = src;
  373. in_len = bytes;
  374. while ((in_len > 0) && (*in != '\0')) {
  375. char buf[5];
  376. ucs4ToUTF8(*(const unsigned char*)in, buf);
  377. out += buf;
  378. in++;
  379. in_len--;
  380. }
  381. return out;
  382. }
  383. std::string utf8ToLatin1(const char* src, size_t bytes) {
  384. std::string out;
  385. size_t sz;
  386. const char* in;
  387. size_t in_len;
  388. // Compute output size
  389. sz = 0;
  390. in = src;
  391. in_len = bytes;
  392. while ((in_len > 0) && (*in != '\0')) {
  393. size_t len;
  394. unsigned ucs;
  395. len = utf8ToUCS4(in, in_len, &ucs);
  396. in += len;
  397. in_len -= len;
  398. sz++;
  399. }
  400. // Reserve space
  401. out.reserve(sz);
  402. // And convert
  403. in = src;
  404. in_len = bytes;
  405. while ((in_len > 0) && (*in != '\0')) {
  406. size_t len;
  407. unsigned ucs;
  408. len = utf8ToUCS4(in, in_len, &ucs);
  409. in += len;
  410. in_len -= len;
  411. if (ucs > 0xff)
  412. out += '?';
  413. else
  414. out += (unsigned char)ucs;
  415. }
  416. return out;
  417. }
  418. std::string utf16ToUTF8(const wchar_t* src, size_t units)
  419. {
  420. std::string out;
  421. size_t sz;
  422. const wchar_t* in;
  423. size_t in_len;
  424. // Compute output size
  425. sz = 0;
  426. in = src;
  427. in_len = units;
  428. while ((in_len > 0) && (*in != '\0')) {
  429. size_t len;
  430. unsigned ucs;
  431. char buf[5];
  432. len = utf16ToUCS4(in, in_len, &ucs);
  433. in += len;
  434. in_len -= len;
  435. sz += ucs4ToUTF8(ucs, buf);
  436. }
  437. // Reserve space
  438. out.reserve(sz);
  439. // And convert
  440. in = src;
  441. in_len = units;
  442. while ((in_len > 0) && (*in != '\0')) {
  443. size_t len;
  444. unsigned ucs;
  445. char buf[5];
  446. len = utf16ToUCS4(in, in_len, &ucs);
  447. in += len;
  448. in_len -= len;
  449. ucs4ToUTF8(ucs, buf);
  450. out += buf;
  451. }
  452. return out;
  453. }
  454. std::wstring utf8ToUTF16(const char* src, size_t bytes)
  455. {
  456. std::wstring out;
  457. size_t sz;
  458. const char* in;
  459. size_t in_len;
  460. // Compute output size
  461. sz = 0;
  462. in = src;
  463. in_len = bytes;
  464. while ((in_len > 0) && (*in != '\0')) {
  465. size_t len;
  466. unsigned ucs;
  467. wchar_t buf[3];
  468. len = utf8ToUCS4(in, in_len, &ucs);
  469. in += len;
  470. in_len -= len;
  471. sz += ucs4ToUTF16(ucs, buf);
  472. }
  473. // Reserve space
  474. out.reserve(sz);
  475. // And convert
  476. in = src;
  477. in_len = bytes;
  478. while ((in_len > 0) && (*in != '\0')) {
  479. size_t len;
  480. unsigned ucs;
  481. wchar_t buf[3];
  482. len = utf8ToUCS4(in, in_len, &ucs);
  483. in += len;
  484. in_len -= len;
  485. ucs4ToUTF16(ucs, buf);
  486. out += buf;
  487. }
  488. return out;
  489. }
  490. unsigned msBetween(const struct timeval *first,
  491. const struct timeval *second)
  492. {
  493. unsigned diff;
  494. diff = (second->tv_sec - first->tv_sec) * 1000;
  495. diff += second->tv_usec / 1000;
  496. diff -= first->tv_usec / 1000;
  497. return diff;
  498. }
  499. unsigned msSince(const struct timeval *then)
  500. {
  501. struct timeval now;
  502. gettimeofday(&now, NULL);
  503. return msBetween(then, &now);
  504. }
  505. bool isBefore(const struct timeval *first,
  506. const struct timeval *second)
  507. {
  508. if (first->tv_sec < second->tv_sec)
  509. return true;
  510. if (first->tv_sec > second->tv_sec)
  511. return false;
  512. if (first->tv_usec < second->tv_usec)
  513. return true;
  514. return false;
  515. }
  516. static std::string doPrefix(long long value, const char *unit,
  517. unsigned divisor, const char **prefixes,
  518. size_t prefixCount, int precision) {
  519. char buffer[256];
  520. double newValue;
  521. size_t prefix;
  522. newValue = value;
  523. prefix = 0;
  524. while (newValue >= divisor) {
  525. if (prefix >= prefixCount)
  526. break;
  527. newValue /= divisor;
  528. prefix++;
  529. }
  530. snprintf(buffer, sizeof(buffer), "%.*g %s%s", precision, newValue,
  531. (prefix == 0) ? "" : prefixes[prefix-1], unit);
  532. buffer[sizeof(buffer)-1] = '\0';
  533. return buffer;
  534. }
  535. static const char *siPrefixes[] =
  536. { "k", "M", "G", "T", "P", "E", "Z", "Y" };
  537. static const char *iecPrefixes[] =
  538. { "Ki", "Mi", "Gi", "Ti", "Pi", "Ei", "Zi", "Yi" };
  539. std::string siPrefix(long long value, const char *unit,
  540. int precision) {
  541. return doPrefix(value, unit, 1000, siPrefixes,
  542. sizeof(siPrefixes)/sizeof(*siPrefixes),
  543. precision);
  544. }
  545. std::string iecPrefix(long long value, const char *unit,
  546. int precision) {
  547. return doPrefix(value, unit, 1024, iecPrefixes,
  548. sizeof(iecPrefixes)/sizeof(*iecPrefixes),
  549. precision);
  550. }
  551. };