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