1 /*
2  * Copyright (c) 2022 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 "utils/psue_manager.h"
17 
18 #include <algorithm>
19 #include <cctype>
20 #include <cstdlib>
21 #include <iostream>
22 #include <string>
23 #include <unzip.h>
24 #include <vector>
25 #include "hilog_wrapper.h"
26 #include "map"
27 #include "utils/errors.h"
28 #ifdef __WINNT__
29 #include <windows.h>
30 #undef ERROR
31 #endif
32 
33 namespace OHOS {
34 namespace Global {
35 namespace Resource {
36 using namespace std;
37 
38 namespace {
39 const float DEFAULT_EXTEND_RATIO = 0.3f;
40 
41 struct ExtendRatioTable {
42     int32_t count;
43     float ratio;
44 };
45 
46 const ExtendRatioTable EXTEND_RATIO_RABLE[] = {
47     {10, 2.0f},
48     {20, 1.0f},
49     {30, 0.8f},
50     {50, 0.6f},
51     {70, 0.4f},
52 };
53 const std::wstring PSUE_CONFIG_CHARS = {L"ReÇÉÄßÑ¿ÃóèìжДﺥ"};
54 
55 const map<wchar_t, wchar_t> REPLACE_TABLE {
56     {L'a', L'à'},
57     {L'A', L'À'},
58     {L'c', L'ć'},
59     {L'C', L'Ć'},
60     {L'i', L'ì'},
61     {L'I', L'Ì'},
62     {L'o', L'ó'},
63     {L'O', L'Ó'},
64     {L'u', L'ü'},
65     {L'U', L'Ü'},
66     {L'y', L'ÿ'},
67     {L'Y', L'Ÿ'},
68     {L'z', L'ž'},
69     {L'Z', L'Ž'},
70 };
71 }
72 
PsueManager()73 PsueManager::PsueManager()
74 {
75 }
76 
~PsueManager()77 PsueManager::~PsueManager()
78 {
79 }
80 
81 /**
82   PsuedoTranslation level default value is 3
83   1. Enclosed in brackets
84   2. Letter replacement
85   3. Lengthen string
86 */
87 int g_fakeLocaleLevel = 3;
88 
89 int g_levelForReplace = 2;
90 int g_levelForAppend = 3;
91 int g_levelForAddBracket = 1;
92 
Convert(const std::string & src,std::string & dest)93 std::string PsueManager::Convert(const std::string &src, std::string &dest)
94 {
95     if (isDigit(src)) {
96         return "";
97     }
98     std::wstring ws;
99     std::string wsStr = ToWstring(ws, src);
100     if (wsStr != "") {
101         return wsStr;
102     }
103     if (g_fakeLocaleLevel >= g_levelForReplace) {
104         // char replace
105         ToAccent(ws);
106     }
107     if (g_fakeLocaleLevel == g_levelForAppend) {
108         // enhance length
109         unsigned int len = src.length();
110         unsigned int extendCount = len * GetExtendRatio(len);
111         unsigned int loop = extendCount / PSUE_CONFIG_CHARS.length();
112         unsigned int left = extendCount % PSUE_CONFIG_CHARS.length();
113         for (unsigned int i = 0; i < loop ; i++) {
114             ws += PSUE_CONFIG_CHARS;
115         }
116         if (left > 0) {
117             ws += PSUE_CONFIG_CHARS.substr(0, left);
118         }
119     }
120     std::string tsStr = ToString(dest, ws);
121     if (tsStr != "") {
122         return tsStr;
123     }
124     if (g_fakeLocaleLevel >= g_levelForAddBracket) {
125         // add brackets
126         dest = '[' + dest + ']';
127     }
128     return "";
129 }
130 
isDigit(const std::string src)131 bool PsueManager::isDigit(const std::string src)
132 {
133     for (unsigned int i = 0 ; i < src.size() ; i++) {
134         if (!isdigit(src[i])) {
135             return false;
136         }
137     }
138     return true;
139 }
140 
GetExtendRatio(int32_t len) const141 float PsueManager::GetExtendRatio(int32_t len) const
142 {
143     for (size_t i = 0; i < sizeof(EXTEND_RATIO_RABLE) / sizeof(EXTEND_RATIO_RABLE[0]) ; i++) {
144         if (len <= EXTEND_RATIO_RABLE[i].count) {
145             return EXTEND_RATIO_RABLE[i].ratio;
146         }
147     }
148     return DEFAULT_EXTEND_RATIO;
149 }
150 
151 // letter replace
ToAccent(wstring & ws) const152 void PsueManager::ToAccent(wstring &ws) const
153 {
154     for (std::wstring::size_type i = 0 ; i < ws.length(); i++) {
155         if (ws[i] == L'%') {
156             i++;
157         } else if (ws[i] == L'{') {
158             while ((i + 1 < ws.length()) && (ws[++i] != L'}')) {}
159         } else {
160             auto iter = REPLACE_TABLE.find(ws[i]);
161             if (iter != REPLACE_TABLE.end()) {
162                 ws[i] = iter->second;
163             }
164         }
165     }
166 }
167 
ToWstring(std::wstring & dest,const std::string & src)168 std::string PsueManager::ToWstring(std::wstring &dest, const std::string &src)
169 {
170     std::string result = setlocale(LC_CTYPE, "");
171     size_t destSize = mbstowcs(NULL, src.c_str(), 0);
172     if (destSize == size_t(-1)) {
173         cout << result << endl;
174         return "get widechar size fail ";
175     }
176     vector<wchar_t> buf(destSize + 1);
177     if (mbstowcs(&buf[0], src.c_str(), src.size()) == static_cast<size_t>(-1)) {
178         return "convert to widechar fail";
179     }
180 
181     dest.assign(buf.begin(), buf.end() - 1);
182     return "";
183 }
184 
ToString(std::string & dest,const std::wstring & src)185 std::string PsueManager::ToString(std::string &dest, const std::wstring &src)
186 {
187     size_t destSize = wcstombs(NULL, src.c_str(), 0);
188     if (destSize == size_t(-1)) {
189         return "get multibyte size fail";
190     }
191     vector<char> buf(destSize + 1);
192     if (wcstombs(&buf[0], src.c_str(), buf.size()) == static_cast<size_t>(-1)) {
193         return "convert to multibyte fail";
194     }
195 
196     dest.assign(buf.begin(), buf.end() - 1);
197     return "";
198 }
199 
SetFakeLocaleLevel(const int level)200 void PsueManager::SetFakeLocaleLevel(const int level)
201 {
202     if (level <= g_levelForAppend && level >= g_levelForAddBracket) {
203         g_fakeLocaleLevel = level;
204     }
205 }
206 
IsAsciiString(const std::string & src)207 bool PsueManager::IsAsciiString(const std::string &src)
208 {
209     bool isAscii = true;
210     for (size_t i = 0; i < src.length(); i++) {
211         if (src[i] < 0 || src[i] > 127) {  // 127 is the max value of ascii
212             isAscii = false;
213             break;
214         }
215     }
216     return isAscii;
217 }
218 
BidirectionConvert(std::string & src)219 std::string PsueManager::BidirectionConvert(std::string &src)
220 {
221     if (!IsAsciiString(src)) {
222         return src;
223     }
224     std::string result;
225     size_t start = 0;
226     size_t end = 0;
227     while (start < src.length()) {
228         while (start < src.length() && isspace(src[start])) {
229             start++;
230         }
231         if (start > end) {
232             result += src.substr(end, start - end);
233         }
234         end = start;
235         while (end < src.length() && !isspace(src[end])) {
236             end++;
237         }
238         if (start < src.length()) {
239             result += directionHead;
240             result += src.substr(start, end - start);
241             result += directionTail;
242         }
243         start = end;
244     }
245     return result;
246 }
247 } // namespace Resource
248 } // namespace Global
249 } // namespace OHOS