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

Implementation of the clean-room RAR4/RAR5 archive walker (ra8_rar.h). More...

#include "ra8_rar.h"
#include <string.h>
#include "ra8_attributes.h"
#include "ra8_check.h"
#include "ra8_rar5.h"
Include dependency graph for ra8_rar.c:

Go to the source code of this file.

Enumerations

enum  rar_vint_bits_t : uint8_t {
  k_rar_vint_data = 0x7FU ,
  k_rar_vint_cont = 0x80U ,
  k_rar_vint_bits = 7U
}
 Bit layout of one RAR5 variable-length integer byte. More...
enum  rar4_layout_t : uint16_t {
  k_rar4_off_type = 2U ,
  k_rar4_off_flags = 3U ,
  k_rar4_off_size = 5U ,
  k_rar4_off_add = 7U ,
  k_rar4_base_len = 7U ,
  k_rar4_off_unp = 11U ,
  k_rar4_off_method = 25U ,
  k_rar4_off_namesz = 26U ,
  k_rar4_off_attr = 28U ,
  k_rar4_off_name = 32U ,
  k_rar4_off_name_large = 40U
}
 RAR4 block/file-header field byte offsets (from the block start). More...
enum  rar4_bits_t : uint16_t {
  k_rar4_flag_long = 0x8000U ,
  k_rar4_flag_large = 0x0100U ,
  k_rar4_flag_dirmsk = 0x00E0U ,
  k_rar4_type_file = 0x0074U ,
  k_rar4_method_stor = 0x0030U
}
 RAR4 header flag bits, block type, and method sentinel. More...
enum  rar5_bits_t : uint8_t {
  k_rar5_type_file = 2U ,
  k_rar5_hflag_extra = 0x01U ,
  k_rar5_hflag_data = 0x02U ,
  k_rar5_fflag_dir = 0x01U ,
  k_rar5_fflag_mtime = 0x02U ,
  k_rar5_fflag_crc = 0x04U ,
  k_rar5_method_shift = 7U ,
  k_rar5_method_mask = 0x07U ,
  k_rar5_fixed_field = 4U
}
 RAR5 header/file flag bits, method field placement, and type. More...
enum  rar_word_t : uint8_t {
  k_rar_w16 = 2U ,
  k_rar_w32 = 4U ,
  k_rar_hi_sh = 32U
}
 Byte widths and the 32-bit high-dword shift used by the decoders. More...

Functions

static void internal_copy_object (void *dst, const void *src, size_t len)
 Copy an object representation through compatible byte-pointer types.
static bool internal_bytes_equal (const void *lhs, const void *rhs, size_t len)
 Compare byte representations through compatible pointer types.
static uint16_t internal_le16 (const uint8_t *p)
 Decode a little-endian uint16 from two unaligned bytes.
static uint32_t internal_le32 (const uint8_t *p)
 Decode a little-endian uint32 from four unaligned bytes.
static bool internal_vint (const uint8_t *buf, size_t len, size_t *pos, uint64_t *val)
 Decode one RAR5 vint, advancing pos past its bytes.
static uint16_t internal_copy_name (const ra8_rar_t *rar, uint64_t name_abs, const uint8_t *scratch, size_t n, size_t in_pos, uint64_t name_len, char *name_buf, uint16_t name_cap)
 Copy a member name into the caller buffer, from scratch or a direct read.
static bool internal_rar4_file (const ra8_rar_t *rar, uint64_t off, const uint8_t *scratch, size_t n, uint16_t flags, uint16_t hsize, char *nbuf, uint16_t ncap, ra8_rar_entry_t *out)
 Decode the RAR4 file-specific fields and fill out.
static ra8_err_t internal_rar4_block (const ra8_rar_t *rar, uint64_t off, char *nbuf, uint16_t ncap, ra8_rar_entry_t *out)
 Walk one RAR4 block at off.
static bool internal_rar5_file_vints (const uint8_t *scratch, size_t n, size_t *pos, uint64_t *fflags, uint64_t *unp, uint64_t *cinfo, uint64_t *namesz)
 Decode the RAR5 file-header vint stream, advancing pos past it.
static bool internal_rar5_file (const ra8_rar_t *rar, uint64_t off, const uint8_t *scratch, size_t n, size_t pos, uint64_t data_off, uint64_t dsize, char *nbuf, uint16_t ncap, ra8_rar_entry_t *out)
 Decode the RAR5 file-specific fields after the common header vints.
static ra8_err_t internal_rar5_block (const ra8_rar_t *rar, uint64_t off, char *nbuf, uint16_t ncap, ra8_rar_entry_t *out)
 Walk one RAR5 block at off.
static void internal_rar_match_signature (const uint8_t *hdr, size_t got, ra8_rar_t *rar)
 Identify the RAR generation from the leading signature bytes.
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.
static ra8_err_t internal_rar_check_stored (const ra8_rar_t *rar, const ra8_rar_entry_t *ent, size_t cap)
 Validate that ent is an extractable STORE member fitting cap.
static bool internal_rar_read_exact (const ra8_rar_t *rar, uint64_t data_off, uint64_t need, uint8_t *buf)
 Stream exactly need bytes of a STORE member into buf.
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.
static ra8_err_t internal_rar_extract_reject_null (const ra8_rar_t *rar, const ra8_rar_entry_t *ent, const uint8_t *buf, const size_t *got)
 Null-check the required arguments of 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)
 Extract any file member – STORE by copy, RAR5-compressed by decode.

Variables

static const char *const s_tag_rar = "ra8_rar"
 Log tag for RAR-walker diagnostics.

Detailed Description

Implementation of the clean-room RAR4/RAR5 archive walker (ra8_rar.h).

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

Two block grammars behind one iterator. ra8_rar_open matches the signature and records the first block offset; ra8_rar_next reads one block header into a fixed stack scratch and decodes it under either the RAR4 fixed-field layout or the RAR5 variable-length-integer (vint) layout, always producing the offset of the next block so the caller walks the archive with a bounded loop. ra8_rar_extract_stored streams a STORE member's literal bytes out.

The RAR5 vint is little-endian base-128: seven data bits per byte, high bit set means "continue". A file member's data area begins immediately after its whole header (RAR5: off + <crc+headersize-vint bytes> + headersize; RAR4: off + head_size), which is how a STORE member's bytes are located without a decompressor.

Every parser guards each read against the bytes actually available, so a truncated block is rejected (k_ra8_err_validation_failed) rather than over-read.

Since
Version 0.1.0

Definition in file ra8_rar.c.

Enumeration Type Documentation

◆ rar4_bits_t

enum rar4_bits_t : uint16_t

RAR4 header flag bits, block type, and method sentinel.

Flags select optional fields; the directory test is a masked equality.

Since
Version 0.1.0
Enumerator
k_rar4_flag_long 

ADD_SIZE present after the base header.

k_rar4_flag_large 

64-bit HIGH_PACK/HIGH_UNP sizes present.

k_rar4_flag_dirmsk 

(flags & this) == this -> directory.

k_rar4_type_file 

File-header block type ('t').

k_rar4_method_stor 

METHOD value for STORE ('0').

Definition at line 120 of file ra8_rar.c.

◆ rar4_layout_t

enum rar4_layout_t : uint16_t

RAR4 block/file-header field byte offsets (from the block start).

The classic RAR4 header is fixed-layout; each member names the offset of a field the parser reads with a little-endian decode.

Since
Version 0.1.0
Enumerator
k_rar4_off_type 

HEAD_TYPE byte.

k_rar4_off_flags 

HEAD_FLAGS uint16.

k_rar4_off_size 

HEAD_SIZE uint16.

k_rar4_off_add 

ADD_SIZE / PACK_SIZE uint32.

k_rar4_base_len 

Base header length before ADD_SIZE.

k_rar4_off_unp 

UNP_SIZE uint32.

k_rar4_off_method 

METHOD byte (0x30 = store).

k_rar4_off_namesz 

NAME_SIZE uint16.

k_rar4_off_attr 

ATTR uint32 (fixed fields end +4).

k_rar4_off_name 

FILE_NAME start (no LARGE flag).

k_rar4_off_name_large 

FILE_NAME start (LARGE 64-bit).

Definition at line 100 of file ra8_rar.c.

◆ rar5_bits_t

enum rar5_bits_t : uint8_t

RAR5 header/file flag bits, method field placement, and type.

Header flags gate the extra/data-size vints; file flags gate the fixed mtime/CRC fields; the method occupies bits 7-9 of comp-info.

Since
Version 0.1.0
Enumerator
k_rar5_type_file 

File-header block type.

k_rar5_hflag_extra 

Extra-area-size vint present.

k_rar5_hflag_data 

Data-size vint present.

k_rar5_fflag_dir 

Member is a directory.

k_rar5_fflag_mtime 

4-byte mtime field present.

k_rar5_fflag_crc 

4-byte data-CRC field present.

k_rar5_method_shift 

Method occupies comp-info bits 7..9.

k_rar5_method_mask 

3-bit method mask after the shift.

k_rar5_fixed_field 

Fixed mtime / CRC field width, bytes.

Definition at line 135 of file ra8_rar.c.

◆ rar_vint_bits_t

enum rar_vint_bits_t : uint8_t

Bit layout of one RAR5 variable-length integer byte.

Low 7 bits carry data; the high bit is the continuation flag.

Since
Version 0.1.0
Enumerator
k_rar_vint_data 

Data bits mask within one vint byte.

k_rar_vint_cont 

Continuation flag within one vint byte.

k_rar_vint_bits 

Data bits contributed per vint byte.

Definition at line 87 of file ra8_rar.c.

◆ rar_word_t

enum rar_word_t : uint8_t

Byte widths and the 32-bit high-dword shift used by the decoders.

Since
Version 0.1.0
Enumerator
k_rar_w16 

uint16 width.

k_rar_w32 

uint32 width.

k_rar_hi_sh 

High-dword shift for 64-bit sizes.

Definition at line 152 of file ra8_rar.c.

Function Documentation

◆ internal_bytes_equal()

bool internal_bytes_equal ( const void * lhs,
const void * rhs,
size_t len )
static

Compare byte representations through compatible pointer types.

Performs an exact bytewise equality check over two bounded spans.

Parameters
[in]lhsFirst span of len readable bytes.
[in]rhsSecond span of len readable bytes.
[in]lenNumber of bytes to compare.
Returns
Whether every corresponding byte is equal.
Return values
trueThe byte spans are identical.
falseAt least one byte differs.
Precondition
lhs is readable for len bytes.
rhs is readable for len bytes.
Postcondition
Neither input span is modified.
The result depends only on the supplied bytes and length.
Note
Pure and thread-safe for immutable input spans.
Since
Version 0.1.0

Definition at line 76 of file ra8_rar.c.

References memcmp(), and RA8_INTERNAL.

Referenced by internal_rar_match_signature().

◆ internal_copy_name()

uint16_t internal_copy_name ( const ra8_rar_t * rar,
uint64_t name_abs,
const uint8_t * scratch,
size_t n,
size_t in_pos,
uint64_t name_len,
char * name_buf,
uint16_t name_cap )
static

Copy a member name into the caller buffer, from scratch or a direct read.

Uses the already-read header scratch when the name lies within it, otherwise issues one targeted read of the name bytes. The copy is clamped to name_cap; the returned length is what was copied.

Parameters
[in]rarBound archive (for the fallback read).
[in]name_absAbsolute offset of the name in the archive.
[in]scratchHeader scratch bytes.
[in]nValid bytes in scratch.
[in]in_posName offset within scratch.
[in]name_lenDeclared name length in bytes.
[out]name_bufDestination (may be NULL if name_cap is 0).
[in]name_capDestination capacity in bytes.
Returns
Bytes actually copied (<= name_cap).
Return values
0name_buf is NULL, name_cap is 0, or a fallback read returned 0.
Precondition
scratch holds n readable bytes.
name_buf holds name_cap writable bytes (when name_cap > 0).
Postcondition
At most name_cap bytes are written to name_buf.
No archive state is modified.
Note
Not thread-safe (may call the archive reader).
Since
Version 0.1.0

Definition at line 279 of file ra8_rar.c.

References ra8_rar_t::ctx, memcpy(), and ra8_rar_t::read.

Referenced by internal_rar4_file(), and internal_rar5_file().

◆ internal_copy_object()

void internal_copy_object ( void * dst,
const void * src,
size_t len )
static

Copy an object representation through compatible byte-pointer types.

Centralizes the parser's permitted bytewise object copy.

Parameters
[out]dstDestination spanning at least len writable bytes.
[in]srcSource spanning at least len readable bytes.
[in]lenNumber of bytes to copy.
Precondition
dst is writable for len bytes.
src is readable for len bytes and does not overlap dst.
Postcondition
The first len destination bytes equal the source bytes on entry.
No bytes outside the destination span are modified.
Note
Thread-safe when callers provide disjoint storage.
Since
Version 0.1.0

Definition at line 55 of file ra8_rar.c.

References memcpy(), and RA8_INTERNAL.

Referenced by internal_le16(), internal_le32(), and internal_vint().

◆ internal_le16()

uint16_t internal_le16 ( const uint8_t * p)
static

Decode a little-endian uint16 from two unaligned bytes.

memcpy-based so the source may sit at any alignment; the whole firmware is little-endian, so the bytes map straight to the value.

Parameters
[in]pPointer to the two bytes (non-NULL, caller-bounded).
Returns
The decoded value.
Return values
0When both bytes are zero.
Precondition
p addresses at least two readable bytes.
The host is little-endian (target and test host both are).
Postcondition
No state is modified (pure read).
The result is a pure function of the two bytes.
Note
Thread-safe: pure read.
Since
Version 0.1.0

Definition at line 173 of file ra8_rar.c.

References internal_copy_object().

Referenced by internal_rar4_block(), and internal_rar4_file().

◆ internal_le32()

uint32_t internal_le32 ( const uint8_t * p)
static

Decode a little-endian uint32 from four unaligned bytes.

memcpy-based so the source may sit at any alignment; the whole firmware is little-endian, so the bytes map straight to the value.

Parameters
[in]pPointer to the four bytes (non-NULL, caller-bounded).
Returns
The decoded value.
Return values
0When all four bytes are zero.
Precondition
p addresses at least four readable bytes.
The host is little-endian (target and test host both are).
Postcondition
No state is modified (pure read).
The result is a pure function of the four bytes.
Note
Thread-safe: pure read.
Since
Version 0.1.0

Definition at line 195 of file ra8_rar.c.

References internal_copy_object().

Referenced by internal_rar4_block(), and internal_rar4_file().

◆ internal_rar4_block()

ra8_err_t internal_rar4_block ( const ra8_rar_t * rar,
uint64_t off,
char * nbuf,
uint16_t ncap,
ra8_rar_entry_t * out )
static

Walk one RAR4 block at off.

Reads the fixed 7-byte base header (plus ADD_SIZE when the LONG flag is set), then dispatches file blocks to internal_rar4_file and treats every other block type as a skip (data-less unless LONG). Guarantees a strictly advancing next_off.

Parameters
[in]rarBound archive.
[in]offBlock offset (< rar->size).
[out]nbufName buffer.
[in]ncapName buffer capacity.
[out]outEntry to fill.
Returns
ra8_err_t status.
Return values
k_ra8_okBlock decoded.
k_ra8_err_validation_failedTruncated / non-advancing block.
Precondition
rar is bound; off < rar->size.
out is writable.
Postcondition
On k_ra8_ok, out->next_off > off.
On error out is left as the caller zeroed it.
Note
Not thread-safe.
Since
Version 0.1.0

Definition at line 390 of file ra8_rar.c.

References ra8_rar_t::ctx, internal_le16(), internal_le32(), internal_rar4_file(), k_ra8_err_validation_failed, k_ra8_ok, k_ra8_rar_hdr_scratch, k_rar4_base_len, k_rar4_flag_long, k_rar4_off_add, k_rar4_off_flags, k_rar4_off_size, k_rar4_off_type, k_rar4_type_file, k_rar_w32, ra8_rar_entry_t::next_off, and ra8_rar_t::read.

Referenced by ra8_rar_next().

◆ internal_rar4_file()

bool internal_rar4_file ( const ra8_rar_t * rar,
uint64_t off,
const uint8_t * scratch,
size_t n,
uint16_t flags,
uint16_t hsize,
char * nbuf,
uint16_t ncap,
ra8_rar_entry_t * out )
static

Decode the RAR4 file-specific fields and fill out.

Reads PACK/UNP sizes (with the optional 64-bit high dwords), the method, and the name; computes the data-area and next-block offsets from head_size. Non-fatal on a short scratch: returns false so the caller reports a malformed block.

Parameters
[in]rarBound archive.
[in]offBlock offset.
[in]scratchHeader scratch bytes.
[in]nValid bytes in scratch.
[in]flagsHEAD_FLAGS of this block.
[in]hsizeHEAD_SIZE of this block.
[out]nbufName buffer.
[in]ncapName buffer capacity.
[out]outEntry to fill (file fields, data_off, next_off).
Returns
Whether the file fields fit n and were decoded.
Return values
trueFields decoded; out is a valid file entry.
falseTruncated fixed fields.
Precondition
scratch holds n bytes; hsize is this block's header size.
out is writable.
Postcondition
On true, out->next_off = off + hsize + pack_size and is_file == 1.
On false out is not relied upon by the caller.
Note
Not thread-safe.
Since
Version 0.1.0

Definition at line 329 of file ra8_rar.c.

References ra8_rar_entry_t::data_off, internal_copy_name(), internal_le16(), internal_le32(), ra8_rar_entry_t::is_dir, ra8_rar_entry_t::is_file, k_ra8_rar_method_compressed, k_ra8_rar_method_store, k_rar4_flag_dirmsk, k_rar4_flag_large, k_rar4_method_stor, k_rar4_off_add, k_rar4_off_method, k_rar4_off_name, k_rar4_off_name_large, k_rar4_off_namesz, k_rar4_off_unp, k_rar_hi_sh, k_rar_w32, ra8_rar_entry_t::method, ra8_rar_entry_t::name_len, ra8_rar_entry_t::next_off, ra8_rar_entry_t::pack_size, and ra8_rar_entry_t::unp_size.

Referenced by internal_rar4_block().

◆ internal_rar5_block()

ra8_err_t internal_rar5_block ( const ra8_rar_t * rar,
uint64_t off,
char * nbuf,
uint16_t ncap,
ra8_rar_entry_t * out )
static

Walk one RAR5 block at off.

Decodes CRC + header-size vint (which fixes the data-area and next-block offsets), then the header type/flags and the optional extra-area-size / data-size vints; file blocks go to internal_rar5_file, all others are skipped with a valid next_off.

Parameters
[in]rarBound archive.
[in]offBlock offset (< rar->size).
[out]nbufName buffer.
[in]ncapName buffer capacity.
[out]outEntry to fill.
Returns
ra8_err_t status.
Return values
k_ra8_okBlock decoded.
k_ra8_err_validation_failedTruncated / non-advancing block.
Precondition
rar is bound; off < rar->size.
out is writable.
Postcondition
On k_ra8_ok, out->next_off > off.
On error out is left as the caller zeroed it.
Note
Not thread-safe.
Since
Version 0.1.0

Definition at line 572 of file ra8_rar.c.

References ra8_rar_t::ctx, internal_rar5_file(), internal_vint(), k_ra8_err_validation_failed, k_ra8_ok, k_ra8_rar_hdr_scratch, k_rar5_hflag_data, k_rar5_hflag_extra, k_rar5_type_file, k_rar_w32, ra8_rar_entry_t::next_off, and ra8_rar_t::read.

Referenced by ra8_rar_next().

◆ internal_rar5_file()

bool internal_rar5_file ( const ra8_rar_t * rar,
uint64_t off,
const uint8_t * scratch,
size_t n,
size_t pos,
uint64_t data_off,
uint64_t dsize,
char * nbuf,
uint16_t ncap,
ra8_rar_entry_t * out )
static

Decode the RAR5 file-specific fields after the common header vints.

From pos (just past header type/flags/extra/data-size), reads the file flags, unpacked size, attributes, optional fixed time/CRC, the compression-info method, host OS, and name; fills the file fields of out. data_off / dsize / next_off were computed by the caller from the header-size vint.

Parameters
[in]rarBound archive.
[in]offBlock offset.
[in]scratchHeader scratch bytes.
[in]nValid bytes in scratch.
[in]posCursor at the first file field.
[in]data_offAbsolute data-area offset for this block.
[in]dsizeData-area length (packed size).
[out]nbufName buffer.
[in]ncapName buffer capacity.
[out]outEntry to fill.
Returns
Whether the fields decoded within n.
Return values
trueFields decoded; out is a valid file entry.
falseTruncated fields.
Precondition
scratch holds n bytes; pos <= n.
out already has next_off set by the caller.
Postcondition
On true, out->is_file == 1 and file fields are populated.
On false out is not relied upon by the caller.
Note
Not thread-safe.
Since
Version 0.1.0

Definition at line 519 of file ra8_rar.c.

References ra8_rar_entry_t::data_off, internal_copy_name(), internal_rar5_file_vints(), ra8_rar_entry_t::is_dir, ra8_rar_entry_t::is_file, k_ra8_rar_method_compressed, k_ra8_rar_method_store, k_rar5_fflag_dir, k_rar5_method_mask, k_rar5_method_shift, ra8_rar_entry_t::method, ra8_rar_entry_t::name_len, ra8_rar_entry_t::pack_size, and ra8_rar_entry_t::unp_size.

Referenced by internal_rar5_block().

◆ internal_rar5_file_vints()

bool internal_rar5_file_vints ( const uint8_t * scratch,
size_t n,
size_t * pos,
uint64_t * fflags,
uint64_t * unp,
uint64_t * cinfo,
uint64_t * namesz )
static

Decode the RAR5 file-header vint stream, advancing pos past it.

Reads the file flags, unpacked size, and attributes; skips the optional fixed mtime / data-CRC fields the file flags gate; then reads the compression-info, host-OS, and name-size vints. The attributes and host-OS vints are decoded only to advance pos and are then discarded. A truncated stream (any vint running off n) fails without over-read.

Parameters
[in]scratchHeader scratch bytes.
[in]nValid bytes in scratch.
[in,out]posCursor into scratch; advanced to the name bytes.
[out]fflagsReceives the file flags.
[out]unpReceives the unpacked size.
[out]cinfoReceives the compression-info word (carries the method).
[out]nameszReceives the declared name length in bytes.
Returns
Whether every field decoded within n.
Return values
trueAll vints decoded; *pos points at the name bytes.
falseA vint ran off n (truncated header).
Precondition
scratch holds n readable bytes; *pos <= n on entry.
fflags, unp, cinfo, and namesz are writable.
Postcondition
On true, *pos addresses the name and the four outputs are set.
On false the outputs are indeterminate and must not be used.
Note
Not thread-safe; reads only its arguments.
Since
Version 0.1.0

Definition at line 452 of file ra8_rar.c.

References internal_vint(), k_rar5_fflag_crc, k_rar5_fflag_mtime, and k_rar5_fixed_field.

Referenced by internal_rar5_file().

◆ internal_rar_check_stored()

ra8_err_t internal_rar_check_stored ( const ra8_rar_t * rar,
const ra8_rar_entry_t * ent,
size_t cap )
static

Validate that ent is an extractable STORE member fitting cap.

Rejects, in order: an unbound archive, a non-file or directory entry, a compressed (non-STORE) member, a member larger than cap, and a member whose data area overruns the archive. Mirrors the guard order ra8_rar_extract_stored needs before it streams the member bytes.

Parameters
[in]rarBound archive (its version / size gate the checks).
[in]entCandidate entry from ra8_rar_next.
[in]capDestination-buffer capacity in bytes.
Returns
ra8_err_t status.
Return values
k_ra8_okThe entry is a STORE member that fits cap.
k_ra8_err_invalid_stateThe archive was never opened.
k_ra8_err_not_supportedA non-file, directory, or compressed member.
k_ra8_err_no_memThe member is larger than cap.
k_ra8_err_invalid_sizeThe member data area overruns the archive.
Precondition
rar was bound by ra8_rar_open.
ent came from ra8_rar_next on rar.
Postcondition
No state is modified (pure validation).
On k_ra8_ok, ent->data_off + ent->unp_size <= rar->size.
Note
Not thread-safe; pure read of its arguments.
Since
Version 0.1.0

Definition at line 727 of file ra8_rar.c.

References ra8_rar_entry_t::data_off, ra8_rar_entry_t::is_dir, ra8_rar_entry_t::is_file, k_ra8_err_invalid_size, k_ra8_err_invalid_state, k_ra8_err_no_mem, k_ra8_err_not_supported, k_ra8_ok, k_ra8_rar_method_store, k_ra8_rar_ver_none, ra8_rar_entry_t::method, ra8_rar_t::size, ra8_rar_entry_t::unp_size, and ra8_rar_t::version.

Referenced by ra8_rar_extract_stored().

◆ internal_rar_extract_reject_null()

ra8_err_t internal_rar_extract_reject_null ( const ra8_rar_t * rar,
const ra8_rar_entry_t * ent,
const uint8_t * buf,
const size_t * got )
static

Null-check the required arguments of ra8_rar_extract.

Runs the mandatory guards on the archive, entry, buffer, and count pointers; the optional decoder scratch is checked later only on the compressed path. Split out so the entry point stays within the function-size budget.

Parameters
[in]rarArchive pointer.
[in]entEntry pointer.
[in]bufOutput buffer pointer.
[in]gotByte-count output pointer.
Returns
ra8_err_t status.
Return values
k_ra8_okEvery required pointer is non-NULL.
k_ra8_err_null_ptrSome required pointer was NULL.
Precondition
The caller forwards its pointer arguments unchanged.
No argument is dereferenced before this returns k_ra8_ok.
Postcondition
On k_ra8_ok each checked pointer is safe to dereference.
No state is modified.
Note
Thread-safe: reads only its pointer arguments.
Since
Version 0.1.0

Definition at line 828 of file ra8_rar.c.

References k_ra8_ok, RA8_CHECK_NULL_PTR, and s_tag_rar.

Referenced by ra8_rar_extract().

◆ internal_rar_match_signature()

void internal_rar_match_signature ( const uint8_t * hdr,
size_t got,
ra8_rar_t * rar )
static

Identify the RAR generation from the leading signature bytes.

Tests the RAR5 8-byte signature first, then the RAR4 7-byte marker. RAR4 marker "Rar!\x1A\x07\x00" and RAR5 signature "Rar!\x1A\x07\x01\x00" share their first six bytes and diverge at byte 6, so each needs its own constant (a RAR4 match against the RAR5 bytes would fail at that byte). The signatures are written as string literals – the escapes carry the control bytes and the implicit terminating NUL supplies each marker's final 0x00 – so the reader holds no raw-byte magic constant.

Parameters
[in]hdrLeading header bytes read from the archive.
[in]gotValid bytes in hdr (>= k_ra8_rar_sig4_len).
[in,out]rarArchive whose version / first_off are set on a match.
Returns
Nothing; the outcome is reported through rar.
Precondition
hdr holds got readable bytes; got >= k_ra8_rar_sig4_len.
rar was zeroed (version == k_ra8_rar_ver_none) on entry.
Postcondition
On a match rar->version is RAR4/RAR5 and rar->first_off is its length.
On no match rar is unchanged (version == k_ra8_rar_ver_none).
Note
Not thread-safe; pure byte compare.
Since
Version 0.1.0

Definition at line 640 of file ra8_rar.c.

References ra8_rar_t::first_off, internal_bytes_equal(), k_ra8_rar_sig4_len, k_ra8_rar_sig5_len, k_ra8_rar_ver_4, k_ra8_rar_ver_5, and ra8_rar_t::version.

Referenced by ra8_rar_open().

◆ internal_rar_read_exact()

bool internal_rar_read_exact ( const ra8_rar_t * rar,
uint64_t data_off,
uint64_t need,
uint8_t * buf )
static

Stream exactly need bytes of a STORE member into buf.

Issues repeated backing reads from data_off until need bytes are copied or a read returns 0 (a short archive). Bounded: need is fixed and every pass copies at least one byte or breaks.

Parameters
[in]rarBound archive (its read / ctx perform the I/O).
[in]data_offAbsolute offset of the member data area.
[in]needBytes to copy (the member's unpacked size).
[out]bufDestination (at least need writable bytes).
Returns
Whether all need bytes were copied.
Return values
trueExactly need bytes were read into buf.
falseA backing read returned 0 before need bytes (short archive).
Precondition
rar was bound by ra8_rar_open.
buf holds at least need writable bytes.
Postcondition
On true, buf[0..need) holds the member's bytes.
On false fewer than need bytes were written.
Note
Not thread-safe (drives the archive reader).
Since
Version 0.1.0

Definition at line 771 of file ra8_rar.c.

References ra8_rar_t::ctx, and ra8_rar_t::read.

Referenced by ra8_rar_extract_stored().

◆ internal_vint()

bool internal_vint ( const uint8_t * buf,
size_t len,
size_t * pos,
uint64_t * val )
static

Decode one RAR5 vint, advancing pos past its bytes.

Accumulates 7 data bits per byte, little-endian, stopping at the first byte whose continuation flag is clear. Fails on truncation or a value longer than k_ra8_rar_vint_max bytes. The value is built in two 32-bit halves and assembled by memcpy rather than with a 64-bit variable shift: on Cortex-M a uint64_t << reg lowers to a libgcc __ashldi3 call, so 32-bit shifts keep this leaner (and side-step the emulator's 64-bit shift seam under ra8_emulator).

Parameters
[in]bufHeader scratch bytes.
[in]lenValid bytes in buf.
[in,out]posCursor into buf; advanced past the vint on success.
[out]valReceives the decoded value.
Returns
Whether a complete vint was decoded.
Return values
trueA terminated vint fit within len and the byte budget.
falseTruncated (ran off len) or overlong.
Precondition
pos <= len on entry.
val is writable.
Postcondition
On true, *pos advanced by 1..k_ra8_rar_vint_max and *val set.
On false, *val is left indeterminate and must not be used.
Note
Thread-safe: reads only its arguments.
Since
Version 0.1.0

Definition at line 226 of file ra8_rar.c.

References internal_copy_object(), k_ra8_rar_vint_max, k_rar_hi_sh, k_rar_vint_bits, k_rar_vint_cont, and k_rar_vint_data.

Referenced by internal_rar5_block(), and internal_rar5_file_vints().

◆ 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().

Variable Documentation

◆ s_tag_rar

const char* const s_tag_rar = "ra8_rar"
static

Log tag for RAR-walker diagnostics.

Definition at line 40 of file ra8_rar.c.

Referenced by internal_rar_extract_reject_null(), ra8_rar_extract(), ra8_rar_extract_stored(), ra8_rar_next(), and ra8_rar_open().