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 #ifndef OHOS_ACELITE_CJSON_PARSER_H
16 #define OHOS_ACELITE_CJSON_PARSER_H
17 #include "acelite_config.h"
18 
19 #if (FEATURE_LOCALIZATION_MODULE == 1)
20 #include <cJSON.h>
21 #include <jerryscript.h>
22 #ifdef __LITEOS_A__
23 #include "dirent.h"
24 #include "unistd.h"
25 #endif
26 #include "ace_mem_base.h"
27 #include "js_app_context.h"
28 #include "non_copyable.h"
29 
30 namespace OHOS {
31 namespace ACELite {
32 class CJSONParser final : public MemoryHeap {
33 public:
34     ACE_DISALLOW_COPY_AND_MOVE(CJSONParser);
35     struct ListNode : public MemoryHeap {
36         char *value = nullptr;
37         ListNode *next = nullptr;
38     };
39 
40     // can't create the node object.it is used to store the json node is psram/ram
41     struct Node {
42         double valueIndex = 0;
43         uint32_t pathIndex = 0; // the path value index in psram
44         uint16_t nextIndex = 0; // the conflicy Node index in array
45         bool isNumber = false;
46     };
47 
48     enum LanguageState : uint8_t {
49         LANGUAGE_FAIL,
50         LANGUAGE_NOT_CHANGE,
51         LANGUAGE_CHANGED
52     };
53 
54     CJSONParser();
55 
~CJSONParser()56     ~CJSONParser()
57     {
58         void *value = reinterpret_cast<void *>(startPos_);
59         ACE_FREE(value);
60         ACE_FREE(countries_);
61         ACE_FREE(language_);
62         ACE_FREE(filePath_);
63         ACE_FREE(languageFile_);
64     }
65 
66     /**
67      * @brief: replace the placeholder in result with the data defined by user
68      * if plural is true, it will replace the number in placeholder,
69      * replace the same name in js object.
70      */
71     char *FillPlaceholder(const char *format, jerry_value_t arg, jerry_length_t num, bool isPlural = false);
72 
73     /**
74      * @brief: init localization, get the resource file path
75      * and get the localization cache ram
76      */
77     bool Init();
78 
79     /**
80      * @brief: merge string destination and resource, save the merge result in destination
81      * if check is true, it will free destination string
82      */
83     char *SubStr(const char *src, size_t start, size_t length);
84 
85     /**
86      * @brief: split the string by delemeter and save the split result in node
87      *
88      * @return the length of node
89      */
90     uint8_t Split(const char *target, char delemeter, ListNode *&node);
91 
92     static bool AddNode(ListNode *&head, char *current);
93     static char *GetNode(ListNode *node, int index);
94     static void ClearNode(ListNode *&node);
95     static char *ToString(ListNode *node, uint8_t length);
96 
97     /**
98      * @brief get localization format result
99      * @param key: the json path
100      * @param args: the args defined the value of placeholder
101      * @return the JS value of localization result
102      */
103     jerry_value_t GetValue(const char *key, const jerry_value_t args[], jerry_size_t argsNum);
104 
105     /**
106      * @brief judge the system language and origion is changed
107      * @return 1: the system language is changed
108      *         0: the system language
109      *         -1: get system language failed
110      */
111     LanguageState ChangeLanguage();
112 
113     /**
114      * @brief cache the frist file in fileList to PSRAM/RAM
115      * @return the cache result, true: cache file success
116      * fail: the fileList is null or the file is too large
117      */
118     bool CacheFile();
119 
120 private:
121     enum conValue {
122         PRIME_OFFSET_1 = 3,
123         PRIME_OFFSET_2 = 5,
124         PRIME_OFFSET_3 = 7,
125         PRIME_OFFSET_4 = 13,
126         PRIME_OFFSET_5 = 17,
127         MAX_KEY_NUM = 500,
128         MAX_VALUE_LEN = 1024,
129         LOCALIZATION_SIZE = 10240,
130         NFV_PRIME = 16777619
131     };
132 
133     /**
134      * @Brief: get the position of delemeter after index
135      * @return if the index is upper than the length of string, return -1
136      * else if the index is not defined in string, return the length, else return the position of it
137      */
138     int IndexOf(const char *string, char delemeter, int index);
139 
140     /**
141      * @Brief: split the string defined in value by '|', and get value in the split string
142      * For example: the string is car|cars, if the value of param is odd, assign value car,else cars
143      */
144 #ifdef LOCALIZATION_PLURAL
145     char *GetPluralValue(char *value, jerry_value_t param);
146     uint8_t FormatString(const char *format, jerry_value_t arg, ListNode *&node, bool isPlural, jerry_value_t num);
147     /**
148      * @brief: get the value defined in param
149      * @param: attrName:the attribute name in param, for example "name"
150      *         param: the object defined attrName, for example {"name":"Jane"}
151      * @return: the value in param
152      */
153     char *GetParamValue(const char *attrName, jerry_value_t param, bool isPlural);
154 #else
155     uint8_t FormatString(const char *format, jerry_value_t arg, ListNode *&node, jerry_value_t num);
156     char *GetParamValue(const char *attrName, jerry_value_t param);
157 #endif
158 
159     char* GetMergeKey(const char *key, const char *addKey);
160 
161     bool CacheValue(const char *key, cJSON item);
162 
163     bool PutNumOrStrValue(const char *key, cJSON item);
164 
165     bool CacheStrValue(const char *value);
166 
167     /**
168      * @brief get value from file in fileList
169      * @param key JSON path
170      * @param args the value to replace the placeholder
171      * @param argsNum the num of args
172      * @param languageFile the target json file name
173      * @return the js value of target value
174      */
175     jerry_value_t GetValueFromFile(const char *key,
176                                    jerry_value_t args,
177                                    jerry_size_t argsNum,
178                                    const char *languageFile,
179                                    bool &nullValueFlag);
180 
181     /**
182      * @brief get 4-byte aligned offset
183      * @param addr the used offset
184      * @return the nearest 4-byte aligned offset
185      */
GetUseLen(uint32_t usedOffset)186     uint32_t GetUseLen(uint32_t usedOffset)
187     {
188         const uint8_t align = 2;
189         uint32_t len = usedOffset + (1 << align);
190         len = (len >> align) << align;
191         if (len > LOCALIZATION_SIZE) {
192             isCached_ = false; // cache json file failed
193             return 0;
194         }
195         return len;
196     }
197 
198     /**
199      * @brief get the string hash value.the hash algorithm is NFV-1a hash
200      * the Algorithm URL is https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function#FNV-1_hash
201      * @param key the string need to hash
202      * @return the hash result which is the index array number
203      */
FNVHash(const char * key)204     uint16_t FNVHash(const char *key)
205     {
206         uint64_t hash = 2166136261;
207         uint32_t len = strlen(key);
208         for (uint32_t i = 0; i < len; i++) {
209             uint8_t keyVal = key[i];
210             hash = (hash ^ keyVal) * NFV_PRIME;
211         }
212         hash += hash << PRIME_OFFSET_4;
213         hash ^= hash >> PRIME_OFFSET_3;
214         hash += hash << PRIME_OFFSET_1;
215         hash ^= hash >> PRIME_OFFSET_5;
216         hash += hash << PRIME_OFFSET_2;
217         return hash % MAX_KEY_NUM;
218     }
219 
220     Node *GetValueFromCache(const char *key);
221     bool ChangeLanguageFileName();
222 
223 #ifdef TARGET_SIMULATOR
224 #if (defined(_WIN32) || (defined(_WIN64)))
225     int GetWinFiles(ListNode *&fileList);
226 #else
227     int GetFiles(ListNode *&fileList);
228 #endif
229     bool CheckLanguageFileName(char *languageFile);
230 #endif
231     bool IsFileExistFullMatch(const char *fileName);
232 
233     bool isCached_;
234     bool isAllocated_;
235     char leftDelemeter_;
236     char rightDelemeter_;
237     uint32_t usedOffset_;
238     uintptr_t startPos_;
239     char *countries_; // the current country and origion
240     char *language_;  // the current system language
241     char *filePath_;
242     char *languageFile_;
243 };
244 } // namespace ACELite
245 } // namespace OHOS
246 #endif // FEATURE_LOCALIZATION_MODULE
247 #endif // OHOS_ACELITE_CJSON_PARSER_H
248