1 /*
2 * Copyright (c) 2023 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 <cctype>
16 #include <filesystem>
17 #include "phonenumbers/phonenumber.h"
18 #include "phonenumbers/shortnumberinfo.h"
19 #include "phonenumbers/phonenumberutil.h"
20 #include "i18n_hilog.h"
21 #include "libxml/globals.h"
22 #include "libxml/tree.h"
23 #include "libxml/xmlstring.h"
24 #include "matched_number_info.h"
25 #include "phone_number_rule.h"
26 #include "utils.h"
27
28 namespace OHOS {
29 namespace Global {
30 namespace I18n {
31 using i18n::phonenumbers::PhoneNumber;
32 using i18n::phonenumbers::PhoneNumberUtil;
33 using i18n::phonenumbers::ShortNumberInfo;
34
35 std::string PhoneNumberRule::xmlCommonPath = "/system/usr/ohos_locale_config/phonenumber/common.xml";
36
PhoneNumberRule(std::string & country)37 PhoneNumberRule::PhoneNumberRule(std::string& country)
38 {
39 xmlPath = "/system/usr/ohos_locale_config/phonenumber/" + country + ".xml";
40 isFixed = true;
41 try {
42 isFixed = std::filesystem::exists(xmlPath);
43 } catch (const std::filesystem::filesystem_error &except) {
44 HILOG_ERROR_I18N("FileExist failed because filesystem_error, error message: %{public}s.",
45 except.code().message().c_str());
46 isFixed = false;
47 } catch (const std::__h::__fs::filesystem::filesystem_error &except) {
48 HILOG_ERROR_I18N("FileExist failed because filesystem_error, error message: %{public}s.",
49 except.code().message().c_str());
50 isFixed = false;
51 } catch (const std::bad_alloc &except) {
52 HILOG_ERROR_I18N("FileExist failed because bad_alloc, error message: %{public}s.", except.what());
53 isFixed = false;
54 }
55 this->commonExit = false;
56 this->country = country;
57 }
58
~PhoneNumberRule()59 PhoneNumberRule::~PhoneNumberRule()
60 {
61 for (auto it = negativeRules.begin(); it != negativeRules.end(); ++it) {
62 if (*it != nullptr) {
63 delete *it;
64 }
65 }
66 for (auto it = positiveRules.begin(); it != positiveRules.end(); ++it) {
67 if (*it != nullptr) {
68 delete *it;
69 }
70 }
71 for (auto it = borderRules.begin(); it != borderRules.end(); ++it) {
72 if (*it != nullptr) {
73 delete *it;
74 }
75 }
76 for (auto it = codesRules.begin(); it != codesRules.end(); ++it) {
77 if (*it != nullptr) {
78 delete *it;
79 }
80 }
81 for (auto it = findRules.begin(); it != findRules.end(); ++it) {
82 if (*it != nullptr) {
83 delete *it;
84 }
85 }
86 }
87
Init()88 void PhoneNumberRule::Init()
89 {
90 if (isFixed) {
91 InitRule(xmlPath);
92 }
93 InitRule(xmlCommonPath);
94 }
95
96 // Load the rules of the corresponding country
InitRule(std::string & xmlPath)97 void PhoneNumberRule::InitRule(std::string& xmlPath)
98 {
99 if (!CheckTzDataFilePath(xmlPath)) {
100 return;
101 }
102 xmlKeepBlanksDefault(0);
103 xmlDocPtr doc = xmlParseFile(xmlPath.c_str());
104 if (doc == nullptr) return;
105 xmlNodePtr root = xmlDocGetRootElement(doc);
106 xmlNodePtr cur = root->xmlChildrenNode;
107 while (cur != nullptr) {
108 std::string category = reinterpret_cast<const char*>(cur->name);
109 ParseXmlNode(cur, category);
110 cur = cur->next;
111 }
112 xmlFreeDoc(doc);
113 }
114
ParseXmlNode(xmlNodePtr cur,std::string & category)115 void PhoneNumberRule::ParseXmlNode(xmlNodePtr cur, std::string& category)
116 {
117 xmlNodePtr rule = cur->xmlChildrenNode;
118 while (rule != nullptr && !xmlStrcmp(rule->name, reinterpret_cast<const xmlChar*>("rule"))) {
119 xmlNodePtr value = rule->xmlChildrenNode;
120 std::string insensitive = XmlNodePtrToString(value);
121 value = value->next;
122 if (category == "common_exit") {
123 commonExit = (insensitive == "True");
124 break;
125 }
126 std::string type = XmlNodePtrToString(value);
127 value = value->next;
128 std::string valid = XmlNodePtrToString(value);
129 value = value->next;
130 std::string handle = XmlNodePtrToString(value);
131 if (IsXmlNodeValueEmpty(insensitive, type, valid, handle)) {
132 break;
133 }
134 icu::UnicodeString content = "";
135 while (value->next != nullptr && !xmlStrcmp(value->next->name,
136 reinterpret_cast<const xmlChar*>("content"))) {
137 value = value->next;
138 xmlChar* contentPtr = xmlNodeGetContent(value);
139 if (contentPtr == nullptr) continue;
140 icu::UnicodeString tempContent = reinterpret_cast<char*>(contentPtr);
141 content += tempContent;
142 xmlFree(contentPtr);
143 }
144 SetRules(category, content, valid, handle, insensitive, type);
145 rule = rule->next;
146 }
147 }
148
IsXmlNodeValueEmpty(const std::string & insensitive,const std::string & type,const std::string & valid,const std::string & handle)149 bool PhoneNumberRule::IsXmlNodeValueEmpty(const std::string& insensitive, const std::string& type,
150 const std::string& valid, const std::string& handle)
151 {
152 if (insensitive.empty() || type.empty() ||
153 valid.empty() || handle.empty()) {
154 return true;
155 }
156 return false;
157 }
158
XmlNodePtrToString(xmlNodePtr valuePtr)159 std::string PhoneNumberRule::XmlNodePtrToString(xmlNodePtr valuePtr)
160 {
161 if (valuePtr == nullptr) {
162 return "";
163 }
164 xmlChar* charPtr = xmlNodeGetContent(valuePtr);
165 if (charPtr == nullptr) {
166 return "";
167 }
168 std::string result = reinterpret_cast<char*>(charPtr);
169 xmlFree(charPtr);
170 return result;
171 }
172
SetRules(std::string & category,icu::UnicodeString & content,std::string & valid,std::string & handle,std::string & insensitive,std::string & type)173 void PhoneNumberRule::SetRules(std::string& category, icu::UnicodeString& content, std::string& valid,
174 std::string& handle, std::string& insensitive, std::string& type)
175 {
176 if (category == "negative" || (category == "common" && commonExit)) {
177 negativeRules.push_back(new NegativeRule(content, insensitive));
178 } else if (category == "positive") {
179 positiveRules.push_back(new PositiveRule(content, handle, insensitive));
180 } else if (category == "border") {
181 borderRules.push_back(new BorderRule(content, insensitive, type));
182 } else if (category == "codes") {
183 codesRules.push_back(new CodeRule(valid));
184 } else if (category == "find_number") {
185 findRules.push_back(new FindRule(content, insensitive));
186 }
187 }
188
GetBorderRules()189 std::vector<BorderRule*> PhoneNumberRule::GetBorderRules()
190 {
191 return borderRules;
192 }
193
GetCodesRules()194 std::vector<CodeRule*> PhoneNumberRule::GetCodesRules()
195 {
196 return codesRules;
197 }
198
GetPositiveRules()199 std::vector<PositiveRule*> PhoneNumberRule::GetPositiveRules()
200 {
201 return positiveRules;
202 }
203
GetNegativeRules()204 std::vector<NegativeRule*> PhoneNumberRule::GetNegativeRules()
205 {
206 return negativeRules;
207 }
208
GetFindRules()209 std::vector<FindRule*> PhoneNumberRule::GetFindRules()
210 {
211 return findRules;
212 }
213 } // namespace I18n
214 } // namespace Global
215 } // namespace OHOS