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; }
bool MinizipUtils::copy_file_raw(unzFile uf, zipFile zf, const std::string &name, void (*cb)(uint64_t bytes, void *), void *userData) { unz_file_info64 ufi; if (!get_info(uf, &ufi, nullptr)) { return false; } bool zip64 = ufi.uncompressed_size >= ((1ull << 32) - 1); zip_fileinfo zfi; memset(&zfi, 0, sizeof(zfi)); zfi.dos_date = ufi.dos_date; 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) { LOGE("miniunz: Failed to open inner file: %s", unz_error_string(ret).c_str()); 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 static_cast<uint16_t>(method), // method level, // level 1, // raw zip64 // zip64 ); if (ret != ZIP_OK) { LOGE("minizip: Failed to open inner file: %s", zip_error_string(ret).c_str()); unzCloseCurrentFile(uf); return false; } uint64_t bytes = 0; // minizip no longer supports buffers larger than UINT16_MAX char buf[UINT16_MAX]; int bytes_read; double ratio; while ((bytes_read = unzReadCurrentFile(uf, buf, sizeof(buf))) > 0) { bytes += static_cast<uint64_t>(bytes_read); if (cb) { // Scale this to the uncompressed size for the purposes of a // progress bar ratio = static_cast<double>(bytes) / static_cast<double>(ufi.compressed_size); cb(static_cast<uint64_t>( ratio * static_cast<double>(ufi.uncompressed_size)), userData); } ret = zipWriteInFileInZip(zf, buf, static_cast<uint32_t>(bytes_read)); if (ret != ZIP_OK) { LOGE("minizip: Failed to write data to inner file: %s", zip_error_string(ret).c_str()); unzCloseCurrentFile(uf); zipCloseFileInZip(zf); return false; } } if (bytes_read != 0) { LOGE("miniunz: Finished before reaching inner file's EOF: %s", unz_error_string(bytes_read).c_str()); } bool close_success = true; ret = unzCloseCurrentFile(uf); if (ret != UNZ_OK) { LOGE("miniunz: Failed to close inner file: %s", unz_error_string(ret).c_str()); close_success = false; } ret = zipCloseFileInZipRaw64(zf, ufi.uncompressed_size, ufi.crc); if (ret != ZIP_OK) { LOGE("minizip: Failed to close inner file: %s", zip_error_string(ret).c_str()); close_success = false; } return bytes_read == 0 && close_success; }