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