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 <cstdlib>
19 #include <fstream>
20 #include <iostream>
21 #include <iomanip>
22 #include <regex>
23 #include "file_entry.h"
24
25 namespace OHOS {
26 namespace Global {
27 namespace Restool {
28 using namespace std;
29 const map<string, ResourceUtil::IgnoreType> ResourceUtil::IGNORE_FILE_REGEX = {
30 { "\\.git", IgnoreType::IGNORE_ALL },
31 { "\\.svn", IgnoreType::IGNORE_ALL },
32 { ".+\\.scc", IgnoreType::IGNORE_ALL },
33 { "\\.ds_store", IgnoreType::IGNORE_ALL },
34 { "desktop\\.ini", IgnoreType::IGNORE_ALL },
35 { "picasa\\.ini", IgnoreType::IGNORE_ALL },
36 { "\\..+", IgnoreType::IGNORE_ALL },
37 { "_.+", IgnoreType::IGNORE_DIR },
38 { "cvs", IgnoreType::IGNORE_ALL },
39 { "thumbs\\.db", IgnoreType::IGNORE_ALL },
40 { ".+~", IgnoreType::IGNORE_ALL }
41 };
42
Split(const string & str,vector<string> & out,const string & splitter)43 void ResourceUtil::Split(const string &str, vector<string> &out, const string &splitter)
44 {
45 string::size_type len = str.size();
46 string::size_type begin = 0;
47 string::size_type end = str.find(splitter, begin);
48 while (end != string::npos) {
49 string sub = str.substr(begin, end - begin);
50 out.push_back(sub);
51 begin = end + splitter.size();
52 if (begin >= len) {
53 break;
54 }
55 end = str.find(splitter, begin);
56 }
57
58 if (begin < len) {
59 out.push_back(str.substr(begin));
60 }
61 }
62
FileExist(const string & path)63 bool ResourceUtil::FileExist(const string &path)
64 {
65 return FileEntry::Exist(path);
66 }
67
RmoveAllDir(const string & path)68 bool ResourceUtil::RmoveAllDir(const string &path)
69 {
70 return FileEntry::RemoveAllDir(path);
71 }
72
OpenJsonFile(const string & path,Json::Value & root)73 bool ResourceUtil::OpenJsonFile(const string &path, Json::Value &root)
74 {
75 ifstream ifs(FileEntry::AdaptLongPath(path), ios::binary);
76 if (!ifs.is_open()) {
77 cerr << "Error: open json failed '" << path << "', reason: " << strerror(errno) << endl;
78 return false;
79 }
80
81 Json::CharReaderBuilder readBuilder;
82 readBuilder["collectComments"] = false;
83 readBuilder["failIfExtra"] = true;
84 JSONCPP_STRING errs;
85 if (!parseFromStream(readBuilder, ifs, &root, &errs)) {
86 cerr << "Error: parseFromStream failed." << NEW_LINE_PATH << path;
87 cerr << "\n" << errs << endl;
88 ifs.close();
89 return false;
90 }
91 ifs.close();
92 return true;
93 }
94
SaveToJsonFile(const string & path,const Json::Value & root)95 bool ResourceUtil::SaveToJsonFile(const string &path, const Json::Value &root)
96 {
97 Json::StreamWriterBuilder writerBuilder;
98 writerBuilder["indentation"] = " ";
99 writerBuilder["emitUTF8"] = true;
100 unique_ptr<Json::StreamWriter> writer(writerBuilder.newStreamWriter());
101 ofstream out(FileEntry::AdaptLongPath(path), ofstream::out | ofstream::binary);
102 if (!out.is_open()) {
103 cerr << "Error: open failed '" << path <<"', reason: " << strerror(errno) << endl;
104 return false;
105 }
106 writer->write(root, &out);
107 out.close();
108 return true;
109 }
110
GetResTypeByDir(const string & name)111 ResType ResourceUtil::GetResTypeByDir(const string &name)
112 {
113 auto ret = g_fileClusterMap.find(name);
114 if (ret == g_fileClusterMap.end()) {
115 return ResType::INVALID_RES_TYPE;
116 }
117 return ret->second;
118 }
119
ResTypeToString(ResType type)120 string ResourceUtil::ResTypeToString(ResType type)
121 {
122 auto ret = find_if(g_fileClusterMap.begin(), g_fileClusterMap.end(), [type](auto iter) {
123 return iter.second == type;
124 });
125 if (ret != g_fileClusterMap.end()) {
126 return ret->first;
127 }
128
129 ret = find_if(g_contentClusterMap.begin(), g_contentClusterMap.end(), [type](auto iter) {
130 return iter.second == type;
131 });
132 if (ret != g_contentClusterMap.end()) {
133 return ret->first;
134 }
135 return "";
136 }
137
GetIdName(const string & name,ResType type)138 string ResourceUtil::GetIdName(const string &name, ResType type)
139 {
140 if (type != ResType::MEDIA && type != ResType::PROF) {
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)); // Move 8 bits to the right
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
GenerateHash(const string & key)247 string ResourceUtil::GenerateHash(const string &key)
248 {
249 hash<string> hash_function;
250 return to_string(hash_function(key));
251 }
252
RealPath(const string & path)253 string ResourceUtil::RealPath(const string &path)
254 {
255 return FileEntry::RealPath(path);
256 }
257
IslegalPath(const string & path)258 bool ResourceUtil::IslegalPath(const string &path)
259 {
260 return path == "element" || path == "media" || path == "profile";
261 }
262
StringReplace(string & sourceStr,const string & oldStr,const string & newStr)263 void ResourceUtil::StringReplace(string &sourceStr, const string &oldStr, const string &newStr)
264 {
265 string::size_type pos = 0;
266 string::size_type oldSize = oldStr.size();
267 string::size_type newSize = newStr.size();
268 while ((pos = sourceStr.find(oldStr, pos)) != string::npos) {
269 sourceStr.replace(pos, oldSize, newStr.c_str());
270 pos += newSize;
271 }
272 }
273
GetLocaleLimitkey(const KeyParam & KeyParam)274 string ResourceUtil::GetLocaleLimitkey(const KeyParam &KeyParam)
275 {
276 string str(reinterpret_cast<const char *>(&KeyParam.value));
277 reverse(str.begin(), str.end());
278 return str;
279 }
280
GetDeviceTypeLimitkey(const KeyParam & KeyParam)281 string ResourceUtil::GetDeviceTypeLimitkey(const KeyParam &KeyParam)
282 {
283 auto ret = find_if(g_deviceMap.begin(), g_deviceMap.end(), [KeyParam](const auto &iter) {
284 return KeyParam.value == static_cast<const uint32_t>(iter.second);
285 });
286 if (ret == g_deviceMap.end()) {
287 return string();
288 }
289 return ret->first;
290 }
291
GetResolutionLimitkey(const KeyParam & KeyParam)292 string ResourceUtil::GetResolutionLimitkey(const KeyParam &KeyParam)
293 {
294 auto ret = find_if(g_resolutionMap.begin(), g_resolutionMap.end(), [KeyParam](const auto &iter) {
295 return KeyParam.value == static_cast<const uint32_t>(iter.second);
296 });
297 if (ret == g_resolutionMap.end()) {
298 return string();
299 }
300 return ret->first;
301 }
302
GetKeyParamValue(const KeyParam & KeyParam)303 string ResourceUtil::GetKeyParamValue(const KeyParam &KeyParam)
304 {
305 string val;
306 switch (KeyParam.keyType) {
307 case KeyType::ORIENTATION:
308 val = KeyParam.value == static_cast<const uint32_t>(OrientationType::VERTICAL) ? "vertical" : "horizontal";
309 break;
310 case KeyType::NIGHTMODE:
311 val = KeyParam.value == static_cast<const uint32_t>(NightMode::DARK) ? "dark" : "light";
312 break;
313 case KeyType::DEVICETYPE:
314 val = GetDeviceTypeLimitkey(KeyParam);
315 break;
316 case KeyType::RESOLUTION:
317 val = GetResolutionLimitkey(KeyParam);
318 break;
319 case KeyType::LANGUAGE:
320 case KeyType::REGION:
321 val = GetLocaleLimitkey(KeyParam);
322 break;
323 default:
324 val = to_string(KeyParam.value);
325 break;
326 }
327 return val;
328 }
329
PaserKeyParam(const vector<KeyParam> & keyParams)330 string ResourceUtil::PaserKeyParam(const vector<KeyParam> &keyParams)
331 {
332 if (keyParams.size() == 0) {
333 return "base";
334 }
335 string result;
336 for (const auto &keyparam : keyParams) {
337 string limitKey = GetKeyParamValue(keyparam);
338 if (limitKey.empty()) {
339 continue;
340 }
341 if (keyparam.keyType == KeyType::MCC) {
342 limitKey = "mcc" + limitKey;
343 }
344 if (keyparam.keyType == KeyType::MNC) {
345 limitKey = "mnc" + limitKey;
346 }
347 if (keyparam.keyType == KeyType::REGION || keyparam.keyType == KeyType::MNC) {
348 result = result + "_" + limitKey;
349 } else {
350 result = result + "-" + limitKey;
351 }
352 }
353 if (!result.empty()) {
354 result = result.substr(1);
355 }
356 return result;
357 }
358
DecToHexStr(const int32_t i)359 string ResourceUtil::DecToHexStr(const int32_t i)
360 {
361 stringstream ot;
362 string result;
363 ot << setiosflags(ios::uppercase) << "0x" << hex << setw(8) << setfill('0') << i; // 0x expadding 8 bit
364 ot >> result;
365 return result;
366 }
367
CheckHexStr(const string & hex)368 bool ResourceUtil::CheckHexStr(const string &hex)
369 {
370 if (regex_match(hex, regex("^0[xX][0-9a-fA-F]{8}"))) {
371 return true;
372 }
373 return false;
374 }
375
GetAllRestypeString()376 string ResourceUtil::GetAllRestypeString()
377 {
378 string result;
379 for (auto iter = g_contentClusterMap.begin(); iter != g_contentClusterMap.end(); ++iter) {
380 result = result + "," + iter->first;
381 }
382 return result;
383 }
384
GetBaseElementPath(const string input)385 FileEntry::FilePath ResourceUtil::GetBaseElementPath(const string input)
386 {
387 return FileEntry::FilePath(input).Append("base").Append("element");
388 }
389
GetMainPath(const string input)390 FileEntry::FilePath ResourceUtil::GetMainPath(const string input)
391 {
392 return FileEntry::FilePath(input).GetParent();
393 }
394
GetNormalSize(const vector<KeyParam> & keyParams,uint32_t index)395 uint32_t ResourceUtil::GetNormalSize(const vector<KeyParam> &keyParams, uint32_t index)
396 {
397 string device;
398 string dpi;
399 if (keyParams.size() == 0) {
400 device = "phone";
401 dpi = "sdpi";
402 }
403 for (const auto &keyparam : keyParams) {
404 string limitKey = GetKeyParamValue(keyparam);
405 if (limitKey.empty()) {
406 continue;
407 }
408 if (keyparam.keyType == KeyType::DEVICETYPE) {
409 device = limitKey;
410 } else if (keyparam.keyType == KeyType::RESOLUTION) {
411 dpi = limitKey;
412 }
413 }
414 if (device.empty()) {
415 device = "phone";
416 }
417 if (dpi.empty()) {
418 dpi = "sdpi";
419 }
420 if (device != "phone" && device != "tablet") {
421 return 0;
422 }
423 return g_normalIconMap.find(dpi + "-" + device)->second[index];
424 }
425
426 }
427 }
428 }
429