mod compress;
mod decompress;
pub use compress::compress;
pub use decompress::{decompress, DecompressionError};
#[derive(Debug)]
enum Command<'a> {
Copy(&'a [u8]),
ByteFill {
data: u8,
len: usize,
},
WordFill {
data: u16,
len: usize,
},
Incrementing {
start: u8,
len: usize,
},
Backreference {
src: Reference,
invert: bool,
len: usize,
},
Stop,
}
impl Command<'_> {
const MAX_LEN: usize = 0x400;
}
#[derive(Debug)]
enum Reference {
Absolute(u16),
Relative(u8),
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_decompress() {
assert_eq!(decompress(&[0x3, 1, 2, 3, 4, 0xFF]), Ok(vec![1, 2, 3, 4]));
assert_eq!(
decompress(&[0x23, 0xAA, 0xFF]),
Ok(vec![0xAA, 0xAA, 0xAA, 0xAA])
);
assert_eq!(
decompress(&[0x43, 0xAA, 0x55, 0xFF]),
Ok(vec![0xAA, 0x55, 0xAA, 0x55])
);
assert_eq!(decompress(&[0x63, 1, 0xFF]), Ok(vec![1, 2, 3, 4]));
assert_eq!(
decompress(&[0x2, 1, 2, 3, 0x85, 0x00, 0x00, 0xFF]),
Ok(vec![1, 2, 3, 1, 2, 3, 1, 2, 3])
);
assert_eq!(
decompress(&[0x2, 1, 2, 3, 0xA5, 0x00, 0x00, 0xFF]),
Ok(vec![1, 2, 3, !1, !2, !3, 1, 2, 3])
);
assert_eq!(
decompress(&[0x2, 1, 2, 3, 0xC5, 0x03, 0xFF]),
Ok(vec![1, 2, 3, 1, 2, 3, 1, 2, 3])
);
assert_eq!(
decompress(&[0x2, 1, 2, 3, 0xFC, 0x5, 0x03, 0xFF]),
Ok(vec![1, 2, 3, !1, !2, !3, 1, 2, 3])
);
assert_eq!(
decompress(&[0x2, 1, 2, 3, 0xFB, 0xFE, 0x3, 0xFF]),
Ok([1, 2, 3].into_iter().cycle().take(1026).collect())
);
}
#[test]
fn test_compress() {
assert_eq!(compress(&[0, 2, 4, 6]), vec![0x03, 0, 2, 4, 6, 0xFF]);
assert_eq!(compress(&[1, 1, 1, 1]), vec![0x23, 1, 0xFF]);
assert_eq!(compress(&[1, 2, 1, 2, 1, 2]), vec![0x45, 1, 2, 0xFF]);
assert_eq!(compress(&[1, 2, 1, 2, 1]), vec![0x44, 1, 2, 0xFF]);
assert_eq!(compress(&[1, 2, 3, 4]), vec![0x63, 1, 0xFF]);
assert_eq!(
compress(&[1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4]),
vec![0x63, 1, 0xC7, 0x4, 0xFF]
);
assert_eq!(
compress(&[1, 2, 3, 4, !1, !2, !3, !4, 1, 2, 3, 4]),
vec![0x63, 1, 0xFC, 0x07, 0x4, 0xFF]
);
let seq = || {
std::iter::successors(Some(1u8), |&x| Some(x.wrapping_add(3)))
.take(256)
.flat_map(|i| [i, i.wrapping_sub(1)])
};
assert_eq!(
compress(&seq().chain(seq()).collect::<Vec<u8>>()),
[0xE1, 0xFF]
.into_iter()
.chain(seq())
.chain([0xF1, 0xFF, 0x00, 0x00, 0xFF])
.collect::<Vec<_>>()
);
}
#[test]
fn test_roundtrip_green_brinstar() {
let data = include_bytes!("green_brinstar_main_shaft.bin");
let decompressed = decompress(data).unwrap();
let recompressed = compress(&decompressed);
let redecompressed = decompress(&recompressed).unwrap();
assert_eq!(decompressed, redecompressed);
}
}