AST content stream'а с сохранением токенов

HPDFContentStream даёт ограниченную модель синтаксиса без потерь для точечных правок декодированных PDF content stream'ов

Разбор и инспекция

HPDFParseContentStreamAST создаёт THPDFContentStreamAST с лимитами по умолчанию: 4,194,304 лексем и 256 вложенных контейнеров; если нужны более жёсткие лимиты, вызывайте THPDFContentStreamAST.Create напрямую

THPDFContentLexemeKind различает пробелы, комментарии, числа, имена, literal- и hexadecimal-строки, булевы значения, null, слова, ограничители контейнеров, данные inline-изображений и повреждённые байты; каждый входной байт принадлежит ровно одному THPDFContentLexeme

THPDFContentSyntaxNodeKind различает корень, операции, операнды, массивы, словари, процедуры, inline-изображения и повреждённые регионы; каждый THPDFContentSyntaxNode хранит индексы parent, first-child, last-child и next-sibling, поэтому обход не выделяет массивы дочерних узлов

Используйте GetLexeme, GetLexemeBytes, GetLexemeText и GetNode вместе с LexemeCount и NodeCount; GetOriginalBytes возвращает независимую копию источника

Valid, ErrorOffset и ErrorMessage сообщают о повреждённом входе, сохраняя побайтово точную сериализацию, а GetStatistics заполняет THPDFContentASTStatistics размером источника, счётчиками, максимальной глубиной, числом inline-изображений и числом повреждённых узлов

Оверлей правок

ReplaceRange работает с полуоткрытыми байтовыми смещениями, а ReplaceLexeme, ReplaceNode, DeleteNode, InsertBeforeNode и InsertAfterNode выводят диапазоны из синтаксических записей

Каждый THPDFContentEdit копируется в отсортированный оверлей; конфликтующие правки отклоняются, смежные диапазоны остаются валидными, EditCount сообщает число принятых правок, а ClearEdits возвращает вывод no-op

Visitors операторов

HPDFVisitContentStreamOperators надстраивает над этим AST visitor'ы с подсчётом ссылок и Delphi event callback'и, даёт read-only представление операндов, соблюдает бюджеты на источник, операторы, лексемы, глубину и замены, а перед успехом перепарсит преобразованный вывод

Сериализация

Serialize собирает один выходной массив байтов после расчёта размера с проверкой переполнения, а WriteToStream пишет нетронутые диапазоны источника и диапазоны замен напрямую в TStream вызывающего кода

Без правок оба пути воспроизводят источник байт в байт, не трогая запись чисел, экранирование строк, комментарии, концы строк, разделители и данные inline-изображений

var
  AST: THPDFContentStreamAST;
  Output: TBytes;
begin
  AST:= HPDFParseContentStreamAST(ContentBytes);
  try
    if AST.Valid and AST.ReplaceRange(StartOfs, EndOfs, ReplacementBytes) then
      AST.Serialize(Output);
  finally
    AST.Free;
  end;
end;