blob: 136b853170b8fa2e305da8a161ab848f58afa082 [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"
Ali Tofighfd6a4d62022-03-31 10:36:48 +020016#include "api/array_view.h"
Jonas Olsson6b1985d2018-07-05 11:59:48 +020017#include "rtc_base/arraysize.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020018#include "rtc_base/checks.h"
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000019
20namespace rtc {
21
22/////////////////////////////////////////////////////////////////////////////
23// String Encoding Utilities
24/////////////////////////////////////////////////////////////////////////////
25
Niels Möllere7e36012019-05-23 12:10:26 +020026namespace {
27const char HEX[] = "0123456789abcdef";
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000028
Niels Möllere7e36012019-05-23 12:10:26 +020029// Convert an unsigned value from 0 to 15 to the hex character equivalent...
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000030char hex_encode(unsigned char val) {
henrikg91d6ede2015-09-17 00:24:34 -070031 RTC_DCHECK_LT(val, 16);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000032 return (val < 16) ? HEX[val] : '!';
33}
34
Niels Möllere7e36012019-05-23 12:10:26 +020035// ...and vice-versa.
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000036bool hex_decode(char ch, unsigned char* val) {
37 if ((ch >= '0') && (ch <= '9')) {
38 *val = ch - '0';
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;
Niels Möller12048c72018-10-29 12:58:48 +010041 } else if ((ch >= 'a') && (ch <= 'f')) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000042 *val = (ch - 'a') + 10;
43 } else {
44 return false;
45 }
46 return true;
47}
48
Niels Möllerf25df352019-05-24 09:14:13 +020049size_t hex_encode_output_length(size_t srclen, char delimiter) {
50 return delimiter && srclen > 0 ? (srclen * 3 - 1) : (srclen * 2);
51}
52
53// hex_encode shows the hex representation of binary data in ascii, with
Artem Titov96e3b992021-07-26 16:03:14 +020054// `delimiter` between bytes, or none if `delimiter` == 0.
Niels Möllerf25df352019-05-24 09:14:13 +020055void hex_encode_with_delimiter(char* buffer,
Ali Tofighfd6a4d62022-03-31 10:36:48 +020056 absl::string_view source,
Niels Möllerf25df352019-05-24 09:14:13 +020057 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 =
Ali Tofighfd6a4d62022-03-31 10:36:48 +020062 reinterpret_cast<const unsigned char*>(source.data());
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000063 size_t srcpos = 0, bufpos = 0;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000064
Ali Tofighfd6a4d62022-03-31 10:36:48 +020065 size_t srclen = source.length();
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000066 while (srcpos < srclen) {
67 unsigned char ch = bsource[srcpos++];
Yves Gerey665174f2018-06-19 15:03:05 +020068 buffer[bufpos] = hex_encode((ch >> 4) & 0xF);
69 buffer[bufpos + 1] = hex_encode((ch)&0xF);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000070 bufpos += 2;
71
72 // Don't write a delimiter after the last byte.
73 if (delimiter && (srcpos < srclen)) {
74 buffer[bufpos] = delimiter;
75 ++bufpos;
76 }
77 }
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000078}
79
Niels Möllere7e36012019-05-23 12:10:26 +020080} // namespace
81
Ali Tofigh7fa90572022-03-17 15:47:49 +010082std::string hex_encode(absl::string_view str) {
Ali Tofighfd6a4d62022-03-31 10:36:48 +020083 return hex_encode_with_delimiter(str, 0);
Peter Thatcher1cf6f812015-05-15 10:40:45 -070084}
85
Ali Tofighfd6a4d62022-03-31 10:36:48 +020086std::string hex_encode_with_delimiter(absl::string_view source,
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000087 char delimiter) {
Ali Tofighfd6a4d62022-03-31 10:36:48 +020088 std::string s(hex_encode_output_length(source.length(), delimiter), 0);
89 hex_encode_with_delimiter(&s[0], source, delimiter);
Niels Möllerf25df352019-05-24 09:14:13 +020090 return s;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000091}
92
Ali Tofighfd6a4d62022-03-31 10:36:48 +020093size_t hex_decode_with_delimiter(ArrayView<char> cbuffer,
94 absl::string_view source,
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000095 char delimiter) {
Ali Tofighfd6a4d62022-03-31 10:36:48 +020096 if (cbuffer.empty())
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000097 return 0;
98
99 // Init and bounds check.
Ali Tofighfd6a4d62022-03-31 10:36:48 +0200100 unsigned char* bbuffer = reinterpret_cast<unsigned char*>(cbuffer.data());
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000101 size_t srcpos = 0, bufpos = 0;
Ali Tofighfd6a4d62022-03-31 10:36:48 +0200102 size_t srclen = source.length();
103
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000104 size_t needed = (delimiter) ? (srclen + 1) / 3 : srclen / 2;
Ali Tofighfd6a4d62022-03-31 10:36:48 +0200105 if (cbuffer.size() < needed)
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000106 return 0;
107
108 while (srcpos < srclen) {
109 if ((srclen - srcpos) < 2) {
110 // This means we have an odd number of bytes.
111 return 0;
112 }
113
114 unsigned char h1, h2;
115 if (!hex_decode(source[srcpos], &h1) ||
116 !hex_decode(source[srcpos + 1], &h2))
117 return 0;
118
119 bbuffer[bufpos++] = (h1 << 4) | h2;
120 srcpos += 2;
121
122 // Remove the delimiter if needed.
123 if (delimiter && (srclen - srcpos) > 1) {
124 if (source[srcpos] != delimiter)
125 return 0;
126 ++srcpos;
127 }
128 }
129
130 return bufpos;
131}
132
Yves Gerey665174f2018-06-19 15:03:05 +0200133size_t hex_decode_with_delimiter(char* buffer,
134 size_t buflen,
Ali Tofigh7fa90572022-03-17 15:47:49 +0100135 absl::string_view source,
Yves Gerey665174f2018-06-19 15:03:05 +0200136 char delimiter) {
Ali Tofighfd6a4d62022-03-31 10:36:48 +0200137 return hex_decode_with_delimiter(ArrayView<char>(buffer, buflen), source,
138 delimiter);
139}
140
141size_t hex_decode(ArrayView<char> buffer, absl::string_view source) {
142 return hex_decode_with_delimiter(buffer, source, 0);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000143}
144
Niels Möller44203802021-09-16 15:39:16 +0200145size_t tokenize(absl::string_view source,
Yves Gerey665174f2018-06-19 15:03:05 +0200146 char delimiter,
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000147 std::vector<std::string>* fields) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000148 fields->clear();
149 size_t last = 0;
150 for (size_t i = 0; i < source.length(); ++i) {
151 if (source[i] == delimiter) {
152 if (i != last) {
Niels Möller44203802021-09-16 15:39:16 +0200153 fields->emplace_back(source.substr(last, i - last));
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000154 }
155 last = i + 1;
156 }
157 }
158 if (last != source.length()) {
Niels Möller44203802021-09-16 15:39:16 +0200159 fields->emplace_back(source.substr(last, source.length() - last));
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000160 }
161 return fields->size();
162}
163
Niels Möller44203802021-09-16 15:39:16 +0200164bool tokenize_first(absl::string_view source,
Donald Curtis144d0182015-05-15 13:14:24 -0700165 const char delimiter,
166 std::string* token,
167 std::string* rest) {
Donald Curtis0e07f922015-05-15 09:21:23 -0700168 // Find the first delimiter
169 size_t left_pos = source.find(delimiter);
Ali Tofigh7fa90572022-03-17 15:47:49 +0100170 if (left_pos == absl::string_view::npos) {
Donald Curtis0e07f922015-05-15 09:21:23 -0700171 return false;
172 }
173
174 // Look for additional occurrances of delimiter.
175 size_t right_pos = left_pos + 1;
Niels Möller44203802021-09-16 15:39:16 +0200176 while (right_pos < source.size() && source[right_pos] == delimiter) {
Donald Curtis0e07f922015-05-15 09:21:23 -0700177 right_pos++;
178 }
179
Niels Möller44203802021-09-16 15:39:16 +0200180 *token = std::string(source.substr(0, left_pos));
181 *rest = std::string(source.substr(right_pos));
Donald Curtis0e07f922015-05-15 09:21:23 -0700182 return true;
183}
184
Diogo Real7bd1f1b2017-09-08 12:50:41 -0700185std::string join(const std::vector<std::string>& source, char delimiter) {
186 if (source.size() == 0) {
187 return std::string();
188 }
189 // Find length of the string to be returned to pre-allocate memory.
190 size_t source_string_length = 0;
191 for (size_t i = 0; i < source.size(); ++i) {
192 source_string_length += source[i].length();
193 }
194
195 // Build the joined string.
196 std::string joined_string;
197 joined_string.reserve(source_string_length + source.size() - 1);
198 for (size_t i = 0; i < source.size(); ++i) {
199 if (i != 0) {
200 joined_string += delimiter;
201 }
202 joined_string += source[i];
203 }
204 return joined_string;
205}
206
Niels Möller2d3186e2022-01-24 14:15:03 +0100207std::vector<absl::string_view> split(absl::string_view source, char delimiter) {
208 std::vector<absl::string_view> fields;
209 size_t last = 0;
210 for (size_t i = 0; i < source.length(); ++i) {
211 if (source[i] == delimiter) {
212 fields.push_back(source.substr(last, i - last));
213 last = i + 1;
214 }
215 }
216 fields.push_back(source.substr(last));
217 return fields;
218}
219
Niels Möller44203802021-09-16 15:39:16 +0200220size_t split(absl::string_view source,
Yves Gerey665174f2018-06-19 15:03:05 +0200221 char delimiter,
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000222 std::vector<std::string>* fields) {
henrikg91d6ede2015-09-17 00:24:34 -0700223 RTC_DCHECK(fields);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000224 fields->clear();
Niels Möller2d3186e2022-01-24 14:15:03 +0100225 for (const absl::string_view field_view : split(source, delimiter)) {
226 fields->emplace_back(field_view);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000227 }
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000228 return fields->size();
229}
230
Jonas Olsson6b1985d2018-07-05 11:59:48 +0200231std::string ToString(const bool b) {
232 return b ? "true" : "false";
233}
234
Ali Tofighfd6a4d62022-03-31 10:36:48 +0200235std::string ToString(absl::string_view s) {
Jonas Olsson6b1985d2018-07-05 11:59:48 +0200236 return std::string(s);
237}
Ali Tofigh7fa90572022-03-17 15:47:49 +0100238
Ali Tofighfd6a4d62022-03-31 10:36:48 +0200239std::string ToString(const char* s) {
Ali Tofigh7fa90572022-03-17 15:47:49 +0100240 return std::string(s);
Jonas Olsson6b1985d2018-07-05 11:59:48 +0200241}
242
243std::string ToString(const short s) {
244 char buf[32];
245 const int len = std::snprintf(&buf[0], arraysize(buf), "%hd", s);
246 RTC_DCHECK_LE(len, arraysize(buf));
247 return std::string(&buf[0], len);
248}
249std::string ToString(const unsigned short s) {
250 char buf[32];
251 const int len = std::snprintf(&buf[0], arraysize(buf), "%hu", s);
252 RTC_DCHECK_LE(len, arraysize(buf));
253 return std::string(&buf[0], len);
254}
255std::string ToString(const int s) {
256 char buf[32];
257 const int len = std::snprintf(&buf[0], arraysize(buf), "%d", s);
258 RTC_DCHECK_LE(len, arraysize(buf));
259 return std::string(&buf[0], len);
260}
261std::string ToString(const unsigned int s) {
262 char buf[32];
263 const int len = std::snprintf(&buf[0], arraysize(buf), "%u", s);
264 RTC_DCHECK_LE(len, arraysize(buf));
265 return std::string(&buf[0], len);
266}
267std::string ToString(const long int s) {
268 char buf[32];
269 const int len = std::snprintf(&buf[0], arraysize(buf), "%ld", s);
270 RTC_DCHECK_LE(len, arraysize(buf));
271 return std::string(&buf[0], len);
272}
273std::string ToString(const unsigned long int s) {
274 char buf[32];
275 const int len = std::snprintf(&buf[0], arraysize(buf), "%lu", s);
276 RTC_DCHECK_LE(len, arraysize(buf));
277 return std::string(&buf[0], len);
278}
279std::string ToString(const long long int s) {
280 char buf[32];
281 const int len = std::snprintf(&buf[0], arraysize(buf), "%lld", s);
282 RTC_DCHECK_LE(len, arraysize(buf));
283 return std::string(&buf[0], len);
284}
285std::string ToString(const unsigned long long int s) {
286 char buf[32];
287 const int len = std::snprintf(&buf[0], arraysize(buf), "%llu", s);
288 RTC_DCHECK_LE(len, arraysize(buf));
289 return std::string(&buf[0], len);
290}
291
292std::string ToString(const double d) {
293 char buf[32];
294 const int len = std::snprintf(&buf[0], arraysize(buf), "%g", d);
295 RTC_DCHECK_LE(len, arraysize(buf));
296 return std::string(&buf[0], len);
297}
298
Jonas Olsson88e18482018-09-03 10:15:08 +0200299std::string ToString(const long double d) {
300 char buf[32];
301 const int len = std::snprintf(&buf[0], arraysize(buf), "%Lg", d);
302 RTC_DCHECK_LE(len, arraysize(buf));
303 return std::string(&buf[0], len);
304}
305
Jonas Olsson6b1985d2018-07-05 11:59:48 +0200306std::string ToString(const void* const p) {
307 char buf[32];
308 const int len = std::snprintf(&buf[0], arraysize(buf), "%p", p);
309 RTC_DCHECK_LE(len, arraysize(buf));
310 return std::string(&buf[0], len);
311}
312
Ali Tofighfd6a4d62022-03-31 10:36:48 +0200313bool FromString(absl::string_view s, bool* b) {
Jonas Olsson6b1985d2018-07-05 11:59:48 +0200314 if (s == "false") {
315 *b = false;
316 return true;
317 }
318 if (s == "true") {
319 *b = true;
320 return true;
321 }
322 return false;
323}
324
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000325} // namespace rtc