mirror of
https://github.com/storytold/craft-libs.git
synced 2026-11-12 08:52:32 +00:00
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.
58 lines
2.0 KiB
Rust
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);
|
|
}
|
|
}
|