• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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