ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
ra8_rar.h File Reference

Clean-room, read-only RAR archive walker (RAR4 + RAR5 headers, STORE data). More...

#include <stddef.h>
#include <stdint.h>
#include "ra8_err.h"
Include dependency graph for ra8_rar.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  ra8_rar_t
 One open RAR archive: the backing plus the detected generation. More...
struct  ra8_rar_entry_t
 One decoded RAR block: a file member, a directory, or a skipped block. More...

Typedefs

typedef struct ra8_rar5_state ra8_rar5_state_t
 Forward declaration of the RAR5 decompressor scratch (see ra8_rar5.h).
typedef size_t(* ra8_rar_read_fn) (void *ctx, uint64_t offset, void *buf, size_t len)
 Seek+read backing over the RAR container bytes.

Enumerations

enum  ra8_rar_version_t : uint8_t {
  k_ra8_rar_ver_none = 0U ,
  k_ra8_rar_ver_4 = 4U ,
  k_ra8_rar_ver_5 = 5U
}
 Which RAR container generation an archive uses. More...
enum  ra8_rar_method_t : uint8_t {
  k_ra8_rar_method_store = 0U ,
  k_ra8_rar_method_compressed = 1U
}
 Normalised compression method of a file member. More...
enum  ra8_rar_limits_t : uint16_t {
  k_ra8_rar_sig4_len = 7U ,
  k_ra8_rar_sig5_len = 8U ,
  k_ra8_rar_hdr_scratch = 128U ,
  k_ra8_rar_vint_max = 10U
}
 Fixed sizes and grammar constants for the RAR block walk. More...

Functions

ra8_err_t ra8_rar_open (ra8_rar_t *rar, ra8_rar_read_fn read, void *ctx, uint64_t size)
 Detect a RAR archive's generation and locate its first block.
ra8_err_t ra8_rar_next (const ra8_rar_t *rar, uint64_t off, char *name_buf, uint16_t name_cap, ra8_rar_entry_t *out)
 Decode the block header at off and advance to the next block.
ra8_err_t ra8_rar_extract_stored (const ra8_rar_t *rar, const ra8_rar_entry_t *ent, uint8_t *buf, size_t cap, size_t *got)
 Extract a STORE-method member's data into the caller buffer.
ra8_err_t ra8_rar_extract (const ra8_rar_t *rar, const ra8_rar_entry_t *ent, uint8_t *buf, size_t cap, ra8_rar5_state_t *st, size_t *got)
 Extract any file member – STORE by copy, RAR5-compressed by decode.

Detailed Description

Clean-room, read-only RAR archive walker (RAR4 + RAR5 headers, STORE data).

Tag
[Ring 4 / Domain] {World: NS}

A first-party, hand-written RAR reader for the comic-book-archive (.cbr) use case. It parses the two on-disk RAR container generations – the classic RAR 1.5-4.x block format ("RAR4") and the RAR 5.0 block format ("RAR5") – and exposes each archive member (name, sizes, data offset, compression method) through a bounded, seek+read backing. It extracts only STORE-method (uncompressed) members, which is the common shape for comic archives whose pages are already-compressed JPEG/PNG images (RAR leaves those near-incompressible bytes stored). Members packed with RAR's LZ/PPM compression are enumerated but report k_ra8_rar_method_compressed and are not decoded here – see the module overview note on the follow-up for full RAR5 decompression.

Licensing (clean-room, deliberate)
This reader is written from the public RAR 5.0 technical note (rarlab.com technote) and the long-published RAR4 block layout. It vendors no code from RARLAB's unrar package, whose license is non-free and forbids building a RAR-compatible archiver. This file only reads an archive and only extracts the STORE (memcpy) case, so it needs none of unrar's decompressor. It is therefore first-party MIT (root LICENSE.txt), not SOUP, and carries no SBOM entry. Do not replace it with a restrictively-licensed library.
Bounded RAM (NASA P10 Rule 3)
The walker never materialises the archive. ra8_rar_open reads only the signature; ra8_rar_next reads one block header at a time into a small internal scratch (a fixed k_ra8_rar_hdr_scratch bytes on the stack) plus the caller's name buffer; ra8_rar_extract_stored streams one member's data area through the caller's output buffer. Resident set is O(one header + one member), never the file size – so a multi-hundred-MB volume walks inside a few hundred bytes.
Note
Not thread-safe; the single-threaded reader loop serialises access.
See also
comic.h The comic facade that turns this walk into a page list.
https://www.rarlab.com/technote.htm RAR 5.0 archive format (reference).
Since
Version 0.1.0

Definition in file ra8_rar.h.

Typedef Documentation

◆ ra8_rar5_state_t

typedef struct ra8_rar5_state ra8_rar5_state_t

Forward declaration of the RAR5 decompressor scratch (see ra8_rar5.h).

ra8_rar_extract routes a compressed RAR5 member through the decoder, which needs this caller-owned pool; the full definition lives in ra8_rar5.h so this header stays free of the decoder internals.

Since
Version 0.1.0

Definition at line 67 of file ra8_rar.h.

◆ ra8_rar_read_fn

typedef size_t(* ra8_rar_read_fn) (void *ctx, uint64_t offset, void *buf, size_t len)

Seek+read backing over the RAR container bytes.

Mirrors the streaming EPUB/CBZ read seam (offset + length, bytes-actually-read return), so the same ra8_fs file / ra8_vmem page-cache backing that streams a .epub off storage drives a .cbr with no whole-file residency. A return shorter than len is treated as end-of-file.

Parameters
[in]ctxOpaque backing context (ra8_rar_t::ctx).
[in]offsetAbsolute byte offset within the archive.
[out]bufDestination buffer (len writable bytes).
[in]lenBytes requested.
Returns
Bytes actually read (0 at/after EOF or on error).
Note
Not thread-safe; the reader serialises access.
Since
Version 0.1.0

Definition at line 88 of file ra8_rar.h.

Enumeration Type Documentation

◆ ra8_rar_limits_t

enum ra8_rar_limits_t : uint16_t

Fixed sizes and grammar constants for the RAR block walk.

Signature lengths, the header scratch window, and the maximum bytes in one variable-length integer – the values the parser is coded against.

Since
Version 0.1.0
Enumerator
k_ra8_rar_sig4_len 

"Rar!\x1A\x07\x00" marker length (RAR4).

k_ra8_rar_sig5_len 

"Rar!\x1A\x07\x01\x00" signature length (RAR5).

k_ra8_rar_hdr_scratch 

Per-block header read window (fixed fields).

k_ra8_rar_vint_max 

Max bytes in one RAR5 vint (64-bit value).

Definition at line 123 of file ra8_rar.h.

◆ ra8_rar_method_t

enum ra8_rar_method_t : uint8_t

Normalised compression method of a file member.

The RAR4 METHOD byte and the RAR5 compression-info method field both collapse to this: either the member is stored verbatim or it is packed with one of RAR's compressors (which this reader does not decode).

Since
Version 0.1.0
Enumerator
k_ra8_rar_method_store 

Uncompressed: data area is the file bytes.

k_ra8_rar_method_compressed 

Packed with a RAR compressor (not decoded).

Definition at line 111 of file ra8_rar.h.

◆ ra8_rar_version_t

enum ra8_rar_version_t : uint8_t

Which RAR container generation an archive uses.

Set by ra8_rar_open from the file signature; selects the block-header grammar ra8_rar_next applies.

Since
Version 0.1.0
Enumerator
k_ra8_rar_ver_none 

Not a recognised RAR archive.

k_ra8_rar_ver_4 

RAR 1.5-4.x block format ("RAR4").

k_ra8_rar_ver_5 

RAR 5.0 block format ("RAR5").

Definition at line 97 of file ra8_rar.h.

Function Documentation

◆ ra8_rar_extract()

ra8_err_t ra8_rar_extract ( const ra8_rar_t * rar,
const ra8_rar_entry_t * ent,
uint8_t * buf,
size_t cap,
ra8_rar5_state_t * st,
size_t * got )
nodiscard

Extract any file member – STORE by copy, RAR5-compressed by decode.

Dispatches on ent's normalised method: a STORE member streams through ra8_rar_extract_stored, while a compressed member of a RAR5 archive is inflated through ra8_rar5_decompress using the caller-owned st pool. A compressed member of a RAR4 archive (the legacy codec) is reported unsupported. This is the single entry the CBR facade uses so both page shapes decode behind one call (SOLID Liskov: STORE and compressed pages are interchangeable to the caller).

Parameters
[in]rarArchive bound by ra8_rar_open (non-NULL).
[in]entA file member from ra8_rar_next (non-NULL, is_file == 1).
[out]bufDestination for the member's decoded bytes (non-NULL).
[in]capCapacity of buf in bytes; must be >= ent->unp_size.
[in,out]stRAR5 decoder scratch, required only for a compressed member.
[out]gotReceives the number of bytes written (non-NULL).
Returns
ra8_err_t Error code.
Return values
k_ra8_okMember decoded; *got == ent->unp_size.
k_ra8_err_null_ptrA required pointer argument was NULL (incl. st for a compressed member).
k_ra8_err_invalid_staterar was never bound by ra8_rar_open.
k_ra8_err_not_supportedA directory, a non-file, or a RAR4-compressed member.
k_ra8_err_no_memcap is smaller than ent->unp_size.
k_ra8_err_invalid_sizeA STORE member overruns the archive / short read.
k_ra8_err_validation_failedA malformed / truncated compressed stream.
Precondition
rar was populated by ra8_rar_open.
ent came from ra8_rar_next on the same rar.
Postcondition
On k_ra8_ok, buf[0..*got) holds the member's original bytes.
On any error buf contents are unspecified and *got == 0.
Note
Not thread-safe.
See also
ra8_rar5_decompress()
Since
Version 0.1.0

Definition at line 840 of file ra8_rar.c.

References ra8_rar_entry_t::data_off, internal_rar_extract_reject_null(), ra8_rar_entry_t::is_dir, ra8_rar_entry_t::is_file, k_ra8_err_invalid_state, k_ra8_err_not_supported, k_ra8_ok, k_ra8_rar_method_store, k_ra8_rar_ver_5, k_ra8_rar_ver_none, ra8_rar_entry_t::method, ra8_rar_entry_t::pack_size, RA8_CHECK_NULL_PTR, ra8_rar5_decompress(), ra8_rar_extract_stored(), s_tag_rar, ra8_rar_entry_t::unp_size, and ra8_rar_t::version.

Referenced by priv_comic_cbr_extract().

◆ ra8_rar_extract_stored()

ra8_err_t ra8_rar_extract_stored ( const ra8_rar_t * rar,
const ra8_rar_entry_t * ent,
uint8_t * buf,
size_t cap,
size_t * got )
nodiscard

Extract a STORE-method member's data into the caller buffer.

Streams ent->unp_size literal bytes from the member's data area ([ent->data_off, ent->data_off + ent->pack_size)) through the archive reader into buf. Only STORE members are supported: a member with ent->method != k_ra8_rar_method_store returns k_ra8_err_not_supported (the RAR compressor is not implemented).

Parameters
[in]rarArchive bound by ra8_rar_open (non-NULL).
[in]entA file member from ra8_rar_next (non-NULL, is_file == 1).
[out]bufDestination for the member's bytes (non-NULL).
[in]capCapacity of buf in bytes; must be >= ent->unp_size.
[out]gotReceives the number of bytes written (non-NULL).
Returns
ra8_err_t Error code.
Return values
k_ra8_okMember copied; *got == ent->unp_size.
k_ra8_err_null_ptrA required pointer argument was NULL.
k_ra8_err_invalid_staterar was never bound by ra8_rar_open.
k_ra8_err_not_supportedent is a directory or a compressed member.
k_ra8_err_no_memcap is smaller than ent->unp_size.
k_ra8_err_invalid_sizeThe member overruns the archive, or the reader returned a short read.
Precondition
rar was populated by ra8_rar_open.
ent came from ra8_rar_next on the same rar.
Postcondition
On k_ra8_ok, buf[0..*got) holds the member's literal bytes.
On any error buf contents are unspecified and *got == 0.
Note
Not thread-safe.
See also
ra8_rar_next()
Since
Version 0.1.0

Definition at line 785 of file ra8_rar.c.

References ra8_rar_entry_t::data_off, internal_rar_check_stored(), internal_rar_read_exact(), k_ra8_err_invalid_size, k_ra8_ok, RA8_CHECK_NULL_PTR, s_tag_rar, and ra8_rar_entry_t::unp_size.

Referenced by ra8_rar_extract().

◆ ra8_rar_next()

ra8_err_t ra8_rar_next ( const ra8_rar_t * rar,
uint64_t off,
char * name_buf,
uint16_t name_cap,
ra8_rar_entry_t * out )
nodiscard

Decode the block header at off and advance to the next block.

Reads one block header through the archive's reader, decodes it under the archive's generation grammar, and fills out – including out->next_off, the absolute offset of the following block. For a file member the member name is copied into name_buf (up to name_cap bytes; longer names are clamped, out->name_len is the copied length). Non-file blocks (archive header, service, end) set out->is_file == 0 and still yield a valid next_off so the walk continues.

Parameters
[in]rarArchive bound by ra8_rar_open (non-NULL).
[in]offAbsolute offset of the block header (< rar->size).
[out]name_bufBuffer for the member name (non-NULL if name_cap > 0).
[in]name_capCapacity of name_buf in bytes.
[out]outDecoded block descriptor (non-NULL).
Returns
ra8_err_t Error code.
Return values
k_ra8_okBlock decoded; out (and name_buf) filled.
k_ra8_err_null_ptrrar or out was NULL.
k_ra8_err_invalid_staterar was never bound by ra8_rar_open.
k_ra8_err_invalid_argoff is at or past rar->size.
k_ra8_err_validation_failedA truncated / malformed / non-advancing block.
Precondition
rar was populated by ra8_rar_open.
off is the start of a block header.
Postcondition
On k_ra8_ok, out->next_off > off (the walk strictly advances).
On any error out is left zeroed.
Note
Not thread-safe.
See also
ra8_rar_extract_stored()
Since
Version 0.1.0

Definition at line 682 of file ra8_rar.c.

References internal_rar4_block(), internal_rar5_block(), k_ra8_err_invalid_arg, k_ra8_err_invalid_state, k_ra8_rar_ver_5, k_ra8_rar_ver_none, RA8_CHECK_NULL_PTR, s_tag_rar, ra8_rar_t::size, and ra8_rar_t::version.

Referenced by priv_comic_cbr_open().

◆ ra8_rar_open()

ra8_err_t ra8_rar_open ( ra8_rar_t * rar,
ra8_rar_read_fn read,
void * ctx,
uint64_t size )
nodiscard

Detect a RAR archive's generation and locate its first block.

Reads the leading signature bytes through read, matches the RAR4 marker or the RAR5 signature, and records the offset just past it in rar->first_off. Performs no other I/O; the walk proceeds through ra8_rar_next.

Parameters
[out]rarReader to populate (caller-owned).
[in]readByte reader over the container file (non-NULL).
[in]ctxContext passed to read.
[in]sizeContainer file length in bytes (> 0).
Returns
ra8_err_t Error code.
Return values
k_ra8_okRecognised RAR archive; rar bound.
k_ra8_err_null_ptrrar or read was NULL.
k_ra8_err_invalid_sizesize is 0 or shorter than a signature.
k_ra8_err_not_supportedThe bytes are not a RAR4 or RAR5 signature.
Precondition
read serves offsets [0, size) of the container file.
rar is a writable ra8_rar_t.
Postcondition
On k_ra8_ok, rar->version is 4 or 5 and rar->first_off <= size.
On any error rar is left with version == k_ra8_rar_ver_none.
Note
Not thread-safe.
See also
ra8_rar_next()
Since
Version 0.1.0

Definition at line 659 of file ra8_rar.c.

References ra8_rar_t::ctx, internal_rar_match_signature(), k_ra8_err_invalid_size, k_ra8_err_not_supported, k_ra8_ok, k_ra8_rar_sig4_len, k_ra8_rar_sig5_len, k_ra8_rar_ver_none, RA8_CHECK_NULL_PTR, ra8_rar_t::read, s_tag_rar, ra8_rar_t::size, and ra8_rar_t::version.

Referenced by internal_open_detect().