NativeElixirPdfUtilities.Validators.PdfValidator (native_elixir_pdf_utilities v0.13.0)

View Source

Shared semantic validation for parsed PDF documents.

The validator consumes the object model produced by the PDF reader. It does not tokenize or load PDF bytes again. Successful validation returns a prepared context containing the resolved catalog, page-tree root, semantic page traversal, inherited page values, and the reader-compatible document.

Operation validators should consume this context instead of walking the raw page tree or resolving document structure independently.

Summary

Types

Reusable validated PDF structure consumed by operation validators.

Diagnostic ownership supplied by the public operation.

A parsed reader document before or after semantic validation.

A normalized stream filter and its validated decoding parameters.

The nearest inherited value and the page-tree node that declared it.

A semantically identified page prepared during page-tree traversal.

Validated cross-reference and trailer data available before object loading.

An indirect PDF object reference.

A structurally validated indirect stream.

A parsed PDF value.

A parsed cross-reference entry.

Functions

Resolves a value and requires the resulting semantic value to be a dictionary.

Resolves a dictionary and returns one of its values.

Resolves a fixed-length array whose elements must all be numbers.

Resolves a stream and prepares its semantic filter chain for byte decoding.

Resolves an indirect value with missing-reference and cycle diagnostics.

Validates reusable catalog, page-tree, reference, and inherited-value invariants.

Validates the public PDF reader input boundary.

Validates object-stream metadata before its decoded header is scanned.

Parses and validates a PDF binary into the reusable shared context.

Resolves and validates an indirect stream and its declared byte length.

Validates a parsed cross-reference table and its trailer.

Types

context()

@type context() :: %{
  document: document(),
  catalog: map(),
  catalog_ref: ref() | nil,
  page_tree_ref: ref(),
  pages: [page_context()]
}

Reusable validated PDF structure consumed by operation validators.

diagnostic_option()

@type diagnostic_option() ::
  {:operation, atom()} | {:module, module()} | {:source, String.t() | nil}

Diagnostic ownership supplied by the public operation.

document()

@type document() :: %{
  :objects => %{optional(ref()) => map()},
  optional(atom()) => term()
}

A parsed reader document before or after semantic validation.

filter_context()

@type filter_context() :: %{name: binary(), parameters: map() | nil}

A normalized stream filter and its validated decoding parameters.

inherited_value()

@type inherited_value() :: %{value: value(), source_ref: ref()}

The nearest inherited value and the page-tree node that declared it.

page_context()

@type page_context() :: %{
  ref: ref(),
  dictionary: map(),
  resources: value(),
  rotate: value(),
  media_box: value(),
  crop_box: value(),
  inherited: %{optional(binary()) => inherited_value()}
}

A semantically identified page prepared during page-tree traversal.

probe_context()

@type probe_context() :: %{
  binary: binary(),
  xref_offset: non_neg_integer(),
  xref: %{optional(integer()) => xref_entry()},
  trailer: map(),
  encrypted?: boolean()
}

Validated cross-reference and trailer data available before object loading.

ref()

@type ref() :: {non_neg_integer(), non_neg_integer()}

An indirect PDF object reference.

stream_context()

@type stream_context() :: %{
  :ref => ref(),
  :dictionary => map(),
  :stream => binary(),
  optional(:filters) => [filter_context()]
}

A structurally validated indirect stream.

value()

@type value() ::
  nil
  | boolean()
  | integer()
  | float()
  | {:name, binary()}
  | {:string, binary()}
  | {:hex, binary()}
  | {:ref, ref()}
  | [value()]
  | %{optional(binary()) => value()}

A parsed PDF value.

xref_entry()

@type xref_entry() ::
  {:free, non_neg_integer(), non_neg_integer()}
  | {:uncompressed, non_neg_integer(), non_neg_integer()}
  | {:compressed, pos_integer(), non_neg_integer()}

A parsed cross-reference entry.

Functions

dictionary(document, value, opts \\ [])

@spec dictionary(document(), value(), [diagnostic_option()]) ::
  {:ok, map()}
  | {:error, {atom(), NativeElixirPdfUtilities.Diagnostics.diagnostic()}}

Resolves a value and requires the resulting semantic value to be a dictionary.

fetch(document, dictionary_value, key, opts \\ [])

@spec fetch(document(), value(), binary(), [diagnostic_option()]) ::
  {:ok, value()}
  | {:error, {atom(), NativeElixirPdfUtilities.Diagnostics.diagnostic()}}

Resolves a dictionary and returns one of its values.

number_array(document, value, expected_length, opts \\ [])

@spec number_array(document(), value(), non_neg_integer(), [diagnostic_option()]) ::
  {:ok, [number()]}
  | {:error, {atom(), NativeElixirPdfUtilities.Diagnostics.diagnostic()}}

Resolves a fixed-length array whose elements must all be numbers.

Operation validators can use this helper for page rectangles, matrices, and other shared PDF number-array structures.

prepare_decoded_stream(document, value, opts \\ [])

@spec prepare_decoded_stream(document(), value(), [diagnostic_option()]) ::
  {:ok, stream_context()}
  | {:error, {atom(), NativeElixirPdfUtilities.Diagnostics.diagnostic()}}

Resolves a stream and prepares its semantic filter chain for byte decoding.

The returned filter names are canonical and their parameters have validated predictor dimensions and LZW settings. Encoded-byte integrity and resource limits remain the reader's responsibility.

resolve(document, value, opts \\ [])

@spec resolve(document(), value(), [diagnostic_option()]) ::
  {:ok, value()}
  | {:error, {atom(), NativeElixirPdfUtilities.Diagnostics.diagnostic()}}

Resolves an indirect value with missing-reference and cycle diagnostics.

validate(document, opts \\ [])

@spec validate(document(), [diagnostic_option()]) ::
  {:ok, context()}
  | {:error, {atom(), NativeElixirPdfUtilities.Diagnostics.diagnostic()}}

Validates reusable catalog, page-tree, reference, and inherited-value invariants.

The returned context contains :document in the same shape returned by NativeElixirPdfUtilities.Pdf.Reader.read/1.

validate_input(pdf, opts \\ [])

@spec validate_input(term(), [diagnostic_option()]) ::
  :ok | {:error, {atom(), NativeElixirPdfUtilities.Diagnostics.diagnostic()}}

Validates the public PDF reader input boundary.

validate_object_stream_header(dictionary, decoded_size, ref, opts \\ [])

@spec validate_object_stream_header(term(), term(), term(), [diagnostic_option()]) ::
  {:ok, %{count: non_neg_integer(), first: non_neg_integer()}}
  | {:error, {atom(), NativeElixirPdfUtilities.Diagnostics.diagnostic()}}

Validates object-stream metadata before its decoded header is scanned.

Object streams are limited independently from the document-wide object count so attacker-controlled entry counts cannot create excessive parsing work.

validate_pdf(pdf)

@spec validate_pdf(binary()) ::
  {:ok, context()}
  | {:error, {atom(), NativeElixirPdfUtilities.Diagnostics.diagnostic()}}

Parses and validates a PDF binary into the reusable shared context.

This is the utility entry point for future public PDF validation and other PDF-consuming features. Existing callers can continue using NativeElixirPdfUtilities.Pdf.Reader.read/1 for its compatibility document.

validate_stream(document, value, opts \\ [])

@spec validate_stream(document(), value(), [diagnostic_option()]) ::
  {:ok, stream_context()}
  | {:error, {atom(), NativeElixirPdfUtilities.Diagnostics.diagnostic()}}

Resolves and validates an indirect stream and its declared byte length.

This validates structure shared by PDF-consuming operations but does not decode operation-specific filters.

validate_xref(entries, trailer, pdf, opts \\ [])

@spec validate_xref(
  %{optional(integer()) => xref_entry()},
  map(),
  binary(),
  [diagnostic_option()]
) :: :ok | {:error, {atom(), NativeElixirPdfUtilities.Diagnostics.diagnostic()}}

Validates a parsed cross-reference table and its trailer.

Object zero must be present as the free-list head with generation 65535. All remaining entries must fit the trailer's declared object and byte bounds.