use std::io::Cursor;
use std::sync::Arc;
use super::bitstream::BitStream;
use super::crypto::decrypt_ace_data;
use super::header::CompressionType;
use super::lz77::Lz77Decoder;
#[derive(Clone)]
pub struct AcePasswordVerifier {
compressed_data: Arc<[u8]>,
compression_type: CompressionType,
expected_crc: u32,
original_size: u64,
dictionary_size: usize,
entry_name: String,
}
unsafe impl Send for AcePasswordVerifier {}
unsafe impl Sync for AcePasswordVerifier {}
impl AcePasswordVerifier {
pub fn new(
compressed_data: Vec<u8>,
compression_type: CompressionType,
expected_crc: u32,
original_size: u64,
dictionary_size: usize,
entry_name: String,
) -> Self {
Self {
compressed_data: Arc::from(compressed_data.into_boxed_slice()),
compression_type,
expected_crc,
original_size,
dictionary_size,
entry_name,
}
}
pub fn entry_name(&self) -> &str {
&self.entry_name
}
pub fn compressed_size(&self) -> usize {
self.compressed_data.len()
}
pub fn original_size(&self) -> u64 {
self.original_size
}
pub fn verify(&self, password: &str) -> bool {
let decrypted = decrypt_ace_data(&self.compressed_data, password);
self.decompress_and_verify(&decrypted).unwrap_or(false)
}
fn decompress_and_verify(&self, decrypted: &[u8]) -> crate::error::Result<bool> {
let decompressed = match self.compression_type {
CompressionType::Stored => decrypted.to_vec(),
CompressionType::Lz77 | CompressionType::Blocked => {
let mut decoder = Lz77Decoder::new();
decoder.set_dictionary_size(self.dictionary_size);
let cursor = Cursor::new(decrypted);
let mut bs = BitStream::new(cursor, decrypted.len());
match decoder.decompress(&mut bs, self.original_size as usize) {
Ok(data) => data,
Err(_) => return Ok(false),
}
}
CompressionType::Unknown(_) => {
return Ok(false);
}
};
if decompressed.len() != self.original_size as usize {
return Ok(false);
}
let checksum = !crc32fast::hash(&decompressed);
Ok(checksum == self.expected_crc)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_verifier_is_send_sync() {
fn assert_send_sync<T: Send + Sync>() {}
assert_send_sync::<AcePasswordVerifier>();
}
}