1 /*
2  * Copyright (c) 2021-2024 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 #include "string_util.h"
16 
17 #include <climits>
18 #include <iomanip>
19 #include <iostream>
20 #include <regex.h>
21 #include <sstream>
22 #include <string>
23 #include <vector>
24 
25 namespace OHOS {
26 namespace HiviewDFX {
27 namespace StringUtil {
28 namespace {
ReplaceMatchedStrWithAsterisk(const std::string & source,const std::string & patternStr)29 std::string ReplaceMatchedStrWithAsterisk(const std::string& source, const std::string& patternStr)
30 {
31     if (source.empty()) {
32         return "";
33     }
34     std::regex pattern(patternStr);
35     std::smatch result;
36     if (regex_search(source, result, pattern)) {
37         const size_t regexSize = 2;
38         if (result.size() == regexSize) {
39             return StringUtil::ReplaceStr(source, result[1].str(), "******");
40         }
41     }
42     return source;
43 }
44 }
45 using namespace std;
46 const char INDICATE_VALUE_CHAR = ':';
47 const char KEY_VALUE_END_CHAR = ';';
48 constexpr int SKIP_NEXT_INDEX_LENGTH = 2;
49 const std::string EMPTY_STRING = "";
ConvertVectorToStr(const std::vector<std::string> & listStr,const std::string & split)50 std::string ConvertVectorToStr(const std::vector<std::string> &listStr, const std::string &split)
51 {
52     std::string str("");
53     for (auto &item : listStr) {
54         if (str == "") {
55             str = item;
56         } else {
57             str += split + item;
58         }
59     }
60     return str;
61 }
62 
ReplaceStr(const string & str,const string & src,const string & dst)63 string ReplaceStr(const string& str, const string& src, const string& dst)
64 {
65     if (src.empty()) {
66         return str;
67     }
68 
69     string::size_type pos = 0;
70     string strTmp = str;
71     while ((pos = strTmp.find(src, pos)) != string::npos) {
72         strTmp.replace(pos, src.length(), dst);
73         pos += dst.length();
74     }
75 
76     return strTmp;
77 }
78 
TrimStr(const string & str,const char cTrim)79 string TrimStr(const string& str, const char cTrim)
80 {
81     string strTmp = str;
82     strTmp.erase(0, strTmp.find_first_not_of(cTrim));
83     strTmp.erase(strTmp.find_last_not_of(cTrim) + sizeof(char));
84     return strTmp;
85 }
86 
SplitStr(const string & str,const string & sep,vector<string> & strs,bool canEmpty,bool needTrim)87 void SplitStr(const string& str, const string& sep, vector<string>& strs,
88               bool canEmpty, bool needTrim)
89 {
90     strs.clear();
91     string strTmp = needTrim ? TrimStr(str) : str;
92     string strPart;
93     while (true) {
94         string::size_type pos = strTmp.find(sep);
95         if (string::npos == pos || sep.empty()) {
96             strPart = needTrim ? TrimStr(strTmp) : strTmp;
97             if (!strPart.empty() || canEmpty) {
98                 strs.push_back(strPart);
99             }
100             break;
101         } else {
102             strPart = needTrim ? TrimStr(strTmp.substr(0, pos)) : strTmp.substr(0, pos);
103             if (!strPart.empty() || canEmpty) {
104                 strs.push_back(strPart);
105             }
106             strTmp = strTmp.substr(sep.size() + pos, strTmp.size() - sep.size() - pos);
107         }
108     }
109 }
110 
StrToInt(const string & str,int & value)111 bool StrToInt(const string& str, int& value)
112 {
113     if (str.empty() || (!isdigit(str.front()) && (str.front() != '-'))) {
114         return false;
115     }
116 
117     char* end = nullptr;
118     const int base = 10;
119     errno = 0;
120     auto addr = str.c_str();
121     auto result = strtol(addr, &end, base);
122     if (end == addr || end[0] != '\0' || errno == ERANGE) {
123         return false;
124     }
125 
126     value = static_cast<int>(result);
127     return true;
128 }
129 
StrToInt(const string & str)130 int StrToInt(const string& str)
131 {
132     int id = -1;
133     StrToInt(str, id);
134     return id;
135 }
136 
DexToHexString(int value,bool upper)137 string DexToHexString(int value, bool upper)
138 {
139     stringstream ioss;
140     string hexString;
141     if (upper) {
142         ioss << setiosflags(ios::uppercase) << hex << value;
143     } else {
144         ioss << hex << value;
145     }
146 
147     ioss >> hexString;
148     return hexString;
149 }
150 
GetKeyValueByString(size_t & start,const std::string & inputString)151 KeyValuePair GetKeyValueByString(size_t &start, const std::string &inputString)
152 {
153     std::string key;
154     std::string value;
155     auto length = inputString.size();
156     while (start < length) {
157         if (inputString[start] == INDICATE_VALUE_CHAR) {
158             start++;
159             break;
160         }
161         key.append(1, inputString[start]);
162         start++;
163     }
164 
165     while (start < length) {
166         if (inputString[start] == KEY_VALUE_END_CHAR) {
167             // replace ;; to ; in value;
168             // one ';' means the end of a "key:value;"
169             if (start + 1 < length && inputString[start + 1] == KEY_VALUE_END_CHAR) {
170                 value.append(1, inputString[start]);
171                 start = start + SKIP_NEXT_INDEX_LENGTH;
172                 continue;
173             } else {
174                 start++;
175                 break;
176             }
177         }
178         if (inputString[start] == INDICATE_VALUE_CHAR && start + 1 < length &&
179             inputString[start + 1] == INDICATE_VALUE_CHAR) {
180             // replace :: to :
181             value.append(1, inputString[start]);
182             start = start + SKIP_NEXT_INDEX_LENGTH;
183             continue;
184         }
185         value.append(1, inputString[start]);
186         start++;
187     }
188     return make_pair(key, make_pair(value, 0));
189 }
190 
IsValidFloatNum(const std::string & value)191 bool IsValidFloatNum(const std::string &value)
192 {
193     int len = value.size();
194     int pointNum = 0;
195 
196     for (int i = 0; i < len; i++) {
197         if (isdigit(value[i])) {
198             continue;
199         }
200         if (value[i] == '.') {
201             pointNum++;
202         } else {
203             // the string contains not valid num;
204             return false;
205         }
206     }
207     // the string contains more than one character '.'
208     if (pointNum > 1) {
209         return false;
210     }
211     // the string format is .111/111.
212     return isdigit(value[0]) && isdigit(value[len - 1]);
213 }
214 
SplitStr(const std::string & str,char delimiter)215 std::list<std::string> SplitStr(const std::string& str, char delimiter)
216 {
217     std::list<std::string> tokens;
218     std::string token;
219     std::istringstream tokenStream(str);
220     while (std::getline(tokenStream, token, delimiter)) {
221         tokens.push_back(token);
222     }
223     return tokens;
224 }
225 
GetLeftSubstr(const string & input,const string & split)226 string GetLeftSubstr(const string& input, const string& split)
227 {
228     size_t pos = input.find(split, 0);
229     if (pos == string::npos) {
230         return input;
231     }
232     return input.substr(0, pos);
233 }
234 
GetRightSubstr(const string & input,const string & split)235 string GetRightSubstr(const string& input, const string& split)
236 {
237     size_t pos = input.find(split, 0);
238     if (pos == string::npos) {
239         return "none";
240     }
241     return input.substr(pos + split.size(), input.size() - pos);
242 }
243 
GetRleftSubstr(const string & input,const string & split)244 string GetRleftSubstr(const string& input, const string& split)
245 {
246     size_t pos = input.rfind(split, string::npos);
247     if (pos == string::npos) {
248         return input;
249     }
250     return input.substr(0, pos);
251 }
252 
GetRrightSubstr(const string & input,const string & split)253 string GetRrightSubstr(const string& input, const string& split)
254 {
255     size_t pos = input.rfind(split, string::npos);
256     if (pos == string::npos) {
257         return "none";
258     }
259     return input.substr(pos + 1, input.size() - pos);
260 }
261 
EraseString(const string & input,const string & toErase)262 string EraseString(const string& input, const string& toErase)
263 {
264     size_t pos = 0;
265     string out = input;
266     while ((pos = out.find(toErase, pos)) != string::npos) {
267         out.erase(pos, toErase.size());
268         pos = (pos == 0) ? (0) : (pos - 1);
269     }
270     return out;
271 }
272 
GetMidSubstr(const string & input,const string & begin,const string & end)273 string GetMidSubstr(const string& input, const string& begin, const string& end)
274 {
275     string midstr = "";
276     size_t beginPos = input.find(begin, 0);
277     if (beginPos == string::npos) {
278         return midstr;
279     }
280     beginPos = beginPos + begin.size();
281     size_t endPos = input.find(end, beginPos);
282     if (endPos == string::npos) {
283         return midstr;
284     }
285     return input.substr(beginPos, endPos - beginPos);
286 }
287 
VectorToString(const vector<string> & src,bool reverse,const string & tag)288 string VectorToString(const vector<string>& src, bool reverse, const string& tag)
289 {
290     string str;
291     for (auto element : src) {
292         if (element.empty()) {
293             continue;
294         }
295         if (reverse) {
296             str = element + tag + str;
297         } else {
298             str = str + element + tag;
299         }
300     }
301     return str;
302 }
303 
StringToUl(const string & flag,int base)304 uint64_t StringToUl(const string& flag, int base)
305 {
306     uint64_t ret = strtoul(flag.c_str(), NULL, base);
307     if (ret == ULONG_MAX) {
308         return 0;
309     }
310     return ret;
311 }
312 
StringToDouble(const string & input)313 double StringToDouble(const string& input)
314 {
315     if (input.empty()) {
316         return 0;
317     }
318     char *e = nullptr;
319     errno = 0;
320     double temp = std::strtod(input.c_str(), &e);
321 
322     if (errno != 0) { // error, overflow or underflow
323         return 0;
324     }
325     return temp;
326 }
327 
FindMatchSubString(const std::string & target,const std::string & begin,int offset,const std::string & end)328 std::string FindMatchSubString(const std::string& target, const std::string& begin, int offset,
329     const std::string& end)
330 {
331     auto matchPos = target.find_first_of(begin);
332     if (matchPos == std::string::npos) {
333         return "";
334     }
335     auto beginPos = matchPos + offset;
336     if (beginPos > target.length()) {
337         return "";
338     }
339     auto endPos = target.find_first_of(end, beginPos);
340     if (endPos == std::string::npos) {
341         return target.substr(beginPos);
342     }
343     return target.substr(beginPos, endPos);
344 }
345 
EscapeJsonStringValue(const std::string & value)346 std::string EscapeJsonStringValue(const std::string &value)
347 {
348     std::string escapeValue;
349     for (auto it = value.begin(); it != value.end(); it++) {
350         switch (*it) {
351             case '\\':
352                 escapeValue.push_back('\\');
353                 escapeValue.push_back('\\');
354                 break;
355             case '\"':
356                 escapeValue.push_back('\\');
357                 escapeValue.push_back('"');
358                 break;
359             case '\b':
360                 escapeValue.push_back('\\');
361                 escapeValue.push_back('b');
362                 break;
363             case '\f':
364                 escapeValue.push_back('\\');
365                 escapeValue.push_back('f');
366                 break;
367             case '\n':
368                 escapeValue.push_back('\\');
369                 escapeValue.push_back('n');
370                 break;
371             case '\r':
372                 escapeValue.push_back('\\');
373                 escapeValue.push_back('r');
374                 break;
375             case '\t':
376                 escapeValue.push_back('\\');
377                 escapeValue.push_back('t');
378                 break;
379             default:
380                 escapeValue.push_back(*it);
381                 break;
382         }
383     }
384     return escapeValue;
385 }
386 
UnescapeJsonStringValue(const std::string & value)387 std::string UnescapeJsonStringValue(const std::string &value)
388 {
389     bool isEscaped = true;
390     std::string unescapeValue;
391     for (auto it = value.begin(); it != value.end(); it++) {
392         if (isEscaped) {
393             switch (*it) {
394                 case '"':
395                     unescapeValue.push_back('\"');
396                     break;
397                 case '/':
398                     unescapeValue.push_back('/');
399                     break;
400                 case 'b':
401                     unescapeValue.push_back('\b');
402                     break;
403                 case 'f':
404                     unescapeValue.push_back('\f');
405                     break;
406                 case 'n':
407                     unescapeValue.push_back('\n');
408                     break;
409                 case 'r':
410                     unescapeValue.push_back('\r');
411                     break;
412                 case 't':
413                     unescapeValue.push_back('\t');
414                     break;
415                 case '\\':
416                     unescapeValue.push_back('\\');
417                     break;
418                 default:
419                     unescapeValue.push_back(*it);
420                     break;
421             }
422             isEscaped = false;
423         } else {
424             switch (*it) {
425                 case '\\':
426                     isEscaped = true;
427                     break;
428                 default:
429                     unescapeValue.push_back(*it);
430                     break;
431             }
432         }
433     }
434     return unescapeValue;
435 }
436 
FormatCmdLine(const std::string & cmdLine)437 std::string FormatCmdLine(const std::string& cmdLine)
438 {
439     size_t startPos = 0;
440     size_t endPos = cmdLine.size();
441     for (size_t i = 0; i < cmdLine.size(); i++) {
442         if (cmdLine[i] == '/') {
443             startPos = i + 1;
444         } else if (cmdLine[i] == '\0') {
445             endPos = i;
446             break;
447         }
448     }
449     return cmdLine.substr(startPos, endPos - startPos);
450 }
451 
FormatProcessName(std::string & processName)452 void FormatProcessName(std::string& processName)
453 {
454     processName = FormatCmdLine(processName);
455     std::for_each(processName.begin(), processName.end(), [] (char &c) {
456         if ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c == ',') || (c == '-') ||
457         (c == '_')) {
458             return;
459         };
460         c = '_';
461     });
462 }
463 
HideSnInfo(const std::string & str)464 std::string HideSnInfo(const std::string& str)
465 {
466     return ReplaceMatchedStrWithAsterisk(str, R"(_([-=+$a-zA-Z0-9\[\)\>]{12,50})_)");
467 }
468 
HideDeviceIdInfo(const std::string & str)469 std::string HideDeviceIdInfo(const std::string& str)
470 {
471     return ReplaceMatchedStrWithAsterisk(str, R"(_([A-Za-z0-9]{60,65})_)");
472 }
473 
StartWith(const std::string & str,const std::string & sub)474 bool StartWith(const std::string& str, const std::string& sub)
475 {
476     return str.find(sub) == 0;
477 }
478 
EndWith(const std::string & str,const std::string & sub)479 bool EndWith(const std::string& str, const std::string& sub)
480 {
481     size_t index = str.rfind(sub);
482     if (index == std::string::npos) {
483         return false;
484     }
485     return index + sub.size() == str.size();
486 }
487 
IsValidRegex(const std::string & regStr)488 bool IsValidRegex(const std::string& regStr)
489 {
490     // ignore empty regx
491     if (regStr.empty()) {
492         return true;
493     }
494 
495     int flags = REG_EXTENDED;
496     regex_t reg;
497     int status = regcomp(&reg, regStr.c_str(), flags);
498     // free regex
499     regfree(&reg);
500     return (status == REG_OK);
501 }
502 } // namespace StringUtil
503 } // namespace HiviewDFX
504 } // namespace OHOS
505