dcx: complete decompression

This commit is contained in:
dece 2020-04-22 02:51:14 +02:00
parent 807523bf22
commit fe4b7c555d
6 changed files with 70 additions and 9 deletions

37
Cargo.lock generated
View file

@ -1,5 +1,10 @@
# This file is automatically @generated by Cargo. # This file is automatically @generated by Cargo.
# It is not intended for manual editing. # 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]] [[package]]
name = "ansi_term" name = "ansi_term"
version = "0.11.0" version = "0.11.0"
@ -55,6 +60,25 @@ dependencies = [
"vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", "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]] [[package]]
name = "hermit-abi" name = "hermit-abi"
version = "0.1.10" version = "0.1.10"
@ -86,6 +110,14 @@ name = "memchr"
version = "2.3.3" version = "2.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index" 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]] [[package]]
name = "nodrop" name = "nodrop"
version = "0.1.14" version = "0.1.14"
@ -141,6 +173,7 @@ name = "rusted_iron_ring"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "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)", "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-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)", "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" source = "registry+https://github.com/rust-lang/crates.io-index"
[metadata] [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 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 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" "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 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 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 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 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 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 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 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 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 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" "checksum num-bigint 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "090c7f9998ee0ff65aa5b723e4009f7b217707f1fb5ea551329cc4d6231fb304"

View file

@ -16,3 +16,4 @@ clap = "2.33"
nom = "5" nom = "5"
num-bigint = "0.2" num-bigint = "0.2"
num-traits = "0.2" num-traits = "0.2"
flate2 = "1.0"

View file

@ -108,6 +108,6 @@ pub fn parse(i: &[u8]) -> IResult<&[u8], Dcx> {
let pos_dcp = header.ofs_dcp as usize; let pos_dcp = header.ofs_dcp as usize;
let (_, params) = parse_params(&full_file[pos_dcp..])?; let (_, params) = parse_params(&full_file[pos_dcp..])?;
let pos_dca = pos_dcp + params.ofs_dca as usize; 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 })) Ok((i, Dcx { header, sizes, params, archive }))
} }

View file

@ -11,6 +11,10 @@ use crate::unpackers::errors::{self as unpackers_errors, UnpackError};
use crate::utils::fs as fs_utils; use crate::utils::fs as fs_utils;
/// Parse a BHD file and extract its content. /// 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( pub fn extract_bhd(
bhd_path: &str, bhd_path: &str,
names: &HashMap<String, String>, names: &HashMap<String, String>,
@ -39,7 +43,7 @@ pub fn extract_bhd(
} }
/// Extract files from a BHD/BDT pair. /// Extract files from a BHD/BDT pair.
pub fn extract_files( fn extract_files(
bhd: &bhd::Bhd, bhd: &bhd::Bhd,
bdt_file: &mut fs::File, bdt_file: &mut fs::File,
names: &HashMap<String, String>, names: &HashMap<String, String>,

View file

@ -1,6 +1,7 @@
use std::fs; 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 nom::Err::{Error as NomError, Failure as NomFailure};
use crate::parsers::dcx; 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 file_len = dcx_file.metadata()?.len() as usize;
let mut dcx_data = vec![0u8; file_len]; let mut dcx_data = vec![0u8; file_len];
dcx_file.read_exact(&mut dcx_data)?; dcx_file.read_exact(&mut dcx_data)?;
let dcx = match dcx::parse(&dcx_data) { let (data, dcx) = match dcx::parse(&dcx_data) {
Ok((_, dcx)) => { dcx } Ok(result) => { result }
Err(NomError(e)) | Err(NomFailure(e)) => { Err(NomError(e)) | Err(NomFailure(e)) => {
let reason = unpackers_errors::get_nom_error_reason(e.1); let reason = unpackers_errors::get_nom_error_reason(e.1);
return Err(UnpackError::Parsing("DCX parsing failed: ".to_owned() + &reason)) 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(()) Ok(())
} }
pub fn decompress_dcx(dcx: &dcx::Dcx) -> Vec<u8> { fn decompress_dcx(dcx: &dcx::Dcx, comp_data: &[u8]) -> Result<Vec<u8>, UnpackError> {
let mut data = vec![0u8; dcx.sizes.uncompressed_size as usize]; let method: &[u8] = dcx.params.method.as_slice();
data 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<Vec<u8>, UnpackError> {
let mut data = vec![0u8; dcx.sizes.uncompressed_size as usize];
let mut deflater = ZlibDecoder::new(comp_data);
deflater.read_exact(&mut data)?;
Ok(data)
} }

View file

@ -4,6 +4,7 @@ use std::io;
pub enum UnpackError { pub enum UnpackError {
Io(io::Error), Io(io::Error),
Parsing(String), Parsing(String),
Compression(String),
Unknown(String), Unknown(String),
} }