• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2024 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 "config_parser.h"
17 #include <iostream>
18 #include <regex>
19 #include "reference_parser.h"
20 #include "restool_errors.h"
21 
22 namespace OHOS {
23 namespace Global {
24 namespace Restool {
25 using namespace std;
26 const map<string, ConfigParser::ModuleType> ConfigParser::MODULE_TYPES = {
27     { "har", ModuleType::HAR },
28     { "entry", ModuleType::ENTRY },
29     { "feature", ModuleType::FEATURE },
30     { "shared", ModuleType::SHARED }
31 };
32 
33 const map<string, string> ConfigParser::JSON_STRING_IDS = {
34     { "icon", "^\\$media:" },
35     { "label", "^\\$string:" },
36     { "description", "^\\$string:" },
37     { "theme", "^\\$theme:" },
38     { "reason", "^\\$string:" },
39     { "startWindowIcon", "^\\$media:" },
40     { "startWindowBackground", "^\\$color:"},
41     { "resource", "^\\$[a-z]+:" },
42     { "extra", "^\\$[a-z]+:" },
43     { "fileContextMenu", "^\\$profile:" }
44 };
45 
46 const map<string, string> ConfigParser::JSON_ARRAY_IDS = {
47     { "landscapeLayouts", "^\\$layout:" },
48     { "portraitLayouts", "^\\$layout:" }
49 };
50 
51 bool ConfigParser::useModule_ = false;
52 
ConfigParser()53 ConfigParser::ConfigParser()
54     : filePath_(""), packageName_(""), moduleName_(""), moduleType_(ModuleType::NONE),
55     abilityIconId_(0), abilityLabelId_(0), root_(nullptr)
56 {
57 }
58 
ConfigParser(const string & filePath)59 ConfigParser::ConfigParser(const string &filePath)
60     : filePath_(filePath), packageName_(""), moduleName_(""), moduleType_(ModuleType::NONE),
61     abilityIconId_(0), abilityLabelId_(0), root_(nullptr)
62 {
63 }
64 
~ConfigParser()65 ConfigParser::~ConfigParser()
66 {
67     if (root_) {
68         cJSON_Delete(root_);
69     }
70 }
71 
Init()72 uint32_t ConfigParser::Init()
73 {
74     if (!ResourceUtil::OpenJsonFile(filePath_, &root_)) {
75         return RESTOOL_ERROR;
76     }
77 
78     if (!root_ || !cJSON_IsObject(root_)) {
79         cerr << "Error: JSON file parsing failed, please check the JSON file." << NEW_LINE_PATH << filePath_ << endl;
80         return RESTOOL_ERROR;
81     }
82 
83     cJSON *moduleNode = cJSON_GetObjectItem(root_, "module");
84     if (!ParseModule(moduleNode)) {
85         return RESTOOL_ERROR;
86     }
87     return RESTOOL_SUCCESS;
88 }
89 
GetPackageName() const90 const string &ConfigParser::GetPackageName() const
91 {
92     return packageName_;
93 }
94 
GetModuleName() const95 const string &ConfigParser::GetModuleName() const
96 {
97     return moduleName_;
98 }
99 
GetAbilityIconId() const100 int64_t ConfigParser::GetAbilityIconId() const
101 {
102     return abilityIconId_;
103 }
104 
GetAbilityLabelId() const105 int64_t ConfigParser::GetAbilityLabelId() const
106 {
107     return abilityLabelId_;
108 }
109 
GetModuleType() const110 ConfigParser::ModuleType ConfigParser::GetModuleType() const
111 {
112     return moduleType_;
113 }
114 
ParseRefence()115 uint32_t ConfigParser::ParseRefence()
116 {
117     if (ParseRefImpl(root_, "", root_)) {
118         return RESTOOL_SUCCESS;
119     }
120     return RESTOOL_ERROR;
121 }
122 
Save(const string & filePath) const123 uint32_t ConfigParser::Save(const string &filePath) const
124 {
125     if (ResourceUtil::SaveToJsonFile(filePath, root_)) {
126         return RESTOOL_SUCCESS;
127     }
128     return RESTOOL_ERROR;
129 }
130 
SetAppIcon(string & icon,int64_t id)131 bool ConfigParser::SetAppIcon(string &icon, int64_t id)
132 {
133     cJSON *appNode = cJSON_GetObjectItem(root_, "app");
134     if (!appNode || !cJSON_IsObject(appNode)) {
135         cerr << "Error: 'app' not object" << endl;
136         return false;
137     }
138     cJSON_AddStringToObject(appNode, "icon", icon.c_str());
139     cJSON_AddNumberToObject(appNode, "iconId", id);
140     return true;
141 }
142 
SetAppLabel(string & label,int64_t id)143 bool ConfigParser::SetAppLabel(string &label, int64_t id)
144 {
145     cJSON *appNode = cJSON_GetObjectItem(root_, "app");
146     if (!appNode || !cJSON_IsObject(appNode)) {
147         cerr << "Error: 'app' not object" << endl;
148         return false;
149     }
150     cJSON_AddStringToObject(appNode, "label", label.c_str());
151     cJSON_AddNumberToObject(appNode, "labelId", id);
152     return true;
153 }
154 
155 // below private
ParseModule(cJSON * moduleNode)156 bool ConfigParser::ParseModule(cJSON *moduleNode)
157 {
158     if (!moduleNode || !cJSON_IsObject(moduleNode)) {
159         cerr << "Error: 'module' not object." << NEW_LINE_PATH << filePath_ << endl;
160         return false;
161     }
162     if (cJSON_GetArraySize(moduleNode) == 0) {
163         cerr << "Error: 'module' empty." << NEW_LINE_PATH << filePath_ << endl;
164         return false;
165     }
166 
167     if (!useModule_) {
168         cJSON *packageNode = cJSON_GetObjectItem(moduleNode, "package");
169         if (packageNode && cJSON_IsString(packageNode)) {
170             packageName_ = packageNode->valuestring;
171         }
172         cJSON *distroNode = cJSON_GetObjectItem(moduleNode, "distro");
173         if (!ParseDistro(distroNode)) {
174             return false;
175         }
176         return ParseAbilitiesForDepend(moduleNode);
177     }
178     cJSON *nameNode = cJSON_GetObjectItem(moduleNode, "name");
179     if (nameNode && cJSON_IsString(nameNode)) {
180         moduleName_ = nameNode->valuestring;
181     }
182 
183     if (moduleName_.empty()) {
184         cerr << "Error: 'name' don't found in 'module'." << NEW_LINE_PATH << filePath_ << endl;
185         return false;
186     }
187     cJSON *typeNode = cJSON_GetObjectItem(moduleNode, "type");
188     if (typeNode && cJSON_IsString(typeNode) && !ParseModuleType(typeNode->valuestring)) {
189         return false;
190     }
191     return true;
192 }
193 
ParseAbilitiesForDepend(cJSON * moduleNode)194 bool ConfigParser::ParseAbilitiesForDepend(cJSON *moduleNode)
195 {
196     if (!IsDependEntry()) {
197         return true;
198     }
199     cJSON *mainAbilityNode = cJSON_GetObjectItem(moduleNode, "mainAbility");
200     if (mainAbilityNode && cJSON_IsString(mainAbilityNode)) {
201         mainAbility_ = mainAbilityNode->valuestring;
202         if (mainAbility_[0] == '.') {
203             mainAbility_ = packageName_ + mainAbility_;
204         }
205         return ParseAbilities(cJSON_GetObjectItem(moduleNode, "abilities"));
206     }
207     return true;
208 }
209 
ParseDistro(cJSON * distroNode)210 bool ConfigParser::ParseDistro(cJSON *distroNode)
211 {
212     if (!distroNode || !cJSON_IsObject(distroNode)) {
213         cerr << "Error: 'distro' not object." << NEW_LINE_PATH << filePath_ << endl;
214         return false;
215     }
216     if (cJSON_GetArraySize(distroNode) == 0) {
217         cerr << "Error: 'distro' empty." << NEW_LINE_PATH << filePath_ << endl;
218         return false;
219     }
220 
221     cJSON *moduleNameNode = cJSON_GetObjectItem(distroNode, "moduleName");
222     if (moduleNameNode && cJSON_IsString(moduleNameNode)) {
223         moduleName_ = moduleNameNode->valuestring;
224     }
225 
226     if (moduleName_.empty()) {
227         cerr << "Error: 'moduleName' don't found in 'distro'." << NEW_LINE_PATH << filePath_ << endl;
228         return false;
229     }
230 
231     cJSON *moduleTypeNode = cJSON_GetObjectItem(distroNode, "moduleType");
232     if (moduleTypeNode && cJSON_IsString(moduleTypeNode) && !ParseModuleType(moduleTypeNode->valuestring)) {
233         return false;
234     }
235     return true;
236 }
237 
ParseAbilities(const cJSON * abilities)238 bool ConfigParser::ParseAbilities(const cJSON *abilities)
239 {
240     if (!abilities || !cJSON_IsArray(abilities)) {
241         cerr << "Error: abilites not array." << NEW_LINE_PATH << filePath_ << endl;
242         return false;
243     }
244     if (cJSON_GetArraySize(abilities) == 0) {
245         return true;
246     }
247     bool isMainAbility = false;
248     for (cJSON *ability = abilities->child; ability; ability = ability->next) {
249         if (!ParseAbilitiy(ability, isMainAbility)) {
250             cerr << "Error: ParseAbilitiy fail." << endl;
251             return false;
252         }
253         if (isMainAbility) {
254             break;
255         }
256     }
257     return true;
258 }
259 
ParseAbilitiy(const cJSON * ability,bool & isMainAbility)260 bool ConfigParser::ParseAbilitiy(const cJSON *ability, bool &isMainAbility)
261 {
262     if (!ability || !cJSON_IsObject(ability)) {
263         cerr << "Error: ability not object." << NEW_LINE_PATH << filePath_ << endl;
264         return false;
265     }
266     if (cJSON_GetArraySize(ability) == 0) {
267         return true;
268     }
269     cJSON *nameNode = cJSON_GetObjectItem(ability, "name");
270     if (!nameNode || !cJSON_IsString(nameNode)) {
271         return false;
272     }
273     string name = nameNode->valuestring;
274     if (name[0] == '.') {
275         name = packageName_ + name;
276     }
277     if (mainAbility_ != name && !IsMainAbility(cJSON_GetObjectItem(ability, "skills"))) {
278         return true;
279     }
280     cJSON *iconIdNode = cJSON_GetObjectItem(ability, "iconId");
281     if (iconIdNode && ResourceUtil::IsIntValue(iconIdNode)) {
282         abilityIconId_ = iconIdNode->valueint;
283     }
284     if (abilityIconId_ <= 0) {
285         cerr << "Error: iconId don't found in 'ability'." << NEW_LINE_PATH << filePath_ << endl;
286         return false;
287     }
288     cJSON *labelIdNode = cJSON_GetObjectItem(ability, "labelId");
289     if (labelIdNode && ResourceUtil::IsIntValue(labelIdNode)) {
290         abilityLabelId_ = labelIdNode->valueint;
291     }
292     if (abilityLabelId_ <= 0) {
293         cerr << "Error: labelId don't found in 'ability'." << NEW_LINE_PATH << filePath_ << endl;
294         return false;
295     }
296     isMainAbility = true;
297     return true;
298 }
299 
IsMainAbility(const cJSON * skills)300 bool ConfigParser::IsMainAbility(const cJSON *skills)
301 {
302     if (!skills || !cJSON_IsArray(skills)) {
303         return false;
304     }
305     for (cJSON *skill = skills->child; skill; skill = skill->next) {
306         if (!cJSON_IsObject(skill)) {
307             return false;
308         }
309         if (IsHomeAction(cJSON_GetObjectItem(skill, "actions"))) {
310             return true;
311         }
312     }
313     return false;
314 }
315 
IsHomeAction(const cJSON * actions)316 bool ConfigParser::IsHomeAction(const cJSON *actions)
317 {
318     if (!actions || !cJSON_IsArray(actions)) {
319         return false;
320     }
321     for (cJSON *action = actions->child; action; action = action->next) {
322         if (!cJSON_IsObject(action)) {
323             return false;
324         }
325         if (strcmp(action->valuestring, "action.system.home") == 0) {
326             return true;
327         }
328     }
329     return false;
330 }
331 
ParseRefImpl(cJSON * parent,const string & key,cJSON * node)332 bool ConfigParser::ParseRefImpl(cJSON *parent, const string &key, cJSON *node)
333 {
334     if (cJSON_IsArray(node)) {
335         const auto &result = JSON_ARRAY_IDS.find(key);
336         if (result != JSON_ARRAY_IDS.end()) {
337             return ParseJsonArrayRef(parent, key, node);
338         }
339         cJSON *arrayItem = node->child;
340         while (arrayItem) {
341             if (!ParseRefImpl(node, "", arrayItem)) {
342                 return false;
343             }
344             arrayItem = arrayItem->next;
345         }
346     } else if (cJSON_IsObject(node)) {
347         cJSON *child = node->child;
348         while (child) {
349             if (!ParseRefImpl(node, child->string, child)) {
350                 return false;
351             }
352             child = child->next;
353         }
354     } else if (!key.empty() && cJSON_IsString(node)) {
355         return ParseJsonStringRef(parent, key, node);
356     }
357     return true;
358 }
359 
ParseJsonArrayRef(cJSON * parent,const string & key,cJSON * node)360 bool ConfigParser::ParseJsonArrayRef(cJSON *parent, const string &key, cJSON *node)
361 {
362     if (!node || !cJSON_IsArray(node)) {
363         cerr << "Error: '"<< key << "'node not array." << NEW_LINE_PATH << filePath_ << endl;
364         return false;
365     }
366     cJSON *array = cJSON_CreateArray();
367     for (cJSON *item = node->child; item; item = item->next) {
368         if (!cJSON_IsString(item)) {
369             cerr << "Error: '" << key << "' invalid value." << NEW_LINE_PATH << filePath_ << endl;
370             cJSON_Delete(array);
371             return false;
372         }
373         string value = item->valuestring;
374         bool update = false;
375         if (!GetRefIdFromString(value, update, JSON_ARRAY_IDS.at(key))) {
376             cerr << "Error: '" << key << "' value " << value << " invalid." << NEW_LINE_PATH << filePath_ << endl;
377             cJSON_Delete(array);
378             return false;
379         }
380         if (update) {
381             cJSON_AddItemToArray(array, cJSON_CreateNumber(atoll(value.c_str())));
382         }
383     }
384     cJSON_AddItemToObject(parent, (key + "Id").c_str(), array);
385     cJSON_Delete(array);
386     return true;
387 }
388 
ParseJsonStringRef(cJSON * parent,const string & key,cJSON * node)389 bool ConfigParser::ParseJsonStringRef(cJSON *parent, const string &key, cJSON *node)
390 {
391     const auto &result = JSON_STRING_IDS.find(key);
392     if (result == JSON_STRING_IDS.end()) {
393         return true;
394     }
395     if (!node || !cJSON_IsString(node)) {
396         cerr << "Error: '" << key << "' invalid value." << endl;
397         return false;
398     }
399     string value = node->valuestring;
400     bool update = false;
401     if (!GetRefIdFromString(value, update, JSON_STRING_IDS.at(key))) {
402         cerr << "Error: '" << key << "' value " << value << " invalid value." << NEW_LINE_PATH << filePath_ << endl;
403         cerr << SOLUTIONS << endl;
404         cerr << SOLUTIONS_ARROW << "Please check the module.json5/config.json file in the src/main directory of the "
405              << GetModuleName() << "' module." << endl;
406         return false;
407     }
408     if (update) {
409         cJSON_AddItemToObject(parent, (key + "Id").c_str(), cJSON_CreateNumber(atoll(value.c_str())));
410         AddCheckNode(key, static_cast<uint32_t>(atoll(value.c_str())));
411     }
412     return true;
413 }
414 
AddCheckNode(const string & key,uint32_t id)415 void ConfigParser::AddCheckNode(const string &key, uint32_t id)
416 {
417     if (g_keyNodeIndexs.find(key) != g_keyNodeIndexs.end()) {
418         auto result = jsonCheckIds_.find(key);
419         if (result == jsonCheckIds_.end()) {
420             set<uint32_t> set;
421             set.emplace(id);
422             jsonCheckIds_.emplace(key, set);
423         } else {
424             result->second.emplace(id);
425         }
426         auto layerIconIds = ReferenceParser::GetLayerIconIds();
427         if (layerIconIds.find(id) != layerIconIds.end()) {
428             auto ids = layerIconIds[id];
429             jsonCheckIds_[key].insert(ids.begin(), ids.end());
430         }
431     }
432 }
433 
GetRefIdFromString(string & value,bool & update,const string & match) const434 bool ConfigParser::GetRefIdFromString(string &value, bool &update, const string &match) const
435 {
436     ReferenceParser refParser;
437     string error = "Error: '" + value + "' must start with '" + match.substr(match.find("\\") + 1) + "'";
438     if (refParser.ParseRefInString(value, update) != RESTOOL_SUCCESS) {
439         return false;
440     }
441     if (!update) {
442         return true;
443     }
444     smatch result;
445     if (regex_search(value, result, regex(match))) {
446         value = value.substr(result[0].str().length());
447         return true;
448     }
449     cerr << error << endl;
450     return false;
451 }
452 
ParseModuleType(const string & type)453 bool ConfigParser::ParseModuleType(const string &type)
454 {
455     const auto &result = MODULE_TYPES.find(type);
456     if (result == MODULE_TYPES.end()) {
457         cerr << "Error: moduleType='" << type << "' invalid value." << NEW_LINE_PATH << filePath_ << endl;
458         return false;
459     }
460     moduleType_ = result->second;
461     return true;
462 }
463 }
464 }
465 }
466