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