fn main() {
use ese_core::EseDatabase;
use forensicnomicon::srum::TABLE_APP_RESOURCE_USAGE;
for (name, fixture) in &[
("chainsaw", "tests/data/srudb/chainsaw_SRUDB.dat"),
("rathbunvm_win10", "tests/data/srudb/museum_rathbunvm_win10_SRUDB.dat"),
("rathbunvm_win11", "tests/data/srudb/museum_rathbunvm_win11_SRUDB.dat"),
] {
let path = std::path::Path::new(fixture);
if !path.exists() { println!("{name}: MISSING"); continue; }
let db = EseDatabase::open(path).expect("open");
let Ok(cursor) = db.table_records(TABLE_APP_RESOURCE_USAGE) else {
println!("{name}: table missing"); continue;
};
let mut len_freq: std::collections::HashMap<usize, u64> = std::collections::HashMap::new();
let mut col_data_samples: Vec<usize> = Vec::new();
let mut count = 0u64;
for r in cursor {
let Ok((_, _, data)) = r else { continue };
if data.len() < 2 { continue; }
let cb_pfx = u16::from_le_bytes([data[0], data[1]]) as usize;
*len_freq.entry(data.len()).or_insert(0) += 1;
if cb_pfx <= 16 {
let col_start = 2 + (16 - cb_pfx);
if data.len() > col_start {
col_data_samples.push(data.len() - col_start);
}
}
count += 1;
}
let most_common_col_data = col_data_samples.iter()
.fold(std::collections::HashMap::new(), |mut m, &v| { *m.entry(v).or_insert(0u64) += 1; m })
.into_iter().max_by_key(|&(_, cnt)| cnt)
.map(|(len, _)| len);
let mut lens: Vec<(usize, u64)> = len_freq.into_iter().collect();
lens.sort_by_key(|&(_, cnt)| std::cmp::Reverse(cnt));
let lens_str: Vec<String> = lens.iter().take(5).map(|(l, c)| format!("len={l}:{c}")).collect();
println!("{name}: total={count} most_common_col_data={most_common_col_data:?} len_freq=[{}]", lens_str.join(", "));
}
}
struct Reverse<T>(T);
impl<T: Ord> Ord for Reverse<T> { fn cmp(&self, o: &Self) -> std::cmp::Ordering { o.0.cmp(&self.0) } }
impl<T: Ord> PartialOrd for Reverse<T> { fn partial_cmp(&self, o: &Self) -> Option<std::cmp::Ordering> { Some(self.cmp(o)) } }
impl<T: Eq> Eq for Reverse<T> {}
impl<T: PartialEq> PartialEq for Reverse<T> { fn eq(&self, o: &Self) -> bool { self.0 == o.0 } }