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 { "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 *moduleNode = cJSON_GetObjectItem(root_, "module");
87 if (!ParseModule(moduleNode)) {
88 return RESTOOL_ERROR;
89 }
90 return RESTOOL_SUCCESS;
91 }
92
GetPackageName() const93 const string &ConfigParser::GetPackageName() const
94 {
95 return packageName_;
96 }
97
GetModuleName() const98 const string &ConfigParser::GetModuleName() const
99 {
100 return moduleName_;
101 }
102
GetAbilityIconId() const103 int64_t ConfigParser::GetAbilityIconId() const
104 {
105 return abilityIconId_;
106 }
107
GetAbilityLabelId() const108 int64_t ConfigParser::GetAbilityLabelId() const
109 {
110 return abilityLabelId_;
111 }
112
GetModuleType() const113 ConfigParser::ModuleType ConfigParser::GetModuleType() const
114 {
115 return moduleType_;
116 }
117
ParseRefence()118 uint32_t ConfigParser::ParseRefence()
119 {
120 if (ParseRefImpl(root_, "", root_)) {
121 return RESTOOL_SUCCESS;
122 }
123 return RESTOOL_ERROR;
124 }
125
Save(const string & filePath) const126 uint32_t ConfigParser::Save(const string &filePath) const
127 {
128 if (ResourceUtil::SaveToJsonFile(filePath, root_)) {
129 return RESTOOL_SUCCESS;
130 }
131 return RESTOOL_ERROR;
132 }
133
SetAppIcon(string & icon,int64_t id)134 bool ConfigParser::SetAppIcon(string &icon, int64_t id)
135 {
136 cJSON *appNode = cJSON_GetObjectItem(root_, "app");
137 if (!appNode || !cJSON_IsObject(appNode)) {
138 cout << "Warning: 'app' not object" << endl;
139 return false;
140 }
141 cJSON_AddStringToObject(appNode, "icon", icon.c_str());
142 cJSON_AddNumberToObject(appNode, "iconId", id);
143 return true;
144 }
145
SetAppLabel(string & label,int64_t id)146 bool ConfigParser::SetAppLabel(string &label, int64_t id)
147 {
148 cJSON *appNode = cJSON_GetObjectItem(root_, "app");
149 if (!appNode || !cJSON_IsObject(appNode)) {
150 cout << "Warning: 'app' not object" << endl;
151 return false;
152 }
153 cJSON_AddStringToObject(appNode, "label", label.c_str());
154 cJSON_AddNumberToObject(appNode, "labelId", id);
155 return true;
156 }
157
158 // below private
ParseModule(cJSON * moduleNode)159 bool ConfigParser::ParseModule(cJSON *moduleNode)
160 {
161 if (!moduleNode || !cJSON_IsObject(moduleNode)) {
162 PrintError(GetError(ERR_CODE_JSON_NODE_MISMATCH).FormatCause("module", "object").SetPosition(filePath_));
163 return false;
164 }
165 if (cJSON_GetArraySize(moduleNode) == 0) {
166 PrintError(GetError(ERR_CODE_JSON_NODE_EMPTY).FormatCause("module").SetPosition(filePath_));
167 return false;
168 }
169
170 if (!useModule_) {
171 cJSON *packageNode = cJSON_GetObjectItem(moduleNode, "package");
172 if (packageNode && cJSON_IsString(packageNode)) {
173 packageName_ = packageNode->valuestring;
174 }
175 cJSON *distroNode = cJSON_GetObjectItem(moduleNode, "distro");
176 if (!ParseDistro(distroNode)) {
177 return false;
178 }
179 return ParseAbilitiesForDepend(moduleNode);
180 }
181 cJSON *nameNode = cJSON_GetObjectItem(moduleNode, "name");
182 if (nameNode && cJSON_IsString(nameNode)) {
183 moduleName_ = nameNode->valuestring;
184 }
185
186 if (moduleName_.empty()) {
187 PrintError(GetError(ERR_CODE_JSON_NODE_MISSING).FormatCause("module.name").SetPosition(filePath_));
188 return false;
189 }
190 cJSON *typeNode = cJSON_GetObjectItem(moduleNode, "type");
191 if (typeNode && cJSON_IsString(typeNode) && !ParseModuleType(typeNode->valuestring)) {
192 return false;
193 }
194 return true;
195 }
196
ParseAbilitiesForDepend(cJSON * moduleNode)197 bool ConfigParser::ParseAbilitiesForDepend(cJSON *moduleNode)
198 {
199 if (!IsDependEntry()) {
200 return true;
201 }
202 cJSON *mainAbilityNode = cJSON_GetObjectItem(moduleNode, "mainAbility");
203 if (mainAbilityNode && cJSON_IsString(mainAbilityNode)) {
204 mainAbility_ = mainAbilityNode->valuestring;
205 if (mainAbility_[0] == '.') {
206 mainAbility_ = packageName_ + mainAbility_;
207 }
208 return ParseAbilities(cJSON_GetObjectItem(moduleNode, "abilities"));
209 }
210 return true;
211 }
212
ParseDistro(cJSON * distroNode)213 bool ConfigParser::ParseDistro(cJSON *distroNode)
214 {
215 if (!distroNode || !cJSON_IsObject(distroNode)) {
216 PrintError(GetError(ERR_CODE_JSON_NODE_MISMATCH).FormatCause("distro", "object").SetPosition(filePath_));
217 return false;
218 }
219 if (cJSON_GetArraySize(distroNode) == 0) {
220 PrintError(GetError(ERR_CODE_JSON_NODE_EMPTY).FormatCause("distro").SetPosition(filePath_));
221 return false;
222 }
223
224 cJSON *moduleNameNode = cJSON_GetObjectItem(distroNode, "moduleName");
225 if (moduleNameNode && cJSON_IsString(moduleNameNode)) {
226 moduleName_ = moduleNameNode->valuestring;
227 }
228
229 if (moduleName_.empty()) {
230 PrintError(GetError(ERR_CODE_JSON_NODE_MISSING).FormatCause("distro.moduleName").SetPosition(filePath_));
231 return false;
232 }
233
234 cJSON *moduleTypeNode = cJSON_GetObjectItem(distroNode, "moduleType");
235 if (moduleTypeNode && cJSON_IsString(moduleTypeNode) && !ParseModuleType(moduleTypeNode->valuestring)) {
236 return false;
237 }
238 return true;
239 }
240
ParseAbilities(const cJSON * abilities)241 bool ConfigParser::ParseAbilities(const cJSON *abilities)
242 {
243 if (!abilities || !cJSON_IsArray(abilities)) {
244 PrintError(GetError(ERR_CODE_JSON_NODE_MISMATCH).FormatCause("abilites", "array").SetPosition(filePath_));
245 return false;
246 }
247 if (cJSON_GetArraySize(abilities) == 0) {
248 return true;
249 }
250 bool isMainAbility = false;
251 for (cJSON *ability = abilities->child; ability; ability = ability->next) {
252 if (!ParseAbilitiy(ability, isMainAbility)) {
253 return false;
254 }
255 if (isMainAbility) {
256 break;
257 }
258 }
259 return true;
260 }
261
ParseAbilitiy(const cJSON * ability,bool & isMainAbility)262 bool ConfigParser::ParseAbilitiy(const cJSON *ability, bool &isMainAbility)
263 {
264 if (!ability || !cJSON_IsObject(ability)) {
265 PrintError(GetError(ERR_CODE_JSON_NODE_MISMATCH).FormatCause("ability", "object").SetPosition(filePath_));
266 return false;
267 }
268 if (cJSON_GetArraySize(ability) == 0) {
269 return true;
270 }
271 cJSON *nameNode = cJSON_GetObjectItem(ability, "name");
272 if (!nameNode || !cJSON_IsString(nameNode)) {
273 PrintError(GetError(ERR_CODE_JSON_NODE_MISMATCH).FormatCause("ability.name", "object")
274 .SetPosition(filePath_));
275 return false;
276 }
277 string name = nameNode->valuestring;
278 if (name[0] == '.') {
279 name = packageName_ + name;
280 }
281 if (mainAbility_ != name && !IsMainAbility(cJSON_GetObjectItem(ability, "skills"))) {
282 return true;
283 }
284 cJSON *iconIdNode = cJSON_GetObjectItem(ability, "iconId");
285 if (iconIdNode && ResourceUtil::IsIntValue(iconIdNode)) {
286 abilityIconId_ = iconIdNode->valueint;
287 }
288 if (abilityIconId_ <= 0) {
289 PrintError(GetError(ERR_CODE_JSON_NODE_MISSING).FormatCause("ability.iconId").SetPosition(filePath_));
290 return false;
291 }
292 cJSON *labelIdNode = cJSON_GetObjectItem(ability, "labelId");
293 if (labelIdNode && ResourceUtil::IsIntValue(labelIdNode)) {
294 abilityLabelId_ = labelIdNode->valueint;
295 }
296 if (abilityLabelId_ <= 0) {
297 PrintError(GetError(ERR_CODE_JSON_NODE_MISSING).FormatCause("ability.labelId").SetPosition(filePath_));
298 return false;
299 }
300 isMainAbility = true;
301 return true;
302 }
303
IsMainAbility(const cJSON * skills)304 bool ConfigParser::IsMainAbility(const cJSON *skills)
305 {
306 if (!skills || !cJSON_IsArray(skills)) {
307 return false;
308 }
309 for (cJSON *skill = skills->child; skill; skill = skill->next) {
310 if (!cJSON_IsObject(skill)) {
311 return false;
312 }
313 if (IsHomeAction(cJSON_GetObjectItem(skill, "actions"))) {
314 return true;
315 }
316 }
317 return false;
318 }
319
IsHomeAction(const cJSON * actions)320 bool ConfigParser::IsHomeAction(const cJSON *actions)
321 {
322 if (!actions || !cJSON_IsArray(actions)) {
323 return false;
324 }
325 for (cJSON *action = actions->child; action; action = action->next) {
326 if (!cJSON_IsObject(action)) {
327 return false;
328 }
329 if (strcmp(action->valuestring, "action.system.home") == 0) {
330 return true;
331 }
332 }
333 return false;
334 }
335
ParseRefImpl(cJSON * parent,const string & key,cJSON * node)336 bool ConfigParser::ParseRefImpl(cJSON *parent, const string &key, cJSON *node)
337 {
338 if (cJSON_IsArray(node)) {
339 const auto &result = JSON_ARRAY_IDS.find(key);
340 if (result != JSON_ARRAY_IDS.end()) {
341 return ParseJsonArrayRef(parent, key, node);
342 }
343 cJSON *arrayItem = node->child;
344 while (arrayItem) {
345 if (!ParseRefImpl(node, "", arrayItem)) {
346 return false;
347 }
348 arrayItem = arrayItem->next;
349 }
350 } else if (cJSON_IsObject(node)) {
351 cJSON *child = node->child;
352 while (child) {
353 if (!ParseRefImpl(node, child->string, child)) {
354 return false;
355 }
356 child = child->next;
357 }
358 } else if (!key.empty() && cJSON_IsString(node)) {
359 return ParseJsonStringRef(parent, key, node);
360 }
361 return true;
362 }
363
ParseJsonArrayRef(cJSON * parent,const string & key,cJSON * node)364 bool ConfigParser::ParseJsonArrayRef(cJSON *parent, const string &key, cJSON *node)
365 {
366 if (!node || !cJSON_IsArray(node)) {
367 PrintError(GetError(ERR_CODE_JSON_NODE_MISMATCH).FormatCause(key.c_str(), "array")
368 .SetPosition(filePath_));
369 return false;
370 }
371 cJSON *array = cJSON_CreateArray();
372 for (cJSON *item = node->child; item; item = item->next) {
373 if (!cJSON_IsString(item)) {
374 PrintError(GetError(ERR_CODE_JSON_NODE_MISMATCH).FormatCause(string(key + " value").c_str(), "string")
375 .SetPosition(filePath_));
376 cJSON_Delete(array);
377 return false;
378 }
379 string value = item->valuestring;
380 bool update = false;
381 if (!GetRefIdFromString(value, update, JSON_ARRAY_IDS.at(key))) {
382 cJSON_Delete(array);
383 return false;
384 }
385 if (update) {
386 cJSON_AddItemToArray(array, cJSON_CreateNumber(atoll(value.c_str())));
387 }
388 }
389 cJSON_AddItemToObject(parent, (key + "Id").c_str(), array);
390 return true;
391 }
392
ParseJsonStringRef(cJSON * parent,const string & key,cJSON * node)393 bool ConfigParser::ParseJsonStringRef(cJSON *parent, const string &key, cJSON *node)
394 {
395 const auto &result = JSON_STRING_IDS.find(key);
396 if (result == JSON_STRING_IDS.end()) {
397 return true;
398 }
399 if (!node || !cJSON_IsString(node)) {
400 PrintError(GetError(ERR_CODE_JSON_NODE_MISMATCH).FormatCause(key.c_str(), "string").SetPosition(filePath_));
401 return false;
402 }
403 string value = node->valuestring;
404 bool update = false;
405 if (!GetRefIdFromString(value, update, JSON_STRING_IDS.at(key))) {
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 if (refParser.ParseRefInString(value, update, filePath_) != RESTOOL_SUCCESS) {
438 return false;
439 }
440 if (!update) {
441 return true;
442 }
443 smatch result;
444 if (regex_search(value, result, regex(match))) {
445 value = value.substr(result[0].str().length());
446 return true;
447 }
448 string ref = match.substr(match.find("\\") + 1);
449 PrintError(GetError(ERR_CODE_INVALID_RESOURCE_REF).FormatCause(value.c_str(), ref.c_str()).SetPosition(filePath_));
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 PrintError(GetError(ERR_CODE_INVALID_MODULE_TYPE).FormatCause(type.c_str()).SetPosition(filePath_));
458 return false;
459 }
460 moduleType_ = result->second;
461 return true;
462 }
463 }
464 }
465 }
466