paramdef: WIP parsing

This commit is contained in:
dece 2020-05-16 00:12:31 +02:00
parent 4777affc2b
commit 09151b6579
6 changed files with 113 additions and 13 deletions

View file

@ -16,8 +16,8 @@ Usage
The project contains 2 artefacts: The project contains 2 artefacts:
- `librir`, a library containing all the parsing/unpacking features implemented. - `ironring`, a library with all the parsing/unpacking features implemented.
- `ironring`, an executable to use main lib features from the CLI. - `rir`, an executable to use main lib features from the CLI.
The goal is to make the lib compatible with FFI tools such as Python's ctypes, The goal is to make the lib compatible with FFI tools such as Python's ctypes,
to ship a dynamic lib accessible for any language to easily script tasks and to ship a dynamic lib accessible for any language to easily script tasks and
@ -26,10 +26,10 @@ ideas, but we're not there yet.
Ironring usage: Ironring usage:
``` ```
Iron Ring Rusted Iron Ring
USAGE: USAGE:
ironring [SUBCOMMAND] rir [SUBCOMMAND]
FLAGS: FLAGS:
-h, --help Prints help information -h, --help Prints help information
@ -64,6 +64,12 @@ Repacking is not supported, maybe one day. It is not that useful when using
[yabber]: https://github.com/JKAnderson/Yabber [yabber]: https://github.com/JKAnderson/Yabber
[sieglib]: https://github.com/Dece/DarkSoulsDev/tree/master/Programs/SiegLib [sieglib]: https://github.com/Dece/DarkSoulsDev/tree/master/Programs/SiegLib
There is a demo Python binding for some `name_hashes` features in the
`bindings/python` dir, that uses [PyO3][pyo3] and thus requires nightly rustc to
build.
[pyo3]: https://pyo3.rs/
Credits Credits

View file

@ -73,6 +73,11 @@ fn main() {
.arg(Arg::with_name("overwrite") .arg(Arg::with_name("overwrite")
.help("Overwrite existing files") .help("Overwrite existing files")
.short("f").long("force").takes_value(false).required(false))) .short("f").long("force").takes_value(false).required(false)))
.subcommand(SubCommand::with_name("paramdef")
.about("TODO")
.arg(Arg::with_name("file")
.help("PARAMDEF file path")
.takes_value(true).required(true)))
.get_matches(); .get_matches();
process::exit(match matches.subcommand() { process::exit(match matches.subcommand() {
@ -82,6 +87,7 @@ fn main() {
("dcx", Some(s)) => { cmd_dcx(s) } ("dcx", Some(s)) => { cmd_dcx(s) }
("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) }
_ => { 0 } _ => { 0 }
}) })
} }
@ -191,3 +197,11 @@ fn cmd_bhf(args: &ArgMatches) -> i32 {
_ => 0 _ => 0
} }
} }
fn cmd_paramdef(args: &ArgMatches) -> i32 {
let file_path: &str = args.value_of("file").unwrap();
match unpackers::paramdef::load_paramdef_file(file_path) {
Ok(paramdef) => { unpackers::paramdef::print_paramdef(&paramdef); 0 }
Err(e) => { eprintln!("Failed to load PARAMDEF: {:?}", e); 1 }
}
}

View file

@ -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 paramdef;
} }
pub mod unpackers { pub mod unpackers {
pub mod bhd; pub mod bhd;
@ -14,6 +15,7 @@ pub mod unpackers {
pub mod bnd; pub mod bnd;
pub mod dcx; pub mod dcx;
pub mod errors; pub mod errors;
pub mod paramdef;
} }
pub mod utils { pub mod utils {
pub mod bin; pub mod bin;

56
src/parsers/paramdef.rs Normal file
View file

@ -0,0 +1,56 @@
use std::str;
use nom::IResult;
use nom::bytes::complete::{tag, take};
use nom::multi::count;
use nom::number::complete::*;
use nom::sequence::tuple;
use crate::parsers::common::{sjis_to_string, take_cstring};
#[derive(Debug)]
pub struct ParamdefHeader {
pub file_size: u32,
pub header_size: u16,
pub data_version: u16,
pub num_entries: u16,
pub entry_size: u16,
pub param_name: Vec<u8>,
pub endianness: u8,
pub unicode: u8,
pub format_version: u16,
}
fn parse_header(i: &[u8]) -> IResult<&[u8], ParamdefHeader> {
let p_u32 = if i[0x2C] == 0xFF { be_u32 } else { le_u32 };
let p_u16 = if i[0x2C] == 0xFF { be_u16 } else { le_u16 };
let (i, (file_size, header_size, data_version, num_entries, entry_size)) =
tuple((p_u32, p_u16, p_u16, p_u16, p_u16))(i)?;
let (_, param_name) = take_cstring(&i[..0x20])?;
let (i, (endianness, unicode, format_version)) =
tuple((le_u8, le_u8, p_u16))(&i[0x20..])?;
Ok((
i,
ParamdefHeader {
file_size,
header_size,
data_version,
num_entries,
entry_size,
param_name: param_name.to_vec(),
endianness,
unicode,
format_version,
}
))
}
#[derive(Debug)]
pub struct Paramdef {
pub header: ParamdefHeader,
}
pub fn parse(i: &[u8]) -> IResult<&[u8], Paramdef> {
let (i, header) = parse_header(i)?;
Ok((i, Paramdef { header }))
}

View file

@ -81,10 +81,9 @@ pub fn get_decompressed_path(dcx_path: &str, output_path: Option<&str>) -> Optio
if path::Path::new(&output_path).is_dir() { if path::Path::new(&output_path).is_dir() {
output_path_valid = false; output_path_valid = false;
if let Some(file_pb) = utils_fs::strip_extension(&path::PathBuf::from(&dcx_path)) { if let Some(file_pb) = utils_fs::strip_extension(&path::PathBuf::from(&dcx_path)) {
if let Some(file_name) = file_pb.file_name() { if let Some(file_name) = file_pb.file_name().and_then(|s| s.to_str()) {
if let Some(file_name_str) = file_name.to_str() {
let mut out_pb = path::PathBuf::from(&output_path); let mut out_pb = path::PathBuf::from(&output_path);
out_pb.push(file_name_str); out_pb.push(file_name);
if let Some(s) = out_pb.as_path().to_str() { if let Some(s) = out_pb.as_path().to_str() {
output_path.clear(); output_path.clear();
output_path.push_str(s); output_path.push_str(s);
@ -93,7 +92,6 @@ pub fn get_decompressed_path(dcx_path: &str, output_path: Option<&str>) -> Optio
} }
} }
} }
}
if !output_path_valid { if !output_path_valid {
eprintln!("Can't determine a valid output path: {}", dcx_path); eprintln!("Can't determine a valid output path: {}", dcx_path);
return None return None

24
src/unpackers/paramdef.rs Normal file
View file

@ -0,0 +1,24 @@
use std::path;
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;
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)?)
}
pub fn load_paramdef(paramdef_data: &[u8]) -> Result<paramdef::Paramdef, UnpackError> {
match paramdef::parse(paramdef_data) {
Ok((_, result)) => Ok(result),
Err(NomError(e)) | Err(NomFailure(e)) => Err(UnpackError::parsing_err("PARAMDEF", e.1)),
e => Err(UnpackError::Unknown(format!("Unknown error: {:?}", e))),
}
}
pub fn print_paramdef(paramdef: &paramdef::Paramdef) {
println!("{:?}", paramdef);
}