v1.2.0 — Linux Flasher, Kali Creator, fixed flashing & counterfeit detection
New features:
- Linux Flasher tab: download+decompress+flash pipeline for RPi OS, Ubuntu,
Debian, Fedora, Kali, DietPi, Alpine, Arch ARM with built-in image catalog
- Kali Creator tab: 4 sub-tabs for USB/SD, VM creation, Docker/Podman
container pulls, and cloud image downloads
- DownloadManager: async downloads with resume support and speed tracking
- Decompressor: streaming .xz (xz-embedded), .gz (zlib), .zip decompression
- ImageCatalog: built-in catalog + remote fetch from rpi-imager JSON endpoint
- SevenZipExtractor: QProcess wrapper for 7z.exe with progress parsing
- Bundled xz-embedded third-party library for native XZ decompression
Bug fixes:
- Fixed VirtualDisk::flashToDisk() — added FSCTL_ALLOW_EXTENDED_DASD_IO,
FSCTL_LOCK_VOLUME, FSCTL_DISMOUNT_VOLUME, 32MB aligned buffers,
WriteFile retry logic (3 attempts), FlushFileBuffers before close
- Fixed VirtualDisk::captureFromDisk() with same improvements
- Fixed ImagingTab::onFlashIso() — now populates targetVolumeLetters from
disk snapshot so IsoFlasher can properly lock/dismount volumes
- Fixed SD card counterfeit detection false positives:
- Changed from write-one-read-one to write-all-then-read-all algorithm
to properly detect NAND address wrapping on fake cards
- Added volume lock/dismount before probing to prevent filesystem
interference (journal writes, metadata updates)
- Added FSCTL_ALLOW_EXTENDED_DASD_IO for probes near end of disk
- Fixed overly aggressive vendor string check — USB card readers
legitimately report "USB"/"Mass Storage", no longer flagged
- Added handle re-open between write and verify phases to defeat
USB reader hardware cache
- README: documented how to unlock the secret menu, added new feature docs
This commit is contained in:
136
third_party/xz-embedded/xz.h
vendored
Normal file
136
third_party/xz-embedded/xz.h
vendored
Normal file
@@ -0,0 +1,136 @@
|
||||
/*
|
||||
* XZ decompressor - Public API header
|
||||
*
|
||||
* Based on xz-embedded by Lasse Collin (public domain).
|
||||
* Minimal subset for streaming XZ decompression.
|
||||
*/
|
||||
|
||||
#ifndef XZ_H
|
||||
#define XZ_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* enum xz_mode - Operation mode
|
||||
*
|
||||
* @XZ_SINGLE: Single-call mode. The caller provides the full input and
|
||||
* output buffers in one call.
|
||||
* @XZ_PREALLOC: Multi-call mode with preallocated dictionary buffer.
|
||||
* @XZ_DYNALLOC: Multi-call mode with dynamically allocated dictionary.
|
||||
*/
|
||||
enum xz_mode {
|
||||
XZ_SINGLE,
|
||||
XZ_PREALLOC,
|
||||
XZ_DYNALLOC
|
||||
};
|
||||
|
||||
/**
|
||||
* enum xz_ret - Return codes
|
||||
*
|
||||
* @XZ_OK: Everything is OK so far. More input or output
|
||||
* space is needed to continue.
|
||||
* @XZ_STREAM_END: Operation finished successfully.
|
||||
* @XZ_UNSUPPORTED_CHECK: Integrity check type is not supported. Decoding
|
||||
* is still possible by simply ignoring the check.
|
||||
* @XZ_MEM_ERROR: Allocating memory failed.
|
||||
* @XZ_MEMLIMIT_ERROR: A bigger dictionary would be needed than allowed
|
||||
* by dict_max in xz_dec_init().
|
||||
* @XZ_FORMAT_ERROR: File format was not recognized (wrong magic bytes).
|
||||
* @XZ_OPTIONS_ERROR: This implementation doesn't support the requested
|
||||
* compression options. In the decoder this means
|
||||
* unsupported header flags.
|
||||
* @XZ_DATA_ERROR: Compressed data is corrupt.
|
||||
* @XZ_BUF_ERROR: Cannot make any progress. Details depend on
|
||||
* function being called.
|
||||
*/
|
||||
enum xz_ret {
|
||||
XZ_OK,
|
||||
XZ_STREAM_END,
|
||||
XZ_UNSUPPORTED_CHECK,
|
||||
XZ_MEM_ERROR,
|
||||
XZ_MEMLIMIT_ERROR,
|
||||
XZ_FORMAT_ERROR,
|
||||
XZ_OPTIONS_ERROR,
|
||||
XZ_DATA_ERROR,
|
||||
XZ_BUF_ERROR
|
||||
};
|
||||
|
||||
/**
|
||||
* struct xz_buf - Passing input and output buffers to XZ code
|
||||
*
|
||||
* @in: Beginning of the input buffer.
|
||||
* @in_pos: Current position in the input buffer. This must not exceed
|
||||
* in_size.
|
||||
* @in_size: Size of the input buffer.
|
||||
* @out: Beginning of the output buffer.
|
||||
* @out_pos: Current position in the output buffer. This must not exceed
|
||||
* out_size.
|
||||
* @out_size: Size of the output buffer.
|
||||
*/
|
||||
struct xz_buf {
|
||||
const uint8_t *in;
|
||||
size_t in_pos;
|
||||
size_t in_size;
|
||||
|
||||
uint8_t *out;
|
||||
size_t out_pos;
|
||||
size_t out_size;
|
||||
};
|
||||
|
||||
/* Opaque decoder state */
|
||||
struct xz_dec;
|
||||
|
||||
/**
|
||||
* xz_crc32_init() - Initialize the CRC32 lookup table.
|
||||
* Must be called before any CRC32 use (including xz_dec_run).
|
||||
*/
|
||||
void xz_crc32_init(void);
|
||||
|
||||
/**
|
||||
* xz_crc64_init() - Initialize the CRC64 lookup table.
|
||||
* Must be called if the stream uses CRC64 checks.
|
||||
*/
|
||||
void xz_crc64_init(void);
|
||||
|
||||
/**
|
||||
* xz_dec_init() - Allocate and initialize a XZ decoder state.
|
||||
* @mode: XZ_SINGLE, XZ_PREALLOC, or XZ_DYNALLOC.
|
||||
* @dict_max: Maximum allowed dictionary size. Use 0 for default.
|
||||
*
|
||||
* Returns NULL on allocation failure.
|
||||
*/
|
||||
struct xz_dec *xz_dec_init(enum xz_mode mode, uint32_t dict_max);
|
||||
|
||||
/**
|
||||
* xz_dec_run() - Run the XZ decoder.
|
||||
* @s: Decoder state allocated with xz_dec_init().
|
||||
* @b: Input/output buffer pointers.
|
||||
*
|
||||
* See enum xz_ret for possible return values.
|
||||
*/
|
||||
enum xz_ret xz_dec_run(struct xz_dec *s, struct xz_buf *b);
|
||||
|
||||
/**
|
||||
* xz_dec_reset() - Reset an already allocated decoder state.
|
||||
* @s: Decoder state allocated with xz_dec_init().
|
||||
*
|
||||
* This allows reusing the decoder state for decoding another stream.
|
||||
*/
|
||||
void xz_dec_reset(struct xz_dec *s);
|
||||
|
||||
/**
|
||||
* xz_dec_end() - Free the decoder state.
|
||||
* @s: Decoder state allocated with xz_dec_init(). Passing NULL is safe.
|
||||
*/
|
||||
void xz_dec_end(struct xz_dec *s);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* XZ_H */
|
||||
41
third_party/xz-embedded/xz_crc32.c
vendored
Normal file
41
third_party/xz-embedded/xz_crc32.c
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* XZ decompressor - CRC32
|
||||
*
|
||||
* Based on xz-embedded by Lasse Collin (public domain).
|
||||
* Standard CRC32 with polynomial 0xEDB88320 (bit-reversed 0x04C11DB7).
|
||||
*/
|
||||
|
||||
#include "xz_private.h"
|
||||
|
||||
uint32_t xz_crc32_table[256];
|
||||
|
||||
void xz_crc32_init(void)
|
||||
{
|
||||
static int done = 0;
|
||||
uint32_t i, j, r;
|
||||
|
||||
if (done)
|
||||
return;
|
||||
|
||||
for (i = 0; i < 256; ++i) {
|
||||
r = i;
|
||||
for (j = 0; j < 8; ++j)
|
||||
r = (r >> 1) ^ (0xEDB88320 & ~((r & 1) - 1));
|
||||
xz_crc32_table[i] = r;
|
||||
}
|
||||
|
||||
done = 1;
|
||||
}
|
||||
|
||||
uint32_t xz_crc32(const uint8_t *buf, size_t size, uint32_t crc)
|
||||
{
|
||||
crc = ~crc;
|
||||
|
||||
while (size > 0) {
|
||||
crc = xz_crc32_table[(crc ^ *buf) & 0xFF] ^ (crc >> 8);
|
||||
++buf;
|
||||
--size;
|
||||
}
|
||||
|
||||
return ~crc;
|
||||
}
|
||||
41
third_party/xz-embedded/xz_crc64.c
vendored
Normal file
41
third_party/xz-embedded/xz_crc64.c
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* XZ decompressor - CRC64
|
||||
*
|
||||
* Based on xz-embedded by Lasse Collin (public domain).
|
||||
* CRC64 with polynomial 0xC96C5795D7870F42 (ECMA-182).
|
||||
*/
|
||||
|
||||
#include "xz_private.h"
|
||||
|
||||
uint64_t xz_crc64_table[256];
|
||||
|
||||
void xz_crc64_init(void)
|
||||
{
|
||||
static int done = 0;
|
||||
uint64_t i, j, r;
|
||||
|
||||
if (done)
|
||||
return;
|
||||
|
||||
for (i = 0; i < 256; ++i) {
|
||||
r = i;
|
||||
for (j = 0; j < 8; ++j)
|
||||
r = (r >> 1) ^ (UINT64_C(0xC96C5795D7870F42) & ~((r & 1) - 1));
|
||||
xz_crc64_table[i] = r;
|
||||
}
|
||||
|
||||
done = 1;
|
||||
}
|
||||
|
||||
uint64_t xz_crc64(const uint8_t *buf, size_t size, uint64_t crc)
|
||||
{
|
||||
crc = ~crc;
|
||||
|
||||
while (size > 0) {
|
||||
crc = xz_crc64_table[(crc ^ *buf) & 0xFF] ^ (crc >> 8);
|
||||
++buf;
|
||||
--size;
|
||||
}
|
||||
|
||||
return ~crc;
|
||||
}
|
||||
816
third_party/xz-embedded/xz_dec_lzma2.c
vendored
Normal file
816
third_party/xz-embedded/xz_dec_lzma2.c
vendored
Normal file
@@ -0,0 +1,816 @@
|
||||
/*
|
||||
* XZ decompressor - LZMA2 decoder
|
||||
*
|
||||
* Based on xz-embedded by Lasse Collin (public domain).
|
||||
*
|
||||
* This implements:
|
||||
* - LZMA2 chunk parsing (control bytes, property resets, dictionary resets)
|
||||
* - The LZMA range decoder
|
||||
* - The full LZMA algorithm (literals, matches, short/long reps)
|
||||
* - Dictionary management as a circular buffer
|
||||
*/
|
||||
|
||||
#include "xz_lzma2.h"
|
||||
|
||||
/*
|
||||
* ============================================================
|
||||
* Range decoder
|
||||
* ============================================================
|
||||
*/
|
||||
struct rc_dec {
|
||||
uint32_t range;
|
||||
uint32_t code;
|
||||
uint32_t init_bytes_left;
|
||||
|
||||
const uint8_t *in;
|
||||
size_t in_pos;
|
||||
size_t in_limit;
|
||||
};
|
||||
|
||||
static inline void rc_reset(struct rc_dec *rc)
|
||||
{
|
||||
rc->range = 0xFFFFFFFF;
|
||||
rc->code = 0;
|
||||
rc->init_bytes_left = 5;
|
||||
}
|
||||
|
||||
static inline int rc_read_init(struct rc_dec *rc, struct xz_buf *b)
|
||||
{
|
||||
while (rc->init_bytes_left > 0) {
|
||||
if (b->in_pos == b->in_size)
|
||||
return 0;
|
||||
rc->code = (rc->code << 8) + b->in[b->in_pos++];
|
||||
--rc->init_bytes_left;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline void rc_normalize(struct rc_dec *rc)
|
||||
{
|
||||
if (rc->range < RC_TOP_VALUE) {
|
||||
rc->range <<= RC_SHIFT_BITS;
|
||||
rc->code = (rc->code << RC_SHIFT_BITS) | rc->in[rc->in_pos++];
|
||||
}
|
||||
}
|
||||
|
||||
static inline int rc_bit(struct rc_dec *rc, uint16_t *prob)
|
||||
{
|
||||
uint32_t bound;
|
||||
|
||||
rc_normalize(rc);
|
||||
bound = (rc->range >> RC_BIT_MODEL_TOTAL_BITS) * *prob;
|
||||
|
||||
if (rc->code < bound) {
|
||||
rc->range = bound;
|
||||
*prob += (RC_BIT_MODEL_TOTAL - *prob) >> RC_MOVE_BITS;
|
||||
return 0;
|
||||
} else {
|
||||
rc->range -= bound;
|
||||
rc->code -= bound;
|
||||
*prob -= *prob >> RC_MOVE_BITS;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
static inline uint32_t rc_bittree(struct rc_dec *rc, uint16_t *probs,
|
||||
uint32_t limit)
|
||||
{
|
||||
uint32_t symbol = 1;
|
||||
do {
|
||||
if (rc_bit(rc, &probs[symbol]))
|
||||
symbol = (symbol << 1) + 1;
|
||||
else
|
||||
symbol <<= 1;
|
||||
} while (symbol < limit);
|
||||
return symbol;
|
||||
}
|
||||
|
||||
static inline uint32_t rc_bittree_reverse(struct rc_dec *rc, uint16_t *probs,
|
||||
uint32_t bits)
|
||||
{
|
||||
uint32_t symbol = 1;
|
||||
uint32_t i, result = 0;
|
||||
|
||||
for (i = 0; i < bits; ++i) {
|
||||
if (rc_bit(rc, &probs[symbol])) {
|
||||
symbol = (symbol << 1) + 1;
|
||||
result |= 1U << i;
|
||||
} else {
|
||||
symbol <<= 1;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline uint32_t rc_direct(struct rc_dec *rc, uint32_t count)
|
||||
{
|
||||
uint32_t result = 0;
|
||||
do {
|
||||
rc_normalize(rc);
|
||||
rc->range >>= 1;
|
||||
rc->code -= rc->range;
|
||||
result = (result << 1) + (rc->code >> 31) + 1;
|
||||
rc->code += rc->range & (rc->code >> 31);
|
||||
} while (--count > 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* ============================================================
|
||||
* Dictionary (circular buffer)
|
||||
* ============================================================
|
||||
*/
|
||||
struct dictionary {
|
||||
uint8_t *buf;
|
||||
size_t pos;
|
||||
size_t full;
|
||||
size_t limit;
|
||||
size_t end;
|
||||
uint32_t size;
|
||||
enum xz_mode mode;
|
||||
uint32_t allocated;
|
||||
};
|
||||
|
||||
static void dict_reset(struct dictionary *dict, struct xz_buf *b)
|
||||
{
|
||||
if (dict->mode == XZ_SINGLE) {
|
||||
dict->buf = b->out + b->out_pos;
|
||||
dict->end = b->out_size - b->out_pos;
|
||||
}
|
||||
dict->pos = 0;
|
||||
dict->full = 0;
|
||||
dict->limit = dict->end;
|
||||
}
|
||||
|
||||
static inline void dict_limit(struct dictionary *dict, size_t out_max)
|
||||
{
|
||||
if (dict->mode == XZ_SINGLE)
|
||||
return;
|
||||
if (dict->end - dict->pos <= out_max)
|
||||
dict->limit = dict->end;
|
||||
else
|
||||
dict->limit = dict->pos + out_max;
|
||||
}
|
||||
|
||||
static inline int dict_has_space(const struct dictionary *dict)
|
||||
{
|
||||
return dict->pos < dict->limit;
|
||||
}
|
||||
|
||||
static inline uint8_t dict_get(const struct dictionary *dict, uint32_t dist)
|
||||
{
|
||||
size_t offset = dict->pos - dist - 1;
|
||||
if (dict->pos <= dist)
|
||||
offset += dict->end;
|
||||
return dict->buf[offset];
|
||||
}
|
||||
|
||||
static inline void dict_put(struct dictionary *dict, uint8_t byte)
|
||||
{
|
||||
dict->buf[dict->pos++] = byte;
|
||||
if (dict->full < dict->pos)
|
||||
dict->full = dict->pos;
|
||||
}
|
||||
|
||||
static int dict_repeat(struct dictionary *dict, uint32_t *len, uint32_t dist)
|
||||
{
|
||||
size_t back;
|
||||
uint32_t left;
|
||||
|
||||
if (dist >= dict->full || dist >= dict->size)
|
||||
return 0;
|
||||
|
||||
left = min_t(uint32_t, (uint32_t)(dict->limit - dict->pos), *len);
|
||||
*len -= left;
|
||||
|
||||
back = dict->pos - dist - 1;
|
||||
if (dict->pos <= dist)
|
||||
back += dict->end;
|
||||
|
||||
while (left > 0) {
|
||||
dict->buf[dict->pos++] = dict->buf[back++];
|
||||
if (back == dict->end)
|
||||
back = 0;
|
||||
if (dict->full < dict->pos)
|
||||
dict->full = dict->pos;
|
||||
--left;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void dict_uncompressed(struct dictionary *dict, struct xz_buf *b,
|
||||
uint32_t *left)
|
||||
{
|
||||
size_t copy_size;
|
||||
|
||||
copy_size = min_t(size_t, b->in_size - b->in_pos,
|
||||
min_t(size_t, *left, dict->limit - dict->pos));
|
||||
|
||||
memcpy(dict->buf + dict->pos, b->in + b->in_pos, copy_size);
|
||||
dict->pos += copy_size;
|
||||
if (dict->full < dict->pos)
|
||||
dict->full = dict->pos;
|
||||
b->in_pos += copy_size;
|
||||
*left -= (uint32_t)copy_size;
|
||||
}
|
||||
|
||||
static uint32_t dict_flush(struct dictionary *dict, struct xz_buf *b)
|
||||
{
|
||||
size_t copy_size;
|
||||
|
||||
if (dict->mode == XZ_SINGLE) {
|
||||
size_t out = dict->pos;
|
||||
b->out_pos += out;
|
||||
return (uint32_t)out;
|
||||
}
|
||||
|
||||
copy_size = min_t(size_t, b->out_size - b->out_pos, dict->pos);
|
||||
memcpy(b->out + b->out_pos, dict->buf, copy_size);
|
||||
b->out_pos += copy_size;
|
||||
|
||||
if (copy_size < dict->pos)
|
||||
memmove(dict->buf, dict->buf + copy_size, dict->pos - copy_size);
|
||||
|
||||
dict->pos -= copy_size;
|
||||
return (uint32_t)copy_size;
|
||||
}
|
||||
|
||||
/*
|
||||
* ============================================================
|
||||
* LZMA decoder
|
||||
* ============================================================
|
||||
*/
|
||||
struct lzma_dec {
|
||||
struct rc_dec rc;
|
||||
|
||||
uint32_t state;
|
||||
uint32_t rep0, rep1, rep2, rep3;
|
||||
|
||||
uint32_t lc;
|
||||
uint32_t literal_pos_mask;
|
||||
uint32_t pos_mask;
|
||||
|
||||
/* Match length decoder */
|
||||
uint16_t match_len_choice;
|
||||
uint16_t match_len_choice2;
|
||||
uint16_t match_len_low[POS_STATES_MAX][LEN_LOW_SYMBOLS];
|
||||
uint16_t match_len_mid[POS_STATES_MAX][LEN_MID_SYMBOLS];
|
||||
uint16_t match_len_high[LEN_HIGH_SYMBOLS];
|
||||
|
||||
/* Rep length decoder */
|
||||
uint16_t rep_len_choice;
|
||||
uint16_t rep_len_choice2;
|
||||
uint16_t rep_len_low[POS_STATES_MAX][LEN_LOW_SYMBOLS];
|
||||
uint16_t rep_len_mid[POS_STATES_MAX][LEN_MID_SYMBOLS];
|
||||
uint16_t rep_len_high[LEN_HIGH_SYMBOLS];
|
||||
|
||||
/* Main probabilities */
|
||||
uint16_t is_match[STATES][POS_STATES_MAX];
|
||||
uint16_t is_rep[STATES];
|
||||
uint16_t is_rep0[STATES];
|
||||
uint16_t is_rep1[STATES];
|
||||
uint16_t is_rep2[STATES];
|
||||
uint16_t is_rep0_long[STATES][POS_STATES_MAX];
|
||||
|
||||
uint16_t dist_slot[DIST_STATES][DIST_SLOTS];
|
||||
uint16_t dist_special[FULL_DISTANCES - DIST_MODEL_END];
|
||||
uint16_t dist_align[ALIGN_SIZE];
|
||||
|
||||
/* Literal probabilities: 3 * 2^lc entries per position coder */
|
||||
uint16_t literal[LITERAL_CODERS_MAX][0x300];
|
||||
};
|
||||
|
||||
static void lzma_reset(struct lzma_dec *lzma)
|
||||
{
|
||||
uint16_t *p;
|
||||
size_t count, i;
|
||||
|
||||
lzma->state = 0;
|
||||
lzma->rep0 = 0;
|
||||
lzma->rep1 = 0;
|
||||
lzma->rep2 = 0;
|
||||
lzma->rep3 = 0;
|
||||
|
||||
/* Initialize all probabilities to RC_BIT_MODEL_TOTAL / 2 */
|
||||
p = &lzma->match_len_choice;
|
||||
count = (size_t)((uint8_t *)&lzma->literal[LITERAL_CODERS_MAX][0]
|
||||
- (uint8_t *)&lzma->match_len_choice) / sizeof(uint16_t);
|
||||
for (i = 0; i < count; ++i)
|
||||
p[i] = RC_BIT_MODEL_TOTAL / 2;
|
||||
}
|
||||
|
||||
static void lzma_literal(struct lzma_dec *lzma, struct dictionary *dict)
|
||||
{
|
||||
uint16_t *probs;
|
||||
uint32_t symbol;
|
||||
uint32_t literal_pos;
|
||||
|
||||
literal_pos = dict->pos & lzma->literal_pos_mask;
|
||||
probs = lzma->literal[literal_pos << lzma->lc];
|
||||
|
||||
if (dict->pos > 0 || dict->full > 0) {
|
||||
uint8_t prev = dict_get(dict, 0);
|
||||
probs = lzma->literal[((literal_pos << lzma->lc)
|
||||
+ ((uint32_t)prev >> (8 - lzma->lc)))
|
||||
& ((LITERAL_CODERS_MAX - 1))];
|
||||
}
|
||||
|
||||
if (lzma_state_is_literal(lzma->state)) {
|
||||
symbol = rc_bittree(&lzma->rc, probs - 1, 0x100);
|
||||
} else {
|
||||
uint32_t match_byte = dict_get(dict, lzma->rep0);
|
||||
uint32_t offset = 0x100;
|
||||
symbol = 1;
|
||||
|
||||
do {
|
||||
uint32_t match_bit, bit;
|
||||
|
||||
match_byte <<= 1;
|
||||
match_bit = match_byte & offset;
|
||||
bit = rc_bit(&lzma->rc, &probs[offset + match_bit + symbol]);
|
||||
symbol = (symbol << 1) | bit;
|
||||
offset &= ~(match_byte ^ (bit ? ~(uint32_t)0 : 0)) & 0x100;
|
||||
} while (symbol < 0x100);
|
||||
}
|
||||
|
||||
dict_put(dict, (uint8_t)symbol);
|
||||
lzma->state = lzma_state_literal(lzma->state);
|
||||
}
|
||||
|
||||
static uint32_t lzma_len_decode(struct rc_dec *rc,
|
||||
uint16_t *choice, uint16_t *choice2,
|
||||
uint16_t low[][LEN_LOW_SYMBOLS],
|
||||
uint16_t mid[][LEN_MID_SYMBOLS],
|
||||
uint16_t *high,
|
||||
uint32_t pos_state)
|
||||
{
|
||||
if (!rc_bit(rc, choice))
|
||||
return rc_bittree(rc, low[pos_state] - 1, LEN_LOW_SYMBOLS)
|
||||
- LEN_LOW_SYMBOLS + MATCH_LEN_MIN;
|
||||
|
||||
if (!rc_bit(rc, choice2))
|
||||
return rc_bittree(rc, mid[pos_state] - 1, LEN_MID_SYMBOLS)
|
||||
- LEN_MID_SYMBOLS + MATCH_LEN_MIN + LEN_LOW_SYMBOLS;
|
||||
|
||||
return rc_bittree(rc, high - 1, LEN_HIGH_SYMBOLS)
|
||||
- LEN_HIGH_SYMBOLS + MATCH_LEN_MIN + LEN_LOW_SYMBOLS
|
||||
+ LEN_MID_SYMBOLS;
|
||||
}
|
||||
|
||||
/*
|
||||
* ============================================================
|
||||
* LZMA2 decoder
|
||||
* ============================================================
|
||||
*/
|
||||
|
||||
enum lzma2_seq {
|
||||
SEQ_LZMA2_CONTROL,
|
||||
SEQ_LZMA2_UNCOMPRESSED_1,
|
||||
SEQ_LZMA2_UNCOMPRESSED_2,
|
||||
SEQ_LZMA2_COMPRESSED_0,
|
||||
SEQ_LZMA2_COMPRESSED_1,
|
||||
SEQ_LZMA2_PROPS,
|
||||
SEQ_LZMA2_LZMA_PREPARE,
|
||||
SEQ_LZMA2_LZMA_RUN,
|
||||
SEQ_LZMA2_COPY
|
||||
};
|
||||
|
||||
struct xz_dec_lzma2 {
|
||||
enum lzma2_seq sequence;
|
||||
|
||||
/* Current LZMA2 control byte */
|
||||
uint32_t control;
|
||||
|
||||
/* Compressed and uncompressed sizes for the current chunk */
|
||||
uint32_t compressed;
|
||||
uint32_t uncompressed;
|
||||
|
||||
int need_lzma_init;
|
||||
int need_dict_reset;
|
||||
int need_props;
|
||||
|
||||
/* Leftover match length from previous call */
|
||||
uint32_t match_len;
|
||||
|
||||
struct lzma_dec lzma;
|
||||
struct dictionary dict;
|
||||
};
|
||||
|
||||
/*
|
||||
* Decode LZMA symbols from the range-coded stream.
|
||||
* Returns 1 on success, 0 on error (invalid distance reference).
|
||||
*/
|
||||
static int lzma_decode_loop(struct xz_dec_lzma2 *s, struct xz_buf *b,
|
||||
size_t in_avail)
|
||||
{
|
||||
struct lzma_dec *lzma = &s->lzma;
|
||||
struct dictionary *dict = &s->dict;
|
||||
struct rc_dec *rc = &lzma->rc;
|
||||
uint32_t pos_state;
|
||||
|
||||
rc->in = b->in;
|
||||
rc->in_pos = b->in_pos;
|
||||
rc->in_limit = b->in_pos + in_avail;
|
||||
|
||||
/* Finish leftover match */
|
||||
if (s->match_len > 0) {
|
||||
if (!dict_repeat(dict, &s->match_len, lzma->rep0)) {
|
||||
/* Dictionary full, need to flush output first */
|
||||
s->compressed -= (uint32_t)(rc->in_pos - b->in_pos);
|
||||
b->in_pos = rc->in_pos;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
while (dict_has_space(dict) && rc->in_pos < rc->in_limit) {
|
||||
pos_state = dict->pos & lzma->pos_mask;
|
||||
|
||||
if (!rc_bit(rc, &lzma->is_match[lzma->state][pos_state])) {
|
||||
lzma_literal(lzma, dict);
|
||||
} else if (rc_bit(rc, &lzma->is_rep[lzma->state])) {
|
||||
/* Repeated match */
|
||||
uint32_t len;
|
||||
|
||||
if (!rc_bit(rc, &lzma->is_rep0[lzma->state])) {
|
||||
if (!rc_bit(rc, &lzma->is_rep0_long[lzma->state][pos_state])) {
|
||||
/* Short rep0 (single byte) */
|
||||
if (dict->full == 0) {
|
||||
s->compressed -= (uint32_t)(rc->in_pos - b->in_pos);
|
||||
b->in_pos = rc->in_pos;
|
||||
return 0;
|
||||
}
|
||||
dict_put(dict, dict_get(dict, lzma->rep0));
|
||||
lzma->state = lzma_state_short_rep(lzma->state);
|
||||
continue;
|
||||
}
|
||||
/* Long rep0 -- distance stays rep0 */
|
||||
} else {
|
||||
uint32_t tmp;
|
||||
if (!rc_bit(rc, &lzma->is_rep1[lzma->state])) {
|
||||
tmp = lzma->rep1;
|
||||
} else if (!rc_bit(rc, &lzma->is_rep2[lzma->state])) {
|
||||
tmp = lzma->rep2;
|
||||
lzma->rep2 = lzma->rep1;
|
||||
} else {
|
||||
tmp = lzma->rep3;
|
||||
lzma->rep3 = lzma->rep2;
|
||||
lzma->rep2 = lzma->rep1;
|
||||
}
|
||||
lzma->rep1 = lzma->rep0;
|
||||
lzma->rep0 = tmp;
|
||||
}
|
||||
|
||||
len = lzma_len_decode(rc,
|
||||
&lzma->rep_len_choice,
|
||||
&lzma->rep_len_choice2,
|
||||
lzma->rep_len_low,
|
||||
lzma->rep_len_mid,
|
||||
lzma->rep_len_high,
|
||||
pos_state);
|
||||
|
||||
lzma->state = lzma_state_long_rep(lzma->state);
|
||||
|
||||
if (!dict_repeat(dict, &len, lzma->rep0)) {
|
||||
s->match_len = len;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
/* Normal match */
|
||||
uint32_t len, dist_slot, dist;
|
||||
|
||||
lzma->rep3 = lzma->rep2;
|
||||
lzma->rep2 = lzma->rep1;
|
||||
lzma->rep1 = lzma->rep0;
|
||||
|
||||
len = lzma_len_decode(rc,
|
||||
&lzma->match_len_choice,
|
||||
&lzma->match_len_choice2,
|
||||
lzma->match_len_low,
|
||||
lzma->match_len_mid,
|
||||
lzma->match_len_high,
|
||||
pos_state);
|
||||
|
||||
dist_slot = rc_bittree(rc,
|
||||
lzma->dist_slot[lzma_get_dist_state(len)] - 1,
|
||||
DIST_SLOTS) - DIST_SLOTS;
|
||||
|
||||
if (dist_slot < DIST_MODEL_START) {
|
||||
dist = dist_slot;
|
||||
} else {
|
||||
uint32_t limit = (dist_slot >> 1) - 1;
|
||||
dist = (2 | (dist_slot & 1)) << limit;
|
||||
|
||||
if (dist_slot < DIST_MODEL_END) {
|
||||
dist += rc_bittree_reverse(rc,
|
||||
lzma->dist_special + dist - dist_slot - 1,
|
||||
limit);
|
||||
} else {
|
||||
dist += rc_direct(rc, limit - ALIGN_BITS) << ALIGN_BITS;
|
||||
dist += rc_bittree_reverse(rc, lzma->dist_align,
|
||||
ALIGN_BITS);
|
||||
}
|
||||
}
|
||||
|
||||
lzma->rep0 = dist;
|
||||
lzma->state = lzma_state_match(lzma->state);
|
||||
|
||||
if (dist >= dict->full || dist >= dict->size) {
|
||||
s->compressed -= (uint32_t)(rc->in_pos - b->in_pos);
|
||||
b->in_pos = rc->in_pos;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!dict_repeat(dict, &len, dist)) {
|
||||
s->match_len = len;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
s->compressed -= (uint32_t)(rc->in_pos - b->in_pos);
|
||||
b->in_pos = rc->in_pos;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate an LZMA2 decoder.
|
||||
*/
|
||||
struct xz_dec_lzma2 *xz_dec_lzma2_create(enum xz_mode mode, uint32_t dict_max)
|
||||
{
|
||||
struct xz_dec_lzma2 *s;
|
||||
|
||||
s = (struct xz_dec_lzma2 *)malloc(sizeof(*s));
|
||||
if (s == NULL)
|
||||
return NULL;
|
||||
|
||||
memset(s, 0, sizeof(*s));
|
||||
s->dict.mode = mode;
|
||||
s->dict.size = dict_max;
|
||||
|
||||
if (mode == XZ_PREALLOC && dict_max > 0) {
|
||||
s->dict.buf = (uint8_t *)malloc(dict_max);
|
||||
if (s->dict.buf == NULL) {
|
||||
free(s);
|
||||
return NULL;
|
||||
}
|
||||
s->dict.allocated = dict_max;
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reset the LZMA2 decoder for a new block.
|
||||
*/
|
||||
enum xz_ret xz_dec_lzma2_reset(struct xz_dec_lzma2 *s, uint8_t props)
|
||||
{
|
||||
uint32_t dict_size;
|
||||
|
||||
if (props > 40)
|
||||
return XZ_OPTIONS_ERROR;
|
||||
|
||||
if (props == 40) {
|
||||
dict_size = 0xFFFFFFFF;
|
||||
} else {
|
||||
dict_size = 2 + (props & 1);
|
||||
dict_size <<= props / 2 + 11;
|
||||
}
|
||||
|
||||
if (s->dict.mode != XZ_SINGLE && s->dict.size > 0 && dict_size > s->dict.size)
|
||||
return XZ_MEMLIMIT_ERROR;
|
||||
|
||||
if (s->dict.mode == XZ_DYNALLOC) {
|
||||
if (s->dict.allocated < dict_size) {
|
||||
free(s->dict.buf);
|
||||
s->dict.buf = (uint8_t *)malloc(dict_size);
|
||||
if (s->dict.buf == NULL) {
|
||||
s->dict.allocated = 0;
|
||||
return XZ_MEM_ERROR;
|
||||
}
|
||||
s->dict.allocated = dict_size;
|
||||
}
|
||||
}
|
||||
|
||||
if (s->dict.mode != XZ_SINGLE)
|
||||
s->dict.end = dict_size;
|
||||
|
||||
s->sequence = SEQ_LZMA2_CONTROL;
|
||||
s->need_dict_reset = 1;
|
||||
s->need_lzma_init = 1;
|
||||
s->need_props = 1;
|
||||
s->match_len = 0;
|
||||
|
||||
return XZ_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* LZMA2 main decoding loop.
|
||||
*/
|
||||
enum xz_ret xz_dec_lzma2_run(struct xz_dec_lzma2 *s, struct xz_buf *b)
|
||||
{
|
||||
for (;;) {
|
||||
switch (s->sequence) {
|
||||
|
||||
case SEQ_LZMA2_CONTROL:
|
||||
if (b->in_pos >= b->in_size)
|
||||
return XZ_OK;
|
||||
|
||||
s->control = b->in[b->in_pos++];
|
||||
|
||||
if (s->control == 0x00)
|
||||
return XZ_STREAM_END;
|
||||
|
||||
if (s->control < 0x03) {
|
||||
/*
|
||||
* Uncompressed chunk:
|
||||
* 0x01 = no dictionary reset
|
||||
* 0x02 = dictionary reset
|
||||
*/
|
||||
if (s->control == 0x02) {
|
||||
s->need_dict_reset = 0;
|
||||
s->need_lzma_init = 1;
|
||||
dict_reset(&s->dict, b);
|
||||
} else if (s->need_dict_reset) {
|
||||
return XZ_DATA_ERROR;
|
||||
}
|
||||
s->sequence = SEQ_LZMA2_UNCOMPRESSED_1;
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* LZMA chunk. The control byte encodes:
|
||||
* 0x80-0x9F: no reset
|
||||
* 0xA0-0xBF: state reset
|
||||
* 0xC0-0xDF: state reset + new properties
|
||||
* 0xE0-0xFF: full reset (state, props, dict)
|
||||
*
|
||||
* Bits 4..0 = uncompressed size high bits.
|
||||
*/
|
||||
if (s->control >= 0xE0) {
|
||||
s->need_dict_reset = 0;
|
||||
dict_reset(&s->dict, b);
|
||||
} else if (s->need_dict_reset) {
|
||||
return XZ_DATA_ERROR;
|
||||
}
|
||||
|
||||
if (s->control >= 0xA0)
|
||||
s->need_lzma_init = 1;
|
||||
|
||||
if (s->control >= 0xC0) {
|
||||
s->need_props = 1;
|
||||
}
|
||||
|
||||
s->uncompressed = (s->control & 0x1F) << 16;
|
||||
s->sequence = SEQ_LZMA2_UNCOMPRESSED_1;
|
||||
break;
|
||||
|
||||
case SEQ_LZMA2_UNCOMPRESSED_1:
|
||||
if (b->in_pos >= b->in_size)
|
||||
return XZ_OK;
|
||||
|
||||
s->uncompressed += (uint32_t)b->in[b->in_pos++] << 8;
|
||||
s->sequence = SEQ_LZMA2_UNCOMPRESSED_2;
|
||||
break;
|
||||
|
||||
case SEQ_LZMA2_UNCOMPRESSED_2:
|
||||
if (b->in_pos >= b->in_size)
|
||||
return XZ_OK;
|
||||
|
||||
s->uncompressed += (uint32_t)b->in[b->in_pos++] + 1;
|
||||
|
||||
if (s->control < 0x03) {
|
||||
/* Uncompressed copy: "compressed" size == uncompressed size */
|
||||
s->compressed = s->uncompressed;
|
||||
s->sequence = SEQ_LZMA2_COPY;
|
||||
break;
|
||||
}
|
||||
|
||||
/* LZMA chunk: read compressed size */
|
||||
s->sequence = SEQ_LZMA2_COMPRESSED_0;
|
||||
break;
|
||||
|
||||
case SEQ_LZMA2_COMPRESSED_0:
|
||||
if (b->in_pos >= b->in_size)
|
||||
return XZ_OK;
|
||||
|
||||
s->compressed = (uint32_t)b->in[b->in_pos++] << 8;
|
||||
s->sequence = SEQ_LZMA2_COMPRESSED_1;
|
||||
break;
|
||||
|
||||
case SEQ_LZMA2_COMPRESSED_1:
|
||||
if (b->in_pos >= b->in_size)
|
||||
return XZ_OK;
|
||||
|
||||
s->compressed += (uint32_t)b->in[b->in_pos++] + 1;
|
||||
|
||||
if (s->need_props)
|
||||
s->sequence = SEQ_LZMA2_PROPS;
|
||||
else
|
||||
s->sequence = SEQ_LZMA2_LZMA_PREPARE;
|
||||
break;
|
||||
|
||||
case SEQ_LZMA2_PROPS:
|
||||
if (b->in_pos >= b->in_size)
|
||||
return XZ_OK;
|
||||
{
|
||||
uint8_t props_byte = b->in[b->in_pos++];
|
||||
uint32_t lc, lp, pb;
|
||||
|
||||
--s->compressed;
|
||||
|
||||
if (props_byte >= 9 * 5 * 5)
|
||||
return XZ_DATA_ERROR;
|
||||
|
||||
lc = props_byte % 9;
|
||||
props_byte /= 9;
|
||||
lp = props_byte % 5;
|
||||
pb = props_byte / 5;
|
||||
|
||||
if (lc + lp > 4)
|
||||
return XZ_DATA_ERROR;
|
||||
|
||||
s->lzma.lc = lc;
|
||||
s->lzma.literal_pos_mask = (1U << lp) - 1;
|
||||
s->lzma.pos_mask = (1U << pb) - 1;
|
||||
s->need_props = 0;
|
||||
}
|
||||
s->sequence = SEQ_LZMA2_LZMA_PREPARE;
|
||||
break;
|
||||
|
||||
case SEQ_LZMA2_LZMA_PREPARE:
|
||||
if (s->need_lzma_init) {
|
||||
lzma_reset(&s->lzma);
|
||||
rc_reset(&s->lzma.rc);
|
||||
s->need_lzma_init = 0;
|
||||
}
|
||||
|
||||
if (!rc_read_init(&s->lzma.rc, b))
|
||||
return XZ_OK;
|
||||
|
||||
s->compressed -= 5;
|
||||
s->match_len = 0;
|
||||
s->sequence = SEQ_LZMA2_LZMA_RUN;
|
||||
break;
|
||||
|
||||
case SEQ_LZMA2_LZMA_RUN: {
|
||||
size_t in_avail;
|
||||
|
||||
dict_limit(&s->dict, s->uncompressed);
|
||||
|
||||
in_avail = min_t(size_t, b->in_size - b->in_pos, s->compressed);
|
||||
|
||||
if (!lzma_decode_loop(s, b, in_avail))
|
||||
return XZ_DATA_ERROR;
|
||||
|
||||
{
|
||||
uint32_t produced = dict_flush(&s->dict, b);
|
||||
s->uncompressed -= produced;
|
||||
}
|
||||
|
||||
if (s->uncompressed == 0) {
|
||||
/* Chunk complete. Compressed may still have trailing
|
||||
* bytes from the range coder (up to 5). Skip them. */
|
||||
s->sequence = SEQ_LZMA2_CONTROL;
|
||||
break;
|
||||
}
|
||||
|
||||
if (b->out_pos == b->out_size
|
||||
|| (b->in_pos == b->in_size && s->compressed > 0))
|
||||
return XZ_OK;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case SEQ_LZMA2_COPY:
|
||||
dict_limit(&s->dict, s->uncompressed);
|
||||
dict_uncompressed(&s->dict, b, &s->compressed);
|
||||
{
|
||||
uint32_t produced = dict_flush(&s->dict, b);
|
||||
s->uncompressed -= produced;
|
||||
}
|
||||
|
||||
if (s->uncompressed == 0) {
|
||||
s->sequence = SEQ_LZMA2_CONTROL;
|
||||
break;
|
||||
}
|
||||
|
||||
if (b->in_pos == b->in_size || b->out_pos == b->out_size)
|
||||
return XZ_OK;
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
return XZ_DATA_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void xz_dec_lzma2_end(struct xz_dec_lzma2 *s)
|
||||
{
|
||||
if (s != NULL) {
|
||||
if (s->dict.mode != XZ_SINGLE)
|
||||
free(s->dict.buf);
|
||||
free(s);
|
||||
}
|
||||
}
|
||||
652
third_party/xz-embedded/xz_dec_stream.c
vendored
Normal file
652
third_party/xz-embedded/xz_dec_stream.c
vendored
Normal file
@@ -0,0 +1,652 @@
|
||||
/*
|
||||
* XZ decompressor - Stream decoder
|
||||
*
|
||||
* Based on xz-embedded by Lasse Collin (public domain).
|
||||
*
|
||||
* This parses the XZ container format: stream header, block headers,
|
||||
* index, and stream footer. Actual data decompression is delegated
|
||||
* to the LZMA2 decoder.
|
||||
*/
|
||||
|
||||
#include "xz_private.h"
|
||||
|
||||
/* Sizes of the stream header and footer fields */
|
||||
#define STREAM_HEADER_SIZE 12
|
||||
#define HEADER_MAGIC_SIZE 6
|
||||
#define FOOTER_MAGIC_SIZE 2
|
||||
|
||||
/*
|
||||
* Supported check types. We accept None, CRC32, CRC64, and SHA-256
|
||||
* (though SHA-256 is not verified -- we just skip those bytes).
|
||||
*/
|
||||
#define CHECK_NONE 0x00
|
||||
#define CHECK_CRC32 0x01
|
||||
#define CHECK_CRC64 0x04
|
||||
#define CHECK_SHA256 0x0A
|
||||
|
||||
/* Sizes of the integrity check fields */
|
||||
static const uint8_t check_sizes[16] = {
|
||||
0, 4, 4, 4,
|
||||
8, 8, 8, 16,
|
||||
16, 16, 32, 32,
|
||||
32, 64, 64, 64
|
||||
};
|
||||
|
||||
/* Maximum block header size (encoded in the first byte as (real_size / 4) - 1) */
|
||||
#define BLOCK_HEADER_SIZE_MAX 1024
|
||||
|
||||
/*
|
||||
* Stream decoder states. The decoder is a state machine driven
|
||||
* by xz_dec_run(), consuming input and producing output as it
|
||||
* transitions through these states.
|
||||
*/
|
||||
enum xz_dec_stream_state {
|
||||
SEQ_STREAM_HEADER,
|
||||
SEQ_BLOCK_START,
|
||||
SEQ_BLOCK_HEADER,
|
||||
SEQ_BLOCK_UNCOMPRESS,
|
||||
SEQ_BLOCK_PADDING,
|
||||
SEQ_BLOCK_CHECK,
|
||||
SEQ_INDEX,
|
||||
SEQ_INDEX_PADDING,
|
||||
SEQ_INDEX_CRC32,
|
||||
SEQ_STREAM_FOOTER
|
||||
};
|
||||
|
||||
struct xz_dec {
|
||||
/* Current sequence/state in the stream decoder */
|
||||
enum xz_dec_stream_state sequence;
|
||||
|
||||
/* Position within the current sequence state */
|
||||
uint32_t pos;
|
||||
|
||||
/* Variable-length integer accumulator for index parsing */
|
||||
uint64_t vli;
|
||||
uint32_t vli_count;
|
||||
|
||||
/* Allocated operating mode */
|
||||
enum xz_mode mode;
|
||||
|
||||
/*
|
||||
* True once the stream footer has been verified; used to
|
||||
* accept stream padding between concatenated streams.
|
||||
*/
|
||||
int allow_buf_error;
|
||||
|
||||
/* CRC32 of stream flags for footer verification */
|
||||
uint32_t crc32_context;
|
||||
|
||||
/* Temporary buffer for collecting small structures */
|
||||
struct {
|
||||
uint8_t buf[BLOCK_HEADER_SIZE_MAX];
|
||||
size_t pos;
|
||||
size_t size;
|
||||
} temp;
|
||||
|
||||
/* Block state */
|
||||
struct {
|
||||
/* Uncompressed size from block header (or VLI_UNKNOWN) */
|
||||
uint64_t compressed;
|
||||
uint64_t uncompressed;
|
||||
|
||||
/* Running counts during decompression */
|
||||
uint64_t count_compressed;
|
||||
uint64_t count_uncompressed;
|
||||
|
||||
/* Size of the integrity check for this stream */
|
||||
uint32_t check_size;
|
||||
uint32_t check_type;
|
||||
|
||||
/* Hash of block sizes for index verification */
|
||||
uint64_t hash_compressed;
|
||||
uint64_t hash_uncompressed;
|
||||
uint32_t hash_count;
|
||||
} block;
|
||||
|
||||
/* Index state */
|
||||
struct {
|
||||
uint64_t compressed;
|
||||
uint64_t uncompressed;
|
||||
uint64_t size;
|
||||
uint32_t count;
|
||||
uint64_t hash_compressed;
|
||||
uint64_t hash_uncompressed;
|
||||
uint32_t hash_count;
|
||||
} index;
|
||||
|
||||
/* Check value accumulation buffer */
|
||||
struct {
|
||||
uint8_t buf[64]; /* big enough for SHA-256 */
|
||||
uint32_t pos;
|
||||
} check;
|
||||
|
||||
/* Stream flags from the stream header */
|
||||
uint32_t stream_flags;
|
||||
|
||||
/* LZMA2 decoder instance */
|
||||
struct xz_dec_lzma2 *lzma2;
|
||||
};
|
||||
|
||||
#define VLI_UNKNOWN UINT64_MAX
|
||||
#define VLI_MAX (UINT64_MAX / 2)
|
||||
#define VLI_BYTES_MAX 9
|
||||
|
||||
/*
|
||||
* Fill the temporary buffer from the input. Returns true when
|
||||
* the temp buffer is full (temp.pos == temp.size).
|
||||
*/
|
||||
static int fill_temp(struct xz_dec *s, struct xz_buf *b)
|
||||
{
|
||||
size_t copy_size = min_t(size_t,
|
||||
s->temp.size - s->temp.pos,
|
||||
b->in_size - b->in_pos);
|
||||
|
||||
memcpy(s->temp.buf + s->temp.pos, b->in + b->in_pos, copy_size);
|
||||
b->in_pos += copy_size;
|
||||
s->temp.pos += copy_size;
|
||||
|
||||
if (s->temp.pos == s->temp.size) {
|
||||
s->temp.pos = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Decode a variable-length integer (VLI). XZ VLIs use 7 bits per byte
|
||||
* with the high bit as a continuation flag. Returns XZ_STREAM_END when
|
||||
* the VLI is complete, XZ_OK when more bytes are needed.
|
||||
*/
|
||||
static enum xz_ret dec_vli(struct xz_dec *s, const uint8_t *in,
|
||||
size_t *in_pos, size_t in_size)
|
||||
{
|
||||
uint8_t byte;
|
||||
|
||||
if (s->vli_count == 0) {
|
||||
s->vli = 0;
|
||||
s->vli_count = 1;
|
||||
}
|
||||
|
||||
while (*in_pos < in_size) {
|
||||
byte = in[*in_pos];
|
||||
++(*in_pos);
|
||||
|
||||
s->vli |= (uint64_t)(byte & 0x7F) << ((s->vli_count - 1) * 7);
|
||||
|
||||
if ((byte & 0x80) == 0) {
|
||||
/* Reject non-minimal encodings */
|
||||
if (byte == 0 && s->vli_count > 1)
|
||||
return XZ_DATA_ERROR;
|
||||
s->vli_count = 0;
|
||||
return XZ_STREAM_END;
|
||||
}
|
||||
|
||||
if (s->vli_count >= VLI_BYTES_MAX)
|
||||
return XZ_DATA_ERROR;
|
||||
|
||||
++s->vli_count;
|
||||
}
|
||||
|
||||
return XZ_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Decode the stream header. It is 12 bytes:
|
||||
* 6 bytes magic, 2 bytes stream flags, 4 bytes CRC32 of flags.
|
||||
*/
|
||||
static enum xz_ret dec_stream_header(struct xz_dec *s)
|
||||
{
|
||||
uint32_t crc;
|
||||
|
||||
if (memcmp(s->temp.buf, XZ_HEADER_MAGIC, XZ_HEADER_MAGIC_SIZE) != 0)
|
||||
return XZ_FORMAT_ERROR;
|
||||
|
||||
/* Stream flags: first byte must be 0, second byte holds check type */
|
||||
if (s->temp.buf[6] != 0)
|
||||
return XZ_OPTIONS_ERROR;
|
||||
|
||||
s->stream_flags = s->temp.buf[7];
|
||||
s->block.check_type = s->stream_flags & 0x0F;
|
||||
s->block.check_size = check_sizes[s->block.check_type];
|
||||
|
||||
/* Verify CRC32 of the two stream flag bytes */
|
||||
crc = xz_crc32(s->temp.buf + 6, 2, 0);
|
||||
if (crc != get_le32(s->temp.buf + 8))
|
||||
return XZ_DATA_ERROR;
|
||||
|
||||
return XZ_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Decode a block header. The first byte gives the header size
|
||||
* (encoded as (real_size / 4) - 1). The header contains filter
|
||||
* flags; we only support a single LZMA2 filter (ID 0x21).
|
||||
*/
|
||||
static enum xz_ret dec_block_header(struct xz_dec *s)
|
||||
{
|
||||
uint32_t crc;
|
||||
size_t header_size;
|
||||
uint8_t bflags;
|
||||
size_t pos;
|
||||
uint8_t filter_id;
|
||||
uint8_t props_size;
|
||||
uint8_t lzma2_props;
|
||||
enum xz_ret ret;
|
||||
|
||||
header_size = ((uint32_t)s->temp.buf[0] + 1) * 4;
|
||||
|
||||
/* The CRC32 covers everything except the CRC32 field itself */
|
||||
crc = xz_crc32(s->temp.buf, (size_t)(header_size - 4), 0);
|
||||
if (crc != get_le32(s->temp.buf + header_size - 4))
|
||||
return XZ_DATA_ERROR;
|
||||
|
||||
bflags = s->temp.buf[1];
|
||||
|
||||
/*
|
||||
* Bits 0-1: number of filters minus 1 (we require exactly 1).
|
||||
* Bit 6: compressed size present.
|
||||
* Bit 7: uncompressed size present.
|
||||
* Other bits must be 0.
|
||||
*/
|
||||
if ((bflags & 0x03) != 0)
|
||||
return XZ_OPTIONS_ERROR; /* more than one filter */
|
||||
if (bflags & 0x3C)
|
||||
return XZ_OPTIONS_ERROR; /* reserved bits set */
|
||||
|
||||
pos = 2;
|
||||
|
||||
/* Compressed size (optional) */
|
||||
if (bflags & 0x40) {
|
||||
s->vli_count = 0;
|
||||
ret = dec_vli(s, s->temp.buf, &pos, header_size);
|
||||
if (ret != XZ_STREAM_END)
|
||||
return ret == XZ_OK ? XZ_DATA_ERROR : ret;
|
||||
s->block.compressed = s->vli;
|
||||
} else {
|
||||
s->block.compressed = VLI_UNKNOWN;
|
||||
}
|
||||
|
||||
/* Uncompressed size (optional) */
|
||||
if (bflags & 0x80) {
|
||||
s->vli_count = 0;
|
||||
ret = dec_vli(s, s->temp.buf, &pos, header_size);
|
||||
if (ret != XZ_STREAM_END)
|
||||
return ret == XZ_OK ? XZ_DATA_ERROR : ret;
|
||||
s->block.uncompressed = s->vli;
|
||||
} else {
|
||||
s->block.uncompressed = VLI_UNKNOWN;
|
||||
}
|
||||
|
||||
/* Filter flags */
|
||||
if (pos >= header_size - 4)
|
||||
return XZ_DATA_ERROR;
|
||||
|
||||
filter_id = s->temp.buf[pos++];
|
||||
if (filter_id != 0x21)
|
||||
return XZ_OPTIONS_ERROR; /* only LZMA2 supported */
|
||||
|
||||
if (pos >= header_size - 4)
|
||||
return XZ_DATA_ERROR;
|
||||
|
||||
props_size = s->temp.buf[pos++];
|
||||
if (props_size != 1)
|
||||
return XZ_OPTIONS_ERROR;
|
||||
|
||||
if (pos >= header_size - 4)
|
||||
return XZ_DATA_ERROR;
|
||||
|
||||
lzma2_props = s->temp.buf[pos++];
|
||||
|
||||
/* Remaining bytes before CRC must be zero (padding) */
|
||||
while (pos < header_size - 4) {
|
||||
if (s->temp.buf[pos++] != 0)
|
||||
return XZ_OPTIONS_ERROR;
|
||||
}
|
||||
|
||||
/* Reset LZMA2 decoder with the new properties */
|
||||
ret = xz_dec_lzma2_reset(s->lzma2, lzma2_props);
|
||||
if (ret != XZ_OK)
|
||||
return ret;
|
||||
|
||||
/* Reset block counters */
|
||||
s->block.count_compressed = 0;
|
||||
s->block.count_uncompressed = 0;
|
||||
|
||||
return XZ_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Validate the stream footer. The footer is 12 bytes:
|
||||
* 4 bytes CRC32, 4 bytes backward size, 2 bytes stream flags, 2 bytes magic.
|
||||
*/
|
||||
static enum xz_ret dec_stream_footer(struct xz_dec *s)
|
||||
{
|
||||
uint32_t crc;
|
||||
|
||||
/* Check footer magic bytes */
|
||||
if (s->temp.buf[10] != 'Y' || s->temp.buf[11] != 'Z')
|
||||
return XZ_DATA_ERROR;
|
||||
|
||||
/* CRC32 covers backward size and stream flags (bytes 4..9) */
|
||||
crc = xz_crc32(s->temp.buf + 4, 6, 0);
|
||||
if (crc != get_le32(s->temp.buf))
|
||||
return XZ_DATA_ERROR;
|
||||
|
||||
/*
|
||||
* Stream flags in the footer must match the header.
|
||||
* Byte 8 must be 0, byte 9 holds check type.
|
||||
*/
|
||||
if (s->temp.buf[8] != 0)
|
||||
return XZ_OPTIONS_ERROR;
|
||||
if (s->temp.buf[9] != (uint8_t)s->stream_flags)
|
||||
return XZ_DATA_ERROR;
|
||||
|
||||
/*
|
||||
* Backward size indicates the size of the Index field.
|
||||
* We don't verify it here in this minimal implementation.
|
||||
*/
|
||||
|
||||
return XZ_STREAM_END;
|
||||
}
|
||||
|
||||
/*
|
||||
* Main decoder loop.
|
||||
*/
|
||||
enum xz_ret xz_dec_run(struct xz_dec *s, struct xz_buf *b)
|
||||
{
|
||||
enum xz_ret ret;
|
||||
size_t copy_size;
|
||||
|
||||
/* Avoid infinite loops: if we can't make progress, return XZ_BUF_ERROR */
|
||||
size_t in_start;
|
||||
size_t out_start;
|
||||
|
||||
for (;;) {
|
||||
in_start = b->in_pos;
|
||||
out_start = b->out_pos;
|
||||
|
||||
switch (s->sequence) {
|
||||
|
||||
case SEQ_STREAM_HEADER:
|
||||
s->temp.size = STREAM_HEADER_SIZE;
|
||||
if (!fill_temp(s, b))
|
||||
return XZ_OK;
|
||||
|
||||
ret = dec_stream_header(s);
|
||||
if (ret != XZ_OK)
|
||||
return ret;
|
||||
|
||||
s->sequence = SEQ_BLOCK_START;
|
||||
break;
|
||||
|
||||
case SEQ_BLOCK_START:
|
||||
/*
|
||||
* The first byte of a block header gives its size.
|
||||
* A zero byte indicates the start of the Index.
|
||||
*/
|
||||
if (b->in_pos >= b->in_size)
|
||||
return XZ_OK;
|
||||
|
||||
/* Peek at the first byte */
|
||||
if (b->in[b->in_pos] == 0x00) {
|
||||
/* Index indicator */
|
||||
++b->in_pos;
|
||||
s->vli_count = 0;
|
||||
s->index.count = 0;
|
||||
s->index.hash_compressed = 0;
|
||||
s->index.hash_uncompressed = 0;
|
||||
s->index.hash_count = 0;
|
||||
s->index.size = 1; /* counting the 0x00 byte */
|
||||
s->crc32_context = xz_crc32((const uint8_t *)"\0", 1, 0);
|
||||
s->sequence = SEQ_INDEX;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Read the full block header into temp buffer */
|
||||
s->temp.size = ((uint32_t)b->in[b->in_pos] + 1) * 4;
|
||||
s->temp.pos = 0;
|
||||
s->sequence = SEQ_BLOCK_HEADER;
|
||||
break;
|
||||
|
||||
case SEQ_BLOCK_HEADER:
|
||||
if (!fill_temp(s, b))
|
||||
return XZ_OK;
|
||||
|
||||
ret = dec_block_header(s);
|
||||
if (ret != XZ_OK)
|
||||
return ret;
|
||||
|
||||
s->sequence = SEQ_BLOCK_UNCOMPRESS;
|
||||
break;
|
||||
|
||||
case SEQ_BLOCK_UNCOMPRESS: {
|
||||
size_t in_before = b->in_pos;
|
||||
size_t out_before = b->out_pos;
|
||||
|
||||
ret = xz_dec_lzma2_run(s->lzma2, b);
|
||||
|
||||
s->block.count_compressed += b->in_pos - in_before;
|
||||
s->block.count_uncompressed += b->out_pos - out_before;
|
||||
|
||||
if (ret == XZ_STREAM_END) {
|
||||
/* Verify sizes if they were specified in the block header */
|
||||
if (s->block.compressed != VLI_UNKNOWN &&
|
||||
s->block.count_compressed != s->block.compressed)
|
||||
return XZ_DATA_ERROR;
|
||||
|
||||
if (s->block.uncompressed != VLI_UNKNOWN &&
|
||||
s->block.count_uncompressed != s->block.uncompressed)
|
||||
return XZ_DATA_ERROR;
|
||||
|
||||
/* Accumulate for index verification */
|
||||
s->block.hash_compressed += s->block.count_compressed;
|
||||
s->block.hash_uncompressed += s->block.count_uncompressed;
|
||||
++s->block.hash_count;
|
||||
|
||||
s->pos = 0;
|
||||
s->sequence = SEQ_BLOCK_PADDING;
|
||||
break;
|
||||
}
|
||||
|
||||
if (ret != XZ_OK)
|
||||
return ret;
|
||||
|
||||
/* Check for limit violations */
|
||||
if (s->block.compressed != VLI_UNKNOWN &&
|
||||
s->block.count_compressed > s->block.compressed)
|
||||
return XZ_DATA_ERROR;
|
||||
|
||||
if (s->block.uncompressed != VLI_UNKNOWN &&
|
||||
s->block.count_uncompressed > s->block.uncompressed)
|
||||
return XZ_DATA_ERROR;
|
||||
|
||||
return XZ_OK;
|
||||
}
|
||||
|
||||
case SEQ_BLOCK_PADDING:
|
||||
/*
|
||||
* Compressed data is padded to a multiple of 4 bytes.
|
||||
* The padding bytes must be zero.
|
||||
*/
|
||||
while ((s->block.count_compressed + s->pos) & 3) {
|
||||
if (b->in_pos >= b->in_size)
|
||||
return XZ_OK;
|
||||
if (b->in[b->in_pos++] != 0)
|
||||
return XZ_DATA_ERROR;
|
||||
++s->pos;
|
||||
}
|
||||
|
||||
s->check.pos = 0;
|
||||
s->sequence = SEQ_BLOCK_CHECK;
|
||||
break;
|
||||
|
||||
case SEQ_BLOCK_CHECK:
|
||||
/*
|
||||
* We consume the check value but don't verify it
|
||||
* (a full implementation would verify CRC32/CRC64/SHA-256).
|
||||
* For CRC32 and CRC64 we could verify, but for simplicity
|
||||
* and size we skip it. The stream/index CRC32s are verified.
|
||||
*/
|
||||
copy_size = min_t(size_t,
|
||||
s->block.check_size - s->check.pos,
|
||||
b->in_size - b->in_pos);
|
||||
b->in_pos += copy_size;
|
||||
s->check.pos += (uint32_t)copy_size;
|
||||
|
||||
if (s->check.pos < s->block.check_size)
|
||||
return XZ_OK;
|
||||
|
||||
s->sequence = SEQ_BLOCK_START;
|
||||
break;
|
||||
|
||||
case SEQ_INDEX: {
|
||||
/*
|
||||
* Parse the Index. Format:
|
||||
* - Number of Records (VLI)
|
||||
* - For each record: Unpadded Size (VLI), Uncompressed Size (VLI)
|
||||
* - Padding to 4-byte boundary
|
||||
* - CRC32 of everything from the Index Indicator to padding
|
||||
*
|
||||
* We do a simplified parse: consume VLIs for count then
|
||||
* skip through the records.
|
||||
*/
|
||||
/* First VLI is the number of records */
|
||||
if (s->index.count == 0 && s->vli_count == 0) {
|
||||
/* Decode number-of-records VLI */
|
||||
ret = dec_vli(s, b->in, &b->in_pos, b->in_size);
|
||||
if (ret == XZ_OK)
|
||||
return XZ_OK;
|
||||
if (ret != XZ_STREAM_END)
|
||||
return ret;
|
||||
|
||||
s->index.count = (uint32_t)s->vli;
|
||||
s->index.hash_count = 0;
|
||||
s->pos = 0; /* sub-state: 0 = compressed VLI, 1 = uncompressed VLI */
|
||||
}
|
||||
|
||||
/* Consume records */
|
||||
while (s->index.hash_count < s->index.count) {
|
||||
s->vli_count = 0;
|
||||
ret = dec_vli(s, b->in, &b->in_pos, b->in_size);
|
||||
if (ret == XZ_OK)
|
||||
return XZ_OK;
|
||||
if (ret != XZ_STREAM_END)
|
||||
return ret;
|
||||
|
||||
if (s->pos == 0) {
|
||||
s->pos = 1;
|
||||
} else {
|
||||
s->pos = 0;
|
||||
++s->index.hash_count;
|
||||
}
|
||||
}
|
||||
|
||||
s->sequence = SEQ_INDEX_PADDING;
|
||||
s->pos = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
case SEQ_INDEX_PADDING:
|
||||
/*
|
||||
* Skip padding. We need to figure out how many bytes the
|
||||
* index consumed; for simplicity we just skip 0-3 zero bytes.
|
||||
*/
|
||||
while (b->in_pos < b->in_size && s->pos < 3) {
|
||||
if (b->in[b->in_pos] != 0)
|
||||
break;
|
||||
++b->in_pos;
|
||||
++s->pos;
|
||||
}
|
||||
/* Now read the 4-byte CRC32 */
|
||||
s->temp.size = 4;
|
||||
s->temp.pos = 0;
|
||||
s->sequence = SEQ_INDEX_CRC32;
|
||||
break;
|
||||
|
||||
case SEQ_INDEX_CRC32:
|
||||
if (!fill_temp(s, b))
|
||||
return XZ_OK;
|
||||
|
||||
/*
|
||||
* In a full implementation we'd verify the CRC32 of the
|
||||
* entire index. We skip that for size, but we do consume it.
|
||||
*/
|
||||
s->temp.size = 12; /* stream footer size */
|
||||
s->temp.pos = 0;
|
||||
s->sequence = SEQ_STREAM_FOOTER;
|
||||
break;
|
||||
|
||||
case SEQ_STREAM_FOOTER:
|
||||
if (!fill_temp(s, b))
|
||||
return XZ_OK;
|
||||
|
||||
return dec_stream_footer(s);
|
||||
|
||||
default:
|
||||
return XZ_DATA_ERROR;
|
||||
}
|
||||
|
||||
/* Detect lack of progress */
|
||||
if (b->in_pos == in_start && b->out_pos == out_start) {
|
||||
/*
|
||||
* If we switched states without consuming anything,
|
||||
* that's fine -- we'll try again. But if we've been
|
||||
* through the loop already without progress, avoid
|
||||
* spinning. The state change itself counts as progress
|
||||
* the first time through.
|
||||
*/
|
||||
if (s->allow_buf_error)
|
||||
return XZ_BUF_ERROR;
|
||||
s->allow_buf_error = 1;
|
||||
} else {
|
||||
s->allow_buf_error = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct xz_dec *xz_dec_init(enum xz_mode mode, uint32_t dict_max)
|
||||
{
|
||||
struct xz_dec *s;
|
||||
|
||||
s = (struct xz_dec *)malloc(sizeof(*s));
|
||||
if (s == NULL)
|
||||
return NULL;
|
||||
|
||||
memset(s, 0, sizeof(*s));
|
||||
|
||||
s->mode = mode;
|
||||
|
||||
s->lzma2 = xz_dec_lzma2_create(mode, dict_max);
|
||||
if (s->lzma2 == NULL) {
|
||||
free(s);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
xz_dec_reset(s);
|
||||
return s;
|
||||
}
|
||||
|
||||
void xz_dec_reset(struct xz_dec *s)
|
||||
{
|
||||
s->sequence = SEQ_STREAM_HEADER;
|
||||
s->allow_buf_error = 0;
|
||||
s->pos = 0;
|
||||
s->vli_count = 0;
|
||||
|
||||
memset(&s->block, 0, sizeof(s->block));
|
||||
memset(&s->index, 0, sizeof(s->index));
|
||||
memset(&s->check, 0, sizeof(s->check));
|
||||
memset(&s->temp, 0, sizeof(s->temp));
|
||||
|
||||
s->stream_flags = 0;
|
||||
s->crc32_context = 0;
|
||||
}
|
||||
|
||||
void xz_dec_end(struct xz_dec *s)
|
||||
{
|
||||
if (s != NULL) {
|
||||
xz_dec_lzma2_end(s->lzma2);
|
||||
free(s);
|
||||
}
|
||||
}
|
||||
116
third_party/xz-embedded/xz_lzma2.h
vendored
Normal file
116
third_party/xz-embedded/xz_lzma2.h
vendored
Normal file
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
* LZMA2 decoder - Internal constants and structures
|
||||
*
|
||||
* Based on xz-embedded by Lasse Collin (public domain).
|
||||
*/
|
||||
|
||||
#ifndef XZ_LZMA2_H
|
||||
#define XZ_LZMA2_H
|
||||
|
||||
#include "xz_private.h"
|
||||
|
||||
/* Range coder constants */
|
||||
#define RC_SHIFT_BITS 8
|
||||
#define RC_TOP_BITS 24
|
||||
#define RC_TOP_VALUE (1U << RC_TOP_BITS)
|
||||
#define RC_BIT_MODEL_TOTAL_BITS 11
|
||||
#define RC_BIT_MODEL_TOTAL (1 << RC_BIT_MODEL_TOTAL_BITS)
|
||||
#define RC_MOVE_BITS 5
|
||||
|
||||
/*
|
||||
* Maximum number of position bits (lp + pb combined).
|
||||
* LZMA uses up to 4 position bits.
|
||||
*/
|
||||
#define POS_STATES_MAX (1 << 4)
|
||||
|
||||
/*
|
||||
* The LZMA state machine has 12 states. States 0-6 indicate that the
|
||||
* previous output was a literal; states 7-11 indicate a match/rep.
|
||||
*/
|
||||
#define STATES 12
|
||||
|
||||
/* Special state values */
|
||||
#define LIT_STATES 7
|
||||
|
||||
/* Match length constants */
|
||||
#define MATCH_LEN_MIN 2
|
||||
#define LEN_LOW_BITS 3
|
||||
#define LEN_LOW_SYMBOLS (1 << LEN_LOW_BITS)
|
||||
#define LEN_MID_BITS 3
|
||||
#define LEN_MID_SYMBOLS (1 << LEN_MID_BITS)
|
||||
#define LEN_HIGH_BITS 8
|
||||
#define LEN_HIGH_SYMBOLS (1 << LEN_HIGH_BITS)
|
||||
|
||||
/* Total number of match length probabilities */
|
||||
#define LEN_SYMBOLS (LEN_LOW_SYMBOLS + LEN_MID_SYMBOLS + LEN_HIGH_SYMBOLS)
|
||||
|
||||
/* Distance slots */
|
||||
#define DIST_STATES 4
|
||||
#define DIST_SLOT_BITS 6
|
||||
#define DIST_SLOTS (1 << DIST_SLOT_BITS)
|
||||
#define DIST_MODEL_START 4
|
||||
#define DIST_MODEL_END 14
|
||||
#define FULL_DISTANCES (1 << (DIST_MODEL_END / 2))
|
||||
|
||||
/* Alignment bits for distance decoding */
|
||||
#define ALIGN_BITS 4
|
||||
#define ALIGN_SIZE (1 << ALIGN_BITS)
|
||||
#define ALIGN_MASK (ALIGN_SIZE - 1)
|
||||
|
||||
/* Total number of LZMA probability variables */
|
||||
#define PROBS_SIZE_LIT(lc) (3U << (lc))
|
||||
|
||||
/* Literal coder */
|
||||
#define LITERAL_CODERS_MAX (1 << 4) /* max lc = 4 */
|
||||
|
||||
/* LZMA2 control byte values */
|
||||
#define LZMA2_CONTROL_LZMA 0x80
|
||||
#define LZMA2_CONTROL_COPY_NO_RESET 0x01
|
||||
#define LZMA2_CONTROL_COPY_RESET 0x02
|
||||
|
||||
/*
|
||||
* lzma_state_is_literal: Returns true if the given LZMA state indicates
|
||||
* that the previous symbol was a literal.
|
||||
*/
|
||||
static inline int lzma_state_is_literal(uint32_t state)
|
||||
{
|
||||
return state < LIT_STATES;
|
||||
}
|
||||
|
||||
/*
|
||||
* State transitions after different symbol types.
|
||||
*/
|
||||
static inline uint32_t lzma_state_literal(uint32_t state)
|
||||
{
|
||||
if (state <= 3)
|
||||
return 0;
|
||||
if (state <= 9)
|
||||
return state - 3;
|
||||
return state - 6;
|
||||
}
|
||||
|
||||
static inline uint32_t lzma_state_match(uint32_t state)
|
||||
{
|
||||
return state < LIT_STATES ? 7 : 10;
|
||||
}
|
||||
|
||||
static inline uint32_t lzma_state_long_rep(uint32_t state)
|
||||
{
|
||||
return state < LIT_STATES ? 8 : 11;
|
||||
}
|
||||
|
||||
static inline uint32_t lzma_state_short_rep(uint32_t state)
|
||||
{
|
||||
return state < LIT_STATES ? 9 : 11;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the distance state (0..3) from the match length.
|
||||
*/
|
||||
static inline uint32_t lzma_get_dist_state(uint32_t len)
|
||||
{
|
||||
return len < DIST_STATES + MATCH_LEN_MIN
|
||||
? len - MATCH_LEN_MIN : DIST_STATES - 1;
|
||||
}
|
||||
|
||||
#endif /* XZ_LZMA2_H */
|
||||
55
third_party/xz-embedded/xz_private.h
vendored
Normal file
55
third_party/xz-embedded/xz_private.h
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* XZ decompressor - Private/internal header
|
||||
*
|
||||
* Based on xz-embedded by Lasse Collin (public domain).
|
||||
*/
|
||||
|
||||
#ifndef XZ_PRIVATE_H
|
||||
#define XZ_PRIVATE_H
|
||||
|
||||
#include "xz.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
/* Six-byte magic at the start of every .xz stream: 0xFD, '7', 'z', 'X', 'Z', 0x00 */
|
||||
#define XZ_HEADER_MAGIC "\3757zXZ\0"
|
||||
#define XZ_HEADER_MAGIC_SIZE 6
|
||||
|
||||
/* Two-byte magic in stream footer: 'Y', 'Z' */
|
||||
#define XZ_FOOTER_MAGIC "YZ"
|
||||
#define XZ_FOOTER_MAGIC_SIZE 2
|
||||
|
||||
#ifndef min_t
|
||||
#define min_t(type, a, b) ((type)(a) < (type)(b) ? (type)(a) : (type)(b))
|
||||
#endif
|
||||
|
||||
#ifndef max_t
|
||||
#define max_t(type, a, b) ((type)(a) > (type)(b) ? (type)(a) : (type)(b))
|
||||
#endif
|
||||
|
||||
/* Get an unaligned 32-bit little-endian value */
|
||||
static inline uint32_t get_le32(const uint8_t *buf)
|
||||
{
|
||||
return (uint32_t)buf[0]
|
||||
| ((uint32_t)buf[1] << 8)
|
||||
| ((uint32_t)buf[2] << 16)
|
||||
| ((uint32_t)buf[3] << 24);
|
||||
}
|
||||
|
||||
/* CRC lookup tables */
|
||||
extern uint32_t xz_crc32_table[256];
|
||||
extern uint64_t xz_crc64_table[256];
|
||||
|
||||
/* CRC functions */
|
||||
uint32_t xz_crc32(const uint8_t *buf, size_t size, uint32_t crc);
|
||||
uint64_t xz_crc64(const uint8_t *buf, size_t size, uint64_t crc);
|
||||
|
||||
/* LZMA2 decoder */
|
||||
struct xz_dec_lzma2;
|
||||
|
||||
struct xz_dec_lzma2 *xz_dec_lzma2_create(enum xz_mode mode, uint32_t dict_max);
|
||||
enum xz_ret xz_dec_lzma2_run(struct xz_dec_lzma2 *s, struct xz_buf *b);
|
||||
enum xz_ret xz_dec_lzma2_reset(struct xz_dec_lzma2 *s, uint8_t props);
|
||||
void xz_dec_lzma2_end(struct xz_dec_lzma2 *s);
|
||||
|
||||
#endif /* XZ_PRIVATE_H */
|
||||
Reference in New Issue
Block a user