mirror of
https://github.com/SimoneN64/Kaizen.git
synced 2025-04-02 10:41:53 -04:00
984 lines
34 KiB
C
984 lines
34 KiB
C
/* Copyright 2015 the unarr project authors (see AUTHORS file).
|
|
License: LGPLv3 */
|
|
|
|
/* adapted from https://code.google.com/p/theunarchiver/source/browse/XADMaster/XADRAR30Handle.m */
|
|
/* adapted from https://code.google.com/p/theunarchiver/source/browse/XADMaster/XADRAR20Handle.m */
|
|
|
|
#include "rar.h"
|
|
|
|
static void *gSzAlloc_Alloc(ISzAllocPtr self, size_t size) { (void)self; return malloc(size); }
|
|
static void gSzAlloc_Free(ISzAllocPtr self, void *ptr) { (void)self; free(ptr); }
|
|
static ISzAlloc gSzAlloc = { gSzAlloc_Alloc, gSzAlloc_Free };
|
|
|
|
static bool br_fill(ar_archive_rar *rar, int bits)
|
|
{
|
|
uint8_t bytes[8];
|
|
int count, i;
|
|
/* read as many bits as possible */
|
|
count = (64 - rar->uncomp.br.available) / 8;
|
|
if (rar->progress.data_left < (size_t)count)
|
|
count = (int)rar->progress.data_left;
|
|
|
|
if (bits > rar->uncomp.br.available + 8 * count || ar_read(rar->super.stream, bytes, count) != (size_t)count) {
|
|
if (!rar->uncomp.br.at_eof) {
|
|
warn("Unexpected EOF during decompression (truncated file?)");
|
|
rar->uncomp.br.at_eof = true;
|
|
}
|
|
return false;
|
|
}
|
|
rar->progress.data_left -= count;
|
|
for (i = 0; i < count; i++) {
|
|
rar->uncomp.br.bits = (rar->uncomp.br.bits << 8) | bytes[i];
|
|
}
|
|
rar->uncomp.br.available += 8 * count;
|
|
return true;
|
|
}
|
|
|
|
static inline bool br_check(ar_archive_rar *rar, int bits)
|
|
{
|
|
return bits <= rar->uncomp.br.available || br_fill(rar, bits);
|
|
}
|
|
|
|
static inline uint64_t br_bits(ar_archive_rar *rar, int bits)
|
|
{
|
|
return (rar->uncomp.br.bits >> (rar->uncomp.br.available -= bits)) & (((uint64_t)1 << bits) - 1);
|
|
}
|
|
|
|
static Byte ByteIn_Read(const IByteIn *p)
|
|
{
|
|
struct ByteReader *self = (struct ByteReader *) p;
|
|
return br_check(self->rar, 8) ? (Byte)br_bits(self->rar, 8) : 0xFF;
|
|
}
|
|
|
|
static void ByteIn_CreateVTable(struct ByteReader *br, ar_archive_rar *rar)
|
|
{
|
|
br->super.Read = ByteIn_Read;
|
|
br->rar = rar;
|
|
}
|
|
|
|
static bool rar_init_uncompress(struct ar_archive_rar_uncomp *uncomp, uint8_t version)
|
|
{
|
|
/* per XADRARParser.m @handleForSolidStreamWithObject these versions are identical */
|
|
if (version == 29 || version == 36)
|
|
version = 3;
|
|
else if (version == 20 || version == 26)
|
|
version = 2;
|
|
else {
|
|
warn("Unsupported compression version: %d", version);
|
|
return false;
|
|
}
|
|
if (uncomp->version) {
|
|
if (uncomp->version != version) {
|
|
warn("Compression version mismatch: %d != %d", version, uncomp->version);
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
memset(uncomp, 0, sizeof(*uncomp));
|
|
uncomp->start_new_table = true;
|
|
if (!lzss_initialize(&uncomp->lzss, LZSS_WINDOW_SIZE)) {
|
|
warn("OOM during decompression");
|
|
return false;
|
|
}
|
|
if (version == 3) {
|
|
uncomp->state.v3.ppmd_escape = 2;
|
|
uncomp->state.v3.filters.filterstart = SIZE_MAX;
|
|
}
|
|
uncomp->version = version;
|
|
return true;
|
|
}
|
|
|
|
static void rar_free_codes(struct ar_archive_rar_uncomp *uncomp);
|
|
|
|
void rar_clear_uncompress(struct ar_archive_rar_uncomp *uncomp)
|
|
{
|
|
if (!uncomp->version)
|
|
return;
|
|
rar_free_codes(uncomp);
|
|
lzss_cleanup(&uncomp->lzss);
|
|
if (uncomp->version == 3) {
|
|
Ppmd7_Free(&uncomp->state.v3.ppmd7_context, &gSzAlloc);
|
|
rar_clear_filters(&uncomp->state.v3.filters);
|
|
}
|
|
uncomp->version = 0;
|
|
}
|
|
|
|
static int rar_read_next_symbol(ar_archive_rar *rar, struct huffman_code *code)
|
|
{
|
|
int node = 0;
|
|
|
|
if (!code->table && !rar_make_table(code))
|
|
return -1;
|
|
|
|
/* performance optimization */
|
|
if (code->tablesize <= rar->uncomp.br.available) {
|
|
uint16_t bits = (uint16_t)br_bits(rar, code->tablesize);
|
|
int length = code->table[bits].length;
|
|
int value = code->table[bits].value;
|
|
|
|
if (length < 0) {
|
|
warn("Invalid data in bitstream"); /* invalid prefix code in bitstream */
|
|
return -1;
|
|
}
|
|
if (length <= code->tablesize) {
|
|
/* Skip only length bits */
|
|
rar->uncomp.br.available += code->tablesize - length;
|
|
return value;
|
|
}
|
|
|
|
node = value;
|
|
}
|
|
|
|
while (!rar_is_leaf_node(code, node)) {
|
|
uint8_t bit;
|
|
if (!br_check(rar, 1))
|
|
return -1;
|
|
bit = (uint8_t)br_bits(rar, 1);
|
|
if (code->tree[node].branches[bit] < 0) {
|
|
warn("Invalid data in bitstream"); /* invalid prefix code in bitstream */
|
|
return -1;
|
|
}
|
|
node = code->tree[node].branches[bit];
|
|
}
|
|
|
|
return code->tree[node].branches[0];
|
|
}
|
|
|
|
/***** RAR version 2 decompression *****/
|
|
|
|
static void rar_free_codes_v2(struct ar_archive_rar_uncomp_v2 *uncomp_v2)
|
|
{
|
|
int i;
|
|
rar_free_code(&uncomp_v2->maincode);
|
|
rar_free_code(&uncomp_v2->offsetcode);
|
|
rar_free_code(&uncomp_v2->lengthcode);
|
|
for (i = 0; i < 4; i++)
|
|
rar_free_code(&uncomp_v2->audiocode[i]);
|
|
}
|
|
|
|
static bool rar_parse_codes_v2(ar_archive_rar *rar)
|
|
{
|
|
struct ar_archive_rar_uncomp_v2 *uncomp_v2 = &rar->uncomp.state.v2;
|
|
struct huffman_code precode;
|
|
uint8_t prelengths[19];
|
|
uint16_t i, count;
|
|
int j, val, n;
|
|
bool ok = false;
|
|
|
|
rar_free_codes_v2(uncomp_v2);
|
|
|
|
if (!br_check(rar, 2))
|
|
return false;
|
|
uncomp_v2->audioblock = br_bits(rar, 1) != 0;
|
|
if (!br_bits(rar, 1))
|
|
memset(uncomp_v2->lengthtable, 0, sizeof(uncomp_v2->lengthtable));
|
|
|
|
if (uncomp_v2->audioblock) {
|
|
if (!br_check(rar, 2))
|
|
return false;
|
|
uncomp_v2->numchannels = (uint8_t)br_bits(rar, 2) + 1;
|
|
count = uncomp_v2->numchannels * 257;
|
|
if (uncomp_v2->channel > uncomp_v2->numchannels)
|
|
uncomp_v2->channel = 0;
|
|
}
|
|
else
|
|
count = MAINCODE_SIZE_20 + OFFSETCODE_SIZE_20 + LENGTHCODE_SIZE_20;
|
|
|
|
for (i = 0; i < 19; i++) {
|
|
if (!br_check(rar, 4))
|
|
return false;
|
|
prelengths[i] = (uint8_t)br_bits(rar, 4);
|
|
}
|
|
|
|
memset(&precode, 0, sizeof(precode));
|
|
if (!rar_create_code(&precode, prelengths, 19))
|
|
goto PrecodeError;
|
|
for (i = 0; i < count; ) {
|
|
val = rar_read_next_symbol(rar, &precode);
|
|
if (val < 0)
|
|
goto PrecodeError;
|
|
if (val < 16) {
|
|
uncomp_v2->lengthtable[i] = (uncomp_v2->lengthtable[i] + val) & 0x0F;
|
|
i++;
|
|
}
|
|
else if (val == 16) {
|
|
if (i == 0) {
|
|
warn("Invalid data in bitstream");
|
|
goto PrecodeError;
|
|
}
|
|
if (!br_check(rar, 2))
|
|
goto PrecodeError;
|
|
n = (uint8_t)br_bits(rar, 2) + 3;
|
|
for (j = 0; j < n && i < count; i++, j++) {
|
|
uncomp_v2->lengthtable[i] = uncomp_v2->lengthtable[i - 1];
|
|
}
|
|
}
|
|
else {
|
|
if (val == 17) {
|
|
if (!br_check(rar, 3))
|
|
goto PrecodeError;
|
|
n = (uint8_t)br_bits(rar, 3) + 3;
|
|
}
|
|
else {
|
|
if (!br_check(rar, 7))
|
|
goto PrecodeError;
|
|
n = (uint8_t)br_bits(rar, 7) + 11;
|
|
}
|
|
for (j = 0; j < n && i < count; i++, j++) {
|
|
uncomp_v2->lengthtable[i] = 0;
|
|
}
|
|
}
|
|
}
|
|
ok = true;
|
|
PrecodeError:
|
|
rar_free_code(&precode);
|
|
if (!ok)
|
|
return false;
|
|
|
|
if (uncomp_v2->audioblock) {
|
|
for (i = 0; i < uncomp_v2->numchannels; i++) {
|
|
if (!rar_create_code(&uncomp_v2->audiocode[i], uncomp_v2->lengthtable + i * 257, 257))
|
|
return false;
|
|
}
|
|
}
|
|
else {
|
|
if (!rar_create_code(&uncomp_v2->maincode, uncomp_v2->lengthtable, MAINCODE_SIZE_20))
|
|
return false;
|
|
if (!rar_create_code(&uncomp_v2->offsetcode, uncomp_v2->lengthtable + MAINCODE_SIZE_20, OFFSETCODE_SIZE_20))
|
|
return false;
|
|
if (!rar_create_code(&uncomp_v2->lengthcode, uncomp_v2->lengthtable + MAINCODE_SIZE_20 + OFFSETCODE_SIZE_20, LENGTHCODE_SIZE_20))
|
|
return false;
|
|
}
|
|
|
|
rar->uncomp.start_new_table = false;
|
|
return true;
|
|
}
|
|
|
|
static uint8_t rar_decode_audio(struct AudioState *state, int8_t *channeldelta, int8_t delta)
|
|
{
|
|
uint8_t predbyte, byte;
|
|
int prederror;
|
|
|
|
state->delta[3] = state->delta[2];
|
|
state->delta[2] = state->delta[1];
|
|
state->delta[1] = state->lastdelta - state->delta[0];
|
|
state->delta[0] = state->lastdelta;
|
|
|
|
predbyte = ((8 * state->lastbyte + state->weight[0] * state->delta[0] + state->weight[1] * state->delta[1] + state->weight[2] * state->delta[2] + state->weight[3] * state->delta[3] + state->weight[4] * *channeldelta) >> 3) & 0xFF;
|
|
byte = (predbyte - delta) & 0xFF;
|
|
|
|
prederror = delta << 3;
|
|
state->error[0] += abs(prederror);
|
|
state->error[1] += abs(prederror - state->delta[0]); state->error[2] += abs(prederror + state->delta[0]);
|
|
state->error[3] += abs(prederror - state->delta[1]); state->error[4] += abs(prederror + state->delta[1]);
|
|
state->error[5] += abs(prederror - state->delta[2]); state->error[6] += abs(prederror + state->delta[2]);
|
|
state->error[7] += abs(prederror - state->delta[3]); state->error[8] += abs(prederror + state->delta[3]);
|
|
state->error[9] += abs(prederror - *channeldelta); state->error[10] += abs(prederror + *channeldelta);
|
|
|
|
*channeldelta = state->lastdelta = (int8_t)(byte - state->lastbyte);
|
|
state->lastbyte = byte;
|
|
|
|
if (!(++state->count & 0x1F)) {
|
|
uint8_t i, idx = 0;
|
|
for (i = 1; i < 11; i++) {
|
|
if (state->error[i] < state->error[idx])
|
|
idx = i;
|
|
}
|
|
memset(state->error, 0, sizeof(state->error));
|
|
|
|
switch (idx) {
|
|
case 1: if (state->weight[0] >= -16) state->weight[0]--; break;
|
|
case 2: if (state->weight[0] < 16) state->weight[0]++; break;
|
|
case 3: if (state->weight[1] >= -16) state->weight[1]--; break;
|
|
case 4: if (state->weight[1] < 16) state->weight[1]++; break;
|
|
case 5: if (state->weight[2] >= -16) state->weight[2]--; break;
|
|
case 6: if (state->weight[2] < 16) state->weight[2]++; break;
|
|
case 7: if (state->weight[3] >= -16) state->weight[3]--; break;
|
|
case 8: if (state->weight[3] < 16) state->weight[3]++; break;
|
|
case 9: if (state->weight[4] >= -16) state->weight[4]--; break;
|
|
case 10: if (state->weight[4] < 16) state->weight[4]++; break;
|
|
}
|
|
}
|
|
|
|
return byte;
|
|
}
|
|
|
|
static int64_t rar_expand_v2(ar_archive_rar *rar, int64_t end)
|
|
{
|
|
static const uint8_t lengthbases[] =
|
|
{ 0, 1, 2, 3, 4, 5, 6,
|
|
7, 8, 10, 12, 14, 16, 20,
|
|
24, 28, 32, 40, 48, 56, 64,
|
|
80, 96, 112, 128, 160, 192, 224 };
|
|
static const uint8_t lengthbits[] =
|
|
{ 0, 0, 0, 0, 0, 0, 0,
|
|
0, 1, 1, 1, 1, 2, 2,
|
|
2, 2, 3, 3, 3, 3, 4,
|
|
4, 4, 4, 5, 5, 5, 5 };
|
|
static const int32_t offsetbases[] =
|
|
{ 0, 1, 2, 3, 4, 6,
|
|
8, 12, 16, 24, 32, 48,
|
|
64, 96, 128, 192, 256, 384,
|
|
512, 768, 1024, 1536, 2048, 3072,
|
|
4096, 6144, 8192, 12288, 16384, 24576,
|
|
32768, 49152, 65536, 98304, 131072, 196608,
|
|
262144, 327680, 393216, 458752, 524288, 589824,
|
|
655360, 720896, 786432, 851968, 917504, 983040 };
|
|
static const uint8_t offsetbits[] =
|
|
{ 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4,
|
|
5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10,
|
|
11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16,
|
|
16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16 };
|
|
static const uint8_t shortbases[] =
|
|
{ 0, 4, 8, 16, 32, 64, 128, 192 };
|
|
static const uint8_t shortbits[] =
|
|
{ 2, 2, 3, 4, 5, 6, 6, 6 };
|
|
|
|
struct ar_archive_rar_uncomp_v2 *uncomp_v2 = &rar->uncomp.state.v2;
|
|
LZSS *lzss = &rar->uncomp.lzss;
|
|
int symbol, offs, len;
|
|
|
|
if ((uint64_t)end > rar->super.entry_size_uncompressed + rar->solid.size_total)
|
|
end = rar->super.entry_size_uncompressed + rar->solid.size_total;
|
|
|
|
for (;;) {
|
|
if (lzss_position(lzss) >= end)
|
|
return end;
|
|
|
|
if (uncomp_v2->audioblock) {
|
|
uint8_t byte;
|
|
symbol = rar_read_next_symbol(rar, &uncomp_v2->audiocode[uncomp_v2->channel]);
|
|
if (symbol < 0)
|
|
return -1;
|
|
if (symbol == 256) {
|
|
rar->uncomp.start_new_table = true;
|
|
return lzss_position(lzss);
|
|
}
|
|
byte = rar_decode_audio(&uncomp_v2->audiostate[uncomp_v2->channel], &uncomp_v2->channeldelta, (int8_t)(uint8_t)symbol);
|
|
uncomp_v2->channel++;
|
|
if (uncomp_v2->channel == uncomp_v2->numchannels)
|
|
uncomp_v2->channel = 0;
|
|
lzss_emit_literal(lzss, byte);
|
|
continue;
|
|
}
|
|
|
|
symbol = rar_read_next_symbol(rar, &uncomp_v2->maincode);
|
|
if (symbol < 0)
|
|
return -1;
|
|
if (symbol < 256) {
|
|
lzss_emit_literal(lzss, (uint8_t)symbol);
|
|
continue;
|
|
}
|
|
if (symbol == 256) {
|
|
offs = uncomp_v2->lastoffset;
|
|
len = uncomp_v2->lastlength;
|
|
}
|
|
else if (symbol <= 260) {
|
|
int idx = symbol - 256;
|
|
int lensymbol = rar_read_next_symbol(rar, &uncomp_v2->lengthcode);
|
|
offs = uncomp_v2->oldoffset[(uncomp_v2->oldoffsetindex - idx) & 0x03];
|
|
if (lensymbol < 0 || lensymbol > (int)(sizeof(lengthbases) / sizeof(lengthbases[0])) || lensymbol > (int)(sizeof(lengthbits) / sizeof(lengthbits[0]))) {
|
|
warn("Invalid data in bitstream");
|
|
return -1;
|
|
}
|
|
len = lengthbases[lensymbol] + 2;
|
|
if (lengthbits[lensymbol] > 0) {
|
|
if (!br_check(rar, lengthbits[lensymbol]))
|
|
return -1;
|
|
len += (uint8_t)br_bits(rar, lengthbits[lensymbol]);
|
|
}
|
|
if (offs >= 0x40000)
|
|
len++;
|
|
if (offs >= 0x2000)
|
|
len++;
|
|
if (offs >= 0x101)
|
|
len++;
|
|
}
|
|
else if (symbol <= 268) {
|
|
int idx = symbol - 261;
|
|
offs = shortbases[idx] + 1;
|
|
if (shortbits[idx] > 0) {
|
|
if (!br_check(rar, shortbits[idx]))
|
|
return -1;
|
|
offs += (uint8_t)br_bits(rar, shortbits[idx]);
|
|
}
|
|
len = 2;
|
|
}
|
|
else if (symbol == 269) {
|
|
rar->uncomp.start_new_table = true;
|
|
return lzss_position(lzss);
|
|
}
|
|
else {
|
|
int idx = symbol - 270;
|
|
int offssymbol;
|
|
if (idx > (int)(sizeof(lengthbases) / sizeof(lengthbases[0])) || idx > (int)(sizeof(lengthbits) / sizeof(lengthbits[0]))) {
|
|
warn("Invalid data in bitstream");
|
|
return -1;
|
|
}
|
|
len = lengthbases[idx] + 3;
|
|
if (lengthbits[idx] > 0) {
|
|
if (!br_check(rar, lengthbits[idx]))
|
|
return -1;
|
|
len += (uint8_t)br_bits(rar, lengthbits[idx]);
|
|
}
|
|
offssymbol = rar_read_next_symbol(rar, &uncomp_v2->offsetcode);
|
|
if (offssymbol < 0 || offssymbol > (int)(sizeof(offsetbases) / sizeof(offsetbases[0])) || offssymbol > (int)(sizeof(offsetbits) / sizeof(offsetbits[0]))) {
|
|
warn("Invalid data in bitstream");
|
|
return -1;
|
|
}
|
|
offs = offsetbases[offssymbol] + 1;
|
|
if (offsetbits[offssymbol] > 0) {
|
|
if (!br_check(rar, offsetbits[offssymbol]))
|
|
return -1;
|
|
offs += (int)br_bits(rar, offsetbits[offssymbol]);
|
|
}
|
|
if (offs >= 0x40000)
|
|
len++;
|
|
if (offs >= 0x2000)
|
|
len++;
|
|
}
|
|
|
|
uncomp_v2->lastoffset = uncomp_v2->oldoffset[uncomp_v2->oldoffsetindex++ & 0x03] = offs;
|
|
uncomp_v2->lastlength = len;
|
|
|
|
lzss_emit_match(lzss, offs, len);
|
|
}
|
|
}
|
|
|
|
/***** RAR version 3 decompression *****/
|
|
|
|
static void rar_free_codes(struct ar_archive_rar_uncomp *uncomp)
|
|
{
|
|
struct ar_archive_rar_uncomp_v3 *uncomp_v3 = &uncomp->state.v3;
|
|
|
|
if (uncomp->version == 2) {
|
|
rar_free_codes_v2(&uncomp->state.v2);
|
|
return;
|
|
}
|
|
|
|
rar_free_code(&uncomp_v3->maincode);
|
|
rar_free_code(&uncomp_v3->offsetcode);
|
|
rar_free_code(&uncomp_v3->lowoffsetcode);
|
|
rar_free_code(&uncomp_v3->lengthcode);
|
|
}
|
|
|
|
static bool rar_parse_codes(ar_archive_rar *rar)
|
|
{
|
|
struct ar_archive_rar_uncomp_v3 *uncomp_v3 = &rar->uncomp.state.v3;
|
|
|
|
if (rar->uncomp.version == 2)
|
|
return rar_parse_codes_v2(rar);
|
|
|
|
rar_free_codes(&rar->uncomp);
|
|
|
|
br_clear_leftover_bits(&rar->uncomp);
|
|
|
|
if (!br_check(rar, 1))
|
|
return false;
|
|
uncomp_v3->is_ppmd_block = br_bits(rar, 1) != 0;
|
|
if (uncomp_v3->is_ppmd_block) {
|
|
uint8_t ppmd_flags;
|
|
uint32_t max_alloc = 0;
|
|
|
|
if (!br_check(rar, 7))
|
|
return false;
|
|
ppmd_flags = (uint8_t)br_bits(rar, 7);
|
|
if ((ppmd_flags & 0x20)) {
|
|
if (!br_check(rar, 8))
|
|
return false;
|
|
max_alloc = ((uint8_t)br_bits(rar, 8) + 1) << 20;
|
|
}
|
|
if ((ppmd_flags & 0x40)) {
|
|
if (!br_check(rar, 8))
|
|
return false;
|
|
uncomp_v3->ppmd_escape = (uint8_t)br_bits(rar, 8);
|
|
}
|
|
if ((ppmd_flags & 0x20)) {
|
|
uint32_t maxorder = (ppmd_flags & 0x1F) + 1;
|
|
if (maxorder == 1)
|
|
return false;
|
|
if (maxorder > 16)
|
|
maxorder = 16 + (maxorder - 16) * 3;
|
|
|
|
Ppmd7_Free(&uncomp_v3->ppmd7_context, &gSzAlloc);
|
|
Ppmd7_Construct(&uncomp_v3->ppmd7_context);
|
|
if (!Ppmd7_Alloc(&uncomp_v3->ppmd7_context, max_alloc, &gSzAlloc)) {
|
|
warn("OOM during decompression");
|
|
return false;
|
|
}
|
|
ByteIn_CreateVTable(&uncomp_v3->bytein, rar);
|
|
// We need to set the stream before calling RangeDec_Init
|
|
uncomp_v3->ppmd7_context.rc.dec.Stream = &uncomp_v3->bytein.super;
|
|
Ppmd7a_RangeDec_Init(&uncomp_v3->ppmd7_context.rc.dec);
|
|
Ppmd7_Init(&uncomp_v3->ppmd7_context, maxorder);
|
|
}
|
|
else {
|
|
if (!Ppmd7_WasAllocated(&uncomp_v3->ppmd7_context)) {
|
|
warn("Invalid data in bitstream"); /* invalid PPMd sequence */
|
|
return false;
|
|
}
|
|
Ppmd7a_RangeDec_Init(&uncomp_v3->ppmd7_context.rc.dec);
|
|
}
|
|
}
|
|
else {
|
|
struct huffman_code precode;
|
|
uint8_t bitlengths[20];
|
|
uint8_t zerocount;
|
|
int i, j, val, n;
|
|
bool ok = false;
|
|
|
|
if (!br_check(rar, 1))
|
|
return false;
|
|
if (!br_bits(rar, 1))
|
|
memset(uncomp_v3->lengthtable, 0, sizeof(uncomp_v3->lengthtable));
|
|
memset(&bitlengths, 0, sizeof(bitlengths));
|
|
for (i = 0; i < (int)sizeof(bitlengths); i++) {
|
|
if (!br_check(rar, 4))
|
|
return false;
|
|
bitlengths[i] = (uint8_t)br_bits(rar, 4);
|
|
if (bitlengths[i] == 0x0F) {
|
|
if (!br_check(rar, 4))
|
|
return false;
|
|
zerocount = (uint8_t)br_bits(rar, 4);
|
|
if (zerocount) {
|
|
for (j = 0; j < zerocount + 2 && i < (int)sizeof(bitlengths); j++) {
|
|
bitlengths[i++] = 0;
|
|
}
|
|
i--;
|
|
}
|
|
}
|
|
}
|
|
|
|
memset(&precode, 0, sizeof(precode));
|
|
if (!rar_create_code(&precode, bitlengths, sizeof(bitlengths)))
|
|
goto PrecodeError;
|
|
for (i = 0; i < HUFFMAN_TABLE_SIZE; ) {
|
|
val = rar_read_next_symbol(rar, &precode);
|
|
if (val < 0)
|
|
goto PrecodeError;
|
|
if (val < 16) {
|
|
uncomp_v3->lengthtable[i] = (uncomp_v3->lengthtable[i] + val) & 0x0F;
|
|
i++;
|
|
}
|
|
else if (val < 18) {
|
|
if (i == 0) {
|
|
warn("Invalid data in bitstream");
|
|
goto PrecodeError;
|
|
}
|
|
if (val == 16) {
|
|
if (!br_check(rar, 3))
|
|
goto PrecodeError;
|
|
n = (uint8_t)br_bits(rar, 3) + 3;
|
|
}
|
|
else {
|
|
if (!br_check(rar, 7))
|
|
goto PrecodeError;
|
|
n = (uint8_t)br_bits(rar, 7) + 11;
|
|
}
|
|
for (j = 0; j < n && i < HUFFMAN_TABLE_SIZE; i++, j++) {
|
|
uncomp_v3->lengthtable[i] = uncomp_v3->lengthtable[i - 1];
|
|
}
|
|
}
|
|
else {
|
|
if (val == 18) {
|
|
if (!br_check(rar, 3))
|
|
goto PrecodeError;
|
|
n = (uint8_t)br_bits(rar, 3) + 3;
|
|
}
|
|
else {
|
|
if (!br_check(rar, 7))
|
|
goto PrecodeError;
|
|
n = (uint8_t)br_bits(rar, 7) + 11;
|
|
}
|
|
for (j = 0; j < n && i < HUFFMAN_TABLE_SIZE; i++, j++) {
|
|
uncomp_v3->lengthtable[i] = 0;
|
|
}
|
|
}
|
|
}
|
|
ok = true;
|
|
PrecodeError:
|
|
rar_free_code(&precode);
|
|
if (!ok)
|
|
return false;
|
|
|
|
if (!rar_create_code(&uncomp_v3->maincode, uncomp_v3->lengthtable, MAINCODE_SIZE))
|
|
return false;
|
|
if (!rar_create_code(&uncomp_v3->offsetcode, uncomp_v3->lengthtable + MAINCODE_SIZE, OFFSETCODE_SIZE))
|
|
return false;
|
|
if (!rar_create_code(&uncomp_v3->lowoffsetcode, uncomp_v3->lengthtable + MAINCODE_SIZE + OFFSETCODE_SIZE, LOWOFFSETCODE_SIZE))
|
|
return false;
|
|
if (!rar_create_code(&uncomp_v3->lengthcode, uncomp_v3->lengthtable + MAINCODE_SIZE + OFFSETCODE_SIZE + LOWOFFSETCODE_SIZE, LENGTHCODE_SIZE))
|
|
return false;
|
|
}
|
|
|
|
rar->uncomp.start_new_table = false;
|
|
return true;
|
|
}
|
|
|
|
static bool rar_read_filter(ar_archive_rar *rar, bool (* decode_byte)(ar_archive_rar *rar, uint8_t *byte), int64_t *end)
|
|
{
|
|
uint8_t flags, val, *code;
|
|
uint16_t length, i;
|
|
|
|
if (!decode_byte(rar, &flags))
|
|
return false;
|
|
length = (flags & 0x07) + 1;
|
|
if (length == 7) {
|
|
if (!decode_byte(rar, &val))
|
|
return false;
|
|
length = val + 7;
|
|
}
|
|
else if (length == 8) {
|
|
if (!decode_byte(rar, &val))
|
|
return false;
|
|
length = val << 8;
|
|
if (!decode_byte(rar, &val))
|
|
return false;
|
|
length |= val;
|
|
}
|
|
|
|
code = malloc(length);
|
|
if (!code) {
|
|
warn("OOM during decompression");
|
|
return false;
|
|
}
|
|
for (i = 0; i < length; i++) {
|
|
if (!decode_byte(rar, &code[i])) {
|
|
free(code);
|
|
return false;
|
|
}
|
|
}
|
|
if (!rar_parse_filter(rar, code, length, flags)) {
|
|
free(code);
|
|
return false;
|
|
}
|
|
free(code);
|
|
|
|
if (rar->uncomp.state.v3.filters.filterstart < (size_t)*end)
|
|
*end = rar->uncomp.state.v3.filters.filterstart;
|
|
|
|
return true;
|
|
}
|
|
|
|
static inline bool rar_decode_ppmd7_symbol(struct ar_archive_rar_uncomp_v3 *uncomp_v3, Byte *symbol)
|
|
{
|
|
int value = Ppmd7a_DecodeSymbol(&uncomp_v3->ppmd7_context);
|
|
if (value < 0) {
|
|
warn("Invalid data in bitstream"); /* invalid PPMd symbol */
|
|
return false;
|
|
}
|
|
*symbol = (Byte)value;
|
|
return true;
|
|
}
|
|
|
|
static bool rar_decode_byte(ar_archive_rar *rar, uint8_t *byte)
|
|
{
|
|
if (!br_check(rar, 8))
|
|
return false;
|
|
*byte = (uint8_t)br_bits(rar, 8);
|
|
return true;
|
|
}
|
|
|
|
static bool rar_decode_ppmd7_byte(ar_archive_rar *rar, uint8_t *byte)
|
|
{
|
|
return rar_decode_ppmd7_symbol(&rar->uncomp.state.v3, byte);
|
|
}
|
|
|
|
static bool rar_handle_ppmd_sequence(ar_archive_rar *rar, int64_t *end)
|
|
{
|
|
struct ar_archive_rar_uncomp_v3 *uncomp_v3 = &rar->uncomp.state.v3;
|
|
LZSS *lzss = &rar->uncomp.lzss;
|
|
Byte sym, code, length;
|
|
int lzss_offset;
|
|
|
|
if (!rar_decode_ppmd7_symbol(uncomp_v3, &sym))
|
|
return false;
|
|
if (sym != uncomp_v3->ppmd_escape) {
|
|
lzss_emit_literal(lzss, sym);
|
|
return true;
|
|
}
|
|
|
|
if (!rar_decode_ppmd7_symbol(uncomp_v3, &code))
|
|
return false;
|
|
switch (code) {
|
|
case 0:
|
|
return rar_parse_codes(rar);
|
|
|
|
case 2:
|
|
rar->uncomp.start_new_table = true;
|
|
return true;
|
|
|
|
case 3:
|
|
return rar_read_filter(rar, rar_decode_ppmd7_byte, end);
|
|
|
|
case 4:
|
|
if (!rar_decode_ppmd7_symbol(uncomp_v3, &code))
|
|
return false;
|
|
lzss_offset = code << 16;
|
|
if (!rar_decode_ppmd7_symbol(uncomp_v3, &code))
|
|
return false;
|
|
lzss_offset |= code << 8;
|
|
if (!rar_decode_ppmd7_symbol(uncomp_v3, &code))
|
|
return false;
|
|
lzss_offset |= code;
|
|
if (!rar_decode_ppmd7_symbol(uncomp_v3, &length))
|
|
return false;
|
|
lzss_emit_match(lzss, lzss_offset + 2, length + 32);
|
|
return true;
|
|
|
|
case 5:
|
|
if (!rar_decode_ppmd7_symbol(uncomp_v3, &length))
|
|
return false;
|
|
lzss_emit_match(lzss, 1, length + 4);
|
|
return true;
|
|
|
|
default:
|
|
lzss_emit_literal(lzss, sym);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
int64_t rar_expand(ar_archive_rar *rar, int64_t end)
|
|
{
|
|
static const uint8_t lengthbases[] =
|
|
{ 0, 1, 2, 3, 4, 5, 6,
|
|
7, 8, 10, 12, 14, 16, 20,
|
|
24, 28, 32, 40, 48, 56, 64,
|
|
80, 96, 112, 128, 160, 192, 224 };
|
|
static const uint8_t lengthbits[] =
|
|
{ 0, 0, 0, 0, 0, 0, 0,
|
|
0, 1, 1, 1, 1, 2, 2,
|
|
2, 2, 3, 3, 3, 3, 4,
|
|
4, 4, 4, 5, 5, 5, 5 };
|
|
static const int32_t offsetbases[] =
|
|
{ 0, 1, 2, 3, 4, 6,
|
|
8, 12, 16, 24, 32, 48,
|
|
64, 96, 128, 192, 256, 384,
|
|
512, 768, 1024, 1536, 2048, 3072,
|
|
4096, 6144, 8192, 12288, 16384, 24576,
|
|
32768, 49152, 65536, 98304, 131072, 196608,
|
|
262144, 327680, 393216, 458752, 524288, 589824,
|
|
655360, 720896, 786432, 851968, 917504, 983040,
|
|
1048576, 1310720, 1572864, 1835008, 2097152, 2359296,
|
|
2621440, 2883584, 3145728, 3407872, 3670016, 3932160 };
|
|
static const uint8_t offsetbits[] =
|
|
{ 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4,
|
|
5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10,
|
|
11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16,
|
|
16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
|
|
18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18 };
|
|
static const uint8_t shortbases[] =
|
|
{ 0, 4, 8, 16, 32, 64, 128, 192 };
|
|
static const uint8_t shortbits[] =
|
|
{ 2, 2, 3, 4, 5, 6, 6, 6 };
|
|
|
|
struct ar_archive_rar_uncomp_v3 *uncomp_v3 = &rar->uncomp.state.v3;
|
|
LZSS *lzss = &rar->uncomp.lzss;
|
|
int symbol, offs, len, i;
|
|
|
|
if (rar->uncomp.version == 2)
|
|
return rar_expand_v2(rar, end);
|
|
|
|
for (;;) {
|
|
if (lzss_position(lzss) >= end)
|
|
return end;
|
|
|
|
if (uncomp_v3->is_ppmd_block) {
|
|
if (!rar_handle_ppmd_sequence(rar, &end))
|
|
return -1;
|
|
if (rar->uncomp.start_new_table)
|
|
return lzss_position(lzss);
|
|
continue;
|
|
}
|
|
|
|
symbol = rar_read_next_symbol(rar, &uncomp_v3->maincode);
|
|
if (symbol < 0)
|
|
return -1;
|
|
if (symbol < 256) {
|
|
lzss_emit_literal(lzss, (uint8_t)symbol);
|
|
continue;
|
|
}
|
|
if (symbol == 256) {
|
|
if (!br_check(rar, 1))
|
|
return -1;
|
|
if (!br_bits(rar, 1)) {
|
|
if (!br_check(rar, 1))
|
|
return -1;
|
|
rar->uncomp.start_new_table = br_bits(rar, 1) != 0;
|
|
return lzss_position(lzss);
|
|
}
|
|
if (!rar_parse_codes(rar))
|
|
return -1;
|
|
continue;
|
|
}
|
|
if (symbol == 257) {
|
|
if (!rar_read_filter(rar, rar_decode_byte, &end))
|
|
return -1;
|
|
continue;
|
|
}
|
|
if (symbol == 258) {
|
|
if (uncomp_v3->lastlength == 0)
|
|
continue;
|
|
offs = uncomp_v3->lastoffset;
|
|
len = uncomp_v3->lastlength;
|
|
}
|
|
else if (symbol <= 262) {
|
|
int idx = symbol - 259;
|
|
int lensymbol = rar_read_next_symbol(rar, &uncomp_v3->lengthcode);
|
|
offs = uncomp_v3->oldoffset[idx];
|
|
if (lensymbol < 0 || lensymbol > (int)(sizeof(lengthbases) / sizeof(lengthbases[0])) || lensymbol > (int)(sizeof(lengthbits) / sizeof(lengthbits[0]))) {
|
|
warn("Invalid data in bitstream");
|
|
return -1;
|
|
}
|
|
len = lengthbases[lensymbol] + 2;
|
|
if (lengthbits[lensymbol] > 0) {
|
|
if (!br_check(rar, lengthbits[lensymbol]))
|
|
return -1;
|
|
len += (uint8_t)br_bits(rar, lengthbits[lensymbol]);
|
|
}
|
|
for (i = idx; i > 0; i--)
|
|
uncomp_v3->oldoffset[i] = uncomp_v3->oldoffset[i - 1];
|
|
uncomp_v3->oldoffset[0] = offs;
|
|
}
|
|
else if (symbol <= 270) {
|
|
int idx = symbol - 263;
|
|
offs = shortbases[idx] + 1;
|
|
if (shortbits[idx] > 0) {
|
|
if (!br_check(rar, shortbits[idx]))
|
|
return -1;
|
|
offs += (uint8_t)br_bits(rar, shortbits[idx]);
|
|
}
|
|
len = 2;
|
|
for (i = 3; i > 0; i--)
|
|
uncomp_v3->oldoffset[i] = uncomp_v3->oldoffset[i - 1];
|
|
uncomp_v3->oldoffset[0] = offs;
|
|
}
|
|
else {
|
|
int idx = symbol - 271;
|
|
int offssymbol;
|
|
if (idx > (int)(sizeof(lengthbases) / sizeof(lengthbases[0])) || idx > (int)(sizeof(lengthbits) / sizeof(lengthbits[0]))) {
|
|
warn("Invalid data in bitstream");
|
|
return -1;
|
|
}
|
|
len = lengthbases[idx] + 3;
|
|
if (lengthbits[idx] > 0) {
|
|
if (!br_check(rar, lengthbits[idx]))
|
|
return -1;
|
|
len += (uint8_t)br_bits(rar, lengthbits[idx]);
|
|
}
|
|
offssymbol = rar_read_next_symbol(rar, &uncomp_v3->offsetcode);
|
|
if (offssymbol < 0 || offssymbol > (int)(sizeof(offsetbases) / sizeof(offsetbases[0])) || offssymbol > (int)(sizeof(offsetbits) / sizeof(offsetbits[0]))) {
|
|
warn("Invalid data in bitstream");
|
|
return -1;
|
|
}
|
|
offs = offsetbases[offssymbol] + 1;
|
|
if (offsetbits[offssymbol] > 0) {
|
|
if (offssymbol > 9) {
|
|
if (offsetbits[offssymbol] > 4) {
|
|
if (!br_check(rar, offsetbits[offssymbol] - 4))
|
|
return -1;
|
|
offs += (int)br_bits(rar, offsetbits[offssymbol] - 4) << 4;
|
|
}
|
|
if (uncomp_v3->numlowoffsetrepeats > 0) {
|
|
uncomp_v3->numlowoffsetrepeats--;
|
|
offs += uncomp_v3->lastlowoffset;
|
|
}
|
|
else {
|
|
int lowoffsetsymbol = rar_read_next_symbol(rar, &uncomp_v3->lowoffsetcode);
|
|
if (lowoffsetsymbol < 0)
|
|
return -1;
|
|
if (lowoffsetsymbol == 16) {
|
|
uncomp_v3->numlowoffsetrepeats = 15;
|
|
offs += uncomp_v3->lastlowoffset;
|
|
}
|
|
else {
|
|
offs += lowoffsetsymbol;
|
|
uncomp_v3->lastlowoffset = lowoffsetsymbol;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
if (!br_check(rar, offsetbits[offssymbol]))
|
|
return -1;
|
|
offs += (int)br_bits(rar, offsetbits[offssymbol]);
|
|
}
|
|
}
|
|
|
|
if (offs >= 0x40000)
|
|
len++;
|
|
if (offs >= 0x2000)
|
|
len++;
|
|
|
|
for (i = 3; i > 0; i--)
|
|
uncomp_v3->oldoffset[i] = uncomp_v3->oldoffset[i - 1];
|
|
uncomp_v3->oldoffset[0] = offs;
|
|
}
|
|
|
|
uncomp_v3->lastoffset = offs;
|
|
uncomp_v3->lastlength = len;
|
|
|
|
lzss_emit_match(lzss, offs, len);
|
|
}
|
|
}
|
|
|
|
bool rar_uncompress_part(ar_archive_rar *rar, void *buffer, size_t buffer_size)
|
|
{
|
|
struct ar_archive_rar_uncomp *uncomp = &rar->uncomp;
|
|
struct ar_archive_rar_uncomp_v3 *uncomp_v3 = NULL;
|
|
size_t end;
|
|
|
|
if (!rar_init_uncompress(uncomp, rar->entry.version))
|
|
return false;
|
|
if (uncomp->version == 3)
|
|
uncomp_v3 = &uncomp->state.v3;
|
|
|
|
for (;;) {
|
|
if (uncomp_v3 && uncomp_v3->filters.bytes_ready > 0) {
|
|
size_t count = smin(uncomp_v3->filters.bytes_ready, buffer_size);
|
|
memcpy(buffer, uncomp_v3->filters.bytes, count);
|
|
uncomp_v3->filters.bytes_ready -= count;
|
|
uncomp_v3->filters.bytes += count;
|
|
rar->progress.bytes_done += count;
|
|
buffer_size -= count;
|
|
buffer = (uint8_t *)buffer + count;
|
|
if (rar->progress.bytes_done == rar->super.entry_size_uncompressed)
|
|
goto FinishBlock;
|
|
}
|
|
else if (uncomp->bytes_ready > 0) {
|
|
int count = (int)smin(uncomp->bytes_ready, buffer_size);
|
|
lzss_copy_bytes_from_window(&uncomp->lzss, buffer, rar->progress.bytes_done + rar->solid.size_total, count);
|
|
uncomp->bytes_ready -= count;
|
|
rar->progress.bytes_done += count;
|
|
buffer_size -= count;
|
|
buffer = (uint8_t *)buffer + count;
|
|
}
|
|
if (buffer_size == 0)
|
|
return true;
|
|
|
|
if (uncomp->br.at_eof)
|
|
return false;
|
|
|
|
if (uncomp_v3 && uncomp_v3->filters.lastend == uncomp_v3->filters.filterstart) {
|
|
if (!rar_run_filters(rar))
|
|
return false;
|
|
continue;
|
|
}
|
|
|
|
FinishBlock:
|
|
if (uncomp->start_new_table && !rar_parse_codes(rar))
|
|
return false;
|
|
|
|
end = rar->progress.bytes_done + rar->solid.size_total + LZSS_WINDOW_SIZE - LZSS_OVERFLOW_SIZE;
|
|
if (uncomp_v3 && uncomp_v3->filters.filterstart < end)
|
|
end = uncomp_v3->filters.filterstart;
|
|
end = (size_t)rar_expand(rar, end);
|
|
if (end == (size_t)-1 || end < rar->progress.bytes_done + rar->solid.size_total)
|
|
return false;
|
|
uncomp->bytes_ready = end - rar->progress.bytes_done - rar->solid.size_total;
|
|
if (uncomp_v3)
|
|
uncomp_v3->filters.lastend = end;
|
|
|
|
if (uncomp_v3 && uncomp_v3->is_ppmd_block && uncomp->start_new_table)
|
|
goto FinishBlock;
|
|
}
|
|
}
|