From aa7e7314a397e96d3a236b2001b51508a5d4400a Mon Sep 17 00:00:00 2001 From: ZhangTingan Date: Wed, 15 Apr 2026 15:52:12 +0800 Subject: [PATCH] fix: auto-detect Deflate64 in ZIP files Use libzip API to detect Deflate64 compression and automatically switch to cli7z plugin for better compatibility. log: fix bug Bug:https://pms.uniontech.com//bug-view-357127.html --- src/CMakeLists.txt | 4 +++ src/source/common/uitools.cpp | 58 +++++++++++++++++++++++++++++++++++ src/source/common/uitools.h | 7 +++++ 3 files changed, 69 insertions(+) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e9c8cef88..630830ed3 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -44,6 +44,9 @@ include_directories(${GOBJECT_INCLUDE_DIRS}) pkg_search_module(GIO REQUIRED gio-unix-2.0) include_directories(${GIO_INCLUDE_DIRS}) +pkg_search_module(ZIP REQUIRED libzip) +include_directories(${ZIP_INCLUDE_DIRS}) + #指定头文件路径 include_directories(${PROJECT_SOURCE_DIR}) include_directories(${PROJECT_SOURCE_DIR}/source) @@ -77,6 +80,7 @@ target_link_libraries(${EXE_NAME} ${DtkWidget_LIBRARIES} ${GOBJECT_LIBRARIES} ${GIO_LIBRARIES} + ${ZIP_LIBRARIES} compressor-interface ) diff --git a/src/source/common/uitools.cpp b/src/source/common/uitools.cpp index 9436a6f07..294144fe5 100644 --- a/src/source/common/uitools.cpp +++ b/src/source/common/uitools.cpp @@ -29,6 +29,8 @@ #include #include +#include // libzip header + #include DCORE_USE_NAMESPACE @@ -223,6 +225,14 @@ ReadOnlyArchiveInterface *UiTools::createInterface(const QString &fileName, bool const CustomMimeType mimeType = determineMimeType(fileName); + // 提前检测 ZIP 文件是否需要替代插件(如 Deflate64) + if (!bWrite && eType == APT_Auto && mimeType.name() == "application/zip") { + if (checkZipNeedsAlternativePlugin(fileName)) { + qInfo() << "Detected need for alternative plugin, switching to cli7z"; + eType = APT_Cli7z; // 自动切换到 cli7z 插件 + } + } + QVector offers; if (bWrite) { offers = PluginManager::get_instance().preferredWritePluginsFor(mimeType); @@ -460,3 +470,51 @@ bool UiTools::isWayland() return false; } } + +bool UiTools::checkZipNeedsAlternativePlugin(const QString &strFileName) +{ + // 使用 libzip API 检测压缩方法 + int errcode = 0; + zip_t *archive = zip_open(QFile::encodeName(strFileName).constData(), ZIP_RDONLY, &errcode); + + if (!archive) { + qWarning() << "Failed to open ZIP file for compression method check:" << strFileName; + return false; // 无法打开文件,使用默认插件 + } + + // 获取文件数量 + zip_int64_t num_entries = zip_get_num_entries(archive, 0); + + // 检查前几个文件,跳过 stored(未压缩)文件,找到第一个实际压缩的文件 + bool needsAlternative = false; + const int maxCheck = 20; // 最多检查前 20 个文件 + + for (zip_int64_t i = 0; i < num_entries && i < maxCheck; i++) { + struct zip_stat stat_buffer; + zip_stat_init(&stat_buffer); + + if (zip_stat_index(archive, static_cast(i), 0, &stat_buffer) == 0) { + // 跳过 stored 文件(comp_method == 0) + if (stat_buffer.comp_method == ZIP_CM_STORE) { + continue; + } + + // 检查压缩方法 + // ZIP_CM_DEFLATE (8) = 标准 Deflate + // ZIP_CM_DEFLATE64 (9) = Deflate64 + if (stat_buffer.comp_method == ZIP_CM_DEFLATE64) { // ZIP_CM_DEFLATE64 + qInfo() << "Detected Deflate64 compression method, switching to cli7z plugin" + << "file:" << strFileName + << "entry:" << stat_buffer.name; + needsAlternative = true; + break; + } + + // 如果找到第一个非 stored 的文件,且不是 Deflate64,则停止检查,通常 ZIP 文件使用统一的压缩方法 + break; + } + } + + zip_close(archive); + return needsAlternative; +} diff --git a/src/source/common/uitools.h b/src/source/common/uitools.h index a873d35c1..40ff41703 100644 --- a/src/source/common/uitools.h +++ b/src/source/common/uitools.h @@ -117,6 +117,13 @@ class UiTools : public QObject static ReadOnlyArchiveInterface *createInterface(const QString &fileName, bool bWrite = false, AssignPluginType eType = APT_Auto/*bool bUseLibArchive = false*/); static ReadOnlyArchiveInterface *createInterface(const QString &fileName, const CustomMimeType &mimeType, Plugin *plugin); + /** + * @brief checkZipNeedsAlternativePlugin 检测 ZIP 文件是否需要替代插件 + * @param strFileName ZIP 文件路径 + * @return 是否需要使用 cli7z 等替代插件 + */ + static bool checkZipNeedsAlternativePlugin(const QString &strFileName); + /** * @brief transSplitFileName 处理7z、rar分卷压缩包名称 * @param fileName 原始名称