• 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 (!CheckFilePath(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 (!CheckFilePath(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     if (root == nullptr) return;
101     xmlNodePtr cur = root->xmlChildrenNode;
102     while (cur != nullptr) {
103         std::string category = reinterpret_cast<const char*>(cur->name);
104         if (category == "sub_rules_map") {
105             xmlNodePtr value = cur->xmlChildrenNode;
106             while (value != nullptr) {
107                 std::string key = reinterpret_cast<const char*>(value->name);
108                 // remove the first 3 chars of key.
109                 key = key.substr(3);
110                 xmlNodePtr subValue = value->xmlChildrenNode;
111                 std::unordered_map<std::string, std::string> tempMap;
112                 LoadStrToStr(&tempMap, subValue);
113                 subRulesMap[key] = tempMap;
114                 value = value->next;
115             }
116         } else if (this->loadMap.find(category) != this->loadMap.end()) {
117             xmlNodePtr valueNext = cur->xmlChildrenNode;
118             LoadStrToStr(this->loadMap[category], valueNext);
119         } else if (category == "pattern") {
120             xmlNodePtr valueNext = cur->xmlChildrenNode;
121             LoadStrToPattern(this->patternsMap, valueNext);
122         }
123         cur = cur->next;
124     }
125     xmlFreeDoc(doc);
126 }
127 
InitRuleBackup(std::string & xmlPathBackup)128 void DateTimeRule::InitRuleBackup(std::string& xmlPathBackup)
129 {
130     if (!CheckFilePath(xmlPathBackup)) {
131         return;
132     }
133     xmlKeepBlanksDefault(0);
134     xmlDocPtr doc = xmlParseFile(xmlPathBackup.c_str());
135     if (doc == nullptr) return;
136     xmlNodePtr cur = xmlDocGetRootElement(doc)->xmlChildrenNode;
137     while (cur != nullptr) {
138         std::string category = reinterpret_cast<const char*>(cur->name);
139         xmlNodePtr valueNext = cur->xmlChildrenNode;
140         if (category == "param") {
141             LoadStrToStr(&paramBackup, valueNext);
142         } else if (category == "locale_rules") {
143             LoadStrToStr(&localesRulesBackup, valueNext);
144         }
145         cur = cur->next;
146     }
147     xmlFreeDoc(doc);
148 }
149 
150 // load the rules of the cur node to the map
LoadStrToPattern(std::unordered_map<std::string,icu::RegexPattern * > & map,xmlNodePtr cur)151 void DateTimeRule::LoadStrToPattern(std::unordered_map<std::string, icu::RegexPattern*>& map, xmlNodePtr cur)
152 {
153     while (cur != nullptr) {
154         std::string key = reinterpret_cast<const char*>(cur->name);
155         // remove the first 3 chars of key.
156         key = key.substr(3);
157         xmlNodePtr value = cur->xmlChildrenNode;
158         bool flag = false;
159         // load rule content
160         if (value != nullptr && !xmlStrcmp(value->name, reinterpret_cast<const xmlChar*>("flag"))) {
161             xmlChar* typePtr = xmlNodeGetContent(value);
162             if (typePtr != nullptr) {
163                 std::string type = reinterpret_cast<const char*>(typePtr);
164                 flag = (type == "True") ? true : flag;
165                 xmlFree(typePtr);
166             }
167             value = value->next;
168         }
169         icu::UnicodeString content;
170         while (value != nullptr && !xmlStrcmp(value->name, reinterpret_cast<const xmlChar*>("content"))) {
171             xmlChar* contentPtr = xmlNodeGetContent(value);
172             if (contentPtr != nullptr) {
173                 icu::UnicodeString tempContent = reinterpret_cast<char*>(contentPtr);
174                 content += tempContent;
175                 xmlFree(contentPtr);
176             }
177             value = value->next;
178         }
179         UErrorCode status = U_ZERO_ERROR;
180         icu::RegexPattern* pattern;
181         if (flag) {
182             pattern = icu::RegexPattern::compile(content, URegexpFlag::UREGEX_CASE_INSENSITIVE, status);
183         } else {
184             pattern = icu::RegexPattern::compile(content, 0, status);
185         }
186         map[key] = pattern;
187         cur = cur->next;
188     }
189 }
190 
191 // load the rules of the cur node to the map
LoadStrToStr(std::unordered_map<std::string,std::string> * map,xmlNodePtr cur)192 void DateTimeRule::LoadStrToStr(std::unordered_map<std::string, std::string>* map, xmlNodePtr cur)
193 {
194     while (cur != nullptr) {
195         std::string key = reinterpret_cast<const char*>(cur->name);
196         // remove the first 3 chars of key.
197         key = key.substr(3);
198         xmlNodePtr value = cur->xmlChildrenNode;
199         // load rule level
200         if (value != nullptr && !xmlStrcmp(value->name, reinterpret_cast<const xmlChar*>("level"))) {
201             xmlChar* levelPtr = xmlNodeGetContent(value);
202             if (levelPtr != nullptr) {
203                 std::string levelStr = reinterpret_cast<const char*>(levelPtr);
204                 int32_t status = 0;
205                 int level = ConvertString2Int(levelStr, status);
206                 levels[key] = level;
207                 xmlFree(levelPtr);
208             } else {
209                 break;
210             }
211             value = value->next;
212         }
213         // load rule content
214         std::string content;
215         while (value != nullptr && !xmlStrcmp(value->name, reinterpret_cast<const xmlChar*>("content"))) {
216             xmlChar* contentPtr = xmlNodeGetContent(value);
217             if (contentPtr != nullptr) {
218                 std::string tempContent = reinterpret_cast<const char*>(contentPtr);
219                 content += tempContent;
220                 xmlFree(contentPtr);
221             }
222             value = value->next;
223         }
224         (*map)[key] = content;
225         cur = cur->next;
226     }
227 }
228 
229 // 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)230 std::string DateTimeRule::Get(std::unordered_map<std::string, std::string>& paramMap, std::string& ruleName)
231 {
232     std::string result = "";
233     if (paramMap.empty() || paramMap.find(ruleName) == paramMap.end()) {
234         return result;
235     }
236     result = paramMap[ruleName];
237     std::vector<std::string> temps;
238     std::string splitStr = "|";
239     Split(result, splitStr, temps);
240     std::string sb;
241     std::string mark = "";
242     if (delimiter.find(locale) != delimiter.end()) {
243         mark = delimiter[locale];
244     } else {
245         mark = "\\b";
246     }
247     for (auto& temp : temps) {
248         if (!CompareBeginEnd(temp, "\\b", true)) {
249             sb += mark;
250         }
251         sb += temp;
252         if (!CompareBeginEnd(temp, "\\b", false) && !CompareBeginEnd(temp, ".", false)) {
253             sb += mark;
254         }
255         sb += "|";
256     }
257     result = sb;
258     if (CompareBeginEnd(result, "|", false)) {
259         result.pop_back();
260     }
261     return result;
262 }
263 
264 // check whether src starts or ends with target.
CompareBeginEnd(const std::string src,const std::string target,bool flag)265 bool DateTimeRule::CompareBeginEnd(const std::string src, const std::string target, bool flag)
266 {
267     size_t lengthSrc = src.length();
268     size_t lengthTarget = target.length();
269     if (lengthSrc < lengthTarget) {
270         return false;
271     }
272     std::string subStr;
273     if (flag) {
274         subStr = src.substr(0, lengthTarget);
275     } else {
276         subStr = src.substr(lengthSrc - lengthTarget, lengthTarget);
277     }
278     return subStr == target;
279 }
280 
281 
GetWithoutB(const std::string & ruleName)282 std::string DateTimeRule::GetWithoutB(const std::string& ruleName)
283 {
284     std::string result = "";
285     if (param.empty() || param.find(ruleName) == param.end()) {
286         return result;
287     }
288     result = param[ruleName];
289     return result;
290 }
291 
292 // check whether hyphen is a valid date and time separator.
IsRelDates(icu::UnicodeString & hyphen,std::string & locale)293 bool DateTimeRule::IsRelDates(icu::UnicodeString& hyphen, std::string& locale)
294 {
295     bool isRel = false;
296     if (hyphen.trim().isEmpty()) {
297         isRel = true;
298     } else if (hyphen.trim() == ',' && relDates.find(locale) != relDates.end() &&
299         relDates[locale].find(",") != std::string::npos) {
300         isRel = true;
301     }
302     return isRel;
303 }
304 
trim(const std::string & src)305 std::string DateTimeRule::trim(const std::string& src)
306 {
307     std::string target = src;
308     if (target.empty()) {
309         return target;
310     }
311     target.erase(0, target.find_first_not_of(" "));
312     target.erase(target.find_last_not_of(" ") + 1);
313     return target;
314 }
315 
CompareLevel(std::string & key1,std::string & key2)316 int DateTimeRule::CompareLevel(std::string& key1, std::string& key2)
317 {
318     int result = 0;
319     int level1 = GetLevel(key1);
320     int level2 = GetLevel(key2);
321     if (level1 > level2) {
322         result = 1;
323     } else if (level1 < level2) {
324         result = -1;
325     }
326     return result;
327 }
328 
GetLevel(std::string & name)329 int DateTimeRule::GetLevel(std::string& name)
330 {
331     int baselevel;
332     int32_t status = 0;
333     int key = ConvertString2Int(name, status);
334     // 9999 and 20000 are the rule numbers.
335     if (key > 9999 && key < 20000) {
336         // 10 is basic level.
337         baselevel = 10;
338     // 19999 and 40000 are the rule numbers.
339     } else if (key > 19999 && key < 40000) {
340         // 20 is basic level.
341         baselevel = 20;
342     } else {
343         // 30 is basic level.
344         baselevel = 30;
345     }
346     int addLeve = 1;
347     if (levels.find(name) != levels.end()) {
348         addLeve = levels[name];
349     }
350     int level = baselevel + addLeve;
351     return level;
352 }
353 
GetUniverseRules()354 std::unordered_map<std::string, std::string> DateTimeRule::GetUniverseRules()
355 {
356     return universeRules;
357 }
358 
GetLocalesRules()359 std::unordered_map<std::string, std::string> DateTimeRule::GetLocalesRules()
360 {
361     return localesRules;
362 }
363 
GetLocalesRulesBackup()364 std::unordered_map<std::string, std::string> DateTimeRule::GetLocalesRulesBackup()
365 {
366     return localesRulesBackup;
367 }
368 
GetSubRulesMap()369 std::unordered_map<std::string, std::unordered_map<std::string, std::string>> DateTimeRule::GetSubRulesMap()
370 {
371     return subRulesMap;
372 }
373 
GetSubRules()374 std::unordered_map<std::string, std::string> DateTimeRule::GetSubRules()
375 {
376     return subRules;
377 }
378 
GetFilterRules()379 std::unordered_map<std::string, std::string> DateTimeRule::GetFilterRules()
380 {
381     return filterRules;
382 }
383 
GetPastRules()384 std::unordered_map<std::string, std::string> DateTimeRule::GetPastRules()
385 {
386     return pastRules;
387 }
388 
GetParam()389 std::unordered_map<std::string, std::string> DateTimeRule::GetParam()
390 {
391     return param;
392 }
393 
GetParamBackup()394 std::unordered_map<std::string, std::string> DateTimeRule::GetParamBackup()
395 {
396     return paramBackup;
397 }
398 
GetPatternByKey(const std::string & key)399 icu::RegexPattern* DateTimeRule::GetPatternByKey(const std::string& key)
400 {
401     if (patternsMap.find(key) != patternsMap.end()) {
402         return patternsMap[key];
403     }
404     return nullptr;
405 }
406 } // namespace I18n
407 } // namespace Global
408 } // namespace OHOS