diff --git a/src/bin/ironring.rs b/src/bin/ironring.rs index 6ae63f2..949c256 100644 --- a/src/bin/ironring.rs +++ b/src/bin/ironring.rs @@ -48,12 +48,18 @@ fn main() { .arg(Arg::with_name("value") .takes_value(true) .required(true))) + .subcommand(SubCommand::with_name("dcx") + .about("?TODO?") + .arg(Arg::with_name("file") + .takes_value(true) + .required(true))) .get_matches(); process::exit(match matches.subcommand() { ("bhd", Some(s)) => { cmd_bhd(s) } ("bhds", Some(s)) => { cmd_bhds(s) } ("hash", Some(s)) => { cmd_hash(s) } + ("dcx", Some(s)) => { cmd_dcx(s) } _ => { 0 } }) } @@ -124,3 +130,11 @@ fn cmd_hash(args: &ArgMatches) -> i32 { println!("{}", name_hashes::hash_as_string(name_hashes::hash(&value))); 0 } + +fn cmd_dcx(args: &ArgMatches) -> i32 { + let file_path: &str = args.value_of("file").unwrap(); + match unpackers::dcx::extract_dcx(file_path) { + Err(e) => { eprintln!("Failed to extract DCX: {:?}", e); return 1 } + _ => { 0 } + } +} diff --git a/src/lib.rs b/src/lib.rs index 199c32f..210902d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,11 +1,12 @@ pub mod name_hashes; pub mod parsers { pub mod bhd; + pub mod dcx; } pub mod unpackers { pub mod bhd; + pub mod dcx; } pub mod utils { pub mod fs; } - diff --git a/src/parsers/bhd.rs b/src/parsers/bhd.rs index ba099bd..4c8bbc4 100644 --- a/src/parsers/bhd.rs +++ b/src/parsers/bhd.rs @@ -1,12 +1,12 @@ -use nom::combinator::verify; +use nom::IResult; +use nom::bytes::complete::tag; use nom::multi::count; use nom::number::complete::*; use nom::sequence::tuple; -use nom::IResult; #[derive(Debug)] pub struct BhdHeader { - pub magic: u32, + pub magic: Vec, pub unk04: i8, // PC=0, PS3=-1 pub unk05: i8, pub unk06: i8, @@ -21,7 +21,7 @@ const MAGIC: u32 = 0x35444842; fn parse_header(i: &[u8]) -> IResult<&[u8], BhdHeader> { let (i, (magic, flags, unk08, file_len, num_buckets, ofs_buckets)) = tuple(( - verify(le_u32, |m| *m == MAGIC), + tag(b"BHD5"), count(le_i8, 4), le_u32, le_u32, @@ -31,7 +31,7 @@ fn parse_header(i: &[u8]) -> IResult<&[u8], BhdHeader> { Ok(( i, BhdHeader { - magic, + magic: magic.to_vec(), unk04: flags[0], unk05: flags[1], unk06: flags[2], diff --git a/src/parsers/dcx.rs b/src/parsers/dcx.rs new file mode 100644 index 0000000..5c0581b --- /dev/null +++ b/src/parsers/dcx.rs @@ -0,0 +1,109 @@ +//typedef struct { +// int unk00; Assert(unk00 == 0); +// int dataOffset; +// int dataLength; +// int unk0C; Assert(unk0C == 1); +//} Block ; +// +//typedef struct { +// char dcx[4]; Assert(dcx == "DCX\0"); +// int unk04; Assert(unk04 == 0x10000 || unk04 == 0x11000); +// int unk08; Assert(unk08 == 0x18); +// int unk0C; Assert(unk0C == 0x24); +// int unk10; Assert(unk10 == 0x24 || unk10 == 0x44); +// int unk14; // In EDGE, size from 0x20 to end of block headers +// char dcs[4]; Assert(dcs == "DCS\0"); +// uint uncompressedSize ; +// uint compressedSize ; +// char dcp[4]; Assert(dcp == "DCP\0"); +// char format[4]; Assert(format == "DFLT" || format == "EDGE" || format == "KRAK"); +// int unk2C; Assert(unk2C == 0x20); +// byte unk30; Assert(unk30 == 6|| unk30 == 8 || unk30 == 9); +// byte unk31 ; Assert(unk31 == 0); +// byte unk32 ; Assert(unk32 == 0); +// byte unk33 ; Assert(unk33 == 0); +// int unk34; Assert(unk34 == 0 || unk34 == 0x10000); // Block size for EDGE? +// int unk38; Assert(unk38 == 0); +// int unk3C; Assert(unk3C == 0); +// int unk40; +// char dca[4]; Assert(dca == "DCA\0"); +// int dcaSize; // From before "DCA" to dca end +// +// if (format == "EDGE") { +// char egdt[4]; Assert(egdt == "EgdT"); +// int unk50; Assert(unk50 == 0x10100); +// int unk54; Assert(unk54 == 0x24); +// int unk58; Assert(unk58 == 0x10); +// int unk5C; Assert(unk5C == 0x10000); +// int lastBlockUncompressedSize; +// int egdtSize; // From before "EgdT" to dca end +// int blockCount; +// int unk6C; Assert(unk6C == 0x100000); +// Block blocks[blockCount]; +// } +//} Header ; + +use nom::IResult; +use nom::bytes::complete::tag; +use nom::multi::count; +use nom::number::complete::*; +use nom::sequence::tuple; + +#[derive(Debug)] +pub struct DcxHeader { + pub magic: Vec, + pub unk04: u32, + pub ofs_dcs: u32, + pub ofs_dcp: u32, + pub unk10: u32, + pub unk14: u32, +} + +const HEADER_MAGIC: u32 = 0x00504344; + +fn parse_header(i: &[u8]) -> IResult<&[u8], DcxHeader> { + let (i, (magic, unk04, ofs_dcs, ofs_dcp, unk10, unk14)) = tuple(( + tag(b"DCX\0"), + be_u32, + be_u32, + be_u32, + be_u32, + be_u32, + ))(i)?; + Ok((i, DcxHeader { magic: magic.to_vec(), unk04, ofs_dcs, ofs_dcp, unk10, unk14 })) +} + +#[derive(Debug)] +pub struct DcxSizes { + pub magic: u32, + pub uncompressed_size: u32, + pub compressed_size: u32, +} + +#[allow(non_snake_case)] +#[derive(Debug)] +pub struct DcxParams { + pub magic: u32, + pub method: [u8; 4], + pub ofs_dca: u32, + pub unk0C: u32, + pub unk10: u32, + pub unk14: u32, + pub unk18: u32, + pub unk1C: u32, +} + +#[derive(Debug)] +pub struct Dcx { + pub header: DcxHeader, + pub sizes: DcxSizes, + pub params: DcxParams, +} + +pub fn parse(i: &[u8]) -> IResult<&[u8], u8> { + let (i, header) = parse_header(i).unwrap(); + println!("{:?}", header); + Ok((i, 0)) + + //Ok((i, Dcx { header: None, sizes: None, params: None })) +} diff --git a/src/unpackers/dcx.rs b/src/unpackers/dcx.rs new file mode 100644 index 0000000..05afb11 --- /dev/null +++ b/src/unpackers/dcx.rs @@ -0,0 +1,13 @@ +use std::fs; +use std::io::{self, Read}; + +use crate::parsers::dcx; + +pub fn extract_dcx(dcx_path: &str) -> Result<(), io::Error> { + let mut dcx_file = fs::File::open(dcx_path)?; + let file_len = dcx_file.metadata()?.len() as usize; + let mut dcx_data = vec![0u8; file_len]; + dcx_file.read_exact(&mut dcx_data)?; + dcx::parse(&dcx_data); + Ok(()) +}