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:
+39
-27
@@ -1,43 +1,55 @@
|
|||||||
use crate::utils::common;
|
use crate::utils::common;
|
||||||
use binrw::BinRead;
|
use binrw::BinRead;
|
||||||
|
|
||||||
|
#[derive(PartialEq, Eq, Debug)]
|
||||||
|
pub enum SlpVariant {
|
||||||
|
Old,
|
||||||
|
Old2,
|
||||||
|
New,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(BinRead)]
|
#[derive(BinRead)]
|
||||||
pub struct Header {
|
pub struct CommonMetaHeader {
|
||||||
_magic_bytes: [u8; 4],
|
_magic_bytes: [u8; 4],
|
||||||
version_bytes: [u8; 8],
|
user_version_bytes: [u8; 8],
|
||||||
model_bytes: [u8; 16],
|
project_name_bytes: [u8; 16],
|
||||||
firmware_bytes: [u8; 16],
|
firmware_version_bytes: [u8; 16],
|
||||||
_unk: u32,
|
|
||||||
check: [u8; 8],
|
|
||||||
_unk2: [u8; 8],
|
|
||||||
}
|
}
|
||||||
impl Header {
|
impl CommonMetaHeader {
|
||||||
pub fn version(&self) -> String {
|
pub fn user_version(&self) -> String {
|
||||||
common::string_from_bytes(&self.version_bytes)
|
common::string_from_bytes(&self.user_version_bytes)
|
||||||
}
|
}
|
||||||
pub fn model(&self) -> String {
|
pub fn project_name(&self) -> String {
|
||||||
common::string_from_bytes(&self.model_bytes)
|
common::string_from_bytes(&self.project_name_bytes)
|
||||||
}
|
}
|
||||||
pub fn firmware(&self) -> String {
|
pub fn firmware_version(&self) -> String {
|
||||||
common::string_from_bytes(&self.firmware_bytes)
|
common::string_from_bytes(&self.firmware_version_bytes)
|
||||||
}
|
|
||||||
pub fn is_new_type(&self) -> bool {
|
|
||||||
&self.check == b"\x01VER_PR1"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(BinRead)]
|
#[derive(BinRead)]
|
||||||
pub struct EntryOld {
|
pub struct MetaHeaderExtOld {
|
||||||
pub size: u32,
|
pub snapshot_included: u8,
|
||||||
pub _unk: u32,
|
pub snapshot_entry_offset: u32,
|
||||||
pub offset: u32,
|
_unuse: [u8; 15]
|
||||||
pub _unk2: u32,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(BinRead)]
|
#[derive(BinRead)]
|
||||||
pub struct EntryNew {
|
pub struct MetaHeaderExtNew {
|
||||||
pub size: u32,
|
pub num_image: u32,
|
||||||
_unk: u32,
|
pub snapshot_included: u8,
|
||||||
pub offset: u32,
|
snapshot_board_version_bytes: [u8; 15]
|
||||||
_unk2: [u8; 12],
|
}
|
||||||
|
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,
|
||||||
|
_crc32: u32,
|
||||||
|
pub offset: u32,
|
||||||
|
pub magic: u32,
|
||||||
}
|
}
|
||||||
+71
-32
@@ -10,64 +10,103 @@ use binrw::BinReaderExt;
|
|||||||
use crate::utils::common;
|
use crate::utils::common;
|
||||||
use include::*;
|
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>> {
|
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 file = match app_ctx.file() {Some(f) => f, None => return Ok(None)};
|
||||||
|
|
||||||
let header = common::read_file(&file, 0, 4)?;
|
let header = common::read_file(&file, 0, 4)?;
|
||||||
if header == b"SLP\x00" {
|
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 {
|
} else {
|
||||||
Ok(None)
|
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 mut file = app_ctx.file().ok_or("Extractor expected file")?;
|
||||||
|
let ctx = ctx.downcast::<SlpContext>().expect("Missing context");
|
||||||
|
|
||||||
let header: Header = file.read_le()?;
|
let meta_header: CommonMetaHeader = file.read_le()?;
|
||||||
println!("File info:\nModel: {}\nVersion: {}\nFirmware: {}\nNew type: {}\n",
|
println!("File info:\nType: {:?}\nProject name: {}\nFirmware Version: {}\nFirmware Version(USER): {}",
|
||||||
header.model(), header.version(), header.firmware(), header.is_new_type());
|
ctx.variant, meta_header.project_name(), meta_header.firmware_version(), meta_header.user_version());
|
||||||
|
|
||||||
let mut first_entry_offset = 0;
|
let num_image;
|
||||||
let mut entries: Vec<EntryOld> = Vec::new();
|
let mut snapshot_entry_offset: Option<u32> = None;
|
||||||
|
if ctx.variant == SlpVariant::New {
|
||||||
for i in 0..100 {
|
let meta_header_ext: MetaHeaderExtNew = file.read_le()?;
|
||||||
if (i != 0) && (file.stream_position()? >= first_entry_offset) {
|
if meta_header_ext.snapshot_included == 0x01 {
|
||||||
break
|
println!("Snapshot Image: Included");
|
||||||
}
|
println!("S/S Img. Board Version: {}", meta_header_ext.snapshot_board_version())
|
||||||
let offset;
|
|
||||||
let size;
|
|
||||||
if header.is_new_type() {
|
|
||||||
let entry: EntryNew = file.read_le()?;
|
|
||||||
offset = entry.offset;
|
|
||||||
size = entry.size;
|
|
||||||
} else {
|
} else {
|
||||||
let entry: EntryOld = file.read_le()?;
|
println!("Snapshot Image: Excluded");
|
||||||
offset = entry.offset;
|
|
||||||
size = entry.size;
|
|
||||||
}
|
}
|
||||||
if i == 0 {
|
num_image = meta_header_ext.num_image;
|
||||||
first_entry_offset = offset as u64;
|
|
||||||
}
|
}
|
||||||
println!("{}. Offset: {}, Size: {}", i + 1, offset, size);
|
else if ctx.variant == SlpVariant::Old {
|
||||||
entries.push(EntryOld {size: size, _unk: 0, offset: offset, _unk2: 0});
|
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");
|
||||||
|
}
|
||||||
|
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;
|
let mut entries: Vec<EntryCommon> = Vec::new();
|
||||||
for entry in &entries {
|
|
||||||
println!("\n({}/{}) - Offset: {}, Size: {}", i, &entries.len(), entry.offset, entry.size);
|
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()))?;
|
file.seek(SeekFrom::Start(entry.offset.into()))?;
|
||||||
let data = common::read_exact(&mut file, entry.size as usize)?;
|
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)?;
|
fs::create_dir_all(&app_ctx.output_dir)?;
|
||||||
let mut out_file = OpenOptions::new().write(true).create(true).open(output_path)?;
|
let mut out_file = OpenOptions::new().write(true).create(true).open(output_path)?;
|
||||||
out_file.write_all(&data)?;
|
out_file.write_all(&data)?;
|
||||||
|
|
||||||
println!("- Saved file!");
|
println!("- Saved file!");
|
||||||
|
|
||||||
i += 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
Reference in New Issue
Block a user