Skip to content

Commit

Permalink
Merge pull request #23 from soulsmods/feat/better-dcx
Browse files Browse the repository at this point in the history
DCX parser rework
  • Loading branch information
garyttierney authored Mar 5, 2024
2 parents 512d92f + 0119419 commit ce2d597
Show file tree
Hide file tree
Showing 10 changed files with 328 additions and 146 deletions.
13 changes: 3 additions & 10 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,8 @@ indicatif = { version = "0.17", features = ["rayon"] }
rayon = "1"
souls_vfs = { path = "../vfs" }
util = { path = "../util" }

[dependencies.memmap2]
version = "0.7"


22 changes: 17 additions & 5 deletions cli/src/bin/dcx-extract.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use std::io::Write;
use std::io::{Read, Write};

use clap::Parser;
use format::{bnd4::BND4, dcx::DCX};
use format::{bnd4::BND4, dcx::Dcx};
use memmap2::MmapOptions;

#[derive(Parser, Debug)]
#[command(version, about, long_about = None)]
Expand All @@ -14,10 +15,21 @@ fn main() -> Result<(), std::io::Error> {
let args = Args::parse();
let path = std::path::PathBuf::from(args.file);

let mut dcx_file = std::fs::File::open(&path)?;
let dcx = DCX::from_reader(&mut dcx_file).expect("Could not parse DCX");
let dcx_file = std::fs::File::open(&path)?;
let data = unsafe {
MmapOptions::new()
.populate()
.map_copy_read_only(&dcx_file)?
};

let mut cursor = std::io::Cursor::new(dcx.decompressed);
let dcx = Dcx::parse(&data).unwrap();

let mut decoder = dcx.create_decoder().expect("Could not create decoder");

let mut decompressed = Vec::with_capacity(decoder.hint_size());
decoder.read_to_end(&mut decompressed)?;

let mut cursor = std::io::Cursor::new(decompressed);
let bnd4 = BND4::from_reader(&mut cursor)?;

let folder = format!(
Expand Down
5 changes: 4 additions & 1 deletion format/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,14 @@ strict-padding = []
bytemuck = "1"
byteorder = "1"
aes = "0.8"
oodle-safe = "0.1.0"
rayon = "1"
rug = "1.24"
rsa = "0.9"
zerocopy = { version = "0.7.32", features = ["derive"] }
flate2 = "1.0"

[dependencies.thiserror]
workspace = true

[dependencies.oodle-sys]
version = "0.1"
114 changes: 0 additions & 114 deletions format/src/dcx.rs

This file was deleted.

17 changes: 17 additions & 0 deletions format/src/dcx/deflate.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
use std::io::{self, Read};

use flate2::read::ZlibDecoder;

pub struct DcxDecoderDeflate<'a>(ZlibDecoder<&'a [u8]>);

impl<'a> DcxDecoderDeflate<'a> {
pub fn from_buffer(buf: &'a [u8]) -> Self {
Self(ZlibDecoder::new(buf))
}
}

impl<'a> Read for DcxDecoderDeflate<'a> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.0.read(buf)
}
}
65 changes: 65 additions & 0 deletions format/src/dcx/kraken.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
use std::io::{Cursor, Error, ErrorKind, Read, Result};

use byteorder::BE;
use oodle_sys::{
OodleLZ_Decode_ThreadPhase_OodleLZ_Decode_ThreadPhaseAll, OodleLZ_Decompress, OODLELZ_FAILED,
};
use zerocopy::U32;

pub struct DcxDecoderKraken<'a> {
compressed: &'a [u8],
uncompressed_size: U32<BE>,
inner_cursor: Option<Cursor<Vec<u8>>>,
}

impl<'a> DcxDecoderKraken<'a> {
pub fn from_buffer(buf: &'a [u8], uncompressed_size: U32<BE>) -> Self {
Self {
compressed: buf,
uncompressed_size,
inner_cursor: None,
}
}
}
impl<'a> Read for DcxDecoderKraken<'a> {
// TODO: implement somewhat incremental reading by working with oodle's
// blocks per example in docs.
// It currently just decompresses the entire input one go and then
// operates a Cursor wrapping the decompressed bytes.
fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
if self.inner_cursor.is_none() {
let mut inner_buffer = vec![0u8; self.uncompressed_size.get() as usize];
let compressed_len =
isize::try_from(inner_buffer.len()).map_err(|e| Error::new(ErrorKind::Other, e))?;
let inner_buffer_len =
isize::try_from(inner_buffer.len()).map_err(|e| Error::new(ErrorKind::Other, e))?;

let result = unsafe {
OodleLZ_Decompress(
self.compressed.as_ptr() as *const _,
compressed_len,
inner_buffer.as_mut_ptr() as *mut _,
inner_buffer_len,
oodle_sys::OodleLZ_FuzzSafe_OodleLZ_FuzzSafe_Yes,
0,
0,
std::ptr::null_mut(),
0,
None,
std::ptr::null_mut(),
std::ptr::null_mut(),
0,
OodleLZ_Decode_ThreadPhase_OodleLZ_Decode_ThreadPhaseAll,
) as usize
};

if result == OODLELZ_FAILED as usize {
return Err(Error::from(ErrorKind::Other));
}

self.inner_cursor = Some(Cursor::new(inner_buffer));
}

self.inner_cursor.as_mut().unwrap().read(buf)
}
}
Loading

0 comments on commit ce2d597

Please sign in to comment.