blob: deb68ca196068ad106f1c358f8987e49a867c145 [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
67
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000068 bool strSplit(const char* src, const char limiter, char** out1, char** out2, bool fromEnd) {
69 CharArray out1old, out2old;
70 if (out1) out1old.buf = *out1;
71 if (out2) out2old.buf = *out2;
72 int len = strlen(src);
73 int i=0, increment=1, limit=len;
74 if (fromEnd) {
75 i=len-1; increment = -1; limit = -1;
76 }
77 while (i!=limit) {
78 if (src[i] == limiter) {
79 if (out1) {
80 *out1 = new char[i+1];
81 if (i) memcpy(*out1, src, i);
82 (*out1)[i] = 0;
83 }
84 if (out2) {
85 *out2 = new char[len-i];
86 if (len-i-1) memcpy(*out2, &src[i+1], len-i-1);
87 (*out2)[len-i-1] = 0;
88 }
89 return true;
90 }
91 i+=increment;
92 }
Adam Tkacd36b6262009-09-04 10:57:20 +000093 if (out1) *out1 = strDup(src);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000094 if (out2) *out2 = 0;
95 return false;
96 }
97
98 bool strContains(const char* src, char c) {
99 int l=strlen(src);
100 for (int i=0; i<l; i++)
101 if (src[i] == c) return true;
102 return false;
103 }
104
105 void strCopy(char* dest, const char* src, int destlen) {
106 if (src)
107 strncpy(dest, src, destlen-1);
108 dest[src ? destlen-1 : 0] = 0;
109 }
110
Pierre Ossman546b2ad2019-05-02 12:32:03 +0200111 char* convertLF(const char* src, size_t bytes)
112 {
113 char* buffer;
114 size_t sz;
115
116 char* out;
117 const char* in;
118 size_t in_len;
119
120 // Always include space for a NULL
121 sz = 1;
122
123 // Compute output size
124 in = src;
125 in_len = bytes;
126 while ((*in != '\0') && (in_len > 0)) {
127 if (*in != '\r') {
128 sz++;
129 in++;
130 in_len--;
131 continue;
132 }
133
134 if ((in_len == 0) || (*(in+1) != '\n'))
135 sz++;
136
137 in++;
138 in_len--;
139 }
140
141 // Alloc
142 buffer = new char[sz];
143 memset(buffer, 0, sz);
144
145 // And convert
146 out = buffer;
147 in = src;
148 in_len = bytes;
149 while ((*in != '\0') && (in_len > 0)) {
150 if (*in != '\r') {
151 *out++ = *in++;
152 in_len--;
153 continue;
154 }
155
156 if ((in_len == 0) || (*(in+1) != '\n'))
157 *out++ = '\n';
158
159 in++;
160 in_len--;
161 }
162
163 return buffer;
164 }
165
Pierre Ossman56fa7822016-01-22 16:40:59 +0100166 size_t ucs4ToUTF8(unsigned src, char* dst) {
167 if (src < 0x80) {
168 *dst++ = src;
169 *dst++ = '\0';
170 return 1;
171 } else if (src < 0x800) {
172 *dst++ = 0xc0 | (src >> 6);
173 *dst++ = 0x80 | (src & 0x3f);
174 *dst++ = '\0';
175 return 2;
176 } else if (src < 0x10000) {
177 *dst++ = 0xe0 | (src >> 12);
178 *dst++ = 0x80 | ((src >> 6) & 0x3f);
179 *dst++ = 0x80 | (src & 0x3f);
180 *dst++ = '\0';
181 return 3;
182 } else if (src < 0x110000) {
183 *dst++ = 0xf0 | (src >> 18);
184 *dst++ = 0x80 | ((src >> 12) & 0x3f);
185 *dst++ = 0x80 | ((src >> 6) & 0x3f);
186 *dst++ = 0x80 | (src & 0x3f);
187 *dst++ = '\0';
188 return 4;
189 } else {
190 return ucs4ToUTF8(0xfffd, dst);
191 }
192 }
193
194 size_t utf8ToUCS4(const char* src, size_t max, unsigned* dst) {
195 size_t count, consumed;
196
197 *dst = 0xfffd;
198
199 if (max == 0)
200 return 0;
201
202 consumed = 1;
203
204 if ((*src & 0x80) == 0) {
205 *dst = *src;
206 count = 0;
207 } else if ((*src & 0xe0) == 0xc0) {
208 *dst = *src & 0x1f;
209 count = 1;
210 } else if ((*src & 0xf0) == 0xe0) {
211 *dst = *src & 0x0f;
212 count = 2;
213 } else if ((*src & 0xf8) == 0xf0) {
214 *dst = *src & 0x07;
215 count = 3;
216 } else {
217 // Invalid sequence, consume all continuation characters
218 src++;
219 max--;
220 while ((max-- > 0) && ((*src++ & 0xc0) == 0x80))
221 consumed++;
222 return consumed;
223 }
224
225 src++;
226 max--;
227
228 while (count--) {
229 // Invalid or truncated sequence?
230 if ((max == 0) || ((*src & 0xc0) != 0x80)) {
231 *dst = 0xfffd;
232 return consumed;
233 }
234
235 *dst <<= 6;
236 *dst |= *src & 0x3f;
237
238 src++;
239 max--;
240 }
241
242 return consumed;
243 }
244
245 char* latin1ToUTF8(const char* src, size_t bytes) {
246 char* buffer;
247 size_t sz;
248
249 char* out;
250 const char* in;
251 size_t in_len;
252
253 // Always include space for a NULL
254 sz = 1;
255
256 // Compute output size
257 in = src;
258 in_len = bytes;
259 while ((*in != '\0') && (in_len > 0)) {
260 char buf[5];
261 sz += ucs4ToUTF8(*in, buf);
262 in++;
263 in_len--;
264 }
265
266 // Alloc
267 buffer = new char[sz];
268 memset(buffer, 0, sz);
269
270 // And convert
271 out = buffer;
272 in = src;
273 in_len = bytes;
274 while ((*in != '\0') && (in_len > 0)) {
275 out += ucs4ToUTF8(*in, out);
276 in++;
277 in_len--;
278 }
279
280 return buffer;
281 }
282
283 char* utf8ToLatin1(const char* src, size_t bytes) {
284 char* buffer;
285 size_t sz;
286
287 char* out;
288 const char* in;
289 size_t in_len;
290
291 // Always include space for a NULL
292 sz = 1;
293
294 // Compute output size
295 in = src;
296 in_len = bytes;
297 while ((*in != '\0') && (in_len > 0)) {
298 size_t len;
299 unsigned ucs;
300
301 len = utf8ToUCS4(in, in_len, &ucs);
302 in += len;
303 in_len -= len;
304 sz++;
305 }
306
307 // Alloc
308 buffer = new char[sz];
309 memset(buffer, 0, sz);
310
311 // And convert
312 out = buffer;
313 in = src;
314 in_len = bytes;
315 while ((*in != '\0') && (in_len > 0)) {
316 size_t len;
317 unsigned ucs;
318
319 len = utf8ToUCS4(in, in_len, &ucs);
320 in += len;
321 in_len -= len;
322
323 if (ucs > 0xff)
324 *out++ = '?';
325 else
326 *out++ = (unsigned char)ucs;
327 }
328
329 return buffer;
330 }
331
Pierre Ossmana99d14d2015-12-13 15:43:46 +0100332 unsigned msBetween(const struct timeval *first,
333 const struct timeval *second)
334 {
335 unsigned diff;
336
337 diff = (second->tv_sec - first->tv_sec) * 1000;
338
339 diff += second->tv_usec / 1000;
340 diff -= first->tv_usec / 1000;
341
342 return diff;
343 }
344
Pierre Ossman5bc20a62011-11-08 12:42:41 +0000345 unsigned msSince(const struct timeval *then)
346 {
347 struct timeval now;
Pierre Ossman5bc20a62011-11-08 12:42:41 +0000348
349 gettimeofday(&now, NULL);
350
Pierre Ossmana99d14d2015-12-13 15:43:46 +0100351 return msBetween(then, &now);
352 }
Pierre Ossman5bc20a62011-11-08 12:42:41 +0000353
Pierre Ossmana99d14d2015-12-13 15:43:46 +0100354 bool isBefore(const struct timeval *first,
355 const struct timeval *second)
356 {
357 if (first->tv_sec < second->tv_sec)
358 return true;
359 if (first->tv_sec > second->tv_sec)
360 return false;
361 if (first->tv_usec < second->tv_usec)
362 return true;
363 return false;
Pierre Ossman5bc20a62011-11-08 12:42:41 +0000364 }
Pierre Ossman64624342015-03-03 16:30:13 +0100365
366 static size_t doPrefix(long long value, const char *unit,
367 char *buffer, size_t maxlen,
368 unsigned divisor, const char **prefixes,
Pierre Ossman921f6c82017-02-24 12:33:09 +0100369 size_t prefixCount, int precision) {
Pierre Ossman64624342015-03-03 16:30:13 +0100370 double newValue;
371 size_t prefix, len;
372
373 newValue = value;
374 prefix = 0;
375 while (newValue >= divisor) {
376 if (prefix >= prefixCount)
377 break;
378 newValue /= divisor;
379 prefix++;
380 }
381
Pierre Ossman921f6c82017-02-24 12:33:09 +0100382 len = snprintf(buffer, maxlen, "%.*g %s%s", precision, newValue,
Pierre Ossman64624342015-03-03 16:30:13 +0100383 (prefix == 0) ? "" : prefixes[prefix-1], unit);
384 buffer[maxlen-1] = '\0';
385
386 return len;
387 }
388
389 static const char *siPrefixes[] =
390 { "k", "M", "G", "T", "P", "E", "Z", "Y" };
391 static const char *iecPrefixes[] =
392 { "Ki", "Mi", "Gi", "Ti", "Pi", "Ei", "Zi", "Yi" };
393
394 size_t siPrefix(long long value, const char *unit,
Pierre Ossman921f6c82017-02-24 12:33:09 +0100395 char *buffer, size_t maxlen, int precision) {
Pierre Ossman64624342015-03-03 16:30:13 +0100396 return doPrefix(value, unit, buffer, maxlen, 1000, siPrefixes,
Pierre Ossman921f6c82017-02-24 12:33:09 +0100397 sizeof(siPrefixes)/sizeof(*siPrefixes),
398 precision);
Pierre Ossman64624342015-03-03 16:30:13 +0100399 }
400
401 size_t iecPrefix(long long value, const char *unit,
Pierre Ossman921f6c82017-02-24 12:33:09 +0100402 char *buffer, size_t maxlen, int precision) {
Pierre Ossman64624342015-03-03 16:30:13 +0100403 return doPrefix(value, unit, buffer, maxlen, 1024, iecPrefixes,
Pierre Ossman921f6c82017-02-24 12:33:09 +0100404 sizeof(iecPrefixes)/sizeof(*iecPrefixes),
405 precision);
Pierre Ossman64624342015-03-03 16:30:13 +0100406 }
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000407};