pcf_debug/lib.rs
1//! `pcf-debug` — a read-only inspector and visualiser for Partitioned Container
2//! Format (PCF) files.
3//!
4//! The crate is organised as a pipeline:
5//!
6//! 1. [`model::walk`] reads the file's physical structure defensively.
7//! 2. [`model::build`] turns that into a [`model::LayoutMap`] with gaps and
8//! overlaps materialised.
9//! 3. [`plugin`] decoders turn each partition's bytes into a field tree.
10//! 4. [`render`] turns the shared [`render::Report`] into text, hexdumps, or
11//! HTML.
12//!
13//! The orchestration helper [`build_report`] runs steps 1–3; the binary in
14//! `main.rs` adds argument parsing and chooses a renderer.
15
16pub mod cli;
17pub mod model;
18pub mod plugin;
19pub mod render;
20
21use plugin::{DecoderRegistry, PartitionMeta};
22use render::Report;
23
24/// Read a partition's used bytes from the file image, or an empty slice when the
25/// region is out of bounds or empty.
26fn partition_bytes(data: &[u8], entry: &pcf::PartitionEntry, in_bounds: bool) -> Vec<u8> {
27 if in_bounds && entry.used_bytes > 0 {
28 let start = entry.start_offset as usize;
29 let end = (entry.start_offset + entry.used_bytes) as usize;
30 data[start..end].to_vec()
31 } else {
32 Vec::new()
33 }
34}
35
36/// Build the full report (physical layout + decoded partitions) from raw bytes.
37pub fn build_report(data: &[u8], verify: bool, registry: &DecoderRegistry) -> Report {
38 let walk = model::walk(data, verify);
39 let layout = model::build(&walk);
40
41 let mut decoded = Vec::new();
42 for b in &layout.blocks {
43 for ev in &b.entries {
44 let e = &ev.entry;
45 let bytes = partition_bytes(data, e, ev.data_in_bounds);
46 let label = e.label_string().unwrap_or_default();
47 let meta = PartitionMeta {
48 partition_type: e.partition_type,
49 uid: &e.uid,
50 label: &label,
51 };
52 decoded.push((e.uid, registry.decode(&meta, &bytes)));
53 }
54 }
55 Report { layout, decoded }
56}