/* * Copyright (c) 2005-2017 Magnus Lind. * * This software is provided 'as-is', without any express or implied warranty. * In no event will the authors be held liable for any damages arising from * the use of this software. * * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * * 1. The origin of this software must not be misrepresented * you must not * claim that you wrote the original software. If you use this software in a * product, an acknowledgment in the product documentation would be * appreciated but is not required. * * 2. Altered source versions must be plainly marked as such, and must not * be misrepresented as being the original software. * * 3. This notice may not be removed or altered from any distribution. * * 4. The names of this software and/or it's copyright holders may not be * used to endorse or promote products derived from this software without * specific prior written permission. */ /** * This decompressor decompresses files that have been compressed * using the raw sub-sub command with the -b (not default) and -P39 * (default) setting of the raw command. */ #include "exodecr.h" static unsigned short int base[52]; static char bits[52]; static unsigned char bit_buffer; static int bitbuffer_rotate(int carry) { int carry_out; /* rol */ carry_out = (bit_buffer & 0x80) != 0; bit_buffer <<= 1; if (carry) { bit_buffer |= 0x01; } return carry_out; } static unsigned char read_byte(const char **inp) { unsigned char val = *--(*inp) & 0xff; return val; } static unsigned short int read_bits(const char **inp, int bit_count) { unsigned short int bits = 0; int byte_copy = bit_count & 8; bit_count &= 7; while(bit_count-- > 0) { int carry = bitbuffer_rotate(0); if (bit_buffer == 0) { bit_buffer = read_byte(inp); carry = bitbuffer_rotate(1); } bits <<= 1; bits |= carry; } if (byte_copy != 0) { bits <<= 8; bits |= read_byte(inp); } return bits; } static void init_table(const char **inp) { int i; unsigned short int b2; for(i = 0; i < 52; ++i) { unsigned short int b1; if((i & 15) == 0) { b2 = 1; } base[i] = b2; b1 = read_bits(inp, 3); b1 |= read_bits(inp, 1) << 3; bits[i] = b1; b2 += 1 << b1; } } char * exo_decrunch(const char *in, char *out) { unsigned short int index; unsigned short int length; unsigned short int offset; char c; char literal = 1; char reuse_offset_state = 1; bit_buffer = read_byte(&in); init_table(&in); goto implicit_literal_byte; for(;;) { literal = read_bits(&in, 1); if(literal == 1) { implicit_literal_byte: /* literal byte */ length = 1; goto copy; } index = 0; while(read_bits(&in, 1) == 0) { ++index; } if(index == 16) { break; } if(index == 17) { literal = 1; length = read_byte(&in) << 8; length |= read_byte(&in); goto copy; } length = base[index]; length += read_bits(&in, bits[index]); if ((reuse_offset_state & 3) != 1 || !read_bits(&in, 1)) { switch(length) { case 1: index = read_bits(&in, 2); index += 48; break; case 2: index = read_bits(&in, 4); index += 32; break; default: index = read_bits(&in, 4); index += 16; break; } offset = base[index]; offset += read_bits(&in, bits[index]); } copy: do { --out; if(literal) { c = read_byte(&in); } else { c = out[offset]; } *out = c; } while(--length > 0); reuse_offset_state = (reuse_offset_state << 1) | literal; } return out; }