Skip to main content

brotli_decompressor/
lib.rs

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// Assert at compile time that the default build contains no unsafe code:
11// the only unsafe in this crate lives behind the "unsafe" and "ffi-api" features.
12#![cfg_attr(not(any(feature="unsafe", feature="ffi-api")), forbid(unsafe_code))]
13
14
15#[macro_use]
16// <-- for debugging, remove xprintln from bit_reader and replace with println
17#[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
61// use io_wrappers::write_all;
62pub use io_wrappers::{CustomRead, CustomWrite};
63#[cfg(feature="std")]
64pub use io_wrappers::{IntoIoReader, IoReaderWrapper, IntoIoWriter, IoWriterWrapper};
65
66// interface
67// pub fn BrotliDecompressStream(mut available_in: &mut usize,
68//                               input_offset: &mut usize,
69//                               input: &[u8],
70//                               mut available_out: &mut usize,
71//                               mut output_offset: &mut usize,
72//                               mut output: &mut [u8],
73//                               mut total_out: &mut usize,
74//                               mut s: &mut BrotliState<AllocU8, AllocU32, AllocHC>);
75
76pub 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          // this would be a call to write_all
250          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          // CustomResult::Transient(e) => continue,
288          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(), // shouldn't shrink too much
412                   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}