/* 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; } }