1 /*
2 * Copyright (c) 2021-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 #include "phone_number_format.h"
16 #include <cctype>
17 #include <dlfcn.h>
18 #include <regex>
19 #include "unicode/localebuilder.h"
20 #include "locale_config.h"
21 #include "unicode/locid.h"
22 #include "i18n_hilog.h"
23 #include "map"
24 #include "new"
25 #include "set"
26 #include "securec.h"
27 #include "string"
28 #include "taboo_utils.h"
29 #include "utility"
30 #include "utils.h"
31
32 namespace OHOS {
33 namespace Global {
34 namespace I18n {
35 const int RECV_CHAR_LEN = 128;
36 using i18n::phonenumbers::PhoneNumberUtil;
37 void* PhoneNumberFormat::dynamicHandler = nullptr;
38 std::mutex PhoneNumberFormat::phoneMutex;
39 std::mutex PhoneNumberFormat::AS_YOU_TYPE_FORMAT_MUTEX;
40 size_t PhoneNumberFormat::MAX_NUMBER_LENGTH = 30;
41 std::map<char, char> PhoneNumberFormat::VALID_PHONE_NUMBER_CHARS {
42 { '+', '+' },
43 { ' ', ' ' },
44 { '*', '*' },
45 { '-', '-' },
46 { '#', '#' },
47 { '(', '(' },
48 { ')', ')' },
49 { ';', ';' },
50 { ',', ',' },
51 { 'A', '2' },
52 { 'B', '2' },
53 { 'C', '2' },
54 { 'D', '3' },
55 { 'E', '3' },
56 { 'F', '3' },
57 { 'G', '4' },
58 { 'H', '4' },
59 { 'I', '4' },
60 { 'J', '5' },
61 { 'K', '5' },
62 { 'L', '5' },
63 { 'M', '6' },
64 { 'N', '6' },
65 { 'O', '6' },
66 { 'P', '7' },
67 { 'Q', '7' },
68 { 'R', '7' },
69 { 'S', '7' },
70 { 'T', '8' },
71 { 'U', '8' },
72 { 'V', '8' },
73 { 'W', '9' },
74 { 'X', '9' },
75 { 'Y', '9' },
76 { 'Z', '9' },
77 { 'a', '2' },
78 { 'b', '2' },
79 { 'c', '2' },
80 { 'd', '3' },
81 { 'e', '3' },
82 { 'f', '3' },
83 { 'g', '4' },
84 { 'h', '4' },
85 { 'i', '4' },
86 { 'j', '5' },
87 { 'k', '5' },
88 { 'l', '5' },
89 { 'm', '6' },
90 { 'n', '6' },
91 { 'o', '6' },
92 { 'p', '7' },
93 { 'q', '7' },
94 { 'r', '7' },
95 { 's', '7' },
96 { 't', '8' },
97 { 'u', '8' },
98 { 'v', '8' },
99 { 'w', '9' },
100 { 'x', '9' },
101 { 'y', '9' },
102 { 'z', '9' },
103 };
104
PhoneNumberFormat(const std::string & countryTag,const std::map<std::string,std::string> & options)105 PhoneNumberFormat::PhoneNumberFormat(const std::string &countryTag,
106 const std::map<std::string, std::string> &options)
107 {
108 util = PhoneNumberUtil::GetInstance();
109 if (LocaleConfig::IsValidRegion(countryTag)) {
110 country = countryTag;
111 } else {
112 icu::Locale locale = icu::Locale::createFromName(countryTag.c_str());
113 country = locale.getCountry();
114 }
115 std::string type = "";
116 auto search = options.find("type");
117 if (search != options.end()) {
118 type = search->second;
119 }
120
121 std::map<std::string, PhoneNumberUtil::PhoneNumberFormat> type2PhoneNumberFormat = {
122 {"E164", PhoneNumberUtil::PhoneNumberFormat::E164},
123 {"RFC3966", PhoneNumberUtil::PhoneNumberFormat::RFC3966},
124 {"INTERNATIONAL", PhoneNumberUtil::PhoneNumberFormat::INTERNATIONAL},
125 {"NATIONAL", PhoneNumberUtil::PhoneNumberFormat::NATIONAL}
126 };
127
128 std::set<std::string> validType = {"E164", "RFC3966", "INTERNATIONAL", "NATIONAL"};
129 if (validType.find(type) != validType.end()) {
130 withOptions = true;
131 phoneNumberFormat = type2PhoneNumberFormat[type];
132 } else {
133 phoneNumberFormat = PhoneNumberUtil::PhoneNumberFormat::NATIONAL;
134 }
135 if (type.compare("TYPING") == 0) {
136 formatter = std::unique_ptr<AsYouTypeFormatter>(util->GetAsYouTypeFormatter(country));
137 }
138 }
139
~PhoneNumberFormat()140 PhoneNumberFormat::~PhoneNumberFormat()
141 {
142 }
143
CloseDynamicHandler()144 void PhoneNumberFormat::CloseDynamicHandler()
145 {
146 std::lock_guard<std::mutex> phoneLock(phoneMutex);
147 if (dynamicHandler != nullptr) {
148 dlclose(dynamicHandler);
149 }
150 dynamicHandler = nullptr;
151 }
152
CreateInstance(const std::string & countryTag,const std::map<std::string,std::string> & options)153 std::unique_ptr<PhoneNumberFormat> PhoneNumberFormat::CreateInstance(const std::string &countryTag,
154 const std::map<std::string, std::string> &options)
155 {
156 std::unique_ptr<PhoneNumberFormat> phoneNumberFormat = std::make_unique<PhoneNumberFormat>(countryTag, options);
157 if (phoneNumberFormat->GetPhoneNumberUtil() == nullptr) {
158 return nullptr;
159 }
160 return phoneNumberFormat;
161 }
162
GetPhoneNumberUtil()163 PhoneNumberUtil* PhoneNumberFormat::GetPhoneNumberUtil()
164 {
165 return util;
166 }
167
isValidPhoneNumber(const std::string & number) const168 bool PhoneNumberFormat::isValidPhoneNumber(const std::string &number) const
169 {
170 i18n::phonenumbers::PhoneNumber phoneNumber;
171 PhoneNumberUtil::ErrorType type = util->Parse(number, country, &phoneNumber);
172 if (type != PhoneNumberUtil::ErrorType::NO_PARSING_ERROR) {
173 return false;
174 }
175 return util->IsValidNumber(phoneNumber);
176 }
177
format(const std::string & number)178 std::string PhoneNumberFormat::format(const std::string &number)
179 {
180 std::string formatted_number;
181 if (formatter != nullptr) {
182 formatted_number = GetAsYouTypeFormatResult(number);
183 return PseudoLocalizationProcessor(formatted_number);
184 }
185 i18n::phonenumbers::PhoneNumber phoneNumber;
186 PhoneNumberUtil::ErrorType type = util->ParseAndKeepRawInput(number, country, &phoneNumber);
187 if (type != PhoneNumberUtil::ErrorType::NO_PARSING_ERROR) {
188 return PseudoLocalizationProcessor("");
189 }
190 const std::string prefix = "106";
191 if (number.compare(0, prefix.length(), prefix) == 0) {
192 util->FormatInOriginalFormat(phoneNumber, country, &formatted_number);
193 } else {
194 util->Format(phoneNumber, phoneNumberFormat, &formatted_number);
195 }
196 return PseudoLocalizationProcessor(formatted_number);
197 }
198
GetAsYouTypeFormatResult(const std::string & number)199 std::string PhoneNumberFormat::GetAsYouTypeFormatResult(const std::string &number)
200 {
201 std::lock_guard<std::mutex> formatLock(AS_YOU_TYPE_FORMAT_MUTEX);
202 if (formatter == nullptr || number.length() > MAX_NUMBER_LENGTH) {
203 return number;
204 }
205 std::regex pattern("[^\\d]");
206 std::string phoneNumber = std::regex_replace(number, pattern, "");
207 if (lastFormatNumber.length() > 0 && phoneNumber.length() == lastFormatNumber.length() + 1) {
208 if (phoneNumber.compare(0, lastFormatNumber.length(), lastFormatNumber) != 0) {
209 return FormatAllInputNumber(number, phoneNumber);
210 }
211 char lastChar = *(phoneNumber.rbegin());
212 std::string result;
213 this->lastFormatNumber = phoneNumber;
214 return formatter->InputDigit(lastChar, &result);
215 }
216
217 return FormatAllInputNumber(number, phoneNumber);
218 }
219
FormatAllInputNumber(const std::string & originalNumber,std::string & replacedNumber)220 std::string PhoneNumberFormat::FormatAllInputNumber(const std::string &originalNumber,
221 std::string &replacedNumber)
222 {
223 formatter->Clear();
224 this->lastFormatNumber = replacedNumber;
225 std::string result;
226 std::string formattedNumber;
227 for (size_t i = 0; i < originalNumber.length(); i++) {
228 char c = originalNumber.at(i);
229 auto iter = VALID_PHONE_NUMBER_CHARS.find(c);
230 if (isdigit(c)) {
231 formattedNumber = formatter->InputDigit(c, &result);
232 } else if (iter != VALID_PHONE_NUMBER_CHARS.end()) {
233 char replacedChar = VALID_PHONE_NUMBER_CHARS[c];
234 formattedNumber = formatter->InputDigit(replacedChar, &result);
235 }
236 }
237 return formattedNumber;
238 }
239
getLocationName(const std::string & number,const std::string & locale)240 std::string PhoneNumberFormat::getLocationName(
241 const std::string &number, const std::string &locale)
242 {
243 // Combine country and locale parameters
244 UErrorCode status = U_ZERO_ERROR;
245 icu::Locale displayLocale = icu::Locale::createFromName(locale.c_str());
246 displayLocale.addLikelySubtags(status);
247 icu::LocaleBuilder builder = icu::LocaleBuilder().setRegion(country);
248 builder.setLanguage(displayLocale.getLanguage());
249 builder.setScript(displayLocale.getScript());
250 icu::Locale phoneLocale = builder.build(status);
251
252 i18n::phonenumbers::PhoneNumber phoneNumber;
253 PhoneNumberUtil::ErrorType type = util->Parse(number, phoneLocale.getCountry(), &phoneNumber);
254 if (type != PhoneNumberUtil::ErrorType::NO_PARSING_ERROR) {
255 return "";
256 }
257 std::string regionCode;
258 util->GetRegionCodeForNumber(phoneNumber, ®ionCode);
259
260 std::string locName = getPhoneLocationName(number, phoneLocale.getName(), locale, regionCode);
261
262 icu::LocaleBuilder regionbuilder = icu::LocaleBuilder().setRegion(regionCode);
263 icu::Locale regionLocale = builder.build(status);
264 icu::UnicodeString displayRegion;
265 regionLocale.getDisplayCountry(displayLocale, displayRegion);
266 std::string displayCountryName;
267 displayRegion.toUTF8String(displayCountryName);
268
269 // Check if region name is a country name
270 if (locName.compare(displayCountryName) == 0) {
271 if (getBlockedRegionName(regionCode, displayLocale.getLanguage())) {
272 return "";
273 }
274
275 TabooUtils taboo;
276 return taboo.ReplaceCountryName(regionCode, locale, displayCountryName);
277 }
278
279 // Process the city name
280 std::string formatted_number;
281 util->Format(phoneNumber, PhoneNumberUtil::PhoneNumberFormat::E164, &formatted_number);
282 return getCityName(locale, formatted_number.substr(1), locName);
283 }
284
getPhoneLocationName(const std::string & number,const std::string & phoneLocale,const std::string & displayLocale,const std::string & regionCode)285 std::string PhoneNumberFormat::getPhoneLocationName(
286 const std::string& number, const std::string& phoneLocale,
287 const std::string& displayLocale, const std::string& regionCode)
288 {
289 OpenHandler();
290 std::lock_guard<std::mutex> phoneLock(phoneMutex);
291 std::string locName;
292 if (dynamicHandler) {
293 HILOG_ERROR_I18N("LocationNameFunc Init");
294 ExposeLocationName locationNameFunc = reinterpret_cast<ExposeLocationName>(
295 dlsym(dynamicHandler, "exposeLocationName"));
296 if (locationNameFunc) {
297 // The function uses the same locale for phone and display.
298 char recvArr[RECV_CHAR_LEN];
299 const char* numberArr = number.c_str();
300 const char* phoneLocaleArr = phoneLocale.c_str();
301 locationNameFunc(numberArr, phoneLocaleArr, recvArr, RECV_CHAR_LEN);
302 locName = recvArr;
303 }
304 }
305 return locName;
306 }
307
OpenHandler()308 void PhoneNumberFormat::OpenHandler()
309 {
310 if (dynamicHandler == nullptr) {
311 HILOG_INFO_I18N("DynamicHandler init.");
312 std::lock_guard<std::mutex> phoneLock(phoneMutex);
313 if (dynamicHandler == nullptr) {
314 HILOG_INFO_I18N("DynamicHandler lock init.");
315 #ifndef SUPPORT_ASAN
316 const char* geocodingSO = "libgeocoding.z.so";
317 #else
318 const char* geocodingSO = "system/asan/lib64/platformsdk/libgeocoding.z.so";
319 #endif
320 HILOG_INFO_I18N("DynamicHandler lock init.");
321 dynamicHandler = dlopen(geocodingSO, RTLD_NOW);
322 }
323 }
324 }
325
getBlockedRegionName(const std::string & regionCode,const std::string & language)326 bool PhoneNumberFormat::getBlockedRegionName(
327 const std::string& regionCode, const std::string& language)
328 {
329 void *i18nUtilHandle = dlopen("libi18n_util.z.so", RTLD_NOW);
330 if (i18nUtilHandle == nullptr) {
331 return false;
332 }
333 GetBlockedRegionName getBlockedRegionName = (GetBlockedRegionName)dlsym(i18nUtilHandle, "GetBlockedRegionName");
334 bool ret = false;
335 if (getBlockedRegionName) {
336 ret = getBlockedRegionName(language.c_str(), regionCode.c_str());
337 }
338 dlclose(i18nUtilHandle);
339 i18nUtilHandle = nullptr;
340 return ret;
341 }
342
getCityName(const std::string & language,const std::string & phonenumber,const std::string & locationName)343 std::string PhoneNumberFormat::getCityName(
344 const std::string& language, const std::string& phonenumber,
345 const std::string& locationName)
346 {
347 char recvArr[RECV_CHAR_LEN];
348 int err = strcpy_s(recvArr, RECV_CHAR_LEN, locationName.c_str());
349 if (err != 0) {
350 return locationName;
351 }
352 void *i18nUtilHandle = dlopen("libi18n_util.z.so", RTLD_NOW);
353 if (i18nUtilHandle == nullptr) {
354 return locationName;
355 }
356 GetBlockedPhoneLocationName getBlockedPhoneLocationName =
357 (GetBlockedPhoneLocationName)dlsym(i18nUtilHandle, "GetBlockedPhoneLocationName");
358 if (getBlockedPhoneLocationName) {
359 getBlockedPhoneLocationName(language.c_str(), phonenumber.c_str(), recvArr);
360 }
361 if (locationName.compare(recvArr) != 0) {
362 dlclose(i18nUtilHandle);
363 i18nUtilHandle = nullptr;
364 return "";
365 }
366
367 GetReplacedPhoneLocationName getReplacedPhoneLocationName =
368 (GetReplacedPhoneLocationName)dlsym(i18nUtilHandle, "GetReplacedPhoneLocationName");
369 if (getReplacedPhoneLocationName) {
370 getReplacedPhoneLocationName(language.c_str(), phonenumber.c_str(), recvArr);
371 }
372 dlclose(i18nUtilHandle);
373 i18nUtilHandle = nullptr;
374 std::string ret(recvArr);
375 return ret;
376 }
377 } // namespace I18n
378 } // namespace Global
379 } // namespace OHOS
380