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

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