1/*
2 * Copyright (c) 2023 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 "extractor.h"
17
18#include <fstream>
19#include <sstream>
20#include "constants.h"
21#include "file_path_utils.h"
22#include "ecmascript/platform/file.h"
23
24namespace panda {
25namespace ecmascript {
26namespace {
27constexpr char EXT_NAME_ABC[] = ".abc";
28}
29Extractor::Extractor(const std::string &source) : zipFile_(source)
30{
31    hapPath_ = source;
32}
33
34Extractor::~Extractor()
35{}
36
37bool Extractor::Init()
38{
39    if (!zipFile_.Open()) {
40        return false;
41    }
42    initial_ = true;
43    return true;
44}
45
46bool Extractor::GetFileBuffer(const std::string& srcPath, std::ostringstream& dest)
47{
48    if (!initial_) {
49        return false;
50    }
51
52    if (srcPath.empty()) {
53        return false;
54    }
55
56    std::string relativePath = GetRelativePath(srcPath);
57    if (!ExtractByName(relativePath, dest)) {
58        return false;
59    }
60
61    return true;
62}
63
64bool Extractor::GetFileList(const std::string& srcPath, std::vector<std::string>& assetList)
65{
66    if (!initial_) {
67        return false;
68    }
69
70    if (srcPath.empty()) {
71        return false;
72    }
73    zipFile_.GetAllFileList(srcPath, assetList);
74    if (assetList.empty()) {
75    }
76
77    return true;
78}
79
80bool Extractor::HasEntry(const std::string &fileName) const
81{
82    if (!initial_) {
83        return false;
84    }
85
86    return zipFile_.HasEntry(fileName);
87}
88
89bool Extractor::IsDirExist(const std::string &dir) const
90{
91    if (!initial_) {
92        return false;
93    }
94    if (dir.empty()) {
95        return false;
96    }
97    return zipFile_.IsDirExist(dir);
98}
99
100bool Extractor::ExtractByName(const std::string &fileName, std::ostream &dest) const
101{
102    if (!initial_) {
103        return false;
104    }
105    if (!zipFile_.ExtractFile(fileName, dest)) {
106        return false;
107    }
108    return true;
109}
110
111bool Extractor::ExtractFile(const std::string &fileName, const std::string &targetPath) const
112{
113    if (!panda::ecmascript::FileExist(targetPath.c_str())) {
114        return false;
115    }
116    std::ofstream fileStream;
117    fileStream.open(targetPath, std::ios_base::out | std::ios_base::binary);
118    if (!fileStream.is_open()) {
119        return false;
120    }
121    if ((!ExtractByName(fileName, fileStream)) || (!fileStream.good())) {
122        fileStream.clear();
123        fileStream.close();
124        if (remove(targetPath.c_str()) != 0) {
125        }
126        return false;
127    }
128    fileStream.clear();
129    fileStream.close();
130    return true;
131}
132
133bool Extractor::IsSameHap(const std::string& hapPath) const
134{
135    return !hapPath_.empty() && !hapPath.empty() && hapPath_ == hapPath;
136}
137
138std::unique_ptr<FileMapper> Extractor::GetData(const std::string &fileName, bool) const
139{
140    std::string relativePath = GetRelativePath(fileName);
141    return zipFile_.CreateFileMapper(relativePath, FileMapperType::NORMAL_MEM);
142}
143
144std::shared_ptr<FileMapper> Extractor::GetSafeData(const std::string &fileName)
145{
146    std::string relativePath = GetRelativePath(fileName);
147    if (!StringEndWith(relativePath, EXT_NAME_ABC, sizeof(EXT_NAME_ABC) - 1)) {
148        return nullptr;
149    }
150
151    return zipFile_.CreateFileMapper(relativePath, FileMapperType::SAFE_ABC);
152}
153
154std::unique_ptr<FileMapper> Extractor::GetMmapData(const std::string &fileName)
155{
156    std::string relativePath = GetRelativePath(fileName);
157    return zipFile_.CreateFileMapper(relativePath, FileMapperType::SHARED_MMAP);
158}
159
160bool Extractor::IsStageModel()
161{
162    if (isStageModel_.has_value()) {
163        return isStageModel_.value();
164    }
165    isStageModel_ = !zipFile_.HasEntry("config.json");
166    return isStageModel_.value();
167}
168
169bool Extractor::ExtractToBufByName(const std::string &fileName, std::unique_ptr<uint8_t[]> &dataPtr,
170    size_t &len)
171{
172    std::string relativePath = GetRelativePath(fileName);
173    return zipFile_.ExtractToBufByName(relativePath, dataPtr, len);
174}
175
176bool Extractor::GetFileInfo(const std::string &fileName, FileInfo &fileInfo) const
177{
178    std::string relativePath = GetRelativePath(fileName);
179    ZipEntry zipEntry;
180    if (!zipFile_.GetEntry(relativePath, zipEntry)) {
181        return false;
182    }
183
184    ZipPos offset = 0;
185    uint32_t length = 0;
186    if (!zipFile_.GetDataOffsetRelative(relativePath, offset, length)) {
187        return false;
188    }
189
190    fileInfo.fileName = fileName;
191    fileInfo.offset = static_cast<uint32_t>(offset);
192    fileInfo.length = static_cast<uint32_t>(length);
193    fileInfo.lastModTime = zipEntry.modifiedTime;
194    fileInfo.lastModDate = zipEntry.modifiedDate;
195    return true;
196}
197
198bool Extractor::GetFileList(const std::string &srcPath, std::set<std::string> &fileSet)
199{
200    if (!initial_) {
201        return false;
202    }
203
204    if (srcPath.empty()) {
205        return false;
206    }
207
208    zipFile_.GetChildNames(srcPath, fileSet);
209    if (fileSet.empty()) {
210    }
211
212    return true;
213}
214
215bool Extractor::IsHapCompress(const std::string &fileName) const
216{
217    std::string relativePath = GetRelativePath(fileName);
218    ZipEntry zipEntry;
219    if (!zipFile_.GetEntry(relativePath, zipEntry)) {
220        return false;
221    }
222    return zipEntry.compressionMethod > 0;
223}
224
225std::mutex ExtractorUtil::mapMutex_;
226std::unordered_map<std::string, std::shared_ptr<Extractor>> ExtractorUtil::extractorMap_;
227std::string ExtractorUtil::GetLoadFilePath(const std::string &hapPath)
228{
229    std::string loadPath;
230    if (StringStartWith(hapPath, Constants::ABS_CODE_PATH, std::string(Constants::ABS_CODE_PATH).length())) {
231        loadPath = GetLoadPath(hapPath);
232    } else {
233        loadPath = hapPath;
234    }
235    return loadPath;
236}
237
238std::shared_ptr<Extractor> ExtractorUtil::GetExtractor(const std::string &hapPath, bool &newCreate, bool cache)
239{
240    newCreate = false;
241    if (hapPath.empty()) {
242        return nullptr;
243    }
244    {
245        std::lock_guard<std::mutex> mapMutex(mapMutex_);
246        auto mapIter = extractorMap_.find(hapPath);
247        if (mapIter != extractorMap_.end()) {
248            return mapIter->second;
249        }
250    }
251
252    std::shared_ptr<Extractor> extractor = std::make_shared<Extractor>(hapPath);
253    if (!extractor->Init()) {
254        return nullptr;
255    }
256    if (cache) {
257        std::lock_guard<std::mutex> mapMutex(mapMutex_);
258        extractorMap_.emplace(hapPath, extractor);
259    }
260    newCreate = true;
261    return extractor;
262}
263
264void ExtractorUtil::DeleteExtractor(const std::string &hapPath)
265{
266    if (hapPath.empty()) {
267        return;
268    }
269
270    std::lock_guard<std::mutex> mapMutex(mapMutex_);
271    auto mapIter = extractorMap_.find(hapPath);
272    if (mapIter != extractorMap_.end()) {
273        extractorMap_.erase(mapIter);
274    }
275}
276}  // namespace AbilityBase
277}  // namespace OHOS
278