• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2022 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 "app_log_wrapper.h"
21 #include "bundle_service_constants.h"
22 #include "securec.h"
23 
24 namespace OHOS {
25 namespace AppExecFwk {
26 namespace {
27 constexpr uint32_t MAX_FILE_PATH = 4096;
28 constexpr uint32_t UNZIP_BUFFER_SIZE = 1024;
29 constexpr uint32_t UNZIP_BUF_IN_LEN = 160 * UNZIP_BUFFER_SIZE;   // in  buffer length: 160KB
30 constexpr uint32_t UNZIP_BUF_OUT_LEN = 320 * UNZIP_BUFFER_SIZE;  // out buffer length: 320KB
31 constexpr uint32_t LOCAL_HEADER_SIGNATURE = 0x04034b50;
32 constexpr uint32_t CENTRAL_SIGNATURE = 0x02014b50;
33 constexpr uint32_t EOCD_SIGNATURE = 0x06054b50;
34 constexpr uint32_t DATA_DESC_SIGNATURE = 0x08074b50;
35 constexpr uint32_t FLAG_DATA_DESC = 0x8;
36 constexpr size_t FILE_READ_COUNT = 1;
37 constexpr uint8_t INFLATE_ERROR_TIMES = 5;
38 }  // namespace
39 
ZipEntry(const CentralDirEntry & centralEntry)40 ZipEntry::ZipEntry(const CentralDirEntry &centralEntry)
41 {
42     compressionMethod = centralEntry.compressionMethod;
43     uncompressedSize = centralEntry.uncompressedSize;
44     compressedSize = centralEntry.compressedSize;
45     localHeaderOffset = centralEntry.localHeaderOffset;
46     crc = centralEntry.crc;
47     flags = centralEntry.flags;
48 }
49 
ZipFile(const std::string & pathName,bool parallel)50 ZipFile::ZipFile(const std::string &pathName, bool parallel) : pathName_(pathName), parallel_(parallel)
51 {
52     APP_LOGD("create instance from %{private}s, parallel mode is %{private}d", pathName_.c_str(), parallel_);
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     APP_LOGD("set content location start position(%{public}llu), length(%{public}zu)", start, length);
63     fileStartPos_ = start;
64     fileLength_ = length;
65 }
66 
CheckEndDir(const EndDir & endDir) const67 bool ZipFile::CheckEndDir(const EndDir &endDir) const
68 {
69     size_t lenEndDir = sizeof(EndDir);
70     if (endDir.numDisk != 0) {
71         APP_LOGE("endDir.numDisk != 0");
72         return false;
73     }
74     if (endDir.signature != EOCD_SIGNATURE) {
75         APP_LOGE("endDir.signature != EOCD_SIGNATURE");
76         return false;
77     }
78     if (endDir.startDiskOfCentralDir != 0) {
79         APP_LOGE("endDir.startDiskOfCentralDir != 0");
80         return false;
81     }
82     if (endDir.offset >= fileLength_) {
83         APP_LOGE("endDir.offset >= fileLength_");
84         return false;
85     }
86     if (endDir.totalEntriesInThisDisk != endDir.totalEntries) {
87         APP_LOGE("endDir.totalEntriesInThisDisk != endDir.totalEntries");
88         return false;
89     }
90     if (endDir.commentLen != 0) {
91         APP_LOGE("endDir.commentLen != 0");
92         return false;
93     }
94     if ((endDir.offset + endDir.sizeOfCentralDir + lenEndDir) > fileLength_) {
95         APP_LOGE("(endDir.offset + endDir.sizeOfCentralDir + lenEndDir) > fileLength_");
96         return false;
97     }
98     return true;
99 }
100 
ParseEndDirectory()101 bool ZipFile::ParseEndDirectory()
102 {
103     size_t endDirLen = sizeof(EndDir);
104     size_t endFilePos = fileStartPos_ + fileLength_;
105 
106     if (fileLength_ <= endDirLen) {
107         APP_LOGE("parse EOCD file length(%{public}llu) <= end dir length(%{public}llu)", fileStartPos_, fileLength_);
108         return false;
109     }
110 
111     size_t eocdPos = endFilePos - endDirLen;
112     if (fseek(file_, eocdPos, SEEK_SET) != 0) {
113         APP_LOGE("locate EOCD seek failed, error: %{public}d", errno);
114         return false;
115     }
116 
117     if (fread(&endDir_, sizeof(EndDir), FILE_READ_COUNT, file_) != FILE_READ_COUNT) {
118         APP_LOGE("read EOCD struct failed, error: %{public}d", errno);
119         return false;
120     }
121 
122     centralDirPos_ = endDir_.offset + fileStartPos_;
123     APP_LOGD("parse EOCD offset(0x%{public}08x) file start position(0x%{public}08llx)", endDir_.offset, fileStartPos_);
124 
125     return CheckEndDir(endDir_);
126 }
127 
ParseAllEntries()128 bool ZipFile::ParseAllEntries()
129 {
130     bool ret = true;
131     ZipPos currentPos = centralDirPos_;
132     CentralDirEntry directoryEntry = {0};
133 
134     for (uint16_t i = 0; i < endDir_.totalEntries; i++) {
135         std::string fileName;
136         fileName.reserve(MAX_FILE_PATH);
137         fileName.resize(MAX_FILE_PATH - 1);
138 
139         if (fseek(file_, currentPos, SEEK_SET) != 0) {
140             APP_LOGE("parse entry(%{public}d) seek zipEntry failed, error: %{public}d", i, errno);
141             ret = false;
142             break;
143         }
144 
145         if (fread(&directoryEntry, sizeof(CentralDirEntry), FILE_READ_COUNT, file_) != FILE_READ_COUNT) {
146             APP_LOGE("parse entry(%{public}d) read ZipEntry failed, error: %{public}d", i, errno);
147             ret = false;
148             break;
149         }
150 
151         if (directoryEntry.signature != CENTRAL_SIGNATURE) {
152             APP_LOGE("parse entry(%{public}d) check signature(0x%08x) at pos(0x%08llx) failed",
153                 i,
154                 directoryEntry.signature,
155                 currentPos);
156             ret = false;
157             break;
158         }
159 
160         size_t fileLength = (directoryEntry.nameSize >= MAX_FILE_PATH) ? (MAX_FILE_PATH - 1) : directoryEntry.nameSize;
161         if (fread(&(fileName[0]), fileLength, FILE_READ_COUNT, file_) != FILE_READ_COUNT) {
162             APP_LOGE("parse entry(%{public}d) read file name failed, error: %{public}d", i, errno);
163             ret = false;
164             break;
165         }
166         fileName.resize(fileLength);
167 
168         ZipEntry currentEntry(directoryEntry);
169         currentEntry.fileName = fileName;
170         entriesMap_[fileName] = currentEntry;
171 
172         currentPos += sizeof(directoryEntry);
173         currentPos += directoryEntry.nameSize + directoryEntry.extraSize + directoryEntry.commentSize;
174     }
175 
176     APP_LOGD("parse %{public}d central entries from %{private}s", endDir_.totalEntries, pathName_.c_str());
177     return ret;
178 }
179 
Open()180 bool ZipFile::Open()
181 {
182     APP_LOGD("open: %{private}s", pathName_.c_str());
183 
184     if (isOpen_) {
185         APP_LOGE("has already opened");
186         return true;
187     }
188 
189     if (pathName_.length() > PATH_MAX) {
190         APP_LOGE("path length(%{public}u) longer than max length(%{public}d)",
191             static_cast<unsigned int>(pathName_.length()),
192             PATH_MAX);
193         return false;
194     }
195     std::string realPath;
196     realPath.reserve(PATH_MAX);
197     realPath.resize(PATH_MAX - 1);
198     if (realpath(pathName_.c_str(), &(realPath[0])) == nullptr) {
199         APP_LOGE("transform real path: %{private}s error: %{public}d", pathName_.c_str(), errno);
200         return false;
201     }
202 
203     FILE *tmpFile = fopen(realPath.c_str(), "rb");
204     if (tmpFile == nullptr) {
205         APP_LOGE("open file(%{private}s) failed, error: %{public}d", pathName_.c_str(), errno);
206         return false;
207     }
208 
209     if (fileLength_ == 0) {
210         if (fseek(tmpFile, 0, SEEK_END) != 0) {
211             APP_LOGE("file seek failed, error: %{public}d", errno);
212             fclose(tmpFile);
213             return false;
214         }
215         int64_t fileLength = ftell(tmpFile);
216         if (fileLength == -1) {
217             APP_LOGE("open file %{private}s failed", pathName_.c_str());
218             fclose(tmpFile);
219             return false;
220         }
221         fileLength_ = static_cast<ZipPos>(fileLength);
222         if (fileStartPos_ >= fileLength_) {
223             APP_LOGE("open start pos > length failed");
224             fclose(tmpFile);
225             return false;
226         }
227 
228         fileLength_ -= fileStartPos_;
229     }
230 
231     file_ = tmpFile;
232     if (parallel_) {
233         for (int32_t i = 0; i < concurrency_; i++) {
234             tmpFile = fopen(realPath.c_str(), "rb");
235             if (tmpFile != nullptr) {
236                 files_.push_back(tmpFile);
237                 continue;
238             }
239             APP_LOGE("open file(%{private}s) failed, error: %{public}d", pathName_.c_str(), errno);
240             fclose(file_);
241             for (int j = 0; j < i; j++) {
242                 fclose(files_[j]);
243             }
244             return false;
245         }
246     }
247     bool result = ParseEndDirectory();
248     if (result) {
249         result = ParseAllEntries();
250     }
251     // it means open file success.
252     isOpen_ = true;
253     return result;
254 }
255 
Close()256 void ZipFile::Close()
257 {
258     APP_LOGD("close: %{private}s", pathName_.c_str());
259 
260     if (!isOpen_ || file_ == nullptr) {
261         APP_LOGW("file is not opened");
262         return;
263     }
264 
265     entriesMap_.clear();
266     pathName_ = "";
267     isOpen_ = false;
268 
269     if (fclose(file_) != 0) {
270         APP_LOGW("close failed err: %{public}d", errno);
271     }
272     file_ = nullptr;
273     if (parallel_) {
274         for (int32_t i = 0; i < concurrency_; i++) {
275             if (fclose(files_[i]) != 0) {
276                 APP_LOGW("close failed err: %{public}d", errno);
277             }
278             files_[i] = nullptr;
279         }
280         files_.clear();
281     }
282 }
283 
284 // Get all file zipEntry in this file
GetAllEntries() const285 const ZipEntryMap &ZipFile::GetAllEntries() const
286 {
287     return entriesMap_;
288 }
289 
HasEntry(const std::string & entryName) const290 bool ZipFile::HasEntry(const std::string &entryName) const
291 {
292     return entriesMap_.find(entryName) != entriesMap_.end();
293 }
294 
IsDirExist(const std::string & dir) const295 bool ZipFile::IsDirExist(const std::string &dir) const
296 {
297     APP_LOGD("target dir: %{public}s", dir.c_str());
298     if (dir.empty()) {
299         APP_LOGE("target dir is empty");
300         return false;
301     }
302 
303     auto tempDir = dir;
304     if (tempDir.back() != ServiceConstants::FILE_SEPARATOR_CHAR) {
305         tempDir.push_back(ServiceConstants::FILE_SEPARATOR_CHAR);
306     }
307 
308     for (const auto &item : entriesMap_) {
309         if (item.first.find(tempDir) == 0) {
310             APP_LOGD("find target dir, fileName : %{public}s", item.first.c_str());
311             return true;
312         }
313     }
314     APP_LOGD("target dir not found, dir : %{public}s", dir.c_str());
315     return false;
316 }
317 
GetEntry(const std::string & entryName,ZipEntry & resultEntry) const318 bool ZipFile::GetEntry(const std::string &entryName, ZipEntry &resultEntry) const
319 {
320     APP_LOGD("get entry by name: %{public}s", entryName.c_str());
321     auto iter = entriesMap_.find(entryName);
322     if (iter != entriesMap_.end()) {
323         resultEntry = iter->second;
324         APP_LOGD("get entry succeed");
325         return true;
326     }
327     APP_LOGE("get entry failed");
328     return false;
329 }
330 
GetLocalHeaderSize(const uint16_t nameSize,const uint16_t extraSize) const331 size_t ZipFile::GetLocalHeaderSize(const uint16_t nameSize, const uint16_t extraSize) const
332 {
333     return sizeof(LocalHeader) + nameSize + extraSize;
334 }
335 
CheckDataDescInternal(const ZipEntry & zipEntry,const LocalHeader & localHeader,FILE * file) const336 bool ZipFile::CheckDataDescInternal(const ZipEntry &zipEntry, const LocalHeader &localHeader, FILE *file) const
337 {
338     uint32_t crcLocal = 0;
339     uint32_t compressedLocal = 0;
340     uint32_t uncompressedLocal = 0;
341 
342     if (localHeader.flags & FLAG_DATA_DESC) {  // use data desc
343         DataDesc dataDesc;
344         auto descPos = zipEntry.localHeaderOffset + GetLocalHeaderSize(localHeader.nameSize, localHeader.extraSize);
345         descPos += fileStartPos_ + zipEntry.compressedSize;
346 
347         if (fseek(file, descPos, SEEK_SET) != 0) {
348             APP_LOGE("check local header seek datadesc failed, error: %{public}d", errno);
349             return false;
350         }
351 
352         if (fread(&dataDesc, sizeof(DataDesc), FILE_READ_COUNT, file) != FILE_READ_COUNT) {
353             APP_LOGE("check local header read datadesc failed, error: %{public}d", errno);
354             return false;
355         }
356 
357         if (dataDesc.signature != DATA_DESC_SIGNATURE) {
358             APP_LOGE("check local header check datadesc signature failed");
359             return false;
360         }
361 
362         crcLocal = dataDesc.crc;
363         compressedLocal = dataDesc.compressedSize;
364         uncompressedLocal = dataDesc.uncompressedSize;
365     } else {
366         crcLocal = localHeader.crc;
367         compressedLocal = localHeader.compressedSize;
368         uncompressedLocal = localHeader.uncompressedSize;
369     }
370 
371     if ((zipEntry.crc != crcLocal) || (zipEntry.compressedSize != compressedLocal) ||
372         (zipEntry.uncompressedSize != uncompressedLocal)) {
373         APP_LOGE("check local header compressed size corrupted");
374         return false;
375     }
376 
377     return true;
378 }
379 
CheckDataDesc(const ZipEntry & zipEntry,const LocalHeader & localHeader) const380 bool ZipFile::CheckDataDesc(const ZipEntry &zipEntry, const LocalHeader &localHeader) const
381 {
382     return CheckDataDescInternal(zipEntry, localHeader, file_);
383 }
384 
CheckCoherencyLocalHeaderInternal(const ZipEntry & zipEntry,uint16_t & extraSize,FILE * file) const385 bool ZipFile::CheckCoherencyLocalHeaderInternal(const ZipEntry &zipEntry, uint16_t &extraSize, FILE *file) const
386 {
387     LocalHeader localHeader = {0};
388 
389     if (zipEntry.localHeaderOffset >= fileLength_) {
390         APP_LOGE("check local file header offset overflow %{public}d", zipEntry.localHeaderOffset);
391         return false;
392     }
393 
394     if (fseek(file, fileStartPos_ + zipEntry.localHeaderOffset, SEEK_SET) != 0) {
395         APP_LOGE("check local header seek failed, error: %{public}d", errno);
396         return false;
397     }
398 
399     if (fread(&localHeader, sizeof(LocalHeader), FILE_READ_COUNT, file) != FILE_READ_COUNT) {
400         APP_LOGE("check local header read localheader failed, error: %{public}d", errno);
401         return false;
402     }
403 
404     if ((localHeader.signature != LOCAL_HEADER_SIGNATURE) ||
405         (zipEntry.compressionMethod != localHeader.compressionMethod)) {
406         APP_LOGE("check local header signature or compressionMethod failed");
407         return false;
408     }
409 
410     // current only support store and Z_DEFLATED method
411     if ((zipEntry.compressionMethod != Z_DEFLATED) && (zipEntry.compressionMethod != 0)) {
412         APP_LOGE("check local header compressionMethod(%{public}d) not support", zipEntry.compressionMethod);
413         return false;
414     }
415 
416     std::string fileName;
417     fileName.reserve(MAX_FILE_PATH);
418     fileName.resize(MAX_FILE_PATH - 1);
419     size_t fileLength = (localHeader.nameSize >= MAX_FILE_PATH) ? (MAX_FILE_PATH - 1) : localHeader.nameSize;
420     if (fileLength != zipEntry.fileName.length()) {
421         APP_LOGE("check local header file name size failed");
422         return false;
423     }
424     if (fread(&(fileName[0]), fileLength, FILE_READ_COUNT, file) != FILE_READ_COUNT) {
425         APP_LOGE("check local header read file name failed, error: %{public}d", errno);
426         return false;
427     }
428     fileName.resize(fileLength);
429     if (zipEntry.fileName != fileName) {
430         APP_LOGE("check local header file name corrupted");
431         return false;
432     }
433 
434     if (!CheckDataDescInternal(zipEntry, localHeader, file)) {
435         APP_LOGE("check data desc failed");
436         return false;
437     }
438 
439     extraSize = localHeader.extraSize;
440     return true;
441 }
442 
CheckCoherencyLocalHeader(const ZipEntry & zipEntry,uint16_t & extraSize) const443 bool ZipFile::CheckCoherencyLocalHeader(const ZipEntry &zipEntry, uint16_t &extraSize) const
444 {
445     return CheckCoherencyLocalHeaderInternal(zipEntry, extraSize, file_);
446 }
447 
SeekToEntryStartInternal(const ZipEntry & zipEntry,const uint16_t extraSize,FILE * file) const448 bool ZipFile::SeekToEntryStartInternal(const ZipEntry &zipEntry, const uint16_t extraSize, FILE *file) const
449 {
450     ZipPos startOffset = zipEntry.localHeaderOffset;
451     // get data offset, add signature+localheader+namesize+extrasize
452     startOffset += GetLocalHeaderSize(zipEntry.fileName.length(), extraSize);
453     if (startOffset + zipEntry.compressedSize > fileLength_) {
454         APP_LOGE("startOffset(%{public}lld)+entryCompressedSize(%{public}ud) > fileLength(%{public}llu)",
455             startOffset,
456             zipEntry.compressedSize,
457             fileLength_);
458         return false;
459     }
460     startOffset += fileStartPos_;  // add file start relative to file stream
461 
462     APP_LOGD("seek to entry start 0x%{public}08llx", startOffset);
463     if (fseek(file, startOffset, SEEK_SET) != 0) {
464         APP_LOGE("seek failed, error: %{public}d", errno);
465         return false;
466     }
467     return true;
468 }
469 
SeekToEntryStart(const ZipEntry & zipEntry,const uint16_t extraSize) const470 bool ZipFile::SeekToEntryStart(const ZipEntry &zipEntry, const uint16_t extraSize) const
471 {
472     return SeekToEntryStartInternal(zipEntry, extraSize, file_);
473 }
474 
UnzipWithStore(const ZipEntry & zipEntry,const uint16_t extraSize,std::ostream & dest,FILE * file) const475 bool ZipFile::UnzipWithStore(const ZipEntry &zipEntry, const uint16_t extraSize, std::ostream &dest, FILE *file) const
476 {
477     APP_LOGD("unzip with store");
478 
479     if (!SeekToEntryStartInternal(zipEntry, extraSize, file)) {
480         APP_LOGE("seek to entry start failed");
481         return false;
482     }
483 
484     uint32_t remainSize = zipEntry.compressedSize;
485     std::string readBuffer;
486     readBuffer.reserve(UNZIP_BUF_OUT_LEN);
487     readBuffer.resize(UNZIP_BUF_OUT_LEN - 1);
488     while (remainSize > 0) {
489         size_t readBytes;
490         size_t readLen = (remainSize > UNZIP_BUF_OUT_LEN) ? UNZIP_BUF_OUT_LEN : remainSize;
491         readBytes = fread(&(readBuffer[0]), sizeof(Byte), readLen, file);
492         if (readBytes == 0) {
493             APP_LOGE("unzip store read failed, error: %{public}d", ferror(file));
494             return false;
495         }
496         remainSize -= readBytes;
497         dest.write(&(readBuffer[0]), readBytes);
498     }
499 
500     return true;
501 }
502 
InitZStream(z_stream & zstream) const503 bool ZipFile::InitZStream(z_stream &zstream) const
504 {
505     // init zlib stream
506     if (memset_s(&zstream, sizeof(z_stream), 0, sizeof(z_stream))) {
507         APP_LOGE("unzip stream buffer init failed");
508         return false;
509     }
510     int32_t zlibErr = inflateInit2(&zstream, -MAX_WBITS);
511     if (zlibErr != Z_OK) {
512         APP_LOGE("unzip inflated init failed");
513         return false;
514     }
515 
516     BytePtr bufOut = new (std::nothrow) Byte[UNZIP_BUF_OUT_LEN];
517     if (bufOut == nullptr) {
518         APP_LOGE("unzip inflated new out buffer failed");
519         return false;
520     }
521 
522     BytePtr bufIn = new (std::nothrow) Byte[UNZIP_BUF_IN_LEN];
523     if (bufIn == nullptr) {
524         APP_LOGE("unzip inflated new in buffer failed");
525         delete[] bufOut;
526         return false;
527     }
528     zstream.next_out = bufOut;
529     zstream.next_in = bufIn;
530     zstream.avail_out = UNZIP_BUF_OUT_LEN;
531     return true;
532 }
533 
ReadZStream(const BytePtr & buffer,z_stream & zstream,uint32_t & remainCompressedSize,FILE * file) const534 bool ZipFile::ReadZStream(const BytePtr &buffer, z_stream &zstream, uint32_t &remainCompressedSize, FILE *file) const
535 {
536     if (zstream.avail_in == 0) {
537         size_t readBytes;
538         size_t remainBytes = (remainCompressedSize > UNZIP_BUF_IN_LEN) ? UNZIP_BUF_IN_LEN : remainCompressedSize;
539         readBytes = fread(buffer, sizeof(Byte), remainBytes, file);
540         if (readBytes == 0) {
541             APP_LOGE("unzip inflated read failed, error: %{public}d", ferror(file));
542             return false;
543         }
544 
545         remainCompressedSize -= readBytes;
546         zstream.avail_in = readBytes;
547         zstream.next_in = buffer;
548     }
549     return true;
550 }
551 
UnzipWithInflated(const ZipEntry & zipEntry,const uint16_t extraSize,std::ostream & dest,FILE * file) const552 bool ZipFile::UnzipWithInflated(const ZipEntry &zipEntry, const uint16_t extraSize, std::ostream &dest,
553     FILE *file) const
554 {
555     APP_LOGD("unzip with inflated");
556 
557     z_stream zstream;
558     if (!SeekToEntryStartInternal(zipEntry, extraSize, file) || !InitZStream(zstream)) {
559         return false;
560     }
561 
562     BytePtr bufIn = zstream.next_in;
563     BytePtr bufOut = zstream.next_out;
564 
565     bool ret = true;
566     int32_t zlibErr = Z_OK;
567     uint32_t remainCompressedSize = zipEntry.compressedSize;
568     uint8_t errorTimes = 0;
569     while ((remainCompressedSize > 0) || (zstream.avail_in > 0)) {
570         if (!ReadZStream(bufIn, zstream, remainCompressedSize, file)) {
571             ret = false;
572             break;
573         }
574 
575         zlibErr = inflate(&zstream, Z_SYNC_FLUSH);
576         if ((zlibErr >= Z_OK) && (zstream.msg != nullptr)) {
577             APP_LOGE("unzip inflated inflate, error: %{public}d, err msg: %{public}s", zlibErr, zstream.msg);
578             ret = false;
579             break;
580         }
581 
582         size_t inflateLen = UNZIP_BUF_OUT_LEN - zstream.avail_out;
583         if (inflateLen > 0) {
584             dest.write(reinterpret_cast<const char *>(bufOut), inflateLen);
585             zstream.next_out = bufOut;
586             zstream.avail_out = UNZIP_BUF_OUT_LEN;
587             errorTimes = 0;
588         } else {
589             errorTimes++;
590         }
591         if (errorTimes >= INFLATE_ERROR_TIMES) {
592             APP_LOGE("unzip inflated data is abnormal");
593             ret = false;
594             break;
595         }
596     }
597 
598     // free all dynamically allocated data structures except the next_in and next_out for this stream.
599     zlibErr = inflateEnd(&zstream);
600     if (zlibErr != Z_OK) {
601         APP_LOGE("unzip inflateEnd error %{public}d", zlibErr);
602         ret = false;
603     }
604 
605     delete[] bufOut;
606     delete[] bufIn;
607     return ret;
608 }
609 
GetEntryDataOffset(const ZipEntry & zipEntry,const uint16_t extraSize) const610 ZipPos ZipFile::GetEntryDataOffset(const ZipEntry &zipEntry, const uint16_t extraSize) const
611 {
612     // get entry data offset relative file
613     ZipPos offset = zipEntry.localHeaderOffset;
614 
615     offset += GetLocalHeaderSize(zipEntry.fileName.length(), extraSize);
616     offset += fileStartPos_;
617 
618     return offset;
619 }
620 
GetDataOffsetRelative(const std::string & file,ZipPos & offset,uint32_t & length) const621 bool ZipFile::GetDataOffsetRelative(const std::string &file, ZipPos &offset, uint32_t &length) const
622 {
623     APP_LOGD("get data relative offset for file %{private}s", file.c_str());
624 
625     ZipEntry zipEntry;
626     if (!GetEntry(file, zipEntry)) {
627         APP_LOGE("extract file: not find file");
628         return false;
629     }
630 
631     uint16_t extraSize = 0;
632     if (!CheckCoherencyLocalHeaderInternal(zipEntry, extraSize, file_)) {
633         APP_LOGE("check coherency local header failed");
634         return false;
635     }
636 
637     offset = GetEntryDataOffset(zipEntry, extraSize);
638     length = zipEntry.compressedSize;
639     return true;
640 }
641 
ExtractFile(const std::string & file,std::ostream & dest) const642 bool ZipFile::ExtractFile(const std::string &file, std::ostream &dest) const
643 {
644     APP_LOGD("extract file %{private}s", file.c_str());
645 
646     ZipEntry zipEntry;
647     if (!GetEntry(file, zipEntry)) {
648         APP_LOGE("extract file: not find file");
649         return false;
650     }
651 
652     uint16_t extraSize = 0;
653     if (!CheckCoherencyLocalHeaderInternal(zipEntry, extraSize, file_)) {
654         APP_LOGE("check coherency local header failed");
655         return false;
656     }
657 
658     bool ret = true;
659     if (zipEntry.compressionMethod == 0) {
660         ret = UnzipWithStore(zipEntry, extraSize, dest, file_);
661     } else {
662         ret = UnzipWithInflated(zipEntry, extraSize, dest, file_);
663     }
664 
665     return ret;
666 }
667 
GetFileHandler(int32_t & resourceId) const668 void ZipFile::GetFileHandler(int32_t &resourceId) const
669 {
670     resourceId %= concurrency_;
671     while (!mtxes_[resourceId].try_lock()) {
672         resourceId = (resourceId + 1) % concurrency_;
673     }
674 }
675 
ReleaseFileHandler(const int32_t resourceId) const676 void ZipFile::ReleaseFileHandler(const int32_t resourceId) const
677 {
678     mtxes_[resourceId].unlock();
679 }
680 
ExtractFileParallel(const std::string & file,std::ostream & dest) const681 bool ZipFile::ExtractFileParallel(const std::string &file, std::ostream &dest) const
682 {
683     APP_LOGD("extract file %{private}s", file.c_str());
684 
685     ZipEntry zipEntry;
686     if (!GetEntry(file, zipEntry)) {
687         APP_LOGE("extract file: not find file");
688         return false;
689     }
690 
691     int resourceId = sched_getcpu();
692     APP_LOGD("get file handler with initial id %{private}d", resourceId);
693     GetFileHandler(resourceId);
694     APP_LOGD("get file handler id %{private}d success", resourceId);
695 
696     uint16_t extraSize = 0;
697     if (!CheckCoherencyLocalHeaderInternal(zipEntry, extraSize, files_[resourceId])) {
698         APP_LOGE("check coherency local header failed");
699         ReleaseFileHandler(resourceId);
700         return false;
701     }
702 
703     bool ret = true;
704     if (zipEntry.compressionMethod == 0) {
705         ret = UnzipWithStore(zipEntry, extraSize, dest, files_[resourceId]);
706     } else {
707         ret = UnzipWithInflated(zipEntry, extraSize, dest, files_[resourceId]);
708     }
709 
710     APP_LOGD("release file handler id %{private}d", resourceId);
711     ReleaseFileHandler(resourceId);
712     APP_LOGD("release file handler id %{private}d success", resourceId);
713 
714     return ret;
715 }
716 }  // namespace AppExecFwk
717 }  // namespace OHOS
718