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