ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
mdl_export_tar.c
Go to the documentation of this file.
1
15#include <stdio.h>
16#include <string.h>
17
18#include "mdl_export.h"
19#include "mdl_export_internal.h"
20#include "miniz.h"
21#include "ra8_attributes.h"
22
24typedef enum : uint16_t {
25 k_tar_block = 512U,
27 k_len_name = 100U,
28 k_off_mode = 100U,
29 k_off_uid = 108U,
30 k_off_gid = 116U,
31 k_len_id = 8U,
32 k_off_size = 124U,
33 k_len_size = 12U,
34 k_off_mtime = 136U,
36 k_off_chksum = 148U,
38 k_off_type = 156U,
39 k_off_magic = 257U,
43
45typedef enum : uint16_t {
46 k_file_mode = 0644U,
48
50typedef enum : uint64_t {
51 k_tar_size_max = 077777777777ULL,
53
55typedef enum : uint16_t {
59 k_byte_mask = 255U,
61
63typedef enum : uint8_t {
64 k_gzip_id1 = 0x1FU,
65 k_gzip_id2 = 0x8BU,
69
74
76typedef struct {
78 tdefl_compressor* compressor;
79 uint32_t crc;
80 uint32_t size;
83
85static const uint8_t s_ustar_magic[k_len_magic] = {'u', 's', 't', 'a', 'r', '\0'};
86static const uint8_t s_ustar_version[2] = {'0', '0'};
87
102RA8_INTERNAL static size_t internal_round_block(size_t bytes)
103{
104 return ((bytes + (size_t)k_tar_block - 1U) / (size_t)k_tar_block) * (size_t)k_tar_block;
105}
106
124RA8_INTERNAL static ra8_err_t internal_tar_header(uint8_t* block, const char* name, size_t size)
125{
126 if ((strlen(name) >= (size_t)k_len_name) || (size > k_tar_size_max)) {
128 }
129 memset(block, 0, k_tar_block);
130 (void)snprintf((char*)block + k_off_name, k_len_name, "%s", name);
131 (void)snprintf((char*)block + k_off_mode, k_len_id, "%07o", (unsigned)k_file_mode);
132 (void)snprintf((char*)block + k_off_uid, k_len_id, "%07o", 0U);
133 (void)snprintf((char*)block + k_off_gid, k_len_id, "%07o", 0U);
134 (void)snprintf((char*)block + k_off_size, k_len_size, "%011zo", size);
135 (void)snprintf((char*)block + k_off_mtime, k_len_mtime, "%011o", 0U);
136 block[k_off_type] = '0';
139 memset(block + k_off_chksum, ' ', k_len_chksum);
140 unsigned sum = 0U;
141 for (size_t i = 0U; i < (size_t)k_tar_block; ++i) {
142 sum += block[i];
143 }
144 (void)snprintf((char*)block + k_off_chksum, k_len_chksum - 1U, "%06o", sum);
145 block[k_off_chksum + k_len_chksum - 1U] = ' ';
146 return k_ra8_ok;
147}
148
166RA8_INTERNAL static ra8_err_t internal_direct_sink(void* ctx, const uint8_t* bytes, uint32_t length)
167{
168 return priv_mdl_export_output_write(((internal_tar_sink_t*)ctx)->output, bytes, length);
169}
170
189internal_write_zeros(mdl_export_sink_fn_t sink, void* ctx, uint32_t length)
190{
191 const uint8_t zeros[k_tar_block] = {};
192 return (length == 0U) ? k_ra8_ok : sink(ctx, zeros, length);
193}
194
215 void* ctx,
216 const char* name,
217 const uint8_t* bytes,
218 size_t length)
219{
220 uint8_t header[k_tar_block];
221 ra8_err_t err = internal_tar_header(header, name, length);
222 if (err == k_ra8_ok) {
223 err = sink(ctx, header, sizeof(header));
224 }
225 if ((err == k_ra8_ok) && (length > UINT32_MAX)) {
227 }
228 if ((err == k_ra8_ok) && (length != 0U)) {
229 err = sink(ctx, bytes, (uint32_t)length);
230 }
231 if (err == k_ra8_ok) {
232 err = internal_write_zeros(sink, ctx, (uint32_t)(internal_round_block(length) - length));
233 }
234 return err;
235}
236
257 const char* path,
258 const char* member,
260 void* ctx)
261{
262 mdl_export_source_t source = {};
263 ra8_err_t err = priv_mdl_export_source_open(&source, storage, path);
264 uint64_t source_size = source.size;
265 if ((err == k_ra8_ok) && (source.size > SIZE_MAX)) {
267 }
268 uint8_t header[k_tar_block];
269 if (err == k_ra8_ok) {
270 err = internal_tar_header(header, member, (size_t)source.size);
271 }
272 if (err == k_ra8_ok) {
273 err = sink(ctx, header, sizeof(header));
274 }
275 if (err == k_ra8_ok) {
276 err = priv_mdl_export_source_copy(&source, sink, ctx);
277 } else if (source.file.is_open) {
278 const ra8_err_t closed = priv_mdl_export_source_close(&source);
279 if (closed != k_ra8_ok) {
280 err = closed;
281 }
282 }
283 if (err == k_ra8_ok) {
285 sink,
286 ctx,
287 (uint32_t)(internal_round_block((size_t)source_size) - (size_t)source_size));
288 }
289 return err;
290}
291
314 const char* directory,
315 char names[][k_name_max],
316 size_t count,
317 const mdl_export_meta_t* meta,
319 void* ctx)
320{
321 ra8_err_t err = k_ra8_ok;
322 for (size_t i = 0U; (err == k_ra8_ok) && (i < count); ++i) {
323 char path[k_fw_fs_path_cap];
324 err = priv_mdl_export_path_join(path, sizeof(path), directory, names[i]);
325 if (err == k_ra8_ok) {
326 err = internal_tar_write_source(storage, path, names[i], sink, ctx);
327 }
328 }
329 char comic_xml[4096];
330 if (err == k_ra8_ok) {
331 err = mdl_export_build_comicinfo_pages(meta, count, comic_xml, sizeof(comic_xml));
332 }
333 if (err == k_ra8_ok) {
334 err = internal_tar_write_memory(sink,
335 ctx,
336 "ComicInfo.xml",
337 (const uint8_t*)comic_xml,
338 strlen(comic_xml));
339 }
340 if (err == k_ra8_ok) {
341 const uint8_t trailer[2U * (size_t)k_tar_block] = {};
342 err = sink(ctx, trailer, sizeof(trailer));
343 }
344 return err;
345}
346
364RA8_INTERNAL static mz_bool internal_gzip_put(const void* bytes, int length, void* ctx)
365{
367 if ((gzip == nullptr) || (length < 0) || (gzip->error != k_ra8_ok)) {
368 return MZ_FALSE;
369 }
370 gzip->error = priv_mdl_export_output_write(gzip->output, bytes, (uint32_t)length);
371 return (gzip->error == k_ra8_ok) ? MZ_TRUE : MZ_FALSE;
372}
373
391RA8_INTERNAL static ra8_err_t internal_gzip_sink(void* ctx, const uint8_t* bytes, uint32_t length)
392{
394 if (gzip->error != k_ra8_ok) {
395 return gzip->error;
396 }
397 gzip->crc = (uint32_t)mz_crc32(gzip->crc, bytes, length);
398 gzip->size += length;
399 if (tdefl_compress_buffer(gzip->compressor, bytes, length, TDEFL_NO_FLUSH) != TDEFL_STATUS_OKAY) {
400 gzip->error = (gzip->error == k_ra8_ok) ? k_ra8_fail : gzip->error;
401 }
402 return gzip->error;
403}
404
417RA8_INTERNAL static void internal_put_u32le(uint8_t* bytes, uint32_t value)
418{
419 for (size_t i = 0U; i < (size_t)k_gzip_u32_bytes; ++i) {
420 bytes[i] = (uint8_t)(value & (uint32_t)k_byte_mask);
421 value >>= (uint32_t)k_byte_bits;
422 }
423}
424
426 const char* dir,
427 char names[][k_name_max],
428 size_t count,
429 mdl_export_output_t* output,
430 const mdl_export_meta_t* meta)
431{
432 internal_tar_sink_t sink = {.output = output};
433 return internal_build_tar(storage, dir, names, count, meta, internal_direct_sink, &sink);
434}
435
437 const char* dir,
438 char names[][k_name_max],
439 size_t count,
440 mdl_export_output_t* output,
441 const mdl_export_meta_t* meta,
443{
444 tdefl_compressor* compressor =
445 (tdefl_compressor*)mdl_export_workspace_take(ws, sizeof(*compressor), 16U);
446 if (compressor == nullptr) {
448 }
449 static const uint8_t header[k_gzip_header_bytes] =
450 {k_gzip_id1, k_gzip_id2, k_gzip_deflate, 0U, 0U, 0U, 0U, 0U, 0U, k_gzip_os_unknown};
451 ra8_err_t err = priv_mdl_export_output_write(output, header, sizeof(header));
452 internal_gzip_sink_t gzip = {.output = output,
453 .compressor = compressor,
454 .crc = (uint32_t)MZ_CRC32_INIT,
455 .error = err};
456 if ((err == k_ra8_ok) &&
457 (tdefl_init(compressor, internal_gzip_put, &gzip, TDEFL_DEFAULT_MAX_PROBES) !=
458 TDEFL_STATUS_OKAY)) {
459 err = k_ra8_fail;
460 }
461 if (err == k_ra8_ok) {
462 err = internal_build_tar(storage, dir, names, count, meta, internal_gzip_sink, &gzip);
463 }
464 if ((err == k_ra8_ok) &&
465 (tdefl_compress_buffer(compressor, nullptr, 0U, TDEFL_FINISH) != TDEFL_STATUS_DONE)) {
466 err = (gzip.error == k_ra8_ok) ? k_ra8_fail : gzip.error;
467 }
468 uint8_t trailer[2U * k_gzip_u32_bytes];
469 internal_put_u32le(trailer, gzip.crc);
471 if (err == k_ra8_ok) {
472 err = priv_mdl_export_output_write(output, trailer, sizeof(trailer));
473 }
474 return err;
475}
@ k_byte_bits
Bits per byte (SHPR field width).
Definition emu_exc.h:99
@ k_fw_fs_path_cap
Largest portable path including its NUL.
Package a downloaded chapter folder into a reader-openable container.
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 mdl_export_build_comicinfo_pages(const mdl_export_meta_t *meta, size_t page_count, char *buf, size_t cap)
Generate ComicInfo.xml including page count and direction semantics.
Module-private contracts shared by chapter export writers.
@ k_name_max
Maximum entry-name bytes.
ra8_err_t priv_mdl_export_path_join(char *out, size_t capacity, const char *directory, const char *leaf)
Join a canonical directory and leaf without truncation.
ra8_err_t priv_mdl_export_source_copy(mdl_export_source_t *source, mdl_export_sink_fn_t sink, void *sink_ctx)
Stream one portable source into a bounded caller sink.
ra8_err_t priv_mdl_export_source_close(mdl_export_source_t *source)
Close one open source and clear its retained binding.
ra8_err_t priv_mdl_export_output_write(mdl_export_output_t *output, const uint8_t *bytes, uint32_t length)
Append one complete byte span to an active export stage.
ra8_err_t priv_mdl_export_source_open(mdl_export_source_t *source, mdl_storage_t *storage, const char *path)
Open one regular source and snapshot its exact nonempty extent.
ra8_err_t(* mdl_export_sink_fn_t)(void *ctx, const uint8_t *bytes, uint32_t length)
Portable archive-output sink signature.
ra8_err_t priv_mdl_export_tar_gzip(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)
Write a gzip-wrapped CBT archive.
mdl_tar_layout_t
ustar header field offsets and widths.
@ k_len_size
Size field width.
@ k_off_mtime
Timestamp field offset.
@ k_off_gid
GID field offset.
@ k_off_version
Ustar version offset.
@ k_off_magic
Ustar magic offset.
@ k_tar_block
Tar record size.
@ k_off_size
Size field offset.
@ k_off_name
Name field offset.
@ k_off_mode
Mode field offset.
@ k_off_chksum
Checksum field offset.
@ k_off_uid
UID field offset.
@ k_off_type
Entry-type field offset.
@ k_len_mtime
Timestamp field width.
@ k_len_name
Name field width.
@ k_len_chksum
Checksum field width.
@ k_len_magic
Ustar magic width.
@ k_len_id
Mode/UID/GID field width.
mdl_gzip_header_t
Fixed non-zero bytes in the RFC 1952 header.
@ k_gzip_deflate
DEFLATE compression method.
@ k_gzip_os_unknown
Unknown originating OS.
@ k_gzip_id2
Gzip identification byte two.
@ k_gzip_id1
Gzip identification byte one.
static ra8_err_t internal_direct_sink(void *ctx, const uint8_t *bytes, uint32_t length)
Append bytes directly to an archive publication stage.
static ra8_err_t internal_gzip_sink(void *ctx, const uint8_t *bytes, uint32_t length)
Feed one uncompressed tar span into streaming DEFLATE.
static const uint8_t s_ustar_magic[k_len_magic]
Fixed ustar magic and version payloads.
static size_t internal_round_block(size_t bytes)
Round one payload extent to a whole tar record.
static ra8_err_t internal_write_zeros(mdl_export_sink_fn_t sink, void *ctx, uint32_t length)
Emit zero padding through one archive sink.
static ra8_err_t internal_build_tar(mdl_storage_t *storage, const char *directory, char names[][k_name_max], size_t count, const mdl_export_meta_t *meta, mdl_export_sink_fn_t sink, void *ctx)
Stream a complete deterministic ustar archive.
mdl_tar_size_t
Largest payload representable by the fixed eleven-digit tar field.
@ k_tar_size_max
Maximum classic octal payload size.
static const uint8_t s_ustar_version[2]
static ra8_err_t internal_tar_write_source(mdl_storage_t *storage, const char *path, const char *member, mdl_export_sink_fn_t sink, void *ctx)
Emit one portable source as a verified tar member.
ra8_err_t priv_mdl_export_tar(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)
Write an uncompressed CBT tar archive.
static mz_bool internal_gzip_put(const void *bytes, int length, void *ctx)
Append DEFLATE callback output to the active stage.
static ra8_err_t internal_tar_header(uint8_t *block, const char *name, size_t size)
Build one deterministic ustar regular-file header.
mdl_gzip_layout_t
Gzip framing and serialization constants.
@ k_gzip_header_bytes
Fixed RFC 1952 header.
@ k_gzip_u32_bytes
Trailer scalar width.
mdl_tar_mode_t
Fixed regular-file mode in deterministic tar headers.
@ k_file_mode
Portable regular-file permission bits.
static void internal_put_u32le(uint8_t *bytes, uint32_t value)
Serialize one little-endian gzip trailer scalar.
static ra8_err_t internal_tar_write_memory(mdl_export_sink_fn_t sink, void *ctx, const char *name, const uint8_t *bytes, size_t length)
Emit one bounded in-memory tar member.
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_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.
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.
@ k_byte_mask
Byte mask.
bool is_open
Facade lifecycle guard.
Online gzip state receiving the uncompressed tar stream.
uint32_t size
Tar size modulo 2^32.
tdefl_compressor * compressor
Caller-arena DEFLATE state.
uint32_t crc
Running tar CRC32.
ra8_err_t error
First output/compress error.
mdl_export_output_t * output
Active gzip output stage.
Direct tar sink adapter.
mdl_export_output_t * output
Active staged transaction.
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.
One open regular source with a snapshotted identity.
fw_fs_file_t file
Open portable source stream.
uint64_t size
Snapshotted source extent.
One non-reentrant downloader filesystem dependency bundle.
Definition mdl_storage.h:40