Bounds-checked readers for big-endian font table data.
Every sfnt-based format — TrueType, OpenType, CFF — stores its tables as
big-endian integers at offsets that the file itself supplies. Those offsets
are untrusted: a malformed or hostile font can point anywhere. These readers
return :error (or nil, for the read_bytes/3 shape) rather than raising,
so a bad offset degrades one table instead of crashing the render.
They were previously private to Tincture.Font.TTF, which meant every table
parser had to live in the same module to reach them.
Summary
Functions
Read len bytes at offset, or nil if the range does not fit.
Read a signed 16-bit big-endian integer at offset.
Decode a whole binary as a list of signed 16-bit big-endian integers.
Read length bytes at offset, or :error if that range is not fully
inside data.
Read an unsigned 16-bit big-endian integer at offset.
Decode a whole binary as a list of unsigned 16-bit big-endian integers.
Read an unsigned 32-bit big-endian integer at offset.
Decode a whole binary as a list of unsigned 32-bit big-endian integers.
Functions
@spec bytes(binary(), non_neg_integer(), pos_integer()) :: binary() | nil
Read len bytes at offset, or nil if the range does not fit.
Returns nil rather than :error because its callers thread the result
straight into pattern matches where a nil is the natural "absent" case.
@spec s16(binary(), non_neg_integer()) :: {:ok, integer()} | :error
Read a signed 16-bit big-endian integer at offset.
Decode a whole binary as a list of signed 16-bit big-endian integers.
@spec slice(binary(), non_neg_integer(), non_neg_integer()) :: {:ok, binary()} | :error
Read length bytes at offset, or :error if that range is not fully
inside data.
@spec u16(binary(), non_neg_integer()) :: {:ok, non_neg_integer()} | :error
Read an unsigned 16-bit big-endian integer at offset.
@spec u16_list(binary()) :: [non_neg_integer()]
Decode a whole binary as a list of unsigned 16-bit big-endian integers.
Deliberately has no clause for a trailing odd byte: callers slice exactly
count * 2 bytes, so an odd length means the slice was computed wrongly and
should surface rather than silently truncate. Preserved from the original
implementation; changing it is a behaviour decision, not a refactor.
@spec u32(binary(), non_neg_integer()) :: {:ok, non_neg_integer()} | :error
Read an unsigned 32-bit big-endian integer at offset.
@spec u32_list(binary()) :: [non_neg_integer()]
Decode a whole binary as a list of unsigned 32-bit big-endian integers.