View Source Pdf.Reader.ObjectResolver (ExPDF v1.0.1)

Lazy indirect-object resolver with Map-based cache.

Per the design (sdd/pdf-reader-core/design § 5 "Lazy Resolution Contract"):

  • Cache: a plain Map on %Pdf.Reader.Document{}.cache. No GenServer. Key: {obj_num, gen_num}. Value: the resolved Elixir term.
  • Signature: resolve(doc, {:ref, n, g}) :: {:ok, value, doc} | {:error, reason}. The returned doc carries the updated cache. The caller threads doc forward for cache benefit; dropping the updated doc still yields correct results on the next call (re-parse, same value — the binary is immutable).

  • Idempotent: calling resolve/2 twice on the same ref with the same doc returns the same value. The cache is a hint, not state.

Resolution paths

  1. Cache hit: Map.get(doc.cache, {n, g}) → immediate return.
  2. In-use (classic): look up {n, g} in doc.xref{:in_use, offset, _gen}. Slice binary_part(doc.binary, offset, ...), run Parser.parse_object/1.
  3. Compressed (ObjStm): look up {n, g}{:compressed, objstm_n, index}. Recursively resolve(doc, {:ref, objstm_n, 0}), decode filters, then ObjectStream.fetch/3.
  4. Free / absent: {:error, {:unresolved_ref, {n, g}}}.

Ref chasing

resolve/2 does NOT automatically follow nested refs. If a resolved value is itself {:ref, _, _}, the caller decides whether to chase it. This avoids infinite loops on circular references and keeps the interface predictable.

Summary

Functions

Resolve an indirect object reference to its value.

Functions

@spec resolve(Pdf.Reader.Document.t(), {:ref, pos_integer(), non_neg_integer()}) ::
  {:ok, term(), Pdf.Reader.Document.t()} | {:error, term()}

Resolve an indirect object reference to its value.

Returns {:ok, value, updated_doc} on success, where updated_doc has the resolved value cached. Returns {:error, reason} on failure.

The caller should thread the returned doc forward to benefit from caching on subsequent resolutions.

Error reasons

  • {:error, {:unresolved_ref, {n, g}}} — ref is absent from xref or is a free entry.
  • {:error, :malformed} — parse failure.
  • {:error, {:unsupported_filter, name}} — propagated from filter chain.