1 //! Implementation for C backends.
2 use std::alloc::{self, Layout};
3 use std::cmp;
4 use std::convert::TryFrom;
5 use std::fmt;
6 use std::marker;
7 use std::ops::{Deref, DerefMut};
8 use std::ptr;
9 
10 pub use libc::{c_int, c_uint, c_void, size_t};
11 
12 use super::*;
13 use crate::mem::{self, FlushDecompress, Status};
14 
15 pub struct StreamWrapper {
16     pub inner: Box<mz_stream>,
17 }
18 
19 impl fmt::Debug for StreamWrapper {
fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error>20     fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
21         write!(f, "StreamWrapper")
22     }
23 }
24 
25 impl Default for StreamWrapper {
default() -> StreamWrapper26     fn default() -> StreamWrapper {
27         StreamWrapper {
28             inner: Box::new(mz_stream {
29                 next_in: ptr::null_mut(),
30                 avail_in: 0,
31                 total_in: 0,
32                 next_out: ptr::null_mut(),
33                 avail_out: 0,
34                 total_out: 0,
35                 msg: ptr::null_mut(),
36                 adler: 0,
37                 data_type: 0,
38                 reserved: 0,
39                 opaque: ptr::null_mut(),
40                 state: ptr::null_mut(),
41                 #[cfg(feature = "any_zlib")]
42                 zalloc,
43                 #[cfg(feature = "any_zlib")]
44                 zfree,
45                 #[cfg(not(feature = "any_zlib"))]
46                 zalloc: Some(zalloc),
47                 #[cfg(not(feature = "any_zlib"))]
48                 zfree: Some(zfree),
49             }),
50         }
51     }
52 }
53 
54 const ALIGN: usize = std::mem::align_of::<usize>();
55 
align_up(size: usize, align: usize) -> usize56 fn align_up(size: usize, align: usize) -> usize {
57     (size + align - 1) & !(align - 1)
58 }
59 
zalloc(_ptr: *mut c_void, items: AllocSize, item_size: AllocSize) -> *mut c_void60 extern "C" fn zalloc(_ptr: *mut c_void, items: AllocSize, item_size: AllocSize) -> *mut c_void {
61     // We need to multiply `items` and `item_size` to get the actual desired
62     // allocation size. Since `zfree` doesn't receive a size argument we
63     // also need to allocate space for a `usize` as a header so we can store
64     // how large the allocation is to deallocate later.
65     let size = match items
66         .checked_mul(item_size)
67         .and_then(|i| usize::try_from(i).ok())
68         .map(|size| align_up(size, ALIGN))
69         .and_then(|i| i.checked_add(std::mem::size_of::<usize>()))
70     {
71         Some(i) => i,
72         None => return ptr::null_mut(),
73     };
74 
75     // Make sure the `size` isn't too big to fail `Layout`'s restrictions
76     let layout = match Layout::from_size_align(size, ALIGN) {
77         Ok(layout) => layout,
78         Err(_) => return ptr::null_mut(),
79     };
80 
81     unsafe {
82         // Allocate the data, and if successful store the size we allocated
83         // at the beginning and then return an offset pointer.
84         let ptr = alloc::alloc(layout) as *mut usize;
85         if ptr.is_null() {
86             return ptr as *mut c_void;
87         }
88         *ptr = size;
89         ptr.add(1) as *mut c_void
90     }
91 }
92 
zfree(_ptr: *mut c_void, address: *mut c_void)93 extern "C" fn zfree(_ptr: *mut c_void, address: *mut c_void) {
94     unsafe {
95         // Move our address being free'd back one pointer, read the size we
96         // stored in `zalloc`, and then free it using the standard Rust
97         // allocator.
98         let ptr = (address as *mut usize).offset(-1);
99         let size = *ptr;
100         let layout = Layout::from_size_align_unchecked(size, ALIGN);
101         alloc::dealloc(ptr as *mut u8, layout)
102     }
103 }
104 
105 impl Deref for StreamWrapper {
106     type Target = mz_stream;
107 
deref(&self) -> &Self::Target108     fn deref(&self) -> &Self::Target {
109         &*self.inner
110     }
111 }
112 
113 impl DerefMut for StreamWrapper {
deref_mut(&mut self) -> &mut Self::Target114     fn deref_mut(&mut self) -> &mut Self::Target {
115         &mut *self.inner
116     }
117 }
118 
119 unsafe impl<D: Direction> Send for Stream<D> {}
120 unsafe impl<D: Direction> Sync for Stream<D> {}
121 
122 /// Trait used to call the right destroy/end function on the inner
123 /// stream object on drop.
124 pub trait Direction {
destroy(stream: *mut mz_stream) -> c_int125     unsafe fn destroy(stream: *mut mz_stream) -> c_int;
126 }
127 
128 #[derive(Debug)]
129 pub enum DirCompress {}
130 #[derive(Debug)]
131 pub enum DirDecompress {}
132 
133 #[derive(Debug)]
134 pub struct Stream<D: Direction> {
135     pub stream_wrapper: StreamWrapper,
136     pub total_in: u64,
137     pub total_out: u64,
138     pub _marker: marker::PhantomData<D>,
139 }
140 
141 impl<D: Direction> Drop for Stream<D> {
drop(&mut self)142     fn drop(&mut self) {
143         unsafe {
144             let _ = D::destroy(&mut *self.stream_wrapper);
145         }
146     }
147 }
148 
149 impl Direction for DirCompress {
destroy(stream: *mut mz_stream) -> c_int150     unsafe fn destroy(stream: *mut mz_stream) -> c_int {
151         mz_deflateEnd(stream)
152     }
153 }
154 impl Direction for DirDecompress {
destroy(stream: *mut mz_stream) -> c_int155     unsafe fn destroy(stream: *mut mz_stream) -> c_int {
156         mz_inflateEnd(stream)
157     }
158 }
159 
160 #[derive(Debug)]
161 pub struct Inflate {
162     pub inner: Stream<DirDecompress>,
163 }
164 
165 impl InflateBackend for Inflate {
make(zlib_header: bool, window_bits: u8) -> Self166     fn make(zlib_header: bool, window_bits: u8) -> Self {
167         assert!(
168             window_bits > 8 && window_bits < 16,
169             "window_bits must be within 9 ..= 15"
170         );
171         unsafe {
172             let mut state = StreamWrapper::default();
173             let ret = mz_inflateInit2(
174                 &mut *state,
175                 if zlib_header {
176                     window_bits as c_int
177                 } else {
178                     -(window_bits as c_int)
179                 },
180             );
181             assert_eq!(ret, 0);
182             Inflate {
183                 inner: Stream {
184                     stream_wrapper: state,
185                     total_in: 0,
186                     total_out: 0,
187                     _marker: marker::PhantomData,
188                 },
189             }
190         }
191     }
192 
decompress( &mut self, input: &[u8], output: &mut [u8], flush: FlushDecompress, ) -> Result<Status, DecompressError>193     fn decompress(
194         &mut self,
195         input: &[u8],
196         output: &mut [u8],
197         flush: FlushDecompress,
198     ) -> Result<Status, DecompressError> {
199         let raw = &mut *self.inner.stream_wrapper;
200         raw.next_in = input.as_ptr() as *mut u8;
201         raw.avail_in = cmp::min(input.len(), c_uint::max_value() as usize) as c_uint;
202         raw.next_out = output.as_mut_ptr();
203         raw.avail_out = cmp::min(output.len(), c_uint::max_value() as usize) as c_uint;
204 
205         let rc = unsafe { mz_inflate(raw, flush as c_int) };
206 
207         // Unfortunately the total counters provided by zlib might be only
208         // 32 bits wide and overflow while processing large amounts of data.
209         self.inner.total_in += (raw.next_in as usize - input.as_ptr() as usize) as u64;
210         self.inner.total_out += (raw.next_out as usize - output.as_ptr() as usize) as u64;
211 
212         match rc {
213             MZ_DATA_ERROR | MZ_STREAM_ERROR => mem::decompress_failed(),
214             MZ_OK => Ok(Status::Ok),
215             MZ_BUF_ERROR => Ok(Status::BufError),
216             MZ_STREAM_END => Ok(Status::StreamEnd),
217             MZ_NEED_DICT => mem::decompress_need_dict(raw.adler as u32),
218             c => panic!("unknown return code: {}", c),
219         }
220     }
221 
222     #[cfg(feature = "any_zlib")]
reset(&mut self, zlib_header: bool)223     fn reset(&mut self, zlib_header: bool) {
224         let bits = if zlib_header {
225             MZ_DEFAULT_WINDOW_BITS
226         } else {
227             -MZ_DEFAULT_WINDOW_BITS
228         };
229         unsafe {
230             inflateReset2(&mut *self.inner.stream_wrapper, bits);
231         }
232         self.inner.total_out = 0;
233         self.inner.total_in = 0;
234     }
235 
236     #[cfg(not(feature = "any_zlib"))]
reset(&mut self, zlib_header: bool)237     fn reset(&mut self, zlib_header: bool) {
238         *self = Self::make(zlib_header, MZ_DEFAULT_WINDOW_BITS as u8);
239     }
240 }
241 
242 impl Backend for Inflate {
243     #[inline]
total_in(&self) -> u64244     fn total_in(&self) -> u64 {
245         self.inner.total_in
246     }
247 
248     #[inline]
total_out(&self) -> u64249     fn total_out(&self) -> u64 {
250         self.inner.total_out
251     }
252 }
253 
254 #[derive(Debug)]
255 pub struct Deflate {
256     pub inner: Stream<DirCompress>,
257 }
258 
259 impl DeflateBackend for Deflate {
make(level: Compression, zlib_header: bool, window_bits: u8) -> Self260     fn make(level: Compression, zlib_header: bool, window_bits: u8) -> Self {
261         assert!(
262             window_bits > 8 && window_bits < 16,
263             "window_bits must be within 9 ..= 15"
264         );
265         unsafe {
266             let mut state = StreamWrapper::default();
267             let ret = mz_deflateInit2(
268                 &mut *state,
269                 level.0 as c_int,
270                 MZ_DEFLATED,
271                 if zlib_header {
272                     window_bits as c_int
273                 } else {
274                     -(window_bits as c_int)
275                 },
276                 9,
277                 MZ_DEFAULT_STRATEGY,
278             );
279             assert_eq!(ret, 0);
280             Deflate {
281                 inner: Stream {
282                     stream_wrapper: state,
283                     total_in: 0,
284                     total_out: 0,
285                     _marker: marker::PhantomData,
286                 },
287             }
288         }
289     }
compress( &mut self, input: &[u8], output: &mut [u8], flush: FlushCompress, ) -> Result<Status, CompressError>290     fn compress(
291         &mut self,
292         input: &[u8],
293         output: &mut [u8],
294         flush: FlushCompress,
295     ) -> Result<Status, CompressError> {
296         let raw = &mut *self.inner.stream_wrapper;
297         raw.next_in = input.as_ptr() as *mut _;
298         raw.avail_in = cmp::min(input.len(), c_uint::max_value() as usize) as c_uint;
299         raw.next_out = output.as_mut_ptr();
300         raw.avail_out = cmp::min(output.len(), c_uint::max_value() as usize) as c_uint;
301 
302         let rc = unsafe { mz_deflate(raw, flush as c_int) };
303 
304         // Unfortunately the total counters provided by zlib might be only
305         // 32 bits wide and overflow while processing large amounts of data.
306         self.inner.total_in += (raw.next_in as usize - input.as_ptr() as usize) as u64;
307         self.inner.total_out += (raw.next_out as usize - output.as_ptr() as usize) as u64;
308 
309         match rc {
310             MZ_OK => Ok(Status::Ok),
311             MZ_BUF_ERROR => Ok(Status::BufError),
312             MZ_STREAM_END => Ok(Status::StreamEnd),
313             MZ_STREAM_ERROR => Err(CompressError(())),
314             c => panic!("unknown return code: {}", c),
315         }
316     }
317 
reset(&mut self)318     fn reset(&mut self) {
319         self.inner.total_in = 0;
320         self.inner.total_out = 0;
321         let rc = unsafe { mz_deflateReset(&mut *self.inner.stream_wrapper) };
322         assert_eq!(rc, MZ_OK);
323     }
324 }
325 
326 impl Backend for Deflate {
327     #[inline]
total_in(&self) -> u64328     fn total_in(&self) -> u64 {
329         self.inner.total_in
330     }
331 
332     #[inline]
total_out(&self) -> u64333     fn total_out(&self) -> u64 {
334         self.inner.total_out
335     }
336 }
337 
338 pub use self::c_backend::*;
339 
340 /// Miniz specific
341 #[cfg(not(feature = "any_zlib"))]
342 mod c_backend {
343     pub use miniz_sys::*;
344     pub type AllocSize = libc::size_t;
345 }
346 
347 /// Zlib specific
348 #[cfg(all(feature = "zlib", not(feature = "cloudflare_zlib")))]
349 #[allow(bad_style)]
350 mod c_backend {
351     use libc::{c_char, c_int};
352     use std::mem;
353 
354     pub use libz_sys::deflate as mz_deflate;
355     pub use libz_sys::deflateEnd as mz_deflateEnd;
356     pub use libz_sys::deflateReset as mz_deflateReset;
357     pub use libz_sys::inflate as mz_inflate;
358     pub use libz_sys::inflateEnd as mz_inflateEnd;
359     pub use libz_sys::z_stream as mz_stream;
360     pub use libz_sys::*;
361 
362     pub use libz_sys::Z_BLOCK as MZ_BLOCK;
363     pub use libz_sys::Z_BUF_ERROR as MZ_BUF_ERROR;
364     pub use libz_sys::Z_DATA_ERROR as MZ_DATA_ERROR;
365     pub use libz_sys::Z_DEFAULT_STRATEGY as MZ_DEFAULT_STRATEGY;
366     pub use libz_sys::Z_DEFLATED as MZ_DEFLATED;
367     pub use libz_sys::Z_FINISH as MZ_FINISH;
368     pub use libz_sys::Z_FULL_FLUSH as MZ_FULL_FLUSH;
369     pub use libz_sys::Z_NEED_DICT as MZ_NEED_DICT;
370     pub use libz_sys::Z_NO_FLUSH as MZ_NO_FLUSH;
371     pub use libz_sys::Z_OK as MZ_OK;
372     pub use libz_sys::Z_PARTIAL_FLUSH as MZ_PARTIAL_FLUSH;
373     pub use libz_sys::Z_STREAM_END as MZ_STREAM_END;
374     pub use libz_sys::Z_STREAM_ERROR as MZ_STREAM_ERROR;
375     pub use libz_sys::Z_SYNC_FLUSH as MZ_SYNC_FLUSH;
376     pub type AllocSize = libz_sys::uInt;
377 
378     pub const MZ_DEFAULT_WINDOW_BITS: c_int = 15;
379 
380     const ZLIB_VERSION: &'static str = "1.2.8\0";
381 
mz_deflateInit2( stream: *mut mz_stream, level: c_int, method: c_int, window_bits: c_int, mem_level: c_int, strategy: c_int, ) -> c_int382     pub unsafe extern "C" fn mz_deflateInit2(
383         stream: *mut mz_stream,
384         level: c_int,
385         method: c_int,
386         window_bits: c_int,
387         mem_level: c_int,
388         strategy: c_int,
389     ) -> c_int {
390         libz_sys::deflateInit2_(
391             stream,
392             level,
393             method,
394             window_bits,
395             mem_level,
396             strategy,
397             ZLIB_VERSION.as_ptr() as *const c_char,
398             mem::size_of::<mz_stream>() as c_int,
399         )
400     }
mz_inflateInit2(stream: *mut mz_stream, window_bits: c_int) -> c_int401     pub unsafe extern "C" fn mz_inflateInit2(stream: *mut mz_stream, window_bits: c_int) -> c_int {
402         libz_sys::inflateInit2_(
403             stream,
404             window_bits,
405             ZLIB_VERSION.as_ptr() as *const c_char,
406             mem::size_of::<mz_stream>() as c_int,
407         )
408     }
409 }
410 
411 /// Cloudflare optimized Zlib specific
412 #[cfg(feature = "cloudflare_zlib")]
413 #[allow(bad_style)]
414 mod c_backend {
415     use libc::{c_char, c_int};
416     use std::mem;
417 
418     pub use cloudflare_zlib_sys::deflate as mz_deflate;
419     pub use cloudflare_zlib_sys::deflateEnd as mz_deflateEnd;
420     pub use cloudflare_zlib_sys::deflateReset as mz_deflateReset;
421     pub use cloudflare_zlib_sys::inflate as mz_inflate;
422     pub use cloudflare_zlib_sys::inflateEnd as mz_inflateEnd;
423     pub use cloudflare_zlib_sys::z_stream as mz_stream;
424     pub use cloudflare_zlib_sys::*;
425 
426     pub use cloudflare_zlib_sys::Z_BLOCK as MZ_BLOCK;
427     pub use cloudflare_zlib_sys::Z_BUF_ERROR as MZ_BUF_ERROR;
428     pub use cloudflare_zlib_sys::Z_DATA_ERROR as MZ_DATA_ERROR;
429     pub use cloudflare_zlib_sys::Z_DEFAULT_STRATEGY as MZ_DEFAULT_STRATEGY;
430     pub use cloudflare_zlib_sys::Z_DEFLATED as MZ_DEFLATED;
431     pub use cloudflare_zlib_sys::Z_FINISH as MZ_FINISH;
432     pub use cloudflare_zlib_sys::Z_FULL_FLUSH as MZ_FULL_FLUSH;
433     pub use cloudflare_zlib_sys::Z_NEED_DICT as MZ_NEED_DICT;
434     pub use cloudflare_zlib_sys::Z_NO_FLUSH as MZ_NO_FLUSH;
435     pub use cloudflare_zlib_sys::Z_OK as MZ_OK;
436     pub use cloudflare_zlib_sys::Z_PARTIAL_FLUSH as MZ_PARTIAL_FLUSH;
437     pub use cloudflare_zlib_sys::Z_STREAM_END as MZ_STREAM_END;
438     pub use cloudflare_zlib_sys::Z_STREAM_ERROR as MZ_STREAM_ERROR;
439     pub use cloudflare_zlib_sys::Z_SYNC_FLUSH as MZ_SYNC_FLUSH;
440     pub type AllocSize = cloudflare_zlib_sys::uInt;
441 
442     pub const MZ_DEFAULT_WINDOW_BITS: c_int = 15;
443 
444     const ZLIB_VERSION: &'static str = "1.2.8\0";
445 
mz_deflateInit2( stream: *mut mz_stream, level: c_int, method: c_int, window_bits: c_int, mem_level: c_int, strategy: c_int, ) -> c_int446     pub unsafe extern "C" fn mz_deflateInit2(
447         stream: *mut mz_stream,
448         level: c_int,
449         method: c_int,
450         window_bits: c_int,
451         mem_level: c_int,
452         strategy: c_int,
453     ) -> c_int {
454         cloudflare_zlib_sys::deflateInit2_(
455             stream,
456             level,
457             method,
458             window_bits,
459             mem_level,
460             strategy,
461             ZLIB_VERSION.as_ptr() as *const c_char,
462             mem::size_of::<mz_stream>() as c_int,
463         )
464     }
mz_inflateInit2(stream: *mut mz_stream, window_bits: c_int) -> c_int465     pub unsafe extern "C" fn mz_inflateInit2(stream: *mut mz_stream, window_bits: c_int) -> c_int {
466         cloudflare_zlib_sys::inflateInit2_(
467             stream,
468             window_bits,
469             ZLIB_VERSION.as_ptr() as *const c_char,
470             mem::size_of::<mz_stream>() as c_int,
471         )
472     }
473 }
474