mirror of
https://github.com/Ap0dexMe0/unixtract.git
synced 2026-07-15 21:00:03 +02:00
improvements to slp
This commit is contained in:
+37
-25
@@ -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,
|
||||
}
|
||||
+72
-33
@@ -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<Option<Box<dyn Any>>, Box<dyn std::error::Error>> {
|
||||
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<dyn Any>) -> Result<(), Box<dyn std::error::Error>> {
|
||||
pub fn extract_slp(app_ctx: &AppContext, ctx: Box<dyn Any>) -> Result<(), Box<dyn std::error::Error>> {
|
||||
let mut file = app_ctx.file().ok_or("Extractor expected file")?;
|
||||
let ctx = ctx.downcast::<SlpContext>().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<EntryOld> = 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<u32> = 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<EntryCommon> = 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(())
|
||||
|
||||
Reference in New Issue
Block a user