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#[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
57pub use io_wrappers::{CustomRead, CustomWrite};
59#[cfg(feature="std")]
60pub use io_wrappers::{IntoIoReader, IoReaderWrapper, IntoIoWriter, IoWriterWrapper};
61
62pub 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 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); 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 Ok(cur_written) => {
283 assert_eq!(cur_written == 0, false); 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(), 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}