JBIG2 段图校验

HotPDF 在内嵌 JBIG2 图像和 JBIG2Globals 流交给本机或外部 decoder 之前,先对它们做校验

校验器先做一次有界的段遍历,再做迭代的依赖图遍历,段号查找走索引而不是反复扫描

自定义处理前先校验

Options := DefaultJBIG2SegmentGraphValidationOptions;
Options.MaxSegments := 32768;
Options.MaxTotalReferences := 131072;
Options.MaxReferenceDepth := 512;
Options.MaxSymbols := 500000;

if not HPDFValidateJBIG2SegmentGraph(ImageData, GlobalData,
  Options, Info) then
  raise Exception.Create(string(
    HPDFJBIG2SegmentGraphValidationStatusName(Info.Status)));

TJBIG2SegmentGraphValidationInfo 报告段数和边数、声明的新符号数、最大依赖深度,以及首次失败相关联的流、字节偏移、段号和引用编号

预算集中在 TJBIG2SegmentGraphValidationOptions 记录里,MaxSegments、MaxReferencesPerSegment、MaxTotalReferences、MaxReferenceDepth 和 MaxSymbols 字段为每一次遍历设置上限

终止状态是 TJBIG2SegmentGraphValidationStatus 值,从 not-checked、valid 一直到选项被拒、头部与引用失败、依赖环和符号字典违规,HPDFJBIG2SegmentGraphValidationStatusName 负责把它渲染成文本

FailureStreamKind 用 TJBIG2SegmentStreamKind 说明首次失败发生在 globals 流(jbsskGlobals)还是图像流(jbsskImage)

THPDFJBIG2Decoder.LastSegmentGraphValidationInfo 在 LoadFromByteArray 或 LoadRegionFromByteArray 之后保留同一份报告

Fail-closed 条件

校验会拒绝:格式错误或被截断的头部、内嵌流中的独立文件头、被禁止的短引用表和超长引用表、重复或缺失的段标识符、物理上向前的依赖、依赖环、超限深度,以及超出配置的段或边预算

图像段必须使用页面关联 1,全局段必须使用页面关联 0,全局段不能依赖图像段

内嵌的 end-of-page、end-of-file 和 color-palette 段会被拒绝,出现在 JBIG2Globals 中的 page-only region 段和 page-information 段同样被拒绝

符号字典头部在解码前就接受检查,因此声明的新增与导出符号数、聚合输入符号池和不合理的导出总数会在位图分配之前就失败

Decoder 与 globals 缓存边界

THPDFJBIG2Decoder、HPDFJBIG2NativeMMRDecode、HPDFJBIG2NativeRegionDecode 以及内嵌的 HPDFJBIG2DecDecodeEx 调用共享同一套策略

已注册的本机和外部后端使用的是已经过校验的内部路径,正常解码不会重复走一遍图遍历

THPDFJBIG2GlobalsPool.Register 只接受合法的 global-only 段流,防止格式错误的共享字典进入文档级复用

以 Embedded = False 传入的独立 JBIG2 文件保留各自面向文件的独立解码路径

参见 JBIG2 压缩支持、THPDFJBIG2Decoder.LoadFromByteArray 和 THPDFJBIG2Decoder.LoadRegionFromByteArray