1600cc4afSopenharmony_ci/* 2600cc4afSopenharmony_ci * Copyright (c) 2021-2022 Huawei Device Co., Ltd. 3600cc4afSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 4600cc4afSopenharmony_ci * you may not use this file except in compliance with the License. 5600cc4afSopenharmony_ci * You may obtain a copy of the License at 6600cc4afSopenharmony_ci * 7600cc4afSopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 8600cc4afSopenharmony_ci * 9600cc4afSopenharmony_ci * Unless required by applicable law or agreed to in writing, software 10600cc4afSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 11600cc4afSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12600cc4afSopenharmony_ci * See the License for the specific language governing permissions and 13600cc4afSopenharmony_ci * limitations under the License. 14600cc4afSopenharmony_ci */ 15600cc4afSopenharmony_ci 16600cc4afSopenharmony_ci#include "zip_file.h" 17600cc4afSopenharmony_ci 18600cc4afSopenharmony_ci#include <ostream> 19600cc4afSopenharmony_ci 20600cc4afSopenharmony_ci#include "app_log_wrapper.h" 21600cc4afSopenharmony_ci#include "bundle_service_constants.h" 22600cc4afSopenharmony_ci#include "securec.h" 23600cc4afSopenharmony_ci 24600cc4afSopenharmony_cinamespace OHOS { 25600cc4afSopenharmony_cinamespace AppExecFwk { 26600cc4afSopenharmony_cinamespace { 27600cc4afSopenharmony_ciconstexpr uint32_t MAX_FILE_PATH = 4096; 28600cc4afSopenharmony_ciconstexpr uint32_t UNZIP_BUFFER_SIZE = 1024; 29600cc4afSopenharmony_ciconstexpr uint32_t UNZIP_BUF_IN_LEN = 160 * UNZIP_BUFFER_SIZE; // in buffer length: 160KB 30600cc4afSopenharmony_ciconstexpr uint32_t UNZIP_BUF_OUT_LEN = 320 * UNZIP_BUFFER_SIZE; // out buffer length: 320KB 31600cc4afSopenharmony_ciconstexpr uint32_t LOCAL_HEADER_SIGNATURE = 0x04034b50; 32600cc4afSopenharmony_ciconstexpr uint32_t CENTRAL_SIGNATURE = 0x02014b50; 33600cc4afSopenharmony_ciconstexpr uint32_t EOCD_SIGNATURE = 0x06054b50; 34600cc4afSopenharmony_ciconstexpr uint32_t DATA_DESC_SIGNATURE = 0x08074b50; 35600cc4afSopenharmony_ciconstexpr uint32_t FLAG_DATA_DESC = 0x8; 36600cc4afSopenharmony_ciconstexpr size_t FILE_READ_COUNT = 1; 37600cc4afSopenharmony_ciconstexpr uint8_t INFLATE_ERROR_TIMES = 5; 38600cc4afSopenharmony_ci} // namespace 39600cc4afSopenharmony_ci 40600cc4afSopenharmony_ciZipEntry::ZipEntry(const CentralDirEntry ¢ralEntry) 41600cc4afSopenharmony_ci{ 42600cc4afSopenharmony_ci compressionMethod = centralEntry.compressionMethod; 43600cc4afSopenharmony_ci uncompressedSize = centralEntry.uncompressedSize; 44600cc4afSopenharmony_ci compressedSize = centralEntry.compressedSize; 45600cc4afSopenharmony_ci localHeaderOffset = centralEntry.localHeaderOffset; 46600cc4afSopenharmony_ci crc = centralEntry.crc; 47600cc4afSopenharmony_ci flags = centralEntry.flags; 48600cc4afSopenharmony_ci} 49600cc4afSopenharmony_ci 50600cc4afSopenharmony_ciZipFile::ZipFile(const std::string &pathName) : pathName_(pathName) 51600cc4afSopenharmony_ci{ 52600cc4afSopenharmony_ci APP_LOGD("create instance from %{private}s", pathName_.c_str()); 53600cc4afSopenharmony_ci} 54600cc4afSopenharmony_ci 55600cc4afSopenharmony_ciZipFile::~ZipFile() 56600cc4afSopenharmony_ci{ 57600cc4afSopenharmony_ci Close(); 58600cc4afSopenharmony_ci} 59600cc4afSopenharmony_ci 60600cc4afSopenharmony_civoid ZipFile::SetContentLocation(const ZipPos start, const size_t length) 61600cc4afSopenharmony_ci{ 62600cc4afSopenharmony_ci APP_LOGD("set content location start position(%{public}llu), length(%{public}zu)", start, length); 63600cc4afSopenharmony_ci fileStartPos_ = start; 64600cc4afSopenharmony_ci fileLength_ = length; 65600cc4afSopenharmony_ci} 66600cc4afSopenharmony_ci 67600cc4afSopenharmony_cibool ZipFile::CheckEndDir(const EndDir &endDir) const 68600cc4afSopenharmony_ci{ 69600cc4afSopenharmony_ci size_t lenEndDir = sizeof(EndDir); 70600cc4afSopenharmony_ci if ((endDir.numDisk != 0) || (endDir.signature != EOCD_SIGNATURE) || (endDir.startDiskOfCentralDir != 0) || 71600cc4afSopenharmony_ci (endDir.offset >= fileLength_) || (endDir.totalEntriesInThisDisk != endDir.totalEntries) || 72600cc4afSopenharmony_ci (endDir.commentLen != 0) || 73600cc4afSopenharmony_ci // central dir can't overlap end of central dir 74600cc4afSopenharmony_ci ((endDir.offset + endDir.sizeOfCentralDir + lenEndDir) > fileLength_)) { 75600cc4afSopenharmony_ci APP_LOGE("end dir format error"); 76600cc4afSopenharmony_ci return false; 77600cc4afSopenharmony_ci } 78600cc4afSopenharmony_ci return true; 79600cc4afSopenharmony_ci} 80600cc4afSopenharmony_ci 81600cc4afSopenharmony_cibool ZipFile::ParseEndDirectory() 82600cc4afSopenharmony_ci{ 83600cc4afSopenharmony_ci size_t endDirLen = sizeof(EndDir); 84600cc4afSopenharmony_ci size_t endFilePos = fileStartPos_ + fileLength_; 85600cc4afSopenharmony_ci 86600cc4afSopenharmony_ci if (fileLength_ <= endDirLen) { 87600cc4afSopenharmony_ci APP_LOGE("parse EOCD file length(%{public}llu) <= end dir length(%{public}llu)", fileStartPos_, fileLength_); 88600cc4afSopenharmony_ci return false; 89600cc4afSopenharmony_ci } 90600cc4afSopenharmony_ci 91600cc4afSopenharmony_ci size_t eocdPos = endFilePos - endDirLen; 92600cc4afSopenharmony_ci if (fseek(file_, eocdPos, SEEK_SET) != 0) { 93600cc4afSopenharmony_ci APP_LOGE("locate EOCD seek failed, error: %{public}d", errno); 94600cc4afSopenharmony_ci return false; 95600cc4afSopenharmony_ci } 96600cc4afSopenharmony_ci 97600cc4afSopenharmony_ci if (fread(&endDir_, sizeof(EndDir), FILE_READ_COUNT, file_) != FILE_READ_COUNT) { 98600cc4afSopenharmony_ci APP_LOGE("read EOCD struct failed, error: %{public}d", errno); 99600cc4afSopenharmony_ci return false; 100600cc4afSopenharmony_ci } 101600cc4afSopenharmony_ci 102600cc4afSopenharmony_ci centralDirPos_ = endDir_.offset + fileStartPos_; 103600cc4afSopenharmony_ci APP_LOGD("parse EOCD offset(0x%{public}08x) file start position(0x%{public}08llx)", endDir_.offset, fileStartPos_); 104600cc4afSopenharmony_ci 105600cc4afSopenharmony_ci return CheckEndDir(endDir_); 106600cc4afSopenharmony_ci} 107600cc4afSopenharmony_ci 108600cc4afSopenharmony_cibool ZipFile::ParseAllEntries() 109600cc4afSopenharmony_ci{ 110600cc4afSopenharmony_ci bool ret = true; 111600cc4afSopenharmony_ci ZipPos currentPos = centralDirPos_; 112600cc4afSopenharmony_ci CentralDirEntry directoryEntry = {0}; 113600cc4afSopenharmony_ci 114600cc4afSopenharmony_ci for (uint16_t i = 0; i < endDir_.totalEntries; i++) { 115600cc4afSopenharmony_ci std::string fileName; 116600cc4afSopenharmony_ci fileName.reserve(MAX_FILE_PATH); 117600cc4afSopenharmony_ci fileName.resize(MAX_FILE_PATH - 1); 118600cc4afSopenharmony_ci 119600cc4afSopenharmony_ci if (fseek(file_, currentPos, SEEK_SET) != 0) { 120600cc4afSopenharmony_ci APP_LOGE("parse entry(%{public}d) seek zipEntry failed, error: %{public}d", i, errno); 121600cc4afSopenharmony_ci ret = false; 122600cc4afSopenharmony_ci break; 123600cc4afSopenharmony_ci } 124600cc4afSopenharmony_ci 125600cc4afSopenharmony_ci if (fread(&directoryEntry, sizeof(CentralDirEntry), FILE_READ_COUNT, file_) != FILE_READ_COUNT) { 126600cc4afSopenharmony_ci APP_LOGE("parse entry(%{public}d) read ZipEntry failed, error: %{public}d", i, errno); 127600cc4afSopenharmony_ci ret = false; 128600cc4afSopenharmony_ci break; 129600cc4afSopenharmony_ci } 130600cc4afSopenharmony_ci 131600cc4afSopenharmony_ci if (directoryEntry.signature != CENTRAL_SIGNATURE) { 132600cc4afSopenharmony_ci APP_LOGE("parse entry(%{public}d) check signature(0x%08x) at pos(0x%08llx) failed", 133600cc4afSopenharmony_ci i, 134600cc4afSopenharmony_ci directoryEntry.signature, 135600cc4afSopenharmony_ci currentPos); 136600cc4afSopenharmony_ci ret = false; 137600cc4afSopenharmony_ci break; 138600cc4afSopenharmony_ci } 139600cc4afSopenharmony_ci 140600cc4afSopenharmony_ci size_t fileLength = (directoryEntry.nameSize >= MAX_FILE_PATH) ? (MAX_FILE_PATH - 1) : directoryEntry.nameSize; 141600cc4afSopenharmony_ci if (fread(&(fileName[0]), fileLength, FILE_READ_COUNT, file_) != FILE_READ_COUNT) { 142600cc4afSopenharmony_ci APP_LOGE("parse entry(%{public}d) read file name failed, error: %{public}d", i, errno); 143600cc4afSopenharmony_ci ret = false; 144600cc4afSopenharmony_ci break; 145600cc4afSopenharmony_ci } 146600cc4afSopenharmony_ci fileName.resize(fileLength); 147600cc4afSopenharmony_ci 148600cc4afSopenharmony_ci ZipEntry currentEntry(directoryEntry); 149600cc4afSopenharmony_ci currentEntry.fileName = fileName; 150600cc4afSopenharmony_ci entriesMap_[fileName] = currentEntry; 151600cc4afSopenharmony_ci 152600cc4afSopenharmony_ci currentPos += sizeof(directoryEntry); 153600cc4afSopenharmony_ci currentPos += directoryEntry.nameSize + directoryEntry.extraSize + directoryEntry.commentSize; 154600cc4afSopenharmony_ci } 155600cc4afSopenharmony_ci 156600cc4afSopenharmony_ci APP_LOGD("parse %{public}d central entries from %{private}s", endDir_.totalEntries, pathName_.c_str()); 157600cc4afSopenharmony_ci return ret; 158600cc4afSopenharmony_ci} 159600cc4afSopenharmony_ci 160600cc4afSopenharmony_cibool ZipFile::Open() 161600cc4afSopenharmony_ci{ 162600cc4afSopenharmony_ci APP_LOGD("open: %{private}s", pathName_.c_str()); 163600cc4afSopenharmony_ci 164600cc4afSopenharmony_ci if (isOpen_) { 165600cc4afSopenharmony_ci APP_LOGE("has already opened"); 166600cc4afSopenharmony_ci return true; 167600cc4afSopenharmony_ci } 168600cc4afSopenharmony_ci 169600cc4afSopenharmony_ci if (pathName_.length() > PATH_MAX) { 170600cc4afSopenharmony_ci APP_LOGE("path length(%{public}u) longer than max length(%{public}d)", 171600cc4afSopenharmony_ci static_cast<unsigned int>(pathName_.length()), 172600cc4afSopenharmony_ci PATH_MAX); 173600cc4afSopenharmony_ci return false; 174600cc4afSopenharmony_ci } 175600cc4afSopenharmony_ci std::string realPath; 176600cc4afSopenharmony_ci realPath.reserve(PATH_MAX); 177600cc4afSopenharmony_ci realPath.resize(PATH_MAX - 1); 178600cc4afSopenharmony_ci if (realpath(pathName_.c_str(), &(realPath[0])) == nullptr) { 179600cc4afSopenharmony_ci APP_LOGE("transform real path error: %{public}d", errno); 180600cc4afSopenharmony_ci return false; 181600cc4afSopenharmony_ci } 182600cc4afSopenharmony_ci 183600cc4afSopenharmony_ci FILE *tmpFile = fopen(realPath.c_str(), "rb"); 184600cc4afSopenharmony_ci if (tmpFile == nullptr) { 185600cc4afSopenharmony_ci APP_LOGE("open file(%{private}s) failed, error: %{public}d", pathName_.c_str(), errno); 186600cc4afSopenharmony_ci return false; 187600cc4afSopenharmony_ci } 188600cc4afSopenharmony_ci 189600cc4afSopenharmony_ci if (fileLength_ == 0) { 190600cc4afSopenharmony_ci if (fseek(tmpFile, 0, SEEK_END) != 0) { 191600cc4afSopenharmony_ci APP_LOGE("file seek failed, error: %{public}d", errno); 192600cc4afSopenharmony_ci fclose(tmpFile); 193600cc4afSopenharmony_ci return false; 194600cc4afSopenharmony_ci } 195600cc4afSopenharmony_ci int64_t fileLength = ftell(tmpFile); 196600cc4afSopenharmony_ci if (fileLength == -1) { 197600cc4afSopenharmony_ci APP_LOGE("open file %{private}s failed", pathName_.c_str()); 198600cc4afSopenharmony_ci fclose(tmpFile); 199600cc4afSopenharmony_ci return false; 200600cc4afSopenharmony_ci } 201600cc4afSopenharmony_ci fileLength_ = static_cast<ZipPos>(fileLength); 202600cc4afSopenharmony_ci if (fileStartPos_ >= fileLength_) { 203600cc4afSopenharmony_ci APP_LOGE("open start pos > length failed"); 204600cc4afSopenharmony_ci fclose(tmpFile); 205600cc4afSopenharmony_ci return false; 206600cc4afSopenharmony_ci } 207600cc4afSopenharmony_ci 208600cc4afSopenharmony_ci fileLength_ -= fileStartPos_; 209600cc4afSopenharmony_ci } 210600cc4afSopenharmony_ci 211600cc4afSopenharmony_ci file_ = tmpFile; 212600cc4afSopenharmony_ci bool result = ParseEndDirectory(); 213600cc4afSopenharmony_ci if (result) { 214600cc4afSopenharmony_ci result = ParseAllEntries(); 215600cc4afSopenharmony_ci } 216600cc4afSopenharmony_ci // it means open file success. 217600cc4afSopenharmony_ci isOpen_ = true; 218600cc4afSopenharmony_ci return result; 219600cc4afSopenharmony_ci} 220600cc4afSopenharmony_ci 221600cc4afSopenharmony_civoid ZipFile::Close() 222600cc4afSopenharmony_ci{ 223600cc4afSopenharmony_ci APP_LOGD("close: %{private}s", pathName_.c_str()); 224600cc4afSopenharmony_ci 225600cc4afSopenharmony_ci if (!isOpen_ || file_ == nullptr) { 226600cc4afSopenharmony_ci APP_LOGW("file is not opened"); 227600cc4afSopenharmony_ci return; 228600cc4afSopenharmony_ci } 229600cc4afSopenharmony_ci 230600cc4afSopenharmony_ci entriesMap_.clear(); 231600cc4afSopenharmony_ci pathName_ = ""; 232600cc4afSopenharmony_ci isOpen_ = false; 233600cc4afSopenharmony_ci 234600cc4afSopenharmony_ci if (fclose(file_) != 0) { 235600cc4afSopenharmony_ci APP_LOGW("close failed err: %{public}d", errno); 236600cc4afSopenharmony_ci } 237600cc4afSopenharmony_ci file_ = nullptr; 238600cc4afSopenharmony_ci} 239600cc4afSopenharmony_ci 240600cc4afSopenharmony_ci// Get all file zipEntry in this file 241600cc4afSopenharmony_ciconst ZipEntryMap &ZipFile::GetAllEntries() const 242600cc4afSopenharmony_ci{ 243600cc4afSopenharmony_ci return entriesMap_; 244600cc4afSopenharmony_ci} 245600cc4afSopenharmony_ci 246600cc4afSopenharmony_cibool ZipFile::HasEntry(const std::string &entryName) const 247600cc4afSopenharmony_ci{ 248600cc4afSopenharmony_ci return entriesMap_.find(entryName) != entriesMap_.end(); 249600cc4afSopenharmony_ci} 250600cc4afSopenharmony_ci 251600cc4afSopenharmony_cibool ZipFile::IsDirExist(const std::string &dir) const 252600cc4afSopenharmony_ci{ 253600cc4afSopenharmony_ci APP_LOGD("target dir: %{public}s", dir.c_str()); 254600cc4afSopenharmony_ci if (dir.empty()) { 255600cc4afSopenharmony_ci APP_LOGE("target dir is empty"); 256600cc4afSopenharmony_ci return false; 257600cc4afSopenharmony_ci } 258600cc4afSopenharmony_ci 259600cc4afSopenharmony_ci auto tempDir = dir; 260600cc4afSopenharmony_ci if (tempDir.back() != ServiceConstants::FILE_SEPARATOR_CHAR) { 261600cc4afSopenharmony_ci tempDir.push_back(ServiceConstants::FILE_SEPARATOR_CHAR); 262600cc4afSopenharmony_ci } 263600cc4afSopenharmony_ci 264600cc4afSopenharmony_ci for (const auto &item : entriesMap_) { 265600cc4afSopenharmony_ci if (item.first.find(tempDir) == 0) { 266600cc4afSopenharmony_ci APP_LOGD("find target dir, fileName : %{public}s", item.first.c_str()); 267600cc4afSopenharmony_ci return true; 268600cc4afSopenharmony_ci } 269600cc4afSopenharmony_ci } 270600cc4afSopenharmony_ci APP_LOGD("target dir not found, dir : %{public}s", dir.c_str()); 271600cc4afSopenharmony_ci return false; 272600cc4afSopenharmony_ci} 273600cc4afSopenharmony_ci 274600cc4afSopenharmony_cibool ZipFile::GetEntry(const std::string &entryName, ZipEntry &resultEntry) const 275600cc4afSopenharmony_ci{ 276600cc4afSopenharmony_ci APP_LOGD("get entry by name: %{public}s", entryName.c_str()); 277600cc4afSopenharmony_ci auto iter = entriesMap_.find(entryName); 278600cc4afSopenharmony_ci if (iter != entriesMap_.end()) { 279600cc4afSopenharmony_ci resultEntry = iter->second; 280600cc4afSopenharmony_ci APP_LOGD("get entry succeed"); 281600cc4afSopenharmony_ci return true; 282600cc4afSopenharmony_ci } 283600cc4afSopenharmony_ci APP_LOGE("get entry failed"); 284600cc4afSopenharmony_ci return false; 285600cc4afSopenharmony_ci} 286600cc4afSopenharmony_ci 287600cc4afSopenharmony_cisize_t ZipFile::GetLocalHeaderSize(const uint16_t nameSize, const uint16_t extraSize) const 288600cc4afSopenharmony_ci{ 289600cc4afSopenharmony_ci return sizeof(LocalHeader) + nameSize + extraSize; 290600cc4afSopenharmony_ci} 291600cc4afSopenharmony_ci 292600cc4afSopenharmony_cibool ZipFile::CheckDataDesc(const ZipEntry &zipEntry, const LocalHeader &localHeader) const 293600cc4afSopenharmony_ci{ 294600cc4afSopenharmony_ci uint32_t crcLocal = 0; 295600cc4afSopenharmony_ci uint32_t compressedLocal = 0; 296600cc4afSopenharmony_ci uint32_t uncompressedLocal = 0; 297600cc4afSopenharmony_ci 298600cc4afSopenharmony_ci if (localHeader.flags & FLAG_DATA_DESC) { // use data desc 299600cc4afSopenharmony_ci DataDesc dataDesc; 300600cc4afSopenharmony_ci auto descPos = zipEntry.localHeaderOffset + GetLocalHeaderSize(localHeader.nameSize, localHeader.extraSize); 301600cc4afSopenharmony_ci descPos += fileStartPos_ + zipEntry.compressedSize; 302600cc4afSopenharmony_ci 303600cc4afSopenharmony_ci if (fseek(file_, descPos, SEEK_SET) != 0) { 304600cc4afSopenharmony_ci APP_LOGE("check local header seek datadesc failed, error: %{public}d", errno); 305600cc4afSopenharmony_ci return false; 306600cc4afSopenharmony_ci } 307600cc4afSopenharmony_ci 308600cc4afSopenharmony_ci if (fread(&dataDesc, sizeof(DataDesc), FILE_READ_COUNT, file_) != FILE_READ_COUNT) { 309600cc4afSopenharmony_ci APP_LOGE("check local header read datadesc failed, error: %{public}d", errno); 310600cc4afSopenharmony_ci return false; 311600cc4afSopenharmony_ci } 312600cc4afSopenharmony_ci 313600cc4afSopenharmony_ci if (dataDesc.signature != DATA_DESC_SIGNATURE) { 314600cc4afSopenharmony_ci APP_LOGE("check local header check datadesc signature failed"); 315600cc4afSopenharmony_ci return false; 316600cc4afSopenharmony_ci } 317600cc4afSopenharmony_ci 318600cc4afSopenharmony_ci crcLocal = dataDesc.crc; 319600cc4afSopenharmony_ci compressedLocal = dataDesc.compressedSize; 320600cc4afSopenharmony_ci uncompressedLocal = dataDesc.uncompressedSize; 321600cc4afSopenharmony_ci } else { 322600cc4afSopenharmony_ci crcLocal = localHeader.crc; 323600cc4afSopenharmony_ci compressedLocal = localHeader.compressedSize; 324600cc4afSopenharmony_ci uncompressedLocal = localHeader.uncompressedSize; 325600cc4afSopenharmony_ci } 326600cc4afSopenharmony_ci 327600cc4afSopenharmony_ci if ((zipEntry.crc != crcLocal) || (zipEntry.compressedSize != compressedLocal) || 328600cc4afSopenharmony_ci (zipEntry.uncompressedSize != uncompressedLocal)) { 329600cc4afSopenharmony_ci APP_LOGE("check local header compressed size corrupted"); 330600cc4afSopenharmony_ci return false; 331600cc4afSopenharmony_ci } 332600cc4afSopenharmony_ci 333600cc4afSopenharmony_ci return true; 334600cc4afSopenharmony_ci} 335600cc4afSopenharmony_ci 336600cc4afSopenharmony_cibool ZipFile::CheckCoherencyLocalHeader(const ZipEntry &zipEntry, uint16_t &extraSize) const 337600cc4afSopenharmony_ci{ 338600cc4afSopenharmony_ci LocalHeader localHeader = {0}; 339600cc4afSopenharmony_ci 340600cc4afSopenharmony_ci if (zipEntry.localHeaderOffset >= fileLength_) { 341600cc4afSopenharmony_ci APP_LOGE("check local file header offset overflow %{public}d", zipEntry.localHeaderOffset); 342600cc4afSopenharmony_ci return false; 343600cc4afSopenharmony_ci } 344600cc4afSopenharmony_ci 345600cc4afSopenharmony_ci if (fseek(file_, fileStartPos_ + zipEntry.localHeaderOffset, SEEK_SET) != 0) { 346600cc4afSopenharmony_ci APP_LOGE("check local header seek failed, error: %{public}d", errno); 347600cc4afSopenharmony_ci return false; 348600cc4afSopenharmony_ci } 349600cc4afSopenharmony_ci 350600cc4afSopenharmony_ci if (fread(&localHeader, sizeof(LocalHeader), FILE_READ_COUNT, file_) != FILE_READ_COUNT) { 351600cc4afSopenharmony_ci APP_LOGE("check local header read localheader failed, error: %{public}d", errno); 352600cc4afSopenharmony_ci return false; 353600cc4afSopenharmony_ci } 354600cc4afSopenharmony_ci 355600cc4afSopenharmony_ci if ((localHeader.signature != LOCAL_HEADER_SIGNATURE) || 356600cc4afSopenharmony_ci (zipEntry.compressionMethod != localHeader.compressionMethod)) { 357600cc4afSopenharmony_ci APP_LOGE("check local header signature or compressionMethod failed"); 358600cc4afSopenharmony_ci return false; 359600cc4afSopenharmony_ci } 360600cc4afSopenharmony_ci 361600cc4afSopenharmony_ci // current only support store and Z_DEFLATED method 362600cc4afSopenharmony_ci if ((zipEntry.compressionMethod != Z_DEFLATED) && (zipEntry.compressionMethod != 0)) { 363600cc4afSopenharmony_ci APP_LOGE("check local header compressionMethod(%{public}d) not support", zipEntry.compressionMethod); 364600cc4afSopenharmony_ci return false; 365600cc4afSopenharmony_ci } 366600cc4afSopenharmony_ci 367600cc4afSopenharmony_ci std::string fileName; 368600cc4afSopenharmony_ci fileName.reserve(MAX_FILE_PATH); 369600cc4afSopenharmony_ci fileName.resize(MAX_FILE_PATH - 1); 370600cc4afSopenharmony_ci size_t fileLength = (localHeader.nameSize >= MAX_FILE_PATH) ? (MAX_FILE_PATH - 1) : localHeader.nameSize; 371600cc4afSopenharmony_ci if (fileLength != zipEntry.fileName.length()) { 372600cc4afSopenharmony_ci APP_LOGE("check local header file name size failed"); 373600cc4afSopenharmony_ci return false; 374600cc4afSopenharmony_ci } 375600cc4afSopenharmony_ci if (fread(&(fileName[0]), fileLength, FILE_READ_COUNT, file_) != FILE_READ_COUNT) { 376600cc4afSopenharmony_ci APP_LOGE("check local header read file name failed, error: %{public}d", errno); 377600cc4afSopenharmony_ci return false; 378600cc4afSopenharmony_ci } 379600cc4afSopenharmony_ci fileName.resize(fileLength); 380600cc4afSopenharmony_ci if (zipEntry.fileName != fileName) { 381600cc4afSopenharmony_ci APP_LOGE("check local header file name corrupted"); 382600cc4afSopenharmony_ci return false; 383600cc4afSopenharmony_ci } 384600cc4afSopenharmony_ci 385600cc4afSopenharmony_ci if (!CheckDataDesc(zipEntry, localHeader)) { 386600cc4afSopenharmony_ci APP_LOGE("check data desc failed"); 387600cc4afSopenharmony_ci return false; 388600cc4afSopenharmony_ci } 389600cc4afSopenharmony_ci 390600cc4afSopenharmony_ci extraSize = localHeader.extraSize; 391600cc4afSopenharmony_ci return true; 392600cc4afSopenharmony_ci} 393600cc4afSopenharmony_ci 394600cc4afSopenharmony_cibool ZipFile::SeekToEntryStart(const ZipEntry &zipEntry, const uint16_t extraSize) const 395600cc4afSopenharmony_ci{ 396600cc4afSopenharmony_ci ZipPos startOffset = zipEntry.localHeaderOffset; 397600cc4afSopenharmony_ci // get data offset, add signature+localheader+namesize+extrasize 398600cc4afSopenharmony_ci startOffset += GetLocalHeaderSize(zipEntry.fileName.length(), extraSize); 399600cc4afSopenharmony_ci if (startOffset + zipEntry.compressedSize > fileLength_) { 400600cc4afSopenharmony_ci APP_LOGE("startOffset(%{public}lld)+entryCompressedSize(%{public}ud) > fileLength(%{public}llu)", 401600cc4afSopenharmony_ci startOffset, 402600cc4afSopenharmony_ci zipEntry.compressedSize, 403600cc4afSopenharmony_ci fileLength_); 404600cc4afSopenharmony_ci return false; 405600cc4afSopenharmony_ci } 406600cc4afSopenharmony_ci startOffset += fileStartPos_; // add file start relative to file stream 407600cc4afSopenharmony_ci 408600cc4afSopenharmony_ci APP_LOGD("seek to entry start 0x%{public}08llx", startOffset); 409600cc4afSopenharmony_ci if (fseek(file_, startOffset, SEEK_SET) != 0) { 410600cc4afSopenharmony_ci APP_LOGE("seek failed, error: %{public}d", errno); 411600cc4afSopenharmony_ci return false; 412600cc4afSopenharmony_ci } 413600cc4afSopenharmony_ci return true; 414600cc4afSopenharmony_ci} 415600cc4afSopenharmony_ci 416600cc4afSopenharmony_cibool ZipFile::UnzipWithStore(const ZipEntry &zipEntry, const uint16_t extraSize, std::ostream &dest) const 417600cc4afSopenharmony_ci{ 418600cc4afSopenharmony_ci APP_LOGD("unzip with store"); 419600cc4afSopenharmony_ci 420600cc4afSopenharmony_ci if (!SeekToEntryStart(zipEntry, extraSize)) { 421600cc4afSopenharmony_ci APP_LOGE("seek to entry start failed"); 422600cc4afSopenharmony_ci return false; 423600cc4afSopenharmony_ci } 424600cc4afSopenharmony_ci 425600cc4afSopenharmony_ci uint32_t remainSize = zipEntry.compressedSize; 426600cc4afSopenharmony_ci std::string readBuffer; 427600cc4afSopenharmony_ci readBuffer.reserve(UNZIP_BUF_OUT_LEN); 428600cc4afSopenharmony_ci readBuffer.resize(UNZIP_BUF_OUT_LEN - 1); 429600cc4afSopenharmony_ci while (remainSize > 0) { 430600cc4afSopenharmony_ci size_t readBytes; 431600cc4afSopenharmony_ci size_t readLen = (remainSize > UNZIP_BUF_OUT_LEN) ? UNZIP_BUF_OUT_LEN : remainSize; 432600cc4afSopenharmony_ci readBytes = fread(&(readBuffer[0]), sizeof(Byte), readLen, file_); 433600cc4afSopenharmony_ci if (readBytes == 0) { 434600cc4afSopenharmony_ci APP_LOGE("unzip store read failed, error: %{public}d", ferror(file_)); 435600cc4afSopenharmony_ci return false; 436600cc4afSopenharmony_ci } 437600cc4afSopenharmony_ci remainSize -= readBytes; 438600cc4afSopenharmony_ci dest.write(&(readBuffer[0]), readBytes); 439600cc4afSopenharmony_ci } 440600cc4afSopenharmony_ci 441600cc4afSopenharmony_ci return true; 442600cc4afSopenharmony_ci} 443600cc4afSopenharmony_ci 444600cc4afSopenharmony_cibool ZipFile::InitZStream(z_stream &zstream) const 445600cc4afSopenharmony_ci{ 446600cc4afSopenharmony_ci // init zlib stream 447600cc4afSopenharmony_ci if (memset_s(&zstream, sizeof(z_stream), 0, sizeof(z_stream))) { 448600cc4afSopenharmony_ci APP_LOGE("unzip stream buffer init failed"); 449600cc4afSopenharmony_ci return false; 450600cc4afSopenharmony_ci } 451600cc4afSopenharmony_ci int32_t zlibErr = inflateInit2(&zstream, -MAX_WBITS); 452600cc4afSopenharmony_ci if (zlibErr != Z_OK) { 453600cc4afSopenharmony_ci APP_LOGE("unzip inflated init failed"); 454600cc4afSopenharmony_ci return false; 455600cc4afSopenharmony_ci } 456600cc4afSopenharmony_ci 457600cc4afSopenharmony_ci BytePtr bufOut = new (std::nothrow) Byte[UNZIP_BUF_OUT_LEN]; 458600cc4afSopenharmony_ci if (bufOut == nullptr) { 459600cc4afSopenharmony_ci APP_LOGE("unzip inflated new out buffer failed"); 460600cc4afSopenharmony_ci return false; 461600cc4afSopenharmony_ci } 462600cc4afSopenharmony_ci 463600cc4afSopenharmony_ci BytePtr bufIn = new (std::nothrow) Byte[UNZIP_BUF_IN_LEN]; 464600cc4afSopenharmony_ci if (bufIn == nullptr) { 465600cc4afSopenharmony_ci APP_LOGE("unzip inflated new in buffer failed"); 466600cc4afSopenharmony_ci delete[] bufOut; 467600cc4afSopenharmony_ci return false; 468600cc4afSopenharmony_ci } 469600cc4afSopenharmony_ci zstream.next_out = bufOut; 470600cc4afSopenharmony_ci zstream.next_in = bufIn; 471600cc4afSopenharmony_ci zstream.avail_out = UNZIP_BUF_OUT_LEN; 472600cc4afSopenharmony_ci return true; 473600cc4afSopenharmony_ci} 474600cc4afSopenharmony_ci 475600cc4afSopenharmony_cibool ZipFile::ReadZStream(const BytePtr &buffer, z_stream &zstream, uint32_t &remainCompressedSize) const 476600cc4afSopenharmony_ci{ 477600cc4afSopenharmony_ci if (zstream.avail_in == 0) { 478600cc4afSopenharmony_ci size_t readBytes; 479600cc4afSopenharmony_ci size_t remainBytes = (remainCompressedSize > UNZIP_BUF_IN_LEN) ? UNZIP_BUF_IN_LEN : remainCompressedSize; 480600cc4afSopenharmony_ci readBytes = fread(buffer, sizeof(Byte), remainBytes, file_); 481600cc4afSopenharmony_ci if (readBytes == 0) { 482600cc4afSopenharmony_ci APP_LOGE("unzip inflated read failed, error: %{public}d", ferror(file_)); 483600cc4afSopenharmony_ci return false; 484600cc4afSopenharmony_ci } 485600cc4afSopenharmony_ci 486600cc4afSopenharmony_ci remainCompressedSize -= readBytes; 487600cc4afSopenharmony_ci zstream.avail_in = readBytes; 488600cc4afSopenharmony_ci zstream.next_in = buffer; 489600cc4afSopenharmony_ci } 490600cc4afSopenharmony_ci return true; 491600cc4afSopenharmony_ci} 492600cc4afSopenharmony_ci 493600cc4afSopenharmony_cibool ZipFile::UnzipWithInflated(const ZipEntry &zipEntry, const uint16_t extraSize, std::ostream &dest) const 494600cc4afSopenharmony_ci{ 495600cc4afSopenharmony_ci APP_LOGD("unzip with inflated"); 496600cc4afSopenharmony_ci 497600cc4afSopenharmony_ci z_stream zstream; 498600cc4afSopenharmony_ci if (!SeekToEntryStart(zipEntry, extraSize) || !InitZStream(zstream)) { 499600cc4afSopenharmony_ci return false; 500600cc4afSopenharmony_ci } 501600cc4afSopenharmony_ci 502600cc4afSopenharmony_ci BytePtr bufIn = zstream.next_in; 503600cc4afSopenharmony_ci BytePtr bufOut = zstream.next_out; 504600cc4afSopenharmony_ci 505600cc4afSopenharmony_ci bool ret = true; 506600cc4afSopenharmony_ci int32_t zlibErr = Z_OK; 507600cc4afSopenharmony_ci uint32_t remainCompressedSize = zipEntry.compressedSize; 508600cc4afSopenharmony_ci uint8_t errorTimes = 0; 509600cc4afSopenharmony_ci while ((remainCompressedSize > 0) || (zstream.avail_in > 0)) { 510600cc4afSopenharmony_ci if (!ReadZStream(bufIn, zstream, remainCompressedSize)) { 511600cc4afSopenharmony_ci ret = false; 512600cc4afSopenharmony_ci break; 513600cc4afSopenharmony_ci } 514600cc4afSopenharmony_ci 515600cc4afSopenharmony_ci zlibErr = inflate(&zstream, Z_SYNC_FLUSH); 516600cc4afSopenharmony_ci if ((zlibErr >= Z_OK) && (zstream.msg != nullptr)) { 517600cc4afSopenharmony_ci APP_LOGE("unzip inflated inflate, error: %{public}d, err msg: %{public}s", zlibErr, zstream.msg); 518600cc4afSopenharmony_ci ret = false; 519600cc4afSopenharmony_ci break; 520600cc4afSopenharmony_ci } 521600cc4afSopenharmony_ci 522600cc4afSopenharmony_ci size_t inflateLen = UNZIP_BUF_OUT_LEN - zstream.avail_out; 523600cc4afSopenharmony_ci if (inflateLen > 0) { 524600cc4afSopenharmony_ci dest.write(reinterpret_cast<const char *>(bufOut), inflateLen); 525600cc4afSopenharmony_ci zstream.next_out = bufOut; 526600cc4afSopenharmony_ci zstream.avail_out = UNZIP_BUF_OUT_LEN; 527600cc4afSopenharmony_ci errorTimes = 0; 528600cc4afSopenharmony_ci } else { 529600cc4afSopenharmony_ci errorTimes++; 530600cc4afSopenharmony_ci } 531600cc4afSopenharmony_ci if (errorTimes >= INFLATE_ERROR_TIMES) { 532600cc4afSopenharmony_ci APP_LOGE("unzip inflated data is abnormal"); 533600cc4afSopenharmony_ci ret = false; 534600cc4afSopenharmony_ci break; 535600cc4afSopenharmony_ci } 536600cc4afSopenharmony_ci } 537600cc4afSopenharmony_ci 538600cc4afSopenharmony_ci // free all dynamically allocated data structures except the next_in and next_out for this stream. 539600cc4afSopenharmony_ci zlibErr = inflateEnd(&zstream); 540600cc4afSopenharmony_ci if (zlibErr != Z_OK) { 541600cc4afSopenharmony_ci APP_LOGE("unzip inflateEnd error %{public}d", zlibErr); 542600cc4afSopenharmony_ci ret = false; 543600cc4afSopenharmony_ci } 544600cc4afSopenharmony_ci 545600cc4afSopenharmony_ci delete[] bufOut; 546600cc4afSopenharmony_ci delete[] bufIn; 547600cc4afSopenharmony_ci return ret; 548600cc4afSopenharmony_ci} 549600cc4afSopenharmony_ci 550600cc4afSopenharmony_ciZipPos ZipFile::GetEntryDataOffset(const ZipEntry &zipEntry, const uint16_t extraSize) const 551600cc4afSopenharmony_ci{ 552600cc4afSopenharmony_ci // get entry data offset relative file 553600cc4afSopenharmony_ci ZipPos offset = zipEntry.localHeaderOffset; 554600cc4afSopenharmony_ci 555600cc4afSopenharmony_ci offset += GetLocalHeaderSize(zipEntry.fileName.length(), extraSize); 556600cc4afSopenharmony_ci offset += fileStartPos_; 557600cc4afSopenharmony_ci 558600cc4afSopenharmony_ci return offset; 559600cc4afSopenharmony_ci} 560600cc4afSopenharmony_ci 561600cc4afSopenharmony_cibool ZipFile::GetDataOffsetRelative(const std::string &file, ZipPos &offset, uint32_t &length) const 562600cc4afSopenharmony_ci{ 563600cc4afSopenharmony_ci APP_LOGD("get data relative offset for file %{private}s", file.c_str()); 564600cc4afSopenharmony_ci 565600cc4afSopenharmony_ci ZipEntry zipEntry; 566600cc4afSopenharmony_ci if (!GetEntry(file, zipEntry)) { 567600cc4afSopenharmony_ci APP_LOGE("extract file: not find file"); 568600cc4afSopenharmony_ci return false; 569600cc4afSopenharmony_ci } 570600cc4afSopenharmony_ci 571600cc4afSopenharmony_ci uint16_t extraSize = 0; 572600cc4afSopenharmony_ci if (!CheckCoherencyLocalHeader(zipEntry, extraSize)) { 573600cc4afSopenharmony_ci APP_LOGE("check coherency local header failed"); 574600cc4afSopenharmony_ci return false; 575600cc4afSopenharmony_ci } 576600cc4afSopenharmony_ci 577600cc4afSopenharmony_ci offset = GetEntryDataOffset(zipEntry, extraSize); 578600cc4afSopenharmony_ci length = zipEntry.compressedSize; 579600cc4afSopenharmony_ci return true; 580600cc4afSopenharmony_ci} 581600cc4afSopenharmony_ci 582600cc4afSopenharmony_cibool ZipFile::ExtractFile(const std::string &file, std::ostream &dest) const 583600cc4afSopenharmony_ci{ 584600cc4afSopenharmony_ci APP_LOGD("extract file %{private}s", file.c_str()); 585600cc4afSopenharmony_ci 586600cc4afSopenharmony_ci ZipEntry zipEntry; 587600cc4afSopenharmony_ci if (!GetEntry(file, zipEntry)) { 588600cc4afSopenharmony_ci APP_LOGE("extract file: not find file"); 589600cc4afSopenharmony_ci return false; 590600cc4afSopenharmony_ci } 591600cc4afSopenharmony_ci 592600cc4afSopenharmony_ci uint16_t extraSize = 0; 593600cc4afSopenharmony_ci if (!CheckCoherencyLocalHeader(zipEntry, extraSize)) { 594600cc4afSopenharmony_ci APP_LOGE("check coherency local header failed"); 595600cc4afSopenharmony_ci return false; 596600cc4afSopenharmony_ci } 597600cc4afSopenharmony_ci 598600cc4afSopenharmony_ci bool ret = true; 599600cc4afSopenharmony_ci if (zipEntry.compressionMethod == 0) { 600600cc4afSopenharmony_ci ret = UnzipWithStore(zipEntry, extraSize, dest); 601600cc4afSopenharmony_ci } else { 602600cc4afSopenharmony_ci ret = UnzipWithInflated(zipEntry, extraSize, dest); 603600cc4afSopenharmony_ci } 604600cc4afSopenharmony_ci 605600cc4afSopenharmony_ci return ret; 606600cc4afSopenharmony_ci} 607600cc4afSopenharmony_ci} // namespace AppExecFwk 608600cc4afSopenharmony_ci} // namespace OHOS 609