1 /*
2 * Copyright (c) 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 "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 };
31
32 const map<string, string> ConfigParser::JSON_STRING_IDS = {
33 { "icon", "^\\$media:" },
34 { "label", "^\\$string:" },
35 { "description", "^\\$string:" },
36 { "theme", "^\\$theme:" },
37 { "reason", "^\\$string:" },
38 { "startWindowIcon", "^\\$media:" },
39 { "startWindowBackground", "^\\$color:"},
40 { "resource", "^\\$[a-z]+:" },
41 { "extra", "^\\$[a-z]+:" }
42 };
43
44 const map<string, string> ConfigParser::JSON_ARRAY_IDS = {
45 { "landscapeLayouts", "^\\$layout:" },
46 { "portraitLayouts", "^\\$layout:" }
47 };
48
49 bool ConfigParser::useModule_ = false;
50
ConfigParser()51 ConfigParser::ConfigParser()
52 : filePath_(""), packageName_(""), moduleName_(""), moduleType_(ModuleType::NONE)
53 {
54 }
55
ConfigParser(const string & filePath)56 ConfigParser::ConfigParser(const string &filePath)
57 : filePath_(filePath), packageName_(""), moduleName_(""), moduleType_(ModuleType::NONE)
58 {
59 }
60
~ConfigParser()61 ConfigParser::~ConfigParser()
62 {
63 }
64
Init()65 uint32_t ConfigParser::Init()
66 {
67 if (!ResourceUtil::OpenJsonFile(filePath_, rootNode_)) {
68 return RESTOOL_ERROR;
69 }
70
71 if (!rootNode_.isObject()) {
72 cerr << "Error: root node not obeject in " << filePath_ << endl;
73 return RESTOOL_ERROR;
74 }
75
76 if (!ParseModule(rootNode_["module"])) {
77 return RESTOOL_ERROR;
78 }
79 return RESTOOL_SUCCESS;
80 }
81
GetPackageName() const82 const string &ConfigParser::GetPackageName() const
83 {
84 return packageName_;
85 }
86
GetModuleName() const87 const string &ConfigParser::GetModuleName() const
88 {
89 return moduleName_;
90 }
91
GetAbilityIconId() const92 int32_t ConfigParser::GetAbilityIconId() const
93 {
94 return abilityIconId_;
95 }
96
GetAbilityLabelId() const97 int32_t ConfigParser::GetAbilityLabelId() const
98 {
99 return abilityLabelId_;
100 }
101
GetModuleType() const102 ConfigParser::ModuleType ConfigParser::GetModuleType() const
103 {
104 return moduleType_;
105 }
106
ParseRefence()107 uint32_t ConfigParser::ParseRefence()
108 {
109 if (ParseRefImpl(rootNode_, "", rootNode_)) {
110 return RESTOOL_SUCCESS;
111 }
112 return RESTOOL_ERROR;
113 }
114
Save(const string & filePath) const115 uint32_t ConfigParser::Save(const string &filePath) const
116 {
117 if (ResourceUtil::SaveToJsonFile(filePath, rootNode_)) {
118 return RESTOOL_SUCCESS;
119 }
120 return RESTOOL_ERROR;
121 }
122
SetAppIcon(string & icon,int32_t id)123 bool ConfigParser::SetAppIcon(string &icon, int32_t id)
124 {
125 if (!rootNode_["app"].isObject()) {
126 cerr << "Error: 'app' not object" << endl;
127 return false;
128 }
129 rootNode_["app"]["icon"] = icon;
130 rootNode_["app"]["iconId"] = id;
131 return true;
132 }
133
SetAppLabel(string & label,int32_t id)134 bool ConfigParser::SetAppLabel(string &label, int32_t id)
135 {
136 if (!rootNode_["app"].isObject()) {
137 cerr << "Error: 'app' not object" << endl;
138 return false;
139 }
140 rootNode_["app"]["label"] = label;
141 rootNode_["app"]["labelId"] = id;
142 return true;
143 }
144
145 // below private
ParseModule(Json::Value & moduleNode)146 bool ConfigParser::ParseModule(Json::Value &moduleNode)
147 {
148 if (!moduleNode.isObject()) {
149 cerr << "Error: 'module' not object in " << filePath_ << endl;
150 return false;
151 }
152 if (moduleNode.empty()) {
153 cerr << "Error: 'module' empty in " << filePath_ << endl;
154 return false;
155 }
156
157 if (!useModule_) {
158 if (moduleNode["package"].isString()) {
159 packageName_ = moduleNode["package"].asString();
160 }
161 if (!ParseDistro(moduleNode["distro"])) {
162 return false;
163 }
164 return ParseAbilitiesForDepend(moduleNode);
165 }
166
167 if (moduleNode["name"].isString()) {
168 moduleName_ = moduleNode["name"].asString();
169 }
170
171 if (moduleName_.empty()) {
172 cerr << "Error: 'name' don't found in 'module', " << filePath_ << endl;
173 return false;
174 }
175
176 if (moduleNode["type"].isString() && !ParseModuleType(moduleNode["type"].asString())) {
177 return false;
178 }
179 return true;
180 }
181
ParseAbilitiesForDepend(Json::Value & moduleNode)182 bool ConfigParser::ParseAbilitiesForDepend(Json::Value &moduleNode)
183 {
184 if (!IsDependEntry()) {
185 return true;
186 }
187 if (moduleNode["mainAbility"].isString()) {
188 mainAbility_ = moduleNode["mainAbility"].asString();
189 if (mainAbility_[0] == '.') {
190 mainAbility_ = packageName_ + mainAbility_;
191 }
192 return ParseAbilities(moduleNode["abilities"]);
193 }
194 return true;
195 }
196
ParseDistro(Json::Value & distroNode)197 bool ConfigParser::ParseDistro(Json::Value &distroNode)
198 {
199 if (!distroNode.isObject()) {
200 cerr << "Error: 'distro' not object in " << filePath_ << endl;
201 return false;
202 }
203 if (distroNode.empty()) {
204 cerr << "Error: 'distro' empty in " << filePath_ << endl;
205 return false;
206 }
207
208 if (distroNode["moduleName"].isString()) {
209 moduleName_ = distroNode["moduleName"].asString();
210 }
211
212 if (moduleName_.empty()) {
213 cerr << "Error: 'moduleName' don't found in 'distro', " << filePath_ << endl;
214 return false;
215 }
216
217 if (distroNode["moduleType"].isString() && !ParseModuleType(distroNode["moduleType"].asString())) {
218 return false;
219 }
220 return true;
221 }
222
ParseAbilities(const Json::Value & abilites)223 bool ConfigParser::ParseAbilities(const Json::Value &abilites)
224 {
225 if (abilites.empty()) {
226 return true;
227 }
228 if (!abilites.isArray()) {
229 cerr << "Error: abilites not array. at " << filePath_ << endl;
230 return false;
231 }
232 bool isMainAbility = false;
233 for (Json::ArrayIndex i = 0; i < abilites.size(); i++) {
234 if (!ParseAbilitiy(abilites[i], isMainAbility)) {
235 cerr << "Error: ParseAbilitiy fail." << endl;
236 return false;
237 }
238 if (isMainAbility) {
239 break;
240 }
241 }
242 return true;
243 }
244
ParseAbilitiy(const Json::Value & ability,bool & isMainAbility)245 bool ConfigParser::ParseAbilitiy(const Json::Value &ability, bool &isMainAbility)
246 {
247 if (ability.empty()) {
248 return true;
249 }
250 if (!ability["name"].isString()) {
251 return false;
252 }
253 string name = ability["name"].asString();
254 if (name[0] == '.') {
255 name = packageName_ + name;
256 }
257 if (mainAbility_ != name && !IsMainAbility(ability["skills"])) {
258 return true;
259 }
260 if (ability["iconId"].isInt()) {
261 abilityIconId_ = ability["iconId"].asInt();
262 }
263 if (abilityIconId_ <= 0) {
264 cerr << "Error: iconId don't found in 'ability'. at " << filePath_ << endl;
265 return false;
266 }
267 if (ability["labelId"].isInt()) {
268 abilityLabelId_ = ability["labelId"].asInt();
269 }
270 if (abilityLabelId_ <= 0) {
271 cerr << "Error: labelId don't found in 'ability'. at "<< filePath_ << endl;
272 return false;
273 }
274 isMainAbility = true;
275 return true;
276 }
277
IsMainAbility(const Json::Value & skills)278 bool ConfigParser::IsMainAbility(const Json::Value &skills)
279 {
280 if (!skills.isArray()) {
281 return false;
282 }
283 for (Json::ArrayIndex i = 0; i < skills.size(); i++) {
284 if (!skills[i].isObject()) {
285 return false;
286 }
287 if (IsHomeAction(skills[i]["actions"])) {
288 return true;
289 }
290 }
291 return false;
292 }
293
IsHomeAction(const Json::Value & actions)294 bool ConfigParser::IsHomeAction(const Json::Value &actions)
295 {
296 if (!actions.isArray()) {
297 return false;
298 }
299 for (Json::ArrayIndex i = 0; i < actions.size(); i++) {
300 if (!actions[i].isObject()) {
301 return false;
302 }
303 if (actions[i].asString() == "action.system.home") {
304 return true;
305 }
306 }
307 return false;
308 }
309
ParseRefImpl(Json::Value & parent,const std::string & key,Json::Value & node)310 bool ConfigParser::ParseRefImpl(Json::Value &parent, const std::string &key, Json::Value &node)
311 {
312 if (node.isArray()) {
313 const auto &result = JSON_ARRAY_IDS.find(key);
314 if (result != JSON_ARRAY_IDS.end()) {
315 return ParseJsonArrayRef(parent, key, node);
316 }
317 for (Json::ArrayIndex index = 0; index < node.size(); index++) {
318 if (!ParseRefImpl(node, "", node[index])) {
319 return false;
320 }
321 }
322 } else if (node.isObject()) {
323 const auto members = node.getMemberNames();
324 for (const auto &member : members) {
325 if (!ParseRefImpl(node, member, node[member])) {
326 return false;
327 }
328 }
329 } else if (!key.empty() && node.isString()) {
330 return ParseJsonStringRef(parent, key, node);
331 }
332 return true;
333 }
334
ParseJsonArrayRef(Json::Value & parent,const string & key,Json::Value & node)335 bool ConfigParser::ParseJsonArrayRef(Json::Value &parent, const string &key, Json::Value &node)
336 {
337 Json::ArrayIndex size = node.size();
338 Json::Value array(Json::arrayValue);
339 for (Json::ArrayIndex index = 0; index < size; index++) {
340 if (!node[index].isString()) {
341 cerr << "Error: '" << key << "' invalid value. " << filePath_ << endl;
342 return false;
343 }
344 string value = node[index].asString();
345 bool update = false;
346 if (!GetRefIdFromString(value, update, JSON_ARRAY_IDS.at(key))) {
347 cerr << "Error: '" << key << "' value " << node[index] << " invalid. " << filePath_ << endl;
348 return false;
349 }
350 if (update) {
351 array.append(atoi(value.c_str()));
352 }
353 }
354 parent[key + "Id"] = array;
355 return true;
356 }
357
ParseJsonStringRef(Json::Value & parent,const string & key,Json::Value & node)358 bool ConfigParser::ParseJsonStringRef(Json::Value &parent, const string &key, Json::Value &node)
359 {
360 const auto &result = JSON_STRING_IDS.find(key);
361 if (result == JSON_STRING_IDS.end()) {
362 return true;
363 }
364 string value = node.asString();
365 bool update = false;
366 if (!GetRefIdFromString(value, update, JSON_STRING_IDS.at(key))) {
367 cerr << "Error: '" << key << "' value " << node << " invalid value. " << filePath_ << endl;
368 return false;
369 }
370 if (update) {
371 parent[key + "Id"] = atoi(value.c_str());
372 }
373 return true;
374 }
375
GetRefIdFromString(string & value,bool & update,const string & match) const376 bool ConfigParser::GetRefIdFromString(string &value, bool &update, const string &match) const
377 {
378 ReferenceParser refParser;
379 string error = "Error: '" + value + "' must start with '" + match.substr(match.find("\\") + 1) + "'";
380 if (refParser.ParseRefInString(value, update) != RESTOOL_SUCCESS) {
381 return false;
382 }
383 if (!update) {
384 return true;
385 }
386 smatch result;
387 if (regex_search(value, result, regex(match))) {
388 value = value.substr(result[0].str().length());
389 return true;
390 }
391 cerr << error << endl;
392 return false;
393 }
394
ParseModuleType(const string & type)395 bool ConfigParser::ParseModuleType(const string &type)
396 {
397 const auto &result = MODULE_TYPES.find(type);
398 if (result == MODULE_TYPES.end()) {
399 cerr << "Error: moduleType='" << type << "' invalid value in " << filePath_ << endl;
400 return false;
401 }
402 moduleType_ = result->second;
403 return true;
404 }
405 }
406 }
407 }
408