Skip to main content

dump_menuitems/
dump_menuitems.rs

1//! Validation helper: decode and dump Apple Biome `App.MenuItem` records
2//! (application name + menu-item text + timestamp) from a SEGB stream.
3//!
4//! Where `dump_structure` reconciles the *container* (state / timestamp / CRC)
5//! against `ccl-segb`, this dumps the decoded *protobuf fields* so the field
6//! mapping itself — field 1 = `application`, field 2 = `menu_item` — can be
7//! reconciled against the *known* menu selections driven on a real macOS Tahoe
8//! system. That closes the gap neither `dump_structure` (container only) nor the
9//! iOS corpus (no menu bar) can: `ccl-segb` hands back raw payload bytes, so it
10//! cannot be the oracle for the protobuf interpretation — the driven selections
11//! are.
12//!
13//! Only `Written` records carry a live payload (a `Deleted` record's payload is
14//! wiped), matching the `segb-forensic` analyzer's Written-only audit.
15//!
16//! Usage: `cargo run -p segb-core --example dump_menuitems -- <segb-file>`
17#![allow(clippy::unwrap_used, clippy::expect_used)]
18
19use segb::common::EntryState;
20
21fn main() {
22    let path = std::env::args()
23        .nth(1)
24        .expect("usage: dump_menuitems <segb-file>");
25    let data = std::fs::read(&path).expect("read file");
26    let mut cur = std::io::Cursor::new(data);
27    let records = segb::read_segb(&mut cur).expect("parse SEGB");
28    let mut decoded = 0usize;
29    for (i, r) in records.iter().enumerate() {
30        if r.state() != EntryState::Written {
31            continue;
32        }
33        match segb::menuitem::decode_app_menu_item(r.payload(), r.timestamp_unix()) {
34            Ok(m) => {
35                println!(
36                    "  [{i}] application={:?} menu_item={:?} ts_unix={:?}",
37                    m.application, m.menu_item, m.timestamp_unix
38                );
39                decoded += 1;
40            }
41            Err(e) => println!("  [{i}] decode_error={e}"),
42        }
43    }
44    println!("menu_items: {decoded}");
45}