SumatraPDF 的 mupdf 补丁化管理:ext/patches 补丁集的设计、应用与验证指南
桌面应用文档【免费下载链接】sumatrapdfSumatraPDF reader项目地址https://gitcode.com/gh_mirrors/su/sumatrapdf点击查看免费下载本文以 ext/patches/README.md 为主线系统讲解 SumatraPDF 如何将内嵌vendored的 mupdf 从原地改、改完就忘的维护困局转变为每项改动都有一条 git diff 补丁 一段动机说明的可审计流程。读完本文你将掌握该仓库补丁集的基线版本与编号规则、40 个补丁的完整清单、git apply --3way的应用/手工合并流程、与上游1.28.2逐字节比对验证的方法以及新增/更新补丁时必须遵守的行尾与同步纪律。为什么需要一套补丁记录ext/mupdf是 mupdf 的内嵌副本vendored copySumatraPDF 直接在其中原地修改源码。这种做法的维护成本很高没有任何记录能说明改了什么、为什么改每次升级 mupdf 都意味着要从一个涉及约 1400 个文件的 diff 中重新推导出自家的改动。ext/patches/目录就是为了解决这个问题而存在的记录层每个.patch文件对应一个逻辑改动采用标准的git diff格式并附有做了什么、为什么做的说明补丁的路径基准是ext/mupdf因此从该目录内使用-p1即可应用完全属于 SumatraPDF 自有的整文件例如pkcs7-windows.[ch]不属于补丁体系它们放在src/mupdf/见其 README根本不在内嵌树内。补丁基线mupdf 1.28.2所有补丁都针对同一个内嵌基线上游版本mupdf1.28.2tag1.28.2commitfe374accd版本记录见 ext/versions.txt该文件在 mupdf 一行同时注明了我们对内嵌树的改动记录在 ext/patches/参见其 README路径约定补丁内的路径相对ext/mupdf展开应用时需在ext/mupdf目录内使用-p1。目录的最终状态是一个严格可复现的封闭集ext/mupdf等于字节级一致的 mupdf1.28.2加上这些补丁除此之外别无其他。补丁清单全览截至当前仓库ext/patches/下共有 38 个.patch文件。编号刻意保留空洞缺少 0020、0028编号一旦分配就不会复用便于回溯历史。其中第一组是 SumatraPDF 自研补丁补丁内容0001-tools-usage-say-sumatrapdf用法文本显示SumatraPDF tool而非mutool0002-tools-reset-fz-optind支持在进程内多次调用工具 main0003-signatures-windows-pkcs7工具改用 Windows CryptoAPI 的 pkcs7 辅助实现src/mupdf/pkcs7-windows.[ch]不再依赖 OpenSSL0004-console-io-for-gui-subsystem-exeGUI 子系统可执行文件的 stdio 接通#5677、#5665、#56810005-pdfinfo-to-buffer将mutool info输出到缓冲区供属性窗口使用0006-jpeg-xr-via-windows-wic通过 Windows WIC 编解码器解码 JPEG-XR0007-thread-local-secret-contextsharfbuzz / openjpeg 的 context 走私并非线程安全改为线程局部存储0008-report-last-uncaught-throw未捕获的fz_throw能进入崩溃报告0009-forms-cp1250-latin2-encoding表单字段中的中欧拉丁字符#54040010-tounicode-from-coded-glyph-names从G45/g0045/C65这类字形名推导 ToUnicode#32190011-tounicode-cp1251-cyrillic带 identity-Latin ToUnicode 的西里尔 Type1 字体#58730012-pdf-external-file-streams指向外部文件的流通过应用回调处理0013-xml-recover-from-mismatched-close-tags恢复处理嵌套错误的 FB2 / HTML#57920014-html-bound-generate-boxes-recursion修复深层嵌套标记导致的栈溢出0015-css-user-stylesheet-important-wins用户来源的!important优先于内联样式0016-stext-search-mujs-include-path构建的是合并版ext/a-mujs0017-svg-font-attributes-on-groupsg的子元素继承字体族0018-pdf-op-run-avoid-double-free结构树修复抛异常时的双重释放问题0019-freetype-enable-zlib-and-brotli本项目 freetype 启用了 zlib/brotli而上游精简配置没有0025-webp-images通过 libwebpHAVE_WEBP解码 WebP使 EPUB/HTML/MOBI/CBZ 能显示.webp#34150027-webp-iccp-without-demux不依赖 libwebp demux自行做 RIFF 遍历以应用 WebPICCP块0030-backport-709661-subset-prefix-font-name匹配内建字体名时忽略ABCDEF子集前缀涵盖 #46550031-backport-709663-image-page-height重排reflow图片适配固定页高而非推进中的块边界涵盖 #60070032-pdf-appearance-unrendered-annots为 Movie/Screen/3D/RichMedia/Watermark/PrinterMark/TrapNet/Projection 生成占位外观流AP0033-pdf-appearance-markup-movie-poster标记注释默认黄色高亮、无 QuadPoints 时使用/Rect、跳过 0 宽未填充的 Square/Circle、Movie 的/Poster作为 AP0034-backport-709678-cjk-fullwidth-punctuation半角/全角形式与 CJK 标点走非内嵌 CJK 路径涵盖 #60820035-backport-709680-flow-anchor-topHTML/EPUB 链接目标使用 flow 节点顶部而非基线涵盖 #60950036-ocg-usage-event-on-visiblePrintState/ViewState 为 ON 时即使 OCG 在配置/OFF列表中也绘制#61010037-backport-709648-inline-context-after-block块元素打断后不再继续向 inline context 追加内容涵盖 #59430038-html-css-background-image块级盒上的 CSSbackground-image/-size/-position/-repeat扫描型固定布局 EPUB 此前渲染为空白#61310039-md-empty-buffer-nul-scan空 markdownfz_md_to_html中的len-1下溢#61430040-svg-css-class-stylesSVGclassst0对照style样式表解析此前这类文件全部画成黑色#2155另有 11 个并非 SumatraPDF 自研、而是提前携带的上游修复详见下节 Backports 策略补丁内容0021-backport-709471-single-line-field-box上游修复单行字段内容框与/DA字号为 0 的问题0022-backport-709480-bound-xml-recursion上游修复XPS 元数据与 EPUB 目录的深度限制涵盖 #50320023-backport-709574-html-metadata上游修复HTML 与 FB2 的标题/作者/主题元数据涵盖 #22540024-backport-5e5ef9e-pool-asprintf上游fz_pool_asprintf0026 依赖它0026-backport-709657-fb2-author上游 FB2 作者遍历每个author的 first-name last-name涵盖 #22540029-backport-709660-tj-array-tc-twTJ数组内出现Tc/Tw后能恢复页面其余部分仍可绘制涵盖 #41570030-backport-709661-subset-prefix-font-name匹配内建字体名时忽略ABCDEF子集标签涵盖 #46550031-backport-709663-image-page-height重排图片在每一页都收缩到固定页高而非仅第一页#60070034-backport-709678-cjk-fullwidth-punctuation半角/全角形式与 CJK 标点使用 CJK 字体而非内嵌回退字体#60820035-backport-709680-flow-anchor-topHTML/EPUB 链接目标使用 flow 节点顶部而非基线#60950037-backport-709648-inline-context-after-block包裹块元素的嵌套span id不再全部跳到章节开头#5943注意0030、0031、0034、0035、0037同时出现在两张表中——它们是backport-*命名、但能力上与自研补丁重叠、最终以上游实现为准的补丁见下节。Backport 策略能拿上游的就别自己写命名含backport-的补丁其本质是该修复存在于 mupdfmaster但不在本仓库内嵌的发布版里1.28.x系列 tag 来自在它分叉之前的维护分支因此提前取来应用。这带来两条硬性纪律升级即删除当内嵌的 mupdf 越过补丁名所指的那个 commit 后必须删除该补丁——否则下次升级时git apply会把基线里已经包含的改动再打一遍而失败。优先 backport 而非自研只要上游已经修了同一件事就优先采用 backport。它是不需要反复合并的代码而且上游实现通常覆盖更多场景。README 给出了一个非常有说服力的案例链0022取代了 SumatraPDF 自研的 XPS 深度限制因为它顺带保护了两个 EPUB 目录解析器0023是 SumatraPDF 的 FB2 元数据补丁被 Artifex 上游化之后上游提交说明中写着 Based on a patch from Krzysztof Kowalczyk of SumatraPDF反过来以 backport 形式并入的0026取代了自研的 FB2 作者名辅助函数0029取代了 TJ 数组内Tc/Tw中断修复0030取代了基础 14 字体的子集标签剥离0031取代了自研的 reflow 图片页高修复。因此写新补丁之前先查上游每次升级再查一次——上游可能已经赶上来了。应用补丁一次完整的 mupdf 升级README 给出了从上游仓库检出新版本、再把补丁集整体应用的标准流程git -C ~/src/mupdf worktree add /tmp/mupdf-new new-tag cd /tmp/mupdf-new for p in ~/src/sumatrapdf/ext/patches/0*.patch; do git apply --3way $p || echo needs hand-merging: $p done--3way让git apply在补丁不能干净落地时尝试三方合并。之后的工作流是手工合并所有标记为needs hand-merging的补丁把结果复制回ext/mupdf——注意保留本项目的文件挑选SumatraPDF 内嵌的是 mupdf 的子集不是整棵树更新ext/versions.txt重新生成补丁目录使每个补丁都是基于新基线的 diff。一个实用的经验法则冲突有时是好消息。冲突往往意味着上游已经修了同一处。README 举了实例旧的0019-stext-device-guard-null-line在升级到 1.28.2 时mupdf 恰好加入了完全相同的cur_line 防护于是该补丁被直接删除而不是重新合并。因此解决冲突前务必先读懂冲突内容。验证补丁字节级回归校验补丁体系的核心承诺是可复现把全部补丁应用到一个干净的基线上必须逐字节复现ext/mupdf。验证命令mkdir /tmp/check git -C ~/src/mupdf -c core.autocrlffalse -c core.eollf archive 1.28.2 | tar -x -C /tmp/check cd /tmp/check for p in ~/src/sumatrapdf/ext/patches/*.patch; do git apply $p || echo FAIL $p; done diff -r /tmp/check ~/src/sumatrapdf/ext/mupdf # only reports files we do not vendor要点解读archive从 git 对象库直接导出1.28.2的树并强制core.autocrlffalse、core.eollf保证基线字节干净diff -r是字节比较只要它开始报告某个内嵌文件vendored file就说明要么漏了补丁、要么内嵌树发生了漂移该检查迄今对所有 1407 个内嵌文件全部通过README 原文。注意内嵌是子集因此 diff 会列出本项目故意不携带的上游文件这是预期输出不属于失败。行尾纪律LF 是硬约束ext/mupdf与上游一致、全树使用 LF补丁文件也必须是 LF-only。不要让编辑器或 checkout 把它改写成 CRLF仓库的.gitattributes设置了* -text所以提交的字节就是所有人拿到的字节一旦出现 CRLF 文件上面的字节比对会无缘无故地失败。这是一个一次失误、全局报错的典型陷阱值得在 CI 或预提交检查中固化。保持补丁集同步改内嵌树必须同时写补丁README 的最后一条纪律最简单也最容易被忽视当你在ext/mupdf下改动任何东西时必须在同一个 commit 里新增或更新这里的补丁。只存在于内嵌树里的改动会在下一次升级时被静默丢弃——这正是当初建立这套补丁体系要消灭的问题。补丁之外的边界src/mupdf 自有代码补丁体系只覆盖对 mupdf 已有文件的修改。完全自有的新文件不放在内嵌树里而是放在 src/mupdf/其 README 有完整说明编译进mupdf工程premake5.files.lua中的mupdf_files()ninja 侧对应cmd/deps-build-defs.ts中的mupdflib但物理上位于内嵌树之外因此既不会被误认为上游代码也不需要ext/patches/条目。该目录当前包含mupdf_load_system_font.c—— 为 mupdf 的字体回退加载 Windows 已安装字体并包含 plain-malloc 的 harfbuzz 分配器包装noto_sumatra.[ch]—— 编译时替代 mupdf 的noto.c内建字体base 14、CJK 回退、Charis SIL、少量 Noto不链接进二进制而是通过fz_set_builtin_font_loader()按文件名获取由 SumatraPDF 从fonts\的IDR_EMBEDDED_PAK资源提供增减字体需同步修改 cmd/pack-embedded-prebuild.cmd 中的清单pkcs7-windows.[ch]—— 在 Win32 CryptoAPI 之上实现 PDF 签名校验与签署取代 OpenSSL补丁0003让 mupdf 的pdfsign/murun调用它。代表性补丁源码剖析补丁的价值不仅在能打上去更在每一条都对应真实的用户问题。下面结合仓库中的补丁文件本身它们自带动机说明与调用侧代码看几个有代表性的例子。0001用法文本从 mutool 改名为 SumatraPDF0001-tools-usage-say-sumatrapdf.patch 是纯字符串修改SumatraPDF 把 mupdf 的 mutool 工具族以SumatraPDF tool子命令形式暴露因此muconvert.c、mudraw.c、mugrep.c、muraster.c、mutrace.c以及pdfaudit/pdfbake/pdfclean/pdfcreate/pdfextract/pdfinfo/pdfmerge/pdfpages/pdfposter/pdfrecolor/pdfshow/pdfsign/pdftrim的 usage 文本全部从mutool xxx/mudraw/muraster改为SumatraPDF tool形式muraster还删掉了版本横幅。它印证了补丁目录与可执行形态的对应关系见 src/sumatrapdf-tool.cpp 中gTools[]把draw/convert/run/info/clean等名字映射到从libsumatrapdf.dll导出的mudraw_main、muconvert_main、murun_main、pdfinfo_main等入口导出清单见 src/libsumatrapdf.def。README 也提醒纯字符串改动若上游重写了 usage 块需要手工重新应用。0004GUI 子系统可执行文件的控制台 IO0004-console-io-for-gui-subsystem-exe.patch 解决一个 Windows 经典难题SumatraPDF.exe是 GUI 子系统二进制从控制台启动SumatraPDF draw .../SumatraPDF run时没有任何可用的 stdio。补丁在mudraw.c该翻译单元会进入 libmupdf新增两个函数fz_redirect_io_to_existing_console()用AttachConsole(ATTACH_PARENT_PROCESS)挂到父控制台但只有流未重定向时才 freopen 到CONOUT$——若 stdout/stderr 已经被重定向到文件或管道再 freopen 会把输出丢掉#5677同时用_open_osfhandle把 stdin 绑到继承的句柄否则mutool run的readline()会报 cannot read line from stdin#5665fz_console_readline()Windows 控制台上fgets(stdin)会莫名返回 EOF#5681改为走ReadConsoleAmurun.c的 REPL 循环与jsB_readline()都改用它。这解释了 src/sumatrapdf-tool.cpp 头注释里的设计取舍专门提供sumatrapdf-tool.exe这个控制台子系统程序来承载这些工具让它们在 cmd.exe / PowerShell 下行为正常同时因为所有实现都在libsumatrapdf.dll可执行体本身保持极小。0003签名从 OpenSSL 换成 Windows CryptoAPI0003-signatures-windows-pkcs7.patch 把murun.c与pdfsign.c中的#include mupdf/helpers/pkcs7-openssl.h换成#include pkcs7-windows.h调用点同步从pkcs7_openssl_new_verifier/pkcs7_openssl_read_pfx换成pkcs7_windows_new_verifier/pkcs7_windows_read_pfx。原因是 SumatraPDF 不链接 OpenSSL。辅助实现本身在src/mupdf/pkcs7-windows.[ch]因为src/mupdf在 mupdf 工程的 include path 上所以补丁内按裸名#include pkcs7-windows.h即可而src/下的自有代码则用#include mupdf/pkcs7-windows.h这种带前缀的写法见 src/mupdf/README.md。0025WebP 图片解码0025-webp-images.patch 解决 #3415独立的.webp文件和漫画包此前已由 EngineImages 解码但 EPUB/MOBI/HTML 内的图片走fz_new_image_from_buffer会显示 IMAGE 占位符。补丁改编自 Artifex bug 697749 与 koreader 的同源补丁新增FZ_IMAGE_WEBP枚举与source/fitz/load-webp.cWebPGetFeaturesWebPDecodeRGB(A)Into解码进 pixmap把fz_recognize_image_format的识别长度从 8 字节扩到 12 字节以匹配RIFF....WEBP特征在 CBZ 扩展名列表加入.webpsource/cbz/mucbz.c为 HTML 的data:image/webp;base64,内联图与 MOBI 的图片提取补充处理明确省略 libwebp demux 的 EXIF/ICC——因为本项目不构建 demux 库。它展示了补丁体系的典型形态跨多个翻译单元的增量、附带#ifdef HAVE_WEBP的降级路径无 libwebp 时抛FZ_ERROR_UNSUPPORTED。0038CSS background-image 修复扫描型固定布局 EPUB0038-html-css-background-image.patch 针对 #6131CSS 引擎此前只知道background-color而扫描转 EPUB 工具如 Jouve LetoGen把每页画面放在div{background-image:url(...)}里、没有img也没有文字导致每页都渲染为空白。补丁为fz_css_style新增background-image/-size/-position/-repeat四个属性含background:简写解析见css-apply.c的add_shorthand_background在构建 box 时像img一样加载图片draw_block_box按 padding box 裁剪绘制支持cover/contain与平铺并用MAX_BACKGROUND_TILES 4096封顶——微图铺满大盒会意味着数百万次填充超过上限就只画一张。注意其css-properties.h是由css-properties.gperf用 gperf 3.2.1 重新生成的TOTAL_KEYWORDS从 81 增至 85。0013XML 错配闭合标签的容错0013-xml-recover-from-mismatched-close-tags.patch 解决 #5792真实世界的 FB2/HTML 经常乱嵌套bix/b/i原fz_parse_xml会放弃整个文档。补丁重写close_tag()遇到错配闭合标签时向上依次关闭中间未闭合的标签直到匹配对于找不到任何匹配开标签的闭合标签则直接忽略——即 HTML 解析器的恢复方式这样修复/b后残留的/i不会弄死整个文档。原上游实现保留在#if 0块中备查。0040SVG 从style样式表解析 class0040-svg-css-class-styles.patch 解决 #2155SVG 解析器原本只读表现属性与内联 style 属性而 Illustrator/Inkscape 输出把颜色全部放进style表、用classst0引用结果每个图形都用默认 fill 渲染成纯黑。补丁在文档打开时收集每个style元素的.name { ... }规则解析前把匹配声明拼接到元素的 style 属性上内联声明排在前因此仍然优先于样式表。超出纯 class 选择器的语法at-rule、元素/id 选择器、组合器、伪类一律跳过而非半支持——这是刻意的最小化实现。小结ext/patches/把 SumatraPDF 与 mupdf 的耦合关系变成了一个可审计、可重放、可验证的工程流程38 个git diff格式补丁含 11 个上游 backport锚定在 mupdf1.28.2commitfe374accd之上全部应用后必须与ext/mupdf逐字节一致当前对 1407 个内嵌文件全部通过升级时用git apply --3way批量应用、手工合并冲突升级后重新生成补丁自有新文件走src/mupdf/而非补丁任何对内嵌树的改动都必须与补丁同 commit。这套机制既是维护手册也是理解SumatraPDF 从 mupdf 继承了什么、又额外补了什么的最佳入口。赞分享桌面应用文档【免费下载链接】sumatrapdfSumatraPDF reader项目地址https://gitcode.com/gh_mirrors/su/sumatrapdf点击查看免费下载相关推荐FreeRTOS CBMC 验证补丁集详解patches 目录的三大类补丁与自动化应用工具链FreeRTOS CBMC 验证补丁集详解patches 目录的三大类补丁与自动化应用工具链 FreeRTOS 仓库的 FreeRTOS/Test/CBMC/操作系统嵌入式OS嵌入式物联网revanced-patches内存管理优化补丁的内存使用revanced patches内存管理优化补丁的内存使用 还在为Android应用补丁的内存占用和性能问题烦恼吗ReVanced Patches通过精心设移动开发Magisk补丁管理及时应用安全补丁的方案Magisk补丁管理及时应用安全补丁的方案 引言Android安全补丁的痛点与解决方案 你是否曾遇到过这样的困境Android系统安全补丁发布后设备制造移动开发系统底层创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考