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 
22 namespace panda {
23 namespace ecmascript {
24 namespace {
25 constexpr uint32_t MAX_FILE_NAME = 4096;
26 constexpr uint32_t UNZIP_BUFFER_SIZE = 1024;
27 constexpr uint32_t UNZIP_BUF_IN_LEN = 160 * UNZIP_BUFFER_SIZE;   // in  buffer length: 160KB
28 constexpr uint32_t UNZIP_BUF_OUT_LEN = 320 * UNZIP_BUFFER_SIZE;  // out buffer length: 320KB
29 constexpr uint32_t LOCAL_HEADER_SIGNATURE = 0x04034b50;
30 constexpr uint32_t CENTRAL_SIGNATURE = 0x02014b50;
31 constexpr uint32_t EOCD_SIGNATURE = 0x06054b50;
32 constexpr uint32_t DATA_DESC_SIGNATURE = 0x08074b50;
33 constexpr uint32_t FLAG_DATA_DESC = 0x8;
34 constexpr uint8_t INFLATE_ERROR_TIMES = 5;
35 const char FILE_SEPARATOR_CHAR = '/';
36 }  // namespace
37 
ZipEntry(const CentralDirEntry &centralEntry)38 ZipEntry::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 
ZipFile(const std::string &pathName)50 ZipFile::ZipFile(const std::string &pathName) : pathName_(pathName)
51 {
52     dirRoot_ = std::make_shared<DirTreeNode>();
53 }
54 
~ZipFile()55 ZipFile::~ZipFile()
56 {
57     Close();
58 }
59 
SetContentLocation(const ZipPos start, const size_t length)60 void ZipFile::SetContentLocation(const ZipPos start, const size_t length)
61 {
62     if (isOpen_) {
63         return;
64     }
65     fileStartPos_ = start;
66     fileLength_ = length;
67 }
68 
CheckEndDir(const EndDir &endDir) const69 bool 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 
ParseEndDirectory()82 bool 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 
ParseOneEntry(uint8_t* &entryPtr)101 bool 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 
AddEntryToTree(const std::string &fileName)131 void 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 
ParseAllEntries()156 bool 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 
Open()176 bool 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 
Close()211 void 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
GetAllEntries() const226 const ZipEntryMap &ZipFile::GetAllEntries() const
227 {
228     return entriesMap_;
229 }
230 
HasEntry(const std::string &entryName) const231 bool ZipFile::HasEntry(const std::string &entryName) const
232 {
233     return entriesMap_.find(entryName) != entriesMap_.end();
234 }
235 
IsDirExist(const std::string &dir) const236 bool 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 }
263 namespace {
GetTreeFileList(const std::shared_ptr<DirTreeNode> &root, const std::string &rootPath, std::vector<std::string> &assetList)264 void 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 
GetAllFileList(const std::string &srcPath, std::vector<std::string> &assetList)277 void 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 
GetChildNames(const std::string &srcPath, std::set<std::string> &fileSet)309 void 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 
GetEntry(const std::string &entryName, ZipEntry &resultEntry) const339 bool 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 
GetLocalHeaderSize(const uint16_t nameSize, const uint16_t extraSize) const349 size_t ZipFile::GetLocalHeaderSize(const uint16_t nameSize, const uint16_t extraSize) const
350 {
351     return sizeof(LocalHeader) + nameSize + extraSize;
352 }
353 
CheckDataDesc(const ZipEntry &zipEntry, const LocalHeader &localHeader) const354 bool 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 
CheckCoherencyLocalHeader(const ZipEntry &zipEntry, uint16_t &extraSize) const390 bool 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 
GetEntryStart(const ZipEntry &zipEntry, const uint16_t extraSize) const430 size_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 
UnzipWithStore(const ZipEntry &zipEntry, const uint16_t extraSize, std::ostream &dest) const440 bool 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 
InitZStream(z_stream &zstream) const457 bool 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 
ReadZStream(const BytePtr &buffer, z_stream &zstream, uint32_t &remainCompressedSize, size_t &startPos) const484 bool 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 
UnzipWithInflated(const ZipEntry &zipEntry, const uint16_t extraSize, std::ostream &dest) const501 bool 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 
GetEntryDataOffset(const ZipEntry &zipEntry, const uint16_t extraSize) const556 ZipPos 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 
GetDataOffsetRelative(const std::string &file, ZipPos &offset, uint32_t &length) const567 bool 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 
GetDataOffsetRelative(const ZipEntry &zipEntry, ZipPos &offset, uint32_t &length) const577 bool 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 
ExtractFile(const std::string &file, std::ostream &dest) const589 bool 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 
ReadZStreamFromMMap(const BytePtr &buffer, void* &dataPtr, z_stream &zstream, uint32_t &remainCompressedSize) const611 bool 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 
CreateFileMapper(const std::string &fileName, FileMapperType type) const634 std::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 
UnzipWithInflatedFromMMap(const ZipEntry &zipEntry, [[maybe_unused]] const uint16_t extraSize, void *mmapDataPtr, std::unique_ptr<uint8_t[]> &dataPtr, size_t &len) const666 bool 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 
ExtractToBufByName(const std::string &fileName, std::unique_ptr<uint8_t[]> &dataPtr, size_t &len) const736 bool 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