gzp/
check.rs

1//! Wrappers around different check types.
2//!
3//! A `Check` simply computes the checksum for a block and keeps track of the number of
4//! bytes that went into that checksum.
5//!
6//! The [`flate2::Crc`] implementation is used for Crc32 with a thin wrapper, and for
7//! the Adler Check the `ader32*` family of functions from zlib is wrapped.
8//!
9//! Additionally, there is a passthrough check to allow for compressions types that
10//! can bypass this check.
11#[cfg(feature = "deflate")]
12use flate2::Crc;
13
14#[cfg(feature = "deflate_zlib_ng")]
15use libz_ng_sys::{adler32, adler32_combine, uInt, z_off_t};
16#[cfg(all(feature = "any_zlib", not(feature = "deflate_zlib_ng")))]
17use libz_sys::{adler32, adler32_combine, uInt, z_off_t};
18
19pub trait Check {
20    /// Current checksum
21    fn sum(&self) -> u32;
22
23    /// Amount input to the check
24    fn amount(&self) -> u32;
25
26    /// Create a new [`Check`] Object
27    fn new() -> Self
28    where
29        Self: Sized;
30
31    /// Update the [`Check`] object with more bytes.
32    fn update(&mut self, bytes: &[u8]);
33
34    /// Combine two like [`Check`] objects.
35    fn combine(&mut self, other: &Self)
36    where
37        Self: Sized;
38}
39
40/// LibDeflates impl of CRC, this does not implement `combine`
41#[cfg(feature = "libdeflate")]
42pub struct LibDeflateCrc {
43    crc: libdeflater::Crc,
44    amount: u32,
45}
46
47#[cfg(feature = "libdeflate")]
48impl Check for LibDeflateCrc {
49    #[inline]
50    fn sum(&self) -> u32 {
51        self.crc.sum()
52    }
53
54    #[inline]
55    fn amount(&self) -> u32 {
56        self.amount
57    }
58
59    #[inline]
60    fn new() -> Self
61    where
62        Self: Sized,
63    {
64        Self {
65            crc: libdeflater::Crc::new(),
66            amount: 0,
67        }
68    }
69
70    #[inline]
71    fn update(&mut self, bytes: &[u8]) {
72        self.amount += bytes.len() as u32;
73        self.crc.update(bytes);
74    }
75
76    /// Not needed for or implemented for libdeflate.
77    ///
78    /// Calling this is an error.
79    fn combine(&mut self, _other: &Self)
80    where
81        Self: Sized,
82    {
83        unimplemented!()
84    }
85}
86
87/// The adler32 check implementation for zlib
88#[cfg(feature = "any_zlib")]
89pub struct Adler32 {
90    sum: u32,
91    amount: u32,
92}
93
94#[cfg(feature = "any_zlib")]
95impl Check for Adler32 {
96    #[inline]
97    fn sum(&self) -> u32 {
98        self.sum
99    }
100
101    #[inline]
102    fn amount(&self) -> u32 {
103        self.amount
104    }
105
106    #[inline]
107    fn new() -> Self {
108        let start = unsafe { adler32(0, std::ptr::null_mut(), 0) } as u32;
109
110        Self {
111            sum: start,
112            amount: 0,
113        }
114    }
115
116    #[inline]
117    #[allow(clippy::useless_conversion)]
118    fn update(&mut self, bytes: &[u8]) {
119        // TODO: safer cast(s)?
120        self.amount += bytes.len() as u32;
121        self.sum = unsafe {
122            adler32(
123                self.sum.into(),
124                bytes.as_ptr() as *mut _,
125                bytes.len() as uInt,
126            )
127        } as u32;
128    }
129
130    #[inline]
131    #[allow(clippy::useless_conversion)]
132    fn combine(&mut self, other: &Self) {
133        self.sum =
134            unsafe { adler32_combine(self.sum.into(), other.sum.into(), other.amount as z_off_t) }
135                as u32;
136        self.amount += other.amount;
137    }
138}
139
140/// The crc32 check implementation for Gzip
141#[cfg(feature = "deflate")]
142pub struct Crc32 {
143    crc: Crc,
144}
145
146#[cfg(feature = "deflate")]
147impl Check for Crc32 {
148    #[inline]
149    fn sum(&self) -> u32 {
150        self.crc.sum()
151    }
152
153    #[inline]
154    fn amount(&self) -> u32 {
155        self.crc.amount()
156    }
157
158    #[inline]
159    fn new() -> Self {
160        let crc = flate2::Crc::new();
161        Self { crc }
162    }
163
164    #[inline]
165    fn update(&mut self, bytes: &[u8]) {
166        self.crc.update(bytes);
167    }
168
169    #[inline]
170    fn combine(&mut self, other: &Self) {
171        self.crc.combine(&other.crc);
172    }
173}
174
175/// A passthrough check object that performs no calculations and no-ops all calls.
176pub struct PassThroughCheck {}
177
178#[allow(unused)]
179impl Check for PassThroughCheck {
180    #[inline]
181    fn sum(&self) -> u32 {
182        0
183    }
184
185    #[inline]
186    fn amount(&self) -> u32 {
187        0
188    }
189
190    #[inline]
191    fn new() -> Self
192    where
193        Self: Sized,
194    {
195        Self {}
196    }
197
198    #[inline]
199    fn update(&mut self, bytes: &[u8]) {}
200
201    #[inline]
202    fn combine(&mut self, other: &Self)
203    where
204        Self: Sized,
205    {
206    }
207}