1 /*
2 * Copyright (c) 2020 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 <cassert>
19 #include <cstring>
20 #include <limits>
21 #include <ostream>
22
23 #include "bundle_log.h"
24 #include "securec.h"
25 #include "zlib.h"
26
27 namespace OHOS {
28 namespace {
29 #define ZIPPOS_ADD_AND_CHECK_OVERFLOW(first, second, sum) \
30 do { \
31 if (((second) > 0) && ((first) > (std::numeric_limits<ZipPos>::max() - (second)))) { \
32 return false; \
33 } \
34 (sum) = (first) + (second); \
35 } while (0)
36
37 constexpr uint32_t MAX_FILE_NAME = 256;
38 constexpr uint32_t UNZIP_BUFFER_SIZE = 1024;
39 constexpr uint32_t UNZIP_BUF_IN_LEN = 2 * UNZIP_BUFFER_SIZE; // in buffer length: 2KB
40 constexpr uint32_t UNZIP_BUF_OUT_LEN = 4 * UNZIP_BUFFER_SIZE; // out buffer length: 4KB
41 constexpr uint32_t LOCAL_HEADER_SIGNATURE = 0x04034b50;
42 constexpr uint32_t CENTRAL_SIGNATURE = 0x02014b50;
43 constexpr uint32_t EOCD_SIGNATURE = 0x06054b50;
44 constexpr uint32_t DATA_DESC_SIGNATURE = 0x08074b50;
45 constexpr uint32_t FLAG_DATA_DESC = 0x8;
46 constexpr size_t FILE_READ_COUNT = 1;
47 constexpr uint8_t INFLATE_ERROR_TIMES = 5;
48 } // namespace
49
ZipEntry(const CentralDirEntry & centralEntry)50 ZipEntry::ZipEntry(const CentralDirEntry ¢ralEntry)
51 {
52 compressionMethod = centralEntry.compressionMethod;
53 uncompressedSize = centralEntry.uncompressedSize;
54 compressedSize = centralEntry.compressedSize;
55 localHeaderOffset = centralEntry.localHeaderOffset;
56 crc = centralEntry.crc;
57 flags = centralEntry.flags;
58 }
59
ZipFile(const std::string & pathName)60 ZipFile::ZipFile(const std::string &pathName)
61 : pathName_(pathName)
62 {
63 HILOG_INFO(HILOG_MODULE_APP, "create ZipFile instance");
64 }
65
~ZipFile()66 ZipFile::~ZipFile()
67 {
68 Close();
69 }
70
CheckEndDir(const EndDir & endDir) const71 bool ZipFile::CheckEndDir(const EndDir &endDir) const
72 {
73 size_t lenEndDir = sizeof(EndDir);
74 if ((endDir.numDisk != 0) ||
75 (endDir.signature != EOCD_SIGNATURE) ||
76 (endDir.startDiskOfCentralDir != 0) ||
77 (endDir.offset >= fileLength_) ||
78 (endDir.totalEntriesInThisDisk != endDir.totalEntries) ||
79 (endDir.commentLen != 0) ||
80 // central dir cant overlap end of central dir
81 ((endDir.offset + endDir.sizeOfCentralDir + lenEndDir) > fileLength_)) {
82 HILOG_ERROR(HILOG_MODULE_APP, "end dir formate error");
83 return false;
84 }
85 return true;
86 }
87
ParseEndDirectory()88 bool ZipFile::ParseEndDirectory()
89 {
90 size_t endDirLen = sizeof(EndDir);
91 ZipPos endFilePos = fileLength_;
92 if (fileLength_ <= endDirLen) {
93 HILOG_ERROR(HILOG_MODULE_APP,
94 "parse EOCD file length(%{public}llu) <= end dir length(%{public}zu)", fileLength_, endDirLen);
95 return false;
96 }
97 ZipPos eocdPos = endFilePos - endDirLen;
98 if (fseek(file_, eocdPos, SEEK_SET) != 0) {
99 HILOG_ERROR(HILOG_MODULE_APP, "locate EOCD seek failed, error: %{public}s", strerror(errno));
100 return false;
101 }
102 if (fread(&endDir_, sizeof(EndDir), FILE_READ_COUNT, file_) != FILE_READ_COUNT) {
103 HILOG_ERROR(HILOG_MODULE_APP, "read EOCD struct failed, error: %{public}s", strerror(errno));
104 return false;
105 }
106 centralDirPos_ = endDir_.offset;
107 return CheckEndDir(endDir_);
108 }
109
ParseAllEntries()110 bool ZipFile::ParseAllEntries()
111 {
112 bool ret = true;
113 ZipPos currentPos = centralDirPos_;
114 CentralDirEntry directoryEntry = {};
115
116 for (int32_t i = 0; i < endDir_.totalEntries; i++) {
117 std::string fileName;
118 fileName.reserve(MAX_FILE_NAME);
119 fileName.resize(MAX_FILE_NAME - 1);
120
121 if (fseek(file_, currentPos, SEEK_SET) != 0) {
122 HILOG_ERROR(HILOG_MODULE_APP,
123 "parse entry(%{public}d) seek zipEntry failed, error: %{public}s", i, strerror(errno));
124 ret = false;
125 break;
126 }
127
128 if (fread(&directoryEntry, sizeof(CentralDirEntry), FILE_READ_COUNT, file_) != FILE_READ_COUNT) {
129 HILOG_ERROR(HILOG_MODULE_APP, "parse entry(%{public}d) read ZipEntry failed, error: %{public}s",
130 i, strerror(errno));
131 ret = false;
132 break;
133 }
134
135 if (directoryEntry.signature != CENTRAL_SIGNATURE) {
136 HILOG_ERROR(HILOG_MODULE_APP,
137 "parse entry(%{public}d) check signature(0x%{public}08x) at pos(0x%{public}08llx) failed",
138 i, directoryEntry.signature, currentPos);
139 ret = false;
140 break;
141 }
142
143 size_t fileLength =
144 (directoryEntry.nameSize >= MAX_FILE_NAME) ? (MAX_FILE_NAME - 1) : (directoryEntry.nameSize);
145 if (fread(&(fileName[0]), fileLength, FILE_READ_COUNT, file_) != FILE_READ_COUNT) {
146 HILOG_ERROR(HILOG_MODULE_APP,
147 "parse entry(%{public}d) read file name failed, error: %{public}s", i, strerror(errno));
148 ret = false;
149 break;
150 }
151 fileName.resize(fileLength);
152
153 ZipEntry currentEntry(directoryEntry);
154 currentEntry.fileName = fileName;
155 entriesMap_[fileName] = currentEntry;
156 fileNames_.emplace_back(fileName);
157
158 ZIPPOS_ADD_AND_CHECK_OVERFLOW(currentPos, sizeof(directoryEntry), currentPos);
159 ZIPPOS_ADD_AND_CHECK_OVERFLOW(currentPos, directoryEntry.nameSize, currentPos);
160 ZIPPOS_ADD_AND_CHECK_OVERFLOW(currentPos, directoryEntry.extraSize, currentPos);
161 ZIPPOS_ADD_AND_CHECK_OVERFLOW(currentPos, directoryEntry.commentSize, currentPos);
162 }
163 HILOG_INFO(HILOG_MODULE_APP, "parse %{public}d central entries from %{private}s", endDir_.totalEntries,
164 pathName_.c_str());
165 return ret;
166 }
167
GetFileNames() const168 const std::vector<std::string> &ZipFile::GetFileNames() const
169 {
170 return fileNames_;
171 }
172
Open()173 bool ZipFile::Open()
174 {
175 HILOG_INFO(HILOG_MODULE_APP, "open: %{private}s", pathName_.c_str());
176 if (isOpen_) {
177 HILOG_ERROR(HILOG_MODULE_APP, "has already opened");
178 return true;
179 }
180
181 if (pathName_.length() > PATH_MAX) {
182 HILOG_ERROR(HILOG_MODULE_APP, "path length(%{public}zu) longer than max path length(%{public}d)",
183 pathName_.length(), PATH_MAX);
184 return false;
185 }
186 char realPath[PATH_MAX + 1] = { 0 };
187 if (realpath(pathName_.c_str(), realPath) == nullptr) {
188 HILOG_ERROR(HILOG_MODULE_APP, "transform real path error: %{public}s", strerror(errno));
189 return false;
190 }
191
192 FILE* tmpFile = fopen(realPath, "rb");
193 if (tmpFile == nullptr) {
194 HILOG_ERROR(HILOG_MODULE_APP, "open file(%{public}s) failed, error: %{private}s", pathName_.c_str(),
195 strerror(errno));
196 return false;
197 }
198
199 if (fseek(tmpFile, 0, SEEK_END) != 0) {
200 HILOG_ERROR(HILOG_MODULE_APP, "file seek failed, error: %{public}s", strerror(errno));
201 fclose(tmpFile);
202 return false;
203 }
204
205 ZipPos fileLength = ftell(tmpFile);
206 if (fileLength_ == 0) {
207 fileLength_ = fileLength;
208 }
209
210 file_ = tmpFile;
211 bool result = ParseEndDirectory();
212 if (result) {
213 result = ParseAllEntries();
214 }
215 // it means open file success.
216 isOpen_ = true;
217 return result;
218 }
219
Close()220 void ZipFile::Close()
221 {
222 HILOG_INFO(HILOG_MODULE_APP, "close: %{private}s", pathName_.c_str());
223 if (!isOpen_ || file_ == nullptr) {
224 HILOG_WARN(HILOG_MODULE_APP, "file is not opened");
225 return;
226 }
227
228 entriesMap_.clear();
229 fileNames_.clear();
230 pathName_ = "";
231 isOpen_ = false;
232
233 if (fclose(file_) != 0) {
234 HILOG_WARN(HILOG_MODULE_APP, "close failed, error: %{public}s", strerror(errno));
235 }
236 file_ = nullptr;
237 }
238
239 // Get all file zipEntry in this file
GetAllEntries() const240 const ZipEntryMap &ZipFile::GetAllEntries() const
241 {
242 return entriesMap_;
243 }
244
GetEntry(const std::string & entryName,ZipEntry & resultEntry) const245 bool ZipFile::GetEntry(const std::string &entryName, ZipEntry &resultEntry) const
246 {
247 HILOG_INFO(HILOG_MODULE_APP, "get entry by name: %{public}s", entryName.c_str());
248 auto iter = entriesMap_.find(entryName);
249 if (iter != entriesMap_.end()) {
250 resultEntry = iter->second;
251 HILOG_DEBUG(HILOG_MODULE_APP, "get entry successed");
252 return true;
253 }
254 HILOG_ERROR(HILOG_MODULE_APP, "get entry failed");
255 return false;
256 }
257
GetLocalHeaderSize(const uint16_t nameSize,const uint16_t extraSize) const258 size_t ZipFile::GetLocalHeaderSize(const uint16_t nameSize, const uint16_t extraSize) const
259 {
260 size_t localSize = sizeof(LocalHeader);
261 if (localSize > std::numeric_limits<size_t>::max() - nameSize - extraSize) {
262 return 0;
263 }
264 return localSize + nameSize + extraSize;
265 }
266
CheckDataDesc(const ZipEntry & zipEntry,const LocalHeader & localHeader) const267 bool ZipFile::CheckDataDesc(const ZipEntry &zipEntry, const LocalHeader &localHeader) const
268 {
269 uint32_t crcLocal = 0;
270 uint32_t compressedLocal = 0;
271 uint32_t uncompressedLocal = 0;
272
273 if (localHeader.flags & FLAG_DATA_DESC) { // use data desc
274 DataDesc dataDesc;
275
276 size_t localHeaderSize = GetLocalHeaderSize(localHeader.nameSize, localHeader.extraSize);
277 if (localHeaderSize == 0) {
278 return false;
279 }
280 ZipPos descPos = 0;
281 ZIPPOS_ADD_AND_CHECK_OVERFLOW(zipEntry.localHeaderOffset, localHeaderSize, descPos);
282 ZIPPOS_ADD_AND_CHECK_OVERFLOW(descPos, zipEntry.compressedSize, descPos);
283
284 if (fseek(file_, descPos, SEEK_SET) != 0) {
285 HILOG_ERROR(HILOG_MODULE_APP,
286 "check local header seek datadesc failed, error: %{public}s", strerror(errno));
287 return false;
288 }
289
290 if (fread(&dataDesc, sizeof(DataDesc), FILE_READ_COUNT, file_) != FILE_READ_COUNT) {
291 HILOG_ERROR(HILOG_MODULE_APP, "check local header read datadesc failed, error: %{public}s",
292 strerror(errno));
293 return false;
294 }
295
296 if (dataDesc.signature != DATA_DESC_SIGNATURE) {
297 HILOG_ERROR(HILOG_MODULE_APP, "check local header check datadesc signature failed");
298 return false;
299 }
300
301 crcLocal = dataDesc.crc;
302 compressedLocal = dataDesc.compressedSize;
303 uncompressedLocal = dataDesc.uncompressedSize;
304 } else {
305 crcLocal = localHeader.crc;
306 compressedLocal = localHeader.compressedSize;
307 uncompressedLocal = localHeader.uncompressedSize;
308 }
309
310 if ((zipEntry.crc != crcLocal) ||
311 (zipEntry.compressedSize != compressedLocal) ||
312 (zipEntry.uncompressedSize != uncompressedLocal)) {
313 HILOG_ERROR(HILOG_MODULE_APP, "check local header compressed size corrupted");
314 return false;
315 }
316
317 return true;
318 }
319
CheckCoherencyLocalHeader(const ZipEntry & zipEntry,uint16_t & extraSize) const320 bool ZipFile::CheckCoherencyLocalHeader(const ZipEntry &zipEntry, uint16_t &extraSize) const
321 {
322 LocalHeader localHeader = {};
323
324 if (zipEntry.localHeaderOffset >= fileLength_) {
325 HILOG_ERROR(HILOG_MODULE_APP, "check local file header offset is overflow %{public}d",
326 zipEntry.localHeaderOffset);
327 return false;
328 }
329 if (fseek(file_, zipEntry.localHeaderOffset, SEEK_SET) != 0) {
330 HILOG_ERROR(HILOG_MODULE_APP, "check local header seek failed, error: %{public}s", strerror(errno));
331 return false;
332 }
333 if (fread(&localHeader, sizeof(LocalHeader), FILE_READ_COUNT, file_) != FILE_READ_COUNT) {
334 HILOG_ERROR(HILOG_MODULE_APP, "check local header read localheader failed, error: %{public}s",
335 strerror(errno));
336 return false;
337 }
338 if ((localHeader.signature != LOCAL_HEADER_SIGNATURE) ||
339 (zipEntry.compressionMethod != localHeader.compressionMethod)) {
340 HILOG_ERROR(HILOG_MODULE_APP, "check local header signature or compressionMethod failed");
341 return false;
342 }
343 // current only support store and Z_DEFLATED method
344 if ((zipEntry.compressionMethod != Z_DEFLATED) &&
345 (zipEntry.compressionMethod != 0)) {
346 HILOG_ERROR(HILOG_MODULE_APP, "check local header compressionMethod(%{public}d) not support",
347 zipEntry.compressionMethod);
348 return false;
349 }
350
351 std::string fileName;
352 fileName.reserve(MAX_FILE_NAME);
353 fileName.resize(MAX_FILE_NAME - 1);
354 size_t fileLength = (localHeader.nameSize >= MAX_FILE_NAME) ? (MAX_FILE_NAME - 1) : localHeader.nameSize;
355 if (fileLength != zipEntry.fileName.length()) {
356 HILOG_ERROR(HILOG_MODULE_APP, "check local header file name size failed");
357 return false;
358 }
359 if (fread(&(fileName[0]), fileLength, FILE_READ_COUNT, file_) != FILE_READ_COUNT) {
360 HILOG_ERROR(HILOG_MODULE_APP, "check local header read file name failed, error: %{public}s", strerror(errno));
361 return false;
362 }
363 fileName.resize(fileLength);
364 if (zipEntry.fileName != fileName) {
365 HILOG_ERROR(HILOG_MODULE_APP, "check local header file name corrupted");
366 return false;
367 }
368
369 if (!CheckDataDesc(zipEntry, localHeader)) {
370 return false;
371 }
372
373 extraSize = localHeader.extraSize;
374 return true;
375 }
376
SeekToEntryStart(const ZipEntry & zipEntry,const uint16_t extraSize) const377 bool ZipFile::SeekToEntryStart(const ZipEntry &zipEntry, const uint16_t extraSize) const
378 {
379 ZipPos startOffset = zipEntry.localHeaderOffset;
380 // get data offset, add signature+localheader+namesize+extrasize
381 size_t localHeaderSize = GetLocalHeaderSize(zipEntry.fileName.length(), extraSize);
382 if (localHeaderSize == 0) {
383 return false;
384 }
385 ZipPos zipEntryPos = 0;
386 ZIPPOS_ADD_AND_CHECK_OVERFLOW(startOffset, localHeaderSize, startOffset);
387 ZIPPOS_ADD_AND_CHECK_OVERFLOW(startOffset, zipEntry.compressedSize, zipEntryPos);
388 if (zipEntryPos > fileLength_) {
389 HILOG_ERROR(HILOG_MODULE_APP, "seek to entry start failed, startOffset(%{public}lld) + entryCompressedSize"
390 "(%{public}ud) > fileLength(%{public}llu)", startOffset, zipEntry.compressedSize, fileLength_);
391 return false;
392 }
393 HILOG_INFO(HILOG_MODULE_APP, "seek to entry start 0x%{public}08llx", startOffset);
394 if (fseek(file_, startOffset, SEEK_SET) != 0) {
395 HILOG_ERROR(HILOG_MODULE_APP, "seek failed, error: %{public}s", strerror(errno));
396 return false;
397 }
398 return true;
399 }
400
UnzipWithStore(const ZipEntry & zipEntry,const uint16_t extraSize,std::ostream & dest) const401 bool ZipFile::UnzipWithStore(const ZipEntry &zipEntry, const uint16_t extraSize, std::ostream &dest) const
402 {
403 HILOG_INFO(HILOG_MODULE_APP, "unzip with store");
404 if (!SeekToEntryStart(zipEntry, extraSize)) {
405 return false;
406 }
407
408 uint32_t remainSize = zipEntry.compressedSize;
409 std::string readBuffer;
410 readBuffer.reserve(UNZIP_BUF_OUT_LEN);
411 readBuffer.resize(UNZIP_BUF_OUT_LEN - 1);
412 while (remainSize > 0) {
413 size_t readBytes;
414 size_t readLen = (remainSize > UNZIP_BUF_OUT_LEN) ? UNZIP_BUF_OUT_LEN : remainSize;
415 readBytes = fread(&(readBuffer[0]), sizeof(Byte), readLen, file_);
416 if (readBytes == 0) {
417 HILOG_ERROR(HILOG_MODULE_APP, "unzip store read failed, error: %{public}s", strerror(errno));
418 return false;
419 }
420 remainSize -= readBytes;
421 dest.write(&(readBuffer[0]), readBytes);
422 }
423 HILOG_INFO(HILOG_MODULE_APP, "unzip with store success");
424 return true;
425 }
426
InitZStream(z_stream & zstream) const427 bool ZipFile::InitZStream(z_stream &zstream) const
428 {
429 // init zlib stream
430 if (memset_s(&zstream, sizeof(z_stream), 0, sizeof(z_stream))) {
431 HILOG_ERROR(HILOG_MODULE_APP, "unzip stream buffer init failed");
432 return false;
433 }
434 int32_t zlibErr = inflateInit2(&zstream, -MAX_WBITS);
435 if (zlibErr != Z_OK) {
436 HILOG_ERROR(HILOG_MODULE_APP, "unzip inflated init failed");
437 return false;
438 }
439
440 BytePtr bufOut = new Byte[UNZIP_BUF_OUT_LEN];
441 if (bufOut == nullptr) {
442 HILOG_ERROR(HILOG_MODULE_APP, "unzip inflated new out buffer failed");
443 return false;
444 }
445
446 BytePtr bufIn = new Byte[UNZIP_BUF_IN_LEN];
447 if (bufIn == nullptr) {
448 HILOG_ERROR(HILOG_MODULE_APP, "unzip inflated new in buffer failed");
449 delete[] bufOut;
450 return false;
451 }
452 zstream.next_out = bufOut;
453 zstream.next_in = bufIn;
454 zstream.avail_out = UNZIP_BUF_OUT_LEN;
455 return true;
456 }
457
ReadZStream(const BytePtr & buffer,z_stream & zstream,uint32_t & remainCompressedSize) const458 bool ZipFile::ReadZStream(const BytePtr &buffer, z_stream &zstream, uint32_t &remainCompressedSize) const
459 {
460 if (zstream.avail_in == 0) {
461 size_t readBytes;
462 size_t remainBytes = (remainCompressedSize > UNZIP_BUF_IN_LEN) ? UNZIP_BUF_IN_LEN : remainCompressedSize;
463 readBytes = fread(buffer, sizeof(Byte), remainBytes, file_);
464 if (readBytes == 0) {
465 HILOG_ERROR(HILOG_MODULE_APP, "unzip inflated read failed, error: %{public}s", strerror(errno));
466 return false;
467 }
468
469 remainCompressedSize -= readBytes;
470 zstream.avail_in = readBytes;
471 zstream.next_in = buffer;
472 }
473 return true;
474 }
475
UnzipWithInflated(const ZipEntry & zipEntry,const uint16_t extraSize,std::ostream & dest) const476 bool ZipFile::UnzipWithInflated(const ZipEntry &zipEntry, const uint16_t extraSize, std::ostream &dest) const
477 {
478 HILOG_INFO(HILOG_MODULE_APP, "unzip with inflated");
479 z_stream zstream;
480 if (!SeekToEntryStart(zipEntry, extraSize)) {
481 return false;
482 }
483 if (!InitZStream(zstream)) {
484 return false;
485 }
486 BytePtr bufIn = zstream.next_in;
487 BytePtr bufOut = zstream.next_out;
488
489 bool ret = true;
490 int32_t zlibErr = Z_OK;
491 uint32_t remainCompressedSize = zipEntry.compressedSize;
492 uint8_t errorTimes = 0;
493
494 while ((remainCompressedSize > 0) || (zstream.avail_in > 0)) {
495 if (!ReadZStream(bufIn, zstream, remainCompressedSize)) {
496 ret = false;
497 break;
498 }
499
500 zlibErr = inflate(&zstream, Z_SYNC_FLUSH);
501 if (zlibErr < Z_OK) {
502 HILOG_ERROR(HILOG_MODULE_APP, "unzip inflated inflate, error: %{public}d", zlibErr);
503 if (zstream.msg != nullptr) {
504 HILOG_ERROR(HILOG_MODULE_APP, "err msg: %{public}s", zstream.msg);
505 }
506 ret = false;
507 break;
508 }
509
510 size_t inflateLen = UNZIP_BUF_OUT_LEN - zstream.avail_out;
511 if (inflateLen > 0) {
512 dest.write(reinterpret_cast<const char*>(bufOut), inflateLen);
513 zstream.next_out = bufOut;
514 zstream.avail_out = UNZIP_BUF_OUT_LEN;
515 errorTimes = 0;
516 } else {
517 errorTimes++;
518 }
519
520 if (errorTimes >= INFLATE_ERROR_TIMES) {
521 HILOG_ERROR(HILOG_MODULE_APP, "unzip inflated data is abnormal!");
522 ret = false;
523 break;
524 }
525 }
526
527 // free all dynamically allocated data structures except the next_in and next_out for this stream.
528 zlibErr = inflateEnd(&zstream);
529 if (zlibErr != Z_OK) {
530 HILOG_ERROR(HILOG_MODULE_APP, "unzip inflateEnd error, error: %{public}d", zlibErr);
531 ret = false;
532 }
533 HILOG_INFO(HILOG_MODULE_APP, "unzip with inflated success");
534
535 delete[] bufOut;
536 delete[] bufIn;
537 return ret;
538 }
539
ExtractFile(const std::string & file,std::ostream & dest) const540 bool ZipFile::ExtractFile(const std::string &file, std::ostream &dest) const
541 {
542 HILOG_INFO(HILOG_MODULE_APP, "extract file %{public}s", file.c_str());
543 ZipEntry zipEntry;
544 if (!GetEntry(file, zipEntry)) {
545 HILOG_ERROR(HILOG_MODULE_APP, "extract file: not find file");
546 return false;
547 }
548
549 uint16_t extraSize = 0;
550 if (!CheckCoherencyLocalHeader(zipEntry, extraSize)) {
551 return false;
552 }
553
554 bool ret = true;
555 if (zipEntry.compressionMethod == 0) {
556 ret = UnzipWithStore(zipEntry, extraSize, dest);
557 } else {
558 ret = UnzipWithInflated(zipEntry, extraSize, dest);
559 }
560 return ret;
561 }
562 }
563