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

Unified demand-paged reader for comic-book archives – CBZ (ZIP) and CBR (RAR). More...

#include <stddef.h>
#include <stdint.h>
#include "epub_miniz_alloc.h"
#include "ra8_err.h"
#include "ra8_rar.h"
#include "ra8_rar5.h"
#include "unarch_gzip.h"
#include "unarch_tar.h"
#include "unarch_xz.h"
Include dependency graph for comic.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  comic_page_t
 One entry in the resident, sorted page index. More...
struct  comic_stream_t
 Stable seek+read descriptor bound to the CBZ backend's miniz reader. More...
struct  comic_t
 One open comic archive: backing, kind, page index, and backend state. More...

Typedefs

typedef size_t(* comic_read_fn) (void *ctx, uint64_t offset, void *buf, size_t len)
 Seek+read backing over the comic-archive bytes.

Enumerations

enum  comic_kind_t : uint8_t {
  k_comic_kind_none = 0U ,
  k_comic_kind_cbz = 1U ,
  k_comic_kind_cbr = 2U ,
  k_comic_kind_cbt = 3U
}
 Which container an opened comic is. More...
enum  comic_limits_t : uint16_t {
  k_comic_magic_len = 8U ,
  k_comic_zip_bytes = 256U
}
 Fixed sizes for magic detection and the inline ZIP-reader storage. More...
enum  comic_wrap_dims_t : uint8_t { k_comic_wrap_align = 8U }
 Alignment of the unwrap arena a wrapped open consumes. More...

Functions

ra8_err_t comic_open (comic_t *c, comic_read_fn read, void *ctx, uint64_t size, comic_page_t *pages, uint32_t page_cap, char *names, uint32_t names_cap)
 Open a comic archive (CBZ or CBR) and build its sorted page index.
static uint32_t comic_page_count (const comic_t *c)
 Number of pages in an open comic.
static comic_kind_t comic_kind (const comic_t *c)
 The detected container kind of an open comic.
ra8_err_t comic_page_info (const comic_t *c, uint32_t page, char *name_buf, uint16_t name_cap, uint16_t *out_name_len, uint64_t *out_raw_size, uint8_t *out_extractable)
 Read one page's manifest entry: name, encoded length, decodability.
ra8_err_t comic_page_read (comic_t *c, uint32_t page, uint8_t *buf, size_t cap, size_t *got)
 Extract one page's encoded image bytes for the decoder.
ra8_err_t comic_close (comic_t *c)
 Release an open comic's backend resources.
ra8_err_t comic_open_wrapped (comic_t *c, comic_read_fn read, void *ctx, uint64_t size, comic_page_t *pages, uint32_t page_cap, char *names, uint32_t names_cap, uint8_t *arena, size_t arena_cap, void *xz_scratch, uint32_t xz_scratch_len)
 Open a comic that may be gzip- or XZ-wrapped (.cbt.gz, .tar.xz).

Detailed Description

Unified demand-paged reader for comic-book archives – CBZ (ZIP) and CBR (RAR).

Tag
[Ring 4 / Domain] {World: NS}

A comic archive is simply a container of page images (JPEG / PNG / GIF / BMP) whose reading order is the sorted entry names. This facade opens either shape – a .cbz (a ZIP of images) or a .cbr (a RAR of images) – behind one interface, so the reader pages through both identically: detect the container, build a sorted page index, then serve each page's encoded image bytes on demand for the image decoder (ra8_img_decode_blit) to rasterise.

Streaming, bounded RAM (#151, NASA P10 Rule 3)
The archive is never resident in full. The CBZ backend drives miniz's user-read ZIP reader off the same seek+read seam that streams a large .epub (epub_open_streamed): only the ZIP central directory and one entry at a time are fetched. The CBR backend walks RAR block headers one at a time (ra8_rar.h) and streams one member. So a full manga volume (hundreds of MB) opens inside a small fixed budget – the caller-owned page-index + name arena plus one page's encoded image, never the whole file.

The caller supplies all storage: a page-index array, a name arena sized for the archive's page count, and (inside comic_t) one per-object bounded miniz workspace. There is no heap (NASA Rule 3).

Substitutability (SOLID L)
CBZ and CBR are drop-in interchangeable behind comic_page_read: the reader opens by extension/magic and pages through the result with no knowledge of the container. Both yield the same "sorted list of encoded page images".
comic_t comic = {};
char names[k_name_arena] = {};
ra8_err_t err = comic_open(&comic, sd_read, &file, file_len,
pages, k_max_pages, names, sizeof names);
for (uint32_t p = 0U; p < comic_page_count(&comic); ++p) {
size_t got = 0U;
err = comic_page_read(&comic, p, img_buf, sizeof img_buf, &got);
ra8_img_decode_blit(&arena, img_buf, got, 0, 0, fb_w, fb_h, NULL, NULL);
}
comic_close(&comic);
ra8_err_t comic_page_read(comic_t *c, uint32_t page, uint8_t *buf, size_t cap, size_t *got)
Extract one page's encoded image bytes for the decoder.
Definition comic.c:472
ra8_err_t comic_close(comic_t *c)
Release an open comic's backend resources.
Definition comic.c:494
ra8_err_t comic_open(comic_t *c, comic_read_fn read, void *ctx, uint64_t size, comic_page_t *pages, uint32_t page_cap, char *names, uint32_t names_cap)
Open a comic archive (CBZ or CBR) and build its sorted page index.
Definition comic.c:390
static uint32_t comic_page_count(const comic_t *c)
Number of pages in an open comic.
Definition comic.h:263
@ k_max_pages
Maximum page entries per chapter.
ra8_err_codes_t ra8_err_t
Canonical error-return type used by every ra8-firmware API.
Definition ra8_err.h:546
ra8_err_t ra8_img_decode_blit(ra8_img_arena_t *arena, const uint8_t *bytes, size_t len, int32_t dst_x, int32_t dst_y, int32_t box_w, int32_t box_h, int32_t *out_w, int32_t *out_h)
Decode bytes and blit it, scaled to fit, into the bound framebuffer.
One entry in the resident, sorted page index.
Definition comic.h:140
One open comic archive: backing, kind, page index, and backend state.
Definition comic.h:179
Note
One comic object is not thread-safe; independent objects share no miniz allocator state and may remain open simultaneously.
The CBZ backend needs miniz built with its archive APIs – pull epub into the app LIBS (which compiles miniz with the ZIP reader and supplies the caller-owned epub_miniz_alloc arena used on host and target).
See also
ra8_rar.h The clean-room RAR walker the CBR backend uses.
epub.h The streaming ZIP open this mirrors for CBZ.
reflow_image.h ra8_img_decode_blit, the page rasteriser.
Since
Version 0.1.0

Definition in file comic.h.

Typedef Documentation

◆ comic_read_fn

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

Seek+read backing over the comic-archive bytes.

Identical in shape to the streaming EPUB read seam and ra8_rar_read_fn, so one ra8_fs / ra8_vmem backing drives EPUB, CBZ, and CBR alike. A return shorter than len signals end-of-file.

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

Definition at line 95 of file comic.h.

Enumeration Type Documentation

◆ comic_kind_t

enum comic_kind_t : uint8_t

Which container an opened comic is.

Set by comic_open from the file magic; selects the backend that comic_page_read dispatches to.

Since
Version 0.1.0
Enumerator
k_comic_kind_none 

Not opened / unrecognised.

k_comic_kind_cbz 

ZIP of images (.cbz).

k_comic_kind_cbr 

RAR of images (.cbr).

k_comic_kind_cbt 

tar of images (.cbt).

Definition at line 104 of file comic.h.

◆ comic_limits_t

enum comic_limits_t : uint16_t

Fixed sizes for magic detection and the inline ZIP-reader storage.

Since
Version 0.1.0
Enumerator
k_comic_magic_len 

Bytes read to detect the container magic.

k_comic_zip_bytes 

Inline storage for miniz's mz_zip_archive.

Definition at line 116 of file comic.h.

◆ comic_wrap_dims_t

enum comic_wrap_dims_t : uint8_t

Alignment of the unwrap arena a wrapped open consumes.

comic_open_wrapped stores its flat-memory descriptor at the arena start, so the caller arena must be at least this aligned (any static or alignas(8) buffer qualifies).

Since
Version 0.1.0
Enumerator
k_comic_wrap_align 

Required unwrap-arena alignment, bytes.

Definition at line 399 of file comic.h.

Function Documentation

◆ comic_close()

ra8_err_t comic_close ( comic_t * c)
nodiscard

Release an open comic's backend resources.

Ends the CBZ miniz reader (freeing its central directory through the per-object bounded arena); the CBR backend allocates nothing. Resets c to the unopened state. Idempotent after a failed open.

Parameters
[in,out]cComic from comic_open (non-NULL).
Returns
ra8_err_t Error code.
Return values
k_ra8_okResources released; c reset.
k_ra8_err_null_ptrc was NULL.
Precondition
c was populated by comic_open or zero-initialised.
c out-lives the call.
Postcondition
c->kind == k_comic_kind_none and c->zip_active == 0.
No further comic_page_read may be issued until re-opened.
Note
Not thread-safe.
See also
comic_open()
Since
Version 0.1.0

Definition at line 494 of file comic.c.

References k_comic_kind_cbz, k_comic_kind_none, k_ra8_ok, comic_t::kind, unarch_tar_t::live, comic_t::page_count, priv_comic_cbz_close(), RA8_CHECK_NULL_PTR, s_tag_comic, comic_t::tar, and comic_t::zip_active.

Referenced by cm_comic_tiled_selfcheck(), comic_open(), ra8_viewer_close(), ra8_viewer_open(), and sh_comic_close().

◆ comic_kind()

comic_kind_t comic_kind ( const comic_t * c)
inlinestatic

The detected container kind of an open comic.

Reports the kind comic_open set from the file magic, guarding a NULL / unopened reader so a caller can branch before a comic is bound.

Parameters
[in]cComic bound by comic_open (may be NULL).
Returns
comic_kind_t; k_comic_kind_none for a NULL / unopened reader.
Return values
k_comic_kind_nonec is NULL or was never opened.
Precondition
c was populated by comic_open (or is NULL).
c out-lives the call.
Postcondition
No state is modified (pure read).
The result is stable for the lifetime of the open comic.
Note
Thread-safe: pure read.
Since
Version 0.1.0

Definition at line 288 of file comic.h.

References k_comic_kind_none, and comic_t::kind.

◆ comic_open()

ra8_err_t comic_open ( comic_t * c,
comic_read_fn read,
void * ctx,
uint64_t size,
comic_page_t * pages,
uint32_t page_cap,
char * names,
uint32_t names_cap )
nodiscard

Open a comic archive (CBZ or CBR) and build its sorted page index.

Reads the leading magic through read, detects a ZIP (.cbz) or a RAR (.cbr) container, enumerates its image members into pages (filtered to decodable image extensions, names copied into names), and sorts the index by entry name so page 0 is the first page. On success at least one page is present.

Parameters
[out]cReader to populate (caller-owned).
[in]readByte reader over the archive (non-NULL).
[in]ctxContext passed to read.
[in]sizeArchive length in bytes (> 0).
[in]pagesCaller page-index array (non-NULL).
[in]page_capCapacity of pages in entries (> 0).
[in]namesCaller name arena (non-NULL).
[in]names_capCapacity of names in bytes (> 0).
Returns
ra8_err_t Error code.
Return values
k_ra8_okComic opened; c bound with >= 1 page.
k_ra8_err_null_ptrA required pointer argument was NULL.
k_ra8_err_invalid_sizesize / a capacity is 0, a short magic read, or the page index / name arena was too small.
k_ra8_err_not_supportedThe bytes are neither a ZIP nor a RAR archive.
k_ra8_err_not_foundA valid archive with no decodable image pages.
k_ra8_err_*A backend (miniz / RAR) or reader error.
Precondition
read serves offsets [0, size) of the archive.
pages / names out-live c and every read from it.
Postcondition
On k_ra8_ok, comic_page_count(c) >= 1 and pages are name-sorted.
On any error c is left with kind == k_comic_kind_none.
Note
Not thread-safe. Call comic_close to release a CBZ's miniz reader.
See also
comic_page_read()
comic_close()
Since
Version 0.1.0

Definition at line 390 of file comic.c.

References comic_close(), comic_t::ctx, internal_open_detect(), internal_open_reject_null(), internal_sort(), k_ra8_err_invalid_size, k_ra8_err_not_found, k_ra8_ok, comic_t::names, comic_t::names_cap, comic_t::page_cap, comic_t::page_count, comic_t::pages, comic_t::read, and comic_t::size.

Referenced by cm_ct_open(), cm_open_comic(), comic_open_wrapped(), internal_open_unwrapped(), priv_viewer_open_comic(), and sh_comic_bind().

◆ comic_open_wrapped()

ra8_err_t comic_open_wrapped ( comic_t * c,
comic_read_fn read,
void * ctx,
uint64_t size,
comic_page_t * pages,
uint32_t page_cap,
char * names,
uint32_t names_cap,
uint8_t * arena,
size_t arena_cap,
void * xz_scratch,
uint32_t xz_scratch_len )
nodiscard

Open a comic that may be gzip- or XZ-wrapped (.cbt.gz, .tar.xz).

Probes the leading magic: a bare container (ZIP / RAR / tar) passes straight through to comic_open; a gzip or XZ wrapper is first decoded whole into the caller arena under the default decompression-limits policy, the unwrapped bytes are re-probed (a wrapper inside a wrapper is rejected as a nesting bomb), and the inner container is opened from the arena. The arena therefore must out-live the comic, exactly like the page-index and name buffers.

Parameters
[out]cReader to populate (caller-owned).
[in]readByte reader over the outer file (non-NULL).
[in]ctxContext passed to read.
[in]sizeOuter file length in bytes (> 0).
[in]pagesCaller page-index array (non-NULL).
[in]page_capCapacity of pages in entries (> 0).
[in]namesCaller name arena (non-NULL).
[in]names_capCapacity of names in bytes (> 0).
[in]arenaUnwrap arena (non-NULL, 8-aligned; out-lives c).
[in]arena_capCapacity of arena in bytes.
[in]xz_scratchXZ session scratch (8-aligned, > k_unarch_xz_state_reserve bytes; may be NULL when XZ content is not expected – an XZ file is then rejected fail-closed).
[in]xz_scratch_lenScratch length in bytes.
Returns
ra8_err_t Error code.
Return values
k_ra8_okComic opened; c bound with >= 1 page.
k_ra8_err_null_ptrA required pointer argument was NULL.
k_ra8_err_invalid_sizeA zero size/capacity, a short magic read, a misaligned or undersized arena, or full index buffers.
k_ra8_err_decomp_depthThe unwrapped bytes are another gzip/XZ wrapper (nesting bomb).
k_ra8_err_decomp_*The wrapper breached the policy.
k_ra8_err_checksum_mismatchThe gzip integrity check failed.
k_ra8_err_not_supportedNot a recognised container or wrapper.
k_ra8_err_*An unwrap or inner-open error.
Precondition
read serves offsets [0, size) of the outer file.
arena (and every other buffer) out-lives c and every read.
Postcondition
On k_ra8_ok the comic serves pages exactly like comic_open.
On any error c is left with kind == k_comic_kind_none.
Note
Not thread-safe (shares the single-client XZ pool / gzip state).
See also
comic_open()
Since
Version 0.1.0

Log tag for wrapped-open diagnostics.

Definition at line 190 of file comic_wrapped.c.

References comic_open(), internal_arena_valid(), internal_open_unwrapped(), internal_unwrap(), k_comic_magic_len, k_ra8_err_invalid_size, k_ra8_ok, k_wrap_hdr_bytes, RA8_CHECK_NULL_PTR, unarch_gzip_magic(), and unarch_xz_magic().

◆ comic_page_count()

uint32_t comic_page_count ( const comic_t * c)
inlinestatic

Number of pages in an open comic.

Returns the count parsed by comic_open, guarding a NULL/unopened reader so a shelf view can query it safely.

Parameters
[in]cComic bound by comic_open (may be NULL).
Returns
The page count, or 0 for a NULL / unopened reader.
Return values
0c is NULL or was never opened.
Precondition
c was populated by comic_open (or is NULL).
c out-lives the call.
Postcondition
No state is modified (pure read).
The result equals the sorted index length.
Note
Thread-safe: pure read of an immutable count.
Since
Version 0.1.0

Definition at line 263 of file comic.h.

References k_comic_kind_none, comic_t::kind, and comic_t::page_count.

Referenced by cm_ct_open(), cm_open_comic(), internal_open_selected(), and sh_comic_bind().

◆ comic_page_info()

ra8_err_t comic_page_info ( const comic_t * c,
uint32_t page,
char * name_buf,
uint16_t name_cap,
uint16_t * out_name_len,
uint64_t * out_raw_size,
uint8_t * out_extractable )
nodiscard

Read one page's manifest entry: name, encoded length, decodability.

Pure index query – no archive I/O. Copies the page's entry name into name_buf (clamped to name_cap) and reports its encoded byte length and whether this reader can decode it (0 for a compressed CBR member).

Parameters
[in]cComic bound by comic_open (non-NULL).
[in]pagePage index (< comic_page_count(c)).
[out]name_bufBuffer for the entry name (may be NULL if name_cap 0).
[in]name_capCapacity of name_buf in bytes.
[out]out_name_lenReceives the copied name length (may be NULL).
[out]out_raw_sizeReceives the encoded image length (may be NULL).
[out]out_extractableReceives 1 if the page is decodable (may be NULL).
Returns
ra8_err_t Error code.
Return values
k_ra8_okOutputs populated from the index.
k_ra8_err_null_ptrc was NULL.
k_ra8_err_invalid_statec was never opened.
k_ra8_err_out_of_rangepage is at or past the page count.
Precondition
c was populated by comic_open.
name_buf holds name_cap writable bytes when name_cap > 0.
Postcondition
On k_ra8_ok every non-NULL output is populated from page page.
On any error no output is modified.
Note
Thread-safe: pure read of an immutable index.
See also
comic_page_read()
Since
Version 0.1.0

Definition at line 434 of file comic.c.

References comic_page_t::extractable, k_comic_kind_none, k_ra8_err_invalid_state, k_ra8_err_out_of_range, k_ra8_ok, comic_t::kind, memcpy(), comic_page_t::name_len, comic_page_t::name_off, comic_t::names, comic_t::page_count, comic_t::pages, RA8_CHECK_NULL_PTR, comic_page_t::raw_size, and s_tag_comic.

Referenced by internal_read_page().

◆ comic_page_read()

ra8_err_t comic_page_read ( comic_t * c,
uint32_t page,
uint8_t * buf,
size_t cap,
size_t * got )
nodiscard

Extract one page's encoded image bytes for the decoder.

Streams the page's encoded image (JPEG / PNG / GIF / BMP) into buf: for a CBZ, miniz inflates the ZIP entry (STORE or DEFLATE) through the streaming reader; for a CBR, a STORE member is copied and a RAR5-compressed member is inflated by the clean-room decompressor, both via the RAR walker. The result is ready to hand to ra8_img_decode_blit. One call is one page's worth of I/O – the demand-paged model.

Parameters
[in]cComic bound by comic_open (non-NULL).
[in]pagePage index (< comic_page_count(c)).
[out]bufDestination for the encoded image (non-NULL).
[in]capCapacity of buf in bytes; must be >= the page raw_size.
[out]gotReceives the bytes written (non-NULL).
Returns
ra8_err_t Error code.
Return values
k_ra8_okPage bytes written; *got == raw_size.
k_ra8_err_null_ptrA required pointer argument was NULL.
k_ra8_err_invalid_statec was never opened.
k_ra8_err_out_of_rangepage is at or past the page count.
k_ra8_err_not_supportedA CBR page packed with a RAR compressor.
k_ra8_err_no_memcap is smaller than the page raw_size.
k_ra8_err_*A backend extract / reader error.
Precondition
c was populated by comic_open.
buf holds at least cap writable bytes.
Postcondition
On k_ra8_ok, buf[0..*got) holds the page's encoded image.
On any error buf contents are unspecified and *got == 0.
Note
Not thread-safe: reuses the backend's decode state across calls.
See also
comic_page_info()
Since
Version 0.1.0

Definition at line 472 of file comic.c.

References k_comic_kind_cbt, k_comic_kind_cbz, k_comic_kind_none, k_ra8_err_invalid_state, k_ra8_err_out_of_range, comic_t::kind, comic_t::page_count, comic_t::pages, priv_comic_cbr_extract(), priv_comic_cbt_extract(), priv_comic_cbz_extract(), RA8_CHECK_NULL_PTR, and s_tag_comic.

Referenced by cm_ct_open(), cm_draw_page(), internal_read_page(), and sh_comic_blit_page().