fn main() { for path_str in [ "_images/_psd_stil_test/hc_drop_shadow.psd", "_images/_psd_stil_test/fx_drop_shadow.psd", ] { println!("\n========================================\nFILE: {}", path_str); let path = std::path::Path::new(path_str); let bytes = std::fs::read(path).unwrap(); let mut r = hcie_psd::psd_reader::PsdReader::new(&bytes); r.read(26).unwrap(); let color_mode_len = r.read_u32().unwrap() as usize; r.read(color_mode_len).unwrap(); let img_res_len = r.read_u32().unwrap() as usize; r.read(img_res_len).unwrap(); let _layer_mask_len_val = r.read_u32().unwrap() as usize; let _layer_info_len = r.read_u32().unwrap() as usize; let layer_count_raw = r.read_i16().unwrap(); let layer_count = layer_count_raw.abs() as usize; for _idx in 0..layer_count { let _top = r.read_i32().unwrap(); let _left = r.read_i32().unwrap(); let _bottom = r.read_i32().unwrap(); let _right = r.read_i32().unwrap(); let channel_count = r.read_u16().unwrap() as usize; for _ in 0..channel_count { let _id = r.read_i16().unwrap(); let _len = r.read_u32().unwrap(); } r.read(4).unwrap(); r.read(4).unwrap(); r.read_u8().unwrap(); r.read_u8().unwrap(); r.read_u8().unwrap(); r.read(1).unwrap(); let extra_data_len = r.read_u32().unwrap() as usize; let extra_start = r.pos(); let layer_mask_len = r.read_u32().unwrap() as usize; r.read(layer_mask_len).unwrap(); let blending_ranges_len = r.read_u32().unwrap() as usize; r.read(blending_ranges_len).unwrap(); let name_len = r.read_u8().unwrap() as usize; let name_bytes = r.read(name_len).unwrap(); let name = String::from_utf8_lossy(name_bytes).to_string(); let bytes_mod_4 = (name_len + 1) % 4; let padding = (4 - bytes_mod_4) % 4; r.read(padding).unwrap(); while r.pos() < extra_start + extra_data_len { let sig = r.read(4).unwrap(); if sig != b"8BIM" && sig != b"8B64" { break; } let key_bytes = r.read(4).unwrap(); let key = String::from_utf8_lossy(key_bytes).to_string(); let block_len = r.read_u32().unwrap() as usize; let block_start = r.pos(); if key == "lfx2" { let data = r.read(block_len).unwrap().to_vec(); println!("Layer '{}' lfx2 block: {} bytes", name, data.len()); // Try different offsets to parse top-level descriptor for offset in [0, 4, 8, 10, 14, 16] { if let Some((entries, _)) = hcie_fx::parser::parse_descriptor_body(&data, offset) { if !entries.is_empty() { println!(" Parsed at offset {} with {} entries", offset, entries.len()); dump_entries(&entries, 2); } } } } else { r.read(block_len).unwrap(); } r.seek(block_start + block_len).unwrap(); if block_len % 2 != 0 { r.read(1).unwrap(); } } r.seek(extra_start + extra_data_len).unwrap(); } } } fn dump_entries(entries: &[( [u8; 4], hcie_fx::parser::DescValue)], depth: usize) { let indent = " ".repeat(depth); for (k, v) in entries { let key_str = String::from_utf8_lossy(k).to_string(); match v { hcie_fx::parser::DescValue::Bool(b) => println!("{}{}: bool = {}", indent, key_str, b), hcie_fx::parser::DescValue::Long(l) => println!("{}{}: long = {}", indent, key_str, l), hcie_fx::parser::DescValue::Double(d) => println!("{}{}: double = {:.4}", indent, key_str, d), hcie_fx::parser::DescValue::UnitFloat { unit, value } => { println!("{}{}: unit_float({:?}) = {:.4}", indent, key_str, String::from_utf8_lossy(unit), value); } hcie_fx::parser::DescValue::Enum { class_id, value } => { println!("{}{}: enum({:?}) = {:?}", indent, key_str, String::from_utf8_lossy(class_id), String::from_utf8_lossy(value)); } hcie_fx::parser::DescValue::Object(sub) => { println!("{}{}: Objc({})", indent, key_str, sub.len()); dump_entries(sub, depth + 1); } hcie_fx::parser::DescValue::List(items) => { println!("{}{}: List({})", indent, key_str, items.len()); for (i, item) in items.iter().enumerate() { println!("{} [{}]: {:?}", indent, i, std::mem::discriminant(item)); if let hcie_fx::parser::DescValue::Object(sub) = item { dump_entries(sub, depth + 2); } } } _ => println!("{}{}: Unknown", indent, key_str), } } }