param: complete printing
This commit is contained in:
parent
15dd0b2cb8
commit
be1d40ac7b
|
@ -79,7 +79,7 @@ fn main() {
|
||||||
.help("PARAMDEF file path")
|
.help("PARAMDEF file path")
|
||||||
.takes_value(true).required(true)))
|
.takes_value(true).required(true)))
|
||||||
.subcommand(SubCommand::with_name("param")
|
.subcommand(SubCommand::with_name("param")
|
||||||
.about("TODO")
|
.about("Parse PARAM contents")
|
||||||
.arg(Arg::with_name("file")
|
.arg(Arg::with_name("file")
|
||||||
.help("PARAM file path")
|
.help("PARAM file path")
|
||||||
.takes_value(true).required(true))
|
.takes_value(true).required(true))
|
||||||
|
@ -217,21 +217,25 @@ fn cmd_paramdef(args: &ArgMatches) -> i32 {
|
||||||
|
|
||||||
fn cmd_param(args: &ArgMatches) -> i32 {
|
fn cmd_param(args: &ArgMatches) -> i32 {
|
||||||
let file_path: &str = args.value_of("file").unwrap();
|
let file_path: &str = args.value_of("file").unwrap();
|
||||||
|
let paramdef_path: Option<&str> = args.value_of("paramdef");
|
||||||
|
|
||||||
if let Some(paramdef_path) = args.value_of("paramdef") {
|
let paramdef = if paramdef_path.is_some() {
|
||||||
match unpackers::paramdef::load_paramdef_file(paramdef_path) {
|
match unpackers::paramdef::load_paramdef_file(paramdef_path.unwrap()) {
|
||||||
Ok(paramdef) => {
|
Ok(paramdef) => Some(paramdef),
|
||||||
match unpackers::param::load_param_file(file_path, Some(¶mdef)) {
|
Err(e) => { eprintln!("Failed to load PARAMDEF: {:?}", e); return 1 }
|
||||||
Ok(param) => { unpackers::param::print_param_with_def(¶m, ¶mdef); 0 }
|
|
||||||
Err(e) => { eprintln!("Failed to load PARAM: {:?}", e); 1 }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(e) => { eprintln!("Failed to load PARAMDEF: {:?}", e); 1 }
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
match unpackers::param::load_param_file(file_path, None) {
|
None
|
||||||
Ok(param) => { unpackers::param::print_param(¶m); 0 }
|
};
|
||||||
Err(e) => { eprintln!("Failed to load PARAM: {:?}", e); 1 }
|
|
||||||
}
|
let param = match unpackers::param::load_param_file(file_path, paramdef.as_ref()) {
|
||||||
}
|
Ok(param) => param,
|
||||||
|
Err(e) => { eprintln!("Failed to load PARAM: {:?}", e); return 1 }
|
||||||
|
};
|
||||||
|
|
||||||
|
match paramdef {
|
||||||
|
Some(paramdef) => unpackers::param::print_param_with_def(¶m, ¶mdef),
|
||||||
|
None => unpackers::param::print_param(¶m),
|
||||||
|
};
|
||||||
|
0
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ use nom::sequence::tuple;
|
||||||
use crate::parsers::common::{sjis_to_string, take_cstring, take_cstring_from, VarSizeInt};
|
use crate::parsers::common::{sjis_to_string, take_cstring, take_cstring_from, VarSizeInt};
|
||||||
use crate::parsers::paramdef;
|
use crate::parsers::paramdef;
|
||||||
use crate::utils::bin::{has_flag, mask};
|
use crate::utils::bin::{has_flag, mask};
|
||||||
|
use crate::utils::str as utils_str;
|
||||||
|
|
||||||
const FLAGS2D_UNK1: u8 = 0b00000001;
|
const FLAGS2D_UNK1: u8 = 0b00000001;
|
||||||
const FLAGS2D_32B_OFS_DATA: u8 = 0b00000010;
|
const FLAGS2D_32B_OFS_DATA: u8 = 0b00000010;
|
||||||
|
@ -39,6 +40,17 @@ impl ParamHeader {
|
||||||
pub fn has_u64_ofs_data(&self) -> bool { has_u64_ofs_data(self.flags2D) }
|
pub fn has_u64_ofs_data(&self) -> bool { has_u64_ofs_data(self.flags2D) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for ParamHeader {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"{} -- {}",
|
||||||
|
self.param_type,
|
||||||
|
utils_str::n_pluralise(self.num_rows as i32, "row", "rows")
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn use_be(endianness: u8) -> bool { endianness == 0xFF }
|
fn use_be(endianness: u8) -> bool { endianness == 0xFF }
|
||||||
|
|
||||||
fn has_ofs_string_name(flags: u8) -> bool { has_flag(flags, FLAGS2D_OFS_STRING) }
|
fn has_ofs_string_name(flags: u8) -> bool { has_flag(flags, FLAGS2D_OFS_STRING) }
|
||||||
|
@ -109,6 +121,12 @@ pub struct ParamRow {
|
||||||
pub data: Vec<ParamRowValue>,
|
pub data: Vec<ParamRowValue>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for ParamRow {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
write!(f, "[{}] {}", self.id, self.name.as_ref().unwrap_or(&String::from("<noname>")))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(strum_macros::IntoStaticStr)]
|
#[derive(strum_macros::IntoStaticStr)]
|
||||||
pub enum ParamRowValue {
|
pub enum ParamRowValue {
|
||||||
S8(i8), U8(u8), S16(i16), U16(u16), S32(i32), U32(u32), F32(f32), UNK(Vec<u8>)
|
S8(i8), U8(u8), S16(i16), U16(u16), S32(i32), U32(u32), F32(f32), UNK(Vec<u8>)
|
||||||
|
@ -152,6 +170,7 @@ fn parse_row<'a>(i: &'a[u8], header: &ParamHeader) -> IResult<&'a[u8], ParamRow>
|
||||||
Ok((i, ParamRow { id, ofs_data, ofs_name, name: None, data: vec!() }))
|
Ok((i, ParamRow { id, ofs_data, ofs_name, name: None, data: vec!() }))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Parse row data using field definitions from PARAMDEF.
|
||||||
fn parse_row_data<'a>(
|
fn parse_row_data<'a>(
|
||||||
i: &'a[u8],
|
i: &'a[u8],
|
||||||
header: &ParamHeader,
|
header: &ParamHeader,
|
||||||
|
@ -163,10 +182,11 @@ fn parse_row_data<'a>(
|
||||||
let mut remaining_bits = 0; // Remaining bits in bitfield.
|
let mut remaining_bits = 0; // Remaining bits in bitfield.
|
||||||
let mut data_slice = i;
|
let mut data_slice = i;
|
||||||
for field in ¶mdef.fields {
|
for field in ¶mdef.fields {
|
||||||
|
let type_str = &field.display_type;
|
||||||
|
let num_bytes = field.byte_count as usize;
|
||||||
let bit_size = field.bit_size();
|
let bit_size = field.bit_size();
|
||||||
let value = if bit_size == 0 {
|
let value = if bit_size == 0 {
|
||||||
let (rest, value) = parse_row_value(data_slice, &field.display_type,
|
let (rest, value) = parse_row_value(data_slice, type_str, num_bytes, use_be)?;
|
||||||
field.byte_count as usize, use_be)?;
|
|
||||||
data_slice = rest;
|
data_slice = rest;
|
||||||
remaining_bits = 0;
|
remaining_bits = 0;
|
||||||
value
|
value
|
||||||
|
@ -174,35 +194,23 @@ fn parse_row_data<'a>(
|
||||||
// Bitfield parsing. If it's the first bitfield in a series, get the containing bytes
|
// Bitfield parsing. If it's the first bitfield in a series, get the containing bytes
|
||||||
// in the bitfield var.
|
// in the bitfield var.
|
||||||
if remaining_bits == 0 {
|
if remaining_bits == 0 {
|
||||||
let (rest, bf) = take(field.byte_count as usize)(data_slice)?;
|
let (rest, bf) = parse_row_bitfield(data_slice, type_str, num_bytes, use_be)?;
|
||||||
bitfield = match field.display_type.as_str() {
|
|
||||||
"u8" => { remaining_bits = 8; le_u8(bf).map(|(_, v)| v as u16)? }
|
|
||||||
"dummy8" => { remaining_bits = 8; le_u8(bf).map(|(_, v)| v as u16)? }
|
|
||||||
"u16" => {
|
|
||||||
remaining_bits = 16;
|
|
||||||
(if use_be { be_u16 } else { le_u16 }) (bf) .map(|(_, v)| v)?
|
|
||||||
}
|
|
||||||
e => panic!("Unhandled PARAMDEF type {}", e),
|
|
||||||
};
|
|
||||||
data_slice = rest;
|
data_slice = rest;
|
||||||
|
bitfield = bf;
|
||||||
|
remaining_bits = bit_size * 8;
|
||||||
}
|
}
|
||||||
// Parse masked bits.
|
let value = parse_row_bitfield_value(bitfield, type_str, bit_size);
|
||||||
let value = bitfield & mask(bit_size as usize) as u16;
|
|
||||||
// Shift bitfield so next values can be parsed directly with a bitmask.
|
// Shift bitfield so next values can be parsed directly with a bitmask.
|
||||||
bitfield >>= bit_size;
|
bitfield >>= bit_size;
|
||||||
remaining_bits -= bit_size;
|
remaining_bits -= bit_size;
|
||||||
match field.display_type.as_str() {
|
value
|
||||||
"u8" => ParamRowValue::U8(value as u8),
|
|
||||||
"dummy8" => ParamRowValue::U8(value as u8),
|
|
||||||
"u16" => ParamRowValue::U16(value),
|
|
||||||
e => panic!("Unhandled PARAMDEF type {}", e),
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
data.push(value);
|
data.push(value);
|
||||||
}
|
}
|
||||||
Ok((i, data))
|
Ok((i, data))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Parse a single row value, using its type string.
|
||||||
fn parse_row_value<'a>(
|
fn parse_row_value<'a>(
|
||||||
i: &'a[u8],
|
i: &'a[u8],
|
||||||
type_str: &str,
|
type_str: &str,
|
||||||
|
@ -229,12 +237,51 @@ fn parse_row_value<'a>(
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Parse a bitfield unsigned int of the max handled size (u16).
|
||||||
|
///
|
||||||
|
/// Parsing is done using the type string. Whatever the size of the int
|
||||||
|
/// is, place it in the max handled size to avoid maintaining one
|
||||||
|
/// bitfield for each type.
|
||||||
|
fn parse_row_bitfield<'a>(
|
||||||
|
bf: &'a[u8],
|
||||||
|
type_str: &str,
|
||||||
|
num_bytes: usize,
|
||||||
|
use_be: bool
|
||||||
|
) -> IResult<&'a[u8], u16> {
|
||||||
|
let (rest, bf) = take(num_bytes)(bf)?;
|
||||||
|
let bitfield = match type_str {
|
||||||
|
"u8" => le_u8(bf).map(|(_, v)| v as u16)?,
|
||||||
|
"dummy8" => le_u8(bf).map(|(_, v)| v as u16)?,
|
||||||
|
"u16" => (if use_be { be_u16 } else { le_u16 })(bf).map(|(_, v)| v)?,
|
||||||
|
e => panic!("Unhandled PARAMDEF type {}", e),
|
||||||
|
};
|
||||||
|
Ok((rest, bitfield))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Parse a single row value (max u16) from a bitfield.
|
||||||
|
fn parse_row_bitfield_value(bitfield: u16, type_str: &str, bit_size: usize) -> ParamRowValue {
|
||||||
|
let value = bitfield & mask(bit_size) as u16;
|
||||||
|
match type_str {
|
||||||
|
"u8" => ParamRowValue::U8(value as u8),
|
||||||
|
"dummy8" => ParamRowValue::U8(value as u8),
|
||||||
|
"u16" => ParamRowValue::U16(value),
|
||||||
|
e => panic!("Unhandled PARAMDEF type {}", e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Param {
|
pub struct Param {
|
||||||
pub header: ParamHeader,
|
pub header: ParamHeader,
|
||||||
pub rows: Vec<ParamRow>,
|
pub rows: Vec<ParamRow>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for Param {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
fmt::Display::fmt(&self.header, f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Parse PARAM data, using PARAMDEF info if provided.
|
||||||
pub fn parse<'a>(i: &'a[u8], paramdef: Option<¶mdef::Paramdef>) -> IResult<&'a[u8], Param> {
|
pub fn parse<'a>(i: &'a[u8], paramdef: Option<¶mdef::Paramdef>) -> IResult<&'a[u8], Param> {
|
||||||
let full_file = i;
|
let full_file = i;
|
||||||
let (i, mut header) = parse_header(i)?;
|
let (i, mut header) = parse_header(i)?;
|
||||||
|
|
|
@ -1,9 +1,12 @@
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
use nom::IResult;
|
use nom::IResult;
|
||||||
use nom::multi::count;
|
use nom::multi::count;
|
||||||
use nom::number::complete::*;
|
use nom::number::complete::*;
|
||||||
use nom::sequence::tuple;
|
use nom::sequence::tuple;
|
||||||
|
|
||||||
use crate::parsers::common::{sjis_to_string_lossy, take_cstring, take_cstring_from, VarSizeInt};
|
use crate::parsers::common::{sjis_to_string_lossy, take_cstring, take_cstring_from, VarSizeInt};
|
||||||
|
use crate::utils::str as utils_str;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct ParamdefHeader {
|
pub struct ParamdefHeader {
|
||||||
|
@ -100,6 +103,23 @@ impl ParamdefField {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for ParamdefField {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"{} {} ({}, {}, {})",
|
||||||
|
self.display_name,
|
||||||
|
self.internal_name.as_ref().unwrap_or(&String::from("<noname>")),
|
||||||
|
self.display_type,
|
||||||
|
self.internal_type,
|
||||||
|
match self.bit_size() {
|
||||||
|
0 => utils_str::n_bytes_pluralise(self.byte_count as i32),
|
||||||
|
x => utils_str::n_pluralise(x as i32, "bit", "bits")
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn parse_field<'a>(i: &'a[u8], header: &ParamdefHeader) -> IResult<&'a[u8], ParamdefField> {
|
fn parse_field<'a>(i: &'a[u8], header: &ParamdefHeader) -> IResult<&'a[u8], ParamdefField> {
|
||||||
let (i, display_name) = take_cstring_from(i, 0x40)?;
|
let (i, display_name) = take_cstring_from(i, 0x40)?;
|
||||||
let (i, display_type) = take_cstring_from(i, 0x8)?;
|
let (i, display_type) = take_cstring_from(i, 0x8)?;
|
||||||
|
@ -175,6 +195,20 @@ impl Paramdef {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for Paramdef {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"{} -- ver. {} -- format ver. {} -- {} fields -- {} per row",
|
||||||
|
self.header.param_name,
|
||||||
|
self.header.data_version,
|
||||||
|
self.header.format_version,
|
||||||
|
self.header.num_fields,
|
||||||
|
utils_str::n_bytes_pluralise(self.row_size() as i32)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn parse(i: &[u8]) -> IResult<&[u8], Paramdef> {
|
pub fn parse(i: &[u8]) -> IResult<&[u8], Paramdef> {
|
||||||
let full_file = i;
|
let full_file = i;
|
||||||
let (i, header) = parse_header(i)?;
|
let (i, header) = parse_header(i)?;
|
||||||
|
|
|
@ -6,7 +6,6 @@ use crate::parsers::param;
|
||||||
use crate::parsers::paramdef;
|
use crate::parsers::paramdef;
|
||||||
use crate::unpackers::errors::UnpackError;
|
use crate::unpackers::errors::UnpackError;
|
||||||
use crate::utils::fs as utils_fs;
|
use crate::utils::fs as utils_fs;
|
||||||
use crate::utils::str as utils_str;
|
|
||||||
|
|
||||||
/// Load a PARAM file from disk.
|
/// Load a PARAM file from disk.
|
||||||
///
|
///
|
||||||
|
@ -35,20 +34,11 @@ pub fn load_param(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Print a PARAM's name and number of 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")
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Print simple information about a PARAM.
|
/// Print simple information about a PARAM.
|
||||||
pub fn print_param(param: ¶m::Param) {
|
pub fn print_param(param: ¶m::Param) {
|
||||||
print_param_intro(param);
|
println!("{}", param);
|
||||||
for row in ¶m.rows {
|
for row in ¶m.rows {
|
||||||
println!(" - [{}] {}", row.id, row.name.as_ref().unwrap_or(&String::from("<noname>")));
|
println!(" - {}", row);
|
||||||
if row.data.len() > 0 {
|
if row.data.len() > 0 {
|
||||||
println!(" {:?}", row.data);
|
println!(" {:?}", row.data);
|
||||||
}
|
}
|
||||||
|
@ -57,10 +47,13 @@ pub fn print_param(param: ¶m::Param) {
|
||||||
|
|
||||||
/// Print a PARAM's data using PARAMDEF fields.
|
/// Print a PARAM's data using PARAMDEF fields.
|
||||||
pub fn print_param_with_def(param: ¶m::Param, paramdef: ¶mdef::Paramdef) {
|
pub fn print_param_with_def(param: ¶m::Param, paramdef: ¶mdef::Paramdef) {
|
||||||
print_param_intro(param);
|
println!("{}", param);
|
||||||
for row in ¶m.rows {
|
for row in ¶m.rows {
|
||||||
|
println!(" - {}", row);
|
||||||
println!("{:?}", row);
|
let mut desc = String::with_capacity(row.data.len() * 32); // Rough estimate.
|
||||||
|
for (value, field_def) in row.data.iter().zip(paramdef.fields.iter()) {
|
||||||
|
desc.push_str(&format!(" - {} = {}\n", field_def, value));
|
||||||
|
}
|
||||||
|
println!("{}", desc.as_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,6 @@ use nom::Err::{Error as NomError, Failure as NomFailure};
|
||||||
use crate::parsers::paramdef;
|
use crate::parsers::paramdef;
|
||||||
use crate::unpackers::errors::UnpackError;
|
use crate::unpackers::errors::UnpackError;
|
||||||
use crate::utils::fs as utils_fs;
|
use crate::utils::fs as utils_fs;
|
||||||
use crate::utils::str as utils_str;
|
|
||||||
|
|
||||||
/// Load a PARAMDEF file from disk.
|
/// Load a PARAMDEF file from disk.
|
||||||
///
|
///
|
||||||
|
@ -24,34 +23,11 @@ pub fn load_paramdef(paramdef_data: &[u8]) -> Result<paramdef::Paramdef, UnpackE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Print brief data about a PARAMDEF.
|
|
||||||
pub fn print_paramdef_intro(paramdef: ¶mdef::Paramdef) {
|
|
||||||
println!(
|
|
||||||
"{} -- ver. {} -- format ver. {} -- {} fields -- {} per row",
|
|
||||||
paramdef.header.param_name,
|
|
||||||
paramdef.header.data_version, paramdef.header.format_version,
|
|
||||||
paramdef.header.num_fields,
|
|
||||||
utils_str::n_bytes_pluralise(paramdef.row_size() as i32)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Print verbose data about a PARAMDEF.
|
/// Print verbose data about a PARAMDEF.
|
||||||
pub fn print_paramdef(paramdef: ¶mdef::Paramdef) {
|
pub fn print_paramdef(paramdef: ¶mdef::Paramdef) {
|
||||||
print_paramdef_intro(paramdef);
|
println!("{}", paramdef);
|
||||||
for field in ¶mdef.fields {
|
for field in ¶mdef.fields {
|
||||||
let size_str = match field.bit_size() {
|
println!(" - {}", field);
|
||||||
0 => utils_str::n_bytes_pluralise(field.byte_count as i32),
|
|
||||||
x => utils_str::n_pluralise(x as i32, "bit", "bits")
|
|
||||||
};
|
|
||||||
println!(
|
|
||||||
" - [{}] {} ({}) {} ({}, {})",
|
|
||||||
field.sort_id,
|
|
||||||
field.display_name,
|
|
||||||
field.internal_name.as_ref().unwrap_or(&String::from("<noname>")),
|
|
||||||
field.display_type,
|
|
||||||
field.internal_type,
|
|
||||||
size_str
|
|
||||||
);
|
|
||||||
println!(
|
println!(
|
||||||
" Values: default {}, range [{}, {}], inc {}",
|
" Values: default {}, range [{}, {}], inc {}",
|
||||||
field.default_value,
|
field.default_value,
|
||||||
|
|
Reference in a new issue