brotli_decompressor/ffi/
mod.rs

1#![cfg(not(feature="safe"))]
2
3#[cfg(feature="std")]
4use std::{thread,panic, io, boxed, any, string};
5#[cfg(feature="std")]
6use std::io::Write;
7use core;
8use core::slice;
9use core::ops;
10pub mod interface;
11pub mod alloc_util;
12use self::alloc_util::SubclassableAllocator;
13use alloc::{Allocator, SliceWrapper, SliceWrapperMut, StackAllocator, AllocatedStackMemory, bzero};
14use self::interface::{CAllocator, c_void, BrotliDecoderParameter, BrotliDecoderResult, brotli_alloc_func, brotli_free_func};
15use ::BrotliResult;
16use ::BrotliDecoderReturnInfo;
17use ::brotli_decode;
18pub use ::HuffmanCode;
19pub use super::state::{BrotliDecoderErrorCode, BrotliState};
20
21pub unsafe fn slice_from_raw_parts_or_nil<'a, T>(data: *const T, len: usize) -> &'a [T] {
22    if len == 0 {
23        return &[];
24    }
25    slice::from_raw_parts(data, len)
26}
27
28pub unsafe fn slice_from_raw_parts_or_nil_mut<'a, T>(data: *mut T, len: usize) -> &'a mut [T] {
29    if len == 0 {
30        return &mut [];
31    }
32    slice::from_raw_parts_mut(data, len)
33}
34
35#[cfg(feature="std")]
36type BrotliAdditionalErrorData = boxed::Box<dyn any::Any + Send + 'static>;
37#[cfg(not(feature="std"))]
38type BrotliAdditionalErrorData = ();
39
40#[repr(C)]
41pub struct BrotliDecoderState {
42    pub custom_allocator: CAllocator,
43    pub decompressor: ::BrotliState<SubclassableAllocator,
44                                    SubclassableAllocator,
45                                    SubclassableAllocator>,
46}
47
48#[cfg(not(feature="std"))]
49fn brotli_new_decompressor_without_custom_alloc(_to_box: BrotliDecoderState) -> *mut BrotliDecoderState{
50    panic!("Must supply allocators if calling divans when compiled without features=std");
51}
52
53#[cfg(feature="std")]
54fn brotli_new_decompressor_without_custom_alloc(to_box: BrotliDecoderState) -> *mut BrotliDecoderState{
55    alloc_util::Box::<BrotliDecoderState>::into_raw(
56        alloc_util::Box::<BrotliDecoderState>::new(to_box))
57}
58
59
60#[no_mangle]
61pub unsafe extern fn BrotliDecoderCreateInstance(
62    alloc_func: brotli_alloc_func,
63    free_func: brotli_free_func,
64    opaque: *mut c_void,
65) -> *mut BrotliDecoderState {
66    match catch_panic_state(|| {
67      let allocators = CAllocator {
68        alloc_func:alloc_func,
69        free_func:free_func,
70        opaque:opaque,
71      };
72      let custom_dictionary = <SubclassableAllocator as Allocator<u8>>::AllocatedMemory::default();
73      let to_box = BrotliDecoderState {
74        custom_allocator: allocators.clone(),
75        decompressor: ::BrotliState::new_with_custom_dictionary(
76          SubclassableAllocator::new(allocators.clone()),
77          SubclassableAllocator::new(allocators.clone()),
78          SubclassableAllocator::new(allocators.clone()),
79          custom_dictionary,
80        ),
81      };
82      if let Some(alloc) = alloc_func {
83        if free_func.is_none() {
84            panic!("either both alloc and free must exist or neither");
85        }
86        let ptr = alloc(allocators.opaque, core::mem::size_of::<BrotliDecoderState>());
87        let brotli_decoder_state_ptr = core::mem::transmute::<*mut c_void, *mut BrotliDecoderState>(ptr);
88        core::ptr::write(brotli_decoder_state_ptr, to_box);
89        brotli_decoder_state_ptr
90      } else {
91        brotli_new_decompressor_without_custom_alloc(to_box)
92      }
93    }) {
94        Ok(ret) => ret,
95        Err(mut e) => {
96            error_print(core::ptr::null_mut(), &mut e);
97            core::ptr::null_mut()
98        },
99    }
100}
101
102#[no_mangle]
103pub unsafe extern fn BrotliDecoderSetParameter(_state_ptr: *mut BrotliDecoderState,
104                                       _selector: BrotliDecoderParameter,
105                                       _value: u32) {
106  // not implemented
107}
108
109#[no_mangle]
110pub unsafe extern fn BrotliDecoderDecompressPrealloc(
111  encoded_size: usize,
112  encoded_buffer: *const u8,
113  decoded_size: usize,
114  decoded_buffer: *mut u8,
115  scratch_u8_size: usize,
116  scratch_u8_buffer: *mut u8,
117  scratch_u32_size: usize,
118  scratch_u32_buffer: *mut u32,
119  scratch_hc_size: usize,
120  scratch_hc_buffer: *mut HuffmanCode,
121) -> BrotliDecoderReturnInfo {
122  let input = slice_from_raw_parts_or_nil(encoded_buffer, encoded_size);
123  let output = slice_from_raw_parts_or_nil_mut(decoded_buffer, decoded_size);
124  let scratch_u8 = slice_from_raw_parts_or_nil_mut(scratch_u8_buffer, scratch_u8_size);
125  let scratch_u32 = slice_from_raw_parts_or_nil_mut(scratch_u32_buffer, scratch_u32_size);
126  let scratch_hc = slice_from_raw_parts_or_nil_mut(scratch_hc_buffer, scratch_hc_size);
127  ::brotli_decode_prealloc(input, output, scratch_u8, scratch_u32, scratch_hc)
128}
129
130
131#[no_mangle]
132pub unsafe extern fn BrotliDecoderDecompressWithReturnInfo(
133  encoded_size: usize,
134  encoded_buffer: *const u8,
135  decoded_size: usize,
136  decoded_buffer: *mut u8,
137) -> BrotliDecoderReturnInfo {
138  let input = slice_from_raw_parts_or_nil(encoded_buffer, encoded_size);
139  let output_scratch = slice_from_raw_parts_or_nil_mut(decoded_buffer, decoded_size);
140  ::brotli_decode(input, output_scratch)
141}
142
143#[no_mangle]
144pub unsafe extern fn BrotliDecoderDecompress(
145  encoded_size: usize,
146  encoded_buffer: *const u8,
147  decoded_size: *mut usize,
148  decoded_buffer: *mut u8,
149) -> BrotliDecoderResult {
150  let res = BrotliDecoderDecompressWithReturnInfo(encoded_size, encoded_buffer, *decoded_size, decoded_buffer);
151  *decoded_size = res.decoded_size;  
152  match res.result {
153      BrotliResult::ResultSuccess => BrotliDecoderResult::BROTLI_DECODER_RESULT_SUCCESS,
154      _ => BrotliDecoderResult::BROTLI_DECODER_RESULT_ERROR
155  }
156}
157
158#[cfg(all(feature="std", not(feature="pass-through-ffi-panics")))]
159fn catch_panic<F:FnOnce()->BrotliDecoderResult+panic::UnwindSafe>(f: F) -> thread::Result<BrotliDecoderResult> {
160    panic::catch_unwind(f)
161}
162
163#[cfg(all(feature="std", not(feature="pass-through-ffi-panics")))]
164fn catch_panic_state<F:FnOnce()->*mut BrotliDecoderState+panic::UnwindSafe>(f: F) -> thread::Result<*mut BrotliDecoderState> {
165    panic::catch_unwind(f)
166}
167
168#[cfg(all(feature="std", not(feature="pass-through-ffi-panics")))]
169unsafe fn error_print(state_ptr: *mut BrotliDecoderState, err: &mut BrotliAdditionalErrorData) {
170    if let Some(st) = err.downcast_ref::<&str>() {
171        if !state_ptr.is_null() {
172          let mut str_cpy = [0u8;256];
173          let src:&[u8] = st.as_ref();
174          let xlen = core::cmp::min(src.len(), str_cpy.len() - 1);
175          str_cpy.split_at_mut(xlen).0.clone_from_slice(
176                src.split_at(xlen).0);
177          str_cpy[xlen] = 0; // null terminate
178          (*state_ptr).decompressor.mtf_or_error_string = Err(str_cpy);
179        }
180        let _ign = writeln!(&mut io::stderr(), "panic: {}", st);
181    } else {
182        if let Some(st) = err.downcast_ref::<string::String>() {
183
184          if !state_ptr.is_null() {
185            let mut str_cpy = [0u8;256];
186            let src: &[u8] = st.as_ref();
187            let xlen = core::cmp::min(src.len(), str_cpy.len() - 1);
188            str_cpy.split_at_mut(xlen).0.clone_from_slice(
189                src.split_at(xlen).0);
190            str_cpy[xlen] = 0; // null terminate
191            (*state_ptr).decompressor.mtf_or_error_string = Err(str_cpy);
192          }
193          let _ign = writeln!(&mut io::stderr(), "Internal Error {:?}", st);
194        } else {
195            let _ign = writeln!(&mut io::stderr(), "Internal Error {:?}", err);
196        }
197    }
198}
199
200// can't catch panics in a reliable way without std:: configure with panic=abort. These shouldn't happen
201#[cfg(any(not(feature="std"), feature="pass-through-ffi-panics"))]
202fn catch_panic<F:FnOnce()->BrotliDecoderResult>(f: F) -> Result<BrotliDecoderResult, BrotliAdditionalErrorData> {
203    Ok(f())
204}
205
206#[cfg(any(not(feature="std"), feature="pass-through-ffi-panics"))]
207fn catch_panic_state<F:FnOnce()->*mut BrotliDecoderState>(f: F) -> Result<*mut BrotliDecoderState, BrotliAdditionalErrorData> {
208    Ok(f())
209}
210
211#[cfg(any(not(feature="std"), feature="pass-through-ffi-panics"))]
212fn error_print(_state_ptr: *mut BrotliDecoderState, _err: &mut BrotliAdditionalErrorData) {
213}
214
215#[no_mangle]
216pub unsafe extern fn BrotliDecoderDecompressStream(
217    state_ptr: *mut BrotliDecoderState,
218    available_in: *mut usize,
219    input_buf_ptr: *mut*const u8,
220    available_out: *mut usize,
221    output_buf_ptr: *mut*mut u8,
222    mut total_out: *mut usize) -> BrotliDecoderResult {
223    match catch_panic(move || {
224    let mut input_offset = 0usize;
225    let mut output_offset = 0usize;
226    let mut fallback_total_out = 0usize;
227    if total_out.is_null() {
228        total_out = &mut fallback_total_out;
229    }
230    let result: BrotliDecoderResult;
231    {
232        let input_buf = slice_from_raw_parts_or_nil(*input_buf_ptr, *available_in);
233        let output_buf = slice_from_raw_parts_or_nil_mut(*output_buf_ptr, *available_out);
234            result = super::decode::BrotliDecompressStream(
235                &mut *available_in,
236                &mut input_offset,
237                input_buf,
238                &mut *available_out,
239                &mut output_offset,
240                output_buf,
241                &mut *total_out,
242                &mut (*state_ptr).decompressor,
243            ).into();
244    }
245    *input_buf_ptr = (*input_buf_ptr).offset(input_offset as isize);
246    *output_buf_ptr = (*output_buf_ptr).offset(output_offset as isize);
247                                           result
248    }) {
249        Ok(ret) => ret,
250        Err(mut readable_err) => { // if we panic (completely unexpected) then we should report it back to C and print
251            error_print(state_ptr, &mut readable_err);
252            (*state_ptr).decompressor.error_code = BrotliDecoderErrorCode::BROTLI_DECODER_ERROR_UNREACHABLE;
253            BrotliDecoderResult::BROTLI_DECODER_RESULT_ERROR
254        }
255    }
256}
257
258/// Equivalent to BrotliDecoderDecompressStream but with no optional arg and no double indirect ptrs
259#[no_mangle]
260pub unsafe extern fn BrotliDecoderDecompressStreaming(
261    state_ptr: *mut BrotliDecoderState,
262    available_in: *mut usize,
263    mut input_buf_ptr: *const u8,
264    available_out: *mut usize,
265    mut output_buf_ptr: *mut u8) -> BrotliDecoderResult {
266    BrotliDecoderDecompressStream(state_ptr,
267                                  available_in,
268                                  &mut input_buf_ptr,
269                                  available_out,
270                                  &mut output_buf_ptr,
271                                  core::ptr::null_mut())
272}
273
274#[cfg(feature="std")]
275unsafe fn free_decompressor_no_custom_alloc(state_ptr: *mut BrotliDecoderState) {
276    let _state = alloc_util::Box::from_raw(state_ptr);
277}
278
279#[cfg(not(feature="std"))]
280unsafe fn free_decompressor_no_custom_alloc(_state_ptr: *mut BrotliDecoderState) {
281    unreachable!();
282}
283
284
285#[no_mangle]
286pub unsafe extern fn BrotliDecoderMallocU8(state_ptr: *mut BrotliDecoderState, size: usize) -> *mut u8 {
287    if let Some(alloc_fn) = (*state_ptr).custom_allocator.alloc_func {
288        return core::mem::transmute::<*mut c_void, *mut u8>(alloc_fn((*state_ptr).custom_allocator.opaque, size));
289    } else {
290        return alloc_util::alloc_stdlib(size);
291    }
292}
293
294#[no_mangle]
295pub unsafe extern fn BrotliDecoderFreeU8(state_ptr: *mut BrotliDecoderState, data: *mut u8, size: usize) {
296    if let Some(free_fn) = (*state_ptr).custom_allocator.free_func {
297        free_fn((*state_ptr).custom_allocator.opaque, core::mem::transmute::<*mut u8, *mut c_void>(data));
298    } else {
299        alloc_util::free_stdlib(data, size);
300    }
301}
302
303#[no_mangle]
304pub unsafe extern fn BrotliDecoderMallocUsize(state_ptr: *mut BrotliDecoderState, size: usize) -> *mut usize {
305    if let Some(alloc_fn) = (*state_ptr).custom_allocator.alloc_func {
306        return core::mem::transmute::<*mut c_void, *mut usize>(alloc_fn((*state_ptr).custom_allocator.opaque,
307                                                                         size * core::mem::size_of::<usize>()));
308    } else {
309        return alloc_util::alloc_stdlib(size);
310    }
311}
312#[no_mangle]
313pub unsafe extern fn BrotliDecoderFreeUsize(state_ptr: *mut BrotliDecoderState, data: *mut usize, size: usize) {
314    if let Some(free_fn) = (*state_ptr).custom_allocator.free_func {
315        free_fn((*state_ptr).custom_allocator.opaque, core::mem::transmute::<*mut usize, *mut c_void>(data));
316    } else {
317        alloc_util::free_stdlib(data, size);
318    }
319}
320
321#[no_mangle]
322pub unsafe extern fn BrotliDecoderDestroyInstance(state_ptr: *mut BrotliDecoderState) {
323    if let Some(_) = (*state_ptr).custom_allocator.alloc_func {
324        if let Some(free_fn) = (*state_ptr).custom_allocator.free_func {
325            let _to_free = core::ptr::read(state_ptr);
326            let ptr = core::mem::transmute::<*mut BrotliDecoderState, *mut c_void>(state_ptr);
327            free_fn((*state_ptr).custom_allocator.opaque, ptr);
328        }
329    } else {
330        free_decompressor_no_custom_alloc(state_ptr);
331    }
332}
333
334#[no_mangle]
335pub unsafe extern fn BrotliDecoderHasMoreOutput(state_ptr: *const BrotliDecoderState) -> i32 {
336  if super::decode::BrotliDecoderHasMoreOutput(&(*state_ptr).decompressor) {1} else {0}
337}
338
339#[no_mangle]
340pub unsafe extern fn BrotliDecoderTakeOutput(state_ptr: *mut BrotliDecoderState, size: *mut usize) -> *const u8 {
341  super::decode::BrotliDecoderTakeOutput(&mut (*state_ptr).decompressor, &mut *size).as_ptr()
342}
343
344
345
346#[no_mangle]
347pub unsafe extern fn BrotliDecoderIsUsed(state_ptr: *const BrotliDecoderState) -> i32 {
348  if super::decode::BrotliDecoderIsUsed(&(*state_ptr).decompressor) {1} else {0}
349}
350#[no_mangle]
351pub unsafe extern fn BrotliDecoderIsFinished(state_ptr: *const BrotliDecoderState) -> i32 {
352  if super::decode::BrotliDecoderIsFinished(&(*state_ptr).decompressor) {1} else {0}
353}
354#[no_mangle]
355pub unsafe extern fn BrotliDecoderGetErrorCode(state_ptr: *const BrotliDecoderState) -> BrotliDecoderErrorCode {
356  super::decode::BrotliDecoderGetErrorCode(&(*state_ptr).decompressor)
357}
358
359#[no_mangle]
360pub unsafe extern fn BrotliDecoderGetErrorString(state_ptr: *const BrotliDecoderState) -> *const u8 {
361  if !state_ptr.is_null() {
362    if let &Err(ref msg) = &(*state_ptr).decompressor.mtf_or_error_string {
363      // important: this must be a ref
364      // so stack memory is not returned
365      return msg.as_ptr();
366    }
367  }
368  BrotliDecoderErrorString(super::decode::BrotliDecoderGetErrorCode(&(*state_ptr).decompressor))
369}
370#[no_mangle]
371pub extern fn BrotliDecoderErrorString(c: BrotliDecoderErrorCode) -> *const u8 {
372    ::state::BrotliDecoderErrorStr(c).as_ptr()
373}
374
375
376#[no_mangle]
377pub extern fn BrotliDecoderVersion() -> u32 {
378  0x1000f00
379}