use std::fs::File;
use std::io::Read;
use std::path::Path;
pub fn is_compressible(path: &Path) -> bool {
let mut file = match File::open(path) {
Ok(f) => f,
Err(_) => return false, };
let mut buffer = [0u8; 4096];
let bytes_read = match file.read(&mut buffer) {
Ok(n) if n > 0 => n,
Ok(_) => return false, Err(_) => return false,
};
if bytes_read < 128 {
return true;
}
let compressed_estimate = estimate_rle_size(&buffer[..bytes_read]);
let ratio = compressed_estimate as f32 / bytes_read as f32;
ratio < 0.95
}
pub fn estimate_size(path: &Path) -> u64 {
let mut file = match File::open(path) {
Ok(f) => f,
Err(_) => return 0,
};
let meta = match file.metadata() {
Ok(m) => m,
Err(_) => return 0,
};
let total_size = meta.len();
if total_size == 0 { return 0; }
let mut buffer = [0u8; 4096];
let bytes_read = match file.read(&mut buffer) {
Ok(n) if n > 0 => n,
_ => return total_size,
};
let est_header = estimate_rle_size(&buffer[..bytes_read]); let ratio = est_header as f64 / bytes_read as f64;
(total_size as f64 * ratio) as u64
}
fn estimate_rle_size(data: &[u8]) -> usize {
let mut estimated_size = 0;
let mut i = 0;
while i < data.len() {
let current = data[i];
let mut run_length = 1;
while i + run_length < data.len() && data[i + run_length] == current && run_length < 255 {
run_length += 1;
}
i += run_length;
estimated_size += 2; }
if estimated_size > data.len() {
return shannon_entropy_check(data);
}
estimated_size
}
fn shannon_entropy_check(data: &[u8]) -> usize {
let mut counts = [0usize; 256];
for &b in data {
counts[b as usize] += 1;
}
let mut entropy = 0.0;
let len_f = data.len() as f32;
for &count in counts.iter() {
if count == 0 { continue; }
let p = count as f32 / len_f;
entropy -= p * p.log2();
}
if entropy > 7.5 {
return data.len(); } else {
return (data.len() as f32 * (entropy / 8.0)) as usize; }
}