1 /*
2 * Copyright (c) 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 "id_defined_parser.h"
17 #include "file_entry.h"
18 #include "resource_util.h"
19
20 namespace OHOS {
21 namespace Global {
22 namespace Restool {
23 using namespace std;
24 const int64_t IdDefinedParser::START_SYS_ID = 0x07800000;
IdDefinedParser(const PackageParser & packageParser,const ResourceIdCluster & type)25 IdDefinedParser::IdDefinedParser(const PackageParser &packageParser, const ResourceIdCluster &type)
26 : packageParser_(packageParser), type_(type), root_(nullptr)
27 {
28 }
29
~IdDefinedParser()30 IdDefinedParser::~IdDefinedParser()
31 {
32 if (root_) {
33 cJSON_Delete(root_);
34 }
35 }
36
Init()37 uint32_t IdDefinedParser::Init()
38 {
39 InitParser();
40 string idDefinedInput = packageParser_.GetIdDefinedInputPath();
41 int64_t startId = static_cast<int64_t>(packageParser_.GetStartId());
42 bool combine = packageParser_.GetCombine();
43 bool isSys = type_ == ResourceIdCluster::RES_ID_SYS;
44 for (const auto &inputPath : packageParser_.GetInputs()) {
45 string idDefinedPath;
46 if (combine) {
47 idDefinedPath = FileEntry::FilePath(inputPath).Append(ID_DEFINED_FILE).GetPath();
48 } else {
49 idDefinedPath = ResourceUtil::GetBaseElementPath(inputPath).Append(ID_DEFINED_FILE).GetPath();
50 }
51 if (ResourceUtil::FileExist(idDefinedPath) && startId > 0) {
52 cerr << "Error: the set start_id and id_defined.json cannot be used together." << endl;
53 return RESTOOL_ERROR;
54 }
55 if (Init(idDefinedPath, isSys) != RESTOOL_SUCCESS) {
56 return RESTOOL_ERROR;
57 }
58 }
59 //SystemResource.hap only defined by base/element/id_defined.json
60 if (isSys) {
61 return RESTOOL_SUCCESS;
62 }
63 if (!idDefinedInput.empty() && ResourceUtil::FileExist(idDefinedInput)) {
64 appDefinedIds_.clear();
65 idDefineds_.clear();
66 string idDefinedPath = FileEntry::FilePath(idDefinedInput).GetPath();
67 if (Init(idDefinedPath, false) != RESTOOL_SUCCESS) {
68 return RESTOOL_ERROR;
69 }
70 }
71 for (const auto &sysIdDefinedPath : packageParser_.GetSysIdDefinedPaths()) {
72 if (Init(sysIdDefinedPath, true) != RESTOOL_SUCCESS) {
73 return RESTOOL_ERROR;
74 }
75 }
76 string sysIdDefinedPath = FileEntry::FilePath(packageParser_.GetRestoolPath())
77 .GetParent().Append(ID_DEFINED_FILE).GetPath();
78 if (Init(sysIdDefinedPath, true) != RESTOOL_SUCCESS) {
79 return RESTOOL_ERROR;
80 }
81 return RESTOOL_SUCCESS;
82 }
83
Init(const string & filePath,bool isSystem)84 uint32_t IdDefinedParser::Init(const string &filePath, bool isSystem)
85 {
86 if (!ResourceUtil::FileExist(filePath)) {
87 return RESTOOL_SUCCESS;
88 }
89
90 if (!ResourceUtil::OpenJsonFile(filePath, &root_)) {
91 return RESTOOL_ERROR;
92 }
93
94 if (!root_ || !cJSON_IsObject(root_)) {
95 cerr << "Error: JSON file parsing failed, please check the JSON file.";
96 cerr << NEW_LINE_PATH << filePath << endl;
97 return RESTOOL_ERROR;
98 }
99
100 cJSON *recordNode = cJSON_GetObjectItem(root_, "record");
101 if (!recordNode || !cJSON_IsArray(recordNode)) {
102 cerr << "Error: 'record' node is not an array, please check the JSON file.";
103 cerr << NEW_LINE_PATH << filePath << endl;
104 return RESTOOL_ERROR;
105 }
106 if (cJSON_GetArraySize(recordNode) == 0) {
107 cerr << "Warning: 'record' node is empty, please check the JSON file.";
108 cerr << NEW_LINE_PATH << filePath << endl;
109 return RESTOOL_SUCCESS;
110 }
111 int64_t startSysId = 0;
112 if (isSystem) {
113 startSysId = GetStartId();
114 if (startSysId < 0) {
115 return RESTOOL_ERROR;
116 }
117 }
118
119 if (IdDefinedToResourceIds(filePath, recordNode, isSystem, startSysId) != RESTOOL_SUCCESS) {
120 return RESTOOL_ERROR;
121 }
122 return RESTOOL_SUCCESS;
123 }
124
InitParser()125 void IdDefinedParser::InitParser()
126 {
127 using namespace placeholders;
128 handles_.emplace("type", bind(&IdDefinedParser::ParseType, this, _1, _2));
129 handles_.emplace("name", bind(&IdDefinedParser::ParseName, this, _1, _2));
130 handles_.emplace("id", bind(&IdDefinedParser::ParseId, this, _1, _2));
131 handles_.emplace("order", bind(&IdDefinedParser::ParseOrder, this, _1, _2));
132 }
133
IdDefinedToResourceIds(const std::string & filePath,const cJSON * record,bool isSystem,const int64_t startSysId)134 uint32_t IdDefinedParser::IdDefinedToResourceIds(const std::string &filePath, const cJSON *record,
135 bool isSystem, const int64_t startSysId)
136 {
137 int64_t index = -1;
138 for (cJSON *item = record->child; item; item = item->next) {
139 index++;
140 if (!cJSON_IsObject(item)) {
141 return RESTOOL_ERROR;
142 }
143 ResourceId resourceId;
144 resourceId.seq = index;
145 resourceId.id = startSysId;
146 for (const auto &handle : handles_) {
147 if ((handle.first == "id" && isSystem) || (handle.first == "order" && !isSystem)) {
148 continue;
149 }
150 if (!handle.second(cJSON_GetObjectItem(item, handle.first.c_str()), resourceId)) {
151 return RESTOOL_ERROR;
152 }
153 }
154 if (!PushResourceId(filePath, resourceId, isSystem)) {
155 return RESTOOL_ERROR;
156 }
157 }
158 return RESTOOL_SUCCESS;
159 }
160
PushResourceId(const std::string & filePath,const ResourceId & resourceId,bool isSystem)161 bool IdDefinedParser::PushResourceId(const std::string &filePath, const ResourceId &resourceId, bool isSystem)
162 {
163 ResType resType = ResourceUtil::GetResTypeFromString(resourceId.type);
164 auto ret = idDefineds_.emplace(resourceId.id, resourceId);
165 if (!ret.second) {
166 cerr << "Error: '" << ret.first->second.name << "' and '" << resourceId.name << "' defind the same ID." << endl;
167 return false;
168 }
169 auto checkRet = checkDefinedIds_.find(filePath);
170 if (checkRet != checkDefinedIds_.end()) {
171 bool found = any_of(checkRet->second.begin(), checkRet->second.end(),
172 [resType, resourceId](const auto &iterItem) {
173 return (resType == iterItem.first) && (resourceId.name == iterItem.second);
174 });
175 if (found) {
176 cerr << "Error: the same resource of '" << resourceId.name << "' exists in the " << filePath << endl;
177 return false;
178 }
179 checkRet->second.push_back(make_pair(resType, resourceId.name));
180 } else {
181 std::vector<std::pair<ResType, std::string>> vects;
182 vects.push_back(make_pair(resType, resourceId.name));
183 checkDefinedIds_.emplace(filePath, vects);
184 }
185 if (isSystem) {
186 sysDefinedIds_.emplace(make_pair(resType, resourceId.name), resourceId);
187 } else {
188 appDefinedIds_.emplace(make_pair(resType, resourceId.name), resourceId);
189 }
190 return true;
191 }
192
ParseId(const cJSON * origId,ResourceId & resourceId)193 bool IdDefinedParser::ParseId(const cJSON *origId, ResourceId &resourceId)
194 {
195 if (!origId) {
196 cerr << "Error: id_defined.json seq =" << resourceId.seq << " id empty." << endl;
197 return false;
198 }
199 if (!cJSON_IsString(origId)) {
200 cerr << "Error: id_defined.json seq =" << resourceId.seq << " id not string." << endl;
201 return false;
202 }
203 string idStr = origId->valuestring;
204 if (!ResourceUtil::CheckHexStr(idStr)) {
205 cerr << "Error: id_defined.json seq =" << resourceId.seq;
206 cerr << " id must be a hex string, eg:^0[xX][0-9a-fA-F]{8}" << endl;
207 return false;
208 }
209 int64_t id = strtoll(idStr.c_str(), nullptr, 16);
210 if (id < 0x01000000 || (id > 0x06FFFFFF && id < 0x08000000) || id > 0xFFFFFFFF) {
211 cerr << "Error: id_defined.json seq = "<< resourceId.seq;
212 cerr << " id must in [0x01000000,0x06FFFFFF],[0x08000000,0xFFFFFFFF]." << endl;
213 return false;
214 }
215 resourceId.id = id;
216 return true;
217 }
218
ParseType(const cJSON * type,ResourceId & resourceId)219 bool IdDefinedParser::ParseType(const cJSON *type, ResourceId &resourceId)
220 {
221 if (!type) {
222 cerr << "Error: id_defined.json seq =" << resourceId.seq << " type empty." << endl;
223 return false;
224 }
225 if (!cJSON_IsString(type)) {
226 cerr << "Error: id_defined.json seq =" << resourceId.seq << " type not string." << endl;
227 return false;
228 }
229 if (ResourceUtil::GetResTypeFromString(type->valuestring) == ResType::INVALID_RES_TYPE) {
230 cerr << "Error: id_defined.json seq =" << resourceId.seq << " type '";
231 cerr << type->valuestring << "' invalid." << endl;
232 return false;
233 }
234 resourceId.type = type->valuestring;
235 return true;
236 }
237
ParseName(const cJSON * name,ResourceId & resourceId)238 bool IdDefinedParser::ParseName(const cJSON *name, ResourceId &resourceId)
239 {
240 if (!name) {
241 cerr << "Error: id_defined.json seq =" << resourceId.seq << " name empty." << endl;
242 return false;
243 }
244 if (!cJSON_IsString(name)) {
245 cerr << "Error: id_defined.json seq =" << resourceId.seq << " name not string." << endl;
246 return false;
247 }
248 resourceId.name = name->valuestring;
249 if (type_ == ResourceIdCluster::RES_ID_SYS &&
250 (static_cast<uint64_t>(resourceId.id) & static_cast<uint64_t>(START_SYS_ID)) == START_SYS_ID &&
251 !ResourceUtil::IsValidName(resourceId.name)) {
252 cerr << "Error: id_defined.json."<< endl;
253 cerr << SOLUTIONS << endl;
254 cerr << SOLUTIONS_ARROW << "Modify the name '" << resourceId.name << "' to match [a-zA-Z0-9_]." << endl;
255 return false;
256 }
257 return true;
258 }
259
ParseOrder(const cJSON * order,ResourceId & resourceId)260 bool IdDefinedParser::ParseOrder(const cJSON *order, ResourceId &resourceId)
261 {
262 if (!order) {
263 cerr << "Error: id_defined.json seq =" << resourceId.seq << " order empty." << endl;
264 return false;
265 }
266 if (!ResourceUtil::IsIntValue(order)) {
267 cerr << "Error: id_defined.json seq =" << resourceId.seq << " order not int." << endl;
268 return false;
269 }
270 int64_t orderId = order->valueint;
271 if (orderId != resourceId.seq) {
272 cerr << "Error: id_defined.json seq =" << resourceId.seq << " order value ";
273 cerr << orderId << " vs expect " << resourceId.seq << endl;
274 return false;
275 }
276 resourceId.id = resourceId.id + orderId;
277 return true;
278 }
279
GetStartId() const280 int64_t IdDefinedParser::GetStartId() const
281 {
282 cJSON *startIdNode = cJSON_GetObjectItem(root_, "startId");
283 if (!startIdNode) {
284 cerr << "Error: id_defined.json 'startId' empty." << endl;
285 return -1;
286 }
287
288 if (!cJSON_IsString(startIdNode)) {
289 cerr << "Error: id_defined.json 'startId' not string." << endl;
290 return -1;
291 }
292
293 int64_t id = strtoll(startIdNode->valuestring, nullptr, 16);
294 return id;
295 }
296
297 }
298 }
299 }