境界付きクロスリファレンス復元

HotPDF は、PDF に欠落、無効、または古い startxref 宣言や使用不能な xref 行がある場合に、実際のオブジェクトグラフとページツリーを復元できます

復元シーケンス

  1. デフォルトの xrrmOnFailure モードで、最初に通常の仕様準拠ローダーが実行されます
  2. 復元はソースを 1 MiB チャンクでスキャンし、チャンク間の短い繰り越しを持ち、検証された間接オブジェクトと xref アンカーを記録します
  3. 検証された間接オブジェクト内にネストされたマーカーは拒否されます。これには、99 0 obj や xref などのテキストを含む文字列、コメント、辞書、およびバイナリストリームデータが含まれます
  4. 有効な xref テーブルまたはストリームは、既存のインクリメンタル、ハイブリッド、およびオブジェクトストリームローダーを通じて新しいものから古いものへと試行されます
  5. 最大 4,096 の xref セクションアンカーが保持され、敵対的なマーカー反復が解析試行を倍増させるのを防ぎます
  6. xref セクションが実際のページツリーを生成しない場合、直接オブジェクトのオフセットが再構築され、重複するオブジェクト番号は最新の物理定義を使用します
  7. 実際の Catalog、Pages ツリー、および少なくとも1つのページリーフが解決された場合にのみ復元は成功します

宣言

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;

設定

メンバーデフォルト目的
XRefRecoveryModexrrmOnFailure復元を無効化する、通常のパースが失敗した後にだけ実行する、または通常のパースの前に強制実行する、のいずれかを指定します
XRefRecoveryMaxScanBytes8 GiBチャンク形式の復元スキャンが受け入れる、ハードな最大ソースサイズ
XRefRecoveryMaxObjects2,000,000復元が受け入れる、検証済み間接オブジェクト候補のハードな最大数
ParserRecoveryEventLimit1,0241 回の読み込みで保持される構造化イベントの最大数。0 でイベント保持を無効化します

復元情報

GetLoadedXRefRecoveryInfo は復元が試行された場合に True を返し、最新の THPDFXRefRecoveryInfo レコードをコピーします

マージ優先情報

GetLoadedParserRecoveryEvents は保持されたイベントストリームの呼び出し側所有のスナップショットを返し、GetLoadedParserRecoveryEvent は配列コピーを確保せずに 1 エントリを読み取ります

復元されたドキュメントの保存

xref ストリームまたはハイブリッドリファレンス読み込みで報告する価値のあるマージ状態が検出された場合、GetLoadedXRefMergeInfo は True を返します

完全性情報

GetLoadedXRefIntegrityInfo は、アクティブなフリーリストチェーン・無効なリンク・サイクル・リンクされていない空きエントリ・ジェネレーション遷移エラー・重複する有効な定義・最新リビジョンに覆い隠された古いエントリを報告します

覆い隠された詳細には、アクティブ / 拒否されたエントリタイプ・オフセットまたはストレージフィールド・ジェネレーション・リビジョンの深さが含まれ、詳細は固定の 256 エントリを上限とします

復元したドキュメントの保存

復元されたドキュメントは、オブジェクトが 1 つも編集されていなくても、常に 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;

関連 API