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