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