xref: /aosp_15_r20/external/webrtc/rtc_base/string_encode.cc (revision d9f758449e529ab9291ac668be2861e7a55c2422)
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 "absl/strings/string_view.h"
16 #include "api/array_view.h"
17 #include "rtc_base/arraysize.h"
18 #include "rtc_base/checks.h"
19 
20 namespace rtc {
21 
22 /////////////////////////////////////////////////////////////////////////////
23 // String Encoding Utilities
24 /////////////////////////////////////////////////////////////////////////////
25 
26 namespace {
27 const char HEX[] = "0123456789abcdef";
28 
29 // Convert an unsigned value from 0 to 15 to the hex character equivalent...
hex_encode(unsigned char val)30 char hex_encode(unsigned char val) {
31   RTC_DCHECK_LT(val, 16);
32   return (val < 16) ? HEX[val] : '!';
33 }
34 
35 // ...and vice-versa.
hex_decode(char ch,unsigned char * val)36 bool hex_decode(char ch, unsigned char* val) {
37   if ((ch >= '0') && (ch <= '9')) {
38     *val = ch - '0';
39   } else if ((ch >= 'A') && (ch <= 'F')) {
40     *val = (ch - 'A') + 10;
41   } else if ((ch >= 'a') && (ch <= 'f')) {
42     *val = (ch - 'a') + 10;
43   } else {
44     return false;
45   }
46   return true;
47 }
48 
hex_encode_output_length(size_t srclen,char delimiter)49 size_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
54 // `delimiter` between bytes, or none if `delimiter` == 0.
hex_encode_with_delimiter(char * buffer,absl::string_view source,char delimiter)55 void hex_encode_with_delimiter(char* buffer,
56                                absl::string_view source,
57                                char delimiter) {
58   RTC_DCHECK(buffer);
59 
60   // Init and check bounds.
61   const unsigned char* bsource =
62       reinterpret_cast<const unsigned char*>(source.data());
63   size_t srcpos = 0, bufpos = 0;
64 
65   size_t srclen = source.length();
66   while (srcpos < srclen) {
67     unsigned char ch = bsource[srcpos++];
68     buffer[bufpos] = hex_encode((ch >> 4) & 0xF);
69     buffer[bufpos + 1] = hex_encode((ch)&0xF);
70     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   }
78 }
79 
80 }  // namespace
81 
hex_encode(absl::string_view str)82 std::string hex_encode(absl::string_view str) {
83   return hex_encode_with_delimiter(str, 0);
84 }
85 
hex_encode_with_delimiter(absl::string_view source,char delimiter)86 std::string hex_encode_with_delimiter(absl::string_view source,
87                                       char delimiter) {
88   std::string s(hex_encode_output_length(source.length(), delimiter), 0);
89   hex_encode_with_delimiter(&s[0], source, delimiter);
90   return s;
91 }
92 
hex_decode_with_delimiter(ArrayView<char> cbuffer,absl::string_view source,char delimiter)93 size_t hex_decode_with_delimiter(ArrayView<char> cbuffer,
94                                  absl::string_view source,
95                                  char delimiter) {
96   if (cbuffer.empty())
97     return 0;
98 
99   // Init and bounds check.
100   unsigned char* bbuffer = reinterpret_cast<unsigned char*>(cbuffer.data());
101   size_t srcpos = 0, bufpos = 0;
102   size_t srclen = source.length();
103 
104   size_t needed = (delimiter) ? (srclen + 1) / 3 : srclen / 2;
105   if (cbuffer.size() < needed)
106     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 
hex_decode(ArrayView<char> buffer,absl::string_view source)133 size_t hex_decode(ArrayView<char> buffer, absl::string_view source) {
134   return hex_decode_with_delimiter(buffer, source, 0);
135 }
136 
tokenize(absl::string_view source,char delimiter,std::vector<std::string> * fields)137 size_t tokenize(absl::string_view source,
138                 char delimiter,
139                 std::vector<std::string>* fields) {
140   fields->clear();
141   size_t last = 0;
142   for (size_t i = 0; i < source.length(); ++i) {
143     if (source[i] == delimiter) {
144       if (i != last) {
145         fields->emplace_back(source.substr(last, i - last));
146       }
147       last = i + 1;
148     }
149   }
150   if (last != source.length()) {
151     fields->emplace_back(source.substr(last, source.length() - last));
152   }
153   return fields->size();
154 }
155 
tokenize_first(absl::string_view source,const char delimiter,std::string * token,std::string * rest)156 bool tokenize_first(absl::string_view source,
157                     const char delimiter,
158                     std::string* token,
159                     std::string* rest) {
160   // Find the first delimiter
161   size_t left_pos = source.find(delimiter);
162   if (left_pos == absl::string_view::npos) {
163     return false;
164   }
165 
166   // Look for additional occurrances of delimiter.
167   size_t right_pos = left_pos + 1;
168   while (right_pos < source.size() && source[right_pos] == delimiter) {
169     right_pos++;
170   }
171 
172   *token = std::string(source.substr(0, left_pos));
173   *rest = std::string(source.substr(right_pos));
174   return true;
175 }
176 
split(absl::string_view source,char delimiter)177 std::vector<absl::string_view> split(absl::string_view source, char delimiter) {
178   std::vector<absl::string_view> fields;
179   size_t last = 0;
180   for (size_t i = 0; i < source.length(); ++i) {
181     if (source[i] == delimiter) {
182       fields.push_back(source.substr(last, i - last));
183       last = i + 1;
184     }
185   }
186   fields.push_back(source.substr(last));
187   return fields;
188 }
189 
ToString(const bool b)190 std::string ToString(const bool b) {
191   return b ? "true" : "false";
192 }
193 
ToString(absl::string_view s)194 std::string ToString(absl::string_view s) {
195   return std::string(s);
196 }
197 
ToString(const char * s)198 std::string ToString(const char* s) {
199   return std::string(s);
200 }
201 
ToString(const short s)202 std::string ToString(const short s) {
203   char buf[32];
204   const int len = std::snprintf(&buf[0], arraysize(buf), "%hd", s);
205   RTC_DCHECK_LE(len, arraysize(buf));
206   return std::string(&buf[0], len);
207 }
ToString(const unsigned short s)208 std::string ToString(const unsigned short s) {
209   char buf[32];
210   const int len = std::snprintf(&buf[0], arraysize(buf), "%hu", s);
211   RTC_DCHECK_LE(len, arraysize(buf));
212   return std::string(&buf[0], len);
213 }
ToString(const int s)214 std::string ToString(const int s) {
215   char buf[32];
216   const int len = std::snprintf(&buf[0], arraysize(buf), "%d", s);
217   RTC_DCHECK_LE(len, arraysize(buf));
218   return std::string(&buf[0], len);
219 }
ToString(const unsigned int s)220 std::string ToString(const unsigned int s) {
221   char buf[32];
222   const int len = std::snprintf(&buf[0], arraysize(buf), "%u", s);
223   RTC_DCHECK_LE(len, arraysize(buf));
224   return std::string(&buf[0], len);
225 }
ToString(const long int s)226 std::string ToString(const long int s) {
227   char buf[32];
228   const int len = std::snprintf(&buf[0], arraysize(buf), "%ld", s);
229   RTC_DCHECK_LE(len, arraysize(buf));
230   return std::string(&buf[0], len);
231 }
ToString(const unsigned long int s)232 std::string ToString(const unsigned long int s) {
233   char buf[32];
234   const int len = std::snprintf(&buf[0], arraysize(buf), "%lu", s);
235   RTC_DCHECK_LE(len, arraysize(buf));
236   return std::string(&buf[0], len);
237 }
ToString(const long long int s)238 std::string ToString(const long long int s) {
239   char buf[32];
240   const int len = std::snprintf(&buf[0], arraysize(buf), "%lld", s);
241   RTC_DCHECK_LE(len, arraysize(buf));
242   return std::string(&buf[0], len);
243 }
ToString(const unsigned long long int s)244 std::string ToString(const unsigned long long int s) {
245   char buf[32];
246   const int len = std::snprintf(&buf[0], arraysize(buf), "%llu", s);
247   RTC_DCHECK_LE(len, arraysize(buf));
248   return std::string(&buf[0], len);
249 }
250 
ToString(const double d)251 std::string ToString(const double d) {
252   char buf[32];
253   const int len = std::snprintf(&buf[0], arraysize(buf), "%g", d);
254   RTC_DCHECK_LE(len, arraysize(buf));
255   return std::string(&buf[0], len);
256 }
257 
ToString(const long double d)258 std::string ToString(const long double d) {
259   char buf[32];
260   const int len = std::snprintf(&buf[0], arraysize(buf), "%Lg", d);
261   RTC_DCHECK_LE(len, arraysize(buf));
262   return std::string(&buf[0], len);
263 }
264 
ToString(const void * const p)265 std::string ToString(const void* const p) {
266   char buf[32];
267   const int len = std::snprintf(&buf[0], arraysize(buf), "%p", p);
268   RTC_DCHECK_LE(len, arraysize(buf));
269   return std::string(&buf[0], len);
270 }
271 
FromString(absl::string_view s,bool * b)272 bool FromString(absl::string_view s, bool* b) {
273   if (s == "false") {
274     *b = false;
275     return true;
276   }
277   if (s == "true") {
278     *b = true;
279     return true;
280   }
281   return false;
282 }
283 
284 }  // namespace rtc
285