From f817dc9254d3943b0ef0519290b79eaa846b4984 Mon Sep 17 00:00:00 2001 From: Dennis Ranke Date: Thu, 8 Sep 2022 23:42:03 +0200 Subject: [PATCH] first try of c decompressor, not working yet --- c_unpacker/.gitignore | 5 +++ c_unpacker/Makefile | 10 +++++ c_unpacker/main.c | 25 +++++++++++ c_unpacker/unpack.c | 97 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 137 insertions(+) create mode 100644 c_unpacker/.gitignore create mode 100644 c_unpacker/Makefile create mode 100644 c_unpacker/main.c create mode 100644 c_unpacker/unpack.c diff --git a/c_unpacker/.gitignore b/c_unpacker/.gitignore new file mode 100644 index 0000000..1251f15 --- /dev/null +++ b/c_unpacker/.gitignore @@ -0,0 +1,5 @@ +unpack +unpack_bitstream +unpack_debug +*.upk + diff --git a/c_unpacker/Makefile b/c_unpacker/Makefile new file mode 100644 index 0000000..0838f11 --- /dev/null +++ b/c_unpacker/Makefile @@ -0,0 +1,10 @@ +all: unpack unpack_bitstream + +unpack: main.c unpack.c + cc -O2 -o unpack main.c unpack.c + +unpack_bitstream: main.c unpack.c + cc -O2 -D UPKR_BITSTREAM -o unpack_bitstream main.c unpack.c + +unpack_debug: main.c unpack.c + cc -g -o unpack_debug main.c unpack.c diff --git a/c_unpacker/main.c b/c_unpacker/main.c new file mode 100644 index 0000000..d9d9c9a --- /dev/null +++ b/c_unpacker/main.c @@ -0,0 +1,25 @@ +#include +#include + +int upkr_unpack(void* destination, void* compressed_data); + +int main(int argn, char** argv) { + void* input_buffer = malloc(1024*1024); + void* output_buffer = malloc(1024*1024); + + FILE* in_file = fopen(argv[1], "rb"); + int in_size = fread(input_buffer, 1, 1024*1024, in_file); + fclose(in_file); + + printf("Compressed size: %d\n", in_size); + + int out_size = upkr_unpack(output_buffer, input_buffer); + + printf("Uncompressed size: %d\n", out_size); + + FILE* out_file = fopen(argv[2], "wb"); + fwrite(output_buffer, 1, out_size, out_file); + fclose(out_file); + + return 0; +} diff --git a/c_unpacker/unpack.c b/c_unpacker/unpack.c new file mode 100644 index 0000000..2318ed5 --- /dev/null +++ b/c_unpacker/unpack.c @@ -0,0 +1,97 @@ +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned long u32; + +u8* upkr_data_ptr; +u8 upkr_probs[1 + 255 + 1 + 2*32 + 2*32]; +#ifdef UPKR_BITSTREAM +u16 upkr_state; +u8 upkr_current_byte; +int upkr_bits_left; +#else +u32 upkr_state; +#endif + +int upkr_decode_bit(int context_index) { +#ifdef UPKR_BITSTREAM + while(upkr_state < 32768) { + if(upkr_bits_left == 0) { + upkr_current_byte = *upkr_data_ptr++; + upkr_bits_left = 8; + } + upkr_state = (upkr_state << 1) + (upkr_current_byte & 1); + upkr_current_byte >>= 1; + --upkr_bits_left; + } +#else + while(upkr_state < 4096) { + upkr_state = (upkr_state << 8) | *upkr_data_ptr++; + } +#endif + + int prob = upkr_probs[context_index]; + int bit = (upkr_state & 255) < prob ? 1 : 0; + + if(bit) { + upkr_state = prob * (upkr_state >> 8) + (upkr_state & 255); + upkr_probs[context_index] = prob + ((255 - prob + 8) >> 4); + } else { + upkr_state = (255 - prob) * (upkr_state >> 8) + (upkr_state & 255) - prob; + upkr_probs[context_index] = prob - ((prob + 8) >> 4); + } + + return bit; +} + +int upkr_decode_length(int context_index) { + int length = 0; + int bit_pos = 0; + while(upkr_decode_bit(context_index)) { + length |= upkr_decode_bit(context_index + 1) << bit_pos++; + context_index += 2; + } + return length | (1 << bit_pos); +} + +int upkr_unpack(void* destination, void* compressed_data) { + upkr_data_ptr = (u8*)compressed_data; + upkr_state = 0; +#ifdef UPKR_BITSTREAM + upkr_bits_left = 0; +#endif + for(int i = 0; i < sizeof(upkr_probs); ++i) + upkr_probs[i] = 128; + + u8* write_ptr = (u8*)destination; + + int prev_was_match = 0; + int offset = 0; + for(;;) { + if(upkr_decode_bit(0)) { + if(prev_was_match || upkr_decode_bit(256)) { + offset = upkr_decode_length(257) - 1; + if(offset == 0) { + break; + } + } + int length = upkr_decode_length(257 + 64); + while(length-- > 1) { + *write_ptr = write_ptr[-offset]; + ++write_ptr; + } + prev_was_match = 1; + } else { + int context_index = 1; + int byte = 0; + for(int i = 0; i < 8; ++i) { + int bit = upkr_decode_bit(context_index); + context_index = (context_index << 1) + bit; + byte |= bit << i; + } + *write_ptr++ = byte; + prev_was_match = 0; + } + } + + return write_ptr - (u8*)destination; +}