From da80ff1d9a8291aa4d5b8620672b6017df3981ea Mon Sep 17 00:00:00 2001 From: dece Date: Tue, 19 May 2020 00:49:21 +0200 Subject: [PATCH] param: WIP combination with paramdef --- src/bin/rir.rs | 19 +++++++++++++++--- src/parsers/common.rs | 7 +++++++ src/parsers/param.rs | 31 ++++++++++++++++------------- src/unpackers/bhf.rs | 2 +- src/unpackers/param.rs | 42 ++++++++++++++++++++++++++++++++------- src/unpackers/paramdef.rs | 6 ++++++ 6 files changed, 82 insertions(+), 25 deletions(-) diff --git a/src/bin/rir.rs b/src/bin/rir.rs index 7bbd469..d94581d 100644 --- a/src/bin/rir.rs +++ b/src/bin/rir.rs @@ -217,8 +217,21 @@ fn cmd_paramdef(args: &ArgMatches) -> i32 { fn cmd_param(args: &ArgMatches) -> i32 { let file_path: &str = args.value_of("file").unwrap(); - match unpackers::param::load_param_file(file_path) { - Ok(param) => { unpackers::param::print_param_no_data(¶m); 0 } - Err(e) => { eprintln!("Failed to load PARAM: {:?}", e); 1 } + + if let Some(paramdef_path) = args.value_of("paramdef") { + match unpackers::paramdef::load_paramdef_file(paramdef_path) { + Ok(paramdef) => { + match unpackers::param::load_param_file(file_path, Some(¶mdef)) { + Ok(param) => { unpackers::param::print_param(¶m); 0 } + Err(e) => { eprintln!("Failed to load PARAM: {:?}", e); 1 } + } + } + Err(e) => { eprintln!("Failed to load PARAMDEF: {:?}", e); 1 } + } + } else { + match unpackers::param::load_param_file(file_path, None) { + Ok(param) => { unpackers::param::print_param_no_data(¶m); 0 } + Err(e) => { eprintln!("Failed to load PARAM: {:?}", e); 1 } + } } } diff --git a/src/parsers/common.rs b/src/parsers/common.rs index baa69cf..aaf55de 100644 --- a/src/parsers/common.rs +++ b/src/parsers/common.rs @@ -39,6 +39,13 @@ pub union VarSizeInt { pub vu64: u64, } +impl VarSizeInt { + /// Set u64 value if condition is true, else the u32 as u64. + pub fn u64_if(&self, c: bool) -> u64 { + if c { unsafe { self.vu64 } } else { unsafe { self.vu32 as u64 } } + } +} + impl fmt::Debug for VarSizeInt { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "VarSizeInt: {{ {}: u32, {}: u64 }}", unsafe { self.vu32 }, unsafe { self.vu64 }) diff --git a/src/parsers/param.rs b/src/parsers/param.rs index d3290e8..65c8737 100644 --- a/src/parsers/param.rs +++ b/src/parsers/param.rs @@ -5,6 +5,7 @@ use nom::number::complete::*; use nom::sequence::tuple; use crate::parsers::common::{sjis_to_string, take_cstring, take_cstring_from, VarSizeInt}; +use crate::parsers::paramdef; use crate::utils::bin::has_flag; const FLAGS2D_UNK1: u8 = 0b00000001; @@ -103,17 +104,7 @@ pub struct ParamRow { pub ofs_data: VarSizeInt, pub ofs_name: VarSizeInt, pub name: Option, -} - -impl ParamRow { - /// Get a u64 for the name offset, regardless of the format. - pub fn get_ofs_name(&self, header: &ParamHeader) -> u64 { - if header.has_u64_ofs_data() { - unsafe { self.ofs_name.vu64 } - } else { - unsafe { self.ofs_name.vu32 as u64 } - } - } + pub data: Vec, } fn parse_row<'a>(i: &'a[u8], header: &ParamHeader) -> IResult<&'a[u8], ParamRow> { @@ -128,7 +119,7 @@ fn parse_row<'a>(i: &'a[u8], header: &ParamHeader) -> IResult<&'a[u8], ParamRow> (i, (id, VarSizeInt { vu32: ofs_data }, VarSizeInt { vu32: ofs_name })) }; - Ok((i, ParamRow { id, ofs_data, ofs_name, name: None })) + Ok((i, ParamRow { id, ofs_data, ofs_name, name: None, data: vec!() })) } #[derive(Debug)] @@ -137,7 +128,7 @@ pub struct Param { pub rows: Vec, } -pub fn parse(i: &[u8]) -> IResult<&[u8], Param> { +pub fn parse<'a>(i: &'a[u8], paramdef: Option<¶mdef::Paramdef>) -> IResult<&'a[u8], Param> { let full_file = i; let (i, mut header) = parse_header(i)?; if header.has_ofs_string_name() && header.ofs_name.is_some() { @@ -149,7 +140,7 @@ pub fn parse(i: &[u8]) -> IResult<&[u8], Param> { let (i, mut rows) = count(|i| parse_row(i, &header), header.num_rows as usize)(i)?; for row in &mut rows { - let ofs_name = row.get_ofs_name(&header) as usize; + let ofs_name = row.ofs_name.u64_if(header.has_u64_ofs_data()) as usize; if ofs_name != 0 { let (_, name) = take_cstring(&full_file[ofs_name..])?; row.name = sjis_to_string(name).or_else(|| { @@ -159,5 +150,17 @@ pub fn parse(i: &[u8]) -> IResult<&[u8], Param> { } } + if paramdef.is_some() { + let row_size = paramdef.unwrap().row_size(); + for row in &mut rows { + let ofs_data = row.ofs_data.u64_if(header.has_u64_ofs_data()) as usize; + if ofs_data == 0 { + continue + } + let ofs_data_end = ofs_data + row_size; + row.data = full_file[ofs_data..ofs_data_end].to_vec(); + } + } + Ok((i, Param { header, rows })) } diff --git a/src/unpackers/bhf.rs b/src/unpackers/bhf.rs index b33b4ee..ef5dc37 100644 --- a/src/unpackers/bhf.rs +++ b/src/unpackers/bhf.rs @@ -123,7 +123,7 @@ pub fn load_bhf_file(bhf_path: &str) -> Result { load_bhf(&bhf_data) } -/// Load a BHF file from a bytes slice. +/// Load a BHF file from a byte slice. pub fn load_bhf(bhf_data: &[u8]) -> Result { match bhf::parse(&bhf_data) { Ok((_, bhf)) => Ok(bhf), diff --git a/src/unpackers/param.rs b/src/unpackers/param.rs index 5a4c885..0161b33 100644 --- a/src/unpackers/param.rs +++ b/src/unpackers/param.rs @@ -3,28 +3,56 @@ use std::path; use nom::Err::{Error as NomError, Failure as NomFailure}; use crate::parsers::param; +use crate::parsers::paramdef; use crate::unpackers::errors::UnpackError; use crate::utils::fs as utils_fs; use crate::utils::str as utils_str; -pub fn load_param_file(param_path: &str) -> Result { +/// Load a PARAM file from disk. +/// +/// Wraps around `load_param` to load the PARAM from disk. +pub fn load_param_file( + param_path: &str, + paramdef: Option<¶mdef::Paramdef> +) -> Result { let param_data = utils_fs::open_file_to_vec(path::Path::new(param_path))?; - Ok(load_param(¶m_data)?) + Ok(load_param(¶m_data, paramdef)?) } -pub fn load_param(param_data: &[u8]) -> Result { - match param::parse(param_data) { +/// Load a PARAM from a byte slice. +/// +/// If paramdef is provided, it copies the right amount of bytes into +/// row data, without parsing them. Else it loads the PARAM with +/// empty row data. +pub fn load_param( + param_data: &[u8], + paramdef: Option<¶mdef::Paramdef> +) -> Result { + match param::parse(param_data, paramdef) { Ok((_, result)) => Ok(result), Err(NomError(e)) | Err(NomFailure(e)) => Err(UnpackError::parsing_err("PARAM", e.1)), Err(e) => Err(UnpackError::Unknown(format!("Unknown error: {:?}", e))), } } -pub fn print_param_no_data(param: ¶m::Param) { - println!("{} -- {}", param.header.param_type, - utils_str::n_plural(param.header.num_rows as i32, "row", "rows")); +fn print_param_intro(param: ¶m::Param) { + println!( + "{} -- {}", + param.header.param_type, + utils_str::n_pluralise(param.header.num_rows as i32, "row", "rows") + ); +} +pub fn print_param_no_data(param: ¶m::Param) { + print_param_intro(param); for row in ¶m.rows { println!(" - [{}] {}", row.id, row.name.as_ref().unwrap_or(&String::from(""))); } } + +pub fn print_param(param: ¶m::Param) { + print_param_intro(param); + for row in ¶m.rows { + println!("{:?}", row); + } +} diff --git a/src/unpackers/paramdef.rs b/src/unpackers/paramdef.rs index 7810a83..8536326 100644 --- a/src/unpackers/paramdef.rs +++ b/src/unpackers/paramdef.rs @@ -7,11 +7,15 @@ use crate::unpackers::errors::UnpackError; use crate::utils::fs as utils_fs; use crate::utils::str as utils_str; +/// Load a PARAMDEF file from disk. +/// +/// Wraps around `load_paramdef` to load the PARAMDEF from disk. pub fn load_paramdef_file(paramdef_path: &str) -> Result { let paramdef_data = utils_fs::open_file_to_vec(path::Path::new(paramdef_path))?; Ok(load_paramdef(¶mdef_data)?) } +/// Load a PARAMDEF file from a byte slice. pub fn load_paramdef(paramdef_data: &[u8]) -> Result { match paramdef::parse(paramdef_data) { Ok((_, result)) => Ok(result), @@ -20,6 +24,7 @@ pub fn load_paramdef(paramdef_data: &[u8]) -> Result