Coverage Report

Created: 2026-10-28 06:43

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