#![no_std] #![allow(non_snake_case)] #![allow(unused_parens)] #![allow(unused_imports)] #![allow(non_camel_case_types)] #![allow(non_snake_case)] #![allow(non_upper_case_globals)] #![cfg_attr(feature="no-stdlib-ffi-binding",cfg_attr(not(feature="std"), feature(lang_items)))] #![cfg_attr(feature="no-stdlib-ffi-binding",cfg_attr(not(feature="std"), feature(panic_handler)))] #[macro_use] // <-- for debugging, remove xprintln from bit_reader and replace with println #[cfg(feature="std")] extern crate std; #[cfg(feature="std")] use std::io::{self, Error, ErrorKind, Read, Write}; #[cfg(feature="std")] extern crate alloc_stdlib; #[macro_use] extern crate alloc_no_stdlib as alloc; pub use alloc::{AllocatedStackMemory, Allocator, SliceWrapper, SliceWrapperMut, StackAllocator, bzero}; use core::ops; #[cfg(feature="std")] pub use alloc_stdlib::StandardAlloc; #[cfg(all(feature="unsafe",feature="std"))] pub use alloc_stdlib::HeapAlloc; #[macro_use] mod memory; pub mod dictionary; mod brotli_alloc; #[macro_use] mod bit_reader; mod huffman; mod state; mod prefix; mod context; pub mod transform; mod test; mod decode; pub mod io_wrappers; pub mod reader; pub mod writer; pub use huffman::{HuffmanCode, HuffmanTreeGroup}; pub use state::BrotliState; pub mod ffi; pub use reader::{DecompressorCustomIo}; #[cfg(feature="std")] pub use reader::{Decompressor}; pub use writer::{DecompressorWriterCustomIo}; #[cfg(feature="std")] pub use writer::{DecompressorWriter}; // use io_wrappers::write_all; pub use io_wrappers::{CustomRead, CustomWrite}; #[cfg(feature="std")] pub use io_wrappers::{IntoIoReader, IoReaderWrapper, IntoIoWriter, IoWriterWrapper}; // interface // pub fn BrotliDecompressStream(mut available_in: &mut usize, // input_offset: &mut usize, // input: &[u8], // mut available_out: &mut usize, // mut output_offset: &mut usize, // mut output: &mut [u8], // mut total_out: &mut usize, // mut s: &mut BrotliState); pub use decode::{BrotliDecompressStream, BrotliResult, BrotliDecoderHasMoreOutput, BrotliDecoderIsFinished, BrotliDecoderTakeOutput}; #[cfg(not(any(feature="unsafe", not(feature="std"))))] pub fn BrotliDecompress(r: &mut InputType, w: &mut OutputType) -> Result<(), io::Error> where InputType: Read, OutputType: Write { let mut input_buffer: [u8; 4096] = [0; 4096]; let mut output_buffer: [u8; 4096] = [0; 4096]; BrotliDecompressCustomAlloc(r, w, &mut input_buffer[..], &mut output_buffer[..], StandardAlloc::default(), StandardAlloc::default(), StandardAlloc::default(), ) } #[cfg(feature="std")] pub fn BrotliDecompressCustomDict(r: &mut InputType, w: &mut OutputType, input_buffer:&mut [u8], output_buffer:&mut [u8], custom_dictionary:std::vec::Vec) -> Result<(), io::Error> where InputType: Read, OutputType: Write { let mut alloc_u8 = brotli_alloc::BrotliAlloc::::new(); let mut input_buffer_backing; let mut output_buffer_backing; { let mut borrowed_input_buffer = input_buffer; let mut borrowed_output_buffer = output_buffer; if borrowed_input_buffer.len() == 0 { input_buffer_backing = alloc_u8.alloc_cell(4096); borrowed_input_buffer = input_buffer_backing.slice_mut(); } if borrowed_output_buffer.len() == 0 { output_buffer_backing = alloc_u8.alloc_cell(4096); borrowed_output_buffer = output_buffer_backing.slice_mut(); } let dict = alloc_u8.take_ownership(custom_dictionary); BrotliDecompressCustomIoCustomDict(&mut IoReaderWrapper::(r), &mut IoWriterWrapper::(w), borrowed_input_buffer, borrowed_output_buffer, alloc_u8, brotli_alloc::BrotliAlloc::::new(), brotli_alloc::BrotliAlloc::::new(), dict, Error::new(ErrorKind::UnexpectedEof, "Unexpected EOF")) } } #[cfg(all(feature="unsafe",feature="std"))] pub fn BrotliDecompress(r: &mut InputType, w: &mut OutputType) -> Result<(), io::Error> where InputType: Read, OutputType: Write { let mut input_buffer: [u8; 4096] = [0; 4096]; let mut output_buffer: [u8; 4096] = [0; 4096]; BrotliDecompressCustomAlloc(r, w, &mut input_buffer[..], &mut output_buffer[..], HeapAlloc::::new(0), HeapAlloc::::new(0), HeapAlloc::::new(HuffmanCode{ bits:2, value: 1})) } #[cfg(feature="std")] pub fn BrotliDecompressCustomAlloc, AllocU32: Allocator, AllocHC: Allocator> (r: &mut InputType, w: &mut OutputType, input_buffer: &mut [u8], output_buffer: &mut [u8], alloc_u8: AllocU8, alloc_u32: AllocU32, alloc_hc: AllocHC) -> Result<(), io::Error> where InputType: Read, OutputType: Write { BrotliDecompressCustomIo(&mut IoReaderWrapper::(r), &mut IoWriterWrapper::(w), input_buffer, output_buffer, alloc_u8, alloc_u32, alloc_hc, Error::new(ErrorKind::UnexpectedEof, "Unexpected EOF")) } pub fn BrotliDecompressCustomIo, AllocU32: Allocator, AllocHC: Allocator> (r: &mut InputType, w: &mut OutputType, input_buffer: &mut [u8], output_buffer: &mut [u8], alloc_u8: AllocU8, alloc_u32: AllocU32, alloc_hc: AllocHC, unexpected_eof_error_constant: ErrType) -> Result<(), ErrType> where InputType: CustomRead, OutputType: CustomWrite { BrotliDecompressCustomIoCustomDict(r, w, input_buffer, output_buffer, alloc_u8, alloc_u32, alloc_hc, AllocU8::AllocatedMemory::default(), unexpected_eof_error_constant) } pub fn BrotliDecompressCustomIoCustomDict, AllocU32: Allocator, AllocHC: Allocator> (r: &mut InputType, w: &mut OutputType, input_buffer: &mut [u8], output_buffer: &mut [u8], alloc_u8: AllocU8, alloc_u32: AllocU32, alloc_hc: AllocHC, custom_dictionary: AllocU8::AllocatedMemory, unexpected_eof_error_constant: ErrType) -> Result<(), ErrType> where InputType: CustomRead, OutputType: CustomWrite { let mut brotli_state = BrotliState::new_with_custom_dictionary(alloc_u8, alloc_u32, alloc_hc, custom_dictionary); assert!(input_buffer.len() != 0); assert!(output_buffer.len() != 0); let mut available_out: usize = output_buffer.len(); let mut available_in: usize = 0; let mut input_offset: usize = 0; let mut output_offset: usize = 0; let mut result: BrotliResult = BrotliResult::NeedsMoreInput; loop { match result { BrotliResult::NeedsMoreInput => { input_offset = 0; match r.read(input_buffer) { Err(e) => { return Err(e); }, Ok(size) => { if size == 0 { return Err(unexpected_eof_error_constant); } available_in = size; } } } BrotliResult::NeedsMoreOutput => { let mut total_written: usize = 0; while total_written < output_offset { // this would be a call to write_all match w.write(&output_buffer[total_written..output_offset]) { Err(e) => { return Result::Err(e); }, Ok(cur_written) => { assert_eq!(cur_written == 0, false); // not allowed by the contract total_written += cur_written; } } } output_offset = 0; } BrotliResult::ResultSuccess => break, BrotliResult::ResultFailure => { return Err(unexpected_eof_error_constant); } } let mut written: usize = 0; result = BrotliDecompressStream(&mut available_in, &mut input_offset, input_buffer, &mut available_out, &mut output_offset, output_buffer, &mut written, &mut brotli_state); if output_offset != 0 { let mut total_written: usize = 0; while total_written < output_offset { match w.write(&output_buffer[total_written..output_offset]) { Err(e) => { return Result::Err(e); }, // CustomResult::Transient(e) => continue, Ok(cur_written) => { assert_eq!(cur_written == 0, false); // not allowed by the contract total_written += cur_written; } } } output_offset = 0; available_out = output_buffer.len() } } Ok(()) } #[cfg(feature="std")] pub fn copy_from_to(mut r: R, mut w: W) -> io::Result { let mut buffer: [u8; 65536] = [0; 65536]; let mut out_size: usize = 0; loop { match r.read(&mut buffer[..]) { Err(e) => { if let io::ErrorKind::Interrupted = e.kind() { continue } return Err(e); } Ok(size) => { if size == 0 { break; } else { match w.write_all(&buffer[..size]) { Err(e) => { if let io::ErrorKind::Interrupted = e.kind() { continue } return Err(e); } Ok(_) => out_size += size, } } } } } Ok(out_size) } #[repr(C)] pub struct BrotliDecoderReturnInfo { pub decoded_size: usize, pub error_string: [u8;256], pub error_code: state::BrotliDecoderErrorCode, pub result: BrotliResult, } impl BrotliDecoderReturnInfo { fn new, AllocU32: Allocator, AllocHC: Allocator>( state: &BrotliState, result: BrotliResult, output_size: usize, ) -> Self { let mut ret = BrotliDecoderReturnInfo{ result: result, decoded_size: output_size, error_code: decode::BrotliDecoderGetErrorCode(&state), error_string: if let &Err(msg) = &state.mtf_or_error_string { msg } else { [0u8;256] }, }; if ret.error_string[0] == 0 { let error_string = state::BrotliDecoderErrorStr(ret.error_code); let to_copy = core::cmp::min(error_string.len(), ret.error_string.len() - 1); for (dst, src) in ret.error_string[..to_copy].iter_mut().zip(error_string[..to_copy].bytes()) { *dst = src; } } ret } } declare_stack_allocator_struct!(MemPool, 512, stack); pub fn brotli_decode_prealloc( input: &[u8], mut output: &mut[u8], scratch_u8: &mut [u8], scratch_u32: &mut [u32], scratch_hc: &mut [HuffmanCode], ) -> BrotliDecoderReturnInfo { let stack_u8_allocator = MemPool::::new_allocator(scratch_u8, bzero); let stack_u32_allocator = MemPool::::new_allocator(scratch_u32, bzero); let stack_hc_allocator = MemPool::::new_allocator(scratch_hc, bzero); let mut available_out = output.len(); let mut available_in: usize = input.len(); let mut input_offset: usize = 0; let mut output_offset: usize = 0; let mut written: usize = 0; let mut brotli_state = BrotliState::new(stack_u8_allocator, stack_u32_allocator, stack_hc_allocator); let result = ::BrotliDecompressStream(&mut available_in, &mut input_offset, &input[..], &mut available_out, &mut output_offset, &mut output, &mut written, &mut brotli_state); let return_info = BrotliDecoderReturnInfo::new(&brotli_state, result.into(), output_offset); return_info } #[cfg(not(feature="std"))] pub fn brotli_decode( input: &[u8], output_and_scratch: &mut[u8], ) -> BrotliDecoderReturnInfo { let mut stack_u32_buffer = [0u32; 12 * 1024 * 6]; 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]; let mut guessed_output_size = core::cmp::min( core::cmp::max(input.len(), // shouldn't shrink too much output_and_scratch.len() / 3), output_and_scratch.len()); if input.len() > 2 { let scratch_len = output_and_scratch.len() - guessed_output_size; if let Ok(lgwin) = decode::lg_window_size(input[0], input[1]) { let extra_window_size = 65536 + (decode::kNumLiteralCodes + decode::kNumInsertAndCopyCodes) as usize * 256 + (1usize << lgwin.0) * 5 / 4; if extra_window_size < scratch_len { guessed_output_size += (scratch_len - extra_window_size) * 3/4; } } } let (mut output, mut scratch_space) = output_and_scratch.split_at_mut(guessed_output_size); let stack_u8_allocator = MemPool::::new_allocator(&mut scratch_space, bzero); let stack_u32_allocator = MemPool::::new_allocator(&mut stack_u32_buffer, bzero); let stack_hc_allocator = MemPool::::new_allocator(&mut stack_hc_buffer, bzero); let mut available_out = output.len(); let mut available_in: usize = input.len(); let mut input_offset: usize = 0; let mut output_offset: usize = 0; let mut written: usize = 0; let mut brotli_state = BrotliState::new(stack_u8_allocator, stack_u32_allocator, stack_hc_allocator); let result = ::BrotliDecompressStream(&mut available_in, &mut input_offset, &input[..], &mut available_out, &mut output_offset, &mut output, &mut written, &mut brotli_state); let return_info = BrotliDecoderReturnInfo::new(&brotli_state, result.into(), output_offset); return_info } #[cfg(feature="std")] pub fn brotli_decode( input: &[u8], mut output: &mut[u8], ) -> BrotliDecoderReturnInfo { let mut available_out = output.len(); let mut available_in: usize = input.len(); let mut input_offset: usize = 0; let mut output_offset: usize = 0; let mut written: usize = 0; let mut brotli_state = BrotliState::new(StandardAlloc::default(), StandardAlloc::default(), StandardAlloc::default()); let result = ::BrotliDecompressStream(&mut available_in, &mut input_offset, &input[..], &mut available_out, &mut output_offset, &mut output, &mut written, &mut brotli_state); let return_info = BrotliDecoderReturnInfo::new(&brotli_state, result.into(), output_offset); return_info }