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