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