ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
mdl_export_rabook.c
Go to the documentation of this file.
1
14
15#include <stddef.h>
16#include <string.h>
17
18#include "book.h"
20#include "miniz.h"
22#include "ra8_rabook_pipeline.h"
23
46
55
73 mdl_rabook_profile_t* profile)
74{
75 ra8_rabook_buffers_t* const builder = &profile->builder;
76 builder->chapters = mdl_export_workspace_take(workspace,
77 k_rabook_chapter_cap * sizeof(*builder->chapters),
78 _Alignof(book_chapter_t));
79 builder->nodes = mdl_export_workspace_take(workspace,
80 k_rabook_node_cap * sizeof(*builder->nodes),
81 _Alignof(book_node_t));
82 builder->attrs = mdl_export_workspace_take(workspace,
83 k_rabook_attr_cap * sizeof(*builder->attrs),
84 _Alignof(book_attr_t));
85 builder->stylesheets =
87 k_rabook_style_cap * sizeof(*builder->stylesheets),
88 _Alignof(book_stylesheet_t));
89 builder->images = mdl_export_workspace_take(workspace,
90 k_rabook_image_cap * sizeof(*builder->images),
91 _Alignof(book_image_t));
93 builder->image_pool =
94 mdl_export_workspace_take(workspace, k_rabook_image_pool_bytes, _Alignof(max_align_t));
95 builder->out = mdl_export_workspace_take(workspace, k_rabook_flat_bytes, _Alignof(max_align_t));
96 if ((builder->chapters == nullptr) || (builder->nodes == nullptr) ||
97 (builder->attrs == nullptr) || (builder->stylesheets == nullptr) ||
98 (builder->images == nullptr) || (builder->string_pool == nullptr) ||
99 (builder->image_pool == nullptr) || (builder->out == nullptr)) {
101 }
103 builder->node_cap = k_rabook_node_cap;
104 builder->attr_cap = k_rabook_attr_cap;
106 builder->image_cap = k_rabook_image_cap;
109 builder->out_cap = k_rabook_flat_bytes;
110 return k_ra8_ok;
111}
112
130 mdl_rabook_profile_t* profile)
131{
132 profile->book =
133 mdl_export_workspace_take(workspace, sizeof(*profile->book), _Alignof(epub_book_t));
134 uint8_t* xhtml = mdl_export_workspace_take(workspace, k_rabook_xhtml_bytes, 1U);
135 uint8_t* raw =
136 mdl_export_workspace_take(workspace, k_rabook_image_raw_bytes, _Alignof(max_align_t));
137 uint8_t* arena =
138 mdl_export_workspace_take(workspace, k_rabook_image_arena_bytes, _Alignof(max_align_t));
139 uint8_t* gray = mdl_export_workspace_take(workspace, k_rabook_gray_bytes, _Alignof(max_align_t));
140 char* css = mdl_export_workspace_take(workspace, k_rabook_css_bytes, 1U);
142 mdl_export_workspace_take(workspace, sizeof(*xml), _Alignof(ra8_rabook_xml_workspace_t));
143 if ((profile->book == nullptr) || (xhtml == nullptr) || (raw == nullptr) || (arena == nullptr) ||
144 (gray == nullptr) || (css == nullptr) || (xml == nullptr)) {
146 }
147 profile->image_arena = (ra8_img_arena_t){.base = arena, .cap = k_rabook_image_arena_bytes};
148 profile->pipeline = (ra8_rabook_pipeline_scratch_t){.xhtml = xhtml,
149 .xhtml_cap = k_rabook_xhtml_bytes,
150 .image_raw = raw,
151 .image_cap = k_rabook_image_raw_bytes,
152 .img_arena = &profile->image_arena,
153 .gray = gray,
154 .gray_cap = k_rabook_gray_bytes,
155 .css = css,
156 .css_cap = k_rabook_css_bytes,
157 .max_image_edge = k_rabook_max_image_edge,
158 .pixel_format = k_book_pixfmt_gray4,
159 .xml_workspace = xml};
160 (void)memset(profile->book, 0, sizeof(*profile->book));
161 return k_ra8_ok;
162}
163
181 mdl_rabook_profile_t* profile)
182{
183 ra8_rabook_container_workspace_t* const container = &profile->container;
184 container->input =
185 mdl_export_workspace_take(workspace, k_rabook_chunk_bytes, _Alignof(max_align_t));
186 container->compressed =
187 mdl_export_workspace_take(workspace, k_rabook_compressed_bytes, _Alignof(max_align_t));
188 container->compressor =
189 mdl_export_workspace_take(workspace, sizeof(tdefl_compressor), _Alignof(max_align_t));
190 container->offsets =
192 k_rabook_offset_entries * sizeof(*container->offsets),
193 _Alignof(uint64_t));
194 if ((container->input == nullptr) || (container->compressed == nullptr) ||
195 (container->compressor == nullptr) || (container->offsets == nullptr)) {
197 }
198 container->input_cap = k_rabook_chunk_bytes;
200 container->compressor_cap = sizeof(tdefl_compressor);
202 return k_ra8_ok;
203}
204
222 mdl_rabook_profile_t* profile)
223{
224 *profile = (mdl_rabook_profile_t){};
225 ra8_err_t error = internal_allocate_builder(workspace, profile);
226 if (error == k_ra8_ok) {
227 error = internal_allocate_pipeline(workspace, profile);
228 }
229 if (error == k_ra8_ok) {
230 error = internal_allocate_container(workspace, profile);
231 }
232 return error;
233}
234
259 const char* directory,
260 char names[][k_name_max],
261 size_t count,
262 const char* destination,
263 const mdl_export_meta_t* meta,
264 mdl_export_workspace_t* workspace,
265 char* temp_path,
266 bool* temp_exists)
267{
268 *temp_exists = false;
269 mdl_export_output_t output = {};
271 storage,
272 directory,
273 destination,
274 temp_path,
276 if (error == k_ra8_ok) {
277 error = priv_mdl_export_epub(storage, directory, names, count, &output, meta, workspace);
278 }
279 if ((error != k_ra8_ok) && output.writer.transaction.active) {
280 const ra8_err_t aborted = priv_mdl_export_output_abort(&output);
281 return (aborted == k_ra8_ok) ? error : aborted;
282 }
283 if (error == k_ra8_ok) {
284 error = priv_mdl_export_output_commit(&output, workspace, temp_exists);
285 }
286 return error;
287}
288
313{
314 ra8_err_t result = error;
315 if ((book != nullptr) && (book->in_use != 0U)) {
316 const ra8_err_t closed = epub_close(book);
317 if ((result == k_ra8_ok) && (closed != k_ra8_ok)) {
318 result = closed;
319 }
320 }
321 if (source->file.is_open) {
322 const ra8_err_t closed = priv_mdl_rabook_epub_close(source);
323 if ((result == k_ra8_ok) && (closed != k_ra8_ok)) {
324 result = closed;
325 }
326 }
327 return result;
328}
329
349 size_t page_count)
350{
351 const book_header_t* header = book_header(blob);
352 const uint32_t expected_pages = (uint32_t)page_count;
353 if ((header->chapter_count != expected_pages) || (header->image_count < expected_pages) ||
354 (header->image_count > (expected_pages + 1U))) {
356 }
357 return k_ra8_ok;
358}
359
381 const char* temp_path,
382 size_t page_count,
383 mdl_export_workspace_t* workspace,
384 mdl_rabook_profile_t* profile,
386{
387 workspace->used = 0U;
388 ra8_err_t error = internal_allocate_profile(workspace, profile);
389 mdl_rabook_epub_source_t source = {};
390 if (error == k_ra8_ok) {
391 error = priv_mdl_rabook_epub_open(&source, storage, temp_path);
392 }
394 .ctx = &source,
395 .size = source.size_bytes};
396 if (error == k_ra8_ok) {
397 error = epub_open_streamed(&media, temp_path, profile->book);
398 }
399 const void* blob = nullptr;
400 uint32_t length = 0U;
401 if (error == k_ra8_ok) {
403 &profile->builder,
404 &profile->pipeline,
405 &blob,
406 &length);
407 }
408 if ((error == k_ra8_ok) && (source.error != k_ra8_ok)) {
409 error = source.error;
410 }
411 error = internal_close_compile_sources(error, profile->book, &source);
412 if (error == k_ra8_ok) {
413 error = book_validate(blob, length);
414 }
415 if (error == k_ra8_ok) {
416 error = internal_check_compiled_page_count(blob, page_count);
417 }
418 if (error == k_ra8_ok) {
419 *flat = (mdl_rabook_flat_source_t){.bytes = blob, .size_bytes = length};
420 }
421 return error;
422}
423
444 const char* destination,
446 mdl_rabook_profile_t* profile,
447 mdl_export_workspace_t* workspace)
448{
449 mdl_export_output_t output = {};
450 ra8_err_t error =
451 priv_mdl_export_output_begin(&output, storage, destination, k_mdl_format_rabook);
452 uint64_t container_length = 0U;
453 if (error == k_ra8_ok) {
455 flat,
456 flat->size_bytes,
459 &output,
460 &profile->container,
461 &container_length);
462 }
463 if ((error == k_ra8_ok) && (container_length != output.extent)) {
465 }
466 if ((error != k_ra8_ok) && output.writer.transaction.active) {
467 const ra8_err_t aborted = priv_mdl_export_output_abort(&output);
468 return (aborted == k_ra8_ok) ? error : aborted;
469 }
470 bool published = false;
471 return (error == k_ra8_ok) ? priv_mdl_export_output_commit(&output, workspace, &published)
472 : error;
473}
474
476 const char* directory,
477 char names[][k_name_max],
478 size_t count,
479 const char* destination,
480 const mdl_export_meta_t* meta,
481 mdl_export_workspace_t* workspace)
482{
483 if ((storage == nullptr) || (directory == nullptr) || (names == nullptr) ||
484 (destination == nullptr) || (meta == nullptr) || (workspace == nullptr)) {
486 }
487 if ((count == 0U) || (count > (size_t)k_rabook_page_cap)) {
489 }
490 char temp_path[k_fw_fs_path_cap] = {};
491 bool temp_exists = false;
492 ra8_err_t error = internal_write_temp_epub(storage,
493 directory,
494 names,
495 count,
496 destination,
497 meta,
498 workspace,
499 temp_path,
500 &temp_exists);
501 mdl_rabook_profile_t profile = {};
502 mdl_rabook_flat_source_t flat = {};
503 if (error == k_ra8_ok) {
504 error = internal_compile_temp(storage, temp_path, count, workspace, &profile, &flat);
505 }
506 if (temp_exists) {
507 const ra8_err_t removed = fw_fs_unlink(&storage->fs->names, temp_path);
508 if (removed != k_ra8_ok) {
509 return removed;
510 }
511 }
512 if (error == k_ra8_ok) {
513 error = internal_emit_container(storage, destination, &flat, &profile, workspace);
514 }
515 return error;
516}
Flat, execute-in-place container for a build-time "compiled" e-book.
static const book_header_t * book_header(const void *base)
View the blob base as its header.
Definition book.h:382
@ k_book_pixfmt_gray4
4bpp packed grayscale, 2px/byte (default; every pre-field blob).
Definition book.h:213
ra8_err_t book_validate(const void *base, size_t size)
Validate that a byte buffer is a well-formed, intact .rabook blob.
Definition book.c:231
ra8_err_t epub_close(epub_book_t *book)
Close a previously opened EPUB book.
Definition epub_open.c:507
ra8_err_t epub_open_streamed(const epub_stream_media_t *media, const char *path, epub_book_t *out_book)
Open an EPUB book from a seekable stream, with no whole-file residency (#151).
Definition epub_open.c:455
ra8_err_t fw_fs_unlink(const fw_fs_namespace_t *names, const char *path)
Remove one regular file; directories require fw_fs_rmdir.
Definition fw_if_fs.c:575
@ k_fw_fs_path_cap
Largest portable path including its NUL.
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 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.
@ k_name_max
Maximum entry-name bytes.
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.
ra8_err_t priv_mdl_export_output_write_at(void *opaque, uint64_t offset, const uint8_t *bytes, uint32_t length, uint32_t *out_written)
Write one complete span at an absolute active-stage offset.
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.
mdl_rabook_profile_limit_t
Fixed production conversion profile within the 96 MiB CLI arena.
@ k_rabook_string_bytes
Interned metadata/DOM strings.
@ k_rabook_xhtml_bytes
One page XHTML member.
@ k_rabook_flat_bytes
Flat RABOOK1 output.
@ k_rabook_css_bytes
One stylesheet member.
@ k_rabook_offset_entries
RBKC offset table entries.
@ k_rabook_attr_cap
Fixed-page XHTML attributes.
@ k_rabook_chapter_cap
Builder chapter rows.
@ k_rabook_image_cap
Pages plus one external cover.
@ k_rabook_image_pool_bytes
48 gray4 1024-square rasters.
@ k_rabook_style_cap
Stylesheet descriptors.
@ k_rabook_compressed_bytes
One complete zlib stream.
@ k_rabook_node_cap
Fixed-page XHTML DOM nodes.
@ k_rabook_max_image_edge
Output raster long-edge clamp.
@ k_rabook_gray_bytes
1024-square downscale buffer.
@ k_rabook_chunk_bytes
Independent RBKC chunk size.
@ k_rabook_image_arena_bytes
One stb grayscale decode.
@ k_rabook_image_raw_bytes
One encoded image member.
@ k_rabook_page_cap
EPUB manifest-safe page count.
static ra8_err_t internal_allocate_builder(mdl_export_workspace_t *workspace, mdl_rabook_profile_t *profile)
Allocate the builder tables and resident flat-book pools.
static ra8_err_t internal_allocate_profile(mdl_export_workspace_t *workspace, mdl_rabook_profile_t *profile)
Carve the complete fixed conversion profile from caller storage.
static ra8_err_t internal_allocate_pipeline(mdl_export_workspace_t *workspace, mdl_rabook_profile_t *profile)
Allocate the streamed EPUB parser and image-conversion scratch.
static ra8_err_t internal_close_compile_sources(ra8_err_t error, epub_book_t *book, mdl_rabook_epub_source_t *source)
Close both compile-time EPUB readers, preserving the first error.
static ra8_err_t internal_write_temp_epub(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, char *temp_path, bool *temp_exists)
Produce and validate one private fixed-layout EPUB intermediate.
static ra8_err_t internal_compile_temp(mdl_storage_t *storage, const char *temp_path, size_t page_count, mdl_export_workspace_t *workspace, mdl_rabook_profile_t *profile, mdl_rabook_flat_source_t *flat)
Compile one temporary EPUB into a validated resident flat RABOOK1.
static ra8_err_t internal_allocate_container(mdl_export_workspace_t *workspace, mdl_rabook_profile_t *profile)
Allocate the independent-chunk RBKC writer workspace.
static ra8_err_t internal_check_compiled_page_count(const void *blob, size_t page_count)
Confirm the compiled flat book matches the source page count.
static ra8_err_t internal_emit_container(mdl_storage_t *storage, const char *destination, mdl_rabook_flat_source_t *flat, mdl_rabook_profile_t *profile, mdl_export_workspace_t *workspace)
Stream one flat book into a strictly validated final RBKC transaction.
Private bounded RABOOK export contracts for the media downloader.
ra8_err_t priv_mdl_rabook_temp_begin(mdl_export_output_t *output, mdl_storage_t *storage, const char *directory, const char *destination, char *path, size_t capacity)
Reserve one collision-free temporary EPUB publication path.
ra8_err_t priv_mdl_rabook_flat_read(void *opaque, uint32_t offset, uint8_t *destination, uint32_t requested, uint32_t *out_read)
Serve one exact flat-blob read to the RBKC writer.
size_t priv_mdl_rabook_epub_read(void *opaque, uint64_t offset, void *destination, size_t length)
Serve one exact random EPUB read to the streamed reader.
ra8_err_t priv_mdl_rabook_epub_close(mdl_rabook_epub_source_t *source)
Close one temporary EPUB stream.
ra8_err_t priv_mdl_rabook_epub_open(mdl_rabook_epub_source_t *source, mdl_storage_t *storage, const char *path)
Open one validated temporary EPUB as a portable random-read stream.
@ k_mdl_format_rabook
Chunked reader-native book (.rabook).
Definition mdl_format.h:44
#define RA8_PRIV
Module-private helper: shared across TUs but only inside one library.
#define RA8_INTERNAL
Marker that a function is intended to be static (file-local).
@ k_ra8_err_invalid_arg
Invalid function argument.
Definition ra8_err.h:152
@ k_ra8_err_validation_failed
Validation rule failed (caller-supplied invariant not satisfied).
Definition ra8_err.h:459
@ k_ra8_ok
Success – operation completed with all postconditions satisfied.
Definition ra8_err.h:119
@ 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
void * memset(void *dst, int value, size_t n)
Fill memory with a constant byte value.
Zero-heap streaming writer for the chunked RBKC .rabook container.
ra8_err_t ra8_rabook_container_write(ra8_rabook_flat_read_fn read, void *read_ctx, uint32_t flat_len, uint32_t chunk_bytes, ra8_rabook_write_at_fn write_at, void *write_ctx, ra8_rabook_container_workspace_t *ws, uint64_t *out_len)
Stream one flat RABOOK1 blob into a chunked RBKC staging object.
End-to-end EPUB -> RABOOK1 compile pipeline (#149).
ra8_err_t rabook_compile_from_epub_to_buffer(epub_book_t *epub, const ra8_rabook_buffers_t *bufs, const ra8_rabook_pipeline_scratch_t *scr, const void **out_blob, uint32_t *out_len)
Compile an open EPUB into a RABOOK1 blob left in bufs->out, with no filesystem write.
One name="value" attribute on an element.
Definition book.h:317
One spine document (a renderable chapter) plus its TOC label.
Definition book.h:280
Fixed 100-byte prologue describing every table and pool in the blob.
Definition book.h:246
uint32_t chapter_count
Number of spine chapters.
Definition book.h:256
uint32_t image_count
Number of image descriptors.
Definition book.h:264
Descriptor for one transcoded image in the image pool.
Definition book.h:354
One DOM node.
Definition book.h:299
A preserved CSS stylesheet and the chapter it scopes to.
Definition book.h:332
Opened EPUB book.
Definition epub.h:286
uint8_t in_use
1 = open, 0 = closed.
Definition epub.h:358
Seekable EPUB media descriptor – opens with no whole-file residency (#151).
Definition epub.h:232
bool is_open
Facade lifecycle guard.
fw_fs_namespace_t names
Namespace operations.
bool active
Begin succeeded.
Rich series and chapter metadata for export containers (ComicInfo.xml, EPUB OPF).
Definition mdl_export.h:96
One validated staged publication, including random ZIP backfill.
uint64_t extent
Greatest written byte edge.
mdl_storage_txn_t writer
Active storage transaction.
size_t used
Current allocation high edge.
Definition mdl_export.h:220
Open portable EPUB stream retained during one compile.
uint64_t size_bytes
Immutable complete EPUB extent.
fw_fs_file_t file
Borrowed portable file handle.
ra8_err_t error
First read/seek protocol failure.
Resident flat RABOOK1 source for the chunked container writer.
uint32_t size_bytes
Complete flat blob extent.
All fixed-profile views carved from the export workspace.
epub_book_t * book
Streamed intermediate EPUB.
ra8_rabook_buffers_t builder
Flat-book builder arenas.
ra8_rabook_container_workspace_t container
RBKC writer workspace.
ra8_rabook_pipeline_scratch_t pipeline
EPUB compiler scratch.
ra8_img_arena_t image_arena
stb decode arena descriptor.
One non-reentrant downloader filesystem dependency bundle.
Definition mdl_storage.h:40
const fw_fs_t * fs
Injected portable filesystem.
Definition mdl_storage.h:41
fw_fs_transaction_t transaction
Active private filesystem stage.
Definition mdl_storage.h:60
Caller-owned bump arena backing a single image decode.
Caller-owned, fixed-capacity arenas the builder appends into (no heap).
uint32_t out_cap
Output capacity in bytes.
uint32_t attr_cap
Max attribute records.
uint8_t * image_pool
Image-pool byte arena.
uint32_t chapter_cap
Max chapters.
uint32_t stylesheet_cap
Max stylesheets.
char * string_pool
String-pool byte arena.
uint32_t image_cap
Max image descriptors.
uint32_t image_pool_cap
Image-pool capacity in bytes.
book_image_t * images
Image-table arena.
uint32_t string_cap
String-pool capacity in bytes.
book_stylesheet_t * stylesheets
Stylesheet-table arena.
uint32_t node_cap
Max DOM nodes.
book_node_t * nodes
Node-table arena.
uint8_t * out
Final-blob output buffer.
book_attr_t * attrs
Attribute-table arena.
book_chapter_t * chapters
Chapter-table arena.
Caller-owned transient storage for one RBKC write.
uint32_t compressor_cap
Writable bytes at compressor.
uint8_t * compressed
One complete zlib stream.
uint64_t * offsets
Payload-relative offset table.
uint32_t offset_cap
Number of uint64 entries at offsets.
uint32_t input_cap
Writable bytes at input.
uint32_t compressed_cap
Writable bytes at compressed.
uint8_t * input
One uncompressed flat chunk.
void * compressor
tdefl_compressor storage, 8-byte aligned.
Caller-owned temporary buffers the pipeline stage needs.
Caller-owned storage for one parser invocation.