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