Skip to content

refactor(export): replace 3rdparty docx lib with zero-dependency docx writer - #973

Merged
deepin-bot[bot] merged 1 commit into
linuxdeepin:masterfrom
add-uos:feat/docx-zero-dep-writer
Nov 12, 2026
Merged

deepin-bot[bot] merged 1 commit into
linuxdeepin:masterfrom
add-uos:feat/docx-zero-dep-writer

Conversation

@add-uos

@add-uos add-uos commented Nov 12, 2026 •

Copy link
Copy Markdown
Contributor

Note / 说明: 本 PR 基于并且叠于 #972(xlsx 零依赖写入器)之上,diff 含两个提交;#972 合并后本 PR 自动收敛为仅 docx 改动。

Note: This PR is stacked on top of #972 (zero-dependency xlsx writer); the diff contains both commits and will shrink to docx-only once #972 merges.

概述 / Summary

移除 3rdparty/docx(python-docx 的 Qt 移植,71 文件约 6.4k 行,依赖模板资源 :/template.docx 与 Qt 私有 API qzipreader_p.h/qzipwriter_p.h),改用自研零依赖 DocxWriter 导出 docx;同时抽取 xlsx/docx 共享的 ZipWriter。

Remove 3rdparty/docx (a Qt port of python-docx, 71 files ~6.4k lines, depends on template resource :/template.docx and Qt private APIs qzipreader_p.h/qzipwriter_p.h) and replace it with a self-implemented zero-dependency DocxWriter; extract a shared ZipWriter for xlsx/docx.

实现 / Implementation

  • 新增 src/DeviceManager/ZipWriter:从 XlsxWriter 抽取的共享层(CRC-32 查表法 + STORE 方式 ZIP 容器 + escapeXml),XlsxWriter 改用之,XlsxDetail 仅保留 columnName
  • 新增 src/DeviceManager/DocxWriter:不依赖模板,styles.xml 内建(Normal/Heading1/Heading2,沿用原模板字体字号与 A4 页面设置),表格内联边框,save 返回真实结果
  • 顺带修复旧库三处缺陷:
    • addHeading 引用不存在的样式名 "1"/"2",标题实际降级为普通文本 → 现在 Heading1/Heading2 真实生效(Word/WPS 导航窗格与目录可识别)
    • pPr 写在 run 之后,违反 OOXML schema 顺序 → 修正为 pPr 在前
    • 表格紧邻正文末尾 → 表格后补空段落
  • 调用点 DeviceManager / DeviceInfo / MacroDefinition.h(EXPORT_TO_DOC 宏)同步替换,接口形状保持一致(addHeading/addParagraph/addTable/cell/addText)
  • 删除 3rdparty/docx 整目录与 assets/template.docx(appimage.qrc 同步移除)

验证 / Verification

  • 单测:新增 ut_docxwriter 20 例;解除此前因旧库默认构造 SEGV 而跳过的 7 个 doc 导出用例;全量 2493/2493 通过(与 upstream master 基线一致,存量 UT_LogTreeView_drawRow 崩溃为基线已有)
  • 覆盖率:DocxWriter.cpp 98.4%、ZipWriter.cpp 97.4%
  • 兼容性:python-docx 回读(Heading 1/Heading 2 内建样式映射成功)、LibreOffice 26.8 headless 转文本/HTML(标题渲染为 <h1>/<h2>,内容与表格边框完整)、OOXML 结构校验(ZIP 完整性、XML 可解析、pPr 顺序、边框六向齐全)均通过

Log

PMS: TASK-398531
删减约 6.4k 行三方代码与模板资源,消除 Qt 私有 API 依赖,修复标题样式失效等 3 处旧缺陷。

Influence

导出 docx 文件仍为 Office Open XML 格式,排版内容与之前一致;标题样式由降级的普通文本恢复为真正的 Heading 1/2。

Summary by Sourcery

Replace the third-party DOCX export stack with a zero-dependency writer and shared ZIP infrastructure while preserving export compatibility and improving document correctness.

New Features:

  • Add a zero-dependency DocxWriter for generating compatible DOCX exports with headings, paragraphs, tables, and built-in styles.

Bug Fixes:

  • Restore functional Heading 1 and Heading 2 styles, produce schema-compliant paragraph markup, and ensure DOCX exports report save failures accurately.

Enhancements:

  • Replace the bundled third-party DOCX implementation and template with a shared QtCore-only ZIP writer used by both DOCX and XLSX exports.
  • Preserve existing export interfaces while removing Qt private API and third-party DOCX dependencies.

Build:

  • Remove third-party DOCX include paths and associated template resources from the build configuration.

Tests:

  • Add comprehensive DocxWriter and ZipWriter unit coverage and enable previously skipped DOCX export tests.

Chores:

  • Delete the obsolete third-party DOCX source tree, translation resources, and template files.

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry @add-uos, this pull request is too large to review

It changes 28,145 lines. Sourcery can review pull requests with up to 20,000 changed lines.

lzwind
lzwind previously approved these changes Nov 12, 2026
@deepin-ci-robot

Copy link
Copy Markdown

deepin pr auto review

🤖 AI 代码审查报告

总体评分: 98 分 (通过阈值: 70分)

Pass


📊 总体评价

项目 结果
审查结论 代码审查通过
评分详情 本次重构用零三方依赖的极简 DocxWriter/XlsxWriter/ZipWriter 替换了原有的 3rdparty/docx 与 3rdparty/QtXlsxWriter 两个第三方库,消除了对 Qt 私有 API(qzipreader_p.h/qzipwriter_p.h) 和模板文件(template.docx)的依赖。新增代码结构清晰、注释完整、测试覆盖充分,CRC-32/XML 转义/ZIP 结构实现正确,无安全漏洞。仅有 2 处轻微优化建议(crc32 静态初始化线程安全、buildStyles/buildSheet 重复遍历),不影响功能正确性。

🔍 详细分析

1. 语法逻辑 ✅

评价: 语法正确,逻辑清晰 ✅ 通过

潜在问题:
✅ 未发现明显问题

建议: ['无需修改']


2. 代码质量 ✅

评价: 代码结构清晰,注释完整 ✅ 通过

潜在问题:
✅ 未发现明显问题

建议: ['建议将 CRC-32 查找表改为编译期常量(constexpr 数组)或使用 std::call_once 初始化,消除线程安全隐患']


3. 代码性能 ✅

评价: 性能良好,资源使用合理 ✅ 通过

潜在问题:
✅ 未发现明显问题

建议: ['可将 used 格式列表的收集提取为独立方法(如 collectUsedFormats()),在 saveAs 中调用一次后传给 buildStyles 和 buildSheet 复用']


4. 代码安全 🔒

评价: 存在0个安全漏洞 ✅ 通过

🔐 发现 0 个安全漏洞

安全漏洞详情:
✅ 未发现安全漏洞

建议: ['无需安全加固']


💡 改进建议代码示例

// ZipWriter.cpp — 将 CRC-32 查找表改为编译期常量,消除线程安全隐患
// 替换原有的 static bool tableReady + static quint32 table[256] 惰性初始化

namespace ZipDetail {

// 编译期生成 CRC-32 查找表(线程安全,无需运行时初始化)
constexpr quint32 crc32Entry(quint32 i)
{
    quint32 c = i;
    for (int k = 0; k < 8; ++k)
        c = (c & 1) ? (0xEDB88320u ^ (c >> 1)) : (c >> 1);
    return c;
}

// C++14 constexpr 不支持循环,可用 Lambda + 编译期展开或直接预生成;
// 此处展示运行时一次性初始化但用 std::call_once 保证线程安全
#include <mutex>
static quint32 table[256];
static std::once_flag tableFlag;

quint32 crc32(const QByteArray &data)
{
    std::call_once(tableFlag, [] {
        for (quint32 i = 0; i < 256; ++i) {
            quint32 c = i;
            for (int k = 0; k < 8; ++k)
                c = (c & 1) ? (0xEDB88320u ^ (c >> 1)) : (c >> 1);
            table[i] = c;
        }
    });

    quint32 crc = 0xFFFFFFFFu;
    const unsigned char *p = reinterpret_cast<const unsigned char *>(data.constData());
    for (int i = 0; i < data.size(); ++i)
        crc = table[(crc ^ p[i]) & 0xFF] ^ (crc >> 8);
    return crc ^ 0xFFFFFFFFu;
}

}   // namespace ZipDetail

本报告由 AI 代码审查工具自动生成

@add-uos

add-uos commented Nov 12, 2026

Copy link
Copy Markdown
Contributor Author

/forcemerge

@deepin-bot

deepin-bot Bot commented Nov 12, 2026

Copy link
Copy Markdown
Contributor

This pr force merged! (status: dirty)

… writer

Replace the 3rdparty/docx library (a Qt port of python-docx) with a
self-contained DocxWriter, eliminating the bundled template resource
and the dependency on Qt private APIs (qzipreader_p/qzipwriter_p).

- add shared ZipWriter (STORE zip + CRC-32), refactor XlsxWriter to
  use it; XlsxDetail keeps only columnName, crc32/escapeXml move to
  ZipDetail
- new DocxWriter builds styles.xml internally (Heading1/Heading2 now
  actually resolve; the old lib referenced non-existent style names),
  places pPr before runs per OOXML schema, and appends an empty
  paragraph after tables
- drop assets/template.docx and the whole 3rdparty/docx tree
- exportToDoc now returns the real save result instead of always true
- add ut_docxwriter (20 cases); unblock previously skipped doc export
  tests in ut_deviceinfo_export/ut_devicemanager_save; all 2493 tests
  pass; DocxWriter coverage 98.4%, ZipWriter 97.4%
- verified with python-docx and LibreOffice: headings render as
  Heading 1/2, content and table borders intact

用零依赖 DocxWriter 替换 3rdparty/docx 库(python-docx 的 Qt 移植),
移除内置模板资源与 Qt 私有 API(qzipreader_p/qzipwriter_p)依赖。

- 新增共享 ZipWriter(STORE zip + CRC-32),XlsxWriter 改用之;
  XlsxDetail 仅保留 columnName,crc32/escapeXml 移至 ZipDetail
- DocxWriter 内置 styles.xml(Heading1/Heading2 真实生效,旧库引用
  不存在的样式名致标题降级为普通文本),按 OOXML 规范将 pPr 置于
  run 之前,表格后补空段落
- 删除 assets/template.docx 与整个 3rdparty/docx 目录
- exportToDoc 返回真实保存结果(旧实现恒返回 true)
- 新增 ut_docxwriter(20 例);解除 ut_deviceinfo_export 与
  ut_devicemanager_save 中因旧库 SEGV 跳过的 doc 导出测试;
  2493 例全过,DocxWriter 覆盖率 98.4%、ZipWriter 97.4%
- 经 python-docx 与 LibreOffice 验证:标题正确渲染为 Heading 1/2,
  内容与表格边框完整

Log: 用零依赖 DocxWriter 替换三方 docx 库并抽取共享 ZipWriter
PMS: TASK-398531
Influence: 导出 Word 报告不再依赖三方库与模板资源,标题样式、表格边框与 OOXML 结构规范化,兼容主流办公软件。
@add-uos
add-uos dismissed lzwind’s stale review November 12, 2026 06:35

The merge-base changed after approval.

@add-uos
add-uos force-pushed the feat/docx-zero-dep-writer branch from 9c84646 to 008b0fc Compare November 12, 2026 06:35
@deepin-ci-robot

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: add-uos

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

1 similar comment
@deepin-ci-robot

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: add-uos

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@add-uos

add-uos commented Nov 12, 2026

Copy link
Copy Markdown
Contributor Author

/forcemerge

@deepin-bot

deepin-bot Bot commented Nov 12, 2026

Copy link
Copy Markdown
Contributor

This pr force merged! (status: blocked)

@deepin-bot
deepin-bot Bot merged commit 9d405bf into linuxdeepin:master Nov 12, 2026
14 of 19 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants