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 <string.h>
20 
21 #include <algorithm>
22 
23 #include "perfetto/base/logging.h"
24 
25 namespace perfetto {
26 namespace base {
27 
StartsWith(const std::string & str,const std::string & prefix)28 bool StartsWith(const std::string& str, const std::string& prefix) {
29   return str.compare(0, prefix.length(), prefix) == 0;
30 }
31 
EndsWith(const std::string & str,const std::string & suffix)32 bool EndsWith(const std::string& str, const std::string& suffix) {
33   if (suffix.size() > str.size())
34     return false;
35   return str.compare(str.size() - suffix.size(), suffix.size(), suffix) == 0;
36 }
37 
Contains(const std::string & haystack,const std::string & needle)38 bool Contains(const std::string& haystack, const std::string& needle) {
39   return haystack.find(needle) != std::string::npos;
40 }
41 
Find(const StringView & needle,const StringView & haystack)42 size_t Find(const StringView& needle, const StringView& haystack) {
43   if (needle.size() == 0)
44     return 0;
45   if (needle.size() > haystack.size())
46     return std::string::npos;
47   for (size_t i = 0; i < haystack.size() - (needle.size() - 1); ++i) {
48     if (strncmp(haystack.data() + i, needle.data(), needle.size()) == 0)
49       return i;
50   }
51   return std::string::npos;
52 }
53 
CaseInsensitiveEqual(const std::string & first,const std::string & second)54 bool CaseInsensitiveEqual(const std::string& first, const std::string& second) {
55   return first.size() == second.size() &&
56          std::equal(
57              first.begin(), first.end(), second.begin(),
58              [](char a, char b) { return Lowercase(a) == Lowercase(b); });
59 }
60 
Join(const std::vector<std::string> & parts,const std::string & delim)61 std::string Join(const std::vector<std::string>& parts,
62                  const std::string& delim) {
63   std::string acc;
64   for (size_t i = 0; i < parts.size(); ++i) {
65     acc += parts[i];
66     if (i + 1 != parts.size()) {
67       acc += delim;
68     }
69   }
70   return acc;
71 }
72 
SplitString(const std::string & text,const std::string & delimiter)73 std::vector<std::string> SplitString(const std::string& text,
74                                      const std::string& delimiter) {
75   PERFETTO_CHECK(!delimiter.empty());
76 
77   std::vector<std::string> output;
78   size_t start = 0;
79   size_t next;
80   for (;;) {
81     next = std::min(text.find(delimiter, start), text.size());
82     if (next > start)
83       output.emplace_back(&text[start], next - start);
84     start = next + delimiter.size();
85     if (start >= text.size())
86       break;
87   }
88   return output;
89 }
90 
StripPrefix(const std::string & str,const std::string & prefix)91 std::string StripPrefix(const std::string& str, const std::string& prefix) {
92   return StartsWith(str, prefix) ? str.substr(prefix.size()) : str;
93 }
94 
StripSuffix(const std::string & str,const std::string & suffix)95 std::string StripSuffix(const std::string& str, const std::string& suffix) {
96   return EndsWith(str, suffix) ? str.substr(0, str.size() - suffix.size())
97                                : str;
98 }
99 
ToUpper(const std::string & str)100 std::string ToUpper(const std::string& str) {
101   // Don't use toupper(), it depends on the locale.
102   std::string res(str);
103   auto end = res.end();
104   for (auto c = res.begin(); c != end; ++c)
105     *c = Uppercase(*c);
106   return res;
107 }
108 
ToLower(const std::string & str)109 std::string ToLower(const std::string& str) {
110   // Don't use tolower(), it depends on the locale.
111   std::string res(str);
112   auto end = res.end();
113   for (auto c = res.begin(); c != end; ++c)
114     *c = Lowercase(*c);
115   return res;
116 }
117 
ToHex(const char * data,size_t size)118 std::string ToHex(const char* data, size_t size) {
119   std::string hex(2 * size + 1, 'x');
120   for (size_t i = 0; i < size; ++i) {
121     // snprintf prints 3 characters, the two hex digits and a null byte. As we
122     // write left to write, we keep overwriting the nullbytes, except for the
123     // last call to snprintf.
124     snprintf(&(hex[2 * i]), 3, "%02hhx", data[i]);
125   }
126   // Remove the trailing nullbyte produced by the last snprintf.
127   hex.resize(2 * size);
128   return hex;
129 }
130 
StripChars(const std::string & str,const std::string & chars,char replacement)131 std::string StripChars(const std::string& str,
132                        const std::string& chars,
133                        char replacement) {
134   std::string res(str);
135   const char* start = res.c_str();
136   const char* remove = chars.c_str();
137   for (const char* c = strpbrk(start, remove); c; c = strpbrk(c + 1, remove))
138     res[static_cast<uintptr_t>(c - start)] = replacement;
139   return res;
140 }
141 
142 }  // namespace base
143 }  // namespace perfetto
144