forked from Shiloh/githaven
296 lines
7.7 KiB
Go
296 lines
7.7 KiB
Go
|
package brotli
|
||
|
|
||
|
import "io"
|
||
|
|
||
|
/* 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 (
|
||
|
stateUninited = iota
|
||
|
stateLargeWindowBits
|
||
|
stateInitialize
|
||
|
stateMetablockBegin
|
||
|
stateMetablockHeader
|
||
|
stateMetablockHeader2
|
||
|
stateContextModes
|
||
|
stateCommandBegin
|
||
|
stateCommandInner
|
||
|
stateCommandPostDecodeLiterals
|
||
|
stateCommandPostWrapCopy
|
||
|
stateUncompressed
|
||
|
stateMetadata
|
||
|
stateCommandInnerWrite
|
||
|
stateMetablockDone
|
||
|
stateCommandPostWrite1
|
||
|
stateCommandPostWrite2
|
||
|
stateHuffmanCode0
|
||
|
stateHuffmanCode1
|
||
|
stateHuffmanCode2
|
||
|
stateHuffmanCode3
|
||
|
stateContextMap1
|
||
|
stateContextMap2
|
||
|
stateTreeGroup
|
||
|
stateDone
|
||
|
)
|
||
|
|
||
|
const (
|
||
|
stateMetablockHeaderNone = iota
|
||
|
stateMetablockHeaderEmpty
|
||
|
stateMetablockHeaderNibbles
|
||
|
stateMetablockHeaderSize
|
||
|
stateMetablockHeaderUncompressed
|
||
|
stateMetablockHeaderReserved
|
||
|
stateMetablockHeaderBytes
|
||
|
stateMetablockHeaderMetadata
|
||
|
)
|
||
|
|
||
|
const (
|
||
|
stateUncompressedNone = iota
|
||
|
stateUncompressedWrite
|
||
|
)
|
||
|
|
||
|
const (
|
||
|
stateTreeGroupNone = iota
|
||
|
stateTreeGroupLoop
|
||
|
)
|
||
|
|
||
|
const (
|
||
|
stateContextMapNone = iota
|
||
|
stateContextMapReadPrefix
|
||
|
stateContextMapHuffman
|
||
|
stateContextMapDecode
|
||
|
stateContextMapTransform
|
||
|
)
|
||
|
|
||
|
const (
|
||
|
stateHuffmanNone = iota
|
||
|
stateHuffmanSimpleSize
|
||
|
stateHuffmanSimpleRead
|
||
|
stateHuffmanSimpleBuild
|
||
|
stateHuffmanComplex
|
||
|
stateHuffmanLengthSymbols
|
||
|
)
|
||
|
|
||
|
const (
|
||
|
stateDecodeUint8None = iota
|
||
|
stateDecodeUint8Short
|
||
|
stateDecodeUint8Long
|
||
|
)
|
||
|
|
||
|
const (
|
||
|
stateReadBlockLengthNone = iota
|
||
|
stateReadBlockLengthSuffix
|
||
|
)
|
||
|
|
||
|
type Reader struct {
|
||
|
src io.Reader
|
||
|
buf []byte // scratch space for reading from src
|
||
|
in []byte // current chunk to decode; usually aliases buf
|
||
|
|
||
|
state int
|
||
|
loop_counter int
|
||
|
br bitReader
|
||
|
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
|
||
|
htree_command []huffmanCode
|
||
|
context_lookup []byte
|
||
|
context_map_slice []byte
|
||
|
dist_context_map_slice []byte
|
||
|
literal_hgroup huffmanTreeGroup
|
||
|
insert_copy_hgroup huffmanTreeGroup
|
||
|
distance_hgroup huffmanTreeGroup
|
||
|
block_type_trees []huffmanCode
|
||
|
block_len_trees []huffmanCode
|
||
|
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
|
||
|
literal_htree []huffmanCode
|
||
|
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
|
||
|
table [32]huffmanCode
|
||
|
symbol_lists symbolList
|
||
|
symbols_lists_array [huffmanMaxCodeLength + 1 + numCommandSymbols]uint16
|
||
|
next_symbol [32]int
|
||
|
code_length_code_lengths [codeLengthCodes]byte
|
||
|
code_length_histo [16]uint16
|
||
|
htree_index int
|
||
|
next []huffmanCode
|
||
|
context_index uint32
|
||
|
max_run_length_prefix uint32
|
||
|
code uint32
|
||
|
context_map_table [huffmanMaxSize272]huffmanCode
|
||
|
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
|
||
|
dictionary *dictionary
|
||
|
transforms *transforms
|
||
|
trivial_literal_contexts [8]uint32
|
||
|
}
|
||
|
|
||
|
func decoderStateInit(s *Reader) bool {
|
||
|
s.error_code = 0 /* BROTLI_DECODER_NO_ERROR */
|
||
|
|
||
|
initBitReader(&s.br)
|
||
|
s.state = stateUninited
|
||
|
s.large_window = false
|
||
|
s.substate_metablock_header = stateMetablockHeaderNone
|
||
|
s.substate_tree_group = stateTreeGroupNone
|
||
|
s.substate_context_map = stateContextMapNone
|
||
|
s.substate_uncompressed = stateUncompressedNone
|
||
|
s.substate_huffman = stateHuffmanNone
|
||
|
s.substate_decode_uint8 = stateDecodeUint8None
|
||
|
s.substate_read_block_length = stateReadBlockLengthNone
|
||
|
|
||
|
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[:]
|
||
|
s.symbol_lists.offset = huffmanMaxCodeLength + 1
|
||
|
|
||
|
s.dictionary = getDictionary()
|
||
|
s.transforms = getTransforms()
|
||
|
|
||
|
return true
|
||
|
}
|
||
|
|
||
|
func decoderStateMetablockBegin(s *Reader) {
|
||
|
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
|
||
|
}
|
||
|
|
||
|
func decoderStateCleanupAfterMetablock(s *Reader) {
|
||
|
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
|
||
|
}
|
||
|
|
||
|
func decoderHuffmanTreeGroupInit(s *Reader, group *huffmanTreeGroup, alphabet_size uint32, max_symbol uint32, ntrees uint32) bool {
|
||
|
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)
|
||
|
group.htrees = make([][]huffmanCode, ntrees)
|
||
|
group.codes = make([]huffmanCode, (uint(ntrees) * max_table_size))
|
||
|
return !(group.codes == nil)
|
||
|
}
|