// 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 #include #include #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 = %zd\n", __func__, #name, (size_t)name) #define BROTLI_LOG_ARRAY_INDEX(array_name, idx) \ printf("[%s] %s[%zd] = %zd\n", __func__, #array_name, \ (size_t)idx, (size_t)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 kCodeLengthLiterals = 16; static const int kCodeLengthRepeatCode = 16; static const int kCodeLengthExtraBits[3] = { 2, 3, 7 }; static const int kCodeLengthRepeatOffsets[3] = { 3, 3, 11 }; static const int kNumLiteralCodes = 256; static const int kNumInsertAndCopyCodes = 704; static const int kNumBlockLengthCodes = 26; #define CODE_LENGTH_CODES 19 static const uint8_t kCodeLengthCodeOrder[CODE_LENGTH_CODES] = { 17, 18, 0, 1, 2, 3, 4, 5, 16, 6, 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 int DecodeSize(BrotliBitReader* br, size_t* len) { int size_bytes = BrotliReadBits(br, 3); *len = 0; int i = 0; for (; i < size_bytes; ++i) { *len |= BrotliReadBits(br, 8) << (i * 8); } return !br->error_; } static int DecodeMetaBlockLength(int input_size_bits, size_t remaining_length, BrotliBitReader* br, size_t* meta_block_length) { if (BrotliReadBits(br, 1)) { *meta_block_length = remaining_length; return 1; } *meta_block_length = 0; int shift = 0; while (input_size_bits > 0) { *meta_block_length |= BrotliReadBits(br, 8) << shift; input_size_bits -= 8; shift += 8; } if (input_size_bits > 0) { *meta_block_length |= BrotliReadBits(br, input_size_bits) << shift; } ++(*meta_block_length); return !br->error_; } // Decodes the next Huffman code from bit-stream. // FillBitWindow(br) needs to be called at minimum every second call // to ReadSymbol, in order to pre-fetch enough bits. static BROTLI_INLINE int ReadSymbol(const HuffmanTree* tree, BrotliBitReader* br) { if (tree->fixed_bit_length_ > 0) { return BrotliReadBits(br, tree->fixed_bit_length_); } const HuffmanTreeNode* node = tree->root_; 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 PrintIntVector(const int* v, int len) { while (len-- > 0) printf(" %d", *v++); printf("\n"); } static int ReadHuffmanCodeLengths( const int* code_length_code_lengths, int num_symbols, int* code_lengths, BrotliBitReader* br) { int ok = 0; int symbol; int max_symbol; int prev_code_len = kDefaultCodeLength; HuffmanTree tree; if (!HuffmanTreeBuildImplicit(&tree, code_length_code_lengths, CODE_LENGTH_CODES)) { printf("[ReadHuffmanCodeLengths] Building code length tree failed: "); PrintIntVector(code_length_code_lengths, CODE_LENGTH_CODES); return 0; } int use_length = BrotliReadBits(br, 1); BROTLI_LOG_UINT(use_length); if (use_length) { const int length_nbits = 2 + 2 * BrotliReadBits(br, 3); max_symbol = 2 + BrotliReadBits(br, length_nbits); BROTLI_LOG_UINT(length_nbits); 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 < num_symbols) { int code_len; if (max_symbol-- == 0) break; BrotliFillBitWindow(br); code_len = ReadSymbol(&tree, br); BROTLI_LOG_UINT(symbol); BROTLI_LOG_UINT(code_len); if (code_len < kCodeLengthLiterals) { code_lengths[symbol++] = code_len; if (code_len != 0) prev_code_len = code_len; } else { const int use_prev = (code_len == kCodeLengthRepeatCode); const int slot = code_len - kCodeLengthLiterals; const int extra_bits = kCodeLengthExtraBits[slot]; const int repeat_offset = kCodeLengthRepeatOffsets[slot]; const int length = use_prev ? prev_code_len : 0; int repeat = BrotliReadBits(br, extra_bits) + repeat_offset; BROTLI_LOG_UINT(repeat); BROTLI_LOG_UINT(length); if (symbol + repeat > num_symbols) { printf("[ReadHuffmanCodeLengths] symbol + repeat > num_symbols " "(%d + %d vs %d)\n", symbol, repeat, num_symbols); goto End; } else { while (repeat-- > 0) { code_lengths[symbol++] = length; } } } } while (symbol < num_symbols) code_lengths[symbol++] = 0; ok = 1; End: HuffmanTreeRelease(&tree); return ok; } static const int64_t kUnitInterval = 1LL<<30; static int RepairHuffmanCodeLengths(int num_symbols, int* code_lengths) { int i; int64_t space = kUnitInterval; int max_length = 0; for(i = 0; i < num_symbols; i++) if (code_lengths[i] != 0) { if (code_lengths[i] > max_length) max_length = code_lengths[i]; space -= kUnitInterval >> code_lengths[i]; } // The code which contains one symbol of length one cannot be made optimal. if (max_length == 1) return 1; if (space < 0) { int count_longest = 0; for(i = 0; i < num_symbols; i++) { if (code_lengths[i] == max_length) count_longest++; } // Substitute all longest codes with sufficiently longer ones, so that all // code words fit into the unit interval. Leftover space will be // redistributed later. space += count_longest * (kUnitInterval >> max_length); if (space < 0) return 0; int new_length = max_length; while (space < count_longest * (kUnitInterval >> new_length)) new_length++; space -= count_longest * (kUnitInterval >> new_length); for(i = 0; i < num_symbols; i++) { if (code_lengths[i] == max_length) code_lengths[i] = new_length; } } while (space > 0) { // Redistribute leftover space in an approximation of a uniform fashion. for(i = 0; i < num_symbols; i++) { if (code_lengths[i] > 1 && space >= (kUnitInterval >> code_lengths[i])) { space -= kUnitInterval >> code_lengths[i]; code_lengths[i]--; } if (space == 0) break; } } return 1; } static int ReadHuffmanCode(int alphabet_size, HuffmanTree* tree, BrotliBitReader* br) { int ok = 0; const int simple_code = BrotliReadBits(br, 1); BROTLI_LOG_UINT(simple_code); if (simple_code) { // Read symbols, codes & code lengths directly. int symbols[2] = { 0 }; int codes[2]; int code_lengths[2]; const int num_symbols = BrotliReadBits(br, 1) + 1; const int first_symbol_len_code = BrotliReadBits(br, 1); // The first code is either 1 bit or 8 bit code. symbols[0] = BrotliReadBits(br, (first_symbol_len_code == 0) ? 1 : 8); codes[0] = 0; code_lengths[0] = num_symbols - 1; // The second code (if present), is always 8 bit long. if (num_symbols == 2) { symbols[1] = BrotliReadBits(br, 8); codes[1] = 1; code_lengths[1] = num_symbols - 1; } BROTLI_LOG_UINT(num_symbols); BROTLI_LOG_UINT(first_symbol_len_code); BROTLI_LOG_UINT(symbols[0]); BROTLI_LOG_UINT(symbols[1]); ok = HuffmanTreeBuildExplicit(tree, code_lengths, codes, symbols, alphabet_size, num_symbols); if (!ok) { printf("[ReadHuffmanCode] HuffmanTreeBuildExplicit failed: "); PrintIntVector(code_lengths, num_symbols); } } else { // Decode Huffman-coded code lengths. int* code_lengths = NULL; int i; int code_length_code_lengths[CODE_LENGTH_CODES] = { 0 }; const int num_codes = BrotliReadBits(br, 4) + 4; BROTLI_LOG_UINT(num_codes); if (num_codes > CODE_LENGTH_CODES) { return 0; } code_lengths = (int*)BrotliSafeMalloc((uint64_t)alphabet_size, sizeof(*code_lengths)); if (code_lengths == NULL) { return 0; } for (i = 0; i < num_codes; ++i) { int code_len_idx = kCodeLengthCodeOrder[i]; code_length_code_lengths[code_len_idx] = BrotliReadBits(br, 3); BROTLI_LOG_ARRAY_INDEX(code_length_code_lengths, code_len_idx); } ok = ReadHuffmanCodeLengths(code_length_code_lengths, alphabet_size, code_lengths, br) && RepairHuffmanCodeLengths(alphabet_size, code_lengths); if (ok) { ok = HuffmanTreeBuildImplicit(tree, code_lengths, alphabet_size); if (!ok) { printf("[ReadHuffmanCode] HuffmanTreeBuildImplicit failed: "); PrintIntVector(code_lengths, alphabet_size); } } free(code_lengths); } ok = ok && !br->error_; if (!ok) { return 0; } return 1; } static int ReadCopyDistance(const HuffmanTree* tree, int num_direct_codes, int postfix_bits, uint32_t postfix_mask, BrotliBitReader* br) { BrotliFillBitWindow(br); int code = ReadSymbol(tree, br); if (code < num_direct_codes) { return code; } code -= num_direct_codes; int postfix = code & postfix_mask; code >>= postfix_bits; int nbits = (code >> 1) + 1; int 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) { BrotliFillBitWindow(br); int code = ReadSymbol(tree, br); int 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) { BrotliFillBitWindow(br); int code = ReadSymbol(tree, br); int range_idx = code >> 6; if (range_idx >= 2) { range_idx -= 2; *copy_dist = -1; } else { *copy_dist = 0; } int insert_code = (kInsertRangeLut[range_idx] << 3) + ((code >> 3) & 7); int copy_code = (kCopyRangeLut[range_idx] << 3) + (code & 7); *insert_len = kInsertLengthPrefixCode[insert_code].offset + BrotliReadBits(br, kInsertLengthPrefixCode[insert_code].nbits); *copy_len = kCopyLengthPrefixCode[copy_code].offset + BrotliReadBits(br, kCopyLengthPrefixCode[copy_code].nbits); } static int TranslateShortCodes(int code, int* ringbuffer, size_t* index) { int val; if (code < NUM_DISTANCE_SHORT_CODES) { val = code; int index_offset = kDistanceShortCodeIndexOffset[val]; int value_offset = kDistanceShortCodeValueOffset[val]; val = ringbuffer[(*index + index_offset) & 3] + value_offset; } else { val = code - NUM_DISTANCE_SHORT_CODES + 1; } if (code > 0) { ringbuffer[*index & 3] = val; ++(*index); } 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; 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); } void HuffmanTreeGroupRelease(HuffmanTreeGroup* group) { int i; for (i = 0; i < group->num_htrees; ++i) { HuffmanTreeRelease(&group->htrees[i]); } free(group->htrees); } int HuffmanTreeGroupDecode(HuffmanTreeGroup* group, BrotliBitReader* br) { int i; for (i = 0; i < group->num_htrees; ++i) { ReadHuffmanCode(group->alphabet_size, &group->htrees[i], br); } return 1; } int DecodeContextMap(int num_block_types, int stream_type, int* context_mode, int* contexts_per_block, int* num_htrees, uint8_t** context_map, BrotliBitReader* br) { int use_context = BrotliReadBits(br, 1); if (!use_context) { *context_mode = 0; *contexts_per_block = 1; *context_map = NULL; *num_htrees = num_block_types; return 1; } switch (stream_type) { case 0: *context_mode = BrotliReadBits(br, 4); *contexts_per_block = NumContexts(*context_mode); break; case 2: *context_mode = 1; *contexts_per_block = 4; break; } int context_map_size = *contexts_per_block * num_block_types; *num_htrees = BrotliReadBits(br, 8) + 1; BROTLI_LOG_UINT(*context_mode); 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; } int i; if (*num_htrees == context_map_size) { for (i = 0; i < context_map_size; ++i) { (*context_map)[i] = i; } return 1; } int use_rle_for_zeros = BrotliReadBits(br, 1); int max_run_length_prefix = 0; if (use_rle_for_zeros) { max_run_length_prefix = BrotliReadBits(br, 4) + 1; } HuffmanTree tree_index_htree; ReadHuffmanCode(*num_htrees + max_run_length_prefix, &tree_index_htree, br); if (use_rle_for_zeros) { for (i = 0; i < context_map_size;) { BrotliFillBitWindow(br); int 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; } } } else { for (i = 0; i < context_map_size; ++i) { BrotliFillBitWindow(br); (*context_map)[i] = ReadSymbol(&tree_index_htree, br); } } HuffmanTreeRelease(&tree_index_htree); if (BrotliReadBits(br, 1)) { InverseMoveToFrontTransform(*context_map, context_map_size); } return 1; } 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); } int BrotliDecompressedSize(size_t encoded_size, const uint8_t* encoded_buffer, size_t* decoded_size) { BrotliBitReader br; BrotliInitBitReader(&br, encoded_buffer, encoded_size); return DecodeSize(&br, decoded_size); } int BrotliDecompressBuffer(size_t encoded_size, const uint8_t* encoded_buffer, size_t* decoded_size, uint8_t* decoded_buffer) { BrotliBitReader br; BrotliInitBitReader(&br, encoded_buffer, encoded_size); int ok = DecodeSize(&br, decoded_size); if (!ok) return 0; if (*decoded_size == 0) { return 1; } size_t n = *decoded_size; int input_size_bits = (n == (n &~ (n - 1))) ? -1 : 0; while (n) { ++input_size_bits; n >>= 1; } BROTLI_LOG_UINT(*decoded_size); BROTLI_LOG_UINT(input_size_bits); int i; size_t pos = 0; const size_t end = *decoded_size; uint8_t* data = decoded_buffer; // This ring buffer holds a few past copy distances that will be used by // some special distance codes. int dist_rb[4] = { 4, 11, 15, 16 }; size_t dist_rb_idx = 0; HuffmanTreeGroup hgroup[3]; while (pos < end && ok) { BROTLI_LOG_UINT(pos); size_t meta_block_len = 0; if (!DecodeMetaBlockLength(input_size_bits, end - pos, &br, &meta_block_len)) { printf("Could not decode meta-block length.\n"); ok = 0; goto End; } BROTLI_LOG_UINT(meta_block_len); size_t meta_block_end = pos + meta_block_len; size_t block_length[3] = { 0 }; int block_type[3] = { 0 }; int num_block_types[3] = { 0 }; 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]; for (i = 0; i < 3; ++i) { block_type_trees[i].root_ = NULL; block_len_trees[i].root_ = NULL; if (BrotliReadBits(&br, 1)) { num_block_types[i] = BrotliReadBits(&br, 8) + 1; ReadHuffmanCode(num_block_types[i] + 2, &block_type_trees[i], &br); ReadHuffmanCode(kNumBlockLengthCodes, &block_len_trees[i], &br); block_length[i] = ReadBlockLength(&block_len_trees[i], &br); block_type_rb_index[i] = 1; } else { num_block_types[i] = 1; block_length[i] = meta_block_len; } } 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]); int distance_postfix_bits = BrotliReadBits(&br, 2); int num_direct_distance_codes = NUM_DISTANCE_SHORT_CODES + (BrotliReadBits(&br, 4) << distance_postfix_bits); uint32_t distance_postfix_mask = (1 << distance_postfix_bits) - 1; int num_distance_codes = (num_direct_distance_codes + (48 << distance_postfix_bits)); BROTLI_LOG_UINT(num_direct_distance_codes); BROTLI_LOG_UINT(distance_postfix_bits); uint8_t* context_map; int context_mode; int contexts_per_block; int num_literal_htrees; DecodeContextMap(num_block_types[0], 0, &context_mode, &contexts_per_block, &num_literal_htrees, &context_map, &br); uint8_t* dist_context_map; int dist_context_mode; int dist_contexts_per_block; int num_dist_htrees; DecodeContextMap(num_block_types[2], 2, &dist_context_mode, &dist_contexts_per_block, &num_dist_htrees, &dist_context_map, &br); 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) { HuffmanTreeGroupDecode(&hgroup[i], &br); } HuffmanTree* literal_htrees = hgroup[0].htrees; int context_offset = 0; uint8_t* context_map_slice = context_map; uint8_t literal_htree_index = 0; int dist_context_offset = 0; uint8_t* dist_context_map_slice = dist_context_map; uint8_t dist_htree_index = 0; while (pos < meta_block_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]; int insert_length; int copy_length; int distance_code; ReadInsertAndCopy(&hgroup[1].htrees[block_type[1]], &insert_length, ©_length, &distance_code, &br); BROTLI_LOG_UINT(insert_length); BROTLI_LOG_UINT(copy_length); BROTLI_LOG_UINT(distance_code); int j; for (j = 0; j < insert_length; ++j) { 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); literal_htree_index = block_type[0]; context_offset = block_type[0] * contexts_per_block; context_map_slice = context_map + context_offset; } --block_length[0]; BrotliFillBitWindow(&br); // Figure out htree if (contexts_per_block > 1) { uint8_t prev_byte = pos > 0 ? data[pos - 1] : 0; uint8_t prev_byte2 = pos > 1 ? data[pos - 2] : 0; uint8_t prev_byte3 = pos > 2 ? data[pos - 3] : 0; uint8_t context = Context(prev_byte, prev_byte2, prev_byte3, context_mode); BROTLI_LOG_UINT(context); literal_htree_index = context_map_slice[context]; } data[pos] = ReadSymbol(&literal_htrees[literal_htree_index], &br); BROTLI_LOG_UINT(literal_htree_index); BROTLI_LOG_ARRAY_INDEX(data, pos); ++pos; } if (br.error_) { printf("Read error after decoding literal sequence.\n"); ok = 0; goto End; } if (pos == meta_block_end) break; if (distance_code < 0) { 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] * dist_contexts_per_block; dist_context_map_slice = dist_context_map + dist_context_offset; } --block_length[2]; if (dist_contexts_per_block > 1) { 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); if (br.error_) { printf("Could not read copy distance.\n"); ok = 0; goto End; } } // Convert the distance code to the actual distance by possibly looking // up past distnaces from the ringbuffer. int dist = TranslateShortCodes(distance_code, dist_rb, &dist_rb_idx); BROTLI_LOG_UINT(dist); // Do the actual copy if it is valid. if (pos >= dist && pos + copy_length <= end) { int j; for (j = 0; j < copy_length; ++j) { data[pos + j] = data[pos + j - dist]; } pos += copy_length; } else { printf("Invalid backward reference. pos: %zd dist: %d " "len: %d end:%zd\n", pos, dist, copy_length, end); ok = 0; goto End; } } End: free(context_map); free(dist_context_map); for (i = 0; i < 3; ++i) { HuffmanTreeGroupRelease(&hgroup[i]); HuffmanTreeRelease(&block_type_trees[i]); HuffmanTreeRelease(&block_len_trees[i]); } } return ok; } #if defined(__cplusplus) || defined(c_plusplus) } // extern "C" #endif