|
ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
|
Facade for the comic-archive reader: magic detect, page index, dispatch. More...
#include "comic.h"#include <string.h>#include "comic_internal.h"#include "ra8_attributes.h"#include "ra8_check.h"Go to the source code of this file.
Enumerations | |
| enum | comic_magic_t : uint16_t { k_zip_b0 = 0x50U , k_zip_b1 = 0x4BU , k_zip_lfh_b2 = 0x03U , k_zip_lfh_b3 = 0x04U , k_zip_eocd_b2 = 0x05U , k_zip_eocd_b3 = 0x06U , k_comic_sig_min = 4U } |
| ZIP magic bytes and the minimum magic-read length. More... | |
| enum | comic_ascii_t : uint8_t { k_ascii_upper_a = 0x41U , k_ascii_alpha_n = 26U , k_ascii_case_sh = 5U , k_comic_ext_max = 8U } |
| Constants for branchless ASCII case folding. More... | |
Functions | |
| static uint8_t | internal_lower (uint8_t c) |
| ASCII-lowercase one byte, branchlessly (letters only). | |
| static bool | internal_ends_with_ci (const char *name, uint16_t len, const char *ext) |
Case-insensitive test that name ends with ext. | |
| static bool | internal_is_image_ext (const char *name, uint16_t len) |
Whether name ends in a decodable image extension. | |
| bool | priv_comic_is_page_name (const char *name, uint16_t len) |
| Whether an archive entry name is a decodable comic page image. | |
| ra8_err_t | priv_comic_page_add (comic_t *c, const char *name, uint16_t name_len, uint64_t raw_size, uint8_t extractable, uint8_t method, uint32_t zip_index, uint64_t data_off, uint64_t pack_size) |
| Append one image member to the resident page index. | |
| static int32_t | internal_name_cmp (const char *a, uint16_t alen, const char *b, uint16_t blen) |
| Lexicographic compare of two entry names (byte order, length tiebreak). | |
| static void | internal_sort (comic_t *c) |
| Insertion-sort the page index by entry name (reading order). | |
| static bool | internal_is_zip (const uint8_t *s) |
| Whether the leading bytes are a ZIP local-file-header or empty EOCD. | |
| static ra8_err_t | internal_open_reject_null (const comic_t *c, comic_read_fn read, const comic_page_t *pages, const char *names) |
| Reject any NULL required argument to comic_open. | |
| static ra8_err_t | internal_open_detect (comic_t *c) |
| Detect the container and run its backend enumeration. | |
| 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. | |
| 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. | |
Variables | |
| static const char *const | s_tag_comic = "comic" |
| Log tag for comic-facade diagnostics. | |
Facade for the comic-archive reader: magic detect, page index, dispatch.
The container-agnostic half of comic.h. comic_open reads the leading magic, routes a ZIP to the CBZ backend, a RAR to the CBR backend, or a tar (probed by header block – tar has no leading magic) to the CBT backend, and lets each backend append its image members to the shared page index through priv_comic_page_add; the index is then sorted by entry name so reading order is the sorted names. comic_page_read / comic_page_info / comic_close dispatch on the detected kind.
Every decision here is a single condition on purpose, so the facade carries no MC/DC obligation of its own.
Definition in file comic.c.
| enum comic_ascii_t : uint8_t |
| enum comic_magic_t : uint16_t |
ZIP magic bytes and the minimum magic-read length.
The ZIP local-file-header and empty-archive (EOCD) signatures; a RAR is delegated to ra8_rar_open, which owns its own signature match.
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.
| [in,out] | c | Comic from comic_open (non-NULL). |
| k_ra8_ok | Resources released; c reset. |
| k_ra8_err_null_ptr | c was NULL. |
c was populated by comic_open or zero-initialised. c out-lives the call. 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().
|
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.
| [out] | c | Reader to populate (caller-owned). |
| [in] | read | Byte reader over the archive (non-NULL). |
| [in] | ctx | Context passed to read. |
| [in] | size | Archive length in bytes (> 0). |
| [in] | pages | Caller page-index array (non-NULL). |
| [in] | page_cap | Capacity of pages in entries (> 0). |
| [in] | names | Caller name arena (non-NULL). |
| [in] | names_cap | Capacity of names in bytes (> 0). |
| k_ra8_ok | Comic opened; c bound with >= 1 page. |
| k_ra8_err_null_ptr | A required pointer argument was NULL. |
| k_ra8_err_invalid_size | size / a capacity is 0, a short magic read, or the page index / name arena was too small. |
| k_ra8_err_not_supported | The bytes are neither a ZIP nor a RAR archive. |
| k_ra8_err_not_found | A valid archive with no decodable image pages. |
| k_ra8_err_* | A backend (miniz / RAR) or reader error. |
read serves offsets [0, size) of the archive. pages / names out-live c and every read from it. c is left with kind == k_comic_kind_none.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().
|
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).
| [in] | c | Comic bound by comic_open (non-NULL). |
| [in] | page | Page index (< comic_page_count(c)). |
| [out] | name_buf | Buffer for the entry name (may be NULL if name_cap 0). |
| [in] | name_cap | Capacity of name_buf in bytes. |
| [out] | out_name_len | Receives the copied name length (may be NULL). |
| [out] | out_raw_size | Receives the encoded image length (may be NULL). |
| [out] | out_extractable | Receives 1 if the page is decodable (may be NULL). |
| k_ra8_ok | Outputs populated from the index. |
| k_ra8_err_null_ptr | c was NULL. |
| k_ra8_err_invalid_state | c was never opened. |
| k_ra8_err_out_of_range | page is at or past the page count. |
c was populated by comic_open. name_buf holds name_cap writable bytes when name_cap > 0. page. 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().
|
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.
| [in] | c | Comic bound by comic_open (non-NULL). |
| [in] | page | Page index (< comic_page_count(c)). |
| [out] | buf | Destination for the encoded image (non-NULL). |
| [in] | cap | Capacity of buf in bytes; must be >= the page raw_size. |
| [out] | got | Receives the bytes written (non-NULL). |
| k_ra8_ok | Page bytes written; *got == raw_size. |
| k_ra8_err_null_ptr | A required pointer argument was NULL. |
| k_ra8_err_invalid_state | c was never opened. |
| k_ra8_err_out_of_range | page is at or past the page count. |
| k_ra8_err_not_supported | A CBR page packed with a RAR compressor. |
| k_ra8_err_no_mem | cap is smaller than the page raw_size. |
| k_ra8_err_* | A backend extract / reader error. |
c was populated by comic_open. buf holds at least cap writable bytes. buf contents are unspecified and *got == 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().
|
static |
Case-insensitive test that name ends with ext.
Compares the tail of name against ext byte-for-byte through internal_lower. A name shorter than ext cannot match.
| [in] | name | Entry name bytes. |
| [in] | len | Length of name. |
| [in] | ext | NUL-terminated extension (e.g. ".png"), <= k_comic_ext_max. |
name ends with ext, case-insensitively. | true | The suffix matches. |
| false | The suffix differs or name is too short. |
name holds len readable bytes; ext is NUL-terminated. ext is at most k_comic_ext_max bytes. Definition at line 103 of file comic.c.
References internal_lower(), k_comic_ext_max, and RA8_INTERNAL.
Referenced by internal_is_image_ext().
|
static |
Whether name ends in a decodable image extension.
The pure suffix test over the stb_image set; the hidden/base-name policy is applied separately by priv_comic_is_page_name.
| [in] | name | Entry name bytes. |
| [in] | len | Length of name. |
name has a supported image extension. | true | A decodable image extension. |
| false | Not a decodable image. |
name holds len readable bytes. len > 0. Definition at line 140 of file comic.c.
References internal_ends_with_ci(), and RA8_INTERNAL.
Referenced by priv_comic_is_page_name().
|
static |
Whether the leading bytes are a ZIP local-file-header or empty EOCD.
Matches "PK" then the local-file-header (0x03 0x04) or empty-archive EOCD (0x05 0x06) pair; a RAR is detected separately via ra8_rar_open.
| [in] | s | At least k_comic_sig_min readable bytes. |
s begins a ZIP archive. | true | A ZIP signature. |
| false | Not a ZIP signature. |
s addresses at least k_comic_sig_min bytes. s is the archive start. Definition at line 296 of file comic.c.
References k_zip_b0, k_zip_b1, k_zip_eocd_b2, k_zip_eocd_b3, k_zip_lfh_b2, k_zip_lfh_b3, and RA8_INTERNAL.
Referenced by internal_open_detect().
|
static |
ASCII-lowercase one byte, branchlessly (letters only).
Sets the case bit only for 'A'..'Z'; the unsigned-wrap range test is a single condition, so no other byte is altered.
| [in] | c | Byte to fold. |
c with the case bit set if it was an uppercase letter. | c | For any non-letter byte (unchanged). |
Definition at line 79 of file comic.c.
References k_ascii_alpha_n, k_ascii_case_sh, k_ascii_upper_a, and RA8_INTERNAL.
Referenced by internal_ends_with_ci().
|
static |
Lexicographic compare of two entry names (byte order, length tiebreak).
Unsigned byte compare over the shorter length, then the shorter name sorts first – the total order the page index is sorted by.
| [in] | a | First name bytes. |
| [in] | alen | First name length. |
| [in] | b | Second name bytes. |
| [in] | blen | Second name length. |
a sorts before, equal to, or after b. | 0 | The names are byte-identical and equal length. |
a / b hold alen / blen readable bytes. Definition at line 231 of file comic.c.
Referenced by internal_sort().
Detect the container and run its backend enumeration.
Reads the magic, dispatches to the CBZ or CBR backend, and leaves the page index populated (unsorted). Split from comic_open so the entry point stays within the function-size budget.
| [in,out] | c | Comic with backing + buffers already bound. |
| k_ra8_ok | A backend populated the index. |
| k_ra8_err_invalid_size | A short magic read. |
| k_ra8_err_not_supported | Neither a ZIP nor a RAR archive. |
| k_ra8_err_* | A backend error. |
c was zeroed then populated by the caller. Definition at line 361 of file comic.c.
References comic_stream_t::ctx, comic_t::ctx, internal_is_zip(), k_comic_kind_cbr, k_comic_kind_cbt, k_comic_kind_cbz, k_comic_magic_len, k_comic_sig_min, k_ra8_err_invalid_size, k_ra8_err_not_supported, k_ra8_ok, comic_t::kind, priv_comic_cbr_open(), priv_comic_cbt_open(), priv_comic_cbz_open(), RA8_INTERNAL, ra8_rar_open(), comic_t::rar, comic_stream_t::read, comic_t::read, comic_stream_t::size, comic_t::size, comic_t::stream, comic_t::tar, and unarch_tar_open().
Referenced by comic_open().
|
static |
Reject any NULL required argument to comic_open.
Runs the mandatory null guards (reader, page index, name arena) so the entry point stays within the function-size budget; scalars may be zero.
| [in] | c | Reader-to-populate pointer. |
| [in] | read | Archive byte reader. |
| [in] | pages | Caller page-index array. |
| [in] | names | Caller name arena. |
| k_ra8_ok | Every required argument is non-NULL. |
| k_ra8_err_null_ptr | Some required argument was NULL. |
Definition at line 331 of file comic.c.
References k_ra8_ok, RA8_CHECK_NULL_PTR, RA8_INTERNAL, and s_tag_comic.
Referenced by comic_open().
|
static |
Insertion-sort the page index by entry name (reading order).
Stable insertion sort over the resident index; page-count-bounded, no recursion. The name arena is immutable, so only the small page records move.
| [in,out] | c | Comic whose pages[0..page_count) is sorted in place. |
Definition at line 263 of file comic.c.
References internal_name_cmp(), comic_page_t::name_len, comic_page_t::name_off, comic_t::names, comic_t::page_count, comic_t::pages, and RA8_INTERNAL.
Referenced by comic_open().
| bool priv_comic_is_page_name | ( | const char * | name, |
| uint16_t | len ) |
Whether an archive entry name is a decodable comic page image.
A page qualifies when its base name is not a dotfile (skips hidden entries and macOS __MACOSX/._* AppleDouble resource forks) and it ends in an image extension the on-device decoder (stb_image) handles: .jpg, .jpeg, .png, .gif, .bmp (case-insensitive). Both / and \\ are treated as path separators for the base-name test.
| [in] | name | Entry name bytes (not NUL-terminated; len is authoritative). |
| [in] | len | Length of name in bytes. |
name is a page image to index. | true | name is a decodable, non-hidden page image. |
| false | name is hidden, a resource fork, or not a decodable image. |
name addresses at least len readable bytes (or len is 0). len is the true entry-name length. name / len. Definition at line 152 of file comic.c.
References internal_is_image_ext(), and RA8_PRIV.
Referenced by internal_add_entry(), internal_add_member(), and internal_add_member().
| ra8_err_t priv_comic_page_add | ( | comic_t * | c, |
| const char * | name, | ||
| uint16_t | name_len, | ||
| uint64_t | raw_size, | ||
| uint8_t | extractable, | ||
| uint8_t | method, | ||
| uint32_t | zip_index, | ||
| uint64_t | data_off, | ||
| uint64_t | pack_size ) |
Append one image member to the resident page index.
Copies name into the comic's name arena and fills the next comic_page_t slot with the backend bookkeeping. Rejects an index or arena overflow so no page is silently dropped.
| [in,out] | c | Comic accumulating its page index. |
| [in] | name | Entry name bytes. |
| [in] | name_len | Length of name in bytes. |
| [in] | raw_size | Encoded image length in bytes. |
| [in] | extractable | 1 if this reader can decode the page, else 0. |
| [in] | method | CBR ra8_rar_method_t (0 = store); 0 for CBZ. |
| [in] | zip_index | CBZ miniz central-directory index (0 for CBR). |
| [in] | data_off | CBR member data-area offset (0 for CBZ). |
| [in] | pack_size | CBR packed size (0 for CBZ). |
| k_ra8_ok | Page appended. |
| k_ra8_err_invalid_size | Page index or name arena is full. |
c has its pages / names buffers bound. name addresses name_len readable bytes. Definition at line 177 of file comic.c.
References comic_page_t::data_off, comic_page_t::extractable, k_ra8_err_invalid_size, k_ra8_ok, memcpy(), comic_page_t::name_len, comic_page_t::name_off, comic_t::names, comic_t::names_cap, comic_t::names_len, comic_page_t::pack_size, comic_t::page_cap, comic_t::page_count, comic_t::pages, RA8_CHECK_NULL_PTR, RA8_PRIV, comic_page_t::rar_method, comic_page_t::raw_size, s_tag_comic, and comic_page_t::zip_index.
Referenced by internal_add_entry(), internal_add_member(), and internal_add_member().
|
static |
Log tag for comic-facade diagnostics.
Definition at line 34 of file comic.c.
Referenced by comic_close(), comic_page_info(), comic_page_read(), internal_open_reject_null(), and priv_comic_page_add().