1 /*
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
11 #include "rtc_base/string_encode.h"
12
13 #include <cstdio>
14
15 #include "rtc_base/arraysize.h"
16 #include "rtc_base/checks.h"
17
18 namespace rtc {
19
20 /////////////////////////////////////////////////////////////////////////////
21 // String Encoding Utilities
22 /////////////////////////////////////////////////////////////////////////////
23
24 namespace {
25 const char HEX[] = "0123456789abcdef";
26
27 // Convert an unsigned value from 0 to 15 to the hex character equivalent...
hex_encode(unsigned char val)28 char hex_encode(unsigned char val) {
29 RTC_DCHECK_LT(val, 16);
30 return (val < 16) ? HEX[val] : '!';
31 }
32
33 // ...and vice-versa.
hex_decode(char ch,unsigned char * val)34 bool hex_decode(char ch, unsigned char* val) {
35 if ((ch >= '0') && (ch <= '9')) {
36 *val = ch - '0';
37 } else if ((ch >= 'A') && (ch <= 'F')) {
38 *val = (ch - 'A') + 10;
39 } else if ((ch >= 'a') && (ch <= 'f')) {
40 *val = (ch - 'a') + 10;
41 } else {
42 return false;
43 }
44 return true;
45 }
46
hex_encode_output_length(size_t srclen,char delimiter)47 size_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.
hex_encode_with_delimiter(char * buffer,const char * csource,size_t srclen,char delimiter)53 void hex_encode_with_delimiter(char* buffer,
54 const char* csource,
55 size_t srclen,
56 char delimiter) {
57 RTC_DCHECK(buffer);
58
59 // Init and check bounds.
60 const unsigned char* bsource =
61 reinterpret_cast<const unsigned char*>(csource);
62 size_t srcpos = 0, bufpos = 0;
63
64 while (srcpos < srclen) {
65 unsigned char ch = bsource[srcpos++];
66 buffer[bufpos] = hex_encode((ch >> 4) & 0xF);
67 buffer[bufpos + 1] = hex_encode((ch)&0xF);
68 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 }
76 }
77
78 } // namespace
79
hex_encode(const std::string & str)80 std::string hex_encode(const std::string& str) {
81 return hex_encode(str.c_str(), str.size());
82 }
83
hex_encode(const char * source,size_t srclen)84 std::string hex_encode(const char* source, size_t srclen) {
85 return hex_encode_with_delimiter(source, srclen, 0);
86 }
87
hex_encode_with_delimiter(const char * source,size_t srclen,char delimiter)88 std::string hex_encode_with_delimiter(const char* source,
89 size_t srclen,
90 char delimiter) {
91 std::string s(hex_encode_output_length(srclen, delimiter), 0);
92 hex_encode_with_delimiter(&s[0], source, srclen, delimiter);
93 return s;
94 }
95
hex_decode(char * cbuffer,size_t buflen,const char * source,size_t srclen)96 size_t hex_decode(char* cbuffer,
97 size_t buflen,
98 const char* source,
99 size_t srclen) {
100 return hex_decode_with_delimiter(cbuffer, buflen, source, srclen, 0);
101 }
102
hex_decode_with_delimiter(char * cbuffer,size_t buflen,const char * source,size_t srclen,char delimiter)103 size_t hex_decode_with_delimiter(char* cbuffer,
104 size_t buflen,
105 const char* source,
106 size_t srclen,
107 char delimiter) {
108 RTC_DCHECK(cbuffer); // TODO(kwiberg): estimate output size
109 if (buflen == 0)
110 return 0;
111
112 // Init and bounds check.
113 unsigned char* bbuffer = reinterpret_cast<unsigned char*>(cbuffer);
114 size_t srcpos = 0, bufpos = 0;
115 size_t needed = (delimiter) ? (srclen + 1) / 3 : srclen / 2;
116 if (buflen < needed)
117 return 0;
118
119 while (srcpos < srclen) {
120 if ((srclen - srcpos) < 2) {
121 // This means we have an odd number of bytes.
122 return 0;
123 }
124
125 unsigned char h1, h2;
126 if (!hex_decode(source[srcpos], &h1) ||
127 !hex_decode(source[srcpos + 1], &h2))
128 return 0;
129
130 bbuffer[bufpos++] = (h1 << 4) | h2;
131 srcpos += 2;
132
133 // Remove the delimiter if needed.
134 if (delimiter && (srclen - srcpos) > 1) {
135 if (source[srcpos] != delimiter)
136 return 0;
137 ++srcpos;
138 }
139 }
140
141 return bufpos;
142 }
143
hex_decode(char * buffer,size_t buflen,const std::string & source)144 size_t hex_decode(char* buffer, size_t buflen, const std::string& source) {
145 return hex_decode_with_delimiter(buffer, buflen, source, 0);
146 }
hex_decode_with_delimiter(char * buffer,size_t buflen,const std::string & source,char delimiter)147 size_t hex_decode_with_delimiter(char* buffer,
148 size_t buflen,
149 const std::string& source,
150 char delimiter) {
151 return hex_decode_with_delimiter(buffer, buflen, source.c_str(),
152 source.length(), delimiter);
153 }
154
tokenize(const std::string & source,char delimiter,std::vector<std::string> * fields)155 size_t tokenize(const std::string& source,
156 char delimiter,
157 std::vector<std::string>* fields) {
158 fields->clear();
159 size_t last = 0;
160 for (size_t i = 0; i < source.length(); ++i) {
161 if (source[i] == delimiter) {
162 if (i != last) {
163 fields->push_back(source.substr(last, i - last));
164 }
165 last = i + 1;
166 }
167 }
168 if (last != source.length()) {
169 fields->push_back(source.substr(last, source.length() - last));
170 }
171 return fields->size();
172 }
173
tokenize_with_empty_tokens(const std::string & source,char delimiter,std::vector<std::string> * fields)174 size_t tokenize_with_empty_tokens(const std::string& source,
175 char delimiter,
176 std::vector<std::string>* fields) {
177 fields->clear();
178 size_t last = 0;
179 for (size_t i = 0; i < source.length(); ++i) {
180 if (source[i] == delimiter) {
181 fields->push_back(source.substr(last, i - last));
182 last = i + 1;
183 }
184 }
185 fields->push_back(source.substr(last, source.length() - last));
186 return fields->size();
187 }
188
tokenize_append(const std::string & source,char delimiter,std::vector<std::string> * fields)189 size_t tokenize_append(const std::string& source,
190 char delimiter,
191 std::vector<std::string>* fields) {
192 if (!fields)
193 return 0;
194
195 std::vector<std::string> new_fields;
196 tokenize(source, delimiter, &new_fields);
197 fields->insert(fields->end(), new_fields.begin(), new_fields.end());
198 return fields->size();
199 }
200
tokenize(const std::string & source,char delimiter,char start_mark,char end_mark,std::vector<std::string> * fields)201 size_t tokenize(const std::string& source,
202 char delimiter,
203 char start_mark,
204 char end_mark,
205 std::vector<std::string>* fields) {
206 if (!fields)
207 return 0;
208 fields->clear();
209
210 std::string remain_source = source;
211 while (!remain_source.empty()) {
212 size_t start_pos = remain_source.find(start_mark);
213 if (std::string::npos == start_pos)
214 break;
215 std::string pre_mark;
216 if (start_pos > 0) {
217 pre_mark = remain_source.substr(0, start_pos - 1);
218 }
219
220 ++start_pos;
221 size_t end_pos = remain_source.find(end_mark, start_pos);
222 if (std::string::npos == end_pos)
223 break;
224
225 // We have found the matching marks. First tokenize the pre-mask. Then add
226 // the marked part as a single field. Finally, loop back for the post-mark.
227 tokenize_append(pre_mark, delimiter, fields);
228 fields->push_back(remain_source.substr(start_pos, end_pos - start_pos));
229 remain_source = remain_source.substr(end_pos + 1);
230 }
231
232 return tokenize_append(remain_source, delimiter, fields);
233 }
234
tokenize_first(const std::string & source,const char delimiter,std::string * token,std::string * rest)235 bool tokenize_first(const std::string& source,
236 const char delimiter,
237 std::string* token,
238 std::string* rest) {
239 // Find the first delimiter
240 size_t left_pos = source.find(delimiter);
241 if (left_pos == std::string::npos) {
242 return false;
243 }
244
245 // Look for additional occurrances of delimiter.
246 size_t right_pos = left_pos + 1;
247 while (source[right_pos] == delimiter) {
248 right_pos++;
249 }
250
251 *token = source.substr(0, left_pos);
252 *rest = source.substr(right_pos);
253 return true;
254 }
255
join(const std::vector<std::string> & source,char delimiter)256 std::string join(const std::vector<std::string>& source, char delimiter) {
257 if (source.size() == 0) {
258 return std::string();
259 }
260 // Find length of the string to be returned to pre-allocate memory.
261 size_t source_string_length = 0;
262 for (size_t i = 0; i < source.size(); ++i) {
263 source_string_length += source[i].length();
264 }
265
266 // Build the joined string.
267 std::string joined_string;
268 joined_string.reserve(source_string_length + source.size() - 1);
269 for (size_t i = 0; i < source.size(); ++i) {
270 if (i != 0) {
271 joined_string += delimiter;
272 }
273 joined_string += source[i];
274 }
275 return joined_string;
276 }
277
split(const std::string & source,char delimiter,std::vector<std::string> * fields)278 size_t split(const std::string& source,
279 char delimiter,
280 std::vector<std::string>* fields) {
281 RTC_DCHECK(fields);
282 fields->clear();
283 size_t last = 0;
284 for (size_t i = 0; i < source.length(); ++i) {
285 if (source[i] == delimiter) {
286 fields->push_back(source.substr(last, i - last));
287 last = i + 1;
288 }
289 }
290 fields->push_back(source.substr(last, source.length() - last));
291 return fields->size();
292 }
293
ToString(const bool b)294 std::string ToString(const bool b) {
295 return b ? "true" : "false";
296 }
297
ToString(const char * const s)298 std::string ToString(const char* const s) {
299 return std::string(s);
300 }
ToString(const std::string s)301 std::string ToString(const std::string s) {
302 return s;
303 }
304
ToString(const short s)305 std::string ToString(const short s) {
306 char buf[32];
307 const int len = std::snprintf(&buf[0], arraysize(buf), "%hd", s);
308 RTC_DCHECK_LE(len, arraysize(buf));
309 return std::string(&buf[0], len);
310 }
ToString(const unsigned short s)311 std::string ToString(const unsigned short s) {
312 char buf[32];
313 const int len = std::snprintf(&buf[0], arraysize(buf), "%hu", s);
314 RTC_DCHECK_LE(len, arraysize(buf));
315 return std::string(&buf[0], len);
316 }
ToString(const int s)317 std::string ToString(const int s) {
318 char buf[32];
319 const int len = std::snprintf(&buf[0], arraysize(buf), "%d", s);
320 RTC_DCHECK_LE(len, arraysize(buf));
321 return std::string(&buf[0], len);
322 }
ToString(const unsigned int s)323 std::string ToString(const unsigned int s) {
324 char buf[32];
325 const int len = std::snprintf(&buf[0], arraysize(buf), "%u", s);
326 RTC_DCHECK_LE(len, arraysize(buf));
327 return std::string(&buf[0], len);
328 }
ToString(const long int s)329 std::string ToString(const long int s) {
330 char buf[32];
331 const int len = std::snprintf(&buf[0], arraysize(buf), "%ld", s);
332 RTC_DCHECK_LE(len, arraysize(buf));
333 return std::string(&buf[0], len);
334 }
ToString(const unsigned long int s)335 std::string ToString(const unsigned long int s) {
336 char buf[32];
337 const int len = std::snprintf(&buf[0], arraysize(buf), "%lu", s);
338 RTC_DCHECK_LE(len, arraysize(buf));
339 return std::string(&buf[0], len);
340 }
ToString(const long long int s)341 std::string ToString(const long long int s) {
342 char buf[32];
343 const int len = std::snprintf(&buf[0], arraysize(buf), "%lld", s);
344 RTC_DCHECK_LE(len, arraysize(buf));
345 return std::string(&buf[0], len);
346 }
ToString(const unsigned long long int s)347 std::string ToString(const unsigned long long int s) {
348 char buf[32];
349 const int len = std::snprintf(&buf[0], arraysize(buf), "%llu", s);
350 RTC_DCHECK_LE(len, arraysize(buf));
351 return std::string(&buf[0], len);
352 }
353
ToString(const double d)354 std::string ToString(const double d) {
355 char buf[32];
356 const int len = std::snprintf(&buf[0], arraysize(buf), "%g", d);
357 RTC_DCHECK_LE(len, arraysize(buf));
358 return std::string(&buf[0], len);
359 }
360
ToString(const long double d)361 std::string ToString(const long double d) {
362 char buf[32];
363 const int len = std::snprintf(&buf[0], arraysize(buf), "%Lg", d);
364 RTC_DCHECK_LE(len, arraysize(buf));
365 return std::string(&buf[0], len);
366 }
367
ToString(const void * const p)368 std::string ToString(const void* const p) {
369 char buf[32];
370 const int len = std::snprintf(&buf[0], arraysize(buf), "%p", p);
371 RTC_DCHECK_LE(len, arraysize(buf));
372 return std::string(&buf[0], len);
373 }
374
FromString(const std::string & s,bool * b)375 bool FromString(const std::string& s, bool* b) {
376 if (s == "false") {
377 *b = false;
378 return true;
379 }
380 if (s == "true") {
381 *b = true;
382 return true;
383 }
384 return false;
385 }
386
387 } // namespace rtc
388