blob: fc4f4ca4063f54f3148febb7c2c9b642cc35bc92 [file] [log] [blame]
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +00001/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
Pierre Ossman546b2ad2019-05-02 12:32:03 +02002 * Copyright 2011-2019 Pierre Ossman for Cendio AB
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +00003 *
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
Adam Tkac8aee1a82009-09-04 12:08:56 +000020#ifdef HAVE_CONFIG_H
21#include <config.h>
Adam Tkacad1cbd92008-10-06 14:08:00 +000022#endif
23
Pierre Ossmanba6fbfe2015-03-03 16:41:29 +010024#include <stdarg.h>
Pierre Ossman64624342015-03-03 16:30:13 +010025#include <stdio.h>
Pierre Ossman5bc20a62011-11-08 12:42:41 +000026#include <sys/time.h>
27
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000028#include <rfb/util.h>
29
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000030namespace rfb {
31
Pierre Ossmanba6fbfe2015-03-03 16:41:29 +010032 void CharArray::format(const char *fmt, ...) {
33 va_list ap;
Steve Kondikb3c9f7b2017-07-08 02:08:43 -070034 int len;
Pierre Ossmanba6fbfe2015-03-03 16:41:29 +010035
36 va_start(ap, fmt);
37 len = vsnprintf(NULL, 0, fmt, ap);
38 va_end(ap);
39
40 delete [] buf;
41
42 if (len < 0) {
43 buf = new char[1];
44 buf[0] = '\0';
45 return;
46 }
47
48 buf = new char[len+1];
49
50 va_start(ap, fmt);
51 vsnprintf(buf, len+1, fmt, ap);
52 va_end(ap);
53 }
54
Adam Tkacd36b6262009-09-04 10:57:20 +000055 char* strDup(const char* s) {
56 if (!s) return 0;
57 int l = strlen(s);
58 char* r = new char[l+1];
59 memcpy(r, s, l+1);
60 return r;
61 };
62
63 void strFree(char* s) {
64 delete [] s;
65 }
66
Pierre Ossman5fbbe102019-05-10 11:44:19 +020067 void strFree(wchar_t* s) {
68 delete [] s;
69 }
70
Adam Tkacd36b6262009-09-04 10:57:20 +000071
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000072 bool strSplit(const char* src, const char limiter, char** out1, char** out2, bool fromEnd) {
73 CharArray out1old, out2old;
74 if (out1) out1old.buf = *out1;
75 if (out2) out2old.buf = *out2;
76 int len = strlen(src);
77 int i=0, increment=1, limit=len;
78 if (fromEnd) {
79 i=len-1; increment = -1; limit = -1;
80 }
81 while (i!=limit) {
82 if (src[i] == limiter) {
83 if (out1) {
84 *out1 = new char[i+1];
85 if (i) memcpy(*out1, src, i);
86 (*out1)[i] = 0;
87 }
88 if (out2) {
89 *out2 = new char[len-i];
90 if (len-i-1) memcpy(*out2, &src[i+1], len-i-1);
91 (*out2)[len-i-1] = 0;
92 }
93 return true;
94 }
95 i+=increment;
96 }
Adam Tkacd36b6262009-09-04 10:57:20 +000097 if (out1) *out1 = strDup(src);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000098 if (out2) *out2 = 0;
99 return false;
100 }
101
102 bool strContains(const char* src, char c) {
103 int l=strlen(src);
104 for (int i=0; i<l; i++)
105 if (src[i] == c) return true;
106 return false;
107 }
108
109 void strCopy(char* dest, const char* src, int destlen) {
110 if (src)
111 strncpy(dest, src, destlen-1);
112 dest[src ? destlen-1 : 0] = 0;
113 }
114
Pierre Ossman546b2ad2019-05-02 12:32:03 +0200115 char* convertLF(const char* src, size_t bytes)
116 {
117 char* buffer;
118 size_t sz;
119
120 char* out;
121 const char* in;
122 size_t in_len;
123
124 // Always include space for a NULL
125 sz = 1;
126
127 // Compute output size
128 in = src;
129 in_len = bytes;
130 while ((*in != '\0') && (in_len > 0)) {
131 if (*in != '\r') {
132 sz++;
133 in++;
134 in_len--;
135 continue;
136 }
137
138 if ((in_len == 0) || (*(in+1) != '\n'))
139 sz++;
140
141 in++;
142 in_len--;
143 }
144
145 // Alloc
146 buffer = new char[sz];
147 memset(buffer, 0, sz);
148
149 // And convert
150 out = buffer;
151 in = src;
152 in_len = bytes;
153 while ((*in != '\0') && (in_len > 0)) {
154 if (*in != '\r') {
155 *out++ = *in++;
156 in_len--;
157 continue;
158 }
159
160 if ((in_len == 0) || (*(in+1) != '\n'))
161 *out++ = '\n';
162
163 in++;
164 in_len--;
165 }
166
167 return buffer;
168 }
169
Pierre Ossman5fbbe102019-05-10 11:44:19 +0200170 char* convertCRLF(const char* src, size_t bytes)
171 {
172 char* buffer;
173 size_t sz;
174
175 char* out;
176 const char* in;
177 size_t in_len;
178
179 // Always include space for a NULL
180 sz = 1;
181
182 // Compute output size
183 in = src;
184 in_len = bytes;
185 while ((*in != '\0') && (in_len > 0)) {
186 sz++;
187
188 if (*in == '\r') {
189 if ((in_len == 0) || (*(in+1) != '\n'))
190 sz++;
191 } else if (*in == '\n') {
192 if ((in == src) || (*(in-1) != '\r'))
193 sz++;
194 }
195
196 in++;
197 in_len--;
198 }
199
200 // Alloc
201 buffer = new char[sz];
202 memset(buffer, 0, sz);
203
204 // And convert
205 out = buffer;
206 in = src;
207 in_len = bytes;
208 while ((*in != '\0') && (in_len > 0)) {
209 if (*in == '\n') {
210 if ((in == src) || (*(in-1) != '\r'))
211 *out++ = '\r';
212 }
213
214 *out = *in;
215
216 if (*in == '\r') {
217 if ((in_len == 0) || (*(in+1) != '\n')) {
218 out++;
219 *out = '\n';
220 }
221 }
222
223 out++;
224 in++;
225 in_len--;
226 }
227
228 return buffer;
229 }
230
Pierre Ossman56fa7822016-01-22 16:40:59 +0100231 size_t ucs4ToUTF8(unsigned src, char* dst) {
232 if (src < 0x80) {
233 *dst++ = src;
234 *dst++ = '\0';
235 return 1;
236 } else if (src < 0x800) {
237 *dst++ = 0xc0 | (src >> 6);
238 *dst++ = 0x80 | (src & 0x3f);
239 *dst++ = '\0';
240 return 2;
241 } else if (src < 0x10000) {
242 *dst++ = 0xe0 | (src >> 12);
243 *dst++ = 0x80 | ((src >> 6) & 0x3f);
244 *dst++ = 0x80 | (src & 0x3f);
245 *dst++ = '\0';
246 return 3;
247 } else if (src < 0x110000) {
248 *dst++ = 0xf0 | (src >> 18);
249 *dst++ = 0x80 | ((src >> 12) & 0x3f);
250 *dst++ = 0x80 | ((src >> 6) & 0x3f);
251 *dst++ = 0x80 | (src & 0x3f);
252 *dst++ = '\0';
253 return 4;
254 } else {
255 return ucs4ToUTF8(0xfffd, dst);
256 }
257 }
258
259 size_t utf8ToUCS4(const char* src, size_t max, unsigned* dst) {
260 size_t count, consumed;
261
262 *dst = 0xfffd;
263
264 if (max == 0)
265 return 0;
266
267 consumed = 1;
268
269 if ((*src & 0x80) == 0) {
270 *dst = *src;
271 count = 0;
272 } else if ((*src & 0xe0) == 0xc0) {
273 *dst = *src & 0x1f;
274 count = 1;
275 } else if ((*src & 0xf0) == 0xe0) {
276 *dst = *src & 0x0f;
277 count = 2;
278 } else if ((*src & 0xf8) == 0xf0) {
279 *dst = *src & 0x07;
280 count = 3;
281 } else {
282 // Invalid sequence, consume all continuation characters
283 src++;
284 max--;
285 while ((max-- > 0) && ((*src++ & 0xc0) == 0x80))
286 consumed++;
287 return consumed;
288 }
289
290 src++;
291 max--;
292
293 while (count--) {
294 // Invalid or truncated sequence?
295 if ((max == 0) || ((*src & 0xc0) != 0x80)) {
296 *dst = 0xfffd;
297 return consumed;
298 }
299
300 *dst <<= 6;
301 *dst |= *src & 0x3f;
302
303 src++;
304 max--;
305 }
306
307 return consumed;
308 }
309
Pierre Ossman5fbbe102019-05-10 11:44:19 +0200310 size_t ucs4ToUTF16(unsigned src, wchar_t* dst) {
311 if ((src < 0xd800) || ((src >= 0xe000) && (src < 0x10000))) {
312 *dst++ = src;
313 *dst++ = L'\0';
314 return 1;
315 } else if (src < 0x110000) {
316 *dst++ = 0xd800 | ((src >> 10) & 0x07ff);
317 *dst++ = 0xdc00 | (src & 0x07ff);
318 *dst++ = L'\0';
319 return 2;
320 } else {
321 return ucs4ToUTF16(0xfffd, dst);
322 }
323 }
324
325 size_t utf16ToUCS4(const wchar_t* src, size_t max, unsigned* dst) {
326 *dst = 0xfffd;
327
328 if (max == 0)
329 return 0;
330
331 if ((*src < 0xd800) || (*src >= 0xe000)) {
332 *dst = *src;
333 return 1;
334 }
335
336 if (*src & 0x0400) {
337 size_t consumed;
338
339 // Invalid sequence, consume all continuation characters
340 consumed = 0;
341 while ((max > 0) && (*src & 0x0400)) {
342 src++;
343 max--;
344 consumed++;
345 }
346
347 return consumed;
348 }
349
350 *dst = *src++;
351 max--;
352
353 // Invalid or truncated sequence?
354 if ((max == 0) || ((*src & 0xfc00) != 0xdc00)) {
355 *dst = 0xfffd;
356 return 1;
357 }
358
359 *dst = 0x10000 | ((*dst & 0x03ff) << 10);
360 *dst |= *src & 0x3ff;
361
362 return 2;
363 }
364
Pierre Ossman56fa7822016-01-22 16:40:59 +0100365 char* latin1ToUTF8(const char* src, size_t bytes) {
366 char* buffer;
367 size_t sz;
368
369 char* out;
370 const char* in;
371 size_t in_len;
372
373 // Always include space for a NULL
374 sz = 1;
375
376 // Compute output size
377 in = src;
378 in_len = bytes;
379 while ((*in != '\0') && (in_len > 0)) {
380 char buf[5];
381 sz += ucs4ToUTF8(*in, buf);
382 in++;
383 in_len--;
384 }
385
386 // Alloc
387 buffer = new char[sz];
388 memset(buffer, 0, sz);
389
390 // And convert
391 out = buffer;
392 in = src;
393 in_len = bytes;
394 while ((*in != '\0') && (in_len > 0)) {
395 out += ucs4ToUTF8(*in, out);
396 in++;
397 in_len--;
398 }
399
400 return buffer;
401 }
402
403 char* utf8ToLatin1(const char* src, size_t bytes) {
404 char* buffer;
405 size_t sz;
406
407 char* out;
408 const char* in;
409 size_t in_len;
410
411 // Always include space for a NULL
412 sz = 1;
413
414 // Compute output size
415 in = src;
416 in_len = bytes;
417 while ((*in != '\0') && (in_len > 0)) {
418 size_t len;
419 unsigned ucs;
420
421 len = utf8ToUCS4(in, in_len, &ucs);
422 in += len;
423 in_len -= len;
424 sz++;
425 }
426
427 // Alloc
428 buffer = new char[sz];
429 memset(buffer, 0, sz);
430
431 // And convert
432 out = buffer;
433 in = src;
434 in_len = bytes;
435 while ((*in != '\0') && (in_len > 0)) {
436 size_t len;
437 unsigned ucs;
438
439 len = utf8ToUCS4(in, in_len, &ucs);
440 in += len;
441 in_len -= len;
442
443 if (ucs > 0xff)
444 *out++ = '?';
445 else
446 *out++ = (unsigned char)ucs;
447 }
448
449 return buffer;
450 }
451
Pierre Ossman5fbbe102019-05-10 11:44:19 +0200452 char* utf16ToUTF8(const wchar_t* src, size_t units)
453 {
454 char* buffer;
455 size_t sz;
456
457 char* out;
458 const wchar_t* in;
459 size_t in_len;
460
461 // Always include space for a NULL
462 sz = 1;
463
464 // Compute output size
465 in = src;
466 in_len = units;
467 while ((*in != '\0') && (in_len > 0)) {
468 size_t len;
469 unsigned ucs;
470 char buf[5];
471
472 len = utf16ToUCS4(in, in_len, &ucs);
473 in += len;
474 in_len -= len;
475
476 sz += ucs4ToUTF8(ucs, buf);
477 }
478
479 // Alloc
480 buffer = new char[sz];
481 memset(buffer, 0, sz);
482
483 // And convert
484 out = buffer;
485 in = src;
486 in_len = units;
487 while ((*in != '\0') && (in_len > 0)) {
488 size_t len;
489 unsigned ucs;
490
491 len = utf16ToUCS4(in, in_len, &ucs);
492 in += len;
493 in_len -= len;
494
495 out += ucs4ToUTF8(ucs, out);
496 }
497
498 return buffer;
499 }
500
501 wchar_t* utf8ToUTF16(const char* src, size_t bytes)
502 {
503 wchar_t* buffer;
504 size_t sz;
505
506 wchar_t* out;
507 const char* in;
508 size_t in_len;
509
510 // Always include space for a NULL
511 sz = 1;
512
513 // Compute output size
514 in = src;
515 in_len = bytes;
516 while ((*in != '\0') && (in_len > 0)) {
517 size_t len;
518 unsigned ucs;
519 wchar_t buf[3];
520
521 len = utf8ToUCS4(in, in_len, &ucs);
522 in += len;
523 in_len -= len;
524
525 sz += ucs4ToUTF16(ucs, buf);
526 }
527
528 // Alloc
529 buffer = new wchar_t[sz];
530 memset(buffer, 0, sz);
531
532 // And convert
533 out = buffer;
534 in = src;
535 in_len = bytes;
536 while ((*in != '\0') && (in_len > 0)) {
537 size_t len;
538 unsigned ucs;
539
540 len = utf8ToUCS4(in, in_len, &ucs);
541 in += len;
542 in_len -= len;
543
544 out += ucs4ToUTF16(ucs, out);
545 }
546
547 return buffer;
548 }
549
Pierre Ossmana99d14d2015-12-13 15:43:46 +0100550 unsigned msBetween(const struct timeval *first,
551 const struct timeval *second)
552 {
553 unsigned diff;
554
555 diff = (second->tv_sec - first->tv_sec) * 1000;
556
557 diff += second->tv_usec / 1000;
558 diff -= first->tv_usec / 1000;
559
560 return diff;
561 }
562
Pierre Ossman5bc20a62011-11-08 12:42:41 +0000563 unsigned msSince(const struct timeval *then)
564 {
565 struct timeval now;
Pierre Ossman5bc20a62011-11-08 12:42:41 +0000566
567 gettimeofday(&now, NULL);
568
Pierre Ossmana99d14d2015-12-13 15:43:46 +0100569 return msBetween(then, &now);
570 }
Pierre Ossman5bc20a62011-11-08 12:42:41 +0000571
Pierre Ossmana99d14d2015-12-13 15:43:46 +0100572 bool isBefore(const struct timeval *first,
573 const struct timeval *second)
574 {
575 if (first->tv_sec < second->tv_sec)
576 return true;
577 if (first->tv_sec > second->tv_sec)
578 return false;
579 if (first->tv_usec < second->tv_usec)
580 return true;
581 return false;
Pierre Ossman5bc20a62011-11-08 12:42:41 +0000582 }
Pierre Ossman64624342015-03-03 16:30:13 +0100583
584 static size_t doPrefix(long long value, const char *unit,
585 char *buffer, size_t maxlen,
586 unsigned divisor, const char **prefixes,
Pierre Ossman921f6c82017-02-24 12:33:09 +0100587 size_t prefixCount, int precision) {
Pierre Ossman64624342015-03-03 16:30:13 +0100588 double newValue;
589 size_t prefix, len;
590
591 newValue = value;
592 prefix = 0;
593 while (newValue >= divisor) {
594 if (prefix >= prefixCount)
595 break;
596 newValue /= divisor;
597 prefix++;
598 }
599
Pierre Ossman921f6c82017-02-24 12:33:09 +0100600 len = snprintf(buffer, maxlen, "%.*g %s%s", precision, newValue,
Pierre Ossman64624342015-03-03 16:30:13 +0100601 (prefix == 0) ? "" : prefixes[prefix-1], unit);
602 buffer[maxlen-1] = '\0';
603
604 return len;
605 }
606
607 static const char *siPrefixes[] =
608 { "k", "M", "G", "T", "P", "E", "Z", "Y" };
609 static const char *iecPrefixes[] =
610 { "Ki", "Mi", "Gi", "Ti", "Pi", "Ei", "Zi", "Yi" };
611
612 size_t siPrefix(long long value, const char *unit,
Pierre Ossman921f6c82017-02-24 12:33:09 +0100613 char *buffer, size_t maxlen, int precision) {
Pierre Ossman64624342015-03-03 16:30:13 +0100614 return doPrefix(value, unit, buffer, maxlen, 1000, siPrefixes,
Pierre Ossman921f6c82017-02-24 12:33:09 +0100615 sizeof(siPrefixes)/sizeof(*siPrefixes),
616 precision);
Pierre Ossman64624342015-03-03 16:30:13 +0100617 }
618
619 size_t iecPrefix(long long value, const char *unit,
Pierre Ossman921f6c82017-02-24 12:33:09 +0100620 char *buffer, size_t maxlen, int precision) {
Pierre Ossman64624342015-03-03 16:30:13 +0100621 return doPrefix(value, unit, buffer, maxlen, 1024, iecPrefixes,
Pierre Ossman921f6c82017-02-24 12:33:09 +0100622 sizeof(iecPrefixes)/sizeof(*iecPrefixes),
623 precision);
Pierre Ossman64624342015-03-03 16:30:13 +0100624 }
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000625};