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 #ifndef INCLUDE_PERFETTO_EXT_BASE_STRING_UTILS_H_
18 #define INCLUDE_PERFETTO_EXT_BASE_STRING_UTILS_H_
19
20 #include <stdarg.h>
21 #include <stdlib.h>
22 #include <string.h>
23
24 #include <charconv>
25 #include <cinttypes>
26 #include <optional>
27 #include <string>
28 #include <system_error>
29 #include <vector>
30
31 #include "perfetto/ext/base/string_view.h"
32
33 namespace perfetto {
34 namespace base {
35
Lowercase(char c)36 inline char Lowercase(char c) {
37 return ('A' <= c && c <= 'Z') ? static_cast<char>(c - ('A' - 'a')) : c;
38 }
39
Uppercase(char c)40 inline char Uppercase(char c) {
41 return ('a' <= c && c <= 'z') ? static_cast<char>(c + ('A' - 'a')) : c;
42 }
43
44 inline std::optional<uint32_t> CStringToUInt32(const char* s, int base = 10) {
45 char* endptr = nullptr;
46 auto value = static_cast<uint32_t>(strtoul(s, &endptr, base));
47 return (*s && !*endptr) ? std::make_optional(value) : std::nullopt;
48 }
49
50 inline std::optional<int32_t> CStringToInt32(const char* s, int base = 10) {
51 char* endptr = nullptr;
52 auto value = static_cast<int32_t>(strtol(s, &endptr, base));
53 return (*s && !*endptr) ? std::make_optional(value) : std::nullopt;
54 }
55
56 // Note: it saturates to 7fffffffffffffff if parsing a hex number >= 0x8000...
57 inline std::optional<int64_t> CStringToInt64(const char* s, int base = 10) {
58 char* endptr = nullptr;
59 auto value = static_cast<int64_t>(strtoll(s, &endptr, base));
60 return (*s && !*endptr) ? std::make_optional(value) : std::nullopt;
61 }
62
63 inline std::optional<uint64_t> CStringToUInt64(const char* s, int base = 10) {
64 char* endptr = nullptr;
65 auto value = static_cast<uint64_t>(strtoull(s, &endptr, base));
66 return (*s && !*endptr) ? std::make_optional(value) : std::nullopt;
67 }
68
69 double StrToD(const char* nptr, char** endptr);
70
CStringToDouble(const char * s)71 inline std::optional<double> CStringToDouble(const char* s) {
72 char* endptr = nullptr;
73 double value = StrToD(s, &endptr);
74 std::optional<double> result(std::nullopt);
75 if (*s != '\0' && *endptr == '\0')
76 result = value;
77 return result;
78 }
79
80 inline std::optional<uint32_t> StringToUInt32(const std::string& s,
81 int base = 10) {
82 return CStringToUInt32(s.c_str(), base);
83 }
84
85 inline std::optional<int32_t> StringToInt32(const std::string& s,
86 int base = 10) {
87 return CStringToInt32(s.c_str(), base);
88 }
89
90 inline std::optional<uint64_t> StringToUInt64(const std::string& s,
91 int base = 10) {
92 return CStringToUInt64(s.c_str(), base);
93 }
94
95 inline std::optional<int64_t> StringToInt64(const std::string& s,
96 int base = 10) {
97 return CStringToInt64(s.c_str(), base);
98 }
99
StringToDouble(const std::string & s)100 inline std::optional<double> StringToDouble(const std::string& s) {
101 return CStringToDouble(s.c_str());
102 }
103
104 template <typename T>
105 inline std::optional<T> StringViewToNumber(const base::StringView& sv,
106 int base = 10) {
107 // std::from_chars() does not regonize the leading '+' character and only
108 // recognizes '-' so remove the '+' if it exists to avoid errors and match
109 // the behavior of the other string conversion utilities above.
110 size_t start_offset = !sv.empty() && sv.at(0) == '+' ? 1 : 0;
111 T value;
112 auto result =
113 std::from_chars(sv.begin() + start_offset, sv.end(), value, base);
114 if (result.ec == std::errc() && result.ptr == sv.end()) {
115 return value;
116 } else {
117 return std::nullopt;
118 }
119 }
120
121 inline std::optional<uint32_t> StringViewToUInt32(const base::StringView& sv,
122 int base = 10) {
123 // std::from_chars() does not recognize the leading '-' character for
124 // unsigned conversions, but strtol does. To Mimic the behavior of strtol,
125 // attempt a signed converion if we see a leading '-', and then cast the
126 // result back to unsigned.
127 if (sv.size() > 0 && sv.at(0) == '-') {
128 return static_cast<std::optional<uint32_t> >(
129 StringViewToNumber<int32_t>(sv, base));
130 } else {
131 return StringViewToNumber<uint32_t>(sv, base);
132 }
133 }
134
135 inline std::optional<int32_t> StringViewToInt32(const base::StringView& sv,
136 int base = 10) {
137 return StringViewToNumber<int32_t>(sv, base);
138 }
139
140 inline std::optional<uint64_t> StringViewToUInt64(const base::StringView& sv,
141 int base = 10) {
142 // std::from_chars() does not recognize the leading '-' character for
143 // unsigned conversions, but strtol does. To Mimic the behavior of strtol,
144 // attempt a signed converion if we see a leading '-', and then cast the
145 // result back to unsigned.
146 if (sv.size() > 0 && sv.at(0) == '-') {
147 return static_cast<std::optional<uint64_t> >(
148 StringViewToNumber<int64_t>(sv, base));
149 } else {
150 return StringViewToNumber<uint64_t>(sv, base);
151 }
152 }
153
154 inline std::optional<int64_t> StringViewToInt64(const base::StringView& sv,
155 int base = 10) {
156 return StringViewToNumber<int64_t>(sv, base);
157 }
158
159 // TODO: As of Clang 19.0 std::from_chars is unimplemented for type double
160 // despite being part of C++17 standard, and already being supported by GCC and
161 // MSVC. Enable this once we have double support in Clang.
162 // inline std::optional<double> StringViewToDouble(const base::StringView& sv) {
163 // return StringViewToNumber<double>(sv);
164 // }
165
166 bool StartsWith(const std::string& str, const std::string& prefix);
167 bool EndsWith(const std::string& str, const std::string& suffix);
168 bool StartsWithAny(const std::string& str,
169 const std::vector<std::string>& prefixes);
170 bool Contains(const std::string& haystack, const std::string& needle);
171 bool Contains(const std::string& haystack, char needle);
172 size_t Find(const StringView& needle, const StringView& haystack);
173 bool CaseInsensitiveEqual(const std::string& first, const std::string& second);
174 std::string Join(const std::vector<std::string>& parts,
175 const std::string& delim);
176 std::vector<std::string> SplitString(const std::string& text,
177 const std::string& delimiter);
178 std::string StripPrefix(const std::string& str, const std::string& prefix);
179 std::string StripSuffix(const std::string& str, const std::string& suffix);
180 std::string TrimWhitespace(const std::string& str);
181 std::string ToLower(const std::string& str);
182 std::string ToUpper(const std::string& str);
183 std::string StripChars(const std::string& str,
184 const std::string& chars,
185 char replacement);
186 std::string ToHex(const char* data, size_t size);
ToHex(const std::string & s)187 inline std::string ToHex(const std::string& s) {
188 return ToHex(s.c_str(), s.size());
189 }
190 std::string IntToHexString(uint32_t number);
191 std::string Uint64ToHexString(uint64_t number);
192 std::string Uint64ToHexStringNoPrefix(uint64_t number);
193 std::string ReplaceAll(std::string str,
194 const std::string& to_replace,
195 const std::string& replacement);
196
197 #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
198 bool WideToUTF8(const std::wstring& source, std::string& output);
199 bool UTF8ToWide(const std::string& source, std::wstring& output);
200 #endif // PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
201
202 // A BSD-style strlcpy without the return value.
203 // Copies at most |dst_size|-1 characters. Unlike strncpy, it always \0
204 // terminates |dst|, as long as |dst_size| is not 0.
205 // Unlike strncpy and like strlcpy it does not zero-pad the rest of |dst|.
206 // Returns nothing. The BSD strlcpy returns the size of |src|, which might
207 // be > |dst_size|. Anecdotal experience suggests people assume the return value
208 // is the number of bytes written in |dst|. That assumption can lead to
209 // dangerous bugs.
210 // In order to avoid being subtly uncompliant with strlcpy AND avoid misuse,
211 // the choice here is to return nothing.
StringCopy(char * dst,const char * src,size_t dst_size)212 inline void StringCopy(char* dst, const char* src, size_t dst_size) {
213 for (size_t i = 0; i < dst_size; ++i) {
214 if ((dst[i] = src[i]) == '\0') {
215 return; // We hit and copied the null terminator.
216 }
217 }
218
219 // We were left off at dst_size. We over copied 1 byte. Null terminate.
220 if (PERFETTO_LIKELY(dst_size > 0))
221 dst[dst_size - 1] = 0;
222 }
223
224 // Like snprintf() but returns the number of chars *actually* written (without
225 // counting the null terminator) NOT "the number of chars which would have been
226 // written to the final string if enough space had been available".
227 // This should be used in almost all cases when the caller uses the return value
228 // of snprintf(). If the return value is not used, there is no benefit in using
229 // this wrapper, as this just calls snprintf() and mangles the return value.
230 // It always null-terminates |dst| (even in case of errors), unless
231 // |dst_size| == 0.
232 // Examples:
233 // SprintfTrunc(x, 4, "123whatever"): returns 3 and writes "123\0".
234 // SprintfTrunc(x, 4, "123"): returns 3 and writes "123\0".
235 // SprintfTrunc(x, 3, "123"): returns 2 and writes "12\0".
236 // SprintfTrunc(x, 2, "123"): returns 1 and writes "1\0".
237 // SprintfTrunc(x, 1, "123"): returns 0 and writes "\0".
238 // SprintfTrunc(x, 0, "123"): returns 0 and writes nothing.
239 // NOTE: This means that the caller has no way to tell when truncation happens
240 // vs the edge case of *just* fitting in the buffer.
241 size_t SprintfTrunc(char* dst, size_t dst_size, const char* fmt, ...)
242 PERFETTO_PRINTF_FORMAT(3, 4);
243
244 // Line number starts from 1
245 struct LineWithOffset {
246 base::StringView line;
247 uint32_t line_offset;
248 uint32_t line_num;
249 };
250
251 // For given string and offset Pfinds a line with character for
252 // which offset points, what number is this line (starts from 1), and the offset
253 // inside this line. returns std::nullopt if the offset points to
254 // line break character or exceeds string length.
255 std::optional<LineWithOffset> FindLineWithOffset(base::StringView str,
256 uint32_t offset);
257
258 // A helper class to facilitate construction and usage of write-once stack
259 // strings.
260 // Example usage:
261 // StackString<32> x("format %d %s", 42, string_arg);
262 // TakeString(x.c_str() | x.string_view() | x.ToStdString());
263 // Rather than char x[32] + sprintf.
264 // Advantages:
265 // - Avoids useless zero-fills caused by people doing `char buf[32] {}` (mainly
266 // by fearing unknown snprintf failure modes).
267 // - Makes the code more robust in case of snprintf truncations (len() and
268 // string_view() will return the truncated length, unlike snprintf).
269 template <size_t N>
270 class StackString {
271 public:
272 explicit PERFETTO_PRINTF_FORMAT(/* 1=this */ 2, 3)
StackString(const char * fmt,...)273 StackString(const char* fmt, ...) {
274 buf_[0] = '\0';
275 va_list args;
276 va_start(args, fmt);
277 int res = vsnprintf(buf_, sizeof(buf_), fmt, args);
278 va_end(args);
279 buf_[sizeof(buf_) - 1] = '\0';
280 len_ = res < 0 ? 0 : std::min(static_cast<size_t>(res), sizeof(buf_) - 1);
281 }
282
string_view()283 StringView string_view() const { return StringView(buf_, len_); }
ToStdString()284 std::string ToStdString() const { return std::string(buf_, len_); }
c_str()285 const char* c_str() const { return buf_; }
len()286 size_t len() const { return len_; }
mutable_data()287 char* mutable_data() { return buf_; }
288
289 private:
290 char buf_[N];
291 size_t len_ = 0; // Does not include the \0.
292 };
293
294 } // namespace base
295 } // namespace perfetto
296
297 #endif // INCLUDE_PERFETTO_EXT_BASE_STRING_UTILS_H_
298