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