ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
book_paged.c File Reference

Paged book-source layer: copy-out reads over ra8_vmem (#163). More...

#include "book_paged.h"
#include <string.h>
#include "book.h"
#include "book_internal.h"
#include "ra8_attributes.h"
#include "ra8_check.h"
#include "ra8_vmem.h"
Include dependency graph for book_paged.c:

Go to the source code of this file.

Enumerations

enum  book_paged_bound_t : uint32_t {
  k_book_paged_span_pad = 2U ,
  k_book_paged_min_frame = 2U
}
 Loop-bound headroom for the frame-by-frame copy-out (NASA Rule 2). More...
enum  book_image_rect_const_t : uint32_t {
  k_book_gray4_nib_lo = 0x0FU ,
  k_book_gray4_nib_sh = 4U ,
  k_book_gray4_ppb = 2U ,
  k_book_rect_chunk_px = 512U ,
  k_book_rect_chunk_pad = 2U
}
 4bpp nibble packing + the per-read pixel budget (no magic numbers). More...
enum  book_paged_walk_bound_t : uint32_t {
  k_book_paged_strbuf = 256U ,
  k_book_paged_tagbuf = 64U ,
  k_book_paged_pad = 2U
}
 Staging sizes and loop bounds for the paged text walk (no magic numbers). More...

Functions

ra8_err_t book_src_resident (book_src_t *out, const void *base, uint32_t size)
 Bind a resident (already-inflated, fully resident) book as a source.
ra8_err_t book_src_paged (book_src_t *out, ra8_vmem_t *vm, uint32_t object_id, uint32_t frame_bytes, uint32_t size)
 Bind a paged book source over an ::ra8_vmem cache + ::ra8_vsource object.
static ra8_err_t internal_book_src_read_paged (const book_src_t *src, uint32_t off, void *dst, uint32_t len)
 Copy a byte range out of a paged source, frame by frame.
ra8_err_t book_src_read (const book_src_t *src, uint32_t off, void *dst, uint32_t len)
 Copy a byte range out of a book source (resident memcpy or paged fault).
static ra8_err_t internal_book_image_row (const book_src_t *src, const book_image_t *img, uint32_t x, uint32_t ry, uint32_t w, uint8_t *out)
 Unpack one horizontal gray4 run [x, x+w) of source row ry to gray8.
static ra8_err_t internal_book_image_row_gray8 (const book_src_t *src, const book_image_t *img, uint32_t x, uint32_t ry, uint32_t w, uint8_t *out)
 Copy one horizontal gray8 run [x, x+w) of source row ry into out.
ra8_err_t book_src_image (const book_src_t *src, uint32_t idx, book_image_t *out_img)
 Read one image descriptor out of a book source (resident or paged).
ra8_err_t book_src_image_rect (const book_src_t *src, const book_image_t *img, uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint8_t *out, uint32_t out_stride)
 Read a sub-rectangle of a raster image (4bpp or 8bpp) as gray8, row by row.
static ra8_err_t internal_paged_node (const book_src_t *src, uint32_t idx, book_node_t *out)
 Read one DOM node record out of a paged/resident book source by index.
static ra8_err_t internal_paged_str_short (const book_src_t *src, uint32_t abs_off, char *buf, uint32_t cap)
 Copy a short NUL-terminated string (a tag name) out into a buffer.
static bool internal_paged_emit_run (const book_src_t *src, uint32_t abs_off, char *out, size_t cap, size_t *pos, bool *at_break, ra8_err_t *io_err)
 Emit one text run from a paged source, collapsing whitespace.
static bool internal_paged_visit_node (const book_src_t *src, uint32_t n, char *out, size_t cap, size_t *pos, bool *at_break, uint32_t *stack, uint32_t *sp, ra8_err_t *io_err)
 Process one popped node in the paged text walk.
static bool internal_walk_text_paged (const book_src_t *src, uint32_t root, uint32_t node_count, char *out, size_t cap, size_t *pos, ra8_err_t *io_err)
 Bounded pre-order text walk over a paged book source.
ra8_err_t book_chapter_text_src (const book_src_t *src, uint32_t chapter_idx, char *out, size_t cap, size_t *out_len)
 Extract one chapter's plain text from a book source (resident or paged).
ra8_err_t book_src_prefetch_chapter (const book_src_t *src, uint32_t chapter_idx)
 Warm the cache frame holding a chapter's first content bytes, without pinning it (single-threaded read-ahead for the display-flush idle window).

Variables

static const char *const s_tag_paged = "book_paged"
 Log tag for paged-source diagnostics.

Detailed Description

Paged book-source layer: copy-out reads over ra8_vmem (#163).

Implements the book_src_t seam from book_paged.h. A source is either resident (a validated blob base; reads are a memcpy) or paged (an ra8_vmem cache fronting an ra8_vsource object; reads fault frames in and copy the requested slice out). book_src_read is the single primitive the DOM walkers build on; the paged path pins at most one frame at a time, so the resident working set stays bounded by the cache budget irrespective of how much of the book a chapter walk touches.

Since
Version 0.1.0

Definition in file book_paged.c.

Enumeration Type Documentation

◆ book_image_rect_const_t

enum book_image_rect_const_t : uint32_t

4bpp nibble packing + the per-read pixel budget (no magic numbers).

A k_book_image_gray4 pool byte holds two pixels; the high nibble is the even flat index, the low nibble the odd. A 4-bit sample expands to gray8 by replicating the nibble into both halves ((nib << 4) | nib). book_src_image_rect unpacks each row in spans of at most k_book_rect_chunk_px pixels so the staging buffer – and every book_src_read – stays small and bounded.

Since
Version 0.1.0
Enumerator
k_book_gray4_nib_lo 

Low-nibble mask (odd flat index).

k_book_gray4_nib_sh 

Nibble shift and 4->8 bit replicate amount.

k_book_gray4_ppb 

Pixels packed per pool byte.

k_book_rect_chunk_px 

Max pixels unpacked per bounded span read.

k_book_rect_chunk_pad 

Loop-bound headroom over ceil(w / k_book_rect_chunk_px).

Definition at line 180 of file book_paged.c.

◆ book_paged_bound_t

enum book_paged_bound_t : uint32_t

Loop-bound headroom for the frame-by-frame copy-out (NASA Rule 2).

A copy of len bytes spans at most ceil(len/frame_bytes) + 1 frames (a leading partial frame plus full frames); the +2 guard covers the partial head and tail so the bounded loop can never spin.

Since
Version 0.1.0
Enumerator
k_book_paged_span_pad 

Extra frame iterations over the exact span.

k_book_paged_min_frame 

Smallest accepted frame size (Rule-2 bound).

Definition at line 40 of file book_paged.c.

◆ book_paged_walk_bound_t

enum book_paged_walk_bound_t : uint32_t

Staging sizes and loop bounds for the paged text walk (no magic numbers).

Since
Version 0.1.0
Enumerator
k_book_paged_strbuf 

Staging chunk for a paged text run.

k_book_paged_tagbuf 

Staging for one (short) element tag name.

k_book_paged_pad 

Loop-bound headroom over the exact span.

Definition at line 380 of file book_paged.c.

Function Documentation

◆ book_chapter_text_src()

ra8_err_t book_chapter_text_src ( const book_src_t * src,
uint32_t chapter_idx,
char * out,
size_t cap,
size_t * out_len )
nodiscard

Extract one chapter's plain text from a book source (resident or paged).

The source-aware counterpart of book_chapter_text(): same output contract (whitespace-collapsed text runs, a newline at each block-level element, not NUL-terminated), but reads the DOM through src so a paged book is walked frame-by-frame. In resident mode it delegates to book_chapter_text() and is byte-for-byte identical; in paged mode it copies each visited node and string out on demand, pinning only what it is reading.

Parameters
[in]srcBound book source.
[in]chapter_idxSpine chapter index (< src->hdr.chapter_count).
[out]outDestination text buffer (non-NULL).
[in]capCapacity of out in bytes.
[out]out_lenReceives the text byte length written.
Returns
ra8_err_t Error code.
Return values
k_ra8_okChapter text extracted.
k_ra8_err_null_ptrsrc, out, or out_len was NULL.
k_ra8_err_invalid_argchapter_idx is out of range.
k_ra8_err_invalid_sizeOutput did not fit cap, or DOM nesting exceeded the bounded walk stack.
k_ra8_err_*A page fault (paged mode only; returned verbatim).
Precondition
src was populated by book_src_resident() / book_src_paged().
chapter_idx is less than src->hdr.chapter_count.
Postcondition
On k_ra8_ok, out[0..*out_len) is the plain-text run (not NUL-terminated).
On error, out content is unspecified.
Note
Not thread-safe.
See also
book_chapter_text()
Since
Version 0.1.0

Definition at line 681 of file book_paged.c.

References book_src_t::base, book_chapter_text(), book_src_read(), book_header_t::chapter_count, book_header_t::chapter_off, book_src_t::hdr, internal_walk_text_paged(), k_ra8_err_invalid_arg, k_ra8_err_invalid_size, k_ra8_ok, book_header_t::node_count, RA8_CHECK_NULL_PTR, book_chapter_t::root_node, and s_tag_paged.

Referenced by sh_book_chapter_text().

◆ book_src_image()

ra8_err_t book_src_image ( const book_src_t * src,
uint32_t idx,
book_image_t * out_img )
nodiscard

Read one image descriptor out of a book source (resident or paged).

The source-aware counterpart of the resident-only book_images() accessor: resolves image idx to its blob offset (hdr.image_off + idx * sizeof(book_image_t)) and copies the 24-byte descriptor out through book_src_read, so a paged book faults the descriptor's frame in on demand. The descriptor names the image geometry and its data_off into the image pool; feed it to book_src_image_rect to read pixels. This is the library-owned replacement for open-coding the image-table stride in a consumer.

Parameters
[in]srcBound book source.
[in]idxImage-table index (< src->hdr.image_count).
[out]out_imgReceives the image descriptor.
Returns
ra8_err_t Error code.
Return values
k_ra8_okDescriptor copied into out_img.
k_ra8_err_null_ptrsrc or out_img was NULL.
k_ra8_err_invalid_argidx is at or past src->hdr.image_count.
k_ra8_err_*A page fault (paged mode only; returned verbatim).
Precondition
src was populated by book_src_resident() / book_src_paged().
out_img addresses writable storage for one book_image_t.
Postcondition
On k_ra8_ok, out_img holds the descriptor at idx.
On any non-ok return out_img content is unspecified.
Note
Not thread-safe.
See also
book_src_image_rect()
book_images()
Since
Version 0.1.0

Definition at line 314 of file book_paged.c.

References book_src_read(), book_src_t::hdr, book_header_t::image_count, book_header_t::image_off, k_ra8_err_invalid_arg, RA8_CHECK_NULL_PTR, and s_tag_paged.

Referenced by sh_gray4_image().

◆ book_src_image_rect()

ra8_err_t book_src_image_rect ( const book_src_t * src,
const book_image_t * img,
uint32_t x,
uint32_t y,
uint32_t w,
uint32_t h,
uint8_t * out,
uint32_t out_stride )
nodiscard

Read a sub-rectangle of a raster image (4bpp or 8bpp) as gray8, row by row.

Owns the image-pool addressing contract so consumers do not. Both raster depths of a k_book_image_gray4 entry are served, selected by the descriptor's book_image_pixfmt_t, and both yield one gray8 byte per output pixel so the renderer sees a single depth:

  • k_book_pixfmt_gray4: 2 pixels per byte, pixel (px,py) at flat nibble index py * width + px; each 4-bit sample is expanded to gray8 ((nib << 4) | nib). The odd-width nibble parity – where a row can start on either the high or low nibble of a pool byte – is handled here, once, instead of in every renderer. Each row is read in bounded packed spans (a fixed pixel budget per book_src_read).
  • k_book_pixfmt_gray8: 1 byte per pixel at flat index py * width + px; the row is the retained full-resolution continuous-tone source (#476) and is copied straight out with no unpack. This is the representation the zoom loupe magnifies and the e-ink dither (#477) re-quantises from – gray4 quantisation is not reversible, gray8 is not quantised at all.

The per-call read stays bounded by the rectangle regardless of the image width (book_src_read itself faults a paged source frame-by-frame), so the whole pool is never inflated. Rows are written at out_stride intervals, so out may be a window into a wider buffer.

Parameters
[in]srcBound book source.
[in]imgImage descriptor from book_src_image (format must be k_book_image_gray4; pixel_format selects the gray4 vs gray8 unpack).
[in]xSub-rect left edge in source pixels (x + w <= img->width).
[in]ySub-rect top edge in source pixels (y + h <= img->height).
[in]wSub-rect width in pixels (> 0, <= out_stride).
[in]hSub-rect height in pixels (> 0).
[out]outDestination gray8 buffer (>= out_stride * h bytes).
[in]out_strideBytes between successive output rows (>= w).
Returns
ra8_err_t Error code.
Return values
k_ra8_okThe wxh window was read into out as gray8.
k_ra8_err_null_ptrsrc, img, or out was NULL.
k_ra8_err_invalid_argimg is not a raster (SVG), its pixel_format is neither gray4 nor gray8, or w == 0, h == 0, or out_stride < w.
k_ra8_err_out_of_rangeThe sub-rect leaves the image, or the pool span it addresses leaves the blob.
k_ra8_err_*A page fault (paged mode only; returned verbatim).
Precondition
src was populated by book_src_resident() / book_src_paged().
out addresses at least out_stride * h writable bytes.
Postcondition
On k_ra8_ok, each out[r*out_stride + c] (0<=r<h, 0<=c<w) is the gray8 value of source pixel (x+c, y+r) (gray4 samples nibble-expanded, gray8 samples verbatim).
On any non-ok return out content is unspecified.
Note
Not thread-safe.
See also
book_src_image()
Since
Version 0.1.0

Definition at line 325 of file book_paged.c.

References book_image_pixfmt(), book_image_t::format, book_image_t::height, internal_book_image_row(), internal_book_image_row_gray8(), k_book_image_gray4, k_book_pixfmt_gray4, k_book_pixfmt_gray8, k_ra8_err_invalid_arg, k_ra8_err_out_of_range, k_ra8_ok, RA8_CHECK_NULL_PTR, s_tag_paged, and book_image_t::width.

Referenced by sh_gray4_fetch_row(), and sh_loupe_stage().

◆ book_src_paged()

ra8_err_t book_src_paged ( book_src_t * out,
ra8_vmem_t * vm,
uint32_t object_id,
uint32_t frame_bytes,
uint32_t size )
nodiscard

Bind a paged book source over an ::ra8_vmem cache + ::ra8_vsource object.

The demand-fetch path for books that do not fit the resident budget. The caller has already registered the book's bytes as an ::ra8_vsource paged (or XIP) object and initialised vm with ra8_vsource_loader. This reads the 100-byte header through the cache into book_src_t::hdr so header fields never fault thereafter.

Parameters
[out]outSource to populate (caller-owned).
[in]vmInitialised page cache fronting the book object (non-NULL).
[in]object_idThe book's ::ra8_vsource object id within vm's loader.
[in]frame_bytesvm's frame size in bytes (>= 2); used for slice math.
[in]sizeBlob length in bytes (> 0, == header total_size).
Returns
ra8_err_t Error code.
Return values
k_ra8_okSource bound in paged mode; header cached.
k_ra8_err_null_ptrout or vm was NULL.
k_ra8_err_invalid_sizesize was zero or frame_bytes was < 2.
k_ra8_err_*A page fault while reading the header (verbatim).
Precondition
vm was initialised with the book registered at object_id.
frame_bytes equals the frame size vm was configured with.
Postcondition
On success out->vm == vm, out->base == NULL, out->hdr is the header.
On any non-ok return out is left unbound.
Note
Not thread-safe; vm's pin/evict state is mutated by reads.
See also
book_src_resident()
Since
Version 0.1.0

Definition at line 61 of file book_paged.c.

References book_src_t::base, book_src_read(), book_src_t::frame_bytes, book_src_t::hdr, k_book_paged_min_frame, k_ra8_err_invalid_size, book_src_t::object_id, RA8_CHECK_NULL_PTR, s_tag_paged, book_src_t::size, and book_src_t::vm.

Referenced by sh_paged_bind().

◆ book_src_prefetch_chapter()

ra8_err_t book_src_prefetch_chapter ( const book_src_t * src,
uint32_t chapter_idx )
nodiscard

Warm the cache frame holding a chapter's first content bytes, without pinning it (single-threaded read-ahead for the display-flush idle window).

The reader-facing wrapper #207 wires into the flush-idle window: after rendering the current page and issuing the panel flush, warm the adjacent chapters (N+1 for forward reading, N-1 for a back-flip) so the next chapter-crossing page turn finds them resident. Resolves chapter_idx to the byte offset of its root DOM node – the first content range book_chapter_text_src reads for that chapter – and hands it to ra8_vmem_prefetch, which does a bounded get+put so the page ends resident but unpinned (SLRU/2Q probationary: a wrong read-ahead guess ages out before hot data, no prefetch backfire on a fast skim). Best-effort and transparent: warming only changes cache residency, never the bytes a later read returns, so rendered output is unchanged. Resident sources are already wholly in RAM and are rejected as a no-op.

Parameters
[in]srcBound (paged) book source.
[in]chapter_idxSpine chapter index to warm (< src->hdr.chapter_count).
Returns
ra8_err_t Error code (callers on the idle path typically discard it).
Return values
k_ra8_okThe chapter's root-node frame is resident, unpinned.
k_ra8_err_null_ptrsrc was NULL.
k_ra8_err_invalid_statesrc is resident (or unbound): nothing to page.
k_ra8_err_invalid_argchapter_idx is out of range.
k_ra8_err_*A chapter-record read or the warm faulted (verbatim).
Precondition
src was populated by book_src_paged() (paged mode, src->vm != NULL).
Called from the single owning context (e.g. the reader idle window).
Postcondition
On k_ra8_ok the chapter's first content frame is resident with a net-zero change to its pin count.
On any return no cache frame is left pinned by this call.
Note
Not thread-safe. Single-threaded read-ahead only.
Warming is transparent: it never alters the bytes a subsequent read sees.
See also
ra8_vmem_prefetch() The bounded get+put warm this maps a chapter to.
book_chapter_text_src() The demand read this warms ahead of.
Since
Version 0.1.0

Definition at line 721 of file book_paged.c.

References book_src_read(), book_header_t::chapter_count, book_header_t::chapter_off, book_src_t::hdr, k_ra8_err_invalid_arg, k_ra8_err_invalid_state, k_ra8_ok, book_header_t::node_off, book_src_t::object_id, RA8_CHECK_NULL_PTR, ra8_vmem_prefetch(), book_chapter_t::root_node, s_tag_paged, and book_src_t::vm.

Referenced by sh_reader_prefetch_adjacent().

◆ book_src_read()

ra8_err_t book_src_read ( const book_src_t * src,
uint32_t off,
void * dst,
uint32_t len )
nodiscard

Copy a byte range out of a book source (resident memcpy or paged fault).

The single read primitive both modes share. Resident mode is a memcpy(dst, base + off, len). Paged mode walks the range frame by frame: ra8_vmem_get pins the frame holding the current offset, the overlapping slice is copied to dst, and ra8_vmem_put releases it before advancing – so at most one frame is pinned at a time and the resident working set stays bounded regardless of len.

Parameters
[in]srcBound book source.
[in]offByte offset within the blob (off + len <= src->size).
[out]dstDestination buffer receiving len bytes (non-NULL).
[in]lenNumber of bytes to copy.
Returns
ra8_err_t Error code.
Return values
k_ra8_okBytes copied into dst.
k_ra8_err_null_ptrsrc or dst was NULL.
k_ra8_err_invalid_statesrc is bound to neither mode.
k_ra8_err_out_of_rangeoff + len exceeds src->size.
k_ra8_err_*A page fault (paged mode only; returned verbatim).
Precondition
src was populated by book_src_resident() / book_src_paged().
dst addresses at least len writable bytes.
Postcondition
On success dst[0..len) holds the blob bytes at off.
On any non-ok return dst content is unspecified and no pin is held.
Note
Not thread-safe.
Since
Version 0.1.0

Definition at line 141 of file book_paged.c.

References book_src_t::base, internal_book_src_read_paged(), k_ra8_err_invalid_state, k_ra8_err_out_of_range, k_ra8_ok, memcpy(), RA8_CHECK_NULL_PTR, s_tag_paged, book_src_t::size, and book_src_t::vm.

Referenced by book_chapter_text_src(), book_src_image(), book_src_paged(), book_src_prefetch_chapter(), internal_book_image_row(), internal_book_image_row_gray8(), internal_paged_emit_run(), internal_paged_node(), internal_paged_str_short(), sh_rabook_label(), and sh_src_string().

◆ book_src_resident()

ra8_err_t book_src_resident ( book_src_t * out,
const void * base,
uint32_t size )
nodiscard

Bind a resident (already-inflated, fully resident) book as a source.

The zero-copy fast path: book_src_t::base is set to base and reads become base + off, byte-for-byte identical to the book.h accessors. The header is copied into book_src_t::hdr.

Parameters
[out]outSource to populate (caller-owned).
[in]baseValidated .rabook blob base (non-NULL), as from book_open().
[in]sizeBlob length in bytes (> 0, == header total_size).
Returns
ra8_err_t Error code.
Return values
k_ra8_okSource bound in resident mode.
k_ra8_err_null_ptrout or base was NULL.
k_ra8_err_invalid_sizesize was zero.
Precondition
base was accepted by book_validate() / book_open().
out points at writable storage out-living the reads.
Postcondition
On success out->base == base, out->vm == NULL, out->hdr is the header.
On any non-ok return out is left unbound.
Note
Not thread-safe; reads over the immutable blob are otherwise re-entrant.
See also
book_src_paged()
Since
Version 0.1.0

Definition at line 45 of file book_paged.c.

References book_src_t::base, book_src_t::frame_bytes, book_src_t::hdr, k_ra8_err_invalid_size, k_ra8_ok, memcpy(), book_src_t::object_id, RA8_CHECK_NULL_PTR, s_tag_paged, book_src_t::size, and book_src_t::vm.

◆ internal_book_image_row()

ra8_err_t internal_book_image_row ( const book_src_t * src,
const book_image_t * img,
uint32_t x,
uint32_t ry,
uint32_t w,
uint8_t * out )
static

Unpack one horizontal gray4 run [x, x+w) of source row ry to gray8.

The per-row worker of book_src_image_rect. Walks the run in spans of at most k_book_rect_chunk_px pixels: each span's flat nibble index maps to an absolute pool offset (image_pool_off + data_off + (flat >> 1)), the packed span is copied out via book_src_read (bounds-checked, paged-fault-aware), and each 4-bit sample is replicated into a gray8 byte. Tracking the absolute flat index per pixel keeps the high/low nibble parity correct across span boundaries and for odd image widths.

Parameters
[in]srcBound book source.
[in]imgGray4 image descriptor (caller already checked the format).
[in]xRun left edge in source pixels (x + w <= img->width).
[in]rySource row index (< img->height).
[in]wRun width in pixels (> 0).
[out]outDestination gray8 run (>= w bytes).
Returns
ra8_err_t Error code.
Return values
k_ra8_okThe run was unpacked into out.
k_ra8_err_out_of_rangeA span it addresses leaves the blob.
k_ra8_err_*A book_src_read fault (returned verbatim).
Precondition
src is bound and img is a gray4 descriptor within src.
out addresses at least w writable bytes.
Postcondition
On k_ra8_ok, out[i] is the gray8 expansion of pixel (x+i, ry).
On any non-ok return out content is unspecified.
Note
Not thread-safe.
Since
Version 0.1.0

Definition at line 220 of file book_paged.c.

References book_src_read(), book_image_t::data_off, book_src_t::hdr, book_header_t::image_pool_off, k_book_gray4_nib_lo, k_book_gray4_nib_sh, k_book_gray4_ppb, k_book_rect_chunk_pad, k_book_rect_chunk_px, k_ra8_err_out_of_range, k_ra8_ok, RA8_INTERNAL, book_src_t::size, and book_image_t::width.

Referenced by book_src_image_rect().

◆ internal_book_image_row_gray8()

ra8_err_t internal_book_image_row_gray8 ( const book_src_t * src,
const book_image_t * img,
uint32_t x,
uint32_t ry,
uint32_t w,
uint8_t * out )
static

Copy one horizontal gray8 run [x, x+w) of source row ry into out.

The per-row worker of book_src_image_rect for a k_book_pixfmt_gray8 raster (the full-resolution, continuous-tone representation the compiled .rabook retains for zoomable content, #476). At 8bpp there is no nibble packing: pixel (px, py) is one byte at flat index py * width + px, so the run maps to a single contiguous pool span [image_pool_off + data_off + (ry * width + x), + w) that is copied straight into out via book_src_read – which is itself bounded (a paged source faults the covering frames in one at a time), so no unpack staging buffer and no per-span loop are needed here.

Parameters
[in]srcBound book source.
[in]imgGray8 image descriptor (caller already checked format + depth).
[in]xRun left edge in source pixels (x + w <= img->width).
[in]rySource row index (< img->height).
[in]wRun width in pixels (> 0).
[out]outDestination gray8 run (>= w bytes).
Returns
ra8_err_t Error code.
Return values
k_ra8_okThe run was copied into out.
k_ra8_err_out_of_rangeThe pool span it addresses leaves the blob.
k_ra8_err_*A book_src_read fault (returned verbatim).
Precondition
src is bound and img is a gray8 descriptor within src.
out addresses at least w writable bytes.
Postcondition
On k_ra8_ok, out[i] is the gray8 value of pixel (x+i, ry).
On any non-ok return out content is unspecified.
Note
Not thread-safe.
Since
Version 0.1.0

Definition at line 296 of file book_paged.c.

References book_src_read(), book_image_t::data_off, book_src_t::hdr, book_header_t::image_pool_off, k_ra8_err_out_of_range, RA8_INTERNAL, book_src_t::size, and book_image_t::width.

Referenced by book_src_image_rect().

◆ internal_book_src_read_paged()

ra8_err_t internal_book_src_read_paged ( const book_src_t * src,
uint32_t off,
void * dst,
uint32_t len )
static

Copy a byte range out of a paged source, frame by frame.

The demand-fetch worker behind book_src_read: walks len bytes at off through the cache, pinning the frame holding the current offset (ra8_vmem_get), copying the overlapping slice, and releasing it (ra8_vmem_put) before advancing – one frame pinned at a time. The loop is bounded by len / frame_bytes + 2 (frame_bytes >= 2 is enforced at bind time, so the bound never overflows).

Parameters
[in]srcPaged source (src->vm non-NULL, src->base NULL).
[in]offByte offset within the blob (range already validated).
[out]dstDestination buffer receiving len bytes.
[in]lenNumber of bytes to copy (non-zero).
Returns
ra8_err_t Error code.
Return values
k_ra8_okAll len bytes copied into dst.
k_ra8_err_out_of_rangeThe loop drained before len bytes (unreachable for a valid range / frame_bytes >= 2).
k_ra8_err_*A ra8_vmem_get / ra8_vmem_put fault (verbatim).
Precondition
src is paged and off + len <= src->size.
dst addresses at least len writable bytes.
Postcondition
On success dst[0..len) holds the blob bytes at off; no pin is held.
On any non-ok return dst content is unspecified and no pin is held.
Note
Not thread-safe.
Since
Version 0.1.0

Definition at line 114 of file book_paged.c.

References book_src_t::frame_bytes, k_book_paged_span_pad, k_ra8_err_out_of_range, k_ra8_ok, memcpy(), book_src_t::object_id, ra8_vmem_get(), ra8_vmem_put(), and book_src_t::vm.

Referenced by book_src_read().

◆ internal_paged_emit_run()

bool internal_paged_emit_run ( const book_src_t * src,
uint32_t abs_off,
char * out,
size_t cap,
size_t * pos,
bool * at_break,
ra8_err_t * io_err )
static

Emit one text run from a paged source, collapsing whitespace.

Streams the NUL-terminated run at abs_off through a staging buffer in k_book_paged_strbuf-sized chunks, calling the shared priv_book_emit_text on each chunk. Chunking keeps the resident footprint bounded for arbitrarily long runs; the at_break flag threads across chunks so whitespace collapsing is identical to the resident single-pass walk.

Parameters
[in]srcBound book source.
[in]abs_offAbsolute blob offset of the NUL-terminated run.
[out]outDestination text buffer.
[in]capCapacity of out in bytes.
[in,out]posCurrent write offset; advanced as text is emitted.
[in,out]at_breakWhitespace-collapse carry flag threaded across chunks.
[out]io_errSet to the fault code on a read fault; untouched otherwise.
Returns
bool Emit result.
Return values
trueThe whole run was emitted; *io_err is unchanged.
falseOutput buffer overflowed (io_err untouched), or a page fault occurred (*io_err set to the fault code).
Precondition
src is bound; out has room for cap bytes.
pos and at_break are non-null and valid.
Postcondition
On true with *io_err == k_ra8_ok the run is fully emitted.
On a fault *io_err holds the fault code and false is returned.
Note
Not thread-safe.
Since
Version 0.1.0

Definition at line 498 of file book_paged.c.

References book_src_read(), k_book_paged_pad, k_book_paged_strbuf, k_ra8_ok, priv_book_emit_text(), RA8_INTERNAL, and book_src_t::size.

Referenced by internal_paged_visit_node().

◆ internal_paged_node()

ra8_err_t internal_paged_node ( const book_src_t * src,
uint32_t idx,
book_node_t * out )
static

Read one DOM node record out of a paged/resident book source by index.

Translates the node index to its blob byte offset (node_off + idx * sizeof(book_node_t)) and copies the 24-byte record out via book_src_read, which bounds-checks the range and faults the frame in for a paged source.

Parameters
[in]srcBound book source.
[in]idxNode-table index to read.
[out]outReceives the node record.
Returns
ra8_err_t Error code.
Return values
k_ra8_okNode copied into out.
k_ra8_err_out_of_rangeidx lies outside the node table.
k_ra8_err_*A book_src_read fault (returned verbatim).
Precondition
src is bound and out is writable.
idx is intended to index a valid node (verified by the read bounds).
Postcondition
On success out holds the node at idx.
On any non-ok return out content is unspecified.
Note
Not thread-safe.
Since
Version 0.1.0

Definition at line 412 of file book_paged.c.

References book_src_read(), book_src_t::hdr, and book_header_t::node_off.

Referenced by internal_paged_visit_node().

◆ internal_paged_str_short()

ra8_err_t internal_paged_str_short ( const book_src_t * src,
uint32_t abs_off,
char * buf,
uint32_t cap )
static

Copy a short NUL-terminated string (a tag name) out into a buffer.

Reads up to cap - 1 bytes at abs_off and NUL-terminates at the first embedded NUL or at the buffer end. Used for element tag names, which are short; a name longer than the buffer is truncated, which at worst makes priv_book_is_block treat it as inline (no break) – never a correctness issue for real markup.

Parameters
[in]srcBound book source.
[in]abs_offAbsolute blob offset of the string start.
[out]bufDestination buffer (>= cap bytes).
[in]capCapacity of buf in bytes (>= 1).
Returns
ra8_err_t Error code.
Return values
k_ra8_okString (possibly truncated) copied + terminated.
k_ra8_err_out_of_rangeabs_off is at or past the blob end.
k_ra8_err_*A book_src_read fault (returned verbatim).
Precondition
src is bound and buf has room for cap bytes.
cap is at least one (for the NUL terminator).
Postcondition
On success buf is a NUL-terminated string.
On any non-ok return buf content is unspecified.
Note
Not thread-safe.
Since
Version 0.1.0

Definition at line 447 of file book_paged.c.

References book_src_read(), k_ra8_err_out_of_range, k_ra8_ok, and book_src_t::size.

Referenced by internal_paged_visit_node().

◆ internal_paged_visit_node()

bool internal_paged_visit_node ( const book_src_t * src,
uint32_t n,
char * out,
size_t cap,
size_t * pos,
bool * at_break,
uint32_t * stack,
uint32_t * sp,
ra8_err_t * io_err )
static

Process one popped node in the paged text walk.

The per-node body of internal_walk_text_paged, split out to keep both functions within the size/complexity budget. Reads the node, pushes its sibling, then either emits a text run (internal_paged_emit_run) or, for an element, inserts a block break (priv_book_is_block over a staged tag name) and pushes its first child. Mutates the caller's stack/sp and whitespace-collapse at_break in place.

Parameters
[in]srcBound (paged) book source.
[in]nNode index to visit (already non-nil).
[out]outDestination plain-text buffer.
[in]capCapacity of out in bytes.
[in,out]posCurrent write offset; advanced as text is emitted.
[in,out]at_breakWhitespace-collapse carry flag.
[in,out]stackCaller walk stack of length k_book_xhtml_stack.
[in,out]spStack pointer (live entry count); pushed up to twice.
[out]io_errSet to the fault code on a read fault; untouched otherwise.
Returns
bool Visit result.
Return values
trueNode handled; the walk may continue.
falseOutput overflow, stack full, or a read fault (see io_err).
Precondition
src is paged; n indexes a node in the blob.
stack / sp / at_break are the walk's live state.
Postcondition
On true the node's text/break is emitted and children/sibling pushed.
On false the walk must stop; io_err is set iff a fault occurred.
Note
Not thread-safe.
Since
Version 0.1.0

Definition at line 570 of file book_paged.c.

References book_node_t::first_child, book_src_t::hdr, internal_paged_emit_run(), internal_paged_node(), internal_paged_str_short(), k_book_node_text, k_book_paged_tagbuf, k_book_xhtml_stack, k_ra8_ok, book_node_t::kind, book_node_t::name_off, book_node_t::next_sibling, priv_book_emit_break(), priv_book_is_block(), RA8_INTERNAL, book_header_t::string_off, and book_node_t::text_off.

Referenced by internal_walk_text_paged().

◆ internal_walk_text_paged()

bool internal_walk_text_paged ( const book_src_t * src,
uint32_t root,
uint32_t node_count,
char * out,
size_t cap,
size_t * pos,
ra8_err_t * io_err )
static

Bounded pre-order text walk over a paged book source.

The paged counterpart of internal_walk_text(): identical iterative, recursion-free pre-order traversal and identical output, dispatching each popped node to internal_paged_visit_node. At most one cache frame is pinned at a time, so the resident working set stays bounded.

Parameters
[in]srcBound (paged) book source.
[in]rootNode index of the subtree root.
[in]node_countTotal node count, for the iteration guard.
[out]outDestination plain-text buffer.
[in]capCapacity of out in bytes.
[in,out]posCurrent write offset; advanced as text is emitted.
[out]io_errSet to the fault code on a read fault; k_ra8_ok otherwise.
Returns
bool Walk result.
Return values
trueSubtree fully serialised (check io_err for a clean run).
falseOverflow, stack/guard exhaustion, or a read fault (see io_err).
Precondition
src is a paged source bound by book_src_paged().
root is a node index within the blob.
Postcondition
On true with *io_err == k_ra8_ok, out holds the chapter text.
On a fault *io_err carries the fault code.
Note
Not thread-safe.
Since
Version 0.1.0

Definition at line 648 of file book_paged.c.

References internal_paged_visit_node(), k_book_nil, k_book_xhtml_iter_x, k_book_xhtml_stack, and RA8_INTERNAL.

Referenced by book_chapter_text_src().

Variable Documentation

◆ s_tag_paged

const char* const s_tag_paged = "book_paged"
static

Log tag for paged-source diagnostics.

Definition at line 30 of file book_paged.c.

Referenced by book_chapter_text_src(), book_src_image(), book_src_image_rect(), book_src_paged(), book_src_prefetch_chapter(), book_src_read(), and book_src_resident().