• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2024 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 <mutex>
21 #include <iostream>
22 #include <iomanip>
23 #include <regex>
24 #include <sstream>
25 #include "file_entry.h"
26 #include "restool_errors.h"
27 
28 namespace OHOS {
29 namespace Global {
30 namespace Restool {
31 using namespace std;
32 const map<string, IgnoreType> ResourceUtil::DEFAULT_IGNORE_FILE_REGEX = {
33     { "\\.git", IgnoreType::IGNORE_ALL },
34     { "\\.svn", IgnoreType::IGNORE_ALL },
35     { ".+\\.scc", IgnoreType::IGNORE_ALL },
36     { "\\.ds_store", IgnoreType::IGNORE_ALL },
37     { "desktop\\.ini", IgnoreType::IGNORE_ALL },
38     { "picasa\\.ini", IgnoreType::IGNORE_ALL },
39     { "\\..+", IgnoreType::IGNORE_ALL },
40     { "cvs", IgnoreType::IGNORE_ALL },
41     { "thumbs\\.db", IgnoreType::IGNORE_ALL },
42     { ".+~", IgnoreType::IGNORE_ALL }
43 };
44 static std::map<std::string, IgnoreType> g_userIgnoreFileRegex;
45 static bool g_isUseCustomRegex = false;
46 
47 static std::mutex fileMutex_;
48 
Split(const string & str,vector<string> & out,const string & splitter)49 void ResourceUtil::Split(const string &str, vector<string> &out, const string &splitter)
50 {
51     string::size_type len = str.size();
52     string::size_type begin = 0;
53     string::size_type end = str.find(splitter, begin);
54     while (end != string::npos) {
55         string sub = str.substr(begin, end - begin);
56         out.push_back(sub);
57         begin = end + splitter.size();
58         if (begin >= len) {
59             break;
60         }
61         end = str.find(splitter, begin);
62     }
63 
64     if (begin < len) {
65         out.push_back(str.substr(begin));
66     }
67 }
68 
FileExist(const string & path)69 bool ResourceUtil::FileExist(const string &path)
70 {
71     return FileEntry::Exist(path);
72 }
73 
RmoveAllDir(const string & path)74 bool ResourceUtil::RmoveAllDir(const string &path)
75 {
76     return FileEntry::RemoveAllDir(path);
77 }
78 
RmoveFile(const string & path)79 bool ResourceUtil::RmoveFile(const string &path)
80 {
81     return FileEntry::RemoveFile(path);
82 }
83 
OpenJsonFile(const string & path,cJSON ** root,const bool & printError)84 bool ResourceUtil::OpenJsonFile(const string &path, cJSON **root, const bool &printError)
85 {
86     ifstream ifs(FileEntry::AdaptLongPath(path), ios::binary);
87     if (!ifs.is_open()) {
88         if (printError) {
89             PrintError(GetError(ERR_CODE_OPEN_JSON_FAIL).FormatCause(path.c_str(), strerror(errno)));
90         }
91         return false;
92     }
93 
94     string jsonString((istreambuf_iterator<char>(ifs)), istreambuf_iterator<char>());
95     *root = cJSON_Parse(jsonString.c_str());
96     if (!*root) {
97         if (printError) {
98             PrintError(GetError(ERR_CODE_JSON_FORMAT_ERROR).SetPosition(path));
99         }
100         ifs.close();
101         return false;
102     }
103     ifs.close();
104     return true;
105 }
106 
SaveToJsonFile(const string & path,const cJSON * root)107 bool ResourceUtil::SaveToJsonFile(const string &path, const cJSON *root)
108 {
109     ofstream out(FileEntry::AdaptLongPath(path), ofstream::out | ofstream::binary);
110     if (!out.is_open()) {
111         PrintError(GetError(ERR_CODE_OPEN_FILE_ERROR).FormatCause(path.c_str(), strerror(errno)));
112         return false;
113     }
114     char *jsonString = cJSON_Print(root);
115     out << jsonString;
116     free(jsonString);
117 
118     out.close();
119     return true;
120 }
121 
GetResTypeByDir(const string & name)122 ResType ResourceUtil::GetResTypeByDir(const string &name)
123 {
124     auto ret = g_fileClusterMap.find(name);
125     if (ret == g_fileClusterMap.end()) {
126         return ResType::INVALID_RES_TYPE;
127     }
128     return ret->second;
129 }
130 
GetAllResTypeDirs()131 string ResourceUtil::GetAllResTypeDirs()
132 {
133     string dirs = "[";
134     for (auto iter = g_fileClusterMap.begin(); iter != g_fileClusterMap.end(); ++iter) {
135         dirs.append("\"").append(iter->first).append("\",");
136     }
137     dirs.pop_back();
138     dirs.append("]");
139     return dirs;
140 }
141 
ResTypeToString(ResType type)142 string ResourceUtil::ResTypeToString(ResType type)
143 {
144     auto ret = find_if(g_fileClusterMap.begin(), g_fileClusterMap.end(), [type](auto iter) {
145         return iter.second == type;
146     });
147     if (ret != g_fileClusterMap.end()) {
148         return ret->first;
149     }
150 
151     ret = find_if(g_contentClusterMap.begin(), g_contentClusterMap.end(), [type](auto iter) {
152         return iter.second == type;
153     });
154     if (ret != g_contentClusterMap.end()) {
155         return ret->first;
156     }
157     return "";
158 }
159 
GetIdName(const string & name,ResType type)160 string ResourceUtil::GetIdName(const string &name, ResType type)
161 {
162     if (type != ResType::MEDIA && type != ResType::PROF) {
163         return name;
164     }
165 
166     string::size_type pos = name.find_last_of(".");
167     if (pos != string::npos) {
168         return name.substr(0, pos);
169     }
170     return name;
171 }
172 
ComposeStrings(const vector<string> & contents,bool addNull)173 string ResourceUtil::ComposeStrings(const vector<string> &contents, bool addNull)
174 {
175     string result;
176     for (const auto &iter : contents) {
177         if (iter.length() > UINT16_MAX) {
178             return "";
179         }
180 
181         uint16_t size = iter.length();
182         if (addNull) {
183             size += sizeof(char);
184         }
185         result.append(sizeof(char), (size & 0xff));
186         result.append(sizeof(char), (size >> 8)); // Move 8 bits to the right
187         result.append(iter);
188         result.append(sizeof(char), '\0');
189         if (result.length() > UINT16_MAX) {
190             return "";
191         }
192     }
193     return result;
194 }
195 
DecomposeStrings(const string & content)196 vector<string> ResourceUtil::DecomposeStrings(const string &content)
197 {
198     vector<string> result;
199     size_t length = content.length();
200     size_t pos = 0;
201     const size_t HEAD_LENGTH = 2;
202     while (pos < length) {
203         if (pos + HEAD_LENGTH >= length) {
204             result.clear();
205             return result;
206         }
207         uint16_t size = (content[pos] & 0xff) | ((content[pos + 1] & 0xff) << 8); // Move 8 bits to the left
208         pos += HEAD_LENGTH;
209 
210         if (pos + size >= length) {
211             result.clear();
212             return result;
213         }
214         string buffer = content.substr(pos, size);
215         result.push_back(buffer);
216         pos += size + sizeof(char);
217     }
218     return result;
219 }
220 
GetResTypeFromString(const string & type)221 ResType ResourceUtil::GetResTypeFromString(const string &type)
222 {
223     ResType resType = GetResTypeByDir(type);
224     if (resType != ResType::INVALID_RES_TYPE) {
225         return resType;
226     }
227 
228     auto ret = g_contentClusterMap.find(type);
229     if (ret != g_contentClusterMap.end()) {
230         return ret->second;
231     }
232     return ResType::INVALID_RES_TYPE;
233 }
234 
CopyFileInner(const string & src,const string & dst)235 bool ResourceUtil::CopyFileInner(const string &src, const string &dst)
236 {
237     return FileEntry::CopyFileInner(src, dst);
238 }
239 
CreateDirs(const string & filePath)240 bool ResourceUtil::CreateDirs(const string &filePath)
241 {
242     std::lock_guard<std::mutex> lock(fileMutex_);
243     if (FileExist(filePath)) {
244         return true;
245     }
246 
247     if (!FileEntry::CreateDirs(filePath)) {
248         PrintError(GetError(ERR_CODE_CREATE_FILE_ERROR).FormatCause(filePath.c_str(), strerror(errno)));
249         return false;
250     }
251     return true;
252 }
253 
IsIgnoreFile(const string & filename,bool isFile)254 bool ResourceUtil::IsIgnoreFile(const string &filename, bool isFile)
255 {
256     map<string, IgnoreType> regexs;
257     std::string regexSources;
258     string key = filename;
259     if (g_isUseCustomRegex) {
260         regexs = g_userIgnoreFileRegex;
261         regexSources = "user";
262     } else {
263         regexs = DEFAULT_IGNORE_FILE_REGEX;
264         regexSources = "default";
265         transform(key.begin(), key.end(), key.begin(), ::tolower);
266     }
267     for (const auto &iter : regexs) {
268         if ((iter.second == IgnoreType::IGNORE_FILE && !isFile) ||
269             (iter.second == IgnoreType::IGNORE_DIR && isFile)) {
270             continue;
271         }
272         if (regex_match(key, regex(iter.first))) {
273             cout << "Info: file '" << filename << "' is ignored by " << regexSources << " regular pattern '"
274                  << iter.first << "'." << endl;
275             return true;
276         }
277     }
278     return false;
279 }
280 
GenerateHash(const string & key)281 string ResourceUtil::GenerateHash(const string &key)
282 {
283     hash<string> hash_function;
284     return to_string(hash_function(key));
285 }
286 
RealPath(const string & path)287 string ResourceUtil::RealPath(const string &path)
288 {
289     return FileEntry::RealPath(path);
290 }
291 
IslegalPath(const string & path)292 bool ResourceUtil::IslegalPath(const string &path)
293 {
294     return path == "element" || path == "media" || path == "profile";
295 }
296 
StringReplace(string & sourceStr,const string & oldStr,const string & newStr)297 void ResourceUtil::StringReplace(string &sourceStr, const string &oldStr, const string &newStr)
298 {
299     string::size_type pos = 0;
300     string::size_type oldSize = oldStr.size();
301     string::size_type newSize = newStr.size();
302     while ((pos = sourceStr.find(oldStr, pos)) != string::npos) {
303         sourceStr.replace(pos, oldSize, newStr.c_str());
304         pos += newSize;
305     }
306 }
307 
GetLocaleLimitkey(const KeyParam & KeyParam)308 string ResourceUtil::GetLocaleLimitkey(const KeyParam &KeyParam)
309 {
310     const char *rawValue = reinterpret_cast<const char *>(&KeyParam.value);
311     size_t len = sizeof(KeyParam.value);
312     char tmp[len + 1];
313     int j = 0;
314     for (size_t i = 1; i <= len; i++) {
315         if (*(rawValue + len - i)) {
316             tmp[j++] = *(rawValue + len - i);
317         }
318     }
319     tmp[j] = '\0';
320     return string(tmp);
321 }
322 
GetDeviceTypeLimitkey(const KeyParam & KeyParam)323 string ResourceUtil::GetDeviceTypeLimitkey(const KeyParam &KeyParam)
324 {
325     auto ret = find_if(g_deviceMap.begin(), g_deviceMap.end(), [KeyParam](const auto &iter) {
326         return KeyParam.value == static_cast<const uint32_t>(iter.second);
327     });
328     if (ret == g_deviceMap.end()) {
329         return string();
330     }
331     return ret->first;
332 }
333 
GetResolutionLimitkey(const KeyParam & KeyParam)334 string ResourceUtil::GetResolutionLimitkey(const KeyParam &KeyParam)
335 {
336     auto ret = find_if(g_resolutionMap.begin(), g_resolutionMap.end(), [KeyParam](const auto &iter) {
337         return KeyParam.value == static_cast<const uint32_t>(iter.second);
338     });
339     if (ret == g_resolutionMap.end()) {
340         return string();
341     }
342     return ret->first;
343 }
344 
GetKeyParamValue(const KeyParam & KeyParam)345 string ResourceUtil::GetKeyParamValue(const KeyParam &KeyParam)
346 {
347     string val;
348     switch (KeyParam.keyType) {
349         case KeyType::ORIENTATION:
350             val = KeyParam.value == static_cast<const uint32_t>(OrientationType::VERTICAL) ? "vertical" : "horizontal";
351             break;
352         case KeyType::NIGHTMODE:
353             val = KeyParam.value == static_cast<const uint32_t>(NightMode::DARK) ? "dark" : "light";
354             break;
355         case KeyType::DEVICETYPE:
356             val = GetDeviceTypeLimitkey(KeyParam);
357             break;
358         case KeyType::RESOLUTION:
359             val = GetResolutionLimitkey(KeyParam);
360             break;
361         case KeyType::LANGUAGE:
362         case KeyType::SCRIPT:
363         case KeyType::REGION:
364             val = GetLocaleLimitkey(KeyParam);
365             break;
366         case KeyType::INPUTDEVICE:
367             val = KeyParam.value == static_cast<const uint32_t>(InputDevice::INPUTDEVICE_NOT_SET) ?
368             "not set" : "pointDevice";
369             break;
370         default:
371             val = to_string(KeyParam.value);
372             break;
373     }
374     return val;
375 }
376 
PaserKeyParam(const vector<KeyParam> & keyParams)377 string ResourceUtil::PaserKeyParam(const vector<KeyParam> &keyParams)
378 {
379     if (keyParams.size() == 0) {
380         return "base";
381     }
382     string result;
383     for (const auto &keyparam : keyParams) {
384         string limitKey = GetKeyParamValue(keyparam);
385         if (limitKey.empty()) {
386             continue;
387         }
388         if (keyparam.keyType == KeyType::MCC) {
389             limitKey = "mcc" + limitKey;
390         }
391         if (keyparam.keyType == KeyType::MNC) {
392             limitKey = "mnc" + limitKey;
393         }
394         if (keyparam.keyType == KeyType::REGION || keyparam.keyType == KeyType::MNC) {
395             result = result + "_" + limitKey;
396         } else {
397             result = result + "-" + limitKey;
398         }
399     }
400     if (!result.empty()) {
401         result = result.substr(1);
402     }
403     return result;
404 }
405 
DecToHexStr(const uint32_t i)406 string ResourceUtil::DecToHexStr(const uint32_t i)
407 {
408     stringstream ot;
409     string result;
410     ot << setiosflags(ios::uppercase) << "0x" << hex << setw(8) << setfill('0') << i; // 0x expadding 8 bit
411     ot >> result;
412     return result;
413 }
414 
CheckHexStr(const string & hex)415 bool ResourceUtil::CheckHexStr(const string &hex)
416 {
417     if (regex_match(hex, regex("^0[xX][0-9a-fA-F]{8}"))) {
418         return true;
419     }
420     return false;
421 }
422 
GetAllRestypeString()423 string ResourceUtil::GetAllRestypeString()
424 {
425     string result = "[";
426     for (auto iter = g_contentClusterMap.begin(); iter != g_contentClusterMap.end(); ++iter) {
427         result.append("\"").append(iter->first).append("\"").append(",");
428     }
429     result.pop_back();
430     result.append("]");
431     return result;
432 }
433 
GetBaseElementPath(const string input)434 FileEntry::FilePath ResourceUtil::GetBaseElementPath(const string input)
435 {
436     return FileEntry::FilePath(input).Append("base").Append("element");
437 }
438 
GetMainPath(const string input)439 FileEntry::FilePath ResourceUtil::GetMainPath(const string input)
440 {
441     return FileEntry::FilePath(input).GetParent();
442 }
443 
GetNormalSize(const vector<KeyParam> & keyParams,uint32_t index)444 uint32_t ResourceUtil::GetNormalSize(const vector<KeyParam> &keyParams, uint32_t index)
445 {
446     string device;
447     string dpi;
448     if (keyParams.size() == 0) {
449         device = "phone";
450         dpi = "sdpi";
451     }
452     for (const auto &keyparam : keyParams) {
453         string limitKey = GetKeyParamValue(keyparam);
454         if (limitKey.empty()) {
455             continue;
456         }
457         if (keyparam.keyType == KeyType::DEVICETYPE) {
458             device = limitKey;
459         } else if (keyparam.keyType == KeyType::RESOLUTION) {
460             dpi = limitKey;
461         }
462     }
463     if (device.empty()) {
464         device = "phone";
465     }
466     if (dpi.empty()) {
467         dpi = "sdpi";
468     }
469     if (device != "phone" && device != "tablet") {
470         return 0;
471     }
472     return g_normalIconMap.find(dpi + "-" + device)->second[index];
473 }
474 
isUnicodeInPlane15or16(int unicode)475 bool ResourceUtil::isUnicodeInPlane15or16(int unicode)
476 {
477     return (unicode >= 0xF0000 && unicode <= 0xFFFFF) || (unicode >= 0x100000 && unicode <= 0x10FFFF);
478 }
479 
RemoveSpaces(string & str)480 void ResourceUtil::RemoveSpaces(string &str)
481 {
482     str.erase(0, str.find_first_not_of(" "));
483     str.erase(str.find_last_not_of(" ") + 1); // move back one place
484 }
485 
IsIntValue(const cJSON * node)486 bool ResourceUtil::IsIntValue(const cJSON *node)
487 {
488     if (node && cJSON_IsNumber(node)) {
489         double num = node->valuedouble;
490         if (num == static_cast<int>(num)) {
491             return true;
492         } else {
493             return false;
494         }
495     }
496     return false;
497 }
498 
IsValidName(const string & name)499 bool ResourceUtil::IsValidName(const string &name)
500 {
501     if (!regex_match(name, regex("[a-zA-Z0-9_]+"))) {
502         return false;
503     }
504     return true;
505 }
506 
PrintWarningMsg(vector<pair<ResType,string>> & noBaseResource)507 void ResourceUtil::PrintWarningMsg(vector<pair<ResType, string>> &noBaseResource)
508 {
509     for (const auto &item : noBaseResource) {
510         cerr << "Warning: the " << ResourceUtil::ResTypeToString(item.first);
511         cerr << " of '" << item.second << "' does not have a base resource." << endl;
512     }
513 }
514 
KeyTypeToStr(KeyType type)515 string ResourceUtil::KeyTypeToStr(KeyType type)
516 {
517     string ret("unknown type: ");
518     auto it = g_keyTypeToStrMap.find(type);
519     if (it != g_keyTypeToStrMap.end()) {
520         ret = it->second;
521     } else {
522         ret += to_string(static_cast<uint32_t>(type));
523     }
524     return ret;
525 }
526 
AddIgnoreFileRegex(const std::string & regex,IgnoreType ignoreType)527 bool ResourceUtil::AddIgnoreFileRegex(const std::string &regex, IgnoreType ignoreType)
528 {
529     try {
530         std::regex rg(regex);
531     } catch (std::regex_error err) {
532         PrintError(GetError(ERR_CODE_INVALID_IGNORE_FILE).FormatCause(regex.c_str(), err.what()));
533         return false;
534     }
535     g_userIgnoreFileRegex[regex] = ignoreType;
536     return true;
537 }
538 
SetUseCustomIgnoreRegex(const bool & isUseCustomRegex)539 void ResourceUtil::SetUseCustomIgnoreRegex(const bool &isUseCustomRegex)
540 {
541     g_isUseCustomRegex = isUseCustomRegex;
542 }
543 }
544 }
545 }
546