1#![cfg(not(feature = "safe"))]
2
3#[cfg(feature = "std")]
4use std::io::Write;
5#[cfg(feature = "std")]
6use std::{io, panic, thread};
7
8use super::alloc_util::BrotliSubclassableAllocator;
9use brotli_decompressor::ffi::alloc_util;
10use brotli_decompressor::ffi::alloc_util::SubclassableAllocator;
11use brotli_decompressor::ffi::interface::{
12 brotli_alloc_func, brotli_free_func, c_void, CAllocator,
13};
14use brotli_decompressor::ffi::{slice_from_raw_parts_or_nil, slice_from_raw_parts_or_nil_mut};
15use core;
16use enc::encode::BrotliEncoderStateStruct;
17
18#[repr(C)]
19pub enum BrotliEncoderOperation {
20 BROTLI_OPERATION_PROCESS = 0,
21 BROTLI_OPERATION_FLUSH = 1,
22 BROTLI_OPERATION_FINISH = 2,
23 BROTLI_OPERATION_EMIT_METADATA = 3,
24}
25
26#[repr(C)]
27pub enum BrotliEncoderMode {
28 BROTLI_MODE_GENERIC = 0,
29 BROTLI_MODE_TEXT = 1,
30 BROTLI_MODE_FONT = 2,
31 BROTLI_MODE_FORCE_LSB_PRIOR = 3,
32 BROTLI_MODE_FORCE_MSB_PRIOR = 4,
33 BROTLI_MODE_FORCE_UTF8_PRIOR = 5,
34 BROTLI_MODE_FORCE_SIGNED_PRIOR = 6,
35}
36
37#[repr(C)]
38pub struct BrotliEncoderState {
39 pub custom_allocator: CAllocator,
40 pub compressor: BrotliEncoderStateStruct<BrotliSubclassableAllocator>,
41}
42
43#[cfg(not(feature = "std"))]
44fn brotli_new_compressor_without_custom_alloc(
45 _to_box: BrotliEncoderState,
46) -> *mut BrotliEncoderState {
47 panic!("Must supply allocators if calling divans when compiled without features=std");
48}
49
50#[cfg(feature = "std")]
51fn brotli_new_compressor_without_custom_alloc(
52 to_box: BrotliEncoderState,
53) -> *mut BrotliEncoderState {
54 alloc_util::Box::<BrotliEncoderState>::into_raw(alloc_util::Box::<BrotliEncoderState>::new(
55 to_box,
56 ))
57}
58#[cfg(feature = "std")]
59unsafe fn free_compressor_no_custom_alloc(state_ptr: *mut BrotliEncoderState) {
60 let _state = alloc_util::Box::from_raw(state_ptr);
61}
62
63#[cfg(not(feature = "std"))]
64unsafe fn free_compressor_no_custom_alloc(_state_ptr: *mut BrotliEncoderState) {
65 unreachable!();
66}
67
68#[no_mangle]
69pub unsafe extern "C" fn BrotliEncoderCreateInstance(
70 alloc_func: brotli_alloc_func,
71 free_func: brotli_free_func,
72 opaque: *mut c_void,
73) -> *mut BrotliEncoderState {
74 catch_panic_cstate(|| {
75 let allocators = CAllocator {
76 alloc_func,
77 free_func,
78 opaque,
79 };
80 let to_box = BrotliEncoderState {
81 custom_allocator: allocators.clone(),
82 compressor: ::enc::encode::BrotliEncoderCreateInstance(
83 BrotliSubclassableAllocator::new(SubclassableAllocator::new(allocators.clone())),
84 ),
85 };
86 if let Some(alloc) = alloc_func {
87 if free_func.is_none() {
88 panic!("either both alloc and free must exist or neither");
89 }
90 let ptr = alloc(
91 allocators.opaque,
92 core::mem::size_of::<BrotliEncoderState>(),
93 );
94 let brotli_decoder_state_ptr =
95 core::mem::transmute::<*mut c_void, *mut BrotliEncoderState>(ptr);
96 core::ptr::write(brotli_decoder_state_ptr, to_box);
97 brotli_decoder_state_ptr
98 } else {
99 brotli_new_compressor_without_custom_alloc(to_box)
100 }
101 })
102 .unwrap_or_else(|err| {
103 error_print(err);
104 core::ptr::null_mut()
105 })
106}
107
108#[no_mangle]
109pub unsafe extern "C" fn BrotliEncoderSetParameter(
110 state_ptr: *mut BrotliEncoderState,
111 param: ::enc::encode::BrotliEncoderParameter,
112 value: u32,
113) -> i32 {
114 ::enc::encode::BrotliEncoderSetParameter(&mut (*state_ptr).compressor, param, value)
115}
116
117#[no_mangle]
118pub unsafe extern "C" fn BrotliEncoderDestroyInstance(state_ptr: *mut BrotliEncoderState) {
119 if state_ptr.is_null() {
120 return;
121 }
122 ::enc::encode::BrotliEncoderDestroyInstance(&mut (*state_ptr).compressor);
123 if (*state_ptr).custom_allocator.alloc_func.is_some() {
124 if let Some(free_fn) = (*state_ptr).custom_allocator.free_func {
125 let _to_free = core::ptr::read(state_ptr);
126 let ptr = core::mem::transmute::<*mut BrotliEncoderState, *mut c_void>(state_ptr);
127 free_fn((*state_ptr).custom_allocator.opaque, ptr);
128 }
129 } else {
130 free_compressor_no_custom_alloc(state_ptr);
131 }
132}
133#[no_mangle]
134pub unsafe extern "C" fn BrotliEncoderIsFinished(state_ptr: *mut BrotliEncoderState) -> i32 {
135 ::enc::encode::BrotliEncoderIsFinished(&mut (*state_ptr).compressor)
136}
137
138#[no_mangle]
139pub unsafe extern "C" fn BrotliEncoderHasMoreOutput(state_ptr: *mut BrotliEncoderState) -> i32 {
140 ::enc::encode::BrotliEncoderHasMoreOutput(&mut (*state_ptr).compressor)
141}
142
143#[no_mangle]
144pub unsafe extern "C" fn BrotliEncoderSetCustomDictionary(
145 state_ptr: *mut BrotliEncoderState,
146 size: usize,
147 dict: *const u8,
148) {
149 if let Err(panic_err) = catch_panic(|| {
150 let dict_slice = slice_from_raw_parts_or_nil(dict, size);
151 ::enc::encode::BrotliEncoderSetCustomDictionary(
152 &mut (*state_ptr).compressor,
153 size,
154 dict_slice,
155 );
156 0
157 }) {
158 error_print(panic_err);
159 }
160}
161
162#[no_mangle]
163pub unsafe extern "C" fn BrotliEncoderTakeOutput(
164 state_ptr: *mut BrotliEncoderState,
165 size: *mut usize,
166) -> *const u8 {
167 ::enc::encode::BrotliEncoderTakeOutput(&mut (*state_ptr).compressor, &mut *size).as_ptr()
168}
169#[no_mangle]
170pub extern "C" fn BrotliEncoderVersion() -> u32 {
171 ::enc::encode::BrotliEncoderVersion()
172}
173#[no_mangle]
174pub extern "C" fn BrotliEncoderMaxCompressedSize(input_size: usize) -> usize {
175 ::enc::encode::BrotliEncoderMaxCompressedSize(input_size)
176}
177#[no_mangle]
178pub unsafe extern "C" fn BrotliEncoderCompress(
179 quality: i32,
180 lgwin: i32,
181 mode: BrotliEncoderMode,
182 input_size: usize,
183 input_buffer: *const u8,
184 encoded_size: *mut usize,
185 encoded_buffer: *mut u8,
186) -> i32 {
187 catch_panic(|| {
188 let input_buf = slice_from_raw_parts_or_nil(input_buffer, input_size);
189 let encoded_buf = slice_from_raw_parts_or_nil_mut(encoded_buffer, *encoded_size);
190 let allocators = CAllocator {
191 alloc_func: None,
192 free_func: None,
193 opaque: core::ptr::null_mut(),
194 };
195 let translated_mode = match mode {
196 BrotliEncoderMode::BROTLI_MODE_GENERIC => {
197 ::enc::backward_references::BrotliEncoderMode::BROTLI_MODE_GENERIC
198 }
199 BrotliEncoderMode::BROTLI_MODE_TEXT => {
200 ::enc::backward_references::BrotliEncoderMode::BROTLI_MODE_TEXT
201 }
202 BrotliEncoderMode::BROTLI_MODE_FONT => {
203 ::enc::backward_references::BrotliEncoderMode::BROTLI_MODE_FONT
204 }
205 BrotliEncoderMode::BROTLI_MODE_FORCE_LSB_PRIOR => {
206 ::enc::backward_references::BrotliEncoderMode::BROTLI_FORCE_LSB_PRIOR
207 }
208 BrotliEncoderMode::BROTLI_MODE_FORCE_MSB_PRIOR => {
209 ::enc::backward_references::BrotliEncoderMode::BROTLI_FORCE_MSB_PRIOR
210 }
211 BrotliEncoderMode::BROTLI_MODE_FORCE_UTF8_PRIOR => {
212 ::enc::backward_references::BrotliEncoderMode::BROTLI_FORCE_UTF8_PRIOR
213 }
214 BrotliEncoderMode::BROTLI_MODE_FORCE_SIGNED_PRIOR => {
215 ::enc::backward_references::BrotliEncoderMode::BROTLI_FORCE_SIGNED_PRIOR
216 }
217 };
218 let mut m8 =
219 BrotliSubclassableAllocator::new(SubclassableAllocator::new(allocators.clone()));
220 let empty_m8 =
221 BrotliSubclassableAllocator::new(SubclassableAllocator::new(allocators.clone()));
222
223 ::enc::encode::BrotliEncoderCompress(
224 empty_m8,
225 &mut m8,
226 quality,
227 lgwin,
228 translated_mode,
229 input_size,
230 input_buf,
231 &mut *encoded_size,
232 encoded_buf,
233 &mut |_a, _b, _c, _d| (),
234 )
235 })
236 .unwrap_or_else(|panic_err| {
237 error_print(panic_err);
238 0
239 })
240}
241
242#[no_mangle]
243pub unsafe extern "C" fn BrotliEncoderCompressStreaming(
244 state_ptr: *mut BrotliEncoderState,
245 op: BrotliEncoderOperation,
246 available_in: *mut usize,
247 mut input_buf: *const u8,
248 available_out: *mut usize,
249 mut output_buf: *mut u8,
250) -> i32 {
251 BrotliEncoderCompressStream(
252 state_ptr,
253 op,
254 available_in,
255 &mut input_buf,
256 available_out,
257 &mut output_buf,
258 core::ptr::null_mut(),
259 )
260}
261
262#[no_mangle]
263pub unsafe extern "C" fn BrotliEncoderCompressStream(
264 state_ptr: *mut BrotliEncoderState,
265 op: BrotliEncoderOperation,
266 available_in: *mut usize,
267 input_buf_ptr: *mut *const u8,
268 available_out: *mut usize,
269 output_buf_ptr: *mut *mut u8,
270 total_out: *mut usize,
271) -> i32 {
272 catch_panic(|| {
273 let mut input_offset = 0usize;
274 let mut output_offset = 0usize;
275 let result;
276 let translated_op = match op {
277 BrotliEncoderOperation::BROTLI_OPERATION_PROCESS => {
278 ::enc::encode::BrotliEncoderOperation::BROTLI_OPERATION_PROCESS
279 }
280 BrotliEncoderOperation::BROTLI_OPERATION_FLUSH => {
281 ::enc::encode::BrotliEncoderOperation::BROTLI_OPERATION_FLUSH
282 }
283 BrotliEncoderOperation::BROTLI_OPERATION_FINISH => {
284 ::enc::encode::BrotliEncoderOperation::BROTLI_OPERATION_FINISH
285 }
286 BrotliEncoderOperation::BROTLI_OPERATION_EMIT_METADATA => {
287 ::enc::encode::BrotliEncoderOperation::BROTLI_OPERATION_EMIT_METADATA
288 }
289 };
290 {
291 let (input_buf, input_any): (&[u8], bool) = if *available_in != 0 {
292 (
293 slice_from_raw_parts_or_nil(*input_buf_ptr, *available_in),
294 true,
295 )
296 } else {
297 (&[], false)
298 };
299 let (output_buf, output_any): (&mut [u8], bool) = if *available_out != 0 {
300 (
301 slice_from_raw_parts_or_nil_mut(*output_buf_ptr, *available_out),
302 true,
303 )
304 } else {
305 (&mut [], false)
306 };
307 let mut to = Some(0);
308 result = ::enc::encode::BrotliEncoderCompressStream(
309 &mut (*state_ptr).compressor,
310 translated_op,
311 &mut *available_in,
312 input_buf,
313 &mut input_offset,
314 &mut *available_out,
315 output_buf,
316 &mut output_offset,
317 &mut to,
318 &mut |_a, _b, _c, _d| (),
319 );
320 if !total_out.is_null() {
321 *total_out = to.unwrap_or(0);
322 }
323 if input_any {
324 *input_buf_ptr = (*input_buf_ptr).add(input_offset);
325 }
326 if output_any {
327 *output_buf_ptr = (*output_buf_ptr).add(output_offset);
328 }
329 }
330 result
331 })
332 .unwrap_or_else(|panic_err| {
333 error_print(panic_err);
334 0
335 })
336}
337
338#[no_mangle]
339pub unsafe extern "C" fn BrotliEncoderMallocU8(
340 state_ptr: *mut BrotliEncoderState,
341 size: usize,
342) -> *mut u8 {
343 if let Some(alloc_fn) = (*state_ptr).custom_allocator.alloc_func {
344 core::mem::transmute::<*mut c_void, *mut u8>(alloc_fn(
345 (*state_ptr).custom_allocator.opaque,
346 size,
347 ))
348 } else {
349 alloc_util::alloc_stdlib(size)
350 }
351}
352
353#[no_mangle]
354pub unsafe extern "C" fn BrotliEncoderFreeU8(
355 state_ptr: *mut BrotliEncoderState,
356 data: *mut u8,
357 size: usize,
358) {
359 if let Some(free_fn) = (*state_ptr).custom_allocator.free_func {
360 free_fn(
361 (*state_ptr).custom_allocator.opaque,
362 core::mem::transmute::<*mut u8, *mut c_void>(data),
363 );
364 } else {
365 alloc_util::free_stdlib(data, size);
366 }
367}
368
369#[no_mangle]
370pub unsafe extern "C" fn BrotliEncoderMallocUsize(
371 state_ptr: *mut BrotliEncoderState,
372 size: usize,
373) -> *mut usize {
374 if let Some(alloc_fn) = (*state_ptr).custom_allocator.alloc_func {
375 core::mem::transmute::<*mut c_void, *mut usize>(alloc_fn(
376 (*state_ptr).custom_allocator.opaque,
377 size * core::mem::size_of::<usize>(),
378 ))
379 } else {
380 alloc_util::alloc_stdlib(size)
381 }
382}
383#[no_mangle]
384pub unsafe extern "C" fn BrotliEncoderFreeUsize(
385 state_ptr: *mut BrotliEncoderState,
386 data: *mut usize,
387 size: usize,
388) {
389 if let Some(free_fn) = (*state_ptr).custom_allocator.free_func {
390 free_fn(
391 (*state_ptr).custom_allocator.opaque,
392 core::mem::transmute::<*mut usize, *mut c_void>(data),
393 );
394 } else {
395 alloc_util::free_stdlib(data, size);
396 }
397}
398
399#[cfg(all(feature = "std", not(feature = "pass-through-ffi-panics")))]
400pub fn catch_panic<F: FnOnce() -> i32 + panic::UnwindSafe>(f: F) -> thread::Result<i32> {
401 panic::catch_unwind(f)
402}
403
404#[cfg(all(feature = "std", not(feature = "pass-through-ffi-panics")))]
405fn catch_panic_cstate<F: FnOnce() -> *mut BrotliEncoderState + panic::UnwindSafe>(
406 f: F,
407) -> thread::Result<*mut BrotliEncoderState> {
408 panic::catch_unwind(f)
409}
410
411#[cfg(all(feature = "std", not(feature = "pass-through-ffi-panics")))]
412fn error_print<Err: core::fmt::Debug>(err: Err) {
413 let _ign = writeln!(&mut io::stderr(), "Internal Error {:?}", err);
414}
415
416#[cfg(any(not(feature = "std"), feature = "pass-through-ffi-panics"))]
418pub fn catch_panic<F: FnOnce() -> i32>(f: F) -> Result<i32, ()> {
419 Ok(f())
420}
421
422#[cfg(any(not(feature = "std"), feature = "pass-through-ffi-panics"))]
423fn catch_panic_cstate<F: FnOnce() -> *mut BrotliEncoderState>(
424 f: F,
425) -> Result<*mut BrotliEncoderState, ()> {
426 Ok(f())
427}
428
429#[cfg(any(not(feature = "std"), feature = "pass-through-ffi-panics"))]
430fn error_print<Err>(_err: Err) {}