26typedef enum : uint16_t {
42 (void)
xml_decode_prefix(source, source_len, span, destination, capacity, &ignored);
52 for (uint16_t i = 0U; i <
event->attribute_count; ++i) {
80 return strstr(value, needle) !=
nullptr;
91 const uint16_t parent_depth = parent;
92 if (parent_depth == UINT16_MAX) {
95 return child == (uint16_t)(parent_depth + 1U);
100 uint16_t frame = depth;
101 uint16_t remaining = levels;
102 while (remaining > 0U) {
122 const uint8_t* source,
134 uint32_t parent_offset,
135 uint16_t parent_depth,
140 bool parent_active =
false;
147 if (use_parent && (event.kind == (uint8_t)
k_xml_event_start) && (event.depth == parent_depth) &&
148 (event.markup.offset == parent_offset)) {
149 parent_active =
true;
158 }
else if (use_parent && parent_active && (event.kind == (uint8_t)
k_xml_event_end) &&
159 (event.depth == parent_depth)) {
173 if ((xml_bytes ==
nullptr) || (out ==
nullptr) || (workspace ==
nullptr)) {
182 err =
priv_epub_xml_find(xml_bytes, xml_len, workspace,
"rootfiles",
false, 0U, 0U, &rootfiles);
195 err =
priv_epub_xml_find(xml_bytes, xml_len, workspace,
"rootfile",
false, 0U, 0U, &rootfile);
214 static const char*
const types[] = {
"application/font-sfnt",
215 "application/vnd.ms-opentype",
218 "application/x-font-ttf"};
219 for (
size_t i = 0U; i < (
sizeof(types) /
sizeof(types[0])); ++i) {
276 if (event->
depth == 0U) {
314 if (
id.present && (unique_id.
length > 0U) &&
328 return ((err ==
k_ra8_ok) && ((manifest_depth == UINT16_MAX) || (spine_depth == UINT16_MAX)))
401 uint16_t* metadata_depth,
402 uint16_t* manifest_depth,
403 uint16_t* spine_depth,
407 if (event->
depth == 0U) {
410 }
else if ((event->
depth == 1U) &&
412 *metadata_depth =
event->depth;
413 }
else if ((event->
depth == 1U) &&
415 *manifest_depth =
event->depth;
417 *spine_depth =
event->depth;
445 uint16_t metadata_depth = UINT16_MAX;
446 uint16_t manifest_depth = UINT16_MAX;
447 uint16_t spine_depth = UINT16_MAX;
483 uint16_t spine_depth = UINT16_MAX;
496 spine_depth =
event.depth;
527 uint16_t manifest_depth = UINT16_MAX;
539 manifest_depth =
event.depth;
548 *out_href = href.
span;
563 bool saw_manifest =
false;
564 bool saw_spine =
false;
565 uint16_t spine_depth = UINT16_MAX;
566 uint16_t references = 0U;
581 spine_depth =
event.depth;
594 if ((err ==
k_ra8_ok) && (!saw_manifest || !saw_spine)) {
679 if ((xml_bytes ==
nullptr) || (book ==
nullptr)) {
@ k_epub_max_manifest
Max <manifest> <item> entries kept (OPF order).
@ k_epub_max_fonts
Max embedded font manifest items kept.
@ k_epub_max_chapters
Max spine length we accept.
@ k_epub_max_path_len
Max href length (incl.
@ k_epub_toc_ncx
Parsed from an EPUB 2 NCX document.
@ k_epub_toc_nav
Parsed from an EPUB 3 nav.xhtml.
Private contracts for streamed EPUB XML consumers.
bool priv_epub_xml_attr_contains(const uint8_t *source, size_t source_len, priv_attr_t attribute, const char *needle)
Test whether a decoded attribute contains an ASCII literal.
priv_attr_t priv_epub_xml_attr(const uint8_t *source, size_t source_len, const xml_event_t *event, const char *name)
Find an exact-name attribute on one start event.
Private contracts for the EPUB container and OPF consumers.
static bool internal_font_type(const uint8_t *source, size_t source_len, priv_attr_t media)
Recognise one supported embedded-font media type.
void priv_epub_xml_copy(const uint8_t *source, size_t source_len, xml_span_t span, char *destination, size_t capacity)
Copy decoded text into a bounded EPUB field.
static ra8_err_t internal_manifest_lookup(const uint8_t *source, size_t length, epub_xml_workspace_t *workspace, xml_span_t wanted, xml_span_t *out_href)
xml_span_t priv_epub_xml_frame_name(const xml_reader_t *reader, uint16_t frame)
Return one live reader-frame name span.
static void internal_mark_metadata(const uint8_t *source, size_t source_len, const xml_event_t *event, xml_reader_t *reader, xml_span_t unique_id)
bool priv_epub_xml_ancestor_frame(uint16_t depth, uint16_t levels, uint16_t *out_frame)
Resolve a bounded ancestor frame index.
static void internal_opf_first_event(const uint8_t *source, size_t length, const xml_event_t *event, xml_reader_t *reader, epub_book_t *book, uint16_t *metadata_depth, uint16_t *manifest_depth, uint16_t *spine_depth, xml_span_t *unique_id, xml_span_t *out_spine_toc)
Classify one OPF start-tag event during the first parse pass.
uint16_t priv_epub_xml_ancestor_marker(const xml_reader_t *reader, uint16_t depth, uint16_t levels)
Return a checked ancestor consumer marker.
ra8_err_t priv_epub_xml_parse_container(const uint8_t *xml_bytes, size_t xml_len, epub_container_result_t *out, epub_xml_workspace_t *workspace)
Parse META-INF/container.xml and copy the rootfile path out.
static ra8_err_t internal_opf_resolve_refs(const uint8_t *xml_bytes, size_t xml_len, xml_span_t spine_toc, epub_book_t *book)
Resolve chapter, cover, and TOC hrefs from cross-referenced ids.
static ra8_err_t internal_opf_status(ra8_err_t err, uint16_t manifest_depth, uint16_t spine_depth)
static ra8_err_t internal_opf_first(const uint8_t *source, size_t length, epub_book_t *book, xml_span_t *out_spine_toc)
static void internal_opf_metadata_child(const uint8_t *source, size_t length, const xml_event_t *event, xml_reader_t *reader, xml_span_t unique_id, epub_book_t *book)
Record one direct metadata child of the OPF metadata element.
static ra8_err_t internal_opf_shape(const uint8_t *source, size_t length, epub_xml_workspace_t *workspace)
static ra8_err_t internal_collect_spine(const uint8_t *source, size_t length, epub_book_t *book)
ra8_err_t priv_epub_xml_find(const uint8_t *source, size_t length, epub_xml_workspace_t *workspace, const char *local, bool use_parent, uint32_t parent_offset, uint16_t parent_depth, xml_event_t *out)
Find the first local-name element under an optional direct parent.
ra8_err_t priv_epub_xml_reader(xml_reader_t *reader, const uint8_t *source, size_t length, epub_xml_workspace_t *workspace)
Initialise another validated EPUB pull pass.
bool priv_epub_xml_attr_contains(const uint8_t *source, size_t source_len, priv_attr_t attribute, const char *needle)
Test whether a decoded attribute contains an ASCII literal.
static void internal_metadata_text(const uint8_t *source, size_t source_len, const xml_event_t *event, const xml_reader_t *reader, epub_book_t *book)
bool priv_epub_xml_direct_child(uint16_t child, uint16_t parent)
Test whether a depth is exactly one level below another.
static void internal_manifest_item(const uint8_t *source, size_t source_len, const xml_event_t *event, epub_book_t *book)
static bool internal_font_type(const uint8_t *source, size_t source_len, priv_attr_t media)
ra8_err_t priv_epub_xml_parse_opf(const uint8_t *xml_bytes, size_t xml_len, epub_book_t *book)
Parse the OPF document into metadata, cover and spine.
priv_attr_t priv_epub_xml_attr(const uint8_t *source, size_t source_len, const xml_event_t *event, const char *name)
Find an exact-name attribute on one start event.
priv_marker_t
Consumer markers stored in live reader frames.
@ k_priv_mark_identifier
Frame is a fallback identifier.
@ k_priv_mark_creator
Frame is a Dublin Core creator.
@ k_priv_mark_language
Frame is a Dublin Core language.
@ k_priv_mark_identifier_match
Frame matches the package identifier.
@ k_priv_mark_none
Frame carries no metadata role.
@ k_priv_mark_title
Frame is a Dublin Core title.
Library-private contract for the bounded EPUB XML parser.
Annotation-attribute framework macros for ra8-firmware.
#define RA8_INTERNAL
Marker that a function is intended to be static (file-local).
@ k_ra8_err_no_mem
Static buffer exhausted (no dynamic memory on this project).
@ k_ra8_err_no_data
No application data available (e.g.
@ k_ra8_err_validation_failed
Validation rule failed (caller-supplied invariant not satisfied).
@ k_ra8_ok
Success – operation completed with all postconditions satisfied.
@ k_ra8_err_null_ptr
Pointer was NULL where a valid pointer was required.
@ k_ra8_err_invalid_size
Invalid size parameter (too large, too small, or misaligned).
ra8_err_codes_t ra8_err_t
Canonical error-return type used by every ra8-firmware API.
char * strstr(const char *haystack, const char *needle)
Locate substring in string.
char author[k_epub_meta_len]
Dublin Core <dc:creator>.
char toc_path[k_epub_max_path_len]
Nav/NCX href (rel.
char chapter_paths[k_epub_max_chapters][k_epub_max_path_len]
Manifest hrefs (relative to OPF dir).
char language[k_epub_meta_len]
Dublin Core <dc:language>.
char cover_path[k_epub_max_path_len]
Path to cover image (or empty).
uint16_t chapter_count
Spine length actually stored.
epub_xml_workspace_t xml_workspace
Per-book XML parser state; never shared with another book.
char title[k_epub_meta_len]
Dublin Core <dc:title>.
uint8_t toc_kind
epub_toc_kind_t: source of the TOC.
epub_manifest_item_t manifest[k_epub_max_manifest]
Items, OPF order.
uint16_t embedded_font_count
Manifest font items found (<= cap).
uint16_t manifest_count
<manifest> <item> entries stored (<= cap).
char identifier[k_epub_meta_len]
Dublin Core <dc:identifier> (unique book id).
char embedded_font_paths[k_epub_max_fonts][k_epub_max_path_len]
Font hrefs (rel.
Out-parameter struct returned by priv_epub_xml_parse_container().
char opf_path[k_epub_max_path_len]
Rootfile path, NUL-terminated.
One <manifest> <item> entry, retained in OPF document order.
char media_type[k_epub_media_len]
Item media-type (or "" if absent).
char id[k_epub_id_len]
Manifest item id (or "" if absent).
char href[k_epub_max_path_len]
Item href (relative to the OPF dir).
Per-book bounded storage for strict OPF/container/TOC parsing.
xml_workspace_t reader
4096-byte open-element stack.
xml_span_t references[k_epub_max_chapters]
Spine idref spans retained between OPF passes.
xml_span_t legacy_cover_id
EPUB 2 cover manifest id.
uint16_t reference_count
Valid entries in references.
xml_span_t span
Value span.
bool present
Attribute existed.
Mutable cursor for one start event's attributes.
Source-order attribute view.
xml_span_t value
Quoted value excluding delimiters.
xml_span_t name
Attribute name.
xml_span_t markup
Complete markup span, or text payload.
xml_span_t name
Element name for start/end.
uint16_t depth
Root is depth zero.
One open-element identity retained for close-tag validation.
uint16_t consumer
Consumer-owned while this frame is live.
uint16_t name_length
Element-name byte count.
uint32_t name_offset
Element-name offset in the source.
Pull-reader state; initialise before each pass.
xml_workspace_t * workspace
Caller-owned stack.
Immutable byte span expressed relative to the source.
uint32_t length
Byte count.
uint32_t offset
First byte offset.
xml_frame_t frames[k_xml_workspace_frames]
Open-element stack.
Bounded, caller-owned, no-heap XML pull reader.
bool xml_decoded_equal(const uint8_t *source, size_t source_len, xml_span_t left, xml_span_t right)
Compare two entity-decoded spans from the same immutable source.
void xml_attr_begin(const xml_event_t *event, xml_attr_cursor_t *cursor)
Initialise source-order attribute iteration for a start event.
bool xml_span_local_equal(const uint8_t *source, size_t source_len, xml_span_t span, const char *literal)
Compare the namespace-local tail of a bounded span with an ASCII literal.
ra8_err_t xml_attr_next(const uint8_t *source, size_t source_len, const xml_event_t *event, xml_attr_cursor_t *cursor, xml_attribute_t *out_attribute, bool *out_has_value)
Return the next source-order attribute.
@ k_xml_event_start
Element start.
@ k_xml_event_none
No event / end of source.
@ k_xml_event_text
Character-data run.
@ k_xml_event_end
Element end.
ra8_err_t xml_validate(const uint8_t *source, size_t source_len, xml_workspace_t *workspace)
Validate a complete document before any consumer mutation.
bool xml_span_equal(const uint8_t *source, size_t source_len, xml_span_t span, const char *literal)
Compare a bounded span with an exact ASCII literal.
ra8_err_t xml_decode(const uint8_t *source, size_t source_len, xml_span_t span, char *destination, size_t capacity, size_t *out_length)
Entity-decode a source span into a bounded NUL-terminated buffer.
ra8_err_t xml_reader_init(xml_reader_t *reader, const uint8_t *source, size_t source_len, xml_workspace_t *workspace)
Initialise a pull pass over immutable bytes.
ra8_err_t xml_reader_next(xml_reader_t *reader, xml_event_t *out_event)
Return the next semantic event and validate syntax incrementally.
ra8_err_t xml_decode_prefix(const uint8_t *source, size_t source_len, xml_span_t span, char *destination, size_t capacity, size_t *out_length)
Decode the longest complete prefix that fits the destination.