| 1 | use onestore::{PropertySets, Reference, Store}; |
| 2 | use std::{env, fs}; |
| 3 | |
| 4 | fn main() -> Result<(), Box<dyn std::error::Error>> { |
| 5 | for path in env::args_os().skip(1) { |
| 6 | let bytes = fs::read(&path)?; |
| 7 | let store = Store::parse(&bytes)?; |
| 8 | let mut count = 0; |
| 9 | for list in store.lists.values() { |
| 10 | for node in &list.nodes { |
| 11 | if node.id == 0x7c { |
| 12 | return Err("Encrypted object space requires revision-aware inspection".into()); |
| 13 | } |
| 14 | if matches!( |
| 15 | node.id, |
| 16 | 0xa4 | 0xa5 | 0xc4 | 0xc5 | 0x2d | 0x2e | 0x41 | 0x42 |
| 17 | ) && let Some(Reference::Data(chunk)) = node.reference |
| 18 | { |
| 19 | let start = usize::try_from(chunk.offset)?; |
| 20 | let end = start |
| 21 | .checked_add(usize::try_from(chunk.length)?) |
| 22 | .ok_or("Property range exceeds address space")?; |
| 23 | let properties = PropertySets::parse( |
| 24 | bytes |
| 25 | .get(start..end) |
| 26 | .ok_or("Property range extends outside the file")?, |
| 27 | ) |
| 28 | .map_err(|error| { |
| 29 | format!( |
| 30 | "{:?}, node {:#x}, data {start:#x}: {error}", |
| 31 | path, node.offset |
| 32 | ) |
| 33 | })?; |
| 34 | count += properties.sets.iter().map(Vec::len).sum::<usize>(); |
| 35 | } |
| 36 | } |
| 37 | } |
| 38 | println!("{:?}: {count} properties", path); |
| 39 | } |
| 40 | Ok(()) |
| 41 | } |