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;
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
58pub use io_wrappers::{CustomRead, CustomWrite};
60#[cfg(feature="std")]
61pub use io_wrappers::{IntoIoReader, IoReaderWrapper, IntoIoWriter, IoWriterWrapper};
62
63pub 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 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 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(), 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}