diff --git a/zlib-rs/Cargo.toml b/zlib-rs/Cargo.toml index acbe84b7..103d665b 100644 --- a/zlib-rs/Cargo.toml +++ b/zlib-rs/Cargo.toml @@ -18,3 +18,5 @@ libc.workspace = true [dev-dependencies] libloading = "0.8.1" libz-ng-sys = "1.1.12" +crc32fast = "1.3.2" +quickcheck = "1.0.3" diff --git a/zlib-rs/src/crc32.rs b/zlib-rs/src/crc32.rs new file mode 100644 index 00000000..4bfb4405 --- /dev/null +++ b/zlib-rs/src/crc32.rs @@ -0,0 +1,46 @@ +use std::sync::Once; + +const LSB_POLY: u32 = 0xedb8_8320u32; +const START_CHECKSUM: u32 = 0xffff_ffffu32; +const FINAL_XOR: u32 = 0xffff_ffffu32; + +// This could be auto-generated +static mut CRC_TABLE: [u32; 256] = [0; 256]; +static CRC_TABLE_ONCE: Once = Once::new(); + +fn get_crc_table() -> &'static [u32] { + CRC_TABLE_ONCE.call_once(|| { + for i in 0..256u16 { + let mut c = u32::from(i); + for k in 0..8 { + if c & 1 != 0 { + c = LSB_POLY ^ (c >> 1); + } else { + c >>= 1; + } + } + unsafe { CRC_TABLE[usize::from(i)] = c; } + } + }); + unsafe { &CRC_TABLE[..] } +} + +fn naive_crc32(data: &[u8]) -> u32 { + let crc_table = get_crc_table(); + let crc = data.iter().fold(START_CHECKSUM, |crc, val| { + let crc_lsb = crc.to_le_bytes()[0]; + crc_table[usize::from(crc_lsb ^ *val)] ^ (crc >> 8) + }); + crc ^ FINAL_XOR +} + +#[cfg(test)] +mod test { + use super::*; + + quickcheck::quickcheck! { + fn naive_is_crc32fast(v: Vec) -> bool { + naive_crc32(&v[..]) == crc32fast::hash(&v[..]) + } + } +} diff --git a/zlib-rs/src/lib.rs b/zlib-rs/src/lib.rs index 68d29907..f7618b3a 100644 --- a/zlib-rs/src/lib.rs +++ b/zlib-rs/src/lib.rs @@ -1,4 +1,5 @@ mod adler32; +mod crc32; pub mod allocate; pub mod c_api; pub mod deflate;