• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 }