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 "base_extractor.h"
17
18 #include <fstream>
19
20 #include "app_log_wrapper.h"
21 #include "bundle_service_constants.h"
22 #include "string_ex.h"
23
24 namespace OHOS {
25 namespace AppExecFwk {
26 namespace {
27 constexpr const char* MODULE_PROFILE_NAME = "module.json";
28 }
29
BaseExtractor(const std::string & source,bool parallel)30 BaseExtractor::BaseExtractor(const std::string &source, bool parallel) : sourceFile_(source), zipFile_(source, parallel)
31 {
32 APP_LOGD("BaseExtractor instance is created");
33 }
34
~BaseExtractor()35 BaseExtractor::~BaseExtractor()
36 {
37 APP_LOGD("BaseExtractor instance is destroyed");
38 }
39
Init()40 bool BaseExtractor::Init()
41 {
42 if (!zipFile_.Open()) {
43 APP_LOGE("open zip file failed, errno:%{public}d", errno);
44 return false;
45 }
46 ZipEntry zipEntry;
47 isNewVersion_ = zipFile_.GetEntry(MODULE_PROFILE_NAME, zipEntry);
48 initial_ = true;
49 return true;
50 }
51
HasEntry(const std::string & fileName) const52 bool BaseExtractor::HasEntry(const std::string &fileName) const
53 {
54 if (!initial_) {
55 APP_LOGE("extractor is not initial");
56 return false;
57 }
58
59 return zipFile_.HasEntry(fileName);
60 }
61
IsDirExist(const std::string & dir) const62 bool BaseExtractor::IsDirExist(const std::string &dir) const
63 {
64 if (!initial_) {
65 APP_LOGE("extractor is not initial");
66 return false;
67 }
68 if (dir.empty()) {
69 APP_LOGE("param dir empty");
70 return false;
71 }
72 return zipFile_.IsDirExist(dir);
73 }
74
ExtractByName(const std::string & fileName,std::ostream & dest) const75 bool BaseExtractor::ExtractByName(const std::string &fileName, std::ostream &dest) const
76 {
77 if (!initial_) {
78 APP_LOGE("extractor is not initial");
79 return false;
80 }
81 if (!zipFile_.ExtractFile(fileName, dest)) {
82 APP_LOGE("extractor is not ExtractFile");
83 return false;
84 }
85 return true;
86 }
87
ExtractFile(const std::string & fileName,const std::string & targetPath) const88 bool BaseExtractor::ExtractFile(const std::string &fileName, const std::string &targetPath) const
89 {
90 APP_LOGD("begin to extract %{public}s file into %{private}s targetPath", fileName.c_str(), targetPath.c_str());
91 std::ofstream fileStream;
92 fileStream.open(targetPath, std::ios_base::out | std::ios_base::binary);
93 if (!fileStream.is_open()) {
94 (void)remove(targetPath.c_str());
95 fileStream.open(targetPath, std::ios_base::out | std::ios_base::binary);
96 if (!fileStream.is_open()) {
97 APP_LOGE("fail to open %{private}s file to write, errno:%{public}d", targetPath.c_str(), errno);
98 return false;
99 }
100 }
101 if ((!ExtractByName(fileName, fileStream)) || (!fileStream.good())) {
102 APP_LOGE("extract %{public}s failed, errno:%{public}d failbit:%{public}d badbit:%{public}d eofbit:%{public}d",
103 fileName.c_str(), errno, fileStream.fail(), fileStream.bad(), fileStream.eof());
104 fileStream.clear();
105 fileStream.close();
106 if (remove(targetPath.c_str()) != 0) {
107 APP_LOGE("fail to remove %{private}s file which writes stream error, errno:%{public}d",
108 targetPath.c_str(), errno);
109 }
110 return false;
111 }
112 fileStream.clear();
113 fileStream.close();
114 return true;
115 }
116
GetZipFileNames(std::vector<std::string> & fileNames) const117 bool BaseExtractor::GetZipFileNames(std::vector<std::string> &fileNames) const
118 {
119 auto &entryMap = zipFile_.GetAllEntries();
120 auto entryFilter = [&fileNames](const auto &entry) {
121 auto position = entry.first.rfind(ServiceConstants::QUICK_FIX_FILE_SUFFIX);
122 bool isHqfFile = false;
123 if (position != std::string::npos) {
124 std::string suffixStr = entry.first.substr(position);
125 isHqfFile = suffixStr == ServiceConstants::QUICK_FIX_FILE_SUFFIX;
126 }
127 if ((entry.first.find(ServiceConstants::RELATIVE_PATH) == std::string::npos) && !isHqfFile) {
128 fileNames.emplace_back(entry.first);
129 }
130 };
131 for_each(entryMap.begin(), entryMap.end(), entryFilter);
132 return true;
133 }
134
IsStageBasedModel(std::string abilityName)135 bool BaseExtractor::IsStageBasedModel(std::string abilityName)
136 {
137 auto &entryMap = zipFile_.GetAllEntries();
138 std::vector<std::string> splitStrs;
139 OHOS::SplitStr(abilityName, ".", splitStrs);
140 std::string name = splitStrs.empty() ? abilityName : splitStrs.back();
141 std::string entry = "assets/js/" + name + "/" + name + ".js";
142 bool isStageBasedModel = entryMap.find(entry) != entryMap.end();
143 APP_LOGI("name:%{public}s isStageBasedModel:%{public}d", abilityName.c_str(), isStageBasedModel);
144 return isStageBasedModel;
145 }
146
IsNewVersion() const147 bool BaseExtractor::IsNewVersion() const
148 {
149 return isNewVersion_;
150 }
151
GetFileInfo(const std::string & fileName,uint32_t & offset,uint32_t & length) const152 bool BaseExtractor::GetFileInfo(const std::string &fileName, uint32_t &offset, uint32_t &length) const
153 {
154 if (!initial_) {
155 APP_LOGE("extractor is not initial");
156 return false;
157 }
158 ZipPos tmpOffset = 0;
159 if (!zipFile_.GetDataOffsetRelative(fileName, tmpOffset, length)) {
160 APP_LOGE("GetDataOffsetRelative failed");
161 return false;
162 }
163 if (tmpOffset > std::numeric_limits<uint32_t>::max()) {
164 APP_LOGE("offset too large");
165 return false;
166 }
167 offset = static_cast<uint32_t>(tmpOffset);
168 return true;
169 }
170 } // namespace AppExecFwk
171 } // namespace OHOS
172