Last active
August 20, 2018 08:44
-
-
Save yupferris/21d4c2862f2145e8301f8657d8283ec7 to your computer and use it in GitHub Desktop.
Mario's Tennis graphics decompression routine in Rust-like pseudo-code. Manual decompilation is a bitch. :)
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
fn decompress(mut src: *const u8, dst: *mut u8) { | |
// Skip first 2 bytes (they're always zero) | |
src += 2; | |
let original_dst = dst; | |
// Load bytes_left | |
let mut bytes_left = ((*src as i32) << 8) + 1; | |
src += 1; | |
bytes_left += *src as i32; | |
src += 1; | |
loop { | |
// Load packet_flags | |
let mut packet_flags = *src; | |
src += 1; | |
// Iterate over control bits (lsb -> msb) | |
for _ in 0..8 { | |
// Load data_byte | |
let data_byte = *src; | |
src += 1; | |
// Load packet_flag from packet_flags lsb | |
let packet_flag = packet_flags & 0x1; | |
if packet_flag != 0 { | |
// Literal byte; output data_byte directly | |
*dst = data_byte; | |
dst += 1; | |
bytes_left -= 1; | |
} else { | |
// Backreference; data_byte and next byte encode distance+length | |
let run_distance = (*src << 4) | (data_byte >> 4); | |
src += 1; | |
let mut run_length = (data_byte & 0xf) + 3; | |
bytes_left -= run_length; | |
// run_length may have been greater than bytes_left; this is some weird logic to correct that :) | |
// (it totally works; don't think too much about it.. I could make this more clear but I want | |
// it to match the original as much as possible) | |
if bytes_left < 0 { | |
run_length += bytes_left; | |
} | |
let mut run_source = dst - run_distance; | |
if run_source < original_dst { | |
let num_zeroes = original_dst - run_source; | |
for _ in 0..num_zeroes { | |
// Output zero and inc dst pointer | |
*dst = 0; | |
dst += 1; | |
} | |
run_length -= num_zeroes; | |
run_source = original_dst; | |
} | |
if run_length > 0 { | |
for _ in 0..run_length { | |
// Output byte at [run_source] and inc run_source and dst pointer | |
*dst = *run_source; | |
run_source += 1; | |
dst += 1; | |
} | |
} | |
} | |
// Shift out packet flag from this iteration | |
packet_flags >>= 1; | |
if bytes_left < 0 { | |
break; | |
} | |
} | |
if bytes_left < 0 { | |
break; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Ended up posting the whole
main.rs
contents here: https://gist.github.com/yupferris/308ae85241f40ccca680d50e79f08e34