use crate::core::RaylibThread;
use crate::ffi;
unsafe fn read_static_hash<const N: usize, const M: usize>(ptr: *const u32, be: bool) -> [u8; M] {
assert_eq!(M, N * 4, "read_static_hash: M must equal N * 4");
let words: &[u32] = unsafe { std::slice::from_raw_parts(ptr, N) };
let mut out = [0u8; M];
for (i, &w) in words.iter().enumerate() {
let bytes = if be { w.to_be_bytes() } else { w.to_le_bytes() };
out[i * 4..(i + 1) * 4].copy_from_slice(&bytes);
}
out
}
pub fn compute_crc32(data: &[u8]) -> u32 {
assert!(
data.len() <= i32::MAX as usize,
"input length {} exceeds raylib's i32 dataSize limit",
data.len(),
);
unsafe { ffi::ComputeCRC32(data.as_ptr() as *mut _, data.len() as i32) }
}
pub fn compute_md5(_thread: &RaylibThread, data: &[u8]) -> [u8; 16] {
assert!(
data.len() <= i32::MAX as usize,
"input length {} exceeds raylib's i32 dataSize limit",
data.len(),
);
let ptr = unsafe { ffi::ComputeMD5(data.as_ptr() as *mut _, data.len() as i32) };
unsafe { read_static_hash::<4, 16>(ptr, false) }
}
pub fn compute_sha1(_thread: &RaylibThread, data: &[u8]) -> [u8; 20] {
assert!(
data.len() <= i32::MAX as usize,
"input length {} exceeds raylib's i32 dataSize limit",
data.len(),
);
let ptr = unsafe { ffi::ComputeSHA1(data.as_ptr() as *mut _, data.len() as i32) };
unsafe { read_static_hash::<5, 20>(ptr, true) }
}
pub fn compute_sha256(_thread: &RaylibThread, data: &[u8]) -> [u8; 32] {
assert!(
data.len() <= i32::MAX as usize,
"input length {} exceeds raylib's i32 dataSize limit",
data.len(),
);
let ptr = unsafe { ffi::ComputeSHA256(data.as_ptr() as *mut _, data.len() as i32) };
unsafe { read_static_hash::<8, 32>(ptr, true) }
}
#[cfg(test)]
mod tests {
use super::*;
fn hex(bytes: &[u8]) -> String {
use std::fmt::Write;
let mut s = String::with_capacity(bytes.len() * 2);
for b in bytes {
write!(&mut s, "{:02x}", b).expect("write to String never fails");
}
s
}
#[test]
fn crc32_known_vectors() {
assert_eq!(compute_crc32(b""), 0x00000000);
assert_eq!(compute_crc32(b"123456789"), 0xCBF43926);
assert_eq!(
compute_crc32(b"The quick brown fox jumps over the lazy dog"),
0x414FA339,
);
}
#[test]
#[should_panic(expected = "exceeds raylib's i32 dataSize limit")]
fn crc32_panics_on_oversize_input() {
let real_byte = 0u8;
let fake_slice: &[u8] =
unsafe { std::slice::from_raw_parts(&real_byte as *const u8, i32::MAX as usize + 1) };
let _ = compute_crc32(fake_slice);
}
#[cfg(feature = "software_renderer")]
#[test]
fn md5_known_vectors() {
crate::test_harness::with_headless(1, 1, |_rl, thread| {
assert_eq!(
hex(&compute_md5(thread, b"")),
"d41d8cd98f00b204e9800998ecf8427e",
);
assert_eq!(
hex(&compute_md5(thread, b"abc")),
"900150983cd24fb0d6963f7d28e17f72",
);
assert_eq!(
hex(&compute_md5(
thread,
b"The quick brown fox jumps over the lazy dog"
)),
"9e107d9d372bb6826bd81d3542a419d6",
);
});
}
#[cfg(feature = "software_renderer")]
#[test]
fn sha1_known_vectors() {
crate::test_harness::with_headless(1, 1, |_rl, thread| {
assert_eq!(
hex(&compute_sha1(thread, b"")),
"da39a3ee5e6b4b0d3255bfef95601890afd80709",
);
assert_eq!(
hex(&compute_sha1(thread, b"abc")),
"a9993e364706816aba3e25717850c26c9cd0d89d",
);
assert_eq!(
hex(&compute_sha1(
thread,
b"The quick brown fox jumps over the lazy dog"
)),
"2fd4e1c67a2d28fced849ee1bb76e7391b93eb12",
);
});
}
#[cfg(feature = "software_renderer")]
#[test]
fn sha256_known_vectors() {
crate::test_harness::with_headless(1, 1, |_rl, thread| {
assert_eq!(
hex(&compute_sha256(thread, b"")),
"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
);
assert_eq!(
hex(&compute_sha256(thread, b"abc")),
"ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad",
);
assert_eq!(
hex(&compute_sha256(
thread,
b"The quick brown fox jumps over the lazy dog"
)),
"d7a8fbb307d7809469ca9abcb0082e4f8d5651e46d3cdb762d02d0bf37c9e592",
);
});
}
}