25typedef enum : uint8_t {
34 if ((s ==
nullptr) || (
strcmp(s,
"loose") == 0)) {
37 if (
strcmp(s,
"cbz") == 0) {
40 if (
strcmp(s,
"cbt") == 0) {
43 if (
strcmp(s,
"cbt.gz") == 0) {
46 if (
strcmp(s,
"epub") == 0) {
49 if (
strcmp(s,
"jof") == 0) {
52 if (
strcmp(s,
"rabook") == 0) {
110 const size_t nl =
strlen(name);
111 const size_t sl =
strlen(suffix);
115 const char* tail = name + (nl - sl);
116 for (
size_t i = 0U; i < sl; ++i) {
117 if (tolower((
unsigned char)tail[i]) != tolower((
unsigned char)suffix[i])) {
146 static const char*
const k_img_exts[] = {
".jpg",
".jpeg",
".png",
".webp",
".gif",
".bmp"};
147 for (
size_t i = 0U; i < (
sizeof(k_img_exts) /
sizeof(k_img_exts[0])); ++i) {
170 for (
size_t i = 1U; i < count; ++i) {
173 memcpy(held, names[i],
sizeof(held));
174 while ((cursor > 0U) && (
strcmp(names[cursor - 1U], held) > 0)) {
178 memcpy(names[cursor], held,
sizeof(held));
208 void* dir_workspace =
nullptr;
212 if (dir_workspace ==
nullptr) {
253 const size_t floor = ws->
used;
258 while ((err ==
k_ra8_ok) && entry) {
261 if ((err ==
k_ra8_ok) && entry && (value.
name[0] !=
'.') &&
303 uint64_t key = value->
year;
305 key = (key * 32U) + value->
day;
335 uint64_t latest_key = 0U;
336 for (
size_t i = 0U; i < count; ++i) {
348 if (!latest.
valid || (key > latest_key)) {
355 return snprintf(meta->
modified,
sizeof(meta->
modified),
"1970-01-01T00:00:00Z") > 0;
360 const int absolute = (offset < 0) ? -offset : offset;
363 "%04u-%02u-%02uT%02u:%02u:%02u%c%02d:%02d",
370 (offset < 0) ?
'-' :
'+',
376 "%04u-%02u-%02uT%02u:%02u:%02uZ",
471 const char* out_path,
482 return (aborted ==
k_ra8_ok) ? rc : aborted;
484 bool published =
false;
510 const char* chapter_dir,
516 if (meta !=
nullptr) {
525 if ((resolved->
modified[0] ==
'\0') &&
534 const char* chapter_dir,
535 const char* out_path,
539 if ((storage ==
nullptr) || (chapter_dir ==
nullptr) || (out_path ==
nullptr) ||
541 (ws->
data ==
nullptr)) {
553 if (names ==
nullptr) {
594 const char* chapter_dir,
595 const char* out_path,
599 if (chapter_dir !=
nullptr) {
ra8_err_t fw_fs_get_caps(const fw_fs_t *fs, fw_fs_caps_t *out)
Copy the immutable capability snapshot from a complete binding.
ra8_err_t fw_fs_stat(const fw_fs_namespace_t *names, const char *path, fw_fs_stat_t *out)
Query a path; a miss is success with out->exists == false.
ra8_err_t fw_fs_dir_next(fw_fs_dir_t *directory, fw_fs_dirent_value_t *out, bool *out_entry)
Copy one stable directory entry from an open cursor.
ra8_err_t fw_fs_dir_close(fw_fs_dir_t *directory)
Close and consume an open directory cursor, including on close error.
ra8_err_t fw_fs_dir_open(const fw_fs_namespace_t *names, const char *path, fw_fs_dir_t *directory, void *workspace, uint32_t workspace_size)
Open one directory cursor into caller-owned backend workspace.
@ k_fw_fs_node_file
Regular byte stream.
@ k_fw_fs_path_cap
Largest portable path including its NUL.
static uint64_t internal_timestamp_key(const fw_fs_datetime_t *value)
Map one civil timestamp to a stable ordering key.
bool mdl_format_is_dir_output(mdl_format_t fmt)
Whether fmt writes per-page sibling files rather than one container.
static ra8_err_t internal_export_dispatch(mdl_storage_t *storage, mdl_format_t fmt, const char *dir, char names[][k_name_max], size_t count, mdl_export_output_t *output, const mdl_export_meta_t *meta, mdl_export_workspace_t *ws)
Dispatch one selected container writer.
static void internal_sort_pages(char names[][k_name_max], size_t count)
Sort a bounded page-name table lexically in place.
static bool internal_ends_with_ci(const char *name, const char *suffix)
Test a filename suffix without ASCII case sensitivity.
mdl_format_t mdl_format_from_str(const char *s)
Map a --format string to a container kind.
static ra8_err_t internal_list_pages_open_dir(mdl_storage_t *storage, const char *dir, mdl_export_workspace_t *ws, fw_fs_dir_t *directory)
Open the chapter directory cursor into workspace-backed state.
const char * mdl_format_ext(mdl_format_t fmt)
File extension (without dot) for a format, e.g.
static bool internal_metadata_set_page_timestamp(mdl_storage_t *storage, mdl_export_meta_t *meta, const char *dir, const char names[][k_name_max], size_t count)
Derive a deterministic UTC modified timestamp from source pages.
ra8_err_t mdl_export_chapter_meta_ws(mdl_storage_t *storage, mdl_format_t fmt, const char *chapter_dir, const char *out_path, const mdl_export_meta_t *meta, mdl_export_workspace_t *ws)
Package a chapter with explicit metadata and caller-owned workspace.
mdl_export_time_radix_t
Mixed-radix civil timestamp geometry used for stable ordering.
@ k_export_month_radix
One-based month field radix.
@ k_export_seconds_per_minute
Civil seconds per minute.
@ k_export_minutes_per_hour
Civil minutes per hour.
@ k_export_hours_per_day
Civil hours per day.
static ra8_err_t internal_resolve_export_metadata(mdl_storage_t *storage, const char *chapter_dir, char names[][k_name_max], size_t count, const mdl_export_meta_t *meta, mdl_export_meta_t *resolved)
Resolve and validate metadata for one chapter export.
static ra8_err_t internal_export_transaction(mdl_storage_t *storage, mdl_format_t fmt, const char *dir, char names[][k_name_max], size_t count, const char *out_path, const mdl_export_meta_t *meta, mdl_export_workspace_t *ws)
Build out_path through one storage transaction.
static bool internal_is_page_image(const char *name)
True if name is a raster page image a reader engine can decode.
static ra8_err_t internal_list_pages(mdl_storage_t *storage, const char *dir, char names[][k_name_max], size_t cap, mdl_export_workspace_t *ws, size_t *out_count)
List and sort regular chapter image entries through a portable cursor.
ra8_err_t mdl_export_chapter_ws(mdl_storage_t *storage, mdl_format_t fmt, const char *chapter_dir, const char *out_path, mdl_export_workspace_t *ws)
Package a chapter after auto-loading bounded local metadata.
Package a downloaded chapter folder into a reader-openable container.
void * mdl_export_workspace_take(mdl_export_workspace_t *ws, size_t bytes, size_t alignment)
Reserve aligned bytes from an exporter arena.
struct mdl_export_workspace mdl_export_workspace_t
Caller-owned bounded arena for all exporter scratch state.
ra8_err_t mdl_meta_load_dir(mdl_storage_t *storage, mdl_export_meta_t *meta, const char *dir)
Load metadata from a directory by looking for metadata files.
void mdl_meta_init(mdl_export_meta_t *meta)
Initialise a metadata struct to empty/default values.
ra8_err_t priv_mdl_export_epub(mdl_storage_t *storage, const char *dir, char names[][k_name_max], size_t count, mdl_export_output_t *output, const mdl_export_meta_t *meta, mdl_export_workspace_t *ws)
Package chapter pages into a valid fixed-layout EPUB3.
Module-private contracts shared by chapter export writers.
ra8_err_t priv_mdl_export_rabook(mdl_storage_t *storage, const char *directory, char names[][k_name_max], size_t count, const char *destination, const mdl_export_meta_t *meta, mdl_export_workspace_t *workspace)
Compile one page directory into a strict chunked RABOOK artifact.
ra8_err_t priv_mdl_export_cbz(mdl_storage_t *storage, const char *dir, char names[][k_name_max], size_t count, mdl_export_output_t *output, const mdl_export_meta_t *meta, mdl_export_workspace_t *ws)
Write a CBZ into a caller-owned staged output.
ra8_err_t priv_mdl_export_tar_gzip(mdl_storage_t *storage, const char *dir, char names[][k_name_max], size_t count, mdl_export_output_t *output, const mdl_export_meta_t *meta, mdl_export_workspace_t *ws)
Write a gzip-wrapped CBT archive.
ra8_err_t priv_mdl_export_jof(mdl_storage_t *storage, const char *dir, const char names[][k_name_max], size_t count, mdl_export_workspace_t *ws)
Convert every page in a chapter directory to a sibling .jof atlas.
ra8_err_t priv_mdl_export_validate_source_url(const char *url)
Validate an optional bounded source-attribution URL.
@ k_max_pages
Maximum page entries per chapter.
@ k_name_max
Maximum entry-name bytes.
ra8_err_t priv_mdl_export_tar(mdl_storage_t *storage, const char *dir, char names[][k_name_max], size_t count, mdl_export_output_t *output, const mdl_export_meta_t *meta)
Write an uncompressed CBT tar archive.
ra8_err_t priv_mdl_export_path_join(char *out, size_t capacity, const char *directory, const char *leaf)
Join a canonical directory and leaf without truncation.
ra8_err_t priv_mdl_export_output_abort(mdl_export_output_t *output)
Abort one unpublished export stage, retaining cleanup failure.
ra8_err_t priv_mdl_export_output_commit(mdl_export_output_t *output, mdl_export_workspace_t *workspace, bool *out_published)
Structurally validate and publish one completed export stage.
ra8_err_t priv_mdl_export_output_begin(mdl_export_output_t *output, mdl_storage_t *storage, const char *destination, mdl_format_t format)
Bind a validated publication transaction to one destination.
Annotation-attribute framework macros for ra8-firmware.
#define RA8_INTERNAL
Marker that a function is intended to be static (file-local).
@ k_ra8_err_not_supported
Requested feature not compiled in, not wired, or not supported by this MCU variant.
@ k_ra8_err_empty
Container empty – nothing to retrieve.
@ k_ra8_fail
Generic unspecified failure.
@ k_ra8_err_invalid_arg
Invalid function argument.
@ k_ra8_ok
Success – operation completed with all postconditions satisfied.
@ 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.
int strcmp(const char *s1, const char *s2)
Compare two null-terminated strings.
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.
Static properties and workspace requirements of one bound port.
uint8_t directory_workspace_align
Required directory-state alignment.
uint32_t directory_workspace_bytes
State bytes required by dir open.
Backend-neutral civil time with nanosecond precision.
uint16_t year
Full civil year.
int16_t utc_offset_min
Offset from UTC when the validity flag is set.
uint8_t month
Month, 1..12.
uint8_t second
Second, 0..59.
uint8_t minute
Minute, 0..59.
Caller-owned open directory cursor; fields are private to the facade.
bool is_open
Facade lifecycle guard.
Stable caller-owned value returned by fw_fs_dir_next.
uint16_t name_bytes
Bytes excluding the NUL.
fw_fs_node_type_t type
Entry kind.
char name[k_fw_fs_path_cap]
Copied NUL-terminated leaf.
Result of a portable metadata query.
bool exists
False means a clean lookup miss.
fw_fs_node_type_t type
Kind of node at the path.
fw_fs_timestamp_t modified
Content modification time, when supported.
fw_fs_namespace_t names
Namespace operations.
One portable timestamp and independent availability facts.
fw_fs_datetime_t value
Decoded civil date and time.
bool utc_offset_valid
True when utc_offset_min is known.
bool valid
True when the field is meaningful.
bool active
Begin succeeded.
One validated staged publication, including random ZIP backfill.
mdl_storage_txn_t writer
Active storage transaction.
size_t high_water
Largest used value observed.
size_t used
Current allocation high edge.
uint8_t * data
Writable arena bytes.
One non-reentrant downloader filesystem dependency bundle.
const fw_fs_t * fs
Injected portable filesystem.
fw_fs_transaction_t transaction
Active private filesystem stage.