zlib_rs/inflate/
window.rs

1use crate::{
2    adler32::{adler32, adler32_fold_copy},
3    crc32::Crc32Fold,
4    weak_slice::WeakSliceMut,
5};
6
7// translation guide:
8//
9// wsize -> buf.capacity()
10// wnext -> buf.ptr
11// whave -> buf.filled.len()
12#[derive(Debug)]
13pub struct Window<'a> {
14    buf: WeakSliceMut<'a, u8>,
15
16    have: usize, // number of bytes logically written to the window. this can be higher than
17    // buf.len() if we run out of space in the window
18    next: usize, // write head
19}
20
21impl<'a> Window<'a> {
22    pub fn into_raw_parts(self) -> (*mut u8, usize) {
23        self.buf.into_raw_parts()
24    }
25
26    pub unsafe fn from_raw_parts(ptr: *mut u8, len: usize) -> Self {
27        Self {
28            buf: unsafe { WeakSliceMut::from_raw_parts_mut(ptr, len) },
29            have: 0,
30            next: 0,
31        }
32    }
33
34    pub fn is_empty(&self) -> bool {
35        self.size() == 0
36    }
37
38    /// The size of the underlying buffer. For inflate, use `size` instead. This function is used
39    /// in `inflateBack` which does not consider the padding.
40    pub fn buffer_size(&self) -> usize {
41        assert!(self.buf.len().is_power_of_two());
42        self.buf.len()
43    }
44
45    pub fn size(&self) -> usize {
46        // `self.len == 0` is used for uninitialized buffers
47        assert!(self.buf.is_empty() || self.buf.len() >= Self::padding());
48        self.buf.len().saturating_sub(Self::padding())
49    }
50
51    /// number of bytes in the window. Saturates at `Self::capacity`.
52    pub fn have(&self) -> usize {
53        self.have
54    }
55
56    pub unsafe fn set_have(&mut self, have: usize) {
57        self.have = have;
58    }
59
60    /// Position where the next byte will be written
61    pub fn next(&self) -> usize {
62        self.next
63    }
64
65    pub fn empty() -> Self {
66        Self {
67            buf: WeakSliceMut::empty(),
68            have: 0,
69            next: 0,
70        }
71    }
72
73    pub fn clear(&mut self) {
74        self.have = 0;
75        self.next = 0;
76    }
77
78    pub fn as_slice(&self) -> &[u8] {
79        &self.buf.as_slice()[..self.have]
80    }
81
82    pub fn as_ptr(&self) -> *const u8 {
83        self.buf.as_ptr()
84    }
85
86    #[cfg(test)]
87    fn extend_adler32(&mut self, slice: &[u8], checksum: &mut u32) {
88        self.extend(slice, 0, true, checksum, &mut Crc32Fold::new());
89    }
90
91    pub fn extend(
92        &mut self,
93        slice: &[u8],
94        flags: i32,
95        update_checksum: bool,
96        checksum: &mut u32,
97        crc_fold: &mut Crc32Fold,
98    ) {
99        let len = slice.len();
100        let wsize = self.size();
101
102        if len >= wsize {
103            // We have to split the checksum over non-copied and copied bytes
104            let pos = len.saturating_sub(self.size());
105            let (non_window_slice, window_slice) = slice.split_at(pos);
106
107            if update_checksum {
108                if flags != 0 {
109                    crc_fold.fold(non_window_slice, 0);
110                    crc_fold.fold_copy(&mut self.buf.as_mut_slice()[..wsize], window_slice);
111                } else {
112                    *checksum = adler32(*checksum, non_window_slice);
113                    *checksum = adler32_fold_copy(*checksum, self.buf.as_mut_slice(), window_slice);
114                }
115            } else {
116                self.buf.as_mut_slice()[..wsize].copy_from_slice(window_slice);
117            }
118
119            self.next = 0;
120            self.have = self.size();
121        } else {
122            let dist = Ord::min(wsize - self.next, slice.len());
123
124            // the end part goes onto the end of the window. The start part wraps around and is
125            // written to the start of the window.
126            let (end_part, start_part) = slice.split_at(dist);
127
128            if update_checksum {
129                let dst = &mut self.buf.as_mut_slice()[self.next..][..end_part.len()];
130                if flags != 0 {
131                    crc_fold.fold_copy(dst, end_part);
132                } else {
133                    *checksum = adler32_fold_copy(*checksum, dst, end_part);
134                }
135            } else {
136                self.buf.as_mut_slice()[self.next..][..end_part.len()].copy_from_slice(end_part);
137            }
138
139            if !start_part.is_empty() {
140                let dst = &mut self.buf.as_mut_slice()[..start_part.len()];
141
142                if update_checksum {
143                    if flags != 0 {
144                        crc_fold.fold_copy(dst, start_part);
145                    } else {
146                        *checksum = adler32_fold_copy(*checksum, dst, start_part);
147                    }
148                } else {
149                    dst.copy_from_slice(start_part);
150                }
151
152                self.next = start_part.len();
153                self.have = self.size();
154            } else {
155                self.next += dist;
156                if self.next == self.size() {
157                    self.next = 0;
158                }
159                if self.have < self.size() {
160                    self.have += dist;
161                }
162            }
163        }
164    }
165
166    #[cfg(test)]
167    pub fn new_in(alloc: &crate::inflate::Allocator<'a>, window_bits: usize) -> Option<Self> {
168        let len = (1 << window_bits) + Self::padding();
169        let ptr = alloc.allocate_zeroed_buffer(len)?;
170
171        Some(Self {
172            buf: unsafe { WeakSliceMut::from_raw_parts_mut(ptr.as_ptr(), len) },
173            have: 0,
174            next: 0,
175        })
176    }
177
178    pub unsafe fn clone_to(&self, ptr: *mut u8, len: usize) -> Self {
179        debug_assert_eq!(self.buf.len(), len);
180
181        unsafe { core::ptr::copy_nonoverlapping(self.buf.as_ptr(), ptr, len) };
182
183        Self {
184            buf: unsafe { WeakSliceMut::from_raw_parts_mut(ptr, len) },
185            have: self.have,
186            next: self.next,
187        }
188    }
189
190    // padding required so that SIMD operations going out-of-bounds are not a problem
191    pub fn padding() -> usize {
192        64 // very conservative
193    }
194}
195
196#[cfg(all(test, feature = "rust-allocator"))]
197mod test {
198    use super::*;
199
200    fn init_window(window_bits_log2: usize) -> Window<'static> {
201        let mut window = Window::new_in(&crate::allocate::RUST, window_bits_log2).unwrap();
202        window.have = 0;
203        window.next = 0;
204        window
205    }
206
207    #[test]
208    fn extend_in_bounds() {
209        let mut checksum = 0;
210
211        let mut window = init_window(4);
212
213        window.extend_adler32(&[1; 5], &mut checksum);
214        assert_eq!(window.have, 5);
215        assert_eq!(window.next, 5);
216
217        let slice = &window.buf.as_slice()[..window.size()];
218        assert_eq!(&[1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], slice);
219
220        window.extend_adler32(&[2; 7], &mut checksum);
221        assert_eq!(window.have, 12);
222        assert_eq!(window.next, 12);
223
224        let slice = &window.buf.as_slice()[..window.size()];
225        assert_eq!(&[1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0], slice);
226
227        assert_eq!(checksum, 6946835);
228
229        unsafe {
230            crate::allocate::RUST.deallocate(
231                window.buf.as_mut_slice().as_mut_ptr(),
232                window.buf.as_slice().len(),
233            )
234        }
235    }
236
237    #[test]
238    fn extend_crosses_bounds() {
239        let mut checksum = 0;
240
241        let mut window = init_window(2);
242
243        window.extend_adler32(&[1; 3], &mut checksum);
244        assert_eq!(window.have, 3);
245        assert_eq!(window.next, 3);
246
247        let slice = &window.buf.as_slice()[..window.size()];
248        assert_eq!(&[1, 1, 1, 0], slice);
249
250        window.extend_adler32(&[2; 3], &mut checksum);
251        assert_eq!(window.have, 4);
252        assert_eq!(window.next, 2);
253
254        let slice = &window.buf.as_slice()[..window.size()];
255        assert_eq!(&[2, 2, 1, 2], slice);
256
257        assert_eq!(checksum, 1769481);
258
259        unsafe {
260            crate::allocate::RUST.deallocate(
261                window.buf.as_mut_slice().as_mut_ptr(),
262                window.buf.as_slice().len(),
263            )
264        }
265    }
266
267    #[test]
268    fn extend_out_of_bounds() {
269        let mut checksum = 0;
270
271        let mut window = init_window(3);
272
273        // adds 9 numbers, that won't fit into a window of size 8
274        window.extend_adler32(&[1, 2, 3, 4, 5, 6, 7, 8, 9], &mut checksum);
275        assert_eq!(window.have, 8);
276        assert_eq!(window.next, 0);
277
278        let slice = &window.as_slice()[..window.size()];
279        assert_eq!(&[2, 3, 4, 5, 6, 7, 8, 9], slice);
280
281        assert_eq!(checksum, 10813485);
282
283        unsafe {
284            crate::allocate::RUST.deallocate(
285                window.buf.as_mut_slice().as_mut_ptr(),
286                window.as_slice().len(),
287            )
288        }
289    }
290}