Skip to main content

brotli_decompressor/
state.rs

1#![allow(non_camel_case_types)]
2#![allow(non_snake_case)]
3#![allow(non_upper_case_globals)]
4
5
6use alloc;
7use core;
8use context::kContextLookup;
9use bit_reader::{BrotliBitReader, BrotliGetAvailableBits, BrotliInitBitReader};
10use huffman::{BROTLI_HUFFMAN_MAX_CODE_LENGTH, BROTLI_HUFFMAN_MAX_CODE_LENGTHS_SIZE,
11              BROTLI_HUFFMAN_MAX_TABLE_SIZE, HuffmanCode, HuffmanTreeGroup};
12use alloc::SliceWrapper;
13use alloc::SliceWrapperMut;
14use shared_dictionary;
15use shared_dictionary::{BrotliSharedDictionary, TRANSFORM_LIST_STRIDE, WORD_LIST_STRIDE};
16
17#[allow(dead_code)]
18pub enum WhichTreeGroup {
19  LITERAL,
20  INSERT_COPY,
21  DISTANCE,
22}
23#[repr(C)]
24#[derive(Clone,Copy, Debug)]
25pub enum BrotliDecoderErrorCode{
26  BROTLI_DECODER_NO_ERROR = 0,
27  /* Same as BrotliDecoderResult values */
28  BROTLI_DECODER_SUCCESS = 1,
29  BROTLI_DECODER_NEEDS_MORE_INPUT = 2,
30  BROTLI_DECODER_NEEDS_MORE_OUTPUT = 3,
31
32  /* Errors caused by invalid input */
33  BROTLI_DECODER_ERROR_FORMAT_EXUBERANT_NIBBLE = -1,
34  BROTLI_DECODER_ERROR_FORMAT_RESERVED = -2,
35  BROTLI_DECODER_ERROR_FORMAT_EXUBERANT_META_NIBBLE = -3,
36  BROTLI_DECODER_ERROR_FORMAT_SIMPLE_HUFFMAN_ALPHABET = -4,
37  BROTLI_DECODER_ERROR_FORMAT_SIMPLE_HUFFMAN_SAME = -5,
38  BROTLI_DECODER_ERROR_FORMAT_CL_SPACE = -6,
39  BROTLI_DECODER_ERROR_FORMAT_HUFFMAN_SPACE = -7,
40  BROTLI_DECODER_ERROR_FORMAT_CONTEXT_MAP_REPEAT = -8,
41  BROTLI_DECODER_ERROR_FORMAT_BLOCK_LENGTH_1 = -9,
42  BROTLI_DECODER_ERROR_FORMAT_BLOCK_LENGTH_2 = -10,
43  BROTLI_DECODER_ERROR_FORMAT_TRANSFORM = -11,
44  BROTLI_DECODER_ERROR_FORMAT_DICTIONARY = -12,
45  BROTLI_DECODER_ERROR_FORMAT_WINDOW_BITS = -13,
46  BROTLI_DECODER_ERROR_FORMAT_PADDING_1 = -14,
47  BROTLI_DECODER_ERROR_FORMAT_PADDING_2 = -15,
48  BROTLI_DECODER_ERROR_FORMAT_DISTANCE = -16,
49
50  /* -17 code is reserved */
51
52  BROTLI_DECODER_ERROR_COMPOUND_DICTIONARY = -18,
53  BROTLI_DECODER_ERROR_DICTIONARY_NOT_SET = -19,
54  BROTLI_DECODER_ERROR_INVALID_ARGUMENTS = -20,
55
56  /* Memory allocation problems */
57  BROTLI_DECODER_ERROR_ALLOC_CONTEXT_MODES = -21,
58  /* Literal = insert and distance trees together */
59  BROTLI_DECODER_ERROR_ALLOC_TREE_GROUPS = -22,
60  /* -23..-24 codes are reserved for distinct tree groups */
61  BROTLI_DECODER_ERROR_ALLOC_CONTEXT_MAP = -25,
62  BROTLI_DECODER_ERROR_ALLOC_RING_BUFFER_1 = -26,
63  BROTLI_DECODER_ERROR_ALLOC_RING_BUFFER_2 = -27,
64  /* -28..-29 codes are reserved for dynamic ring-buffer allocation */
65  BROTLI_DECODER_ERROR_ALLOC_BLOCK_TYPE_TREES = -30,
66
67  /* "Impossible" states */
68  BROTLI_DECODER_ERROR_UNREACHABLE = -31,
69}
70
71#[derive(Debug)]
72pub enum BrotliRunningState {
73  BROTLI_STATE_UNINITED,
74  BROTLI_STATE_LARGE_WINDOW_BITS,
75  BROTLI_STATE_INITIALIZE,
76  BROTLI_STATE_METABLOCK_BEGIN,
77  BROTLI_STATE_METABLOCK_HEADER,
78  BROTLI_STATE_METABLOCK_HEADER_2,
79  BROTLI_STATE_CONTEXT_MODES,
80  BROTLI_STATE_COMMAND_BEGIN,
81  BROTLI_STATE_COMMAND_INNER,
82  BROTLI_STATE_COMMAND_POST_DECODE_LITERALS,
83  BROTLI_STATE_COMMAND_POST_WRAP_COPY,
84  BROTLI_STATE_UNCOMPRESSED,
85  BROTLI_STATE_METADATA,
86  BROTLI_STATE_COMMAND_INNER_WRITE,
87  BROTLI_STATE_METABLOCK_DONE,
88  BROTLI_STATE_COMMAND_POST_WRITE_1,
89  BROTLI_STATE_COMMAND_POST_WRITE_2,
90  BROTLI_STATE_HUFFMAN_CODE_0,
91  BROTLI_STATE_HUFFMAN_CODE_1,
92  BROTLI_STATE_HUFFMAN_CODE_2,
93  BROTLI_STATE_HUFFMAN_CODE_3,
94  BROTLI_STATE_CONTEXT_MAP_1,
95  BROTLI_STATE_CONTEXT_MAP_2,
96  BROTLI_STATE_TREE_GROUP,
97  BROTLI_STATE_DONE,
98}
99
100pub enum BrotliRunningMetablockHeaderState {
101  BROTLI_STATE_METABLOCK_HEADER_NONE,
102  BROTLI_STATE_METABLOCK_HEADER_EMPTY,
103  BROTLI_STATE_METABLOCK_HEADER_NIBBLES,
104  BROTLI_STATE_METABLOCK_HEADER_SIZE,
105  BROTLI_STATE_METABLOCK_HEADER_UNCOMPRESSED,
106  BROTLI_STATE_METABLOCK_HEADER_RESERVED,
107  BROTLI_STATE_METABLOCK_HEADER_BYTES,
108  BROTLI_STATE_METABLOCK_HEADER_METADATA,
109}
110pub enum BrotliRunningUncompressedState {
111  BROTLI_STATE_UNCOMPRESSED_NONE,
112  BROTLI_STATE_UNCOMPRESSED_WRITE,
113}
114
115pub enum BrotliRunningTreeGroupState {
116  BROTLI_STATE_TREE_GROUP_NONE,
117  BROTLI_STATE_TREE_GROUP_LOOP,
118}
119
120pub enum BrotliRunningContextMapState {
121  BROTLI_STATE_CONTEXT_MAP_NONE,
122  BROTLI_STATE_CONTEXT_MAP_READ_PREFIX,
123  BROTLI_STATE_CONTEXT_MAP_HUFFMAN,
124  BROTLI_STATE_CONTEXT_MAP_DECODE,
125  BROTLI_STATE_CONTEXT_MAP_TRANSFORM,
126}
127
128pub enum BrotliRunningHuffmanState {
129  BROTLI_STATE_HUFFMAN_NONE,
130  BROTLI_STATE_HUFFMAN_SIMPLE_SIZE,
131  BROTLI_STATE_HUFFMAN_SIMPLE_READ,
132  BROTLI_STATE_HUFFMAN_SIMPLE_BUILD,
133  BROTLI_STATE_HUFFMAN_COMPLEX,
134  BROTLI_STATE_HUFFMAN_LENGTH_SYMBOLS,
135}
136
137pub enum BrotliRunningDecodeUint8State {
138  BROTLI_STATE_DECODE_UINT8_NONE,
139  BROTLI_STATE_DECODE_UINT8_SHORT,
140  BROTLI_STATE_DECODE_UINT8_LONG,
141}
142
143pub enum BrotliRunningReadBlockLengthState {
144  BROTLI_STATE_READ_BLOCK_LENGTH_NONE,
145  BROTLI_STATE_READ_BLOCK_LENGTH_SUFFIX,
146}
147
148pub const kLiteralContextBits: usize = 6;
149
150// Maximum number of compound dictionary chunks that may be attached to a
151// decoder instance, per the shared-brotli draft
152// (https://datatracker.ietf.org/doc/draft-vandevenne-shared-brotli-format/).
153pub const SHARED_BROTLI_MAX_COMPOUND_DICTS: usize = 15;
154// Practical limit for the total size of attached raw dictionaries; matches
155// SHARED_BROTLI_MAX_RAW_DICT_SIZE in the C implementation.
156#[cfg(target_pointer_width = "64")]
157pub const SHARED_BROTLI_MAX_RAW_DICT_SIZE: usize = 1usize << 31;
158#[cfg(not(target_pointer_width = "64"))]
159pub const SHARED_BROTLI_MAX_RAW_DICT_SIZE: usize = 1usize << 27;
160
161// Backing store for an attached dictionary: either memory this decoder owns
162// (allocated through AllocU8, freed on cleanup) or memory the caller owns and
163// has promised to keep alive and unmodified for as long as the decoder lives.
164//
165// The borrowed variant exists so that the FFI can honor the C API's contract
166// -- "Attached dictionary ownership is not transferred. Data provided to this
167// method should be kept accessible until decoding is finished and decoder
168// instance is destroyed." (c/include/brotli/decode.h) -- which lets many
169// decoder instances share one dictionary image at zero marginal cost instead
170// of each holding a private copy.
171#[allow(dead_code)]
172pub enum MaybeOwnedSlice<AllocU8: alloc::Allocator<u8>> {
173  Owned(AllocU8::AllocatedMemory),
174  // The 'static here is a lie maintained by the unsafe constructors below:
175  // the referent only has to outlive the BrotliState that holds it. It is
176  // spelled 'static rather than as a raw pointer so that BrotliState keeps
177  // its automatic Send/Sync.
178  Borrowed(&'static [u8]),
179}
180
181impl<AllocU8: alloc::Allocator<u8>> Default for MaybeOwnedSlice<AllocU8> {
182  fn default() -> Self {
183    MaybeOwnedSlice::Owned(AllocU8::AllocatedMemory::default())
184  }
185}
186
187impl<AllocU8: alloc::Allocator<u8>> alloc::SliceWrapper<u8> for MaybeOwnedSlice<AllocU8> {
188  fn slice(&self) -> &[u8] {
189    match *self {
190      MaybeOwnedSlice::Owned(ref mem) => mem.slice(),
191      MaybeOwnedSlice::Borrowed(data) => data,
192    }
193  }
194}
195
196// Sentinel stored in BrotliDecoderCompoundDictionary::block_bits while the
197// block map is stale, i.e. a marker rather than a shift amount. Real shift
198// amounts computed by EnsureCompoundDictionaryInitialized are in 0..=23
199// (total_size is capped at SHARED_BROTLI_MAX_RAW_DICT_SIZE), so this value can
200// never collide with one. The C implementation uses -1 for the same purpose;
201// the field is unsigned here.
202pub const COMPOUND_DICTIONARY_BLOCK_MAP_UNINITIALIZED: u32 = 255;
203
204// LZ77 prefix ("compound") dictionaries attached to the decoder. Unlike the
205// historical approach of copying the dictionary into the ring buffer, chunks
206// are kept in their own buffers and referenced by backward distances in
207// (max_distance, max_distance + total_size], so they stay addressable even
208// after the ring buffer wraps (issue #42).
209pub struct BrotliDecoderCompoundDictionary<AllocU8: alloc::Allocator<u8>> {
210  pub num_chunks: usize,
211  pub total_size: usize,
212  // Map from address >> block_bits to the first chunk that might contain that
213  // address; COMPOUND_DICTIONARY_BLOCK_MAP_UNINITIALIZED means "not yet
214  // computed".
215  pub block_bits: u32,
216  pub block_map: [u8; 256],
217  // chunk_offsets[i] is the address of the first byte of chunk i;
218  // chunk_offsets[num_chunks] == total_size.
219  pub chunk_offsets: [u32; SHARED_BROTLI_MAX_COMPOUND_DICTS + 1],
220  pub chunks: [MaybeOwnedSlice<AllocU8>; SHARED_BROTLI_MAX_COMPOUND_DICTS],
221  // Cursor for an in-progress copy from the dictionary into the ring buffer:
222  // a single copy command may be interrupted to flush the ring buffer.
223  pub br_index: usize,
224  pub br_offset: usize,
225  pub br_length: usize,
226  pub br_copied: usize,
227}
228
229impl<AllocU8: alloc::Allocator<u8>> Default for BrotliDecoderCompoundDictionary<AllocU8> {
230  fn default() -> Self {
231    BrotliDecoderCompoundDictionary::<AllocU8> {
232      num_chunks: 0,
233      total_size: 0,
234      block_bits: COMPOUND_DICTIONARY_BLOCK_MAP_UNINITIALIZED,
235      block_map: [0; 256],
236      chunk_offsets: [0; SHARED_BROTLI_MAX_COMPOUND_DICTS + 1],
237      chunks: Default::default(),
238      br_index: 0,
239      br_offset: 0,
240      br_length: 0,
241      br_copied: 0,
242    }
243  }
244}
245
246pub struct BlockTypeAndLengthState<AllocHC: alloc::Allocator<HuffmanCode>> {
247  pub substate_read_block_length: BrotliRunningReadBlockLengthState,
248  pub num_block_types: [u32; 3],
249  pub block_length_index: u32,
250  pub block_length: [u32; 3],
251  pub block_type_trees: AllocHC::AllocatedMemory,
252  pub block_len_trees: AllocHC::AllocatedMemory,
253  pub block_type_rb: [u32; 6],
254}
255
256pub struct BrotliState<AllocU8: alloc::Allocator<u8>,
257                       AllocU32: alloc::Allocator<u32>,
258                       AllocHC: alloc::Allocator<HuffmanCode>>
259{
260  pub state: BrotliRunningState,
261
262  // This counter is reused for several disjoint loops.
263  pub loop_counter: i32,
264  pub br: BrotliBitReader,
265  pub alloc_u8: AllocU8,
266  pub alloc_u32: AllocU32,
267  pub alloc_hc: AllocHC,
268  // void* memory_manager_opaque,
269  pub buffer: [u8; 8],
270  pub buffer_length: u32,
271  pub pos: i32,
272  pub max_backward_distance: i32,
273  pub max_distance: i32,
274  pub ringbuffer_size: i32,
275  pub ringbuffer_mask: i32,
276  pub dist_rb_idx: i32,
277  pub dist_rb: [i32; 4],
278  pub ringbuffer: AllocU8::AllocatedMemory,
279  // pub ringbuffer_end : usize,
280  pub htree_command_index: u16,
281  pub context_lookup: &'static [u8;512],
282  pub context_map_slice_index: usize,
283  pub dist_context_map_slice_index: usize,
284
285  pub sub_loop_counter: u32,
286
287  // This ring buffer holds a few past copy distances that will be used by */
288  // some special distance codes.
289  pub literal_hgroup: HuffmanTreeGroup<AllocU32, AllocHC>,
290  pub insert_copy_hgroup: HuffmanTreeGroup<AllocU32, AllocHC>,
291  pub distance_hgroup: HuffmanTreeGroup<AllocU32, AllocHC>,
292  // This is true if the literal context map histogram type always matches the
293  // block type. It is then not needed to keep the context (faster decoding).
294  pub trivial_literal_context: i32,
295  // Distance context is actual after command is decoded and before distance
296  // is computed. After distance computation it is used as a temporary variable
297  pub distance_context: i32,
298  pub meta_block_remaining_len: i32,
299  pub block_type_length_state: BlockTypeAndLengthState<AllocHC>,
300  pub distance_postfix_bits: u32,
301  pub num_direct_distance_codes: u32,
302  pub distance_postfix_mask: i32,
303  pub num_dist_htrees: u32,
304  pub dist_context_map: AllocU8::AllocatedMemory,
305  // NOT NEEDED? the index below seems to supersede it pub literal_htree : AllocHC::AllocatedMemory,
306  pub literal_htree_index: u8,
307  pub dist_htree_index: u8,
308  pub large_window: bool,
309  pub(crate) canny_ringbuffer_allocation: bool,
310  pub should_wrap_ringbuffer: bool,
311  pub error_code: BrotliDecoderErrorCode,
312  pub repeat_code_len: u32,
313  pub prev_code_len: u32,
314
315  pub copy_length: i32,
316  pub distance_code: i32,
317
318  // For partial write operations
319  // u64, not usize: as usize these would wrap after 4GiB of output on a 32-bit
320  // target, and WriteRingBuffer works from their difference.
321  pub rb_roundtrips: u64, // How many times we went around the ringbuffer
322  pub partial_pos_out: u64, // How much output to the user in total (<= rb)
323
324  // For ReadHuffmanCode
325  pub symbol: u32,
326  pub repeat: u32,
327  pub space: u32,
328
329  pub table: [HuffmanCode; 32],
330  // List of of symbol chains.
331  pub symbol_lists_index: usize, // AllocU16::AllocatedMemory,
332  // Storage from symbol_lists.
333  pub symbols_lists_array: [u16; BROTLI_HUFFMAN_MAX_CODE_LENGTH + 1 +
334                                 BROTLI_HUFFMAN_MAX_CODE_LENGTHS_SIZE],
335  // Tails of symbol chains.
336  pub next_symbol: [i32; 32],
337  pub code_length_code_lengths: [u8; 18],
338  // Population counts for the code lengths
339  pub code_length_histo: [u16; 16],
340
341  // For HuffmanTreeGroupDecode
342  pub htree_index: i32,
343  pub htree_next_offset: u32,
344
345  // For DecodeContextMap
346  pub context_index: u32,
347  pub max_run_length_prefix: u32,
348  pub code: u32,
349  // always pre-allocated on state creation
350  pub context_map_table: AllocHC::AllocatedMemory,
351
352  // For InverseMoveToFrontTransform
353  pub mtf_upper_bound: u32,
354  pub mtf_or_error_string: Result<[u8; 256], [u8; 256]>,
355
356  // For custom dictionaries
357  pub custom_dict: AllocU8::AllocatedMemory,
358  pub compound_dictionary: BrotliDecoderCompoundDictionary<AllocU8>,
359  // Custom word/transform lists from an attached serialized shared
360  // dictionary; selects the built-in static dictionary when empty.
361  pub dictionary: BrotliSharedDictionary<AllocU8, AllocU32>,
362  // less used attributes are in the end of this struct */
363  // States inside function calls
364  pub substate_metablock_header: BrotliRunningMetablockHeaderState,
365  pub substate_tree_group: BrotliRunningTreeGroupState,
366  pub substate_context_map: BrotliRunningContextMapState,
367  pub substate_uncompressed: BrotliRunningUncompressedState,
368  pub substate_huffman: BrotliRunningHuffmanState,
369  pub substate_decode_uint8: BrotliRunningDecodeUint8State,
370
371  pub is_last_metablock: u8,
372  pub is_uncompressed: u8,
373  pub is_metadata: u8,
374  pub size_nibbles: u8,
375  pub window_bits: u32,
376
377  pub num_literal_htrees: u32,
378  pub context_map: AllocU8::AllocatedMemory,
379  pub context_modes: AllocU8::AllocatedMemory,
380  pub trivial_literal_contexts: [u32; 8],
381}
382macro_rules! make_brotli_state {
383 ($alloc_u8 : expr, $alloc_u32 : expr, $alloc_hc : expr, $custom_dict : expr) => (BrotliState::<AllocU8, AllocU32, AllocHC>{
384            state : BrotliRunningState::BROTLI_STATE_UNINITED,
385            loop_counter : 0,
386            br : BrotliBitReader::default(),
387            alloc_u8 : $alloc_u8,
388            alloc_u32 : $alloc_u32,
389            alloc_hc : $alloc_hc,
390            buffer : [0u8; 8],
391            buffer_length : 0,
392            pos : 0,
393            max_backward_distance : 0,
394            max_distance : 0,
395            ringbuffer_size : 0,
396            ringbuffer_mask: 0,
397            dist_rb_idx : 0,
398            dist_rb : [16, 15, 11, 4],
399            ringbuffer : AllocU8::AllocatedMemory::default(),
400            htree_command_index : 0,
401            context_lookup : &kContextLookup[0],
402            context_map_slice_index : 0,
403            dist_context_map_slice_index : 0,
404            sub_loop_counter : 0,
405
406            literal_hgroup : HuffmanTreeGroup::<AllocU32, AllocHC>::default(),
407            insert_copy_hgroup : HuffmanTreeGroup::<AllocU32, AllocHC>::default(),
408            distance_hgroup : HuffmanTreeGroup::<AllocU32, AllocHC>::default(),
409            trivial_literal_context : 0,
410            distance_context : 0,
411            meta_block_remaining_len : 0,
412            block_type_length_state : BlockTypeAndLengthState::<AllocHC> {
413              block_length_index : 0,
414              block_length : [0; 3],
415              num_block_types : [0;3],
416              block_type_rb: [0;6],
417              substate_read_block_length : BrotliRunningReadBlockLengthState::BROTLI_STATE_READ_BLOCK_LENGTH_NONE,
418              block_type_trees : AllocHC::AllocatedMemory::default(),
419              block_len_trees : AllocHC::AllocatedMemory::default(),
420            },
421            distance_postfix_bits : 0,
422            num_direct_distance_codes : 0,
423            distance_postfix_mask : 0,
424            num_dist_htrees : 0,
425            dist_context_map : AllocU8::AllocatedMemory::default(),
426            //// not needed literal_htree : AllocHC::AllocatedMemory::default(),
427            literal_htree_index : 0,
428            dist_htree_index : 0,
429            repeat_code_len : 0,
430            prev_code_len : 0,
431            copy_length : 0,
432            distance_code : 0,
433            rb_roundtrips : 0,  /* How many times we went around the ringbuffer */
434            partial_pos_out : 0,  /* How much output to the user in total (<= rb) */
435            symbol : 0,
436            repeat : 0,
437            space : 0,
438            table : [HuffmanCode::default(); 32],
439            //symbol_lists: AllocU16::AllocatedMemory::default(),
440            symbol_lists_index : BROTLI_HUFFMAN_MAX_CODE_LENGTH + 1,
441            symbols_lists_array : [0;BROTLI_HUFFMAN_MAX_CODE_LENGTH + 1 +
442                              BROTLI_HUFFMAN_MAX_CODE_LENGTHS_SIZE],
443            next_symbol : [0; 32],
444            code_length_code_lengths : [0; 18],
445            code_length_histo : [0; 16],
446            htree_index : 0,
447            htree_next_offset : 0,
448
449            /* For DecodeContextMap */
450           context_index : 0,
451           max_run_length_prefix : 0,
452           code : 0,
453           context_map_table : AllocHC::AllocatedMemory::default(),
454
455           /* For InverseMoveToFrontTransform */
456           mtf_upper_bound : 255,
457           mtf_or_error_string : Ok([0; 256]),
458
459           /* For custom dictionaries */
460           custom_dict : $custom_dict,
461           compound_dictionary : BrotliDecoderCompoundDictionary::default(),
462           dictionary : BrotliSharedDictionary::default(),
463           /* less used attributes are in the end of this struct */
464           /* States inside function calls */
465           substate_metablock_header : BrotliRunningMetablockHeaderState::BROTLI_STATE_METABLOCK_HEADER_NONE,
466           substate_tree_group : BrotliRunningTreeGroupState::BROTLI_STATE_TREE_GROUP_NONE,
467           substate_context_map : BrotliRunningContextMapState::BROTLI_STATE_CONTEXT_MAP_NONE,
468           substate_uncompressed : BrotliRunningUncompressedState::BROTLI_STATE_UNCOMPRESSED_NONE,
469           substate_huffman : BrotliRunningHuffmanState::BROTLI_STATE_HUFFMAN_NONE,
470           substate_decode_uint8 : BrotliRunningDecodeUint8State::BROTLI_STATE_DECODE_UINT8_NONE,
471
472           is_last_metablock : 0,
473           is_uncompressed : 0,
474           is_metadata : 0,
475           size_nibbles : 0,
476           window_bits : 0,
477           large_window: false,
478           canny_ringbuffer_allocation: true,
479           should_wrap_ringbuffer: false,
480           error_code: BrotliDecoderErrorCode::BROTLI_DECODER_SUCCESS,
481           num_literal_htrees : 0,
482           context_map : AllocU8::AllocatedMemory::default(),
483           context_modes : AllocU8::AllocatedMemory::default(),
484           trivial_literal_contexts : [0u32; 8],
485        }
486    );
487}
488impl <'brotli_state,
489      AllocU8 : alloc::Allocator<u8>,
490      AllocU32 : alloc::Allocator<u32>,
491      AllocHC : alloc::Allocator<HuffmanCode> > BrotliState<AllocU8, AllocU32, AllocHC> {
492    pub fn new(alloc_u8 : AllocU8,
493           alloc_u32 : AllocU32,
494           alloc_hc : AllocHC) -> Self{
495        let mut retval = make_brotli_state!(alloc_u8, alloc_u32, alloc_hc, AllocU8::AllocatedMemory::default());
496        retval.large_window = true;
497        retval.context_map_table = retval.alloc_hc.alloc_cell(
498          BROTLI_HUFFMAN_MAX_TABLE_SIZE as usize);
499        BrotliInitBitReader(&mut retval.br);
500        retval
501    }
502    pub fn new_with_custom_dictionary(alloc_u8 : AllocU8,
503           alloc_u32 : AllocU32,
504           alloc_hc : AllocHC,
505           custom_dict: AllocU8::AllocatedMemory) -> Self{
506        let custom_dict_len = custom_dict.slice().len();
507        let mut retval = make_brotli_state!(alloc_u8, alloc_u32, alloc_hc, custom_dict);
508        retval.context_map_table = retval.alloc_hc.alloc_cell(
509          BROTLI_HUFFMAN_MAX_TABLE_SIZE as usize);
510        retval.large_window =  true;
511        BrotliInitBitReader(&mut retval.br);
512        // The dictionary becomes the furthest compound dictionary chunk;
513        // any subsequently attach_dictionary'd ones are nearer in distance
514        // space.
515        if custom_dict_len != 0 && custom_dict_len <= SHARED_BROTLI_MAX_RAW_DICT_SIZE {
516            let dict = core::mem::replace(&mut retval.custom_dict,
517                                          AllocU8::AllocatedMemory::default());
518            // A fresh state has no chunks, so the size check above makes this
519            // infallible. Oversized dictionaries remain in `custom_dict` and
520            // are rejected through the normal decoder error path at startup.
521            let attached = retval.attach_compound_dictionary_chunk(MaybeOwnedSlice::Owned(dict));
522            debug_assert!(attached);
523        }
524        retval
525    }
526    pub fn new_strict(alloc_u8 : AllocU8,
527           alloc_u32 : AllocU32,
528           alloc_hc : AllocHC) -> Self{
529        let mut retval = make_brotli_state!(alloc_u8, alloc_u32, alloc_hc, AllocU8::AllocatedMemory::default());
530        retval.context_map_table = retval.alloc_hc.alloc_cell(
531          BROTLI_HUFFMAN_MAX_TABLE_SIZE as usize);
532        retval.large_window =  false;
533        BrotliInitBitReader(&mut retval.br);
534        retval
535    }
536    // Attaches a raw LZ77 prefix dictionary, the equivalent of the C API
537    // BrotliDecoderAttachDictionary with BROTLI_SHARED_DICTIONARY_RAW.
538    // Up to SHARED_BROTLI_MAX_COMPOUND_DICTS dictionaries may be attached,
539    // only before any compressed data has been processed. The most recently
540    // attached dictionary is the closest in backward-distance space.
541    // Returns false (and frees the dictionary) if it cannot be attached.
542    pub fn attach_dictionary(self : &mut Self,
543                             dict: AllocU8::AllocatedMemory) -> bool {
544        self.attach_dictionary_chunk(MaybeOwnedSlice::Owned(dict))
545    }
546    // As attach_dictionary, but the decoder only borrows `dict`: nothing is
547    // copied and nothing is freed on cleanup, so one dictionary image can back
548    // any number of concurrent decoder instances.
549    //
550    // The 'static bound is what makes this safe without a lifetime parameter
551    // on BrotliState: the data provably outlives the decoder. Callers holding
552    // a shorter-lived buffer can leak it (Box::leak, a leaked mmap) to obtain
553    // one, or use attach_dictionary and pay for the copy.
554    pub fn attach_dictionary_borrowed(self : &mut Self, dict: &'static [u8]) -> bool {
555        self.attach_dictionary_chunk(MaybeOwnedSlice::Borrowed(dict))
556    }
557    fn attach_dictionary_chunk(self : &mut Self,
558                               dict: MaybeOwnedSlice<AllocU8>) -> bool {
559        match self.state {
560            BrotliRunningState::BROTLI_STATE_UNINITED => {},
561            _ => {
562                self.free_chunk(dict);
563                return false;
564            },
565        }
566        self.attach_compound_dictionary_chunk(dict)
567    }
568    // Attaches a serialized shared dictionary (magic bytes 0x91 0x00), the
569    // equivalent of the C API BrotliDecoderAttachDictionary with
570    // BROTLI_SHARED_DICTIONARY_SERIALIZED. An embedded LZ77 prefix dictionary
571    // becomes a compound dictionary chunk; custom word lists and transform
572    // lists replace the built-in static dictionary. Only one attached
573    // dictionary may carry custom word/transform lists. Allowed only before
574    // any compressed data has been processed. Returns false (and frees the
575    // dictionary) on failure.
576    pub fn attach_serialized_dictionary(self : &mut Self,
577                                        dict_data: AllocU8::AllocatedMemory) -> bool {
578        self.attach_serialized_dictionary_chunk(MaybeOwnedSlice::Owned(dict_data))
579    }
580    // As attach_serialized_dictionary, but the decoder only borrows
581    // `dict_data`: the blob is referenced in place and an embedded LZ77
582    // prefix becomes a borrowed chunk rather than a copy. Note that custom
583    // word/transform lists keep referencing the blob for the whole decode,
584    // not just for parsing, which is why the 'static bound covers both.
585    pub fn attach_serialized_dictionary_borrowed(self : &mut Self,
586                                                 dict_data: &'static [u8]) -> bool {
587        self.attach_serialized_dictionary_chunk(MaybeOwnedSlice::Borrowed(dict_data))
588    }
589    fn attach_serialized_dictionary_chunk(self : &mut Self,
590                                          dict_data: MaybeOwnedSlice<AllocU8>) -> bool {
591        match self.state {
592            BrotliRunningState::BROTLI_STATE_UNINITED => {},
593            _ => {
594                self.free_chunk(dict_data);
595                return false;
596            },
597        }
598        let summary = match shared_dictionary::dry_parse_serialized_dictionary(
599            dict_data.slice()) {
600            Ok(summary) => summary,
601            Err(()) => {
602                self.free_chunk(dict_data);
603                return false;
604            },
605        };
606        let is_custom = summary.num_word_lists != 0 || summary.num_transform_lists != 0;
607        // Cannot combine different custom static dictionaries, only prefix
608        // dictionaries.
609        if is_custom && self.dictionary.is_custom() {
610            self.free_chunk(dict_data);
611            return false;
612        }
613        // If the blob itself is borrowed, an embedded prefix can be handed to
614        // the compound dictionary as a subslice of it; both are shared
615        // references to caller-owned memory, so no copy is needed.
616        let borrowed_blob: Option<&'static [u8]> = match dict_data {
617            MaybeOwnedSlice::Borrowed(data) => Some(data),
618            MaybeOwnedSlice::Owned(_) => None,
619        };
620        let mut parsed = BrotliSharedDictionary::<AllocU8, AllocU32>::default();
621        if is_custom {
622            let arena_size = summary.num_word_lists as usize * WORD_LIST_STRIDE +
623                             summary.num_transform_lists as usize * TRANSFORM_LIST_STRIDE;
624            parsed.meta = self.alloc_u32.alloc_cell(arena_size);
625            if parsed.meta.slice().len() != arena_size ||
626               shared_dictionary::parse_serialized_dictionary_into(
627                   dict_data.slice(), &summary, &mut parsed).is_err() {
628                self.alloc_u32.free_cell(core::mem::replace(&mut parsed.meta,
629                                         AllocU32::AllocatedMemory::default()));
630                self.free_chunk(dict_data);
631                return false;
632            }
633        }
634        if let Some((prefix_offset, prefix_len)) = summary.prefix {
635            let chunk = match borrowed_blob {
636                Some(blob) => MaybeOwnedSlice::Borrowed(
637                    &blob[prefix_offset..prefix_offset + prefix_len]),
638                // An owned blob is not kept around unless it carries custom
639                // lists, so the prefix is copied into its own buffer; that
640                // also leaves the parsed word/transform offsets referencing
641                // the blob unchanged.
642                None => {
643                    let mut chunk = self.alloc_u8.alloc_cell(prefix_len);
644                    if chunk.slice().len() != prefix_len {
645                        self.alloc_u8.free_cell(chunk);
646                        self.alloc_u32.free_cell(core::mem::replace(&mut parsed.meta,
647                                                 AllocU32::AllocatedMemory::default()));
648                        self.free_chunk(dict_data);
649                        return false;
650                    }
651                    chunk.slice_mut().clone_from_slice(
652                        &dict_data.slice()[prefix_offset..prefix_offset + prefix_len]);
653                    MaybeOwnedSlice::Owned(chunk)
654                },
655            };
656            if !self.attach_compound_dictionary_chunk(chunk) {
657                self.alloc_u32.free_cell(core::mem::replace(&mut parsed.meta,
658                                         AllocU32::AllocatedMemory::default()));
659                self.free_chunk(dict_data);
660                return false;
661            }
662        }
663        if is_custom {
664            parsed.blob = dict_data;
665            let old = core::mem::replace(&mut self.dictionary, parsed);
666            self.free_chunk(old.blob);
667            self.alloc_u32.free_cell(old.meta);
668        } else {
669            // Nothing references the blob: a prefix chunk, if any, either
670            // borrows the caller's memory or was copied out.
671            self.free_chunk(dict_data);
672        }
673        true
674    }
675    // Attaches one LZ77 prefix ("compound") dictionary chunk. Chunks must be
676    // attached before any data is decompressed; the most recently attached
677    // chunk is the closest in backward-distance space. Returns false (and
678    // frees the chunk) if the chunk cannot be attached.
679    // Releases a dictionary backing store: owned memory goes back to the
680    // allocator, borrowed memory belongs to the caller and is left alone.
681    pub(crate) fn free_chunk(self : &mut Self, chunk: MaybeOwnedSlice<AllocU8>) {
682        if let MaybeOwnedSlice::Owned(mem) = chunk {
683            self.alloc_u8.free_cell(mem);
684        }
685    }
686    pub(crate) fn attach_compound_dictionary_chunk(self : &mut Self,
687                                            chunk: MaybeOwnedSlice<AllocU8>) -> bool {
688        let size = chunk.slice().len();
689        // A zero-length chunk is a no-op and not counted toward the limit.
690        if size == 0 {
691            self.free_chunk(chunk);
692            return true;
693        }
694        let addon = &mut self.compound_dictionary;
695        if addon.num_chunks == SHARED_BROTLI_MAX_COMPOUND_DICTS ||
696           size > SHARED_BROTLI_MAX_RAW_DICT_SIZE - addon.total_size {
697            self.free_chunk(chunk);
698            return false;
699        }
700        addon.chunks[addon.num_chunks] = chunk;
701        addon.num_chunks += 1;
702        addon.total_size += size;
703        addon.chunk_offsets[addon.num_chunks] = addon.total_size as u32;
704        // Invalidate the lazily-computed block map.
705        addon.block_bits = COMPOUND_DICTIONARY_BLOCK_MAP_UNINITIALIZED;
706        true
707    }
708    pub fn BrotliStateMetablockBegin(self : &mut Self) {
709        self.meta_block_remaining_len = 0;
710        self.block_type_length_state.block_length[0] = 1u32 << 24;
711        self.block_type_length_state.block_length[1] = 1u32 << 24;
712        self.block_type_length_state.block_length[2] = 1u32 << 24;
713        self.block_type_length_state.num_block_types[0] = 1;
714        self.block_type_length_state.num_block_types[1] = 1;
715        self.block_type_length_state.num_block_types[2] = 1;
716        self.block_type_length_state.block_type_rb[0] = 1;
717        self.block_type_length_state.block_type_rb[1] = 0;
718        self.block_type_length_state.block_type_rb[2] = 1;
719        self.block_type_length_state.block_type_rb[3] = 0;
720        self.block_type_length_state.block_type_rb[4] = 1;
721        self.block_type_length_state.block_type_rb[5] = 0;
722        self.alloc_u8.free_cell(core::mem::replace(&mut self.context_map,
723                                             AllocU8::AllocatedMemory::default()));
724        self.alloc_u8.free_cell(core::mem::replace(&mut self.context_modes,
725                                             AllocU8::AllocatedMemory::default()));
726        self.alloc_u8.free_cell(core::mem::replace(&mut self.dist_context_map,
727                                             AllocU8::AllocatedMemory::default()));
728        self.context_map_slice_index = 0;
729        self.literal_htree_index = 0;
730        self.dist_context_map_slice_index = 0;
731        self.dist_htree_index = 0;
732        self.context_lookup = &kContextLookup[0];
733        self.literal_hgroup.reset(&mut self.alloc_u32, &mut self.alloc_hc);
734        self.insert_copy_hgroup.reset(&mut self.alloc_u32, &mut self.alloc_hc);
735        self.distance_hgroup.reset(&mut self.alloc_u32, &mut self.alloc_hc);
736    }
737    pub fn BrotliStateCleanupAfterMetablock(self : &mut Self) {
738        self.alloc_u8.free_cell(core::mem::replace(&mut self.context_map,
739                                             AllocU8::AllocatedMemory::default()));
740        self.alloc_u8.free_cell(core::mem::replace(&mut self.context_modes,
741                                             AllocU8::AllocatedMemory::default()));
742        self.alloc_u8.free_cell(core::mem::replace(&mut self.dist_context_map,
743                                             AllocU8::AllocatedMemory::default()));
744
745
746        self.literal_hgroup.reset(&mut self.alloc_u32, &mut self.alloc_hc);
747        self.insert_copy_hgroup.reset(&mut self.alloc_u32, &mut self.alloc_hc);
748        self.distance_hgroup.reset(&mut self.alloc_u32, &mut self.alloc_hc);
749    }
750
751   fn BrotliStateCleanup(self : &mut Self) {
752      self.BrotliStateCleanupAfterMetablock();
753      self.alloc_u8.free_cell(core::mem::replace(&mut self.ringbuffer,
754                              AllocU8::AllocatedMemory::default()));
755      self.alloc_hc.free_cell(core::mem::replace(&mut self.block_type_length_state.block_type_trees,
756                              AllocHC::AllocatedMemory::default()));
757      self.alloc_hc.free_cell(core::mem::replace(&mut self.block_type_length_state.block_len_trees,
758                              AllocHC::AllocatedMemory::default()));
759      self.alloc_hc.free_cell(core::mem::replace(&mut self.context_map_table,
760                              AllocHC::AllocatedMemory::default()));
761      self.alloc_u8.free_cell(core::mem::replace(&mut self.custom_dict,
762                              AllocU8::AllocatedMemory::default()));
763      for chunk in self.compound_dictionary.chunks.iter_mut() {
764        if let MaybeOwnedSlice::Owned(mem) =
765            core::mem::replace(chunk, MaybeOwnedSlice::default()) {
766          self.alloc_u8.free_cell(mem);
767        }
768      }
769      self.compound_dictionary = BrotliDecoderCompoundDictionary::default();
770      if let MaybeOwnedSlice::Owned(mem) =
771          core::mem::replace(&mut self.dictionary.blob, MaybeOwnedSlice::default()) {
772        self.alloc_u8.free_cell(mem);
773      }
774      self.alloc_u32.free_cell(core::mem::replace(&mut self.dictionary.meta,
775                               AllocU32::AllocatedMemory::default()));
776
777      //FIXME??  BROTLI_FREE(s, s->legacy_input_buffer);
778      //FIXME??  BROTLI_FREE(s, s->legacy_output_buffer);
779    }
780
781    pub fn BrotliStateIsStreamStart(self : &Self) -> bool {
782        match self.state {
783            BrotliRunningState::BROTLI_STATE_UNINITED =>
784                BrotliGetAvailableBits(&self.br) == 0,
785            _ => false,
786        }
787    }
788
789    pub fn BrotliStateIsStreamEnd(self : &Self) -> bool {
790        match self.state {
791            BrotliRunningState::BROTLI_STATE_DONE => true,
792            _ => false
793        }
794    }
795    pub fn BrotliHuffmanTreeGroupInit(self :&mut Self, group : WhichTreeGroup,
796                                      alphabet_size : u16, max_symbol: u16, ntrees : u16) {
797        match group {
798            WhichTreeGroup::LITERAL => self.literal_hgroup.init(&mut self.alloc_u32,
799                                                                &mut self.alloc_hc,
800                                                                alphabet_size, max_symbol, ntrees),
801            WhichTreeGroup::INSERT_COPY => self.insert_copy_hgroup.init(&mut self.alloc_u32,
802                                                                        &mut self.alloc_hc,
803                                                                        alphabet_size, max_symbol, ntrees),
804            WhichTreeGroup::DISTANCE => self.distance_hgroup.init(&mut self.alloc_u32,
805                                                                  &mut self.alloc_hc,
806                                                                  alphabet_size, max_symbol, ntrees),
807        }
808    }
809    pub fn BrotliHuffmanTreeGroupRelease(self :&mut Self, group : WhichTreeGroup) {
810        match group {
811            WhichTreeGroup::LITERAL => self.literal_hgroup.reset(&mut self.alloc_u32,
812                                                                 &mut self.alloc_hc),
813            WhichTreeGroup::INSERT_COPY => self.insert_copy_hgroup.reset(&mut self.alloc_u32,
814                                                                         &mut self.alloc_hc),
815            WhichTreeGroup::DISTANCE => self.distance_hgroup.reset(&mut self.alloc_u32,
816                                                                   &mut self.alloc_hc),
817        }
818    }
819}
820
821impl <'brotli_state,
822      AllocU8 : alloc::Allocator<u8>,
823      AllocU32 : alloc::Allocator<u32>,
824      AllocHC : alloc::Allocator<HuffmanCode> > Drop for BrotliState<AllocU8, AllocU32, AllocHC> {
825    fn drop(&mut self) {
826        self.BrotliStateCleanup();
827    }
828}
829
830
831
832pub fn BrotliDecoderErrorStr(c: BrotliDecoderErrorCode) -> &'static str {
833  match c {
834  BrotliDecoderErrorCode::BROTLI_DECODER_NO_ERROR => "NO_ERROR\0",
835  /* Same as BrotliDecoderResult values */
836  BrotliDecoderErrorCode::BROTLI_DECODER_SUCCESS => "SUCCESS\0",
837  BrotliDecoderErrorCode::BROTLI_DECODER_NEEDS_MORE_INPUT => "NEEDS_MORE_INPUT\0",
838  BrotliDecoderErrorCode::BROTLI_DECODER_NEEDS_MORE_OUTPUT => "NEEDS_MORE_OUTPUT\0",
839
840  /* Errors caused by invalid input */
841  BrotliDecoderErrorCode::BROTLI_DECODER_ERROR_FORMAT_EXUBERANT_NIBBLE => "ERROR_FORMAT_EXUBERANT_NIBBLE\0",
842  BrotliDecoderErrorCode::BROTLI_DECODER_ERROR_FORMAT_RESERVED => "ERROR_FORMAT_RESERVED\0",
843  BrotliDecoderErrorCode::BROTLI_DECODER_ERROR_FORMAT_EXUBERANT_META_NIBBLE => "ERROR_FORMAT_EXUBERANT_META_NIBBLE\0",
844  BrotliDecoderErrorCode::BROTLI_DECODER_ERROR_FORMAT_SIMPLE_HUFFMAN_ALPHABET => "ERROR_FORMAT_SIMPLE_HUFFMAN_ALPHABET\0",
845  BrotliDecoderErrorCode::BROTLI_DECODER_ERROR_FORMAT_SIMPLE_HUFFMAN_SAME => "ERROR_FORMAT_SIMPLE_HUFFMAN_SAME\0",
846  BrotliDecoderErrorCode::BROTLI_DECODER_ERROR_FORMAT_CL_SPACE => "ERROR_FORMAT_FL_SPACE\0",
847  BrotliDecoderErrorCode::BROTLI_DECODER_ERROR_FORMAT_HUFFMAN_SPACE => "ERROR_FORMAT_HUFFMAN_SPACE\0",
848  BrotliDecoderErrorCode::BROTLI_DECODER_ERROR_FORMAT_CONTEXT_MAP_REPEAT => "ERROR_FORMAT_CONTEXT_MAP_REPEAT\0",
849  BrotliDecoderErrorCode::BROTLI_DECODER_ERROR_FORMAT_BLOCK_LENGTH_1 =>"ERROR_FORMAT_BLOCK_LENGTH_1\0",
850  BrotliDecoderErrorCode::BROTLI_DECODER_ERROR_FORMAT_BLOCK_LENGTH_2 =>"ERROR_FORMAT_BLOCK_LENGTH_2\0",
851  BrotliDecoderErrorCode::BROTLI_DECODER_ERROR_FORMAT_TRANSFORM => "ERROR_FORMAT_TRANSFORM\0",
852  BrotliDecoderErrorCode::BROTLI_DECODER_ERROR_FORMAT_DICTIONARY =>"ERROR_FORMAT_DICTIONARY\0",
853  BrotliDecoderErrorCode::BROTLI_DECODER_ERROR_FORMAT_WINDOW_BITS =>"ERROR_FORMAT_WINDOW_BITS\0",
854  BrotliDecoderErrorCode::BROTLI_DECODER_ERROR_FORMAT_PADDING_1 =>"ERROR_FORMAT_PADDING_1\0",
855  BrotliDecoderErrorCode::BROTLI_DECODER_ERROR_FORMAT_PADDING_2 =>"ERROR_FORMAT_PADDING_2\0",
856  BrotliDecoderErrorCode::BROTLI_DECODER_ERROR_FORMAT_DISTANCE =>"ERROR_FORMAT_DISTANCE\0",
857
858  /* -17 code is reserved */
859
860  BrotliDecoderErrorCode::BROTLI_DECODER_ERROR_COMPOUND_DICTIONARY => "ERROR_COMPOUND_DICTIONARY\0",
861  BrotliDecoderErrorCode::BROTLI_DECODER_ERROR_DICTIONARY_NOT_SET => "ERROR_DICTIONARY_NOT_SET\0",
862  BrotliDecoderErrorCode::BROTLI_DECODER_ERROR_INVALID_ARGUMENTS => "ERROR_INVALID_ARGUMENTS\0",
863
864  /* Memory allocation problems */
865  BrotliDecoderErrorCode::BROTLI_DECODER_ERROR_ALLOC_CONTEXT_MODES => "ERROR_ALLOC_CONTEXT_MODES\0",
866  /* Literal => insert and distance trees together */
867  BrotliDecoderErrorCode::BROTLI_DECODER_ERROR_ALLOC_TREE_GROUPS => "ERROR_ALLOC_TREE_GROUPS\0",
868  /* -23..-24 codes are reserved for distinct tree groups */
869  BrotliDecoderErrorCode::BROTLI_DECODER_ERROR_ALLOC_CONTEXT_MAP => "ERROR_ALLOC_CONTEXT_MAP\0",
870  BrotliDecoderErrorCode::BROTLI_DECODER_ERROR_ALLOC_RING_BUFFER_1 => "ERROR_ALLOC_RING_BUFFER_1\0",
871  BrotliDecoderErrorCode::BROTLI_DECODER_ERROR_ALLOC_RING_BUFFER_2 => "ERROR_ALLOC_RING_BUFFER_2\0",
872  /* -28..-29 codes are reserved for dynamic ring-buffer allocation */
873  BrotliDecoderErrorCode::BROTLI_DECODER_ERROR_ALLOC_BLOCK_TYPE_TREES => "ERROR_ALLOC_BLOCK_TYPE_TREES\0",
874
875  /* "Impossible" states */
876  BrotliDecoderErrorCode::BROTLI_DECODER_ERROR_UNREACHABLE => "ERROR_UNREACHABLE\0",
877  }
878}