• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 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 
16 #include "res_locale.h"
17 
18 #include <cctype>
19 #include <cstdint>
20 #include <cstring>
21 #include <new>
22 
23 #include "auto_mutex.h"
24 #include "hilog_wrapper.h"
25 #include "locale_matcher.h"
26 #include "res_config.h"
27 #include "rstate.h"
28 #include "utils/common.h"
29 #include "utils/utils.h"
30 
31 namespace OHOS {
32 namespace Global {
33 namespace Resource {
34 LocaleInfo *ResLocale::defaultLocale_ = nullptr;
35 Lock ResLocale::lock_;
36 
ResLocale()37 ResLocale::ResLocale() : language_(nullptr), region_(nullptr), script_(nullptr)
38 {
39 }
40 
SetLanguage(const char * language,size_t len)41 RState ResLocale::SetLanguage(const char *language, size_t len)
42 {
43     if (len == 0) {
44         delete this->language_;
45         this->language_ = nullptr;
46         return SUCCESS;
47     }
48     char *temp = new(std::nothrow) char[len + 1];
49     if (temp == nullptr) {
50         return NOT_ENOUGH_MEM;
51     }
52     delete this->language_;
53     this->language_ = temp;
54     size_t i = 0;
55     while (i < len) {
56         *(temp + i) = tolower(*(language + i));
57         ++i;
58     }
59     *(temp + len) = '\0';
60     return SUCCESS;
61 }
62 
SetRegion(const char * region,size_t len)63 RState ResLocale::SetRegion(const char *region, size_t len)
64 {
65     if (len == 0) {
66         delete this->region_;
67         this->region_ = nullptr;
68         return SUCCESS;
69     }
70     char *temp = new(std::nothrow) char[len + 1];
71     if (temp == nullptr) {
72         return NOT_ENOUGH_MEM;
73     }
74     delete this->region_;
75     this->region_ = temp;
76     size_t i = 0;
77     while (i < len) {
78         *(temp + i) = toupper(*(region + i));
79         ++i;
80     }
81     *(temp + len) = '\0';
82     return SUCCESS;
83 }
84 
SetScript(const char * script,size_t len)85 RState ResLocale::SetScript(const char *script, size_t len)
86 {
87     if (len == 0) {
88         delete this->script_;
89         this->script_ = nullptr;
90         return SUCCESS;
91     }
92     char *temp = new(std::nothrow) char[len + 1];
93     if (temp == nullptr) {
94         return NOT_ENOUGH_MEM;
95     }
96     delete this->script_;
97     this->script_ = temp;
98     size_t i = 0;
99     while (i < len) {
100         if (i == 0) {
101             *(temp + i) = toupper(*(script + i));
102         } else {
103             *(temp + i) = tolower(*(script + i));
104         }
105         ++i;
106     }
107     *(temp + len) = '\0';
108     return SUCCESS;
109 }
110 
Init(const char * language,size_t languageLen,const char * script,size_t scriptLen,const char * region,size_t regionLen)111 RState ResLocale::Init(const char *language, size_t languageLen, const char *script, size_t scriptLen,
112     const char *region, size_t regionLen)
113 {
114     RState r = this->SetLanguage(language, languageLen);
115     if (r != SUCCESS) {
116         return r;
117     }
118     r = this->SetScript(script, scriptLen);
119     if (r != SUCCESS) {
120         return r;
121     }
122     r = this->SetRegion(region, regionLen);
123     if (r != SUCCESS) {
124         return r;
125     }
126     return SUCCESS;
127 }
128 
CopyFromLocaleInfo(const LocaleInfo * other)129 RState ResLocale::CopyFromLocaleInfo(const LocaleInfo *other)
130 {
131     if (other == nullptr) {
132         return ERROR;
133     }
134     return this->Init(other->GetLanguage(), Utils::StrLen(other->GetLanguage()), other->GetScript(),
135         Utils::StrLen(other->GetScript()), other->GetRegion(), Utils::StrLen(other->GetRegion()));
136 }
137 
Copy(const ResLocale * other)138 RState ResLocale::Copy(const ResLocale *other)
139 {
140     if (other == nullptr) {
141         return ERROR;
142     }
143     return this->Init(other->GetLanguage(), Utils::StrLen(other->GetLanguage()), other->GetScript(),
144         Utils::StrLen(other->GetScript()), other->GetRegion(), Utils::StrLen(other->GetRegion()));
145 }
146 
GetLanguage() const147 const char *ResLocale::GetLanguage() const
148 {
149     return this->language_;
150 }
151 
GetRegion() const152 const char *ResLocale::GetRegion() const
153 {
154     return this->region_;
155 }
156 
GetScript() const157 const char *ResLocale::GetScript() const
158 {
159     return this->script_;
160 }
161 
ProcessSubtag(const char * curPos,int32_t subTagLen,uint16_t & nextType,ParseResult & r)162 RState ProcessSubtag(const char *curPos, int32_t subTagLen, uint16_t &nextType, ParseResult &r)
163 {
164     if ((ResLocale::LANG_TYPE & nextType) && (LocaleMatcher::IsLanguageTag(curPos, subTagLen))) {
165         r.tempLanguage = curPos;
166         r.languageTagLen = subTagLen;
167         nextType = ResLocale::SCRIPT_TYPE | ResLocale::REGION_TYPE;
168         return SUCCESS;
169     }
170     if ((ResLocale::SCRIPT_TYPE & nextType) && LocaleMatcher::IsScriptTag(curPos, subTagLen)) {
171         r.tempScript = curPos;
172         r.scriptTagLen = subTagLen;
173         nextType = ResLocale::REGION_TYPE;
174         return SUCCESS;
175     }
176     if ((ResLocale::REGION_TYPE & nextType) && LocaleMatcher::IsRegionTag(curPos, subTagLen)) {
177         r.tempRegion = curPos;
178         r.regionTagLen = subTagLen;
179         nextType = ResLocale::END_TYPE;
180         return SUCCESS;
181     }
182     return ERROR;
183 }
184 
CheckArg(char sep,RState & rState)185 void CheckArg(char sep, RState &rState)
186 {
187     rState = SUCCESS;
188     if (sep != DASH_SEP && sep != UNDERLINE_SEP) {
189         rState = NOT_SUPPORT_SEP;
190     }
191 }
192 
CreateResLocale(ParseResult & r,RState & rState)193 ResLocale *ResLocale::CreateResLocale(ParseResult &r, RState &rState)
194 {
195     ResLocale *resLocale = new(std::nothrow) ResLocale;
196     if (resLocale == nullptr) {
197         rState = NOT_ENOUGH_MEM;
198         return nullptr;
199     }
200     rState = resLocale->Init(r.tempLanguage, r.languageTagLen, r.tempScript, r.scriptTagLen,
201         r.tempRegion, r.regionTagLen);
202     if (rState == SUCCESS) {
203         return resLocale;
204     }
205     delete resLocale;
206     return nullptr;
207 }
208 
DoParse(const char * str,char sep,RState & rState)209 ResLocale *ResLocale::DoParse(const char *str, char sep, RState &rState)
210 {
211     uint16_t nextType = LANG_TYPE;
212     const char *nextPos = str;
213     const char *curPos = nextPos;
214     ParseResult r;
215     while (nextPos) {
216         if (nextType == END_TYPE) {
217             break;
218         }
219         const char *pSep = nextPos;
220         curPos = nextPos;
221         while (*pSep) {
222             if (*pSep == sep) {
223                 break;
224             }
225             pSep++;
226         }
227         nextPos = ((*pSep == 0) ? nullptr : (pSep + 1));
228         int16_t subTagLen = pSep - curPos;
229         if (nextType & LANG_TYPE) {
230             rState = ProcessSubtag(curPos, subTagLen, nextType, r);
231             if (rState == SUCCESS) {
232                 continue;
233             }
234             rState = INVALID_BCP47_LANGUAGE_SUBTAG;
235             return nullptr;
236         }
237         if (nextType & SCRIPT_TYPE) {
238             rState = ProcessSubtag(curPos, subTagLen, nextType, r);
239             if (rState == SUCCESS) {
240                 continue;
241             }
242             rState = INVALID_BCP47_SCRIPT_SUBTAG;
243             return nullptr;
244         }
245         if (nextType & REGION_TYPE) {
246             rState = ProcessSubtag(curPos, subTagLen, nextType, r);
247             if (rState == SUCCESS) {
248                 continue;
249             }
250             rState = INVALID_BCP47_REGION_SUBTAG;
251             return nullptr;
252         }
253     }
254     return CreateResLocale(r, rState);
255 }
256 
BuildFromString(const char * str,char sep,RState & rState)257 ResLocale *ResLocale::BuildFromString(const char *str, char sep, RState &rState)
258 {
259     CheckArg(sep, rState);
260     if (rState != SUCCESS) {
261         return nullptr;
262     }
263     size_t strLen = Utils::StrLen(str);
264     if (strLen == 0) {
265         return nullptr;
266     }
267     return DoParse(str, sep, rState);
268 } // end of ParseBCP47Tag
269 
BuildFromParts(const char * language,const char * script,const char * region,RState & rState)270 ResLocale *ResLocale::BuildFromParts(const char *language,
271     const char *script,
272     const char *region,
273     RState &rState)
274 {
275     size_t len = Utils::StrLen(language);
276     if (len == 0) {
277         rState = INVALID_BCP47_LANGUAGE_SUBTAG;
278         return nullptr;
279     }
280 
281     const char *tempLanguage = nullptr;
282     const char *tempScript = nullptr;
283     const char *tempRegion = nullptr;
284     size_t languageTagLen = 0;
285     size_t scriptTagLen = 0;
286     size_t regionTagLen = 0;
287     if (LocaleMatcher::IsLanguageTag(language, len)) {
288         tempLanguage = language;
289         languageTagLen = len;
290     } else {
291         rState = INVALID_BCP47_LANGUAGE_SUBTAG;
292         return nullptr;
293     }
294 
295     len = Utils::StrLen(script);
296     if (len > 0) {
297         if (LocaleMatcher::IsScriptTag(script, len)) {
298             tempScript = script;
299             scriptTagLen = len;
300         } else {
301             rState = INVALID_BCP47_SCRIPT_SUBTAG;
302             return nullptr;
303         }
304     }
305     len = Utils::StrLen(region);
306     if (len > 0) {
307         if (LocaleMatcher::IsRegionTag(region, len)) {
308             tempRegion = region;
309             regionTagLen = len;
310         } else {
311             rState = INVALID_BCP47_REGION_SUBTAG;
312             return nullptr;
313         }
314     }
315     ResLocale *resLocale = new(std::nothrow) ResLocale;
316     if (resLocale == nullptr) {
317         rState = NOT_ENOUGH_MEM;
318         return nullptr;
319     }
320     rState = resLocale->Init(tempLanguage, languageTagLen, tempScript, scriptTagLen, tempRegion, regionTagLen);
321     if (rState == SUCCESS) {
322         return resLocale;
323     }
324     delete resLocale;
325     return nullptr;
326 };
327 
GetDefault()328 const LocaleInfo *ResLocale::GetDefault()
329 {
330     AutoMutex mutex(ResLocale::lock_);
331     return ResLocale::defaultLocale_;
332 }
333 
UpdateDefault(const LocaleInfo & localeInfo,bool needNotify)334 bool ResLocale::UpdateDefault(const LocaleInfo &localeInfo, bool needNotify)
335 {
336     AutoMutex mutex(ResLocale::lock_);
337     LocaleInfo *temp = new(std::nothrow) LocaleInfo(localeInfo.GetLanguage(),
338         localeInfo.GetScript(), localeInfo.GetRegion());
339     if (temp == nullptr) {
340         return false;
341     }
342     delete ResLocale::defaultLocale_;
343     ResLocale::defaultLocale_ = temp;
344     return true;
345 };
346 
~ResLocale()347 ResLocale::~ResLocale()
348 {
349     if (this->language_ != nullptr) {
350         delete[] this->language_;
351         this->language_ = nullptr;
352     }
353 
354     if (this->script_ != nullptr) {
355         delete[] this->script_;
356         this->script_ = nullptr;
357     }
358 
359     if (this->region_ != nullptr) {
360         delete[] this->region_;
361         this->region_ = nullptr;
362     }
363 }
364 
BuildFromString(const char * str,char sep,RState & rState)365 LocaleInfo *BuildFromString(const char *str, char sep, RState &rState)
366 {
367     ResLocale *resLocale = ResLocale::BuildFromString(str, sep, rState);
368     if (rState == SUCCESS) {
369         LocaleInfo *localeInfo = new(std::nothrow) LocaleInfo(resLocale->GetLanguage(),
370             resLocale->GetScript(), resLocale->GetRegion());
371         if (localeInfo == nullptr) {
372             delete resLocale;
373             rState = ERROR;
374             return nullptr;
375         }
376         return localeInfo;
377     }
378     return nullptr;
379 };
380 
BuildFromParts(const char * language,const char * script,const char * region,RState & rState)381 LocaleInfo *BuildFromParts(const char *language, const char *script, const char *region, RState &rState)
382 {
383     size_t len = Utils::StrLen(language);
384     if (len == 0) {
385         rState = INVALID_BCP47_LANGUAGE_SUBTAG;
386         return nullptr;
387     }
388     if (!(LocaleMatcher::IsLanguageTag(language, len))) {
389         rState = INVALID_BCP47_LANGUAGE_SUBTAG;
390         return nullptr;
391     }
392 
393     len = Utils::StrLen(script);
394     if (len > 0) {
395         if (LocaleMatcher::IsScriptTag(script, len) == 0) {
396             rState = INVALID_BCP47_SCRIPT_SUBTAG;
397             return nullptr;
398         }
399     }
400     len = Utils::StrLen(region);
401     if (len > 0) {
402         if (LocaleMatcher::IsRegionTag(region, len) == 0) {
403             rState = INVALID_BCP47_REGION_SUBTAG;
404             return nullptr;
405         }
406     }
407     LocaleInfo *localeInfo = new(std::nothrow) LocaleInfo(language, script, region);
408     if (localeInfo == nullptr) {
409         rState = ERROR;
410         return nullptr;
411     }
412     return localeInfo;
413 }
414 
GetSysDefault()415 const LocaleInfo *GetSysDefault()
416 {
417     return ResLocale::GetDefault();
418 }
419 
UpdateSysDefault(const LocaleInfo & localeInfo,bool needNotify)420 void UpdateSysDefault(const LocaleInfo &localeInfo, bool needNotify)
421 {
422     ResLocale::UpdateDefault(localeInfo, needNotify);
423 }
424 
FindAndSort(const std::string localeStr,std::vector<std::string> & candidateLocale,std::vector<std::string> & outValue)425 void FindAndSort(const std::string localeStr, std::vector<std::string> &candidateLocale,
426     std::vector<std::string> &outValue)
427 {
428     if (candidateLocale.size() == 0) {
429         return;
430     }
431     std::vector<ResLocale *> tempCandidate;
432     RState state = SUCCESS;
433     ResLocale *currentLocale = ResLocale::BuildFromString(localeStr.c_str(), DASH_SEP, state);
434     LocaleMatcher::Normalize(currentLocale);
435     std::vector<std::string>::const_iterator iter;
436     for (iter = candidateLocale.cbegin(); iter != candidateLocale.cend(); ++iter) {
437         ResLocale *resLocale = ResLocale::BuildFromString(iter->c_str(), DASH_SEP, state);
438         if (state == SUCCESS) {
439             LocaleMatcher::Normalize(resLocale);
440             bool isMatch = LocaleMatcher::Match(currentLocale, resLocale);
441             if (isMatch) {
442                 tempCandidate.push_back(resLocale);
443                 outValue.push_back(*iter);
444             } else {
445                 delete resLocale;
446             }
447         } else {
448             delete resLocale;
449         }
450     }
451     // sort
452     std::size_t len = tempCandidate.size();
453     if (len == 0) {
454         delete currentLocale;
455         return;
456     }
457     for (std::size_t i = 0; i < len - 1; i++) {
458         for (std::size_t j = 0; j < len - 1 - i; j++) {
459             if (LocaleMatcher::IsMoreSuitable(tempCandidate.at(j), tempCandidate.at(j + 1), currentLocale) <= 0) {
460                 ResLocale *temp = tempCandidate.at(j + 1);
461                 tempCandidate.at(j + 1) = tempCandidate.at(j);
462                 tempCandidate.at(j) = temp;
463                 std::string tempStr = outValue.at(j + 1);
464                 outValue.at(j + 1) = outValue.at(j);
465                 outValue.at(j) = tempStr;
466             }
467         }
468     }
469 
470     for (auto iter = tempCandidate.cbegin(); iter != tempCandidate.cend(); iter++) {
471         delete *iter;
472     }
473     delete currentLocale;
474 }
475 } // namespace Resource
476 } // namespace Global
477 } // namespace OHOS