]> git.proxmox.com Git - rustc.git/blob - vendor/flate2/src/ffi/c.rs
New upstream version 1.41.1+dfsg1
[rustc.git] / vendor / flate2 / src / ffi / c.rs
1
2 //! Implementation for C backends.
3 use std::alloc::{self, Layout};
4 use std::cmp;
5 use std::convert::TryFrom;
6 use std::fmt;
7 use std::marker;
8 use std::ops::{Deref, DerefMut};
9 use std::ptr;
10
11 pub use libc::{c_int, c_uint, c_void, size_t};
12
13 use super::*;
14 use crate::mem::{self, FlushDecompress, Status};
15
16 pub struct StreamWrapper {
17 pub inner: Box<mz_stream>,
18 }
19
20 impl fmt::Debug for StreamWrapper {
21 fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
22 write!(f, "StreamWrapper")
23 }
24 }
25
26 impl Default for StreamWrapper {
27 fn default() -> StreamWrapper {
28 StreamWrapper {
29 inner: Box::new(mz_stream {
30 next_in: ptr::null_mut(),
31 avail_in: 0,
32 total_in: 0,
33 next_out: ptr::null_mut(),
34 avail_out: 0,
35 total_out: 0,
36 msg: ptr::null_mut(),
37 adler: 0,
38 data_type: 0,
39 reserved: 0,
40 opaque: ptr::null_mut(),
41 state: ptr::null_mut(),
42 #[cfg(feature = "zlib")]
43 zalloc,
44 #[cfg(feature = "zlib")]
45 zfree,
46 #[cfg(not(feature = "zlib"))]
47 zalloc: Some(zalloc),
48 #[cfg(not(feature = "zlib"))]
49 zfree: Some(zfree),
50 }),
51 }
52 }
53 }
54
55 const ALIGN: usize = std::mem::align_of::<usize>();
56
57 fn align_up(size: usize, align: usize) -> usize {
58 (size + align - 1) & !(align - 1)
59 }
60
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>()))
71 {
72 Some(i) => i,
73 None => return ptr::null_mut(),
74 };
75
76 // Make sure the `size` isn't too big to fail `Layout`'s restrictions
77 let layout = match Layout::from_size_align(size, ALIGN) {
78 Ok(layout) => layout,
79 Err(_) => return ptr::null_mut(),
80 };
81
82 unsafe {
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;
86 if ptr.is_null() {
87 return ptr as *mut c_void;
88 }
89 *ptr = size;
90 ptr.add(1) as *mut c_void
91 }
92 }
93
94 extern "C" fn zfree(_ptr: *mut c_void, address: *mut c_void) {
95 unsafe {
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
98 // allocator.
99 let ptr = (address as *mut usize).offset(-1);
100 let size = *ptr;
101 let layout = Layout::from_size_align_unchecked(size, ALIGN);
102 alloc::dealloc(ptr as *mut u8, layout)
103 }
104 }
105
106 impl Deref for StreamWrapper {
107 type Target = mz_stream;
108
109 fn deref(&self) -> &Self::Target {
110 &*self.inner
111 }
112 }
113
114 impl DerefMut for StreamWrapper {
115 fn deref_mut(&mut self) -> &mut Self::Target {
116 &mut *self.inner
117 }
118 }
119
120 unsafe impl<D: Direction> Send for Stream<D> {}
121 unsafe impl<D: Direction> Sync for Stream<D> {}
122
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;
127 }
128
129 #[derive(Debug)]
130 pub enum DirCompress {}
131 #[derive(Debug)]
132 pub enum DirDecompress {}
133
134 #[derive(Debug)]
135 pub struct Stream<D: Direction> {
136 pub stream_wrapper: StreamWrapper,
137 pub total_in: u64,
138 pub total_out: u64,
139 pub _marker: marker::PhantomData<D>,
140 }
141
142 impl<D: Direction> Drop for Stream<D> {
143 fn drop(&mut self) {
144 unsafe {
145 let _ = D::destroy(&mut *self.stream_wrapper);
146 }
147 }
148 }
149
150 impl Direction for DirCompress {
151 unsafe fn destroy(stream: *mut mz_stream) -> c_int {
152 mz_deflateEnd(stream)
153 }
154 }
155 impl Direction for DirDecompress {
156 unsafe fn destroy(stream: *mut mz_stream) -> c_int {
157 mz_inflateEnd(stream)
158 }
159 }
160
161 #[derive(Debug)]
162 pub struct Inflate {
163 pub inner: Stream<DirDecompress>,
164 }
165
166 impl InflateBackend for Inflate {
167 fn make(zlib_header: bool, window_bits: u8) -> Self {
168 assert!(
169 window_bits > 8 && window_bits < 16,
170 "window_bits must be within 9 ..= 15"
171 );
172 unsafe {
173 let mut state = StreamWrapper::default();
174 let ret = mz_inflateInit2(
175 &mut *state,
176 if zlib_header {
177 window_bits as c_int
178 } else {
179 -(window_bits as c_int)
180 },
181 );
182 assert_eq!(ret, 0);
183 Inflate {
184 inner: Stream {
185 stream_wrapper: state,
186 total_in: 0,
187 total_out: 0,
188 _marker: marker::PhantomData,
189 },
190 }
191 }
192 }
193
194 fn decompress(
195 &mut self,
196 input: &[u8],
197 output: &mut [u8],
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;
205
206 let rc = unsafe { mz_inflate(raw, flush as c_int) };
207
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;
212
213 match rc {
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),
220 }
221 }
222
223 #[cfg(feature = "zlib")]
224 fn reset(&mut self, zlib_header: bool) {
225 let bits = if zlib_header {
226 MZ_DEFAULT_WINDOW_BITS
227 } else {
228 -MZ_DEFAULT_WINDOW_BITS
229 };
230 unsafe {
231 inflateReset2(&mut *self.inner.stream_wrapper, bits);
232 }
233 self.inner.total_out = 0;
234 self.inner.total_in = 0;
235 }
236
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);
240 }
241 }
242
243 impl Backend for Inflate {
244 #[inline]
245 fn total_in(&self) -> u64 {
246 self.inner.total_in
247 }
248
249 #[inline]
250 fn total_out(&self) -> u64 {
251 self.inner.total_out
252 }
253 }
254
255 #[derive(Debug)]
256 pub struct Deflate {
257 pub inner: Stream<DirCompress>,
258 }
259
260 impl DeflateBackend for Deflate {
261 fn make(level: Compression, zlib_header: bool, window_bits: u8) -> Self {
262 assert!(
263 window_bits > 8 && window_bits < 16,
264 "window_bits must be within 9 ..= 15"
265 );
266 unsafe {
267 let mut state = StreamWrapper::default();
268 let ret = mz_deflateInit2(
269 &mut *state,
270 level.0 as c_int,
271 MZ_DEFLATED,
272 if zlib_header {
273 window_bits as c_int
274 } else {
275 -(window_bits as c_int)
276 },
277 9,
278 MZ_DEFAULT_STRATEGY,
279 );
280 assert_eq!(ret, 0);
281 Deflate {
282 inner: Stream {
283 stream_wrapper: state,
284 total_in: 0,
285 total_out: 0,
286 _marker: marker::PhantomData,
287 },
288 }
289 }
290 }
291 fn compress(
292 &mut self,
293 input: &[u8],
294 output: &mut [u8],
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;
302
303 let rc = unsafe { mz_deflate(raw, flush as c_int) };
304
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;
309
310 match rc {
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),
316 }
317 }
318
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);
324 }
325 }
326
327 impl Backend for Deflate {
328 #[inline]
329 fn total_in(&self) -> u64 {
330 self.inner.total_in
331 }
332
333 #[inline]
334 fn total_out(&self) -> u64 {
335 self.inner.total_out
336 }
337 }
338
339 pub use self::c_backend::*;
340
341 /// Miniz specific
342 #[cfg(not(feature = "zlib"))]
343 mod c_backend {
344 pub use miniz_sys::*;
345 pub type AllocSize = libc::size_t;
346 }
347
348 /// Zlib specific
349 #[cfg(feature = "zlib")]
350 #[allow(bad_style)]
351 mod c_backend {
352 use libc::{c_char, c_int};
353 use std::mem;
354
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;
361 pub use libz_sys::*;
362
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;
378
379 pub const MZ_DEFAULT_WINDOW_BITS: c_int = 15;
380
381 const ZLIB_VERSION: &'static str = "1.2.8\0";
382
383 pub unsafe extern "C" fn mz_deflateInit2(
384 stream: *mut mz_stream,
385 level: c_int,
386 method: c_int,
387 window_bits: c_int,
388 mem_level: c_int,
389 strategy: c_int,
390 ) -> c_int {
391 libz_sys::deflateInit2_(
392 stream,
393 level,
394 method,
395 window_bits,
396 mem_level,
397 strategy,
398 ZLIB_VERSION.as_ptr() as *const c_char,
399 mem::size_of::<mz_stream>() as c_int,
400 )
401 }
402 pub unsafe extern "C" fn mz_inflateInit2(
403 stream: *mut mz_stream,
404 window_bits: c_int,
405 ) -> c_int {
406 libz_sys::inflateInit2_(
407 stream,
408 window_bits,
409 ZLIB_VERSION.as_ptr() as *const c_char,
410 mem::size_of::<mz_stream>() as c_int,
411 )
412 }
413 }