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

Serialize a compiled-book chapter DOM back to XHTML for the renderer. More...

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

Go to the source code of this file.

Data Structures

struct  book_walk_entry_t
 One deferred unit of work on the serializer stack. More...

Functions

static bool internal_emit (char *out, size_t cap, size_t *pos, const char *src, size_t len)
 Append a raw byte span to the output buffer.
static bool internal_emit_cstr (char *out, size_t cap, size_t *pos, const char *str)
 Append a NUL-terminated string to the output buffer.
static bool internal_emit_escaped (char *out, size_t cap, size_t *pos, const char *str, bool in_attr)
 Append entity-escaped text to the output buffer.
static bool internal_is_void (const char *name)
 Test whether an element name is an HTML void element.
static bool internal_emit_attrs (const void *base, const book_node_t *node, char *out, size_t cap, size_t *pos)
 Append all attributes of a DOM node to the output buffer.
static bool internal_open_element (const void *base, const book_node_t *node, char *out, size_t cap, size_t *pos, book_walk_entry_t *stack, uint32_t *sp)
 Emit an element open tag and schedule its close and children on the walk stack.
static bool internal_walk_to_xhtml (const void *base, uint32_t root, uint32_t node_count, char *out, size_t cap, size_t *pos)
 Iterative, bounded DOM walk that serialises a subtree to XHTML.
bool priv_book_is_block (const char *name)
 Test whether an element name is a block-level HTML element.
bool priv_book_emit_text (char *out, size_t cap, size_t *pos, const char *str, bool *at_break)
 Append a whitespace-collapsed text run to the output buffer.
bool priv_book_emit_break (char *out, size_t cap, size_t *pos, bool *at_break)
 Append a paragraph break, collapsing consecutive block-level breaks.
static bool internal_walk_text (const void *base, uint32_t root, uint32_t node_count, char *out, size_t cap, size_t *pos)
 Bounded pre-order walk that extracts plain text from a DOM subtree.
ra8_err_t book_chapter_text (const void *base, uint32_t chapter_idx, char *out, size_t cap, size_t *out_len)
 Extract one chapter's readable plain text from the DOM.
ra8_err_t book_chapter_to_xhtml (const void *base, uint32_t chapter_idx, char *out, size_t cap, size_t *out_len)
 Serialize one chapter's DOM subtree back to XHTML for the renderer.

Variables

static const char *const s_tag_xhtml = "book_xhtml"
 Log tag for serializer diagnostics.

Detailed Description

Serialize a compiled-book chapter DOM back to XHTML for the renderer.

reflow_layout_chapter() consumes XHTML. This bridge walks a chapter's pre-parsed book DOM and re-emits well-formed XHTML so a compiled book renders through the existing, MC/DC-tested reflow engine without modifying it. The walk is iterative (an explicit open/close stack, NASA Rule 1) and bounded (NASA Rule 2): nothing recurses, the stack and iteration count are capped. Serialization is lossless – every element tag, attribute and text run is preserved; void elements self-close and text/attribute values are entity-escaped.

A future optimization can feed the DOM straight into the tokenizer and skip this XHTML round-trip; until then the bridge keeps the renderer untouched.

Since
Version 0.1.0

Definition in file book_xhtml.c.

Function Documentation

◆ book_chapter_text()

ra8_err_t book_chapter_text ( const void * base,
uint32_t chapter_idx,
char * out,
size_t cap,
size_t * out_len )

Extract one chapter's readable plain text from the DOM.

Walks the chapter's element/text tree iteratively (no recursion, bounded stack) and writes its text runs into out, inserting a newline at each block-level element so paragraphs stay separated. Markup, attributes and inline structure are dropped – this is for a simple word-wrap reader, not rich layout. The output is NOT NUL-terminated.

Parameters
[in]baseValidated book blob base (non-NULL).
[in]chapter_idxSpine chapter index (< header chapter_count).
[out]outDestination text buffer (non-NULL).
[in]capCapacity of out in bytes.
[out]out_lenReceives the text byte length written.
Returns
Error code.
Return values
k_ra8_okChapter text extracted.
k_ra8_err_null_ptrA required pointer argument is 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.
Precondition
base was accepted by book_validate() / book_open().
chapter_idx is less than book_header(base)->chapter_count.
Postcondition
On k_ra8_ok, out[0..*out_len) contains the plain-text run (not NUL-terminated).
On error, out contents are unspecified.
Note
Thread-safe: reads only the immutable blob, writes only out.
Since
Version 0.1.0

Definition at line 683 of file book_xhtml.c.

References book_chapters(), book_header(), book_header_t::chapter_count, internal_walk_text(), 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_xhtml.

Referenced by book_chapter_text_src(), and imp_walk_book().

◆ book_chapter_to_xhtml()

ra8_err_t book_chapter_to_xhtml ( const void * base,
uint32_t chapter_idx,
char * out,
size_t cap,
size_t * out_len )

Serialize one chapter's DOM subtree back to XHTML for the renderer.

A bridge for feeding a compiled book into reflow_layout_chapter(), which consumes XHTML. Walks the chapter's element/text tree iteratively (no recursion, bounded stack) and writes well-formed XHTML – every tag, attribute and text run, faithfully – into out. Void elements self-close; text and attribute values are entity-escaped. The output is NOT NUL-terminated.

Parameters
[in]baseValidated book blob base (non-NULL).
[in]chapter_idxSpine chapter index (< header chapter_count).
[out]outDestination XHTML buffer (non-NULL).
[in]capCapacity of out in bytes.
[out]out_lenReceives the XHTML byte length written.
Returns
Error code.
Return values
k_ra8_okChapter serialized; out_len bytes written.
k_ra8_err_null_ptrA required pointer argument is 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.
Precondition
base was accepted by book_validate() / book_open().
cap is large enough for the chapter's serialized XHTML.
Postcondition
On k_ra8_ok, out[0..*out_len) is well-formed (not NUL-terminated).
On error, out contents are unspecified.
Note
Thread-safe: reads only the immutable blob, writes only out.
See also
reflow_layout_chapter()
Since
Version 0.1.0

Definition at line 702 of file book_xhtml.c.

References book_chapters(), book_header(), book_header_t::chapter_count, internal_walk_to_xhtml(), 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_xhtml.

Referenced by erb_render_chapter().

◆ internal_emit()

bool internal_emit ( char * out,
size_t cap,
size_t * pos,
const char * src,
size_t len )
static

Append a raw byte span to the output buffer.

Copies exactly len bytes from src into out starting at *pos, advancing *pos by len on success. If the copy would exceed cap the buffer is left unchanged and the function returns false so callers can chain with && and abort the entire serialisation on first overflow.

Parameters
[out]outDestination character buffer receiving the bytes.
[in]capTotal capacity of out in bytes.
[in,out]posCurrent write offset into out; advanced by len when the append succeeds.
[in]srcSource byte span to copy (need not be NUL-terminated).
[in]lenNumber of bytes to copy from src.
Returns
bool Append result.
Return values
trueBytes copied successfully; *pos advanced by len.
falseOutput buffer would overflow; buffer and *pos unchanged.
Precondition
out is a valid, writable buffer of at least cap bytes.
pos is non-null and *pos <= cap on entry.
Postcondition
On success *pos equals the previous value plus len.
On failure *pos and out contents are unchanged.
Note
Not thread-safe; callers must provide external synchronisation.
Since
Version 0.1.0

Definition at line 75 of file book_xhtml.c.

References memcpy().

Referenced by internal_emit_attrs(), internal_emit_cstr(), internal_emit_escaped(), internal_open_element(), internal_walk_to_xhtml(), priv_book_emit_break(), and priv_book_emit_text().

◆ internal_emit_attrs()

bool internal_emit_attrs ( const void * base,
const book_node_t * node,
char * out,
size_t cap,
size_t * pos )
static

Append all attributes of a DOM node to the output buffer.

Iterates over the attr_count attribute slots starting at node->first_attr in the flat attribute array returned by book_attrs. For each attribute it emits a single space, the attribute name, =" (with entity-escaped value), and a closing @c " using internal_emit and internal_emit_escaped. The function is called while the opening tag is still open (before the > or />) so the caller must emit the tag terminator after this returns.

Parameters
[in]basePointer to the start of the compiled book blob; used to resolve attribute name and value string offsets via book_string and book_attrs.
[in]nodeDOM node whose attributes are to be serialised.
[out]outDestination character buffer.
[in]capTotal capacity of out in bytes.
[in,out]posCurrent write offset; advanced for each byte emitted.
Returns
bool Serialisation result.
Return values
trueAll attributes emitted successfully.
falseOutput buffer overflowed; partial output may have been written.
Precondition
base points to a valid, fully initialised compiled book blob.
node is a non-null pointer to an element node within the blob.
Postcondition
On success *pos reflects all attribute bytes written.
On failure the write stops at the overflowing attribute byte; *pos reflects the bytes written before the overflow.
Note
Not thread-safe; callers must provide external synchronisation.
Since
Version 0.1.0

Definition at line 274 of file book_xhtml.c.

References book_node_t::attr_count, book_attrs(), book_string(), book_node_t::first_attr, internal_emit(), internal_emit_cstr(), internal_emit_escaped(), book_attr_t::name_off, and book_attr_t::value_off.

Referenced by internal_open_element().

◆ internal_emit_cstr()

bool internal_emit_cstr ( char * out,
size_t cap,
size_t * pos,
const char * str )
static

Append a NUL-terminated string to the output buffer.

Determines the length of str with strlen and delegates to internal_emit. Provides a convenient wrapper so callers do not need to compute string lengths manually when emitting tag names, attribute names, or literal XML punctuation.

Parameters
[out]outDestination character buffer.
[in]capTotal capacity of out in bytes.
[in,out]posCurrent write offset; advanced by the string length on success.
[in]strNUL-terminated source string to append.
Returns
bool Append result.
Return values
trueString appended; *pos advanced by strlen(str).
falseOutput buffer would overflow; buffer and *pos unchanged.
Precondition
out is a valid, writable buffer of at least cap bytes.
str is a valid, NUL-terminated C string.
Postcondition
On success *pos equals the previous value plus strlen(str).
On failure *pos and out contents are unchanged.
Note
Not thread-safe; callers must provide external synchronisation.
Since
Version 0.1.0

Definition at line 113 of file book_xhtml.c.

References internal_emit(), RA8_INTERNAL, and strlen().

Referenced by internal_emit_attrs(), internal_emit_escaped(), internal_open_element(), and internal_walk_to_xhtml().

◆ internal_emit_escaped()

bool internal_emit_escaped ( char * out,
size_t cap,
size_t * pos,
const char * str,
bool in_attr )
static

Append entity-escaped text to the output buffer.

Iterates over every character in str and replaces XML-special characters with their entity references before writing them to the output buffer via internal_emit or internal_emit_cstr. The substitution table is:

  • & becomes &
  • < becomes <
  • > becomes >
  • " becomes @c &quot; only when @p in_attr is @c true; otherwise the literal @c " is emitted unchanged. All other characters are forwarded as-is. The function stops on the first overflow, leaving *pos at the last successfully written position.
Parameters
[out]outDestination character buffer.
[in]capTotal capacity of out in bytes.
[in,out]posCurrent write offset; advanced for each character (or its entity expansion) successfully appended.
[in]strNUL-terminated source text to escape and append.
[in]in_attrWhen true the context is an XML attribute value and double-quotes are entity-escaped; when false the context is element content and " is literal.
Returns
bool Escape-and-append result.
Return values
trueAll characters written successfully.
falseOutput buffer overflowed; partial output may have been written.
Precondition
out is a valid, writable buffer of at least cap bytes.
str is a valid, NUL-terminated C string.
Postcondition
On success every character of str has been entity-escaped and appended; *pos reflects the total bytes written.
On failure the write stops at the overflowing character; *pos reflects the number of bytes written before the overflow.
Note
Not thread-safe; callers must provide external synchronisation.
Since
Version 0.1.0

Definition at line 158 of file book_xhtml.c.

References internal_emit(), and internal_emit_cstr().

Referenced by internal_emit_attrs(), and internal_walk_to_xhtml().

◆ internal_is_void()

bool internal_is_void ( const char * name)
static

Test whether an element name is an HTML void element.

Performs a linear search through a fixed table of HTML void element names (elements that must self-close and may not have child nodes in XHTML): br, hr, img, meta, link, input, area, base, col, embed, param, source, track, and wbr. The comparison is case-sensitive because compiled book DOM names are already lower-cased during parsing.

Parameters
[in]nameNUL-terminated element name to test (e.g. "br").
Returns
bool Query result.
Return values
truename matches a known void element; the serialiser must emit /> instead of a separate close tag.
falsename is not a void element; a close tag is required.
Precondition
name is a valid, NUL-terminated C string.
name contains only lower-case ASCII letters (DOM invariant).
Postcondition
The void-element table is not modified.
The return value is purely a function of name with no side effects.
Note
Not thread-safe; callers must provide external synchronisation.
Since
Version 0.1.0

Definition at line 214 of file book_xhtml.c.

References RA8_INTERNAL, and strcmp().

Referenced by internal_open_element().

◆ internal_open_element()

bool internal_open_element ( const void * base,
const book_node_t * node,
char * out,
size_t cap,
size_t * pos,
book_walk_entry_t * stack,
uint32_t * sp )
static

Emit an element open tag and schedule its close and children on the walk stack.

Serialises the opening half of a DOM element node into out: emits <, the tag name, all attributes via internal_emit_attrs, then either /> for void elements (using internal_is_void) or > for non-void elements. For non-void elements two entries are pushed onto the caller-supplied stack before returning: first a close entry (so the closing tag is emitted after all descendants), then a child-list entry (so the first child is processed next by the outer loop in internal_walk_to_xhtml). Stack indices grow upward; the current depth is held in *sp.

Parameters
[in]basePointer to the compiled book blob; used to resolve string offsets via book_string.
[in]nodeElement node to open; must have kind == element.
[out]outDestination character buffer.
[in]capTotal capacity of out in bytes.
[in,out]posCurrent write offset; advanced for each byte emitted.
[in,out]stackCaller-managed walk stack array of length k_book_xhtml_stack.
[in,out]spStack pointer (count of live entries); incremented by up to 2 for non-void elements.
Returns
bool Operation result.
Return values
trueOpen tag emitted; child and close entries pushed for non-void.
falseOutput buffer overflowed or stack is full.
Precondition
base points to a valid, fully initialised compiled book blob.
node is a non-null pointer to an element node; *sp < k_book_xhtml_stack.
Postcondition
On success the open tag bytes are in out and *sp is incremented by 2 for non-void elements (0 for void elements).
On failure *pos and *sp may reflect partially completed writes; the caller must abort the walk.
Note
Not thread-safe; callers must provide external synchronisation.
Since
Version 0.1.0

Definition at line 331 of file book_xhtml.c.

References book_string(), book_node_t::first_child, internal_emit(), internal_emit_attrs(), internal_emit_cstr(), internal_is_void(), k_book_xhtml_stack, book_node_t::name_off, and RA8_INTERNAL.

Referenced by internal_walk_to_xhtml().

◆ internal_walk_text()

bool internal_walk_text ( const void * base,
uint32_t root,
uint32_t node_count,
char * out,
size_t cap,
size_t * pos )
static

Bounded pre-order walk that extracts plain text from a DOM subtree.

Traverses the subtree rooted at root in pre-order using an iterative stack (maximum depth k_book_xhtml_stack) without recursion. An iteration guard capped at node_count * k_book_xhtml_iter_x + k_book_xhtml_stack prevents unbounded execution. For each node:

  • Text nodes are handed to priv_book_emit_text for whitespace collapsing.
  • Element nodes that are block-level (tested via priv_book_is_block) trigger priv_book_emit_break to insert a paragraph separator before descending into the element's children.
  • All other element nodes descend immediately with no separator. The at_break flag threads through all text and break calls so that leading whitespace at the start of each block is suppressed.
Parameters
[in]basePointer to the compiled book blob.
[in]rootNode index of the subtree root to extract text from.
[in]node_countTotal number of nodes in the blob; used to compute the iteration guard bound.
[out]outDestination character buffer for the plain text.
[in]capTotal capacity of out in bytes.
[in,out]posCurrent write offset; advanced as bytes are emitted.
Returns
bool Walk result.
Return values
trueEntire subtree processed; plain text in out at *pos bytes.
falseOutput buffer overflowed, stack exhausted, or iteration guard triggered (possible cycle in DOM).
Precondition
base points to a valid, fully initialised compiled book blob.
root is a valid node index within the blob (less than node_count).
Postcondition
On success *pos equals the number of plain-text bytes written.
On failure *pos reflects bytes written before the error condition.
Note
Not thread-safe; callers must provide external synchronisation.
Since
Version 0.1.0

Definition at line 633 of file book_xhtml.c.

References book_nodes(), book_string(), book_node_t::first_child, k_book_nil, k_book_node_text, k_book_xhtml_iter_x, k_book_xhtml_stack, book_node_t::kind, book_node_t::name_off, book_node_t::next_sibling, priv_book_emit_break(), priv_book_emit_text(), priv_book_is_block(), RA8_INTERNAL, and book_node_t::text_off.

Referenced by book_chapter_text().

◆ internal_walk_to_xhtml()

bool internal_walk_to_xhtml ( const void * base,
uint32_t root,
uint32_t node_count,
char * out,
size_t cap,
size_t * pos )
static

Iterative, bounded DOM walk that serialises a subtree to XHTML.

Performs a depth-first serialisation of the subtree rooted at root without recursion. A book_walk_entry_t stack (maximum depth k_book_xhtml_stack) holds deferred work: each entry is either a node-to-open or a pending close tag. The main loop pops one entry per iteration, emitting the appropriate text. An iteration guard capped at node_count * k_book_xhtml_iter_x + k_book_xhtml_stack prevents any unbounded execution even if the DOM contains cycles. Element nodes delegate opening (and child/close scheduling) to internal_open_element; text nodes are emitted via internal_emit_escaped.

Parameters
[in]basePointer to the compiled book blob.
[in]rootNode index of the subtree root to serialise.
[in]node_countTotal number of nodes in the blob; used to compute the iteration guard bound.
[out]outDestination character buffer for the XHTML output.
[in]capTotal capacity of out in bytes.
[in,out]posCurrent write offset; advanced as bytes are emitted.
Returns
bool Walk result.
Return values
trueEntire subtree serialised without overflow or guard expiry.
falseOutput buffer overflowed, stack exhausted, or iteration guard triggered (possible cycle in DOM).
Precondition
base points to a valid, fully initialised compiled book blob.
root is a valid node index within the blob (less than node_count).
Postcondition
On success *pos reflects all XHTML bytes written for the subtree.
On failure *pos reflects bytes written before the error condition.
Note
Not thread-safe; callers must provide external synchronisation.
Since
Version 0.1.0

Definition at line 393 of file book_xhtml.c.

References book_nodes(), book_string(), internal_emit(), internal_emit_cstr(), internal_emit_escaped(), internal_open_element(), book_walk_entry_t::is_close, k_book_nil, k_book_node_text, k_book_xhtml_iter_x, k_book_xhtml_stack, book_node_t::kind, book_node_t::next_sibling, RA8_INTERNAL, book_node_t::text_off, and book_walk_entry_t::value.

Referenced by book_chapter_to_xhtml().

◆ priv_book_emit_break()

bool priv_book_emit_break ( char * out,
size_t cap,
size_t * pos,
bool * at_break )

Append a paragraph break, collapsing consecutive block-level breaks.

Trims any trailing space characters already written to out (by decrementing *pos while the last byte is ' '), then sets *at_break to true to suppress leading whitespace in the next text fragment. If the last byte already in out is '\n' no additional newline is written, which collapses runs of breaks produced by consecutive or nested block-level elements (e.g. a p inside a div) into a single blank line. Otherwise a single '\n' is appended via internal_emit.

Parameters
[out]outDestination character buffer.
[in]capTotal capacity of out in bytes.
[in,out]posCurrent write offset; may be decremented to trim trailing spaces, then advanced by 1 if a newline is emitted.
[in,out]at_breakSet to true on entry to suppress subsequent leading whitespace; value on entry is ignored.
Returns
bool Append result.
Return values
trueBreak emitted (or collapsed into an existing newline).
falseOutput buffer overflowed while writing the newline byte.
Precondition
out is a valid, writable buffer of at least cap bytes.
pos is non-null and *pos <= cap on entry.
Postcondition
*at_break is true on return.
Trailing space characters in out before the current *pos have been removed; at most one '\n' is appended.
Note
Not thread-safe; callers must provide external synchronisation.
Since
Version 0.1.0

Definition at line 583 of file book_xhtml.c.

References internal_emit(), and RA8_PRIV.

Referenced by internal_paged_visit_node(), and internal_walk_text().

◆ priv_book_emit_text()

bool priv_book_emit_text ( char * out,
size_t cap,
size_t * pos,
const char * str,
bool * at_break )

Append a whitespace-collapsed text run to the output buffer.

Iterates over str character by character applying the HTML whitespace-collapsing rule: any run of space (' '), tab ('\t'), carriage return ('\r'), or newline ('\n') characters is folded into at most a single ASCII space. Non-whitespace characters are passed through unchanged via internal_emit. The at_break flag carries inter-call state: when true any leading whitespace in the current fragment is silently dropped, preventing pretty-print indentation between inline elements from leaking into the rendered prose. at_break is set to true after a whitespace run is emitted and set to false after any non-whitespace character is emitted.

Parameters
[out]outDestination character buffer.
[in]capTotal capacity of out in bytes.
[in,out]posCurrent write offset; advanced for each byte written.
[in]strNUL-terminated text fragment to collapse and append.
[in,out]at_breakOn entry: true if the previous output ended with a break or collapsed space that suppresses leading whitespace. On exit: updated to reflect the trailing state of this fragment.
Returns
bool Append result.
Return values
trueText run appended successfully (or was entirely suppressed whitespace).
falseOutput buffer overflowed; partial output may have been written.
Precondition
out is a valid, writable buffer of at least cap bytes.
str is a valid, NUL-terminated C string.
Postcondition
On success every character in str has been processed and *pos reflects the bytes appended to out.
*at_break accurately reflects the trailing whitespace state after the call, regardless of success or failure.
Note
Not thread-safe; callers must provide external synchronisation.
Since
Version 0.1.0

Definition at line 526 of file book_xhtml.c.

References internal_emit().

Referenced by internal_paged_emit_run(), and internal_walk_text().

◆ priv_book_is_block()

bool priv_book_is_block ( const char * name)

Test whether an element name is a block-level HTML element.

Performs a linear search through a fixed table of block-level element names used to decide where to insert paragraph-break newlines during plain-text extraction. The checked names are: p, h1, h2, h3, h4, h5, h6, li, ul, ol, div, br, hr, section, tr, pre, header, blockquote, article, aside, footer, figure, and figcaption. The comparison is case-sensitive because compiled book DOM names are lower-cased during parsing.

Parameters
[in]nameNUL-terminated element name to test (e.g. "p").
Returns
bool Query result.
Return values
truename is a block-level element; the text walker should emit a line break before descending into this element.
falsename is an inline element; no break is inserted.
Precondition
name is a valid, NUL-terminated C string.
name contains only lower-case ASCII letters (DOM invariant).
Postcondition
The block-element table is not modified.
The return value is purely a function of name with no side effects.
Note
Not thread-safe; callers must provide external synchronisation.
Since
Version 0.1.0

Definition at line 470 of file book_xhtml.c.

References RA8_PRIV, and strcmp().

Referenced by internal_paged_visit_node(), and internal_walk_text().

Variable Documentation

◆ s_tag_xhtml

const char* const s_tag_xhtml = "book_xhtml"
static

Log tag for serializer diagnostics.

Definition at line 32 of file book_xhtml.c.

Referenced by book_chapter_text(), and book_chapter_to_xhtml().