• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-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 "reference_parser.h"
17 #include <iostream>
18 #include <regex>
19 #include "file_entry.h"
20 #include "restool_errors.h"
21 
22 namespace OHOS {
23 namespace Global {
24 namespace Restool {
25 using namespace std;
26 const map<string, ResType> ReferenceParser::ID_REFS = {
27     { "^\\$id:", ResType::ID },
28     { "^\\$boolean:", ResType::BOOLEAN },
29     { "^\\$color:", ResType::COLOR },
30     { "^\\$float:", ResType::FLOAT },
31     { "^\\$media:", ResType::MEDIA },
32     { "^\\$profile:", ResType::PROF },
33     { "^\\$integer:", ResType::INTEGER },
34     { "^\\$string:", ResType::STRING },
35     { "^\\$pattern:", ResType::PATTERN },
36     { "^\\$plural:", ResType::PLURAL },
37     { "^\\$theme:", ResType::THEME },
38     { "^\\$symbol:", ResType::SYMBOL }
39 };
40 
41 const map<string, ResType> ReferenceParser::ID_OHOS_REFS = {
42     { "^\\$ohos:id:", ResType::ID },
43     { "^\\$ohos:boolean:", ResType::BOOLEAN },
44     { "^\\$ohos:color:", ResType::COLOR },
45     { "^\\$ohos:float:", ResType::FLOAT },
46     { "^\\$ohos:media:", ResType::MEDIA },
47     { "^\\$ohos:profile:", ResType::PROF },
48     { "^\\$ohos:integer:", ResType::INTEGER },
49     { "^\\$ohos:string:", ResType::STRING },
50     { "^\\$ohos:pattern:", ResType::PATTERN },
51     { "^\\$ohos:plural:", ResType::PLURAL },
52     { "^\\$ohos:theme:", ResType::THEME },
53     { "^\\$ohos:symbol:", ResType::SYMBOL }
54 };
55 
56 std::map<int64_t, std::set<int64_t>> ReferenceParser::layerIconIds_;
57 
ReferenceParser()58 ReferenceParser::ReferenceParser() : idWorker_(IdWorker::GetInstance()), root_(nullptr), isParsingMediaJson_(false)
59 {
60 }
61 
~ReferenceParser()62 ReferenceParser::~ReferenceParser()
63 {
64     if (root_) {
65         cJSON_Delete(root_);
66     }
67 }
68 
ParseRefInResources(map<int64_t,vector<ResourceItem>> & items,const string & output)69 uint32_t ReferenceParser::ParseRefInResources(map<int64_t, vector<ResourceItem>> &items, const string &output)
70 {
71     for (auto &iter : items) {
72         for (auto &resourceItem : iter.second) {
73             if (resourceItem.IsCoverable()) {
74                 continue;
75             }
76             if (IsElementRef(resourceItem) && ParseRefInResourceItem(resourceItem) != RESTOOL_SUCCESS) {
77                 return RESTOOL_ERROR;
78             }
79             if ((IsMediaRef(resourceItem) || IsProfileRef(resourceItem)) &&
80                 ParseRefInJsonFile(resourceItem, output) != RESTOOL_SUCCESS) {
81                 return RESTOOL_ERROR;
82             }
83         }
84     }
85     return RESTOOL_SUCCESS;
86 }
87 
ParseRefInResourceItem(ResourceItem & resourceItem) const88 uint32_t ReferenceParser::ParseRefInResourceItem(ResourceItem &resourceItem) const
89 {
90     ResType resType = resourceItem.GetResType();
91     string data;
92     bool update = false;
93     if (IsStringOfResourceItem(resType)) {
94         if (resourceItem.GetData() == nullptr) {
95             std::string msg = "item data is null, resource name: " + resourceItem.GetName();
96             PrintError(GetError(ERR_CODE_UNDEFINED_ERROR).FormatCause(msg.c_str()));
97             return RESTOOL_ERROR;
98         }
99         data = string(reinterpret_cast<const char *>(resourceItem.GetData()), resourceItem.GetDataLength());
100         if (!ParseRefString(data, update, resourceItem.GetFilePath())) {
101             return RESTOOL_ERROR;
102         }
103         if (!update) {
104             return RESTOOL_SUCCESS;
105         }
106     } else if (IsArrayOfResourceItem(resType)) {
107         if (!ParseRefResourceItemData(resourceItem, data, update)) {
108             return RESTOOL_ERROR;
109         }
110         if (!update) {
111             return RESTOOL_SUCCESS;
112         }
113     }
114     if (update && !resourceItem.SetData(reinterpret_cast<const int8_t *>(data.c_str()), data.length())) {
115         std::string msg = "item data is null, resource name: " + resourceItem.GetName();
116         PrintError(GetError(ERR_CODE_UNDEFINED_ERROR).FormatCause(msg.c_str()).SetPosition(resourceItem.GetFilePath()));
117         return RESTOOL_ERROR;
118     }
119     return RESTOOL_SUCCESS;
120 }
121 
ParseRefInJsonFile(ResourceItem & resourceItem,const string & output,const bool isIncrement)122 uint32_t ReferenceParser::ParseRefInJsonFile(ResourceItem &resourceItem, const string &output, const bool isIncrement)
123 {
124     string jsonPath;
125     ResType resType = resourceItem.GetResType();
126     string resName = resourceItem.GetName();
127     if (resType == ResType::MEDIA) {
128         jsonPath = FileEntry::FilePath(output).Append(RESOURCES_DIR).Append(resourceItem.GetLimitKey()).Append("media")
129             .Append(resName).GetPath();
130         isParsingMediaJson_ = true;
131         mediaJsonId_ = idWorker_.GetId(resType, ResourceUtil::GetIdName(resName, resType));
132         if (mediaJsonId_ != INVALID_ID) {
133             set<int64_t> set;
134             layerIconIds_[mediaJsonId_] = set;
135         }
136     } else {
137         jsonPath = FileEntry::FilePath(output).Append(RESOURCES_DIR).Append("base").Append("profile").Append(resName)
138             .GetPath();
139     }
140     bool parseJsonRet = ParseRefJson(resourceItem.GetFilePath(), jsonPath);
141     isParsingMediaJson_ = false;
142     mediaJsonId_ = INVALID_ID;
143     if (!parseJsonRet) {
144         return RESTOOL_ERROR;
145     }
146 
147     if (isIncrement && ResourceUtil::FileExist(jsonPath)) {
148         resourceItem.SetData(reinterpret_cast<const int8_t *>(jsonPath.c_str()), jsonPath.length());
149     }
150     return RESTOOL_SUCCESS;
151 }
152 
ParseRefInString(string & value,bool & update,const std::string & filePath) const153 uint32_t ReferenceParser::ParseRefInString(string &value, bool &update, const std::string &filePath) const
154 {
155     if (ParseRefString(value, update, filePath)) {
156         return RESTOOL_SUCCESS;
157     }
158     return RESTOOL_ERROR;
159 }
160 
ParseRefJson(const string & from,const string & to)161 bool ReferenceParser::ParseRefJson(const string &from, const string &to)
162 {
163     if (!ResourceUtil::OpenJsonFile(from, &root_)) {
164         return false;
165     }
166     if (!root_ || !cJSON_IsObject(root_)) {
167         PrintError(GetError(ERR_CODE_JSON_FORMAT_ERROR).SetPosition(from));
168         return RESTOOL_ERROR;
169     }
170     bool needSave = false;
171     if (!ParseRefJsonImpl(root_, needSave, from)) {
172         return false;
173     }
174 
175     if (!needSave) {
176         return true;
177     }
178 
179     if (!ResourceUtil::CreateDirs(FileEntry::FilePath(to).GetParent().GetPath())) {
180         return false;
181     }
182 
183     if (!ResourceUtil::SaveToJsonFile(to, root_)) {
184         return false;
185     }
186     return true;
187 }
188 
ParseRefResourceItemData(const ResourceItem & resourceItem,string & data,bool & update) const189 bool ReferenceParser::ParseRefResourceItemData(const ResourceItem &resourceItem, string &data, bool &update) const
190 {
191     if (resourceItem.GetData() == nullptr) {
192         std::string msg = "item data is null, resource name: " + resourceItem.GetName();
193         PrintError(GetError(ERR_CODE_UNDEFINED_ERROR).FormatCause(msg.c_str()));
194         return false;
195     }
196     data = string(reinterpret_cast<const char *>(resourceItem.GetData()), resourceItem.GetDataLength());
197     vector<string> contents = ResourceUtil::DecomposeStrings(data);
198     if (contents.empty()) {
199         PrintError(GetError(ERR_CODE_ARRAY_TOO_LARGE).FormatCause(resourceItem.GetName().c_str())
200             .SetPosition(resourceItem.GetFilePath()));
201         return false;
202     }
203 
204     for (auto &content : contents) {
205         bool flag = false;
206         if (!ParseRefString(content, flag, resourceItem.GetFilePath())) {
207             return false;
208         }
209         update = (update || flag);
210     }
211 
212     if (!update) {
213         return true;
214     }
215 
216     data = ResourceUtil::ComposeStrings(contents);
217     if (data.empty()) {
218         PrintError(GetError(ERR_CODE_ARRAY_TOO_LARGE).FormatCause(resourceItem.GetName().c_str())
219             .SetPosition(resourceItem.GetFilePath()));
220         return false;
221     }
222     return true;
223 }
224 
IsStringOfResourceItem(ResType resType) const225 bool ReferenceParser::IsStringOfResourceItem(ResType resType) const
226 {
227     if (resType == ResType::STRING ||
228         resType == ResType::INTEGER ||
229         resType == ResType::BOOLEAN ||
230         resType == ResType::COLOR ||
231         resType == ResType::FLOAT ||
232         resType == ResType::SYMBOL) {
233         return true;
234     }
235     return false;
236 }
237 
IsArrayOfResourceItem(ResType resType) const238 bool ReferenceParser::IsArrayOfResourceItem(ResType resType) const
239 {
240     if (resType == ResType::STRARRAY ||
241         resType == ResType::INTARRAY ||
242         resType == ResType::PLURAL ||
243         resType == ResType::THEME ||
244         resType == ResType::PATTERN) {
245         return true;
246     }
247     return false;
248 }
249 
IsElementRef(const ResourceItem & resourceItem) const250 bool ReferenceParser::IsElementRef(const ResourceItem &resourceItem) const
251 {
252     ResType resType = resourceItem.GetResType();
253     auto result = find_if(g_contentClusterMap.begin(), g_contentClusterMap.end(), [resType](const auto &iter) {
254         return resType == iter.second;
255     });
256     if (result == g_contentClusterMap.end()) {
257         return false;
258     }
259     return true;
260 }
261 
IsMediaRef(const ResourceItem & resourceItem) const262 bool ReferenceParser::IsMediaRef(const ResourceItem &resourceItem) const
263 {
264     return resourceItem.GetResType() == ResType::MEDIA &&
265                 FileEntry::FilePath(resourceItem.GetFilePath()).GetExtension() == JSON_EXTENSION;
266 }
267 
IsProfileRef(const ResourceItem & resourceItem) const268 bool ReferenceParser::IsProfileRef(const ResourceItem &resourceItem) const
269 {
270     return resourceItem.GetResType() == ResType::PROF && resourceItem.GetLimitKey() == "base" &&
271                 FileEntry::FilePath(resourceItem.GetFilePath()).GetExtension() == JSON_EXTENSION;
272 }
273 
ParseRefString(string & key) const274 bool ReferenceParser::ParseRefString(string &key) const
275 {
276     bool update = false;
277     return ParseRefString(key, update);
278 }
279 
ParseRefString(std::string & key,bool & update,const std::string & filePath) const280 bool ReferenceParser::ParseRefString(std::string &key, bool &update, const std::string &filePath) const
281 {
282     update = false;
283     if (regex_match(key, regex("^\\$ohos:[a-z]+:.+"))) {
284         update = true;
285         return ParseRefImpl(key, ID_OHOS_REFS, true, filePath);
286     } else if (regex_match(key, regex("^\\$[a-z]+:.+"))) {
287         update = true;
288         return ParseRefImpl(key, ID_REFS, false, filePath);
289     }
290     return true;
291 }
292 
ParseRefImpl(string & key,const map<string,ResType> & refs,bool isSystem,const std::string & filePath) const293 bool ReferenceParser::ParseRefImpl(string &key, const map<string, ResType> &refs, bool isSystem,
294     const std::string &filePath) const
295 {
296     for (const auto &ref : refs) {
297         smatch result;
298         if (regex_search(key, result, regex(ref.first))) {
299             string name = key.substr(result[0].str().length());
300             int64_t id = idWorker_.GetId(ref.second, name);
301             if (!isSystem && ref.second == ResType::MEDIA && mediaJsonId_ != 0
302                 && layerIconIds_.find(mediaJsonId_) != layerIconIds_.end()) {
303                 layerIconIds_[mediaJsonId_].insert(id);
304             }
305             if (isSystem) {
306                 id = idWorker_.GetSystemId(ref.second, name);
307             }
308             if (id < 0) {
309                 PrintError(GetError(ERR_CODE_REF_NOT_DEFINED).FormatCause(key.c_str()).SetPosition(filePath));
310                 return false;
311             }
312 
313             key = to_string(id);
314             if (ref.second != ResType::ID) {
315                 key = "$" + ResourceUtil::ResTypeToString(ref.second) + ":" + to_string(id);
316             }
317             return true;
318         }
319     }
320     string refer;
321     for (const auto &ref:refs) {
322         refer.append(ref.first).append(" ");
323     }
324     PrintError(GetError(ERR_CODE_INVALID_RESOURCE_REF).FormatCause(key.c_str(), refer.c_str()).SetPosition(filePath));
325     return false;
326 }
327 
ParseRefJsonImpl(cJSON * node,bool & needSave,const std::string & filePath) const328 bool ReferenceParser::ParseRefJsonImpl(cJSON *node, bool &needSave, const std::string &filePath) const
329 {
330     if (cJSON_IsObject(node) || cJSON_IsArray(node)) {
331         for (cJSON *item = node->child; item; item = item->next) {
332             if (!ParseRefJsonImpl(item, needSave, filePath)) {
333                 return false;
334             }
335         }
336     }  else if (cJSON_IsString(node)) {
337         string value = node->valuestring;
338         bool update = false;
339         if (!ParseRefString(value, update, filePath)) {
340             return false;
341         }
342         if (update) {
343             needSave = update;
344         }
345         cJSON_SetValuestring(node, value.c_str());
346     }
347     return true;
348 }
349 
GetLayerIconIds()350 std::map<int64_t, std::set<int64_t>> &ReferenceParser::GetLayerIconIds()
351 {
352     return layerIconIds_;
353 }
354 }
355 }
356 }
357