param: WIP combination with paramdef

This commit is contained in:
dece 2020-05-19 00:49:21 +02:00
parent 7ab1f763f9
commit da80ff1d9a
6 changed files with 82 additions and 25 deletions

View file

@ -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) {
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(&paramdef)) {
Ok(param) => { unpackers::param::print_param(&param); 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(&param); 0 }
Err(e) => { eprintln!("Failed to load PARAM: {:?}", e); 1 }
}
}
}

View file

@ -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 })

View file

@ -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<String>,
}
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<u8>,
}
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<ParamRow>,
}
pub fn parse(i: &[u8]) -> IResult<&[u8], Param> {
pub fn parse<'a>(i: &'a[u8], paramdef: Option<&paramdef::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 }))
}

View file

@ -123,7 +123,7 @@ pub fn load_bhf_file(bhf_path: &str) -> Result<bhf::Bhf, UnpackError> {
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<bhf::Bhf, UnpackError> {
match bhf::parse(&bhf_data) {
Ok((_, bhf)) => Ok(bhf),

View file

@ -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<param::Param, UnpackError> {
/// 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<&paramdef::Paramdef>
) -> Result<param::Param, UnpackError> {
let param_data = utils_fs::open_file_to_vec(path::Path::new(param_path))?;
Ok(load_param(&param_data)?)
Ok(load_param(&param_data, paramdef)?)
}
pub fn load_param(param_data: &[u8]) -> Result<param::Param, UnpackError> {
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<&paramdef::Paramdef>
) -> Result<param::Param, UnpackError> {
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: &param::Param) {
println!("{} -- {}", param.header.param_type,
utils_str::n_plural(param.header.num_rows as i32, "row", "rows"));
fn print_param_intro(param: &param::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: &param::Param) {
print_param_intro(param);
for row in &param.rows {
println!(" - [{}] {}", row.id, row.name.as_ref().unwrap_or(&String::from("<noname>")));
}
}
pub fn print_param(param: &param::Param) {
print_param_intro(param);
for row in &param.rows {
println!("{:?}", row);
}
}

View file

@ -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<paramdef::Paramdef, UnpackError> {
let paramdef_data = utils_fs::open_file_to_vec(path::Path::new(paramdef_path))?;
Ok(load_paramdef(&paramdef_data)?)
}
/// Load a PARAMDEF file from a byte slice.
pub fn load_paramdef(paramdef_data: &[u8]) -> Result<paramdef::Paramdef, UnpackError> {
match paramdef::parse(paramdef_data) {
Ok((_, result)) => Ok(result),
@ -20,6 +24,7 @@ pub fn load_paramdef(paramdef_data: &[u8]) -> Result<paramdef::Paramdef, UnpackE
}
}
/// Print brief data about a PARAMDEF.
pub fn print_paramdef_intro(paramdef: &paramdef::Paramdef) {
println!(
"{} -- ver. {} -- format ver. {} -- {} fields -- {} per row",
@ -30,6 +35,7 @@ pub fn print_paramdef_intro(paramdef: &paramdef::Paramdef) {
);
}
/// Print verbose data about a PARAMDEF.
pub fn print_paramdef(paramdef: &paramdef::Paramdef) {
print_paramdef_intro(paramdef);
for field in &paramdef.fields {