mirror of
https://github.com/Ap0dexMe0/unixtract.git
synced 2026-07-15 21:00:03 +02:00
funai_bdp: add support of uncmpr(sparse like) and decompressing image rom
This commit is contained in:
@@ -6,10 +6,62 @@ pub struct IndexTableEntry {
|
|||||||
name_bytes: [u8; 32],
|
name_bytes: [u8; 32],
|
||||||
pub offset: u32,
|
pub offset: u32,
|
||||||
pub size: u32,
|
pub size: u32,
|
||||||
_unk: u32,
|
_checksum: u32,
|
||||||
}
|
}
|
||||||
impl IndexTableEntry {
|
impl IndexTableEntry {
|
||||||
pub fn name(&self) -> String {
|
pub fn name(&self) -> String {
|
||||||
common::string_from_bytes(&self.name_bytes)
|
common::string_from_bytes(&self.name_bytes)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//cmpr
|
||||||
|
|
||||||
|
#[derive(BinRead)]
|
||||||
|
pub struct CmprHeader {
|
||||||
|
pub out_checksum: u32,
|
||||||
|
pub count: u32,
|
||||||
|
pub data_size: u32,
|
||||||
|
#[br(count=count)] pub entries: Vec<CmprEntry>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(BinRead)]
|
||||||
|
pub struct CmprEntry {
|
||||||
|
pub size: u32,
|
||||||
|
pub mode: u32,
|
||||||
|
pub fill: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
//dumb check, since this information is not stored in header
|
||||||
|
pub fn is_cmpr(data: &[u8], size: u32) -> bool {
|
||||||
|
if data.len() < 0x20+12 {return false};
|
||||||
|
|
||||||
|
let count = u32::from_le_bytes(data[0x20+4..0x20+8].try_into().unwrap());
|
||||||
|
let data_size = u32::from_le_bytes(data[0x20+8..0x20+12].try_into().unwrap());
|
||||||
|
|
||||||
|
if count > size || data_size > size {return false};
|
||||||
|
|
||||||
|
return (size - 0x20 - (count*12) - 12) == data_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
//image rom
|
||||||
|
#[derive(BinRead)]
|
||||||
|
pub struct ImageRomHeader {
|
||||||
|
pub count: u32,
|
||||||
|
_unk: u32,
|
||||||
|
_pad1: [u8; 8],
|
||||||
|
_entry_table_sha1: [u8; 20],
|
||||||
|
_pad2: [u8; 12],
|
||||||
|
pub start_offset: u32,
|
||||||
|
_pad3: [u8; 12],
|
||||||
|
#[br(count=count)] pub entries: Vec<ImageRomEntry>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(BinRead)]
|
||||||
|
pub struct ImageRomEntry {
|
||||||
|
_decompressed_sha1: [u8; 20],
|
||||||
|
_compressed_sha1: [u8; 20],
|
||||||
|
_pad1: [u8; 8],
|
||||||
|
pub offset: u32, //relative to start_offset in header
|
||||||
|
pub size: u32,
|
||||||
|
_pad2: [u8; 8],
|
||||||
}
|
}
|
||||||
@@ -7,10 +7,11 @@ use std::fs::{self, OpenOptions};
|
|||||||
use std::io::{Cursor, Read, Seek, SeekFrom, Write};
|
use std::io::{Cursor, Read, Seek, SeekFrom, Write};
|
||||||
use binrw::BinReaderExt;
|
use binrw::BinReaderExt;
|
||||||
|
|
||||||
use crate::utils::common;
|
use crate::utils::common::{self, read_exact};
|
||||||
use crate::formats::funai_upg::funai_des::funai_des_decrypt;
|
use crate::formats::funai_upg::funai_des::funai_des_decrypt;
|
||||||
use include::*;
|
use include::*;
|
||||||
use crate::keys;
|
use crate::keys;
|
||||||
|
use crate::utils::compression::decompress_zlib;
|
||||||
|
|
||||||
pub struct FunaiBdpContext {
|
pub struct FunaiBdpContext {
|
||||||
key: u32,
|
key: u32,
|
||||||
@@ -58,18 +59,85 @@ pub fn extract_funai_bdp(app_ctx: &AppContext, ctx: Box<dyn Any>) -> Result<(),
|
|||||||
println!("\n({}/{}) - {}, Offset: {}, Size: {}", i +1, index_entry_count, entry.name(), entry.offset, entry.size);
|
println!("\n({}/{}) - {}, Offset: {}, Size: {}", i +1, index_entry_count, entry.name(), entry.offset, entry.size);
|
||||||
|
|
||||||
file_reader.seek(SeekFrom::Start(entry.offset as u64))?;
|
file_reader.seek(SeekFrom::Start(entry.offset as u64))?;
|
||||||
let data = common::read_exact(&mut file_reader, entry.size as usize)?;
|
let mut data = common::read_exact(&mut file_reader, entry.size as usize)?;
|
||||||
|
|
||||||
|
if is_cmpr(&data, entry.size) {
|
||||||
|
println!("- cmpr detected!, 'uncompressing' data...");
|
||||||
|
data = uncmpr_data(&data)?;
|
||||||
|
|
||||||
|
} else if entry.name().ends_with("_image_rom") {
|
||||||
|
println!("- Decompressing image ROM...");
|
||||||
|
data = uncomp_image_rom(&data)?;
|
||||||
|
|
||||||
|
} else {//strip partition name at start
|
||||||
|
data = data[0x20..].to_vec()
|
||||||
|
}
|
||||||
|
|
||||||
let output_path = Path::new(&app_ctx.output_dir).join(format!("{}.bin", entry.name()));
|
let output_path = Path::new(&app_ctx.output_dir).join(format!("{}.bin", entry.name()));
|
||||||
|
|
||||||
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)?;
|
||||||
|
|
||||||
//at start of location there is an additional 0x20 with the entry's name
|
out_file.write_all(&data)?;
|
||||||
out_file.write_all(&data[0x20..])?;
|
|
||||||
|
|
||||||
println!("-- Saved file!");
|
println!("-- Saved file!");
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn uncmpr_data(data: &[u8]) -> Result<Vec<u8>, Box<dyn std::error::Error>> {
|
||||||
|
let mut data_reader = Cursor::new(data);
|
||||||
|
let _part_name = read_exact(&mut data_reader, 0x20)?;
|
||||||
|
let cmpr_header: CmprHeader = data_reader.read_le()?;
|
||||||
|
println!("[cmpr] out chk: {:02x}, count: {}, data size: {}",
|
||||||
|
cmpr_header.out_checksum, cmpr_header.count, cmpr_header.data_size);
|
||||||
|
|
||||||
|
let mut out_data: Vec<u8> = Vec::new();
|
||||||
|
|
||||||
|
for (i, entry) in cmpr_header.entries.iter().enumerate() {
|
||||||
|
println!("[cmpr] ({}/{}) size: {}, mode: {}, fill: {:02x}",
|
||||||
|
i+1, cmpr_header.count, entry.size, entry.mode, entry.fill);
|
||||||
|
|
||||||
|
let mut data;
|
||||||
|
if entry.mode == 0 { //raw data
|
||||||
|
data = read_exact(&mut data_reader, entry.size as usize)?;
|
||||||
|
|
||||||
|
} else if entry.mode == 1 { //fill data
|
||||||
|
data = vec![entry.fill as u8; entry.size as usize];
|
||||||
|
|
||||||
|
} else {
|
||||||
|
return Err("invalid/unknown entry mode value!".into());
|
||||||
|
};
|
||||||
|
|
||||||
|
out_data.append(&mut data);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(out_data)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn uncomp_image_rom(data: &[u8]) -> Result<Vec<u8>, Box<dyn std::error::Error>> {
|
||||||
|
let mut data_reader = Cursor::new(data);
|
||||||
|
let _part_name = read_exact(&mut data_reader, 0x20)?;
|
||||||
|
let header: ImageRomHeader = data_reader.read_le()?;
|
||||||
|
println!("[rom] count: {}", header.count);
|
||||||
|
|
||||||
|
let mut out_data: Vec<u8> = Vec::new();
|
||||||
|
|
||||||
|
for (i, entry) in header.entries.iter().enumerate() {
|
||||||
|
let offset = header.start_offset + entry.offset;
|
||||||
|
|
||||||
|
println!("[rom] ({}/{}) offset: {}, size: {}",
|
||||||
|
i+1, header.count, offset, entry.size);
|
||||||
|
|
||||||
|
data_reader.seek(SeekFrom::Start(offset as u64))?;
|
||||||
|
let compr_data = read_exact(&mut data_reader, entry.size as usize)?;
|
||||||
|
|
||||||
|
println!("[rom] - Decompressing...");
|
||||||
|
let mut decomp_data = decompress_zlib(&compr_data)?;
|
||||||
|
|
||||||
|
out_data.append(&mut decomp_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(out_data)
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user