ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
ra8_fmt_stream_inspect.c
Go to the documentation of this file.
1
16
17#include <stddef.h>
18#include <stdint.h>
19
20#include "ra8_attributes.h"
21#include "ra8_fmt_stream.h"
22
36
54static ra8_err_t internal_put(const ra8_fmt_sink_t* report, const uint8_t* bytes, size_t len)
55{
56 return report->write(report->ctx, bytes, len);
57}
58
75static ra8_err_t internal_text(const ra8_fmt_sink_t* report, const char* text)
76{
77 size_t len = 0U;
78 while (text[len] != '\0') {
79 len++;
80 }
81 return internal_put(report, (const uint8_t*)text, len);
82}
83
100static ra8_err_t internal_char(const ra8_fmt_sink_t* report, char value)
101{
102 const uint8_t byte = (uint8_t)value;
103 return internal_put(report, &byte, 1U);
104}
105
123static ra8_err_t internal_u64(const ra8_fmt_sink_t* report, uint64_t value, uint32_t width)
124{
125 char digits[k_fmt_text_dec_digits];
126 uint32_t count = 0U;
127 do {
128 digits[count++] = (char)('0' + (char)(value % k_fmt_text_dec_radix));
129 value /= k_fmt_text_dec_radix;
130 } while (value != 0U);
131 ra8_err_t rc = k_ra8_ok;
132 for (uint32_t i = count; (i < width) && (rc == k_ra8_ok); ++i) {
133 rc = internal_char(report, ' ');
134 }
135 while ((count != 0U) && (rc == k_ra8_ok)) {
136 rc = internal_char(report, digits[--count]);
137 }
138 return rc;
139}
140
159static ra8_err_t internal_hex(const ra8_fmt_sink_t* report, uint64_t value, uint32_t width)
160{
161 static const char s_digits[] = "0123456789ABCDEF";
162 char text[k_fmt_text_hex_digits];
163 if (width > (uint32_t)sizeof(text)) {
165 }
166 for (uint32_t i = 0U; i < width; ++i) {
167 const uint32_t shift = (width - i - 1U) * k_fmt_text_nibble;
168 text[i] = s_digits[(value >> shift) & k_fmt_text_nibble_mask];
169 }
170 return internal_put(report, (const uint8_t*)text, width);
171}
172
192 const char* label,
193 uint64_t value,
194 const char* suffix)
195{
196 ra8_err_t rc = internal_text(report, label);
197 if (rc == k_ra8_ok) {
198 rc = internal_u64(report, value, 0U);
199 }
200 if (rc == k_ra8_ok) {
201 rc = internal_text(report, suffix);
202 }
203 return rc;
204}
205
225static ra8_err_t
226internal_read_exact(const ra8_fmt_source_t* source, uint64_t offset, uint8_t* bytes, size_t len)
227{
228 size_t got = 0U;
229 const ra8_err_t rc = source->read_at(source->ctx, offset, bytes, len, &got);
230 if (rc != k_ra8_ok) {
231 return rc;
232 }
233 return (got == len) ? k_ra8_ok : k_ra8_err_validation_failed;
234}
235
256 const char* label,
257 uint64_t offset,
258 size_t len)
259{
260 ra8_err_t rc = internal_text(report, label);
261 if (rc == k_ra8_ok) {
262 rc = internal_text(report, " (");
263 }
264 if (rc == k_ra8_ok) {
265 rc = internal_u64(report, len, 0U);
266 }
267 if (rc == k_ra8_ok) {
268 rc = internal_text(report, " bytes at +");
269 }
270 if (rc == k_ra8_ok) {
271 rc = internal_u64(report, offset, 0U);
272 }
273 if (rc == k_ra8_ok) {
274 rc = internal_text(report, "):\n");
275 }
276 return rc;
277}
278
301 uint64_t offset,
302 const uint8_t* row,
303 size_t count)
304{
305 ra8_err_t rc = internal_text(report, " ");
306 if (rc == k_ra8_ok) {
307 rc = internal_hex(report, offset, 8U);
308 }
309 if (rc == k_ra8_ok) {
310 rc = internal_text(report, " ");
311 }
312 for (size_t i = 0U; (i < (size_t)k_fmt_text_hex_row) && (rc == k_ra8_ok); ++i) {
313 if (i < count) {
314 rc = internal_hex(report, row[i], 2U);
315 if (rc == k_ra8_ok) {
316 rc = internal_char(report, ' ');
317 }
318 } else {
319 rc = internal_text(report, " ");
320 }
321 }
322 if (rc == k_ra8_ok) {
323 rc = internal_text(report, " |");
324 }
325 for (size_t i = 0U; (i < count) && (rc == k_ra8_ok); ++i) {
326 const bool printable =
327 (row[i] >= (uint8_t)k_fmt_text_ascii_low) && (row[i] <= (uint8_t)k_fmt_text_ascii_high);
328 rc = internal_char(report, (char)(printable ? (char)row[i] : '.'));
329 }
330 if (rc == k_ra8_ok) {
331 rc = internal_text(report, "|\n");
332 }
333 return rc;
334}
335
356 const ra8_fmt_sink_t* report,
357 const char* label,
358 uint64_t offset,
359 size_t len)
360{
361 ra8_err_t rc = internal_hex_dump_header(report, label, offset, len);
362 uint8_t row[k_fmt_text_hex_row];
363 size_t done = 0U;
364 while ((done < len) && (rc == k_ra8_ok)) {
365 size_t count = len - done;
366 if (count > sizeof(row)) {
367 count = sizeof(row);
368 }
369 rc = internal_read_exact(source, offset + done, row, count);
370 if (rc == k_ra8_ok) {
371 rc = internal_hex_dump_row(report, offset + done, row, count);
372 }
373 done += count;
374 }
375 return rc;
376}
377
394static ra8_err_t internal_dimensions(const jof_info_t* info, const ra8_fmt_sink_t* report)
395{
396 ra8_err_t rc = internal_text(report, " image : ");
397 if (rc == k_ra8_ok) {
398 rc = internal_u64(report, info->width, 0U);
399 }
400 if (rc == k_ra8_ok) {
401 rc = internal_text(report, " x ");
402 }
403 if (rc == k_ra8_ok) {
404 rc = internal_u64(report, info->height, 0U);
405 }
406 if (rc == k_ra8_ok) {
407 rc = internal_text(report, " px\n tile : ");
408 }
409 if (rc == k_ra8_ok) {
410 rc = internal_u64(report, info->tile_w, 0U);
411 }
412 if (rc == k_ra8_ok) {
413 rc = internal_text(report, " x ");
414 }
415 if (rc == k_ra8_ok) {
416 rc = internal_u64(report, info->tile_h, 0U);
417 }
418 if (rc == k_ra8_ok) {
419 rc = internal_text(report, " px\n grid : ");
420 }
421 if (rc == k_ra8_ok) {
422 rc = internal_u64(report, info->tile_cols, 0U);
423 }
424 if (rc == k_ra8_ok) {
425 rc = internal_text(report, " cols x ");
426 }
427 if (rc == k_ra8_ok) {
428 rc = internal_u64(report, info->tile_rows, 0U);
429 }
430 if (rc == k_ra8_ok) {
431 rc = internal_text(report, " rows\n");
432 }
433 return rc;
434}
435
454 const jof_info_t* info,
455 const ra8_fmt_sink_t* report)
456{
457 ra8_err_t rc = internal_text(report, "JOF atlas: ");
458 if (rc == k_ra8_ok) {
459 rc = internal_u64(report, source->size, 0U);
460 }
461 if (rc == k_ra8_ok) {
462 rc = internal_text(report, " bytes\n");
463 }
464 if (rc == k_ra8_ok) {
465 rc = internal_dimensions(info, report);
466 }
467 if (rc == k_ra8_ok) {
468 rc = internal_value_line(report, " bpp : ", info->bpp, "\n");
469 }
470 if (rc == k_ra8_ok) {
471 rc = internal_value_line(report, " codec : ", info->codec, " (");
472 }
473 if (rc == k_ra8_ok) {
474 rc = internal_text(report,
475 (info->codec == (uint8_t)k_jof_codec_deflate) ? "deflate)\n" : "raw)\n");
476 }
477 if (rc == k_ra8_ok) {
478 rc = internal_value_line(report, " tile_count : ", info->tile_count, "\n");
479 }
480 if (rc == k_ra8_ok) {
481 rc = internal_value_line(report, " index_off : ", info->index_off, "\n");
482 }
483 if (rc == k_ra8_ok) {
484 rc = internal_value_line(report, " total_size : ", info->total_size, "\n longstrip : ");
485 }
486 if (rc == k_ra8_ok) {
487 rc = internal_text(report,
488 (info->tile_w == info->width) ? "YES (tile_w == width)\n"
489 : "NO (tile_w != width)\n");
490 }
491 return rc;
492}
493
512static ra8_err_t
513internal_table_row(const ra8_fmt_sink_t* report, uint32_t index, const jof_audit_record_t* record)
514{
515 ra8_err_t rc = internal_u64(report, index, 8U);
516 if (rc == k_ra8_ok) {
517 rc = internal_u64(report, record->offset, k_fmt_text_col_width);
518 }
519 if (rc == k_ra8_ok) {
520 rc = internal_u64(report, record->length, k_fmt_text_col_width);
521 }
522 if (rc == k_ra8_ok) {
523 rc = internal_u64(report, record->payload, k_fmt_text_col_width);
524 }
525 if (rc == k_ra8_ok) {
526 rc = internal_u64(report, record->width, 6U);
527 }
528 if (rc == k_ra8_ok) {
529 rc = internal_u64(report, record->height, 6U);
530 }
531 if (rc == k_ra8_ok) {
532 rc = internal_text(report, " ");
533 }
534 if (rc == k_ra8_ok) {
535 rc = internal_hex(report, record->content_hash, 8U);
536 }
537 if (rc == k_ra8_ok) {
538 rc = internal_char(report, '\n');
539 }
540 return rc;
541}
542
560static ra8_err_t
561internal_table(const jof_audit_record_t* records, uint32_t count, const ra8_fmt_sink_t* report)
562{
563 ra8_err_t rc =
564 internal_text(report, " tile offset length payload tw th hash\n");
565 uint32_t shown = count;
566 if (shown > k_fmt_text_max_rows) {
567 shown = k_fmt_text_max_rows;
568 }
569 for (uint32_t i = 0U; (i < shown) && (rc == k_ra8_ok); ++i) {
570 rc = internal_table_row(report, i, &records[i]);
571 }
572 if ((shown < count) && (rc == k_ra8_ok)) {
573 rc = internal_text(report, " ... ");
574 }
575 if ((shown < count) && (rc == k_ra8_ok)) {
576 rc = internal_u64(report, count - shown, 0U);
577 }
578 if ((shown < count) && (rc == k_ra8_ok)) {
579 rc = internal_text(report, " more tiles elided\n");
580 }
581 return rc;
582}
583
585 bool verbose,
586 const ra8_fmt_jof_inspect_workspace_t* workspace,
587 const ra8_fmt_sink_t* report)
588{
589 if ((source == nullptr) || (source->read_at == nullptr) || (workspace == nullptr) ||
590 (report == nullptr) || (report->write == nullptr)) {
591 return k_ra8_err_null_ptr;
592 }
593 jof_audit_workspace_t audit_workspace = {.records = workspace->records,
594 .record_cap = workspace->record_cap,
595 .tile = workspace->tile,
596 .tile_cap = workspace->tile_cap,
597 .scratch = workspace->scratch,
598 .scratch_cap = workspace->scratch_cap};
599 jof_audit_result_t result = {};
600 const ra8_err_t audit_rc =
601 jof_audit(source->read_at, source->ctx, source->size, &audit_workspace, &result);
602 if ((audit_rc != k_ra8_ok) && (audit_rc != k_ra8_err_validation_failed)) {
603 return audit_rc;
604 }
605 ra8_err_t rc = internal_geometry(source, &result.info, report);
606 if (verbose && (rc == k_ra8_ok)) {
607 rc = internal_hex_dump(source, report, "header", 0U, (size_t)k_jof_hdr_bytes);
608 }
609 if (verbose && (rc == k_ra8_ok)) {
610 rc = internal_hex_dump(source,
611 report,
612 "footer",
613 source->size - (uint64_t)k_jof_footer_bytes,
614 (size_t)k_jof_footer_bytes);
615 }
616 if (verbose && (rc == k_ra8_ok)) {
617 rc = internal_table(workspace->records, result.info.tile_count, report);
618 }
619 if ((result.duplicate_candidates != 0U) && (rc == k_ra8_ok)) {
620 rc = internal_value_line(report,
621 " duplicate hash candidates: ",
623 " (diagnostic only)\n");
624 }
625 if (rc == k_ra8_ok) {
626 const char* verdict = "verdict: INVALID (see anomalies above)\n";
627 if ((audit_rc == k_ra8_ok) && (result.duplicate_candidates == 0U)) {
628 verdict = "verdict: VALID (coverage exact, no duplicate tiles)\n";
629 } else if (audit_rc == k_ra8_ok) {
630 verdict = "verdict: VALID (coverage exact; duplicate hashes are diagnostic)\n";
631 }
632 rc = internal_text(report, verdict);
633 }
634 return (rc == k_ra8_ok) ? audit_rc : rc;
635}
@ k_jof_footer_bytes
Footer length.
Definition jof.h:144
@ k_jof_hdr_bytes
Header length.
Definition jof.h:143
@ k_jof_codec_deflate
Tile stream is one raw-DEFLATE run.
Definition jof.h:192
ra8_err_t jof_audit(jof_pread_fn pread, void *pread_ctx, uint64_t total_size, jof_audit_workspace_t *workspace, jof_audit_result_t *out)
Audit coverage, geometry and duplicate-content evidence in bounded RAM.
Definition jof_audit.c:513
Annotation-attribute framework macros for ra8-firmware.
#define RA8_INTERNAL
Marker that a function is intended to be static (file-local).
@ 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_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
Caller-workspace I/O contracts for portable format-tool engines.
static ra8_err_t internal_hex_dump_header(const ra8_fmt_sink_t *report, const char *label, uint64_t offset, size_t len)
Emit the label/length/offset header line for a hex/ASCII dump.
static ra8_err_t internal_table(const jof_audit_record_t *records, uint32_t count, const ra8_fmt_sink_t *report)
Emit the verbose per-tile table.
static ra8_err_t internal_value_line(const ra8_fmt_sink_t *report, const char *label, uint64_t value, const char *suffix)
Emit one label/value decimal line.
static ra8_err_t internal_dimensions(const jof_info_t *info, const ra8_fmt_sink_t *report)
Emit image, tile, and grid dimensions in the legacy CLI layout.
static ra8_err_t internal_hex_dump_row(const ra8_fmt_sink_t *report, uint64_t offset, const uint8_t *row, size_t count)
Render one already-loaded hex/ASCII row: offset, hex bytes, ASCII.
static ra8_err_t internal_hex_dump(const ra8_fmt_source_t *source, const ra8_fmt_sink_t *report, const char *label, uint64_t offset, size_t len)
Emit one labelled hex/ASCII source window.
static ra8_err_t internal_put(const ra8_fmt_sink_t *report, const uint8_t *bytes, size_t len)
Append a byte span to the report sink.
static ra8_err_t internal_hex(const ra8_fmt_sink_t *report, uint64_t value, uint32_t width)
Append an uppercase hexadecimal value with zero padding.
static ra8_err_t internal_u64(const ra8_fmt_sink_t *report, uint64_t value, uint32_t width)
Append an unsigned decimal with optional left padding.
static ra8_err_t internal_geometry(const ra8_fmt_source_t *source, const jof_info_t *info, const ra8_fmt_sink_t *report)
Emit parsed JOF geometry in the legacy CLI layout.
static ra8_err_t internal_read_exact(const ra8_fmt_source_t *source, uint64_t offset, uint8_t *bytes, size_t len)
Read an exact source window.
ra8_err_t ra8_fmt_jof_inspect_stream(const ra8_fmt_source_t *source, bool verbose, const ra8_fmt_jof_inspect_workspace_t *workspace, const ra8_fmt_sink_t *report)
Inspect one JOF source through callbacks and caller storage.
static ra8_err_t internal_table_row(const ra8_fmt_sink_t *report, uint32_t index, const jof_audit_record_t *record)
Render one audit-record row of the verbose per-tile table.
static ra8_err_t internal_char(const ra8_fmt_sink_t *report, char value)
Append one character.
fmt_text_const_t
Text formatting constants.
@ k_fmt_text_hex_digits
Maximum u64 hex digits.
@ k_fmt_text_nibble_mask
Low-nibble extraction mask.
@ k_fmt_text_dec_radix
Decimal formatting radix.
@ k_fmt_text_ascii_low
First printable ASCII byte.
@ k_fmt_text_col_width
Stored-value column width.
@ k_fmt_text_max_rows
Maximum verbose tile rows.
@ k_fmt_text_dec_digits
Maximum u64 decimal digits.
@ k_fmt_text_nibble
Bits in one hex digit.
@ k_fmt_text_ascii_high
Last printable ASCII byte.
@ k_fmt_text_hex_row
Bytes per hex dump row.
static ra8_err_t internal_text(const ra8_fmt_sink_t *report, const char *text)
Append a NUL-terminated literal to the report sink.
One decoded tile's stored window and content evidence.
Definition jof_audit.h:38
uint16_t height
Edge-clamped decoded height.
Definition jof_audit.h:44
uint32_t length
Stored-stream length.
Definition jof_audit.h:40
uint16_t width
Edge-clamped decoded width.
Definition jof_audit.h:43
uint32_t offset
Absolute stored-stream offset.
Definition jof_audit.h:39
uint32_t content_hash
FNV-1a over decoded bytes.
Definition jof_audit.h:42
uint32_t payload
Exact decoded payload bytes.
Definition jof_audit.h:41
Geometry plus anomaly counts emitted by a complete audit.
Definition jof_audit.h:78
jof_info_t info
Parsed atlas geometry.
Definition jof_audit.h:79
uint32_t duplicate_candidates
Matching non-uniform hash/size evidence.
Definition jof_audit.h:83
Caller-owned buffers consumed by one audit.
Definition jof_audit.h:64
Parsed + validated geometry of one JOF atlas.
Definition jof.h:208
uint8_t bpp
Bytes per pixel (1, 3 or 4).
Definition jof.h:215
uint8_t codec
jof_codec_t member.
Definition jof.h:216
uint16_t tile_w
Tile width, pixels.
Definition jof.h:211
uint16_t width
Image width, pixels.
Definition jof.h:209
uint32_t index_off
Absolute byte offset of the tile index.
Definition jof.h:218
uint16_t tile_rows
Ceil(height / tile_h) tile rows.
Definition jof.h:214
uint16_t tile_h
Tile height, pixels.
Definition jof.h:212
uint32_t tile_count
Total tiles (== cols * rows).
Definition jof.h:217
uint16_t height
Image height, pixels.
Definition jof.h:210
uint32_t total_size
Whole atlas byte length (footer included).
Definition jof.h:219
uint16_t tile_cols
Ceil(width / tile_w) tile columns.
Definition jof.h:213
Exact caller-owned storage used by streaming JOF inspection.
uint32_t scratch_cap
Compressed staging capacity.
uint8_t * scratch
Compressed tile staging.
uint32_t tile_cap
Decoded tile capacity.
uint8_t * tile
Reusable decoded tile.
uint32_t record_cap
Record entries available.
jof_audit_record_t * records
Audit record array.
Injected append-only sink.
Immutable, randomly readable input object.
uint64_t size
Exact object byte length.
void * ctx
Backend-owned context.
jof_pread_fn read_at
Positioned-read callback.