• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
17 #include <dlfcn.h>
18 
19 #include "localebuilder.h"
20 #include "locale_config.h"
21 #include "locid.h"
22 #include "hilog/log.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 
31 
32 namespace OHOS {
33 namespace Global {
34 namespace I18n {
35 const int RECV_CHAR_LEN = 128;
36 using i18n::phonenumbers::PhoneNumberUtil;
37 static constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, 0xD001E00, "PhoneNumberFormat" };
38 using namespace OHOS::HiviewDFX;
39 void* PhoneNumberFormat::dynamicHandler = nullptr;
40 std::mutex PhoneNumberFormat::phoneMutex;
41 
PhoneNumberFormat(const std::string & countryTag,const std::map<std::string,std::string> & options)42 PhoneNumberFormat::PhoneNumberFormat(const std::string &countryTag,
43                                      const std::map<std::string, std::string> &options)
44 {
45     util = PhoneNumberUtil::GetInstance();
46     if (LocaleConfig::IsValidRegion(countryTag)) {
47         country = countryTag;
48     } else {
49         icu::Locale locale = icu::Locale::createFromName(countryTag.c_str());
50         country = locale.getCountry();
51     }
52     std::string type = "";
53     auto search = options.find("type");
54     if (search != options.end()) {
55         type = search->second;
56     }
57 
58     std::map<std::string, PhoneNumberUtil::PhoneNumberFormat> type2PhoneNumberFormat = {
59         {"E164", PhoneNumberUtil::PhoneNumberFormat::E164},
60         {"RFC3966", PhoneNumberUtil::PhoneNumberFormat::RFC3966},
61         {"INTERNATIONAL", PhoneNumberUtil::PhoneNumberFormat::INTERNATIONAL},
62         {"NATIONAL", PhoneNumberUtil::PhoneNumberFormat::NATIONAL}
63     };
64 
65     std::set<std::string> validType = {"E164", "RFC3966", "INTERNATIONAL", "NATIONAL"};
66     if (validType.find(type) != validType.end()) {
67         phoneNumberFormat = type2PhoneNumberFormat[type];
68     } else {
69         phoneNumberFormat = PhoneNumberUtil::PhoneNumberFormat::NATIONAL;
70     }
71 }
72 
~PhoneNumberFormat()73 PhoneNumberFormat::~PhoneNumberFormat()
74 {
75 }
76 
CloseDynamicHandler()77 void PhoneNumberFormat::CloseDynamicHandler()
78 {
79     if (dynamicHandler != nullptr) {
80         dlclose(dynamicHandler);
81     }
82     dynamicHandler = nullptr;
83 }
84 
CreateInstance(const std::string & countryTag,const std::map<std::string,std::string> & options)85 std::unique_ptr<PhoneNumberFormat> PhoneNumberFormat::CreateInstance(const std::string &countryTag,
86     const std::map<std::string, std::string> &options)
87 {
88     std::unique_ptr<PhoneNumberFormat> phoneNumberFormat = std::make_unique<PhoneNumberFormat>(countryTag, options);
89     if (phoneNumberFormat->GetPhoneNumberUtil() == nullptr) {
90         return nullptr;
91     }
92     return phoneNumberFormat;
93 }
94 
GetPhoneNumberUtil()95 PhoneNumberUtil* PhoneNumberFormat::GetPhoneNumberUtil()
96 {
97     return util;
98 }
99 
isValidPhoneNumber(const std::string & number) const100 bool PhoneNumberFormat::isValidPhoneNumber(const std::string &number) const
101 {
102     i18n::phonenumbers::PhoneNumber phoneNumber;
103     PhoneNumberUtil::ErrorType type = util->Parse(number, country, &phoneNumber);
104     if (type != PhoneNumberUtil::ErrorType::NO_PARSING_ERROR) {
105         return false;
106     }
107     return util->IsValidNumber(phoneNumber);
108 }
109 
format(const std::string & number) const110 std::string PhoneNumberFormat::format(const std::string &number) const
111 {
112     i18n::phonenumbers::PhoneNumber phoneNumber;
113     PhoneNumberUtil::ErrorType type = util->Parse(number, country, &phoneNumber);
114     if (type != PhoneNumberUtil::ErrorType::NO_PARSING_ERROR) {
115         return "";
116     }
117     std::string formatted_number;
118     util->Format(phoneNumber, phoneNumberFormat, &formatted_number);
119     return formatted_number;
120 }
121 
getLocationName(const std::string & number,const std::string & locale)122 std::string PhoneNumberFormat::getLocationName(const std::string &number, const std::string &locale)
123 {
124     // Combine country and locale parameters
125     UErrorCode status = U_ZERO_ERROR;
126     icu::Locale displayLocale = icu::Locale::createFromName(locale.c_str());
127     displayLocale.addLikelySubtags(status);
128     icu::LocaleBuilder builder = icu::LocaleBuilder().setRegion(country);
129     builder.setLanguage(displayLocale.getLanguage());
130     builder.setScript(displayLocale.getScript());
131     icu::Locale phoneLocale = builder.build(status);
132 
133     i18n::phonenumbers::PhoneNumber phoneNumber;
134     PhoneNumberUtil::ErrorType type = util->Parse(number, phoneLocale.getCountry(), &phoneNumber);
135     if (type != PhoneNumberUtil::ErrorType::NO_PARSING_ERROR) {
136         return "";
137     }
138     std::string regionCode;
139     util->GetRegionCodeForNumber(phoneNumber, &regionCode);
140 
141     std::string locName = getPhoneLocationName(number, phoneLocale.getName(), locale, regionCode);
142 
143     icu::LocaleBuilder regionbuilder = icu::LocaleBuilder().setRegion(regionCode);
144     icu::Locale regionLocale = builder.build(status);
145     icu::UnicodeString displayRegion;
146     regionLocale.getDisplayCountry(displayLocale, displayRegion);
147     std::string displayCountryName;
148     displayRegion.toUTF8String(displayCountryName);
149 
150     // Check if region name is a country name
151     if (locName.compare(displayCountryName) == 0) {
152         if (getBlockedRegionName(regionCode, displayLocale.getLanguage())) {
153             return "";
154         }
155 
156         TabooUtils taboo;
157         return taboo.ReplaceCountryName(regionCode, locale, displayCountryName);
158     }
159 
160     // Process the city name
161     std::string formatted_number;
162     util->Format(phoneNumber, PhoneNumberUtil::PhoneNumberFormat::E164, &formatted_number);
163     return getCityName(locale, formatted_number.substr(1), locName);
164 }
165 
getPhoneLocationName(const std::string & number,const std::string & phoneLocale,const std::string & displayLocale,const std::string & regionCode)166 std::string PhoneNumberFormat::getPhoneLocationName(const std::string& number, const std::string& phoneLocale,
167     const std::string& displayLocale, const std::string& regionCode)
168 {
169     OpenHandler();
170     if (dynamicHandler && !locationNameFunc) {
171         HiLog::Error(LABEL, "LocationNameFunc Init");
172         locationNameFunc = reinterpret_cast<ExposeLocationName>(dlsym(dynamicHandler, "exposeLocationName"));
173     }
174     std::string locName;
175     if (locationNameFunc) {
176         // The function uses the same locale for phone and display.
177         char recvArr[RECV_CHAR_LEN];
178         locationNameFunc(number.c_str(), phoneLocale.c_str(), recvArr, RECV_CHAR_LEN);
179         locName = recvArr;
180     }
181     if (!locationNameFunc || locName.empty()) {
182         locName = LocaleConfig::GetDisplayRegion(regionCode, displayLocale, false);
183     }
184     return locName;
185 }
186 
OpenHandler()187 void PhoneNumberFormat::OpenHandler()
188 {
189     if (dynamicHandler == nullptr) {
190         HiLog::Info(LABEL, "DynamicHandler init.");
191         std::lock_guard<std::mutex> phoneLock(phoneMutex);
192         if (dynamicHandler == nullptr) {
193 #ifndef SUPPORT_ASAN
194             const char* geocodingSO = "libgeocoding.z.so";
195 #else
196             const char* geocodingSO = "system/asan/lib64/libgeocoding.z.so";
197 #endif
198             HiLog::Info(LABEL, "DynamicHandler lock init.");
199             dynamicHandler = dlopen(geocodingSO, RTLD_NOW);
200         }
201     }
202 }
203 
getBlockedRegionName(const std::string & regionCode,const std::string & language)204 bool PhoneNumberFormat::getBlockedRegionName(const std::string& regionCode, const std::string& language)
205 {
206     void *i18nUtilHandle = dlopen("libi18n_util.z.so", RTLD_NOW);
207     if (i18nUtilHandle == nullptr) {
208         return false;
209     }
210     GetBlockedRegionName getBlockedRegionName = (GetBlockedRegionName)dlsym(i18nUtilHandle, "GetBlockedRegionName");
211     if (getBlockedRegionName) {
212         return getBlockedRegionName(language.c_str(), regionCode.c_str());
213     } else {
214         return false;
215     }
216 }
217 
getCityName(const std::string & language,const std::string & phonenumber,const std::string & locationName)218 std::string PhoneNumberFormat::getCityName(const std::string& language, const std::string& phonenumber,
219     const std::string& locationName)
220 {
221     char recvArr[RECV_CHAR_LEN];
222     int err = strcpy_s(recvArr, RECV_CHAR_LEN, locationName.c_str());
223     if (err != 0) {
224         return locationName;
225     }
226     void *i18nUtilHandle = dlopen("libi18n_util.z.so", RTLD_NOW);
227     if (i18nUtilHandle == nullptr) {
228         return locationName;
229     }
230     GetBlockedPhoneLocationName getBlockedPhoneLocationName =
231         (GetBlockedPhoneLocationName)dlsym(i18nUtilHandle, "GetBlockedPhoneLocationName");
232     if (getBlockedPhoneLocationName) {
233         getBlockedPhoneLocationName(language.c_str(), phonenumber.c_str(), recvArr);
234     }
235     if (locationName.compare(recvArr) != 0) {
236         return "";
237     }
238 
239     GetReplacedPhoneLocationName getReplacedPhoneLocationName =
240         (GetReplacedPhoneLocationName)dlsym(i18nUtilHandle, "GetReplacedPhoneLocationName");
241     if (getReplacedPhoneLocationName) {
242         getReplacedPhoneLocationName(language.c_str(), phonenumber.c_str(), recvArr);
243     }
244     std::string ret(recvArr);
245     return ret;
246 }
247 } // namespace I18n
248 } // namespace Global
249 } // namespace OHOS
250