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

EPUB (.epub) reader and chapter iterator for ra8-firmware. More...

#include <stdalign.h>
#include <stddef.h>
#include <stdint.h>
#include "epub_miniz_alloc.h"
#include "ra8_err.h"
#include "xml.h"
Include dependency graph for epub.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  epub_xml_workspace_t
 Per-book bounded storage for strict OPF/container/TOC parsing. More...
struct  epub_toc_entry_t
 One titled entry in the table of contents. More...
struct  epub_mem_media_t
 In-memory EPUB media descriptor. More...
struct  epub_stream_media_t
 Seekable EPUB media descriptor – opens with no whole-file residency (#151). More...
struct  epub_manifest_item_t
 One <manifest> <item> entry, retained in OPF document order. More...
struct  epub_book_t
 Opened EPUB book. More...
 Dublin Core metadata bundle returned by epub_get_metadata(). More...

Typedefs

typedef size_t(* epub_stream_read_fn) (void *ctx, uint64_t offset, void *buf, size_t len)
 Seek+read callback backing a streamed (non-resident) EPUB open (#151).

Enumerations

enum  epub_limits_t : uint16_t {
  k_epub_max_chapters = 64 ,
  k_epub_max_toc = 64 ,
  k_epub_max_path_len = 192 ,
  k_epub_meta_len = 128 ,
  k_epub_max_fonts = 8 ,
  k_epub_max_manifest = 96 ,
  k_epub_id_len = 64 ,
  k_epub_media_len = 48 ,
  k_epub_zip_archive_bytes
}
 Static-allocation caps for the EPUB reader. More...
enum  epub_toc_kind_t : uint8_t {
  k_epub_toc_none = 0 ,
  k_epub_toc_ncx = 1 ,
  k_epub_toc_nav = 2
}
 Which navigation document the table of contents was parsed from. More...
enum  epub_render_t : uint8_t { k_epub_render_alpha8 = 0 }
 Pixel-format selectors for epub_render_glyph(). More...

Functions

ra8_err_t epub_open (const void *media, const char *path, epub_book_t *out_book)
 Open an EPUB book from an opaque media handle.
ra8_err_t epub_open_streamed (const epub_stream_media_t *media, const char *path, epub_book_t *out_book)
 Open an EPUB book from a seekable stream, with no whole-file residency (#151).
ra8_err_t epub_close (epub_book_t *book)
 Close a previously opened EPUB book.
ra8_err_t epub_get_chapter_count (const epub_book_t *book, uint16_t *out_count)
 Report how many chapters the spine contains.
ra8_err_t epub_load_chapter (epub_book_t *book, uint16_t idx, uint8_t *out_xhtml, size_t max_len, size_t *got_len)
 Extract the raw XHTML bytes of one chapter into the caller's buffer.
ra8_err_t epub_get_toc_kind (const epub_book_t *book, uint8_t *out_kind)
 Report which navigation document the TOC was parsed from.
ra8_err_t epub_get_toc_count (const epub_book_t *book, uint16_t *out_count)
 Report how many table-of-contents entries the book exposes.
ra8_err_t epub_get_toc_entry (const epub_book_t *book, uint16_t idx, epub_toc_entry_t *out_entry)
 Copy one table-of-contents entry into the caller's struct.
ra8_err_t epub_toc_entry_to_chapter (const epub_book_t *book, uint16_t toc_idx, uint16_t *out_chapter_idx)
 Resolve a TOC entry to the spine chapter index it points into.
ra8_err_t epub_get_metadata (const epub_book_t *book, epub_metadata_t *out_meta)
 Return Dublin Core metadata strings.
ra8_err_t epub_get_cover_image (epub_book_t *book, uint8_t *out_buf, size_t max_len, size_t *got_len)
 Copy the raw bytes of the cover image into the caller's buffer.
ra8_err_t epub_get_resource (epub_book_t *book, const char *path, uint8_t *out_buf, size_t max_len, size_t *got_len)
 Copy the raw bytes of an arbitrary archive resource into the caller's buffer (#140 external stylesheets, and any href-referenced resource).
uint16_t epub_manifest_count (const epub_book_t *book)
 Number of <manifest> <item> entries retained (#151).
const epub_manifest_item_tepub_manifest_item (const epub_book_t *book, uint16_t index)
 Borrow the manifest item at index (OPF document order, #151).
ra8_err_t epub_get_embedded_font_count (const epub_book_t *book, uint16_t *out_count)
 Count the fonts the EPUB ships in its OPF manifest (#109).
ra8_err_t epub_get_embedded_font (epub_book_t *book, uint16_t idx, uint8_t *out_buf, size_t max_len, size_t *got_len)
 Extract one EPUB-shipped font's bytes into a caller buffer (#109).
ra8_err_t epub_set_font (epub_book_t *book, const uint8_t *font_data, size_t font_size)
 Attach a TTF font blob to be used by epub_render_glyph().
ra8_err_t epub_render_glyph (const epub_book_t *book, int32_t codepoint, float font_size, uint8_t *out_bitmap, size_t max_pixels, uint32_t *out_w, uint32_t *out_h)
 Rasterise a single Unicode code point into an alpha-8 bitmap.

Detailed Description

EPUB (.epub) reader and chapter iterator for ra8-firmware.

epub is a small, dependency-light domain layer that opens an EPUB (.epub) file and exposes an iterator over its chapters, plus a handful of metadata accessors and a glyph rasteriser that reaches through to stb_truetype.

Internally epub:

  1. Treats the .epub as a ZIP container and reads the central directory via miniz (mz_zip_reader_init_mem).
  2. Locates META-INF/container.xml, parses it with the bounded XML reader, and follows the <rootfile full-path="..."> to the OPF document (typically OEBPS/content.opf).
  3. Parses the OPF manifest + spine to build a fixed-size, statically-allocated chapter list (k_epub_max_chapters).
  4. Pulls the Dublin Core metadata block (<dc:title>, <dc:creator>, <dc:language>) into the book record.
  5. Resolves the cover-image manifest item (or the legacy <meta name="cover" content="...">) and exposes its raw bytes so the caller can decode them with stb_image.

The media parameter to epub_open() is intentionally opaque:

  • On the host unit-test build, media points at an epub_mem_media_t describing an in-memory .epub blob.
  • On the target firmware, the caller reads the entire .epub off the mounted filesystem (ra8_fs_read()) into a caller-owned buffer before handing it to epub_open().

Static-allocation footprint

  • Chapter list: k_epub_max_chapters * k_epub_max_path_len
  • Metadata: 3 * k_epub_meta_len
  • Backing zip: one mz_zip_archive embedded in the book record.
  • ZIP allocator: one caller-owned, per-book bounded miniz workspace.
  • Font slot: one (uint8_t* font_data, size_t font_len) pair.

NASA Rule 3 (zero malloc/free in firmware) is honored: the book record holds the entire mz_zip_archive and its allocator workspace inline, the OPF scratch is a single static slot, and the chapter table is a fixed-size 2D array. The same bounded allocator is used on host and target.

[Ring 4 / EPUB] {World: NS}

Definition in file epub.h.

Typedef Documentation

◆ epub_stream_read_fn

typedef size_t(* epub_stream_read_fn) (void *ctx, uint64_t offset, void *buf, size_t len)

Seek+read callback backing a streamed (non-resident) EPUB open (#151).

The storage seam for epub_open_streamed(): the reader hands the callback an absolute byte offset into the .epub archive and asks for len bytes. The callback is free to seek+read from any backing – an ra8_fs file on the SD card, an ra8_io block device, or a page cache (ra8_vmem) – so the reader never needs the whole archive resident. Only the ZIP tail (end-of-central- directory + central directory) and one entry at a time are ever fetched, so a multi-GB book opens inside a fixed, small RAM budget.

The signature deliberately mirrors miniz's mz_file_read_func (offset+length, bytes-actually-read return) so the reader can drive miniz directly with no copy: a return < len is treated as end-of-file / read error, exactly as the in-memory path treats a short read.

Parameters
[in]ctxOpaque backing context (epub_stream_media_t::ctx).
[in]offsetAbsolute byte offset within the .epub archive.
[out]bufDestination buffer (len writable bytes).
[in]lenNumber of bytes requested.
Returns
Bytes actually read (0 at/after EOF or on error; < len aborts).
Note
Not thread-safe; the reader serialises access.
Since
0.1.0

Definition at line 212 of file epub.h.

Enumeration Type Documentation

◆ epub_limits_t

enum epub_limits_t : uint16_t

Static-allocation caps for the EPUB reader.

The reader holds at most k_epub_max_chapters chapter entries; an EPUB with a longer spine is truncated and epub_open() returns k_ra8_err_no_mem. k_epub_max_path_len covers the longest <item href="..."> string we can store; k_epub_meta_len is the cap for any single Dublin Core metadata field (title, creator, language).

Enumerator
k_epub_max_chapters 

Max spine length we accept.

k_epub_max_toc 

Max table-of-contents entries we keep.

k_epub_max_path_len 

Max href length (incl.

NUL).

k_epub_meta_len 

Max bytes per metadata field.

k_epub_max_fonts 

Max embedded font manifest items kept.

k_epub_max_manifest 

Max <manifest> <item> entries kept (OPF order).

k_epub_id_len 

Max manifest item id length (incl.

NUL).

k_epub_media_len 

Max media-type length (incl.

NUL).

k_epub_zip_archive_bytes 

Storage for mz_zip_archive (miniz 3.0.2 sizeof=112; margin; static_assert in .c).

Definition at line 86 of file epub.h.

◆ epub_render_t

enum epub_render_t : uint8_t

Pixel-format selectors for epub_render_glyph().

Currently the reader exposes a single 8-bit grayscale rasteriser; the enum exists so future backends (subpixel-AA, MVE-vectorised) can be added without changing the public function signature.

Enumerator
k_epub_render_alpha8 

8 bits per pixel, alpha mask.

Definition at line 157 of file epub.h.

◆ epub_toc_kind_t

enum epub_toc_kind_t : uint8_t

Which navigation document the table of contents was parsed from.

EPUB 2 books ship an NCX (toc.ncx, referenced by the spine's toc attribute); EPUB 3 books ship an XHTML navigation document (the manifest item carrying properties="nav"). When both are present the reader prefers the EPUB 3 nav document. k_epub_toc_none means no usable TOC was found (the book is still readable via the spine).

Enumerator
k_epub_toc_none 

No table of contents parsed.

k_epub_toc_ncx 

Parsed from an EPUB 2 NCX document.

k_epub_toc_nav 

Parsed from an EPUB 3 nav.xhtml.

Definition at line 124 of file epub.h.

Function Documentation

◆ epub_close()

ra8_err_t epub_close ( epub_book_t * book)
nodiscard

Close a previously opened EPUB book.

Parameters
[in,out]bookBook opened by epub_open().
Return values
k_ra8_okBook closed and slot released.
k_ra8_err_null_ptrbook is NULL.
k_ra8_err_not_initializedbook->in_use == 0.
Precondition
book non-NULL.
book->in_use == 1.
Postcondition
book->in_use == 0.
book->zip_archive == NULL.
Since
0.1.0

Definition at line 507 of file epub_open.c.

References epub_book_t::chapter_count, epub_miniz_arena_deinit(), epub_book_t::in_use, internal_zip_destroy(), k_ra8_err_not_initialized, k_ra8_err_null_ptr, k_ra8_ok, epub_book_t::miniz_arena, epub_book_t::zip_archive_active, and epub_book_t::zip_archive_storage.

Referenced by compile_fixture(), internal_close_compile_sources(), and rabook_import_compile_adapter().

◆ epub_get_chapter_count()

ra8_err_t epub_get_chapter_count ( const epub_book_t * book,
uint16_t * out_count )
nodiscard

Report how many chapters the spine contains.

Parameters
[in]bookOpen book.
[out]out_countChapter count.
Return values
k_ra8_okReported.
k_ra8_err_null_ptrAny pointer NULL.
k_ra8_err_not_initializedbook->in_use == 0.
Precondition
book non-NULL, out_count non-NULL.
Postcondition
*out_count <= k_epub_max_chapters.
Since
0.1.0

Definition at line 310 of file epub_chapter.c.

References epub_book_t::chapter_count, epub_book_t::in_use, k_ra8_err_not_initialized, k_ra8_err_null_ptr, and k_ra8_ok.

Referenced by eoh_parse_or_halt(), ep_parse_or_halt(), est_open_or_halt(), etoc_check_bad(), internal_compile_chapters(), and sh_book_open().

◆ epub_get_cover_image()

ra8_err_t epub_get_cover_image ( epub_book_t * book,
uint8_t * out_buf,
size_t max_len,
size_t * got_len )
nodiscard

Copy the raw bytes of the cover image into the caller's buffer.

The image is returned in its on-disk encoding (PNG / JPEG / GIF). The caller decodes it with stb_image (see apps/shared_libs/third_party/stb) or any other decoder.

Parameters
[in]bookOpen book.
[out]out_bufDestination buffer.
[in]max_lenCapacity of out_buf, bytes.
[out]got_lenBytes actually written.
Return values
k_ra8_okCover copied.
k_ra8_err_null_ptrAny pointer NULL.
k_ra8_err_not_initializedbook->in_use == 0.
k_ra8_err_invalid_sizemax_len == 0.
k_ra8_err_not_foundNo cover image declared.
k_ra8_err_no_memCover does not fit in max_len.
Since
0.1.0

Definition at line 444 of file epub_chapter.c.

References epub_book_t::cover_path, epub_book_t::in_use, internal_locate_extract(), k_epub_max_path_len, k_ra8_err_invalid_size, k_ra8_err_not_found, k_ra8_err_not_initialized, k_ra8_err_null_ptr, epub_book_t::opf_dir, priv_epub_book_not_ready(), priv_epub_join_path(), epub_book_t::zip_archive_active, and epub_book_t::zip_archive_storage.

Referenced by ec_render_cover_or_halt(), sh_book_cover_fullscreen(), and sh_epub_thumb().

◆ epub_get_embedded_font()

ra8_err_t epub_get_embedded_font ( epub_book_t * book,
uint16_t idx,
uint8_t * out_buf,
size_t max_len,
size_t * got_len )
nodiscard

Extract one EPUB-shipped font's bytes into a caller buffer (#109).

Joins the recorded font href onto the OPF directory and extracts the resource from the open ZIP (same path as epub_get_cover_image()). The returned bytes can be validated + bound into the reflow engine via reflow_bind_font(), or attached with epub_set_font().

Parameters
[in,out]bookOpen book.
[in]idxFont index, 0 .. epub_get_embedded_font_count()-1.
[out]out_bufDestination buffer for the raw font bytes.
[in]max_lenCapacity of out_buf, bytes.
[out]got_lenBytes actually written.
Returns
ra8_err_t Error code.
Return values
k_ra8_okFont copied; *got_len > 0.
k_ra8_err_null_ptrbook, out_buf, or got_len is NULL.
k_ra8_err_not_initializedbook->in_use == 0.
k_ra8_err_invalid_sizemax_len == 0.
k_ra8_err_out_of_rangeidx >= embedded_font_count.
k_ra8_err_no_memFont does not fit in max_len.
k_ra8_err_not_foundRecorded font href missing from the archive.
Precondition
book->in_use == 1 and idx < epub_get_embedded_font_count().
out_buf and got_len are non-NULL, max_len > 0.
Postcondition
On success *got_len holds the font length; on failure *got_len == 0.
Note
Not thread-safe; single-threaded init-context use.
See also
epub_get_embedded_font_count(), reflow_bind_font()
Since
0.1.0

Definition at line 527 of file epub_chapter.c.

References epub_book_t::embedded_font_count, epub_book_t::embedded_font_paths, epub_book_t::in_use, internal_locate_extract(), k_epub_max_path_len, k_ra8_err_invalid_size, k_ra8_err_not_initialized, k_ra8_err_null_ptr, k_ra8_err_out_of_range, epub_book_t::opf_dir, priv_epub_book_not_ready(), priv_epub_join_path(), epub_book_t::zip_archive_active, and epub_book_t::zip_archive_storage.

◆ epub_get_embedded_font_count()

ra8_err_t epub_get_embedded_font_count ( const epub_book_t * book,
uint16_t * out_count )
nodiscard

Count the fonts the EPUB ships in its OPF manifest (#109).

During epub_open() the manifest is scanned for <item> entries whose media-type is a known font type (application/font-sfnt, application/vnd.ms-opentype, font/ttf, font/otf, application/x-font-ttf); their hrefs are recorded (up to k_epub_max_fonts). This returns how many were found so the caller can iterate epub_get_embedded_font(). Zero is normal – many books rely on the reading-system font.

Parameters
[in]bookOpen book.
[out]out_countReceives the embedded font count (0 .. k_epub_max_fonts).
Returns
ra8_err_t Error code.
Return values
k_ra8_okCount written.
k_ra8_err_null_ptrbook or out_count is NULL.
k_ra8_err_not_initializedbook->in_use == 0.
Precondition
book->in_use == 1.
out_count is non-NULL.
Postcondition
*out_count <= k_epub_max_fonts.
book is unmodified.
Note
Not thread-safe; single-threaded init-context use.
See also
epub_get_embedded_font()
Since
0.1.0

Definition at line 493 of file epub_chapter.c.

References epub_book_t::embedded_font_count, epub_book_t::in_use, k_ra8_err_not_initialized, k_ra8_err_null_ptr, and k_ra8_ok.

◆ epub_get_metadata()

ra8_err_t epub_get_metadata ( const epub_book_t * book,
epub_metadata_t * out_meta )
nodiscard

Return Dublin Core metadata strings.

The returned const char* pointers alias book storage and are valid until epub_close() is called. Missing fields point at the empty string "", never NULL.

Parameters
[in]bookOpen book.
[out]out_metaPopulated metadata struct on success.
Return values
k_ra8_okReported.
k_ra8_err_null_ptrAny pointer NULL.
k_ra8_err_not_initializedbook->in_use == 0.
Since
0.1.0

Definition at line 429 of file epub_chapter.c.

References epub_book_t::author, epub_metadata_t::author, epub_book_t::identifier, epub_metadata_t::identifier, epub_book_t::in_use, k_ra8_err_not_initialized, k_ra8_err_null_ptr, k_ra8_ok, epub_book_t::language, epub_metadata_t::language, epub_book_t::title, and epub_metadata_t::title.

Referenced by eoh_parse_or_halt(), ep_parse_or_halt(), internal_compile_metadata(), and sh_book_capture_meta().

◆ epub_get_resource()

ra8_err_t epub_get_resource ( epub_book_t * book,
const char * path,
uint8_t * out_buf,
size_t max_len,
size_t * got_len )
nodiscard

Copy the raw bytes of an arbitrary archive resource into the caller's buffer (#140 external stylesheets, and any href-referenced resource).

Generic by-path extraction from the open ZIP – the same path the cover, embedded fonts, and chapters use. path is resolved relative to the OPF directory (book->opf_dir), with a fall-back to path taken as an archive-rooted path; so "style.css", "css/main.css", and a bare "OEBPS/style.css" all resolve. The bytes are returned exactly as stored (decompressed); the caller owns out_buf and interprets them (e.g. CSS text fed to ra8_css_parse() via a reflow css-loader).

Parameters
[in]bookOpen book (in_use == 1, archive active).
[in]pathResource path, OPF-dir-relative or archive-rooted, NUL-terminated.
[out]out_bufDestination buffer.
[in]max_lenCapacity of out_buf, bytes.
[out]got_lenBytes actually written.
Return values
k_ra8_okResource copied.
k_ra8_err_null_ptrAny pointer NULL.
k_ra8_err_not_initializedBook not open / archive inactive.
k_ra8_err_invalid_sizemax_len == 0.
k_ra8_err_not_foundNo entry at path (prefixed or bare).
k_ra8_err_no_memResource does not fit in max_len.
Precondition
book->in_use == 1 and the archive is active.
path, out_buf, got_len are non-NULL; max_len > 0.
Postcondition
On success *got_len bytes are written to out_buf.
On any error *got_len == 0.
Note
Not thread-safe; single-threaded reader context.
See also
epub_get_cover_image(), epub_get_embedded_font()
Since
0.1.0

Definition at line 468 of file epub_chapter.c.

References epub_book_t::in_use, internal_locate_extract(), k_epub_max_path_len, k_ra8_err_invalid_size, k_ra8_err_not_initialized, k_ra8_err_null_ptr, epub_book_t::opf_dir, priv_epub_book_not_ready(), priv_epub_join_path(), epub_book_t::zip_archive_active, and epub_book_t::zip_archive_storage.

Referenced by internal_add_manifest_image(), and internal_compile_stylesheets().

◆ epub_get_toc_count()

ra8_err_t epub_get_toc_count ( const epub_book_t * book,
uint16_t * out_count )
nodiscard

Report how many table-of-contents entries the book exposes.

The count is the flattened (depth-first) entry total parsed from the book's NCX or nav document; 0 means no usable TOC was found. Use epub_get_toc_entry() to read each entry's title, href, and depth.

Parameters
[in]bookOpen book.
[out]out_countEntry count.
Returns
ra8_err_t
Return values
k_ra8_okReported.
k_ra8_err_null_ptrAny pointer NULL.
k_ra8_err_not_initializedbook->in_use == 0.
Precondition
book non-NULL, out_count non-NULL.
book->in_use == 1.
Postcondition
*out_count <= k_epub_max_toc.
Since
0.1.0

Definition at line 367 of file epub_chapter.c.

References epub_book_t::in_use, k_ra8_err_not_initialized, k_ra8_err_null_ptr, k_ra8_ok, and epub_book_t::toc_count.

Referenced by est_open_or_halt(), etoc_read_toc(), internal_compile_chapters(), and sh_epub_label().

◆ epub_get_toc_entry()

ra8_err_t epub_get_toc_entry ( const epub_book_t * book,
uint16_t idx,
epub_toc_entry_t * out_entry )
nodiscard

Copy one table-of-contents entry into the caller's struct.

Parameters
[in]bookOpen book.
[in]idxEntry index, [0, toc_count).
[out]out_entryDestination entry (title, href, depth) on success.
Returns
ra8_err_t
Return values
k_ra8_okEntry copied.
k_ra8_err_null_ptrAny pointer NULL.
k_ra8_err_not_initializedbook->in_use == 0.
k_ra8_err_out_of_rangeidx >= toc_count.
Precondition
book non-NULL, out_entry non-NULL.
book->in_use == 1.
Postcondition
On success, *out_entry is a NUL-terminated, bounded copy.
On failure, *out_entry is left unmodified.
Since
0.1.0

Definition at line 379 of file epub_chapter.c.

References epub_book_t::in_use, k_ra8_err_not_initialized, k_ra8_err_null_ptr, k_ra8_err_out_of_range, k_ra8_ok, epub_book_t::toc, and epub_book_t::toc_count.

Referenced by etoc_read_toc(), internal_chapter_title(), and sh_epub_label().

◆ epub_get_toc_kind()

ra8_err_t epub_get_toc_kind ( const epub_book_t * book,
uint8_t * out_kind )
nodiscard

Report which navigation document the TOC was parsed from.

Parameters
[in]bookOpen book.
[out]out_kindReceives a epub_toc_kind_t value.
Returns
ra8_err_t
Return values
k_ra8_okReported.
k_ra8_err_null_ptrAny pointer NULL.
k_ra8_err_not_initializedbook->in_use == 0.
Precondition
book non-NULL, out_kind non-NULL.
book->in_use == 1.
Postcondition
*out_kind is one of the epub_toc_kind_t enumerators.
*out_kind == k_epub_toc_none iff toc_count == 0.
Since
0.1.0

Definition at line 355 of file epub_chapter.c.

References epub_book_t::in_use, k_ra8_err_not_initialized, k_ra8_err_null_ptr, k_ra8_ok, and epub_book_t::toc_kind.

Referenced by etoc_check_bad(), and etoc_read_toc().

◆ epub_load_chapter()

ra8_err_t epub_load_chapter ( epub_book_t * book,
uint16_t idx,
uint8_t * out_xhtml,
size_t max_len,
size_t * got_len )
nodiscard

Extract the raw XHTML bytes of one chapter into the caller's buffer.

Parameters
[in]bookOpen book.
[in]idxChapter index, [0, chapter_count).
[out]out_xhtmlDestination buffer (caller-owned).
[in]max_lenCapacity of out_xhtml, bytes.
[out]got_lenBytes actually written (0 on failure).
Return values
k_ra8_okChapter copied (got_len <= max_len).
k_ra8_err_null_ptrAny pointer NULL.
k_ra8_err_not_initializedbook->in_use == 0.
k_ra8_err_out_of_rangeidx >= chapter_count.
k_ra8_err_invalid_sizemax_len == 0.
k_ra8_err_no_memChapter does not fit in max_len.
k_ra8_err_not_foundManifest references a missing zip entry.
Precondition
book non-NULL, book->in_use == 1.
Postcondition
On success, *got_len > 0. On failure, *got_len == 0.
Since
0.1.0

Definition at line 322 of file epub_chapter.c.

References epub_book_t::chapter_count, epub_book_t::chapter_paths, epub_book_t::in_use, internal_locate_extract(), k_epub_max_path_len, k_ra8_err_invalid_size, k_ra8_err_not_initialized, k_ra8_err_null_ptr, k_ra8_err_out_of_range, epub_book_t::opf_dir, priv_epub_book_not_ready(), priv_epub_join_path(), epub_book_t::zip_archive_active, and epub_book_t::zip_archive_storage.

Referenced by eoh_parse_or_halt(), ep_parse_or_halt(), internal_compile_chapters(), and sh_book_chapter_text().

◆ epub_manifest_count()

uint16_t epub_manifest_count ( const epub_book_t * book)
nodiscard

Number of <manifest> <item> entries retained (#151).

epub_open() records every manifest item – id, href, media-type – in OPF document order, up to k_epub_max_manifest. The on-device compiler walks them in that order to emit the stylesheet and image tables, matching the desktop epub_compile.py (manifest.items()), which keeps the blob byte-identical.

Parameters
[in]bookOpen book (in_use == 1).
Returns
Item count (0 .. k_epub_max_manifest), or 0 if book is NULL.
Return values
0No items, a closed book, or a NULL handle.
Precondition
book was populated by epub_open().
The caller treats the count as a read-only snapshot.
Postcondition
No state is mutated.
Note
Not thread-safe; single-threaded reader context.
See also
epub_manifest_item()
Since
0.1.0

Definition at line 505 of file epub_chapter.c.

References epub_book_t::in_use, and epub_book_t::manifest_count.

Referenced by internal_compile_images(), and internal_compile_stylesheets().

◆ epub_manifest_item()

const epub_manifest_item_t * epub_manifest_item ( const epub_book_t * book,
uint16_t index )
nodiscard

Borrow the manifest item at index (OPF document order, #151).

Returns a const pointer into the book's retained manifest array; the storage lives in book and stays valid until epub_close(). The caller must not write through the pointer.

Parameters
[in]bookOpen book (in_use == 1).
[in]indexZero-based item index, < epub_manifest_count(book).
Returns
Pointer to the item, or NULL if book is NULL or index is out of range.
Return values
NULLbook is NULL or index >= the retained count.
Precondition
book was populated by epub_open().
index is less than epub_manifest_count for book.
Postcondition
No state is mutated; the returned storage is owned by book.
Note
Not thread-safe; single-threaded reader context.
See also
epub_manifest_count()
Since
0.1.0

Definition at line 516 of file epub_chapter.c.

References epub_book_t::in_use, epub_book_t::manifest, and epub_book_t::manifest_count.

Referenced by internal_compile_images(), and internal_compile_stylesheets().

◆ epub_open()

ra8_err_t epub_open ( const void * media,
const char * path,
epub_book_t * out_book )
nodiscard

Open an EPUB book from an opaque media handle.

Treats media as a pointer to epub_mem_media_t, opens the ZIP via miniz, follows META-INF/container.xml to the OPF document, parses metadata + manifest + spine, and populates *out_book.

Algorithm:

  1. Validate args, zero *out_book.
  2. mz_zip_reader_init_mem() against the in-memory blob.
  3. Extract META-INF/container.xml to the local stack buffer.
  4. Parse with the bounded XML reader; pull the first <rootfile> full-path.
  5. Extract the OPF file; parse the <metadata>, <manifest>, and <spine> blocks.
  6. Walk the spine in document order; for each <itemref idref="X">, look up the manifest entry with id="X" and copy its href into chapter_paths[chapter_count++].
Parameters
[in]mediaOpaque pointer; currently expected to be a epub_mem_media_t*.
[in]pathCosmetic file path for diagnostic logs; may be NULL. Not used to read bytes – the caller is responsible for loading the blob into media.
[out]out_bookPopulated book on success.
Returns
ra8_err_t
Return values
k_ra8_okBook opened.
k_ra8_err_null_ptrmedia or out_book is NULL.
k_ra8_err_invalid_argMedia payload invalid.
k_ra8_err_no_memSpine longer than k_epub_max_chapters.
k_ra8_err_validation_failedZIP/XML/OPF could not be parsed.
Precondition
media non-NULL.
out_book non-NULL.
Postcondition
On success, out_book->in_use == 1 and chapter_count >= 0.
On failure, *out_book is zero-initialized.
Note
Not thread-safe. Single-threaded init context.
See also
epub_close()
Since
0.1.0

Definition at line 405 of file epub_open.c.

References epub_mem_media_t::data, epub_miniz_arena_deinit(), internal_byte_zero(), k_ra8_err_invalid_arg, k_ra8_err_null_ptr, k_ra8_err_validation_failed, k_ra8_ok, epub_book_t::miniz_arena, priv_epub_finish_open(), priv_epub_mem_read(), priv_epub_set_miniz_alloc(), ra8_decomp_zip_entry_preflight(), epub_mem_media_t::size, epub_book_t::zip_archive_storage, epub_book_t::zip_bytes, and epub_book_t::zip_size.

Referenced by compile_fixture(), ec_render_cover_or_halt(), ep_parse_or_halt(), and est_open_or_halt().

◆ epub_open_streamed()

ra8_err_t epub_open_streamed ( const epub_stream_media_t * media,
const char * path,
epub_book_t * out_book )
nodiscard

Open an EPUB book from a seekable stream, with no whole-file residency (#151).

The streaming counterpart to epub_open(). Instead of a fully-resident blob (epub_mem_media_t), it takes a epub_stream_media_t – a seek+read callback plus the archive size – and drives miniz's user-read reader (mz_zip_reader_init) off it. Only the ZIP tail (end-of-central-directory + central directory) is read at open, and each entry (container.xml, OPF, a chapter, the cover) is inflated on demand through the same callback, so the resident working set is bounded by the largest single entry plus the central directory – never the whole archive. This is what lets a book far larger than SRAM+SDRAM (e.g. a multi-hundred-MB manga omnibus on the SD card) be opened and parsed at all.

The parsed book is identical to one opened via epub_open(): every accessor (epub_load_chapter(), epub_get_cover_image(), epub_get_resource(), ...) works unchanged, streaming each entry from the backing on demand. epub_close() tears the reader down for both paths.

Parameters
[in]mediaSeekable media descriptor; read non-NULL, size > 0. The backing referenced by media->ctx must out-live the opened book.
[in]pathCosmetic path for diagnostics; may be NULL. Not used to read bytes – all I/O goes through media->read.
[out]out_bookPopulated book on success.
Returns
ra8_err_t
Return values
k_ra8_okBook opened; streams from media on demand.
k_ra8_err_null_ptrmedia or out_book is NULL.
k_ra8_err_invalid_argmedia->read is NULL or media->size == 0.
k_ra8_err_no_memSpine longer than k_epub_max_chapters.
k_ra8_err_validation_failedZIP/XML/OPF could not be parsed / read.
Precondition
media and out_book are non-NULL.
media->read faithfully reads [offset, offset+len) of the archive.
Postcondition
On success out_book->in_use == 1 and out_book->zip_bytes == NULL.
On failure *out_book is zero-initialized.
Note
Not thread-safe. Single-threaded reader context.
The whole-file epub_open() stays the right choice for small, already resident (baked / XIP) books; this path is additive for the large/FS case.
See also
epub_open()
epub_close()
Since
0.1.0

Definition at line 455 of file epub_open.c.

References epub_stream_media_t::ctx, epub_miniz_arena_deinit(), internal_byte_zero(), k_ra8_err_invalid_arg, k_ra8_err_null_ptr, k_ra8_err_validation_failed, k_ra8_ok, epub_book_t::miniz_arena, priv_epub_finish_open(), priv_epub_set_miniz_alloc(), priv_epub_stream_read(), ra8_decomp_zip_entry_preflight(), epub_stream_media_t::read, epub_stream_media_t::size, epub_book_t::stream_media, epub_book_t::zip_archive_storage, epub_book_t::zip_bytes, and epub_book_t::zip_size.

Referenced by internal_compile_temp(), and internal_stream_open().

◆ epub_render_glyph()

ra8_err_t epub_render_glyph ( const epub_book_t * book,
int32_t codepoint,
float font_size,
uint8_t * out_bitmap,
size_t max_pixels,
uint32_t * out_w,
uint32_t * out_h )
nodiscard

Rasterise a single Unicode code point into an alpha-8 bitmap.

Wraps stbtt_GetCodepointBitmap() against the font installed via epub_set_font(). The resulting bitmap is 8 bits per pixel, grayscale, with the glyph's advance and side-bearing dropped (the caller positions glyphs on the page).

Parameters
[in]bookOpen book with a font installed.
[in]codepointUnicode code point (e.g. 'A').
[in]font_sizePixel size for the rasteriser.
[out]out_bitmapDestination buffer (caller-owned).
[in]max_pixelsCapacity of out_bitmap, in bytes.
[out]out_wGlyph width in pixels.
[out]out_hGlyph height in pixels.
Return values
k_ra8_okGlyph rasterised.
k_ra8_err_null_ptrAny pointer NULL.
k_ra8_err_not_initializedbook->in_use == 0 or no font set.
k_ra8_err_invalid_argfont_size <= 0.
k_ra8_err_no_memGlyph does not fit in max_pixels.
k_ra8_err_validation_failedFont blob malformed.
Since
0.1.0

Definition at line 576 of file epub_chapter.c.

References epub_book_t::font_data, epub_book_t::in_use, internal_font_init(), internal_render_into(), k_ra8_err_invalid_arg, k_ra8_err_not_initialized, k_ra8_err_null_ptr, and k_ra8_ok.

◆ epub_set_font()

ra8_err_t epub_set_font ( epub_book_t * book,
const uint8_t * font_data,
size_t font_size )
nodiscard

Attach a TTF font blob to be used by epub_render_glyph().

epub does not embed a default font; the caller (or the host application) must point the book at a TTF blob that lives for the lifetime of the book. Typical sources are:

  • A font baked into the firmware image as a static const.
  • A font/-prefixed manifest entry inside the EPUB, extracted via epub_load_chapter() style code into a caller buffer.
Parameters
[in,out]bookOpen book.
[in]font_dataTTF buffer; must outlive book.
[in]font_sizeLength of font_data, bytes.
Return values
k_ra8_okFont installed.
k_ra8_err_null_ptrAny pointer NULL.
k_ra8_err_not_initializedbook->in_use == 0.
k_ra8_err_invalid_sizefont_size < 16.
Since
0.1.0

Definition at line 560 of file epub_chapter.c.

References epub_book_t::font_data, epub_book_t::font_size, epub_book_t::in_use, k_epub_min_font_bytes, k_ra8_err_invalid_size, k_ra8_err_not_initialized, k_ra8_err_null_ptr, and k_ra8_ok.

◆ epub_toc_entry_to_chapter()

ra8_err_t epub_toc_entry_to_chapter ( const epub_book_t * book,
uint16_t toc_idx,
uint16_t * out_chapter_idx )
nodiscard

Resolve a TOC entry to the spine chapter index it points into.

Makes the parsed TOC navigable: a TOC entry's href is an OPF-relative path with an optional #fragment (e.g. ch3.xhtml#sec2), whereas epub_load_chapter() is indexed by spine position. This strips any fragment from the entry href and returns the index of the first spine chapter (chapter_paths) whose path matches, suitable to hand to epub_load_chapter().

Parameters
[in]bookOpen book.
[in]toc_idxTOC entry index, [0, toc_count).
[out]out_chapter_idxSpine chapter index on success.
Returns
ra8_err_t
Return values
k_ra8_okResolved; *out_chapter_idx < chapter_count.
k_ra8_err_null_ptrAny pointer NULL.
k_ra8_err_not_initializedbook->in_use == 0.
k_ra8_err_out_of_rangetoc_idx >= toc_count.
k_ra8_err_not_foundThe entry points outside the spine.
Precondition
book non-NULL, out_chapter_idx non-NULL.
book->in_use == 1.
Postcondition
On success, *out_chapter_idx indexes a valid spine chapter.
On failure, *out_chapter_idx is left unmodified.
Since
0.1.0

Definition at line 395 of file epub_chapter.c.

References epub_book_t::chapter_count, epub_book_t::chapter_paths, epub_toc_entry_t::href, epub_book_t::in_use, k_ra8_err_not_found, k_ra8_err_not_initialized, k_ra8_err_null_ptr, k_ra8_err_out_of_range, k_ra8_ok, strlen(), strncmp(), epub_book_t::toc, and epub_book_t::toc_count.

Referenced by etoc_read_toc(), internal_chapter_title(), and sh_epub_label().