有界的交互參考復原
當 PDF 有遺失、無效或過時的 startxref 宣告或無法使用的 xref 列時,HotPDF 可以復原真實的物件圖與頁面樹
復原順序
- 在預設的
xrrmOnFailure模式下,一般符合規範的載入器會先執行 - 復原會以 1 MiB 的分塊掃描來源,分塊之間帶有簡短延續,並記錄已驗證的間接物件與 xref 錨點
- 巢狀於已驗證間接物件內的標記會被拒絕,包含字串、註解、字典,以及含有如
99 0 obj或xref等文字的二進位串流資料 - 有效的 xref 表格或串流會透過既有的增量、混合與物件串流載入器,從最新到最舊嘗試
- 最多保留 4,096 個 xref 區段錨點,以防範敵意的標記重複增加剖析嘗試
- 若沒有任何 xref 區段產生真實的頁面樹,則會重建直接物件偏移,且重複的物件編號會使用最新的實體定義
- 只有當真實的 Catalog、Pages 樹與至少一個頁面分葉解析時,復原才會成功
宣告
type
THPDFXRefRecoveryMode = (
xrrmDisabled,
xrrmOnFailure,
xrrmForce
);
THPDFXRefRecoveryStatus = (
xrrsNotNeeded,
xrrsSucceeded,
xrrsDisabled,
xrrsScanLimitExceeded,
xrrsObjectLimitExceeded,
xrrsXRefLimitExceeded,
xrrsFailed
);
THPDFXRefRecoveryMethod = (
xrrmethodNone,
xrrmethodRelocatedSection,
xrrmethodRebuiltObjectOffsets
);
THPDFXRefMergeInfo = record
HybridRevisionCount: Integer;
HybridOverlapCount: Integer;
OlderRevisionShadowedEntryCount: Integer;
DuplicateEntryCount: Integer;
NewestRevisionPrecedenceApplied: boolean;
HybridStreamPrecedenceApplied: boolean;
end;
property XRefRecoveryMode: THPDFXRefRecoveryMode;
property XRefRecoveryMaxScanBytes: Int64;
property XRefRecoveryMaxObjects: Integer;
function GetLoadedXRefRecoveryInfo(
out Info: THPDFXRefRecoveryInfo
): boolean;
function GetLoadedXRefMergeInfo(
out Info: THPDFXRefMergeInfo
): boolean;
組態
| 成員 | 預設值 | 用途 |
|---|---|---|
XRefRecoveryMode | xrrmOnFailure | 停用復原、僅在正常剖析失敗後執行,或在正常剖析之前強制執行 |
XRefRecoveryMaxScanBytes | 8 GiB | 分塊復原掃描接受的硬性來源大小上限 |
XRefRecoveryMaxObjects | 2,000,000 | 復原接受的已驗證間接物件候選硬性上限 |
ParserRecoveryEventLimit | 1,024 | 單次載入保留的結構化事件上限,零表示停用事件保留 |
復原資訊
GetLoadedXRefRecoveryInfo 在已嘗試復原時傳回 True,並複製最近的 THPDFXRefRecoveryInfo 記錄
Status區分成功、停用復原、位元組限制失敗、物件限制失敗、xref 錨點限制失敗與結構失敗Method識別重新定位的 xref 區段或重建的直接物件偏移BytesScanned、CandidateObjectCount、RecoveredObjectCount、DuplicateObjectCount、RejectedCandidateCount與XRefCandidateCount公建有界的工作量與復原品質SelectedXRefOffset在該方法成功時識別重新定位的區段Diagnostic包含簡明的英文結果描述
合併優先順序資訊
GetLoadedXRefMergeInfo 在 xref 串流或混合參照載入遇到值得回報的合併狀態時傳回 True
HybridRevisionCount計算透過FirstByte為含端點、EndByte為不含端點;不存在來源範圍時兩者皆為-1ObjectNumber與GenerationNumber識別間接物件候選;文件層級或 xref 錨點事件使用-1Confidence從prcNone依低、中、高到已驗證遞進LoadedParserRecoveryEventDroppedCount回報超過設定保留上限後被省略的事件數,在惡意輸入下維持有界記憶體
合併優先序資訊
GetLoadedXRefMergeInfo 在 xref stream 或混合參照載入遇到值得回報的合併狀態時回傳 True
HybridRevisionCount/XRefStm提供側邊 xref 串流的傳統修訂數HybridOverlapCount計算已由相同修訂之 xref 串流提供的表格項目數(該串流具有優先順序)OlderRevisionShadowedEntryCount計算因較新修訂已定義該物件編號而被忽略的項目數DuplicateEntryCount計算最新非混合區段內重複的項目數- 兩個優先順序旗標說明是否行使了對應的規則,而非僅僅可用
完整性資訊
GetLoadedXRefIntegrityInfo 回報作用中的 free-list 鏈、無效連結、循環、未連結的 free 項目、generation 轉換錯誤、重複的存活定義,以及被最新修訂版遮蔽的較舊項目
遮蔽細節包含作用中與被拒的項目型別、偏移量或儲存欄位、generation 與修訂深度,細節上限固定為 256 項
儲存已復原的文件
已復原的文件在 SaveLoadedDocument 中一律使用完整重寫路徑,即使沒有編輯任何物件也是如此,因此 HotPDF 絕不會將損壞的來源位元組複製為看似修復的輸出
範例
var
Info: THPDFXRefRecoveryInfo;
PDF: THotPDF;
begin
PDF := THotPDF.Create(nil);
try
PDF.XRefRecoveryMode := xrrmOnFailure;
PDF.XRefRecoveryMaxScanBytes := Int64(16) * 1024 * 1024 * 1024;
PDF.XRefRecoveryMaxObjects := 3000000;
if PDF.LoadFromFile('damaged.pdf') > 0 then
begin
if PDF.GetLoadedXRefRecoveryInfo(Info) then
WriteLn(Info.Diagnostic);
PDF.SaveLoadedDocument('recovered.pdf');
end;
finally
PDF.Free;
end;
end;