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