ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
rabook_import.c
Go to the documentation of this file.
1
12
13#include "rabook_import.h"
14
15#include <stddef.h>
16#include <stdint.h>
17#include <string.h>
18
19#include "ra8_attributes.h"
20#include "ra8_check.h"
21#include "ra8_err.h"
22#include "ra8_fs.h"
23#include "ra8_log.h"
25
26/* -------------------------------------------------------------------------- */
27/* Private constants */
28/* -------------------------------------------------------------------------- */
29
35typedef enum : uint32_t {
36 k_crc32_poly = 0xEDB88320U,
37 k_crc32_seed = 0xFFFFFFFFU,
39
45typedef enum : uint32_t {
49
51static const char* const s_tag = "rabook_import";
52
53/* -------------------------------------------------------------------------- */
54/* Private helpers */
55/* -------------------------------------------------------------------------- */
56
76RA8_INTERNAL static uint32_t internal_crc32_block(uint32_t crc, const uint8_t* data, uint32_t len)
77{
78 if (data == nullptr) {
79 return crc;
80 }
81 if (len == 0U) {
82 return crc;
83 }
84 uint32_t running_crc = crc;
85 for (uint32_t i = 0U; i < len; i++) {
86 running_crc ^= data[i];
87 for (uint8_t b = 0U; b < (uint8_t)k_crc32_bits; b++) {
88 const bool lsb = (running_crc & 1U) != 0U;
89 running_crc >>= 1U;
90 if (lsb) {
91 running_crc ^= (uint32_t)k_crc32_poly;
92 }
93 }
94 }
95 return running_crc;
96}
97
122 void* read_ctx,
123 uint64_t expected_size,
124 uint8_t* buf,
125 uint32_t cap,
126 uint32_t* crc,
127 uint32_t* total)
128{
129 uint64_t remain = expected_size - (uint64_t)*total;
130 uint32_t request = cap;
131 if (remain < (uint64_t)request) {
132 request = (uint32_t)remain;
133 }
134 uint32_t got = 0U;
135 const ra8_err_t err = read_fn(read_ctx, buf, request, &got);
136 if (err != k_ra8_ok) {
137 return err;
138 }
139 if ((got == 0U) || (got > request)) {
141 }
142 *crc = internal_crc32_block(*crc, buf, got);
143 *total += got;
144 return k_ra8_ok;
145}
146
171 const uint8_t* buf,
172 const uint32_t* out_size,
173 const uint32_t* out_crc,
174 uint64_t expected_size,
175 uint32_t cap,
176 uint32_t max_reads)
177{
178 if (read_fn == nullptr) {
179 ra8_log_error(s_tag, "read_fn is NULL");
180 return k_ra8_err_null_ptr;
181 }
182 RA8_CHECK_NULL_PTR(buf, s_tag, "buf");
183 RA8_CHECK_NULL_PTR(out_size, s_tag, "out_size");
184 RA8_CHECK_NULL_PTR(out_crc, s_tag, "out_crc");
185 if ((cap == 0U) || (expected_size > (uint64_t)UINT32_MAX)) {
187 }
188 const uint64_t required_reads =
189 (expected_size / (uint64_t)cap) + (((expected_size % (uint64_t)cap) != 0U) ? 1U : 0U);
190 if (required_reads > (uint64_t)max_reads) {
192 }
193 return k_ra8_ok;
194}
195
197 void* read_ctx,
198 uint64_t expected_size,
199 uint8_t* buf,
200 uint32_t cap,
201 uint32_t max_reads,
202 uint32_t* out_size,
203 uint32_t* out_crc)
204{
205 const ra8_err_t arg_err = internal_crc_stream_validate_args(read_fn,
206 buf,
207 out_size,
208 out_crc,
209 expected_size,
210 cap,
211 max_reads);
212 if (arg_err != k_ra8_ok) {
213 return arg_err;
214 }
215
216 uint32_t crc = (uint32_t)k_crc32_seed;
217 uint32_t total = 0U;
218 for (uint32_t i = 0U; (i < max_reads) && ((uint64_t)total < expected_size); ++i) {
219 const ra8_err_t err =
220 internal_crc_stream_read_chunk(read_fn, read_ctx, expected_size, buf, cap, &crc, &total);
221 if (err != k_ra8_ok) {
222 return err;
223 }
224 }
225 if ((uint64_t)total != expected_size) {
227 }
228 uint32_t extra = 0U;
229 const ra8_err_t err = read_fn(read_ctx, buf, 1U, &extra);
230 if (err != k_ra8_ok) {
231 return err;
232 }
233 if (extra != 0U) {
235 }
236 *out_size = total;
237 *out_crc = crc ^ (uint32_t)k_crc32_seed;
238 return k_ra8_ok;
239}
240
242 void* read_ctx,
243 uint64_t expected_size,
244 uint8_t* buf,
245 uint32_t cap,
246 uint32_t max_reads,
247 uint32_t* out_size,
248 uint32_t* out_crc)
249{
250 return priv_rabook_import_crc_stream(read_fn,
251 read_ctx,
252 expected_size,
253 buf,
254 cap,
255 max_reads,
256 out_size,
257 out_crc);
258}
259
279internal_import_fs_read(void* ctx, uint8_t* buf, uint32_t requested, uint32_t* out_read)
280{
281 return ra8_fs_read((ra8_fs_file_t*)ctx, buf, requested, out_read);
282}
283
309 uint8_t* buf,
310 uint32_t cap,
311 uint32_t* out_size,
312 uint32_t* out_crc)
313{
314 RA8_CHECK_NULL_PTR(file, s_tag, "file");
315 RA8_CHECK_NULL_PTR(buf, s_tag, "buf");
316
317 uint64_t expected_size = 0U;
318 ra8_err_t err = ra8_fs_size(file, &expected_size);
319 if (err != k_ra8_ok) {
320 return err;
321 }
323 file,
324 expected_size,
325 buf,
326 cap,
327 (uint32_t)k_import_max_chunks,
328 out_size,
329 out_crc);
330}
331
357 const char* epub_path,
358 uint8_t* buf,
359 uint32_t cap,
360 uint32_t* out_size,
361 uint32_t* out_crc)
362{
363 RA8_CHECK_NULL_PTR(out_size, s_tag, "out_size");
364 RA8_CHECK_NULL_PTR(out_crc, s_tag, "out_crc");
365 if (cap == 0U) {
367 }
368
369 ra8_fs_file_t* file = nullptr;
370 ra8_err_t err = ra8_fs_open(mount, epub_path, k_ra8_fs_mode_read, &file);
371 if (err != k_ra8_ok) {
372 return err;
373 }
374 err = internal_crc_stream(file, buf, cap, out_size, out_crc);
375 ra8_err_t cerr = ra8_fs_close(file);
376 if (err != k_ra8_ok) {
377 return err;
378 }
379 return cerr;
380}
381
404RA8_INTERNAL static ra8_err_t internal_derive_stem(const char* epub_path, char* out, uint32_t cap)
405{
406 RA8_CHECK_NULL_PTR(epub_path, s_tag, "epub_path");
407 RA8_CHECK_NULL_PTR(out, s_tag, "out");
408
409 size_t start = 0U;
410 size_t i = 0U;
411 for (; epub_path[i] != '\0'; i++) {
412 if (epub_path[i] == '/') {
413 start = i + 1U;
414 }
415 }
416 size_t len = i - start;
417 for (size_t j = len; j > 1U; j--) {
418 if (epub_path[start + j - 1U] == '.') {
419 len = j - 1U;
420 break;
421 }
422 }
423 if (len == 0U) {
425 }
426 if (len >= (size_t)cap) {
428 }
429 (void)memcpy(out, &epub_path[start], len);
430 out[len] = '\0';
431 return k_ra8_ok;
432}
433
455internal_make_name(const char* stem, const char* suffix, char* out, uint32_t cap)
456{
457 RA8_CHECK_NULL_PTR(stem, s_tag, "stem");
458 RA8_CHECK_NULL_PTR(suffix, s_tag, "suffix");
459 RA8_CHECK_NULL_PTR(out, s_tag, "out");
460 const size_t sn = strlen(stem);
461 const size_t xn = strlen(suffix);
462 if ((sn + xn + 1U) > (size_t)cap) {
464 }
465 (void)memcpy(out, stem, sn);
466 (void)memcpy(&out[sn], suffix, xn);
467 out[sn + xn] = '\0';
468 return k_ra8_ok;
469}
470
491internal_derive_names(const char* stem, char* cache_name, char* tmp_name, char* mark_name)
492{
493 RA8_CHECK_NULL_PTR(cache_name, s_tag, "cache_name");
494 RA8_CHECK_NULL_PTR(tmp_name, s_tag, "tmp_name");
495 RA8_CHECK_NULL_PTR(mark_name, s_tag, "mark_name");
496 static const char* const ext_cache = ".rabook"; /* cache blob */
497 static const char* const ext_tmp = ".rabook.tmp"; /* crash-safe temp */
498 static const char* const ext_mark = ".rabook.mrk"; /* freshness marker */
499 const uint32_t cap = (uint32_t)k_rabook_import_name_cap;
500 ra8_err_t err = internal_make_name(stem, ext_cache, cache_name, cap);
501 if (err != k_ra8_ok) {
502 return err;
503 }
504 err = internal_make_name(stem, ext_tmp, tmp_name, cap);
505 if (err != k_ra8_ok) {
506 return err;
507 }
508 return internal_make_name(stem, ext_mark, mark_name, cap);
509}
510
528RA8_INTERNAL static bool internal_file_exists(ra8_fs_mount_t* mount, const char* path)
529{
530 if (mount == nullptr) {
531 return false;
532 }
533 if (path == nullptr) {
534 return false;
535 }
536 ra8_fs_file_t* file = nullptr;
537 ra8_err_t err = ra8_fs_open(mount, path, k_ra8_fs_mode_read, &file);
538 if (err != k_ra8_ok) {
539 return false;
540 }
541 (void)ra8_fs_close(file);
542 return true;
543}
544
567{
568 RA8_CHECK_NULL_PTR(mount, s_tag, "mount");
569 RA8_CHECK_NULL_PTR(path, s_tag, "path");
570 RA8_CHECK_NULL_PTR(out, s_tag, "out");
571
572 ra8_fs_file_t* file = nullptr;
573 ra8_err_t err = ra8_fs_open(mount, path, k_ra8_fs_mode_read, &file);
574 if (err != k_ra8_ok) {
575 return err;
576 }
577 uint32_t got = 0U;
578 err = ra8_fs_read(file, (uint8_t*)out, (uint32_t)sizeof(*out), &got);
579 ra8_err_t cerr = ra8_fs_close(file);
580 if (err != k_ra8_ok) {
581 return err;
582 }
583 if (got != (uint32_t)sizeof(*out)) {
585 }
586 return cerr;
587}
588
609 const char* mark_path,
610 const rabook_import_stamp_t* want)
611{
612 if (mount == nullptr) {
613 return false;
614 }
615 if (want == nullptr) {
616 return false;
617 }
618 rabook_import_stamp_t got = {};
619 ra8_err_t err = internal_read_stamp(mount, mark_path, &got);
620 if (err != k_ra8_ok) {
621 return false;
622 }
623 return (got.magic == want->magic) && (got.format_version == want->format_version) &&
624 (got.importer_version == want->importer_version) &&
625 (got.source_size == want->source_size) && (got.source_crc32 == want->source_crc32);
626}
627
648internal_write_stamp(ra8_fs_mount_t* mount, const char* path, const rabook_import_stamp_t* stamp)
649{
650 RA8_CHECK_NULL_PTR(mount, s_tag, "mount");
651 RA8_CHECK_NULL_PTR(path, s_tag, "path");
652 RA8_CHECK_NULL_PTR(stamp, s_tag, "stamp");
653 (void)ra8_fs_unlink(mount, path);
654 return ra8_fs_write_file(mount, path, (const uint8_t*)stamp, (uint32_t)sizeof(*stamp));
655}
656
675internal_atomic_replace(ra8_fs_mount_t* mount, const char* tmp_path, const char* dst_path)
676{
677 RA8_CHECK_NULL_PTR(mount, s_tag, "mount");
678 RA8_CHECK_NULL_PTR(tmp_path, s_tag, "tmp_path");
679 RA8_CHECK_NULL_PTR(dst_path, s_tag, "dst_path");
680 (void)ra8_fs_unlink(mount, dst_path);
681 return ra8_fs_rename(mount, tmp_path, dst_path);
682}
683
703RA8_INTERNAL static ra8_err_t internal_copy_name(char* dst, uint32_t cap, const char* src)
704{
705 RA8_CHECK_NULL_PTR(dst, s_tag, "dst");
706 RA8_CHECK_NULL_PTR(src, s_tag, "src");
707 for (uint32_t i = 0U; i < cap; i++) {
708 dst[i] = src[i];
709 if (src[i] == '\0') {
710 return k_ra8_ok;
711 }
712 }
714}
715
739 const char* epub_path,
740 const char* cache_name,
741 const char* tmp_name,
742 const char* mark_name,
743 const rabook_import_stamp_t* want)
744{
745 RA8_CHECK_NULL_PTR(cfg, s_tag, "cfg");
746 RA8_CHECK_NULL_PTR(cfg->compile, s_tag, "cfg->compile");
747 RA8_CHECK_NULL_PTR(want, s_tag, "want");
748 (void)ra8_fs_unlink(cfg->mount, tmp_name);
749 ra8_err_t err = cfg->compile(cfg->compile_ctx, cfg->mount, epub_path, tmp_name);
750 if (err != k_ra8_ok) {
751 ra8_log_error(s_tag, "compile seam failed");
752 return err;
753 }
754 err = internal_atomic_replace(cfg->mount, tmp_name, cache_name);
755 if (err != k_ra8_ok) {
756 return err;
757 }
758 return internal_write_stamp(cfg->mount, mark_name, want);
759}
760
786 const char* epub_path,
787 const char* out_cache_path,
788 uint32_t cache_path_cap,
789 const rabook_import_outcome_t* out_outcome)
790{
791 RA8_CHECK_NULL_PTR(cfg, s_tag, "cfg");
792 RA8_CHECK_NULL_PTR(epub_path, s_tag, "epub_path");
793 RA8_CHECK_NULL_PTR(out_cache_path, s_tag, "out_cache_path");
794 RA8_CHECK_NULL_PTR(out_outcome, s_tag, "out_outcome");
795 RA8_CHECK_NULL_PTR(cfg->mount, s_tag, "cfg->mount");
796 if (cache_path_cap == 0U) {
798 }
799 return k_ra8_ok;
800}
801
802/* -------------------------------------------------------------------------- */
803/* Public API */
804/* -------------------------------------------------------------------------- */
805
807 const char* epub_path,
808 char* out_cache_path,
809 uint32_t cache_path_cap,
810 rabook_import_outcome_t* out_outcome)
811{
812 ra8_err_t err =
813 internal_validate_open_args(cfg, epub_path, out_cache_path, cache_path_cap, out_outcome);
814 if (err != k_ra8_ok) {
815 return err;
816 }
817 /* Derive the cache names from the source's own basename FIRST, so a bad name
818 * or a too-small output buffer is refused before the source is streamed or
819 * the compiler is invoked (a compile must never run for a doomed request). */
820 char stem[k_rabook_import_name_cap];
821 err = internal_derive_stem(epub_path, stem, (uint32_t)k_rabook_import_name_cap);
822 if (err != k_ra8_ok) {
823 return err;
824 }
825 char cache_name[k_rabook_import_name_cap];
826 char tmp_name[k_rabook_import_name_cap];
827 char mark_name[k_rabook_import_name_cap];
828 err = internal_derive_names(stem, cache_name, tmp_name, mark_name);
829 if (err != k_ra8_ok) {
830 return err;
831 }
832 if ((strlen(cache_name) + 1U) > (size_t)cache_path_cap) {
834 }
835
836 uint32_t src_size = 0U;
837 uint32_t src_crc = 0U;
839 epub_path,
840 cfg->scratch,
841 cfg->scratch_cap,
842 &src_size,
843 &src_crc);
844 if (err != k_ra8_ok) {
845 return err;
846 }
847
848 const rabook_import_stamp_t want = {
849 .magic = (uint32_t)k_rabook_import_stamp_magic,
850 .format_version = cfg->format_version,
851 .importer_version = cfg->importer_version,
852 .source_size = src_size,
853 .source_crc32 = src_crc,
854 };
855
856 if (internal_cache_is_fresh(cfg->mount, mark_name, &want)) {
857 if (internal_file_exists(cfg->mount, cache_name)) {
858 *out_outcome = k_rabook_import_hit;
859 return internal_copy_name(out_cache_path, cache_path_cap, cache_name);
860 }
861 }
862
863 err = internal_compile_and_cache(cfg, epub_path, cache_name, tmp_name, mark_name, &want);
864 if (err != k_ra8_ok) {
865 return err;
866 }
867 *out_outcome = k_rabook_import_compiled;
868 return internal_copy_name(out_cache_path, cache_path_cap, cache_name);
869}
@ k_crc32_poly
Reflected CRC-32 polynomial.
Definition cpu1_main.c:156
@ k_crc32_bits
Bits folded per input byte.
Definition cpu1_main.c:165
static const char * s_tag
Logging / check tag.
Definition ra8_app.c:17
Annotation-attribute framework macros for ra8-firmware.
#define RA8_PRIV
Module-private helper: shared across TUs but only inside one library.
#define RA8_TEST_HELPER
Mark a symbol as externally-linked but only callable from tests.
#define RA8_INTERNAL
Marker that a function is intended to be static (file-local).
Validation and Error-Checking Macros for ra8-firmware.
#define RA8_CHECK_NULL_PTR(ptr, tag, message)
Reject nullptr pointer, returning k_ra8_err_null_ptr.
Definition ra8_check.h:243
Error Code Definitions for ra8-firmware.
@ k_ra8_err_invalid_arg
Invalid function argument.
Definition ra8_err.h:152
@ k_ra8_ok
Success – operation completed with all postconditions satisfied.
Definition ra8_err.h:119
@ k_ra8_err_null_ptr
Pointer was NULL where a valid pointer was required.
Definition ra8_err.h:478
@ k_ra8_err_invalid_size
Invalid size parameter (too large, too small, or misaligned).
Definition ra8_err.h:167
ra8_err_codes_t ra8_err_t
Canonical error-return type used by every ra8-firmware API.
Definition ra8_err.h:546
size_t strlen(const char *s)
Calculate string length.
void * memcpy(void *dst, const void *src, size_t n)
Copy memory area between non-overlapping regions.
Minimal FAT12/FAT16/FAT32 filesystem adapter (read + write).
ra8_err_t ra8_fs_rename(const ra8_fs_mount_t *handle, const char *old_path, const char *new_path)
Rename a file within its own directory.
ra8_err_t ra8_fs_size(const ra8_fs_file_t *file, uint64_t *out_bytes)
Report the file's size in bytes (64-bit on exFAT, #676).
ra8_err_t ra8_fs_read(ra8_fs_file_t *file, uint8_t *buf, uint32_t max_len, uint32_t *got_len)
Read up to max_len bytes; advance the cluster chain on cluster crossings.
ra8_err_t ra8_fs_unlink(const ra8_fs_mount_t *handle, const char *path)
Delete a file: mark its dir entry deleted and free its clusters.
ra8_err_t ra8_fs_open(ra8_fs_mount_t *handle, const char *path, ra8_fs_mode_t mode, ra8_fs_file_t **out_file)
Open or create a file by path, 8.3 or long.
ra8_err_t ra8_fs_close(ra8_fs_file_t *file)
Close an open file, stamping its final modification time.
ra8_err_t ra8_fs_write_file(ra8_fs_mount_t *handle, const char *path, const uint8_t *data, uint32_t len)
Create a whole file in one call (provisioning helper).
@ k_ra8_fs_mode_read
Read-only, must exist.
Lightweight Logging Interface for ra8-firmware.
#define ra8_log_error(tag, message)
RA8 log error.
Definition ra8_log.h:335
static ra8_err_t internal_crc_stream(ra8_fs_file_t *file, uint8_t *buf, uint32_t cap, uint32_t *out_size, uint32_t *out_crc)
Fold an already-open file through CRC-32 in bounded chunks.
static ra8_err_t internal_derive_names(const char *stem, char *cache_name, char *tmp_name, char *mark_name)
Derive the cache (.rabook), temp (.rabook.tmp), and marker (.rabook.mrk) names from the source stem.
static ra8_err_t internal_compute_source_key(ra8_fs_mount_t *mount, const char *epub_path, uint8_t *buf, uint32_t cap, uint32_t *out_size, uint32_t *out_crc)
Stream a source file through CRC-32, reporting its size and key.
static ra8_err_t internal_read_stamp(ra8_fs_mount_t *mount, const char *path, rabook_import_stamp_t *out)
Read a freshness marker file into a stamp record.
static ra8_err_t internal_crc_stream_validate_args(rabook_import_read_fn read_fn, const uint8_t *buf, const uint32_t *out_size, const uint32_t *out_crc, uint64_t expected_size, uint32_t cap, uint32_t max_reads)
Validate the crc-stream entry point's arguments.
ra8_import_crc_const_t
CRC-32/ISO-HDLC parameters (reflected, matches zlib.crc32).
@ k_crc32_seed
Pre/post conditioning (init = final).
static ra8_err_t internal_validate_open_args(const rabook_import_cfg_t *cfg, const char *epub_path, const char *out_cache_path, uint32_t cache_path_cap, const rabook_import_outcome_t *out_outcome)
Validate the public entry's arguments and the mount dependency.
ra8_err_t priv_rabook_import_crc_stream(rabook_import_read_fn read_fn, void *read_ctx, uint64_t expected_size, uint8_t *buf, uint32_t cap, uint32_t max_reads, uint32_t *out_size, uint32_t *out_crc)
Compute one exact bounded source CRC through an injected reader.
static ra8_err_t internal_crc_stream_read_chunk(rabook_import_read_fn read_fn, void *read_ctx, uint64_t expected_size, uint8_t *buf, uint32_t cap, uint32_t *crc, uint32_t *total)
Read and CRC-fold one bounded chunk of the expected stream.
static ra8_err_t internal_write_stamp(ra8_fs_mount_t *mount, const char *path, const rabook_import_stamp_t *stamp)
Write a fresh marker file, replacing any stale one.
static ra8_err_t internal_import_fs_read(void *ctx, uint8_t *buf, uint32_t requested, uint32_t *out_read)
Adapt the generic bounded CRC reader to one open filesystem file.
static ra8_err_t internal_derive_stem(const char *epub_path, char *out, uint32_t cap)
Extract the cache-name stem from a source path: its basename, minus a trailing extension.
static bool internal_file_exists(ra8_fs_mount_t *mount, const char *path)
Report whether a root-level file can be opened for reading.
static bool internal_cache_is_fresh(ra8_fs_mount_t *mount, const char *mark_path, const rabook_import_stamp_t *want)
Decide if the cached marker matches the expected stamp.
ra8_err_t rabook_import_crc_stream_test(rabook_import_read_fn read_fn, void *read_ctx, uint64_t expected_size, uint8_t *buf, uint32_t cap, uint32_t max_reads, uint32_t *out_size, uint32_t *out_crc)
Exercise the bounded source-key CRC contract from focused tests.
static ra8_err_t internal_atomic_replace(ra8_fs_mount_t *mount, const char *tmp_path, const char *dst_path)
Atomically replace dst_path with tmp_path (temp+rename).
ra8_import_misc_t
Small fixed quantities used by the name + CRC helpers.
@ k_import_max_chunks
Loop bound: chunks streamed for the CRC.
static ra8_err_t internal_compile_and_cache(const rabook_import_cfg_t *cfg, const char *epub_path, const char *cache_name, const char *tmp_name, const char *mark_name, const rabook_import_stamp_t *want)
Compile-on-miss: temp compile, atomic promote, fresh marker.
static ra8_err_t internal_make_name(const char *stem, const char *suffix, char *out, uint32_t cap)
Build <stem><suffix> into out, bounded by cap.
static ra8_err_t internal_copy_name(char *dst, uint32_t cap, const char *src)
Copy a NUL-terminated name into a caller buffer, bounded by capacity.
static uint32_t internal_crc32_block(uint32_t crc, const uint8_t *data, uint32_t len)
Fold a byte block into a running CRC-32/ISO-HDLC accumulator.
ra8_err_t rabook_import_open(const rabook_import_cfg_t *cfg, const char *epub_path, char *out_cache_path, uint32_t cache_path_cap, rabook_import_outcome_t *out_outcome)
Resolve a source .epub to a fresh cached .rabook, compiling once.
On-import EPUB -> .rabook compile-and-cache manager (#151).
@ k_rabook_import_name_cap
Cache/temp/marker name buffer bytes incl.
rabook_import_outcome_t
How rabook_import_open satisfied the request.
@ k_rabook_import_hit
Fresh cache reused; the compiler was NOT invoked.
@ k_rabook_import_compiled
Miss/stale; the book was compiled and cached.
@ k_rabook_import_stamp_magic
Importer marker tag "RBK1".
Module-private bounded source-key streaming contracts.
ra8_err_t(* rabook_import_read_fn)(void *ctx, uint8_t *buf, uint32_t requested, uint32_t *out_read)
Exact sequential-reader seam used by the source-key CRC pass.
Open-file state.
Cached parse of one mounted FAT volume.
Injected dependencies + versioning for rabook_import_open.
uint32_t scratch_cap
Capacity of scratch in bytes.
ra8_fs_mount_t * mount
Mounted FAT volume (cache + source).
void * compile_ctx
Cookie forwarded to compile.
rabook_import_compile_fn compile
Compile-on-miss seam (non-NULL).
uint32_t format_version
.rabook format version stamp.
uint8_t * scratch
Streaming buffer for the source CRC.
uint32_t importer_version
Importer/compiler version stamp.
Body of the sidecar freshness marker (<name>.rabook.mrk).
uint32_t format_version
.rabook (RABOOK1) on-disk layout revision.
uint32_t importer_version
Compiler/importer stamp; bump to invalidate.
uint32_t source_size
Byte length of the source .epub.
uint32_t magic
k_rabook_import_stamp_magic.
uint32_t source_crc32
CRC-32/ISO-HDLC of the source .epub bytes.