• 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 "data_resource.h"
17 #include <cstring>
18 #ifdef I18N_PRODUCT
19 #include <cerrno>
20 #include <log.h>
21 #endif
22 #include "i18n_memory_adapter.h"
23 #include "securec.h"
24 #include "str_util.h"
25 
26 using namespace OHOS::I18N;
27 using namespace std;
28 
29 #ifdef I18N_PRODUCT
30 static const char *DATA_RESOURCE_PATH = "system/i18n/i18n.dat";
31 #else
32 static const char *DATA_RESOURCE_PATH = "/storage/data/i18n.dat";
33 #endif
34 
DataResource(const LocaleInfo * localeInfo)35 DataResource::DataResource(const LocaleInfo *localeInfo)
36 {
37     uint32_t enMask = LocaleInfo("en", "US").GetMask();
38     if (localeInfo == nullptr) {
39         localeMask = enMask;
40     } else {
41         localeMask = localeInfo->GetMask();
42         if (localeInfo->IsDefaultLocale()) {
43             fallbackMask = 0;
44         } else {
45             fallbackMask = GetFallbackMask(*localeInfo);
46         }
47         if ((fallbackMask != 0) && (fallbackMask != enMask)) {
48             defaultMask = enMask;
49         }
50     }
51     for (int i = 0; i < DataResourceType::RESOURCE_TYPE_END; ++i) {
52         loaded[i] = DataResourceType::RESOURCE_TYPE_END;
53     }
54 }
55 
~DataResource()56 DataResource::~DataResource()
57 {
58     if (resourceIndex != nullptr) {
59         I18nFree(static_cast<void *>(resourceIndex));
60     }
61     if (fallbackResourceIndex) {
62         I18nFree(static_cast<void *>(fallbackResourceIndex));
63     }
64     if (defaultResourceIndex) {
65         I18nFree(static_cast<void *>(defaultResourceIndex));
66     }
67     FreeResource();
68 }
69 
FreeResource()70 void DataResource::FreeResource()
71 {
72     if (resource != nullptr) {
73         while (resourceCount > 0) {
74             I18nFree(static_cast<void *>(resource[resourceCount - 1]));
75             --resourceCount;
76         }
77     }
78     I18nFree(static_cast<void *>(resource));
79     if (fallbackResource != nullptr) {
80         while (fallbackResourceCount > 0) {
81             I18nFree(static_cast<void *>(fallbackResource[fallbackResourceCount - 1]));
82             --fallbackResourceCount;
83         }
84     }
85     I18nFree(static_cast<void *>(fallbackResource));
86     if (defaultResource != nullptr) {
87         while (defaultResourceCount > 0) {
88             I18nFree(static_cast<void *>(defaultResource[defaultResourceCount - 1]));
89             --defaultResourceCount;
90         }
91     }
92     I18nFree(static_cast<void *>(defaultResource));
93 }
94 
GetString(DataResourceType type) const95 char *DataResource::GetString(DataResourceType type) const
96 {
97     uint32_t index = static_cast<uint32_t>(type);
98     return GetString(index);
99 }
100 
GetString(uint32_t index) const101 char *DataResource::GetString(uint32_t index) const
102 {
103     if (index >= DataResourceType::RESOURCE_TYPE_END) {
104         return nullptr;
105     }
106     uint32_t targetType = loaded[index];
107     if (targetType == DataResourceType::RESOURCE_TYPE_END) {
108         return nullptr;
109     }
110     switch (targetType) {
111         case LocaleDataType::RESOURCE: {
112             return BinarySearchString(resourceIndex, resourceCount, index, resource, resourceCount);
113         }
114         case LocaleDataType::FALLBACK_RESOURCE: {
115             return BinarySearchString(fallbackResourceIndex, fallbackResourceCount, index,
116                 fallbackResource, fallbackResourceCount);
117         }
118         default: {
119             return BinarySearchString(defaultResourceIndex, defaultResourceCount, index,
120                 defaultResource, defaultResourceCount);
121         }
122     }
123 }
124 
BinarySearchString(uint32_t * indexArray,uint32_t length,uint32_t target,char ** stringArray,uint32_t stringLength) const125 char *DataResource::BinarySearchString(uint32_t *indexArray, uint32_t length, uint32_t target,
126     char **stringArray, uint32_t stringLength) const
127 {
128     if ((indexArray == nullptr) || (stringArray == nullptr) || (stringLength == 0) || (length == 0)) {
129         return nullptr;
130     }
131     int32_t low = 0;
132     int32_t high = static_cast<int32_t>(length - 1);
133     while (low <= high) {
134         int32_t mid = low + (high - low) / 2;
135         if (mid > static_cast<int32_t>(stringLength)) {
136             return nullptr;
137         }
138         uint32_t temp = indexArray[mid];
139         if (temp == target) {
140             return stringArray[mid];
141         } else if (temp < target) {
142             low = mid + 1;
143         } else {
144             high = mid - 1;
145         }
146     }
147     return nullptr;
148 }
149 
Init(void)150 bool DataResource::Init(void)
151 {
152     int32_t infile = open(DATA_RESOURCE_PATH, O_RDONLY);
153     if (infile < 0) {
154 #ifdef I18N_PRODUCT
155         HILOG_ERROR(HILOG_MODULE_GLOBAL, "DataResource::Init: open DATA_RESOURCE_PATH failed, errno(%d)!", errno);
156 #endif
157         return false;
158     }
159     bool ret = ReadHeader(infile);
160     if (!ret) {
161         close(infile);
162         return false;
163     }
164     if ((localesCount < 1) || (localesCount > MAX_LOCALE_ITEM_SIZE)) {
165         close(infile);
166         return false;
167     }
168     ret = PrepareData(infile);
169     close(infile);
170     return ret;
171 }
172 
ReadHeader(int32_t infile)173 bool DataResource::ReadHeader(int32_t infile)
174 {
175     int32_t seekSize = lseek(infile, GLOBAL_RESOURCE_HEADER_SKIP, SEEK_SET);
176     if (seekSize < 0) {
177         return false;
178     }
179     char cache[GLOBAL_RESOURCE_HEADER_LEFT] = {0};
180     int32_t readSize = read(infile, cache, GLOBAL_RESOURCE_HEADER_LEFT);
181     if (readSize != GLOBAL_RESOURCE_HEADER_LEFT) {
182         return false;
183     }
184     localesCount = ((static_cast<unsigned char>(cache[0]) << SHIFT_ONE_BYTE) | (static_cast<unsigned char>(cache[1])));
185     stringPoolOffset = ((static_cast<unsigned char>(cache[GLOBAL_RESOURCE_INDEX_OFFSET]) << SHIFT_ONE_BYTE) |
186         (static_cast<unsigned char>(cache[GLOBAL_RESOURCE_INDEX_OFFSET + 1])));
187     return true;
188 }
189 
PrepareData(int32_t infile)190 bool DataResource::PrepareData(int32_t infile)
191 {
192     uint32_t localeSize = localesCount * GLOBAL_LOCALE_MASK_ITEM_SIZE;
193     char *locales = reinterpret_cast<char *>(I18nMalloc(localeSize));
194     if (locales == nullptr) {
195         return false;
196     }
197     int32_t readSize = read(infile, locales, localeSize);
198     if (readSize < 0 || localeSize != static_cast<uint32_t>(readSize)) {
199         I18nFree(static_cast<void *>(locales));
200         return false;
201     }
202     int32_t localeIndex = BinarySearchLocale(localeMask, reinterpret_cast<unsigned char*>(locales));
203     int32_t fallbackLocaleIndex = -1;
204     int32_t defaultLocaleIndex = -1;
205     GetFallbackAndDefaultLocaleIndex(fallbackLocaleIndex, defaultLocaleIndex, locales);
206     uint32_t configOffset = 0;
207     if (localeIndex >= 0) {
208         configOffset = ConvertUChar(reinterpret_cast<unsigned char*>(locales + GLOBAL_LOCALE_MASK_ITEM_SIZE *
209             localeIndex + GLOBAL_RESOURCE_MASK_OFFSET));
210         resourceCount = ConvertUChar(reinterpret_cast<unsigned char*>(locales + GLOBAL_LOCALE_MASK_ITEM_SIZE *
211             localeIndex + GLOBAL_RESOURCE_MASK_OFFSET + GLOBAL_RESOURCE_INDEX_OFFSET));
212     }
213     uint32_t fallbackConfigOffset = 0;
214     uint32_t defaultConfigOffset = 0;
215     GetFallbackAndDefaultInfo(fallbackLocaleIndex, defaultLocaleIndex, fallbackConfigOffset, defaultConfigOffset,
216         locales);
217     I18nFree(static_cast<void *>(locales));
218     bool ret = true;
219     if (IsTypeNeeded(localeIndex, resourceCount)) {
220         ret = PrepareLocaleData(infile, configOffset, resourceCount, LocaleDataType::RESOURCE);
221     }
222     if (IsTypeNeeded(fallbackLocaleIndex, fallbackResourceCount)) {
223         ret = PrepareLocaleData(infile, fallbackConfigOffset, fallbackResourceCount,
224             LocaleDataType::FALLBACK_RESOURCE);
225     }
226     if (IsTypeNeeded(defaultLocaleIndex, defaultResourceCount)) {
227         ret = PrepareLocaleData(infile, defaultConfigOffset, defaultResourceCount, LocaleDataType::DEFAULT_RESOURCE);
228     }
229     return ret;
230 }
231 
IsTypeNeeded(int32_t index,uint32_t count)232 bool DataResource::IsTypeNeeded(int32_t index, uint32_t count)
233 {
234     if ((index < 0) || FullLoaded()) {
235         return false;
236     }
237     return (count > 0) && (count <= DataResourceType::RESOURCE_TYPE_END);
238 }
239 
GetFallbackAndDefaultLocaleIndex(int32_t & fallbackLocaleIndex,int32_t & defaultLocaleIndex,char * locales)240 void DataResource::GetFallbackAndDefaultLocaleIndex(int32_t &fallbackLocaleIndex, int32_t &defaultLocaleIndex,
241     char *locales)
242 {
243     if (fallbackMask != 0) {
244         fallbackLocaleIndex = BinarySearchLocale(fallbackMask, reinterpret_cast<unsigned char*>(locales));
245     }
246     if (defaultMask != 0) {
247         defaultLocaleIndex = BinarySearchLocale(defaultMask, reinterpret_cast<unsigned char*>(locales));
248     }
249 }
250 
GetFallbackAndDefaultInfo(const int32_t & fallbackLocaleIndex,const int32_t & defaultLocaleIndex,uint32_t & fallbackConfigOffset,uint32_t & defaultConfigOffset,char * locales)251 void DataResource::GetFallbackAndDefaultInfo(const int32_t &fallbackLocaleIndex, const int32_t &defaultLocaleIndex,
252     uint32_t &fallbackConfigOffset, uint32_t &defaultConfigOffset, char* locales)
253 {
254     if (fallbackLocaleIndex != -1) {
255         fallbackConfigOffset = ConvertUChar(reinterpret_cast<unsigned char*>(locales + GLOBAL_LOCALE_MASK_ITEM_SIZE *
256             fallbackLocaleIndex + GLOBAL_RESOURCE_MASK_OFFSET));
257         fallbackResourceCount = ConvertUChar(reinterpret_cast<unsigned char*>(locales + GLOBAL_LOCALE_MASK_ITEM_SIZE *
258             fallbackLocaleIndex + GLOBAL_RESOURCE_MASK_OFFSET + GLOBAL_RESOURCE_INDEX_OFFSET));
259     }
260     if (defaultLocaleIndex != -1) {
261         defaultConfigOffset = ConvertUChar(reinterpret_cast<unsigned char*>(locales + GLOBAL_LOCALE_MASK_ITEM_SIZE *
262             defaultLocaleIndex + GLOBAL_RESOURCE_MASK_OFFSET));
263         defaultResourceCount = ConvertUChar(reinterpret_cast<unsigned char*>(locales + GLOBAL_LOCALE_MASK_ITEM_SIZE *
264             defaultLocaleIndex + GLOBAL_RESOURCE_MASK_OFFSET + GLOBAL_RESOURCE_INDEX_OFFSET));
265     }
266 }
267 
PrepareLocaleData(int32_t infile,uint32_t configOffset,uint32_t count,LocaleDataType type)268 bool DataResource::PrepareLocaleData(int32_t infile, uint32_t configOffset, uint32_t count, LocaleDataType type)
269 {
270     currentType = type;
271     if (count < 1 || count > DataResourceType::RESOURCE_TYPE_END) {
272         return false;
273     }
274     uint32_t resourceSize = count * GLOBAL_RESOURCE_CONFIG_SIZE;
275     char *configs = reinterpret_cast<char *>(I18nMalloc(resourceSize));
276     if (configs == nullptr) {
277         return false;
278     }
279     int32_t seekSize = lseek(infile, configOffset, SEEK_SET);
280     if (configOffset != static_cast<uint32_t>(seekSize)) {
281         I18nFree(static_cast<void *>(configs));
282         return false;
283     }
284     int32_t readSize = read(infile, configs, resourceSize);
285     if (readSize != static_cast<int32_t>(resourceSize)) {
286         I18nFree(static_cast<void *>(configs));
287         return false;
288     }
289     bool ret = GetStringFromStringPool(configs, infile, type);
290     I18nFree(static_cast<void *>(configs));
291     return ret;
292 }
293 
GetFinalCount(char * configs,LocaleDataType type)294 uint32_t DataResource::GetFinalCount(char *configs, LocaleDataType type)
295 {
296     uint32_t count = 0;
297     switch (type) {
298         case LocaleDataType::RESOURCE: {
299             count = resourceCount;
300             break;
301         }
302         case LocaleDataType::FALLBACK_RESOURCE: {
303             count = fallbackResourceCount;
304             break;
305         }
306         default: {
307             count = defaultResourceCount;
308         }
309     }
310     uint32_t finalCount = 0;
311     for (uint32_t i = 0; i < count; ++i) {
312         uint32_t index = ConvertUChar(reinterpret_cast<unsigned char*>(configs + i * GLOBAL_RESOURCE_CONFIG_SIZE));
313         if (index >= DataResourceType::RESOURCE_TYPE_END) {
314             return 0;
315         }
316         if (loaded[index] != DataResourceType::RESOURCE_TYPE_END) {
317             continue;
318         } else {
319             loaded[index] = type;
320         }
321         ++finalCount;
322     }
323     return finalCount;
324 }
325 
GetStringFromStringPool(char * configs,int32_t infile,LocaleDataType type)326 bool DataResource::GetStringFromStringPool(char *configs, int32_t infile,
327     LocaleDataType type)
328 {
329     uint32_t finalCount = GetFinalCount(configs, type);
330     if (finalCount == 0) {
331         return true;
332     }
333     uint32_t **index = nullptr;
334     char ***wanted = nullptr;
335     uint32_t originalCount = 0;
336     switch (type) {
337         case LocaleDataType::RESOURCE: {
338             originalCount = resourceCount;
339             resourceCount = finalCount;
340             index = &resourceIndex;
341             wanted = &resource;
342             break;
343         }
344         case LocaleDataType::FALLBACK_RESOURCE: {
345             originalCount = fallbackResourceCount;
346             fallbackResourceCount = finalCount;
347             index = &fallbackResourceIndex;
348             wanted = &fallbackResource;
349             break;
350         }
351         default: {
352             originalCount = defaultResourceCount;
353             defaultResourceCount = finalCount;
354             index = &defaultResourceIndex;
355             wanted = &defaultResource;
356             break;
357         }
358     }
359     if (!ApplyForResource(index, wanted, finalCount)) {
360         return false;
361     }
362     return Retrieve(configs, infile, originalCount, type);
363 }
364 
GetType(char ** & adjustResource,uint32_t * & adjustResourceIndex,uint32_t & count,LocaleDataType type)365 void DataResource::GetType(char** &adjustResource, uint32_t* &adjustResourceIndex, uint32_t &count,
366     LocaleDataType type)
367 {
368     switch (type) {
369         case LocaleDataType::RESOURCE: {
370             adjustResource = resource;
371             adjustResourceIndex = resourceIndex;
372             count = resourceCount;
373             break;
374         }
375         case LocaleDataType::FALLBACK_RESOURCE: {
376             adjustResource = fallbackResource;
377             adjustResourceIndex = fallbackResourceIndex;
378             count = fallbackResourceCount;
379             break;
380         }
381         default: {
382             adjustResource = defaultResource;
383             adjustResourceIndex = defaultResourceIndex;
384             count = defaultResourceCount;
385             break;
386         }
387     }
388 }
389 
Retrieve(char * configs,int32_t infile,const uint32_t orginalCount,LocaleDataType type)390 bool DataResource::Retrieve(char *configs, int32_t infile, const uint32_t orginalCount,
391     LocaleDataType type)
392 {
393     uint32_t count = 0;
394     char **adjustResource = nullptr;
395     uint32_t *adjustResourceIndex = nullptr;
396     GetType(adjustResource, adjustResourceIndex, count, type);
397     uint32_t currentIndex = 0;
398     for (uint32_t i = 0; i < orginalCount; ++i) {
399         uint32_t index = ConvertUChar(reinterpret_cast<unsigned char*>(configs + i * GLOBAL_RESOURCE_CONFIG_SIZE));
400         if (loaded[index] != type) {
401             continue;
402         }
403         uint32_t offset = ConvertUChar(reinterpret_cast<unsigned char*>(configs + i *
404             GLOBAL_RESOURCE_CONFIG_SIZE + GLOBAL_RESOURCE_INDEX_OFFSET));
405         uint32_t length = ConvertUChar(reinterpret_cast<unsigned char*>(configs + i *
406             GLOBAL_RESOURCE_CONFIG_SIZE + GLOBAL_RESOURCE_MASK_OFFSET));
407         int32_t seekSize = lseek(infile, stringPoolOffset + offset, SEEK_SET);
408         if ((length == 0) || (seekSize != static_cast<int32_t>(stringPoolOffset + offset))) {
409             adjustResource[currentIndex] = nullptr;
410             adjustResourceIndex[currentIndex] = index;
411         } else {
412             char *temp = reinterpret_cast<char *>(I18nMalloc(length + 1));
413             if (temp == nullptr) {
414                 loaded[index] = DataResourceType::RESOURCE_TYPE_END;
415                 return false;
416             }
417             int32_t readSize = read(infile, temp, length);
418             temp[length] = 0;
419             if ((readSize < 0) || (static_cast<uint32_t>(readSize) != length)) {
420                 I18nFree(static_cast<void *>(temp));
421                 return false;
422             }
423             adjustResource[currentIndex] = temp;
424             adjustResourceIndex[currentIndex] = index;
425         }
426         ++currentIndex;
427     }
428     return true;
429 }
430 
ApplyForResource(uint32_t ** index,char *** wanted,uint32_t totalCount)431 bool DataResource::ApplyForResource(uint32_t **index, char ***wanted, uint32_t totalCount)
432 {
433     if ((index == nullptr) || (wanted == nullptr) || (totalCount == 0)) {
434         return false;
435     }
436     *index = reinterpret_cast<uint32_t *>(I18nMalloc(sizeof(uint32_t) * totalCount));
437     if (*index == nullptr) {
438         return false;
439     }
440     *wanted = reinterpret_cast<char **>(I18nMalloc(sizeof(char *) * totalCount));
441     if (*wanted == nullptr) {
442         return false; // free *index in FreeResource
443     }
444     for (uint32_t i = 0; i < totalCount; ++i) {
445         (*wanted)[i] = nullptr;
446     }
447     return true;
448 }
449 
BinarySearchLocale(const uint32_t mask,unsigned char * locales)450 int32_t DataResource::BinarySearchLocale(const uint32_t mask, unsigned char *locales)
451 {
452     if ((locales == nullptr) || (localesCount == 0)) {
453         return -1;
454     }
455     int32_t low = 0;
456     int32_t high = static_cast<int32_t>(localesCount - 1);
457     while (low <= high) {
458         int32_t mid = low + (high - low) / 2;
459         if (mid > 1024) { // locales count < 1024
460             return -1;
461         }
462         uint32_t midMask = ConvertUint(locales + mid * GLOBAL_LOCALE_MASK_ITEM_SIZE);
463         if (midMask == mask) {
464             return mid;
465         } else if (midMask < mask) {
466             low = mid + 1;
467         } else {
468             high = mid - 1;
469         }
470     }
471     return -1;
472 }
473 
ConvertUint(unsigned char * src)474 uint32_t DataResource::ConvertUint(unsigned char *src)
475 {
476     if (src == nullptr) {
477         return 0;
478     }
479     uint32_t ret = 0;
480     ret |= (src[0] << SHIFT_THREE_BYTE); // 0 indicates first byte
481     ret |= (src[1] << SHIFT_TWO_BYTE); // 1 indicates second byte
482     ret |= (src[2] << SHIFT_ONE_BYTE); // 2 indicates third byte
483     ret |= src[3]; // 3 indicates forth byte
484     return ret;
485 }
486 
ConvertUChar(unsigned char * src)487 uint32_t DataResource::ConvertUChar(unsigned char *src)
488 {
489     if (src == nullptr) {
490         return 0;
491     }
492     uint32_t ret = 0;
493     ret |= (src[0] << SHIFT_ONE_BYTE);
494     ret |= src[1];
495     return ret;
496 }
497 
FullLoaded()498 bool DataResource::FullLoaded()
499 {
500     for (uint32_t i = 0; i < DataResourceType::RESOURCE_TYPE_END; ++i) {
501         if (loaded[i] == DataResourceType::RESOURCE_TYPE_END) {
502             return false;
503         }
504     }
505     return true;
506 }
507 
GetFallbackMask(const LocaleInfo & src)508 uint32_t DataResource::GetFallbackMask(const LocaleInfo &src)
509 {
510     const char *language = src.GetLanguage();
511     const char *script = src.GetScript();
512     const char *region = src.GetRegion();
513     if ((language != nullptr) && (strcmp("en", language) == 0) && (script == nullptr)) {
514         return LocaleInfo("en", "", "US").GetMask();
515     }
516     if (region == nullptr) {
517         return LocaleInfo("en", "US").GetMask();
518     }
519     if (script == nullptr) {
520         return LocaleInfo(language, "", "").GetMask();
521     }
522     return LocaleInfo(language, script, "").GetMask();
523 }
524 
GetString(DataResourceType type,std::string & ret) const525 void DataResource::GetString(DataResourceType type, std::string &ret) const
526 {
527     uint32_t index = static_cast<uint32_t>(type);
528     char *temp = GetString(index);
529     if (temp == nullptr) {
530         ret = "";
531     } else {
532         ret = temp;
533     }
534 }
535