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 "id_worker.h"
17 #include<iostream>
18 #include<regex>
19 #include "cmd_parser.h"
20 #include "file_entry.h"
21
22 namespace OHOS {
23 namespace Global {
24 namespace Restool {
25 using namespace std;
26 const int32_t IdWorker::START_SYS_ID = 0x07800000;
Init(ResourceIdCluster type,int32_t startId)27 uint32_t IdWorker::Init(ResourceIdCluster type, int32_t startId)
28 {
29 type_ = type;
30 if (InitIdDefined() != RESTOOL_SUCCESS) {
31 return RESTOOL_ERROR;
32 }
33
34 if (type == ResourceIdCluster::RES_ID_APP) {
35 appId_ = startId;
36 maxId_ = GetMaxId(startId);
37 }
38 return RESTOOL_SUCCESS;
39 }
40
GenerateId(ResType resType,const string & name)41 int32_t IdWorker::GenerateId(ResType resType, const string &name)
42 {
43 if (type_ == ResourceIdCluster::RES_ID_APP) {
44 return GenerateAppId(resType, name);
45 }
46 return GenerateSysId(resType, name);
47 }
48
GetHeaderId() const49 vector<IdWorker::ResourceId> IdWorker::GetHeaderId() const
50 {
51 map<ResType, vector<ResourceId>> idClassify;
52 for (const auto &it : ids_) {
53 ResourceId resourceId;
54 resourceId.id = it.second;
55 resourceId.type = ResourceUtil::ResTypeToString(it.first.first);
56 resourceId.name = it.first.second;
57 idClassify[it.first.first].push_back(resourceId);
58 }
59
60 vector<ResourceId> ids;
61 for (const auto &item : idClassify) {
62 ids.insert(ids.end(), item.second.begin(), item.second.end());
63 }
64 return ids;
65 }
66
GetId(ResType resType,const string & name) const67 int32_t IdWorker::GetId(ResType resType, const string &name) const
68 {
69 auto result = ids_.find(make_pair(resType, name));
70 if (result == ids_.end()) {
71 return -1;
72 }
73 return result->second;
74 }
75
GetSystemId(ResType resType,const string & name) const76 int32_t IdWorker::GetSystemId(ResType resType, const string &name) const
77 {
78 auto result = sysDefinedIds_.find(make_pair(resType, name));
79 if (result == sysDefinedIds_.end()) {
80 return -1;
81 }
82 return result->second.id;
83 }
84
IsValidName(const string & name) const85 bool IdWorker::IsValidName(const string &name) const
86 {
87 if (!regex_match(name, regex("[a-zA-z0-9_]+"))) {
88 cerr << "Error: '" << name << "' only contain [a-zA-z0-9_]." << endl;
89 return false;
90 }
91 if (type_ != ResourceIdCluster::RES_ID_SYS) {
92 return true;
93 }
94 return IsValidSystemName(name);
95 }
96
PushCache(ResType resType,const string & name,int32_t id)97 bool IdWorker::PushCache(ResType resType, const string &name, int32_t id)
98 {
99 auto result = cacheIds_.emplace(make_pair(resType, name), id);
100 if (!result.second) {
101 return false;
102 }
103 if (appId_ == id) {
104 appId_ = id + 1;
105 return true;
106 }
107
108 if (id < appId_) {
109 return false;
110 }
111
112 for (int32_t i = appId_; i < id; i++) {
113 delIds_.push_back(i);
114 }
115 appId_ = id + 1;
116 return true;
117 }
118
PushDelId(int32_t id)119 void IdWorker::PushDelId(int32_t id)
120 {
121 delIds_.push_back(id);
122 }
123
GenerateAppId(ResType resType,const string & name)124 int32_t IdWorker::GenerateAppId(ResType resType, const string &name)
125 {
126 auto result = ids_.find(make_pair(resType, name));
127 if (result != ids_.end()) {
128 return result->second;
129 }
130
131 auto defined = appDefinedIds_.find(make_pair(resType, name));
132 if (defined != appDefinedIds_.end()) {
133 ids_.emplace(make_pair(resType, name), defined->second.id);
134 return defined->second.id;
135 }
136
137 result = cacheIds_.find(make_pair(resType, name));
138 if (result != cacheIds_.end()) {
139 ids_.emplace(make_pair(resType, name), result->second);
140 return result->second;
141 }
142
143 if (appId_ > maxId_) {
144 cerr << "Error: id count exceed " << appId_ << ">" << maxId_ << endl;
145 return -1;
146 }
147 int32_t id = -1;
148 if (!delIds_.empty()) {
149 id = delIds_.front();
150 delIds_.erase(delIds_.begin());
151 } else {
152 id = GetCurId();
153 if (id < 0) {
154 return -1;
155 }
156 }
157 ids_.emplace(make_pair(resType, name), id);
158 return id;
159 }
160
GetCurId()161 int32_t IdWorker::GetCurId()
162 {
163 if (appDefinedIds_.size() == 0) {
164 return appId_++;
165 }
166 while (appId_ <= maxId_) {
167 int32_t id = appId_;
168 auto ret = find_if(appDefinedIds_.begin(), appDefinedIds_.end(), [id](const auto &iter) {
169 return id == iter.second.id;
170 });
171 if (ret == appDefinedIds_.end()) {
172 return appId_++;
173 }
174 appId_++;
175 }
176 cerr << "Error: id count exceed in id_defined." << appId_ << ">" << maxId_ << endl;
177 return -1;
178 }
179
GenerateSysId(ResType resType,const string & name)180 int32_t IdWorker::GenerateSysId(ResType resType, const string &name)
181 {
182 auto result = ids_.find(make_pair(resType, name));
183 if (result != ids_.end()) {
184 return result->second;
185 }
186
187 auto defined = sysDefinedIds_.find(make_pair(resType, name));
188 if (defined != sysDefinedIds_.end()) {
189 ids_.emplace(make_pair(resType, name), defined->second.id);
190 return defined->second.id;
191 }
192 return -1;
193 }
194
InitIdDefined()195 uint32_t IdWorker::InitIdDefined()
196 {
197 InitParser();
198 CmdParser<PackageParser> &parser = CmdParser<PackageParser>::GetInstance();
199 PackageParser &packageParser = parser.GetCmdParser();
200 string idDefinedInput = packageParser.GetIdDefinedInputPath();
201 int32_t startId = packageParser.GetStartId();
202 bool combine = packageParser.GetCombine();
203 bool isSys = type_ == ResourceIdCluster::RES_ID_SYS;
204 for (const auto &inputPath : packageParser.GetInputs()) {
205 string idDefinedPath;
206 if (combine) {
207 idDefinedPath = FileEntry::FilePath(inputPath).Append(ID_DEFINED_FILE).GetPath();
208 } else {
209 idDefinedPath = ResourceUtil::GetBaseElementPath(inputPath).Append(ID_DEFINED_FILE).GetPath();
210 }
211 if (ResourceUtil::FileExist(idDefinedPath) && startId > 0) {
212 cerr << "Error: the set start_id and id_defined.json cannot be used together." << endl;
213 return RESTOOL_ERROR;
214 }
215 if (InitIdDefined(idDefinedPath, isSys) != RESTOOL_SUCCESS) {
216 return RESTOOL_ERROR;
217 }
218 }
219 if (isSys) {
220 return RESTOOL_SUCCESS;
221 }
222 if (!idDefinedInput.empty()) {
223 appDefinedIds_.clear();
224 string idDefinedPath = FileEntry::FilePath(idDefinedInput).GetPath();
225 if (InitIdDefined(idDefinedPath, false) != RESTOOL_SUCCESS) {
226 return RESTOOL_ERROR;
227 }
228 }
229 string sysIdDefinedPath = FileEntry::FilePath(packageParser.GetRestoolPath())
230 .GetParent().Append(ID_DEFINED_FILE).GetPath();
231 if (InitIdDefined(sysIdDefinedPath, true) != RESTOOL_SUCCESS) {
232 return RESTOOL_ERROR;
233 }
234 return RESTOOL_SUCCESS;
235 }
236
InitIdDefined(const std::string & filePath,bool isSystem)237 uint32_t IdWorker::InitIdDefined(const std::string &filePath, bool isSystem)
238 {
239 if (!ResourceUtil::FileExist(filePath)) {
240 return RESTOOL_SUCCESS;
241 }
242
243 Json::Value root;
244 if (!ResourceUtil::OpenJsonFile(filePath, root)) {
245 return RESTOOL_ERROR;
246 }
247
248 auto record = root["record"];
249 if (record.empty()) {
250 cerr << "Error: id_defined.json record empty." << endl;
251 return RESTOOL_ERROR;
252 }
253 if (!record.isArray()) {
254 cerr << "Error: id_defined.json record not array." << endl;
255 return RESTOOL_ERROR;
256 }
257 int32_t startSysId = 0;
258 if (isSystem) {
259 startSysId = GetStartId(root);
260 if (startSysId < 0) {
261 return RESTOOL_ERROR;
262 }
263 }
264
265 if (IdDefinedToResourceIds(record, isSystem, startSysId) != RESTOOL_SUCCESS) {
266 return RESTOOL_ERROR;
267 }
268 return RESTOOL_SUCCESS;
269 }
270
IdDefinedToResourceIds(const Json::Value & record,bool isSystem,const int32_t startSysId)271 uint32_t IdWorker::IdDefinedToResourceIds(const Json::Value &record, bool isSystem, const int32_t startSysId)
272 {
273 for (Json::ArrayIndex index = 0; index < record.size(); index++) {
274 auto arrayItem = record[index];
275 if (!arrayItem.isObject()) {
276 return RESTOOL_ERROR;
277 }
278 ResourceId resourceId;
279 resourceId.seq = index;
280 resourceId.id = startSysId;
281 for (const auto &handle : handles_) {
282 if ((handle.first == "id" && isSystem) || (handle.first == "order" && !isSystem)) {
283 continue;
284 }
285 if (!handle.second(arrayItem[handle.first], resourceId)) {
286 return RESTOOL_ERROR;
287 }
288 }
289 if (!PushResourceId(resourceId, isSystem)) {
290 return RESTOOL_ERROR;
291 }
292 }
293 return RESTOOL_SUCCESS;
294 }
295
InitParser()296 void IdWorker::InitParser()
297 {
298 using namespace placeholders;
299 handles_.emplace("type", bind(&IdWorker::ParseType, this, _1, _2));
300 handles_.emplace("name", bind(&IdWorker::ParseName, this, _1, _2));
301 handles_.emplace("id", bind(&IdWorker::ParseId, this, _1, _2));
302 handles_.emplace("order", bind(&IdWorker::ParseOrder, this, _1, _2));
303 }
304
ParseId(const Json::Value & origId,ResourceId & resourceId)305 bool IdWorker::ParseId(const Json::Value &origId, ResourceId &resourceId)
306 {
307 if (origId.empty()) {
308 cerr << "Error: id_defined.json seq =" << resourceId.seq << " id empty." << endl;
309 return false;
310 }
311 if (!origId.isString()) {
312 cerr << "Error: id_defined.json seq =" << resourceId.seq << " id not string." << endl;
313 return false;
314 }
315 string idStr = origId.asString();
316 if (!ResourceUtil::CheckHexStr(idStr)) {
317 cerr << "Error: id_defined.json seq =" << resourceId.seq;
318 cerr << " id must be a hex string, eg:^0[xX][0-9a-fA-F]{8}" << endl;
319 return false;
320 }
321 int32_t id = strtol(idStr.c_str(), nullptr, 16);
322 if (id < 0x01000000 || (id >= 0x06FFFFFF && id < 0x08000000) || id >= 0x41FFFFFF) {
323 cerr << "Error: id_defined.json seq = "<< resourceId.seq;
324 cerr << " id must in [0x01000000,0x06FFFFFF),[0x08000000,0x41FFFFFF)." << endl;
325 return false;
326 }
327 resourceId.id = id;
328 return true;
329 }
330
ParseType(const Json::Value & type,ResourceId & resourceId)331 bool IdWorker::ParseType(const Json::Value &type, ResourceId &resourceId)
332 {
333 if (type.empty()) {
334 cerr << "Error: id_defined.json seq =" << resourceId.seq << " type empty." << endl;
335 return false;
336 }
337 if (!type.isString()) {
338 cerr << "Error: id_defined.json seq =" << resourceId.seq << " type not string." << endl;
339 return false;
340 }
341 if (ResourceUtil::GetResTypeFromString(type.asString()) == ResType::INVALID_RES_TYPE) {
342 cerr << "Error: id_defined.json seq =" << resourceId.seq << " type '";
343 cerr << type.asString() << "' invalid." << endl;
344 return false;
345 }
346 resourceId.type = type.asString();
347 return true;
348 }
349
ParseName(const Json::Value & name,ResourceId & resourceId)350 bool IdWorker::ParseName(const Json::Value &name, ResourceId &resourceId)
351 {
352 if (name.empty()) {
353 cerr << "Error: id_defined.json seq =" << resourceId.seq << " name empty." << endl;
354 return false;
355 }
356 if (!name.isString()) {
357 cerr << "Error: id_defined.json seq =" << resourceId.seq << " name not string." << endl;
358 return false;
359 }
360 resourceId.name = name.asString();
361 if (type_ == ResourceIdCluster::RES_ID_SYS &&
362 (resourceId.id & START_SYS_ID) == START_SYS_ID && !IsValidSystemName(resourceId.name)) {
363 cerr << "Error: id_defined.json."<< endl;
364 return false;
365 }
366 return true;
367 }
368
ParseOrder(const Json::Value & order,ResourceId & resourceId)369 bool IdWorker::ParseOrder(const Json::Value &order, ResourceId &resourceId)
370 {
371 if (order.empty()) {
372 cerr << "Error: id_defined.json seq =" << resourceId.seq << " order empty." << endl;
373 return false;
374 }
375 if (!order.isInt()) {
376 cerr << "Error: id_defined.json seq =" << resourceId.seq << " order not int." << endl;
377 return false;
378 }
379 if (order.asInt() != resourceId.seq) {
380 cerr << "Error: id_defined.json seq =" << resourceId.seq << " order value ";
381 cerr << order.asInt() << " vs expect " << resourceId.seq << endl;
382 return false;
383 }
384 resourceId.id = resourceId.id + order.asInt();
385 return true;
386 }
387
PushResourceId(const ResourceId & resourceId,bool isSystem)388 bool IdWorker::PushResourceId(const ResourceId &resourceId, bool isSystem)
389 {
390 ResType resType = ResourceUtil::GetResTypeFromString(resourceId.type);
391 auto ret = idDefineds_.emplace(resourceId.id, resourceId);
392 if (!ret.second) {
393 cerr << "Error: '" << ret.first->second.name << "' and '" << resourceId.name << "' defind the same ID." << endl;
394 return false;
395 }
396 if (isSystem) {
397 sysDefinedIds_.emplace(make_pair(resType, resourceId.name), resourceId);
398 } else {
399 appDefinedIds_.emplace(make_pair(resType, resourceId.name), resourceId);
400 }
401 return true;
402 }
403
IsValidSystemName(const string & name) const404 bool IdWorker::IsValidSystemName(const string &name) const
405 {
406 if (regex_match(name, regex("^ohos.+"))) {
407 return true;
408 }
409 cerr << "Error: '" << name << "' must start with 'ohos'" << endl;
410 return false;
411 }
412
GetStartId(const Json::Value & root) const413 int32_t IdWorker::GetStartId(const Json::Value &root) const
414 {
415 auto startId = root["startId"];
416 if (startId.empty()) {
417 cerr << "Error: id_defined.json 'startId' empty." << endl;
418 return -1;
419 }
420
421 if (!startId.isString()) {
422 cerr << "Error: id_defined.json 'startId' not string." << endl;
423 return -1;
424 }
425
426 int32_t id = strtol(startId.asString().c_str(), nullptr, 16);
427 return id;
428 }
429
GetMaxId(int32_t startId) const430 int32_t IdWorker::GetMaxId(int32_t startId) const
431 {
432 int32_t flag = 1;
433 while ((flag & startId) == 0) {
434 flag = flag << 1;
435 }
436 return (startId + flag - 1);
437 }
438 }
439 }
440 }