1 /**
2 * Copyright (c) 2024-2025 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "string_util.h"
17
18 #include <regex>
19
20 #include "utils/string_helpers.h"
21
22 using panda::helpers::string::Format;
23
24 namespace {
25 const std::regex ANONYMOUS_FUNCTION_NAME_REG = std::regex("\\^[\\da-f]+$");
26 const std::regex ANONYMOUS_NAMESPACE_NAME_REG = std::regex("=ens\\d+");
27
28 const char REGEX_DELIMITER = '/';
29 } // namespace
30
Split(const std::string & str,const std::string & delimiter)31 std::vector<std::string> panda::guard::StringUtil::Split(const std::string &str, const std::string &delimiter)
32 {
33 std::vector<std::string> tokens;
34 auto start = str.find_first_not_of(delimiter, 0);
35 auto pos = str.find_first_of(delimiter, 0);
36 while (start != std::string::npos) {
37 if (pos > start) {
38 tokens.push_back(str.substr(start, pos - start));
39 }
40 start = str.find_first_not_of(delimiter, pos);
41 pos = str.find_first_of(delimiter, start + 1);
42 }
43
44 return tokens;
45 }
46
StrictSplit(const std::string & str,const std::string & delimiter)47 std::vector<std::string> panda::guard::StringUtil::StrictSplit(const std::string &str, const std::string &delimiter)
48 {
49 std::vector<std::string> tokens;
50 size_t start = 0;
51 size_t end;
52 while (start <= str.size()) {
53 end = str.find_first_of(delimiter, start);
54 if (end == std::string::npos) {
55 end = str.size();
56 }
57
58 if (start < end) {
59 tokens.push_back(str.substr(start, end - start));
60 } else {
61 tokens.emplace_back("");
62 }
63
64 start = end + 1;
65 }
66 return tokens;
67 }
68
RSplitOnce(const std::string & str,const std::string & delimiter)69 std::tuple<std::string, std::string> panda::guard::StringUtil::RSplitOnce(const std::string &str,
70 const std::string &delimiter)
71 {
72 auto pos = str.rfind(delimiter);
73 if (pos == std::string::npos) {
74 return std::make_tuple("", "");
75 }
76
77 return std::make_tuple(str.substr(0, pos), str.substr(pos + delimiter.length()));
78 }
79
IsAnonymousFunctionName(const std::string & functionName)80 bool panda::guard::StringUtil::IsAnonymousFunctionName(const std::string &functionName)
81 {
82 if (functionName.empty()) {
83 return true;
84 }
85
86 if (functionName[0] != '^') {
87 return false;
88 }
89 return std::regex_search(functionName, ANONYMOUS_FUNCTION_NAME_REG);
90 }
91
IsAnonymousNameSpaceName(const std::string & name)92 bool panda::guard::StringUtil::IsAnonymousNameSpaceName(const std::string &name)
93 {
94 if (name.empty()) {
95 return false;
96 }
97
98 return std::regex_search(name, ANONYMOUS_NAMESPACE_NAME_REG);
99 }
100
IsPrefixMatched(const std::string & str,const std::string & prefix,size_t start)101 bool panda::guard::StringUtil::IsPrefixMatched(const std::string &str, const std::string &prefix,
102 size_t start /* = 0 */)
103 {
104 if (start > str.size() || start + prefix.size() > str.size()) {
105 return false;
106 }
107 return str.compare(start, prefix.size(), prefix) == 0;
108 }
109
IsSuffixMatched(const std::string & str,const std::string & suffix)110 bool panda::guard::StringUtil::IsSuffixMatched(const std::string &str, const std::string &suffix)
111 {
112 if (str.size() < suffix.size()) {
113 return false;
114 }
115 return StringUtil::IsPrefixMatched(str, suffix, str.size() - suffix.size());
116 }
117
UnicodeEscape(std::string_view string)118 std::string panda::guard::StringUtil::UnicodeEscape(std::string_view string)
119 {
120 std::string out;
121 while (!string.empty()) {
122 auto iter =
123 std::find_if(string.begin(), string.end(), [](char ch) { return ch == '"' || ch == '\\' || ch < ' '; });
124 auto pos = iter - string.begin();
125 out += string.substr(0, pos);
126 if (iter == string.end()) {
127 break;
128 }
129
130 out += '\\';
131 switch (*iter) {
132 case '"':
133 case '\\':
134 out += *iter;
135 break;
136 case '\b':
137 out += 'b';
138 break;
139 case '\f':
140 out += 'f';
141 break;
142 case '\n':
143 out += 'n';
144 break;
145 case '\r':
146 out += 'r';
147 break;
148 case '\t':
149 out += 't';
150 break;
151 default:
152 out += Format("u%04X", *iter); // NOLINT(cppcoreguidelines-pro-type-vararg)
153 }
154 string.remove_prefix(pos + 1);
155 }
156 return out;
157 }
158
RemoveSlashFromBothEnds(std::string & str)159 void panda::guard::StringUtil::RemoveSlashFromBothEnds(std::string &str)
160 {
161 if (!str.empty() && str.front() == REGEX_DELIMITER && str.back() == REGEX_DELIMITER) {
162 str.erase(str.begin());
163 str.pop_back();
164 }
165 }
166
IsNumber(const std::string & str)167 bool panda::guard::StringUtil::IsNumber(const std::string &str)
168 {
169 return std::all_of(str.begin(), str.end(), [](const char &ch) {
170 if ((ch >= '0') && (ch <= '9')) {
171 return true;
172 }
173 return false;
174 });
175 }
176
SplitAnonymousName(const std::string & str)177 std::tuple<std::string, std::string> panda::guard::StringUtil::SplitAnonymousName(const std::string &str)
178 {
179 std::smatch match;
180 if (std::regex_search(str.begin(), str.end(), match, ANONYMOUS_FUNCTION_NAME_REG)) {
181 std::string suffix = match[0].str();
182 std::string prefix = str.substr(0, str.find(suffix));
183 return std::make_tuple(prefix, suffix);
184 }
185 return std::make_tuple(str, "");
186 }