Skip to content

Instantly share code, notes, and snippets.

@yupferris
Last active August 20, 2018 08:44
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save yupferris/21d4c2862f2145e8301f8657d8283ec7 to your computer and use it in GitHub Desktop.
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. :)
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;
}
}
}
@yupferris
Copy link
Author

Ended up posting the whole main.rs contents here: https://gist.github.com/yupferris/308ae85241f40ccca680d50e79f08e34

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment