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