1600cc4afSopenharmony_ci/*
2600cc4afSopenharmony_ci * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
3600cc4afSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4600cc4afSopenharmony_ci * you may not use this file except in compliance with the License.
5600cc4afSopenharmony_ci * You may obtain a copy of the License at
6600cc4afSopenharmony_ci *
7600cc4afSopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
8600cc4afSopenharmony_ci *
9600cc4afSopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10600cc4afSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
11600cc4afSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12600cc4afSopenharmony_ci * See the License for the specific language governing permissions and
13600cc4afSopenharmony_ci * limitations under the License.
14600cc4afSopenharmony_ci */
15600cc4afSopenharmony_ci
16600cc4afSopenharmony_ci#include "zip_file.h"
17600cc4afSopenharmony_ci
18600cc4afSopenharmony_ci#include <ostream>
19600cc4afSopenharmony_ci
20600cc4afSopenharmony_ci#include "app_log_wrapper.h"
21600cc4afSopenharmony_ci#include "bundle_service_constants.h"
22600cc4afSopenharmony_ci#include "securec.h"
23600cc4afSopenharmony_ci
24600cc4afSopenharmony_cinamespace OHOS {
25600cc4afSopenharmony_cinamespace AppExecFwk {
26600cc4afSopenharmony_cinamespace {
27600cc4afSopenharmony_ciconstexpr uint32_t MAX_FILE_PATH = 4096;
28600cc4afSopenharmony_ciconstexpr uint32_t UNZIP_BUFFER_SIZE = 1024;
29600cc4afSopenharmony_ciconstexpr uint32_t UNZIP_BUF_IN_LEN = 160 * UNZIP_BUFFER_SIZE;   // in  buffer length: 160KB
30600cc4afSopenharmony_ciconstexpr uint32_t UNZIP_BUF_OUT_LEN = 320 * UNZIP_BUFFER_SIZE;  // out buffer length: 320KB
31600cc4afSopenharmony_ciconstexpr uint32_t LOCAL_HEADER_SIGNATURE = 0x04034b50;
32600cc4afSopenharmony_ciconstexpr uint32_t CENTRAL_SIGNATURE = 0x02014b50;
33600cc4afSopenharmony_ciconstexpr uint32_t EOCD_SIGNATURE = 0x06054b50;
34600cc4afSopenharmony_ciconstexpr uint32_t DATA_DESC_SIGNATURE = 0x08074b50;
35600cc4afSopenharmony_ciconstexpr uint32_t FLAG_DATA_DESC = 0x8;
36600cc4afSopenharmony_ciconstexpr size_t FILE_READ_COUNT = 1;
37600cc4afSopenharmony_ciconstexpr uint8_t INFLATE_ERROR_TIMES = 5;
38600cc4afSopenharmony_ci}  // namespace
39600cc4afSopenharmony_ci
40600cc4afSopenharmony_ciZipEntry::ZipEntry(const CentralDirEntry &centralEntry)
41600cc4afSopenharmony_ci{
42600cc4afSopenharmony_ci    compressionMethod = centralEntry.compressionMethod;
43600cc4afSopenharmony_ci    uncompressedSize = centralEntry.uncompressedSize;
44600cc4afSopenharmony_ci    compressedSize = centralEntry.compressedSize;
45600cc4afSopenharmony_ci    localHeaderOffset = centralEntry.localHeaderOffset;
46600cc4afSopenharmony_ci    crc = centralEntry.crc;
47600cc4afSopenharmony_ci    flags = centralEntry.flags;
48600cc4afSopenharmony_ci}
49600cc4afSopenharmony_ci
50600cc4afSopenharmony_ciZipFile::ZipFile(const std::string &pathName) : pathName_(pathName)
51600cc4afSopenharmony_ci{
52600cc4afSopenharmony_ci    APP_LOGD("create instance from %{private}s", pathName_.c_str());
53600cc4afSopenharmony_ci}
54600cc4afSopenharmony_ci
55600cc4afSopenharmony_ciZipFile::~ZipFile()
56600cc4afSopenharmony_ci{
57600cc4afSopenharmony_ci    Close();
58600cc4afSopenharmony_ci}
59600cc4afSopenharmony_ci
60600cc4afSopenharmony_civoid ZipFile::SetContentLocation(const ZipPos start, const size_t length)
61600cc4afSopenharmony_ci{
62600cc4afSopenharmony_ci    APP_LOGD("set content location start position(%{public}llu), length(%{public}zu)", start, length);
63600cc4afSopenharmony_ci    fileStartPos_ = start;
64600cc4afSopenharmony_ci    fileLength_ = length;
65600cc4afSopenharmony_ci}
66600cc4afSopenharmony_ci
67600cc4afSopenharmony_cibool ZipFile::CheckEndDir(const EndDir &endDir) const
68600cc4afSopenharmony_ci{
69600cc4afSopenharmony_ci    size_t lenEndDir = sizeof(EndDir);
70600cc4afSopenharmony_ci    if ((endDir.numDisk != 0) || (endDir.signature != EOCD_SIGNATURE) || (endDir.startDiskOfCentralDir != 0) ||
71600cc4afSopenharmony_ci        (endDir.offset >= fileLength_) || (endDir.totalEntriesInThisDisk != endDir.totalEntries) ||
72600cc4afSopenharmony_ci        (endDir.commentLen != 0) ||
73600cc4afSopenharmony_ci        // central dir can't overlap end of central dir
74600cc4afSopenharmony_ci        ((endDir.offset + endDir.sizeOfCentralDir + lenEndDir) > fileLength_)) {
75600cc4afSopenharmony_ci        APP_LOGE("end dir format error");
76600cc4afSopenharmony_ci        return false;
77600cc4afSopenharmony_ci    }
78600cc4afSopenharmony_ci    return true;
79600cc4afSopenharmony_ci}
80600cc4afSopenharmony_ci
81600cc4afSopenharmony_cibool ZipFile::ParseEndDirectory()
82600cc4afSopenharmony_ci{
83600cc4afSopenharmony_ci    size_t endDirLen = sizeof(EndDir);
84600cc4afSopenharmony_ci    size_t endFilePos = fileStartPos_ + fileLength_;
85600cc4afSopenharmony_ci
86600cc4afSopenharmony_ci    if (fileLength_ <= endDirLen) {
87600cc4afSopenharmony_ci        APP_LOGE("parse EOCD file length(%{public}llu) <= end dir length(%{public}llu)", fileStartPos_, fileLength_);
88600cc4afSopenharmony_ci        return false;
89600cc4afSopenharmony_ci    }
90600cc4afSopenharmony_ci
91600cc4afSopenharmony_ci    size_t eocdPos = endFilePos - endDirLen;
92600cc4afSopenharmony_ci    if (fseek(file_, eocdPos, SEEK_SET) != 0) {
93600cc4afSopenharmony_ci        APP_LOGE("locate EOCD seek failed, error: %{public}d", errno);
94600cc4afSopenharmony_ci        return false;
95600cc4afSopenharmony_ci    }
96600cc4afSopenharmony_ci
97600cc4afSopenharmony_ci    if (fread(&endDir_, sizeof(EndDir), FILE_READ_COUNT, file_) != FILE_READ_COUNT) {
98600cc4afSopenharmony_ci        APP_LOGE("read EOCD struct failed, error: %{public}d", errno);
99600cc4afSopenharmony_ci        return false;
100600cc4afSopenharmony_ci    }
101600cc4afSopenharmony_ci
102600cc4afSopenharmony_ci    centralDirPos_ = endDir_.offset + fileStartPos_;
103600cc4afSopenharmony_ci    APP_LOGD("parse EOCD offset(0x%{public}08x) file start position(0x%{public}08llx)", endDir_.offset, fileStartPos_);
104600cc4afSopenharmony_ci
105600cc4afSopenharmony_ci    return CheckEndDir(endDir_);
106600cc4afSopenharmony_ci}
107600cc4afSopenharmony_ci
108600cc4afSopenharmony_cibool ZipFile::ParseAllEntries()
109600cc4afSopenharmony_ci{
110600cc4afSopenharmony_ci    bool ret = true;
111600cc4afSopenharmony_ci    ZipPos currentPos = centralDirPos_;
112600cc4afSopenharmony_ci    CentralDirEntry directoryEntry = {0};
113600cc4afSopenharmony_ci
114600cc4afSopenharmony_ci    for (uint16_t i = 0; i < endDir_.totalEntries; i++) {
115600cc4afSopenharmony_ci        std::string fileName;
116600cc4afSopenharmony_ci        fileName.reserve(MAX_FILE_PATH);
117600cc4afSopenharmony_ci        fileName.resize(MAX_FILE_PATH - 1);
118600cc4afSopenharmony_ci
119600cc4afSopenharmony_ci        if (fseek(file_, currentPos, SEEK_SET) != 0) {
120600cc4afSopenharmony_ci            APP_LOGE("parse entry(%{public}d) seek zipEntry failed, error: %{public}d", i, errno);
121600cc4afSopenharmony_ci            ret = false;
122600cc4afSopenharmony_ci            break;
123600cc4afSopenharmony_ci        }
124600cc4afSopenharmony_ci
125600cc4afSopenharmony_ci        if (fread(&directoryEntry, sizeof(CentralDirEntry), FILE_READ_COUNT, file_) != FILE_READ_COUNT) {
126600cc4afSopenharmony_ci            APP_LOGE("parse entry(%{public}d) read ZipEntry failed, error: %{public}d", i, errno);
127600cc4afSopenharmony_ci            ret = false;
128600cc4afSopenharmony_ci            break;
129600cc4afSopenharmony_ci        }
130600cc4afSopenharmony_ci
131600cc4afSopenharmony_ci        if (directoryEntry.signature != CENTRAL_SIGNATURE) {
132600cc4afSopenharmony_ci            APP_LOGE("parse entry(%{public}d) check signature(0x%08x) at pos(0x%08llx) failed",
133600cc4afSopenharmony_ci                i,
134600cc4afSopenharmony_ci                directoryEntry.signature,
135600cc4afSopenharmony_ci                currentPos);
136600cc4afSopenharmony_ci            ret = false;
137600cc4afSopenharmony_ci            break;
138600cc4afSopenharmony_ci        }
139600cc4afSopenharmony_ci
140600cc4afSopenharmony_ci        size_t fileLength = (directoryEntry.nameSize >= MAX_FILE_PATH) ? (MAX_FILE_PATH - 1) : directoryEntry.nameSize;
141600cc4afSopenharmony_ci        if (fread(&(fileName[0]), fileLength, FILE_READ_COUNT, file_) != FILE_READ_COUNT) {
142600cc4afSopenharmony_ci            APP_LOGE("parse entry(%{public}d) read file name failed, error: %{public}d", i, errno);
143600cc4afSopenharmony_ci            ret = false;
144600cc4afSopenharmony_ci            break;
145600cc4afSopenharmony_ci        }
146600cc4afSopenharmony_ci        fileName.resize(fileLength);
147600cc4afSopenharmony_ci
148600cc4afSopenharmony_ci        ZipEntry currentEntry(directoryEntry);
149600cc4afSopenharmony_ci        currentEntry.fileName = fileName;
150600cc4afSopenharmony_ci        entriesMap_[fileName] = currentEntry;
151600cc4afSopenharmony_ci
152600cc4afSopenharmony_ci        currentPos += sizeof(directoryEntry);
153600cc4afSopenharmony_ci        currentPos += directoryEntry.nameSize + directoryEntry.extraSize + directoryEntry.commentSize;
154600cc4afSopenharmony_ci    }
155600cc4afSopenharmony_ci
156600cc4afSopenharmony_ci    APP_LOGD("parse %{public}d central entries from %{private}s", endDir_.totalEntries, pathName_.c_str());
157600cc4afSopenharmony_ci    return ret;
158600cc4afSopenharmony_ci}
159600cc4afSopenharmony_ci
160600cc4afSopenharmony_cibool ZipFile::Open()
161600cc4afSopenharmony_ci{
162600cc4afSopenharmony_ci    APP_LOGD("open: %{private}s", pathName_.c_str());
163600cc4afSopenharmony_ci
164600cc4afSopenharmony_ci    if (isOpen_) {
165600cc4afSopenharmony_ci        APP_LOGE("has already opened");
166600cc4afSopenharmony_ci        return true;
167600cc4afSopenharmony_ci    }
168600cc4afSopenharmony_ci
169600cc4afSopenharmony_ci    if (pathName_.length() > PATH_MAX) {
170600cc4afSopenharmony_ci        APP_LOGE("path length(%{public}u) longer than max length(%{public}d)",
171600cc4afSopenharmony_ci            static_cast<unsigned int>(pathName_.length()),
172600cc4afSopenharmony_ci            PATH_MAX);
173600cc4afSopenharmony_ci        return false;
174600cc4afSopenharmony_ci    }
175600cc4afSopenharmony_ci    std::string realPath;
176600cc4afSopenharmony_ci    realPath.reserve(PATH_MAX);
177600cc4afSopenharmony_ci    realPath.resize(PATH_MAX - 1);
178600cc4afSopenharmony_ci    if (realpath(pathName_.c_str(), &(realPath[0])) == nullptr) {
179600cc4afSopenharmony_ci        APP_LOGE("transform real path error: %{public}d", errno);
180600cc4afSopenharmony_ci        return false;
181600cc4afSopenharmony_ci    }
182600cc4afSopenharmony_ci
183600cc4afSopenharmony_ci    FILE *tmpFile = fopen(realPath.c_str(), "rb");
184600cc4afSopenharmony_ci    if (tmpFile == nullptr) {
185600cc4afSopenharmony_ci        APP_LOGE("open file(%{private}s) failed, error: %{public}d", pathName_.c_str(), errno);
186600cc4afSopenharmony_ci        return false;
187600cc4afSopenharmony_ci    }
188600cc4afSopenharmony_ci
189600cc4afSopenharmony_ci    if (fileLength_ == 0) {
190600cc4afSopenharmony_ci        if (fseek(tmpFile, 0, SEEK_END) != 0) {
191600cc4afSopenharmony_ci            APP_LOGE("file seek failed, error: %{public}d", errno);
192600cc4afSopenharmony_ci            fclose(tmpFile);
193600cc4afSopenharmony_ci            return false;
194600cc4afSopenharmony_ci        }
195600cc4afSopenharmony_ci        int64_t fileLength = ftell(tmpFile);
196600cc4afSopenharmony_ci        if (fileLength == -1) {
197600cc4afSopenharmony_ci            APP_LOGE("open file %{private}s failed", pathName_.c_str());
198600cc4afSopenharmony_ci            fclose(tmpFile);
199600cc4afSopenharmony_ci            return false;
200600cc4afSopenharmony_ci        }
201600cc4afSopenharmony_ci        fileLength_ = static_cast<ZipPos>(fileLength);
202600cc4afSopenharmony_ci        if (fileStartPos_ >= fileLength_) {
203600cc4afSopenharmony_ci            APP_LOGE("open start pos > length failed");
204600cc4afSopenharmony_ci            fclose(tmpFile);
205600cc4afSopenharmony_ci            return false;
206600cc4afSopenharmony_ci        }
207600cc4afSopenharmony_ci
208600cc4afSopenharmony_ci        fileLength_ -= fileStartPos_;
209600cc4afSopenharmony_ci    }
210600cc4afSopenharmony_ci
211600cc4afSopenharmony_ci    file_ = tmpFile;
212600cc4afSopenharmony_ci    bool result = ParseEndDirectory();
213600cc4afSopenharmony_ci    if (result) {
214600cc4afSopenharmony_ci        result = ParseAllEntries();
215600cc4afSopenharmony_ci    }
216600cc4afSopenharmony_ci    // it means open file success.
217600cc4afSopenharmony_ci    isOpen_ = true;
218600cc4afSopenharmony_ci    return result;
219600cc4afSopenharmony_ci}
220600cc4afSopenharmony_ci
221600cc4afSopenharmony_civoid ZipFile::Close()
222600cc4afSopenharmony_ci{
223600cc4afSopenharmony_ci    APP_LOGD("close: %{private}s", pathName_.c_str());
224600cc4afSopenharmony_ci
225600cc4afSopenharmony_ci    if (!isOpen_ || file_ == nullptr) {
226600cc4afSopenharmony_ci        APP_LOGW("file is not opened");
227600cc4afSopenharmony_ci        return;
228600cc4afSopenharmony_ci    }
229600cc4afSopenharmony_ci
230600cc4afSopenharmony_ci    entriesMap_.clear();
231600cc4afSopenharmony_ci    pathName_ = "";
232600cc4afSopenharmony_ci    isOpen_ = false;
233600cc4afSopenharmony_ci
234600cc4afSopenharmony_ci    if (fclose(file_) != 0) {
235600cc4afSopenharmony_ci        APP_LOGW("close failed err: %{public}d", errno);
236600cc4afSopenharmony_ci    }
237600cc4afSopenharmony_ci    file_ = nullptr;
238600cc4afSopenharmony_ci}
239600cc4afSopenharmony_ci
240600cc4afSopenharmony_ci// Get all file zipEntry in this file
241600cc4afSopenharmony_ciconst ZipEntryMap &ZipFile::GetAllEntries() const
242600cc4afSopenharmony_ci{
243600cc4afSopenharmony_ci    return entriesMap_;
244600cc4afSopenharmony_ci}
245600cc4afSopenharmony_ci
246600cc4afSopenharmony_cibool ZipFile::HasEntry(const std::string &entryName) const
247600cc4afSopenharmony_ci{
248600cc4afSopenharmony_ci    return entriesMap_.find(entryName) != entriesMap_.end();
249600cc4afSopenharmony_ci}
250600cc4afSopenharmony_ci
251600cc4afSopenharmony_cibool ZipFile::IsDirExist(const std::string &dir) const
252600cc4afSopenharmony_ci{
253600cc4afSopenharmony_ci    APP_LOGD("target dir: %{public}s", dir.c_str());
254600cc4afSopenharmony_ci    if (dir.empty()) {
255600cc4afSopenharmony_ci        APP_LOGE("target dir is empty");
256600cc4afSopenharmony_ci        return false;
257600cc4afSopenharmony_ci    }
258600cc4afSopenharmony_ci
259600cc4afSopenharmony_ci    auto tempDir = dir;
260600cc4afSopenharmony_ci    if (tempDir.back() != ServiceConstants::FILE_SEPARATOR_CHAR) {
261600cc4afSopenharmony_ci        tempDir.push_back(ServiceConstants::FILE_SEPARATOR_CHAR);
262600cc4afSopenharmony_ci    }
263600cc4afSopenharmony_ci
264600cc4afSopenharmony_ci    for (const auto &item : entriesMap_) {
265600cc4afSopenharmony_ci        if (item.first.find(tempDir) == 0) {
266600cc4afSopenharmony_ci            APP_LOGD("find target dir, fileName : %{public}s", item.first.c_str());
267600cc4afSopenharmony_ci            return true;
268600cc4afSopenharmony_ci        }
269600cc4afSopenharmony_ci    }
270600cc4afSopenharmony_ci    APP_LOGD("target dir not found, dir : %{public}s", dir.c_str());
271600cc4afSopenharmony_ci    return false;
272600cc4afSopenharmony_ci}
273600cc4afSopenharmony_ci
274600cc4afSopenharmony_cibool ZipFile::GetEntry(const std::string &entryName, ZipEntry &resultEntry) const
275600cc4afSopenharmony_ci{
276600cc4afSopenharmony_ci    APP_LOGD("get entry by name: %{public}s", entryName.c_str());
277600cc4afSopenharmony_ci    auto iter = entriesMap_.find(entryName);
278600cc4afSopenharmony_ci    if (iter != entriesMap_.end()) {
279600cc4afSopenharmony_ci        resultEntry = iter->second;
280600cc4afSopenharmony_ci        APP_LOGD("get entry succeed");
281600cc4afSopenharmony_ci        return true;
282600cc4afSopenharmony_ci    }
283600cc4afSopenharmony_ci    APP_LOGE("get entry failed");
284600cc4afSopenharmony_ci    return false;
285600cc4afSopenharmony_ci}
286600cc4afSopenharmony_ci
287600cc4afSopenharmony_cisize_t ZipFile::GetLocalHeaderSize(const uint16_t nameSize, const uint16_t extraSize) const
288600cc4afSopenharmony_ci{
289600cc4afSopenharmony_ci    return sizeof(LocalHeader) + nameSize + extraSize;
290600cc4afSopenharmony_ci}
291600cc4afSopenharmony_ci
292600cc4afSopenharmony_cibool ZipFile::CheckDataDesc(const ZipEntry &zipEntry, const LocalHeader &localHeader) const
293600cc4afSopenharmony_ci{
294600cc4afSopenharmony_ci    uint32_t crcLocal = 0;
295600cc4afSopenharmony_ci    uint32_t compressedLocal = 0;
296600cc4afSopenharmony_ci    uint32_t uncompressedLocal = 0;
297600cc4afSopenharmony_ci
298600cc4afSopenharmony_ci    if (localHeader.flags & FLAG_DATA_DESC) {  // use data desc
299600cc4afSopenharmony_ci        DataDesc dataDesc;
300600cc4afSopenharmony_ci        auto descPos = zipEntry.localHeaderOffset + GetLocalHeaderSize(localHeader.nameSize, localHeader.extraSize);
301600cc4afSopenharmony_ci        descPos += fileStartPos_ + zipEntry.compressedSize;
302600cc4afSopenharmony_ci
303600cc4afSopenharmony_ci        if (fseek(file_, descPos, SEEK_SET) != 0) {
304600cc4afSopenharmony_ci            APP_LOGE("check local header seek datadesc failed, error: %{public}d", errno);
305600cc4afSopenharmony_ci            return false;
306600cc4afSopenharmony_ci        }
307600cc4afSopenharmony_ci
308600cc4afSopenharmony_ci        if (fread(&dataDesc, sizeof(DataDesc), FILE_READ_COUNT, file_) != FILE_READ_COUNT) {
309600cc4afSopenharmony_ci            APP_LOGE("check local header read datadesc failed, error: %{public}d", errno);
310600cc4afSopenharmony_ci            return false;
311600cc4afSopenharmony_ci        }
312600cc4afSopenharmony_ci
313600cc4afSopenharmony_ci        if (dataDesc.signature != DATA_DESC_SIGNATURE) {
314600cc4afSopenharmony_ci            APP_LOGE("check local header check datadesc signature failed");
315600cc4afSopenharmony_ci            return false;
316600cc4afSopenharmony_ci        }
317600cc4afSopenharmony_ci
318600cc4afSopenharmony_ci        crcLocal = dataDesc.crc;
319600cc4afSopenharmony_ci        compressedLocal = dataDesc.compressedSize;
320600cc4afSopenharmony_ci        uncompressedLocal = dataDesc.uncompressedSize;
321600cc4afSopenharmony_ci    } else {
322600cc4afSopenharmony_ci        crcLocal = localHeader.crc;
323600cc4afSopenharmony_ci        compressedLocal = localHeader.compressedSize;
324600cc4afSopenharmony_ci        uncompressedLocal = localHeader.uncompressedSize;
325600cc4afSopenharmony_ci    }
326600cc4afSopenharmony_ci
327600cc4afSopenharmony_ci    if ((zipEntry.crc != crcLocal) || (zipEntry.compressedSize != compressedLocal) ||
328600cc4afSopenharmony_ci        (zipEntry.uncompressedSize != uncompressedLocal)) {
329600cc4afSopenharmony_ci        APP_LOGE("check local header compressed size corrupted");
330600cc4afSopenharmony_ci        return false;
331600cc4afSopenharmony_ci    }
332600cc4afSopenharmony_ci
333600cc4afSopenharmony_ci    return true;
334600cc4afSopenharmony_ci}
335600cc4afSopenharmony_ci
336600cc4afSopenharmony_cibool ZipFile::CheckCoherencyLocalHeader(const ZipEntry &zipEntry, uint16_t &extraSize) const
337600cc4afSopenharmony_ci{
338600cc4afSopenharmony_ci    LocalHeader localHeader = {0};
339600cc4afSopenharmony_ci
340600cc4afSopenharmony_ci    if (zipEntry.localHeaderOffset >= fileLength_) {
341600cc4afSopenharmony_ci        APP_LOGE("check local file header offset overflow %{public}d", zipEntry.localHeaderOffset);
342600cc4afSopenharmony_ci        return false;
343600cc4afSopenharmony_ci    }
344600cc4afSopenharmony_ci
345600cc4afSopenharmony_ci    if (fseek(file_, fileStartPos_ + zipEntry.localHeaderOffset, SEEK_SET) != 0) {
346600cc4afSopenharmony_ci        APP_LOGE("check local header seek failed, error: %{public}d", errno);
347600cc4afSopenharmony_ci        return false;
348600cc4afSopenharmony_ci    }
349600cc4afSopenharmony_ci
350600cc4afSopenharmony_ci    if (fread(&localHeader, sizeof(LocalHeader), FILE_READ_COUNT, file_) != FILE_READ_COUNT) {
351600cc4afSopenharmony_ci        APP_LOGE("check local header read localheader failed, error: %{public}d", errno);
352600cc4afSopenharmony_ci        return false;
353600cc4afSopenharmony_ci    }
354600cc4afSopenharmony_ci
355600cc4afSopenharmony_ci    if ((localHeader.signature != LOCAL_HEADER_SIGNATURE) ||
356600cc4afSopenharmony_ci        (zipEntry.compressionMethod != localHeader.compressionMethod)) {
357600cc4afSopenharmony_ci        APP_LOGE("check local header signature or compressionMethod failed");
358600cc4afSopenharmony_ci        return false;
359600cc4afSopenharmony_ci    }
360600cc4afSopenharmony_ci
361600cc4afSopenharmony_ci    // current only support store and Z_DEFLATED method
362600cc4afSopenharmony_ci    if ((zipEntry.compressionMethod != Z_DEFLATED) && (zipEntry.compressionMethod != 0)) {
363600cc4afSopenharmony_ci        APP_LOGE("check local header compressionMethod(%{public}d) not support", zipEntry.compressionMethod);
364600cc4afSopenharmony_ci        return false;
365600cc4afSopenharmony_ci    }
366600cc4afSopenharmony_ci
367600cc4afSopenharmony_ci    std::string fileName;
368600cc4afSopenharmony_ci    fileName.reserve(MAX_FILE_PATH);
369600cc4afSopenharmony_ci    fileName.resize(MAX_FILE_PATH - 1);
370600cc4afSopenharmony_ci    size_t fileLength = (localHeader.nameSize >= MAX_FILE_PATH) ? (MAX_FILE_PATH - 1) : localHeader.nameSize;
371600cc4afSopenharmony_ci    if (fileLength != zipEntry.fileName.length()) {
372600cc4afSopenharmony_ci        APP_LOGE("check local header file name size failed");
373600cc4afSopenharmony_ci        return false;
374600cc4afSopenharmony_ci    }
375600cc4afSopenharmony_ci    if (fread(&(fileName[0]), fileLength, FILE_READ_COUNT, file_) != FILE_READ_COUNT) {
376600cc4afSopenharmony_ci        APP_LOGE("check local header read file name failed, error: %{public}d", errno);
377600cc4afSopenharmony_ci        return false;
378600cc4afSopenharmony_ci    }
379600cc4afSopenharmony_ci    fileName.resize(fileLength);
380600cc4afSopenharmony_ci    if (zipEntry.fileName != fileName) {
381600cc4afSopenharmony_ci        APP_LOGE("check local header file name corrupted");
382600cc4afSopenharmony_ci        return false;
383600cc4afSopenharmony_ci    }
384600cc4afSopenharmony_ci
385600cc4afSopenharmony_ci    if (!CheckDataDesc(zipEntry, localHeader)) {
386600cc4afSopenharmony_ci        APP_LOGE("check data desc failed");
387600cc4afSopenharmony_ci        return false;
388600cc4afSopenharmony_ci    }
389600cc4afSopenharmony_ci
390600cc4afSopenharmony_ci    extraSize = localHeader.extraSize;
391600cc4afSopenharmony_ci    return true;
392600cc4afSopenharmony_ci}
393600cc4afSopenharmony_ci
394600cc4afSopenharmony_cibool ZipFile::SeekToEntryStart(const ZipEntry &zipEntry, const uint16_t extraSize) const
395600cc4afSopenharmony_ci{
396600cc4afSopenharmony_ci    ZipPos startOffset = zipEntry.localHeaderOffset;
397600cc4afSopenharmony_ci    // get data offset, add signature+localheader+namesize+extrasize
398600cc4afSopenharmony_ci    startOffset += GetLocalHeaderSize(zipEntry.fileName.length(), extraSize);
399600cc4afSopenharmony_ci    if (startOffset + zipEntry.compressedSize > fileLength_) {
400600cc4afSopenharmony_ci        APP_LOGE("startOffset(%{public}lld)+entryCompressedSize(%{public}ud) > fileLength(%{public}llu)",
401600cc4afSopenharmony_ci            startOffset,
402600cc4afSopenharmony_ci            zipEntry.compressedSize,
403600cc4afSopenharmony_ci            fileLength_);
404600cc4afSopenharmony_ci        return false;
405600cc4afSopenharmony_ci    }
406600cc4afSopenharmony_ci    startOffset += fileStartPos_;  // add file start relative to file stream
407600cc4afSopenharmony_ci
408600cc4afSopenharmony_ci    APP_LOGD("seek to entry start 0x%{public}08llx", startOffset);
409600cc4afSopenharmony_ci    if (fseek(file_, startOffset, SEEK_SET) != 0) {
410600cc4afSopenharmony_ci        APP_LOGE("seek failed, error: %{public}d", errno);
411600cc4afSopenharmony_ci        return false;
412600cc4afSopenharmony_ci    }
413600cc4afSopenharmony_ci    return true;
414600cc4afSopenharmony_ci}
415600cc4afSopenharmony_ci
416600cc4afSopenharmony_cibool ZipFile::UnzipWithStore(const ZipEntry &zipEntry, const uint16_t extraSize, std::ostream &dest) const
417600cc4afSopenharmony_ci{
418600cc4afSopenharmony_ci    APP_LOGD("unzip with store");
419600cc4afSopenharmony_ci
420600cc4afSopenharmony_ci    if (!SeekToEntryStart(zipEntry, extraSize)) {
421600cc4afSopenharmony_ci        APP_LOGE("seek to entry start failed");
422600cc4afSopenharmony_ci        return false;
423600cc4afSopenharmony_ci    }
424600cc4afSopenharmony_ci
425600cc4afSopenharmony_ci    uint32_t remainSize = zipEntry.compressedSize;
426600cc4afSopenharmony_ci    std::string readBuffer;
427600cc4afSopenharmony_ci    readBuffer.reserve(UNZIP_BUF_OUT_LEN);
428600cc4afSopenharmony_ci    readBuffer.resize(UNZIP_BUF_OUT_LEN - 1);
429600cc4afSopenharmony_ci    while (remainSize > 0) {
430600cc4afSopenharmony_ci        size_t readBytes;
431600cc4afSopenharmony_ci        size_t readLen = (remainSize > UNZIP_BUF_OUT_LEN) ? UNZIP_BUF_OUT_LEN : remainSize;
432600cc4afSopenharmony_ci        readBytes = fread(&(readBuffer[0]), sizeof(Byte), readLen, file_);
433600cc4afSopenharmony_ci        if (readBytes == 0) {
434600cc4afSopenharmony_ci            APP_LOGE("unzip store read failed, error: %{public}d", ferror(file_));
435600cc4afSopenharmony_ci            return false;
436600cc4afSopenharmony_ci        }
437600cc4afSopenharmony_ci        remainSize -= readBytes;
438600cc4afSopenharmony_ci        dest.write(&(readBuffer[0]), readBytes);
439600cc4afSopenharmony_ci    }
440600cc4afSopenharmony_ci
441600cc4afSopenharmony_ci    return true;
442600cc4afSopenharmony_ci}
443600cc4afSopenharmony_ci
444600cc4afSopenharmony_cibool ZipFile::InitZStream(z_stream &zstream) const
445600cc4afSopenharmony_ci{
446600cc4afSopenharmony_ci    // init zlib stream
447600cc4afSopenharmony_ci    if (memset_s(&zstream, sizeof(z_stream), 0, sizeof(z_stream))) {
448600cc4afSopenharmony_ci        APP_LOGE("unzip stream buffer init failed");
449600cc4afSopenharmony_ci        return false;
450600cc4afSopenharmony_ci    }
451600cc4afSopenharmony_ci    int32_t zlibErr = inflateInit2(&zstream, -MAX_WBITS);
452600cc4afSopenharmony_ci    if (zlibErr != Z_OK) {
453600cc4afSopenharmony_ci        APP_LOGE("unzip inflated init failed");
454600cc4afSopenharmony_ci        return false;
455600cc4afSopenharmony_ci    }
456600cc4afSopenharmony_ci
457600cc4afSopenharmony_ci    BytePtr bufOut = new (std::nothrow) Byte[UNZIP_BUF_OUT_LEN];
458600cc4afSopenharmony_ci    if (bufOut == nullptr) {
459600cc4afSopenharmony_ci        APP_LOGE("unzip inflated new out buffer failed");
460600cc4afSopenharmony_ci        return false;
461600cc4afSopenharmony_ci    }
462600cc4afSopenharmony_ci
463600cc4afSopenharmony_ci    BytePtr bufIn = new (std::nothrow) Byte[UNZIP_BUF_IN_LEN];
464600cc4afSopenharmony_ci    if (bufIn == nullptr) {
465600cc4afSopenharmony_ci        APP_LOGE("unzip inflated new in buffer failed");
466600cc4afSopenharmony_ci        delete[] bufOut;
467600cc4afSopenharmony_ci        return false;
468600cc4afSopenharmony_ci    }
469600cc4afSopenharmony_ci    zstream.next_out = bufOut;
470600cc4afSopenharmony_ci    zstream.next_in = bufIn;
471600cc4afSopenharmony_ci    zstream.avail_out = UNZIP_BUF_OUT_LEN;
472600cc4afSopenharmony_ci    return true;
473600cc4afSopenharmony_ci}
474600cc4afSopenharmony_ci
475600cc4afSopenharmony_cibool ZipFile::ReadZStream(const BytePtr &buffer, z_stream &zstream, uint32_t &remainCompressedSize) const
476600cc4afSopenharmony_ci{
477600cc4afSopenharmony_ci    if (zstream.avail_in == 0) {
478600cc4afSopenharmony_ci        size_t readBytes;
479600cc4afSopenharmony_ci        size_t remainBytes = (remainCompressedSize > UNZIP_BUF_IN_LEN) ? UNZIP_BUF_IN_LEN : remainCompressedSize;
480600cc4afSopenharmony_ci        readBytes = fread(buffer, sizeof(Byte), remainBytes, file_);
481600cc4afSopenharmony_ci        if (readBytes == 0) {
482600cc4afSopenharmony_ci            APP_LOGE("unzip inflated read failed, error: %{public}d", ferror(file_));
483600cc4afSopenharmony_ci            return false;
484600cc4afSopenharmony_ci        }
485600cc4afSopenharmony_ci
486600cc4afSopenharmony_ci        remainCompressedSize -= readBytes;
487600cc4afSopenharmony_ci        zstream.avail_in = readBytes;
488600cc4afSopenharmony_ci        zstream.next_in = buffer;
489600cc4afSopenharmony_ci    }
490600cc4afSopenharmony_ci    return true;
491600cc4afSopenharmony_ci}
492600cc4afSopenharmony_ci
493600cc4afSopenharmony_cibool ZipFile::UnzipWithInflated(const ZipEntry &zipEntry, const uint16_t extraSize, std::ostream &dest) const
494600cc4afSopenharmony_ci{
495600cc4afSopenharmony_ci    APP_LOGD("unzip with inflated");
496600cc4afSopenharmony_ci
497600cc4afSopenharmony_ci    z_stream zstream;
498600cc4afSopenharmony_ci    if (!SeekToEntryStart(zipEntry, extraSize) || !InitZStream(zstream)) {
499600cc4afSopenharmony_ci        return false;
500600cc4afSopenharmony_ci    }
501600cc4afSopenharmony_ci
502600cc4afSopenharmony_ci    BytePtr bufIn = zstream.next_in;
503600cc4afSopenharmony_ci    BytePtr bufOut = zstream.next_out;
504600cc4afSopenharmony_ci
505600cc4afSopenharmony_ci    bool ret = true;
506600cc4afSopenharmony_ci    int32_t zlibErr = Z_OK;
507600cc4afSopenharmony_ci    uint32_t remainCompressedSize = zipEntry.compressedSize;
508600cc4afSopenharmony_ci    uint8_t errorTimes = 0;
509600cc4afSopenharmony_ci    while ((remainCompressedSize > 0) || (zstream.avail_in > 0)) {
510600cc4afSopenharmony_ci        if (!ReadZStream(bufIn, zstream, remainCompressedSize)) {
511600cc4afSopenharmony_ci            ret = false;
512600cc4afSopenharmony_ci            break;
513600cc4afSopenharmony_ci        }
514600cc4afSopenharmony_ci
515600cc4afSopenharmony_ci        zlibErr = inflate(&zstream, Z_SYNC_FLUSH);
516600cc4afSopenharmony_ci        if ((zlibErr >= Z_OK) && (zstream.msg != nullptr)) {
517600cc4afSopenharmony_ci            APP_LOGE("unzip inflated inflate, error: %{public}d, err msg: %{public}s", zlibErr, zstream.msg);
518600cc4afSopenharmony_ci            ret = false;
519600cc4afSopenharmony_ci            break;
520600cc4afSopenharmony_ci        }
521600cc4afSopenharmony_ci
522600cc4afSopenharmony_ci        size_t inflateLen = UNZIP_BUF_OUT_LEN - zstream.avail_out;
523600cc4afSopenharmony_ci        if (inflateLen > 0) {
524600cc4afSopenharmony_ci            dest.write(reinterpret_cast<const char *>(bufOut), inflateLen);
525600cc4afSopenharmony_ci            zstream.next_out = bufOut;
526600cc4afSopenharmony_ci            zstream.avail_out = UNZIP_BUF_OUT_LEN;
527600cc4afSopenharmony_ci            errorTimes = 0;
528600cc4afSopenharmony_ci        } else {
529600cc4afSopenharmony_ci            errorTimes++;
530600cc4afSopenharmony_ci        }
531600cc4afSopenharmony_ci        if (errorTimes >= INFLATE_ERROR_TIMES) {
532600cc4afSopenharmony_ci            APP_LOGE("unzip inflated data is abnormal");
533600cc4afSopenharmony_ci            ret = false;
534600cc4afSopenharmony_ci            break;
535600cc4afSopenharmony_ci        }
536600cc4afSopenharmony_ci    }
537600cc4afSopenharmony_ci
538600cc4afSopenharmony_ci    // free all dynamically allocated data structures except the next_in and next_out for this stream.
539600cc4afSopenharmony_ci    zlibErr = inflateEnd(&zstream);
540600cc4afSopenharmony_ci    if (zlibErr != Z_OK) {
541600cc4afSopenharmony_ci        APP_LOGE("unzip inflateEnd error %{public}d", zlibErr);
542600cc4afSopenharmony_ci        ret = false;
543600cc4afSopenharmony_ci    }
544600cc4afSopenharmony_ci
545600cc4afSopenharmony_ci    delete[] bufOut;
546600cc4afSopenharmony_ci    delete[] bufIn;
547600cc4afSopenharmony_ci    return ret;
548600cc4afSopenharmony_ci}
549600cc4afSopenharmony_ci
550600cc4afSopenharmony_ciZipPos ZipFile::GetEntryDataOffset(const ZipEntry &zipEntry, const uint16_t extraSize) const
551600cc4afSopenharmony_ci{
552600cc4afSopenharmony_ci    // get entry data offset relative file
553600cc4afSopenharmony_ci    ZipPos offset = zipEntry.localHeaderOffset;
554600cc4afSopenharmony_ci
555600cc4afSopenharmony_ci    offset += GetLocalHeaderSize(zipEntry.fileName.length(), extraSize);
556600cc4afSopenharmony_ci    offset += fileStartPos_;
557600cc4afSopenharmony_ci
558600cc4afSopenharmony_ci    return offset;
559600cc4afSopenharmony_ci}
560600cc4afSopenharmony_ci
561600cc4afSopenharmony_cibool ZipFile::GetDataOffsetRelative(const std::string &file, ZipPos &offset, uint32_t &length) const
562600cc4afSopenharmony_ci{
563600cc4afSopenharmony_ci    APP_LOGD("get data relative offset for file %{private}s", file.c_str());
564600cc4afSopenharmony_ci
565600cc4afSopenharmony_ci    ZipEntry zipEntry;
566600cc4afSopenharmony_ci    if (!GetEntry(file, zipEntry)) {
567600cc4afSopenharmony_ci        APP_LOGE("extract file: not find file");
568600cc4afSopenharmony_ci        return false;
569600cc4afSopenharmony_ci    }
570600cc4afSopenharmony_ci
571600cc4afSopenharmony_ci    uint16_t extraSize = 0;
572600cc4afSopenharmony_ci    if (!CheckCoherencyLocalHeader(zipEntry, extraSize)) {
573600cc4afSopenharmony_ci        APP_LOGE("check coherency local header failed");
574600cc4afSopenharmony_ci        return false;
575600cc4afSopenharmony_ci    }
576600cc4afSopenharmony_ci
577600cc4afSopenharmony_ci    offset = GetEntryDataOffset(zipEntry, extraSize);
578600cc4afSopenharmony_ci    length = zipEntry.compressedSize;
579600cc4afSopenharmony_ci    return true;
580600cc4afSopenharmony_ci}
581600cc4afSopenharmony_ci
582600cc4afSopenharmony_cibool ZipFile::ExtractFile(const std::string &file, std::ostream &dest) const
583600cc4afSopenharmony_ci{
584600cc4afSopenharmony_ci    APP_LOGD("extract file %{private}s", file.c_str());
585600cc4afSopenharmony_ci
586600cc4afSopenharmony_ci    ZipEntry zipEntry;
587600cc4afSopenharmony_ci    if (!GetEntry(file, zipEntry)) {
588600cc4afSopenharmony_ci        APP_LOGE("extract file: not find file");
589600cc4afSopenharmony_ci        return false;
590600cc4afSopenharmony_ci    }
591600cc4afSopenharmony_ci
592600cc4afSopenharmony_ci    uint16_t extraSize = 0;
593600cc4afSopenharmony_ci    if (!CheckCoherencyLocalHeader(zipEntry, extraSize)) {
594600cc4afSopenharmony_ci        APP_LOGE("check coherency local header failed");
595600cc4afSopenharmony_ci        return false;
596600cc4afSopenharmony_ci    }
597600cc4afSopenharmony_ci
598600cc4afSopenharmony_ci    bool ret = true;
599600cc4afSopenharmony_ci    if (zipEntry.compressionMethod == 0) {
600600cc4afSopenharmony_ci        ret = UnzipWithStore(zipEntry, extraSize, dest);
601600cc4afSopenharmony_ci    } else {
602600cc4afSopenharmony_ci        ret = UnzipWithInflated(zipEntry, extraSize, dest);
603600cc4afSopenharmony_ci    }
604600cc4afSopenharmony_ci
605600cc4afSopenharmony_ci    return ret;
606600cc4afSopenharmony_ci}
607600cc4afSopenharmony_ci}  // namespace AppExecFwk
608600cc4afSopenharmony_ci}  // namespace OHOS
609