• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "perfetto/ext/base/string_utils.h"
18 
19 #include <inttypes.h>
20 #include <locale.h>
21 #include <string.h>
22 
23 #if PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
24 #include <xlocale.h>
25 #endif
26 
27 #include <algorithm>
28 
29 #include "perfetto/base/logging.h"
30 
31 namespace perfetto {
32 namespace base {
33 namespace {
34 constexpr char kBase64Table[] =
35     "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
36     "abcdefghijklmnopqrstuvwxyz0123456789+/";
37 }
38 
39 // Locale-independant as possible version of strtod.
StrToD(const char * nptr,char ** endptr)40 double StrToD(const char* nptr, char** endptr) {
41 #if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) || \
42     PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) ||   \
43     PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
44   static auto c_locale = newlocale(LC_ALL, "C", nullptr);
45   return strtod_l(nptr, endptr, c_locale);
46 #else
47   return strtod(nptr, endptr);
48 #endif
49 }
50 
QuoteAndEscapeControlCodes(const std::string & raw)51 std::string QuoteAndEscapeControlCodes(const std::string& raw) {
52   std::string ret;
53   for (auto it = raw.cbegin(); it != raw.cend(); it++) {
54     switch (*it) {
55       case '\\':
56         ret += "\\\\";
57         break;
58       case '"':
59         ret += "\\\"";
60         break;
61       case '/':
62         ret += "\\/";
63         break;
64       case '\b':
65         ret += "\\b";
66         break;
67       case '\f':
68         ret += "\\f";
69         break;
70       case '\n':
71         ret += "\\n";
72         break;
73       case '\r':
74         ret += "\\r";
75         break;
76       case '\t':
77         ret += "\\t";
78         break;
79       default:
80         ret += *it;
81         break;
82     }
83   }
84   return '"' + ret + '"';
85 }
86 
StartsWith(const std::string & str,const std::string & prefix)87 bool StartsWith(const std::string& str, const std::string& prefix) {
88   return str.compare(0, prefix.length(), prefix) == 0;
89 }
90 
EndsWith(const std::string & str,const std::string & suffix)91 bool EndsWith(const std::string& str, const std::string& suffix) {
92   if (suffix.size() > str.size())
93     return false;
94   return str.compare(str.size() - suffix.size(), suffix.size(), suffix) == 0;
95 }
96 
Contains(const std::string & haystack,const std::string & needle)97 bool Contains(const std::string& haystack, const std::string& needle) {
98   return haystack.find(needle) != std::string::npos;
99 }
100 
Contains(const std::string & haystack,const char needle)101 bool Contains(const std::string& haystack, const char needle) {
102   return haystack.find(needle) != std::string::npos;
103 }
104 
Find(const StringView & needle,const StringView & haystack)105 size_t Find(const StringView& needle, const StringView& haystack) {
106   if (needle.empty())
107     return 0;
108   if (needle.size() > haystack.size())
109     return std::string::npos;
110   for (size_t i = 0; i < haystack.size() - (needle.size() - 1); ++i) {
111     if (strncmp(haystack.data() + i, needle.data(), needle.size()) == 0)
112       return i;
113   }
114   return std::string::npos;
115 }
116 
CaseInsensitiveEqual(const std::string & first,const std::string & second)117 bool CaseInsensitiveEqual(const std::string& first, const std::string& second) {
118   return first.size() == second.size() &&
119          std::equal(
120              first.begin(), first.end(), second.begin(),
121              [](char a, char b) { return Lowercase(a) == Lowercase(b); });
122 }
123 
Join(const std::vector<std::string> & parts,const std::string & delim)124 std::string Join(const std::vector<std::string>& parts,
125                  const std::string& delim) {
126   std::string acc;
127   for (size_t i = 0; i < parts.size(); ++i) {
128     acc += parts[i];
129     if (i + 1 != parts.size()) {
130       acc += delim;
131     }
132   }
133   return acc;
134 }
135 
SplitString(const std::string & text,const std::string & delimiter)136 std::vector<std::string> SplitString(const std::string& text,
137                                      const std::string& delimiter) {
138   PERFETTO_CHECK(!delimiter.empty());
139 
140   std::vector<std::string> output;
141   size_t start = 0;
142   size_t next;
143   for (;;) {
144     next = std::min(text.find(delimiter, start), text.size());
145     if (next > start)
146       output.emplace_back(&text[start], next - start);
147     start = next + delimiter.size();
148     if (start >= text.size())
149       break;
150   }
151   return output;
152 }
153 
StripPrefix(const std::string & str,const std::string & prefix)154 std::string StripPrefix(const std::string& str, const std::string& prefix) {
155   return StartsWith(str, prefix) ? str.substr(prefix.size()) : str;
156 }
157 
StripSuffix(const std::string & str,const std::string & suffix)158 std::string StripSuffix(const std::string& str, const std::string& suffix) {
159   return EndsWith(str, suffix) ? str.substr(0, str.size() - suffix.size())
160                                : str;
161 }
162 
ToUpper(const std::string & str)163 std::string ToUpper(const std::string& str) {
164   // Don't use toupper(), it depends on the locale.
165   std::string res(str);
166   auto end = res.end();
167   for (auto c = res.begin(); c != end; ++c)
168     *c = Uppercase(*c);
169   return res;
170 }
171 
ToLower(const std::string & str)172 std::string ToLower(const std::string& str) {
173   // Don't use tolower(), it depends on the locale.
174   std::string res(str);
175   auto end = res.end();
176   for (auto c = res.begin(); c != end; ++c)
177     *c = Lowercase(*c);
178   return res;
179 }
180 
ToHex(const char * data,size_t size)181 std::string ToHex(const char* data, size_t size) {
182   std::string hex(2 * size + 1, 'x');
183   for (size_t i = 0; i < size; ++i) {
184     // snprintf prints 3 characters, the two hex digits and a null byte. As we
185     // write left to right, we keep overwriting the nullbytes, except for the
186     // last call to snprintf.
187     snprintf(&(hex[2 * i]), 3, "%02hhx", data[i]);
188   }
189   // Remove the trailing nullbyte produced by the last snprintf.
190   hex.resize(2 * size);
191   return hex;
192 }
193 
IntToHexString(uint32_t number)194 std::string IntToHexString(uint32_t number) {
195   size_t max_size = 11;  // Max uint32 is 0xFFFFFFFF + 1 for null byte.
196   std::string buf;
197   buf.resize(max_size);
198   auto final_size = snprintf(&buf[0], max_size, "0x%02x", number);
199   PERFETTO_DCHECK(final_size >= 0);
200   buf.resize(static_cast<size_t>(final_size));  // Cuts off the final null byte.
201   return buf;
202 }
203 
Uint64ToHexString(uint64_t number)204 std::string Uint64ToHexString(uint64_t number) {
205   return "0x" + Uint64ToHexStringNoPrefix(number);
206 }
207 
Uint64ToHexStringNoPrefix(uint64_t number)208 std::string Uint64ToHexStringNoPrefix(uint64_t number) {
209   size_t max_size = 17;  // Max uint64 is FFFFFFFFFFFFFFFF + 1 for null byte.
210   std::string buf;
211   buf.resize(max_size);
212   auto final_size = snprintf(&buf[0], max_size, "%" PRIx64 "", number);
213   PERFETTO_DCHECK(final_size >= 0);
214   buf.resize(static_cast<size_t>(final_size));  // Cuts off the final null byte.
215   return buf;
216 }
217 
StripChars(const std::string & str,const std::string & chars,char replacement)218 std::string StripChars(const std::string& str,
219                        const std::string& chars,
220                        char replacement) {
221   std::string res(str);
222   const char* start = res.c_str();
223   const char* remove = chars.c_str();
224   for (const char* c = strpbrk(start, remove); c; c = strpbrk(c + 1, remove))
225     res[static_cast<uintptr_t>(c - start)] = replacement;
226   return res;
227 }
228 
ReplaceAll(std::string str,const std::string & to_replace,const std::string & replacement)229 std::string ReplaceAll(std::string str,
230                        const std::string& to_replace,
231                        const std::string& replacement) {
232   PERFETTO_CHECK(!to_replace.empty());
233   size_t pos = 0;
234   while ((pos = str.find(to_replace, pos)) != std::string::npos) {
235     str.replace(pos, to_replace.length(), replacement);
236     pos += replacement.length();
237   }
238   return str;
239 }
240 
TrimLeading(const std::string & str)241 std::string TrimLeading(const std::string& str) {
242   size_t idx = str.find_first_not_of(' ');
243   return idx == std::string::npos ? str : str.substr(idx);
244 }
245 
Base64Encode(const void * raw,size_t size)246 std::string Base64Encode(const void* raw, size_t size) {
247   // The following three cases are based on the tables in the example
248   // section in https://en.wikipedia.org/wiki/Base64. We process three
249   // input bytes at a time, emitting 4 output bytes at a time.
250   const uint8_t* ptr = static_cast<const uint8_t*>(raw);
251   size_t ii = 0;
252 
253   std::string out;
254   out.reserve((size + 2) * 4 / 3);
255 
256   // While possible, process three input bytes.
257   for (; ii + 3 <= size; ii += 3) {
258     uint32_t twentyfour_bits =
259         (uint32_t(ptr[ii]) << 16) | (uint32_t(ptr[ii + 1]) << 8) | ptr[ii + 2];
260     out.push_back(kBase64Table[(twentyfour_bits >> 18)]);
261     out.push_back(kBase64Table[(twentyfour_bits >> 12) & 0x3f]);
262     out.push_back(kBase64Table[(twentyfour_bits >> 6) & 0x3f]);
263     out.push_back(kBase64Table[twentyfour_bits & 0x3f]);
264   }
265   if (ii + 2 <= size) {  // Process two input bytes.
266     uint32_t twentyfour_bits =
267         (uint32_t(ptr[ii]) << 16) | (uint32_t(ptr[ii + 1]) << 8);
268     out.push_back(kBase64Table[(twentyfour_bits >> 18)]);
269     out.push_back(kBase64Table[(twentyfour_bits >> 12) & 0x3f]);
270     out.push_back(kBase64Table[(twentyfour_bits >> 6) & 0x3f]);
271     out.push_back('=');  // Emit padding.
272     return out;
273   }
274   if (ii + 1 <= size) {  // Process a single input byte.
275     uint32_t twentyfour_bits = (uint32_t(ptr[ii]) << 16);
276     out.push_back(kBase64Table[(twentyfour_bits >> 18)]);
277     out.push_back(kBase64Table[(twentyfour_bits >> 12) & 0x3f]);
278     out.push_back('=');  // Emit padding.
279     out.push_back('=');  // Emit padding.
280   }
281   return out;
282 }
283 
284 }  // namespace base
285 }  // namespace perfetto
286