1 /*
2 * Copyright (c) 2020-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 "cjson_parser.h"
17 #if (FEATURE_LOCALIZATION_MODULE == 1)
18 #include "ace_log.h"
19 #include "global.h"
20 #include "js_fwk_common.h"
21 #if defined(TARGET_SIMULATOR)
22 #if (defined(_WIN32) || defined(_WIN64))
23 #include <io.h>
24 #else
25 #include "gfx_utils/file.h"
26 #include <dirent.h>
27 #include <sys/types.h>
28 #endif
29 #endif
30 #include "securec.h"
31 #include "string_util.h"
32 #include <string.h>
33
34 namespace OHOS {
35 namespace ACELite {
CJSONParser()36 CJSONParser::CJSONParser()
37 : isCached_(false),
38 isAllocated_(true),
39 startPos_(-1),
40 countries_(nullptr),
41 language_(nullptr),
42 filePath_(nullptr),
43 languageFile_(nullptr)
44 {
45 char left = '{';
46 leftDelemeter_ = left;
47 char right = '}';
48 rightDelemeter_ = right;
49 usedOffset_ = sizeof(uint32_t) * MAX_KEY_NUM;
50 }
51
Init()52 bool CJSONParser::Init()
53 {
54 const char * const filePath = JsAppContext::GetInstance()->GetCurrentAbilityPath();
55 const char * const folderName = "i18n";
56 filePath_ = RelocateResourceFilePath(filePath, folderName);
57 void *ram = ace_malloc(LOCALIZATION_SIZE);
58 if (ram == nullptr) {
59 HILOG_ERROR(HILOG_MODULE_ACE, "malloc cache ram failed");
60 isAllocated_ = false;
61 return false;
62 }
63 startPos_ = reinterpret_cast<uintptr_t>(ram);
64 return (filePath_ != nullptr);
65 }
66
FillPlaceholder(const char * format,jerry_value_t arg,jerry_length_t num,bool isPlural)67 char *CJSONParser::FillPlaceholder(const char *format, jerry_value_t arg, jerry_length_t num, bool isPlural)
68 {
69 if (format == nullptr) {
70 return nullptr;
71 }
72 if (isPlural) {
73 #ifdef LOCALIZATION_PLURAL
74 format = GetPluralValue(format, arg);
75 if (format == nullptr) {
76 return nullptr;
77 }
78 #endif
79 }
80 ListNode *values = nullptr; // store the value after split.
81 #ifdef LOCALIZATION_PLURAL
82 uint8_t length = FormatString(format, arg, values, isPlural, num);
83 if (isPlural) {
84 ACE_FREE(format);
85 }
86 #else
87 uint8_t length = FormatString(format, arg, values, num);
88 #endif // LOCALIZATION_PLURAL
89 char *result = nullptr;
90 if (values != nullptr) {
91 result = ToString(values, length);
92 ClearNode(values);
93 }
94 return result;
95 }
96
97 #ifdef LOCALIZATION_PLURAL
FormatString(const char * format,jerry_value_t arg,ListNode * & values,bool isPlural,jerry_length_t num)98 uint8_t CJSONParser::FormatString(const char *format,
99 jerry_value_t arg,
100 ListNode *&values,
101 bool isPlural,
102 jerry_length_t num)
103 #else
104 uint8_t CJSONParser::FormatString(const char *format, jerry_value_t arg, ListNode *&values, jerry_length_t num)
105 #endif
106 {
107 uint8_t length = 0;
108 int index = 0;
109 int leftIndex = IndexOf(format, leftDelemeter_, index); // get the index of '{'
110 while (leftIndex >= 0) {
111 char *value = SubStr(format, index, leftIndex - index);
112 if (AddNode(values, value)) {
113 length++;
114 } else {
115 ACE_FREE(value);
116 }
117 leftIndex++;
118 index = IndexOf(format, rightDelemeter_, leftIndex); // get the index of '}'
119 if (index > 0 && num > 1) {
120 char *content = SubStr(format, leftIndex, index - leftIndex);
121 #ifdef LOCALIZATION_PLURAL
122 char *contentValue = GetParamValue(content, arg, isPlural);
123 #else
124 char *contentValue = GetParamValue(content, arg);
125 #endif // LOCALIZATION_PLURAL
126 ACE_FREE(content);
127 if (AddNode(values, contentValue)) {
128 length++;
129 } else {
130 ACE_FREE(contentValue);
131 }
132 }
133 if ((index > 0) && (static_cast<size_t>(index) < strlen(format))) {
134 index++; // move the index '}' to the next char
135 } else {
136 // add the remain character to node.eg.the value is {count}aa, add the last aa to the node
137 char *currentVal = SubStr(format, index, strlen(format) - index);
138 if (AddNode(values, currentVal)) {
139 length++;
140 } else {
141 ACE_FREE(currentVal);
142 }
143 }
144 leftIndex = IndexOf(format, leftDelemeter_, index);
145 }
146 if (leftIndex < 0 && (static_cast<size_t>(index) < strlen(format))) {
147 char *currentVal = SubStr(format, index, strlen(format) - index);
148 if (AddNode(values, currentVal)) {
149 length++;
150 } else {
151 ACE_FREE(currentVal);
152 }
153 }
154 return length;
155 }
156
157 #ifdef LOCALIZATION_PLURAL
GetPluralValue(char * value,jerry_value_t param)158 char *CJSONParser::GetPluralValue(char *value, jerry_value_t param)
159 {
160 ListNode *plurals = nullptr;
161 int defaultNum = jerry_value_is_number(param) ? IntegerOf(param) : 1;
162 const char delemeter = '|'; // if the function is get plural, split the value in json by '|'
163 int len = Split(value, delemeter, plurals);
164 const int maxLen = 2;
165 // get the index in plural array
166 if (len <= maxLen) {
167 value = (defaultNum != 1) ? GetNode(plurals, 1) : GetNode(plurals, len);
168 } else {
169 int index = (abs(defaultNum) < maxLen) ? abs(defaultNum) : maxLen; // get the index in plurals
170 value = GetNode(plurals, len - index);
171 }
172 char *result = SubStr(value, 0, strlen(value));
173 if (plurals) {
174 ClearNode(plurals);
175 }
176 return result;
177 }
178 #endif // LOCALIZATION_PLURAL
179
AddNode(ListNode * & head,char * current)180 bool CJSONParser::AddNode(ListNode *&head, char *current)
181 {
182 if (current == nullptr || strlen(current) == 0) {
183 return false;
184 }
185 ListNode *node = new ListNode();
186 if (node == nullptr) {
187 HILOG_ERROR(HILOG_MODULE_ACE, "create node failed");
188 return false;
189 }
190 node->next = head;
191 node->value = current;
192 head = node;
193 return true;
194 }
195
GetNode(ListNode * node,int index)196 char *CJSONParser::GetNode(ListNode *node, int index)
197 {
198 for (int i = 0; i < index - 1; i++) {
199 if (node == nullptr) {
200 break;
201 }
202 node = node->next;
203 }
204 return (node == nullptr) ? nullptr : node->value;
205 }
206
ClearNode(ListNode * & node)207 void CJSONParser::ClearNode(ListNode *&node)
208 {
209 while (node != nullptr) {
210 ListNode *current = node->next;
211 ACE_FREE(node->value);
212 delete node;
213 node = current;
214 }
215 }
216
ToString(ListNode * node,uint8_t length)217 char *CJSONParser::ToString(ListNode *node, uint8_t length)
218 {
219 if (node == nullptr || (length == 0)) {
220 return nullptr;
221 }
222 char **temp = static_cast<char **>(ace_malloc(length * sizeof(char *)));
223 if (temp == nullptr) {
224 return nullptr;
225 }
226 // reverse node value
227 uint8_t index = 0;
228 uint16_t strLength = 0; // the length of result
229 while (node != nullptr) {
230 if ((length - index > 0) && (node->value != nullptr)) {
231 size_t valueLen = strlen(node->value);
232 if ((valueLen > (MAX_VALUE_LEN - 1)) || (strLength > (MAX_VALUE_LEN - 1)) ||
233 (strLength + valueLen > (MAX_VALUE_LEN - 1))) {
234 ACE_FREE(temp);
235 return nullptr;
236 }
237 temp[length - 1 - index] = node->value;
238 strLength += valueLen;
239 }
240 node = node->next;
241 index++;
242 }
243 // the strLength is no more than maxValueLen_ - 1
244 strLength++;
245 char *result = static_cast<char *>(ace_malloc(strLength));
246 if (result == nullptr) {
247 HILOG_ERROR(HILOG_MODULE_ACE, "malloc localization result failed");
248 ACE_FREE(temp);
249 return nullptr;
250 }
251 // convert the value in node to string
252 if (strcpy_s(result, strLength, temp[0]) != 0) {
253 HILOG_ERROR(HILOG_MODULE_ACE, "merge string failed");
254 ACE_FREE(result);
255 ACE_FREE(temp);
256 return nullptr;
257 }
258 for (int i = 1; i < length; i++) {
259 if (strcat_s(result, strLength, temp[i]) != 0) {
260 HILOG_INFO(HILOG_MODULE_ACE, "merge string failed");
261 ACE_FREE(result);
262 ACE_FREE(temp);
263 return nullptr;
264 }
265 }
266 ACE_FREE(temp);
267 return result;
268 }
269
SubStr(const char * src,size_t start,size_t length)270 char *CJSONParser::SubStr(const char *src, size_t start, size_t length)
271 {
272 if (src == nullptr || start >= strlen(src)) {
273 return nullptr;
274 }
275 if (length > (MAX_VALUE_LEN - 1)) {
276 HILOG_ERROR(HILOG_MODULE_ACE, "the length is too long");
277 return nullptr;
278 }
279 size_t len = length + 1;
280 char *result = static_cast<char *>(ace_malloc(len));
281 if (result == nullptr) {
282 HILOG_ERROR(HILOG_MODULE_ACE, "malloc failed");
283 return nullptr;
284 }
285 errno_t error = strncpy_s(result, len, src + start, length);
286 if (error != 0) {
287 HILOG_ERROR(HILOG_MODULE_ACE, "copy string failed");
288 ACE_FREE(result);
289 return nullptr;
290 }
291 result[length] = '\0';
292 return result;
293 }
294
ChangeLanguage()295 CJSONParser::LanguageState CJSONParser::ChangeLanguage()
296 {
297 char *currentLanguage = static_cast<char *>(ace_malloc(MAX_LANGUAGE_LENGTH));
298 char *currentOrigion = static_cast<char *>(ace_malloc(MAX_REGION_LENGTH));
299 if ((currentLanguage == nullptr) || (currentOrigion == nullptr)) {
300 HILOG_ERROR(HILOG_MODULE_ACE, "malloc system language info failed");
301 ACE_FREE(currentLanguage);
302 ACE_FREE(currentOrigion);
303 return LanguageState::LANGUAGE_FAIL;
304 }
305 int langRet = GLOBAL_GetLanguage(currentLanguage, MAX_LANGUAGE_LENGTH);
306 int regionRet = GLOBAL_GetRegion(currentOrigion, MAX_REGION_LENGTH);
307 LanguageState result = LanguageState::LANGUAGE_CHANGED;
308 if ((langRet != 0) || (regionRet != 0)) {
309 result = LanguageState::LANGUAGE_FAIL;
310 }
311 if ((language_ != nullptr) && (strcmp(currentLanguage, language_) == 0) &&
312 (countries_ != nullptr) && (strcmp(currentOrigion, countries_) == 0)) {
313 result = LanguageState::LANGUAGE_NOT_CHANGE;
314 }
315 if ((result == LanguageState::LANGUAGE_NOT_CHANGE) || (result == LanguageState::LANGUAGE_FAIL)) {
316 ace_free(currentOrigion);
317 currentOrigion = nullptr;
318 ace_free(currentLanguage);
319 currentLanguage = nullptr;
320 return result;
321 }
322 ACE_FREE(language_);
323 language_ = currentLanguage;
324 ACE_FREE(countries_);
325 countries_ = currentOrigion;
326 return LanguageState::LANGUAGE_CHANGED;
327 }
328
329 #ifdef TARGET_SIMULATOR
330 #if (defined(_WIN32) || (defined(_WIN64)))
GetWinFiles(ListNode * & fileList)331 int CJSONParser::GetWinFiles(ListNode *&fileList)
332 {
333 if (language_ == nullptr) {
334 return 0;
335 }
336 int fileCount = 0;
337 _finddata_t file;
338 intptr_t opendir;
339 const char * const match = "*.*";
340 char* fileDir = RelocateResourceFilePath(filePath_, match);
341 if (fileDir == nullptr) {
342 HILOG_ERROR(HILOG_MODULE_ACE, "get localization path failed");
343 return 0;
344 }
345 if ((opendir = _findfirst(fileDir, &file)) == -1) {
346 HILOG_ERROR(HILOG_MODULE_ACE, "file not defined");
347 ACE_FREE(fileDir);
348 return 0;
349 }
350 while ((_findnext(opendir, &file) == 0) && (fileCount < UINT8_MAX)) {
351 if (strncmp(file.name, "..", strlen(language_)) == 0) {
352 continue;
353 }
354 char *value = SubStr(file.name, 0, strlen(file.name));
355 bool check = true;
356 check = AddNode(fileList, value);
357 if (!check) {
358 ACE_FREE(value);
359 } else {
360 fileCount++;
361 }
362 }
363 _findclose(opendir);
364 ACE_FREE(fileDir);
365 return fileCount;
366 }
367 #else
GetFiles(ListNode * & fileList)368 int CJSONParser::GetFiles(ListNode *&fileList)
369 {
370 DIR* dp = nullptr;
371 if ((dp = opendir(filePath_)) == nullptr) {
372 return 0;
373 }
374 struct dirent* dptr = nullptr;
375 int fileCount = 0;
376 while ((dptr = readdir(dp)) != nullptr) {
377 if (strcmp(dptr->d_name, ".") == 0 || strcmp(dptr->d_name, "..") == 0) {
378 continue;
379 }
380 char *value = SubStr(dptr->d_name, 0, strlen(dptr->d_name));
381 bool check = true;
382 check = AddNode(fileList, value);
383 if (!check) {
384 ACE_FREE(value);
385 } else {
386 fileCount++;
387 }
388 }
389 closedir(dp);
390 ACE_FREE(dptr);
391 return fileCount;
392 }
393 #endif // (defined(_WIN32) || (defined(_WIN64))
CheckLanguageFileName(char * languageFile)394 bool CJSONParser::CheckLanguageFileName(char *languageFile)
395 {
396 const int32_t i18nChangeLanguageApiVersion = 6;
397 bool isBelowAPI7 = (JsAppContext::GetInstance()->GetTargetApi() < i18nChangeLanguageApiVersion);
398 ACE_FREE(languageFile_);
399 if (isBelowAPI7) {
400 languageFile_ = languageFile;
401 return true;
402 }
403 bool canBeFullMatched = IsFileExistFullMatch(languageFile);
404 if (canBeFullMatched) {
405 languageFile_ = languageFile;
406 return true;
407 }
408 return false;
409 }
410 #endif // TARGET_SIMULATOR
411
IsFileExistFullMatch(const char * fileName)412 bool CJSONParser::IsFileExistFullMatch(const char *fileName)
413 {
414 #if defined(TARGET_SIMULATOR)
415 if (fileName == nullptr) {
416 return false;
417 }
418 ListNode *fileList = nullptr;
419 #if (defined(_WIN32) || (defined(_WIN64)))
420 int count = GetWinFiles(fileList);
421 #else
422 int count = GetFiles(fileList);
423 #endif
424 if (count == 0) {
425 ClearNode(fileList);
426 return false;
427 }
428 bool canBeFullMatched = false;
429 for (int i = 0; i <= count; i++) {
430 if (!strcmp(fileName, GetNode(fileList, i))) {
431 canBeFullMatched = true;
432 break;
433 }
434 }
435 ClearNode(fileList);
436 return canBeFullMatched;
437 #else
438 return true;
439 #endif
440 }
441
ChangeLanguageFileName()442 bool CJSONParser::ChangeLanguageFileName()
443 {
444 if ((language_ == nullptr) || (countries_ == nullptr)) {
445 if ((languageFile_ != nullptr) && (!strcmp(languageFile_, "en-US.json"))) {
446 return false;
447 }
448 ACE_FREE(languageFile_); // avoid leaking
449 languageFile_ = StringUtil::Copy("en-US.json");
450 return true;
451 }
452 uint8_t addedLen = 7; // the length of '-', ".json" and '\0'
453 uint8_t langLen = strlen(language_);
454 size_t fileLen = langLen + strlen(countries_) + addedLen;
455 char *languageFile = StringUtil::Malloc(fileLen);
456 if (languageFile == nullptr) {
457 return false;
458 }
459 errno_t error = strcpy_s(languageFile, fileLen, language_);
460 languageFile[langLen] = '-';
461 languageFile[langLen + 1] = '\0';
462 error += strcat_s(languageFile, fileLen, countries_);
463 error += strcat_s(languageFile, fileLen, ".json");
464 if (error > 0) {
465 ace_free(languageFile);
466 languageFile = nullptr;
467 return false;
468 }
469 #if defined(TARGET_SIMULATOR)
470 if (CheckLanguageFileName(languageFile)) {
471 return true;
472 }
473 // reset to en-US.json as default
474 ACE_FREE(languageFile);
475 languageFile_ = StringUtil::Copy("en-US.json");
476 #else
477 if ((languageFile_ != nullptr) && (!strcmp(languageFile, languageFile_))) {
478 ace_free(languageFile);
479 languageFile = nullptr;
480 } else {
481 ACE_FREE(languageFile_);
482 languageFile_ = languageFile;
483 }
484 #endif
485 return true;
486 }
487
CacheFile()488 bool CJSONParser::CacheFile()
489 {
490 if (!ChangeLanguageFileName()) {
491 HILOG_ERROR(HILOG_MODULE_ACE, "prepare language file name failed, cache status[%{public}d]", isCached_);
492 return true;
493 }
494 isCached_ = false;
495 usedOffset_ = sizeof(uint32_t) * MAX_KEY_NUM;
496 if (!isAllocated_) {
497 HILOG_ERROR(HILOG_MODULE_ACE, "cache buffer not ready");
498 return false;
499 }
500 if (memset_s(reinterpret_cast<void *>(startPos_), usedOffset_, 0, usedOffset_) != EOK) {
501 HILOG_ERROR(HILOG_MODULE_ACE, "initial psram failed");
502 return false;
503 }
504 if (memset_s(reinterpret_cast<void *>(startPos_ + usedOffset_), LOCALIZATION_SIZE - usedOffset_, '\0',
505 LOCALIZATION_SIZE - usedOffset_) != EOK) {
506 HILOG_ERROR(HILOG_MODULE_ACE, "init cache content failed");
507 return false;
508 }
509 // set the keyIndex 0
510 for (int i = 0; i < MAX_KEY_NUM; i++) {
511 uint32_t *index = reinterpret_cast<uint32_t *>(startPos_ + i * sizeof(uint32_t));
512 *index = 0;
513 }
514 if (languageFile_ == nullptr) {
515 HILOG_ERROR(HILOG_MODULE_ACE, "waring: no correct language file name presented, will cach en-US as default");
516 // cache the default file en-US.json
517 languageFile_ = StringUtil::Copy("en-US.json");
518 }
519 uint32_t fileContentLength = 0;
520 char *content = ReadJSFile(filePath_, languageFile_, fileContentLength);
521 if (content == nullptr || fileContentLength == 0) {
522 HILOG_ERROR(HILOG_MODULE_ACE, "cache failing, read language file failed");
523 return false;
524 }
525 cJSON *json = cJSON_Parse(content);
526 ace_free(content);
527 content = nullptr;
528 if (json == nullptr) {
529 HILOG_ERROR(HILOG_MODULE_ACE, "cache failing, cJSON_Parse failed");
530 return false;
531 }
532 isCached_ = CacheValue(nullptr, *json);
533 cJSON_Delete(json);
534 json = nullptr;
535 return isCached_;
536 }
537
GetMergeKey(const char * key,const char * addKey)538 char *CJSONParser::GetMergeKey(const char *key, const char *addKey)
539 {
540 if (addKey == nullptr) {
541 return const_cast<char *>(key);
542 }
543 uint16_t addKeyLen = strlen(addKey);
544 uint32_t preLen = (key == nullptr) ? 0 : strlen(key);
545 const uint8_t addedLen = 2;
546 uint16_t mergeLen = preLen + addKeyLen + addedLen;
547 char *mergeKey = reinterpret_cast<char *>(ace_malloc(mergeLen));
548 if (mergeKey == nullptr) {
549 HILOG_ERROR(HILOG_MODULE_ACE, "merge key failed");
550 return nullptr;
551 }
552 if (key != nullptr) {
553 if ((strcpy_s(mergeKey, mergeLen, key) != EOK) || (strcat_s(mergeKey, mergeLen, ".") != EOK) ||
554 (strcat_s(mergeKey, mergeLen, addKey) != EOK)) {
555 HILOG_ERROR(HILOG_MODULE_ACE, "copy preKey failed");
556 ace_free(mergeKey);
557 return nullptr;
558 }
559 } else {
560 if (strcpy_s(mergeKey, mergeLen, addKey)) {
561 HILOG_ERROR(HILOG_MODULE_ACE, "copy json key failed\n");
562 ace_free(mergeKey);
563 return nullptr;
564 }
565 }
566 return mergeKey;
567 }
568
PutNumOrStrValue(const char * key,cJSON item)569 bool CJSONParser::PutNumOrStrValue(const char *key, cJSON item)
570 {
571 if (key == nullptr) {
572 HILOG_ERROR(HILOG_MODULE_ACE, "the json key is nullptr");
573 return false;
574 }
575 uint32_t index = FNVHash(key);
576 uint32_t *valueIndex = reinterpret_cast<uint32_t *>(startPos_ + index * sizeof(uint32_t));
577 if (valueIndex == nullptr) {
578 return false;
579 }
580 if (*valueIndex != 0) {
581 // the hash value is conflict
582 Node *currentNode = reinterpret_cast<Node *>(startPos_ + (*valueIndex));
583 while ((currentNode != nullptr) && (currentNode->nextIndex != 0)) {
584 currentNode = reinterpret_cast<Node *>(startPos_ + currentNode->nextIndex);
585 }
586 if (currentNode != nullptr) {
587 currentNode->nextIndex = usedOffset_;
588 }
589 } else {
590 *valueIndex = usedOffset_;
591 }
592 Node *node = reinterpret_cast<Node *>(startPos_ + usedOffset_);
593 usedOffset_ = GetUseLen(usedOffset_ + sizeof(Node));
594 if (usedOffset_ == 0) {
595 return false;
596 }
597 node->pathIndex = usedOffset_;
598 if (!CacheStrValue(key)) {
599 return false;
600 }
601 if (item.type == cJSON_Number) {
602 node->isNumber = true;
603 node->valueIndex = item.valuedouble;
604 return true;
605 }
606 node->valueIndex = usedOffset_;
607 return CacheStrValue(item.valuestring);
608 }
609
CacheStrValue(const char * value)610 bool CJSONParser::CacheStrValue(const char *value)
611 {
612 if (strcpy_s(reinterpret_cast<char *>(startPos_ + usedOffset_), LOCALIZATION_SIZE - usedOffset_, value)) {
613 HILOG_ERROR(HILOG_MODULE_ACE, "copy value failed");
614 return false;
615 }
616 usedOffset_ = GetUseLen(usedOffset_ + strlen(value) + 1);
617 if (usedOffset_ == 0) {
618 return false;
619 }
620 return true;
621 }
622
CacheValue(const char * key,cJSON item)623 bool CJSONParser::CacheValue(const char *key, cJSON item)
624 {
625 char *mergeKey = GetMergeKey(const_cast<char *>(key), item.string);
626 bool result = true;
627 if ((item.type == cJSON_Number) || (item.type == cJSON_String)) {
628 result = PutNumOrStrValue(mergeKey, item);
629 } else if (item.type == cJSON_Object) {
630 if ((item.child == nullptr) || (!CacheValue(mergeKey, *item.child))) {
631 result = false;
632 }
633 } else {
634 // if the object is array, skip it. find the array value through read json file
635 }
636 ACE_FREE(mergeKey);
637 if (!result) {
638 return false;
639 }
640 return (item.next == nullptr) || (CacheValue(key, *item.next));
641 }
642
GetValueFromFile(const char * key,jerry_value_t args,jerry_size_t argsNum,const char * languageFile,bool & nullValueFlag)643 jerry_value_t CJSONParser::GetValueFromFile(const char *key,
644 jerry_value_t args,
645 jerry_size_t argsNum,
646 const char *languageFile,
647 bool &nullValueFlag)
648 {
649 if (languageFile == nullptr || strlen(languageFile) == 0) {
650 HILOG_ERROR(HILOG_MODULE_ACE, "invalid language file name");
651 return UNDEFINED;
652 }
653 ListNode *keys = nullptr;
654 uint8_t keyCount = Split(key, '.', *&keys);
655 char *content = ReadJSFile(filePath_, languageFile);
656 if (content == nullptr) {
657 return UNDEFINED;
658 }
659 cJSON *fileJson = cJSON_Parse(content);
660 ACE_FREE(content);
661 if (fileJson == nullptr) {
662 return UNDEFINED;
663 }
664 cJSON *curJsonItem = fileJson;
665 uint8_t curKeyIndex = 0;
666 do {
667 // get the current splited key
668 char *message = CJSONParser::GetNode(keys, keyCount - curKeyIndex);
669 curJsonItem = cJSON_GetObjectItemCaseSensitive(curJsonItem, message);
670 curKeyIndex++;
671 } while (!(curKeyIndex == keyCount || (curJsonItem == nullptr)));
672 ClearNode(keys);
673 jerry_value_t result = UNDEFINED;
674 do {
675 if (curJsonItem == nullptr) {
676 break;
677 }
678 if (cJSON_IsNumber(curJsonItem)) {
679 result = jerry_create_number(curJsonItem->valuedouble);
680 break;
681 }
682 char *value = FillPlaceholder(curJsonItem->valuestring, args, argsNum);
683 if (value == nullptr) {
684 HILOG_ERROR(HILOG_MODULE_ACE, "get nullptr value after place holder filling");
685 nullValueFlag = true;
686 break;
687 }
688 if (strlen(value) == 0) {
689 HILOG_ERROR(HILOG_MODULE_ACE, "get 0 length str after place holder filling");
690 }
691 result = jerry_create_string(reinterpret_cast<jerry_char_t *>(value));
692 ace_free(value);
693 value = nullptr;
694 } while (0);
695 cJSON_Delete(fileJson);
696 fileJson = nullptr;
697 return result;
698 }
699
GetValue(const char * key,const jerry_value_t args[],const jerry_size_t argsNum)700 jerry_value_t CJSONParser::GetValue(const char *key, const jerry_value_t args[], const jerry_size_t argsNum)
701 {
702 jerry_value_t arg = (argsNum > 1) ? args[1] : UNDEFINED;
703 // try finding from cache first
704 Node *node = GetValueFromCache(key);
705 if (node == nullptr) {
706 HILOG_ERROR(HILOG_MODULE_ACE, "warning: get value from cache failed, keyLen[%{public}d]", strlen(key));
707 // no node found from cache, searching from current language file then
708 bool nullValueFlag = false;
709 jerry_value_t resultFromFile = GetValueFromFile(key, arg, argsNum, languageFile_, nullValueFlag);
710 if (nullValueFlag) {
711 HILOG_INFO(HILOG_MODULE_ACE, "get undefined value for key[%{public}s]", key);
712 return resultFromFile;
713 }
714 if (!IS_UNDEFINED(resultFromFile) && !IS_ERROR_VALUE(resultFromFile)) {
715 // found
716 return resultFromFile;
717 }
718 jerry_release_value(resultFromFile);
719 HILOG_ERROR(HILOG_MODULE_ACE, "get error from current language file, try en-US last");
720 // failed, get from default language file last
721 resultFromFile = GetValueFromFile(key, arg, argsNum, "en-US.json", nullValueFlag);
722 if (nullValueFlag) {
723 HILOG_INFO(HILOG_MODULE_ACE, "get undefined value for key[%{public}s]", key);
724 return resultFromFile;
725 }
726 if (!IS_UNDEFINED(resultFromFile) && !IS_ERROR_VALUE(resultFromFile)) {
727 return resultFromFile;
728 }
729 jerry_release_value(resultFromFile);
730 HILOG_ERROR(HILOG_MODULE_ACE, "get error from default file, return the key, keyLen[%{public}d]", strlen(key));
731 return jerry_create_string((const jerry_char_t *)(key));
732 }
733
734 // cache node found, number case
735 if (node->isNumber) {
736 return jerry_create_number(node->valueIndex);
737 }
738 // NOT number case
739 const char *result = reinterpret_cast<char *>(startPos_ + (uint32_t)(node->valueIndex));
740 char *valueStr = FillPlaceholder(result, arg, argsNum);
741 if (valueStr == nullptr) {
742 HILOG_ERROR(HILOG_MODULE_ACE,
743 "get null value after place holder filling, valudeIndex[%{public}d], return the key",
744 (uint32_t)(node->valueIndex));
745 // empty value, return the key
746 return jerry_create_string((const jerry_char_t *)(key));
747 }
748 if (strlen(valueStr) == 0) {
749 HILOG_ERROR(HILOG_MODULE_ACE,
750 "warning: get empty value after place holder filling, valudeIndex[%{public}d], keyLen[%{public}d]",
751 (uint32_t)(node->valueIndex), strlen(key));
752 }
753 jerry_value_t valueJSValue = jerry_create_string(reinterpret_cast<jerry_char_t *>(valueStr));
754 ACE_FREE(valueStr);
755 return valueJSValue;
756 }
757
GetValueFromCache(const char * key)758 CJSONParser::Node *CJSONParser::GetValueFromCache(const char *key)
759 {
760 if (!isCached_) {
761 HILOG_ERROR(HILOG_MODULE_ACE, "warning: cache status is NO, keyLen[%{public}d]", strlen(key));
762 return nullptr;
763 }
764 uint16_t index = FNVHash(key);
765 uint32_t *valueIndex = reinterpret_cast<uint32_t *>(startPos_ + index * sizeof(uint32_t));
766 while ((valueIndex != nullptr) && (*valueIndex != 0)) {
767 Node *node = reinterpret_cast<Node *>(startPos_ + (*valueIndex));
768 if (node == nullptr) {
769 HILOG_ERROR(HILOG_MODULE_ACE,
770 "get value from cache failed, valueIndex[%{public}d], keyLen[%{public}d]",
771 (*valueIndex), strlen(key));
772 return nullptr;
773 }
774 char *nodeKey = reinterpret_cast<char *>(startPos_ + node->pathIndex);
775 if ((nodeKey != nullptr) && (!strcmp(key, nodeKey))) {
776 return node;
777 } else {
778 *valueIndex = node->nextIndex;
779 }
780 }
781 return nullptr;
782 }
783
Split(const char * target,char delemeter,ListNode * & node)784 uint8_t CJSONParser::Split(const char *target, char delemeter, ListNode *&node)
785 {
786 if (target == nullptr) {
787 return 0;
788 }
789 uint8_t nodeCount = 0;
790 char *current = nullptr;
791 int startPos = 0;
792 // get the position of delemeter
793 int pos = IndexOf(target, delemeter, startPos);
794 while (pos != -1) {
795 // add the value between startPos and index to node
796 current = SubStr(target, startPos, pos - startPos);
797 if (AddNode(node, current)) {
798 nodeCount++;
799 } else {
800 ACE_FREE(current);
801 }
802 startPos = pos + 1;
803 pos = IndexOf(target, delemeter, startPos);
804 }
805 if ((startPos != -1) && (static_cast<size_t>(startPos) < strlen(target))) {
806 current = SubStr(target, startPos, strlen(target) - startPos);
807 if (AddNode(node, current)) {
808 nodeCount++;
809 } else {
810 ACE_FREE(current);
811 }
812 }
813 // deal the key from lastIndex to strlen(target), the last find would return -1
814 return nodeCount;
815 }
816
IndexOf(const char * string,char delemeter,int index)817 int CJSONParser::IndexOf(const char *string, char delemeter, int index)
818 {
819 if (string == nullptr) {
820 return -1;
821 }
822 if ((index < 0) || (strlen(string) >= INT8_MAX) || (static_cast<size_t>(index) >= strlen(string))) {
823 return -1;
824 }
825 int length = strlen(string);
826 int i = index;
827 do {
828 if (string[i] == delemeter) {
829 return i;
830 }
831 i++;
832 } while (i < length);
833 // if the delemeter is not find return -1
834 return -1;
835 }
836
837 #ifdef LOCALIZATION_PLURAL
838 char *CJSONParser::GetParamValue(const char *attrName, jerry_value_t param, bool isPlural)
839 #else
840 char *CJSONParser::GetParamValue(const char *attrName, jerry_value_t param)
841 {
842 if (attrName == nullptr) {
843 return nullptr;
844 }
845 char *contentValue = nullptr; // store the value defined in param
846 uint16_t contentLen = 0;
847 #ifdef LOCALIZATION_PLURAL
848 if (jerry_value_is_number(param)) {
849 contentValue = MallocStringOf(param, &contentLen);
850 }
851 #else
852 jerry_value_t propName = jerry_create_string(reinterpret_cast<jerry_char_t const *>(attrName));
853 if (JerryHasProperty(param, propName)) { // get the placeholder {...} value defined in param
854 jerry_value_t paramValue = jerry_get_property(param, propName);
855 // the contentValue would be released in clearNode values
856 contentValue = MallocStringOf(paramValue, &contentLen);
857 jerry_release_value(paramValue);
858 }
859 jerry_release_value(propName);
860 #endif
861 // if the length of attrVal is 0, the node wouldn't add to the list
862 if ((contentValue != nullptr) && contentLen != 0) {
863 return contentValue;
864 }
865 ACE_FREE(contentValue); // if the contentValue is \0
866 return nullptr;
867 }
868 #endif
869 } // namespace ACELite
870 } // namespace OHOS
871 #endif
872