Bug fixes for the brotli encoder and decoder.
This commit is contained in:
+53
-13
@@ -199,6 +199,9 @@ static int ReadHuffmanCodeLengths(
|
|||||||
repeat <<= extra_bits;
|
repeat <<= extra_bits;
|
||||||
}
|
}
|
||||||
repeat += BrotliReadBits(br, extra_bits) + 3;
|
repeat += BrotliReadBits(br, extra_bits) + 3;
|
||||||
|
if (repeat + symbol > num_symbols) {
|
||||||
|
goto End;
|
||||||
|
}
|
||||||
if (code_len == kCodeLengthRepeatCode) {
|
if (code_len == kCodeLengthRepeatCode) {
|
||||||
repeat_length = prev_code_len;
|
repeat_length = prev_code_len;
|
||||||
for (; i < repeat; ++i) {
|
for (; i < repeat; ++i) {
|
||||||
@@ -258,7 +261,7 @@ static int ReadHuffmanCode(int alphabet_size,
|
|||||||
}
|
}
|
||||||
memset(code_lengths, 0, alphabet_size);
|
memset(code_lengths, 0, alphabet_size);
|
||||||
for (i = 0; i < num_symbols; ++i) {
|
for (i = 0; i < num_symbols; ++i) {
|
||||||
symbols[i] = BrotliReadBits(br, max_bits);
|
symbols[i] = BrotliReadBits(br, max_bits) % alphabet_size;
|
||||||
code_lengths[symbols[i]] = 2;
|
code_lengths[symbols[i]] = 2;
|
||||||
}
|
}
|
||||||
code_lengths[symbols[0]] = 1;
|
code_lengths[symbols[0]] = 1;
|
||||||
@@ -386,8 +389,8 @@ static void ReadInsertAndCopy(const HuffmanTree* tree,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int TranslateShortCodes(int code, int* ringbuffer, size_t index) {
|
static size_t TranslateShortCodes(int code, int* ringbuffer, size_t index) {
|
||||||
int val;
|
size_t val;
|
||||||
if (code < NUM_DISTANCE_SHORT_CODES) {
|
if (code < NUM_DISTANCE_SHORT_CODES) {
|
||||||
index += kDistanceShortCodeIndexOffset[code];
|
index += kDistanceShortCodeIndexOffset[code];
|
||||||
index &= 3;
|
index &= 3;
|
||||||
@@ -427,9 +430,13 @@ typedef struct {
|
|||||||
|
|
||||||
static void HuffmanTreeGroupInit(HuffmanTreeGroup* group, int alphabet_size,
|
static void HuffmanTreeGroupInit(HuffmanTreeGroup* group, int alphabet_size,
|
||||||
int ntrees) {
|
int ntrees) {
|
||||||
|
int i;
|
||||||
group->alphabet_size = alphabet_size;
|
group->alphabet_size = alphabet_size;
|
||||||
group->num_htrees = ntrees;
|
group->num_htrees = ntrees;
|
||||||
group->htrees = (HuffmanTree*)malloc(sizeof(HuffmanTree) * ntrees);
|
group->htrees = (HuffmanTree*)malloc(sizeof(HuffmanTree) * ntrees);
|
||||||
|
for (i = 0; i < ntrees; ++i) {
|
||||||
|
group->htrees[i].root_ = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void HuffmanTreeGroupRelease(HuffmanTreeGroup* group) {
|
static void HuffmanTreeGroupRelease(HuffmanTreeGroup* group) {
|
||||||
@@ -437,7 +444,9 @@ static void HuffmanTreeGroupRelease(HuffmanTreeGroup* group) {
|
|||||||
for (i = 0; i < group->num_htrees; ++i) {
|
for (i = 0; i < group->num_htrees; ++i) {
|
||||||
BrotliHuffmanTreeRelease(&group->htrees[i]);
|
BrotliHuffmanTreeRelease(&group->htrees[i]);
|
||||||
}
|
}
|
||||||
|
if (group->htrees) {
|
||||||
free(group->htrees);
|
free(group->htrees);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int HuffmanTreeGroupDecode(HuffmanTreeGroup* group,
|
static int HuffmanTreeGroupDecode(HuffmanTreeGroup* group,
|
||||||
@@ -466,6 +475,9 @@ static int DecodeContextMap(int context_map_size,
|
|||||||
BROTLI_LOG_UINT(*num_htrees);
|
BROTLI_LOG_UINT(*num_htrees);
|
||||||
|
|
||||||
*context_map = (uint8_t*)malloc(context_map_size);
|
*context_map = (uint8_t*)malloc(context_map_size);
|
||||||
|
if (*context_map == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
if (*num_htrees <= 1) {
|
if (*num_htrees <= 1) {
|
||||||
memset(*context_map, 0, context_map_size);
|
memset(*context_map, 0, context_map_size);
|
||||||
return 1;
|
return 1;
|
||||||
@@ -497,6 +509,10 @@ static int DecodeContextMap(int context_map_size,
|
|||||||
} else if (code <= max_run_length_prefix) {
|
} else if (code <= max_run_length_prefix) {
|
||||||
int reps = 1 + (1 << code) + BrotliReadBits(br, code);
|
int reps = 1 + (1 << code) + BrotliReadBits(br, code);
|
||||||
while (--reps) {
|
while (--reps) {
|
||||||
|
if (i >= context_map_size) {
|
||||||
|
ok = 0;
|
||||||
|
goto End;
|
||||||
|
}
|
||||||
(*context_map)[i] = 0;
|
(*context_map)[i] = 0;
|
||||||
++i;
|
++i;
|
||||||
}
|
}
|
||||||
@@ -514,7 +530,8 @@ static int DecodeContextMap(int context_map_size,
|
|||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
static BROTLI_INLINE void DecodeBlockType(const HuffmanTree* trees,
|
static BROTLI_INLINE void DecodeBlockType(const int max_block_type,
|
||||||
|
const HuffmanTree* trees,
|
||||||
int tree_type,
|
int tree_type,
|
||||||
int* block_types,
|
int* block_types,
|
||||||
int* ringbuffers,
|
int* ringbuffers,
|
||||||
@@ -531,6 +548,9 @@ static BROTLI_INLINE void DecodeBlockType(const HuffmanTree* trees,
|
|||||||
} else {
|
} else {
|
||||||
block_type = type_code - 2;
|
block_type = type_code - 2;
|
||||||
}
|
}
|
||||||
|
if (block_type >= max_block_type) {
|
||||||
|
block_type -= max_block_type;
|
||||||
|
}
|
||||||
block_types[tree_type] = block_type;
|
block_types[tree_type] = block_type;
|
||||||
ringbuffer[(*index) & 1] = block_type;
|
ringbuffer[(*index) & 1] = block_type;
|
||||||
++(*index);
|
++(*index);
|
||||||
@@ -639,7 +659,9 @@ int BrotliDecompress(BrotliInput input, BrotliOutput output) {
|
|||||||
HuffmanTreeGroup hgroup[3];
|
HuffmanTreeGroup hgroup[3];
|
||||||
BrotliBitReader br;
|
BrotliBitReader br;
|
||||||
|
|
||||||
static const int kRingBufferWriteAheadSlack = 16;
|
/* 16 bytes would be enough, but we add some more slack for transforms */
|
||||||
|
/* to work at the end of the ringbuffer. */
|
||||||
|
static const int kRingBufferWriteAheadSlack = 128;
|
||||||
|
|
||||||
static const int kMaxDictionaryWordLength = 0;
|
static const int kMaxDictionaryWordLength = 0;
|
||||||
|
|
||||||
@@ -656,6 +678,9 @@ int BrotliDecompress(BrotliInput input, BrotliOutput output) {
|
|||||||
ringbuffer = (uint8_t*)malloc(ringbuffer_size +
|
ringbuffer = (uint8_t*)malloc(ringbuffer_size +
|
||||||
kRingBufferWriteAheadSlack +
|
kRingBufferWriteAheadSlack +
|
||||||
kMaxDictionaryWordLength);
|
kMaxDictionaryWordLength);
|
||||||
|
if (!ringbuffer) {
|
||||||
|
ok = 0;
|
||||||
|
}
|
||||||
ringbuffer_end = ringbuffer + ringbuffer_size;
|
ringbuffer_end = ringbuffer + ringbuffer_size;
|
||||||
|
|
||||||
while (!input_end && ok) {
|
while (!input_end && ok) {
|
||||||
@@ -755,6 +780,10 @@ int BrotliDecompress(BrotliInput input, BrotliOutput output) {
|
|||||||
num_distance_codes = (num_direct_distance_codes +
|
num_distance_codes = (num_direct_distance_codes +
|
||||||
(48 << distance_postfix_bits));
|
(48 << distance_postfix_bits));
|
||||||
context_modes = (uint8_t*)malloc(num_block_types[0]);
|
context_modes = (uint8_t*)malloc(num_block_types[0]);
|
||||||
|
if (context_modes == 0) {
|
||||||
|
ok = 0;
|
||||||
|
goto End;
|
||||||
|
}
|
||||||
for (i = 0; i < num_block_types[0]; ++i) {
|
for (i = 0; i < num_block_types[0]; ++i) {
|
||||||
context_modes[i] = BrotliReadBits(&br, 2) << 1;
|
context_modes[i] = BrotliReadBits(&br, 2) << 1;
|
||||||
BROTLI_LOG_ARRAY_INDEX(context_modes, i);
|
BROTLI_LOG_ARRAY_INDEX(context_modes, i);
|
||||||
@@ -792,7 +821,7 @@ int BrotliDecompress(BrotliInput input, BrotliOutput output) {
|
|||||||
int insert_length;
|
int insert_length;
|
||||||
int copy_length;
|
int copy_length;
|
||||||
int distance_code;
|
int distance_code;
|
||||||
int distance;
|
size_t distance;
|
||||||
size_t max_distance;
|
size_t max_distance;
|
||||||
uint8_t context;
|
uint8_t context;
|
||||||
int j;
|
int j;
|
||||||
@@ -804,7 +833,8 @@ int BrotliDecompress(BrotliInput input, BrotliOutput output) {
|
|||||||
goto End;
|
goto End;
|
||||||
}
|
}
|
||||||
if (block_length[1] == 0) {
|
if (block_length[1] == 0) {
|
||||||
DecodeBlockType(block_type_trees, 1, block_type, block_type_rb,
|
DecodeBlockType(num_block_types[1],
|
||||||
|
block_type_trees, 1, block_type, block_type_rb,
|
||||||
block_type_rb_index, &br);
|
block_type_rb_index, &br);
|
||||||
block_length[1] = ReadBlockLength(&block_len_trees[1], &br);
|
block_length[1] = ReadBlockLength(&block_len_trees[1], &br);
|
||||||
}
|
}
|
||||||
@@ -821,7 +851,8 @@ int BrotliDecompress(BrotliInput input, BrotliOutput output) {
|
|||||||
goto End;
|
goto End;
|
||||||
}
|
}
|
||||||
if (block_length[0] == 0) {
|
if (block_length[0] == 0) {
|
||||||
DecodeBlockType(block_type_trees, 0, block_type, block_type_rb,
|
DecodeBlockType(num_block_types[0],
|
||||||
|
block_type_trees, 0, block_type, block_type_rb,
|
||||||
block_type_rb_index, &br);
|
block_type_rb_index, &br);
|
||||||
block_length[0] = ReadBlockLength(&block_len_trees[0], &br);
|
block_length[0] = ReadBlockLength(&block_len_trees[0], &br);
|
||||||
context_offset = block_type[0] << kLiteralContextBits;
|
context_offset = block_type[0] << kLiteralContextBits;
|
||||||
@@ -858,7 +889,8 @@ int BrotliDecompress(BrotliInput input, BrotliOutput output) {
|
|||||||
goto End;
|
goto End;
|
||||||
}
|
}
|
||||||
if (block_length[2] == 0) {
|
if (block_length[2] == 0) {
|
||||||
DecodeBlockType(block_type_trees, 2, block_type, block_type_rb,
|
DecodeBlockType(num_block_types[2],
|
||||||
|
block_type_trees, 2, block_type, block_type_rb,
|
||||||
block_type_rb_index, &br);
|
block_type_rb_index, &br);
|
||||||
block_length[2] = ReadBlockLength(&block_len_trees[2], &br);
|
block_length[2] = ReadBlockLength(&block_len_trees[2], &br);
|
||||||
dist_htree_index = block_type[2];
|
dist_htree_index = block_type[2];
|
||||||
@@ -891,16 +923,16 @@ int BrotliDecompress(BrotliInput input, BrotliOutput output) {
|
|||||||
|
|
||||||
copy_dst = &ringbuffer[pos & ringbuffer_mask];
|
copy_dst = &ringbuffer[pos & ringbuffer_mask];
|
||||||
|
|
||||||
if ((size_t)distance > max_distance) {
|
if (distance > max_distance) {
|
||||||
printf("Invalid backward reference. pos: %lu distance: %d "
|
printf("Invalid backward reference. pos: %lu distance: %d "
|
||||||
"len: %d end: %lu\n", (unsigned long)pos, distance, copy_length,
|
"len: %d end: %lu\n", (unsigned long)pos, (int)distance,
|
||||||
(unsigned long)meta_block_end_pos);
|
copy_length, (unsigned long)meta_block_end_pos);
|
||||||
ok = 0;
|
ok = 0;
|
||||||
goto End;
|
goto End;
|
||||||
} else {
|
} else {
|
||||||
if (pos + copy_length > meta_block_end_pos) {
|
if (pos + copy_length > meta_block_end_pos) {
|
||||||
printf("Invalid backward reference. pos: %lu distance: %d "
|
printf("Invalid backward reference. pos: %lu distance: %d "
|
||||||
"len: %d end: %lu\n", (unsigned long)pos, distance,
|
"len: %d end: %lu\n", (unsigned long)pos, (int)distance,
|
||||||
copy_length, (unsigned long)meta_block_end_pos);
|
copy_length, (unsigned long)meta_block_end_pos);
|
||||||
ok = 0;
|
ok = 0;
|
||||||
goto End;
|
goto End;
|
||||||
@@ -942,9 +974,15 @@ int BrotliDecompress(BrotliInput input, BrotliOutput output) {
|
|||||||
prev_byte2 = ringbuffer[(pos - 2) & ringbuffer_mask];
|
prev_byte2 = ringbuffer[(pos - 2) & ringbuffer_mask];
|
||||||
}
|
}
|
||||||
End:
|
End:
|
||||||
|
if (context_modes != 0) {
|
||||||
free(context_modes);
|
free(context_modes);
|
||||||
|
}
|
||||||
|
if (context_map != 0) {
|
||||||
free(context_map);
|
free(context_map);
|
||||||
|
}
|
||||||
|
if (dist_context_map != 0) {
|
||||||
free(dist_context_map);
|
free(dist_context_map);
|
||||||
|
}
|
||||||
for (i = 0; i < 3; ++i) {
|
for (i = 0; i < 3; ++i) {
|
||||||
HuffmanTreeGroupRelease(&hgroup[i]);
|
HuffmanTreeGroupRelease(&hgroup[i]);
|
||||||
BrotliHuffmanTreeRelease(&block_type_trees[i]);
|
BrotliHuffmanTreeRelease(&block_type_trees[i]);
|
||||||
@@ -952,10 +990,12 @@ int BrotliDecompress(BrotliInput input, BrotliOutput output) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ringbuffer != 0) {
|
||||||
if (BrotliWrite(output, ringbuffer, pos & ringbuffer_mask) < 0) {
|
if (BrotliWrite(output, ringbuffer, pos & ringbuffer_mask) < 0) {
|
||||||
ok = 0;
|
ok = 0;
|
||||||
}
|
}
|
||||||
free(ringbuffer);
|
free(ringbuffer);
|
||||||
|
}
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ static void AssignChildren(HuffmanTree* const tree,
|
|||||||
|
|
||||||
static int TreeInit(HuffmanTree* const tree, int num_leaves) {
|
static int TreeInit(HuffmanTree* const tree, int num_leaves) {
|
||||||
assert(tree != NULL);
|
assert(tree != NULL);
|
||||||
|
tree->root_ = NULL;
|
||||||
if (num_leaves == 0) return 0;
|
if (num_leaves == 0) return 0;
|
||||||
/* We allocate maximum possible nodes in the tree at once. */
|
/* We allocate maximum possible nodes in the tree at once. */
|
||||||
/* Note that a Huffman tree is a full binary tree; and in a full binary */
|
/* Note that a Huffman tree is a full binary tree; and in a full binary */
|
||||||
@@ -70,7 +71,9 @@ static int TreeInit(HuffmanTree* const tree, int num_leaves) {
|
|||||||
|
|
||||||
void BrotliHuffmanTreeRelease(HuffmanTree* const tree) {
|
void BrotliHuffmanTreeRelease(HuffmanTree* const tree) {
|
||||||
if (tree != NULL) {
|
if (tree != NULL) {
|
||||||
|
if (tree->root_ != NULL) {
|
||||||
free(tree->root_);
|
free(tree->root_);
|
||||||
|
}
|
||||||
tree->root_ = NULL;
|
tree->root_ = NULL;
|
||||||
tree->max_nodes_ = 0;
|
tree->max_nodes_ = 0;
|
||||||
tree->num_nodes_ = 0;
|
tree->num_nodes_ = 0;
|
||||||
|
|||||||
@@ -82,18 +82,6 @@ void CopyCommandsToByteArray(const std::vector<Command>& cmds,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<int kSize>
|
|
||||||
double HistogramAddEval(const Histogram<kSize>& a,
|
|
||||||
const Histogram<kSize>& b) {
|
|
||||||
int total = a.total_count_ + b.total_count_;
|
|
||||||
double retval = total * FastLog2(total);
|
|
||||||
for (int i = 0; i < kSize; ++i) {
|
|
||||||
int count = a.data_[i] + b.data_[i];
|
|
||||||
retval -= count * FastLog2(count);
|
|
||||||
}
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename HistogramType, typename DataType>
|
template<typename HistogramType, typename DataType>
|
||||||
void InitialEntropyCodes(const DataType* data, size_t length,
|
void InitialEntropyCodes(const DataType* data, size_t length,
|
||||||
int literals_per_histogram,
|
int literals_per_histogram,
|
||||||
@@ -120,28 +108,19 @@ void InitialEntropyCodes(const DataType* data, size_t length,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename HistogramType>
|
|
||||||
int FindClosest(const HistogramType& sample,
|
|
||||||
const std::vector<HistogramType>& vec) {
|
|
||||||
double best_distance = 1e99;
|
|
||||||
int best_ix = 0;
|
|
||||||
for (int i = 0; i < vec.size(); ++i) {
|
|
||||||
double distance = HistogramAddEval(sample, vec[i]);
|
|
||||||
if (distance < best_distance) {
|
|
||||||
best_ix = i;
|
|
||||||
best_distance = distance;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return best_ix;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename HistogramType, typename DataType>
|
template<typename HistogramType, typename DataType>
|
||||||
void RandomSample(unsigned int* seed,
|
void RandomSample(unsigned int* seed,
|
||||||
const DataType* data,
|
const DataType* data,
|
||||||
size_t length,
|
size_t length,
|
||||||
size_t stride,
|
size_t stride,
|
||||||
HistogramType* sample) {
|
HistogramType* sample) {
|
||||||
size_t pos = rand_r(seed) % (length - stride);
|
size_t pos = 0;
|
||||||
|
if (stride >= length) {
|
||||||
|
pos = 0;
|
||||||
|
stride = length;
|
||||||
|
} else {
|
||||||
|
pos = rand_r(seed) % (length - stride + 1);
|
||||||
|
}
|
||||||
sample->Add(data + pos, stride);
|
sample->Add(data + pos, stride);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -149,13 +128,14 @@ template<typename HistogramType, typename DataType>
|
|||||||
void RefineEntropyCodes(const DataType* data, size_t length,
|
void RefineEntropyCodes(const DataType* data, size_t length,
|
||||||
size_t stride,
|
size_t stride,
|
||||||
std::vector<HistogramType>* vec) {
|
std::vector<HistogramType>* vec) {
|
||||||
const int iters =
|
int iters =
|
||||||
kIterMulForRefining * length / stride + kMinItersForRefining;
|
kIterMulForRefining * length / stride + kMinItersForRefining;
|
||||||
unsigned int seed = 7;
|
unsigned int seed = 7;
|
||||||
|
iters = ((iters + vec->size() - 1) / vec->size()) * vec->size();
|
||||||
for (int iter = 0; iter < iters; ++iter) {
|
for (int iter = 0; iter < iters; ++iter) {
|
||||||
HistogramType sample;
|
HistogramType sample;
|
||||||
RandomSample(&seed, data, length, stride, &sample);
|
RandomSample(&seed, data, length, stride, &sample);
|
||||||
int ix = FindClosest(sample, *vec);
|
int ix = iter % vec->size();
|
||||||
(*vec)[ix].AddHistogram(sample);
|
(*vec)[ix].AddHistogram(sample);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-2
@@ -205,7 +205,9 @@ class HashLongestMatch {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
prev_ix &= ring_buffer_mask;
|
prev_ix &= ring_buffer_mask;
|
||||||
if (data[cur_ix_masked + best_len] != data[prev_ix + best_len]) {
|
if (cur_ix_masked + best_len > ring_buffer_mask ||
|
||||||
|
prev_ix + best_len > ring_buffer_mask ||
|
||||||
|
data[cur_ix_masked + best_len] != data[prev_ix + best_len]) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const size_t len =
|
const size_t len =
|
||||||
@@ -277,7 +279,9 @@ class HashLongestMatch {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
prev_ix &= ring_buffer_mask;
|
prev_ix &= ring_buffer_mask;
|
||||||
if (data[cur_ix_masked + best_len] != data[prev_ix + best_len]) {
|
if (cur_ix_masked + best_len > ring_buffer_mask ||
|
||||||
|
prev_ix + best_len > ring_buffer_mask ||
|
||||||
|
data[cur_ix_masked + best_len] != data[prev_ix + best_len]) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const size_t len =
|
const size_t len =
|
||||||
|
|||||||
Reference in New Issue
Block a user