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