Span-Based Simple-Object Parsing

The HPDFParser unit parses standalone PDF dictionaries and arrays without copying token or nested-container substrings

Entry points

function HPDFParserParseSimpleDictionary(
  const Data: AnsiString;
  RecursionLevel: Integer = 0): THPDFDictionaryObject;

function HPDFParserParseSimpleDictionaryWithStatistics(
  const Data: AnsiString;
  out Statistics: THPDFParserViewStatistics;
  RecursionLevel: Integer = 0): THPDFDictionaryObject;

function HPDFParserParseSimpleArray(
  const Data: AnsiString): THPDFArrayObject;

function HPDFParserParseSimpleArrayWithStatistics(
  const Data: AnsiString;
  out Statistics: THPDFParserViewStatistics): THPDFArrayObject;

The returned dictionary or array is owned by the caller and contains normal persistent HotPDF objects with no dependency on the source string lifetime

View statistics

THPDFParserViewStatistics exposes SourceBytes, TokenViewCount, MaterializedStringCount, MaterializedBytes, ObjectCount, ContainerCount, MaxDepth, ErrorCount, and Valid

Token views count bounded source ranges, whilst materialised-string counters cover bytes copied into durable PDF names, keys, and strings

Supported objects

The parser recognises names, integers, real numbers, booleans, nulls, indirect references, literal strings, hexadecimal strings, arrays, and dictionaries

Literal strings preserve nested parentheses, escaped delimiters, octal escapes, and escaped line continuations, whilst PDF whitespace and comments are ignored

Unescaped CR, CRLF and LF line endings within literal strings decode to a single LF per line ending; escaped carriage returns such as \r or \015 stay CR bytes, and backslash line continuations contribute no bytes

Nested containers share one cursor over the immutable input, recursion is bounded, and duplicate dictionary keys replace earlier values with case-sensitive matching

Malformed delimiters move the recovery cursor on without skipping neighbouring valid tokens; array bodies handed over without an opening bracket likewise recover from stray closing brackets and count them in ErrorCount

Performance characteristics

Names and strings materialise once at their persistent object boundary, numeric conversion reads source bytes directly, and an operation-local open-addressed index prevents quadratic duplicate scans whilst constructing large dictionaries

A 30,000-pair Win32 regression fixture reduced five-pass allocation bytes from 50,866,510 to 17,936,800 and elapsed time from 3,656 ms to 46 ms

See also: Scalable and Random-Access PDF Loading, Bounded PDF Parser Budgets