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 { "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::AdaptLongPath(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::AdaptLongPath(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::PROF) {
140 return name;
141 }
142
143 string::size_type pos = name.find_last_of(".");
144 if (pos != string::npos) {
145 return name.substr(0, pos);
146 }
147 return name;
148 }
149
ComposeStrings(const vector<string> & contents,bool addNull)150 string ResourceUtil::ComposeStrings(const vector<string> &contents, bool addNull)
151 {
152 string result;
153 for (const auto &iter : contents) {
154 if (iter.length() > UINT16_MAX) {
155 return "";
156 }
157
158 uint16_t size = iter.length();
159 if (addNull) {
160 size += sizeof(char);
161 }
162 result.append(sizeof(char), (size & 0xff));
163 result.append(sizeof(char), (size >> 8)); // Move 8 bits to the right
164 result.append(iter);
165 result.append(sizeof(char), '\0');
166 if (result.length() > UINT16_MAX) {
167 return "";
168 }
169 }
170 return result;
171 }
172
DecomposeStrings(const string & content)173 vector<string> ResourceUtil::DecomposeStrings(const string &content)
174 {
175 vector<string> result;
176 size_t length = content.length();
177 size_t pos = 0;
178 const size_t HEAD_LENGTH = 2;
179 while (pos < length) {
180 if (pos + HEAD_LENGTH >= length) {
181 result.clear();
182 return result;
183 }
184 uint16_t size = (content[pos] & 0xff) | ((content[pos + 1] & 0xff) << 8);
185 pos += HEAD_LENGTH;
186
187 if (pos + size >= length) {
188 result.clear();
189 return result;
190 }
191 string buffer = content.substr(pos, size);
192 result.push_back(buffer);
193 pos += size + sizeof(char);
194 }
195 return result;
196 }
197
GetResTypeFromString(const string & type)198 ResType ResourceUtil::GetResTypeFromString(const string &type)
199 {
200 ResType resType = GetResTypeByDir(type);
201 if (resType != ResType::INVALID_RES_TYPE) {
202 return resType;
203 }
204
205 auto ret = g_contentClusterMap.find(type);
206 if (ret != g_contentClusterMap.end()) {
207 return ret->second;
208 }
209 return ResType::INVALID_RES_TYPE;
210 }
211
CopyFleInner(const string & src,const string & dst)212 bool ResourceUtil::CopyFleInner(const string &src, const string &dst)
213 {
214 return FileEntry::CopyFileInner(src, dst);
215 }
216
CreateDirs(const string & filePath)217 bool ResourceUtil::CreateDirs(const string &filePath)
218 {
219 if (FileExist(filePath)) {
220 return true;
221 }
222
223 if (!FileEntry::CreateDirs(filePath)) {
224 cerr << "Error: create dir '" << filePath << "' failed, reason:" << strerror(errno) << endl;
225 return false;
226 }
227 return true;
228 }
229
IsIgnoreFile(const string & filename,bool isFile)230 bool ResourceUtil::IsIgnoreFile(const string &filename, bool isFile)
231 {
232 string key = filename;
233 transform(key.begin(), key.end(), key.begin(), ::tolower);
234 for (const auto &iter : IGNORE_FILE_REGEX) {
235 if ((iter.second == IgnoreType::IGNORE_FILE && !isFile) ||
236 (iter.second == IgnoreType::IGNORE_DIR && isFile)) {
237 continue;
238 }
239 if (regex_match(key, regex(iter.first))) {
240 return true;
241 }
242 }
243 return false;
244 }
245
GenerateHash(const string & key)246 string ResourceUtil::GenerateHash(const string &key)
247 {
248 hash<string> hash_function;
249 return to_string(hash_function(key));
250 }
251
RealPath(const string & path)252 string ResourceUtil::RealPath(const string &path)
253 {
254 return FileEntry::RealPath(path);
255 }
256
IslegalPath(const string & path)257 bool ResourceUtil::IslegalPath(const string &path)
258 {
259 return path == "element" || path == "media" || path == "profile";
260 }
261
StringReplace(string & sourceStr,const string & oldStr,const string & newStr)262 void ResourceUtil::StringReplace(string &sourceStr, const string &oldStr, const string &newStr)
263 {
264 string::size_type pos = 0;
265 string::size_type oldSize = oldStr.size();
266 string::size_type newSize = newStr.size();
267 while ((pos = sourceStr.find(oldStr, pos)) != string::npos) {
268 sourceStr.replace(pos, oldSize, newStr.c_str());
269 pos += newSize;
270 }
271 }
272
GetLocaleLimitkey(const KeyParam & KeyParam)273 string ResourceUtil::GetLocaleLimitkey(const KeyParam &KeyParam)
274 {
275 string str(reinterpret_cast<const char *>(&KeyParam.value));
276 reverse(str.begin(), str.end());
277 return str;
278 }
279
GetDeviceTypeLimitkey(const KeyParam & KeyParam)280 string ResourceUtil::GetDeviceTypeLimitkey(const KeyParam &KeyParam)
281 {
282 auto ret = find_if(g_deviceMap.begin(), g_deviceMap.end(), [KeyParam](const auto &iter) {
283 return KeyParam.value == static_cast<const uint32_t>(iter.second);
284 });
285 if (ret == g_deviceMap.end()) {
286 return string();
287 }
288 return ret->first;
289 }
290
GetResolutionLimitkey(const KeyParam & KeyParam)291 string ResourceUtil::GetResolutionLimitkey(const KeyParam &KeyParam)
292 {
293 auto ret = find_if(g_resolutionMap.begin(), g_resolutionMap.end(), [KeyParam](const auto &iter) {
294 return KeyParam.value == static_cast<const uint32_t>(iter.second);
295 });
296 if (ret == g_resolutionMap.end()) {
297 return string();
298 }
299 return ret->first;
300 }
301
GetKeyParamValue(const KeyParam & KeyParam)302 string ResourceUtil::GetKeyParamValue(const KeyParam &KeyParam)
303 {
304 string val;
305 switch (KeyParam.keyType) {
306 case KeyType::ORIENTATION:
307 val = KeyParam.value == static_cast<const uint32_t>(OrientationType::VERTICAL) ? "vertical" : "horizontal";
308 break;
309 case KeyType::NIGHTMODE:
310 val = KeyParam.value == static_cast<const uint32_t>(NightMode::DARK) ? "dark" : "light";
311 break;
312 case KeyType::DEVICETYPE:
313 val = GetDeviceTypeLimitkey(KeyParam);
314 break;
315 case KeyType::RESOLUTION:
316 val = GetResolutionLimitkey(KeyParam);
317 break;
318 case KeyType::LANGUAGE:
319 case KeyType::REGION:
320 val = GetLocaleLimitkey(KeyParam);
321 break;
322 default:
323 val = to_string(KeyParam.value);
324 break;
325 }
326 return val;
327 }
328
PaserKeyParam(const vector<KeyParam> & keyParams)329 string ResourceUtil::PaserKeyParam(const vector<KeyParam> &keyParams)
330 {
331 if (keyParams.size() == 0) {
332 return "base";
333 }
334 string result;
335 for (const auto &keyparam : keyParams) {
336 string limitKey = GetKeyParamValue(keyparam);
337 if (limitKey.empty()) {
338 continue;
339 }
340 if (keyparam.keyType == KeyType::MCC) {
341 limitKey = "mcc" + limitKey;
342 }
343 if (keyparam.keyType == KeyType::MNC) {
344 limitKey = "mnc" + limitKey;
345 }
346 if (keyparam.keyType == KeyType::REGION || keyparam.keyType == KeyType::MNC) {
347 result = result + "_" + limitKey;
348 } else {
349 result = result + "-" + limitKey;
350 }
351 }
352 if (!result.empty()) {
353 result = result.substr(1);
354 }
355 return result;
356 }
357
DecToHexStr(const int32_t i)358 string ResourceUtil::DecToHexStr(const int32_t i)
359 {
360 stringstream ot;
361 string result;
362 ot << setiosflags(ios::uppercase) << "0x" << hex << setw(8) << setfill('0') << i; // 0x expadding 8 bit
363 ot >> result;
364 return result;
365 }
366
CheckHexStr(const string & hex)367 bool ResourceUtil::CheckHexStr(const string &hex)
368 {
369 if (regex_match(hex, regex("^0[xX][0-9a-fA-F]{8}"))) {
370 return true;
371 }
372 return false;
373 }
374
GetAllRestypeString()375 string ResourceUtil::GetAllRestypeString()
376 {
377 string result;
378 for (auto iter = g_contentClusterMap.begin(); iter != g_contentClusterMap.end(); ++iter) {
379 result = result + "," + iter->first;
380 }
381 return result;
382 }
383
GetBaseElementPath(const string input)384 FileEntry::FilePath ResourceUtil::GetBaseElementPath(const string input)
385 {
386 return FileEntry::FilePath(input).Append("base").Append("element");
387 }
388
GetMainPath(const string input)389 FileEntry::FilePath ResourceUtil::GetMainPath(const string input)
390 {
391 return FileEntry::FilePath(input).GetParent();
392 }
393
GetNormalSize(const vector<KeyParam> & keyParams,uint32_t index)394 uint32_t ResourceUtil::GetNormalSize(const vector<KeyParam> &keyParams, uint32_t index)
395 {
396 string device;
397 string dpi;
398 if (keyParams.size() == 0) {
399 device = "phone";
400 dpi = "sdpi";
401 }
402 for (const auto &keyparam : keyParams) {
403 string limitKey = GetKeyParamValue(keyparam);
404 if (limitKey.empty()) {
405 continue;
406 }
407 if (keyparam.keyType == KeyType::DEVICETYPE) {
408 device = limitKey;
409 } else if (keyparam.keyType == KeyType::RESOLUTION) {
410 dpi = limitKey;
411 }
412 }
413 if (device.empty()) {
414 device = "phone";
415 }
416 if (dpi.empty()) {
417 dpi = "sdpi";
418 }
419 if (device != "phone" && device != "tablet") {
420 return 0;
421 }
422 return g_normalIconMap.find(dpi + "-" + device)->second[index];
423 }
424
isUnicodeInPlane15or16(int unicode)425 bool ResourceUtil::isUnicodeInPlane15or16(int unicode)
426 {
427 return (unicode >= 0xF0000 && unicode <= 0xFFFFF) || (unicode >= 0x100000 && unicode <= 0x10FFFF);
428 }
429
RemoveSpaces(string & str)430 void ResourceUtil::RemoveSpaces(string &str)
431 {
432 str.erase(0, str.find_first_not_of(" "));
433 str.erase(str.find_last_not_of(" ") + 1); // move back one place
434 }
435
436 }
437 }
438 }
439