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 "zip_file.h"
17
18#include <ostream>
19#include "securec.h"
20#include "zip_file_reader.h"
21
22namespace panda {
23namespace ecmascript {
24namespace {
25constexpr uint32_t MAX_FILE_NAME = 4096;
26constexpr uint32_t UNZIP_BUFFER_SIZE = 1024;
27constexpr uint32_t UNZIP_BUF_IN_LEN = 160 * UNZIP_BUFFER_SIZE;   // in  buffer length: 160KB
28constexpr uint32_t UNZIP_BUF_OUT_LEN = 320 * UNZIP_BUFFER_SIZE;  // out buffer length: 320KB
29constexpr uint32_t LOCAL_HEADER_SIGNATURE = 0x04034b50;
30constexpr uint32_t CENTRAL_SIGNATURE = 0x02014b50;
31constexpr uint32_t EOCD_SIGNATURE = 0x06054b50;
32constexpr uint32_t DATA_DESC_SIGNATURE = 0x08074b50;
33constexpr uint32_t FLAG_DATA_DESC = 0x8;
34constexpr uint8_t INFLATE_ERROR_TIMES = 5;
35const char FILE_SEPARATOR_CHAR = '/';
36}  // namespace
37
38ZipEntry::ZipEntry(const CentralDirEntry &centralEntry)
39{
40    compressionMethod = centralEntry.compressionMethod;
41    uncompressedSize = centralEntry.uncompressedSize;
42    compressedSize = centralEntry.compressedSize;
43    localHeaderOffset = centralEntry.localHeaderOffset;
44    crc = centralEntry.crc;
45    flags = centralEntry.flags;
46    modifiedTime = centralEntry.modifiedTime;
47    modifiedDate = centralEntry.modifiedDate;
48}
49
50ZipFile::ZipFile(const std::string &pathName) : pathName_(pathName)
51{
52    dirRoot_ = std::make_shared<DirTreeNode>();
53}
54
55ZipFile::~ZipFile()
56{
57    Close();
58}
59
60void ZipFile::SetContentLocation(const ZipPos start, const size_t length)
61{
62    if (isOpen_) {
63        return;
64    }
65    fileStartPos_ = start;
66    fileLength_ = length;
67}
68
69bool ZipFile::CheckEndDir(const EndDir &endDir) const
70{
71    size_t lenEndDir = sizeof(EndDir);
72    if ((endDir.numDisk != 0) || (endDir.signature != EOCD_SIGNATURE) || (endDir.startDiskOfCentralDir != 0) ||
73        (endDir.offset >= fileLength_) || (endDir.totalEntriesInThisDisk != endDir.totalEntries) ||
74        (endDir.commentLen != 0) ||
75        // central dir can't overlap end of central dir
76        ((endDir.offset + endDir.sizeOfCentralDir + lenEndDir) > fileLength_)) {
77        return false;
78    }
79    return true;
80}
81
82bool ZipFile::ParseEndDirectory()
83{
84    size_t endDirLen = sizeof(EndDir);
85    size_t endFilePos = fileStartPos_ + fileLength_;
86
87    if (fileLength_ <= endDirLen) {
88        return false;
89    }
90
91    size_t eocdPos = endFilePos - endDirLen;
92    if (!zipFileReader_->ReadBuffer(reinterpret_cast<uint8_t*>(&endDir_), eocdPos, sizeof(EndDir))) {
93        return false;
94    }
95
96    centralDirPos_ = endDir_.offset + fileStartPos_;
97
98    return CheckEndDir(endDir_);
99}
100
101bool ZipFile::ParseOneEntry(uint8_t* &entryPtr)
102{
103    if (entryPtr == nullptr) {
104        return false;
105    }
106
107    CentralDirEntry directoryEntry;
108    if (memcpy_s(&directoryEntry, sizeof(CentralDirEntry), entryPtr, sizeof(CentralDirEntry)) != EOK) {
109        return false;
110    }
111
112    if (directoryEntry.signature != CENTRAL_SIGNATURE) {
113        return false;
114    }
115
116    entryPtr += sizeof(CentralDirEntry);
117    size_t fileLength = (directoryEntry.nameSize >= MAX_FILE_NAME) ? (MAX_FILE_NAME - 1) : directoryEntry.nameSize;
118    std::string fileName(fileLength, 0);
119    if (memcpy_s(&(fileName[0]), fileLength, entryPtr, fileLength) != EOK) {
120        return false;
121    }
122
123    ZipEntry currentEntry(directoryEntry);
124    currentEntry.fileName = fileName;
125    entriesMap_[fileName] = currentEntry;
126    AddEntryToTree(fileName);
127    entryPtr += directoryEntry.nameSize + directoryEntry.extraSize + directoryEntry.commentSize;
128    return true;
129}
130
131void ZipFile::AddEntryToTree(const std::string &fileName)
132{
133    size_t cur = 0;
134    auto parent = dirRoot_;
135    do {
136        while (cur < fileName.size() && fileName[cur] == FILE_SEPARATOR_CHAR) {
137            cur++;
138        }
139        if (cur >= fileName.size()) {
140            break;
141        }
142        auto next = fileName.find_first_of(FILE_SEPARATOR_CHAR, cur);
143        auto nodeName = fileName.substr(cur, next - cur);
144        auto it = parent->children.find(nodeName);
145        if (it != parent->children.end()) {
146            parent = it->second;
147        } else {
148            auto node = std::make_shared<DirTreeNode>();
149            parent->children.emplace(nodeName, node);
150            parent = node;
151        }
152        cur = next;
153    } while (cur != std::string::npos);
154}
155
156bool ZipFile::ParseAllEntries()
157{
158    auto centralData = zipFileReader_->ReadBuffer(static_cast<size_t>(centralDirPos_),
159        static_cast<size_t>(endDir_.sizeOfCentralDir));
160    if (centralData.empty()) {
161        return false;
162    }
163
164    bool ret = true;
165    uint8_t *entryPtr = reinterpret_cast<uint8_t *>(centralData.data());
166    for (uint16_t i = 0; i < endDir_.totalEntries; i++) {
167        if (!ParseOneEntry(entryPtr)) {
168            ret = false;
169            break;
170        }
171    }
172
173    return ret;
174}
175
176bool ZipFile::Open()
177{
178    if (isOpen_) {
179        return true;
180    }
181
182    if (pathName_.length() > PATH_MAX) {
183        return false;
184    }
185
186    zipFileReader_ = ZipFileReader::CreateZipFileReader(pathName_);
187    if (!zipFileReader_) {
188        return false;
189    }
190
191    if (fileLength_ == 0) {
192        auto fileLength = zipFileReader_->GetFileLen();
193        fileLength_ = static_cast<ZipPos>(fileLength);
194        if (fileStartPos_ >= fileLength_) {
195            zipFileReader_.reset();
196            return false;
197        }
198
199        fileLength_ -= fileStartPos_;
200    }
201
202    bool result = ParseEndDirectory();
203    if (result) {
204        result = ParseAllEntries();
205    }
206    // it means open file success.
207    isOpen_ = true;
208    return result;
209}
210
211void ZipFile::Close()
212{
213    if (!isOpen_ || zipFileReader_ == nullptr) {
214        return;
215    }
216
217    isOpen_ = false;
218    entriesMap_.clear();
219    dirRoot_->children.clear();
220    pathName_ = "";
221
222    zipFileReader_.reset();
223}
224
225// Get all file zipEntry in this file
226const ZipEntryMap &ZipFile::GetAllEntries() const
227{
228    return entriesMap_;
229}
230
231bool ZipFile::HasEntry(const std::string &entryName) const
232{
233    return entriesMap_.find(entryName) != entriesMap_.end();
234}
235
236bool ZipFile::IsDirExist(const std::string &dir) const
237{
238    if (dir.empty()) {
239        return false;
240    }
241
242    size_t cur = 0;
243    auto parent = dirRoot_;
244    do {
245        while (cur < dir.size() && dir[cur] == FILE_SEPARATOR_CHAR) {
246            cur++;
247        }
248        if (cur >= dir.size()) {
249            break;
250        }
251        auto next = dir.find_first_of(FILE_SEPARATOR_CHAR, cur);
252        auto nodeName = dir.substr(cur, next - cur);
253        auto it = parent->children.find(nodeName);
254        if (it == parent->children.end()) {
255            return false;
256        }
257        parent = it->second;
258        cur = next;
259    } while (cur != std::string::npos);
260
261    return true;
262}
263namespace {
264void GetTreeFileList(const std::shared_ptr<DirTreeNode> &root, const std::string &rootPath,
265    std::vector<std::string> &assetList)
266{
267    if (root->children.empty()) {
268        assetList.push_back(rootPath);
269    } else {
270        for (const auto &child : root->children) {
271            GetTreeFileList(child.second, rootPath + "/" + child.first, assetList);
272        }
273    }
274}
275}
276
277void ZipFile::GetAllFileList(const std::string &srcPath, std::vector<std::string> &assetList)
278{
279    if (srcPath.empty()) {
280        return;
281    }
282
283    auto rootName = srcPath.back() == FILE_SEPARATOR_CHAR ?
284        srcPath.substr(0, srcPath.length() - 1) : srcPath;
285
286    size_t cur = 0;
287    auto parent = dirRoot_;
288    do {
289        while (cur < rootName.size() && rootName[cur] == FILE_SEPARATOR_CHAR) {
290            cur++;
291        }
292        if (cur >= rootName.size()) {
293            break;
294        }
295        auto next = rootName.find_first_of(FILE_SEPARATOR_CHAR, cur);
296        auto nodeName = (next == std::string::npos) ? rootName.substr(cur) :
297            rootName.substr(cur, next - cur);
298        auto it = parent->children.find(nodeName);
299        if (it == parent->children.end()) {
300            return;
301        }
302        parent = it->second;
303        cur = next;
304    } while (cur != std::string::npos);
305
306    GetTreeFileList(parent, rootName, assetList);
307}
308
309void ZipFile::GetChildNames(const std::string &srcPath, std::set<std::string> &fileSet)
310{
311    if (srcPath.empty()) {
312        return;
313    }
314
315    size_t cur = 0;
316    auto parent = dirRoot_;
317    do {
318        while (cur < srcPath.size() && srcPath[cur] == FILE_SEPARATOR_CHAR) {
319            cur++;
320        }
321        if (cur >= srcPath.size()) {
322            break;
323        }
324        auto next = srcPath.find_first_of(FILE_SEPARATOR_CHAR, cur);
325        auto nodeName = srcPath.substr(cur, next - cur);
326        auto it = parent->children.find(nodeName);
327        if (it == parent->children.end()) {
328            return;
329        }
330        parent = it->second;
331        cur = next;
332    } while (cur != std::string::npos);
333
334    for (const auto &child : parent->children) {
335        fileSet.insert(child.first);
336    }
337}
338
339bool ZipFile::GetEntry(const std::string &entryName, ZipEntry &resultEntry) const
340{
341    auto iter = entriesMap_.find(entryName);
342    if (iter != entriesMap_.end()) {
343        resultEntry = iter->second;
344        return true;
345    }
346    return false;
347}
348
349size_t ZipFile::GetLocalHeaderSize(const uint16_t nameSize, const uint16_t extraSize) const
350{
351    return sizeof(LocalHeader) + nameSize + extraSize;
352}
353
354bool ZipFile::CheckDataDesc(const ZipEntry &zipEntry, const LocalHeader &localHeader) const
355{
356    uint32_t crcLocal = 0;
357    uint32_t compressedLocal = 0;
358    uint32_t uncompressedLocal = 0;
359
360    if (localHeader.flags & FLAG_DATA_DESC) {  // use data desc
361        DataDesc dataDesc;
362        auto descPos = zipEntry.localHeaderOffset + GetLocalHeaderSize(localHeader.nameSize, localHeader.extraSize);
363        descPos += fileStartPos_ + zipEntry.compressedSize;
364
365        if (!zipFileReader_->ReadBuffer(reinterpret_cast<uint8_t*>(&dataDesc), descPos, sizeof(DataDesc))) {
366            return false;
367        }
368
369        if (dataDesc.signature != DATA_DESC_SIGNATURE) {
370            return false;
371        }
372
373        crcLocal = dataDesc.crc;
374        compressedLocal = dataDesc.compressedSize;
375        uncompressedLocal = dataDesc.uncompressedSize;
376    } else {
377        crcLocal = localHeader.crc;
378        compressedLocal = localHeader.compressedSize;
379        uncompressedLocal = localHeader.uncompressedSize;
380    }
381
382    if ((zipEntry.crc != crcLocal) || (zipEntry.compressedSize != compressedLocal) ||
383        (zipEntry.uncompressedSize != uncompressedLocal)) {
384        return false;
385    }
386
387    return true;
388}
389
390bool ZipFile::CheckCoherencyLocalHeader(const ZipEntry &zipEntry, uint16_t &extraSize) const
391{
392    // current only support store and Z_DEFLATED method
393    if ((zipEntry.compressionMethod != Z_DEFLATED) && (zipEntry.compressionMethod != 0)) {
394        return false;
395    }
396
397    auto nameSize = zipEntry.fileName.length();
398    auto startPos = fileStartPos_ + zipEntry.localHeaderOffset;
399    size_t buffSize = sizeof(LocalHeader) + nameSize;
400    auto buff = zipFileReader_->ReadBuffer(startPos, buffSize);
401    if (buff.size() < buffSize) {
402        return false;
403    }
404
405    LocalHeader localHeader = {0};
406    if (memcpy_s(&localHeader, sizeof(LocalHeader), buff.data(), sizeof(LocalHeader)) != EOK) {
407        return false;
408    }
409    if ((localHeader.signature != LOCAL_HEADER_SIGNATURE) ||
410        (zipEntry.compressionMethod != localHeader.compressionMethod)) {
411        return false;
412    }
413
414    if (localHeader.nameSize != nameSize && nameSize < MAX_FILE_NAME - 1) {
415        return false;
416    }
417    std::string fileName = buff.substr(sizeof(LocalHeader));
418    if (zipEntry.fileName != fileName) {
419        return false;
420    }
421
422    if (!CheckDataDesc(zipEntry, localHeader)) {
423        return false;
424    }
425
426    extraSize = localHeader.extraSize;
427    return true;
428}
429
430size_t ZipFile::GetEntryStart(const ZipEntry &zipEntry, const uint16_t extraSize) const
431{
432    ZipPos startOffset = zipEntry.localHeaderOffset;
433    // get data offset, add signature+localheader+namesize+extrasize
434    startOffset += GetLocalHeaderSize(zipEntry.fileName.length(), extraSize);
435    startOffset += fileStartPos_;  // add file start relative to file stream
436
437    return startOffset;
438}
439
440bool ZipFile::UnzipWithStore(const ZipEntry &zipEntry, const uint16_t extraSize, std::ostream &dest) const
441{
442    auto startPos = GetEntryStart(zipEntry, extraSize);
443    uint32_t remainSize = zipEntry.compressedSize;
444    while (remainSize > 0) {
445        size_t readLen = (remainSize > UNZIP_BUF_OUT_LEN) ? UNZIP_BUF_OUT_LEN : remainSize;
446        std::string readBuffer = zipFileReader_->ReadBuffer(startPos, readLen);
447        if (readBuffer.empty()) {
448            return false;
449        }
450        remainSize -= readLen;
451        startPos += readLen;
452        dest.write(readBuffer.data(), readBuffer.length());
453    }
454    return true;
455}
456
457bool ZipFile::InitZStream(z_stream &zstream) const
458{
459    // init zlib stream
460    if (memset_s(&zstream, sizeof(z_stream), 0, sizeof(z_stream))) {
461        return false;
462    }
463    int32_t zlibErr = inflateInit2(&zstream, -MAX_WBITS);
464    if (zlibErr != Z_OK) {
465        return false;
466    }
467
468    BytePtr bufOut = new (std::nothrow) Byte[UNZIP_BUF_OUT_LEN];
469    if (bufOut == nullptr) {
470        return false;
471    }
472
473    BytePtr bufIn = new (std::nothrow) Byte[UNZIP_BUF_IN_LEN];
474    if (bufIn == nullptr) {
475        delete[] bufOut;
476        return false;
477    }
478    zstream.next_out = bufOut;
479    zstream.next_in = bufIn;
480    zstream.avail_out = UNZIP_BUF_OUT_LEN;
481    return true;
482}
483
484bool ZipFile::ReadZStream(const BytePtr &buffer, z_stream &zstream, uint32_t &remainCompressedSize,
485    size_t &startPos) const
486{
487    if (zstream.avail_in == 0) {
488        size_t remainBytes = (remainCompressedSize > UNZIP_BUF_IN_LEN) ? UNZIP_BUF_IN_LEN : remainCompressedSize;
489        if (!zipFileReader_->ReadBuffer(buffer, startPos, remainBytes)) {
490            return false;
491        }
492
493        remainCompressedSize -= remainBytes;
494        startPos += remainBytes;
495        zstream.avail_in = remainBytes;
496        zstream.next_in = buffer;
497    }
498    return true;
499}
500
501bool ZipFile::UnzipWithInflated(const ZipEntry &zipEntry, const uint16_t extraSize, std::ostream &dest) const
502{
503    z_stream zstream;
504    if (!InitZStream(zstream)) {
505        return false;
506    }
507
508    auto startPos = GetEntryStart(zipEntry, extraSize);
509
510    BytePtr bufIn = zstream.next_in;
511    BytePtr bufOut = zstream.next_out;
512
513    bool ret = true;
514    int32_t zlibErr = Z_OK;
515    uint32_t remainCompressedSize = zipEntry.compressedSize;
516    size_t inflateLen = 0;
517    uint8_t errorTimes = 0;
518    while ((remainCompressedSize > 0) || (zstream.avail_in > 0)) {
519        if (!ReadZStream(bufIn, zstream, remainCompressedSize, startPos)) {
520            ret = false;
521            break;
522        }
523
524        zlibErr = inflate(&zstream, Z_SYNC_FLUSH);
525        if ((zlibErr >= Z_OK) && (zstream.msg != nullptr)) {
526            ret = false;
527            break;
528        }
529
530        inflateLen = UNZIP_BUF_OUT_LEN - zstream.avail_out;
531        if (inflateLen > 0) {
532            dest.write((const char *)bufOut, inflateLen);
533            zstream.next_out = bufOut;
534            zstream.avail_out = UNZIP_BUF_OUT_LEN;
535            errorTimes = 0;
536        } else {
537            errorTimes++;
538        }
539        if (errorTimes >= INFLATE_ERROR_TIMES) {
540            ret = false;
541            break;
542        }
543    }
544
545    // free all dynamically allocated data structures except the next_in and next_out for this stream.
546    zlibErr = inflateEnd(&zstream);
547    if (zlibErr != Z_OK) {
548        ret = false;
549    }
550
551    delete[] bufOut;
552    delete[] bufIn;
553    return ret;
554}
555
556ZipPos ZipFile::GetEntryDataOffset(const ZipEntry &zipEntry, const uint16_t extraSize) const
557{
558    // get entry data offset relative file
559    ZipPos offset = zipEntry.localHeaderOffset;
560
561    offset += GetLocalHeaderSize(zipEntry.fileName.length(), extraSize);
562    offset += fileStartPos_;
563
564    return offset;
565}
566
567bool ZipFile::GetDataOffsetRelative(const std::string &file, ZipPos &offset, uint32_t &length) const
568{
569    ZipEntry zipEntry;
570    if (!GetEntry(file, zipEntry)) {
571        return false;
572    }
573
574    return GetDataOffsetRelative(zipEntry, offset, length);
575}
576
577bool ZipFile::GetDataOffsetRelative(const ZipEntry &zipEntry, ZipPos &offset, uint32_t &length) const
578{
579    uint16_t extraSize = 0;
580    if (!CheckCoherencyLocalHeader(zipEntry, extraSize)) {
581        return false;
582    }
583
584    offset = GetEntryDataOffset(zipEntry, extraSize);
585    length = zipEntry.compressedSize;
586    return true;
587}
588
589bool ZipFile::ExtractFile(const std::string &file, std::ostream &dest) const
590{
591    ZipEntry zipEntry;
592    if (!GetEntry(file, zipEntry)) {
593        return false;
594    }
595
596    uint16_t extraSize = 0;
597    if (!CheckCoherencyLocalHeader(zipEntry, extraSize)) {
598        return false;
599    }
600
601    bool ret = true;
602    if (zipEntry.compressionMethod == 0) {
603        ret = UnzipWithStore(zipEntry, extraSize, dest);
604    } else {
605        ret = UnzipWithInflated(zipEntry, extraSize, dest);
606    }
607
608    return ret;
609}
610
611bool ZipFile::ReadZStreamFromMMap(const BytePtr &buffer, void* &dataPtr,
612    z_stream &zstream, uint32_t &remainCompressedSize) const
613{
614    if (!dataPtr) {
615        return false;
616    }
617
618    uint8_t *srcDataPtr = static_cast<uint8_t *>(dataPtr);
619    if (zstream.avail_in == 0) {
620        size_t remainBytes = (remainCompressedSize > UNZIP_BUF_IN_LEN) ? UNZIP_BUF_IN_LEN : remainCompressedSize;
621        size_t readBytes = sizeof(Byte) * remainBytes;
622        if (memcpy_s(buffer, readBytes, srcDataPtr, readBytes) != EOK) {
623            return false;
624        }
625        srcDataPtr += readBytes;
626        remainCompressedSize -= remainBytes;
627        zstream.avail_in = remainBytes;
628        zstream.next_in = buffer;
629    }
630    dataPtr = srcDataPtr;
631    return true;
632}
633
634std::unique_ptr<FileMapper> ZipFile::CreateFileMapper(const std::string &fileName, FileMapperType type) const
635{
636    ZipEntry zipEntry;
637    if (!GetEntry(fileName, zipEntry)) {
638        return nullptr;
639    }
640
641    ZipPos offset = 0;
642    uint32_t length = 0;
643    if (!GetDataOffsetRelative(zipEntry, offset, length)) {
644        return nullptr;
645    }
646    bool compress = zipEntry.compressionMethod > 0;
647    if (type == FileMapperType::SAFE_ABC && compress) {
648    }
649    std::unique_ptr<FileMapper> fileMapper = std::make_unique<FileMapper>();
650    auto result = false;
651    if (type == FileMapperType::NORMAL_MEM) {
652        result = fileMapper->CreateFileMapper(zipFileReader_, fileName, offset, length, compress);
653    } else {
654        result = fileMapper->CreateFileMapper(fileName, compress, zipFileReader_->GetFd(), offset, length, type);
655        if (result && type == FileMapperType::SAFE_ABC) {
656            zipFileReader_->SetClosable(false);
657        }
658    }
659
660    if (!result) {
661        return nullptr;
662    }
663    return fileMapper;
664}
665
666bool ZipFile::UnzipWithInflatedFromMMap(const ZipEntry &zipEntry, [[maybe_unused]] const uint16_t extraSize,
667    void *mmapDataPtr, std::unique_ptr<uint8_t[]> &dataPtr, size_t &len) const
668{
669    z_stream zstream;
670    if (!InitZStream(zstream)) {
671        return false;
672    }
673
674    BytePtr bufIn = zstream.next_in;
675    BytePtr bufOut = zstream.next_out;
676
677    bool ret = true;
678    int32_t zlibErr = Z_OK;
679    uint32_t remainCompressedSize = zipEntry.compressedSize;
680    size_t inflateLen = 0;
681    uint8_t errorTimes = 0;
682
683    len = zipEntry.uncompressedSize;
684    dataPtr = std::make_unique<uint8_t[]>(len);
685    if (!dataPtr) {
686        delete[] bufOut;
687        delete[] bufIn;
688        return false;
689    }
690    uint8_t *dstDataPtr = static_cast<uint8_t *>(dataPtr.get());
691    void *mmapSrcDataPtr = mmapDataPtr;
692
693    while ((remainCompressedSize > 0) || (zstream.avail_in > 0)) {
694        if (!ReadZStreamFromMMap(bufIn, mmapSrcDataPtr, zstream, remainCompressedSize)) {
695            ret = false;
696            break;
697        }
698
699        zlibErr = inflate(&zstream, Z_SYNC_FLUSH);
700        if ((zlibErr >= Z_OK) && (zstream.msg != nullptr)) {
701            ret = false;
702            break;
703        }
704
705        inflateLen = UNZIP_BUF_OUT_LEN - zstream.avail_out;
706        if (inflateLen > 0) {
707            if (memcpy_s(dstDataPtr, inflateLen, bufOut, inflateLen) != EOK) {
708                ret = false;
709                break;
710            }
711
712            dstDataPtr += inflateLen;
713            zstream.next_out = bufOut;
714            zstream.avail_out = UNZIP_BUF_OUT_LEN;
715            errorTimes = 0;
716        } else {
717            errorTimes++;
718        }
719        if (errorTimes >= INFLATE_ERROR_TIMES) {
720            ret = false;
721            break;
722        }
723    }
724
725    // free all dynamically allocated data structures except the next_in and next_out for this stream.
726    zlibErr = inflateEnd(&zstream);
727    if (zlibErr != Z_OK) {
728        ret = false;
729    }
730
731    delete[] bufOut;
732    delete[] bufIn;
733    return ret;
734}
735
736bool ZipFile::ExtractToBufByName(const std::string &fileName, std::unique_ptr<uint8_t[]> &dataPtr,
737    size_t &len) const
738{
739    ZipEntry zipEntry;
740    if (!GetEntry(fileName, zipEntry)) {
741        return false;
742    }
743    uint16_t extraSize = 0;
744    if (!CheckCoherencyLocalHeader(zipEntry, extraSize)) {
745        return false;
746    }
747
748    ZipPos offset = GetEntryDataOffset(zipEntry, extraSize);
749    uint32_t length = zipEntry.compressedSize;
750    auto dataTmp = std::make_unique<uint8_t[]>(length);
751    if (!zipFileReader_->ReadBuffer(dataTmp.get(), offset, length)) {
752        dataTmp.reset();
753        return false;
754    }
755
756    if (zipEntry.compressionMethod > 0) {
757        return UnzipWithInflatedFromMMap(zipEntry, extraSize, dataTmp.get(), dataPtr, len);
758    }
759
760    len = length;
761    dataPtr = std::move(dataTmp);
762
763    return true;
764}
765}  // namespace AbilityBase
766}  // namespace OHOS
767