35typedef enum : uint8_t {
69 const size_t mask = alignment - 1U;
70 if ((alignment == 0U) || ((alignment & mask) != 0U) || (value > (SIZE_MAX - mask))) {
73 *out = (value + mask) & ~mask;
97 (start > SIZE_MAX - bytes)) {
98 layout->
valid =
false;
101 const size_t end = start + bytes;
102 if ((layout->
base !=
nullptr) && (end > layout->
capacity)) {
103 layout->
valid =
false;
106 void* result = (layout->
base ==
nullptr) ?
nullptr : &layout->
base[start];
193 const size_t path_len =
strlen(path);
194 const size_t suffix_len =
strlen(suffix);
195 if (path_len < suffix_len) {
198 const char* tail = &path[path_len - suffix_len];
199 for (
size_t index = 0U; index < suffix_len; ++index) {
200 char value = tail[index];
201 if ((value >=
'A') && (value <=
'Z')) {
202 value = (char)(value + (
'a' -
'A'));
204 if (value != suffix[index]) {
257 const size_t length =
strlen(text);
258 while (offset < length) {
259 const ssize_t written =
write(STDERR_FILENO, &text[offset], length - offset);
260 if ((written < 0) && (errno == EINTR)) {
266 offset += (size_t)written;
290 "descriptor-spooled gzip/XZ output seam");
293 "(font + image loader) is not wired into the viewer yet");
318 const int descriptor = open(path, O_RDONLY |
O_CLOEXEC);
319 if (descriptor < 0) {
322 struct stat metadata = {};
323 if ((fstat(descriptor, &metadata) != 0) || !S_ISREG(metadata.st_mode) ||
324 (metadata.st_size <= 0)) {
325 (void)close(descriptor);
329 (
viewer_file_ctx_t){.size = (uint64_t)metadata.st_size, .fd = descriptor, .is_open =
true};
337 if (out_read ==
nullptr) {
341 if ((file ==
nullptr) || (buffer ==
nullptr)) {
344 if (!file->is_open || (offset > (uint64_t)INT64_MAX)) {
347 if (offset >= file->size) {
350 const uint64_t available = file->size - offset;
351 size_t requested = ((uint64_t)length > available) ? (
size_t)available : length;
352 size_t completed = 0U;
353 while (completed < requested) {
354 size_t pass = requested - completed;
355 if (pass > (
size_t)SSIZE_MAX) {
356 pass = (size_t)SSIZE_MAX;
359 pread(file->fd, &((uint8_t*)buffer)[completed], pass, (off_t)(offset + (uint64_t)completed));
360 if ((got < 0) && (errno == EINTR)) {
365 *out_read = completed;
370 completed += (size_t)got;
372 *out_read = completed;
394 viewer_layout_t layout = {.base = base, .capacity = capacity, .used = 0U, .valid =
true};
398 (void)
internal_take(&layout, dimension_bytes,
alignof(uint32_t));
399 (void)
internal_take(&layout, dimension_bytes,
alignof(uint32_t));
405 layout.
valid =
false;
492 const uint64_t band = (uint64_t)info.
tile_w * (uint64_t)info.
tile_h * (uint64_t)info.
bpp;
493 if ((error ==
k_ra8_ok) && (band == 0U)) {
539 if ((path ==
nullptr) || (out ==
nullptr)) {
561 (void)close(file.fd);
578 size_t workspace_bytes,
582 if ((out ==
nullptr) || (requirements ==
nullptr) || (report ==
nullptr)) {
587 .supplied_bytes = workspace_bytes};
590 (workspace_bytes < requirements->required_bytes)) {
594 .capacity = workspace_bytes,
599 uint16_t* framebuffer =
602 uint32_t* widths = (uint32_t*)
internal_take(&layout, dimension_bytes,
alignof(uint32_t));
603 uint32_t* heights = (uint32_t*)
internal_take(&layout, dimension_bytes,
alignof(uint32_t));
616 .engine = requirements->
engine,
622 .rt565 = framebuffer,
703 if ((reader ==
nullptr) || (path ==
nullptr)) {
725 (void)close(reader->
file.
fd);
734 return ((reader ==
nullptr) || !reader->
is_open) ? 0U : reader->
tile_n;
739 if (reader ==
nullptr) {
745 if (page >= reader->
tile_n) {
763 if ((reader ==
nullptr) || (width ==
nullptr) || (height ==
nullptr)) {
769 if (index >= reader->
tile_n) {
780 size_t* out_alignment)
783 uint32_t height = 0U;
785 if ((out_bytes ==
nullptr) || (out_alignment ==
nullptr)) {
791 *out_bytes = (size_t)width * (
size_t)height *
sizeof(uint16_t);
792 *out_alignment =
alignof(uint16_t);
799 size_t workspace_bytes,
802 uint16_t** out_pixels,
805 if ((reader ==
nullptr) || (width ==
nullptr) || (height ==
nullptr) || (out_pixels ==
nullptr) ||
806 (report ==
nullptr)) {
809 *out_pixels =
nullptr;
810 size_t required = 0U;
811 size_t alignment = 0U;
818 if ((workspace ==
nullptr) || (((uintptr_t)workspace % alignment) != 0U) ||
819 (workspace_bytes < required)) {
827 *out_pixels = (uint16_t*)workspace;
834 if (reader ==
nullptr) {
841 (void)close(reader->
file.
fd);
ra8_err_t comic_close(comic_t *c)
Release an open comic's backend resources.
static uint32_t comic_page_count(const comic_t *c)
Number of pages in an open comic.
#define O_CLOEXEC
Zero fallback when the host lacks close-on-exec open flags.
JOF band-tile atlas: the display-native normalized image format (#231, shared with the longstrip scro...
ra8_err_t jof_parse(jof_pread_fn pread, void *pread_ctx, uint64_t total_size, jof_info_t *out_info)
Parse + validate a JOF atlas's header, footer and index bounds.
@ k_jof_codec_raw
Tile stream is the packed pixels.
uint32_t jof_stored_bound(uint32_t raw_bytes)
Worst-case stored-tile byte bound for scratch/cell sizing.
Annotation-attribute framework macros for ra8-firmware.
#define RA8_INTERNAL
Marker that a function is intended to be static (file-local).
Unified decompression-limits policy: one bound set for every decoder.
ra8_decomp_limits_t ra8_decomp_limits_default(void)
The owner-approved default decompression policy.
ra8_err_t ra8_decomp_check_declared(const ra8_decomp_limits_t *limits, uint64_t comp_size, uint64_t out_size)
Header-level check of a member's declared sizes against a policy.
Error Code Definitions for ra8-firmware.
@ k_ra8_err_not_supported
Requested feature not compiled in, not wired, or not supported by this MCU variant.
@ k_ra8_err_out_of_range
Sensor or peripheral output out of valid range.
@ k_ra8_err_invalid_state
Module in wrong state for requested operation.
@ 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_not_found
Requested item not found (lookup / search missed).
@ 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.
size_t strlen(const char *s)
Calculate string length.
ra8_err_t priv_viewer_pread(void *ctx, uint64_t offset, uint8_t *buffer, size_t length, size_t *out_read)
JOF positional-reader seam over viewer_file_ctx_t.
uint32_t ra8_viewer_tile_count(const ra8_viewer_reader_t *reader)
Number of scroll tiles in reader, or zero for NULL/closed.
uint32_t ra8_viewer_page_count(const ra8_viewer_reader_t *reader)
Number of viewport pages in reader, or zero for NULL/closed.
static void internal_require_comic(ra8_viewer_reader_requirements_t *out)
Populate the fixed bounded bare-comic requirements shape.
static bool internal_requirements_valid(const ra8_viewer_reader_requirements_t *need)
Validate a requirements object before workspace mutation.
void ra8_viewer_close(ra8_viewer_reader_t *reader)
Close the descriptor and reset reader state without freeing workspace.
static ra8_err_t internal_require_jof(viewer_file_ctx_t *file, ra8_viewer_reader_requirements_t *out)
Populate JOF-specific requirements from one open descriptor.
ra8_err_t ra8_viewer_open(ra8_viewer_reader_t *reader, const char *path)
Open the document class used to size and bind reader.
static void internal_stderr_write(const char *text)
Best-effort exact diagnostic fragment over standard error.
static ra8_err_t internal_file_open(viewer_file_ctx_t *file, const char *path)
Open and size one non-empty regular host file.
static viewer_comic_t internal_take_comic(viewer_layout_t *layout, const ra8_viewer_reader_requirements_t *requirements)
Take the complete comic-specific workspace tail.
viewer_fmt_t
Recognised filename classes at the host composition edge.
@ k_viewer_fmt_reflow
EPUB/RABOOK engine not wired.
@ k_viewer_fmt_jof
Supported streamed JOF.
@ k_viewer_fmt_unknown
Unrecognised extension.
@ k_viewer_fmt_comic_wrap
Gzip/XZ whole-output seam remains.
@ k_viewer_fmt_comic
Supported bare CBZ/CBR/CBT.
static ra8_err_t internal_open_selected(ra8_viewer_reader_t *reader)
Open and size the reader's selected engine.
static viewer_fmt_t internal_classify(const char *path)
Classify a path without opening it.
ra8_err_t ra8_viewer_tile_requirements(const ra8_viewer_reader_t *reader, uint32_t index, size_t *out_bytes, size_t *out_alignment)
Report exact caller storage needed to render tile index.
static viewer_layout_t internal_layout(const ra8_viewer_reader_requirements_t *need, uint8_t *base, size_t capacity)
Charge the complete deterministic reader layout.
static bool internal_engine_requirements_valid(const ra8_viewer_reader_requirements_t *need)
Validate engine-specific requirement fields.
ra8_err_t ra8_viewer_render_tile565(ra8_viewer_reader_t *reader, uint32_t index, void *workspace, size_t workspace_bytes, uint32_t *width, uint32_t *height, uint16_t **out_pixels, ra8_viewer_workspace_report_t *report)
Render tile index into caller-owned RGB565 storage.
ra8_err_t ra8_viewer_render_page(ra8_viewer_reader_t *reader, uint32_t page)
Render one page into the reader's fixed RGB565 framebuffer.
static viewer_jof_t internal_take_jof(viewer_layout_t *layout, const ra8_viewer_reader_requirements_t *requirements)
Take the complete JOF-specific workspace tail.
static bool internal_ends_with(const char *path, const char *suffix)
Test one case-insensitive ASCII filename suffix.
static ra8_err_t internal_reject(viewer_fmt_t format, const char *path)
Emit the truthful unsupported-format reason.
ra8_err_t ra8_viewer_reader_bind(ra8_viewer_reader_t **out, void *workspace, size_t workspace_bytes, const ra8_viewer_reader_requirements_t *requirements, ra8_viewer_workspace_report_t *report)
Bind one reader state to caller-owned bytes.
ra8_err_t ra8_viewer_reader_requirements(const char *path, ra8_viewer_reader_requirements_t *out)
Inspect path and calculate its exact reader workspace.
static void * internal_take(viewer_layout_t *layout, size_t bytes, size_t alignment)
Take one aligned layout slice, or only charge it while sizing.
static bool internal_align_up(size_t value, size_t alignment, size_t *out)
Align value upward with overflow rejection.
static bool internal_engine_matches(const ra8_viewer_reader_t *reader, viewer_fmt_t format)
Whether a path class matches the engine frozen at bind time.
ra8_err_t ra8_viewer_tile_size(const ra8_viewer_reader_t *reader, uint32_t index, uint32_t *width, uint32_t *height)
Read native dimensions for tile index.
Caller-owned host JOF/comic reader and RGB565 render surface.
@ k_ra8_viewer_fb_height
Framebuffer height in pixels.
@ k_ra8_viewer_fb_width
Framebuffer width in pixels.
@ k_ra8_viewer_engine_comic
Bare CBZ/CBR/CBT comic engine.
@ k_ra8_viewer_engine_jof
Streamed JOF long-strip engine.
struct ra8_viewer_reader ra8_viewer_reader_t
Opaque state bound inside caller-owned workspace.
Cross-translation-unit state for the bounded JOF/comic viewer.
ra8_err_t priv_viewer_pread(void *ctx, uint64_t offset, uint8_t *buffer, size_t length, size_t *out_read)
JOF positional-reader seam over viewer_file_ctx_t.
void priv_viewer_size_jof_tiles(ra8_viewer_reader_t *reader, uint32_t count)
Populate native tile dimensions after the strip opens.
ra8_err_t priv_viewer_render_comic(ra8_viewer_reader_t *reader, uint32_t page)
Render one comic page into the fixed framebuffer.
ra8_err_t priv_viewer_tile_jof(ra8_viewer_reader_t *reader, uint32_t index, uint16_t *pixels, size_t pixel_bytes, uint32_t *width, uint32_t *height)
Render one JOF viewport into caller-owned RGB565 output.
@ k_viewer_layout_version
Workspace layout ABI guard.
@ k_viewer_jof_buckets
Power-of-two cache bucket count.
ra8_err_t priv_viewer_size_comic_tiles(ra8_viewer_reader_t *reader)
Probe every comic page into the bound dimension arrays.
ra8_err_t priv_viewer_open_jof(ra8_viewer_reader_t *reader)
Open and wire the JOF engine over a bound reader.
ra8_err_t priv_viewer_tile_comic(ra8_viewer_reader_t *reader, uint32_t index, uint16_t *pixels, size_t pixel_bytes, uint32_t *width, uint32_t *height)
Render one comic page into caller-owned RGB565 storage.
@ k_viewer_comic_page_cap
Maximum indexed pages.
@ k_viewer_comic_arena_bytes
stb decode arena capacity.
@ k_viewer_comic_page_bytes
Encoded-page resident cap.
@ k_viewer_comic_name_bytes
Member-name arena bytes.
ra8_err_t priv_viewer_open_comic(ra8_viewer_reader_t *reader)
Open a bare CBZ/CBR/CBT engine over a bound reader.
ra8_err_t priv_viewer_render_jof(ra8_viewer_reader_t *reader, uint32_t page)
Render one JOF viewport into the fixed framebuffer.
One entry in the resident, sorted page index.
Parsed + validated geometry of one JOF atlas.
uint8_t bpp
Bytes per pixel (1, 3 or 4).
uint8_t codec
jof_codec_t member.
uint16_t tile_w
Tile width, pixels.
uint16_t tile_h
Tile height, pixels.
uint16_t height
Image height, pixels.
jof_info_t info
Parsed atlas geometry.
One decompression policy: the five resource bounds decoders enforce.
Per-cell link metadata (one caller-owned array entry per cell).
Per-cell user descriptor: the decoded tile dimensions.
Identifies one decoded image tile.
Exact immutable layout returned for one document.
size_t comic_pages_bytes
Comic page-index storage, or zero.
size_t required_bytes
Complete workspace extent.
size_t comic_page_bytes
Resident encoded-page storage, or zero.
uint32_t layout_version
ABI guard consumed by bind.
size_t comic_arena_bytes
stb decode arena storage, or zero.
size_t scratch_bytes
One bounded compressed-band staging area.
size_t comic_names_bytes
Comic member-name arena, or zero.
size_t cell_bytes
One resident decoded JOF band.
uint32_t engine
ra8_viewer_reader_engine_t selection.
size_t framebuffer_bytes
Resident fixed RGB565 framebuffer.
uint32_t tile_count
Number of viewport tiles in the strip.
size_t dimensions_bytes
Two resident per-tile dimension arrays.
size_t required_alignment
Required base-address alignment.
uint32_t * tile_hpx
Native height per viewport tile.
uint32_t * tile_wpx
Native width per viewport tile.
uint16_t * rt565
Current composite target.
viewer_jof_t jof
JOF engine and caller-bound cache.
viewer_comic_t comic
Comic engine and caller slices.
uint32_t rt_w
Current target width.
uint16_t * fb
Fixed headless framebuffer.
bool is_open
Successful engine-open flag.
bool is_bound
Successful workspace bind flag.
uint32_t engine
ra8_viewer_reader_engine_t value.
viewer_file_ctx_t file
Raw source descriptor.
uint32_t tile_cap
Bound dimension entries.
uint32_t tile_n
Populated dimension entries.
uint32_t rt_h
Current target height.
Required-versus-supplied evidence from a bind attempt.
Bare comic engine and every caller-bound backing slice.
uint8_t * page
Resident encoded-image bytes.
comic_t archive
Open CBZ/CBR/CBT facade.
char * names
Resident member-name arena.
size_t page_cap
Encoded-image capacity in bytes.
uint8_t * arena
stb caller-owned decode arena.
comic_page_t * pages
Resident sorted page index.
size_t arena_cap
Decode-arena capacity in bytes.
Raw host descriptor behind the reusable positional-read callback.
int fd
Owned descriptor while open.
bool is_open
Descriptor ownership flag.
Caller-bound JOF engine and one-band cache backing.
size_t scratch_cap
Bound compressed staging bytes.
uint8_t * scratch
Compressed-band staging.
longstrip_decode_ctx_t dctx
JOF decoder callback state.
ra8_tile_dims_t * dims
Single cache dimensions entry.
uint8_t * cells
One decoded-band buffer.
ra8_tile_key_t * keys
Single cache key.
int32_t * buckets
Hash bucket heads.
ra8_keycache_cell_t * meta
Single cache metadata entry.
size_t cell_cap
Bound decoded-band bytes.
Mutable cursor used to calculate or bind one aligned layout.
bool valid
False after overflow/capacity failure.
uint8_t * base
Workspace base, or NULL during sizing.
size_t used
First unused byte.
size_t capacity
Accessible extent during binding.