ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
book_stream.c
Go to the documentation of this file.
1
15#include "book_stream.h"
16
17#include <string.h>
18
19#include "book_internal.h"
21#include "ra8_attributes.h"
22
23/*
24 * @brief Validate the four metadata strings and optional cover index.
25 * @details Validates every metadata string boundary and requires any non-nil
26 * cover reference to select an existing image descriptor.
27 * @param[in] ctx Validation state.
28 * @return Metadata validation status.
29 * @retval k_ra8_ok All metadata references are valid.
30 * @retval k_ra8_err_invalid_arg A string or cover-image reference is invalid.
31 * @pre Header and string envelope are valid.
32 * @pre Image count and metadata offsets are decoded from the validated header.
33 * @post No state is modified.
34 * @post Success makes all metadata references safe for later lookup.
35 * @note Not thread-safe with respect to the source callback.
36 * @since Version 0.1.0
37 */
39{
40 const uint32_t refs[4] = {
41 ctx->hdr.title_off,
42 ctx->hdr.author_off,
43 ctx->hdr.language_off,
45 };
46 for (uint8_t i = 0U; i < (uint8_t)(sizeof(refs) / sizeof(refs[0])); ++i) {
47 const ra8_err_t err = priv_book_stream_string_ref(ctx, refs[i]);
48 if (err != k_ra8_ok) {
49 return err;
50 }
51 }
52 if ((ctx->hdr.cover_image_index != (uint32_t)k_book_nil) &&
53 (ctx->hdr.cover_image_index >= ctx->hdr.image_count)) {
55 }
56 return k_ra8_ok;
57}
58
76{
77 uint8_t rec[k_book_sizeof_chapter] = {};
78 for (uint32_t i = 0U; i < ctx->hdr.chapter_count; ++i) {
79 const uint64_t off =
80 (uint64_t)ctx->hdr.chapter_off + ((uint64_t)i * (uint64_t)k_book_sizeof_chapter);
81 ra8_err_t err = priv_book_stream_read(ctx, off, rec, (uint32_t)sizeof(rec));
82 if (err != k_ra8_ok) {
83 return err;
84 }
86 if (err == k_ra8_ok) {
88 }
89 const uint32_t root = internal_book_stream_le32(&rec[8]);
90 if ((err == k_ra8_ok) && (root >= ctx->hdr.node_count)) {
92 }
93 if (err == k_ra8_ok) {
94 uint8_t node[k_book_sizeof_node] = {};
95 err = priv_book_stream_read(ctx,
96 (uint64_t)ctx->hdr.node_off +
97 ((uint64_t)root * (uint64_t)k_book_sizeof_node),
98 node,
99 (uint32_t)sizeof(node));
100 if ((err == k_ra8_ok) && ((node[k_stream_node_kind] != (uint8_t)k_book_node_element) ||
102 (uint32_t)k_book_nil))) {
104 }
105 }
106 if (err == k_ra8_ok) {
107 const uint32_t byte = root / 8U;
108 const uint8_t mask = (uint8_t)(1U << (root % 8U));
109 if ((ctx->scratch[byte] & mask) != 0U) {
111 } else {
112 ctx->scratch[byte] |= mask;
113 }
114 }
115 if (err != k_ra8_ok) {
116 return err;
117 }
118 }
119 return k_ra8_ok;
120}
121
139RA8_INTERNAL static ra8_err_t internal_forward_link(uint32_t link, uint32_t current, uint32_t count)
140{
141 if (link == (uint32_t)k_book_nil) {
142 return k_ra8_ok;
143 }
144 if ((link <= current) || (link >= count)) {
146 }
147 return k_ra8_ok;
148}
149
168static ra8_err_t
169internal_mark_forward_link(const stream_validate_t* ctx, uint32_t link, uint32_t current)
170{
171 const ra8_err_t err = internal_forward_link(link, current, ctx->hdr.node_count);
172 if ((err != k_ra8_ok) || (link == (uint32_t)k_book_nil)) {
173 return err;
174 }
175 const uint32_t byte = link / 8U;
176 const uint8_t mask = (uint8_t)(1U << (link % 8U));
177 if ((ctx->scratch[byte] & mask) != 0U) {
179 }
180 ctx->scratch[byte] |= mask;
181 return k_ra8_ok;
182}
183
184/*
185 * @brief Validate one element node and advance canonical attribute ownership.
186 * @details Requires element-only fields, a non-empty name, and either no
187 * attributes or the exact next contiguous attribute-table span.
188 * @param[in] ctx Validation state.
189 * @param[in] rec Decoded-wire node bytes.
190 * @param[in,out] attr_cursor Next unowned attribute index.
191 * @return Element validation status.
192 * @retval k_ra8_ok The element fields and attribute span are canonical.
193 * @retval k_ra8_err_invalid_arg An element invariant or reference is invalid.
194 * @pre Node kind is element and @p attr_cursor is in range.
195 * @pre @p rec addresses one complete node wire record.
196 * @post Success consumes exactly the node's contiguous attribute span.
197 * @post Failure never advances beyond the advertised attribute count.
198 * @note Not thread-safe with respect to the source callback.
199 * @since Version 0.1.0
200 */
202 const uint8_t* rec,
203 uint32_t* attr_cursor)
204{
207 }
208 ra8_err_t err =
210 if (err != k_ra8_ok) {
211 return err;
212 }
213 const uint32_t first = internal_book_stream_le32(&rec[k_stream_node_first_attr]);
214 const uint32_t count = internal_book_stream_le16(&rec[k_stream_node_attr_count]);
215 if (count == 0U) {
216 return (first == (uint32_t)k_book_nil) ? k_ra8_ok : k_ra8_err_invalid_arg;
217 }
218 if ((first != *attr_cursor) || (count > (ctx->hdr.attr_count - *attr_cursor))) {
220 }
221 *attr_cursor += count;
222 return k_ra8_ok;
223}
224
225/*
226 * @brief Validate one text-node invariant set.
227 * @details Rejects element-only fields on text records, then validates the
228 * text string boundary through the shared string-pool contract.
229 * @param[in] ctx Validation state.
230 * @param[in] rec Decoded-wire node bytes.
231 * @return Text-node validation status.
232 * @retval k_ra8_ok The text node fields and string reference are valid.
233 * @retval k_ra8_err_invalid_arg An element-only field or string reference is
234 * invalid.
235 * @pre Node kind is text.
236 * @pre @p rec addresses one complete node wire record.
237 * @post No state is modified.
238 * @post Success proves the node owns no children or attributes.
239 * @note Not thread-safe with respect to the source callback.
240 * @since Version 0.1.0
241 */
252
274 const uint8_t* rec,
275 uint32_t* attr_cursor,
276 uint32_t index)
277{
278 ra8_err_t err;
279 if (rec[k_stream_node_kind] == (uint8_t)k_book_node_element) {
280 err = priv_book_stream_validate_element(ctx, rec, attr_cursor);
281 } else if (rec[k_stream_node_kind] == (uint8_t)k_book_node_text) {
282 err = priv_book_stream_validate_text(ctx, rec);
283 } else {
285 }
286 if (err == k_ra8_ok) {
289 index);
290 }
291 if (err == k_ra8_ok) {
294 index);
295 }
296 return err;
297}
298
316{
317 uint8_t rec[k_book_sizeof_node] = {};
318 uint32_t attr_cursor = 0U;
319 for (uint32_t i = 0U; i < ctx->hdr.node_count; ++i) {
320 const uint64_t off = (uint64_t)ctx->hdr.node_off + ((uint64_t)i * (uint64_t)k_book_sizeof_node);
321 ra8_err_t err = priv_book_stream_read(ctx, off, rec, (uint32_t)sizeof(rec));
322 if (err != k_ra8_ok) {
323 return err;
324 }
325 if (rec[k_stream_node_reserved] != 0U) {
327 }
328 err = internal_validate_one_node(ctx, rec, &attr_cursor, i);
329 if (err != k_ra8_ok) {
330 return err;
331 }
332 }
333 if (attr_cursor != ctx->hdr.attr_count) {
335 }
336 for (uint32_t i = 0U; i < ctx->hdr.node_count; ++i) {
337 const uint8_t mask = (uint8_t)(1U << (i % 8U));
338 if ((ctx->scratch[i / 8U] & mask) == 0U) {
340 }
341 }
342 return k_ra8_ok;
343}
344
362{
363 uint8_t rec[k_book_sizeof_attr] = {};
364 for (uint32_t i = 0U; i < ctx->hdr.attr_count; ++i) {
366 (uint64_t)ctx->hdr.attr_off +
367 ((uint64_t)i * (uint64_t)k_book_sizeof_attr),
368 rec,
369 (uint32_t)sizeof(rec));
370 if (err == k_ra8_ok) {
372 }
373 if (err == k_ra8_ok) {
375 }
376 if (err != k_ra8_ok) {
377 return err;
378 }
379 }
380 return k_ra8_ok;
381}
382
383/*
384 * @brief Validate every stylesheet source and scope.
385 * @details Validates each stylesheet source string and permits only nil or an
386 * existing chapter index as its optional scope.
387 * @param[in] ctx Validation state.
388 * @return Stylesheet-table validation status.
389 * @retval k_ra8_ok Every stylesheet source and scope is valid.
390 * @retval k_ra8_err_invalid_arg A source boundary or scope index is invalid.
391 * @pre Header layout and string envelope are valid.
392 * @pre Chapter count is the validated table-record count.
393 * @post No state is modified.
394 * @post Success makes each stylesheet reference safe for later lookup.
395 * @note Iteration is bounded by stylesheet_count.
396 * @since Version 0.1.0
397 */
399{
400 uint8_t rec[k_book_sizeof_stylesheet] = {};
401 for (uint32_t i = 0U; i < ctx->hdr.stylesheet_count; ++i) {
403 (uint64_t)ctx->hdr.stylesheet_off +
404 ((uint64_t)i * (uint64_t)k_book_sizeof_stylesheet),
405 rec,
406 (uint32_t)sizeof(rec));
407 if (err == k_ra8_ok) {
409 }
410 const uint32_t scope = internal_book_stream_le32(&rec[4]);
411 if ((err == k_ra8_ok) && (scope != (uint32_t)k_book_nil) && (scope >= ctx->hdr.chapter_count)) {
413 }
414 if (err != k_ra8_ok) {
415 return err;
416 }
417 }
418 return k_ra8_ok;
419}
420
438{
439 const uint32_t width = internal_book_stream_le16(&rec[k_stream_image_width]);
440 const uint32_t height = internal_book_stream_le16(&rec[k_stream_image_height]);
441 const uint8_t pixfmt = rec[k_stream_image_pixfmt];
442 if ((width == 0U) || (height == 0U) ||
443 ((pixfmt != (uint8_t)k_book_pixfmt_gray4) && (pixfmt != (uint8_t)k_book_pixfmt_gray8))) {
445 }
446 const uint64_t pixels = (uint64_t)width * (uint64_t)height;
447 const uint64_t expect = (pixfmt == (uint8_t)k_book_pixfmt_gray4) ? ((pixels + 1U) / 2U) : pixels;
448 // mcdc-deactivated: internal_validate_raster overflow backstop; width and height are decoded from 16-bit wire fields, so `pixels` is at most 65535*65535 == 0xFFFE0001 and `expect` (pixels, or half of it for gray4) can never exceed UINT32_MAX -- the first condition is provably constant-false and no input can flip it.
449 if ((expect > (uint64_t)UINT32_MAX) ||
453 }
454 return k_ra8_ok;
455}
456
473{
476 (rec[k_stream_image_pixfmt] != (uint8_t)k_book_pixfmt_gray4)) {
478 }
479 const uint32_t data_size = internal_book_stream_le32(&rec[k_stream_image_data_size]);
480 return ((data_size != 0U) &&
482 ? k_ra8_ok
484}
485
503{
504 uint8_t rec[k_book_sizeof_image] = {};
505 uint32_t pool_cursor = 0U;
506 for (uint32_t i = 0U; i < ctx->hdr.image_count; ++i) {
508 (uint64_t)ctx->hdr.image_off +
509 ((uint64_t)i * (uint64_t)k_book_sizeof_image),
510 rec,
511 (uint32_t)sizeof(rec));
512 if (err == k_ra8_ok) {
513 err =
516 }
517 if ((err == k_ra8_ok) && (internal_book_stream_le16(&rec[k_stream_image_reserved]) != 0U)) {
519 }
520 if (err == k_ra8_ok) {
521 if (rec[k_stream_image_format] == (uint8_t)k_book_image_gray4) {
522 err = internal_validate_raster(rec);
523 } else if (rec[k_stream_image_format] == (uint8_t)k_book_image_svg) {
524 err = internal_validate_svg(rec);
525 } else {
527 }
528 }
529 const uint32_t data_off = internal_book_stream_le32(&rec[k_stream_image_data_off]);
530 const uint32_t data_size = internal_book_stream_le32(&rec[k_stream_image_data_size]);
531 if ((err == k_ra8_ok) &&
532 ((data_off != pool_cursor) || (data_size > (ctx->hdr.image_pool_size - pool_cursor)))) {
534 }
535 if (err != k_ra8_ok) {
536 return err;
537 }
538 pool_cursor += data_size;
539 }
540 return (pool_cursor == ctx->hdr.image_pool_size) ? k_ra8_ok : k_ra8_err_invalid_size;
541}
542
559{
560 uint64_t at = (uint64_t)k_book_sizeof_header;
561 uint32_t crc = 0U;
562 while (at < (uint64_t)ctx->hdr.total_size) {
563 uint64_t remain = (uint64_t)ctx->hdr.total_size - at;
564 uint32_t span = ctx->scratch_cap;
565 if (remain < (uint64_t)span) {
566 span = (uint32_t)remain;
567 }
568 const ra8_err_t err = priv_book_stream_read(ctx, at, ctx->scratch, span);
569 if (err != k_ra8_ok) {
570 return err;
571 }
572 crc = priv_book_crc32_extend(crc, ctx->scratch, span);
573 at += span;
574 }
575 return (crc == ctx->hdr.crc32_val) ? k_ra8_ok : k_ra8_err_range_check_failed;
576}
577
596{
598 if (err == k_ra8_ok) {
600 }
601 if (err == k_ra8_ok) {
603 }
604 if (err == k_ra8_ok) {
605 const uint32_t mark_bytes =
606 (ctx->hdr.node_count / 8U) + (((ctx->hdr.node_count % 8U) != 0U) ? 1U : 0U);
607 (void)memset(ctx->scratch, 0, mark_bytes);
608 }
609 if (err == k_ra8_ok) {
611 }
612 if (err == k_ra8_ok) {
613 err = internal_validate_nodes(ctx);
614 }
615 if (err == k_ra8_ok) {
616 err = internal_validate_attrs(ctx);
617 }
618 if (err == k_ra8_ok) {
620 }
621 if (err == k_ra8_ok) {
622 err = internal_validate_images(ctx);
623 }
624 if (err == k_ra8_ok) {
625 err = internal_validate_crc(ctx);
626 }
627 return err;
628}
629
631 void* read_ctx,
632 uint64_t source_size,
633 uint8_t* scratch,
634 uint32_t scratch_cap,
635 book_header_t* out_header)
636{
637 if (out_header == nullptr) {
638 return k_ra8_err_null_ptr;
639 }
640 *out_header = (book_header_t){};
641 if ((read == nullptr) || (scratch == nullptr)) {
642 return k_ra8_err_null_ptr;
643 }
644 if ((source_size < (uint64_t)k_book_sizeof_header) || (scratch_cap == 0U)) {
646 }
647 stream_validate_t ctx = {
648 .read = read,
649 .read_ctx = read_ctx,
650 .source_size = source_size,
651 .scratch = scratch,
652 .scratch_cap = scratch_cap,
653 .hdr = {},
654 };
655 const ra8_err_t err = internal_validate_body(&ctx);
656 if (err == k_ra8_ok) {
657 *out_header = ctx.hdr;
658 }
659 return err;
660}
uint32_t priv_book_crc32_extend(uint32_t crc, const uint8_t *data, size_t len)
Extend a reflected CRC-32 over one byte span.
Definition book.c:86
@ k_book_sizeof_image
Bytes in book_image_t.
Definition book.h:233
@ k_book_sizeof_header
Bytes in book_header_t.
Definition book.h:228
@ k_book_sizeof_node
Bytes in book_node_t.
Definition book.h:230
@ k_book_sizeof_chapter
Bytes in book_chapter_t.
Definition book.h:229
@ k_book_sizeof_stylesheet
Bytes in book_stylesheet_t.
Definition book.h:232
@ k_book_sizeof_attr
Bytes in book_attr_t.
Definition book.h:231
@ 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
@ k_book_image_svg
Verbatim UTF-8 SVG source (vector; on-device rasterized).
Definition book.h:176
@ k_book_image_gray4
4bpp gray, 2px/byte; pixel (x,y) is at flat index y*width + x.
Definition book.h:175
@ k_book_pixfmt_gray4
4bpp packed grayscale, 2px/byte (default; every pre-field blob).
Definition book.h:213
@ k_book_pixfmt_gray8
8bpp grayscale, 1px/byte (lossless against any grey panel).
Definition book.h:215
book DOM-walk helpers shared across the library's translation units.
static ra8_err_t internal_validate_images(const stream_validate_t *ctx)
Validate every image descriptor and exact gap-free pool tiling.
static ra8_err_t internal_validate_nodes(const stream_validate_t *ctx)
Validate every DOM node and exact attribute ownership.
static ra8_err_t internal_mark_forward_link(const stream_validate_t *ctx, uint32_t link, uint32_t current)
Record one unique incoming node reference in the caller bitset.
ra8_err_t priv_book_stream_validate_text(const stream_validate_t *ctx, const uint8_t *rec)
Validate one text node's element-only fields and string reference.
static ra8_err_t internal_validate_attrs(const stream_validate_t *ctx)
Validate every attribute name/value string reference.
static ra8_err_t internal_validate_chapters(const stream_validate_t *ctx)
Validate every chapter string and root-node index.
Definition book_stream.c:75
static ra8_err_t internal_validate_body(stream_validate_t *ctx)
Run the strict passes after public argument validation.
static ra8_err_t internal_validate_crc(const stream_validate_t *ctx)
Hash every body byte through the caller transfer buffer.
static ra8_err_t internal_validate_raster(const uint8_t *rec)
Validate one raster image's dimensions, depth, and exact byte count.
static ra8_err_t internal_validate_svg(const uint8_t *rec)
Validate one SVG image's zero extent/depth and raw-storage length.
ra8_err_t priv_book_stream_validate_element(const stream_validate_t *ctx, const uint8_t *rec, uint32_t *attr_cursor)
Validate one element node and its canonical attribute span.
static ra8_err_t internal_validate_one_node(const stream_validate_t *ctx, const uint8_t *rec, uint32_t *attr_cursor, uint32_t index)
Validate one node record's fields and mark its forward links.
static ra8_err_t internal_forward_link(uint32_t link, uint32_t current, uint32_t count)
Validate one optional forward node link.
ra8_err_t priv_book_stream_validate_styles(const stream_validate_t *ctx)
Validate every stylesheet source and optional chapter scope.
ra8_err_t book_validate_stream_strict(book_stream_read_fn read, void *read_ctx, uint64_t source_size, uint8_t *scratch, uint32_t scratch_cap, book_header_t *out_header)
Strictly validate one callback-backed RABOOK1 flat blob.
ra8_err_t priv_book_stream_validate_metadata(const stream_validate_t *ctx)
Validate metadata string references and the optional cover index.
Definition book_stream.c:38
Strict, zero-allocation validation of a streamed RABOOK1 flat blob.
ra8_err_t(* book_stream_read_fn)(void *ctx, uint64_t offset, uint8_t *dst, uint32_t len)
Exact random-read callback over an inflated RABOOK1 flat blob.
Definition book_stream.h:38
Private wire geometry for strict RABOOK1 stream validation.
@ k_stream_image_raw_size
Decoded payload-size field.
@ k_stream_image_pixfmt
Raster pixel-format offset.
@ k_stream_image_data_off
Payload-relative offset field.
@ k_stream_image_format
Image-kind byte offset.
@ k_stream_image_width
Raster-width field offset.
@ k_stream_image_reserved
Reserved-zero field offset.
@ k_stream_image_height
Raster-height field offset.
@ k_stream_image_id
Image-id string offset.
@ k_stream_image_data_size
Stored payload-size field.
static uint32_t internal_book_stream_le32(const uint8_t *p)
Decode one little-endian 32-bit field from unaligned bytes.
ra8_err_t priv_book_stream_validate_string_envelope(const stream_validate_t *ctx)
Validate the string pool's leading and trailing NUL sentinels.
static uint16_t internal_book_stream_le16(const uint8_t *p)
Decode one little-endian 16-bit field from unaligned bytes.
ra8_err_t priv_book_stream_nonempty_string_ref(const stream_validate_t *ctx, uint32_t off)
Require a string reference to name a non-empty interned string.
@ k_stream_node_kind
Node-kind byte offset.
@ k_stream_node_reserved
Reserved-zero byte offset.
@ k_stream_node_first_child
First-child node index field.
@ k_stream_node_name
Element-name string offset.
@ k_stream_node_first_attr
First-attribute index field.
@ k_stream_node_text
Text string-offset field.
@ k_stream_node_attr_count
Attribute-count field offset.
@ k_stream_node_next_sibling
Next-sibling node index field.
ra8_err_t priv_book_stream_read_validate_header(stream_validate_t *ctx)
Read, decode, and validate the canonical stream header and layout.
ra8_err_t priv_book_stream_read(const stream_validate_t *ctx, uint64_t off, uint8_t *dst, uint32_t len)
Read one exact, bounded source span.
ra8_err_t priv_book_stream_string_ref(const stream_validate_t *ctx, uint32_t off)
Require a referenced offset to name an interned-string boundary.
Annotation-attribute framework macros for ra8-firmware.
#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_range_check_failed
Value outside range enforced by RA8_CHECK_RANGE / RA8_CHECK_RANGE_TAG.
Definition ra8_err.h:471
@ 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
void * memset(void *dst, int value, size_t n)
Fill memory with a constant byte value.
Fixed 100-byte prologue describing every table and pool in the blob.
Definition book.h:246
uint32_t author_off
String-pool offset of the author.
Definition book.h:252
uint32_t crc32_val
CRC-32/ISO-HDLC of the body (all bytes after this header).
Definition book.h:270
uint32_t image_off
Offset to the image table.
Definition book.h:265
uint32_t image_pool_size
Image-pool length in bytes.
Definition book.h:269
uint32_t language_off
String-pool offset of the BCP-47 language.
Definition book.h:253
uint32_t attr_count
Number of attribute records.
Definition book.h:260
uint32_t node_count
Number of DOM nodes.
Definition book.h:258
uint32_t chapter_count
Number of spine chapters.
Definition book.h:256
uint32_t image_count
Number of image descriptors.
Definition book.h:264
uint32_t title_off
String-pool offset of the book title.
Definition book.h:251
uint32_t attr_off
Offset to the attribute table.
Definition book.h:261
uint32_t node_off
Offset to the node table.
Definition book.h:259
uint32_t identifier_off
String-pool offset of the unique book id.
Definition book.h:254
uint32_t stylesheet_off
Offset to the stylesheet table.
Definition book.h:263
uint32_t chapter_off
Offset to the chapter table.
Definition book.h:257
uint32_t stylesheet_count
Number of preserved stylesheets.
Definition book.h:262
uint32_t total_size
Total blob length in bytes.
Definition book.h:249
uint32_t cover_image_index
Image-table index of the cover, or nil.
Definition book.h:255
Immutable validation state shared by the bounded table passes.
uint8_t * scratch
Caller transfer buffer.
uint32_t scratch_cap
Transfer-buffer capacity.
book_header_t hdr
Decoded host-order header.