Permalink
Cannot retrieve contributors at this time
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
executable file
1728 lines (1390 sloc)
45.1 KB
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Decompiled source of the famous RNC ProPack compression tool. | |
// https://github.com/lab313ru/rnc_propack_source | |
// | |
// LICENSING (Copied verbatim from the rnc_propack_source Git repo) | |
// To make it more clear: | |
// Rob Northen knows about this project, and has no claims about it. | |
// | |
// Usage: | |
// You may use this source code in any commercial|no commercial project you want. | |
// | |
// You may even do not specify this repo's url if you want. But it would be great for me if you do that!:) | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#ifndef _countof | |
#ifndef __cplusplus | |
#define _countof(_Array) (sizeof(_Array) / sizeof(_Array[0])) | |
#else | |
extern "C++" { | |
template <typename _CountofType, size_t _SizeOfArray> char(*__countof_helper(UNALIGNED _CountofType(&_Array)[_SizeOfArray]))[_SizeOfArray]; | |
#define _countof(_Array) sizeof(*__countof_helper(_Array)) | |
} | |
#endif | |
#endif | |
typedef unsigned char uint8; | |
typedef unsigned short uint16; | |
typedef unsigned int uint32; | |
#pragma pack(push, 1) | |
typedef struct huftable_s { | |
uint32 l1; // +0 | |
uint16 l2; // +4 | |
uint32 l3; // +6 | |
uint16 bit_depth; // +A | |
} huftable_t; | |
#pragma pack(pop) | |
typedef struct vars_s { | |
uint8 quiet; | |
uint16 max_matches; | |
uint16 enc_key; | |
uint32 pack_block_size; | |
uint16 dict_size; | |
uint32 method; | |
uint32 pus_mode; | |
uint32 input_size; | |
uint32 file_size; | |
// inner | |
uint32 bytes_left; | |
uint32 packed_size; | |
uint32 processed_size; | |
uint32 v7; | |
uint32 pack_block_pos; | |
uint16 pack_token, bit_count, v11; | |
uint16 last_min_offset; | |
uint32 v17; | |
uint32 pack_block_left_size; | |
uint16 match_count; | |
uint16 match_offset; | |
uint32 v20, v21; | |
uint32 bit_buffer; | |
uint32 unpacked_size; | |
uint32 rnc_data_size; | |
uint16 unpacked_crc, unpacked_crc_real; | |
uint16 packed_crc; | |
uint32 leeway; | |
uint32 chunks_count; | |
uint8 *mem1; | |
uint8 *pack_block_start; | |
uint8 *pack_block_max; | |
uint8 *pack_block_end; | |
uint16 *mem2; | |
uint16 *mem3; | |
uint16 *mem4; | |
uint16 *mem5; | |
uint8 *decoded; | |
uint8 *window; | |
size_t read_start_offset, write_start_offset; | |
uint8 *input, *output, *temp; | |
size_t input_offset, output_offset, temp_offset; | |
uint8 tmp_crc_data[2048]; | |
huftable_t raw_table[16]; | |
huftable_t pos_table[16]; | |
huftable_t len_table[16]; | |
} vars_t; | |
#define RNC_SIGN 0x524E43 // RNC | |
#define RNC_HEADER_SIZE 0x12 | |
#define MAX_BUF_SIZE 0x100000 | |
static const uint16 crc_table[] = { | |
0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241, | |
0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440, | |
0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40, | |
0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841, | |
0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40, | |
0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41, | |
0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641, | |
0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040, | |
0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240, | |
0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441, | |
0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41, | |
0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840, | |
0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41, | |
0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40, | |
0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640, | |
0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041, | |
0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240, | |
0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441, | |
0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41, | |
0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840, | |
0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41, | |
0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40, | |
0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640, | |
0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041, | |
0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241, | |
0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440, | |
0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40, | |
0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841, | |
0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40, | |
0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41, | |
0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641, | |
0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040 | |
}; | |
static const uint8 match_count_bits_table[] = { 0x00, 0x0E, 0x08, 0x0A, 0x012, 0x013, 0x016 }; | |
static const uint8 match_count_bits_count_table[] = { 0, 4, 4, 4, 5, 5, 5 }; | |
static const uint8 match_offset_bits_table[] = { 0x00, 0x06, 0x08, 0x09, 0x15, 0x17, 0x1D, 0x1F, 0x28, 0x29, 0x2C, 0x2D, 0x38, 0x39, 0x3C, 0x3D }; | |
static const uint8 match_offset_bits_count_table[] = { 1, 3, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6 }; | |
uint8 peek_byte(uint8 *buf, size_t offset) | |
{ | |
return buf[offset]; | |
} | |
uint8 read_byte(uint8 *buf, size_t *offset) | |
{ | |
return buf[(*offset)++]; | |
} | |
void write_byte(uint8 *buf, size_t *offset, uint8 b) | |
{ | |
buf[(*offset)++] = b; | |
} | |
uint16 peek_word_be(uint8 *buf, size_t offset) | |
{ | |
uint8 b1 = peek_byte(buf, offset + 0); | |
uint8 b2 = peek_byte(buf, offset + 1); | |
return (b1 << 8) | b2; | |
} | |
uint16 read_word_be(uint8 *buf, size_t *offset) | |
{ | |
uint8 b1 = read_byte(buf, offset); | |
uint8 b2 = read_byte(buf, offset); | |
return (b1 << 8) | b2; | |
} | |
void write_word_be(uint8 *buf, size_t *offset, uint16 val) | |
{ | |
write_byte(buf, offset, (val >> 8) & 0xFF); | |
write_byte(buf, offset, (val >> 0) & 0xFF); | |
} | |
uint32 peek_dword_be(uint8 *buf, size_t offset) | |
{ | |
uint16 w1 = peek_word_be(buf, offset + 0); | |
uint16 w2 = peek_word_be(buf, offset + 2); | |
return (w1 << 16) | w2; | |
} | |
uint32 read_dword_be(uint8 *buf, size_t *offset) | |
{ | |
uint16 w1 = read_word_be(buf, offset); | |
uint16 w2 = read_word_be(buf, offset); | |
return (w1 << 16) | w2; | |
} | |
void write_dword_be(uint8 *buf, size_t *offset, uint32 val) | |
{ | |
write_word_be(buf, offset, (val >> 16)); | |
write_word_be(buf, offset, (val & 0xFFFF)); | |
} | |
void read_buf(uint8 *dest, uint8 *source, size_t *offset, int size) | |
{ | |
memmove(dest, &source[*offset], size); | |
*offset += size; | |
} | |
void write_buf(uint8 *dest, size_t *offset, uint8 *source, int size) | |
{ | |
memmove(&dest[*offset], source, size); | |
*offset += size; | |
} | |
uint16 crc_block(uint8 *buf, size_t offset, int size) | |
{ | |
uint16 crc = 0; | |
while (size--) | |
{ | |
crc ^= read_byte(buf, &offset); | |
crc = (crc >> 8) ^ crc_table[crc & 0xFF]; | |
} | |
return crc; | |
} | |
void ror_w(uint16 *x) | |
{ | |
if (*x & 1) | |
*x = 0x8000 | (*x >> 1); | |
else | |
*x >>= 1; | |
} | |
vars_t *init_vars() | |
{ | |
vars_t *v = (vars_t*)malloc(sizeof(vars_t)); | |
v->enc_key = 0; | |
v->max_matches = 0x1000; | |
v->unpacked_crc_real = 0; | |
v->pack_block_size = 0x3000; | |
v->dict_size = 0xFFFF; | |
v->method = 1; | |
v->pus_mode = 0; | |
v->read_start_offset = 0; | |
v->write_start_offset = 0; | |
v->input_offset = 0; | |
v->output_offset = 0; | |
v->temp_offset = 0; | |
memset(v->tmp_crc_data, 0, sizeof(v->tmp_crc_data)); | |
memset(v->raw_table, 0, sizeof(v->raw_table)); | |
memset(v->pos_table, 0, sizeof(v->pos_table)); | |
memset(v->len_table, 0, sizeof(v->len_table)); | |
return v; | |
} | |
void init_dicts(vars_t *v) | |
{ | |
uint16 dict_size = v->dict_size; | |
for (int i = 0; i < 0x800; ++i) | |
{ | |
v->mem2[i * 0x10 + 0x0] = dict_size; v->mem2[i * 0x10 + 0x1] = dict_size; | |
v->mem2[i * 0x10 + 0x2] = dict_size; v->mem2[i * 0x10 + 0x3] = dict_size; | |
v->mem2[i * 0x10 + 0x4] = dict_size; v->mem2[i * 0x10 + 0x5] = dict_size; | |
v->mem2[i * 0x10 + 0x6] = dict_size; v->mem2[i * 0x10 + 0x7] = dict_size; | |
v->mem2[i * 0x10 + 0x8] = dict_size; v->mem2[i * 0x10 + 0x9] = dict_size; | |
v->mem2[i * 0x10 + 0xA] = dict_size; v->mem2[i * 0x10 + 0xB] = dict_size; | |
v->mem2[i * 0x10 + 0xC] = dict_size; v->mem2[i * 0x10 + 0xD] = dict_size; | |
v->mem2[i * 0x10 + 0xE] = dict_size; v->mem2[i * 0x10 + 0xF] = dict_size; | |
v->mem3[i * 0x10 + 0x0] = dict_size; v->mem3[i * 0x10 + 0x1] = dict_size; | |
v->mem3[i * 0x10 + 0x2] = dict_size; v->mem3[i * 0x10 + 0x3] = dict_size; | |
v->mem3[i * 0x10 + 0x4] = dict_size; v->mem3[i * 0x10 + 0x5] = dict_size; | |
v->mem3[i * 0x10 + 0x6] = dict_size; v->mem3[i * 0x10 + 0x7] = dict_size; | |
v->mem3[i * 0x10 + 0x8] = dict_size; v->mem3[i * 0x10 + 0x9] = dict_size; | |
v->mem3[i * 0x10 + 0xA] = dict_size; v->mem3[i * 0x10 + 0xB] = dict_size; | |
v->mem3[i * 0x10 + 0xC] = dict_size; v->mem3[i * 0x10 + 0xD] = dict_size; | |
v->mem3[i * 0x10 + 0xE] = dict_size; v->mem3[i * 0x10 + 0xF] = dict_size; | |
} | |
for (int i = 0; i < dict_size; ++i) | |
{ | |
v->mem5[i & 0x7FFF] = 0; | |
v->mem4[i & 0x7FFF] = i; | |
} | |
v->last_min_offset = 0; | |
} | |
void update_packed_crc(vars_t *v, uint8 b) | |
{ | |
uint16 crc = v->packed_crc; | |
v->packed_crc = crc_table[(crc & 0xFF) ^ b] ^ (crc >> 8); | |
v->packed_size++; | |
} | |
void update_unpacked_crc(vars_t *v, uint8 b) | |
{ | |
uint16 crc = v->unpacked_crc; | |
v->unpacked_crc = crc_table[(crc & 0xFF) ^ b] ^ (crc >> 8); | |
v->processed_size++; | |
} | |
void write_to_output(vars_t *v, uint8 b) | |
{ | |
if (v->packed_size >= (v->file_size - RNC_HEADER_SIZE)) | |
return; | |
write_byte(v->output, &v->output_offset, b); | |
update_packed_crc(v, b); | |
} | |
uint8 read_from_input(vars_t *v) | |
{ | |
uint8 b = read_byte(v->input, &v->input_offset); | |
update_unpacked_crc(v, b); | |
return b; | |
} | |
void write_bits_m2(vars_t *v, uint16 value, int count) | |
{ | |
uint32 mask = (1 << (count - 1)); | |
while (count--) | |
{ | |
v->pack_token <<= 1; | |
if (value & mask) | |
v->pack_token++; | |
mask >>= 1; | |
v->bit_count++; | |
if (v->bit_count == 8) | |
{ | |
write_to_output(v, (v->pack_token >> 0) & 0xFF); | |
for (int i = 0; i < v->v11; ++i) | |
write_to_output(v, v->tmp_crc_data[i]); | |
v->v11 = 0; | |
if ((v->processed_size > v->packed_size) && (v->processed_size - v->packed_size > v->leeway)) | |
v->leeway = v->processed_size - v->packed_size; | |
v->bit_count = 0; | |
v->pack_token = 0; | |
} | |
} | |
} | |
void write_bits_m1(vars_t *v, uint16 value, int count) | |
{ | |
while (count--) | |
{ | |
v->pack_token >>= 1; | |
v->pack_token |= (value & 1) ? 0x8000 : 0; | |
value >>= 1; | |
v->bit_count++; | |
if (v->bit_count == 16) | |
{ | |
write_to_output(v, (v->pack_token >> 0) & 0xFF); | |
write_to_output(v, (v->pack_token >> 8) & 0xFF); | |
for (int i = 0; i < v->v11; ++i) | |
write_to_output(v, v->tmp_crc_data[i]); | |
v->v11 = 0; | |
if ((v->processed_size > v->packed_size) && (v->processed_size - v->packed_size > v->leeway)) | |
v->leeway = v->processed_size - v->packed_size; | |
v->bit_count = 0; | |
v->pack_token = 0; | |
} | |
} | |
} | |
void write_bits(vars_t *v, uint16 bits, int count) | |
{ | |
if (v->method == 2) | |
write_bits_m2(v, bits, count); | |
else | |
write_bits_m1(v, bits, count); | |
} | |
int find_matches(vars_t *v) | |
{ | |
v->match_count = 1; | |
v->match_offset = 0; | |
int match_offset = 1; | |
while (match_offset < (v->pack_block_end - v->pack_block_start) && (v->pack_block_start[match_offset] == v->pack_block_start[0])) | |
match_offset++; | |
uint16 first_word = peek_word_be(v->pack_block_start, 0); | |
uint16 offset = v->mem2[first_word & 0x7FFF]; | |
while (1) | |
{ | |
if (offset == v->dict_size) | |
{ | |
if ((v->match_count == 2) && (v->match_offset > 0x100)) | |
{ | |
v->match_count = 1; | |
v->match_offset = 0; | |
} | |
break; | |
} | |
uint16 restore = v->mem4[offset & 0x7FFF]; | |
uint16 min_offset = v->last_min_offset; | |
if (min_offset <= offset) | |
min_offset += v->dict_size; | |
min_offset -= offset; | |
if (peek_word_be(v->pack_block_start, -min_offset) == peek_word_be(v->pack_block_start, 0)) | |
{ | |
uint16 max_count = v->mem5[offset & 0x7FFF]; | |
if (max_count <= min_offset) | |
{ | |
if (max_count > match_offset) | |
{ | |
min_offset = min_offset - max_count + match_offset; | |
max_count = match_offset; | |
} | |
int max_size = v->pack_block_end - v->pack_block_start; | |
if (max_count == match_offset) | |
{ | |
while (max_count < max_size && (v->pack_block_start[max_count] == v->pack_block_start[max_count - min_offset])) | |
max_count++; | |
} | |
} | |
else | |
{ | |
min_offset = 1; | |
max_count = match_offset; | |
} | |
if (max_count > v->max_matches) | |
max_count = v->max_matches; | |
if (max_count >= v->match_count) | |
{ | |
v->match_count = max_count; | |
v->match_offset = min_offset; | |
} | |
} | |
offset = restore; | |
} | |
return 0; | |
} | |
void find_and_check_matches(vars_t *v) | |
{ | |
find_matches(v); | |
if (v->match_count >= 2) | |
{ | |
if (v->pack_block_max - v->pack_block_start >= 3) | |
{ | |
uint16 count = v->match_count; | |
uint16 offset = v->match_offset; | |
uint16 min_offset = v->last_min_offset; | |
v->last_min_offset = (v->last_min_offset + 1) % v->dict_size; | |
v->pack_block_start++; | |
find_matches(v); | |
v->pack_block_start--; | |
v->last_min_offset = min_offset; | |
if (count < v->match_count) | |
{ | |
count = 1; | |
offset = 0; | |
} | |
v->match_count = count; | |
v->match_offset = offset; | |
} | |
} | |
} | |
int bits_count(int value) | |
{ | |
int count = 1; | |
while (value >>= 1) | |
count++; | |
return count; | |
} | |
void update_bits_table(vars_t *v, huftable_t *data, uint16 bits) | |
{ | |
if (bits <= 1) | |
data[bits].l1++; | |
else | |
data[bits_count(bits)].l1++; | |
write_word_be(v->temp, &v->temp_offset, bits); | |
} | |
void encode_matches(vars_t *v, uint16 w) | |
{ | |
while (1) | |
{ | |
uint16 restore = v->mem4[v->last_min_offset & 0x7FFF]; | |
v->mem4[v->last_min_offset & 0x7FFF] = v->dict_size; | |
if (restore != v->last_min_offset) | |
{ | |
uint16 buffer_word = peek_word_be(v->pack_block_start, -v->dict_size); | |
v->mem2[buffer_word & 0x7FFF] = restore; | |
if (v->dict_size == restore) | |
v->mem3[buffer_word & 0x7FFF] = v->dict_size; | |
} | |
uint16 buffer_word = peek_word_be(v->pack_block_start, 0); | |
if (v->mem2[buffer_word & 0x7FFF] == v->dict_size) | |
v->mem2[buffer_word & 0x7FFF] = v->last_min_offset; | |
else | |
v->mem4[v->mem3[buffer_word & 0x7FFF] & 0x7FFF] = v->last_min_offset; | |
v->mem3[buffer_word & 0x7FFF] = v->last_min_offset; | |
int count = 1; | |
while ((count < (v->pack_block_end - v->pack_block_start)) && (v->pack_block_start[count] == v->pack_block_start[0])) | |
count++; | |
v->mem5[v->last_min_offset & 0x7FFF] = count; | |
while (1) | |
{ | |
v->last_min_offset = (v->last_min_offset + 1) % v->dict_size; | |
v->pack_block_start++; | |
if (!(--w)) | |
return; | |
if ((--count) <= 1) | |
break; | |
v->mem5[v->last_min_offset & 0x7FFF] = count; | |
if (v->last_min_offset != v->mem4[v->last_min_offset & 0x7FFF]) | |
{ | |
restore = v->mem4[v->last_min_offset & 0x7FFF]; | |
v->mem4[v->last_min_offset & 0x7FFF] = v->last_min_offset; | |
buffer_word = peek_word_be(v->pack_block_start, -v->dict_size); | |
v->mem2[buffer_word & 0x7FFF] = restore; | |
if (v->dict_size == restore) | |
v->mem3[buffer_word & 0x7FFF] = v->dict_size; | |
} | |
} | |
} | |
} | |
void proc_6(vars_t *v) | |
{ | |
v->v17 = 0; | |
v->pack_block_left_size = v->pack_block_size; | |
v->input_offset = v->read_start_offset + v->v7 + v->pack_block_pos; | |
v->temp_offset = 0; | |
uint32 data_length = 0; | |
while (v->bytes_left || v->pack_block_pos) | |
{ | |
uint16 size_to_read = 0xFFFF - v->dict_size - v->pack_block_pos; | |
if (v->bytes_left < size_to_read) | |
size_to_read = v->bytes_left; | |
v->pack_block_start = &v->mem1[v->dict_size]; | |
read_buf(&v->pack_block_start[v->pack_block_pos], v->input, &v->input_offset, size_to_read); | |
v->bytes_left -= size_to_read; | |
v->pack_block_pos += size_to_read; | |
v->pack_block_max = &v->pack_block_start[v->pack_block_pos]; | |
v->pack_block_end = &v->pack_block_start[v->pack_block_pos]; | |
if (v->pack_block_left_size < v->pack_block_pos) | |
v->pack_block_max = &v->pack_block_start[v->pack_block_left_size]; | |
while ((v->pack_block_start < v->pack_block_max - 1) && v->v17 < 0xFFFE) | |
{ | |
find_and_check_matches(v); | |
if (v->match_count >= 2) | |
{ | |
if (v->pack_block_start + v->match_count <= v->pack_block_max) | |
{ | |
update_bits_table(v, v->raw_table, data_length); | |
update_bits_table(v, v->pos_table, v->match_count - 2); | |
update_bits_table(v, v->len_table, v->match_offset - 1); | |
encode_matches(v, v->match_count); | |
v->v17++; | |
data_length = 0; | |
} | |
else | |
{ | |
if (v->v17 != 0) | |
break; | |
v->match_count = v->pack_block_max - v->pack_block_start; | |
} | |
} | |
else | |
{ | |
encode_matches(v, 1); | |
data_length++; | |
} | |
} | |
v->pack_block_pos = v->pack_block_end - v->pack_block_start; | |
memmove(v->mem1, &v->pack_block_start[-v->dict_size], v->dict_size + v->pack_block_pos); | |
if ((v->pack_block_max < v->pack_block_end) || ((v->pack_block_max == v->pack_block_end) && !v->bytes_left) || v->v17 == 0xFFFE) | |
break; | |
v->pack_block_left_size -= &v->pack_block_start[-v->dict_size] - v->mem1; | |
} | |
if (v->pack_block_max == v->pack_block_end && !v->bytes_left && v->v17 != 0xFFFE) | |
data_length += v->pack_block_pos; | |
update_bits_table(v, v->raw_table, data_length); | |
v->v17++; | |
v->temp_offset = 0; | |
} | |
void update_tmp_crc_data(vars_t *v, uint8 b) | |
{ | |
if (v->bit_count) | |
{ | |
v->tmp_crc_data[v->v11] = b; | |
v->v11++; | |
} | |
else | |
write_to_output(v, b); | |
} | |
void encode_matches_count(vars_t *v, int count) | |
{ | |
while (count > 0) | |
{ | |
if (count >= 12) | |
{ | |
if (count & 3) | |
{ | |
write_bits_m2(v, 0, 1); | |
uint8 b = read_from_input(v); | |
update_tmp_crc_data(v, (v->enc_key ^ b) & 0xFF); | |
count--; | |
} | |
else | |
{ | |
write_bits_m2(v, 0x17, 5); | |
if (count >= 72) | |
{ | |
write_bits_m2(v, 0xF, 4); | |
for (int i = 0; i < 72; ++i) | |
{ | |
uint8 b = read_from_input(v); | |
update_tmp_crc_data(v, (v->enc_key ^ b) & 0xFF); | |
} | |
count -= 72; | |
} | |
else | |
{ | |
write_bits_m2(v, (count - 12) >> 2, 4); | |
while (count--) | |
{ | |
uint8 b = read_from_input(v); | |
update_tmp_crc_data(v, (v->enc_key ^ b) & 0xFF); | |
} | |
} | |
} | |
ror_w(&v->enc_key); | |
} | |
else while (count != 0) | |
{ | |
write_bits_m2(v, 0, 1); | |
uint8 b = read_from_input(v); | |
update_tmp_crc_data(v, (v->enc_key ^ b) & 0xFF); | |
ror_w(&v->enc_key); | |
count--; | |
} | |
} | |
} | |
void clear_table(huftable_t *data, int count) | |
{ | |
for (int i = 0; i < count; ++i) | |
{ | |
data[i].l1 = 0; | |
data[i].l2 = 0xFFFF; | |
data[i].l3 = 0; | |
data[i].bit_depth = 0; | |
} | |
} | |
int proc_17(vars_t *v, huftable_t *data, int count) | |
{ | |
uint32 d6 = 0xFFFFFFFF; | |
uint32 d5 = 0xFFFFFFFF; | |
int i = 0; | |
while (i < count) | |
{ | |
if (data[i].l1) | |
{ | |
if (data[i].l1 < d5) | |
{ | |
d6 = d5; | |
v->v21 = v->v20; | |
d5 = data[i].l1; | |
v->v20 = i; | |
} | |
else if (data[i].l1 < d6) | |
{ | |
d6 = data[i].l1; | |
v->v21 = i; | |
} | |
} | |
i++; | |
} | |
return (d5 != 0xFFFFFFFF && d6 != 0xFFFFFFFF); | |
} | |
uint32 inverse_bits(uint32 value, int count) | |
{ | |
int i = 0; | |
while (count--) | |
{ | |
i <<= 1; | |
if (value & 1) | |
i |= 1; | |
value >>= 1; | |
} | |
return i; | |
} | |
void proc_20(huftable_t *data, int count) | |
{ | |
int val = 0; | |
uint32 div = 0x80000000; | |
int bits_count = 1; | |
while (bits_count <= 16) | |
{ | |
int i = 0; | |
while (1) | |
{ | |
if (i >= count) | |
{ | |
bits_count++; | |
div >>= 1; | |
break; | |
} | |
if (data[i].bit_depth == bits_count) | |
{ | |
data[i].l3 = inverse_bits(val / div, bits_count); | |
val += div; | |
} | |
i++; | |
} | |
} | |
} | |
void proc_16(vars_t *v, huftable_t *data, int count) | |
{ | |
int d4 = 0; | |
int ve = 0; | |
for (int i = 0; i < count; ++i) | |
{ | |
if (data[i].l1) | |
{ | |
d4++; | |
ve = i; | |
} | |
} | |
if (!d4) | |
return; | |
if (d4 == 1) | |
{ | |
data[ve].bit_depth++; | |
return; | |
} | |
while (proc_17(v, data, count)) | |
{ | |
data[v->v20].l1 += data[v->v21].l1; | |
data[v->v21].l1 = 0; | |
data[v->v20].bit_depth++; | |
while (data[v->v20].l2 != 0xFFFF) | |
{ | |
v->v20 = data[v->v20].l2; | |
data[v->v20].bit_depth++; | |
} | |
data[v->v20].l2 = v->v21; | |
data[v->v21].bit_depth++; | |
while (data[v->v21].l2 != 0xFFFF) | |
{ | |
v->v21 = data[v->v21].l2; | |
data[v->v21].bit_depth++; | |
} | |
} | |
proc_20(data, count); | |
} | |
void proc_18(vars_t *v, huftable_t *data, int count) | |
{ | |
int cnt = count; | |
while (cnt && !data[--cnt].bit_depth) | |
count--; | |
write_bits_m1(v, count, 5); | |
for (int i = 0; i < count; ++i) | |
write_bits_m1(v, data[i].bit_depth, 4); | |
} | |
void proc_19(vars_t *v, huftable_t *data, int count) | |
{ | |
int bits; | |
if (count > 1) | |
bits = bits_count(count); | |
else | |
bits = count; | |
write_bits_m1(v, data[bits].l3, data[bits].bit_depth); | |
if (bits > 1) | |
write_bits_m1(v, count - (1 << (bits - 1)), bits - 1); | |
} | |
void compress_data_2(vars_t *v) | |
{ | |
int src_offset = v->read_start_offset; | |
while (v->v7 < v->unpacked_size) | |
{ | |
proc_6(v); | |
v->input_offset = src_offset; | |
while (v->v17--) | |
{ | |
uint32 data_length = read_word_be(v->temp, &v->temp_offset); | |
v->v7 += data_length; | |
encode_matches_count(v, data_length); | |
if (v->v17) | |
{ | |
v->match_count = read_word_be(v->temp, &v->temp_offset); | |
v->match_offset = read_word_be(v->temp, &v->temp_offset); | |
if (v->match_count) | |
{ | |
if (v->match_count >= 7) | |
{ | |
write_bits_m2(v, 0xF, 4); | |
update_tmp_crc_data(v, (v->match_count - 6) & 0xFF); | |
} | |
else | |
write_bits_m2(v, match_count_bits_table[v->match_count], match_count_bits_count_table[v->match_count]); | |
write_bits_m2(v, match_offset_bits_table[v->match_offset >> 8], match_offset_bits_count_table[v->match_offset >> 8]); | |
} | |
else | |
write_bits_m2(v, 6, 3); | |
update_tmp_crc_data(v, v->match_offset & 0xFF); | |
v->match_count += 2; | |
v->v7 += v->match_count; | |
while (v->match_count--) | |
read_from_input(v); | |
} | |
} | |
write_bits_m2(v, 0xF, 4); | |
update_tmp_crc_data(v, 0); | |
if (v->v7 >= v->unpacked_size) | |
write_bits_m2(v, 0, 1); | |
else | |
write_bits_m2(v, 1, 1); | |
if (!v->bit_count) | |
{ | |
for (int i = 0; i < v->v11; ++i) | |
write_to_output(v, v->tmp_crc_data[i]); | |
v->v11 = 0; | |
} | |
v->chunks_count++; | |
src_offset = v->input_offset; | |
} | |
v->pack_token <<= (8 - v->bit_count); | |
if (v->bit_count || v->v11) | |
write_to_output(v, v->pack_token & 0xFF); | |
} | |
void compress_data_1(vars_t *v) | |
{ | |
int src_offset = v->read_start_offset; | |
while (v->v7 < v->unpacked_size) | |
{ | |
clear_table(v->len_table, _countof(v->len_table)); | |
clear_table(v->pos_table, _countof(v->pos_table)); | |
clear_table(v->raw_table, _countof(v->raw_table)); | |
proc_6(v); | |
v->input_offset = src_offset; | |
proc_16(v, v->raw_table, _countof(v->raw_table)); | |
proc_16(v, v->len_table, _countof(v->len_table)); | |
proc_16(v, v->pos_table, _countof(v->pos_table)); | |
proc_18(v, v->raw_table, _countof(v->raw_table)); | |
proc_18(v, v->len_table, _countof(v->len_table)); | |
proc_18(v, v->pos_table, _countof(v->pos_table)); | |
write_bits_m1(v, v->v17, 16); | |
while (v->v17--) | |
{ | |
uint32 data_length = read_word_be(v->temp, &v->temp_offset); | |
v->v7 += data_length; | |
proc_19(v, v->raw_table, data_length); | |
if (data_length) | |
{ | |
while (data_length--) | |
{ | |
uint8 b = read_from_input(v); | |
if (!v->bit_count) | |
write_to_output(v, (v->enc_key ^ b) & 0xFF); | |
else | |
{ | |
v->tmp_crc_data[v->v11] = (v->enc_key ^ b) & 0xFF; | |
v->v11++; | |
} | |
} | |
ror_w(&v->enc_key); | |
} | |
if (v->v17) | |
{ | |
v->match_count = read_word_be(v->temp, &v->temp_offset); | |
v->match_offset = read_word_be(v->temp, &v->temp_offset); | |
proc_19(v, v->len_table, v->match_offset); | |
proc_19(v, v->pos_table, v->match_count); | |
v->match_count += 2; | |
v->v7 += v->match_count; | |
while (v->match_count--) | |
read_from_input(v); | |
} | |
} | |
if (!v->bit_count) | |
{ | |
for (int i = 0; i < v->v11; ++i) | |
write_to_output(v, v->tmp_crc_data[i]); | |
v->v11 = 0; | |
} | |
v->chunks_count++; | |
src_offset = v->input_offset; | |
} | |
v->pack_token >>= (16 - v->bit_count); | |
if (v->bit_count || v->v11) | |
write_to_output(v, v->pack_token & 0xFF); | |
if (v->bit_count > 8 || v->v11) | |
write_to_output(v, v->pack_token >> 8); | |
} | |
void do_pack_data(vars_t *v) | |
{ | |
v->unpacked_size = v->file_size; | |
v->packed_size = v->file_size; | |
v->bytes_left = v->file_size; | |
if (v->file_size <= RNC_HEADER_SIZE) | |
return; | |
v->unpacked_crc = 0; | |
v->packed_crc = 0; | |
v->packed_size = 0; | |
v->processed_size = 0; | |
v->v7 = 0; | |
v->pack_block_pos = 0; | |
v->pack_token = 0; | |
v->bit_count = 0; | |
v->v11 = 0; | |
v->leeway = 0; | |
v->chunks_count = 0; | |
v->mem1 = (uint8 *)malloc(0xFFFF); | |
v->mem2 = (uint16 *)malloc(0x10000); | |
v->mem3 = (uint16 *)malloc(0x10000); | |
v->mem4 = (uint16 *)malloc(0x10000); | |
v->mem5 = (uint16 *)malloc(0x10000); | |
init_dicts(v); | |
write_dword_be(v->output, &v->output_offset, (RNC_SIGN << 8) | (v->method & 0xFF)); | |
write_dword_be(v->output, &v->output_offset, v->unpacked_size); | |
write_dword_be(v->output, &v->output_offset, 0); | |
write_word_be(v->output, &v->output_offset, 0); | |
write_word_be(v->output, &v->output_offset, 0); | |
write_word_be(v->output, &v->output_offset, 0); | |
uint16 key = v->enc_key; | |
write_bits(v, 0, 1); // no lock | |
write_bits(v, (v->enc_key ? 1 : 0), 1); | |
switch (v->method) | |
{ | |
case 1: compress_data_1(v); break; | |
case 2: compress_data_2(v); | |
} | |
for (int i = 0; i < v->v11; ++i) | |
write_to_output(v, v->tmp_crc_data[i]); | |
v->v11 = 0; | |
v->enc_key = key; | |
if (v->leeway >(v->unpacked_size - v->packed_size)) | |
v->leeway -= (v->unpacked_size - v->packed_size); | |
else | |
v->leeway = 0; | |
if (v->method == 2) | |
v->leeway += 2; | |
v->packed_size = v->output_offset - v->write_start_offset; | |
v->output_offset = v->write_start_offset + 8; | |
write_dword_be(v->output, &v->output_offset, v->packed_size - RNC_HEADER_SIZE); | |
write_word_be(v->output, &v->output_offset, v->unpacked_crc); | |
write_word_be(v->output, &v->output_offset, v->packed_crc); | |
write_byte(v->output, &v->output_offset, v->leeway); | |
write_byte(v->output, &v->output_offset, v->chunks_count); | |
v->output_offset = v->packed_size + v->write_start_offset; | |
v->input_offset = v->unpacked_size + v->read_start_offset; | |
free(v->mem1); | |
free(v->mem2); | |
free(v->mem3); | |
free(v->mem4); | |
free(v->mem5); | |
} | |
int do_pack(vars_t *v) | |
{ | |
if (v->file_size <= RNC_HEADER_SIZE) | |
return 2; | |
v->input_offset = 0; | |
v->output_offset = 0; | |
if ((peek_dword_be(v->input, v->input_offset) >> 8) == RNC_SIGN) | |
return 3; | |
do_pack_data(v); | |
return 0; | |
} | |
uint8 read_source_byte(vars_t *v) | |
{ | |
if (v->pack_block_start == &v->mem1[0xFFFD]) | |
{ | |
int left_size = v->file_size - v->input_offset; | |
int size_to_read; | |
if (left_size <= 0xFFFD) | |
size_to_read = left_size; | |
else | |
size_to_read = 0xFFFD; | |
v->pack_block_start = v->mem1; | |
read_buf(v->pack_block_start, v->input, &v->input_offset, size_to_read); | |
if (left_size - size_to_read > 2) | |
left_size = 2; | |
else | |
left_size -= size_to_read; | |
read_buf(&v->mem1[size_to_read], v->input, &v->input_offset, left_size); | |
v->input_offset -= left_size; | |
} | |
return *v->pack_block_start++; | |
} | |
uint32 input_bits_m2(vars_t *v, short count) | |
{ | |
uint32 bits = 0; | |
while (count--) | |
{ | |
if (!v->bit_count) | |
{ | |
v->bit_buffer = read_source_byte(v); | |
v->bit_count = 8; | |
} | |
bits <<= 1; | |
if (v->bit_buffer & 0x80) | |
bits |= 1; | |
v->bit_buffer <<= 1; | |
v->bit_count--; | |
} | |
return bits; | |
} | |
uint32 input_bits_m1(vars_t *v, short count) | |
{ | |
uint32 bits = 0; | |
uint32 prev_bits = 1; | |
while (count--) | |
{ | |
if (!v->bit_count) | |
{ | |
uint8 b1 = read_source_byte(v); | |
uint8 b2 = read_source_byte(v); | |
v->bit_buffer = (v->pack_block_start[1] << 24) | (v->pack_block_start[0] << 16) | (b2 << 8) | b1; | |
v->bit_count = 16; | |
} | |
if (v->bit_buffer & 1) | |
bits |= prev_bits; | |
v->bit_buffer >>= 1; | |
prev_bits <<= 1; | |
v->bit_count--; | |
} | |
return bits; | |
} | |
int input_bits(vars_t *v, short count) | |
{ | |
if (v->method != 2) | |
return input_bits_m1(v, count); | |
else | |
return input_bits_m2(v, count); | |
} | |
void decode_match_count(vars_t *v) | |
{ | |
v->match_count = input_bits_m2(v, 1) + 4; | |
if (input_bits_m2(v, 1)) | |
v->match_count = ((v->match_count - 1) << 1) + input_bits_m2(v, 1); | |
} | |
void decode_match_offset(vars_t *v) | |
{ | |
v->match_offset = 0; | |
if (input_bits_m2(v, 1)) | |
{ | |
v->match_offset = input_bits_m2(v, 1); | |
if (input_bits_m2(v, 1)) | |
{ | |
v->match_offset = ((v->match_offset << 1) | input_bits_m2(v, 1)) | 4; | |
if (!input_bits_m2(v, 1)) | |
v->match_offset = (v->match_offset << 1) | input_bits_m2(v, 1); | |
} | |
else if (!v->match_offset) | |
v->match_offset = input_bits_m2(v, 1) + 2; | |
} | |
v->match_offset = ((v->match_offset << 8) | read_source_byte(v)) + 1; | |
} | |
void write_decoded_byte(vars_t *v, uint8 b) | |
{ | |
if (&v->decoded[0xFFFF] == v->window) | |
{ | |
write_buf(v->output, &v->output_offset, &v->decoded[v->dict_size], 0xFFFF - v->dict_size); | |
memmove(v->decoded, &v->window[-v->dict_size], v->dict_size); | |
v->window = &v->decoded[v->dict_size]; | |
} | |
*v->window++ = b; | |
v->unpacked_crc_real = crc_table[(v->unpacked_crc_real ^ b) & 0xFF] ^ (v->unpacked_crc_real >> 8); | |
} | |
int unpack_data_m2(vars_t *v) | |
{ | |
while (v->processed_size < v->input_size) | |
{ | |
while (1) | |
{ | |
if (!input_bits_m2(v, 1)) | |
{ | |
write_decoded_byte(v, (v->enc_key ^ read_source_byte(v)) & 0xFF); | |
ror_w(&v->enc_key); | |
v->processed_size++; | |
} | |
else | |
{ | |
if (input_bits_m2(v, 1)) | |
{ | |
if (input_bits_m2(v, 1)) | |
{ | |
if (input_bits_m2(v, 1)) | |
{ | |
v->match_count = read_source_byte(v) + 8; | |
if (v->match_count == 8) | |
{ | |
input_bits_m2(v, 1); | |
break; | |
} | |
} | |
else | |
v->match_count = 3; | |
decode_match_offset(v); | |
} | |
else | |
{ | |
v->match_count = 2; | |
v->match_offset = read_source_byte(v) + 1; | |
} | |
v->processed_size += v->match_count; | |
while (v->match_count--) | |
write_decoded_byte(v, v->window[-v->match_offset]); | |
} | |
else | |
{ | |
decode_match_count(v); | |
if (v->match_count != 9) | |
{ | |
decode_match_offset(v); | |
v->processed_size += v->match_count; | |
while (v->match_count--) | |
write_decoded_byte(v, v->window[-v->match_offset]); | |
} | |
else | |
{ | |
uint32 data_length = (input_bits_m2(v, 4) << 2) + 12; | |
v->processed_size += data_length; | |
while (data_length--) | |
write_decoded_byte(v, (v->enc_key ^ read_source_byte(v)) & 0xFF); | |
ror_w(&v->enc_key); | |
} | |
} | |
} | |
} | |
} | |
write_buf(v->output, &v->output_offset, &v->decoded[v->dict_size], v->window - &v->decoded[v->dict_size]); | |
return 0; | |
} | |
void make_huftable(vars_t *v, huftable_t *data, int count) | |
{ | |
clear_table(data, count); | |
int leaf_nodes = input_bits_m1(v, 5); | |
if (leaf_nodes) | |
{ | |
if (leaf_nodes > 16) | |
leaf_nodes = 16; | |
for (int i = 0; i < leaf_nodes; ++i) | |
data[i].bit_depth = input_bits_m1(v, 4); | |
proc_20(data, leaf_nodes); | |
} | |
} | |
uint32 decode_table_data(vars_t *v, huftable_t *data) | |
{ | |
uint32 i = 0; | |
while (1) | |
{ | |
if (data[i].bit_depth && (data[i].l3 == (v->bit_buffer & ((1 << data[i].bit_depth) - 1)))) | |
{ | |
input_bits_m1(v, data[i].bit_depth); | |
if (i < 2) | |
return i; | |
return input_bits_m1(v, i - 1) | (1 << (i - 1)); | |
} | |
i++; | |
} | |
} | |
int unpack_data_m1(vars_t *v) | |
{ | |
while (v->processed_size < v->input_size) | |
{ | |
make_huftable(v, v->raw_table, _countof(v->raw_table)); | |
make_huftable(v, v->len_table, _countof(v->len_table)); | |
make_huftable(v, v->pos_table, _countof(v->pos_table)); | |
int subchunks = input_bits_m1(v, 16); | |
while (subchunks--) | |
{ | |
uint32 data_length = decode_table_data(v, v->raw_table); | |
v->processed_size += data_length; | |
if (data_length) | |
{ | |
while (data_length--) | |
write_decoded_byte(v, (v->enc_key ^ read_source_byte(v)) & 0xFF); | |
ror_w(&v->enc_key); | |
v->bit_buffer = (((v->pack_block_start[2] << 16) | (v->pack_block_start[1] << 8) | v->pack_block_start[0]) << v->bit_count) | (v->bit_buffer & ((1 << v->bit_count) - 1)); | |
} | |
if (subchunks) | |
{ | |
v->match_offset = decode_table_data(v, v->len_table) + 1; | |
v->match_count = decode_table_data(v, v->pos_table) + 2; | |
v->processed_size += v->match_count; | |
while (v->match_count--) | |
write_decoded_byte(v, v->window[-v->match_offset]); | |
} | |
} | |
} | |
write_buf(v->output, &v->output_offset, &v->decoded[v->dict_size], v->window - &v->decoded[v->dict_size]); | |
return 0; | |
} | |
int do_unpack_data(vars_t *v) | |
{ | |
int start_pos = v->input_offset; | |
uint32 sign = read_dword_be(v->input, &v->input_offset); | |
if ((sign >> 8) != RNC_SIGN) | |
return 6; | |
v->method = sign & 3; | |
v->input_size = read_dword_be(v->input, &v->input_offset); | |
v->packed_size = read_dword_be(v->input, &v->input_offset); | |
if (v->file_size < v->packed_size) | |
return 7; | |
v->unpacked_crc = read_word_be(v->input, &v->input_offset); | |
v->packed_crc = read_word_be(v->input, &v->input_offset); | |
/*v->leeway = */read_byte(v->input, &v->input_offset); | |
/*v->chunks_count = */read_byte(v->input, &v->input_offset); | |
if (crc_block(v->input, v->input_offset, v->packed_size) != v->packed_crc) | |
return 4; | |
v->mem1 = (uint8*)malloc(0xFFFF); | |
v->decoded = (uint8*)malloc(0xFFFF); | |
v->pack_block_start = &v->mem1[0xFFFD]; | |
v->window = &v->decoded[v->dict_size]; | |
v->unpacked_crc_real = 0; | |
v->bit_count = 0; | |
v->bit_buffer = 0; | |
v->processed_size = 0; | |
uint16 specified_key = v->enc_key; | |
int error_code = 0; | |
if (input_bits(v, 1) && !v->pus_mode) | |
error_code = 9; | |
if (!error_code) | |
{ | |
if (input_bits(v, 1) && !v->enc_key) // key is needed, but not specified as argument | |
error_code = 10; | |
} | |
if (!error_code) | |
{ | |
switch (v->method) | |
{ | |
case 1: error_code = unpack_data_m1(v); break; | |
case 2: error_code = unpack_data_m2(v); break; | |
} | |
} | |
v->enc_key = specified_key; | |
free(v->mem1); | |
free(v->decoded); | |
v->input_offset = start_pos + v->packed_size + RNC_HEADER_SIZE; | |
if (error_code) | |
return error_code; | |
if (v->unpacked_crc != v->unpacked_crc_real) | |
return 5; | |
return 0; | |
} | |
int do_unpack(vars_t *v) | |
{ | |
v->packed_size = v->file_size; | |
if (v->file_size < RNC_HEADER_SIZE) | |
return 6; | |
return do_unpack_data(v); // data | |
} | |
int do_search(vars_t *v) | |
{ | |
int error_code = 11; | |
for (uint32 i = 0; i < v->file_size - RNC_HEADER_SIZE; ) | |
{ | |
v->read_start_offset = i; | |
v->input_offset = 0; | |
v->output_offset = 0; | |
uint8 *input_ptr = v->input; | |
v->input = &v->input[i]; | |
if (!(error_code = do_unpack(v))) | |
{ | |
printf("RNC archive found: 0x%.6x (%.6d/%.6zu bytes)\n", i, v->packed_size + RNC_HEADER_SIZE, v->output_offset); | |
i += v->packed_size + RNC_HEADER_SIZE; | |
error_code = 0; | |
} | |
else | |
{ | |
switch (error_code) | |
{ | |
case 4: printf("Position 0x%.6X: Packed CRC is wrong!\n", i); break; | |
case 5: printf("Position 0x%.6X: Unpacked CRC is wrong!\n", i); break; | |
case 9: printf("Position 0x%.6X: File already packed!\n", i); break; | |
case 10: printf("Position 0x%.6X: Decryption key required!\n", i); break; | |
} | |
i++; | |
} | |
v->input = input_ptr; | |
} | |
return (error_code == 6) ? 11 : error_code; | |
} | |
void print_usage() | |
{ | |
printf("Unpack: <u> <infile.bin> [outfile.bin] [-i=hex_offset_to_read_from] [-k=hex_key_if_protected]\n"); | |
printf("Search: <s> <infile.bin>\n"); | |
printf("Pack: <p> <infile.bin> [outfile.bin] <-m=1|2> [-k=hex_key_to_protect]\n"); | |
} | |
int parse_args(int argc, char **argv, vars_t *vars) | |
{ | |
if (argc < 2) | |
return 1; | |
if (argv[1][0] == 'q') { | |
vars->quiet = 1; | |
argv++; | |
argc--; | |
} else { | |
vars->quiet = 0; | |
} | |
if (strchr("pus", argv[1][0]) || strchr("PUS", argv[1][0])) | |
{ | |
switch (argv[1][0]) | |
{ | |
case 'p': vars->pus_mode = 0; break; | |
case 'u': vars->pus_mode = 1; break; | |
case 's': vars->pus_mode = 2; break; | |
} | |
} | |
else | |
return 1; | |
int i = 3; | |
while (i < argc) | |
{ | |
if (((argv[i][0] == '-') || (argv[i][0] == '/'))) | |
switch (argv[i][1]) | |
{ | |
case 'k': | |
sscanf(&argv[i][3], "%hx", &vars->enc_key); | |
if (!vars->enc_key) | |
return 3; | |
break; | |
case 'd': | |
sscanf(&argv[i][3], "%hx", &vars->dict_size); | |
if (vars->dict_size < 0x400) | |
vars->dict_size = 0x400; | |
break; | |
case 'i': | |
sscanf(&argv[i][3], "%zx", &vars->read_start_offset); | |
break; | |
case 'o': | |
sscanf(&argv[i][3], "%zx", &vars->write_start_offset); | |
break; | |
case 'm': | |
sscanf(&argv[i][3], "%d", &vars->method); | |
if (!vars->method || vars->method > 2) | |
return 3; | |
break; | |
default: | |
break; | |
} | |
i++; | |
} | |
return 0; | |
} | |
int main(int argc, char *argv[]) | |
{ | |
if (argc >= 2 && argv[1][0] != 'q') { | |
printf("-= RNC ProPackED v1.4 [by Lab 313] (11/04/2018) =-\n"); | |
printf("-----------------------------\n"); | |
} | |
if (argc <= 2) { | |
printf("Compression type: Huffman + LZ77\n"); | |
printf("De/Compressor: Dr.MefistO\n"); | |
printf("Coding: Dr. MefistO\n"); | |
printf("Original: Rob Northen Computing\n"); | |
printf("Info: De(re)compiled source of the famous RNC ProPack compression tool\n\n"); | |
print_usage(); | |
printf("-----------------------------\n\n"); | |
} | |
vars_t *v = init_vars(); | |
if (parse_args(argc, argv, v)) { | |
printf("Wrong command line specified!\n"); | |
return 1; | |
} | |
if (v->quiet) { | |
argv++; | |
argc--; | |
} | |
if (v->method == 1) | |
{ | |
if (v->dict_size > 0x8000) | |
v->dict_size = 0x8000; | |
v->max_matches = 0x1000; | |
} | |
else if (v->method == 2) | |
{ | |
if (v->dict_size > 0x1000) | |
v->dict_size = 0x1000; | |
v->max_matches = 0xFF; | |
} | |
FILE *in = fopen(argv[2], "rb"); | |
if (in == NULL) | |
{ | |
free(v); | |
printf("Cannot open input file!\n"); | |
return -1; | |
} | |
fseek(in, 0, SEEK_END); | |
v->file_size = ftell(in) - v->read_start_offset; | |
fseek(in, v->read_start_offset, SEEK_SET); | |
v->input = (uint8*)malloc(v->file_size); | |
fread(v->input, v->file_size, 1, in); | |
fclose(in); | |
v->output = (uint8*)malloc(MAX_BUF_SIZE); | |
v->temp = (uint8*)malloc(MAX_BUF_SIZE); | |
int error_code = 0; | |
switch (v->pus_mode) | |
{ | |
case 0: error_code = do_pack(v); break; | |
case 1: error_code = do_unpack(v); break; | |
case 2: error_code = do_search(v); break; | |
} | |
if (!error_code && v->pus_mode != 2) | |
{ | |
FILE *out; | |
if (argc <= 3 || ((argv[3][0] == '-') || (argv[3][0] == '/'))) | |
{ | |
char out_name[256]; | |
snprintf(out_name, sizeof(out_name), "%s.%.6zx.bin", argv[2], v->read_start_offset); | |
out = fopen(out_name, "wb"); | |
} | |
else | |
out = fopen(argv[3], "wb"); | |
if (out == NULL) | |
{ | |
free(v->input); | |
free(v->output); | |
free(v->temp); | |
free(v); | |
printf("Cannot create output file!\n"); | |
return -1; | |
} | |
fwrite(v->output, v->output_offset, 1, out); | |
fclose(out); | |
if (!v->quiet) { | |
printf("File successfully %s!\n", ((v->pus_mode == 0) ? "packed" : "unpacked")); | |
printf("Original/new size: %d/%zd bytes\n", (v->pus_mode == 1) ? (v->packed_size + RNC_HEADER_SIZE) : v->file_size, v->output_offset); | |
} | |
} | |
else { | |
switch (error_code) { | |
case 0: break; | |
case 4: printf("Corrupted input data.\n"); break; | |
case 5: printf("CRC check failed.\n"); break; | |
case 6: | |
case 7: printf("Wrong RNC header.\n"); break; | |
case 10: printf("Decryption key required.\n"); break; | |
case 11: printf("No RNC archives were found.\n"); break; | |
default: printf("Cannot process file. Error code: %x\n", error_code); break; | |
} | |
} | |
free(v->input); | |
free(v->output); | |
free(v->temp); | |
free(v); | |
return error_code; | |
} |