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],
|
||||
pub offset: u32,
|
||||
pub size: u32,
|
||||
_unk: u32,
|
||||
_checksum: u32,
|
||||
}
|
||||
impl IndexTableEntry {
|
||||
pub fn name(&self) -> String {
|
||||
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 binrw::BinReaderExt;
|
||||
|
||||
use crate::utils::common;
|
||||
use crate::utils::common::{self, read_exact};
|
||||
use crate::formats::funai_upg::funai_des::funai_des_decrypt;
|
||||
use include::*;
|
||||
use crate::keys;
|
||||
use crate::utils::compression::decompress_zlib;
|
||||
|
||||
pub struct FunaiBdpContext {
|
||||
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);
|
||||
|
||||
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()));
|
||||
|
||||
fs::create_dir_all(&app_ctx.output_dir)?;
|
||||
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[0x20..])?;
|
||||
out_file.write_all(&data)?;
|
||||
|
||||
println!("-- Saved file!");
|
||||
}
|
||||
|
||||
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