brotli_decompressor/ffi/
mod.rs

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