blob: da31ac08b3fd7207fa5eda8a0ccf7c523f027049 [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"
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000017
18namespace rtc {
19
20/////////////////////////////////////////////////////////////////////////////
21// String Encoding Utilities
22/////////////////////////////////////////////////////////////////////////////
23
Niels Möllere7e36012019-05-23 12:10:26 +020024namespace {
25const char HEX[] = "0123456789abcdef";
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000026
Niels Möllere7e36012019-05-23 12:10:26 +020027// Convert an unsigned value from 0 to 15 to the hex character equivalent...
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000028char hex_encode(unsigned char val) {
henrikg91d6ede2015-09-17 00:24:34 -070029 RTC_DCHECK_LT(val, 16);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000030 return (val < 16) ? HEX[val] : '!';
31}
32
Niels Möllere7e36012019-05-23 12:10:26 +020033// ...and vice-versa.
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000034bool hex_decode(char ch, unsigned char* val) {
35 if ((ch >= '0') && (ch <= '9')) {
36 *val = ch - '0';
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;
Niels Möller12048c72018-10-29 12:58:48 +010039 } else if ((ch >= 'a') && (ch <= 'f')) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000040 *val = (ch - 'a') + 10;
41 } else {
42 return false;
43 }
44 return true;
45}
46
Niels Möller74b373f2019-05-23 13:13:23 +020047size_t hex_encode_output_length(size_t srclen, char delimiter) {
48 return delimiter && srclen > 0 ? (srclen * 3 - 1) : (srclen * 2);
49}
50
51// hex_encode shows the hex representation of binary data in ascii, with
52// |delimiter| between bytes, or none if |delimiter| == 0.
53void hex_encode_with_delimiter(char* buffer,
54 const char* csource,
55 size_t srclen,
56 char delimiter) {
57 RTC_DCHECK(buffer);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000058
59 // Init and check bounds.
60 const unsigned char* bsource =
61 reinterpret_cast<const unsigned char*>(csource);
62 size_t srcpos = 0, bufpos = 0;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000063
64 while (srcpos < srclen) {
65 unsigned char ch = bsource[srcpos++];
Yves Gerey665174f2018-06-19 15:03:05 +020066 buffer[bufpos] = hex_encode((ch >> 4) & 0xF);
67 buffer[bufpos + 1] = hex_encode((ch)&0xF);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000068 bufpos += 2;
69
70 // Don't write a delimiter after the last byte.
71 if (delimiter && (srcpos < srclen)) {
72 buffer[bufpos] = delimiter;
73 ++bufpos;
74 }
75 }
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000076}
77
Niels Möllere7e36012019-05-23 12:10:26 +020078} // namespace
79
Peter Thatcher1cf6f812015-05-15 10:40:45 -070080std::string hex_encode(const std::string& str) {
81 return hex_encode(str.c_str(), str.size());
82}
83
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000084std::string hex_encode(const char* source, size_t srclen) {
85 return hex_encode_with_delimiter(source, srclen, 0);
86}
87
Yves Gerey665174f2018-06-19 15:03:05 +020088std::string hex_encode_with_delimiter(const char* source,
89 size_t srclen,
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000090 char delimiter) {
Niels Möller74b373f2019-05-23 13:13:23 +020091 std::string s(hex_encode_output_length(srclen, delimiter), 0);
92 // TODO(nisse): When we can use C++17, switch the below hack with begin to
93 // just s.data().
94 hex_encode_with_delimiter(&*s.begin(), source, srclen, delimiter);
95 return s;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000096}
97
Yves Gerey665174f2018-06-19 15:03:05 +020098size_t hex_decode(char* cbuffer,
99 size_t buflen,
100 const char* source,
101 size_t srclen) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000102 return hex_decode_with_delimiter(cbuffer, buflen, source, srclen, 0);
103}
104
Yves Gerey665174f2018-06-19 15:03:05 +0200105size_t hex_decode_with_delimiter(char* cbuffer,
106 size_t buflen,
107 const char* source,
108 size_t srclen,
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000109 char delimiter) {
Henrik Grunell84879882018-03-23 15:33:03 +0100110 RTC_DCHECK(cbuffer); // TODO(kwiberg): estimate output size
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000111 if (buflen == 0)
112 return 0;
113
114 // Init and bounds check.
115 unsigned char* bbuffer = reinterpret_cast<unsigned char*>(cbuffer);
116 size_t srcpos = 0, bufpos = 0;
117 size_t needed = (delimiter) ? (srclen + 1) / 3 : srclen / 2;
118 if (buflen < needed)
119 return 0;
120
121 while (srcpos < srclen) {
122 if ((srclen - srcpos) < 2) {
123 // This means we have an odd number of bytes.
124 return 0;
125 }
126
127 unsigned char h1, h2;
128 if (!hex_decode(source[srcpos], &h1) ||
129 !hex_decode(source[srcpos + 1], &h2))
130 return 0;
131
132 bbuffer[bufpos++] = (h1 << 4) | h2;
133 srcpos += 2;
134
135 // Remove the delimiter if needed.
136 if (delimiter && (srclen - srcpos) > 1) {
137 if (source[srcpos] != delimiter)
138 return 0;
139 ++srcpos;
140 }
141 }
142
143 return bufpos;
144}
145
146size_t hex_decode(char* buffer, size_t buflen, const std::string& source) {
147 return hex_decode_with_delimiter(buffer, buflen, source, 0);
148}
Yves Gerey665174f2018-06-19 15:03:05 +0200149size_t hex_decode_with_delimiter(char* buffer,
150 size_t buflen,
151 const std::string& source,
152 char delimiter) {
153 return hex_decode_with_delimiter(buffer, buflen, source.c_str(),
154 source.length(), delimiter);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000155}
156
Yves Gerey665174f2018-06-19 15:03:05 +0200157size_t tokenize(const std::string& source,
158 char delimiter,
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000159 std::vector<std::string>* fields) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000160 fields->clear();
161 size_t last = 0;
162 for (size_t i = 0; i < source.length(); ++i) {
163 if (source[i] == delimiter) {
164 if (i != last) {
165 fields->push_back(source.substr(last, i - last));
166 }
167 last = i + 1;
168 }
169 }
170 if (last != source.length()) {
171 fields->push_back(source.substr(last, source.length() - last));
172 }
173 return fields->size();
174}
175
deadbeef0a6c4ca2015-10-06 11:38:28 -0700176size_t tokenize_with_empty_tokens(const std::string& source,
177 char delimiter,
178 std::vector<std::string>* fields) {
179 fields->clear();
180 size_t last = 0;
181 for (size_t i = 0; i < source.length(); ++i) {
182 if (source[i] == delimiter) {
183 fields->push_back(source.substr(last, i - last));
184 last = i + 1;
185 }
186 }
187 fields->push_back(source.substr(last, source.length() - last));
188 return fields->size();
189}
190
Yves Gerey665174f2018-06-19 15:03:05 +0200191size_t tokenize_append(const std::string& source,
192 char delimiter,
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000193 std::vector<std::string>* fields) {
Yves Gerey665174f2018-06-19 15:03:05 +0200194 if (!fields)
195 return 0;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000196
197 std::vector<std::string> new_fields;
198 tokenize(source, delimiter, &new_fields);
199 fields->insert(fields->end(), new_fields.begin(), new_fields.end());
200 return fields->size();
201}
202
Yves Gerey665174f2018-06-19 15:03:05 +0200203size_t tokenize(const std::string& source,
204 char delimiter,
205 char start_mark,
206 char end_mark,
207 std::vector<std::string>* fields) {
208 if (!fields)
209 return 0;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000210 fields->clear();
211
212 std::string remain_source = source;
213 while (!remain_source.empty()) {
214 size_t start_pos = remain_source.find(start_mark);
Yves Gerey665174f2018-06-19 15:03:05 +0200215 if (std::string::npos == start_pos)
216 break;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000217 std::string pre_mark;
218 if (start_pos > 0) {
219 pre_mark = remain_source.substr(0, start_pos - 1);
220 }
221
222 ++start_pos;
223 size_t end_pos = remain_source.find(end_mark, start_pos);
Yves Gerey665174f2018-06-19 15:03:05 +0200224 if (std::string::npos == end_pos)
225 break;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000226
227 // We have found the matching marks. First tokenize the pre-mask. Then add
228 // the marked part as a single field. Finally, loop back for the post-mark.
229 tokenize_append(pre_mark, delimiter, fields);
230 fields->push_back(remain_source.substr(start_pos, end_pos - start_pos));
231 remain_source = remain_source.substr(end_pos + 1);
232 }
233
234 return tokenize_append(remain_source, delimiter, fields);
235}
236
Donald Curtis144d0182015-05-15 13:14:24 -0700237bool tokenize_first(const std::string& source,
238 const char delimiter,
239 std::string* token,
240 std::string* rest) {
Donald Curtis0e07f922015-05-15 09:21:23 -0700241 // Find the first delimiter
242 size_t left_pos = source.find(delimiter);
243 if (left_pos == std::string::npos) {
244 return false;
245 }
246
247 // Look for additional occurrances of delimiter.
248 size_t right_pos = left_pos + 1;
Donald Curtis144d0182015-05-15 13:14:24 -0700249 while (source[right_pos] == delimiter) {
Donald Curtis0e07f922015-05-15 09:21:23 -0700250 right_pos++;
251 }
252
253 *token = source.substr(0, left_pos);
254 *rest = source.substr(right_pos);
255 return true;
256}
257
Diogo Real7bd1f1b2017-09-08 12:50:41 -0700258std::string join(const std::vector<std::string>& source, char delimiter) {
259 if (source.size() == 0) {
260 return std::string();
261 }
262 // Find length of the string to be returned to pre-allocate memory.
263 size_t source_string_length = 0;
264 for (size_t i = 0; i < source.size(); ++i) {
265 source_string_length += source[i].length();
266 }
267
268 // Build the joined string.
269 std::string joined_string;
270 joined_string.reserve(source_string_length + source.size() - 1);
271 for (size_t i = 0; i < source.size(); ++i) {
272 if (i != 0) {
273 joined_string += delimiter;
274 }
275 joined_string += source[i];
276 }
277 return joined_string;
278}
279
Yves Gerey665174f2018-06-19 15:03:05 +0200280size_t split(const std::string& source,
281 char delimiter,
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000282 std::vector<std::string>* fields) {
henrikg91d6ede2015-09-17 00:24:34 -0700283 RTC_DCHECK(fields);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000284 fields->clear();
285 size_t last = 0;
286 for (size_t i = 0; i < source.length(); ++i) {
287 if (source[i] == delimiter) {
288 fields->push_back(source.substr(last, i - last));
289 last = i + 1;
290 }
291 }
292 fields->push_back(source.substr(last, source.length() - last));
293 return fields->size();
294}
295
Jonas Olsson6b1985d2018-07-05 11:59:48 +0200296std::string ToString(const bool b) {
297 return b ? "true" : "false";
298}
299
300std::string ToString(const char* const s) {
301 return std::string(s);
302}
303std::string ToString(const std::string s) {
304 return s;
305}
306
307std::string ToString(const short s) {
308 char buf[32];
309 const int len = std::snprintf(&buf[0], arraysize(buf), "%hd", s);
310 RTC_DCHECK_LE(len, arraysize(buf));
311 return std::string(&buf[0], len);
312}
313std::string ToString(const unsigned short s) {
314 char buf[32];
315 const int len = std::snprintf(&buf[0], arraysize(buf), "%hu", s);
316 RTC_DCHECK_LE(len, arraysize(buf));
317 return std::string(&buf[0], len);
318}
319std::string ToString(const int s) {
320 char buf[32];
321 const int len = std::snprintf(&buf[0], arraysize(buf), "%d", s);
322 RTC_DCHECK_LE(len, arraysize(buf));
323 return std::string(&buf[0], len);
324}
325std::string ToString(const unsigned int s) {
326 char buf[32];
327 const int len = std::snprintf(&buf[0], arraysize(buf), "%u", s);
328 RTC_DCHECK_LE(len, arraysize(buf));
329 return std::string(&buf[0], len);
330}
331std::string ToString(const long int s) {
332 char buf[32];
333 const int len = std::snprintf(&buf[0], arraysize(buf), "%ld", s);
334 RTC_DCHECK_LE(len, arraysize(buf));
335 return std::string(&buf[0], len);
336}
337std::string ToString(const unsigned long int s) {
338 char buf[32];
339 const int len = std::snprintf(&buf[0], arraysize(buf), "%lu", s);
340 RTC_DCHECK_LE(len, arraysize(buf));
341 return std::string(&buf[0], len);
342}
343std::string ToString(const long long int s) {
344 char buf[32];
345 const int len = std::snprintf(&buf[0], arraysize(buf), "%lld", s);
346 RTC_DCHECK_LE(len, arraysize(buf));
347 return std::string(&buf[0], len);
348}
349std::string ToString(const unsigned long long int s) {
350 char buf[32];
351 const int len = std::snprintf(&buf[0], arraysize(buf), "%llu", s);
352 RTC_DCHECK_LE(len, arraysize(buf));
353 return std::string(&buf[0], len);
354}
355
356std::string ToString(const double d) {
357 char buf[32];
358 const int len = std::snprintf(&buf[0], arraysize(buf), "%g", d);
359 RTC_DCHECK_LE(len, arraysize(buf));
360 return std::string(&buf[0], len);
361}
362
Jonas Olsson88e18482018-09-03 10:15:08 +0200363std::string ToString(const long double d) {
364 char buf[32];
365 const int len = std::snprintf(&buf[0], arraysize(buf), "%Lg", d);
366 RTC_DCHECK_LE(len, arraysize(buf));
367 return std::string(&buf[0], len);
368}
369
Jonas Olsson6b1985d2018-07-05 11:59:48 +0200370std::string ToString(const void* const p) {
371 char buf[32];
372 const int len = std::snprintf(&buf[0], arraysize(buf), "%p", p);
373 RTC_DCHECK_LE(len, arraysize(buf));
374 return std::string(&buf[0], len);
375}
376
377bool FromString(const std::string& s, bool* b) {
378 if (s == "false") {
379 *b = false;
380 return true;
381 }
382 if (s == "true") {
383 *b = true;
384 return true;
385 }
386 return false;
387}
388
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000389} // namespace rtc