diff --git a/src/lib.rs b/src/lib.rs index 6b633b6..2397e09 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -20,4 +20,5 @@ pub mod unpackers { pub mod utils { pub mod bin; pub mod fs; + pub mod str; } diff --git a/src/parsers/paramdef.rs b/src/parsers/paramdef.rs index 42eb1df..a3e3e70 100644 --- a/src/parsers/paramdef.rs +++ b/src/parsers/paramdef.rs @@ -23,6 +23,7 @@ impl ParamdefHeader { pub fn use_be(&self) -> bool { use_be(self.endianness) } pub fn has_ofs_fields(&self) -> bool { has_ofs_fields(self.format_version) } pub fn has_64b_ofs_desc(&self) -> bool { self.format_version >= 201 } + pub fn can_have_bit_size(&self) -> bool { self.format_version >= 102 } } fn use_be(endianness: u8) -> bool { endianness == 0xFF } @@ -80,7 +81,25 @@ pub struct ParamdefField { pub description: Option, } -pub union ParamdefEntryDescOffset { +impl ParamdefField { + /// Return the bit size for this field, or 0 if unknown. + /// + /// It is contained in the internal name, unsure if there is a + /// better way to get it. + pub fn bit_size(&self) -> usize { + if let Some(name) = &self.internal_name { + if !name.contains(":") { + return 0 + } + if let Some(bit_size_str) = name.split(":").last().and_then(|s| Some(s.trim())) { + return bit_size_str.parse::().unwrap_or(0) + } + } + 0 + } +} + +pub union ParamdefFieldDescOffset { ofs32: u32, ofs64: u64, } @@ -166,5 +185,5 @@ pub fn parse(i: &[u8]) -> IResult<&[u8], Paramdef> { field.description = Some(sjis_to_string_lossy(sjis_desc)); } - Ok((i, Paramdef { header, fields: fields })) + Ok((i, Paramdef { header, fields })) } diff --git a/src/unpackers/paramdef.rs b/src/unpackers/paramdef.rs index d3c3045..1c99035 100644 --- a/src/unpackers/paramdef.rs +++ b/src/unpackers/paramdef.rs @@ -5,6 +5,7 @@ use nom::Err::{Error as NomError, Failure as NomFailure}; 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_paramdef_file(paramdef_path: &str) -> Result { let paramdef_data = utils_fs::open_file_to_vec(path::Path::new(paramdef_path))?; @@ -25,16 +26,35 @@ pub fn print_paramdef(paramdef: ¶mdef::Paramdef) { paramdef.header.data_version, paramdef.header.format_version, paramdef.header.num_fields); + let mut row_size = 0; + let mut bit_count = 0; for field in ¶mdef.fields { - println!(" - [{}] {} ({}) {} ({}, {} bytes)", + let bit_size = field.bit_size(); + let size_str = match bit_size { + 0 => utils_str::n_plural(field.byte_count as i32, "byte", "bytes"), + x => utils_str::n_plural(x as i32, "bit", "bits") + }; + + println!(" - [{}] {} ({}) {} ({}, {})", field.sort_id, field.display_name, field.internal_name.as_ref().unwrap_or(&String::from("")), - field.display_type, field.internal_type, field.byte_count); + field.display_type, field.internal_type, size_str); println!(" Values: default {}, range [{}, {}], inc {}", field.default_value, field.min_value, field.max_value, field.increment); if let Some(desc) = &field.description { println!(" Description: {}", desc); } - println!(" Edit flags: {:X}", field.edit_flags); + + if bit_size != 0 { + bit_count += bit_size; + while bit_count >= 8 { + bit_count -= 8; + row_size += 1; + } + } else { + row_size += field.byte_count; + } } + + println!("Size per row: {}", utils_str::n_plural(row_size as i32, "byte", "bytes")); } diff --git a/src/utils/str.rs b/src/utils/str.rs new file mode 100644 index 0000000..6c41d70 --- /dev/null +++ b/src/utils/str.rs @@ -0,0 +1,10 @@ +pub fn plural<'a>(num: i32, singular_name: &'a str, plural_name: &'a str) -> &'a str { + match num { + 1 => singular_name, + _ => plural_name, + } +} + +pub fn n_plural<'a>(num: i32, singular_name: &'a str, plural_name: &'a str) -> String { + format!("{} {}", num, plural(num, singular_name, plural_name)) +}