ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
rabook_compile.c
Go to the documentation of this file.
1
17
18#include "rabook_compile.h"
19
20#include <stdint.h>
21#include <string.h>
22
23#include "ra8_attributes.h"
24#include "ra8_check.h"
25
27static const char* const s_tag_rabook = "rabook_compile";
28
37
44
64{
66
67 const void* const members[k_rabook_buffer_ptr_count] = {
68 buf->chapters,
69 buf->nodes,
70 buf->attrs,
71 buf->stylesheets,
72 buf->images,
73 buf->string_pool,
74 buf->image_pool,
75 buf->out,
76 };
77 static const char* const names[k_rabook_buffer_ptr_count] = {
78 "buf->chapters",
79 "buf->nodes",
80 "buf->attrs",
81 "buf->stylesheets",
82 "buf->images",
83 "buf->string_pool",
84 "buf->image_pool",
85 "buf->out",
86 };
87
88 for (uint8_t i = 0U; i < (uint8_t)k_rabook_buffer_ptr_count; i++) {
89 RA8_CHECK_NULL_PTR(members[i], s_tag_rabook, names[i]);
90 }
91 return k_ra8_ok;
92}
93
95{
97 const ra8_err_t buf_err = internal_check_buffer_members(buf);
98 if (buf_err != k_ra8_ok) {
99 return buf_err;
100 }
101
102 *ctx = (ra8_rabook_ctx_t){};
103 ctx->buf = *buf;
104 ctx->cover_image_index = (uint32_t)k_book_nil;
105
106 /* Reserve string-pool offset 0 for "" so it is the empty-string sentinel that
107 * add_text/add_element store, matching the desktop StringPool.__init__ in
108 * tools/epub_compile/src/epub_compile.py (offset 0 == ""). */
109 (void)ra8_rabook_intern(ctx, "");
110 return k_ra8_ok;
111}
112
113uint32_t ra8_rabook_intern(ra8_rabook_ctx_t* ctx, const char* str)
114{
115 if (ctx == nullptr) {
116 return (uint32_t)k_book_nil;
117 }
118 if (str == nullptr) {
119 ctx->failed = true;
120 return (uint32_t)k_book_nil;
121 }
122 if (ctx->failed) {
123 return (uint32_t)k_book_nil;
124 }
125
126 const uint32_t len = (uint32_t)strlen(str);
127 /* De-dup: walk the pool string-by-string, return the first exact match. */
128 uint32_t scan = 0U;
129 while (scan < ctx->string_size) {
130 const char* cand = &ctx->buf.string_pool[scan];
131 const uint32_t cand_len = (uint32_t)strlen(cand);
132 if (cand_len == len) {
133 uint32_t equal_bytes = 0U;
134 while ((equal_bytes < len) && (cand[equal_bytes] == str[equal_bytes])) {
135 equal_bytes++;
136 }
137 if (equal_bytes == len) {
138 return scan;
139 }
140 }
141 scan += cand_len + 1U; /* skip the candidate and its NUL */
142 }
143
144 /* Miss: append str + NUL, guarding the pool capacity. */
145 const uint32_t need = len + 1U;
146 if (need > (ctx->buf.string_cap - ctx->string_size)) {
147 ctx->failed = true;
148 return (uint32_t)k_book_nil;
149 }
150 const uint32_t off = ctx->string_size;
151 (void)memcpy(&ctx->buf.string_pool[off], str, (size_t)len);
152 ctx->buf.string_pool[off + len] = '\0';
153 ctx->string_size += need;
154 return off;
155}
156
176static uint32_t
177internal_append_attrs(ra8_rabook_ctx_t* ctx, const book_attr_t* attrs, uint16_t attr_count)
178{
179 if (attr_count == 0U) {
180 return (uint32_t)k_book_nil;
181 }
182
183 const uint32_t first_attr = ctx->attr_count;
184 for (uint16_t i = 0U; i < attr_count; i++) {
185 ctx->buf.attrs[ctx->attr_count] = attrs[i];
186 ctx->attr_count++;
187 }
188 return first_attr;
189}
190
192 uint32_t name_off,
193 const book_attr_t* attrs,
194 uint16_t attr_count)
195{
196 if (ctx == nullptr) {
197 return (uint32_t)k_book_nil;
198 }
199 if (ctx->failed) {
200 return (uint32_t)k_book_nil;
201 }
202 if (attr_count != 0U) {
203 if (attrs == nullptr) {
204 ctx->failed = true;
205 return (uint32_t)k_book_nil;
206 }
207 }
208 if (ctx->node_count >= ctx->buf.node_cap) {
209 ctx->failed = true;
210 return (uint32_t)k_book_nil;
211 }
212 if ((uint32_t)attr_count > (ctx->buf.attr_cap - ctx->attr_count)) {
213 ctx->failed = true;
214 return (uint32_t)k_book_nil;
215 }
216
217 const uint32_t first_attr = internal_append_attrs(ctx, attrs, attr_count);
218
219 const uint32_t idx = ctx->node_count;
220 book_node_t* node = &ctx->buf.nodes[idx];
221 *node = (book_node_t){};
222 node->kind = (uint8_t)k_book_node_element;
223 node->attr_count = attr_count;
224 node->name_off = name_off;
225 node->text_off = 0U;
226 node->first_attr = first_attr;
227 node->first_child = (uint32_t)k_book_nil;
228 node->next_sibling = (uint32_t)k_book_nil;
229 ctx->node_count++;
230 return idx;
231}
232
233uint32_t ra8_rabook_add_text(ra8_rabook_ctx_t* ctx, uint32_t text_off)
234{
235 if (ctx == nullptr) {
236 return (uint32_t)k_book_nil;
237 }
238 if (ctx->failed) {
239 return (uint32_t)k_book_nil;
240 }
241 if (ctx->node_count >= ctx->buf.node_cap) {
242 ctx->failed = true;
243 return (uint32_t)k_book_nil;
244 }
245
246 const uint32_t idx = ctx->node_count;
247 book_node_t* node = &ctx->buf.nodes[idx];
248 *node = (book_node_t){};
249 node->kind = (uint8_t)k_book_node_text;
250 node->attr_count = 0U;
251 node->name_off = 0U;
252 node->text_off = text_off;
253 node->first_attr = (uint32_t)k_book_nil;
254 node->first_child = (uint32_t)k_book_nil;
255 node->next_sibling = (uint32_t)k_book_nil;
256 ctx->node_count++;
257 return idx;
258}
259
260ra8_err_t ra8_rabook_link_child(ra8_rabook_ctx_t* ctx, uint32_t parent, uint32_t child)
261{
262 RA8_CHECK_NULL_PTR(ctx, s_tag_rabook, "ctx");
263 if (parent >= ctx->node_count) {
264 ra8_log_error(s_tag_rabook, "link_child parent out of range");
266 }
267 if (child >= ctx->node_count) {
268 ra8_log_error(s_tag_rabook, "link_child child out of range");
270 }
271 ctx->buf.nodes[parent].first_child = child;
272 return k_ra8_ok;
273}
274
276ra8_rabook_link_sibling(ra8_rabook_ctx_t* ctx, uint32_t previous_node, uint32_t next_sibling)
277{
278 RA8_CHECK_NULL_PTR(ctx, s_tag_rabook, "ctx");
279 if (previous_node >= ctx->node_count) {
280 ra8_log_error(s_tag_rabook, "link_sibling node out of range");
282 }
283 if (next_sibling >= ctx->node_count) {
284 ra8_log_error(s_tag_rabook, "link_sibling sibling out of range");
286 }
287 ctx->buf.nodes[previous_node].next_sibling = next_sibling;
288 return k_ra8_ok;
289}
290
292 uint32_t title_off,
293 uint32_t href_off,
294 uint32_t root_node)
295{
296 if (ctx == nullptr) {
297 return (uint32_t)k_book_nil;
298 }
299 if (ctx->failed) {
300 return (uint32_t)k_book_nil;
301 }
302 if (ctx->chapter_count >= ctx->buf.chapter_cap) {
303 ctx->failed = true;
304 return (uint32_t)k_book_nil;
305 }
306
307 const uint32_t idx = ctx->chapter_count;
308 book_chapter_t* ch = &ctx->buf.chapters[idx];
309 ch->title_off = title_off;
310 ch->href_off = href_off;
311 ch->root_node = root_node;
312 ctx->chapter_count++;
313 return idx;
314}
315
339 uint32_t id_off,
340 uint16_t width,
341 uint16_t height,
342 uint8_t format,
343 uint8_t pixel_format,
344 uint32_t data_off,
345 uint32_t data_size)
346{
347 const uint32_t idx = ctx->image_count;
348 book_image_t* img = &ctx->buf.images[idx];
349 *img = (book_image_t){};
350 img->id_off = id_off;
351 img->width = width;
352 img->height = height;
353 img->format = format;
354 img->pixel_format = pixel_format;
355 img->data_off = data_off;
356 img->data_size = data_size;
357 img->raw_size = data_size;
358 ctx->image_count++;
359 return idx;
360}
361
363 uint32_t id_off,
364 uint16_t width,
365 uint16_t height,
366 uint8_t format,
367 uint8_t pixel_format,
368 const uint8_t* data,
369 uint32_t data_size)
370{
371 if (ctx == nullptr) {
372 return (uint32_t)k_book_nil;
373 }
374 if (ctx->failed) {
375 return (uint32_t)k_book_nil;
376 }
377 if (data_size != 0U) {
378 if (ctx->image_pool_mode == (uint8_t)k_rabook_pool_external) {
379 ctx->failed = true;
380 return (uint32_t)k_book_nil;
381 }
382 if (data == nullptr) {
383 ctx->failed = true;
384 return (uint32_t)k_book_nil;
385 }
386 }
387 if (ctx->image_count >= ctx->buf.image_cap) {
388 ctx->failed = true;
389 return (uint32_t)k_book_nil;
390 }
391 if (data_size > (ctx->buf.image_pool_cap - ctx->image_pool_size)) {
392 ctx->failed = true;
393 return (uint32_t)k_book_nil;
394 }
395
396 const uint32_t data_off = ctx->image_pool_size;
397 if (data_size != 0U) {
399 (void)memcpy(&ctx->buf.image_pool[data_off], data, (size_t)data_size);
400 ctx->image_pool_size += data_size;
401 }
402
404 id_off,
405 width,
406 height,
407 format,
408 pixel_format,
409 data_off,
410 data_size);
411}
412
414 uint32_t id_off,
415 uint16_t width,
416 uint16_t height,
417 uint8_t format,
418 uint8_t pixel_format,
419 uint32_t data_size,
420 uint32_t* out_data_off)
421{
422 if (ctx == nullptr) {
423 return (uint32_t)k_book_nil;
424 }
425 if (out_data_off == nullptr) {
426 ctx->failed = true;
427 return (uint32_t)k_book_nil;
428 }
429 if (ctx->failed) {
430 ctx->failed = true;
431 return (uint32_t)k_book_nil;
432 }
433 if (data_size != 0U) {
434 if (ctx->image_pool_mode == (uint8_t)k_rabook_pool_internal) {
435 ctx->failed = true;
436 return (uint32_t)k_book_nil;
437 }
438 }
439 if (ctx->image_count >= ctx->buf.image_cap) {
440 ctx->failed = true;
441 return (uint32_t)k_book_nil;
442 }
443 if (data_size > (UINT32_MAX - ctx->image_pool_size)) {
444 ctx->failed = true;
445 return (uint32_t)k_book_nil;
446 }
447
448 const uint32_t data_off = ctx->image_pool_size;
449 if (data_size != 0U) {
451 ctx->image_pool_size += data_size;
452 }
453
454 *out_data_off = data_off;
456 id_off,
457 width,
458 height,
459 format,
460 pixel_format,
461 data_off,
462 data_size);
463}
464
465uint32_t
466ra8_rabook_add_stylesheet(ra8_rabook_ctx_t* ctx, uint32_t source_off, uint32_t scope_chapter)
467{
468 if (ctx == nullptr) {
469 return (uint32_t)k_book_nil;
470 }
471 if (ctx->failed) {
472 return (uint32_t)k_book_nil;
473 }
474 if (ctx->stylesheet_count >= ctx->buf.stylesheet_cap) {
475 ctx->failed = true;
476 return (uint32_t)k_book_nil;
477 }
478
479 const uint32_t idx = ctx->stylesheet_count;
480 book_stylesheet_t* ss = &ctx->buf.stylesheets[idx];
481 ss->source_off = source_off;
482 ss->scope_chapter = scope_chapter;
483 ctx->stylesheet_count++;
484 return idx;
485}
486
488 uint32_t title_off,
489 uint32_t author_off,
490 uint32_t language_off,
491 uint32_t identifier_off,
492 uint32_t cover_image_index)
493{
494 RA8_CHECK_NULL_PTR(ctx, s_tag_rabook, "ctx");
495 if (ctx->failed) {
496 ra8_log_error(s_tag_rabook, "set_metadata after a builder overflow");
497 return k_ra8_err_no_mem;
498 }
499 ctx->title_off = title_off;
500 ctx->author_off = author_off;
501 ctx->language_off = language_off;
502 ctx->identifier_off = identifier_off;
503 ctx->cover_image_index = cover_image_index;
504 return k_ra8_ok;
505}
@ k_book_node_element
An element: has a tag name and attributes.
Definition book.h:162
@ k_book_node_text
A text run: carries a string, no children.
Definition book.h:163
@ k_book_nil
Absent index / "applies to all chapters".
Definition book.h:129
Annotation-attribute framework macros for ra8-firmware.
#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
@ k_ra8_err_no_mem
Static buffer exhausted (no dynamic memory on this project).
Definition ra8_err.h:142
@ 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
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.
#define ra8_log_error(tag, message)
RA8 log error.
Definition ra8_log.h:335
ra8_rabook_pool_mode_t
Image-pool backing recorded by the builder context.
@ k_rabook_pool_external
Bytes live behind the read callback.
static const char *const s_tag_rabook
Component tag for finalizer diagnostics.
uint32_t ra8_rabook_add_element(ra8_rabook_ctx_t *ctx, uint32_t name_off, const book_attr_t *attrs, uint16_t attr_count)
Append an element node with its attributes; return its node index.
ra8_err_t ra8_rabook_link_sibling(ra8_rabook_ctx_t *ctx, uint32_t previous_node, uint32_t next_sibling)
Set previous_node's next sibling to next_sibling.
uint32_t ra8_rabook_add_text(ra8_rabook_ctx_t *ctx, uint32_t text_off)
Append a text node carrying text_off; return its node index.
ra8_err_t ra8_rabook_link_child(ra8_rabook_ctx_t *ctx, uint32_t parent, uint32_t child)
Set parent's first child to child.
uint32_t ra8_rabook_intern(ra8_rabook_ctx_t *ctx, const char *str)
Intern a NUL-terminated UTF-8 string into the pool, de-duplicated.
@ k_rabook_pool_internal
Bytes live in buf.image_pool.
@ k_rabook_pool_none
No non-empty image has selected storage.
uint32_t ra8_rabook_add_image(ra8_rabook_ctx_t *ctx, uint32_t id_off, uint16_t width, uint16_t height, uint8_t format, uint8_t pixel_format, const uint8_t *data, uint32_t data_size)
Append an image descriptor and copy its pixel/SVG bytes into the pool.
ra8_err_t ra8_rabook_set_metadata(ra8_rabook_ctx_t *ctx, uint32_t title_off, uint32_t author_off, uint32_t language_off, uint32_t identifier_off, uint32_t cover_image_index)
Record the book metadata offsets that land in the blob header.
uint32_t ra8_rabook_add_image_external(ra8_rabook_ctx_t *ctx, uint32_t id_off, uint16_t width, uint16_t height, uint8_t format, uint8_t pixel_format, uint32_t data_size, uint32_t *out_data_off)
Append an image descriptor whose bytes live in a caller-owned spool.
uint32_t ra8_rabook_add_stylesheet(ra8_rabook_ctx_t *ctx, uint32_t source_off, uint32_t scope_chapter)
Append a preserved stylesheet; return its stylesheet index.
static uint32_t internal_append_attrs(ra8_rabook_ctx_t *ctx, const book_attr_t *attrs, uint16_t attr_count)
Append attr_count attribute records to the attr table contiguously.
uint32_t ra8_rabook_add_chapter(ra8_rabook_ctx_t *ctx, uint32_t title_off, uint32_t href_off, uint32_t root_node)
Append a spine chapter; return its chapter index.
ra8_rabook_buffer_ptr_count_t
Number of caller-owned arena pointers validated by init.
@ k_rabook_buffer_ptr_count
chapters..out member pointers.
static ra8_err_t internal_check_buffer_members(const ra8_rabook_buffers_t *buf)
Reject a buffers struct with any NULL arena pointer.
static uint32_t internal_append_image_descriptor(ra8_rabook_ctx_t *ctx, uint32_t id_off, uint16_t width, uint16_t height, uint8_t format, uint8_t pixel_format, uint32_t data_off, uint32_t data_size)
Append one already-bounded image descriptor.
ra8_err_t rabook_compile_init(ra8_rabook_ctx_t *ctx, const ra8_rabook_buffers_t *buf)
Bind a builder context to its caller-provided arenas.
Zero-heap builder that emits a RABOOK1 blob (the #149 compiler back-end).
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
uint32_t root_node
Node-table index of this chapter's root element.
Definition book.h:283
uint32_t href_off
String-pool offset of the source spine href.
Definition book.h:282
uint32_t title_off
String-pool offset of the TOC label ("" if none).
Definition book.h:281
Descriptor for one transcoded image in the image pool.
Definition book.h:354
uint16_t height
Pixel height.
Definition book.h:357
uint32_t id_off
String-pool offset of the source href / manifest id.
Definition book.h:355
uint32_t raw_size
Inflated length in bytes.
Definition book.h:363
uint8_t format
book_image_format_t.
Definition book.h:358
uint32_t data_size
Compressed length in bytes.
Definition book.h:362
uint8_t pixel_format
book_image_pixfmt_t (0 == gray4; SVG: 0).
Definition book.h:359
uint16_t width
Pixel width.
Definition book.h:356
uint32_t data_off
Image-pool offset of the compressed pixel data.
Definition book.h:361
One DOM node.
Definition book.h:299
uint8_t kind
book_node_kind_t.
Definition book.h:300
uint32_t text_off
Text: string-pool offset of the run (element: 0).
Definition book.h:304
uint16_t attr_count
Element: number of attributes (text: 0).
Definition book.h:302
uint32_t next_sibling
Index of next sibling node, or nil.
Definition book.h:307
uint32_t name_off
Element: string-pool offset of tag name (text: 0).
Definition book.h:303
uint32_t first_child
Index of first child node, or nil.
Definition book.h:306
uint32_t first_attr
Index of first attribute, or nil.
Definition book.h:305
A preserved CSS stylesheet and the chapter it scopes to.
Definition book.h:332
uint32_t scope_chapter
Chapter index this applies to, or nil (= all).
Definition book.h:334
uint32_t source_off
String-pool offset of the verbatim CSS text.
Definition book.h:333
Caller-owned, fixed-capacity arenas the builder appends into (no heap).
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.
Builder state: the arenas plus running counts and a sticky-fail flag.
bool failed
Sticky: an arena overflowed.
uint32_t title_off
Metadata: title string offset.
uint8_t image_pool_mode
Internal builder storage mode.
uint32_t string_size
String-pool bytes used.
uint32_t stylesheet_count
Stylesheets appended so far.
uint32_t cover_image_index
Cover image index, or nil.
uint32_t image_pool_size
Image-pool bytes used.
ra8_rabook_buffers_t buf
Caller-provided arenas.
uint32_t language_off
Metadata: language string offset.
uint32_t chapter_count
Chapters appended so far.
uint32_t node_count
Nodes appended so far.
uint32_t image_count
Images appended so far.
uint32_t author_off
Metadata: author string offset.
uint32_t identifier_off
Metadata: identifier string offset.
uint32_t attr_count
Attributes appended so far.