brotli/dec/decode.c
Zoltan Szabadka 60c24c0c2d Updates to Brotli compression format, decoder and encoder
This commit contains a batch of changes that were made to the Brotli
compression algorithm in the last month. Most important changes:

   * Updated spec
   * Changed Huffman code length alphabet to use run length codes more
     efficiently, based on a suggestion by Robert Obryk
   * Changed encoding of the number of Huffman code lengths (HLEN)
   * Changed encoding of the number of Huffman trees (NTREES)
   * Added support for uncompressed meta-blocks
2013-12-12 13:18:04 +01:00

961 lines
30 KiB
C

// Copyright 2013 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "./bit_reader.h"
#include "./context.h"
#include "./decode.h"
#include "./huffman.h"
#include "./prefix.h"
#include "./safe_malloc.h"
#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
#endif
#ifdef BROTLI_DECODE_DEBUG
#define BROTLI_LOG_UINT(name) \
printf("[%s] %s = %lu\n", __func__, #name, (unsigned long)(name))
#define BROTLI_LOG_ARRAY_INDEX(array_name, idx) \
printf("[%s] %s[%lu] = %lu\n", __func__, #array_name, \
(unsigned long)(idx), (unsigned long)array_name[idx])
#else
#define BROTLI_LOG_UINT(name)
#define BROTLI_LOG_ARRAY_INDEX(array_name, idx)
#endif
static const int kDefaultCodeLength = 8;
static const int kCodeLengthRepeatCode = 16;
static const int kNumLiteralCodes = 256;
static const int kNumInsertAndCopyCodes = 704;
static const int kNumBlockLengthCodes = 26;
static const int kLiteralContextBits = 6;
static const int kDistanceContextBits = 2;
#define CODE_LENGTH_CODES 18
static const uint8_t kCodeLengthCodeOrder[CODE_LENGTH_CODES] = {
1, 2, 3, 4, 0, 17, 5, 6, 16, 7, 8, 9, 10, 11, 12, 13, 14, 15,
};
#define NUM_DISTANCE_SHORT_CODES 16
static const int kDistanceShortCodeIndexOffset[NUM_DISTANCE_SHORT_CODES] = {
3, 2, 1, 0, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2
};
static const int kDistanceShortCodeValueOffset[NUM_DISTANCE_SHORT_CODES] = {
0, 0, 0, 0, -1, 1, -2, 2, -3, 3, -1, 1, -2, 2, -3, 3
};
static BROTLI_INLINE int DecodeWindowBits(BrotliBitReader* br) {
if (BrotliReadBits(br, 1)) {
return 17 + BrotliReadBits(br, 3);
} else {
return 16;
}
}
// Decodes a number in the range [0..255], by reading 1 - 11 bits.
static BROTLI_INLINE int DecodeVarLenUint8(BrotliBitReader* br) {
if (BrotliReadBits(br, 1)) {
int nbits = BrotliReadBits(br, 3);
if (nbits == 0) {
return 1;
} else {
return BrotliReadBits(br, nbits) + (1 << nbits);
}
}
return 0;
}
static void DecodeMetaBlockLength(BrotliBitReader* br,
size_t* meta_block_length,
int* input_end,
int* is_uncompressed) {
*input_end = BrotliReadBits(br, 1);
*meta_block_length = 0;
*is_uncompressed = 0;
if (*input_end && BrotliReadBits(br, 1)) {
return;
}
int size_nibbles = BrotliReadBits(br, 2) + 4;
int i;
for (i = 0; i < size_nibbles; ++i) {
*meta_block_length |= BrotliReadBits(br, 4) << (i * 4);
}
++(*meta_block_length);
if (!*input_end) {
*is_uncompressed = BrotliReadBits(br, 1);
}
}
// Decodes the next Huffman code from bit-stream.
static BROTLI_INLINE int ReadSymbol(const HuffmanTree* tree,
BrotliBitReader* br) {
const HuffmanTreeNode* node = tree->root_;
BrotliFillBitWindow(br);
uint32_t bits = BrotliPrefetchBits(br);
int bitpos = br->bit_pos_;
// Check if we find the bit combination from the Huffman lookup table.
const int lut_ix = bits & (HUFF_LUT - 1);
const int lut_bits = tree->lut_bits_[lut_ix];
if (lut_bits <= HUFF_LUT_BITS) {
BrotliSetBitPos(br, bitpos + lut_bits);
return tree->lut_symbol_[lut_ix];
}
node += tree->lut_jump_[lut_ix];
bitpos += HUFF_LUT_BITS;
bits >>= HUFF_LUT_BITS;
// Decode the value from a binary tree.
assert(node != NULL);
do {
node = HuffmanTreeNextNode(node, bits & 1);
bits >>= 1;
++bitpos;
} while (HuffmanTreeNodeIsNotLeaf(node));
BrotliSetBitPos(br, bitpos);
return node->symbol_;
}
static void PrintUcharVector(const uint8_t* v, int len) {
while (len-- > 0) printf(" %d", *v++);
printf("\n");
}
static int ReadHuffmanCodeLengths(
const uint8_t* code_length_code_lengths,
int num_symbols, uint8_t* code_lengths,
BrotliBitReader* br) {
int ok = 0;
int symbol;
int max_symbol;
int decode_number_of_code_length_codes;
int prev_code_len = kDefaultCodeLength;
int repeat = 0;
int repeat_length = 0;
HuffmanTree tree;
if (!BrotliHuffmanTreeBuildImplicit(&tree, code_length_code_lengths,
CODE_LENGTH_CODES)) {
printf("[ReadHuffmanCodeLengths] Building code length tree failed: ");
PrintUcharVector(code_length_code_lengths, CODE_LENGTH_CODES);
return 0;
}
if (!BrotliReadMoreInput(br)) {
printf("[ReadHuffmanCodeLengths] Unexpected end of input.\n");
return 0;
}
decode_number_of_code_length_codes = BrotliReadBits(br, 1);
BROTLI_LOG_UINT(decode_number_of_code_length_codes);
if (decode_number_of_code_length_codes) {
if (BrotliReadBits(br, 1)) {
max_symbol = 68 + BrotliReadBits(br, 7);
} else {
max_symbol = 4 + BrotliReadBits(br, 6);
}
if (max_symbol > num_symbols) {
printf("[ReadHuffmanCodeLengths] max_symbol > num_symbols (%d vs %d)\n",
max_symbol, num_symbols);
goto End;
}
} else {
max_symbol = num_symbols;
}
BROTLI_LOG_UINT(max_symbol);
symbol = 0;
while (symbol + repeat < num_symbols) {
int code_len;
if (max_symbol-- == 0) break;
if (!BrotliReadMoreInput(br)) {
printf("[ReadHuffmanCodeLengths] Unexpected end of input.\n");
goto End;
}
code_len = ReadSymbol(&tree, br);
BROTLI_LOG_UINT(symbol);
BROTLI_LOG_UINT(repeat);
BROTLI_LOG_UINT(repeat_length);
BROTLI_LOG_UINT(code_len);
if ((code_len < kCodeLengthRepeatCode) ||
(code_len == kCodeLengthRepeatCode && repeat_length == 0) ||
(code_len > kCodeLengthRepeatCode && repeat_length > 0)) {
while (repeat > 0) {
code_lengths[symbol++] = repeat_length;
--repeat;
}
}
if (code_len < kCodeLengthRepeatCode) {
code_lengths[symbol++] = code_len;
if (code_len != 0) prev_code_len = code_len;
} else {
const int extra_bits = code_len - 14;
if (repeat > 0) {
repeat -= 2;
repeat <<= extra_bits;
}
repeat += BrotliReadBits(br, extra_bits) + 3;
repeat_length = (code_len == kCodeLengthRepeatCode ? prev_code_len : 0);
}
}
if (symbol + repeat > num_symbols) {
printf("[ReadHuffmanCodeLengths] symbol + repeat > num_symbols "
"(%d + %d vs %d)\n", symbol, repeat, num_symbols);
goto End;
}
while (repeat-- > 0) code_lengths[symbol++] = repeat_length;
while (symbol < num_symbols) code_lengths[symbol++] = 0;
ok = 1;
End:
BrotliHuffmanTreeRelease(&tree);
return ok;
}
static int ReadHuffmanCode(int alphabet_size,
HuffmanTree* tree,
BrotliBitReader* br) {
int ok = 1;
int simple_code;
uint8_t* code_lengths = NULL;
code_lengths =
(uint8_t*)BrotliSafeMalloc((uint64_t)alphabet_size,
sizeof(*code_lengths));
if (code_lengths == NULL) {
return 0;
}
if (!BrotliReadMoreInput(br)) {
printf("[ReadHuffmanCode] Unexpected end of input.\n");
return 0;
}
simple_code = BrotliReadBits(br, 1);
BROTLI_LOG_UINT(simple_code);
if (simple_code) { // Read symbols, codes & code lengths directly.
int i;
int max_bits_counter = alphabet_size - 1;
int max_bits = 0;
int symbols[4] = { 0 };
const int num_symbols = BrotliReadBits(br, 2) + 1;
while (max_bits_counter) {
max_bits_counter >>= 1;
++max_bits;
}
memset(code_lengths, 0, alphabet_size);
for (i = 0; i < num_symbols; ++i) {
symbols[i] = BrotliReadBits(br, max_bits);
code_lengths[symbols[i]] = 2;
}
code_lengths[symbols[0]] = 1;
switch (num_symbols) {
case 1:
case 3:
break;
case 2:
code_lengths[symbols[1]] = 1;
break;
case 4:
if (BrotliReadBits(br, 1)) {
code_lengths[symbols[2]] = 3;
code_lengths[symbols[3]] = 3;
} else {
code_lengths[symbols[0]] = 2;
}
break;
}
BROTLI_LOG_UINT(num_symbols);
} else { // Decode Huffman-coded code lengths.
int i;
uint8_t code_length_code_lengths[CODE_LENGTH_CODES] = { 0 };
const int num_codes = BrotliReadBits(br, 4) + 3;
BROTLI_LOG_UINT(num_codes);
if (num_codes > CODE_LENGTH_CODES) {
return 0;
}
for (i = BrotliReadBits(br, 1) * 2; i < num_codes; ++i) {
int code_len_idx = kCodeLengthCodeOrder[i];
int v = BrotliReadBits(br, 2);
if (v == 1) {
v = BrotliReadBits(br, 1);
if (v == 0) {
v = 2;
} else {
v = BrotliReadBits(br, 1);
if (v == 0) {
v = 1;
} else {
v = 5;
}
}
} else if (v == 2) {
v = 4;
}
code_length_code_lengths[code_len_idx] = v;
BROTLI_LOG_ARRAY_INDEX(code_length_code_lengths, code_len_idx);
}
ok = ReadHuffmanCodeLengths(code_length_code_lengths, alphabet_size,
code_lengths, br);
}
if (ok) {
ok = BrotliHuffmanTreeBuildImplicit(tree, code_lengths, alphabet_size);
if (!ok) {
printf("[ReadHuffmanCode] HuffmanTreeBuildImplicit failed: ");
PrintUcharVector(code_lengths, alphabet_size);
}
}
free(code_lengths);
return ok;
}
static int ReadCopyDistance(const HuffmanTree* tree,
int num_direct_codes,
int postfix_bits,
uint32_t postfix_mask,
BrotliBitReader* br) {
int code;
int nbits;
int postfix;
int offset;
code = ReadSymbol(tree, br);
if (code < num_direct_codes) {
return code;
}
code -= num_direct_codes;
postfix = code & postfix_mask;
code >>= postfix_bits;
nbits = (code >> 1) + 1;
offset = ((2 + (code & 1)) << nbits) - 4;
return (num_direct_codes +
((offset + BrotliReadBits(br, nbits)) << postfix_bits) +
postfix);
}
static int ReadBlockLength(const HuffmanTree* tree, BrotliBitReader* br) {
int code;
int nbits;
code = ReadSymbol(tree, br);
nbits = kBlockLengthPrefixCode[code].nbits;
return kBlockLengthPrefixCode[code].offset + BrotliReadBits(br, nbits);
}
static void ReadInsertAndCopy(const HuffmanTree* tree,
int* insert_len,
int* copy_len,
int* copy_dist,
BrotliBitReader* br) {
int code;
int range_idx;
int insert_code;
int insert_extra_bits;
int copy_code;
int copy_extra_bits;
code = ReadSymbol(tree, br);
range_idx = code >> 6;
if (range_idx >= 2) {
range_idx -= 2;
*copy_dist = -1;
} else {
*copy_dist = 0;
}
insert_code = kInsertRangeLut[range_idx] + ((code >> 3) & 7);
copy_code = kCopyRangeLut[range_idx] + (code & 7);
*insert_len = kInsertLengthPrefixCode[insert_code].offset;
insert_extra_bits = kInsertLengthPrefixCode[insert_code].nbits;
if (insert_extra_bits > 0) {
*insert_len += BrotliReadBits(br, insert_extra_bits);
}
*copy_len = kCopyLengthPrefixCode[copy_code].offset;
copy_extra_bits = kCopyLengthPrefixCode[copy_code].nbits;
if (copy_extra_bits > 0) {
*copy_len += BrotliReadBits(br, copy_extra_bits);
}
}
static int TranslateShortCodes(int code, int* ringbuffer, size_t index) {
int val;
if (code < NUM_DISTANCE_SHORT_CODES) {
index += kDistanceShortCodeIndexOffset[code];
index &= 3;
val = ringbuffer[index] + kDistanceShortCodeValueOffset[code];
} else {
val = code - NUM_DISTANCE_SHORT_CODES + 1;
}
return val;
}
static void MoveToFront(uint8_t* v, uint8_t index) {
uint8_t value = v[index];
uint8_t i = index;
for (; i; --i) v[i] = v[i - 1];
v[0] = value;
}
static void InverseMoveToFrontTransform(uint8_t* v, int v_len) {
uint8_t mtf[256];
int i;
for (i = 0; i < 256; ++i) {
mtf[i] = i;
}
for (i = 0; i < v_len; ++i) {
uint8_t index = v[i];
v[i] = mtf[index];
if (index) MoveToFront(mtf, index);
}
}
// Contains a collection of huffman trees with the same alphabet size.
typedef struct {
int alphabet_size;
int num_htrees;
HuffmanTree* htrees;
} HuffmanTreeGroup;
static void HuffmanTreeGroupInit(HuffmanTreeGroup* group, int alphabet_size,
int ntrees) {
group->alphabet_size = alphabet_size;
group->num_htrees = ntrees;
group->htrees = (HuffmanTree*)malloc(sizeof(HuffmanTree) * ntrees);
}
static void HuffmanTreeGroupRelease(HuffmanTreeGroup* group) {
int i;
for (i = 0; i < group->num_htrees; ++i) {
BrotliHuffmanTreeRelease(&group->htrees[i]);
}
free(group->htrees);
}
static int HuffmanTreeGroupDecode(HuffmanTreeGroup* group,
BrotliBitReader* br) {
int i;
for (i = 0; i < group->num_htrees; ++i) {
if (!ReadHuffmanCode(group->alphabet_size, &group->htrees[i], br)) {
return 0;
}
}
return 1;
}
static int DecodeContextMap(int context_map_size,
int* num_htrees,
uint8_t** context_map,
BrotliBitReader* br) {
int ok = 1;
if (!BrotliReadMoreInput(br)) {
printf("[DecodeContextMap] Unexpected end of input.\n");
return 0;
}
*num_htrees = DecodeVarLenUint8(br) + 1;
BROTLI_LOG_UINT(context_map_size);
BROTLI_LOG_UINT(*num_htrees);
*context_map = (uint8_t*)malloc(context_map_size);
if (*num_htrees <= 1) {
memset(*context_map, 0, context_map_size);
return 1;
}
{
HuffmanTree tree_index_htree;
int use_rle_for_zeros = BrotliReadBits(br, 1);
int max_run_length_prefix = 0;
int i;
if (use_rle_for_zeros) {
max_run_length_prefix = BrotliReadBits(br, 4) + 1;
}
if (!ReadHuffmanCode(*num_htrees + max_run_length_prefix,
&tree_index_htree, br)) {
return 0;
}
for (i = 0; i < context_map_size;) {
int code;
if (!BrotliReadMoreInput(br)) {
printf("[DecodeContextMap] Unexpected end of input.\n");
ok = 0;
goto End;
}
code = ReadSymbol(&tree_index_htree, br);
if (code == 0) {
(*context_map)[i] = 0;
++i;
} else if (code <= max_run_length_prefix) {
int reps = 1 + (1 << code) + BrotliReadBits(br, code);
while (--reps) {
(*context_map)[i] = 0;
++i;
}
} else {
(*context_map)[i] = code - max_run_length_prefix;
++i;
}
}
End:
BrotliHuffmanTreeRelease(&tree_index_htree);
}
if (BrotliReadBits(br, 1)) {
InverseMoveToFrontTransform(*context_map, context_map_size);
}
return ok;
}
static BROTLI_INLINE void DecodeBlockType(const HuffmanTree* trees,
int tree_type,
int* block_types,
int* ringbuffers,
size_t* indexes,
BrotliBitReader* br) {
int* ringbuffer = ringbuffers + tree_type * 2;
size_t* index = indexes + tree_type;
int type_code = ReadSymbol(trees + tree_type, br);
int block_type;
if (type_code == 0) {
block_type = ringbuffer[*index & 1];
} else if (type_code == 1) {
block_type = ringbuffer[(*index - 1) & 1] + 1;
} else {
block_type = type_code - 2;
}
block_types[tree_type] = block_type;
ringbuffer[(*index) & 1] = block_type;
++(*index);
}
// Copy len bytes from src to dst. It can write up to ten extra bytes
// after the end of the copy.
//
// The main part of this loop is a simple copy of eight bytes at a time until
// we've copied (at least) the requested amount of bytes. However, if dst and
// src are less than eight bytes apart (indicating a repeating pattern of
// length < 8), we first need to expand the pattern in order to get the correct
// results. For instance, if the buffer looks like this, with the eight-byte
// <src> and <dst> patterns marked as intervals:
//
// abxxxxxxxxxxxx
// [------] src
// [------] dst
//
// a single eight-byte copy from <src> to <dst> will repeat the pattern once,
// after which we can move <dst> two bytes without moving <src>:
//
// ababxxxxxxxxxx
// [------] src
// [------] dst
//
// and repeat the exercise until the two no longer overlap.
//
// This allows us to do very well in the special case of one single byte
// repeated many times, without taking a big hit for more general cases.
//
// The worst case of extra writing past the end of the match occurs when
// dst - src == 1 and len == 1; the last copy will read from byte positions
// [0..7] and write to [4..11], whereas it was only supposed to write to
// position 1. Thus, ten excess bytes.
static BROTLI_INLINE void IncrementalCopyFastPath(
uint8_t* dst, const uint8_t* src, int len) {
if (src < dst) {
while (dst - src < 8) {
UNALIGNED_COPY64(dst, src);
len -= dst - src;
dst += dst - src;
}
}
while (len > 0) {
UNALIGNED_COPY64(dst, src);
src += 8;
dst += 8;
len -= 8;
}
}
int BrotliDecompressedSize(size_t encoded_size,
const uint8_t* encoded_buffer,
size_t* decoded_size) {
BrotliMemInput memin;
BrotliInput input = BrotliInitMemInput(encoded_buffer, encoded_size, &memin);
BrotliBitReader br;
if (!BrotliInitBitReader(&br, input)) {
return 0;
}
DecodeWindowBits(&br);
size_t meta_block_len;
int input_end;
int is_uncompressed;
DecodeMetaBlockLength(&br, &meta_block_len, &input_end, &is_uncompressed);
if (!input_end) {
return 0;
}
*decoded_size = meta_block_len;
return 1;
}
int BrotliDecompressBuffer(size_t encoded_size,
const uint8_t* encoded_buffer,
size_t* decoded_size,
uint8_t* decoded_buffer) {
BrotliMemInput memin;
BrotliInput in = BrotliInitMemInput(encoded_buffer, encoded_size, &memin);
BrotliMemOutput mout;
BrotliOutput out = BrotliInitMemOutput(decoded_buffer, *decoded_size, &mout);
int success = BrotliDecompress(in, out);
*decoded_size = mout.pos;
return success;
}
int BrotliDecompress(BrotliInput input, BrotliOutput output) {
int ok = 1;
int i;
size_t pos = 0;
int input_end = 0;
int window_bits = 0;
size_t max_backward_distance;
size_t ringbuffer_size;
size_t ringbuffer_mask;
uint8_t* ringbuffer;
uint8_t* ringbuffer_end;
// This ring buffer holds a few past copy distances that will be used by
// some special distance codes.
int dist_rb[4] = { 16, 15, 11, 4 };
size_t dist_rb_idx = 0;
// The previous 2 bytes used for context.
uint8_t prev_byte1 = 0;
uint8_t prev_byte2 = 0;
HuffmanTreeGroup hgroup[3];
BrotliBitReader br;
if (!BrotliInitBitReader(&br, input)) {
return 0;
}
// Decode window size.
window_bits = DecodeWindowBits(&br);
max_backward_distance = (1 << window_bits) - 16;
static const int kRingBufferWriteAheadSlack = 16;
static const int kMaxDictionaryWordLength = 0;
ringbuffer_size = 1 << window_bits;
ringbuffer_mask = ringbuffer_size - 1;
ringbuffer = (uint8_t*)malloc(ringbuffer_size +
kRingBufferWriteAheadSlack +
kMaxDictionaryWordLength);
ringbuffer_end = ringbuffer + ringbuffer_size;
while (!input_end && ok) {
size_t meta_block_len = 0;
size_t meta_block_end_pos;
int is_uncompressed;
uint32_t block_length[3] = { 1 << 28, 1 << 28, 1 << 28 };
int block_type[3] = { 0 };
int num_block_types[3] = { 1, 1, 1 };
int block_type_rb[6] = { 0, 1, 0, 1, 0, 1 };
size_t block_type_rb_index[3] = { 0 };
HuffmanTree block_type_trees[3];
HuffmanTree block_len_trees[3];
int distance_postfix_bits;
int num_direct_distance_codes;
uint32_t distance_postfix_mask;
int num_distance_codes;
uint8_t* context_map = NULL;
uint8_t* context_modes = NULL;
int num_literal_htrees;
uint8_t* dist_context_map = NULL;
int num_dist_htrees;
int context_offset = 0;
uint8_t* context_map_slice = NULL;
uint8_t literal_htree_index = 0;
int dist_context_offset = 0;
uint8_t* dist_context_map_slice = NULL;
uint8_t dist_htree_index = 0;
int context_lookup_offset1 = 0;
int context_lookup_offset2 = 0;
uint8_t context_mode;
for (i = 0; i < 3; ++i) {
hgroup[i].num_htrees = 0;
hgroup[i].htrees = NULL;
block_type_trees[i].root_ = NULL;
block_len_trees[i].root_ = NULL;
}
if (!BrotliReadMoreInput(&br)) {
printf("[BrotliDecompress] Unexpected end of input.\n");
ok = 0;
goto End;
}
BROTLI_LOG_UINT(pos);
DecodeMetaBlockLength(&br, &meta_block_len, &input_end, &is_uncompressed);
BROTLI_LOG_UINT(meta_block_len);
if (meta_block_len == 0) {
goto End;
}
meta_block_end_pos = pos + meta_block_len;
if (is_uncompressed) {
BrotliSetBitPos(&br, (br.bit_pos_ + 7) & ~7);
for (; pos < meta_block_end_pos; ++pos) {
ringbuffer[pos & ringbuffer_mask] = BrotliReadBits(&br, 8);
if ((pos & ringbuffer_mask) == ringbuffer_mask) {
if (BrotliWrite(output, ringbuffer, ringbuffer_size) < 0) {
ok = 0;
goto End;
}
}
}
goto End;
}
for (i = 0; i < 3; ++i) {
block_type_trees[i].root_ = NULL;
block_len_trees[i].root_ = NULL;
num_block_types[i] = DecodeVarLenUint8(&br) + 1;
if (num_block_types[i] >= 2) {
if (!ReadHuffmanCode(
num_block_types[i] + 2, &block_type_trees[i], &br) ||
!ReadHuffmanCode(kNumBlockLengthCodes, &block_len_trees[i], &br)) {
ok = 0;
goto End;
}
block_length[i] = ReadBlockLength(&block_len_trees[i], &br);
block_type_rb_index[i] = 1;
}
}
BROTLI_LOG_UINT(num_block_types[0]);
BROTLI_LOG_UINT(num_block_types[1]);
BROTLI_LOG_UINT(num_block_types[2]);
BROTLI_LOG_UINT(block_length[0]);
BROTLI_LOG_UINT(block_length[1]);
BROTLI_LOG_UINT(block_length[2]);
if (!BrotliReadMoreInput(&br)) {
printf("[BrotliDecompress] Unexpected end of input.\n");
ok = 0;
goto End;
}
distance_postfix_bits = BrotliReadBits(&br, 2);
num_direct_distance_codes = NUM_DISTANCE_SHORT_CODES +
(BrotliReadBits(&br, 4) << distance_postfix_bits);
distance_postfix_mask = (1 << distance_postfix_bits) - 1;
num_distance_codes = (num_direct_distance_codes +
(48 << distance_postfix_bits));
context_modes = (uint8_t*)malloc(num_block_types[0]);
for (i = 0; i < num_block_types[0]; ++i) {
context_modes[i] = BrotliReadBits(&br, 2) << 1;
BROTLI_LOG_ARRAY_INDEX(context_modes, i);
}
BROTLI_LOG_UINT(num_direct_distance_codes);
BROTLI_LOG_UINT(distance_postfix_bits);
if (!DecodeContextMap(num_block_types[0] << kLiteralContextBits,
&num_literal_htrees, &context_map, &br) ||
!DecodeContextMap(num_block_types[2] << kDistanceContextBits,
&num_dist_htrees, &dist_context_map, &br)) {
ok = 0;
goto End;
}
HuffmanTreeGroupInit(&hgroup[0], kNumLiteralCodes, num_literal_htrees);
HuffmanTreeGroupInit(&hgroup[1], kNumInsertAndCopyCodes,
num_block_types[1]);
HuffmanTreeGroupInit(&hgroup[2], num_distance_codes, num_dist_htrees);
for (i = 0; i < 3; ++i) {
if (!HuffmanTreeGroupDecode(&hgroup[i], &br)) {
ok = 0;
goto End;
}
}
context_map_slice = context_map;
dist_context_map_slice = dist_context_map;
context_mode = context_modes[block_type[0]];
context_lookup_offset1 = kContextLookupOffsets[context_mode];
context_lookup_offset2 = kContextLookupOffsets[context_mode + 1];
while (pos < meta_block_end_pos) {
int insert_length;
int copy_length;
int distance_code;
int distance;
size_t max_distance;
uint8_t context;
int j;
const uint8_t* copy_src;
uint8_t* copy_dst;
if (!BrotliReadMoreInput(&br)) {
printf("[BrotliDecompress] Unexpected end of input.\n");
ok = 0;
goto End;
}
if (block_length[1] == 0) {
DecodeBlockType(block_type_trees, 1, block_type, block_type_rb,
block_type_rb_index, &br);
block_length[1] = ReadBlockLength(&block_len_trees[1], &br);
}
--block_length[1];
ReadInsertAndCopy(&hgroup[1].htrees[block_type[1]],
&insert_length, &copy_length, &distance_code, &br);
BROTLI_LOG_UINT(insert_length);
BROTLI_LOG_UINT(copy_length);
BROTLI_LOG_UINT(distance_code);
for (j = 0; j < insert_length; ++j) {
if (!BrotliReadMoreInput(&br)) {
printf("[BrotliDecompress] Unexpected end of input.\n");
ok = 0;
goto End;
}
if (block_length[0] == 0) {
DecodeBlockType(block_type_trees, 0, block_type, block_type_rb,
block_type_rb_index, &br);
block_length[0] = ReadBlockLength(&block_len_trees[0], &br);
context_offset = block_type[0] << kLiteralContextBits;
context_map_slice = context_map + context_offset;
context_mode = context_modes[block_type[0]];
context_lookup_offset1 = kContextLookupOffsets[context_mode];
context_lookup_offset2 = kContextLookupOffsets[context_mode + 1];
}
context = (kContextLookup[context_lookup_offset1 + prev_byte1] |
kContextLookup[context_lookup_offset2 + prev_byte2]);
BROTLI_LOG_UINT(context);
literal_htree_index = context_map_slice[context];
--block_length[0];
prev_byte2 = prev_byte1;
prev_byte1 = ReadSymbol(&hgroup[0].htrees[literal_htree_index], &br);
ringbuffer[pos & ringbuffer_mask] = prev_byte1;
BROTLI_LOG_UINT(literal_htree_index);
BROTLI_LOG_ARRAY_INDEX(ringbuffer, pos & ringbuffer_mask);
if ((pos & ringbuffer_mask) == ringbuffer_mask) {
if (BrotliWrite(output, ringbuffer, ringbuffer_size) < 0) {
ok = 0;
goto End;
}
}
++pos;
}
if (pos == meta_block_end_pos) break;
if (distance_code < 0) {
if (!BrotliReadMoreInput(&br)) {
printf("[BrotliDecompress] Unexpected end of input.\n");
ok = 0;
goto End;
}
if (block_length[2] == 0) {
DecodeBlockType(block_type_trees, 2, block_type, block_type_rb,
block_type_rb_index, &br);
block_length[2] = ReadBlockLength(&block_len_trees[2], &br);
dist_htree_index = block_type[2];
dist_context_offset = block_type[2] << kDistanceContextBits;
dist_context_map_slice = dist_context_map + dist_context_offset;
}
--block_length[2];
uint8_t context = copy_length > 4 ? 3 : copy_length - 2;
dist_htree_index = dist_context_map_slice[context];
distance_code = ReadCopyDistance(&hgroup[2].htrees[dist_htree_index],
num_direct_distance_codes,
distance_postfix_bits,
distance_postfix_mask,
&br);
}
// Convert the distance code to the actual distance by possibly looking
// up past distnaces from the ringbuffer.
distance = TranslateShortCodes(distance_code, dist_rb, dist_rb_idx);
if (distance_code > 0) {
dist_rb[dist_rb_idx & 3] = distance;
++dist_rb_idx;
}
BROTLI_LOG_UINT(distance);
max_distance = max_backward_distance;
if (pos < max_distance) {
max_distance = pos;
}
copy_dst = &ringbuffer[pos & ringbuffer_mask];
if ((size_t)distance > max_distance) {
printf("Invalid backward reference. pos: %lu distance: %d "
"len: %d end: %lu\n", (unsigned long)pos, distance, copy_length,
(unsigned long)meta_block_end_pos);
ok = 0;
goto End;
} else {
if (pos + copy_length > meta_block_end_pos) {
printf("Invalid backward reference. pos: %lu distance: %d "
"len: %d end: %lu\n", (unsigned long)pos, distance,
copy_length, (unsigned long)meta_block_end_pos);
ok = 0;
goto End;
}
copy_src = &ringbuffer[(pos - distance) & ringbuffer_mask];
#if (defined(__x86_64__) || defined(_M_X64))
if (copy_src + copy_length <= ringbuffer_end &&
copy_dst + copy_length < ringbuffer_end) {
if (copy_length <= 16 && distance >= 8) {
UNALIGNED_COPY64(copy_dst, copy_src);
UNALIGNED_COPY64(copy_dst + 8, copy_src + 8);
} else {
IncrementalCopyFastPath(copy_dst, copy_src, copy_length);
}
pos += copy_length;
copy_length = 0;
}
#endif
for (j = 0; j < copy_length; ++j) {
ringbuffer[pos & ringbuffer_mask] =
ringbuffer[(pos - distance) & ringbuffer_mask];
if ((pos & ringbuffer_mask) == ringbuffer_mask) {
if (BrotliWrite(output, ringbuffer, ringbuffer_size) < 0) {
ok = 0;
goto End;
}
}
++pos;
}
}
// When we get here, we must have inserted at least one literal and made
// a copy of at least length two, therefore accessing the last 2 bytes is
// valid.
prev_byte1 = ringbuffer[(pos - 1) & ringbuffer_mask];
prev_byte2 = ringbuffer[(pos - 2) & ringbuffer_mask];
}
End:
free(context_modes);
free(context_map);
free(dist_context_map);
for (i = 0; i < 3; ++i) {
HuffmanTreeGroupRelease(&hgroup[i]);
BrotliHuffmanTreeRelease(&block_type_trees[i]);
BrotliHuffmanTreeRelease(&block_len_trees[i]);
}
}
if (BrotliWrite(output, ringbuffer, pos & ringbuffer_mask) < 0) {
ok = 0;
}
free(ringbuffer);
return ok;
}
#if defined(__cplusplus) || defined(c_plusplus)
} // extern "C"
#endif