Created
July 23, 2019 22:14
-
-
Save tatarize/4abd5345eb269603cfc98ff4070717d8 to your computer and use it in GitHub Desktop.
Archive Lib Expand Deobfuscated Source
This file contains hidden or 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
#include <iostream> | |
#include <climits> | |
#include <cstdlib> | |
#include <cstring> | |
#include <cstdio> | |
#include <fstream> | |
#include "show_dump2.h" | |
using namespace std; | |
void expand(unsigned char *input, unsigned char *output, int compressedSize, int bits_for_buffer); | |
/***************************************** | |
* HUS Expand Variables | |
****************************************/ | |
unsigned char *sliding_window; | |
short remaining_bit_length; | |
short sliding_window_size; | |
short window_mask; | |
unsigned char *bitlengths_511; | |
unsigned char *bitlengths_19; | |
unsigned short bitstream_window; | |
unsigned short *g1021_bit0_token_lookup; | |
unsigned short *g1021_bit1_token_lookup; | |
unsigned short *g12bit_token_lookup; | |
unsigned short *g8bit_token_lookup; | |
short end_of_file_or_error; | |
unsigned short elements_before_reset; | |
unsigned char remaining_bits; | |
short bytes_left_in_chunk; | |
int mStatus; | |
int currentIndex; | |
long remainingBytes; | |
unsigned char *outputArray; | |
unsigned char *inputArray; | |
unsigned char *inputBuffer; | |
int currentPosition; | |
int outputPosition; | |
/***************************************** | |
* HUS Expand Functions | |
****************************************/ | |
void update_tables(int lengths_table_size, const unsigned char *lengths_table, int bit_depth, | |
unsigned short *token_tables, unsigned short token_table_size); | |
void bitstream_initialize(); | |
void bitstream_forward(int bits_forward); | |
unsigned short get_bits(int bit_count); | |
int decompress_main(); | |
unsigned short reset_check_read_token_12_4(); | |
unsigned short read_token_12_4(); | |
unsigned short read_token_8_8(); | |
void setup_8_bit_table(short clear_amount, short pos_at_skip_2bit_length); | |
void setup_12_bit_table(); | |
void expand(unsigned char *input, unsigned char *output, int compressedSize, int bits_for_buffer) { | |
currentPosition = 0; | |
outputPosition = 0; | |
currentIndex = 0; | |
mStatus = 0; | |
outputArray = output; | |
inputArray = input; | |
remainingBytes = compressedSize; | |
if (bits_for_buffer > 14 || bits_for_buffer < 10) { | |
mStatus = -1; | |
sliding_window_size = 2; | |
} else { | |
sliding_window_size = (short) (1U << bits_for_buffer); //[10-14] 1024-16384 | |
} | |
remaining_bit_length = 0; | |
end_of_file_or_error = 0; | |
bytes_left_in_chunk = 0; | |
elements_before_reset = 0; | |
remaining_bits = 0; | |
window_mask = (short) (sliding_window_size - 1); | |
sliding_window = (unsigned char *) malloc(sizeof(unsigned char) * (sliding_window_size + 2)); | |
if (sliding_window) memset(sliding_window, 0, (sliding_window_size + 2) * sizeof(unsigned char)); | |
g12bit_token_lookup = (unsigned short *) malloc(sizeof(unsigned short) * 4096); | |
if (g12bit_token_lookup) memset(g12bit_token_lookup, 0, 4096 * sizeof(unsigned short)); | |
g8bit_token_lookup = (unsigned short *) malloc(sizeof(unsigned short) * 256); | |
if (g8bit_token_lookup) memset(g8bit_token_lookup, 0, 256 * sizeof(unsigned short)); | |
g1021_bit0_token_lookup = (unsigned short *) malloc(sizeof(unsigned short) * 1021); | |
if (g1021_bit0_token_lookup) memset(g1021_bit0_token_lookup, 0, 1021 * sizeof(unsigned short)); | |
g1021_bit1_token_lookup = (unsigned short *) malloc(sizeof(unsigned short) * 1021); | |
if (g1021_bit1_token_lookup) memset(g1021_bit1_token_lookup, 0, 1021 * sizeof(unsigned short)); | |
bitlengths_511 = (unsigned char *) malloc(sizeof(unsigned char) * 511); | |
if (bitlengths_511) memset(bitlengths_511, 0, 511 * sizeof(unsigned char)); | |
bitlengths_19 = (unsigned char *) malloc(sizeof(unsigned char) * 19); | |
if (bitlengths_19) memset(bitlengths_19, 0, 19 * sizeof(unsigned char)); | |
if (sliding_window == nullptr || | |
g1021_bit0_token_lookup == nullptr || | |
g1021_bit1_token_lookup == nullptr || | |
bitlengths_511 == nullptr || | |
bitlengths_19 == nullptr || | |
g12bit_token_lookup == nullptr || | |
g8bit_token_lookup == nullptr || | |
inputBuffer == nullptr) { | |
mStatus = -1; | |
} | |
decompress_main(); | |
free(sliding_window); | |
free(g1021_bit0_token_lookup); | |
free(g1021_bit1_token_lookup); | |
free(bitlengths_511); | |
free(bitlengths_19); | |
free(g12bit_token_lookup); | |
free(g8bit_token_lookup); | |
} | |
void bitstream_initialize() { | |
elements_before_reset = 0; | |
bitstream_window = 0; | |
remaining_bits = 0; | |
remaining_bit_length = 0; | |
bytes_left_in_chunk = 0; | |
bitstream_forward(16); | |
} | |
unsigned short get_bits(int bit_count) { | |
auto bits_off_scope = bitstream_window >> (16 - bit_count); | |
bitstream_forward(bit_count); | |
return bits_off_scope; | |
} | |
void bitstream_forward(int bits_forward) { | |
while (bits_forward > remaining_bit_length) { | |
bits_forward -= remaining_bit_length; | |
bitstream_window = (bitstream_window << remaining_bit_length) + (remaining_bits >> (8 - remaining_bit_length)); | |
if (bytes_left_in_chunk <= 0) { //new block needed | |
currentIndex = 0; | |
if (remainingBytes >= 0 && remainingBytes < 512) { //incomplete block | |
inputBuffer = &inputArray[currentPosition]; | |
currentPosition += remainingBytes; | |
bytes_left_in_chunk = (short) remainingBytes; | |
remainingBytes -= bytes_left_in_chunk; | |
} else { //full block. | |
inputBuffer = &inputArray[currentPosition]; | |
currentPosition += 512; | |
bytes_left_in_chunk = 512; | |
} | |
if (bytes_left_in_chunk <= 0) end_of_file_or_error++; | |
} | |
remaining_bits = inputBuffer[currentIndex++]; | |
bytes_left_in_chunk--; | |
remaining_bit_length = 8; | |
} | |
remaining_bit_length = (short) (remaining_bit_length - bits_forward); | |
bitstream_window = (bitstream_window << bits_forward) + (remaining_bits >> (8 - bits_forward)); | |
remaining_bits <<= bits_forward; | |
} | |
int decompress_main() { | |
short current_pos = 0; | |
end_of_file_or_error = 0; | |
bitstream_initialize(); | |
while (end_of_file_or_error < 5) { | |
short token; | |
token = (short) reset_check_read_token_12_4(); | |
if (token <= 255) { | |
//this is simply a value. | |
sliding_window[current_pos] = (unsigned char) token; | |
if (++current_pos >= sliding_window_size) { | |
current_pos = 0; | |
memcpy(&outputArray[outputPosition], sliding_window, static_cast<size_t>(sliding_window_size)); | |
outputPosition += sliding_window_size; | |
} | |
} else { | |
//this is a lookup. 256 <= token <= 511 | |
auto length_move = (short) (token - 253); | |
if (length_move == 257) break; | |
auto relative_lookback = (current_pos - read_token_8_8() - 1); | |
auto read_pos = (short) (relative_lookback & window_mask); | |
if (read_pos < sliding_window_size - 257 && current_pos < sliding_window_size - 257) { | |
while (--length_move >= 0) { | |
sliding_window[current_pos++] = sliding_window[read_pos++]; | |
} | |
} else { | |
while (--length_move >= 0) { | |
sliding_window[current_pos] = sliding_window[read_pos]; | |
if (++current_pos >= sliding_window_size) { | |
current_pos = 0; | |
memcpy(&outputArray[outputPosition], sliding_window, static_cast<size_t>(sliding_window_size)); | |
outputPosition += sliding_window_size; | |
} | |
read_pos = (short) ((read_pos + 1) & window_mask); | |
} | |
} | |
} | |
} | |
if (current_pos != 0) { | |
memcpy(&outputArray[outputPosition], sliding_window, static_cast<size_t>(current_pos)); | |
outputPosition += current_pos; | |
} | |
return 0; | |
} | |
unsigned short reset_check_read_token_12_4() { | |
if (elements_before_reset == 0) { //initialized or reset | |
elements_before_reset = get_bits(16); | |
setup_8_bit_table(19, 3); | |
setup_12_bit_table(); | |
setup_8_bit_table(15, -1); | |
if (mStatus < 0) return 0; | |
} | |
elements_before_reset--; | |
return read_token_12_4(); | |
} | |
unsigned short read_token_12_4() { | |
auto index_value = bitstream_window >> 4U; | |
auto token = g12bit_token_lookup[index_value]; | |
if (token >= 511) { //is outside bitlength lookup | |
unsigned short bit_mask_3 = 1U << 3U; | |
do { | |
if (bitstream_window & bit_mask_3) { | |
token = g1021_bit1_token_lookup[token]; | |
} else { | |
token = g1021_bit0_token_lookup[token]; | |
} | |
bit_mask_3 >>= 1U; | |
} while (token >= 511); | |
} | |
auto token_length = bitlengths_511[token]; | |
bitstream_forward(token_length); | |
return token; | |
} | |
unsigned short read_token_8_8() { | |
auto index_value = bitstream_window >> 8U; | |
auto token = g8bit_token_lookup[index_value]; | |
if (token >= 15) { | |
unsigned short bit_mask_7 = 1U << 7U; | |
do { | |
if (bitstream_window & bit_mask_7) { | |
token = g1021_bit1_token_lookup[token]; | |
} else { | |
token = g1021_bit0_token_lookup[token]; | |
} | |
bit_mask_7 >>= 1U; | |
} while (token >= 15); | |
} | |
auto a = bitlengths_19[token]; | |
bitstream_forward(a); | |
if (token != 0) { | |
token--; | |
token = (1U << token) + get_bits(token); | |
} | |
return token; | |
} | |
void setup_8_bit_table(short clear_amount, short pos_at_skip_2bit_length) { | |
short get_header = get_bits(5); | |
if (get_header == 0) { //0b00000 means 19chars blank and set all g256 to next_five_bits | |
auto next_5_bits = get_bits(5); | |
for (int i = 0; i < clear_amount; i++) bitlengths_19[i] = 0; | |
for (int i = 0; i < 256; i++) g8bit_token_lookup[i] = next_5_bits; | |
} else { | |
int i = 0; | |
while (i < get_header) { | |
auto value = (short) (bitstream_window >> 13U); //lookahead 3 bits. | |
if (value == 7) { //0b111 | |
unsigned short mask_bit_12 = 1U << 12U; | |
while (mask_bit_12 & bitstream_window) { //find next 0 in bitstream. | |
mask_bit_12 >>= 1U; | |
value++; | |
} | |
} //lookahead either 1-6 001 - 110, or 1110 = 7, 11110=8, 111110=9 up to 11111111_11111111 = 20 | |
bitstream_forward((value < 7) ? 3 : value - 3); //remove value out | |
bitlengths_19[i++] = (unsigned char) value; | |
if (i == pos_at_skip_2bit_length) { | |
short length_to_zero = get_bits(2); | |
while (--length_to_zero >= 0) bitlengths_19[i++] = 0; | |
} | |
} | |
while (i < clear_amount) bitlengths_19[i++] = 0; | |
update_tables(clear_amount, bitlengths_19, 8, g8bit_token_lookup, 256); | |
} | |
} | |
void setup_12_bit_table() { | |
auto get_header = get_bits(9); | |
if (get_header == 0) { | |
auto set_value = get_bits(9); | |
for (short i = 0; i < 511; i++) bitlengths_511[i] = 0; | |
for (short j = 0; j < 4096; j++) g12bit_token_lookup[j] = set_value; | |
} else { | |
short i = 0; | |
while (i < get_header) { | |
auto upper_byte = bitstream_window >> 8; | |
short token = g8bit_token_lookup[upper_byte]; //MUST BE SIGNED. | |
if (token >= 19) { | |
unsigned short bit_mask_7 = 1U << 7U; | |
do { | |
if ((bitstream_window & bit_mask_7) != 0) { | |
token = (short) g1021_bit1_token_lookup[token]; | |
} else { | |
token = (short) g1021_bit0_token_lookup[token]; | |
} | |
bit_mask_7 >>= 1; | |
} while (token >= 19); | |
} | |
auto m = bitlengths_19[token]; | |
bitstream_forward(m); | |
if (token <= 2) { | |
if (token == 0) { | |
token = 1; | |
} else if (token == 1) { | |
token = (short) (get_bits(4) + 3); | |
} else { | |
token = (short) (get_bits(9) + 20); | |
} | |
while (--token >= 0) { | |
bitlengths_511[i++] = 0; | |
} | |
} else { | |
bitlengths_511[i++] = (unsigned char) (token - 2); | |
} | |
} | |
while (i < 511) { | |
bitlengths_511[i++] = 0; //everything left set to zero. | |
} | |
update_tables(511, bitlengths_511, 12, g12bit_token_lookup, 4096); | |
} | |
} | |
void update_tables(int lengths_table_size, const unsigned char *lengths_table, int bit_depth, | |
unsigned short *token_tables, unsigned short token_table_size) { | |
unsigned short length_sums[17], step_2[18], step_3[17]; | |
for (int i = 0; i <= 16; i++) { | |
length_sums[i] = 0; | |
} | |
for (int i = 0; i < lengths_table_size; i++) { | |
auto index = lengths_table[i]; | |
length_sums[index]++; | |
} | |
step_2[0] = 0; | |
step_2[1] = 0; | |
for (int i = 1; i <= 16; i++) { | |
step_2[i + 1] = step_2[i] + (length_sums[i] << (16 - i)); | |
} | |
if (step_2[17] != 0) { | |
mStatus = -1; | |
end_of_file_or_error = 10; //error, abort? | |
return; | |
} | |
auto remain_bits = 16 - bit_depth; | |
step_3[0] = 0; | |
int q; | |
for (q = 1; q <= bit_depth; q++) { | |
step_2[q] >>= remain_bits; | |
step_3[q] = (unsigned short) (1U << (bit_depth - q)); | |
} | |
for (; q <= 16; q++) { | |
step_3[q] = (unsigned short) (1U << (16 - q)); | |
} | |
int r = step_2[bit_depth + 1] >> remain_bits; | |
if (r != 0) { | |
unsigned int max_value_for_bitdepth = 1U << bit_depth; | |
while (r != max_value_for_bitdepth) token_tables[r++] = 0; | |
} | |
int a = lengths_table_size; | |
unsigned int bit_mask_msd = 1U << (15 - bit_depth); | |
for (int c_index = 0; c_index < lengths_table_size; c_index++) { | |
int c_value = lengths_table[c_index]; | |
if (c_value == 0) continue; | |
int sum_of_steps_2_3 = step_2[c_value] + step_3[c_value]; | |
if (c_value <= bit_depth) { | |
if (sum_of_steps_2_3 > token_table_size) { | |
mStatus = -1; | |
end_of_file_or_error = 10; | |
//error abort. | |
return; | |
} | |
for (int i = step_2[c_value]; i < sum_of_steps_2_3; i++) { | |
token_tables[i] = (unsigned short) c_index; | |
} | |
} else { | |
unsigned int step_2_c_value = step_2[c_value]; | |
unsigned short *table_element = &token_tables[step_2_c_value >> remain_bits]; | |
int i = c_value - bit_depth; | |
while (i != 0) { | |
if (*table_element == 0) { | |
g1021_bit1_token_lookup[a] = g1021_bit0_token_lookup[a] = 0; | |
*table_element = (unsigned short) a++; | |
} | |
if (step_2_c_value & bit_mask_msd) { | |
table_element = &g1021_bit1_token_lookup[*table_element]; | |
} else { | |
table_element = &g1021_bit0_token_lookup[*table_element]; | |
} | |
step_2_c_value <<= 1; | |
i--; | |
} | |
*table_element = (unsigned short) c_index; | |
} | |
step_2[c_value] = (unsigned short) sum_of_steps_2_3; | |
} | |
} | |
int main() { | |
char *memblock; | |
cout << "Hus parser." << endl; | |
ifstream infile; | |
//infile.open("C:\\Users\\Tat\\CLionProjects\\deobf-expand\\BN00883_A.HUS", ios::in|ios::binary|ios::ate); | |
infile.open(R"(C:\Users\Tat\CLionProjects\deobf-expand\wet.hus)", ios::in | ios::binary | ios::ate); | |
unsigned char *input = nullptr; | |
if (infile.is_open()) { | |
infile.seekg(0, ios::end); | |
int length_of_file = static_cast<int>(infile.tellg()); | |
infile.seekg(0, ios::beg); | |
char *read = new char[4]; | |
infile.read(read, 4); | |
int magic = ((read[3] & 0xFF) << 24) | ((read[2] & 0xFF) << 16) | ((read[1] & 0xFF) << 8) | (read[0] & 0xFF); | |
cout << magic << endl; | |
infile.read(read, 4); | |
int stitch_count = | |
((read[3] & 0xFF) << 24) | ((read[2] & 0xFF) << 16) | ((read[1] & 0xFF) << 8) | (read[0] & 0xFF); | |
cout << stitch_count << endl; | |
infile.read(read, 4); | |
int color_count = | |
((read[3] & 0xFF) << 24) | ((read[2] & 0xFF) << 16) | ((read[1] & 0xFF) << 8) | (read[0] & 0xFF); | |
cout << color_count << endl; | |
infile.read(read, 4); | |
infile.read(read, 4); | |
infile.read(read, 4); | |
int command_offset = | |
((read[3] & 0xFF) << 24) | ((read[2] & 0xFF) << 16) | ((read[1] & 0xFF) << 8) | (read[0] & 0xFF); | |
cout << command_offset << endl; | |
infile.read(read, 4); | |
int x_offset = ((read[3] & 0xFF) << 24) | ((read[2] & 0xFF) << 16) | ((read[1] & 0xFF) << 8) | (read[0] & 0xFF); | |
cout << x_offset << endl; | |
infile.read(read, 4); | |
int y_offset = ((read[3] & 0xFF) << 24) | ((read[2] & 0xFF) << 16) | ((read[1] & 0xFF) << 8) | (read[0] & 0xFF); | |
cout << y_offset << endl; | |
int type = 10; | |
int len_compressed; | |
int len_uncompressed; | |
unsigned char *decompressedData; | |
infile.seekg(0, ios::beg); | |
infile.seekg(command_offset); | |
len_compressed = x_offset - command_offset; | |
memblock = new char[len_compressed]; | |
infile.read(memblock, len_compressed); | |
input = reinterpret_cast<unsigned char *>(memblock); | |
len_uncompressed = stitch_count + 1; | |
decompressedData = (unsigned char *) malloc(sizeof(unsigned char) * len_uncompressed); | |
expand(input, decompressedData, len_uncompressed, type); | |
show_dump(5, decompressedData, static_cast<unsigned int>(len_uncompressed), stdout); | |
cout << endl << endl << endl << endl; | |
infile.seekg(0, ios::beg); | |
infile.seekg(x_offset); | |
len_compressed = y_offset - x_offset; | |
memblock = new char[len_compressed]; | |
infile.read(memblock, len_compressed); | |
input = reinterpret_cast<unsigned char *>(memblock); | |
len_uncompressed = stitch_count; | |
decompressedData = (unsigned char *) malloc(sizeof(unsigned char) * len_uncompressed); | |
expand(input, decompressedData, len_uncompressed, type); | |
show_dump(5, decompressedData, static_cast<unsigned int>(len_uncompressed), stdout); | |
cout << endl << endl << endl << endl; | |
infile.seekg(0, ios::beg); | |
infile.seekg(y_offset); | |
len_compressed = length_of_file - y_offset; | |
memblock = new char[len_compressed]; | |
infile.read(memblock, len_compressed); | |
input = reinterpret_cast<unsigned char *>(memblock); | |
len_uncompressed = stitch_count; | |
decompressedData = (unsigned char *) malloc(sizeof(unsigned char) * len_uncompressed); | |
expand(input, decompressedData, len_uncompressed, type); | |
show_dump(5, decompressedData, static_cast<unsigned int>(len_uncompressed), stdout); | |
infile.close(); | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment