• 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 "reference_parser.h"
17 #include<iostream>
18 #include<regex>
19 #include "file_entry.h"
20 #include "restool_errors.h"
21 #include "xml_key_node.h"
22 
23 namespace OHOS {
24 namespace Global {
25 namespace Restool {
26 using namespace std;
27 const map<string, ResType> ReferenceParser::ID_REFS = {
28     { "^\\$id:", ResType::ID },
29     { "^\\$boolean:", ResType::BOOLEAN },
30     { "^\\$color:", ResType::COLOR },
31     { "^\\$float:", ResType::FLOAT },
32     { "^\\$media:", ResType::MEDIA },
33     { "^\\$profile:", ResType::PROF },
34     { "^\\$integer:", ResType::INTEGER },
35     { "^\\$string:", ResType::STRING },
36     { "^\\$layout:", ResType::LAYOUT },
37     { "^\\$pattern:", ResType::PATTERN },
38     { "^\\$plural:", ResType::PLURAL },
39     { "^\\$graphic:", ResType::GRAPHIC },
40     { "^\\$theme:", ResType::THEME }
41 };
42 
43 const map<string, ResType> ReferenceParser::ID_OHOS_REFS = {
44     { "^\\$ohos:id:", ResType::ID },
45     { "^\\$ohos:boolean:", ResType::BOOLEAN },
46     { "^\\$ohos:color:", ResType::COLOR },
47     { "^\\$ohos:float:", ResType::FLOAT },
48     { "^\\$ohos:media:", ResType::MEDIA },
49     { "^\\$ohos:profile:", ResType::PROF },
50     { "^\\$ohos:integer:", ResType::INTEGER },
51     { "^\\$ohos:string:", ResType::STRING },
52     { "^\\$ohos:layout:", ResType::LAYOUT },
53     { "^\\$ohos:pattern:", ResType::PATTERN },
54     { "^\\$ohos:plural:", ResType::PLURAL },
55     { "^\\$ohos:graphic:", ResType::GRAPHIC },
56     { "^\\$ohos:theme:", ResType::THEME }
57 };
58 
ReferenceParser()59 ReferenceParser::ReferenceParser() : idWorker_(IdWorker::GetInstance())
60 {
61 }
62 
~ReferenceParser()63 ReferenceParser::~ReferenceParser()
64 {
65 }
66 
ParseRefInSolidXml(const vector<string> & solidXmlFolders) const67 uint32_t ReferenceParser::ParseRefInSolidXml(const vector<string> &solidXmlFolders) const
68 {
69     for (const auto &solidXmlFolder : solidXmlFolders) {
70         string filePath = FileEntry::FilePath(solidXmlFolder)
71             .Append(XmlKeyNode::KEY_TO_FILE_NAME.at(XmlKeyNode::KeyType::CONSTANT)).GetPath();
72         if (!ResourceUtil::FileExist(filePath)) {
73             continue;
74         }
75 
76         XmlKeyNode xmlKeyNode;
77         if (!xmlKeyNode.LoadFromFile(filePath, [this](auto &key) -> bool {
78             return ParseRefString(key);
79             })) {
80             return RESTOOL_ERROR;
81         }
82 
83         if (!xmlKeyNode.SaveToFile(filePath)) {
84             return RESTOOL_ERROR;
85         }
86     }
87     return RESTOOL_SUCCESS;
88 }
89 
ParseRefInElement(map<int32_t,vector<ResourceItem>> & items) const90 uint32_t ReferenceParser::ParseRefInElement(map<int32_t, vector<ResourceItem>> &items) const
91 {
92     for (auto &iter : items) {
93         for (auto &resourceItem : iter.second) {
94             if (IsNotElement(resourceItem.GetResType())) {
95                 break;
96             }
97             if (!ParseRefResourceItem(resourceItem)) {
98                 return RESTOOL_ERROR;
99             }
100         }
101     }
102     return RESTOOL_SUCCESS;
103 }
104 
ParseRefInString(string & value,bool & update) const105 uint32_t ReferenceParser::ParseRefInString(string &value, bool &update) const
106 {
107     if (ParseRefString(value, update)) {
108         return RESTOOL_SUCCESS;
109     }
110     return RESTOOL_ERROR;
111 }
112 
ParseRefInProfile(const string & output) const113 uint32_t ReferenceParser::ParseRefInProfile(const string &output) const
114 {
115     string profileFolder = FileEntry::FilePath(output).Append(RESOURCES_DIR).Append("base").Append("profile").GetPath();
116     if (!ResourceUtil::FileExist(profileFolder)) {
117         return RESTOOL_SUCCESS;
118     }
119 
120     FileEntry f(profileFolder);
121     for (const auto &entry : f.GetChilds()) {
122         if (!entry->IsFile()) {
123             cerr << "Error: '" << entry->GetFilePath().GetPath() << "' is directory." << endl;
124             return false;
125         }
126 
127         if (entry->GetFilePath().GetExtension() != ".json") {
128             continue;
129         }
130 
131         if (ParseRefInJson(entry->GetFilePath().GetPath()) != RESTOOL_SUCCESS) {
132             return RESTOOL_ERROR;
133         }
134     }
135     return RESTOOL_SUCCESS;
136 }
137 
ParseRefInJson(const string & filePath) const138 uint32_t ReferenceParser::ParseRefInJson(const string &filePath) const
139 {
140     return ParseRefInJson(filePath, filePath);
141 }
142 
ParseRefInJson(const string & from,const string & to) const143 uint32_t ReferenceParser::ParseRefInJson(const string &from, const string &to) const
144 {
145     Json::Value root;
146     if (!ResourceUtil::OpenJsonFile(from, root)) {
147         return RESTOOL_ERROR;
148     }
149 
150     bool needSave = false;
151     if (!ParseRefJsonImpl(root, needSave)) {
152         return RESTOOL_ERROR;
153     }
154 
155     if (!needSave) {
156         return RESTOOL_SUCCESS;
157     }
158 
159     if (!ResourceUtil::CreateDirs(FileEntry::FilePath(to).GetParent().GetPath())) {
160         return RESTOOL_ERROR;
161     }
162 
163     if (!ResourceUtil::SaveToJsonFile(to, root)) {
164         return RESTOOL_ERROR;
165     }
166     return RESTOOL_SUCCESS;
167 }
168 
ParseRefInResourceItem(ResourceItem & resourceItem) const169 uint32_t ReferenceParser::ParseRefInResourceItem(ResourceItem &resourceItem) const
170 {
171     if (!ParseRefResourceItem(resourceItem)) {
172         return RESTOOL_ERROR;
173     }
174     return RESTOOL_SUCCESS;
175 }
176 
ParseRefResourceItem(ResourceItem & resourceItem) const177 bool ReferenceParser::ParseRefResourceItem(ResourceItem &resourceItem) const
178 {
179     ResType resType = resourceItem.GetResType();
180     string data;
181     bool update = false;
182     if (IsStringOfResourceItem(resType)) {
183         data = string(reinterpret_cast<const char *>(resourceItem.GetData()), resourceItem.GetDataLength());
184         if (!ParseRefString(data, update)) {
185             cerr << "Error: " << NEW_LINE_PATH << resourceItem.GetFilePath() << endl;
186             return false;
187         }
188         if (!update) {
189             return true;
190         }
191     } else if (IsArrayOfResourceItem(resType)) {
192         if (!ParseRefResourceItemData(resourceItem, data, update)) {
193             return false;
194         }
195         if (!update) {
196             return true;
197         }
198     }
199     if (update && !resourceItem.SetData(reinterpret_cast<const int8_t *>(data.c_str()), data.length())) {
200         cerr << "Error: set data fail. name = '" << resourceItem.GetName() << "' data = '" << data << "'.";
201         cerr << NEW_LINE_PATH << resourceItem.GetFilePath() << endl;
202         return false;
203     }
204     return true;
205 }
206 
ParseRefResourceItemData(const ResourceItem & resourceItem,string & data,bool & update) const207 bool ReferenceParser::ParseRefResourceItemData(const ResourceItem &resourceItem, string &data, bool &update) const
208 {
209     data = string(reinterpret_cast<const char *>(resourceItem.GetData()), resourceItem.GetDataLength());
210     vector<string> contents = ResourceUtil::DecomposeStrings(data);
211     if (contents.empty()) {
212         cerr << "Error: DecomposeStrings fail. name = '" << resourceItem.GetName() << "' data = '" << data << "'.";
213         cerr << NEW_LINE_PATH << resourceItem.GetFilePath() << endl;
214         return false;
215     }
216 
217     for (auto &content : contents) {
218         bool flag = false;
219         if (!ParseRefString(content, flag)) {
220             cerr << "Error: " << NEW_LINE_PATH << resourceItem.GetFilePath() << endl;
221             return false;
222         }
223         update = (update || flag);
224     }
225 
226     if (!update) {
227         return true;
228     }
229 
230     data = ResourceUtil::ComposeStrings(contents);
231     if (data.empty()) {
232         cerr << "Error: ComposeStrings fail. name = '" << resourceItem.GetName();
233         cerr << "'  contents size is " << contents.size() << NEW_LINE_PATH << resourceItem.GetFilePath() << endl;
234         return false;
235     }
236     return true;
237 }
238 
IsStringOfResourceItem(ResType resType) const239 bool ReferenceParser::IsStringOfResourceItem(ResType resType) const
240 {
241     if (resType == ResType::STRING ||
242         resType == ResType::INTEGER ||
243         resType == ResType::BOOLEAN ||
244         resType == ResType::COLOR ||
245         resType == ResType::FLOAT) {
246         return true;
247     }
248     return false;
249 }
250 
IsArrayOfResourceItem(ResType resType) const251 bool ReferenceParser::IsArrayOfResourceItem(ResType resType) const
252 {
253     if (resType == ResType::STRARRAY ||
254         resType == ResType::INTARRAY ||
255         resType == ResType::PLURAL ||
256         resType == ResType::THEME ||
257         resType == ResType::PATTERN) {
258         return true;
259     }
260     return false;
261 }
262 
IsNotElement(ResType resType) const263 bool ReferenceParser::IsNotElement(ResType resType) const
264 {
265     auto result = find_if(g_contentClusterMap.begin(), g_contentClusterMap.end(), [resType](const auto &iter) {
266         return resType == iter.second;
267     });
268     if (result == g_contentClusterMap.end()) {
269         return true;
270     }
271     return false;
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) const280 bool ReferenceParser::ParseRefString(std::string &key, bool &update) 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);
286     } else if (regex_match(key, regex("^\\$[a-z]+:.+"))) {
287         update = true;
288         return ParseRefImpl(key, ID_REFS, false);
289     }
290     return true;
291 }
292 
ParseRefImpl(string & key,const map<string,ResType> & refs,bool isSystem) const293 bool ReferenceParser::ParseRefImpl(string &key, const map<string, ResType> &refs, bool isSystem) const
294 {
295     for (const auto &ref : refs) {
296         smatch result;
297         if (regex_search(key, result, regex(ref.first))) {
298             string name = key.substr(result[0].str().length());
299             int32_t id = idWorker_.GetId(ref.second, name);
300             if (isSystem) {
301                 id = idWorker_.GetSystemId(ref.second, name);
302             }
303             if (id < 0) {
304                 cerr << "Error: ref '" << key << "' don't be defined." << endl;
305                 return false;
306             }
307 
308             key = to_string(id);
309             if (ref.second != ResType::ID) {
310                 key = key = "$" + ResourceUtil::ResTypeToString(ref.second) + ":" + to_string(id);
311             }
312             return true;
313         }
314     }
315     cerr << "Error: reference '" << key << "' invalid." << endl;
316     return false;
317 }
318 
ParseRefJsonImpl(Json::Value & node,bool & needSave) const319 bool ReferenceParser::ParseRefJsonImpl(Json::Value &node, bool &needSave) const
320 {
321     if (node.isObject()) {
322         for (const auto &member : node.getMemberNames()) {
323             if (!ParseRefJsonImpl(node[member], needSave)) {
324                 return false;
325             }
326         }
327     } else if (node.isArray()) {
328         for (Json::ArrayIndex i = 0; i < node.size(); i++) {
329             if (!ParseRefJsonImpl(node[i], needSave)) {
330                 return false;
331             }
332         }
333     } else if (node.isString()) {
334         string value = node.asString();
335         bool update = false;
336         if (!ParseRefString(value, update)) {
337             return false;
338         }
339         if (update) {
340             needSave = update;
341         }
342         node = value;
343     }
344     return true;
345 }
346 }
347 }
348 }
349