• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 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 "compression_parser.h"
17 
18 #include <algorithm>
19 #include <iostream>
20 #include <mutex>
21 #include "restool_errors.h"
22 
23 namespace OHOS {
24 namespace Global {
25 namespace Restool {
26 using namespace std;
27 static shared_ptr<CompressionParser> compressionParseMgr = nullptr;
28 static once_flag compressionParserMgrFlag;
29 
30 const map<TranscodeError, string> ERRORCODEMAP = {
31     { TranscodeError::SUCCESS, "SUCCESS" },
32     { TranscodeError::INVALID_PARAMETERS, "INVALID_PARAMETERS" },
33     { TranscodeError::IMAGE_ERROR, "IMAGE_ERROR" },
34     { TranscodeError::ANIMATED_IMAGE_SKIP, "ANIMATED_IMAGE_SKIP" },
35     { TranscodeError::MALLOC_FAILED, "MALLOC_FAILED" },
36     { TranscodeError::ENCODE_ASTC_FAILED, "ENCODE_ASTC_FAILED" },
37     { TranscodeError::SUPER_COMPRESS_FAILED, "SUPER_COMPRESS_FAILED" },
38     { TranscodeError::IMAGE_SIZE_NOT_MATCH, "IMAGE_SIZE_NOT_MATCH" },
39     { TranscodeError::IMAGE_RESOLUTION_NOT_MATCH, "IMAGE_RESOLUTION_NOT_MATCH" },
40     { TranscodeError::EXCLUDE_MATCH, "EXCLUDE_MATCH" },
41     { TranscodeError::LOAD_COMPRESS_FAILED, "LOAD_COMPRESS_FAILED" },
42 };
43 
CompressionParser()44 CompressionParser::CompressionParser()
45     : filePath_(""), extensionPath_(""), mediaSwitch_(false), root_(nullptr), defaultCompress_(false), outPath_("")
46 {
47 }
48 
CompressionParser(const string & filePath)49 CompressionParser::CompressionParser(const string &filePath)
50     : filePath_(filePath), extensionPath_(""), mediaSwitch_(false), root_(nullptr), defaultCompress_(false),
51     outPath_("")
52 {
53 }
54 
~CompressionParser()55 CompressionParser::~CompressionParser()
56 {
57     if (root_) {
58         cJSON_Delete(root_);
59     }
60 #ifdef __WIN32
61     if (handle_) {
62         FreeLibrary(handle_);
63         handle_ = nullptr;
64     }
65 #else
66     if (handle_) {
67         dlclose(handle_);
68         handle_ = nullptr;
69     }
70 #endif
71 }
72 
GetCompressionParser(const string & filePath)73 shared_ptr<CompressionParser> CompressionParser::GetCompressionParser(const string &filePath)
74 {
75     call_once(compressionParserMgrFlag, [&] {
76         compressionParseMgr = make_shared<CompressionParser>(filePath);
77     });
78     return compressionParseMgr;
79 }
80 
GetCompressionParser()81 shared_ptr<CompressionParser> CompressionParser::GetCompressionParser()
82 {
83     if (!compressionParseMgr) {
84         compressionParseMgr = make_shared<CompressionParser>();
85     }
86     return compressionParseMgr;
87 }
88 
Init()89 uint32_t CompressionParser::Init()
90 {
91     if (!ResourceUtil::OpenJsonFile(filePath_, &root_)) {
92         return RESTOOL_ERROR;
93     }
94     if (!root_ || !cJSON_IsObject(root_)) {
95         PrintError(GetError(ERR_CODE_JSON_FORMAT_ERROR).SetPosition(filePath_));
96         return RESTOOL_ERROR;
97     }
98     cJSON *contextNode = cJSON_GetObjectItem(root_, "context");
99     if (!ParseContext(contextNode)) {
100         cout << NEW_LINE_PATH << filePath_ << endl;
101         return RESTOOL_SUCCESS;
102     }
103     if (!LoadImageTranscoder()) {
104         return RESTOOL_ERROR;
105     }
106     cJSON *compressionNode = cJSON_GetObjectItem(root_, "compression");
107     if (!ParseCompression(compressionNode)) {
108         return RESTOOL_ERROR;
109     }
110     if (!mediaSwitch_) {
111         return RESTOOL_SUCCESS;
112     }
113     cJSON *filtersNode = cJSON_GetObjectItem(compressionNode, "filters");
114     if (!ParseFilters(filtersNode)) {
115         return RESTOOL_ERROR;
116     }
117     string caches = outPath_;
118     caches.append(SEPARATOR_FILE).append(CACHES_DIR);
119     if (!ResourceUtil::CreateDirs(caches)) {
120         return RESTOOL_ERROR;
121     }
122     return RESTOOL_SUCCESS;
123 }
124 
ParseCompression(const cJSON * compressionNode)125 bool CompressionParser::ParseCompression(const cJSON *compressionNode)
126 {
127     if (!compressionNode) {
128         cerr << "Warning: get 'compression' node is empty, the compiled images are not transcoded.";
129         cerr << NEW_LINE_PATH << filePath_ << endl;
130         return true;
131     }
132     if (!cJSON_IsObject(compressionNode)) {
133         PrintError(GetError(ERR_CODE_JSON_NODE_MISMATCH).FormatCause("compression", "object").SetPosition(filePath_));
134         return false;
135     }
136     cJSON *mediaNode = cJSON_GetObjectItem(compressionNode, "media");
137     if (!mediaNode) {
138         cerr << "Warning: get 'media' node is empty, the compiled images are not transcoded.";
139         cerr << NEW_LINE_PATH << filePath_ << endl;
140         return true;
141     }
142     if (!cJSON_IsObject(mediaNode)) {
143         PrintError(GetError(ERR_CODE_JSON_NODE_MISMATCH).FormatCause("media", "object").SetPosition(filePath_));
144         return false;
145     }
146     cJSON *enableNode = cJSON_GetObjectItem(mediaNode, "enable");
147     if (!enableNode) {
148         cerr << "Warning: get 'enable' node is empty, the compiled images are not transcoded.";
149         cerr << NEW_LINE_PATH << filePath_ << endl;
150         return true;
151     }
152     if (!cJSON_IsBool(enableNode)) {
153         PrintError(GetError(ERR_CODE_JSON_NODE_MISMATCH).FormatCause("enable", "bool").SetPosition(filePath_));
154         return false;
155     }
156     mediaSwitch_ = cJSON_IsTrue(enableNode);
157     return true;
158 }
159 
ParseContext(const cJSON * contextNode)160 bool CompressionParser::ParseContext(const cJSON *contextNode)
161 {
162     if (!contextNode) {
163         cout << "Warning: if image transcoding is supported, the 'context' node cannot be empty.";
164         return false;
165     }
166     if (!cJSON_IsObject(contextNode)) {
167         cout << "Warning: 'context' must be object.";
168         return false;
169     }
170     cJSON *extensionPathNode = cJSON_GetObjectItem(contextNode, "extensionPath");
171     if (!extensionPathNode) {
172         cout << "Warning: if image transcoding is supported, the 'extensionPath' node cannot be empty.";
173         return false;
174     }
175     if (!cJSON_IsString(extensionPathNode)) {
176         cout << "Warning: 'extensionPath' must be string.";
177         return false;
178     }
179     extensionPath_ = extensionPathNode->valuestring;
180     if (extensionPath_.empty()) {
181         cout << "Warning: 'extensionPath' value cannot be empty.";
182         return false;
183     }
184     return true;
185 }
186 
ParseFilters(const cJSON * filtersNode)187 bool CompressionParser::ParseFilters(const cJSON *filtersNode)
188 {
189     if (!filtersNode) {
190         PrintError(GetError(ERR_CODE_JSON_NODE_MISSING).FormatCause("filters").SetPosition(filePath_));
191         return false;
192     }
193     if (!cJSON_IsArray(filtersNode)) {
194         PrintError(GetError(ERR_CODE_JSON_NODE_MISMATCH).FormatCause("filters", "array").SetPosition(filePath_));
195         return false;
196     }
197     if (cJSON_GetArraySize(filtersNode) == 0) {
198         PrintError(GetError(ERR_CODE_JSON_NODE_EMPTY).FormatCause("filters").SetPosition(filePath_));
199         return false;
200     }
201     for (cJSON *item = filtersNode->child; item; item = item->next) {
202         if (!cJSON_IsObject(item)) {
203             PrintError(GetError(ERR_CODE_JSON_NODE_MISMATCH).FormatCause("filters's value", "object")
204                 .SetPosition(filePath_));
205             return false;
206         }
207         cJSON *methodNode = cJSON_GetObjectItem(item, "method");
208         if (!methodNode) {
209             PrintError(GetError(ERR_CODE_JSON_NODE_MISSING).FormatCause("method").SetPosition(filePath_));
210             return false;
211         }
212         if (!cJSON_IsObject(methodNode)) {
213             PrintError(GetError(ERR_CODE_JSON_NODE_MISMATCH).FormatCause("method", "object").SetPosition(filePath_));
214             return false;
215         }
216         shared_ptr<CompressFilter> compressFilter = make_shared<CompressFilter>();
217         compressFilter->method = "\"method\":" + ParseJsonStr(methodNode);
218         cJSON *pathNode = cJSON_GetObjectItem(item, "path");
219         compressFilter->path = ParsePath(pathNode);
220         cJSON *excludePathNode = cJSON_GetObjectItem(item, "exclude_path");
221         compressFilter->excludePath = ParsePath(excludePathNode);
222         cJSON *rulesNode = cJSON_GetObjectItem(item, "rules_origin");
223         compressFilter->rules = ParseRules(rulesNode);
224         cJSON *excludeRulesNode = cJSON_GetObjectItem(item, "rules_exclude");
225         compressFilter->excludeRules = ParseRules(excludeRulesNode);
226         compressFilters_.emplace_back(compressFilter);
227     }
228     defaultCompress_ = IsDefaultCompress();
229     return true;
230 }
231 
IsDefaultCompress()232 bool CompressionParser::IsDefaultCompress()
233 {
234     if (compressFilters_.size() != 1) {
235         return false;
236     }
237     auto compressFilter = compressFilters_[0];
238     bool pathEmpty = (compressFilter->path.size() == 1) && (compressFilter->path[0] == "true");
239     bool excludePathEmpty = (compressFilter->excludePath.size() == 1) && (compressFilter->excludePath[0] == "true");
240     return pathEmpty && excludePathEmpty && (compressFilter->rules.empty()) && (compressFilter->excludeRules.empty());
241 }
242 
SetOutPath(const string & path)243 void CompressionParser::SetOutPath(const string &path)
244 {
245     outPath_ = path;
246 }
247 
ParseRules(const cJSON * rulesNode)248 string CompressionParser::ParseRules(const cJSON *rulesNode)
249 {
250     string res = "";
251     if (!rulesNode || !cJSON_IsObject(rulesNode)) {
252         cout << "Warning: rules is not exist or node type is wrong" << endl;
253         return res;
254     }
255     for (cJSON *item = rulesNode->child; item; item = item->next) {
256         if (!item || !cJSON_IsArray(item)) {
257             continue;
258         }
259         string name(item->string);
260         res.append("\"").append(name).append("\":").append(ParseJsonStr(item)).append(",");
261     }
262     if (res.size() - 1 < 0) {
263         return res;
264     }
265     return res.substr(0, res.size() - 1);
266 }
267 
ParsePath(const cJSON * pathNode)268 vector<string> CompressionParser::ParsePath(const cJSON *pathNode)
269 {
270     vector<string> res;
271     if (!pathNode) {
272         res.emplace_back("true");
273         return res;
274     }
275     if (!cJSON_IsArray(pathNode)) {
276         cout << "Warning: pathnode is not array." << endl;
277         return res;
278     }
279     for (cJSON *item = pathNode->child; item; item = item->next) {
280         if (!item || !cJSON_IsString(item)) {
281             continue;
282         }
283         res.emplace_back(item->valuestring);
284     }
285     return res;
286 }
287 
ParseJsonStr(const cJSON * node)288 string CompressionParser::ParseJsonStr(const cJSON *node)
289 {
290     if (!node) {
291         return "";
292     }
293     char *jsonString = cJSON_Print(node);
294     if (jsonString == nullptr) {
295         return "";
296     }
297     string res(jsonString);
298     free(jsonString);
299     return res;
300 }
301 
LoadImageTranscoder()302 bool CompressionParser::LoadImageTranscoder()
303 {
304 #ifdef __WIN32
305     if (!handle_) {
306         handle_ = LoadLibrary(TEXT(extensionPath_.c_str()));
307         if (!handle_) {
308             DWORD err = GetLastError();
309             LPVOID lpMsgBuf;
310             FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
311                 NULL, err, MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT), (LPTSTR)&lpMsgBuf, 0, NULL);
312             const char *msg = static_cast<const char *>(lpMsgBuf);
313             std::string errMsg = "(" + std::to_string(err) + ")" + string(msg);
314             PrintError(GetError(ERR_CODE_LOAD_LIBRARY_FAIL).FormatCause(extensionPath_.c_str(), errMsg.c_str()));
315             LocalFree(lpMsgBuf);
316             return false;
317         }
318     }
319 #else
320     if (!handle_) {
321         string realPath = ResourceUtil::RealPath(extensionPath_);
322         if (realPath.empty()) {
323             PrintError(GetError(ERR_CODE_LOAD_LIBRARY_FAIL).FormatCause(extensionPath_.c_str(), "path invalid"));
324             return false;
325         }
326         handle_ = dlopen(realPath.c_str(), RTLD_LAZY);
327         if (!handle_) {
328             char *err = dlerror();
329             PrintError(GetError(ERR_CODE_LOAD_LIBRARY_FAIL).FormatCause(realPath.c_str(), err));
330             return false;
331         }
332     }
333 #endif
334     return true;
335 }
336 
SetTranscodeOptions(const string & optionJson,const string & optionJsonExclude)337 bool CompressionParser::SetTranscodeOptions(const string &optionJson, const string &optionJsonExclude)
338 {
339     if (!handle_) {
340         cout << "Warning: SetTranscodeOptions handle_ is nullptr." << endl;
341         return false;
342     }
343 #ifdef __WIN32
344     ISetTranscodeOptions iSetTranscodeOptions = (ISetTranscodeOptions)GetProcAddress(handle_, "SetTranscodeOptions");
345 #else
346     ISetTranscodeOptions iSetTranscodeOptions = (ISetTranscodeOptions)dlsym(handle_, "SetTranscodeOptions");
347 #endif
348     if (!iSetTranscodeOptions) {
349         cout << "Warning: Failed to get the 'SetTranscodeOptions'." << endl;
350         return false;
351     }
352     bool ret = (*iSetTranscodeOptions)(optionJson, optionJsonExclude);
353     if (!ret) {
354         cout << "Warning: SetTranscodeOptions failed." << endl;
355         return false;
356     }
357     return true;
358 }
359 
TranscodeImages(const string & imagePath,const bool extAppend,string & outputPath,TranscodeResult & result)360 TranscodeError CompressionParser::TranscodeImages(const string &imagePath, const bool extAppend,
361     string &outputPath, TranscodeResult &result)
362 {
363     if (!handle_) {
364         cout << "Warning: TranscodeImages handle_ is nullptr." << endl;
365         return TranscodeError::LOAD_COMPRESS_FAILED;
366     }
367 #ifdef __WIN32
368     ITranscodeImages iTranscodeImages = (ITranscodeImages)GetProcAddress(handle_, "Transcode");
369 #else
370     ITranscodeImages iTranscodeImages = (ITranscodeImages)dlsym(handle_, "Transcode");
371 #endif
372     if (!iTranscodeImages) {
373         cout << "Warning: Failed to get the 'Transcode'." << endl;
374         return TranscodeError::LOAD_COMPRESS_FAILED;
375     }
376     TranscodeError ret = (*iTranscodeImages)(imagePath, extAppend, outputPath, result);
377     if (ret != TranscodeError::SUCCESS) {
378         auto iter = ERRORCODEMAP.find(ret);
379         if (iter != ERRORCODEMAP.end()) {
380             cout << "Warning: TranscodeImages failed, error message: " << iter->second << ", file path = " <<
381                 imagePath << endl;
382         } else {
383             cout << "Warning: TranscodeImages failed" << ", file path = " << imagePath << endl;
384         }
385         return ret;
386     }
387     return TranscodeError::SUCCESS;
388 }
389 
ScaleImage(const std::string & imagePath,std::string & outputPath)390 TranscodeError CompressionParser::ScaleImage(const std::string &imagePath, std::string &outputPath)
391 {
392     if (!handle_) {
393         cout << "Warning: ScaleImage handle_ is nullptr." << endl;
394         return TranscodeError::LOAD_COMPRESS_FAILED;
395     }
396 #ifdef __WIN32
397     IScaleImage iScaleImage = (IScaleImage)GetProcAddress(handle_, "TranscodeSLR");
398 #else
399     IScaleImage iScaleImage = (IScaleImage)dlsym(handle_, "TranscodeSLR");
400 #endif
401     if (!iScaleImage) {
402         cout << "Warning: Failed to get the 'TranscodeSLR'." << endl;
403         return TranscodeError::LOAD_COMPRESS_FAILED;
404     }
405     TranscodeError ret = (*iScaleImage)(imagePath, outputPath, { 512, 512 });
406     if (ret != TranscodeError::SUCCESS) {
407         auto iter = ERRORCODEMAP.find(ret);
408         if (iter != ERRORCODEMAP.end()) {
409             cout << "Warning: ScaleImage failed, error message: " << iter->second << ", file path = " << imagePath
410                  << endl;
411         } else {
412             cout << "Warning: ScaleImage failed" << ", file path = " << imagePath << endl;
413         }
414         return ret;
415     }
416     return TranscodeError::SUCCESS;
417 }
418 
CheckPath(const string & src,const vector<string> & paths)419 bool CompressionParser::CheckPath(const string &src, const vector<string> &paths)
420 {
421     if (paths.size() == 1 && paths[0] == "true") {
422         return true;
423     }
424     return any_of(paths.begin(), paths.end(), [src](const auto &iter) {
425         return iter == src;
426     });
427 }
428 
IsInPath(const string & src,const shared_ptr<CompressFilter> & compressFilter)429 bool CompressionParser::IsInPath(const string &src, const shared_ptr<CompressFilter> &compressFilter)
430 {
431     return CheckPath(src, compressFilter->path);
432 }
433 
IsInExcludePath(const string & src,const shared_ptr<CompressFilter> & compressFilter)434 bool CompressionParser::IsInExcludePath(const string &src, const shared_ptr<CompressFilter> &compressFilter)
435 {
436     return CheckPath(src, compressFilter->excludePath);
437 }
438 
GetMethod(const shared_ptr<CompressFilter> & compressFilter)439 string CompressionParser::GetMethod(const shared_ptr<CompressFilter> &compressFilter)
440 {
441     return "{" + compressFilter->method + "}";
442 }
443 
GetRules(const shared_ptr<CompressFilter> & compressFilter)444 string CompressionParser::GetRules(const shared_ptr<CompressFilter> &compressFilter)
445 {
446     return GetFileRules(compressFilter->rules, compressFilter->method);
447 }
448 
GetExcludeRules(const shared_ptr<CompressFilter> & compressFilter)449 string CompressionParser::GetExcludeRules(const shared_ptr<CompressFilter> &compressFilter)
450 {
451     return GetFileRules(compressFilter->excludeRules, compressFilter->method);
452 }
453 
GetFileRules(const string & rules,const string & method)454 string CompressionParser::GetFileRules(const string &rules, const string &method)
455 {
456     if (rules.empty()) {
457         return "{" + method + "}";
458     }
459     string res = "{";
460     return res.append(method).append(",").append(rules).append("}");
461 }
462 
CollectTime(uint32_t & count,unsigned long long & time,std::chrono::time_point<std::chrono::steady_clock> & start)463 void CompressionParser::CollectTime(uint32_t &count, unsigned long long &time,
464     std::chrono::time_point<std::chrono::steady_clock> &start)
465 {
466     unsigned long long costTime = static_cast<unsigned long long>(
467         std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::steady_clock::now() - start).count());
468     time += costTime;
469     count++;
470 }
471 
CollectTimeAndSize(TranscodeError res,std::chrono::time_point<std::chrono::steady_clock> & start,TranscodeResult & result)472 void CompressionParser::CollectTimeAndSize(TranscodeError res,
473     std::chrono::time_point<std::chrono::steady_clock> &start, TranscodeResult &result)
474 {
475     unsigned long long costTime = static_cast<unsigned long long>(
476         std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::steady_clock::now() - start).count());
477     if (res == TranscodeError::SUCCESS) {
478         totalTime_ += costTime;
479         totalCounts_++;
480         compressTime_ += costTime;
481         compressCounts_++;
482         successTime_ += costTime;
483         successCounts_++;
484         originalSize_ += result.originSize;
485         successSize_ += static_cast<unsigned long long>(result.size);
486     } else if (res < TranscodeError::NOT_MATCH_BASE) {
487         totalTime_ += costTime;
488         compressTime_ += costTime;
489         compressCounts_++;
490     } else {
491         totalTime_ += costTime;
492     }
493 }
494 
PrintTransMessage()495 string CompressionParser::PrintTransMessage()
496 {
497     string res = "Processing report:\n";
498     res.append("total:").append(to_string(totalCounts_)).append(", ").append(to_string(totalTime_)).append(" us.\n");
499     res.append("compressed:").append(to_string(compressCounts_)).append(", ").append(to_string(compressTime_))
500         .append(" us.\n");
501     res.append("success:").append(to_string(successCounts_)).append(", ").append(to_string(successTime_))
502         .append(" us, ").append(to_string(originalSize_)).append(" Bytes to ").append(to_string(successSize_))
503         .append(" Bytes.");
504     return res;
505 }
506 
GetMediaSwitch()507 bool CompressionParser::GetMediaSwitch()
508 {
509     return mediaSwitch_;
510 }
511 
GetDefaultCompress()512 bool CompressionParser::GetDefaultCompress()
513 {
514     return defaultCompress_;
515 }
516 
CheckAndTranscode(const string & src,string & dst,string & output,const shared_ptr<CompressFilter> & compressFilter,const bool extAppend)517 bool CompressionParser::CheckAndTranscode(const string &src, string &dst, string &output,
518     const shared_ptr<CompressFilter> &compressFilter, const bool extAppend)
519 {
520     auto t1 = std::chrono::steady_clock::now();
521     TranscodeResult result = {0, 0, 0, 0};
522     if (defaultCompress_) {
523         if (!SetTranscodeOptions(GetMethod(compressFilter), "")) {
524             return false;
525         }
526         auto res = TranscodeImages(src, extAppend, output, result);
527         CollectTimeAndSize(res, t1, result);
528         if (res != TranscodeError::SUCCESS) {
529             return false;
530         }
531         dst = output;
532         return true;
533     }
534     if (!IsInPath(src, compressFilter)) {
535         return false;
536     }
537     if (IsInExcludePath(src, compressFilter)) {
538         if (!SetTranscodeOptions(GetRules(compressFilter), GetExcludeRules(compressFilter))) {
539             return false;
540         }
541         auto res = TranscodeImages(src, extAppend, output, result);
542         CollectTimeAndSize(res, t1, result);
543         if (res != TranscodeError::SUCCESS) {
544             return false;
545         }
546         dst = output;
547         return true;
548     }
549     if (!SetTranscodeOptions(GetRules(compressFilter), "")) {
550         return false;
551     }
552     auto res = TranscodeImages(src, extAppend, output, result);
553     CollectTimeAndSize(res, t1, result);
554     if (res != TranscodeError::SUCCESS) {
555         return false;
556     }
557     dst = output;
558     return true;
559 }
560 
CopyForTrans(const string & src,const string & originDst,const string & dst)561 bool CompressionParser::CopyForTrans(const string &src, const string &originDst, const string &dst)
562 {
563     string srcSuffix;
564     string dstSuffix;
565     auto srcIndex = src.find_last_of(".");
566     auto dstIndex = dst.find_last_of(".");
567     if (srcIndex != string::npos && dstIndex != string::npos) {
568         srcSuffix = src.substr(srcIndex + 1);
569         dstSuffix = dst.substr(dstIndex + 1);
570     }
571     auto ret = false;
572     if (srcSuffix == dstSuffix) {
573         ret = ResourceUtil::CopyFileInner(src, dst);
574     } else {
575         uint32_t startIndex = outPath_.size() + CACHES_DIR.size() + 1;
576         string dstPath = outPath_ + SEPARATOR_FILE + RESOURCES_DIR + dst.substr(startIndex);
577         ret = ResourceUtil::CopyFileInner(dst, dstPath);
578     }
579     return ret;
580 }
581 
CopyAndTranscode(const string & src,string & dst,const bool extAppend)582 bool CompressionParser::CopyAndTranscode(const string &src, string &dst, const bool extAppend)
583 {
584     auto t0 = std::chrono::steady_clock::now();
585     if (!mediaSwitch_) {
586         auto res = ResourceUtil::CopyFileInner(src, dst);
587         CollectTime(totalCounts_, totalTime_, t0);
588         return res;
589     }
590 
591     auto index = dst.find_last_of(SEPARATOR_FILE);
592     if (index == string::npos) {
593         PrintError(GetError(ERR_CODE_INVALID_RESOURCE_PATH).FormatCause(dst.c_str(), "missing separator"));
594         return false;
595     }
596     uint32_t startIndex = outPath_.size() + RESOURCES_DIR.size() + 1;
597     string endStr = dst.substr(startIndex, index - startIndex);
598     string output = outPath_ + SEPARATOR_FILE + CACHES_DIR + endStr;
599     string originDst = dst;
600     if (!ResourceUtil::CreateDirs(output)) {
601         return false;
602     }
603     for (const auto &compressFilter : compressFilters_) {
604         if (!CheckAndTranscode(src, dst, output, compressFilter, extAppend)) {
605             continue;
606         }
607         break;
608     }
609     auto t2 = std::chrono::steady_clock::now();
610     auto ret = CopyForTrans(src, originDst, dst);
611     CollectTime(totalCounts_, totalTime_, t2);
612     return ret;
613 }
614 
CheckAndScaleIcon(const std::string & src,const std::string & originDst,std::string & scaleDst)615 bool CompressionParser::CheckAndScaleIcon(const std::string &src, const std::string &originDst, std::string &scaleDst)
616 {
617     scaleDst = src;
618     if (filePath_.empty() || outPath_.empty()) {
619         cout << "Info: compression path or out path is empty, unable to scale icon." << endl;
620         return true;
621     }
622     auto index = originDst.find_last_of(SEPARATOR_FILE);
623     if (index == string::npos) {
624         PrintError(GetError(ERR_CODE_INVALID_RESOURCE_PATH).FormatCause(originDst.c_str(), "missing separator"));
625         return false;
626     }
627     uint32_t startIndex = outPath_.size() + RESOURCES_DIR.size() + 1;
628     string qualifierDir = originDst.substr(startIndex, index - startIndex);
629     string outputCache = outPath_ + SEPARATOR_FILE + CACHES_DIR + qualifierDir;
630     if (!ResourceUtil::CreateDirs(outputCache)) {
631         return false;
632     }
633     string fileName = originDst.substr(index + 1);
634     string outputFile = outputCache + SEPARATOR_FILE + fileName;
635     auto ret = ScaleImage(src, outputFile);
636     if (ret == TranscodeError::SUCCESS) {
637         // if scale success, change src file to scale image
638         scaleDst = outputFile;
639     }
640     return true;
641 }
642 
ScaleIconEnable()643 bool CompressionParser::ScaleIconEnable()
644 {
645     return !filePath_.empty() && !outPath_.empty() && handle_ != nullptr;
646 }
647 }
648 }
649 }
650