5 Commits

Author SHA1 Message Date
dranke 629c5fce7d optimize c_unpacker state update a bit, add -b flag to --help 2022-09-09 19:10:31 +02:00
dranke a205473ad6 slight optimization 2022-09-09 08:32:03 +02:00
dranke 4903ac3786 c unpacker now works 2022-09-09 00:47:33 +02:00
dranke f817dc9254 first try of c decompressor, not working yet 2022-09-08 23:42:03 +02:00
dranke d93aec186c add compressed_size function 2022-06-19 23:08:47 +02:00
7 changed files with 158 additions and 3 deletions
+5
View File
@@ -0,0 +1,5 @@
unpack
unpack_bitstream
unpack_debug
*.upk
+10
View File
@@ -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
+25
View File
@@ -0,0 +1,25 @@
#include <stdio.h>
#include <stdlib.h>
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;
}
+4
View File
@@ -0,0 +1,4 @@
a very simple unpacker in c, as a reference for people wanting to implement their own unpacker.
absolutely not production ready, it makes no effort to ensure the output buffer can actually
hold the uncompressed data.
!!! Never run on untrusted input !!!
+99
View File
@@ -0,0 +1,99 @@
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;
int tmp = prob;
if(!bit) {
tmp = 256 - tmp;
}
upkr_state = tmp * (upkr_state >> 8) + (upkr_state & 255);
tmp += (256 - tmp + 8) >> 4;
if(!bit) {
upkr_state -= prob;
tmp = 256 - tmp;
}
upkr_probs[context_index] = tmp;
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--) {
*write_ptr = write_ptr[-offset];
++write_ptr;
}
prev_was_match = 1;
} else {
int byte = 1;
while(byte < 256) {
int bit = upkr_decode_bit(byte);
byte = (byte << 1) + bit;
}
*write_ptr++ = byte;
prev_was_match = 0;
}
}
return write_ptr - (u8*)destination;
}
+9
View File
@@ -21,3 +21,12 @@ pub fn pack(
parsing_packer::pack(data, level, use_bitstream, progress_callback)
}
}
pub fn compressed_size(mut data: &[u8]) -> f32 {
let mut state = 0;
while state < 4096 {
state = (state << 8) | data[0] as u32;
data = &data[1..];
}
data.len() as f32 + (state as f32).log2() / 8.
}
+5 -2
View File
@@ -58,7 +58,10 @@ fn main() -> Result<()> {
fn print_help() {
eprintln!("Usage:");
eprintln!(" upkr pack [-l level(0-9)] <infile> <outfile>");
eprintln!(" upkr unpack <infile> <outfile>");
eprintln!(" upkr pack [-b] [-l level(0-9)] <infile> <outfile>");
eprintln!(" upkr unpack [-b] <infile> <outfile>");
eprintln!();
eprintln!(" -b, --bitstream bitstream mode");
eprintln!(" -l, --level N compression level 0-9");
std::process::exit(1);
}