1#![no_std]
2#![allow(non_snake_case)]
3#![allow(unused_parens)]
4#![allow(unused_imports)]
5#![allow(non_camel_case_types)]
6#![allow(non_snake_case)]
7#![allow(non_upper_case_globals)]
8#![cfg_attr(feature="no-stdlib-ffi-binding",cfg_attr(not(feature="std"), feature(lang_items)))]
9#![cfg_attr(feature="no-stdlib-ffi-binding",cfg_attr(not(feature="std"), feature(panic_handler)))]
10#![cfg_attr(not(any(feature="unsafe", feature="ffi-api")), forbid(unsafe_code))]
13
14
15#[macro_use]
16#[cfg(feature="std")]
18extern crate std;
19#[cfg(feature="std")]
20use std::io::{self, Error, ErrorKind, Read, Write};
21#[cfg(feature="std")]
22extern crate alloc_stdlib;
23#[macro_use]
24extern crate alloc_no_stdlib as alloc;
25pub use alloc::{AllocatedStackMemory, Allocator, SliceWrapper, SliceWrapperMut, StackAllocator, bzero};
26use core::ops;
27
28#[cfg(feature="std")]
29pub use alloc_stdlib::StandardAlloc;
30#[cfg(all(feature="unsafe",feature="std"))]
31pub use alloc_stdlib::HeapAlloc;
32#[macro_use]
33mod memory;
34pub mod dictionary;
35mod brotli_alloc;
36#[macro_use]
37mod bit_reader;
38mod huffman;
39mod state;
40mod prefix;
41mod context;
42pub mod transform;
43mod test;
44mod decode;
45pub mod io_wrappers;
46pub mod reader;
47pub mod writer;
48pub use huffman::{HuffmanCode, HuffmanTreeGroup};
49pub use state::BrotliState;
50#[cfg(feature="ffi-api")]
51pub mod ffi;
52pub use reader::{DecompressorCustomIo};
53
54#[cfg(feature="std")]
55pub use reader::{Decompressor};
56
57pub use writer::{DecompressorWriterCustomIo};
58#[cfg(feature="std")]
59pub use writer::{DecompressorWriter};
60
61pub use io_wrappers::{CustomRead, CustomWrite};
63#[cfg(feature="std")]
64pub use io_wrappers::{IntoIoReader, IoReaderWrapper, IntoIoWriter, IoWriterWrapper};
65
66pub use decode::{BrotliDecompressStream, BrotliResult, BrotliDecoderHasMoreOutput, BrotliDecoderIsFinished, BrotliDecoderTakeOutput};
77
78
79
80
81#[cfg(not(any(feature="unsafe", not(feature="std"))))]
82pub fn BrotliDecompress<InputType, OutputType>(r: &mut InputType,
83 w: &mut OutputType)
84 -> Result<(), io::Error>
85 where InputType: Read,
86 OutputType: Write
87{
88 let mut input_buffer: [u8; 4096] = [0; 4096];
89 let mut output_buffer: [u8; 4096] = [0; 4096];
90 BrotliDecompressCustomAlloc(r,
91 w,
92 &mut input_buffer[..],
93 &mut output_buffer[..],
94 StandardAlloc::default(),
95 StandardAlloc::default(),
96 StandardAlloc::default(),
97 )
98}
99
100#[cfg(feature="std")]
101pub fn BrotliDecompressCustomDict<InputType, OutputType>(r: &mut InputType,
102 w: &mut OutputType,
103 input_buffer:&mut [u8],
104 output_buffer:&mut [u8],
105 custom_dictionary:std::vec::Vec<u8>)
106 -> Result<(), io::Error>
107 where InputType: Read,
108 OutputType: Write
109{
110 let mut alloc_u8 = brotli_alloc::BrotliAlloc::<u8>::new();
111 let mut input_buffer_backing;
112 let mut output_buffer_backing;
113 {
114 let mut borrowed_input_buffer = input_buffer;
115 let mut borrowed_output_buffer = output_buffer;
116 if borrowed_input_buffer.len() == 0 {
117 input_buffer_backing = alloc_u8.alloc_cell(4096);
118 borrowed_input_buffer = input_buffer_backing.slice_mut();
119 }
120 if borrowed_output_buffer.len() == 0 {
121 output_buffer_backing = alloc_u8.alloc_cell(4096);
122 borrowed_output_buffer = output_buffer_backing.slice_mut();
123 }
124 let dict = alloc_u8.take_ownership(custom_dictionary);
125 BrotliDecompressCustomIoCustomDict(&mut IoReaderWrapper::<InputType>(r),
126 &mut IoWriterWrapper::<OutputType>(w),
127 borrowed_input_buffer,
128 borrowed_output_buffer,
129 alloc_u8,
130 brotli_alloc::BrotliAlloc::<u32>::new(),
131 brotli_alloc::BrotliAlloc::<HuffmanCode>::new(),
132 dict,
133 Error::new(ErrorKind::UnexpectedEof, "Unexpected EOF"))
134 }
135}
136
137#[cfg(all(feature="unsafe",feature="std"))]
138pub fn BrotliDecompress<InputType, OutputType>(r: &mut InputType,
139 w: &mut OutputType)
140 -> Result<(), io::Error>
141 where InputType: Read,
142 OutputType: Write
143{
144 let mut input_buffer: [u8; 4096] = [0; 4096];
145 let mut output_buffer: [u8; 4096] = [0; 4096];
146 BrotliDecompressCustomAlloc(r,
147 w,
148 &mut input_buffer[..],
149 &mut output_buffer[..],
150 HeapAlloc::<u8>::new(0),
151 HeapAlloc::<u32>::new(0),
152 HeapAlloc::<HuffmanCode>::new(HuffmanCode{ bits:2, value: 1}))
153}
154
155
156#[cfg(feature="std")]
157pub fn BrotliDecompressCustomAlloc<InputType,
158 OutputType,
159 AllocU8: Allocator<u8>,
160 AllocU32: Allocator<u32>,
161 AllocHC: Allocator<HuffmanCode>>
162 (r: &mut InputType,
163 w: &mut OutputType,
164 input_buffer: &mut [u8],
165 output_buffer: &mut [u8],
166 alloc_u8: AllocU8,
167 alloc_u32: AllocU32,
168 alloc_hc: AllocHC)
169 -> Result<(), io::Error>
170 where InputType: Read,
171 OutputType: Write
172{
173 BrotliDecompressCustomIo(&mut IoReaderWrapper::<InputType>(r),
174 &mut IoWriterWrapper::<OutputType>(w),
175 input_buffer,
176 output_buffer,
177 alloc_u8,
178 alloc_u32,
179 alloc_hc,
180 Error::new(ErrorKind::UnexpectedEof, "Unexpected EOF"))
181}
182pub fn BrotliDecompressCustomIo<ErrType,
183 InputType,
184 OutputType,
185 AllocU8: Allocator<u8>,
186 AllocU32: Allocator<u32>,
187 AllocHC: Allocator<HuffmanCode>>
188 (r: &mut InputType,
189 w: &mut OutputType,
190 input_buffer: &mut [u8],
191 output_buffer: &mut [u8],
192 alloc_u8: AllocU8,
193 alloc_u32: AllocU32,
194 alloc_hc: AllocHC,
195 unexpected_eof_error_constant: ErrType)
196 -> Result<(), ErrType>
197 where InputType: CustomRead<ErrType>,
198 OutputType: CustomWrite<ErrType>
199{
200 BrotliDecompressCustomIoCustomDict(r, w, input_buffer, output_buffer, alloc_u8, alloc_u32, alloc_hc, AllocU8::AllocatedMemory::default(), unexpected_eof_error_constant)
201}
202pub fn BrotliDecompressCustomIoCustomDict<ErrType,
203 InputType,
204 OutputType,
205 AllocU8: Allocator<u8>,
206 AllocU32: Allocator<u32>,
207 AllocHC: Allocator<HuffmanCode>>
208 (r: &mut InputType,
209 w: &mut OutputType,
210 input_buffer: &mut [u8],
211 output_buffer: &mut [u8],
212 alloc_u8: AllocU8,
213 alloc_u32: AllocU32,
214 alloc_hc: AllocHC,
215 custom_dictionary: AllocU8::AllocatedMemory,
216 unexpected_eof_error_constant: ErrType)
217 -> Result<(), ErrType>
218 where InputType: CustomRead<ErrType>,
219 OutputType: CustomWrite<ErrType>
220{
221 let mut brotli_state = BrotliState::new_with_custom_dictionary(alloc_u8, alloc_u32, alloc_hc, custom_dictionary);
222 assert!(input_buffer.len() != 0);
223 assert!(output_buffer.len() != 0);
224 let mut available_out: usize = output_buffer.len();
225
226 let mut available_in: usize = 0;
227 let mut input_offset: usize = 0;
228 let mut output_offset: usize = 0;
229 let mut result: BrotliResult = BrotliResult::NeedsMoreInput;
230 loop {
231 match result {
232 BrotliResult::NeedsMoreInput => {
233 input_offset = 0;
234 match r.read(input_buffer) {
235 Err(e) => {
236 return Err(e);
237 },
238 Ok(size) => {
239 if size == 0 {
240 return Err(unexpected_eof_error_constant);
241 }
242 available_in = size;
243 }
244 }
245 }
246 BrotliResult::NeedsMoreOutput => {
247 let mut total_written: usize = 0;
248 while total_written < output_offset {
249 match w.write(&output_buffer[total_written..output_offset]) {
251 Err(e) => {
252 return Result::Err(e);
253 },
254 Ok(0) => {
255 return Result::Err(unexpected_eof_error_constant);
256 }
257 Ok(cur_written) => {
258 total_written += cur_written;
259 }
260 }
261 }
262
263 output_offset = 0;
264 }
265 BrotliResult::ResultSuccess => break,
266 BrotliResult::ResultFailure => {
267 return Err(unexpected_eof_error_constant);
268 }
269 }
270 let mut written: usize = 0;
271 result = BrotliDecompressStream(&mut available_in,
272 &mut input_offset,
273 input_buffer,
274 &mut available_out,
275 &mut output_offset,
276 output_buffer,
277 &mut written,
278 &mut brotli_state);
279
280 if output_offset != 0 {
281 let mut total_written: usize = 0;
282 while total_written < output_offset {
283 match w.write(&output_buffer[total_written..output_offset]) {
284 Err(e) => {
285 return Result::Err(e);
286 },
287 Ok(0) => {
289 return Result::Err(unexpected_eof_error_constant);
290 }
291 Ok(cur_written) => {
292 total_written += cur_written;
293 }
294 }
295 }
296 output_offset = 0;
297 available_out = output_buffer.len()
298 }
299 }
300 Ok(())
301}
302
303
304#[cfg(feature="std")]
305pub fn copy_from_to<R: io::Read, W: io::Write>(mut r: R, mut w: W) -> io::Result<usize> {
306 let mut buffer: [u8; 65536] = [0; 65536];
307 let mut out_size: usize = 0;
308 loop {
309 match r.read(&mut buffer[..]) {
310 Err(e) => {
311 if let io::ErrorKind::Interrupted = e.kind() {
312 continue
313 }
314 return Err(e);
315 }
316 Ok(size) => {
317 if size == 0 {
318 break;
319 } else {
320 match w.write_all(&buffer[..size]) {
321 Err(e) => {
322 if let io::ErrorKind::Interrupted = e.kind() {
323 continue
324 }
325 return Err(e);
326 }
327 Ok(_) => out_size += size,
328 }
329 }
330 }
331 }
332 }
333 Ok(out_size)
334}
335
336#[repr(C)]
337pub struct BrotliDecoderReturnInfo {
338 pub decoded_size: usize,
339 pub error_string: [u8;256],
340 pub error_code: state::BrotliDecoderErrorCode,
341 pub result: BrotliResult,
342}
343impl BrotliDecoderReturnInfo {
344 fn new<AllocU8: Allocator<u8>,
345 AllocU32: Allocator<u32>,
346 AllocHC: Allocator<HuffmanCode>>(
347 state: &BrotliState<AllocU8, AllocU32, AllocHC>,
348 result: BrotliResult,
349 output_size: usize,
350 ) -> Self {
351 let mut ret = BrotliDecoderReturnInfo{
352 result: result,
353 decoded_size: output_size,
354 error_code: decode::BrotliDecoderGetErrorCode(&state),
355 error_string: if let &Err(msg) = &state.mtf_or_error_string {
356 msg
357 } else {
358 [0u8;256]
359 },
360 };
361 if ret.error_string[0] == 0 {
362 let error_string = state::BrotliDecoderErrorStr(ret.error_code);
363 let to_copy = core::cmp::min(error_string.len(), ret.error_string.len() - 1);
364 for (dst, src) in ret.error_string[..to_copy].iter_mut().zip(error_string[..to_copy].bytes()) {
365 *dst = src;
366 }
367 }
368 ret
369 }
370}
371
372declare_stack_allocator_struct!(MemPool, 512, stack);
373
374pub fn brotli_decode_prealloc(
375 input: &[u8],
376 mut output: &mut[u8],
377 scratch_u8: &mut [u8],
378 scratch_u32: &mut [u32],
379 scratch_hc: &mut [HuffmanCode],
380) -> BrotliDecoderReturnInfo {
381 let stack_u8_allocator = MemPool::<u8>::new_allocator(scratch_u8, bzero);
382 let stack_u32_allocator = MemPool::<u32>::new_allocator(scratch_u32, bzero);
383 let stack_hc_allocator = MemPool::<HuffmanCode>::new_allocator(scratch_hc, bzero);
384 let mut available_out = output.len();
385 let mut available_in: usize = input.len();
386 let mut input_offset: usize = 0;
387 let mut output_offset: usize = 0;
388 let mut written: usize = 0;
389 let mut brotli_state =
390 BrotliState::new(stack_u8_allocator, stack_u32_allocator, stack_hc_allocator);
391 let result = ::BrotliDecompressStream(&mut available_in,
392 &mut input_offset,
393 &input[..],
394 &mut available_out,
395 &mut output_offset,
396 &mut output,
397 &mut written,
398 &mut brotli_state);
399 let return_info = BrotliDecoderReturnInfo::new(&brotli_state, result.into(), output_offset);
400 return_info
401}
402
403#[cfg(not(feature="std"))]
404pub fn brotli_decode(
405 input: &[u8],
406 output_and_scratch: &mut[u8],
407) -> BrotliDecoderReturnInfo {
408 let mut stack_u32_buffer = [0u32; 12 * 1024 * 6];
409 let mut stack_hc_buffer = [HuffmanCode::default(); 128 * (decode::kNumInsertAndCopyCodes as usize + decode::kNumLiteralCodes as usize) + 6 * decode::kNumBlockLengthCodes as usize * huffman::BROTLI_HUFFMAN_MAX_TABLE_SIZE as usize];
410 let mut guessed_output_size = core::cmp::min(
411 core::cmp::max(input.len(), output_and_scratch.len() / 3),
413 output_and_scratch.len());
414 if input.len() > 2 {
415 let scratch_len = output_and_scratch.len() - guessed_output_size;
416 if let Ok(lgwin) = decode::lg_window_size(input[0], input[1]) {
417 let extra_window_size = 65536 + (decode::kNumLiteralCodes + decode::kNumInsertAndCopyCodes) as usize * 256 + (1usize << lgwin.0) * 5 / 4;
418 if extra_window_size < scratch_len {
419 guessed_output_size += (scratch_len - extra_window_size) * 3/4;
420 }
421 }
422 }
423 let (mut output, mut scratch_space) = output_and_scratch.split_at_mut(guessed_output_size);
424 let stack_u8_allocator = MemPool::<u8>::new_allocator(&mut scratch_space, bzero);
425 let stack_u32_allocator = MemPool::<u32>::new_allocator(&mut stack_u32_buffer, bzero);
426 let stack_hc_allocator = MemPool::<HuffmanCode>::new_allocator(&mut stack_hc_buffer, bzero);
427 let mut available_out = output.len();
428 let mut available_in: usize = input.len();
429 let mut input_offset: usize = 0;
430 let mut output_offset: usize = 0;
431 let mut written: usize = 0;
432 let mut brotli_state =
433 BrotliState::new(stack_u8_allocator, stack_u32_allocator, stack_hc_allocator);
434 let result = ::BrotliDecompressStream(&mut available_in,
435 &mut input_offset,
436 &input[..],
437 &mut available_out,
438 &mut output_offset,
439 &mut output,
440 &mut written,
441 &mut brotli_state);
442 let return_info = BrotliDecoderReturnInfo::new(&brotli_state, result.into(), output_offset);
443 return_info
444}
445
446#[cfg(feature="std")]
447pub fn brotli_decode(
448 input: &[u8],
449 mut output: &mut[u8],
450) -> BrotliDecoderReturnInfo {
451 let mut available_out = output.len();
452 let mut available_in: usize = input.len();
453 let mut input_offset: usize = 0;
454 let mut output_offset: usize = 0;
455 let mut written: usize = 0;
456 let mut brotli_state =
457 BrotliState::new(StandardAlloc::default(), StandardAlloc::default(), StandardAlloc::default());
458 let result = ::BrotliDecompressStream(&mut available_in,
459 &mut input_offset,
460 &input[..],
461 &mut available_out,
462 &mut output_offset,
463 &mut output,
464 &mut written,
465 &mut brotli_state);
466 let return_info = BrotliDecoderReturnInfo::new(&brotli_state, result.into(), output_offset);
467 return_info
468}