File indexing completed on 2025-02-02 04:26:01

0001 /* Copyright 2015 the unarr project authors (see AUTHORS file).
0002    License: LGPLv3 */
0003 
0004 /* adapted from https://code.google.com/p/theunarchiver/source/browse/XADMaster/XADPrefixCode.m */
0005 
0006 #include "rar.h"
0007 
0008 bool rar_new_node(struct huffman_code *code)
0009 {
0010     if (!code->tree) {
0011         code->minlength = INT_MAX;
0012         code->maxlength = INT_MIN;
0013     }
0014     if (code->numentries + 1 >= code->capacity) {
0015         /* in my small file sample, 1024 is the value needed most often */
0016         int new_capacity = code->capacity ? code->capacity * 2 : 1024;
0017         void *new_tree = calloc(new_capacity, sizeof(*code->tree));
0018         if (!new_tree) {
0019             warn("OOM during decompression");
0020             return false;
0021         }
0022         memcpy(new_tree, code->tree, code->capacity * sizeof(*code->tree));
0023         free(code->tree);
0024         code->tree = new_tree;
0025         code->capacity = new_capacity;
0026     }
0027     code->tree[code->numentries].branches[0] = -1;
0028     code->tree[code->numentries].branches[1] = -2;
0029     code->numentries++;
0030     return true;
0031 }
0032 
0033 bool rar_add_value(struct huffman_code *code, int value, int codebits, int length)
0034 {
0035     int lastnode, bitpos, bit;
0036 
0037     free(code->table);
0038     code->table = NULL;
0039 
0040     if (length > code->maxlength)
0041         code->maxlength = length;
0042     if (length < code->minlength)
0043         code->minlength = length;
0044 
0045     lastnode = 0;
0046     for (bitpos = length - 1; bitpos >= 0; bitpos--) {
0047         bit = (codebits >> bitpos) & 1;
0048         if (rar_is_leaf_node(code, lastnode)) {
0049             warn("Invalid data in bitstream"); /* prefix found */
0050             return false;
0051         }
0052         if (code->tree[lastnode].branches[bit] < 0) {
0053             if (!rar_new_node(code))
0054                 return false;
0055             code->tree[lastnode].branches[bit] = code->numentries - 1;
0056         }
0057         lastnode = code->tree[lastnode].branches[bit];
0058     }
0059 
0060     if (code->tree[lastnode].branches[0] != -1 || code->tree[lastnode].branches[1] != -2) {
0061         warn("Invalid data in bitstream"); /* prefix found */
0062         return false;
0063     }
0064     code->tree[lastnode].branches[0] = code->tree[lastnode].branches[1] = value;
0065     return true;
0066 }
0067 
0068 bool rar_create_code(struct huffman_code *code, uint8_t *lengths, int numsymbols)
0069 {
0070     int symbolsleft = numsymbols;
0071     int codebits = 0;
0072     int i, j;
0073 
0074     if (!rar_new_node(code))
0075         return false;
0076 
0077     for (i = 1; i <= 0x0F; i++) {
0078         for (j = 0; j < numsymbols; j++) {
0079             if (lengths[j] != i)
0080                 continue;
0081             if (!rar_add_value(code, j, codebits, i))
0082                 return false;
0083             if (--symbolsleft <= 0)
0084                 return true;
0085             codebits++;
0086         }
0087         codebits <<= 1;
0088     }
0089     return true;
0090 }
0091 
0092 static bool rar_make_table_rec(struct huffman_code *code, int node, int offset, int depth, int maxdepth)
0093 {
0094     int currtablesize = 1 << (maxdepth - depth);
0095 
0096     if (node < 0 || code->numentries <= node) {
0097         warn("Invalid data in bitstream"); /* invalid location to Huffman tree specified */
0098         return false;
0099     }
0100 
0101     if (rar_is_leaf_node(code, node)) {
0102         int i;
0103         for (i = 0; i < currtablesize; i++) {
0104             code->table[offset + i].length = depth;
0105             code->table[offset + i].value = code->tree[node].branches[0];
0106         }
0107     }
0108     else if (depth == maxdepth) {
0109         code->table[offset].length = maxdepth + 1;
0110         code->table[offset].value = node;
0111     }
0112     else {
0113         if (!rar_make_table_rec(code, code->tree[node].branches[0], offset, depth + 1, maxdepth))
0114             return false;
0115         if (!rar_make_table_rec(code, code->tree[node].branches[1], offset + currtablesize / 2, depth + 1, maxdepth))
0116             return false;
0117     }
0118     return true;
0119 }
0120 
0121 bool rar_make_table(struct huffman_code *code)
0122 {
0123     if (code->minlength <= code->maxlength && code->maxlength <= 10)
0124         code->tablesize = code->maxlength;
0125     else
0126         code->tablesize = 10;
0127 
0128     code->table = calloc(1ULL << code->tablesize, sizeof(*code->table));
0129     if (!code->table) {
0130         warn("OOM during decompression");
0131         return false;
0132     }
0133 
0134     return rar_make_table_rec(code, 0, 0, 0, code->tablesize);
0135 }
0136 
0137 void rar_free_code(struct huffman_code *code)
0138 {
0139     free(code->tree);
0140     free(code->table);
0141     memset(code, 0, sizeof(*code));
0142 }