2019-03-07 01:55:38 +03:00
|
|
|
package brotli
|
|
|
|
|
2019-03-07 04:08:24 +03:00
|
|
|
import "io"
|
|
|
|
|
2019-03-07 01:55:38 +03:00
|
|
|
/* Copyright 2015 Google Inc. All Rights Reserved.
|
|
|
|
|
|
|
|
Distributed under MIT license.
|
|
|
|
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
|
|
|
*/
|
|
|
|
/* Copyright 2015 Google Inc. All Rights Reserved.
|
|
|
|
|
|
|
|
Distributed under MIT license.
|
|
|
|
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* Brotli state for partial streaming decoding. */
|
|
|
|
const (
|
|
|
|
BROTLI_STATE_UNINITED = iota
|
|
|
|
BROTLI_STATE_LARGE_WINDOW_BITS
|
|
|
|
BROTLI_STATE_INITIALIZE
|
|
|
|
BROTLI_STATE_METABLOCK_BEGIN
|
|
|
|
BROTLI_STATE_METABLOCK_HEADER
|
|
|
|
BROTLI_STATE_METABLOCK_HEADER_2
|
|
|
|
BROTLI_STATE_CONTEXT_MODES
|
|
|
|
BROTLI_STATE_COMMAND_BEGIN
|
|
|
|
BROTLI_STATE_COMMAND_INNER
|
|
|
|
BROTLI_STATE_COMMAND_POST_DECODE_LITERALS
|
|
|
|
BROTLI_STATE_COMMAND_POST_WRAP_COPY
|
|
|
|
BROTLI_STATE_UNCOMPRESSED
|
|
|
|
BROTLI_STATE_METADATA
|
|
|
|
BROTLI_STATE_COMMAND_INNER_WRITE
|
|
|
|
BROTLI_STATE_METABLOCK_DONE
|
|
|
|
BROTLI_STATE_COMMAND_POST_WRITE_1
|
|
|
|
BROTLI_STATE_COMMAND_POST_WRITE_2
|
|
|
|
BROTLI_STATE_HUFFMAN_CODE_0
|
|
|
|
BROTLI_STATE_HUFFMAN_CODE_1
|
|
|
|
BROTLI_STATE_HUFFMAN_CODE_2
|
|
|
|
BROTLI_STATE_HUFFMAN_CODE_3
|
|
|
|
BROTLI_STATE_CONTEXT_MAP_1
|
|
|
|
BROTLI_STATE_CONTEXT_MAP_2
|
|
|
|
BROTLI_STATE_TREE_GROUP
|
|
|
|
BROTLI_STATE_DONE
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
BROTLI_STATE_METABLOCK_HEADER_NONE = iota
|
|
|
|
BROTLI_STATE_METABLOCK_HEADER_EMPTY
|
|
|
|
BROTLI_STATE_METABLOCK_HEADER_NIBBLES
|
|
|
|
BROTLI_STATE_METABLOCK_HEADER_SIZE
|
|
|
|
BROTLI_STATE_METABLOCK_HEADER_UNCOMPRESSED
|
|
|
|
BROTLI_STATE_METABLOCK_HEADER_RESERVED
|
|
|
|
BROTLI_STATE_METABLOCK_HEADER_BYTES
|
|
|
|
BROTLI_STATE_METABLOCK_HEADER_METADATA
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
BROTLI_STATE_UNCOMPRESSED_NONE = iota
|
|
|
|
BROTLI_STATE_UNCOMPRESSED_WRITE
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
BROTLI_STATE_TREE_GROUP_NONE = iota
|
|
|
|
BROTLI_STATE_TREE_GROUP_LOOP
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
BROTLI_STATE_CONTEXT_MAP_NONE = iota
|
|
|
|
BROTLI_STATE_CONTEXT_MAP_READ_PREFIX
|
|
|
|
BROTLI_STATE_CONTEXT_MAP_HUFFMAN
|
|
|
|
BROTLI_STATE_CONTEXT_MAP_DECODE
|
|
|
|
BROTLI_STATE_CONTEXT_MAP_TRANSFORM
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
BROTLI_STATE_HUFFMAN_NONE = iota
|
|
|
|
BROTLI_STATE_HUFFMAN_SIMPLE_SIZE
|
|
|
|
BROTLI_STATE_HUFFMAN_SIMPLE_READ
|
|
|
|
BROTLI_STATE_HUFFMAN_SIMPLE_BUILD
|
|
|
|
BROTLI_STATE_HUFFMAN_COMPLEX
|
|
|
|
BROTLI_STATE_HUFFMAN_LENGTH_SYMBOLS
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
BROTLI_STATE_DECODE_UINT8_NONE = iota
|
|
|
|
BROTLI_STATE_DECODE_UINT8_SHORT
|
|
|
|
BROTLI_STATE_DECODE_UINT8_LONG
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
BROTLI_STATE_READ_BLOCK_LENGTH_NONE = iota
|
|
|
|
BROTLI_STATE_READ_BLOCK_LENGTH_SUFFIX
|
|
|
|
)
|
|
|
|
|
2019-03-07 04:08:24 +03:00
|
|
|
type Reader struct {
|
|
|
|
src io.Reader
|
|
|
|
buf []byte // scratch space for reading from src
|
|
|
|
in []byte // current chunk to decode; usually aliases buf
|
|
|
|
|
2019-03-07 01:55:38 +03:00
|
|
|
state int
|
|
|
|
loop_counter int
|
2019-03-10 04:11:32 +03:00
|
|
|
br bitReader
|
2019-03-07 01:55:38 +03:00
|
|
|
buffer struct {
|
|
|
|
u64 uint64
|
|
|
|
u8 [8]byte
|
|
|
|
}
|
|
|
|
buffer_length uint32
|
|
|
|
pos int
|
|
|
|
max_backward_distance int
|
|
|
|
max_distance int
|
|
|
|
ringbuffer_size int
|
|
|
|
ringbuffer_mask int
|
|
|
|
dist_rb_idx int
|
|
|
|
dist_rb [4]int
|
|
|
|
error_code int
|
|
|
|
sub_loop_counter uint32
|
|
|
|
ringbuffer []byte
|
|
|
|
ringbuffer_end []byte
|
2019-03-16 03:24:40 +03:00
|
|
|
htree_command []huffmanCode
|
2019-03-07 01:55:38 +03:00
|
|
|
context_lookup []byte
|
|
|
|
context_map_slice []byte
|
|
|
|
dist_context_map_slice []byte
|
2019-03-16 03:24:40 +03:00
|
|
|
literal_hgroup huffmanTreeGroup
|
|
|
|
insert_copy_hgroup huffmanTreeGroup
|
|
|
|
distance_hgroup huffmanTreeGroup
|
|
|
|
block_type_trees []huffmanCode
|
|
|
|
block_len_trees []huffmanCode
|
2019-03-07 01:55:38 +03:00
|
|
|
trivial_literal_context int
|
|
|
|
distance_context int
|
|
|
|
meta_block_remaining_len int
|
|
|
|
block_length_index uint32
|
|
|
|
block_length [3]uint32
|
|
|
|
num_block_types [3]uint32
|
|
|
|
block_type_rb [6]uint32
|
|
|
|
distance_postfix_bits uint32
|
|
|
|
num_direct_distance_codes uint32
|
|
|
|
distance_postfix_mask int
|
|
|
|
num_dist_htrees uint32
|
|
|
|
dist_context_map []byte
|
2019-03-16 03:24:40 +03:00
|
|
|
literal_htree []huffmanCode
|
2019-03-07 01:55:38 +03:00
|
|
|
dist_htree_index byte
|
|
|
|
repeat_code_len uint32
|
|
|
|
prev_code_len uint32
|
|
|
|
copy_length int
|
|
|
|
distance_code int
|
|
|
|
rb_roundtrips uint
|
|
|
|
partial_pos_out uint
|
|
|
|
symbol uint32
|
|
|
|
repeat uint32
|
|
|
|
space uint32
|
2019-03-16 03:24:40 +03:00
|
|
|
table [32]huffmanCode
|
2019-03-07 01:55:38 +03:00
|
|
|
symbol_lists SymbolList
|
2019-03-16 03:24:40 +03:00
|
|
|
symbols_lists_array [huffmanMaxCodeLength + 1 + numCommandSymbols]uint16
|
2019-03-07 01:55:38 +03:00
|
|
|
next_symbol [32]int
|
2019-03-15 22:05:31 +03:00
|
|
|
code_length_code_lengths [codeLengthCodes]byte
|
2019-03-07 01:55:38 +03:00
|
|
|
code_length_histo [16]uint16
|
|
|
|
htree_index int
|
2019-03-16 03:24:40 +03:00
|
|
|
next []huffmanCode
|
2019-03-07 01:55:38 +03:00
|
|
|
context_index uint32
|
|
|
|
max_run_length_prefix uint32
|
|
|
|
code uint32
|
2019-03-16 03:24:40 +03:00
|
|
|
context_map_table [huffmanMaxSize272]huffmanCode
|
2019-03-07 01:55:38 +03:00
|
|
|
substate_metablock_header int
|
|
|
|
substate_tree_group int
|
|
|
|
substate_context_map int
|
|
|
|
substate_uncompressed int
|
|
|
|
substate_huffman int
|
|
|
|
substate_decode_uint8 int
|
|
|
|
substate_read_block_length int
|
|
|
|
is_last_metablock uint
|
|
|
|
is_uncompressed uint
|
|
|
|
is_metadata uint
|
|
|
|
should_wrap_ringbuffer uint
|
|
|
|
canny_ringbuffer_allocation uint
|
|
|
|
large_window bool
|
|
|
|
size_nibbles uint
|
|
|
|
window_bits uint32
|
|
|
|
new_ringbuffer_size int
|
|
|
|
num_literal_htrees uint32
|
|
|
|
context_map []byte
|
|
|
|
context_modes []byte
|
2019-03-16 03:24:40 +03:00
|
|
|
dictionary *dictionary
|
2019-03-07 01:55:38 +03:00
|
|
|
transforms *BrotliTransforms
|
|
|
|
trivial_literal_contexts [8]uint32
|
|
|
|
}
|
|
|
|
|
2019-03-07 04:08:24 +03:00
|
|
|
func BrotliDecoderStateInit(s *Reader) bool {
|
2019-03-07 01:55:38 +03:00
|
|
|
s.error_code = 0 /* BROTLI_DECODER_NO_ERROR */
|
|
|
|
|
2019-03-10 04:11:32 +03:00
|
|
|
initBitReader(&s.br)
|
2019-03-07 01:55:38 +03:00
|
|
|
s.state = BROTLI_STATE_UNINITED
|
|
|
|
s.large_window = false
|
|
|
|
s.substate_metablock_header = BROTLI_STATE_METABLOCK_HEADER_NONE
|
|
|
|
s.substate_tree_group = BROTLI_STATE_TREE_GROUP_NONE
|
|
|
|
s.substate_context_map = BROTLI_STATE_CONTEXT_MAP_NONE
|
|
|
|
s.substate_uncompressed = BROTLI_STATE_UNCOMPRESSED_NONE
|
|
|
|
s.substate_huffman = BROTLI_STATE_HUFFMAN_NONE
|
|
|
|
s.substate_decode_uint8 = BROTLI_STATE_DECODE_UINT8_NONE
|
|
|
|
s.substate_read_block_length = BROTLI_STATE_READ_BLOCK_LENGTH_NONE
|
|
|
|
|
|
|
|
s.buffer_length = 0
|
|
|
|
s.loop_counter = 0
|
|
|
|
s.pos = 0
|
|
|
|
s.rb_roundtrips = 0
|
|
|
|
s.partial_pos_out = 0
|
|
|
|
|
|
|
|
s.block_type_trees = nil
|
|
|
|
s.block_len_trees = nil
|
|
|
|
s.ringbuffer = nil
|
|
|
|
s.ringbuffer_size = 0
|
|
|
|
s.new_ringbuffer_size = 0
|
|
|
|
s.ringbuffer_mask = 0
|
|
|
|
|
|
|
|
s.context_map = nil
|
|
|
|
s.context_modes = nil
|
|
|
|
s.dist_context_map = nil
|
|
|
|
s.context_map_slice = nil
|
|
|
|
s.dist_context_map_slice = nil
|
|
|
|
|
|
|
|
s.sub_loop_counter = 0
|
|
|
|
|
|
|
|
s.literal_hgroup.codes = nil
|
|
|
|
s.literal_hgroup.htrees = nil
|
|
|
|
s.insert_copy_hgroup.codes = nil
|
|
|
|
s.insert_copy_hgroup.htrees = nil
|
|
|
|
s.distance_hgroup.codes = nil
|
|
|
|
s.distance_hgroup.htrees = nil
|
|
|
|
|
|
|
|
s.is_last_metablock = 0
|
|
|
|
s.is_uncompressed = 0
|
|
|
|
s.is_metadata = 0
|
|
|
|
s.should_wrap_ringbuffer = 0
|
|
|
|
s.canny_ringbuffer_allocation = 1
|
|
|
|
|
|
|
|
s.window_bits = 0
|
|
|
|
s.max_distance = 0
|
|
|
|
s.dist_rb[0] = 16
|
|
|
|
s.dist_rb[1] = 15
|
|
|
|
s.dist_rb[2] = 11
|
|
|
|
s.dist_rb[3] = 4
|
|
|
|
s.dist_rb_idx = 0
|
|
|
|
s.block_type_trees = nil
|
|
|
|
s.block_len_trees = nil
|
|
|
|
|
|
|
|
s.symbol_lists.storage = s.symbols_lists_array[:]
|
2019-03-16 03:24:40 +03:00
|
|
|
s.symbol_lists.offset = huffmanMaxCodeLength + 1
|
2019-03-07 01:55:38 +03:00
|
|
|
|
2019-03-16 03:24:40 +03:00
|
|
|
s.dictionary = getDictionary()
|
2019-03-07 01:55:38 +03:00
|
|
|
s.transforms = BrotliGetTransforms()
|
|
|
|
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
2019-03-07 04:08:24 +03:00
|
|
|
func BrotliDecoderStateMetablockBegin(s *Reader) {
|
2019-03-07 01:55:38 +03:00
|
|
|
s.meta_block_remaining_len = 0
|
|
|
|
s.block_length[0] = 1 << 24
|
|
|
|
s.block_length[1] = 1 << 24
|
|
|
|
s.block_length[2] = 1 << 24
|
|
|
|
s.num_block_types[0] = 1
|
|
|
|
s.num_block_types[1] = 1
|
|
|
|
s.num_block_types[2] = 1
|
|
|
|
s.block_type_rb[0] = 1
|
|
|
|
s.block_type_rb[1] = 0
|
|
|
|
s.block_type_rb[2] = 1
|
|
|
|
s.block_type_rb[3] = 0
|
|
|
|
s.block_type_rb[4] = 1
|
|
|
|
s.block_type_rb[5] = 0
|
|
|
|
s.context_map = nil
|
|
|
|
s.context_modes = nil
|
|
|
|
s.dist_context_map = nil
|
|
|
|
s.context_map_slice = nil
|
|
|
|
s.literal_htree = nil
|
|
|
|
s.dist_context_map_slice = nil
|
|
|
|
s.dist_htree_index = 0
|
|
|
|
s.context_lookup = nil
|
|
|
|
s.literal_hgroup.codes = nil
|
|
|
|
s.literal_hgroup.htrees = nil
|
|
|
|
s.insert_copy_hgroup.codes = nil
|
|
|
|
s.insert_copy_hgroup.htrees = nil
|
|
|
|
s.distance_hgroup.codes = nil
|
|
|
|
s.distance_hgroup.htrees = nil
|
|
|
|
}
|
|
|
|
|
2019-03-07 04:08:24 +03:00
|
|
|
func BrotliDecoderStateCleanupAfterMetablock(s *Reader) {
|
2019-03-07 01:55:38 +03:00
|
|
|
s.context_modes = nil
|
|
|
|
s.context_map = nil
|
|
|
|
s.dist_context_map = nil
|
|
|
|
s.literal_hgroup.htrees = nil
|
|
|
|
s.insert_copy_hgroup.htrees = nil
|
|
|
|
s.distance_hgroup.htrees = nil
|
|
|
|
}
|
|
|
|
|
2019-03-07 04:08:24 +03:00
|
|
|
func BrotliDecoderStateCleanup(s *Reader) {
|
2019-03-07 01:55:38 +03:00
|
|
|
BrotliDecoderStateCleanupAfterMetablock(s)
|
|
|
|
|
|
|
|
s.ringbuffer = nil
|
|
|
|
s.block_type_trees = nil
|
|
|
|
}
|
|
|
|
|
2019-03-16 03:24:40 +03:00
|
|
|
func BrotliDecoderHuffmanTreeGroupInit(s *Reader, group *huffmanTreeGroup, alphabet_size uint32, max_symbol uint32, ntrees uint32) bool {
|
2019-03-07 01:55:38 +03:00
|
|
|
var max_table_size uint = uint(kMaxHuffmanTableSize[(alphabet_size+31)>>5])
|
|
|
|
group.alphabet_size = uint16(alphabet_size)
|
|
|
|
group.max_symbol = uint16(max_symbol)
|
|
|
|
group.num_htrees = uint16(ntrees)
|
2019-03-16 03:24:40 +03:00
|
|
|
group.htrees = make([][]huffmanCode, ntrees)
|
|
|
|
group.codes = make([]huffmanCode, (uint(ntrees) * max_table_size))
|
2019-03-07 01:55:38 +03:00
|
|
|
return !(group.codes == nil)
|
|
|
|
}
|