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