param: WIP parsing
This commit is contained in:
parent
4f63f2bb1a
commit
1d3dab7523
|
@ -78,6 +78,14 @@ fn main() {
|
||||||
.arg(Arg::with_name("file")
|
.arg(Arg::with_name("file")
|
||||||
.help("PARAMDEF file path")
|
.help("PARAMDEF file path")
|
||||||
.takes_value(true).required(true)))
|
.takes_value(true).required(true)))
|
||||||
|
.subcommand(SubCommand::with_name("param")
|
||||||
|
.about("TODO")
|
||||||
|
.arg(Arg::with_name("file")
|
||||||
|
.help("PARAM file path")
|
||||||
|
.takes_value(true).required(true))
|
||||||
|
.arg(Arg::with_name("paramdef")
|
||||||
|
.help("PARAMDEF file path")
|
||||||
|
.short("d").long("def").takes_value(true).required(false)))
|
||||||
.get_matches();
|
.get_matches();
|
||||||
|
|
||||||
process::exit(match matches.subcommand() {
|
process::exit(match matches.subcommand() {
|
||||||
|
@ -88,6 +96,7 @@ fn main() {
|
||||||
("bnd", Some(s)) => { cmd_bnd(s) }
|
("bnd", Some(s)) => { cmd_bnd(s) }
|
||||||
("bhf", Some(s)) => { cmd_bhf(s) }
|
("bhf", Some(s)) => { cmd_bhf(s) }
|
||||||
("paramdef", Some(s)) => { cmd_paramdef(s) }
|
("paramdef", Some(s)) => { cmd_paramdef(s) }
|
||||||
|
("param", Some(s)) => { cmd_param(s) }
|
||||||
_ => { 0 }
|
_ => { 0 }
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -205,3 +214,11 @@ fn cmd_paramdef(args: &ArgMatches) -> i32 {
|
||||||
Err(e) => { eprintln!("Failed to load PARAMDEF: {:?}", e); 1 }
|
Err(e) => { eprintln!("Failed to load PARAMDEF: {:?}", e); 1 }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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(¶m); 0 }
|
||||||
|
Err(e) => { eprintln!("Failed to load PARAM: {:?}", e); 1 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ pub mod parsers {
|
||||||
pub mod bnd;
|
pub mod bnd;
|
||||||
pub mod common;
|
pub mod common;
|
||||||
pub mod dcx;
|
pub mod dcx;
|
||||||
|
pub mod param;
|
||||||
pub mod paramdef;
|
pub mod paramdef;
|
||||||
}
|
}
|
||||||
pub mod unpackers {
|
pub mod unpackers {
|
||||||
|
@ -15,6 +16,7 @@ pub mod unpackers {
|
||||||
pub mod bnd;
|
pub mod bnd;
|
||||||
pub mod dcx;
|
pub mod dcx;
|
||||||
pub mod errors;
|
pub mod errors;
|
||||||
|
pub mod param;
|
||||||
pub mod paramdef;
|
pub mod paramdef;
|
||||||
}
|
}
|
||||||
pub mod utils {
|
pub mod utils {
|
||||||
|
|
103
src/parsers/param.rs
Normal file
103
src/parsers/param.rs
Normal file
|
@ -0,0 +1,103 @@
|
||||||
|
use nom::IResult;
|
||||||
|
use nom::number::complete::*;
|
||||||
|
use nom::sequence::tuple;
|
||||||
|
|
||||||
|
use crate::parsers::common::{sjis_to_string, take_cstring_from};
|
||||||
|
use crate::utils::bin::has_flag;
|
||||||
|
|
||||||
|
const FLAGS2D_UNK1: u8 = 0b00000001;
|
||||||
|
const FLAGS2D_32B_OFS_DATA: u8 = 0b00000010;
|
||||||
|
const FLAGS2D_64B_OFS_DATA: u8 = 0b00000100;
|
||||||
|
const FLAGS2D_OFS_STRING: u8 = 0b10000000;
|
||||||
|
const FLAGS2E_UNICODE_NAMES: u8 = 0b00000001;
|
||||||
|
|
||||||
|
pub struct ParamHeader {
|
||||||
|
pub ofs_strings: u32,
|
||||||
|
pub ofs_data: u16,
|
||||||
|
pub unk06: u16,
|
||||||
|
pub paramdef_data_version: u16,
|
||||||
|
pub num_rows: u16,
|
||||||
|
pub param_type: String,
|
||||||
|
pub endianness: u8,
|
||||||
|
pub flags2D: u8,
|
||||||
|
pub flags2E: u8,
|
||||||
|
pub paramdef_format_version: u8,
|
||||||
|
pub ofs_data_long: Option<ParamHeaderLongOfsData>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub union ParamHeaderLongOfsData {
|
||||||
|
ofs32: u32,
|
||||||
|
ofs64: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ParamHeader {
|
||||||
|
pub fn use_be(&self) -> bool { use_be(self.endianness) }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn use_be(endianness: u8) -> bool { endianness == 0xFF }
|
||||||
|
|
||||||
|
fn has_ofs_string_name(flags: u8) -> bool { has_flag(flags, FLAGS2D_OFS_STRING) }
|
||||||
|
|
||||||
|
fn has_u32_ofs_data(flags: u8) -> bool { has_flag(flags, FLAGS2D_UNK1 & FLAGS2D_32B_OFS_DATA) }
|
||||||
|
|
||||||
|
fn has_u64_ofs_data(flags: u8) -> bool { has_flag(flags, FLAGS2D_64B_OFS_DATA) }
|
||||||
|
|
||||||
|
fn parse_header(i: &[u8]) -> IResult<&[u8], ParamHeader> {
|
||||||
|
let endianness = i[0x2C];
|
||||||
|
let p_u16 = if use_be(endianness) { be_u16 } else { le_u16 };
|
||||||
|
let p_u32 = if use_be(endianness) { be_u32 } else { le_u32 };
|
||||||
|
let p_u64 = if use_be(endianness) { be_u64 } else { le_u64 };
|
||||||
|
let flags2D = i[0x2D];
|
||||||
|
let use_u32_ofs_data = has_u32_ofs_data(flags2D);
|
||||||
|
let use_u64_ofs_data = has_u64_ofs_data(flags2D);
|
||||||
|
|
||||||
|
let (i, (ofs_strings, ofs_data, unk06, paramdef_data_version, num_rows)) =
|
||||||
|
tuple((p_u32, p_u16, p_u16, p_u16, p_u16))(i)?;
|
||||||
|
|
||||||
|
let (i, param_type) = if has_ofs_string_name(flags2D) {
|
||||||
|
// Name is in the strings block, parse it later.
|
||||||
|
(&i[0x20..], String::new())
|
||||||
|
} else {
|
||||||
|
take_cstring_from(i, 0x20).map(|(i, s)| (i, String::from_utf8_lossy(s).to_string()))?
|
||||||
|
};
|
||||||
|
|
||||||
|
let i = &i[0x2..]; // Skip endianness and flags2D.
|
||||||
|
let (i, (flags2E, paramdef_format_version)) = tuple((le_u8, le_u8))(i)?;
|
||||||
|
|
||||||
|
let (i, ofs_data_long) = if use_u32_ofs_data {
|
||||||
|
let (_, o) = p_u32(i)?;
|
||||||
|
(&i[0x20..], Some(ParamHeaderLongOfsData { ofs32: o }))
|
||||||
|
} else if use_u64_ofs_data {
|
||||||
|
let (_, o) = p_u64(i)?;
|
||||||
|
(&i[0x20..], Some(ParamHeaderLongOfsData { ofs64: o }))
|
||||||
|
} else {
|
||||||
|
(i, None)
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok((
|
||||||
|
i,
|
||||||
|
ParamHeader {
|
||||||
|
ofs_strings,
|
||||||
|
ofs_data,
|
||||||
|
unk06,
|
||||||
|
paramdef_data_version,
|
||||||
|
num_rows,
|
||||||
|
param_type,
|
||||||
|
endianness,
|
||||||
|
flags2D,
|
||||||
|
flags2E,
|
||||||
|
paramdef_format_version,
|
||||||
|
ofs_data_long,
|
||||||
|
}
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Param {
|
||||||
|
pub header: ParamHeader,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parse(i: &[u8]) -> IResult<&[u8], Param> {
|
||||||
|
let full_file = i;
|
||||||
|
let (i, header) = parse_header(i)?;
|
||||||
|
Ok((i, Param { header }))
|
||||||
|
}
|
24
src/unpackers/param.rs
Normal file
24
src/unpackers/param.rs
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
use std::path;
|
||||||
|
|
||||||
|
use nom::Err::{Error as NomError, Failure as NomFailure};
|
||||||
|
|
||||||
|
use crate::parsers::param;
|
||||||
|
use crate::unpackers::errors::UnpackError;
|
||||||
|
use crate::utils::fs as utils_fs;
|
||||||
|
|
||||||
|
pub fn load_param_file(param_path: &str) -> Result<param::Param, UnpackError> {
|
||||||
|
let param_data = utils_fs::open_file_to_vec(path::Path::new(param_path))?;
|
||||||
|
Ok(load_param(¶m_data)?)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn load_param(param_data: &[u8]) -> Result<param::Param, UnpackError> {
|
||||||
|
match param::parse(param_data) {
|
||||||
|
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(param: ¶m::Param) {
|
||||||
|
println!("{} -- {} rows", param.header.param_type, param.header.num_rows);
|
||||||
|
}
|
Reference in a new issue