2 //! Implementation for C backends.
3 use std
::alloc
::{self, Layout}
;
5 use std
::convert
::TryFrom
;
8 use std
::ops
::{Deref, DerefMut}
;
11 pub use libc
::{c_int, c_uint, c_void, size_t}
;
14 use crate::mem
::{self, FlushDecompress, Status}
;
16 pub struct StreamWrapper
{
17 pub inner
: Box
<mz_stream
>,
20 impl fmt
::Debug
for StreamWrapper
{
21 fn fmt(&self, f
: &mut fmt
::Formatter
) -> Result
<(), fmt
::Error
> {
22 write
!(f
, "StreamWrapper")
26 impl Default
for StreamWrapper
{
27 fn default() -> StreamWrapper
{
29 inner
: Box
::new(mz_stream
{
30 next_in
: ptr
::null_mut(),
33 next_out
: ptr
::null_mut(),
40 opaque
: ptr
::null_mut(),
41 state
: ptr
::null_mut(),
42 #[cfg(feature = "zlib")]
44 #[cfg(feature = "zlib")]
46 #[cfg(not(feature = "zlib"))]
48 #[cfg(not(feature = "zlib"))]
55 const ALIGN
: usize = std
::mem
::align_of
::<usize>();
57 fn align_up(size
: usize, align
: usize) -> usize {
58 (size
+ align
- 1) & !(align
- 1)
61 extern "C" fn zalloc(_ptr
: *mut c_void
, items
: AllocSize
, item_size
: AllocSize
) -> *mut c_void
{
62 // We need to multiply `items` and `item_size` to get the actual desired
63 // allocation size. Since `zfree` doesn't receive a size argument we
64 // also need to allocate space for a `usize` as a header so we can store
65 // how large the allocation is to deallocate later.
66 let size
= match items
67 .checked_mul(item_size
)
68 .and_then(|i
| usize::try_from(i
).ok())
69 .map(|size
| align_up(size
, ALIGN
))
70 .and_then(|i
| i
.checked_add(std
::mem
::size_of
::<usize>()))
73 None
=> return ptr
::null_mut(),
76 // Make sure the `size` isn't too big to fail `Layout`'s restrictions
77 let layout
= match Layout
::from_size_align(size
, ALIGN
) {
79 Err(_
) => return ptr
::null_mut(),
83 // Allocate the data, and if successful store the size we allocated
84 // at the beginning and then return an offset pointer.
85 let ptr
= alloc
::alloc(layout
) as *mut usize;
87 return ptr
as *mut c_void
;
90 ptr
.add(1) as *mut c_void
94 extern "C" fn zfree(_ptr
: *mut c_void
, address
: *mut c_void
) {
96 // Move our address being free'd back one pointer, read the size we
97 // stored in `zalloc`, and then free it using the standard Rust
99 let ptr
= (address
as *mut usize).offset(-1);
101 let layout
= Layout
::from_size_align_unchecked(size
, ALIGN
);
102 alloc
::dealloc(ptr
as *mut u8, layout
)
106 impl Deref
for StreamWrapper
{
107 type Target
= mz_stream
;
109 fn deref(&self) -> &Self::Target
{
114 impl DerefMut
for StreamWrapper
{
115 fn deref_mut(&mut self) -> &mut Self::Target
{
120 unsafe impl<D
: Direction
> Send
for Stream
<D
> {}
121 unsafe impl<D
: Direction
> Sync
for Stream
<D
> {}
123 /// Trait used to call the right destroy/end function on the inner
124 /// stream object on drop.
125 pub trait Direction
{
126 unsafe fn destroy(stream
: *mut mz_stream
) -> c_int
;
130 pub enum DirCompress {}
132 pub enum DirDecompress {}
135 pub struct Stream
<D
: Direction
> {
136 pub stream_wrapper
: StreamWrapper
,
139 pub _marker
: marker
::PhantomData
<D
>,
142 impl<D
: Direction
> Drop
for Stream
<D
> {
145 let _
= D
::destroy(&mut *self.stream_wrapper
);
150 impl Direction
for DirCompress
{
151 unsafe fn destroy(stream
: *mut mz_stream
) -> c_int
{
152 mz_deflateEnd(stream
)
155 impl Direction
for DirDecompress
{
156 unsafe fn destroy(stream
: *mut mz_stream
) -> c_int
{
157 mz_inflateEnd(stream
)
163 pub inner
: Stream
<DirDecompress
>,
166 impl InflateBackend
for Inflate
{
167 fn make(zlib_header
: bool
, window_bits
: u8) -> Self {
169 window_bits
> 8 && window_bits
< 16,
170 "window_bits must be within 9 ..= 15"
173 let mut state
= StreamWrapper
::default();
174 let ret
= mz_inflateInit2(
179 -(window_bits
as c_int
)
185 stream_wrapper
: state
,
188 _marker
: marker
::PhantomData
,
198 flush
: FlushDecompress
,
199 ) -> Result
<Status
, DecompressError
> {
200 let raw
= &mut *self.inner
.stream_wrapper
;
201 raw
.next_in
= input
.as_ptr() as *mut u8;
202 raw
.avail_in
= cmp
::min(input
.len(), c_uint
::max_value() as usize) as c_uint
;
203 raw
.next_out
= output
.as_mut_ptr();
204 raw
.avail_out
= cmp
::min(output
.len(), c_uint
::max_value() as usize) as c_uint
;
206 let rc
= unsafe { mz_inflate(raw, flush as c_int) }
;
208 // Unfortunately the total counters provided by zlib might be only
209 // 32 bits wide and overflow while processing large amounts of data.
210 self.inner
.total_in
+= (raw
.next_in
as usize - input
.as_ptr() as usize) as u64;
211 self.inner
.total_out
+= (raw
.next_out
as usize - output
.as_ptr() as usize) as u64;
214 MZ_DATA_ERROR
| MZ_STREAM_ERROR
=> mem
::decompress_failed(),
215 MZ_OK
=> Ok(Status
::Ok
),
216 MZ_BUF_ERROR
=> Ok(Status
::BufError
),
217 MZ_STREAM_END
=> Ok(Status
::StreamEnd
),
218 MZ_NEED_DICT
=> mem
::decompress_need_dict(raw
.adler
as u32),
219 c
=> panic
!("unknown return code: {}", c
),
223 #[cfg(feature = "zlib")]
224 fn reset(&mut self, zlib_header
: bool
) {
225 let bits
= if zlib_header
{
226 MZ_DEFAULT_WINDOW_BITS
228 -MZ_DEFAULT_WINDOW_BITS
231 inflateReset2(&mut *self.inner
.stream_wrapper
, bits
);
233 self.inner
.total_out
= 0;
234 self.inner
.total_in
= 0;
237 #[cfg(not(feature = "zlib"))]
238 fn reset(&mut self, zlib_header
: bool
) {
239 *self = Self::make(zlib_header
, MZ_DEFAULT_WINDOW_BITS
as u8);
243 impl Backend
for Inflate
{
245 fn total_in(&self) -> u64 {
250 fn total_out(&self) -> u64 {
257 pub inner
: Stream
<DirCompress
>,
260 impl DeflateBackend
for Deflate
{
261 fn make(level
: Compression
, zlib_header
: bool
, window_bits
: u8) -> Self {
263 window_bits
> 8 && window_bits
< 16,
264 "window_bits must be within 9 ..= 15"
267 let mut state
= StreamWrapper
::default();
268 let ret
= mz_deflateInit2(
275 -(window_bits
as c_int
)
283 stream_wrapper
: state
,
286 _marker
: marker
::PhantomData
,
295 flush
: FlushCompress
,
296 ) -> Result
<Status
, CompressError
> {
297 let raw
= &mut *self.inner
.stream_wrapper
;
298 raw
.next_in
= input
.as_ptr() as *mut _
;
299 raw
.avail_in
= cmp
::min(input
.len(), c_uint
::max_value() as usize) as c_uint
;
300 raw
.next_out
= output
.as_mut_ptr();
301 raw
.avail_out
= cmp
::min(output
.len(), c_uint
::max_value() as usize) as c_uint
;
303 let rc
= unsafe { mz_deflate(raw, flush as c_int) }
;
305 // Unfortunately the total counters provided by zlib might be only
306 // 32 bits wide and overflow while processing large amounts of data.
307 self.inner
.total_in
+= (raw
.next_in
as usize - input
.as_ptr() as usize) as u64;
308 self.inner
.total_out
+= (raw
.next_out
as usize - output
.as_ptr() as usize) as u64;
311 MZ_OK
=> Ok(Status
::Ok
),
312 MZ_BUF_ERROR
=> Ok(Status
::BufError
),
313 MZ_STREAM_END
=> Ok(Status
::StreamEnd
),
314 MZ_STREAM_ERROR
=> Err(CompressError(())),
315 c
=> panic
!("unknown return code: {}", c
),
319 fn reset(&mut self) {
320 self.inner
.total_in
= 0;
321 self.inner
.total_out
= 0;
322 let rc
= unsafe { mz_deflateReset(&mut *self.inner.stream_wrapper) }
;
323 assert_eq
!(rc
, MZ_OK
);
327 impl Backend
for Deflate
{
329 fn total_in(&self) -> u64 {
334 fn total_out(&self) -> u64 {
339 pub use self::c_backend
::*;
342 #[cfg(not(feature = "zlib"))]
344 pub use miniz_sys
::*;
345 pub type AllocSize
= libc
::size_t
;
349 #[cfg(feature = "zlib")]
352 use libc
::{c_char, c_int}
;
355 pub use libz_sys
::deflate
as mz_deflate
;
356 pub use libz_sys
::deflateEnd
as mz_deflateEnd
;
357 pub use libz_sys
::deflateReset
as mz_deflateReset
;
358 pub use libz_sys
::inflate
as mz_inflate
;
359 pub use libz_sys
::inflateEnd
as mz_inflateEnd
;
360 pub use libz_sys
::z_stream
as mz_stream
;
363 pub use libz_sys
::Z_BLOCK
as MZ_BLOCK
;
364 pub use libz_sys
::Z_BUF_ERROR
as MZ_BUF_ERROR
;
365 pub use libz_sys
::Z_DATA_ERROR
as MZ_DATA_ERROR
;
366 pub use libz_sys
::Z_DEFAULT_STRATEGY
as MZ_DEFAULT_STRATEGY
;
367 pub use libz_sys
::Z_DEFLATED
as MZ_DEFLATED
;
368 pub use libz_sys
::Z_FINISH
as MZ_FINISH
;
369 pub use libz_sys
::Z_FULL_FLUSH
as MZ_FULL_FLUSH
;
370 pub use libz_sys
::Z_NEED_DICT
as MZ_NEED_DICT
;
371 pub use libz_sys
::Z_NO_FLUSH
as MZ_NO_FLUSH
;
372 pub use libz_sys
::Z_OK
as MZ_OK
;
373 pub use libz_sys
::Z_PARTIAL_FLUSH
as MZ_PARTIAL_FLUSH
;
374 pub use libz_sys
::Z_STREAM_END
as MZ_STREAM_END
;
375 pub use libz_sys
::Z_STREAM_ERROR
as MZ_STREAM_ERROR
;
376 pub use libz_sys
::Z_SYNC_FLUSH
as MZ_SYNC_FLUSH
;
377 pub type AllocSize
= libz_sys
::uInt
;
379 pub const MZ_DEFAULT_WINDOW_BITS
: c_int
= 15;
381 const ZLIB_VERSION
: &'
static str = "1.2.8\0";
383 pub unsafe extern "C" fn mz_deflateInit2(
384 stream
: *mut mz_stream
,
391 libz_sys
::deflateInit2_(
398 ZLIB_VERSION
.as_ptr() as *const c_char
,
399 mem
::size_of
::<mz_stream
>() as c_int
,
402 pub unsafe extern "C" fn mz_inflateInit2(
403 stream
: *mut mz_stream
,
406 libz_sys
::inflateInit2_(
409 ZLIB_VERSION
.as_ptr() as *const c_char
,
410 mem
::size_of
::<mz_stream
>() as c_int
,