X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;ds=sidebyside;f=dehuff.c;fp=dehuff.c;h=3e0fd6c4ec86ab441ca36c921cb134d1cf842228;hb=47de6c270a336574dce220cde780a802a513d113;hp=0000000000000000000000000000000000000000;hpb=71b4fae2b31acf415c3b07a019ae252f4d128952;p=fjl diff --git a/dehuff.c b/dehuff.c new file mode 100644 index 0000000..3e0fd6c --- /dev/null +++ b/dehuff.c @@ -0,0 +1,127 @@ +#include +#include +#include + +#include "dehuff.h" + +void reliable_read(raw_input_func_t* input_func, void* userdata, uint8_t* buf, size_t len) +{ + while (len > 0) { + ssize_t bytes_read = input_func(userdata, buf, len); + assert(bytes_read <= len); + + // TODO: We need better error handling here. setjmp()/longjmp() + // should hopefully do the trick, but we need to take care for + // suspension. + if (bytes_read == (ssize_t)-1) { + fprintf(stderr, "Input function returned error\n"); + exit(1); + } + if (bytes_read == 0) { + fprintf(stderr, "Premature EOF\n"); + exit(1); + } + + buf += bytes_read; + len -= bytes_read; + } +} + +uint16_t read_length(raw_input_func_t* input_func, void* userdata) +{ + uint8_t buf[2]; + reliable_read(input_func, userdata, buf, 2); + return (buf[0] << 8) | buf[1]; +} + +void read_huffman_tables(huffman_tables_t* dst, raw_input_func_t* input_func, void* userdata) +{ + size_t len = read_length(input_func, userdata); + assert(len > 2); + len -= 2; + + // TODO: check for NULL return + uint8_t* buf = (uint8_t*)malloc(len); + uint8_t* inptr = buf; + reliable_read(input_func, userdata, buf, len); + + while (len > 0) { + unsigned char tc_th = *inptr++; + --len; + unsigned table_class = tc_th >> 4; + unsigned table_dest = tc_th & 0x0f; + + if (table_class != 0 && table_class != 1) { + fprintf(stderr, "Error: Unknown table class %u\n", table_class); + exit(1); + } + if (table_dest >= 4) { + fprintf(stderr, "Error: Unknown table destination %u\n", table_dest); + exit(1); + } + + struct huffman_table* tbl = dst[table_class][table_dest]; + if (len < 16) { + fprintf(stderr, "Short read for num_codes\n"); + exit(1); + } + for (unsigned i = 0; i < 16; ++i) { + tbl->num_codes[i] = *inptr++; + --len; + } + for (unsigned i = 0, k = 0; i < 16; ++i) { + if (len < tbl->num_codes[i]) { + fprintf(stderr, "Short read for codes\n"); + exit(1); + } + for (unsigned j = 0; j < tbl->num_codes[i]; ++j, ++k) { + tbl->codes[k] = *inptr++; + --len; + } + } + + // Generate derived tables + + // generate_size_table (figure C.1) + { + unsigned k = 0; + for (unsigned i = 0; i < 16; ++i) { + for (unsigned j = 0; j < tbl->num_codes[i]; ++j, ++k) { + tbl->huffsize[k] = i + 1; + } + } + tbl->huffsize[k] = 0; + } + + // generate_code_table (figure C.2) + unsigned si = tbl->huffsize[0]; + for (unsigned i = 0, j = 0;; ) { + tbl->huffcode[i++] = j++; + if (tbl->huffsize[i] == si) { + continue; + } + if (tbl->huffsize[i] == 0) { + break; + } + + do { + j <<= 1; + } while (++si != tbl->huffsize[i]); + } + + // decoder_tables (figure F.15) + for (unsigned i = 0, j = 0; i < 16; ++i) { + if (tbl->num_codes[i] == 0) { + tbl->maxcode[i] = -1; + continue; + } + + tbl->valptr[i] = j; + tbl->mincode[i] = tbl->huffcode[j]; + j += tbl->num_codes[i]; + tbl->maxcode[i] = tbl->huffcode[j - 1]; + } + } + + free(buf); +}