|
ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
|
RAR 5.0 LZ decoder driver: token loop, data filters, public entry. More...
#include "ra8_rar5.h"#include <string.h>#include "ra8_attributes.h"#include "ra8_check.h"#include "ra8_rar5_internal.h"Go to the source code of this file.
Functions | |
| static void | internal_copy_object (void *dst, const void *src, size_t len) |
| Copy an object representation through compatible byte-pointer types. | |
| static uint32_t | internal_rd_le32 (const uint8_t *p) |
| Read a little-endian uint32 from four unaligned bytes. | |
| static void | internal_wr_le32 (uint8_t *p, uint32_t v) |
| Write a uint32 as four little-endian bytes. | |
| static uint32_t | internal_slot_to_length (ra8_rar5_state_t *st, uint32_t slot) |
| Convert an LZ length slot into a match length, reading any extra bits. | |
| static uint64_t | internal_decode_distance (ra8_rar5_state_t *st) |
| Decode an LZ match distance from the distance / low-distance tables. | |
| static uint32_t | internal_adjust_length (uint32_t length, uint64_t dist) |
| Add the RAR5 distance-dependent bias to a match length. | |
| static void | internal_push_dist (ra8_rar5_state_t *st, uint64_t dist) |
| Push a fresh match distance onto the recent-distance ring. | |
| bool | priv_rar5_copy_match (uint8_t *out, size_t *out_pos, size_t unp, uint32_t length, uint64_t dist) |
| Implementation of priv_rar5_copy_match() – self-overlapping back-copy. | |
| static uint32_t | internal_read_filter_data (ra8_rar5_state_t *st) |
| Read one length/offset field of a RAR5 filter descriptor. | |
| static ra8_err_t | internal_read_filter (ra8_rar5_state_t *st, size_t out_pos) |
| Read one filter descriptor and queue it for post-decode replay. | |
| void | priv_rar5_filter_delta (ra8_rar5_state_t *st, uint8_t *d, uint32_t len, uint32_t channels) |
| Implementation of priv_rar5_filter_delta() – per-channel running byte-sum. | |
| static bool | internal_x86_is_op (uint8_t op, bool e9) |
Test whether op is an x86 branch opcode this filter transforms. | |
| static void | internal_filter_x86 (uint8_t *d, uint32_t len, uint64_t filepos, bool e9) |
Apply the x86 CALL/JMP relative-address filter over d. | |
| static void | internal_filter_arm (uint8_t *d, uint32_t len, uint64_t filepos) |
Apply the ARM BL branch-offset filter over d. | |
| static void | internal_apply_one_filter (ra8_rar5_state_t *st, uint8_t *out, size_t unp, const ra8_rar5_filter_t *f) |
| Replay one queued filter over its (clamped) output range. | |
| static void | internal_apply_filters (ra8_rar5_state_t *st, uint8_t *out, size_t unp) |
| Replay every queued filter in stream order. | |
| static ra8_err_t | internal_do_match (ra8_rar5_state_t *st, uint32_t slot, uint8_t *out, size_t *out_pos, size_t unp) |
Decode a length-slot LZ match (main symbol >= 262) into out. | |
| static ra8_err_t | internal_do_repdist (ra8_rar5_state_t *st, uint32_t slot, uint8_t *out, size_t *out_pos, size_t unp) |
Decode a remembered-distance LZ match (main symbols 258..261) into out. | |
| static ra8_err_t | internal_do_replast (ra8_rar5_state_t *st, uint8_t *out, size_t *out_pos, size_t unp) |
Replay the last match (main symbol 257) into out. | |
| static ra8_err_t | internal_decode_token (ra8_rar5_state_t *st, uint8_t *out, size_t *out_pos, size_t unp) |
| Decode one LZ token: literal, match, repeat-match, or filter. | |
| static ra8_err_t | internal_open_block (ra8_rar5_state_t *st, uint64_t *end_bit, bool *last) |
| Open the next compressed block: header, tables, and its bit-end. | |
| static ra8_err_t | internal_decode_stream (ra8_rar5_state_t *st, uint8_t *out, size_t out_cap, size_t unp) |
Drive the block + token loops until unp bytes are produced. | |
| static ra8_err_t | internal_decompress_check (const ra8_rar_t *rar, const uint8_t *out, const ra8_rar5_state_t *st, size_t out_cap, uint64_t unp_size, uint64_t pack_size) |
| Validate the non-output arguments of ra8_rar5_decompress. | |
| ra8_err_t | ra8_rar5_decompress (const ra8_rar_t *rar, uint64_t data_off, uint64_t pack_size, uint8_t *out, size_t out_cap, uint64_t unp_size, ra8_rar5_state_t *st, size_t *got) |
| Decompress one RAR5-packed member into the caller's output buffer. | |
Variables | |
| static const char *const | s_tag_rar5 = "ra8_rar5" |
| Log tag for RAR5 decoder diagnostics. | |
RAR 5.0 LZ decoder driver: token loop, data filters, public entry.
The upper half of the clean-room RAR 5.0 unpacker (paired with the entropy front-end in ra8_rar5_tables.c). It drives an LZ77 token loop over the Huffman-decoded symbol stream, writing the reconstructed bytes straight into the caller's output buffer (which is also the sliding window), then replays any recorded data filters (delta / x86 / ARM) over their output ranges.
The front-end (ra8_rar5_tables.c) supplies the four ::ra8_rar5_internal.h primitives this driver calls – priv_rar5_get, priv_rar5_decode_num, priv_rar5_read_block_header, priv_rar5_read_tables – and never calls back.
Definition in file ra8_rar5.c.
|
static |
Add the RAR5 distance-dependent bias to a match length.
Distances above 0x100 / 0x2000 / 0x40000 add 1 / 2 / 3 to the length.
| [in] | length | Base match length. |
| [in] | dist | Match distance. |
| length | When dist <= 0x100. |
length is a decoded base length. dist is a decoded distance. length. Definition at line 186 of file ra8_rar5.c.
References k_r5_dist_th1, k_r5_dist_th2, k_r5_dist_th3, and RA8_INTERNAL.
Referenced by internal_do_match().
|
static |
Replay every queued filter in stream order.
Iterates the recorded filter list front to back, applying each via internal_apply_one_filter; a no-op when no filter was recorded (the comic case).
| [in,out] | st | Decoder state (non-NULL). |
| [in,out] | out | Decoded output buffer (non-NULL). |
| [in] | unp | Total unpacked length. |
out holds unp writable bytes. st::filter_count <= k_ra8_rar5_max_filters. unp is written. Definition at line 475 of file ra8_rar5.c.
References internal_apply_one_filter(), and RA8_INTERNAL.
Referenced by ra8_rar5_decompress().
|
static |
Replay one queued filter over its (clamped) output range.
Clamps the filter's range to the decoded output, then dispatches to the delta / x86 / x86-e8e9 / ARM transform; a range starting past the output end is skipped.
| [in,out] | st | Decoder state (non-NULL). |
| [in,out] | out | Decoded output buffer (non-NULL). |
| [in] | unp | Total unpacked length (range clamp). |
| [in] | f | Filter to apply (non-NULL). |
out holds unp writable bytes. f came from internal_read_filter. Definition at line 435 of file ra8_rar5.c.
References ra8_rar5_filter_t::channels, internal_filter_arm(), internal_filter_x86(), k_ra8_rar5_filter_delta, k_ra8_rar5_filter_e8, k_ra8_rar5_filter_e8e9, ra8_rar5_filter_t::len, priv_rar5_filter_delta(), RA8_INTERNAL, ra8_rar5_filter_t::start, and ra8_rar5_filter_t::type.
Referenced by internal_apply_filters().
|
static |
Copy an object representation through compatible byte-pointer types.
Centralizes the decoder's permitted bytewise object copy.
| [out] | dst | Destination spanning at least len writable bytes. |
| [in] | src | Source spanning at least len readable bytes. |
| [in] | len | Number of bytes to copy. |
dst is writable for len bytes. src is readable for len bytes and does not overlap dst. len destination bytes equal the source bytes on entry. Definition at line 64 of file ra8_rar5.c.
References memcpy(), and RA8_INTERNAL.
Referenced by internal_rd_le32(), and internal_wr_le32().
|
static |
Decode an LZ match distance from the distance / low-distance tables.
Slots 0-3 give a direct distance; higher slots reconstruct the top bits from the slot and the remaining bits from either extra bits or the low-distance table.
| [in,out] | st | Decoder state (non-NULL). |
| 1 | For distance slot 0. |
st is a bound decoder state with the DD/LDD tables built. st scratch tables are usable. Definition at line 154 of file ra8_rar5.c.
References priv_rar5_decode_num(), priv_rar5_get(), and RA8_INTERNAL.
Referenced by internal_do_match().
|
static |
Drive the block + token loops until unp bytes are produced.
Opens the first compressed block, then reads a fresh block header whenever the current block's bits are exhausted, decoding tokens into out until the output is complete, the last block ends, or the packed member (plus a small pad) is fully consumed. Opening the first block before the loop keeps the in-loop block check single-condition – the entry-time !have_block / consumed >= block_end pair was correlated (on the first pass block_end is still zero) and so could never reach MC/DC; hoisting the open removes that correlated compound decision.
| [in,out] | st | Decoder state (non-NULL). |
| [in,out] | out | Output/window buffer (non-NULL). |
| [in] | out_cap | Capacity of out in bytes. |
| [in] | unp | Target unpacked length (<= out_cap, > 0). |
| k_ra8_ok | Exactly unp bytes were produced. |
| k_ra8_err_validation_failed | Truncated / malformed stream, short output. |
out holds out_cap writable bytes, unp <= out_cap. st is a freshly reset decoder state and unp > 0. Definition at line 696 of file ra8_rar5.c.
References internal_decode_token(), internal_open_block(), k_r5_byte_bits, k_r5_max_pad_bits, k_ra8_err_validation_failed, and k_ra8_ok.
Referenced by ra8_rar5_decompress().
|
static |
Decode one LZ token: literal, match, repeat-match, or filter.
Classifies the main symbol: below 256 is a literal byte, 256 a filter, 257 the last-match repeat, 258-261 a remembered-distance match, 262+ a length-slot match.
| [in,out] | st | Decoder state (non-NULL). |
| [in,out] | out | Output/window buffer (non-NULL). |
| [in,out] | out_pos | Current output length; advanced (non-NULL). |
| [in] | unp | Target unpacked length. |
| k_ra8_ok | One token was decoded. |
| k_ra8_err_validation_failed | A malformed match or filter. |
st has the LZ tables built. Definition at line 609 of file ra8_rar5.c.
References internal_do_match(), internal_do_repdist(), internal_do_replast(), internal_read_filter(), k_r5_sym_filter, k_r5_sym_lenbase, k_r5_sym_replast, k_ra8_ok, and priv_rar5_decode_num().
Referenced by internal_decode_stream().
|
static |
Validate the non-output arguments of ra8_rar5_decompress.
Null-checks the archive, output, and scratch pointers, then rejects a non-RAR5 archive, an output buffer smaller than the unpacked size, and a zero packed size. Split out so the entry point stays within the function-size budget.
| [in] | rar | Archive to decode from. |
| [in] | out | Output buffer. |
| [in] | st | Decoder scratch. |
| [in] | out_cap | Output-buffer capacity in bytes. |
| [in] | unp_size | Expected unpacked length. |
| [in] | pack_size | Packed member length. |
| k_ra8_ok | Arguments are usable. |
| k_ra8_err_null_ptr | rar, out, or st was NULL. |
| k_ra8_err_invalid_state | rar is not a RAR5 archive. |
| k_ra8_err_no_mem | out_cap is smaller than unp_size. |
| k_ra8_err_validation_failed | pack_size is zero. |
got was already validated and cleared by the caller. rar fields). Definition at line 754 of file ra8_rar5.c.
References k_ra8_err_invalid_state, k_ra8_err_no_mem, k_ra8_err_validation_failed, k_ra8_ok, k_ra8_rar_ver_5, RA8_CHECK_NULL_PTR, RA8_INTERNAL, s_tag_rar5, and ra8_rar_t::version.
Referenced by ra8_rar5_decompress().
|
static |
Decode a length-slot LZ match (main symbol >= 262) into out.
Reads the length from the slot, the distance from the DD/LDD tables, applies the distance-length bias, remembers the distance, and copies the match into the output window.
| [in,out] | st | Decoder state (non-NULL). |
| [in] | slot | Main symbol (>= k_r5_sym_lenbase). |
| [in,out] | out | Output/window buffer (non-NULL). |
| [in,out] | out_pos | Current output length; advanced (non-NULL). |
| [in] | unp | Target unpacked length. |
| k_ra8_ok | The match was copied. |
| k_ra8_err_validation_failed | An invalid back-distance. |
st has the LZ tables built. Definition at line 506 of file ra8_rar5.c.
References internal_adjust_length(), internal_decode_distance(), internal_push_dist(), internal_slot_to_length(), k_r5_sym_lenbase, k_ra8_err_validation_failed, k_ra8_ok, and priv_rar5_copy_match().
Referenced by internal_decode_token().
|
static |
Decode a remembered-distance LZ match (main symbols 258..261) into out.
Selects one of the four remembered distances, promotes it to most-recent, reads a repeat length from the RD table, and copies the match.
| [in,out] | st | Decoder state (non-NULL). |
| [in] | slot | Main symbol in 258..261. |
| [in,out] | out | Output/window buffer (non-NULL). |
| [in,out] | out_pos | Current output length; advanced (non-NULL). |
| [in] | unp | Target unpacked length. |
| k_ra8_ok | The match was copied. |
| k_ra8_err_validation_failed | An invalid back-distance. |
st has the LZ tables built. Definition at line 540 of file ra8_rar5.c.
References internal_slot_to_length(), k_r5_sym_repdist0, k_ra8_err_validation_failed, k_ra8_ok, priv_rar5_copy_match(), and priv_rar5_decode_num().
Referenced by internal_decode_token().
|
static |
Replay the last match (main symbol 257) into out.
Copies the most-recent match's length at the most-recent distance; a no-op when no match has been seen yet (last length is zero).
| [in,out] | st | Decoder state (non-NULL). |
| [in,out] | out | Output/window buffer (non-NULL). |
| [in,out] | out_pos | Current output length; advanced (non-NULL). |
| [in] | unp | Target unpacked length. |
| k_ra8_ok | The repeat was copied (or was a no-op). |
| k_ra8_err_validation_failed | An invalid back-distance. |
st is a bound decoder state. Definition at line 577 of file ra8_rar5.c.
References k_ra8_err_validation_failed, k_ra8_ok, and priv_rar5_copy_match().
Referenced by internal_decode_token().
|
static |
Apply the ARM BL branch-offset filter over d.
For each 4-byte word whose top byte is the BL opcode, subtracts the word position from the 24-bit branch offset – the inverse of the writer's add.
| [in,out] | d | Output range to transform (non-NULL). |
| [in] | len | Range length in bytes. |
| [in] | filepos | Absolute output offset of d[0]. |
d holds len writable bytes. len >= 4 to transform anything. Definition at line 397 of file ra8_rar5.c.
References k_r5_arm_bl, k_r5_arm_off_mask, k_r5_byte_bits, k_r5_byte_mask, and RA8_INTERNAL.
Referenced by internal_apply_one_filter().
|
static |
Apply the x86 CALL/JMP relative-address filter over d.
For each transformed branch, subtracts the operand's stream position from the stored 32-bit operand – the inverse of the writer's add.
| [in,out] | d | Output range to transform (non-NULL). |
| [in] | len | Range length in bytes. |
| [in] | filepos | Absolute output offset of d[0]. |
| [in] | e9 | Whether 0xE9 JMP is transformed too. |
d holds len writable bytes. len fits an x86 instruction (>= 5) to transform anything. Definition at line 363 of file ra8_rar5.c.
References internal_rd_le32(), internal_wr_le32(), internal_x86_is_op(), k_r5_x86_ilen, and RA8_INTERNAL.
Referenced by internal_apply_one_filter().
|
static |
Open the next compressed block: header, tables, and its bit-end.
Reads and validates the block header, rejects a zero-size block, computes the block's end bit position, and (re)builds the Huffman tables when the block carries them – else requires that a prior block already did.
| [in,out] | st | Decoder state (non-NULL). |
| [out] | end_bit | Receives the block's absolute end bit position (non-NULL). |
| [out] | last | Receives whether this is the last block (non-NULL). |
| k_ra8_ok | Block opened and tables ready. |
| k_ra8_err_validation_failed | A bad header, zero-size block, or no tables. |
st is a bound decoder state. end_bit and last are writable. Definition at line 648 of file ra8_rar5.c.
References k_r5_byte_bits, k_ra8_err_validation_failed, k_ra8_ok, r5_block_t::last, r5_block_t::last_bits, priv_rar5_read_block_header(), priv_rar5_read_tables(), r5_block_t::size, and r5_block_t::tables.
Referenced by internal_decode_stream().
|
static |
Push a fresh match distance onto the recent-distance ring.
Shifts the four remembered distances down by one and stores dist at the front, so a later remembered-distance symbol can reuse it.
| [in,out] | st | Decoder state (non-NULL). |
| [in] | dist | Distance to remember. |
st is a bound decoder state. st::old_dist has k_ra8_rar5_old_dist entries. Definition at line 215 of file ra8_rar5.c.
References k_ra8_rar5_old_dist, and RA8_INTERNAL.
Referenced by internal_do_match().
|
static |
Read a little-endian uint32 from four unaligned bytes.
memcpy-based so the source may sit at any alignment on a little-endian host/target.
| [in] | p | Pointer to four readable bytes (non-NULL). |
| 0 | When all four bytes are zero. |
p addresses at least four readable bytes. Definition at line 85 of file ra8_rar5.c.
References internal_copy_object(), and RA8_INTERNAL.
Referenced by internal_filter_x86().
|
static |
Read one filter descriptor and queue it for post-decode replay.
Records the transform's absolute output start (relative offset plus the current output position), its length, kind, and delta channel count.
| [in,out] | st | Decoder state (non-NULL). |
| [in] | out_pos | Current output position (filter start base). |
| k_ra8_ok | The filter was queued. |
| k_ra8_err_validation_failed | The filter list is full or the kind is invalid. |
st is a bound decoder state. out_pos is the current output length. Definition at line 281 of file ra8_rar5.c.
References ra8_rar5_filter_t::channels, internal_read_filter_data(), k_r5_fchan_bits, k_r5_ftype_bits, k_ra8_err_validation_failed, k_ra8_ok, k_ra8_rar5_filter_arm, k_ra8_rar5_filter_delta, k_ra8_rar5_max_filters, ra8_rar5_filter_t::len, priv_rar5_get(), RA8_INTERNAL, ra8_rar5_filter_t::start, and ra8_rar5_filter_t::type.
Referenced by internal_decode_token().
|
static |
Read one length/offset field of a RAR5 filter descriptor.
A 2-bit byte count selects 1..4 little-endian bytes of the value.
| [in,out] | st | Decoder state (non-NULL). |
| 0 | When the encoded bytes are all zero. |
st is a bound decoder state at a filter descriptor. st has bits remaining or pads with zero. Definition at line 255 of file ra8_rar5.c.
References k_r5_byte_bits, priv_rar5_get(), and RA8_INTERNAL.
Referenced by internal_read_filter().
|
static |
Convert an LZ length slot into a match length, reading any extra bits.
Slots 0-7 map to lengths 2-9 directly; higher slots add (4 | slot&3) << (slot/4 - 1) plus that many extra bits.
| [in,out] | st | Decoder state (non-NULL). |
| [in] | slot | Length slot value. |
| 2 | For length slot 0. |
st is a bound decoder state. slot is a valid length slot. Definition at line 127 of file ra8_rar5.c.
References priv_rar5_get(), and RA8_INTERNAL.
Referenced by internal_do_match(), and internal_do_repdist().
|
static |
Write a uint32 as four little-endian bytes.
memcpy-based so the destination may sit at any alignment.
| [out] | p | Pointer to four writable bytes (non-NULL). |
| [in] | v | Value to store. |
p addresses at least four writable bytes. v in little-endian order. p. Definition at line 105 of file ra8_rar5.c.
References internal_copy_object(), and RA8_INTERNAL.
Referenced by internal_filter_x86().
|
static |
Test whether op is an x86 branch opcode this filter transforms.
CALL (0xE8) always; JMP (0xE9) only when e9 is set (E8E9 variant).
| [in] | op | Instruction opcode byte. |
| [in] | e9 | Whether 0xE9 is also transformed. |
op is a transformed branch. | true | op is CALL, or JMP with e9 set. |
| false | Any other opcode. |
op is the candidate opcode byte. e9 selects the E8E9 variant. e9) return true. Definition at line 339 of file ra8_rar5.c.
References k_r5_x86_call, k_r5_x86_jmp, and RA8_INTERNAL.
Referenced by internal_filter_x86().
| bool priv_rar5_copy_match | ( | uint8_t * | out, |
| size_t * | out_pos, | ||
| size_t | unp, | ||
| uint32_t | length, | ||
| uint64_t | dist ) |
Implementation of priv_rar5_copy_match() – self-overlapping back-copy.
Copy an LZ match of length bytes at back-distance dist into out.
Definition at line 225 of file ra8_rar5.c.
Referenced by internal_do_match(), internal_do_repdist(), and internal_do_replast().
| void priv_rar5_filter_delta | ( | ra8_rar5_state_t * | st, |
| uint8_t * | d, | ||
| uint32_t | len, | ||
| uint32_t | channels ) |
Implementation of priv_rar5_filter_delta() – per-channel running byte-sum.
Apply the per-channel byte-delta filter over d.
Definition at line 307 of file ra8_rar5.c.
References k_ra8_rar5_delta_scratch, and memcpy().
Referenced by internal_apply_one_filter().
|
nodiscard |
Decompress one RAR5-packed member into the caller's output buffer.
Streams the packed bytes at [data_off, data_off + pack_size) through the archive reader, decodes the RAR 5.0 Huffman-coded LZ token stream into out (which is also the LZ sliding window), then replays any filters the stream recorded. Produces exactly unp_size bytes on success. Malformed, truncated, or hostile input is rejected without reading or writing out of bounds – never a crash.
| [in] | rar | Archive bound by ra8_rar_open (non-NULL). |
| [in] | data_off | Absolute offset of the packed member data (< rar->size). |
| [in] | pack_size | Packed member length in bytes (> 0). |
| [out] | out | Destination and LZ window (non-NULL, out_cap writable). |
| [in] | out_cap | Capacity of out in bytes; must be >= unp_size. |
| [in] | unp_size | Expected unpacked length in bytes. |
| [in,out] | st | Caller-owned decoder scratch (non-NULL). |
| [out] | got | Receives bytes written (non-NULL). |
| k_ra8_ok | Member decoded; *got == unp_size. |
| k_ra8_err_null_ptr | A required pointer argument was NULL. |
| k_ra8_err_invalid_state | rar was never bound by ra8_rar_open. |
| k_ra8_err_no_mem | out_cap is smaller than unp_size. |
| k_ra8_err_validation_failed | Malformed / truncated / solid-reference stream. |
rar was populated by ra8_rar_open (version 5). out holds at least out_cap writable bytes. out contents are unspecified.st. Definition at line 776 of file ra8_rar5.c.
References internal_apply_filters(), internal_decode_stream(), internal_decompress_check(), k_ra8_ok, RA8_CHECK_NULL_PTR, and s_tag_rar5.
Referenced by ra8_rar_extract().
|
static |
Log tag for RAR5 decoder diagnostics.
Definition at line 49 of file ra8_rar5.c.
Referenced by internal_decompress_check(), and ra8_rar5_decompress().