1 /*
2 * Copyright (c) 2024-2025 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 "utils.h"
17
18 #include <algorithm>
19 #include <cmath>
20 #include <cstdlib>
21 #include <cstring>
22 #include <dirent.h>
23 #include <fstream>
24 #include <iomanip>
25 #include <random>
26 #include <sstream>
27 #include <sys/stat.h>
28 #include <sys/types.h>
29 #include <unistd.h>
30 #include <vector>
31
32 #include "log.h"
33 #include "pt_json.h"
34
35 namespace OHOS {
36 namespace AppPackingTool {
37 namespace {
38 const int BUFFER_SIZE = 1024;
39 const int HEX_WIDTH = 2;
40 const char PATH_DELIMITER = '/';
41 const long FILE_LENGTH_1KB = 1024L;
42 const double FILE_SIZE_OFFSET_DOUBLE = 0.01;
43 const int FILE_SIZE_DECIMAL_PRECISION = 2;
44 const int MAX_UUID_LENGTH = 32;
45 const int RANGE_MIN = 0;
46 const int RANGE_MAX = 15;
47 const int TEN = 10;
48 }
49
GetFileContent(const std::string filePath)50 std::string Utils::GetFileContent(const std::string filePath)
51 {
52 std::string realFilePath;
53 if (!Utils::GetRealPath(filePath, realFilePath)) {
54 LOGE("get real file path failed! filePath=%s", filePath.c_str());
55 return nullptr;
56 }
57 std::ifstream inFile(realFilePath, std::ios::in);
58 if (!inFile.is_open()) {
59 LOGE("open file path failed![filePath=%s][realFilePath=%s]", filePath.c_str(), realFilePath.c_str());
60 return nullptr;
61 }
62 std::string fileContent((std::istreambuf_iterator<char>(inFile)), std::istreambuf_iterator<char>());
63 inFile.close();
64 return fileContent;
65 }
66
ListToString(const std::list<std::string> & lst)67 std::string Utils::ListToString(const std::list<std::string>& lst)
68 {
69 std::stringstream ss;
70 for (auto str : lst) {
71 ss << str;
72 }
73 return ss.str();
74 }
75
CopyListToSet(const std::list<std::string> & lst,std::set<std::string> & st)76 void Utils::CopyListToSet(const std::list<std::string>& lst, std::set<std::string>& st)
77 {
78 for (auto& em : lst) {
79 st.insert(em);
80 }
81 }
82
ReplaceAll(std::string str,const std::string & from,const std::string & to)83 std::string Utils::ReplaceAll(std::string str, const std::string& from, const std::string& to)
84 {
85 size_t startPos = 0;
86 while ((startPos = str.find(from, startPos)) != std::string::npos) {
87 str.replace(startPos, from.length(), to);
88 startPos += to.length();
89 }
90 return str;
91 }
92
GetFileLength(const std::string filePath)93 int64_t Utils::GetFileLength(const std::string filePath)
94 {
95 struct stat statbuf = { 0 };
96 if (stat(filePath.c_str(), &statbuf) != 0) {
97 LOGE("file stat failed! filePath=%s", filePath.c_str());
98 return -1;
99 }
100 return statbuf.st_size;
101 }
102
EndsWith(const std::string & str,const std::string & suffix)103 bool Utils::EndsWith(const std::string& str, const std::string& suffix)
104 {
105 if (str.size() >= suffix.size() && std::equal(suffix.rbegin(), suffix.rend(), str.rbegin())) {
106 return true;
107 }
108 return false;
109 }
110
111 // If there is no same element then returns true, else then returns false
CheckDisjoint(const std::list<std::string> & list1,const std::list<std::string> & list2)112 bool Utils::CheckDisjoint(const std::list<std::string>& list1, const std::list<std::string>& list2)
113 {
114 for (const std::string& str1 : list1) {
115 for (const std::string& str2 : list2) {
116 if (str1.compare(str2) == 0) {
117 return false;
118 }
119 }
120 }
121 return true;
122 }
123
124 // If list1 contains all elements in list2, returns true, else returns false
CheckContainsAll(const std::list<std::string> & list1,const std::list<std::string> & list2)125 bool Utils::CheckContainsAll(const std::list<std::string>& list1, const std::list<std::string>& list2)
126 {
127 bool isFind = false;
128 for (const std::string& str2 : list2) {
129 isFind = false;
130 for (const std::string& str1 : list1) {
131 if (str2.compare(str1) == 0) {
132 isFind = true;
133 break;
134 }
135 }
136 if (!isFind) {
137 return false;
138 }
139 }
140 return true;
141 }
142
CheckListContain(const std::list<std::string> & lst,const std::string & value)143 bool Utils::CheckListContain(const std::list<std::string>& lst, const std::string& value)
144 {
145 return std::find(lst.begin(), lst.end(), value) != lst.end();
146 }
147
GetListDistinctCount(const std::list<std::string> & lst)148 long Utils::GetListDistinctCount(const std::list<std::string>& lst)
149 {
150 std::set<std::string> st;
151 std::copy(lst.begin(), lst.end(), std::inserter(st, st.end()));
152 return st.size();
153 }
154
GetSha256Str(const std::string & str)155 std::string Utils::GetSha256Str(const std::string &str)
156 {
157 unsigned char hash[SHA256_DIGEST_LENGTH];
158 SHA256_CTX ctx;
159 SHA256_Init(&ctx);
160 SHA256_Update(&ctx, str.c_str(), str.length());
161 SHA256_Final(hash, &ctx);
162
163 // Convert hash to hex string
164 std::stringstream ss;
165 for (int i = 0; i < SHA256_DIGEST_LENGTH; ++i) {
166 ss << std::hex << std::setw(HEX_WIDTH) << std::setfill('0') << static_cast<uint32_t>(hash[i]);
167 }
168 return ss.str();
169 }
170
GetSha256File(const std::string & filePath)171 std::string Utils::GetSha256File(const std::string &filePath)
172 {
173 std::string realFilePath;
174 if (!GetRealPath(filePath, realFilePath)) {
175 LOGE("get real file path failed! jsonFile=%s", filePath.c_str());
176 return "";
177 }
178 std::ifstream file(realFilePath, std::ios::binary);
179 if (!file) {
180 return "";
181 }
182 SHA256_CTX ctx;
183 SHA256_Init(&ctx);
184 std::vector<char> buffer(BUFFER_SIZE);
185 while (!file.eof()) {
186 file.read(buffer.data(), BUFFER_SIZE);
187 SHA256_Update(&ctx, buffer.data(), file.gcount());
188 }
189 unsigned char hash[SHA256_DIGEST_LENGTH];
190 SHA256_Final(hash, &ctx);
191
192 // Convert hash to hex string
193 std::stringstream ss;
194 for (int i = 0; i < SHA256_DIGEST_LENGTH; ++i) {
195 ss << std::hex << std::setw(HEX_WIDTH) << std::setfill('0') << static_cast<uint32_t>(hash[i]);
196 }
197 return ss.str();
198 }
199
GetSha256Folder(const std::string & filePath)200 std::string Utils::GetSha256Folder(const std::string &filePath)
201 {
202 SHA256_CTX ctx;
203 SHA256_Init(&ctx);
204 for (const auto& entry : fs::recursive_directory_iterator(filePath)) {
205 if (fs::is_regular_file(entry)) {
206 std::ifstream file(entry, std::ios::binary);
207 if (!file.is_open()) {
208 LOGE("file open failed! filePath=%s", entry.path().string().c_str());
209 return "";
210 }
211 std::vector<char> buffer((std::istreambuf_iterator<char>(file)),
212 std::istreambuf_iterator<char>());
213 SHA256_Update(&ctx, buffer.data(), buffer.size());
214 }
215 }
216 unsigned char hash[SHA256_DIGEST_LENGTH];
217 SHA256_Final(hash, &ctx);
218
219 // Convert hash to hex string
220 std::stringstream ss;
221 for (int i = 0; i < SHA256_DIGEST_LENGTH; ++i) {
222 ss << std::hex << std::setw(HEX_WIDTH) << std::setfill('0') << static_cast<uint32_t>(hash[i]);
223 }
224 return ss.str();
225 }
226
IsFileExists(const std::string & file)227 bool Utils::IsFileExists(const std::string& file)
228 {
229 return access(file.c_str(), F_OK) == 0;
230 }
231
IsFile(const std::string & file)232 bool Utils::IsFile(const std::string& file)
233 {
234 struct stat statBuf {};
235 return lstat(file.c_str(), &statBuf) == 0 ? S_ISREG(statBuf.st_mode) : false;
236 }
237
IsDirectory(const std::string & dir)238 bool Utils::IsDirectory(const std::string& dir)
239 {
240 struct stat statBuf {};
241 return lstat(dir.c_str(), &statBuf) == 0 ? S_ISDIR(statBuf.st_mode) : false;
242 }
243
RemoveFile(const std::string & file)244 bool Utils::RemoveFile(const std::string& file)
245 {
246 return !IsFileExists(file) || (remove(file.c_str()) == 0);
247 }
248
RemoveDirectory(const std::string & dir)249 bool Utils::RemoveDirectory(const std::string& dir)
250 {
251 return !IsFileExists(dir) || (rmdir(dir.c_str()) == 0);
252 }
253
GetFilePathByDir(const std::string & dir,const std::string & fileName)254 std::string Utils::GetFilePathByDir(const std::string& dir, const std::string& fileName)
255 {
256 if (dir.empty()) {
257 return fileName;
258 }
259 std::string filePath = dir;
260 if (filePath.back() != '/') {
261 filePath.push_back(PATH_DELIMITER);
262 }
263 filePath.append(fileName);
264 return filePath;
265 }
266
ForceCreateDirectory(const std::string & dir)267 bool Utils::ForceCreateDirectory(const std::string& dir)
268 {
269 std::string::size_type index = 0;
270 do {
271 std::string subPath;
272 index = dir.find('/', index + 1); // (index + 1) means the next char traversed
273 if (index == std::string::npos) {
274 subPath = dir;
275 } else {
276 subPath = dir.substr(0, index);
277 }
278
279 if (!IsFileExists(subPath) && mkdir(subPath.c_str(), S_IRWXU) != 0) {
280 return false;
281 }
282 } while (index != std::string::npos);
283 return IsFileExists(dir);
284 }
285
ForceRemoveDirectory(const std::string & dir,bool isDeleteSelf)286 bool Utils::ForceRemoveDirectory(const std::string& dir, bool isDeleteSelf)
287 {
288 if (IsFile(dir)) {
289 return RemoveFile(dir);
290 } else if (IsDirectory(dir)) {
291 DIR* dirPtr = opendir(dir.c_str());
292 if (dirPtr == nullptr) {
293 return false;
294 }
295 struct dirent* dirInfo = nullptr;
296 while ((dirInfo = readdir(dirPtr)) != nullptr) {
297 // do not process the special dir
298 if (strcmp(dirInfo->d_name, ".") == 0 || strcmp(dirInfo->d_name, "..") == 0) {
299 continue;
300 }
301 std::string filePath = GetFilePathByDir(dir, dirInfo->d_name);
302 if (!ForceRemoveDirectory(filePath)) {
303 closedir(dirPtr);
304 return false;
305 }
306 }
307 closedir(dirPtr);
308 if (isDeleteSelf && !RemoveDirectory(dir)) {
309 return false;
310 }
311 } else {
312 return false;
313 }
314 return true;
315 }
316
GetCeilFileSize(long fileSize,int sizeLimit)317 double Utils::GetCeilFileSize(long fileSize, int sizeLimit)
318 {
319 double threshold = static_cast<double>(sizeLimit) + FILE_SIZE_OFFSET_DOUBLE;
320 double size = static_cast<double>(fileSize) / FILE_LENGTH_1KB;
321 size = std::round(size * std::pow(TEN, FILE_SIZE_DECIMAL_PRECISION)) / std::pow(TEN, FILE_SIZE_DECIMAL_PRECISION);
322 if (size < threshold && size >= sizeLimit) {
323 size = threshold;
324 }
325 return size;
326 }
327
IsPositiveInteger(const std::string & str,int min,int max)328 bool Utils::IsPositiveInteger(const std::string& str, int min, int max)
329 {
330 if (str.empty()) {
331 return false;
332 }
333 for (char c : str) {
334 if (!std::isdigit(c)) {
335 return false;
336 }
337 }
338 try {
339 int number = std::stoi(str);
340 return number >= min && number <= max;
341 } catch (const std::out_of_range& e) {
342 LOGE("Number %s is Out of Range!", str.c_str());
343 return false;
344 }
345 return true;
346 }
347
StringToBool(const std::string & str)348 bool Utils::StringToBool(const std::string& str)
349 {
350 std::string lowerStr = str;
351 std::transform(lowerStr.begin(), lowerStr.end(), lowerStr.begin(), ::tolower);
352 if (lowerStr == "true") {
353 return true;
354 }
355 return false;
356 }
357
StringToArray(const std::string & str,std::list<std::string> & array)358 bool Utils::StringToArray(const std::string& str, std::list<std::string>& array)
359 {
360 array.clear();
361 std::istringstream iss(str);
362 std::string item;
363
364 while (std::getline(iss, item, ',')) {
365 array.push_back(item);
366 }
367 return true;
368 }
369
CheckFileName(const std::string & filePath,const std::string & fileName)370 bool Utils::CheckFileName(const std::string& filePath, const std::string& fileName)
371 {
372 fs::path fsFilePath(filePath);
373 if (fs::is_regular_file(fsFilePath) && fsFilePath.filename().compare(fileName) == 0) {
374 return true;
375 }
376 return false;
377 }
378
CheckFileSuffix(const std::string & filePath,const std::string & suffix)379 bool Utils::CheckFileSuffix(const std::string& filePath, const std::string& suffix)
380 {
381 fs::path fsFilePath(filePath);
382 if (fs::is_regular_file(fsFilePath) && EndsWith(fsFilePath.filename(), suffix)) {
383 return true;
384 }
385 return false;
386 }
387
GenerateUUID()388 std::string Utils::GenerateUUID()
389 {
390 static const char* hexDigits = "0123456789abcdef";
391 std::random_device rd;
392 std::mt19937 gen(rd());
393 std::uniform_int_distribution<> dis(RANGE_MIN, RANGE_MAX);
394
395 std::stringstream ss;
396 std::vector<int> format = {8, 4, 4, 4, 12};
397 int flag = 1;
398 for (int i = 0; i < MAX_UUID_LENGTH; ++i) {
399 ss << hexDigits[dis(gen)];
400 if ((i + 1) == format[0] && i != MAX_UUID_LENGTH - 1) {
401 ss << "-";
402 format[0] += format[flag];
403 flag++;
404 }
405 }
406 return ss.str();
407 }
408
CopyFile(const std::string & srcPath,const std::string & dstPath)409 bool Utils::CopyFile(const std::string& srcPath, const std::string& dstPath)
410 {
411 std::string realSrcPath;
412 std::string realDstPath;
413 if (!GetRealPath(srcPath, realSrcPath)) {
414 LOGE("get real src path failed! srcPath=%s", srcPath.c_str());
415 return false;
416 }
417 fs::path fsDstPath(dstPath);
418 std::string parentOfDstPath = fsDstPath.parent_path().string();
419 std::string dstFileName = fsDstPath.filename();
420 if (!GetRealPathOfNoneExistFile(parentOfDstPath, realDstPath)) {
421 LOGE("get real dst path failed! dstPath=%s", dstPath.c_str());
422 return false;
423 }
424 realDstPath += fs::path::preferred_separator + dstFileName;
425 std::ifstream srcFile(realSrcPath, std::ios::binary);
426 std::ofstream dstFile(realDstPath, std::ios::binary);
427 if (!srcFile.is_open()) {
428 LOGE("Open srcPath failed![srcPath=%s][realSrcPath=%s]", srcPath.c_str(), realSrcPath.c_str());
429 return false;
430 }
431 if (!dstFile.is_open()) {
432 LOGE("Open dstPath failed![dstPath=%s][realDstPath=%s]", dstPath.c_str(), realDstPath.c_str());
433 return false;
434 }
435 dstFile << srcFile.rdbuf();
436 srcFile.close();
437 dstFile.close();
438 return true;
439 }
440
GetFormattedPath(const std::string & path,std::string & formattedPath)441 bool Utils::GetFormattedPath(const std::string& path, std::string& formattedPath)
442 {
443 if (path.empty()) {
444 formattedPath = "";
445 return true;
446 }
447 try {
448 formattedPath = fs::canonical(path).string();
449 } catch (const fs::filesystem_error& err) {
450 LOGE("GetFormattedPath exception: ", err.what());
451 return false;
452 }
453 return true;
454 }
455
GetRealPath(const std::string & path,std::string & realPath)456 bool Utils::GetRealPath(const std::string& path, std::string& realPath)
457 {
458 if (path.length() >= PATH_MAX) {
459 return false;
460 }
461 char buffer[PATH_MAX] = {0};
462 if (realpath(path.c_str(), buffer) == nullptr) {
463 return false;
464 }
465 realPath = std::string(buffer);
466 return true;
467 }
468
GetRealPathOfNoneExistFile(const std::string & path,std::string & realPath)469 bool Utils::GetRealPathOfNoneExistFile(const std::string& path, std::string& realPath)
470 {
471 fs::path fsPath = fs::path(path);
472 std::string filePath = fsPath.parent_path().string();
473 std::string fileName = fsPath.filename().string();
474 if (path.length() >= PATH_MAX) {
475 return false;
476 }
477 char buffer[PATH_MAX] = {0};
478 if (realpath(filePath.c_str(), buffer) == nullptr) {
479 return false;
480 }
481 realPath = std::string(buffer) + fs::path::preferred_separator + fileName;
482 return true;
483 }
484
RemoveAllFilesInDirectory(const std::string & directoryPath)485 bool Utils::RemoveAllFilesInDirectory(const std::string& directoryPath)
486 {
487 fs::path fsPath(directoryPath);
488 if (!fs::exists(fsPath) || !fs::is_directory(fsPath)) {
489 return false;
490 }
491 for (auto& entry : fs::directory_iterator(fsPath)) {
492 if (fs::is_regular_file(entry)) {
493 fs::remove(entry);
494 }
495 }
496 return true;
497 }
498
499 } // namespace AppPackingTool
500 } // namespace OHOS
501