• 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 "i18n_memory_adapter.h"
17 #include "securec.h"
18 #include "str_util.h"
19 #include "types.h"
20 #include "locale_info.h"
21 
22 using namespace OHOS::I18N;
23 
24 const std::set<std::string> LocaleInfo::SCRIPTS = {
25     "Hans", "Latn", "Hant", "Qaag", "Cyrl", "Deva", "Guru"
26 };
27 
Init(const char * newLang,const char * newScript,const char * newRegion,int & status)28 void LocaleInfo::Init(const char *newLang, const char *newScript, const char *newRegion, int &status)
29 {
30     id = nullptr;
31     status = IERROR;
32     if (newLang == nullptr) {
33         return;
34     }
35     int langLength = LenCharArray(newLang);
36     // language consists of two or three letters
37     if ((langLength > LANGUAGE_MAX_LENGTH) || (langLength < LANGUAGE_MIN_LENGTH)) {
38         return;
39     }
40     I18nFree(static_cast<void *>(language));
41     language = NewArrayAndCopy(newLang, langLength);
42     if (newScript != nullptr) {
43         int scriptLength = LenCharArray(newScript);
44         if (scriptLength == SCRIPT_LENGTH) {
45             script = NewArrayAndCopy(newScript, scriptLength);
46         }
47     }
48     if (newRegion != nullptr) {
49         int regionLength = LenCharArray(newRegion);
50         if (regionLength == REGION_LENGTH) {
51             region = NewArrayAndCopy(newRegion, regionLength);
52         }
53     }
54     InitIdstr();
55     status = ISUCCESS;
56 }
57 
InitIdstr()58 void LocaleInfo::InitIdstr()
59 {
60     if (language == nullptr) {
61         return;
62     }
63     std::string idStr(language);
64     // script consists of four letters
65     if ((script != nullptr) && (LenCharArray(script) > 0)) {
66         idStr = idStr + "-" + script;
67     }
68     if ((region != nullptr) && (LenCharArray(region) > 0)) {
69         idStr = idStr + "-" + region;
70     }
71     I18nFree(static_cast<void *>(id));
72     id = NewArrayAndCopy(idStr.data(), idStr.size());
73 }
74 
LocaleInfo(const char * newLang,const char * newScript,const char * newRegion)75 LocaleInfo::LocaleInfo(const char *newLang, const char *newScript, const char *newRegion)
76 {
77     int status = ISUCCESS;
78     Init(newLang, newScript, newRegion, status);
79     if (status != ISUCCESS) {
80         SetFail();
81     }
82 }
83 
IsDefaultLocale() const84 bool LocaleInfo::IsDefaultLocale() const
85 {
86     if ((GetLanguage() == nullptr) || (GetRegion() == nullptr)) {
87         return false;
88     }
89     return ((strcmp(GetLanguage(), "en") == 0) && (strcmp(GetRegion(), "US") == 0));
90 }
91 
LocaleInfo(const char * newLang,const char * newRegion)92 LocaleInfo::LocaleInfo(const char *newLang, const char *newRegion)
93 {
94     int status = ISUCCESS;
95     Init(newLang, nullptr, newRegion, status);
96     if (status != ISUCCESS) {
97         SetFail();
98     }
99 }
100 
LocaleInfo()101 LocaleInfo::LocaleInfo()
102 {
103     id = nullptr;
104     SetFail();
105 }
106 
LocaleInfo(const LocaleInfo & o)107 LocaleInfo::LocaleInfo(const LocaleInfo &o)
108 {
109     int status = ISUCCESS;
110     Init(o.language, o.script, o.region, status);
111     if (status != ISUCCESS) {
112         SetFail();
113     }
114 }
115 
~LocaleInfo()116 LocaleInfo::~LocaleInfo()
117 {
118     FreeResource();
119 }
120 
FreeResource()121 void LocaleInfo::FreeResource()
122 {
123     I18nFree(static_cast<void *>(language));
124     I18nFree(static_cast<void *>(script));
125     I18nFree(static_cast<void *>(region));
126     I18nFree(static_cast<void *>(id));
127     I18nFree(static_cast<void *>(numberDigits));
128 }
129 
operator ==(const LocaleInfo & other) const130 bool LocaleInfo::operator ==(const LocaleInfo &other) const
131 {
132     bool ret = CompareLocaleItem(language, other.language);
133     if (!ret) {
134         return false;
135     }
136     ret = CompareLocaleItem(script, other.script);
137     if (!ret) {
138         return false;
139     }
140     ret = CompareLocaleItem(region, other.region);
141     return ret;
142 }
143 
operator =(const LocaleInfo & o)144 LocaleInfo &LocaleInfo::operator =(const LocaleInfo &o)
145 {
146     if (&o == this) {
147         return *this;
148     }
149     FreeResource();
150     if (o.language != nullptr) {
151         language = NewArrayAndCopy(o.language, strlen(o.language));
152     }
153     if (o.script != nullptr) {
154         script = NewArrayAndCopy(o.script, strlen(o.script));
155     }
156     if (o.region != nullptr) {
157         region = NewArrayAndCopy(o.region, strlen(o.region));
158     }
159     if (o.id != nullptr) {
160         id = NewArrayAndCopy(o.id, LenCharArray(o.id));
161     }
162     if (o.numberDigits != nullptr) {
163         numberDigits = NewArrayAndCopy(o.numberDigits, LenCharArray(o.numberDigits));
164     }
165     return *this;
166 }
167 
GetLanguage() const168 const char *LocaleInfo::GetLanguage() const
169 {
170     return language;
171 }
172 
GetScript() const173 const char *LocaleInfo::GetScript() const
174 {
175     return script;
176 }
177 
GetRegion() const178 const char *LocaleInfo::GetRegion() const
179 {
180     return region;
181 }
182 
GetId() const183 const char *LocaleInfo::GetId() const
184 {
185     const char *rid = id;
186     return rid;
187 }
188 
IsSuccess()189 bool LocaleInfo::IsSuccess()
190 {
191     bool r = isSucc;
192     isSucc = true;
193     return r;
194 }
195 
SetFail()196 void LocaleInfo::SetFail()
197 {
198     isSucc = false;
199 }
200 
ChangeLanguageCode(char * lang,const int32_t dstSize,const char * src,const int32_t srcSize) const201 bool LocaleInfo::ChangeLanguageCode(char *lang, const int32_t dstSize, const char *src, const int32_t srcSize) const
202 {
203     if (lang == nullptr || src == nullptr) {
204         return false;
205     }
206     if (srcSize == (LANGUAGE_MIN_LENGTH + 1)) { // three letter language only support fil and mai
207         if (memcmp(src, "fil", srcSize) == 0) {
208             lang[0] = 't';
209             lang[1] = 'l';
210         } else if (memcmp(src, "mai", srcSize) == 0) {
211             lang[0] = 'm';
212             lang[1] = 'd';
213         } else {
214             return false;
215         }
216         return true;
217     } else if (srcSize == LANGUAGE_MIN_LENGTH) {
218         if (memcmp(src, "he", srcSize) == 0) {
219             lang[0] = 'i';
220             lang[1] = 'w';
221         } else if (memcmp(src, "id", srcSize) == 0) {
222             lang[0] = 'i';
223             lang[1] = 'n';
224         } else {
225             if (strcpy_s(lang, dstSize, src) != EOK) {
226                 return false;
227             }
228         }
229         return true;
230     }
231     return false;
232 }
233 
GetMask() const234 uint32_t LocaleInfo::GetMask() const
235 {
236     if (language == nullptr) {
237         return 0;
238     }
239     char lang[LANGUAGE_MAX_LENGTH];
240     bool isRight = ChangeLanguageCode(lang, LANGUAGE_MAX_LENGTH, language, LenCharArray(language));
241     if (!isRight) {
242         return 0;
243     }
244     // use 7bit to represent an English letter,
245     // 32--- language ---18--- script ---14--- region ---0
246     uint32_t tempLangFirst = (lang[0] - CHAR_OFF);
247     uint32_t tempLangSecond = (lang[1] - CHAR_OFF);
248     uint32_t mask = (tempLangFirst << LANG_FIRST_BEGIN) | (tempLangSecond << LANG_SECOND_BEGIN);
249     if ((script != nullptr) && (LenCharArray(script) > 0)) {
250         if (strcmp(script, "Hans") == 0) {
251             mask = mask | (HANS << SCRIPT_BEGIN);
252         } else if (strcmp(script, "Hant") == 0) {
253             mask = mask | (HANT << SCRIPT_BEGIN);
254         } else if (strcmp(script, "Latn") == 0) {
255             mask = mask | (LATN << SCRIPT_BEGIN);
256         } else if (strcmp(script, "Qaag") == 0) {
257             mask = mask | (QAAG << SCRIPT_BEGIN);
258         } else if (strcmp(script, "Cyrl") == 0) {
259             mask = mask | (CYRL << SCRIPT_BEGIN);
260         } else if (strcmp(script, "Deva") == 0) {
261             mask = mask | (DEVA << SCRIPT_BEGIN);
262         } else if (strcmp(script, "Guru") == 0) {
263             mask = mask | (GURU << SCRIPT_BEGIN);
264         }
265     }
266     if ((region != nullptr) && (LenCharArray(region) > 1)) {
267         uint32_t tempRegion = (region[0] - CHAR_OFF);
268         uint32_t tempRegionSecond = (region[1] - CHAR_OFF);
269         mask = mask | (tempRegion << REGION_FIRST_LETTER) | (tempRegionSecond);
270     }
271     return mask;
272 }
273 
ForLanguageTag(const char * languageTag,I18nStatus & status)274 LocaleInfo LocaleInfo::ForLanguageTag(const char *languageTag, I18nStatus &status)
275 {
276     LocaleInfo locale;
277     if (languageTag == nullptr) {
278         status = IERROR;
279         return locale;
280     }
281     ParseLanguageTag(locale, languageTag, status);
282     locale.InitIdstr();
283     return locale;
284 }
285 
ParseLanguageTag(LocaleInfo & locale,const char * languageTag,I18nStatus & status)286 void LocaleInfo::ParseLanguageTag(LocaleInfo &locale, const char *languageTag, I18nStatus &status)
287 {
288     const char *tag = languageTag;
289     uint16_t options = OPT_LANG;
290     const char *key = nullptr;
291     const char *value = nullptr;
292     uint8_t type = 0;
293     while (tag) {
294         const char *start = tag;
295         const char *end = tag;
296         while (*end) {
297             if (*end == '-') {
298                 break;
299             }
300             ++end;
301         }
302         tag = end + 1;
303         if (*end == '\0') {
304             tag = nullptr;
305         }
306         auto tagLength = end - start;
307         ConfirmTagType(start, tagLength, type, key, value);
308         if (!ParseNormalSubTag(locale, start, tagLength, options, type)) {
309             if ((options & OPT_EXTENSION) && (type == TAG_VALUE)) {
310                 ProcessExtension(locale, key, value);
311                 type = TAG_COMMON;
312             }
313         }
314     }
315     I18nFree(static_cast<void *>(const_cast<char *>(key)));
316     I18nFree(static_cast<void *>(const_cast<char *>(value)));
317 }
318 
ParseNormalSubTag(LocaleInfo & locale,const char * start,size_t tagLength,uint16_t & options,uint8_t & type)319 bool LocaleInfo::ParseNormalSubTag(LocaleInfo &locale, const char *start, size_t tagLength, uint16_t &options,
320     uint8_t &type)
321 {
322     if ((start == nullptr) || (tagLength == 0)) {
323         return false;
324     }
325     if ((options & OPT_LANG) && (type == TAG_COMMON)) {
326         if (IsLanguage(start, tagLength)) {
327             locale.language = I18nNewCharString(start, tagLength);
328             options &= ~OPT_LANG;
329             options |= OPT_SCRIPT | OPT_REGION | OPT_EXTENSION;
330             return true;
331         }
332     }
333     if ((options & OPT_SCRIPT) && (type == TAG_COMMON)) {
334         if (IsScript(start, tagLength)) {
335             options &= ~OPT_SCRIPT;
336             locale.script = I18nNewCharString(start, tagLength);
337             return true;
338         }
339     }
340     if ((options & OPT_REGION) && (type == TAG_COMMON)) {
341         if (IsRegion(start, tagLength)) {
342             options &= ~OPT_REGION;
343             options &= ~OPT_SCRIPT;
344             locale.region = I18nNewCharString(start, tagLength);
345             return true;
346         }
347     }
348     return false;
349 }
350 
ConfirmTagType(const char * start,size_t length,uint8_t & type,const char * & key,const char * & value)351 void LocaleInfo::ConfirmTagType(const char *start, size_t length, uint8_t &type, const char* &key, const char* &value)
352 {
353     if (start == nullptr) {
354         return;
355     }
356     switch (type) {
357         case TAG_COMMON: {
358             if ((length == 1) && (*start == 'u')) {
359                 type = TAG_U;
360             }
361             return;
362         }
363         case TAG_U: {
364             type = TAG_KEY;
365             I18nFree(static_cast<void *>(const_cast<char *>(key)));
366             key = I18nNewCharString(start, length);
367             return;
368         }
369         case TAG_KEY: {
370             type = TAG_VALUE;
371             I18nFree(static_cast<void *>(const_cast<char *>(value)));
372             value = I18nNewCharString(start, length);
373             return;
374         }
375         default: {
376             type = TAG_COMMON;
377             return;
378         }
379     }
380 }
381 
ProcessExtension(LocaleInfo & locale,const char * key,const char * value)382 void LocaleInfo::ProcessExtension(LocaleInfo &locale, const char *key, const char *value)
383 {
384     if (key == nullptr || value == nullptr) {
385         return;
386     }
387     // now we only support numbering systems in extensions
388     if (strcmp(key, "nu") == 0) {
389         locale.numberDigits = NewArrayAndCopy(value, strlen(value));
390         return;
391     }
392 }
393 
IsLanguage(const char * start,uint8_t length)394 bool LocaleInfo::IsLanguage(const char *start, uint8_t length)
395 {
396     if ((length != LANGUAGE_MAX_LENGTH) && (length != LANGUAGE_MIN_LENGTH)) {
397         return false;
398     }
399     for (uint8_t i = 0; i < length; ++i) {
400         const char ch = *(start + i);
401         if (ch < 'a' || ch > 'z') {
402             return false;
403         }
404     }
405     return true;
406 }
407 
IsScript(const char * start,uint8_t length)408 bool LocaleInfo::IsScript(const char *start, uint8_t length)
409 {
410     // all scripts's length is 4,
411     // now we support Latn, Hans, Hant, Qaag, Cyrl, Deva, Guru
412     if (length != SCRIPT_LENGTH || start == nullptr) {
413         return false;
414     }
415     if (SCRIPTS.find(std::string(start, length)) != SCRIPTS.end()) {
416         return true;
417     } else {
418         return false;
419     }
420 }
421 
IsRegion(const char * start,uint8_t length)422 bool LocaleInfo::IsRegion(const char *start, uint8_t length)
423 {
424     if (length != REGION_LENGTH) {
425         return false;
426     }
427     for (uint8_t i = 0; i < length; ++i) {
428         const char ch = *(start + i);
429         if (ch < 'A' || ch > 'Z') { // region characters should all be upper case.
430             return false;
431         }
432     }
433     return true;
434 }
435 
GetExtension(const char * key)436 const char *LocaleInfo::GetExtension(const char *key)
437 {
438     if (strcmp(key, "nu") == 0) {
439         return numberDigits;
440     }
441     return nullptr;
442 }
443