bool FileUtils::mzExtractFile(unzFile uf, const std::string &directory) { unz_file_info64 fi; std::string filename; if (!mzGetInfo(uf, &fi, &filename)) { return false; } std::string fullPath(directory); fullPath += "/"; fullPath += filename; std::string parentPath = io::dirName(fullPath); if (!io::createDirectories(parentPath)) { FLOGW("%s: Failed to create directory: %s", parentPath.c_str(), io::lastErrorString().c_str()); } io::File file; if (!file.open(fullPath, io::File::OpenWrite)) { FLOGE("%s: Failed to open for writing: %s", fullPath.c_str(), file.errorString().c_str()); return false; } int ret = unzOpenCurrentFile(uf); if (ret != UNZ_OK) { FLOGE("miniunz: Failed to open inner file: %s", mzUnzErrorString(ret).c_str()); return false; } int n; char buf[32768]; uint64_t bytesWritten; while ((n = unzReadCurrentFile(uf, buf, sizeof(buf))) > 0) { if (!file.write(buf, n, &bytesWritten)) { FLOGE("%s: Failed to write file: %s", fullPath.c_str(), file.errorString().c_str()); unzCloseCurrentFile(uf); return false; } } if (n != 0) { FLOGE("miniunz: Finished before reaching inner file's EOF: %s", mzUnzErrorString(n).c_str()); } ret = unzCloseCurrentFile(uf); if (ret != UNZ_OK) { FLOGE("miniunz: Failed to close inner file: %s", mzUnzErrorString(ret).c_str()); return false; } return n == 0; }
PatcherError FileUtils::mzArchiveStats(const std::string &path, FileUtils::ArchiveStats *stats, std::vector<std::string> ignore) { assert(stats != nullptr); unzFile uf = mzOpenInputFile(path); if (!uf) { FLOGE("minizip: Failed to open for reading: {}", path); return PatcherError::createArchiveError( ErrorCode::ArchiveReadOpenError, path); } uint64_t count = 0; uint64_t totalSize = 0; std::string name; unz_file_info64 fi; memset(&fi, 0, sizeof(fi)); int ret = unzGoToFirstFile(uf); if (ret != UNZ_OK) { mzCloseInputFile(uf); return PatcherError::createArchiveError( ErrorCode::ArchiveReadHeaderError, std::string()); } do { if (!mzGetInfo(uf, &fi, &name)) { mzCloseInputFile(uf); return PatcherError::createArchiveError( ErrorCode::ArchiveReadHeaderError, std::string()); } if (std::find(ignore.begin(), ignore.end(), name) == ignore.end()) { ++count; totalSize += fi.uncompressed_size; } } while ((ret = unzGoToNextFile(uf)) == UNZ_OK); if (ret != UNZ_END_OF_LIST_OF_FILE) { mzCloseInputFile(uf); return PatcherError::createArchiveError( ErrorCode::ArchiveReadHeaderError, std::string()); } mzCloseInputFile(uf); stats->files = count; stats->totalSize = totalSize; return PatcherError(); }
ErrorCode FileUtils::mzArchiveStats(const std::string &path, FileUtils::ArchiveStats *stats, std::vector<std::string> ignore) { assert(stats != nullptr); MzUnzCtx *ctx = mzOpenInputFile(path); if (!ctx) { FLOGE("miniunz: Failed to open for reading: %s", path.c_str()); return ErrorCode::ArchiveReadOpenError; } uint64_t count = 0; uint64_t totalSize = 0; std::string name; unz_file_info64 fi; memset(&fi, 0, sizeof(fi)); int ret = unzGoToFirstFile(ctx->uf); if (ret != UNZ_OK) { FLOGE("miniunz: Failed to move to first file: %s", mzUnzErrorString(ret).c_str()); mzCloseInputFile(ctx); return ErrorCode::ArchiveReadHeaderError; } do { if (!mzGetInfo(ctx->uf, &fi, &name)) { mzCloseInputFile(ctx); return ErrorCode::ArchiveReadHeaderError; } if (std::find(ignore.begin(), ignore.end(), name) == ignore.end()) { ++count; totalSize += fi.uncompressed_size; } } while ((ret = unzGoToNextFile(ctx->uf)) == UNZ_OK); if (ret != UNZ_END_OF_LIST_OF_FILE) { FLOGE("miniunz: Finished before EOF: %s", mzUnzErrorString(ret).c_str()); mzCloseInputFile(ctx); return ErrorCode::ArchiveReadHeaderError; } mzCloseInputFile(ctx); stats->files = count; stats->totalSize = totalSize; return ErrorCode::NoError; }
bool FileUtils::mzReadToMemory(unzFile uf, std::vector<unsigned char> *output, void (*cb)(uint64_t bytes, void *), void *userData) { unz_file_info64 fi; if (!mzGetInfo(uf, &fi, nullptr)) { return false; } std::vector<unsigned char> data; data.reserve(fi.uncompressed_size); int ret = unzOpenCurrentFile(uf); if (ret != UNZ_OK) { FLOGE("miniunz: Failed to open inner file: %s", mzUnzErrorString(ret).c_str()); return false; } int n; char buf[32768]; while ((n = unzReadCurrentFile(uf, buf, sizeof(buf))) > 0) { if (cb) { cb(data.size() + n, userData); } data.insert(data.end(), buf, buf + n); } if (n != 0) { FLOGE("miniunz: Finished before reaching inner file's EOF: %s", mzUnzErrorString(n).c_str()); } ret = unzCloseCurrentFile(uf); if (ret != UNZ_OK) { FLOGE("miniunz: Failed to close inner file: %s", mzUnzErrorString(ret).c_str()); return false; } if (n != 0) { return false; } data.swap(*output); return true; }
bool FileUtils::mzExtractFile(unzFile uf, const std::string &directory) { unz_file_info64 fi; std::string filename; if (!mzGetInfo(uf, &fi, &filename)) { return false; } std::string fullPath(directory); fullPath += "/"; fullPath += filename; boost::filesystem::path path(fullPath); boost::filesystem::create_directories(path.parent_path()); std::ofstream file(fullPath, std::ios::binary); if (file.fail()) { return false; } int ret = unzOpenCurrentFile(uf); if (ret != UNZ_OK) { return false; } int n; char buf[32768]; while ((n = unzReadCurrentFile(uf, buf, sizeof(buf))) > 0) { file.write(buf, n); } unzCloseCurrentFile(uf); return n == 0; }
bool FileUtils::mzReadToMemory(unzFile uf, std::vector<unsigned char> *output, void (*cb)(uint64_t bytes, void *), void *userData) { unz_file_info64 fi; if (!mzGetInfo(uf, &fi, nullptr)) { return false; } std::vector<unsigned char> data; data.reserve(fi.uncompressed_size); int ret = unzOpenCurrentFile(uf); if (ret != UNZ_OK) { return false; } int n; char buf[32768]; while ((n = unzReadCurrentFile(uf, buf, sizeof(buf))) > 0) { if (cb) { cb(data.size() + n, userData); } data.insert(data.end(), buf, buf + n); } unzCloseCurrentFile(uf); if (n != 0) { return false; } data.swap(*output); return true; }
bool FileUtils::mzCopyFileRaw(unzFile uf, zipFile zf, const std::string &name, void (*cb)(uint64_t bytes, void *), void *userData) { unz_file_info64 ufi; if (!mzGetInfo(uf, &ufi, nullptr)) { return false; } bool zip64 = ufi.uncompressed_size >= ((1ull << 32) - 1); zip_fileinfo zfi; memset(&zfi, 0, sizeof(zfi)); zfi.dosDate = ufi.dosDate; zfi.tmz_date.tm_sec = ufi.tmu_date.tm_sec; zfi.tmz_date.tm_min = ufi.tmu_date.tm_min; zfi.tmz_date.tm_hour = ufi.tmu_date.tm_hour; zfi.tmz_date.tm_mday = ufi.tmu_date.tm_mday; zfi.tmz_date.tm_mon = ufi.tmu_date.tm_mon; zfi.tmz_date.tm_year = ufi.tmu_date.tm_year; zfi.internal_fa = ufi.internal_fa; zfi.external_fa = ufi.external_fa; int method; int level; // Open raw file in input zip int ret = unzOpenCurrentFile2( uf, // file &method, // method &level, // level 1 // raw ); if (ret != UNZ_OK) { return false; } // Open raw file in output zip ret = zipOpenNewFileInZip2_64( zf, // file name.c_str(), // filename &zfi, // zip_fileinfo nullptr, // extrafield_local 0, // size_extrafield_local nullptr, // extrafield_global 0, // size_extrafield_global nullptr, // comment method, // method level, // level 1, // raw zip64 // zip64 ); if (ret != ZIP_OK) { unzCloseCurrentFile(uf); return false; } uint64_t bytes = 0; // Exceeds Android's default stack size, unfortunately, so allocate // on the heap std::vector<unsigned char> buf(1024 * 1024); // 1MiB int bytes_read; double ratio; while ((bytes_read = unzReadCurrentFile(uf, buf.data(), buf.size())) > 0) { bytes += bytes_read; if (cb) { // Scale this to the uncompressed size for the purposes of a // progress bar ratio = (double) bytes / ufi.compressed_size; cb(ratio * ufi.uncompressed_size, userData); } ret = zipWriteInFileInZip(zf, buf.data(), bytes_read); if (ret != ZIP_OK) { unzCloseCurrentFile(uf); zipCloseFileInZip(zf); return false; } } unzCloseCurrentFile(uf); zipCloseFileInZipRaw64(zf, ufi.uncompressed_size, ufi.crc); return bytes_read == 0; }