diff --git a/Cargo.toml b/Cargo.toml index 9a66afc..2261f59 100755 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,6 +29,8 @@ hmac-sha512 = "1" # used while rust doesn't have native benchmarking capability brunch = { version = "0.5.3", default-features = false } +# used for testing our crc implementations +crc = "3" [features] default = ["visual_data"] @@ -66,6 +68,3 @@ bitflags = { version = "1.3", optional = true } # needed for dxt/bc decompression texture2ddecoder = { version = "0.0.5", optional = true } - -# used for testing our jamcrc implementation and currently SHPK -crc = "3" \ No newline at end of file diff --git a/src/crc.rs b/src/crc.rs index bd687f1..37e08f2 100644 --- a/src/crc.rs +++ b/src/crc.rs @@ -1,6 +1,10 @@ // SPDX-FileCopyrightText: 2023 Joshua Goins // SPDX-License-Identifier: GPL-3.0-or-later +use std::ops::{Add, AddAssign, BitXor, BitXorAssign}; +use libz_ng_sys::z_off_t; + +/// CRC used for filepath hashes in index file pub(crate) struct Jamcrc { table: [u32; 256], } @@ -40,12 +44,86 @@ impl Jamcrc { } } +fn crc32(crc: u32, s: &[u8]) -> u32 { + unsafe { libz_ng_sys::crc32(crc, s.as_ptr(), s.len() as u32) as u32 } +} + +fn crc32_combine(crc1: u32, crc2: u32, len2: usize) -> u32 { + unsafe { libz_ng_sys::crc32_combine(crc1, crc2, len2 as z_off_t) as u32 } +} + +/// CRC used for shader keys +/// Credit to https://github.com/NotNite/crcracker/ for the original Rust code +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Default)] +pub(crate) struct XivCrc32 { + pub crc: u32, + pub len: usize, +} + +impl XivCrc32 { + pub(crate) fn new(crc: u32, len: usize) -> Self { + Self { + crc, + len, + } + } +} + +impl From<&[u8]> for XivCrc32 { + fn from(s: &[u8]) -> Self { + Self::new(!crc32(0xFFFFFFFF, s), s.len()) + } +} + +impl From<&[u8; N]> for XivCrc32 { + fn from(s: &[u8; N]) -> Self { + Self::new(!crc32(0xFFFFFFFF, s), N) + } +} + +impl From<&str> for XivCrc32 { + fn from(s: &str) -> Self { + Self::from(s.as_bytes()) + } +} + +impl Add for XivCrc32 { + type Output = XivCrc32; + + fn add(self, rhs: XivCrc32) -> Self::Output { + Self::new(crc32_combine(self.crc, rhs.crc, rhs.len), self.len + rhs.len) + } +} + +impl AddAssign for XivCrc32 { + fn add_assign(&mut self, rhs: XivCrc32) { + self.crc = crc32_combine(self.crc, rhs.crc, rhs.len); + self.len += rhs.len; + } +} + +impl BitXor for XivCrc32 { + type Output = XivCrc32; + + fn bitxor(self, rhs: XivCrc32) -> Self::Output { + Self::new(self.crc ^ rhs.crc, self.len.max(rhs.len)) + } +} + +impl BitXorAssign for XivCrc32 { + fn bitxor_assign(&mut self, rhs: XivCrc32) { + self.crc ^= rhs.crc; + self.len = self.len.max(rhs.len); + } +} + #[cfg(test)] mod tests { + use crc::{Algorithm, Crc}; use super::*; #[test] - fn check_library() { + fn check_jamcrc() { use crc::{Crc, CRC_32_JAMCRC}; const JAMCR: Crc = Crc::::new(&CRC_32_JAMCRC); @@ -56,4 +134,14 @@ mod tests { assert_eq!(JAMCR.checksum(&bytes), CRC.checksum(&bytes)) } + + #[test] + fn check_xivcrc() { + const CRC_32_TEST: Algorithm = Algorithm { width: 32, poly: 0x04c11db7, init: 0x00000000, refin: true, refout: true, xorout: 0x00000000, check: 0x765e7680, residue: 0xc704dd7b }; + const JAMCR: Crc = Crc::::new(&CRC_32_TEST); + + let str = "Default"; + + assert_eq!(XivCrc32::from(str).crc, JAMCR.checksum(str.as_bytes())); + } } diff --git a/src/shpk.rs b/src/shpk.rs index b2ef658..5e88b44 100644 --- a/src/shpk.rs +++ b/src/shpk.rs @@ -5,7 +5,7 @@ use std::io::{Cursor, SeekFrom}; use crate::ByteSpan; use binrw::{binread, BinRead}; -use crc::{Algorithm, Crc}; +use crate::crc::XivCrc32; #[binread] #[br(little, import { @@ -209,10 +209,6 @@ pub struct ShaderPackage { const SELECTOR_MULTIPLER: u32 = 31; -// TODO: replace use of crc crate here -const CRC_32_TEST: Algorithm = Algorithm { width: 32, poly: 0x04c11db7, init: 0x00000000, refin: true, refout: true, xorout: 0x00000000, check: 0x765e7680, residue: 0xc704dd7b }; -const JAMCR: Crc = Crc::::new(&CRC_32_TEST); - impl ShaderPackage { /// Reads an existing SHPK file pub fn from_existing(buffer: ByteSpan) -> Option { @@ -275,7 +271,7 @@ impl ShaderPackage { } pub fn crc(str: &str) -> u32 { - return JAMCR.checksum(str.as_bytes()); + return XivCrc32::from(str).crc; } } @@ -283,7 +279,6 @@ impl ShaderPackage { mod tests { use std::fs::read; use std::path::PathBuf; - use crate::repository::Category::Shader; use super::*;