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