ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
ra8_fmt_portable_verify.c
Go to the documentation of this file.
1
11
12#include <stddef.h>
13#include <stdint.h>
14#include <string.h>
15#include <unistd.h>
16
17#include "ra8_attributes.h"
21#include "ra8_fmt_stream.h"
22
32
34typedef struct {
35 const char* input;
36 const char* output;
37 const char* format;
39
41typedef struct {
42 size_t producer;
43 size_t webp;
44 size_t scratch;
45 size_t row;
46 size_t total;
48
65static ra8_err_t internal_text(const ra8_fmt_sink_t* sink, const char* text)
66{
67 return sink->write(sink->ctx, (const uint8_t*)text, strlen(text));
68}
69
86static ra8_err_t internal_u64(const ra8_fmt_sink_t* sink, uint64_t value)
87{
88 char reverse[k_verify_cli_digits];
89 size_t count = 0U;
90 do {
91 reverse[count++] = (char)('0' + (char)(value % k_verify_cli_decimal));
92 value /= k_verify_cli_decimal;
93 } while (value != 0U);
94 char text[k_verify_cli_digits];
95 for (size_t i = 0U; i < count; ++i) {
96 text[i] = reverse[count - i - 1U];
97 }
98 return sink->write(sink->ctx, (const uint8_t*)text, count);
99}
100
116static void
117internal_field(const ra8_fmt_sink_t* sink, uint64_t value, const char* suffix, ra8_err_t* status)
118{
119 if (*status == k_ra8_ok) {
120 *status = internal_u64(sink, value);
121 }
122 if (*status == k_ra8_ok) {
123 *status = internal_text(sink, suffix);
124 }
125}
126
141static void internal_status(const ra8_fmt_sink_t* sink, const char* prefix, ra8_err_t status)
142{
143 ra8_err_t rc = internal_text(sink, prefix);
144 internal_field(sink, status, ")\n", &rc);
145}
146
164static bool internal_parse(int argc, char** argv, verify_cli_args_t* args)
165{
166 for (int i = 2; i < argc; ++i) {
167 if ((strcmp(argv[i], "--format") == 0) && ((i + 1) < argc)) {
168 args->format = argv[++i];
169 } else if ((strcmp(argv[i], "--in") == 0) && ((i + 1) < argc)) {
170 args->input = argv[++i];
171 } else if ((strcmp(argv[i], "--out") == 0) && ((i + 1) < argc)) {
172 args->output = argv[++i];
173 } else if ((strcmp(argv[i], "--verbose") == 0) || (strcmp(argv[i], "-v") == 0)) {
174 continue;
175 } else if ((argv[i][0] != '-') && (args->input == nullptr)) {
176 args->input = argv[i];
177 } else {
178 return false;
179 }
180 }
181 return true;
182}
183
200static bool internal_align(size_t value, size_t* out)
201{
202 const size_t mask = (size_t)k_verify_cli_align - 1U;
203 if (value > (SIZE_MAX - mask)) {
204 return false;
205 }
206 *out = (value + mask) & ~mask;
207 return true;
208}
209
227static bool internal_add(size_t offset, size_t bytes, size_t* next)
228{
229 size_t aligned = 0U;
230 if (!internal_align(offset, &aligned) || (bytes > (SIZE_MAX - aligned))) {
231 return false;
232 }
233 *next = aligned + bytes;
234 return true;
235}
236
254{
255 *layout = (verify_layout_t){};
256 layout->producer = (need->reference_work_bytes > need->banded_work_bytes)
258 : need->banded_work_bytes;
259 size_t producer_end = 0U;
260 if (!internal_align(layout->producer, &layout->webp) ||
261 !internal_add(layout->webp, need->webp_work_bytes, &producer_end)) {
262 return false;
263 }
264 size_t scratch_end = 0U;
265 size_t compare_end = 0U;
266 if (!internal_align(need->band_tile_bytes, &layout->scratch) ||
267 !internal_add(layout->scratch, need->scratch_bytes, &scratch_end) ||
268 !internal_align(scratch_end, &layout->row) ||
269 !internal_add(layout->row, need->row_bytes, &compare_end)) {
270 return false;
271 }
272 layout->total = (producer_end > compare_end) ? producer_end : compare_end;
273 return true;
274}
275
291static void internal_capacity(const ra8_fmt_sink_t* errors,
293 const verify_layout_t* layout,
294 size_t supplied)
295{
296 ra8_err_t rc = internal_text(errors, "ra8_fmt: JOF verify workspace too small: required ");
297 internal_field(errors, layout->total, " supplied ", &rc);
298 internal_field(errors, supplied, " (producer ", &rc);
299 internal_field(errors, layout->producer, ", webp ", &rc);
300 internal_field(errors, need->webp_work_bytes, ", band ", &rc);
301 internal_field(errors, need->band_tile_bytes, ", scratch ", &rc);
302 internal_field(errors, need->scratch_bytes, ", row ", &rc);
303 internal_field(errors, need->row_bytes, ")\n", &rc);
304}
305
308static ra8_err_t internal_failed_append(void* ctx, const uint8_t* bytes, size_t len)
309{
310 (void)ctx;
311 (void)bytes;
312 (void)len;
313 return k_ra8_fail;
314}
315
331{
332 (void)ctx;
333 return k_ra8_fail;
334}
335
348static void internal_failed_abort(void* ctx)
349{
350 (void)ctx;
351}
352
358
376 const verify_layout_t* layout,
378{
380 .work = root->bytes,
381 .work_cap = (uint32_t)layout->producer,
382 .webp_work = (need->webp_work_bytes == 0U) ? nullptr : &root->bytes[layout->webp],
383 .webp_work_cap = need->webp_work_bytes,
384 .band_tile = root->bytes,
385 .band_tile_cap = need->band_tile_bytes,
386 .scratch = &root->bytes[layout->scratch],
387 .scratch_cap = need->scratch_bytes,
388 .row = &root->bytes[layout->row],
389 .row_cap = need->row_bytes,
390 };
391}
392
418
443 const ra8_fmt_host_source_t* got,
446 ra8_fmt_spool_t* ref_spool,
447 ra8_fmt_spool_t* got_spool,
449 const char* dump_name,
450 const ra8_fmt_sink_t* report)
451{
453 &got->source,
454 need,
455 work,
456 ref_spool,
457 got_spool,
458 dump,
459 dump_name,
460 report);
461}
462
485static int internal_execute(const verify_cli_args_t* args,
486 ra8_fmt_cli_workspace_t* workspace,
487 ra8_fmt_host_source_t* ref_source,
488 ra8_fmt_host_source_t* got_source,
490 const verify_layout_t* layout,
491 const ra8_fmt_sink_t* errors,
492 const ra8_fmt_sink_t* report)
493{
494 ra8_fmt_host_spool_t ref_host_spool = {.fd = -1};
495 ra8_fmt_host_spool_t got_host_spool = {.fd = -1};
496 ra8_fmt_spool_t ref_spool = {};
497 ra8_fmt_spool_t got_spool = {};
498 ra8_err_t rc = priv_fmt_host_spool_open(args->input, &ref_host_spool, &ref_spool);
499 if (rc == k_ra8_ok) {
500 rc = priv_fmt_host_spool_open(args->input, &got_host_spool, &got_spool);
501 }
502 if (rc != k_ra8_ok) {
503 internal_status(errors, "ra8_fmt: cannot create verify spool (rc=", rc);
504 internal_cleanup(ref_source, got_source, &ref_host_spool, &got_host_spool);
505 return (int)k_verify_cli_fail;
506 }
507 ra8_fmt_host_transaction_t host_dump = {.parent_fd = -1, .stage_fd = -1};
508 ra8_fmt_transaction_t dump = {};
509 ra8_fmt_transaction_t* dump_ptr = nullptr;
510 if (args->output != nullptr) {
511 rc = priv_fmt_host_transaction_begin(args->output, &host_dump, &dump);
512 if (rc != k_ra8_ok) {
513 dump = (ra8_fmt_transaction_t){.ops = &s_failed_transaction_ops, .ctx = nullptr};
514 }
515 dump_ptr = &dump;
516 }
518 internal_bind(workspace, need, layout, &work);
519 rc = internal_run(ref_source,
520 got_source,
521 need,
522 &work,
523 &ref_spool,
524 &got_spool,
525 dump_ptr,
526 args->output,
527 report);
528 if (host_dump.active) {
529 dump.ops->abort(dump.ctx);
530 }
531 internal_cleanup(ref_source, got_source, &ref_host_spool, &got_host_spool);
532 return (rc == k_ra8_ok) ? (int)k_verify_cli_ok : (int)k_verify_cli_fail;
533}
534
560 size_t workspace_bytes,
561 ra8_fmt_host_source_t* ref_source,
562 ra8_fmt_host_source_t* got_source,
564 verify_layout_t* layout,
565 const ra8_fmt_sink_t* errors,
566 const ra8_fmt_sink_t* report)
567{
569 if (rc == k_ra8_ok) {
570 rc = priv_fmt_host_source_open(args->input, k_verify_cli_input, got_source);
571 }
572 if ((rc == k_ra8_ok) && (!priv_fmt_host_sources_same(ref_source, got_source) ||
573 (priv_fmt_host_source_unchanged(ref_source) != k_ra8_ok) ||
574 (priv_fmt_host_source_unchanged(got_source) != k_ra8_ok))) {
576 }
577 if (rc != k_ra8_ok) {
578 internal_status(errors, "ra8_fmt: cannot open verify input (rc=", rc);
579 internal_cleanup(ref_source, got_source, nullptr, nullptr);
580 return rc;
581 }
582 rc = ra8_fmt_jof_verify_requirements(&ref_source->source, need);
583 const bool sized = (rc == k_ra8_ok) && internal_layout(need, layout);
584 if ((rc == k_ra8_ok) && (!sized || (layout->total > workspace_bytes))) {
585 internal_capacity(errors, need, layout, workspace_bytes);
587 }
588 if (rc != k_ra8_ok) {
589 internal_status(report, "verify: cannot read source dimensions (rc=", rc);
590 internal_cleanup(ref_source, got_source, nullptr, nullptr);
591 }
592 return rc;
593}
594
596 char** argv,
597 ra8_fmt_cli_workspace_t* workspace,
598 bool* handled)
599{
600 if ((handled == nullptr) || (workspace == nullptr)) {
601 return (int)k_verify_cli_fail;
602 }
603 *handled = false;
604 if ((argc < 2) || (strcmp(argv[1], "verify") != 0)) {
605 return (int)k_verify_cli_ok;
606 }
607 verify_cli_args_t args = {};
608 if (!internal_parse(argc, argv, &args) || (args.format == nullptr) ||
609 (strcmp(args.format, "jof") != 0) || (args.input == nullptr)) {
610 return (int)k_verify_cli_ok;
611 }
612 *handled = true;
613 ra8_fmt_host_fd_sink_t error_state = {.fd = STDERR_FILENO};
614 ra8_fmt_host_fd_sink_t report_state = {.fd = STDOUT_FILENO};
615 const ra8_fmt_sink_t errors = priv_fmt_host_fd_sink(&error_state);
616 const ra8_fmt_sink_t report = priv_fmt_host_fd_sink(&report_state);
617 ra8_fmt_host_source_t ref_source = {.fd = -1};
618 ra8_fmt_host_source_t got_source = {.fd = -1};
620 verify_layout_t layout = {};
621 const ra8_err_t rc = internal_open_and_size(&args,
622 sizeof(workspace->bytes),
623 &ref_source,
624 &got_source,
625 &need,
626 &layout,
627 &errors,
628 &report);
629 if (rc != k_ra8_ok) {
630 return (int)k_verify_cli_fail;
631 }
632 return internal_execute(&args,
633 workspace,
634 &ref_source,
635 &got_source,
636 &need,
637 &layout,
638 &errors,
639 &report);
640}
#define nullptr
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_fail
Generic unspecified failure.
Definition ra8_err.h:133
@ 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
Raw file-descriptor adapters for the portable format-tool contracts.
ra8_err_t priv_fmt_host_transaction_begin(const char *path, ra8_fmt_host_transaction_t *state, ra8_fmt_transaction_t *out)
Begin a sibling-temp durable replacement transaction.
bool priv_fmt_host_sources_same(const ra8_fmt_host_source_t *first, const ra8_fmt_host_source_t *second)
Confirm two opens captured the same unchanged regular-file object.
ra8_err_t priv_fmt_host_source_open(const char *path, uint64_t max_size, ra8_fmt_host_source_t *out)
Open a bounded, regular, non-symlink input object.
ra8_fmt_sink_t priv_fmt_host_fd_sink(ra8_fmt_host_fd_sink_t *state)
Obtain the exact-write portable sink for a raw descriptor.
void priv_fmt_host_source_close(ra8_fmt_host_source_t *source)
Close an open host source; safe after failed open.
ra8_err_t priv_fmt_host_source_unchanged(const ra8_fmt_host_source_t *source)
Revalidate one open descriptor against its captured snapshot.
Anonymous raw-fd scratch artifacts for portable format verification.
void priv_fmt_host_spool_close(ra8_fmt_host_spool_t *state)
Close an anonymous scratch artifact.
ra8_err_t priv_fmt_host_spool_open(const char *anchor_path, ra8_fmt_host_spool_t *state, ra8_fmt_spool_t *out)
Create an anonymous scratch file beside an anchored input path.
static bool internal_align(size_t value, size_t *aligned)
Round one byte count up to the composition arena alignment.
Caller-workspace CLI composition for every supported tool verb.
static ra8_err_t internal_failed_append(void *ctx, const uint8_t *bytes, size_t len)
Append text or binary bytes to a bounded backend.
static void internal_cleanup(ra8_fmt_host_source_t *ref, ra8_fmt_host_source_t *got, ra8_fmt_host_spool_t *ref_spool, ra8_fmt_host_spool_t *got_spool)
Close all verifier-owned source and spool descriptors.
static void internal_bind(ra8_fmt_cli_workspace_t *root, const ra8_fmt_jof_verify_requirements_t *need, const verify_layout_t *layout, ra8_fmt_jof_verify_workspace_t *out)
Bind phase-overlaid producer and comparison arena views.
static bool internal_align(size_t value, size_t *out)
Align one size to the composition slice boundary.
static ra8_err_t internal_text(const ra8_fmt_sink_t *sink, const char *text)
Append one NUL-terminated text fragment.
static ra8_err_t internal_run(const ra8_fmt_host_source_t *ref, const ra8_fmt_host_source_t *got, const ra8_fmt_jof_verify_requirements_t *need, ra8_fmt_jof_verify_workspace_t *work, ra8_fmt_spool_t *ref_spool, ra8_fmt_spool_t *got_spool, ra8_fmt_transaction_t *dump, const char *dump_name, const ra8_fmt_sink_t *report)
Run the fully bound portable verifier engine.
static void internal_capacity(const ra8_fmt_sink_t *errors, const ra8_fmt_jof_verify_requirements_t *need, const verify_layout_t *layout, size_t supplied)
Report exact required and supplied shared-workspace evidence.
verify_cli_const_t
CLI and workspace-layout constants.
@ k_verify_cli_digits
Digits in uint64_t.
@ k_verify_cli_fail
Verification or host failure.
@ k_verify_cli_align
Arena slice alignment.
@ k_verify_cli_input
Maximum encoded input (256 MiB).
@ k_verify_cli_ok
Successful exact verdict.
@ k_verify_cli_decimal
Decimal formatting radix.
int priv_fmt_try_portable_verify(int argc, char **argv, ra8_fmt_cli_workspace_t *workspace, bool *handled)
Try the bounded two-spool JOF-verification command path.
static int internal_execute(const verify_cli_args_t *args, ra8_fmt_cli_workspace_t *workspace, ra8_fmt_host_source_t *ref_source, ra8_fmt_host_source_t *got_source, const ra8_fmt_jof_verify_requirements_t *need, const verify_layout_t *layout, const ra8_fmt_sink_t *errors, const ra8_fmt_sink_t *report)
Bind host spools and optional output, run, and close every owner.
static const ra8_fmt_transaction_ops_t s_failed_transaction_ops
static bool internal_add(size_t offset, size_t bytes, size_t *next)
Add one aligned arena slice without size_t wrapping.
static bool internal_layout(const ra8_fmt_jof_verify_requirements_t *need, verify_layout_t *layout)
Compute exact maximum high-water across producer and compare phases.
static void internal_failed_abort(void *ctx)
Abort an output transaction that never began.
static ra8_err_t internal_open_and_size(const verify_cli_args_t *args, size_t workspace_bytes, ra8_fmt_host_source_t *ref_source, ra8_fmt_host_source_t *got_source, ra8_fmt_jof_verify_requirements_t *need, verify_layout_t *layout, const ra8_fmt_sink_t *errors, const ra8_fmt_sink_t *report)
Open both verify sources and compute the workspace sizing.
static ra8_err_t internal_failed_commit(void *ctx)
Report commit failure for an unavailable optional output.
static void internal_field(const ra8_fmt_sink_t *sink, uint64_t value, const char *suffix, ra8_err_t *status)
Append one numeric field and suffix while status succeeds.
static void internal_status(const ra8_fmt_sink_t *sink, const char *prefix, ra8_err_t status)
Emit one canonical status diagnostic.
static ra8_err_t internal_u64(const ra8_fmt_sink_t *sink, uint64_t value)
Append one uint64_t in decimal.
static bool internal_parse(int argc, char **argv, verify_cli_args_t *args)
Parse only the legacy JOF verify option spellings.
Caller-workspace I/O contracts for portable format-tool engines.
ra8_err_t ra8_fmt_jof_verify_requirements(const ra8_fmt_source_t *source, ra8_fmt_jof_verify_requirements_t *out)
Derive exact producer and comparison storage for bounded JOF verification.
ra8_err_t ra8_fmt_jof_verify_stream(const ra8_fmt_source_t *reference_source, const ra8_fmt_source_t *banded_source, const ra8_fmt_jof_verify_requirements_t *requirements, ra8_fmt_jof_verify_workspace_t *workspace, ra8_fmt_spool_t *reference_spool, ra8_fmt_spool_t *banded_spool, ra8_fmt_transaction_t *dump, const char *dump_name, const ra8_fmt_sink_t *report)
Verify banded JOF pixels against an independently decoded row reference.
int strcmp(const char *s1, const char *s2)
Compare two null-terminated strings.
size_t strlen(const char *s)
Calculate string length.
static void internal_add(ra8_kbd_layout_t *kb, int32_t x, int32_t w, int32_t y, int32_t h, char lo, char hi, ra8_kbd_key_kind_t kind, uint8_t aux)
Append one key descriptor to the layout, bounded by k_ra8_kbd_max_keys.
One explicit, shared composition-root workspace for portable verbs.
uint8_t bytes[k_ra8_fmt_cli_workspace_bytes]
Shared named storage.
Append sink backed by a caller-owned descriptor.
Open raw-fd source and its portable view.
ra8_fmt_source_t source
Portable positioned-read view.
Caller-owned state for one unlinked scratch file.
Caller-owned state for one sibling-file transaction.
bool active
Transaction is usable.
Exact phase-reused storage requirements for JOF verification.
uint32_t row_bytes
One decoded reference row.
uint32_t reference_work_bytes
One-row reference producer arena.
uint32_t band_tile_bytes
Largest decoded subject tile.
uint32_t scratch_bytes
Largest stored-tile staging buffer.
uint32_t webp_work_bytes
Whole-frame WebP arena, or zero.
uint32_t banded_work_bytes
Banded subject producer arena.
Caller-owned phase-overlaid arenas for one bounded JOF verification.
Injected append-only sink.
ra8_fmt_sink_write_fn write
Exact append callback.
void * ctx
Backend-owned context.
Caller-owned scratch artifact with append, seal, and read seams.
Durable artifact-transaction operations.
void(* abort)(void *ctx)
Discard owned staging data.
One caller-owned artifact transaction.
void * ctx
Backend-owned state.
const ra8_fmt_transaction_ops_t * ops
Transaction implementation.
Parsed legacy-compatible JOF verify selections.
const char * output
Optional PPM path.
const char * format
Explicit format.
const char * input
Encoded source path.
Exact phase-overlaid byte offsets in the shared composition arena.
size_t webp
WebP arena offset.
size_t row
Reference-row offset.
size_t scratch
Comparison scratch offset.
size_t producer
Maximum producer work bytes.
size_t total
Exact maximum phase high-water.