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#![cfg_attr(not(any(feature="unsafe", feature="ffi-api")), forbid(unsafe_code))]
13
14
15#[macro_use]
16#[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
64pub use io_wrappers::{CustomRead, CustomWrite};
66#[cfg(feature="std")]
67pub use io_wrappers::{IntoIoReader, IoReaderWrapper, IntoIoWriter, IoWriterWrapper};
68
69pub 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 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 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(), 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}