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 "resource_util.h"
17 #include<algorithm>
18 #include<fstream>
19 #include<iostream>
20 #include<regex>
21 #include<cstdlib>
22 #include "file_entry.h"
23
24 namespace OHOS {
25 namespace Global {
26 namespace Restool {
27 using namespace std;
28 const map<string, ResourceUtil::IgnoreType> ResourceUtil::IGNORE_FILE_REGEX = {
29 { "\\.git", IgnoreType::IGNORE_ALL },
30 { "\\.svn", IgnoreType::IGNORE_ALL },
31 { ".+\\.scc", IgnoreType::IGNORE_ALL },
32 { "\\.ds_store", IgnoreType::IGNORE_ALL },
33 { "desktop\\.ini", IgnoreType::IGNORE_ALL },
34 { "picasa\\.ini", IgnoreType::IGNORE_ALL },
35 { "\\..+", IgnoreType::IGNORE_ALL },
36 { "_.+", IgnoreType::IGNORE_DIR },
37 { "cvs", IgnoreType::IGNORE_ALL },
38 { "thumbs\\.db", IgnoreType::IGNORE_ALL },
39 { ".+~", IgnoreType::IGNORE_ALL }
40 };
41
Split(const string & str,vector<string> & out,const string & splitter)42 void ResourceUtil::Split(const string &str, vector<string> &out, const string &splitter)
43 {
44 string::size_type len = str.size();
45 string::size_type begin = 0;
46 string::size_type end = str.find(splitter, begin);
47 while (end != string::npos) {
48 string sub = str.substr(begin, end - begin);
49 out.push_back(sub);
50 begin = end + splitter.size();
51 if (begin >= len) {
52 break;
53 }
54 end = str.find(splitter, begin);
55 }
56
57 if (begin < len) {
58 out.push_back(str.substr(begin));
59 }
60 }
61
FileExist(const string & path)62 bool ResourceUtil::FileExist(const string &path)
63 {
64 return FileEntry::Exist(path);
65 }
66
RmoveAllDir(const string & path)67 bool ResourceUtil::RmoveAllDir(const string &path)
68 {
69 return FileEntry::RemoveAllDir(path);
70 }
71
OpenJsonFile(const string & path,Json::Value & root)72 bool ResourceUtil::OpenJsonFile(const string &path, Json::Value &root)
73 {
74 ifstream ifs(FileEntry::AdapateLongPath(path), ios::binary);
75 if (!ifs.is_open()) {
76 cerr << "Error: open json failed '" << path << "', reason: " << strerror(errno) << endl;
77 return false;
78 }
79
80 Json::CharReaderBuilder readBuilder;
81 readBuilder["collectComments"] = false;
82 readBuilder["failIfExtra"] = true;
83 JSONCPP_STRING errs;
84 if (!parseFromStream(readBuilder, ifs, &root, &errs)) {
85 cerr << "Error: parseFromStream failed." << NEW_LINE_PATH << path;
86 cerr << "\n" << errs << endl;
87 ifs.close();
88 return false;
89 }
90 ifs.close();
91 return true;
92 }
93
SaveToJsonFile(const string & path,const Json::Value & root)94 bool ResourceUtil::SaveToJsonFile(const string &path, const Json::Value &root)
95 {
96 Json::StreamWriterBuilder writerBuilder;
97 writerBuilder["indentation"] = " ";
98 writerBuilder["emitUTF8"] = true;
99 unique_ptr<Json::StreamWriter> writer(writerBuilder.newStreamWriter());
100 ofstream out(FileEntry::AdapateLongPath(path), ofstream::out | ofstream::binary);
101 if (!out.is_open()) {
102 cerr << "Error: open failed '" << path <<"', reason: " << strerror(errno) << endl;
103 return false;
104 }
105 writer->write(root, &out);
106 out.close();
107 return true;
108 }
109
GetResTypeByDir(const string & name)110 ResType ResourceUtil::GetResTypeByDir(const string &name)
111 {
112 auto ret = g_fileClusterMap.find(name);
113 if (ret == g_fileClusterMap.end()) {
114 return ResType::INVALID_RES_TYPE;
115 }
116 return ret->second;
117 }
118
ResTypeToString(ResType type)119 string ResourceUtil::ResTypeToString(ResType type)
120 {
121 auto ret = find_if(g_fileClusterMap.begin(), g_fileClusterMap.end(), [type](auto iter) {
122 return iter.second == type;
123 });
124 if (ret != g_fileClusterMap.end()) {
125 return ret->first;
126 }
127
128 ret = find_if(g_contentClusterMap.begin(), g_contentClusterMap.end(), [type](auto iter) {
129 return iter.second == type;
130 });
131 if (ret != g_contentClusterMap.end()) {
132 return ret->first;
133 }
134 return "";
135 }
136
GetIdName(const string & name,ResType type)137 string ResourceUtil::GetIdName(const string &name, ResType type)
138 {
139 if (type != ResType::MEDIA && type != ResType::LAYOUT && type != ResType::PROF &&
140 type != ResType::ANIMATION && type != ResType::GRAPHIC) {
141 return name;
142 }
143
144 string::size_type pos = name.find_last_of(".");
145 if (pos != string::npos) {
146 return name.substr(0, pos);
147 }
148 return name;
149 }
150
ComposeStrings(const vector<string> & contents,bool addNull)151 string ResourceUtil::ComposeStrings(const vector<string> &contents, bool addNull)
152 {
153 string result;
154 for (const auto &iter : contents) {
155 if (iter.length() > UINT16_MAX) {
156 return "";
157 }
158
159 uint16_t size = iter.length();
160 if (addNull) {
161 size += sizeof(char);
162 }
163 result.append(sizeof(char), (size & 0xff));
164 result.append(sizeof(char), (size >> 8));
165 result.append(iter);
166 result.append(sizeof(char), '\0');
167 if (result.length() > UINT16_MAX) {
168 return "";
169 }
170 }
171 return result;
172 }
173
DecomposeStrings(const string & content)174 vector<string> ResourceUtil::DecomposeStrings(const string &content)
175 {
176 vector<string> result;
177 size_t length = content.length();
178 size_t pos = 0;
179 const size_t HEAD_LENGTH = 2;
180 while (pos < length) {
181 if (pos + HEAD_LENGTH >= length) {
182 result.clear();
183 return result;
184 }
185 uint16_t size = (content[pos] & 0xff) | ((content[pos + 1] & 0xff) << 8);
186 pos += HEAD_LENGTH;
187
188 if (pos + size >= length) {
189 result.clear();
190 return result;
191 }
192 string buffer = content.substr(pos, size);
193 result.push_back(buffer);
194 pos += size + sizeof(char);
195 }
196 return result;
197 }
198
GetResTypeFromString(const string & type)199 ResType ResourceUtil::GetResTypeFromString(const string &type)
200 {
201 ResType resType = GetResTypeByDir(type);
202 if (resType != ResType::INVALID_RES_TYPE) {
203 return resType;
204 }
205
206 auto ret = g_contentClusterMap.find(type);
207 if (ret != g_contentClusterMap.end()) {
208 return ret->second;
209 }
210 return ResType::INVALID_RES_TYPE;
211 }
212
CopyFleInner(const string & src,const string & dst)213 bool ResourceUtil::CopyFleInner(const string &src, const string &dst)
214 {
215 return FileEntry::CopyFileInner(src, dst);
216 }
217
CreateDirs(const string & filePath)218 bool ResourceUtil::CreateDirs(const string &filePath)
219 {
220 if (FileExist(filePath)) {
221 return true;
222 }
223
224 if (!FileEntry::CreateDirs(filePath)) {
225 cerr << "Error: create dir '" << filePath << "' failed, reason:" << strerror(errno) << endl;
226 return false;
227 }
228 return true;
229 }
230
IsIgnoreFile(const string & filename,bool isFile)231 bool ResourceUtil::IsIgnoreFile(const string &filename, bool isFile)
232 {
233 string key = filename;
234 transform(key.begin(), key.end(), key.begin(), ::tolower);
235 for (const auto &iter : IGNORE_FILE_REGEX) {
236 if ((iter.second == IgnoreType::IGNORE_FILE && !isFile) ||
237 (iter.second == IgnoreType::IGNORE_DIR && isFile)) {
238 continue;
239 }
240 if (regex_match(key, regex(iter.first))) {
241 return true;
242 }
243 }
244 return false;
245 }
246
NeedConverToSolidXml(ResType resType)247 bool ResourceUtil::NeedConverToSolidXml(ResType resType)
248 {
249 if (resType == ResType::LAYOUT || resType == ResType::ANIMATION ||
250 resType == ResType::GRAPHIC) {
251 return true;
252 }
253 return false;
254 }
255
GenerateHash(const string & key)256 string ResourceUtil::GenerateHash(const string &key)
257 {
258 hash<string> hash_function;
259 return to_string(hash_function(key));
260 }
261
RealPath(const string & path)262 string ResourceUtil::RealPath(const string &path)
263 {
264 return FileEntry::RealPath(path);
265 }
266
IslegalPath(const string & path)267 bool ResourceUtil::IslegalPath(const string &path)
268 {
269 return path == "element" || path == "media" || path == "profile";
270 }
271
StringReplace(string & sourceStr,const string & oldStr,const string & newStr)272 void ResourceUtil::StringReplace(string &sourceStr, const string &oldStr, const string &newStr)
273 {
274 string::size_type pos = 0;
275 string::size_type oldSize = oldStr.size();
276 string::size_type newSize = newStr.size();
277 while ((pos = sourceStr.find(oldStr, pos)) != string::npos) {
278 sourceStr.replace(pos, oldSize, newStr.c_str());
279 pos += newSize;
280 }
281 }
282
GetLocaleLimitkey(const KeyParam & KeyParam)283 string ResourceUtil::GetLocaleLimitkey(const KeyParam &KeyParam)
284 {
285 string str(reinterpret_cast<const char *>(&KeyParam.value));
286 reverse(str.begin(), str.end());
287 return str;
288 }
289
GetDeviceTypeLimitkey(const KeyParam & KeyParam)290 string ResourceUtil::GetDeviceTypeLimitkey(const KeyParam &KeyParam)
291 {
292 auto ret = find_if(g_deviceMap.begin(), g_deviceMap.end(), [KeyParam](const auto &iter) {
293 return KeyParam.value == static_cast<const uint32_t>(iter.second);
294 });
295 if (ret == g_deviceMap.end()) {
296 return string();
297 }
298 return ret->first;
299 }
300
GetResolutionLimitkey(const KeyParam & KeyParam)301 string ResourceUtil::GetResolutionLimitkey(const KeyParam &KeyParam)
302 {
303 auto ret = find_if(g_resolutionMap.begin(), g_resolutionMap.end(), [KeyParam](const auto &iter) {
304 return KeyParam.value == static_cast<const uint32_t>(iter.second);
305 });
306 if (ret == g_resolutionMap.end()) {
307 return string();
308 }
309 return ret->first;
310 }
311
GetKeyParamValue(const KeyParam & KeyParam)312 string ResourceUtil::GetKeyParamValue(const KeyParam &KeyParam)
313 {
314 string val;
315 switch (KeyParam.keyType) {
316 case KeyType::ORIENTATION:
317 val = KeyParam.value == static_cast<const uint32_t>(OrientationType::VERTICAL) ? "vertical" : "horizontal";
318 break;
319 case KeyType::NIGHTMODE:
320 val = KeyParam.value == static_cast<const uint32_t>(NightMode::DARK) ? "dark" : "light";
321 break;
322 case KeyType::DEVICETYPE:
323 val = GetDeviceTypeLimitkey(KeyParam);
324 break;
325 case KeyType::RESOLUTION:
326 val = GetResolutionLimitkey(KeyParam);
327 break;
328 case KeyType::LANGUAGE:
329 case KeyType::REGION:
330 val = GetLocaleLimitkey(KeyParam);
331 break;
332 default:
333 val = to_string(KeyParam.value);
334 break;
335 }
336 return val;
337 }
338
PaserKeyParam(const vector<KeyParam> & keyParams)339 string ResourceUtil::PaserKeyParam(const vector<KeyParam> &keyParams)
340 {
341 if (keyParams.size() == 0) {
342 return "base";
343 }
344 string result;
345 for (const auto &keyparam : keyParams) {
346 string limitKey = GetKeyParamValue(keyparam);
347 if (limitKey.empty()) {
348 continue;
349 }
350 if (keyparam.keyType == KeyType::MCC) {
351 limitKey = "mcc" + limitKey;
352 }
353 if (keyparam.keyType == KeyType::MNC) {
354 limitKey = "mnc" + limitKey;
355 }
356 if (keyparam.keyType == KeyType::REGION || keyparam.keyType == KeyType::MNC) {
357 result = result + "_" + limitKey;
358 } else {
359 result = result + "-" + limitKey;
360 }
361 }
362 if (!result.empty()) {
363 result = result.substr(1);
364 }
365 return result;
366 }
367
368 }
369 }
370 }
371