From 5cc00a773dc2b681ad226e513593460297b92655 Mon Sep 17 00:00:00 2001 From: theubusu <80545678+theubusu@users.noreply.github.com> Date: Thu, 9 Apr 2026 22:23:55 +0200 Subject: [PATCH] improvements to slp --- src/formats/slp/include.rs | 62 +++++++++++++--------- src/formats/slp/mod.rs | 105 +++++++++++++++++++++++++------------ 2 files changed, 109 insertions(+), 58 deletions(-) diff --git a/src/formats/slp/include.rs b/src/formats/slp/include.rs index cc31b6d..053ecc2 100644 --- a/src/formats/slp/include.rs +++ b/src/formats/slp/include.rs @@ -1,43 +1,55 @@ use crate::utils::common; use binrw::BinRead; +#[derive(PartialEq, Eq, Debug)] +pub enum SlpVariant { + Old, + Old2, + New, +} + #[derive(BinRead)] -pub struct Header { +pub struct CommonMetaHeader { _magic_bytes: [u8; 4], - version_bytes: [u8; 8], - model_bytes: [u8; 16], - firmware_bytes: [u8; 16], - _unk: u32, - check: [u8; 8], - _unk2: [u8; 8], + user_version_bytes: [u8; 8], + project_name_bytes: [u8; 16], + firmware_version_bytes: [u8; 16], } -impl Header { - pub fn version(&self) -> String { - common::string_from_bytes(&self.version_bytes) +impl CommonMetaHeader { + pub fn user_version(&self) -> String { + common::string_from_bytes(&self.user_version_bytes) } - pub fn model(&self) -> String { - common::string_from_bytes(&self.model_bytes) + pub fn project_name(&self) -> String { + common::string_from_bytes(&self.project_name_bytes) } - pub fn firmware(&self) -> String { - common::string_from_bytes(&self.firmware_bytes) - } - pub fn is_new_type(&self) -> bool { - &self.check == b"\x01VER_PR1" + pub fn firmware_version(&self) -> String { + common::string_from_bytes(&self.firmware_version_bytes) } } #[derive(BinRead)] -pub struct EntryOld { - pub size: u32, - pub _unk: u32, - pub offset: u32, - pub _unk2: u32, +pub struct MetaHeaderExtOld { + pub snapshot_included: u8, + pub snapshot_entry_offset: u32, + _unuse: [u8; 15] } #[derive(BinRead)] -pub struct EntryNew { +pub struct MetaHeaderExtNew { + pub num_image: u32, + pub snapshot_included: u8, + snapshot_board_version_bytes: [u8; 15] +} +impl MetaHeaderExtNew { + pub fn snapshot_board_version(&self) -> String { + common::string_from_bytes(&self.snapshot_board_version_bytes) + } +} + +#[derive(BinRead)] +pub struct EntryCommon { pub size: u32, - _unk: u32, + _crc32: u32, pub offset: u32, - _unk2: [u8; 12], + pub magic: u32, } \ No newline at end of file diff --git a/src/formats/slp/mod.rs b/src/formats/slp/mod.rs index 6b3813b..a85fc1e 100644 --- a/src/formats/slp/mod.rs +++ b/src/formats/slp/mod.rs @@ -10,64 +10,103 @@ use binrw::BinReaderExt; use crate::utils::common; use include::*; +pub struct SlpContext { + variant: SlpVariant, +} + pub fn is_slp_file(app_ctx: &AppContext) -> Result>, Box> { let file = match app_ctx.file() {Some(f) => f, None => return Ok(None)}; let header = common::read_file(&file, 0, 4)?; if header == b"SLP\x00" { - Ok(Some(Box::new(()))) + let check = common::read_file(&file, 44, 1)?[0]; + let variant: SlpVariant; + if check == 0 || check == 1 { + variant = SlpVariant::Old + } + else if check == 5 || check == 6 { //? + variant = SlpVariant::Old2 + } + else { + variant = SlpVariant::New + } + + Ok(Some(Box::new(SlpContext {variant}))) } else { Ok(None) } } -pub fn extract_slp(app_ctx: &AppContext, _ctx: Box) -> Result<(), Box> { +pub fn extract_slp(app_ctx: &AppContext, ctx: Box) -> Result<(), Box> { let mut file = app_ctx.file().ok_or("Extractor expected file")?; + let ctx = ctx.downcast::().expect("Missing context"); - let header: Header = file.read_le()?; - println!("File info:\nModel: {}\nVersion: {}\nFirmware: {}\nNew type: {}\n", - header.model(), header.version(), header.firmware(), header.is_new_type()); + let meta_header: CommonMetaHeader = file.read_le()?; + println!("File info:\nType: {:?}\nProject name: {}\nFirmware Version: {}\nFirmware Version(USER): {}", + ctx.variant, meta_header.project_name(), meta_header.firmware_version(), meta_header.user_version()); - let mut first_entry_offset = 0; - let mut entries: Vec = Vec::new(); - - for i in 0..100 { - if (i != 0) && (file.stream_position()? >= first_entry_offset) { - break - } - let offset; - let size; - if header.is_new_type() { - let entry: EntryNew = file.read_le()?; - offset = entry.offset; - size = entry.size; + let num_image; + let mut snapshot_entry_offset: Option = None; + if ctx.variant == SlpVariant::New { + let meta_header_ext: MetaHeaderExtNew = file.read_le()?; + if meta_header_ext.snapshot_included == 0x01 { + println!("Snapshot Image: Included"); + println!("S/S Img. Board Version: {}", meta_header_ext.snapshot_board_version()) } else { - let entry: EntryOld = file.read_le()?; - offset = entry.offset; - size = entry.size; + println!("Snapshot Image: Excluded"); } - if i == 0 { - first_entry_offset = offset as u64; + num_image = meta_header_ext.num_image; + } + else if ctx.variant == SlpVariant::Old { + let meta_header_ext: MetaHeaderExtOld = file.read_le()?; + if meta_header_ext.snapshot_included == 0x01 { + println!("Snapshot Image: Included"); + println!("Snapshot Image offset: {}", meta_header_ext.snapshot_entry_offset); + snapshot_entry_offset = Some(meta_header_ext.snapshot_entry_offset); + } else { + println!("Snapshot Image: Excluded"); } - println!("{}. Offset: {}, Size: {}", i + 1, offset, size); - entries.push(EntryOld {size: size, _unk: 0, offset: offset, _unk2: 0}); + num_image = 5; //hardcoded for old variant + } + else if ctx.variant == SlpVariant::Old2 { + let meta_header_ext: MetaHeaderExtNew = file.read_le()?; + //snapshot fields of new meta_header_ext are not used in this case + num_image = meta_header_ext.num_image; + } + else { + return Err("invalid slp variant".into()); } - let mut i = 1; - for entry in &entries { - println!("\n({}/{}) - Offset: {}, Size: {}", i, &entries.len(), entry.offset, entry.size); + let mut entries: Vec = Vec::new(); + + for _i in 0..num_image { + let entry: EntryCommon = file.read_le()?; + if ctx.variant == SlpVariant::New { + let _version_bytes = common::read_exact(&mut file, 8)?; + } + entries.push(entry); + } + + //push additional snapshot entry + if let Some(offset) = snapshot_entry_offset { + file.seek(SeekFrom::Start(offset as u64))?; + let entry: EntryCommon = file.read_le()?; + entries.push(entry); + } + + for (i, entry) in entries.iter().enumerate() { + println!("\n({}/{}) - Offset: {}, Size: {}, Magic: 0x{:02X}", i+1, &entries.len(), entry.offset, entry.size, entry.magic); + + let output_path = Path::new(&app_ctx.output_dir).join(format!("{}.bin", i+1)); + file.seek(SeekFrom::Start(entry.offset.into()))?; let data = common::read_exact(&mut file, entry.size as usize)?; - - let output_path = Path::new(&app_ctx.output_dir).join(format!("{}.bin", i)); - + fs::create_dir_all(&app_ctx.output_dir)?; let mut out_file = OpenOptions::new().write(true).create(true).open(output_path)?; out_file.write_all(&data)?; println!("- Saved file!"); - - i += 1; } Ok(())