// 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 = %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, &copy_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
