1/*
2 * Copyright (c) 2021 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_ex.h"
17#include "unicode_ex.h"
18#include "utils_log.h"
19#include "securec.h"
20#include <iostream>
21#include <iomanip>
22#include <sstream>
23using namespace std;
24
25namespace OHOS {
26
27static const int CHAR16_TO_CHAR8_PARAM_INVALID = -1;
28static const int CHAR16_TO_CHAR8_EMPTY_STR = -2;
29static const int CHAR16_TO_CHAR8_INSUFFICIENT_BUFFER = -3;
30
31string UpperStr(const string& str)
32{
33    string upperString = str;
34    transform(upperString.begin(), upperString.end(), upperString.begin(), ::toupper);
35    return upperString;
36}
37
38string LowerStr(const string& str)
39{
40    string lowerString = str;
41    transform(lowerString.begin(), lowerString.end(), lowerString.begin(), ::tolower);
42    return lowerString;
43}
44
45string ReplaceStr(const string& str, const string& src, const string& dst)
46{
47    if (src.empty()) {
48        return str;
49    }
50
51    string::size_type pos = 0;
52    string strTmp = str;
53    while ((pos = strTmp.find(src, pos)) != string::npos) {
54        strTmp.replace(pos, src.length(), dst);
55        pos += dst.length();
56    }
57
58    return strTmp;
59}
60
61string TrimStr(const string& str, const char cTrim /*= ' '*/)
62{
63    if (str.size() == 1 && str[0] == cTrim) {
64        return string{};
65    }
66
67    string strTmp = str;
68    std::string::size_type firstBound = strTmp.find_first_not_of(cTrim);
69    if (firstBound != std::string::npos) {
70        strTmp.erase(0, firstBound);
71    }
72
73    std::string::size_type lastBound = strTmp.find_last_not_of(cTrim);
74    if (lastBound != std::string::npos && lastBound != strTmp.size() - 1) {
75        strTmp.erase(lastBound + sizeof(char));
76    }
77
78    return strTmp;
79}
80
81string DexToHexString(int value, bool upper /*= true*/)
82{
83    stringstream ioss;
84    string hexString;
85    if (upper) {
86        ioss << setiosflags(ios::uppercase) << hex << value;
87    } else {
88        ioss << hex << value;
89    }
90
91    ioss >> hexString;
92    return hexString;
93}
94
95void SplitStr(const string& str, const string& sep, vector<string>& strs, bool canEmpty, bool needTrim)
96{
97    strs.clear();
98    string strTmp = needTrim ? TrimStr(str) : str;
99    string strPart;
100    while (true) {
101        string::size_type pos = strTmp.find(sep);
102        if (string::npos == pos || sep.empty()) {
103            strPart = needTrim ? TrimStr(strTmp) : strTmp;
104            if (!strPart.empty() || canEmpty) {
105                strs.push_back(strPart);
106            }
107            break;
108        } else {
109            strPart = needTrim ? TrimStr(strTmp.substr(0, pos)) : strTmp.substr(0, pos);
110            if (!strPart.empty() || canEmpty) {
111                strs.push_back(strPart);
112            }
113            strTmp = strTmp.substr(sep.size() + pos, strTmp.size() - sep.size() - pos);
114        }
115    }
116}
117
118bool StrToInt(const string& str, int& value)
119{
120    if (str.empty() || (!isdigit(str.front()) && (str.front() != '-'))) {
121        return false;
122    }
123
124    char* end = nullptr;
125    errno = 0;
126    auto addr = str.c_str();
127    auto result = strtol(addr, &end, 10); /* 10 means decimal */
128    if ((end == addr) || (end[0] != '\0') || (errno == ERANGE) ||
129            (result > INT_MAX) || (result < INT_MIN)) {
130        return false;
131    }
132    value = static_cast<int>(result);
133    return true;
134}
135
136bool IsNumericStr(const string& str)
137{
138    if (str.empty()) {
139        return false;
140    }
141
142    for (const auto& c : str) {
143        if (!isdigit(c)) {
144            return false;
145        }
146    }
147
148    return true;
149}
150
151bool IsAlphaStr(const string& str)
152{
153    if (str.empty()) {
154        return false;
155    }
156
157    for (const auto& c : str) {
158        if (!isalpha(c)) {
159            return false;
160        }
161    }
162
163    return true;
164}
165
166bool IsUpperStr(const string& str)
167{
168    if (str.empty()) {
169        return false;
170    }
171
172    for (const auto& c : str) {
173        if (!isupper(c)) {
174            return false;
175        }
176    }
177
178    return true;
179}
180
181bool IsLowerStr(const string& str)
182{
183    if (str.empty()) {
184        return false;
185    }
186
187    for (const auto& c : str) {
188        if (!islower(c)) {
189            return false;
190        }
191    }
192
193    return true;
194}
195
196bool IsSubStr(const string& str, const string& sub)
197{
198    if (sub.empty() || str.empty()) {
199        return false;
200    }
201
202    return str.find(sub) != string::npos;
203}
204
205string::size_type GetFirstSubStrBetween(const string& str, const string& left,
206    const string& right, string& sub)
207{
208    string::size_type leftPos = str.find(left);
209    if (leftPos == string::npos) {
210        return string::npos;
211    }
212
213    string::size_type rightPos = str.find(right, leftPos + left.length());
214    if (rightPos == string::npos) {
215        return string::npos;
216    }
217
218    sub = str.substr((leftPos + left.length()), (rightPos - (leftPos + left.length())));
219    return rightPos;
220}
221
222void GetSubStrBetween(const string& str, const string& left, const string& right, vector<string>& sub)
223{
224    string subString;
225    string strTmp = str;
226    string::size_type pos = GetFirstSubStrBetween(strTmp, left, right, subString);
227    while (pos != string::npos) {
228        sub.push_back(subString);
229        strTmp = strTmp.substr(pos);
230        pos = GetFirstSubStrBetween(strTmp, left, right, subString);
231    }
232}
233
234bool IsSameTextStr(const string& first, const string& second)
235{
236    return UpperStr(first) == UpperStr(second);
237}
238
239/*
240 * utf8 rule
241 * 0000 ~ 007F        : 0xxxxxxx
242 * 0080 ~ 07FF        : 110xxxxx 10xxxxxx
243 * 0800 ~ FFFF        : 1110xxxx 10xxxxxx 10xxxxxx
244 * 10000 ~ 1FFFFF     : 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
245 */
246bool IsAsciiString(const string& str)
247{
248    size_t strLen = str.length();
249    for (size_t i = 0; i < strLen; ++i) {
250        if ((str[i] & 0x80) != 0) {
251            return false;
252        }
253    }
254
255    return true;
256}
257
258#ifndef IOS_PLATFORM
259u16string Str8ToStr16(const string& str)
260{
261    u16string str16Value;
262    if (!String8ToString16(str, str16Value)) {
263        return u16string();
264    }
265
266    return str16Value;
267}
268
269string Str16ToStr8(const u16string& str16)
270{
271    string str8Value;
272    if (!String16ToString8(str16, str8Value)) {
273        return string();
274    }
275
276    return str8Value;
277}
278
279int GetUtf16ToUtf8Length(const u16string& str16)
280{
281    size_t str16Len = str16.length();
282    if (str16Len == 0) {
283        return -1;
284    }
285    const char16_t *utf16Str = str16.c_str();
286    return Utf16ToUtf8Length(utf16Str, str16Len);
287}
288
289int Char16ToChar8(const u16string& str16, char *buffer, int bufferLen)
290{
291    if (buffer == nullptr || bufferLen <= 0) {
292        return CHAR16_TO_CHAR8_PARAM_INVALID;
293    }
294    size_t str16Len = str16.length();
295    if (str16Len == 0) {
296        return CHAR16_TO_CHAR8_EMPTY_STR;
297    }
298    const char16_t *utf16Str = str16.c_str();
299    int utf8Len = Utf16ToUtf8Length(utf16Str, str16Len);
300    if (utf8Len < 0 || utf8Len >= INT_MAX || (utf8Len + 1) > bufferLen) {
301        UTILS_LOGD("utf8buffer len:%{public}d, actual buffer len:%{public}d!", utf8Len + 1, bufferLen);
302        return CHAR16_TO_CHAR8_INSUFFICIENT_BUFFER;
303    }
304    StrncpyStr16ToStr8(utf16Str, str16Len, buffer, utf8Len + 1);
305    return utf8Len + 1;
306}
307
308#endif
309} // namespace OHOS
310