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