From fe4b7c555d8d553cd5b0ae0a204fba9777aab2a7 Mon Sep 17 00:00:00 2001 From: dece Date: Wed, 22 Apr 2020 02:51:14 +0200 Subject: [PATCH] dcx: complete decompression --- Cargo.lock | 37 +++++++++++++++++++++++++++++++++++++ Cargo.toml | 1 + src/parsers/dcx.rs | 2 +- src/unpackers/bhd.rs | 6 +++++- src/unpackers/dcx.rs | 30 ++++++++++++++++++++++++------ src/unpackers/errors.rs | 1 + 6 files changed, 69 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a83ed68..5f36abb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,5 +1,10 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +[[package]] +name = "adler32" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "ansi_term" version = "0.11.0" @@ -55,6 +60,25 @@ dependencies = [ "vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "crc32fast" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "flate2" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", + "miniz_oxide 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "hermit-abi" version = "0.1.10" @@ -86,6 +110,14 @@ name = "memchr" version = "2.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "miniz_oxide" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "adler32 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "nodrop" version = "0.1.14" @@ -141,6 +173,7 @@ name = "rusted_iron_ring" version = "0.1.0" dependencies = [ "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", + "flate2 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", "nom 5.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "num-bigint 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", @@ -217,6 +250,7 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" [metadata] +"checksum adler32 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "5d2e7343e7fc9de883d1b0341e0b13970f764c14101234857d2ddafa1cb1cac2" "checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" "checksum arrayvec 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "cd9fd44efafa8690358b7408d253adf110036b88f55672a933f01d616ad9b1b9" "checksum atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" @@ -224,10 +258,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" "checksum cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b486ce3ccf7ffd79fdeb678eac06a9e6c09fc88d33836340becb8fffe87c5e33" "checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9" +"checksum crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1" +"checksum flate2 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)" = "2cfff41391129e0a856d6d822600b8d71179d46879e310417eb9c762eb178b42" "checksum hermit-abi 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "725cf19794cf90aa94e65050cb4191ff5d8fa87a498383774c47b332e3af952e" "checksum lexical-core 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f86d66d380c9c5a685aaac7a11818bdfa1f733198dfd9ec09c70b762cd12ad6f" "checksum libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)" = "dea0c0405123bba743ee3f91f49b1c7cfb684eef0da0a50110f758ccf24cdff0" "checksum memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400" +"checksum miniz_oxide 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "aa679ff6578b1cddee93d7e82e263b94a575e0bfced07284eb0c037c1d2416a5" "checksum nodrop 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" "checksum nom 5.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0b471253da97532da4b61552249c521e01e736071f71c1a4f7ebbfbf0a06aad6" "checksum num-bigint 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "090c7f9998ee0ff65aa5b723e4009f7b217707f1fb5ea551329cc4d6231fb304" diff --git a/Cargo.toml b/Cargo.toml index c93aca8..e9f9c79 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,3 +16,4 @@ clap = "2.33" nom = "5" num-bigint = "0.2" num-traits = "0.2" +flate2 = "1.0" diff --git a/src/parsers/dcx.rs b/src/parsers/dcx.rs index 39d33ed..310b234 100644 --- a/src/parsers/dcx.rs +++ b/src/parsers/dcx.rs @@ -108,6 +108,6 @@ pub fn parse(i: &[u8]) -> IResult<&[u8], Dcx> { let pos_dcp = header.ofs_dcp as usize; let (_, params) = parse_params(&full_file[pos_dcp..])?; let pos_dca = pos_dcp + params.ofs_dca as usize; - let (_, archive) = parse_archive(&full_file[pos_dca..])?; + let (i, archive) = parse_archive(&full_file[pos_dca..])?; Ok((i, Dcx { header, sizes, params, archive })) } diff --git a/src/unpackers/bhd.rs b/src/unpackers/bhd.rs index 6dcc6e2..38c2a41 100644 --- a/src/unpackers/bhd.rs +++ b/src/unpackers/bhd.rs @@ -11,6 +11,10 @@ use crate::unpackers::errors::{self as unpackers_errors, UnpackError}; use crate::utils::fs as fs_utils; /// Parse a BHD file and extract its content. +/// +/// As names are often a path rather than a simple file name, +/// output path is used as the BHD root and required subdirs +/// are automatically created. pub fn extract_bhd( bhd_path: &str, names: &HashMap, @@ -39,7 +43,7 @@ pub fn extract_bhd( } /// Extract files from a BHD/BDT pair. -pub fn extract_files( +fn extract_files( bhd: &bhd::Bhd, bdt_file: &mut fs::File, names: &HashMap, diff --git a/src/unpackers/dcx.rs b/src/unpackers/dcx.rs index db69c98..efe0d71 100644 --- a/src/unpackers/dcx.rs +++ b/src/unpackers/dcx.rs @@ -1,6 +1,7 @@ use std::fs; -use std::io::{Read}; +use std::io::{Read, Write}; +use flate2::read::ZlibDecoder; use nom::Err::{Error as NomError, Failure as NomFailure}; use crate::parsers::dcx; @@ -11,8 +12,8 @@ pub fn extract_dcx(dcx_path: &str, output_path: &str) -> Result<(), UnpackError> let file_len = dcx_file.metadata()?.len() as usize; let mut dcx_data = vec![0u8; file_len]; dcx_file.read_exact(&mut dcx_data)?; - let dcx = match dcx::parse(&dcx_data) { - Ok((_, dcx)) => { dcx } + let (data, dcx) = match dcx::parse(&dcx_data) { + Ok(result) => { result } Err(NomError(e)) | Err(NomFailure(e)) => { let reason = unpackers_errors::get_nom_error_reason(e.1); return Err(UnpackError::Parsing("DCX parsing failed: ".to_owned() + &reason)) @@ -22,12 +23,29 @@ pub fn extract_dcx(dcx_path: &str, output_path: &str) -> Result<(), UnpackError> } }; + let decomp_data = decompress_dcx(&dcx, data)?; - println!("{:?}", dcx); + let mut output_file = fs::File::create(output_path)?; + output_file.write_all(&decomp_data)?; Ok(()) } -pub fn decompress_dcx(dcx: &dcx::Dcx) -> Vec { +fn decompress_dcx(dcx: &dcx::Dcx, comp_data: &[u8]) -> Result, UnpackError> { + let method: &[u8] = dcx.params.method.as_slice(); + if method == b"DFLT" { + decompress_dcx_deflate(dcx, comp_data) + } else { + let method_string = match std::str::from_utf8(method) { + Ok(s) => { String::from(s) } + Err(_) => { format!("{:?}", method) } + }; + Err(UnpackError::Compression(format!("Unknown method: {}", method_string))) + } +} + +fn decompress_dcx_deflate(dcx: &dcx::Dcx, comp_data: &[u8]) -> Result, UnpackError> { let mut data = vec![0u8; dcx.sizes.uncompressed_size as usize]; - data + let mut deflater = ZlibDecoder::new(comp_data); + deflater.read_exact(&mut data)?; + Ok(data) } diff --git a/src/unpackers/errors.rs b/src/unpackers/errors.rs index 95231a8..acc7b32 100644 --- a/src/unpackers/errors.rs +++ b/src/unpackers/errors.rs @@ -4,6 +4,7 @@ use std::io; pub enum UnpackError { Io(io::Error), Parsing(String), + Compression(String), Unknown(String), }