| 1 | use onestore::{ExGuid, FileDataReference, ObjectData, PropertySets, RevisionIndex, Store, Value}; |
| 2 | use std::{ |
| 3 | collections::BTreeSet, |
| 4 | env, |
| 5 | io::{self, Write}, |
| 6 | }; |
| 7 | |
| 8 | fn main() -> Result<(), Box<dyn std::error::Error>> { |
| 9 | let mut output = io::BufWriter::new(io::stdout().lock()); |
| 10 | for path in env::args_os().skip(1) { |
| 11 | let bytes = onestore::read_file(path)?; |
| 12 | let store = Store::parse(&bytes)?; |
| 13 | let index = RevisionIndex::parse(&store)?; |
| 14 | index.validate_current()?; |
| 15 | let mut seen = BTreeSet::new(); |
| 16 | let mut pending = vec![index.root]; |
| 17 | while let Some(osid) = pending.pop() { |
| 18 | if !seen.insert(osid) { |
| 19 | continue; |
| 20 | } |
| 21 | let rid = index.spaces[&osid].labels[&(ExGuid::default(), 1)]; |
| 22 | let revision = index.resolve(osid, rid)?; |
| 23 | for oid in revision.reachable()? { |
| 24 | let object = &revision.objects[&oid]; |
| 25 | pending.extend(object.references()?.object_spaces); |
| 26 | if object.jcid == 0x6000b { |
| 27 | let metadata = revision |
| 28 | .roots |
| 29 | .get(&2) |
| 30 | .map(|oid| revision.objects[oid].jcid) |
| 31 | .unwrap_or(0); |
| 32 | writeln!(output, "page\t{osid}\t{metadata:x}")?; |
| 33 | } |
| 34 | let mut record = None; |
| 35 | if object.jcid == 0x6000e |
| 36 | && let ObjectData::Properties(data) = object.data |
| 37 | { |
| 38 | let properties = PropertySets::parse(data)?; |
| 39 | let boiler = properties.sets[0] |
| 40 | .iter() |
| 41 | .any(|p| matches!(p.id, 0x88001c87 | 0x88001c88 | 0x88001cb5)); |
| 42 | record = Some(("ascii", &[][..])); |
| 43 | let property = properties.sets[0] |
| 44 | .iter() |
| 45 | .find(|property| property.id == 0x1c001c22) |
| 46 | .or_else(|| { |
| 47 | properties.sets[0] |
| 48 | .iter() |
| 49 | .find(|property| property.id == 0x1c003498) |
| 50 | }); |
| 51 | if let Some(property) = property |
| 52 | && let Value::Bytes(data) = property.value |
| 53 | { |
| 54 | record = Some(( |
| 55 | if property.id == 0x1c001c22 { |
| 56 | if boiler { "boiler-unicode" } else { "unicode" } |
| 57 | } else { |
| 58 | if boiler { "boiler-ascii" } else { "ascii" } |
| 59 | }, |
| 60 | data, |
| 61 | )); |
| 62 | } |
| 63 | } |
| 64 | if let Some(FileDataReference::Internal(guid)) = object.file_reference()? { |
| 65 | record = Some(("file", store.file_data(guid)?)); |
| 66 | } |
| 67 | if let Some((kind, data)) = record { |
| 68 | write!(output, "{kind}\t{osid}\t")?; |
| 69 | for byte in data { |
| 70 | write!(output, "{byte:02x}")?; |
| 71 | } |
| 72 | writeln!(output)?; |
| 73 | } |
| 74 | } |
| 75 | } |
| 76 | } |
| 77 | Ok(()) |
| 78 | } |