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