blob: 85c7a3f6a6c95b97d5720964d7c1b1ccca285f32 [file] [log] [blame]
henrike@webrtc.orgf0488722014-05-13 18:00:26 +00001/*
2 * Copyright 2004 The WebRTC Project Authors. All rights reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
Steve Anton10542f22019-01-11 09:11:00 -080011#include "rtc_base/string_encode.h"
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000012
Yves Gerey988cc082018-10-23 12:03:01 +020013#include <cstdio>
14
Jonas Olsson6b1985d2018-07-05 11:59:48 +020015#include "rtc_base/arraysize.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020016#include "rtc_base/checks.h"
Steve Anton10542f22019-01-11 09:11:00 -080017#include "rtc_base/string_utils.h"
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000018
19namespace rtc {
20
21/////////////////////////////////////////////////////////////////////////////
22// String Encoding Utilities
23/////////////////////////////////////////////////////////////////////////////
24
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000025static const char HEX[] = "0123456789abcdef";
26
27char hex_encode(unsigned char val) {
henrikg91d6ede2015-09-17 00:24:34 -070028 RTC_DCHECK_LT(val, 16);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000029 return (val < 16) ? HEX[val] : '!';
30}
31
32bool hex_decode(char ch, unsigned char* val) {
33 if ((ch >= '0') && (ch <= '9')) {
34 *val = ch - '0';
Niels Möller12048c72018-10-29 12:58:48 +010035 } else if ((ch >= 'A') && (ch <= 'F')) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000036 *val = (ch - 'A') + 10;
Niels Möller12048c72018-10-29 12:58:48 +010037 } else if ((ch >= 'a') && (ch <= 'f')) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000038 *val = (ch - 'a') + 10;
39 } else {
40 return false;
41 }
42 return true;
43}
44
Yves Gerey665174f2018-06-19 15:03:05 +020045size_t hex_encode(char* buffer,
46 size_t buflen,
47 const char* csource,
48 size_t srclen) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000049 return hex_encode_with_delimiter(buffer, buflen, csource, srclen, 0);
50}
51
Yves Gerey665174f2018-06-19 15:03:05 +020052size_t hex_encode_with_delimiter(char* buffer,
53 size_t buflen,
54 const char* csource,
55 size_t srclen,
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000056 char delimiter) {
Henrik Grunell84879882018-03-23 15:33:03 +010057 RTC_DCHECK(buffer); // TODO(kwiberg): estimate output size
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000058 if (buflen == 0)
59 return 0;
60
61 // Init and check bounds.
62 const unsigned char* bsource =
63 reinterpret_cast<const unsigned char*>(csource);
64 size_t srcpos = 0, bufpos = 0;
65 size_t needed = delimiter ? (srclen * 3) : (srclen * 2 + 1);
66 if (buflen < needed)
67 return 0;
68
69 while (srcpos < srclen) {
70 unsigned char ch = bsource[srcpos++];
Yves Gerey665174f2018-06-19 15:03:05 +020071 buffer[bufpos] = hex_encode((ch >> 4) & 0xF);
72 buffer[bufpos + 1] = hex_encode((ch)&0xF);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000073 bufpos += 2;
74
75 // Don't write a delimiter after the last byte.
76 if (delimiter && (srcpos < srclen)) {
77 buffer[bufpos] = delimiter;
78 ++bufpos;
79 }
80 }
81
82 // Null terminate.
83 buffer[bufpos] = '\0';
84 return bufpos;
85}
86
Peter Thatcher1cf6f812015-05-15 10:40:45 -070087std::string hex_encode(const std::string& str) {
88 return hex_encode(str.c_str(), str.size());
89}
90
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000091std::string hex_encode(const char* source, size_t srclen) {
92 return hex_encode_with_delimiter(source, srclen, 0);
93}
94
Yves Gerey665174f2018-06-19 15:03:05 +020095std::string hex_encode_with_delimiter(const char* source,
96 size_t srclen,
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000097 char delimiter) {
98 const size_t kBufferSize = srclen * 3;
99 char* buffer = STACK_ARRAY(char, kBufferSize);
Yves Gerey665174f2018-06-19 15:03:05 +0200100 size_t length =
101 hex_encode_with_delimiter(buffer, kBufferSize, source, srclen, delimiter);
henrikg91d6ede2015-09-17 00:24:34 -0700102 RTC_DCHECK(srclen == 0 || length > 0);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000103 return std::string(buffer, length);
104}
105
Yves Gerey665174f2018-06-19 15:03:05 +0200106size_t hex_decode(char* cbuffer,
107 size_t buflen,
108 const char* source,
109 size_t srclen) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000110 return hex_decode_with_delimiter(cbuffer, buflen, source, srclen, 0);
111}
112
Yves Gerey665174f2018-06-19 15:03:05 +0200113size_t hex_decode_with_delimiter(char* cbuffer,
114 size_t buflen,
115 const char* source,
116 size_t srclen,
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000117 char delimiter) {
Henrik Grunell84879882018-03-23 15:33:03 +0100118 RTC_DCHECK(cbuffer); // TODO(kwiberg): estimate output size
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000119 if (buflen == 0)
120 return 0;
121
122 // Init and bounds check.
123 unsigned char* bbuffer = reinterpret_cast<unsigned char*>(cbuffer);
124 size_t srcpos = 0, bufpos = 0;
125 size_t needed = (delimiter) ? (srclen + 1) / 3 : srclen / 2;
126 if (buflen < needed)
127 return 0;
128
129 while (srcpos < srclen) {
130 if ((srclen - srcpos) < 2) {
131 // This means we have an odd number of bytes.
132 return 0;
133 }
134
135 unsigned char h1, h2;
136 if (!hex_decode(source[srcpos], &h1) ||
137 !hex_decode(source[srcpos + 1], &h2))
138 return 0;
139
140 bbuffer[bufpos++] = (h1 << 4) | h2;
141 srcpos += 2;
142
143 // Remove the delimiter if needed.
144 if (delimiter && (srclen - srcpos) > 1) {
145 if (source[srcpos] != delimiter)
146 return 0;
147 ++srcpos;
148 }
149 }
150
151 return bufpos;
152}
153
154size_t hex_decode(char* buffer, size_t buflen, const std::string& source) {
155 return hex_decode_with_delimiter(buffer, buflen, source, 0);
156}
Yves Gerey665174f2018-06-19 15:03:05 +0200157size_t hex_decode_with_delimiter(char* buffer,
158 size_t buflen,
159 const std::string& source,
160 char delimiter) {
161 return hex_decode_with_delimiter(buffer, buflen, source.c_str(),
162 source.length(), delimiter);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000163}
164
Yves Gerey665174f2018-06-19 15:03:05 +0200165size_t tokenize(const std::string& source,
166 char delimiter,
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000167 std::vector<std::string>* fields) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000168 fields->clear();
169 size_t last = 0;
170 for (size_t i = 0; i < source.length(); ++i) {
171 if (source[i] == delimiter) {
172 if (i != last) {
173 fields->push_back(source.substr(last, i - last));
174 }
175 last = i + 1;
176 }
177 }
178 if (last != source.length()) {
179 fields->push_back(source.substr(last, source.length() - last));
180 }
181 return fields->size();
182}
183
deadbeef0a6c4ca2015-10-06 11:38:28 -0700184size_t tokenize_with_empty_tokens(const std::string& source,
185 char delimiter,
186 std::vector<std::string>* fields) {
187 fields->clear();
188 size_t last = 0;
189 for (size_t i = 0; i < source.length(); ++i) {
190 if (source[i] == delimiter) {
191 fields->push_back(source.substr(last, i - last));
192 last = i + 1;
193 }
194 }
195 fields->push_back(source.substr(last, source.length() - last));
196 return fields->size();
197}
198
Yves Gerey665174f2018-06-19 15:03:05 +0200199size_t tokenize_append(const std::string& source,
200 char delimiter,
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000201 std::vector<std::string>* fields) {
Yves Gerey665174f2018-06-19 15:03:05 +0200202 if (!fields)
203 return 0;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000204
205 std::vector<std::string> new_fields;
206 tokenize(source, delimiter, &new_fields);
207 fields->insert(fields->end(), new_fields.begin(), new_fields.end());
208 return fields->size();
209}
210
Yves Gerey665174f2018-06-19 15:03:05 +0200211size_t tokenize(const std::string& source,
212 char delimiter,
213 char start_mark,
214 char end_mark,
215 std::vector<std::string>* fields) {
216 if (!fields)
217 return 0;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000218 fields->clear();
219
220 std::string remain_source = source;
221 while (!remain_source.empty()) {
222 size_t start_pos = remain_source.find(start_mark);
Yves Gerey665174f2018-06-19 15:03:05 +0200223 if (std::string::npos == start_pos)
224 break;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000225 std::string pre_mark;
226 if (start_pos > 0) {
227 pre_mark = remain_source.substr(0, start_pos - 1);
228 }
229
230 ++start_pos;
231 size_t end_pos = remain_source.find(end_mark, start_pos);
Yves Gerey665174f2018-06-19 15:03:05 +0200232 if (std::string::npos == end_pos)
233 break;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000234
235 // We have found the matching marks. First tokenize the pre-mask. Then add
236 // the marked part as a single field. Finally, loop back for the post-mark.
237 tokenize_append(pre_mark, delimiter, fields);
238 fields->push_back(remain_source.substr(start_pos, end_pos - start_pos));
239 remain_source = remain_source.substr(end_pos + 1);
240 }
241
242 return tokenize_append(remain_source, delimiter, fields);
243}
244
Donald Curtis144d0182015-05-15 13:14:24 -0700245bool tokenize_first(const std::string& source,
246 const char delimiter,
247 std::string* token,
248 std::string* rest) {
Donald Curtis0e07f922015-05-15 09:21:23 -0700249 // Find the first delimiter
250 size_t left_pos = source.find(delimiter);
251 if (left_pos == std::string::npos) {
252 return false;
253 }
254
255 // Look for additional occurrances of delimiter.
256 size_t right_pos = left_pos + 1;
Donald Curtis144d0182015-05-15 13:14:24 -0700257 while (source[right_pos] == delimiter) {
Donald Curtis0e07f922015-05-15 09:21:23 -0700258 right_pos++;
259 }
260
261 *token = source.substr(0, left_pos);
262 *rest = source.substr(right_pos);
263 return true;
264}
265
Diogo Real7bd1f1b2017-09-08 12:50:41 -0700266std::string join(const std::vector<std::string>& source, char delimiter) {
267 if (source.size() == 0) {
268 return std::string();
269 }
270 // Find length of the string to be returned to pre-allocate memory.
271 size_t source_string_length = 0;
272 for (size_t i = 0; i < source.size(); ++i) {
273 source_string_length += source[i].length();
274 }
275
276 // Build the joined string.
277 std::string joined_string;
278 joined_string.reserve(source_string_length + source.size() - 1);
279 for (size_t i = 0; i < source.size(); ++i) {
280 if (i != 0) {
281 joined_string += delimiter;
282 }
283 joined_string += source[i];
284 }
285 return joined_string;
286}
287
Yves Gerey665174f2018-06-19 15:03:05 +0200288size_t split(const std::string& source,
289 char delimiter,
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000290 std::vector<std::string>* fields) {
henrikg91d6ede2015-09-17 00:24:34 -0700291 RTC_DCHECK(fields);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000292 fields->clear();
293 size_t last = 0;
294 for (size_t i = 0; i < source.length(); ++i) {
295 if (source[i] == delimiter) {
296 fields->push_back(source.substr(last, i - last));
297 last = i + 1;
298 }
299 }
300 fields->push_back(source.substr(last, source.length() - last));
301 return fields->size();
302}
303
Jonas Olsson6b1985d2018-07-05 11:59:48 +0200304std::string ToString(const bool b) {
305 return b ? "true" : "false";
306}
307
308std::string ToString(const char* const s) {
309 return std::string(s);
310}
311std::string ToString(const std::string s) {
312 return s;
313}
314
315std::string ToString(const short s) {
316 char buf[32];
317 const int len = std::snprintf(&buf[0], arraysize(buf), "%hd", s);
318 RTC_DCHECK_LE(len, arraysize(buf));
319 return std::string(&buf[0], len);
320}
321std::string ToString(const unsigned short s) {
322 char buf[32];
323 const int len = std::snprintf(&buf[0], arraysize(buf), "%hu", s);
324 RTC_DCHECK_LE(len, arraysize(buf));
325 return std::string(&buf[0], len);
326}
327std::string ToString(const int s) {
328 char buf[32];
329 const int len = std::snprintf(&buf[0], arraysize(buf), "%d", s);
330 RTC_DCHECK_LE(len, arraysize(buf));
331 return std::string(&buf[0], len);
332}
333std::string ToString(const unsigned int s) {
334 char buf[32];
335 const int len = std::snprintf(&buf[0], arraysize(buf), "%u", s);
336 RTC_DCHECK_LE(len, arraysize(buf));
337 return std::string(&buf[0], len);
338}
339std::string ToString(const long int s) {
340 char buf[32];
341 const int len = std::snprintf(&buf[0], arraysize(buf), "%ld", s);
342 RTC_DCHECK_LE(len, arraysize(buf));
343 return std::string(&buf[0], len);
344}
345std::string ToString(const unsigned long int s) {
346 char buf[32];
347 const int len = std::snprintf(&buf[0], arraysize(buf), "%lu", s);
348 RTC_DCHECK_LE(len, arraysize(buf));
349 return std::string(&buf[0], len);
350}
351std::string ToString(const long long int s) {
352 char buf[32];
353 const int len = std::snprintf(&buf[0], arraysize(buf), "%lld", s);
354 RTC_DCHECK_LE(len, arraysize(buf));
355 return std::string(&buf[0], len);
356}
357std::string ToString(const unsigned long long int s) {
358 char buf[32];
359 const int len = std::snprintf(&buf[0], arraysize(buf), "%llu", s);
360 RTC_DCHECK_LE(len, arraysize(buf));
361 return std::string(&buf[0], len);
362}
363
364std::string ToString(const double d) {
365 char buf[32];
366 const int len = std::snprintf(&buf[0], arraysize(buf), "%g", d);
367 RTC_DCHECK_LE(len, arraysize(buf));
368 return std::string(&buf[0], len);
369}
370
Jonas Olsson88e18482018-09-03 10:15:08 +0200371std::string ToString(const long double d) {
372 char buf[32];
373 const int len = std::snprintf(&buf[0], arraysize(buf), "%Lg", d);
374 RTC_DCHECK_LE(len, arraysize(buf));
375 return std::string(&buf[0], len);
376}
377
Jonas Olsson6b1985d2018-07-05 11:59:48 +0200378std::string ToString(const void* const p) {
379 char buf[32];
380 const int len = std::snprintf(&buf[0], arraysize(buf), "%p", p);
381 RTC_DCHECK_LE(len, arraysize(buf));
382 return std::string(&buf[0], len);
383}
384
385bool FromString(const std::string& s, bool* b) {
386 if (s == "false") {
387 *b = false;
388 return true;
389 }
390 if (s == "true") {
391 *b = true;
392 return true;
393 }
394 return false;
395}
396
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000397} // namespace rtc