Files
craft-libs/crates/psd/examples/atn_roundtrip.rs
Dylan M. Taylor ee78a9bd46 craft-psd: Photoshop PSD/PSB reader and writer, moved from PhotoCraft (#875)
PhotoCraft's `photocraft-psd` crate (crates/psd at storytold/photocraft
63b641b55e54bf8f5c83efd977fdb16a2c255431) as `craft-psd`: the lossless
PSD/PSB model, reader, writer and builder, descriptors, the Photoshop
resource files that share its primitives (.abr, .asl, .aco, .act, .ase,
.grd, .pat, .atn, .csh, .shc) and the Photoshop blocks of a layered TIFF.
The crate had no dependency on any other PhotoCraft crate.

Code is unchanged apart from the crate name, craft-libs' rustfmt width,
comments that named other PhotoCraft crates, issue references (now
`photocraft#N`), and the corpus tests' directory (`CRAFT_PSD_CORPUS` or
`corpus/` at the workspace root). Tests, proptests, fuzz targets and
fixtures move with it.

Part of #778, #786.
2026-11-11 17:00:33 -05:00

58 lines
2.0 KiB
Rust

//! Check `.atn` files for byte-exact round trips: parse, write, compare, and show the first
//! difference with its context: `cargo run -p craft-psd --example atn_roundtrip -- set.atn…`
//!
//! Exit status 1 when any file differs or fails to parse.
use craft_psd::atn;
fn hex(b: &[u8]) -> String {
b.iter().map(|x| format!("{x:02x}")).collect::<Vec<_>>().join(" ")
}
fn main() {
let mut failed = false;
for path in std::env::args().skip(1) {
let bytes = match std::fs::read(&path) {
Ok(b) => b,
Err(e) => {
eprintln!("{path}: {e}");
failed = true;
continue;
}
};
let file = match atn::parse(&bytes) {
Ok(f) => f,
Err(e) => {
println!("{path}: parse failed: {e}");
failed = true;
continue;
}
};
let written = match atn::write(&file) {
Ok(w) => w,
Err(e) => {
println!("{path}: write failed: {e}");
failed = true;
continue;
}
};
if written == bytes {
println!("{path}: identical ({} bytes)", bytes.len());
continue;
}
failed = true;
let at = bytes.iter().zip(&written).position(|(a, b)| a != b).unwrap_or(bytes.len().min(written.len()));
let lo = at.saturating_sub(24);
println!("{path}: differs at byte {at} (original {} bytes, rewritten {} bytes)", bytes.len(), written.len());
println!(" original : {}", hex(bytes.get(lo..(at + 40).min(bytes.len())).unwrap_or(&[])));
println!(" rewritten: {}", hex(written.get(lo..(at + 40).min(written.len())).unwrap_or(&[])));
println!(
" original : {}",
String::from_utf8_lossy(bytes.get(lo..(at + 40).min(bytes.len())).unwrap_or(&[])).replace(|c: char| c.is_control(), ".")
);
}
if failed {
std::process::exit(1);
}
}