• 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 
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 
ReferenceParser()56 ReferenceParser::ReferenceParser() : idWorker_(IdWorker::GetInstance())
57 {
58 }
59 
~ReferenceParser()60 ReferenceParser::~ReferenceParser()
61 {
62 }
63 
ParseRefInResources(map<int32_t,vector<ResourceItem>> & items,const string & output)64 uint32_t ReferenceParser::ParseRefInResources(map<int32_t, vector<ResourceItem>> &items, const string &output)
65 {
66     for (auto &iter : items) {
67         for (auto &resourceItem : iter.second) {
68             if (IsElementRef(resourceItem) && ParseRefInResourceItem(resourceItem) != RESTOOL_SUCCESS) {
69                 return RESTOOL_ERROR;
70             }
71             if ((IsMediaRef(resourceItem) || IsProfileRef(resourceItem)) &&
72                 ParseRefInJsonFile(resourceItem, output) != RESTOOL_SUCCESS) {
73                 return RESTOOL_ERROR;
74             }
75         }
76     }
77     return RESTOOL_SUCCESS;
78 }
79 
ParseRefInResourceItem(ResourceItem & resourceItem) const80 uint32_t ReferenceParser::ParseRefInResourceItem(ResourceItem &resourceItem) const
81 {
82     ResType resType = resourceItem.GetResType();
83     string data;
84     bool update = false;
85     if (IsStringOfResourceItem(resType)) {
86         data = string(reinterpret_cast<const char *>(resourceItem.GetData()), resourceItem.GetDataLength());
87         if (!ParseRefString(data, update)) {
88             cerr << "Error: " << NEW_LINE_PATH << resourceItem.GetFilePath() << endl;
89             return RESTOOL_ERROR;
90         }
91         if (!update) {
92             return RESTOOL_SUCCESS;
93         }
94     } else if (IsArrayOfResourceItem(resType)) {
95         if (!ParseRefResourceItemData(resourceItem, data, update)) {
96             return RESTOOL_ERROR;
97         }
98         if (!update) {
99             return RESTOOL_SUCCESS;
100         }
101     }
102     if (update && !resourceItem.SetData(reinterpret_cast<const int8_t *>(data.c_str()), data.length())) {
103         cerr << "Error: set data fail. name = '" << resourceItem.GetName() << "' data = '" << data << "'.";
104         cerr << NEW_LINE_PATH << resourceItem.GetFilePath() << endl;
105         return RESTOOL_ERROR;
106     }
107     return RESTOOL_SUCCESS;
108 }
109 
ParseRefInJsonFile(ResourceItem & resourceItem,const string & output,const bool isIncrement)110 uint32_t ReferenceParser::ParseRefInJsonFile(ResourceItem &resourceItem, const string &output, const bool isIncrement)
111 {
112     string jsonPath;
113     if (resourceItem.GetResType() == ResType::MEDIA) {
114         jsonPath = FileEntry::FilePath(output).Append(RESOURCES_DIR)
115             .Append(resourceItem.GetLimitKey()).Append("media").Append(resourceItem.GetName()).GetPath();
116     } else {
117         jsonPath = FileEntry::FilePath(output).Append(RESOURCES_DIR)
118             .Append("base").Append("profile").Append(resourceItem.GetName()).GetPath();
119     }
120     if (!ParseRefJson(resourceItem.GetFilePath(), jsonPath)) {
121         return RESTOOL_ERROR;
122     }
123 
124     if (isIncrement && ResourceUtil::FileExist(jsonPath)) {
125         resourceItem.SetData(reinterpret_cast<const int8_t *>(jsonPath.c_str()), jsonPath.length());
126     }
127     return RESTOOL_SUCCESS;
128 }
129 
ParseRefInString(string & value,bool & update) const130 uint32_t ReferenceParser::ParseRefInString(string &value, bool &update) const
131 {
132     if (ParseRefString(value, update)) {
133         return RESTOOL_SUCCESS;
134     }
135     return RESTOOL_ERROR;
136 }
137 
ParseRefJson(const string & from,const string & to) const138 bool ReferenceParser::ParseRefJson(const string &from, const string &to) const
139 {
140     Json::Value root;
141     if (!ResourceUtil::OpenJsonFile(from, root)) {
142         return false;
143     }
144 
145     bool needSave = false;
146     if (!ParseRefJsonImpl(root, needSave)) {
147         return false;
148     }
149 
150     if (!needSave) {
151         return true;
152     }
153 
154     if (!ResourceUtil::CreateDirs(FileEntry::FilePath(to).GetParent().GetPath())) {
155         return false;
156     }
157 
158     if (!ResourceUtil::SaveToJsonFile(to, root)) {
159         return false;
160     }
161     return true;
162 }
163 
ParseRefResourceItemData(const ResourceItem & resourceItem,string & data,bool & update) const164 bool ReferenceParser::ParseRefResourceItemData(const ResourceItem &resourceItem, string &data, bool &update) const
165 {
166     data = string(reinterpret_cast<const char *>(resourceItem.GetData()), resourceItem.GetDataLength());
167     vector<string> contents = ResourceUtil::DecomposeStrings(data);
168     if (contents.empty()) {
169         cerr << "Error: DecomposeStrings fail. name = '" << resourceItem.GetName() << "' data = '" << data << "'.";
170         cerr << NEW_LINE_PATH << resourceItem.GetFilePath() << endl;
171         return false;
172     }
173 
174     for (auto &content : contents) {
175         bool flag = false;
176         if (!ParseRefString(content, flag)) {
177             cerr << "Error: " << NEW_LINE_PATH << resourceItem.GetFilePath() << endl;
178             return false;
179         }
180         update = (update || flag);
181     }
182 
183     if (!update) {
184         return true;
185     }
186 
187     data = ResourceUtil::ComposeStrings(contents);
188     if (data.empty()) {
189         cerr << "Error: ComposeStrings fail. name = '" << resourceItem.GetName();
190         cerr << "'  contents size is " << contents.size() << NEW_LINE_PATH << resourceItem.GetFilePath() << endl;
191         return false;
192     }
193     return true;
194 }
195 
IsStringOfResourceItem(ResType resType) const196 bool ReferenceParser::IsStringOfResourceItem(ResType resType) const
197 {
198     if (resType == ResType::STRING ||
199         resType == ResType::INTEGER ||
200         resType == ResType::BOOLEAN ||
201         resType == ResType::COLOR ||
202         resType == ResType::FLOAT ||
203         resType == ResType::SYMBOL) {
204         return true;
205     }
206     return false;
207 }
208 
IsArrayOfResourceItem(ResType resType) const209 bool ReferenceParser::IsArrayOfResourceItem(ResType resType) const
210 {
211     if (resType == ResType::STRARRAY ||
212         resType == ResType::INTARRAY ||
213         resType == ResType::PLURAL ||
214         resType == ResType::THEME ||
215         resType == ResType::PATTERN) {
216         return true;
217     }
218     return false;
219 }
220 
IsElementRef(const ResourceItem & resourceItem) const221 bool ReferenceParser::IsElementRef(const ResourceItem &resourceItem) const
222 {
223     ResType resType = resourceItem.GetResType();
224     auto result = find_if(g_contentClusterMap.begin(), g_contentClusterMap.end(), [resType](const auto &iter) {
225         return resType == iter.second;
226     });
227     if (result == g_contentClusterMap.end()) {
228         return false;
229     }
230     return true;
231 }
232 
IsMediaRef(const ResourceItem & resourceItem) const233 bool ReferenceParser::IsMediaRef(const ResourceItem &resourceItem) const
234 {
235     return resourceItem.GetResType() == ResType::MEDIA &&
236                 FileEntry::FilePath(resourceItem.GetFilePath()).GetExtension() == JSON_EXTENSION;
237 }
238 
IsProfileRef(const ResourceItem & resourceItem) const239 bool ReferenceParser::IsProfileRef(const ResourceItem &resourceItem) const
240 {
241     return resourceItem.GetResType() == ResType::PROF && resourceItem.GetLimitKey() == "base" &&
242                 FileEntry::FilePath(resourceItem.GetFilePath()).GetExtension() == JSON_EXTENSION;
243 }
244 
ParseRefString(string & key) const245 bool ReferenceParser::ParseRefString(string &key) const
246 {
247     bool update = false;
248     return ParseRefString(key, update);
249 }
250 
ParseRefString(std::string & key,bool & update) const251 bool ReferenceParser::ParseRefString(std::string &key, bool &update) const
252 {
253     update = false;
254     if (regex_match(key, regex("^\\$ohos:[a-z]+:.+"))) {
255         update = true;
256         return ParseRefImpl(key, ID_OHOS_REFS, true);
257     } else if (regex_match(key, regex("^\\$[a-z]+:.+"))) {
258         update = true;
259         return ParseRefImpl(key, ID_REFS, false);
260     }
261     return true;
262 }
263 
ParseRefImpl(string & key,const map<string,ResType> & refs,bool isSystem) const264 bool ReferenceParser::ParseRefImpl(string &key, const map<string, ResType> &refs, bool isSystem) const
265 {
266     for (const auto &ref : refs) {
267         smatch result;
268         if (regex_search(key, result, regex(ref.first))) {
269             string name = key.substr(result[0].str().length());
270             int32_t id = idWorker_.GetId(ref.second, name);
271             if (isSystem) {
272                 id = idWorker_.GetSystemId(ref.second, name);
273             }
274             if (id < 0) {
275                 cerr << "Error: ref '" << key << "' don't be defined." << endl;
276                 return false;
277             }
278 
279             key = to_string(id);
280             if (ref.second != ResType::ID) {
281                 key = "$" + ResourceUtil::ResTypeToString(ref.second) + ":" + to_string(id);
282             }
283             return true;
284         }
285     }
286     cerr << "Error: reference '" << key << "' invalid." << endl;
287     return false;
288 }
289 
ParseRefJsonImpl(Json::Value & node,bool & needSave) const290 bool ReferenceParser::ParseRefJsonImpl(Json::Value &node, bool &needSave) const
291 {
292     if (node.isObject()) {
293         for (const auto &member : node.getMemberNames()) {
294             if (!ParseRefJsonImpl(node[member], needSave)) {
295                 return false;
296             }
297         }
298     } else if (node.isArray()) {
299         for (Json::ArrayIndex i = 0; i < node.size(); i++) {
300             if (!ParseRefJsonImpl(node[i], needSave)) {
301                 return false;
302             }
303         }
304     } else if (node.isString()) {
305         string value = node.asString();
306         bool update = false;
307         if (!ParseRefString(value, update)) {
308             return false;
309         }
310         if (update) {
311             needSave = update;
312         }
313         node = value;
314     }
315     return true;
316 }
317 }
318 }
319 }
320