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