use lzham;
use lzma;
use std::fmt::Write;
use std::fs;
#[derive(Debug)]
pub enum Signature {
NONE,
LZMA, SC, SCLZ, SIG, }
pub struct ScCompression {
buffer: Vec<u8>,
}
pub fn new(fp: String) -> ScCompression {
ScCompression {
buffer: fs::read(fp).expect("Something went wrong reading the file"),
}
}
pub fn new_from_buffer(buffer: Vec<u8>) -> ScCompression {
ScCompression { buffer: (buffer) }
}
impl ScCompression {
pub fn compress(&mut self, sig: Signature) -> Vec<u8> {
match sig {
Signature::NONE => self.buffer.clone(),
Signature::LZMA => self.compress_lzma(),
Signature::SC => self.compress_sc(),
Signature::SCLZ => self.compress_sclz(),
Signature::SIG => self.compress_sig(),
}
}
fn compress_lzma(&mut self) -> Vec<u8> {
let mut compressed = lzma::compress(&self.buffer, 6).unwrap();
compressed.drain(5..9);
compressed
}
fn compress_sc(&mut self) -> Vec<u8> {
let mut lzma_compressed = self.compress(Signature::LZMA);
let mut compressed_with_header = vec![0; 26];
compressed_with_header.append(&mut lzma_compressed);
compressed_with_header
}
fn compress_sclz(&mut self) -> Vec<u8> {
let mut lzham_compressed = Vec::new();
let usize = self.buffer.len();
let status = lzham::compress(&mut &self.buffer[..], &mut lzham_compressed);
if !status.is_success() {
panic!("{:?}", status);
}
let mut compressed_with_header = vec![0; 31];
compressed_with_header.append(&mut usize.to_be_bytes().to_vec());
compressed_with_header.append(&mut lzham_compressed);
compressed_with_header
}
fn compress_sig(&mut self) -> Vec<u8> {
let mut lzma_compressed = self.compress(Signature::LZMA);
let mut compressed_with_header = String::from("Sig:").as_bytes().to_vec();
compressed_with_header.append(vec![0; 64].to_vec().as_mut());
compressed_with_header.append(&mut lzma_compressed);
compressed_with_header
}
pub fn decompress(&mut self) -> Vec<u8> {
let sig = self.read_signature();
let decompressed = match sig {
Signature::NONE => self.buffer.clone(),
Signature::LZMA => self.decompress_lzma(),
Signature::SC => self.decompress_sc(),
Signature::SCLZ => self.decompress_sclz(),
Signature::SIG => self.decompress_sig(),
};
decompressed.to_vec()
}
fn decompress_lzma(&mut self) -> Vec<u8> {
let uncompressed_size = i32::from_le_bytes(self.buffer[5..9].try_into().unwrap());
if uncompressed_size == -1 {
self.buffer.append(&mut vec![0xFF; 4]);
self.buffer[9..].rotate_right(4);
} else {
self.buffer.append(&mut vec![0x00; 4]);
self.buffer[9..].rotate_right(4);
}
let data = lzma::decompress(&self.buffer).unwrap();
return data;
}
fn decompress_sc(&mut self) -> Vec<u8> {
self.buffer = self.buffer[26..].to_vec();
self.decompress_lzma()
}
fn decompress_sclz(&mut self) -> Vec<u8> {
let mut decompressed = Vec::new();
let usize = usize::from_le_bytes(self.buffer[31..35].try_into().unwrap());
let status = lzham::decompress(&mut &self.buffer[35..], &mut decompressed, usize);
if !status.is_success() {
panic!("{:?}", status);
}
decompressed
}
fn decompress_sig(&mut self) -> Vec<u8> {
self.buffer = self.buffer[68..].to_vec();
self.decompress_lzma()
}
fn read_signature(&self) -> Signature {
if encode_hex(&self.buffer[..3]).to_lowercase() == "5d0000" {
return Signature::LZMA;
} else if vec8_to_lower_str(&self.buffer[..2].to_vec()) == "sc" {
if self.buffer.len() > 30 && vec8_to_lower_str(&self.buffer[26..30].to_vec()) == "sclz"
{
return Signature::SCLZ;
}
return Signature::SC;
} else if vec8_to_lower_str(&self.buffer[..4].to_vec()) == "sig:" {
return Signature::SIG;
}
Signature::NONE
}
}
fn vec8_to_lower_str(vec: &Vec<u8>) -> String {
String::from_utf8(vec.to_vec())
.expect("bad bytes")
.to_lowercase()
}
pub fn encode_hex(bytes: &[u8]) -> String {
let mut s = String::with_capacity(bytes.len() * 2);
for &b in bytes {
write!(&mut s, "{:02x}", b).unwrap();
}
s
}