• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 locale governing permissions and
13  * limitations under the License.
14  */
15 #include "date_time_rule.h"
16 #include "utils.h"
17 
18 namespace OHOS {
19 namespace Global {
20 namespace I18n {
21 std::string DateTimeRule::xmlCommonPath = "/system/usr/ohos_locale_config/datetime/common.xml";
22 
DateTimeRule(std::string & locale)23 DateTimeRule::DateTimeRule(std::string& locale)
24 {
25     this->loadMap = {{"sub_rules", &this->subRules},
26                      {"universe_rules", &this->universeRules},
27                      {"filter_rules", &this->filterRules},
28                      {"past_rules", &this->pastRules},
29                      {"locale_rules", &this->localesRules},
30                      {"delimiter", &this->delimiter},
31                      {"param", &this->param},
32                      {"default_locale", &this->localeMap},
33                      {"isRelDates", &this->relDates}};
34     Init(locale);
35 }
36 
~DateTimeRule()37 DateTimeRule::~DateTimeRule()
38 {
39     std::unordered_map<std::string, icu::RegexPattern*>::iterator iter;
40     for (iter = patternsMap.begin(); iter != patternsMap.end(); ++iter) {
41         icu::RegexPattern* pattern = iter->second;
42         if (pattern != nullptr) {
43             delete pattern;
44         }
45         pattern = nullptr;
46     }
47 }
48 
Init(std::string & locale)49 void DateTimeRule::Init(std::string& locale)
50 {
51     InitRules(xmlCommonPath);
52     std::string xmlPath = "/system/usr/ohos_locale_config/datetime/" + locale + ".xml";
53     if (!CheckTzDataFilePath(xmlPath)) {
54         this->locale = this->localeMap["locale"];
55     } else {
56         this->locale = locale;
57     }
58     xmlPath = "/system/usr/ohos_locale_config/datetime/" + this->locale + ".xml";
59     InitRules(xmlPath);
60     std::string xmlPathBackup = "/system/usr/ohos_locale_config/datetime/" + this->localeMap["backup"] + ".xml";
61     InitRuleBackup(xmlPathBackup);
62     RuleLevel();
63 }
64 
GetLocale()65 std::string DateTimeRule::GetLocale()
66 {
67     return this->locale;
68 }
69 
RuleLevel()70 void DateTimeRule::RuleLevel()
71 {
72     std::string ruleName = "mark_ShortDateLevel";
73     std::string shortDateMark = GetWithoutB(ruleName);
74     if (shortDateMark == "ymd") {
75         // 1 indicates the level of the "20016" rule in the "ymd" style.
76         levels["20016"] = 1;
77         // 3 indicates the level of the "20014" rule in the "ymd" style.
78         levels["20014"] = 3;
79         // 2 indicates the level of the "20015" rule in the "ymd" style.
80         levels["20015"] = 2;
81     } else if (shortDateMark == "mdy") {
82         // 2 indicates the level of the "20016" rule in the "mdy" style.
83         levels["20016"] = 2;
84         // 3 indicates the level of the "20014" rule in the "mdy" style.
85         levels["20014"] = 3;
86         // 1 indicates the level of the "20015" rule in the "mdy" style.
87         levels["20015"] = 1;
88     }
89 }
90 
InitRules(std::string & xmlPath)91 void DateTimeRule::InitRules(std::string& xmlPath)
92 {
93     if (!CheckTzDataFilePath(xmlPath)) {
94         return;
95     }
96     xmlKeepBlanksDefault(0);
97     xmlDocPtr doc = xmlParseFile(xmlPath.c_str());
98     if (doc == nullptr) return;
99     xmlNodePtr root = xmlDocGetRootElement(doc);
100     xmlNodePtr cur = root->xmlChildrenNode;
101     while (cur != nullptr) {
102         std::string category = reinterpret_cast<const char*>(cur->name);
103         if (category == "sub_rules_map") {
104             xmlNodePtr value = cur->xmlChildrenNode;
105             while (value != nullptr) {
106                 std::string key = reinterpret_cast<const char*>(value->name);
107                 // remove the first 3 chars of key.
108                 key = key.substr(3);
109                 xmlNodePtr subValue = value->xmlChildrenNode;
110                 std::unordered_map<std::string, std::string> tempMap;
111                 LoadStrToStr(&tempMap, subValue);
112                 subRulesMap[key] = tempMap;
113                 value = value->next;
114             }
115         } else if (this->loadMap.find(category) != this->loadMap.end()) {
116             xmlNodePtr valueNext = cur->xmlChildrenNode;
117             LoadStrToStr(this->loadMap[category], valueNext);
118         } else if (category == "pattern") {
119             xmlNodePtr valueNext = cur->xmlChildrenNode;
120             LoadStrToPattern(this->patternsMap, valueNext);
121         }
122         cur = cur->next;
123     }
124     xmlFreeDoc(doc);
125 }
126 
InitRuleBackup(std::string & xmlPathBackup)127 void DateTimeRule::InitRuleBackup(std::string& xmlPathBackup)
128 {
129     if (!CheckTzDataFilePath(xmlPathBackup)) {
130         return;
131     }
132     xmlKeepBlanksDefault(0);
133     xmlDocPtr doc = xmlParseFile(xmlPathBackup.c_str());
134     if (doc == nullptr) return;
135     xmlNodePtr cur = xmlDocGetRootElement(doc)->xmlChildrenNode;
136     while (cur != nullptr) {
137         std::string category = reinterpret_cast<const char*>(cur->name);
138         xmlNodePtr valueNext = cur->xmlChildrenNode;
139         if (category == "param") {
140             LoadStrToStr(&paramBackup, valueNext);
141         } else if (category == "locale_rules") {
142             LoadStrToStr(&localesRulesBackup, valueNext);
143         }
144         cur = cur->next;
145     }
146     xmlFreeDoc(doc);
147 }
148 
149 // load the rules of the cur node to the map
LoadStrToPattern(std::unordered_map<std::string,icu::RegexPattern * > & map,xmlNodePtr cur)150 void DateTimeRule::LoadStrToPattern(std::unordered_map<std::string, icu::RegexPattern*>& map, xmlNodePtr cur)
151 {
152     while (cur != nullptr) {
153         std::string key = reinterpret_cast<const char*>(cur->name);
154         // remove the first 3 chars of key.
155         key = key.substr(3);
156         xmlNodePtr value = cur->xmlChildrenNode;
157         bool flag = false;
158         // load rule content
159         if (value != nullptr && !xmlStrcmp(value->name, reinterpret_cast<const xmlChar*>("flag"))) {
160             std::string type = reinterpret_cast<const char*>(xmlNodeGetContent(value));
161             if (type == "True") {
162                 flag = true;
163             }
164             value = value->next;
165         }
166         icu::UnicodeString content;
167         while (value != nullptr && !xmlStrcmp(value->name, reinterpret_cast<const xmlChar*>("content"))) {
168             icu::UnicodeString tempContent = reinterpret_cast<char*>(xmlNodeGetContent(value));
169             content += tempContent;
170             value = value->next;
171         }
172         UErrorCode status = U_ZERO_ERROR;
173         icu::RegexPattern* pattern;
174         if (flag) {
175             pattern = icu::RegexPattern::compile(content, URegexpFlag::UREGEX_CASE_INSENSITIVE, status);
176         } else {
177             pattern = icu::RegexPattern::compile(content, 0, status);
178         }
179         map[key] = pattern;
180         cur = cur->next;
181     }
182 }
183 
184 // load the rules of the cur node to the map
LoadStrToStr(std::unordered_map<std::string,std::string> * map,xmlNodePtr cur)185 void DateTimeRule::LoadStrToStr(std::unordered_map<std::string, std::string>* map, xmlNodePtr cur)
186 {
187     while (cur != nullptr) {
188         std::string key = reinterpret_cast<const char*>(cur->name);
189         // remove the first 3 chars of key.
190         key = key.substr(3);
191         xmlNodePtr value = cur->xmlChildrenNode;
192         // load rule level
193         if (value != nullptr && !xmlStrcmp(value->name, reinterpret_cast<const xmlChar*>("level"))) {
194             std::string levelStr = reinterpret_cast<const char*>(xmlNodeGetContent(value));
195             int32_t status = 0;
196             int level = ConvertString2Int(levelStr, status);
197             levels[key] = level;
198             value = value->next;
199         }
200         // load rule content
201         std::string content;
202         while (value != nullptr && !xmlStrcmp(value->name, reinterpret_cast<const xmlChar*>("content"))) {
203             std::string tempContent = reinterpret_cast<const char*>(xmlNodeGetContent(value));
204             content += tempContent;
205             value = value->next;
206         }
207         (*map)[key] = content;
208         cur = cur->next;
209     }
210 }
211 
212 // process rule paramMap[ruleName]. for example: Sat|Mon|Tue  ->  \\bSat\\b|\\bMon\\b|\\bTue\\b
Get(std::unordered_map<std::string,std::string> & paramMap,std::string & ruleName)213 std::string DateTimeRule::Get(std::unordered_map<std::string, std::string>& paramMap, std::string& ruleName)
214 {
215     std::string result = "";
216     if (paramMap.empty() || paramMap.find(ruleName) == paramMap.end()) {
217         return result;
218     }
219     result = paramMap[ruleName];
220     std::vector<std::string> temps;
221     std::string splitStr = "|";
222     Split(result, splitStr, temps);
223     std::string sb;
224     std::string mark = "";
225     if (delimiter.find(locale) != delimiter.end()) {
226         mark = delimiter[locale];
227     } else {
228         mark = "\\b";
229     }
230     for (auto& temp : temps) {
231         if (!CompareBeginEnd(temp, "\\b", true)) {
232             sb += mark;
233         }
234         sb += temp;
235         if (!CompareBeginEnd(temp, "\\b", false) && !CompareBeginEnd(temp, ".", false)) {
236             sb += mark;
237         }
238         sb += "|";
239     }
240     result = sb;
241     if (CompareBeginEnd(result, "|", false)) {
242         result.pop_back();
243     }
244     return result;
245 }
246 
247 // check whether src starts or ends with target.
CompareBeginEnd(const std::string src,const std::string target,bool flag)248 bool DateTimeRule::CompareBeginEnd(const std::string src, const std::string target, bool flag)
249 {
250     int lengthSrc = src.length();
251     int lengthTarget = target.length();
252     if (lengthSrc < lengthTarget) {
253         return false;
254     }
255     std::string subStr;
256     if (flag) {
257         subStr = src.substr(0, lengthTarget);
258     } else {
259         subStr = src.substr(lengthSrc - lengthTarget, lengthTarget);
260     }
261     return subStr == target;
262 }
263 
264 // replace subStr in src with newStr.
SubReplace(std::string & src,const std::string & subStr,const std::string & newStr)265 std::string DateTimeRule::SubReplace(std::string& src, const std::string& subStr, const std::string& newStr)
266 {
267     std::string::size_type pos = 0;
268     std::string result = src;
269     if (subStr.empty() || subStr.compare(newStr) == 0) {
270         return result;
271     }
272     while ((pos = result.find(subStr)) != std::string::npos) {
273         result.replace(pos, subStr.length(), newStr);
274     }
275     return result;
276 }
277 
GetWithoutB(const std::string & ruleName)278 std::string DateTimeRule::GetWithoutB(const std::string& ruleName)
279 {
280     std::string result = "";
281     if (param.empty() || param.find(ruleName) == param.end()) {
282         return result;
283     }
284     result = param[ruleName];
285     return result;
286 }
287 
288 // check whether hyphen is a valid date and time separator.
IsRelDates(icu::UnicodeString & hyphen,std::string & locale)289 bool DateTimeRule::IsRelDates(icu::UnicodeString& hyphen, std::string& locale)
290 {
291     bool isRel = false;
292     if (hyphen.trim().isEmpty()) {
293         isRel = true;
294     } else if (hyphen.trim() == ',' && relDates.find(locale) != relDates.end() &&
295         relDates[locale].find(",") != std::string::npos) {
296         isRel = true;
297     }
298     return isRel;
299 }
300 
trim(const std::string & src)301 std::string DateTimeRule::trim(const std::string& src)
302 {
303     std::string target = src;
304     if (target.empty()) {
305         return target;
306     }
307     target.erase(0, target.find_first_not_of(" "));
308     target.erase(target.find_last_not_of(" ") + 1);
309     return target;
310 }
311 
CompareLevel(std::string & key1,std::string & key2)312 int DateTimeRule::CompareLevel(std::string& key1, std::string& key2)
313 {
314     int result = 0;
315     int level1 = GetLevel(key1);
316     int level2 = GetLevel(key2);
317     if (level1 > level2) {
318         result = 1;
319     } else if (level1 < level2) {
320         result = -1;
321     }
322     return result;
323 }
324 
GetLevel(std::string & name)325 int DateTimeRule::GetLevel(std::string& name)
326 {
327     int baselevel;
328     int32_t status = 0;
329     int key = ConvertString2Int(name, status);
330     // 9999 and 20000 are the rule numbers.
331     if (key > 9999 && key < 20000) {
332         // 10 is basic level.
333         baselevel = 10;
334     // 19999 and 40000 are the rule numbers.
335     } else if (key > 19999 && key < 40000) {
336         // 20 is basic level.
337         baselevel = 20;
338     } else {
339         // 30 is basic level.
340         baselevel = 30;
341     }
342     int addLeve = 1;
343     if (levels.find(name) != levels.end()) {
344         addLeve = levels[name];
345     }
346     int level = baselevel + addLeve;
347     return level;
348 }
349 
GetUniverseRules()350 std::unordered_map<std::string, std::string> DateTimeRule::GetUniverseRules()
351 {
352     return universeRules;
353 }
354 
GetLocalesRules()355 std::unordered_map<std::string, std::string> DateTimeRule::GetLocalesRules()
356 {
357     return localesRules;
358 }
359 
GetLocalesRulesBackup()360 std::unordered_map<std::string, std::string> DateTimeRule::GetLocalesRulesBackup()
361 {
362     return localesRulesBackup;
363 }
364 
GetSubRulesMap()365 std::unordered_map<std::string, std::unordered_map<std::string, std::string>> DateTimeRule::GetSubRulesMap()
366 {
367     return subRulesMap;
368 }
369 
GetSubRules()370 std::unordered_map<std::string, std::string> DateTimeRule::GetSubRules()
371 {
372     return subRules;
373 }
374 
GetFilterRules()375 std::unordered_map<std::string, std::string> DateTimeRule::GetFilterRules()
376 {
377     return filterRules;
378 }
379 
GetPastRules()380 std::unordered_map<std::string, std::string> DateTimeRule::GetPastRules()
381 {
382     return pastRules;
383 }
384 
GetParam()385 std::unordered_map<std::string, std::string> DateTimeRule::GetParam()
386 {
387     return param;
388 }
389 
GetParamBackup()390 std::unordered_map<std::string, std::string> DateTimeRule::GetParamBackup()
391 {
392     return paramBackup;
393 }
394 
GetPatternsMap()395 std::unordered_map<std::string, icu::RegexPattern*> DateTimeRule::GetPatternsMap()
396 {
397     return patternsMap;
398 }
399 } // namespace I18n
400 } // namespace Global
401 } // namespace OHOS