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 ¢ralEntry)
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