1use libz_rs_sys::z_off_t;
5use std::ops::{Add, AddAssign, BitXor, BitXorAssign};
6
7pub(crate) struct Jamcrc {
9 table: [u32; 256],
10}
11
12impl Jamcrc {
13 pub(crate) const fn new() -> Self {
14 let mut table: [u32; 256] = [0u32; 256];
15
16 let polynomial: u32 = 0xEDB88320;
17 let mut i = 0;
18 while i < table.len() {
19 let mut c: u32 = i as u32;
20 let mut j = 0;
21 while j < 8 {
22 if (c & 1u32) == 1u32 {
23 c = polynomial ^ (c >> 1);
24 } else {
25 c >>= 1;
26 }
27 j += 1;
28 }
29
30 table[i] = c;
31 i += 1;
32 }
33
34 Self { table }
35 }
36
37 pub(crate) fn checksum(&self, bytes: &[u8]) -> u32 {
38 let mut c: u32 = 0xFFFFFFFF;
39 for byte in bytes {
40 c = self.table[((c ^ *byte as u32) & 0xFF) as usize] ^ (c >> 8);
41 }
42
43 !(c ^ 0xFFFFFFFF)
44 }
45}
46
47fn crc32(crc: u32, s: &[u8]) -> u32 {
48 unsafe { libz_rs_sys::crc32(crc.into(), s.as_ptr(), s.len() as u32) as u32 }
49}
50
51fn crc32_combine(crc1: u32, crc2: u32, len2: usize) -> u32 {
52 libz_rs_sys::crc32_combine(crc1.into(), crc2.into(), len2 as z_off_t) as u32
53}
54
55#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Default)]
58pub(crate) struct XivCrc32 {
59 pub crc: u32,
60 pub len: usize,
61}
62
63impl XivCrc32 {
64 pub(crate) fn new(crc: u32, len: usize) -> Self {
65 Self { crc, len }
66 }
67}
68
69impl From<&[u8]> for XivCrc32 {
70 fn from(s: &[u8]) -> Self {
71 Self::new(!crc32(0xFFFFFFFF, s), s.len())
72 }
73}
74
75impl<const N: usize> From<&[u8; N]> for XivCrc32 {
76 fn from(s: &[u8; N]) -> Self {
77 Self::new(!crc32(0xFFFFFFFF, s), N)
78 }
79}
80
81impl From<&str> for XivCrc32 {
82 fn from(s: &str) -> Self {
83 Self::from(s.as_bytes())
84 }
85}
86
87impl Add<XivCrc32> for XivCrc32 {
88 type Output = XivCrc32;
89
90 fn add(self, rhs: XivCrc32) -> Self::Output {
91 Self::new(
92 crc32_combine(self.crc, rhs.crc, rhs.len),
93 self.len + rhs.len,
94 )
95 }
96}
97
98impl AddAssign<XivCrc32> for XivCrc32 {
99 fn add_assign(&mut self, rhs: XivCrc32) {
100 self.crc = crc32_combine(self.crc, rhs.crc, rhs.len);
101 self.len += rhs.len;
102 }
103}
104
105impl BitXor<XivCrc32> for XivCrc32 {
106 type Output = XivCrc32;
107
108 fn bitxor(self, rhs: XivCrc32) -> Self::Output {
109 Self::new(self.crc ^ rhs.crc, self.len.max(rhs.len))
110 }
111}
112
113impl BitXorAssign<XivCrc32> for XivCrc32 {
114 fn bitxor_assign(&mut self, rhs: XivCrc32) {
115 self.crc ^= rhs.crc;
116 self.len = self.len.max(rhs.len);
117 }
118}
119
120#[cfg(test)]
121mod tests {
122 use super::*;
123 use crc::{Algorithm, Crc};
124
125 #[test]
126 fn check_jamcrc() {
127 use crc::{CRC_32_JAMCRC, Crc};
128
129 const JAMCR: Crc<u32> = Crc::<u32>::new(&CRC_32_JAMCRC);
130
131 let bytes: [u8; 9] = [1, 1, 2, 4, 5, 6, 12, 12, 12];
132
133 const CRC: Jamcrc = Jamcrc::new();
134
135 assert_eq!(JAMCR.checksum(&bytes), CRC.checksum(&bytes))
136 }
137
138 #[test]
139 fn check_xivcrc() {
140 const CRC_32_TEST: Algorithm<u32> = Algorithm {
141 width: 32,
142 poly: 0x04c11db7,
143 init: 0x00000000,
144 refin: true,
145 refout: true,
146 xorout: 0x00000000,
147 check: 0x765e7680,
148 residue: 0xc704dd7b,
149 };
150 const JAMCR: Crc<u32> = Crc::<u32>::new(&CRC_32_TEST);
151
152 let str = "Default";
153
154 assert_eq!(XivCrc32::from(str).crc, JAMCR.checksum(str.as_bytes()));
155 }
156}