blob: fa99c7a439b7bdb41e236886e46524b7a82ce5a4 [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
Ali Tofigh7fa90572022-03-17 15:47:49 +010015#include "absl/strings/string_view.h"
Jonas Olsson6b1985d2018-07-05 11:59:48 +020016#include "rtc_base/arraysize.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020017#include "rtc_base/checks.h"
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000018
19namespace rtc {
20
21/////////////////////////////////////////////////////////////////////////////
22// String Encoding Utilities
23/////////////////////////////////////////////////////////////////////////////
24
Niels Möllere7e36012019-05-23 12:10:26 +020025namespace {
26const char HEX[] = "0123456789abcdef";
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000027
Niels Möllere7e36012019-05-23 12:10:26 +020028// Convert an unsigned value from 0 to 15 to the hex character equivalent...
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000029char hex_encode(unsigned char val) {
henrikg91d6ede2015-09-17 00:24:34 -070030 RTC_DCHECK_LT(val, 16);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000031 return (val < 16) ? HEX[val] : '!';
32}
33
Niels Möllere7e36012019-05-23 12:10:26 +020034// ...and vice-versa.
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000035bool hex_decode(char ch, unsigned char* val) {
36 if ((ch >= '0') && (ch <= '9')) {
37 *val = ch - '0';
Niels Möller12048c72018-10-29 12:58:48 +010038 } else if ((ch >= 'A') && (ch <= 'F')) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000039 *val = (ch - 'A') + 10;
Niels Möller12048c72018-10-29 12:58:48 +010040 } else if ((ch >= 'a') && (ch <= 'f')) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000041 *val = (ch - 'a') + 10;
42 } else {
43 return false;
44 }
45 return true;
46}
47
Niels Möllerf25df352019-05-24 09:14:13 +020048size_t hex_encode_output_length(size_t srclen, char delimiter) {
49 return delimiter && srclen > 0 ? (srclen * 3 - 1) : (srclen * 2);
50}
51
52// hex_encode shows the hex representation of binary data in ascii, with
Artem Titov96e3b992021-07-26 16:03:14 +020053// `delimiter` between bytes, or none if `delimiter` == 0.
Niels Möllerf25df352019-05-24 09:14:13 +020054void hex_encode_with_delimiter(char* buffer,
55 const char* csource,
56 size_t srclen,
57 char delimiter) {
58 RTC_DCHECK(buffer);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000059
60 // Init and check bounds.
61 const unsigned char* bsource =
62 reinterpret_cast<const unsigned char*>(csource);
63 size_t srcpos = 0, bufpos = 0;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000064
65 while (srcpos < srclen) {
66 unsigned char ch = bsource[srcpos++];
Yves Gerey665174f2018-06-19 15:03:05 +020067 buffer[bufpos] = hex_encode((ch >> 4) & 0xF);
68 buffer[bufpos + 1] = hex_encode((ch)&0xF);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000069 bufpos += 2;
70
71 // Don't write a delimiter after the last byte.
72 if (delimiter && (srcpos < srclen)) {
73 buffer[bufpos] = delimiter;
74 ++bufpos;
75 }
76 }
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000077}
78
Niels Möllere7e36012019-05-23 12:10:26 +020079} // namespace
80
Ali Tofigh7fa90572022-03-17 15:47:49 +010081std::string hex_encode(absl::string_view str) {
82 return hex_encode(str.data(), str.size());
Peter Thatcher1cf6f812015-05-15 10:40:45 -070083}
84
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000085std::string hex_encode(const char* source, size_t srclen) {
86 return hex_encode_with_delimiter(source, srclen, 0);
87}
88
Yves Gerey665174f2018-06-19 15:03:05 +020089std::string hex_encode_with_delimiter(const char* source,
90 size_t srclen,
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000091 char delimiter) {
Niels Möllerf25df352019-05-24 09:14:13 +020092 std::string s(hex_encode_output_length(srclen, delimiter), 0);
Kimmo Kinnunen022a7c82019-08-29 16:22:39 +030093 hex_encode_with_delimiter(&s[0], source, srclen, delimiter);
Niels Möllerf25df352019-05-24 09:14:13 +020094 return s;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000095}
96
Yves Gerey665174f2018-06-19 15:03:05 +020097size_t hex_decode(char* cbuffer,
98 size_t buflen,
99 const char* source,
100 size_t srclen) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000101 return hex_decode_with_delimiter(cbuffer, buflen, source, srclen, 0);
102}
103
Yves Gerey665174f2018-06-19 15:03:05 +0200104size_t hex_decode_with_delimiter(char* cbuffer,
105 size_t buflen,
106 const char* source,
107 size_t srclen,
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000108 char delimiter) {
Henrik Grunell84879882018-03-23 15:33:03 +0100109 RTC_DCHECK(cbuffer); // TODO(kwiberg): estimate output size
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000110 if (buflen == 0)
111 return 0;
112
113 // Init and bounds check.
114 unsigned char* bbuffer = reinterpret_cast<unsigned char*>(cbuffer);
115 size_t srcpos = 0, bufpos = 0;
116 size_t needed = (delimiter) ? (srclen + 1) / 3 : srclen / 2;
117 if (buflen < needed)
118 return 0;
119
120 while (srcpos < srclen) {
121 if ((srclen - srcpos) < 2) {
122 // This means we have an odd number of bytes.
123 return 0;
124 }
125
126 unsigned char h1, h2;
127 if (!hex_decode(source[srcpos], &h1) ||
128 !hex_decode(source[srcpos + 1], &h2))
129 return 0;
130
131 bbuffer[bufpos++] = (h1 << 4) | h2;
132 srcpos += 2;
133
134 // Remove the delimiter if needed.
135 if (delimiter && (srclen - srcpos) > 1) {
136 if (source[srcpos] != delimiter)
137 return 0;
138 ++srcpos;
139 }
140 }
141
142 return bufpos;
143}
144
Ali Tofigh7fa90572022-03-17 15:47:49 +0100145size_t hex_decode(char* buffer, size_t buflen, absl::string_view source) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000146 return hex_decode_with_delimiter(buffer, buflen, source, 0);
147}
Yves Gerey665174f2018-06-19 15:03:05 +0200148size_t hex_decode_with_delimiter(char* buffer,
149 size_t buflen,
Ali Tofigh7fa90572022-03-17 15:47:49 +0100150 absl::string_view source,
Yves Gerey665174f2018-06-19 15:03:05 +0200151 char delimiter) {
Ali Tofigh7fa90572022-03-17 15:47:49 +0100152 return hex_decode_with_delimiter(buffer, buflen, source.data(),
Yves Gerey665174f2018-06-19 15:03:05 +0200153 source.length(), delimiter);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000154}
155
Niels Möller44203802021-09-16 15:39:16 +0200156size_t tokenize(absl::string_view source,
Yves Gerey665174f2018-06-19 15:03:05 +0200157 char delimiter,
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000158 std::vector<std::string>* fields) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000159 fields->clear();
160 size_t last = 0;
161 for (size_t i = 0; i < source.length(); ++i) {
162 if (source[i] == delimiter) {
163 if (i != last) {
Niels Möller44203802021-09-16 15:39:16 +0200164 fields->emplace_back(source.substr(last, i - last));
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000165 }
166 last = i + 1;
167 }
168 }
169 if (last != source.length()) {
Niels Möller44203802021-09-16 15:39:16 +0200170 fields->emplace_back(source.substr(last, source.length() - last));
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000171 }
172 return fields->size();
173}
174
Niels Möller44203802021-09-16 15:39:16 +0200175bool tokenize_first(absl::string_view source,
Donald Curtis144d0182015-05-15 13:14:24 -0700176 const char delimiter,
177 std::string* token,
178 std::string* rest) {
Donald Curtis0e07f922015-05-15 09:21:23 -0700179 // Find the first delimiter
180 size_t left_pos = source.find(delimiter);
Ali Tofigh7fa90572022-03-17 15:47:49 +0100181 if (left_pos == absl::string_view::npos) {
Donald Curtis0e07f922015-05-15 09:21:23 -0700182 return false;
183 }
184
185 // Look for additional occurrances of delimiter.
186 size_t right_pos = left_pos + 1;
Niels Möller44203802021-09-16 15:39:16 +0200187 while (right_pos < source.size() && source[right_pos] == delimiter) {
Donald Curtis0e07f922015-05-15 09:21:23 -0700188 right_pos++;
189 }
190
Niels Möller44203802021-09-16 15:39:16 +0200191 *token = std::string(source.substr(0, left_pos));
192 *rest = std::string(source.substr(right_pos));
Donald Curtis0e07f922015-05-15 09:21:23 -0700193 return true;
194}
195
Diogo Real7bd1f1b2017-09-08 12:50:41 -0700196std::string join(const std::vector<std::string>& source, char delimiter) {
197 if (source.size() == 0) {
198 return std::string();
199 }
200 // Find length of the string to be returned to pre-allocate memory.
201 size_t source_string_length = 0;
202 for (size_t i = 0; i < source.size(); ++i) {
203 source_string_length += source[i].length();
204 }
205
206 // Build the joined string.
207 std::string joined_string;
208 joined_string.reserve(source_string_length + source.size() - 1);
209 for (size_t i = 0; i < source.size(); ++i) {
210 if (i != 0) {
211 joined_string += delimiter;
212 }
213 joined_string += source[i];
214 }
215 return joined_string;
216}
217
Niels Möller2d3186e2022-01-24 14:15:03 +0100218std::vector<absl::string_view> split(absl::string_view source, char delimiter) {
219 std::vector<absl::string_view> fields;
220 size_t last = 0;
221 for (size_t i = 0; i < source.length(); ++i) {
222 if (source[i] == delimiter) {
223 fields.push_back(source.substr(last, i - last));
224 last = i + 1;
225 }
226 }
227 fields.push_back(source.substr(last));
228 return fields;
229}
230
Niels Möller44203802021-09-16 15:39:16 +0200231size_t split(absl::string_view source,
Yves Gerey665174f2018-06-19 15:03:05 +0200232 char delimiter,
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000233 std::vector<std::string>* fields) {
henrikg91d6ede2015-09-17 00:24:34 -0700234 RTC_DCHECK(fields);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000235 fields->clear();
Niels Möller2d3186e2022-01-24 14:15:03 +0100236 for (const absl::string_view field_view : split(source, delimiter)) {
237 fields->emplace_back(field_view);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000238 }
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000239 return fields->size();
240}
241
Jonas Olsson6b1985d2018-07-05 11:59:48 +0200242std::string ToString(const bool b) {
243 return b ? "true" : "false";
244}
245
246std::string ToString(const char* const s) {
247 return std::string(s);
248}
Ali Tofigh7fa90572022-03-17 15:47:49 +0100249
250std::string ToString(absl::string_view s) {
251 return std::string(s);
Jonas Olsson6b1985d2018-07-05 11:59:48 +0200252}
253
254std::string ToString(const short s) {
255 char buf[32];
256 const int len = std::snprintf(&buf[0], arraysize(buf), "%hd", s);
257 RTC_DCHECK_LE(len, arraysize(buf));
258 return std::string(&buf[0], len);
259}
260std::string ToString(const unsigned short s) {
261 char buf[32];
262 const int len = std::snprintf(&buf[0], arraysize(buf), "%hu", s);
263 RTC_DCHECK_LE(len, arraysize(buf));
264 return std::string(&buf[0], len);
265}
266std::string ToString(const int s) {
267 char buf[32];
268 const int len = std::snprintf(&buf[0], arraysize(buf), "%d", s);
269 RTC_DCHECK_LE(len, arraysize(buf));
270 return std::string(&buf[0], len);
271}
272std::string ToString(const unsigned int s) {
273 char buf[32];
274 const int len = std::snprintf(&buf[0], arraysize(buf), "%u", s);
275 RTC_DCHECK_LE(len, arraysize(buf));
276 return std::string(&buf[0], len);
277}
278std::string ToString(const long int s) {
279 char buf[32];
280 const int len = std::snprintf(&buf[0], arraysize(buf), "%ld", s);
281 RTC_DCHECK_LE(len, arraysize(buf));
282 return std::string(&buf[0], len);
283}
284std::string ToString(const unsigned long int s) {
285 char buf[32];
286 const int len = std::snprintf(&buf[0], arraysize(buf), "%lu", s);
287 RTC_DCHECK_LE(len, arraysize(buf));
288 return std::string(&buf[0], len);
289}
290std::string ToString(const long long int s) {
291 char buf[32];
292 const int len = std::snprintf(&buf[0], arraysize(buf), "%lld", s);
293 RTC_DCHECK_LE(len, arraysize(buf));
294 return std::string(&buf[0], len);
295}
296std::string ToString(const unsigned long long int s) {
297 char buf[32];
298 const int len = std::snprintf(&buf[0], arraysize(buf), "%llu", s);
299 RTC_DCHECK_LE(len, arraysize(buf));
300 return std::string(&buf[0], len);
301}
302
303std::string ToString(const double d) {
304 char buf[32];
305 const int len = std::snprintf(&buf[0], arraysize(buf), "%g", d);
306 RTC_DCHECK_LE(len, arraysize(buf));
307 return std::string(&buf[0], len);
308}
309
Jonas Olsson88e18482018-09-03 10:15:08 +0200310std::string ToString(const long double d) {
311 char buf[32];
312 const int len = std::snprintf(&buf[0], arraysize(buf), "%Lg", d);
313 RTC_DCHECK_LE(len, arraysize(buf));
314 return std::string(&buf[0], len);
315}
316
Jonas Olsson6b1985d2018-07-05 11:59:48 +0200317std::string ToString(const void* const p) {
318 char buf[32];
319 const int len = std::snprintf(&buf[0], arraysize(buf), "%p", p);
320 RTC_DCHECK_LE(len, arraysize(buf));
321 return std::string(&buf[0], len);
322}
323
324bool FromString(const std::string& s, bool* b) {
325 if (s == "false") {
326 *b = false;
327 return true;
328 }
329 if (s == "true") {
330 *b = true;
331 return true;
332 }
333 return false;
334}
335
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000336} // namespace rtc