diff --git a/Cargo.lock b/Cargo.lock index 7dcbae1..48d591c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1715,6 +1715,7 @@ dependencies = [ "webp", "windows-sys 0.61.2", "xml5ever", + "xxhash-rust", "zopfli", "zstd", ] @@ -3192,6 +3193,12 @@ dependencies = [ "markup5ever", ] +[[package]] +name = "xxhash-rust" +version = "0.8.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdd20c5420375476fbd4394763288da7eb0cc0b8c11deed431a91562af7335d3" + [[package]] name = "yoke" version = "0.8.2" diff --git a/Cargo.toml b/Cargo.toml index 2a3deb5..5adf01e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -70,6 +70,7 @@ url = { version = "2.5", optional = true } utf16string = "0.2" webp = { version = "0.3", default-features = false, optional = true } xml5ever = { version = "0.38", optional = true } +xxhash-rust = { version = "0.8", optional = true } zopfli = { version = "0.8", optional = true } zstd = { version = "0.13", optional = true } @@ -123,7 +124,7 @@ will-plus-img = ["will-plus", "image"] yaneurao = [] yaneurao-itufuru = ["yaneurao", "utils-xored-stream"] yuris = ["dep:chrono", "dep:hex", "utils-serde-base64bytes", "utils-xored-stream"] -yuris-arc = ["yuris", "dep:adler", "dep:crc32fast", "flate2", "dep:int-enum", "utils-murmur2"] +yuris-arc = ["yuris", "dep:adler", "dep:crc32fast", "flate2", "dep:int-enum", "utils-murmur2", "dep:xxhash-rust", "xxhash-rust/xxh32"] yuris-img = ["yuris", "image", "qoi", "webp"] # basic feature image = ["dep:png"] diff --git a/src/args.rs b/src/args.rs index 5e7cfc0..ba38641 100644 --- a/src/args.rs +++ b/src/args.rs @@ -789,6 +789,11 @@ pub struct Arg { #[arg(long, global = true)] /// Check hash when unpack Yu-RIS archive (.ypf) pub yuris_check_hash: bool, + #[cfg(feature = "yuris-arc")] + #[arg(long, global = true)] + /// Print debug information for Yu-RIS archive (.ypf) when extracting archive to stdout. + /// This is used to find correct configuration for Yu-RIS archives. + pub yuris_debug_archive: bool, #[command(subcommand)] /// Command pub command: Command, diff --git a/src/main.rs b/src/main.rs index 345b34d..1afbd13 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3427,8 +3427,10 @@ fn main() { yuris_name_hash_type: arg.yuris_name_hash_type, #[cfg(feature = "yuris-arc")] yuris_data_hash_type: arg.yuris_data_hash_type, - #[cfg(feature = "yuris")] + #[cfg(feature = "yuris-arc")] yuris_check_hash: arg.yuris_check_hash, + #[cfg(feature = "yuris-arc")] + yuris_debug_archive: arg.yuris_debug_archive, }); match &arg.command { args::Command::Export { input, output } => { diff --git a/src/scripts/yuris/arc/ypf.rs b/src/scripts/yuris/arc/ypf.rs index c361ee1..810291d 100644 --- a/src/scripts/yuris/arc/ypf.rs +++ b/src/scripts/yuris/arc/ypf.rs @@ -8,7 +8,7 @@ use anyhow::{Result, anyhow, bail}; use clap::ValueEnum; use int_enum::IntEnum; use std::hash::Hasher; -use std::io::{Read, Seek, SeekFrom}; +use std::io::{Read, Seek, SeekFrom, Write}; use std::sync::{Arc, Mutex}; #[derive(Debug)] @@ -150,12 +150,13 @@ impl Default for NameHashType { } #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, ValueEnum)] -// #TODO: Whirlpool Relirium has another hash type pub enum DataHashType { /// Adler32 Adler32, /// Murmur2 Murmur2, + /// Xxhash32 + Xxh32, } impl Default for DataHashType { @@ -224,6 +225,7 @@ fn detect_data_hash( ) -> Result { let mut murmur2_hasher = StreamingMurmur2::new(0, size); let mut adler32_hasher = adler::Adler32::new(); + let mut xxh32_hasher = Xxh32::new(0); let mut buf = [0; 1024]; loop { let readed = stream.read(&mut buf)?; @@ -233,6 +235,7 @@ fn detect_data_hash( let b = &buf[..readed]; murmur2_hasher.write(b); adler32_hasher.write(b); + xxh32_hasher.write(b); } if murmur2_hasher.finish() as u32 == expected { return Ok(DataHashType::Murmur2); @@ -240,6 +243,9 @@ fn detect_data_hash( if adler32_hasher.finish() as u32 == expected { return Ok(DataHashType::Adler32); } + if xxh32_hasher.finish() as u32 == expected { + return Ok(DataHashType::Xxh32); + } bail!("Unknown hash type or checksum/data is invalid/broken") } @@ -327,6 +333,10 @@ impl<'b, T: Read + Seek + std::fmt::Debug + Send + Sync + 'b> YPF<'b, T> { }) } } + if config.yuris_debug_archive { + println!("Entries in yuris YPF: {:#?}", entries); + let _ = std::io::stdout().flush(); + } if config.yuris_check_hash { let mut data_hash_type = None; for entry in &entries { @@ -345,6 +355,7 @@ impl<'b, T: Read + Seek + std::fmt::Debug + Send + Sync + 'b> YPF<'b, T> { DataHashType::Murmur2 => { Box::new(StreamingMurmur2::new(0, entry.compressed_size)) } + DataHashType::Xxh32 => Box::new(Xxh32::new(0)), }; let mut buf = [0; 1024]; loop { @@ -570,3 +581,24 @@ impl<'a, T: Read + Seek + std::fmt::Debug + Send + Sync + 'a> Seek for Entry<'a, } } } + +pub struct Xxh32 { + inner: xxhash_rust::xxh32::Xxh32, +} + +impl Xxh32 { + pub fn new(seed: u32) -> Self { + Self { + inner: xxhash_rust::xxh32::Xxh32::new(seed), + } + } +} + +impl Hasher for Xxh32 { + fn write(&mut self, bytes: &[u8]) { + self.inner.update(bytes); + } + fn finish(&self) -> u64 { + self.inner.digest() as u64 + } +} diff --git a/src/types.rs b/src/types.rs index 741d074..a198c79 100644 --- a/src/types.rs +++ b/src/types.rs @@ -689,6 +689,10 @@ pub struct ExtraConfig { #[cfg(feature = "yuris-arc")] /// Check hash when unpack Yu-RIS archive (.ypf) pub yuris_check_hash: bool, + #[cfg(feature = "yuris-arc")] + /// Print debug information for Yu-RIS archive (.ypf) when extracting archive to stdout. + /// This is used to find correct configuration for Yu-RIS archives. + pub yuris_debug_archive: bool, } #[cfg(feature = "artemis")]