From 0e964c9bd6021043cc7ce2d3c4b7de2f707f42c4 Mon Sep 17 00:00:00 2001 From: "Jasper St. Pierre" Date: Thu, 23 Jan 2025 20:42:40 -0800 Subject: [PATCH] rust: Fix bit-endianness issue with new-deku This was the cause of all of our WoW rendering failures with new-deku. Unfortunate we can't (yet?) use Deku for this part, but honestly I think the shift + mask is better than a loop anyway. --- rust/src/wow/db.rs | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/rust/src/wow/db.rs b/rust/src/wow/db.rs index 6e8ea434e..bfc9585d9 100644 --- a/rust/src/wow/db.rs +++ b/rust/src/wow/db.rs @@ -139,20 +139,23 @@ fn from_u32(v: u32) -> Result fn read_field_to_u32(reader: &mut Reader, field_offset_bits: usize, field_size_bits: usize) -> Result { // Assumes the reader points to the start of the record let old = reader.seek(std::io::SeekFrom::Current(0i64)).unwrap(); - reader.skip_bits(field_offset_bits)?; + + // This is somewhat annoying. Deku uses Msb0 ordering, while we want Lsb0 ordering. + // Do the math ourselves rather than using Deku's read_bits. + // Deku trunk supports Lsb0 ordering, but that's not released yet. + let field_offset_bytes = field_offset_bits >> 3; + reader.seek(std::io::SeekFrom::Current(field_offset_bytes as i64)).unwrap(); + + let shift = field_offset_bits & 7; + let field_size_bytes = (field_size_bits + 7 + shift) >> 3; assert!(field_size_bits <= 32); - let num_bits_to_read = (field_size_bits + 7) & !7; - - let mut result = 0; - if let Some(bits) = reader.read_bits(num_bits_to_read)? { - for bit_num in 0..field_size_bits { - let byte_index = bit_num >> 3; - let bit_index = 7 - (bit_num % 8); - if bits[byte_index * 8 + bit_index] { - result |= 1 << bit_num; - } - } - } + + let mut buf = [0x00; 4]; + reader.read_bytes(field_size_bytes, &mut buf)?; + let v = u32::from_le_bytes(buf); + + let mask = (1 << field_size_bits) - 1; + let result = (v >> shift) & mask; reader.seek(std::io::SeekFrom::Start(old)).unwrap(); Ok(result)