use std::io::Cursor;
use byteorder::{LittleEndian, ReadBytesExt};
use crate::{
crc32::crc32,
huffman,
};
pub fn decompress(file_buffer: Vec<u8>) -> Result<Vec<u8>, String> {
let mut cursor = Cursor::new(&file_buffer);
let mut offset = 0;
let mut sector_type = 0;
while offset <= 1024 && offset+3 < file_buffer.len() {
let word = cursor.read_u32::<LittleEndian>().unwrap();
if word == 0x434f4d50 {
sector_type = word;
break;
}
offset += 64;
cursor.set_position(offset as u64);
}
if sector_type == 0 {
return Err("not a compressed 3ds file".to_owned())
}
cursor.set_position(offset as u64 + 8);
let expected_length = cursor.read_u32::<LittleEndian>().unwrap() as usize;
let expected_crc = cursor.read_u32::<LittleEndian>().unwrap();
let huff_set_start = cursor.position() as usize;
if cursor.read_u8().unwrap() != 0x28 {
return Err("unkown compresssion format".to_owned())
}
let decrypted = huffman::decode(&file_buffer[huff_set_start..]).unwrap();
if decrypted.len() != expected_length {
return Err("unexpected length, something defeinitely went wrong".to_owned())
}
let header = &file_buffer[..offset];
let crc = !crc32(crc32(!0, header), &decrypted);
if crc != expected_crc {
return Err("unexpected crc".to_owned())
}
return Ok([header, &decrypted].concat());
}