Ограниченное восстановление перекрёстных ссылок
HotPDF может восстановить реальный граф объектов и дерево страниц, если PDF имеет отсутствующее, недопустимое или устаревшее объявление startxref или непригодные строки xref
Последовательность восстановления
- Сначала выполняется обычный соответствующий спецификации загрузчик в режиме по умолчанию
xrrmOnFailure - Восстановление сканирует источник порциями по 1 МиБ с коротким переносом между порциями и фиксирует проверенные косвенные объекты и якоря xref
- Маркеры, вложенные в проверенный косвенный объект, отклоняются, включая строки, комментарии, словари и бинарные данные потоков, содержащие текст вида
99 0 objилиxref - Корректные таблицы или потоки xref проверяются от новой к более старой через существующий инкрементный, гибридный загрузчик и загрузчик объектных потоков
- Сохраняется не более 4096 якорей разделов 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 возвращает True, если при загрузке потоков xref или гибридных ссылок встретилось состояние слияния, о котором стоит сообщить
Kindразличает события attempt, policy, limit, кандидата объекта, кандидата xref, выбранную секцию, перестроенные смещения, успех и сбойFirstByte— включительно, аEndByte— исключительно; оба равны-1когда диапазона источника нетObjectNumberиGenerationNumberидентифицируют кандидатов в непрямые объекты и используют-1для событий уровня документа или xref-якоряConfidenceпроходит отprcNoneчерез low, medium, high и verifiedLoadedParserRecoveryEventDroppedCountсообщает события, опущенные после настроенного лимита удержания, сохраняя ограниченную память на враждебных входных данных
Информация о приоритете слияния
GetLoadedXRefMergeInfo возвращает True когда загрузка xref stream или гибридных ссылок встретила заслуживающее отчёта состояние слияния
HybridRevisionCountподсчитывает традиционные редакции, предоставившие боковой поток xref через/XRefStmHybridOverlapCountподсчитывает записи таблицы, уже предоставленные потоком xref той же редакции, который имеет приоритетOlderRevisionShadowedEntryCountподсчитывает записи, проигнорированные из-за того, что более новая редакция уже определила этот номер объектаDuplicateEntryCountподсчитывает повторяющиеся записи внутри нового не гибридного раздела- Два флага приоритета сообщают, было ли соответствующее правило применено, а не просто доступно
Информация о целостности
GetLoadedXRefIntegrityInfo сообщает активную цепочку free list, неверные ссылки, циклы, несвязанные свободные записи, ошибки переходов поколений, дублирующиеся живые определения и старые записи, затенённые новейшей ревизией
Детали затенения включают активные и отклонённые типы записей, смещения или поля хранилища, поколения и глубину ревизии с фиксированным потолком деталей в 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;