Обмежене відновлення перехресних посилань

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 і щонайменше один лист сторінки

Оголошення

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,024Максимум структурованих подій, що зберігаються для одного завантаження; нуль вимикає збереження подій

Інформація про відновлення

GetLoadedXRefRecoveryInfo повертає True, коли відновлення було спробовано, і копіює найновіший запис THPDFXRefRecoveryInfo

Структуровані події відновлення

GetLoadedParserRecoveryEvents повертає належний викликачу знімок збереженого потоку подій, тоді як GetLoadedParserRecoveryEvent читає один запис без розподілу копії масиву

Інформація про пріоритет злиття

GetLoadedXRefMergeInfo повертає True, коли завантаження потоку xref або гібридного посилання зустріло стан злиття, вартий звітування

Інформація про цілісність

GetLoadedXRefIntegrityInfo повідомляє активний ланцюг вільного списку, недійсні посилання, цикли, неприв'язані вільні записи, помилки переходу поколінь, дублікати живих визначень і старіші записи, затінені найновішою редакцією

Деталі затінення включають активні та відхилені типи записів, зміщення або поля сховища, покоління та глибину редакції, зі фіксованою стелею деталізації в 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;

Пов'язані API