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