# -*- coding: utf-8 -*-
#!/usr/bin/env python3
# Copyright (C) 2016 Kai Lüke kailueke@riseup.net
# This program comes with ABSOLUTELY NO WARRANTY and is free software, you are welcome to redistribute it
# under certain conditions, see https://www.gnu.org/licenses/gpl-3.0.en.html

# super slow pure python brotli decoder, please ignore
#
# ported from brotli-rs to a minimal python subset and now back to standard python (but unpolished) as a side project
#
# usage:
#
#     from brotlipython import brotlidec
#     in = open('test.br', 'rb').read()
#     outbuf = []
#     dec = brotlidec(in, outbuf)  # also returns bytes(outbuf) again
#
# or see `./brotlipython.py --help`

# @TODO:
# look into brotlidump.py
# whole file is unpythonic (no for loops, mostly integers, global variables, no classes, no good exception model)
# is needlessly complicated comes becfrom a malloc/free world (transformations)

import sys, array, argparse, os

dir_path = os.path.dirname(os.path.abspath(__file__))
fo = open(dir_path+'/brotli-dict','rb')
BROTLI_DICTIONARY = fo.read()
fo.close()

# alloc_pM = lambda length: array.array('B', [0 for x in range(0, length)])
# alloc_pH = lambda length: array.array('L', [0 for x in range(0, length)])
alloc_L = lambda length: [0 for x in range(0, length)]
alloc_pM = alloc_pH = alloc_L

input_buf_pos = 0
input_buf = []
NONE = None
gcmpbuf = []
cmpbuf_pos = 0
output_buf = []

def out(a):
  global cmpbuf_pos, output_buf
  if gcmpbuf is not None:
    expected = gcmpbuf[cmpbuf_pos]
    cmpbuf_pos += 1
    if a != expected:
      import ipdb; ipdb.set_trace()
  output_buf.append(a)

def read_b():
    global input_buf, input_buf_pos
    if input_buf_pos == len(input_buf):
        return NONE
    a = input_buf[input_buf_pos]
    input_buf_pos += 1
    return a

def error():
  raise Exception("error() invoked")


# /bitreader/mod.rs
bit_pos = 0
current_byte = NONE
global_bit_pos = 0

read_exact_result = 0
def read_exact(): # read only one as it's anyway not used for more
  global read_exact_result
  read_exact_result = read_b()
  if read_exact_result is None:
    return 1 # eos error()
  return 0

def read_u8():  # return NONE for eof
  global bit_pos, current_byte, global_bit_pos
  res = read_exact()
  buf = read_exact_result
  if bit_pos == 0 and current_byte is not None and res == 1:  # i.e. res == EOS
    tmp_ = current_byte
    current_byte = NONE
    global_bit_pos += 8
    return tmp_
  elif current_byte is None and res == 0:  # i.e. res == Ok()
    global_bit_pos += 8
    return buf
  elif current_byte is not None and res == 0:
    tmp_ = current_byte
    current_byte = buf
    global_bit_pos += 8
    return (tmp_ >> bit_pos) | (buf << (8 - bit_pos))
  else:
    return NONE

read_u8_from_nibble_result = 0
def read_u8_from_nibble():  # returns 0 for OK, 1 for Error
  global bit_pos, current_byte, global_bit_pos, read_u8_from_nibble_result
  if bit_pos == 0 and current_byte is None:
    res = read_exact()
    buf = read_exact_result
    if res == 0:  # i.e. Ok()
      global_bit_pos += 4
      bit_pos = 4
      current_byte = buf
      read_u8_from_nibble_result = buf & 0x0f
      return 0
    else:
      return res
  elif (bit_pos == 1 or bit_pos == 2 or bit_pos == 3) and current_byte is not None:
    global_bit_pos += 4
    bit_pos += 4
    read_u8_from_nibble_result = (current_byte >> (bit_pos - 4)) & 0x0f
    return 0
  elif bit_pos == 4 and current_byte is not None:
    global_bit_pos += 4
    bit_pos = 0
    tmp_ = current_byte
    current_byte = NONE
    read_u8_from_nibble_result = (tmp_ >> 4) & 0x0f
    return 0
  elif (bit_pos == 5 or bit_pos == 6 or bit_pos == 7) and current_byte is not None:
    res = read_exact()
    buf = read_exact_result
    if res == 0:
      global_bit_pos += 4
      bit_pos_prev = bit_pos
      bit_pos = bit_pos - 4
      tmp_ = current_byte
      current_byte = buf
      read_u8_from_nibble_result = ((tmp_ >> (bit_pos_prev)) | (buf << (8 - bit_pos_prev))) & 0x0f
      return 0
    else:
      return res
  else:
    return 1 # unreachable


read_bit_result = 0
def read_bit():  # returns 0 for OK, 1 for Error
  global bit_pos, current_byte, global_bit_pos, read_bit_result
  if current_byte is not None:
      tmp_ = bit_pos
      tmp_2 = current_byte
      bit_pos = (tmp_ + 1) % 8
      global_bit_pos = global_bit_pos + 1
      if bit_pos == 0:
          current_byte = NONE
      read_bit_result = tmp_2 >> tmp_ & 1
      return 0
  else:
      if read_exact():
        return 1
      else:
        current_byte = read_exact_result
        bit_pos = 1
        global_bit_pos = 1
        read_bit_result = read_exact_result & 1
        return 0


read_u32_from_n_bits_result = 0
# returns 0 for OK, 1 for Error
def read_u32_from_n_bits(n):  # does also serve as read_u8_from_n_bits, read_u16_from_n_bits
  global bit_pos, current_byte, global_bit_pos, read_u32_from_n_bits_result
  read_u32_from_n_bits_result = 0
  i = 0
  while i < n:
    if read_bit():
      return 1  # error
    elif read_bit_result == 1:
      read_u32_from_n_bits_result = read_u32_from_n_bits_result | (1 << i)
    i += 1
  return 0

def read_u8_from_byte_tail():  # return NONE for eof
  if bit_pos == 0:
    return 0
  else:
    if read_u32_from_n_bits(8 - bit_pos):
      return NONE
    return read_u32_from_n_bits_result

read_u32_from_n_nibbles_result = 0
# returns 0 for OK, 1 for Error
def read_u32_from_n_nibbles(n):
  global bit_pos, current_byte, global_bit_pos, read_u32_from_n_nibbles_result
  read_u32_from_n_nibbles_result = 0
  i = 0
  while i < n:
    if read_u8_from_nibble() == 0:
      read_u32_from_n_nibbles_result = read_u32_from_n_nibbles_result | (read_u8_from_nibble_result  << (4 * i))
    else:
      return 1
    i += 1
  return 0

def read_fixed_length_string(length):
    my_string =  alloc_pM(length)
    i = 0
    while i < length:
        t = read_u8()
        if t == NONE:
            return NONE
        my_string[i] = t
        i += 1
    return my_string


# /huffman/tree/mod.rs

# tree as [buf, len, last_symbol]
#   buf: tree[0]
#   len: tree[1]
#   last_symbol: tree[2]

def tree_from_raw_data(buf, len_, last_symbol):
  return [buf, len_, last_symbol]

def tree_with_max_depth(max_depth):
  len_ = (1 << (max_depth + 1)) - 1
  # u16 entries
  arr = alloc_L(len_)
  i = 0  # init all values with NONE
  while i < len_:
    arr[i] = NONE
    i += 1
  return tree_from_raw_data(arr, 0, NONE)

def insert(tree, code, symbol):  # code[0,1,0,1,0,1]
  # code is 32 bit array
  tree[1] = tree[1] + 1
  tree[2] = symbol
  insert_at_index = 0
  i = 0
  while i < len(code):
    insert_at_index = (insert_at_index << 1) + code[i]
    i += 1
  insert_at_index = (1 << len(code)) - 1 + insert_at_index
  if insert_at_index > len(tree[0]) - 1:
    error() # panic!()
  tr = tree[0]
  tr[insert_at_index] = symbol


def lookup(tree):
  pseudo_code = 1
  len_ = len(tree[0])
  while True:
    if read_bit():
      return NONE
    pseudo_code = (pseudo_code << 1) + read_bit_result
    lookup_index = pseudo_code - 1
    if lookup_index > len_ - 1:
      return NONE # None but anyway None is always leading to DecompressorError
    tr = tree[0]
    tmp_ = tr[lookup_index] # buf[lookup_index]
    if tmp_ != NONE:
      return tmp_

def lookup_symbol(tree):
  if tree[1] == 0: # len == 0
    return NONE  # None empty table
  if tree[1] == 1: # len == 1
    return tree[2] # last_symbol
  return lookup(tree)

# /huffman/mod.rs

def bit_string_from_code_and_length(code, len_): # nr, nr
  bits = alloc_pM(len_)
  i = 0
  while i < len_:  # all bits get set, no initialisation with zero needed
    if (code >> i) & 1 == 1:
      bits[len_ - i - 1] = 1
    else:
      bits[len_ - i - 1] = 0
    i += 1
  return bits

def codes_from_lengths_and_symbols(lengths, symbols): # [], [] -> tree
  # treat lengths as u8 in pM, symbols as u32 in pH
  max_length = 0
  i = 0
  while i < len(lengths):
    j = lengths[i]
    if j > max_length:
      max_length = j
    i += 1
  bl_count = alloc_pH(max_length + 1)
  i = 0
  while i < max_length + 1:
    bl_count[i] = 0  # init
    i += 1
  i = 0
  while i < len(lengths):
    j = lengths[i]
    bl_count[j] = bl_count[j] + 1
    i += 1
  code = 0
  next_code = alloc_pH(max_length + 1)
  next_code[0] = 0  # init, rest is in loop
  bits = 1
  while bits < max_length + 1:
    code = (code + bl_count[bits - 1]) << 1
    next_code[bits] = code
    bits += 1
  codes = tree_with_max_depth(max_length)
  i = 0
  while i < len(lengths):
    len_ = lengths[i]
    if len_ > 0 or max_length == 0:
      insert(codes, bit_string_from_code_and_length(next_code[len_], len_), symbols[i])
      next_code[len_] = next_code[len_] + 1
    i += 1
  return codes

def codes_from_lengths(lengths): # [] -> Tree
  # lengths is in pM
  symbols = alloc_pH(len(lengths))
  i = 0
  while i < len(lengths):
    symbols[i] = i
    i += 1
  ret = codes_from_lengths_and_symbols(lengths, symbols)
  return ret

# /transformation/mod.rs

def uppercase_all(base_word):
  l = len(base_word)
  v = alloc_pM(l)
  i = 0
  while i < l:
    b = base_word[i]
    if (b >= 0 and b <= 96) or (b >= 123 and b <= 191):
      v[i] = b
      i += 1
    elif b >= 97 and b <= 122:
      v[i] = b ^ 32
      i += 1
    elif b >= 192 and b <= 223:
      v[i] = b
      i += 1
      if i < l:
        v[i] = base_word[i] ^ 32
      i += 1
    elif b >= 224 and b <= 255:
      v[i] = b
      i += 1
      if i < l:
        v[i] = base_word[i]
      i += 1
      if i < l:
        v[i] = base_word[i] ^ 5
      i += 1
    else:
      error() # unreachable
  return v

def uppercase_first(base_word):
  l = len(base_word)
  if l == 0:
    return alloc_pM(0)
  v = alloc_pM(l)
  i = 0
  b = base_word[0]
  if (b >= 1 and b <= 96) or (b >= 123 and b <= 191):
    v[0] = b
    i = 1
  elif b >= 97 and b <= 122:
    v[0] = b ^ 32
    i = 1
  elif b >= 192 and b <= 223:
    v[0] = b
    if 1 < l:
      v[1] = base_word[1] ^ 32
    i = 2
  elif b >= 224 and b <= 255:
    v[0] = b
    if 1 < l:
      v[1] = base_word[1]
    if 2 < l:
      v[2] = base_word[2] ^ 5
    i = 3
  else:
    error() # unreachable
  while i < l:
    v[i] = base_word[i]
    i += 1
  return v

def transformation(id_, base_word):
  #print("t:", id_, str(bytearray(base_word)))
  # rewrite like: t1 = [0x22] t2= omit_first(2) t3=[0x22,0x21] tc=3
  l = len(base_word)
  i = 0
  if id_ == 0:
    return base_word
  elif id_ == 1 or id_ == 19 or id_ == 20 or id_ == 22 or id_ == 24 or id_ == 36 or id_ == 51 or id_ == 57 or id_ == 76:  # 1 hinten an
    v = alloc_pM(l+1)
    while i < l:
      v[i] = base_word[i]
      i += 1
    if id_ == 1:
      v[i] = 0x20
    elif id_ == 19:
      v[i] = 0x22
    elif id_ == 20:
      v[i] = 0x2e
    elif id_ == 22:
      v[i] = 0x0a
    elif id_ == 24:
      v[i] = 0x5d
    elif id_ == 36:
      v[i] = 0x27
    elif id_ == 51:
      v[i] = 0x3a
    elif id_ == 57:
      v[i] = 0x28
    elif id_ == 76:
      v[i] = 0x2c
  elif id_ == 2 or id_ == 67 or id_ == 71 or id_ == 77 or id_ == 89 or id_ == 103:  # 1 vorne 1 hinten an
    v = alloc_pM(l+2)
    if id_ == 2 or id_ == 71 or id_ == 89 or id_ == 103:
      v[i] = 0x20
    elif id_ == 67 or id_ == 77:
      v[i] = 0x2e
    i += 1
    while i <= l:
      v[i] = base_word[i-1]
      i += 1
    if id_ == 2 or id_ == 77:
      v[i] = 0x20
    elif id_ == 67 or id_ == 89:
      v[i] = 0x28
    elif id_ == 71:
      v[i] = 0x2e
    elif id_ == 103:
      v[i] = 0x2c
  elif id_ == 3 or id_ == 11 or id_ == 26 or id_ == 34 or id_ == 39 or id_ == 40 or id_ == 54 or id_ == 55:
    if id_ == 3:
      j = 1
    elif id_ == 11:
      j = 2
    elif id_ == 26:
      j = 3
    elif id_ == 34:
      j = 4
    elif id_ == 39:
      j = 5
    elif id_ == 40:
      j = 6
    elif id_ == 54:
      j = 9
    elif id_ == 55:
      j = 7
    if l-1 < j:
      j = l-1
    v = alloc_pM(l-j)
    while i < l-j:
      v[i] = base_word[i+j]
      i += 1
  elif id_ == 4 or id_ == 66 or id_ == 74 or id_ == 78 or id_ == 79 or id_ == 99:  # upper first 1 hinten an
    u = uppercase_first(base_word)
    j = len(u)
    v = alloc_pM(j+1)
    while i < j:
      v[i] = u[i]
      i += 1
    if id_ == 4:
      v[i] = 0x20
    elif id_ == 66:
      v[i] = 0x22
    elif id_ == 74:
      v[i] = 0x27
    elif id_ == 78:
      v[i] = 0x28
    elif id_ == 79:
      v[i] = 0x2e
    elif id_ == 99:
      v[i] = 0x2c
  elif id_ == 5 or id_ == 10 or id_ == 25 or id_ == 80 or id_ == 93:  # 5 hinten an
    v = alloc_pM(l+5)
    while i < l:
      v[i] = base_word[i]
      i += 1
    if id_ == 93:
      v[i] = 0x6c
    else:
      v[i] = 0x20
    i += 1
    if id_ == 5:
      v[i] = 0x74
    elif id_ == 10:
      v[i] = 0x61
    elif id_ == 25:
      v[i] = 0x66
    elif id_ == 80:
      v[i] = 0x6e
    elif id_ == 93:
      v[i] = 0x65
    i += 1
    if id_ == 5:
      v[i] = 0x68
    elif id_ == 10:
      v[i] = 0x6e
    elif id_ == 25 or id_ == 80:
      v[i] = 0x6f
    elif id_ == 93:
      v[i] = 0x73
    i += 1
    if id_ == 5:
      v[i] = 0x65
    elif id_ == 10:
      v[i] = 0x64
    elif id_ == 25:
      v[i] = 0x72
    elif id_ == 80:
      v[i] = 0x74
    elif id_ == 93:
      v[i] = 0x73
    i += 1
    v[i] = 0x20
  elif id_ == 6 or id_ == 32:  # 1 vorne an
    v = alloc_pM(l+1)
    if id_ == 6:
      v[i] = 0x20
    elif id_ == 32:
      v[i] = 0x2e
    i += 1
    while i <= l:
      v[i] = base_word[i-1]
      i += 1
  elif id_ == 7 or id_ == 13 or id_ == 18:  # 2 vorne an 1 hinten an
    v = alloc_pM(l+3)
    if id_ == 7:
      v[i] = 0x73
    elif id_ == 13:
      v[i] = 0x2c
    elif id_ == 18:
      v[i] = 0x65
    i += 1
    v[i] = 0x20
    i += 1
    l += 1
    while i <= l:
      v[i] = base_word[i-2]
      i += 1
    v[i] = 0x20
  elif id_ == 8 or id_ == 16 or id_ == 17 or id_ == 38 or id_ == 45 or id_ == 46 or id_ == 47 or id_ == 60 or id_ == 90 or id_ == 92 or id_ == 95 or id_ == 100 or id_ == 106:  # 4 hinten an
    v = alloc_pM(l+4)
    while i < l:
      v[i] = base_word[i]
      i += 1
    if id_ == 90:
      v[i] = 0x66
    elif id_ == 92 or id_ == 100:
      v[i] = 0x69
    elif id_ == 95:
      v[i] = 0x65
    elif id_ == 106:
      v[i] = 0x6f
    else:
      v[i] = 0x20
    i += 1
    if id_ == 8:
      v[i] = 0x6f
    elif id_ == 16:
      v[i] = 0x69
    elif id_ == 17:
      v[i] = 0x74
    elif id_ == 38:
      v[i] = 0x62
    elif id_ == 45:
      v[i] = 0x6f
    elif id_ == 46 or id_ == 60:
      v[i] = 0x61
    elif id_ == 47:
      v[i] = 0x69
    elif id_ == 90 or id_ == 106:
      v[i] = 0x75
    elif id_ == 92:
      v[i] = 0x76
    elif id_ == 95:
      v[i] = 0x73
    elif id_ == 100:
      v[i] = 0x7a
    i += 1
    if id_ == 8:
      v[i] = 0x66
    elif id_ == 16:
      v[i] = 0x6e
    elif id_ == 17:
      v[i] = 0x6f
    elif id_ == 38:
      v[i] = 0x79
    elif id_ == 45:
      v[i] = 0x6e
    elif id_ == 46 or id_ == 47 or id_ == 106:
      v[i] = 0x73
    elif id_ == 60 or id_ == 95:
      v[i] = 0x74
    elif id_ == 90:
      v[i] = 0x6c
    elif id_ == 92 or id_ == 100:
      v[i] = 0x65
    i += 1
    v[i] = 0x20
  elif id_ == 9:
    v = uppercase_first(base_word)
  elif id_ == 12 or id_ == 23 or id_ == 27 or id_ == 42 or id_ == 48 or id_ == 56 or id_ == 59 or id_ == 63 or id_ == 64:
    if id_ == 12:
      j = 1
    elif id_ == 23:
      j = 3
    elif id_ == 27:
      j = 2
    elif id_ == 42:
      j = 4
    elif id_ == 48:
      j = 7
    elif id_ == 56:
      j = 6
    elif id_ == 59:
      j = 8
    elif id_ == 63:
      j = 5
    elif id_ == 64:
      j = 9
    if l > j:
      j = l
    if id_ == 12:
      j -= 1
    elif id_ == 23:
      j -= 3
    elif id_ == 27:
      j -= 2
    elif id_ == 42:
      j -= 4
    elif id_ == 48:
      j -= 7
    elif id_ == 56:
      j -= 6
    elif id_ == 59:
      j -= 8
    elif id_ == 63:
      j -= 5
    elif id_ == 64:
      j -= 9
    v = alloc_pM(j)
    while i < j:
      v[i] = base_word[i]
      i += 1
  elif id_ == 14 or id_ == 21 or id_ == 31 or id_ == 50 or id_ == 70 or id_ == 86:  # 2 hinten an
    v = alloc_pM(l+2)
    while i < l:
      v[i] = base_word[i]
      i += 1
    if id_ == 14:
      v[i] = 0x2c
    elif id_ == 21:
      v[i] = 0x22
    elif id_ == 31:
      v[i] = 0x2e
    elif id_ == 50:
      v[i] = 0x0a
    elif id_ == 70 or id_ == 86:
      v[i] = 0x3d
    i += 1
    if id_ == 14 or id_ == 31:
      v[i] = 0x20
    elif id_ == 21:
      v[i] = 0x3e
    elif id_ == 50:
      v[i] = 0x09
    elif id_ == 70:
      v[i] = 0x22
    elif id_ == 86:
      v[i] = 0x27
  elif id_ == 15 or id_ == 96 or id_ == 109:  # upper first 1 vorne an 1 hinten an
    u = uppercase_first(base_word)
    j = len(u)
    v = alloc_pM(j+2)
    v[0] = 0x20
    while i < j:
      v[i+1] = u[i]
      i += 1
    i += 1
    if id_ == 96:
      v[i] = 0x2e
    elif id_ == 109:
      v[i] = 0x2c
    else:
      v[i] = 0x20
  elif id_ == 28 or id_ == 53 or id_ == 61 or id_ == 82 or id_ == 84:  # 3 hinten an
    v = alloc_pM(l+3)
    while i < l:
      v[i] = base_word[i]
      i += 1
    if id_ == 28:
      v[i] = 0x20
    elif id_ == 53 or id_ == 82:
      v[i] = 0x65
    elif id_ == 61:
      v[i] = 0x6c
    elif id_ == 84:
      v[i] = 0x61
    i += 1
    if id_ == 28:
      v[i] = 0x61
    elif id_ == 53:
      v[i] = 0x64
    elif id_ == 61:
      v[i] = 0x79
    elif id_ == 82:
      v[i] = 0x72
    elif id_ == 84:
      v[i] = 0x6c
    i += 1
    v[i] = 0x20
  elif id_ == 29 or id_ == 35 or id_ == 37 or id_ == 43:  # 6 hinten an
    v = alloc_pM(l+6)
    while i < l:
      v[i] = base_word[i]
      i += 1
    if id_ == 43:
      v[i] = 0x2e
    else:
      v[i] = 0x20
    i += 1
    if id_ == 29:
      v[i] = 0x74
    elif id_ == 35:
      v[i] = 0x77
    elif id_ == 37:
      v[i] = 0x66
    elif id_ == 43:
      v[i] = 0x20
    i += 1
    if id_ == 29:
      v[i] = 0x68
    elif id_ == 35:
      v[i] = 0x69
    elif id_ == 37:
      v[i] = 0x72
    elif id_ == 43:
      v[i] = 0x54
    i += 1
    if id_ == 29:
      v[i] = 0x61
    elif id_ == 35:
      v[i] = 0x74
    elif id_ == 37:
      v[i] = 0x6f
    elif id_ == 43:
      v[i] = 0x68
    i += 1
    if id_ == 29:
      v[i] = 0x74
    elif id_ == 35:
      v[i] = 0x68
    elif id_ == 37:
      v[i] = 0x6d
    elif id_ == 43:
      v[i] = 0x65
    i += 1
    v[i] = 0x20
  elif id_ == 30:  # upper first 1 vorne an
    u = uppercase_first(base_word)
    j = len(u)
    v = alloc_pM(j+1)
    v[0] = 0x20
    while i < j:
      v[i+1] = u[i]
      i += 1
  elif id_ == 33 or id_ == 52 or id_ == 81 or id_ == 98:  # 1 vorne 2 hinten an
    v = alloc_pM(l+3)
    v[i] = 0x20
    i += 1
    while i <= l:
      v[i] = base_word[i-1]
      i += 1
    if id_ == 33:
      v[i] = 0x2c
    elif id_ == 52:
      v[i] = 0x2e
    elif id_ == 81 or id_ == 98:
      v[i] = 0x3d
    i += 1
    if id_ == 81:
      v[i] = 0x22
    elif id_ == 98:
      v[i] = 0x27
    else:
      v[i] = 0x20
  elif id_ == 41 or id_ == 72:  # 5 vorne an
    v = alloc_pM(l+5)
    if id_ == 41:
      v[i] = 0x20
    elif id_ == 72:
      v[i] = 0x2e
    i += 1
    if id_ == 41:
      v[i] = 0x74
    elif id_ == 72:
      v[i] = 0x63
    i += 1
    if id_ == 41:
      v[i] = 0x68
    elif id_ == 72:
      v[i] = 0x6f
    i += 1
    if id_ == 41:
      v[i] = 0x65
    elif id_ == 72:
      v[i] = 0x6d
    i += 1
    if id_ == 41:
      v[i] = 0x20
    elif id_ == 72:
      v[i] = 0x2f
    i += 1
    while i-5 < l:
      v[i] = base_word[i-5]
      i += 1
  elif id_ == 44:
    v = uppercase_all(base_word)
  elif id_ == 49:
    j = 1
    if l > j:
      j = l
    j -= 1
    v = alloc_pM(j+4)
    while i < j:
      v[i] = base_word[i]
      i += 1
    v[i] = 0x69
    i += 1
    v[i] = 0x6e
    i += 1
    v[i] = 0x67
    i += 1
    v[i] = 0x20
  elif id_ == 58 or id_ == 69 or id_ == 88 or id_ == 104 or id_ == 108:  # upper first 2 hinten an
    u = uppercase_first(base_word)
    j = len(u)
    v = alloc_pM(j+2)
    while i < j:
      v[i] = u[i]
      i += 1
    if id_ == 58:
      v[i] = 0x2c
    elif id_ == 69:
      v[i] = 0x22
    elif id_ == 88:
      v[i] = 0x2e
    elif id_ == 104 or id_ == 108:
      v[i] = 0x3d
    i += 1
    if id_ == 58 or id_ == 88:
      v[i] = 0x20
    elif id_ == 69:
      v[i] = 0x3e
    elif id_ == 104:
      v[i] = 0x22
    elif id_ == 108:
      v[i] = 0x27
  elif id_ == 62:  # 5 vorne 4 hinten an
    v = alloc_pM(l+9)
    v[i] = 0x20
    i += 1
    v[i] = 0x74
    i += 1
    v[i] = 0x68
    i += 1
    v[i] = 0x65
    i += 1
    v[i] = 0x20
    i += 1
    while i-5 < l:
      v[i] = base_word[i-5]
      i += 1
    v[i] = 0x20
    i += 1
    v[i] = 0x6f
    i += 1
    v[i] = 0x66
    i += 1
    v[i] = 0x20
  elif id_ == 65 or id_ == 91 or id_ == 118 or id_ == 120:  # upper first 1 vorne 2 hinten an
    u = uppercase_first(base_word)
    j = len(u)
    v = alloc_pM(j+3)
    v[0] = 0x20
    while i < j:
      v[i+1] = u[i]
      i += 1
    i += 1
    if id_ == 65:
      v[i] = 0x2c
    elif id_ == 91:
      v[i] = 0x2e
    else:
      v[i] = 0x3d
    i += 1
    if id_ == 118:
      v[i] = 0x22
    elif id_ == 120:
      v[i] = 0x27
    else:
      v[i] = 0x20
  elif id_ == 68 or id_ == 87 or id_ == 94 or id_ == 101 or id_ == 112 or id_ == 113:  # upper all 1 hinten
    u = uppercase_all(base_word)
    j = len(u)
    v = alloc_pM(j+1)
    while i < j:
      v[i] = u[i]
      i += 1
    if id_ == 87:
      v[i] = 0x22
    elif id_ == 94:
      v[i] = 0x27
    elif id_ == 101:
      v[i] = 0x2e
    elif id_ == 112:
      v[i] = 0x2c
    elif id_ == 113:
      v[i] = 0x28
    else:
      v[i] = 0x20
  elif id_ == 73:  # 5 vorne 8 hinten an
    v = alloc_pM(l+13)
    v[i] = 0x20
    i += 1
    v[i] = 0x74
    i += 1
    v[i] = 0x68
    i += 1
    v[i] = 0x65
    i += 1
    v[i] = 0x20
    i += 1
    while i-5 < l:
      v[i] = base_word[i-5]
      i += 1
    v[i] = 0x20
    i += 1
    v[i] = 0x6f
    i += 1
    v[i] = 0x66
    i += 1
    v[i] = 0x20
    i += 1
    v[i] = 0x74
    i += 1
    v[i] = 0x68
    i += 1
    v[i] = 0x65
    i += 1
    v[i] = 0x20
  elif id_ == 75:  # 7 hinten an
    v = alloc_pM(l+7)
    while i < l:
      v[i] = base_word[i]
      i += 1
    v[i] = 0x2e
    i += 1
    v[i] = 0x20
    i += 1
    v[i] = 0x54
    i += 1
    v[i] = 0x68
    i += 1
    v[i] = 0x69
    i += 1
    v[i] = 0x73
    i += 1
    v[i] = 0x20
  elif id_ == 83 or id_ == 115:  # upper all 1 vorne 1 hinten
    u = uppercase_all(base_word)
    j = len(u)
    v = alloc_pM(j+2)
    v[0] = 0x20
    while i < j:
      v[i+1] = u[i]
      i += 1
    i += 1
    if id_ == 83:
      v[i] = 0x20
    elif id_ == 115:
      v[i] = 0x2e
  elif id_ == 85:  # upper all 1 vorne
    u = uppercase_all(base_word)
    j = len(u)
    v = alloc_pM(j+1)
    v[0] = 0x20
    while i < j:
      v[i+1] = u[i]
      i += 1
  elif id_ == 97 or id_ == 105 or id_ == 107 or id_ == 114 or id_ == 116:  # upper all 2 hinten
    u = uppercase_all(base_word)
    j = len(u)
    v = alloc_pM(j+2)
    while i < j:
      v[i] = u[i]
      i += 1
    if id_ == 97:
      v[i] = 0x22
    elif id_ == 105 or id_ == 116:
      v[i] = 0x3d
    elif id_ == 107:
      v[i] = 0x2c
    elif id_ == 114:
      v[i] = 0x2e
    i += 1
    if id_ == 97:
      v[i] = 0x3e
    elif id_ == 105:
      v[i] = 0x22
    elif id_ == 116:
      v[i] = 0x27
    elif id_ == 107 or id_ == 114:
      v[i] = 0x20
  elif id_ == 102: # 2 vorne
    v = alloc_pM(l+2)
    v[i] = 0xc2
    i += 1
    v[i] = 0xa0
    i += 1
    l += 1
    while i <= l:
      v[i] = base_word[i-2]
      i += 1
  elif id_ == 110 or id_ == 111 or id_ == 117 or id_ == 119:  # upper all 1 vorne 2 hinten
    u = uppercase_all(base_word)
    j = len(u)
    v = alloc_pM(j+3)
    v[0] = 0x20
    while i < j:
      v[i+1] = u[i]
      i += 1
    i += 1
    if id_ == 110 or id_ == 119:
      v[i] = 0x3d
    elif id_ == 111:
      v[i] = 0x2c
    elif id_ == 117:
      v[i] = 0x2e
    i += 1
    if id_ == 110:
      v[i] = 0x22
    elif id_ == 110:
      v[i] = 0x27
    else:
      v[i] = 0x20
  else:
    return NONE # unreachable
  return v

# /dictionary/mod.rs
BROTLI_DICTIONARY_OFFSETS_BY_LENGTH = [0,      0,      0,      0,      0,   4096,   9216,  21504,  35840,  44032, 53248,  63488 , 74752,  87040,  93696, 100864, 104704, 106752, 108928, 113536, 115968, 118528, 119872, 121280, 122016]
BROTLI_DICTIONARY_SIZE_BITS_BY_LENGTH = [0,  0,  0,  0, 10, 10, 11, 11, 10, 10, 10, 10, 10,  9,  9,  8,  7,  7,  8,  7, 7,  6,  6,  5,  5]

# /lookuptable/mod.rs

LUT_0 = [
	 0,  0,  0,  0,  0,  0,  0,  0,  0,  4,  4,  0,  0,  4,  0,  0,
	 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
	 8, 12, 16, 12, 12, 20, 12, 16, 24, 28, 12, 12, 32, 12, 36, 12,
	44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 32, 32, 24, 40, 28, 12,
	12, 48, 52, 52, 52, 48, 52, 52, 52, 48, 52, 52, 52, 52, 52, 48,
	52, 52, 52, 52, 52, 48, 52, 52, 52, 52, 52, 24, 12, 28, 12, 12,
	12, 56, 60, 60, 60, 56, 60, 60, 60, 56, 60, 60, 60, 60, 60, 56,
	60, 60, 60, 60, 60, 56, 60, 60, 60, 60, 60, 24, 12, 28, 12,  0,
	 0,  1,  0,  1,  0,  1,  0,  1,  0,  1,  0,  1,  0,  1,  0,  1,
	 0,  1,  0,  1,  0,  1,  0,  1,  0,  1,  0,  1,  0,  1,  0,  1,
	 0,  1,  0,  1,  0,  1,  0,  1,  0,  1,  0,  1,  0,  1,  0,  1,
	 0,  1,  0,  1,  0,  1,  0,  1,  0,  1,  0,  1,  0,  1,  0,  1,
	 2,  3,  2,  3,  2,  3,  2,  3,  2,  3,  2,  3,  2,  3,  2,  3,
	 2,  3,  2,  3,  2,  3,  2,  3,  2,  3,  2,  3,  2,  3,  2,  3,
	 2,  3,  2,  3,  2,  3,  2,  3,  2,  3,  2,  3,  2,  3,  2,  3,
	 2,  3,  2,  3,  2,  3,  2,  3,  2,  3,  2,  3,  2,  3,  2,  3
]

LUT_1 = [
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
	2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1,
	1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
	2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1,
	1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
	3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 1, 1, 1, 0,
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
	2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2
]

LUT_2 = [
	0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
	2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
	2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
	2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
	3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
	3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
	3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
	3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
	4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
	4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
	4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
	4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
	5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
	5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
	5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
	6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7
]

table = alloc_pH(704*4)
insert_and_copy_length = 0
while insert_and_copy_length < 704:
  if insert_and_copy_length >= 0 and insert_and_copy_length <= 63:
    insert_length_code = 0
    copy_length_code = 0
  elif insert_and_copy_length >= 64 and insert_and_copy_length <= 127:
    insert_length_code = 0
    copy_length_code = 8
  elif insert_and_copy_length >= 128 and insert_and_copy_length <= 191:
    insert_length_code = 0
    copy_length_code = 0
  elif insert_and_copy_length >= 192 and insert_and_copy_length <= 255:
    insert_length_code = 0
    copy_length_code = 8
  elif insert_and_copy_length >= 256 and insert_and_copy_length <= 319:
    insert_length_code = 8
    copy_length_code = 0
  elif insert_and_copy_length >= 320 and insert_and_copy_length <= 383:
    insert_length_code = 8
    copy_length_code = 8
  elif insert_and_copy_length >= 384 and insert_and_copy_length <= 447:
    insert_length_code = 0
    copy_length_code = 16
  elif insert_and_copy_length >= 448 and insert_and_copy_length <= 511:
    insert_length_code = 16
    copy_length_code = 0
  elif insert_and_copy_length >= 512 and insert_and_copy_length <= 575:
    insert_length_code = 8
    copy_length_code = 16
  elif insert_and_copy_length >= 576 and insert_and_copy_length <= 639:
    insert_length_code = 16
    copy_length_code = 8
  elif insert_and_copy_length >= 640 and insert_and_copy_length <= 703:
    insert_length_code = 16
    copy_length_code = 16
  else:
    error() # print('unreachable')
  insert_length_code += 0x07 & (insert_and_copy_length >> 3)
  copy_length_code += 0x07 & insert_and_copy_length
  if insert_length_code >= 0 and insert_length_code <= 5:
    insert_length = insert_length_code
    extra_bits_insert = 0
  elif insert_length_code == 6 or insert_length_code == 7:
    insert_length = 6 + 2 * (insert_length_code - 6)
    extra_bits_insert = 1
  elif insert_length_code == 8 or insert_length_code == 9:
    insert_length = 10 + 4 * (insert_length_code - 8)
    extra_bits_insert = 2
  elif insert_length_code == 10 or insert_length_code == 11:
    insert_length = 18 + 8 * (insert_length_code - 10)
    extra_bits_insert = 3
  elif insert_length_code == 12 or insert_length_code == 13:
    insert_length = 34 + 16 * (insert_length_code - 12)
    extra_bits_insert = 4
  elif insert_length_code == 14 or insert_length_code == 15:
    insert_length = 66 + 32 * (insert_length_code - 14)
    extra_bits_insert = 5
  elif insert_length_code == 16:
    insert_length = 130
    extra_bits_insert = 6
  elif insert_length_code == 17:
    insert_length = 194
    extra_bits_insert = 7
  elif insert_length_code == 18:
    insert_length = 322
    extra_bits_insert = 8
  elif insert_length_code == 19:
    insert_length = 578
    extra_bits_insert = 9
  elif insert_length_code == 20:
    insert_length = 1090
    extra_bits_insert = 10
  elif insert_length_code == 21:
    insert_length = 2114
    extra_bits_insert = 12
  elif insert_length_code == 22:
    insert_length = 6210
    extra_bits_insert = 14
  elif insert_length_code == 23:
    insert_length = 22594
    extra_bits_insert = 24
  else:
    error() # print('unreachable')
  if copy_length_code >= 0 and copy_length_code <= 7:
    copy_length = copy_length_code + 2
    extra_bits_copy = 0
  elif copy_length_code == 8 or copy_length_code == 9:
    copy_length = 10 + 2 * (copy_length_code - 8)
    extra_bits_copy = 1
  elif copy_length_code == 10 or copy_length_code == 11:
    copy_length = 14 + 4 * (copy_length_code - 10)
    extra_bits_copy = 2
  elif copy_length_code == 12 or copy_length_code == 13:
    copy_length = 22 + 8 * (copy_length_code - 12)
    extra_bits_copy = 3
  elif copy_length_code == 14 or copy_length_code == 15:
    copy_length = 38 + 16 * (copy_length_code - 14)
    extra_bits_copy = 4
  elif copy_length_code == 16 or copy_length_code == 17:
    copy_length = 70 + 32 * (copy_length_code - 16)
    extra_bits_copy = 5
  elif copy_length_code == 18:
    copy_length = 134
    extra_bits_copy = 6
  elif copy_length_code == 19:
    copy_length = 198
    extra_bits_copy = 7
  elif copy_length_code == 20:
    copy_length = 326
    extra_bits_copy = 8
  elif copy_length_code == 21:
    copy_length = 582
    extra_bits_copy = 9
  elif copy_length_code == 22:
    copy_length = 1094
    extra_bits_copy = 10
  elif copy_length_code == 23:
    copy_length = 2118
    extra_bits_copy = 24
  else:
    error() # print('unreachable')
  table[insert_and_copy_length*4] = insert_length
  table[insert_and_copy_length*4 + 1] = extra_bits_insert
  table[insert_and_copy_length*4 + 2] = copy_length
  table[insert_and_copy_length*4 + 3] = extra_bits_copy
  insert_and_copy_length += 1

INSERT_LENGTHS_AND_COPY_LENGTHS = table

# /lib.rs

PrefixCodeKind_Simple = 1
PrefixCodeKind_Complex = 2
PrefixCodeKind_Complex_data = NONE

StreamBegin = 1
HeaderBegin = 2
WBits = 3
WBits_data = 0
HeaderEnd = 4
HeaderMetaBlockBegin = 5
IsLast = 6
IsLast_data = 0
IsLastEmpty = 7
IsLastEmpty_data = 0
MNibbles = 8
MNibbles_data = 0
MSkipBytes = 9
MSkipBytes_data = 0
MSkipLen = 10
MSkipLen_data = 0
MLen = 11
MLen_data = 0
IsUncompressed = 12
IsUncompressed_data = 0
MLenLiterals = 13
MLenLiterals_data = 0 # []
NBltypesL = 14
NBltypesL_data = 0
PrefixCodeBlockTypesLiterals = 15
PrefixCodeBlockTypesLiterals_data = 0  # (HuffmanCodes)
PrefixCodeBlockCountsLiterals = 16
PrefixCodeBlockCountsLiterals_data = 0 # (HuffmanCodes)
FirstBlockCountLiterals = 17
FirstBlockCountLiterals_data = 0 # (BLen)
NBltypesI = 18
NBltypesI_data = 0
PrefixCodeBlockTypesInsertAndCopyLengths = 19
PrefixCodeBlockTypesInsertAndCopyLengths_data = 0 # (HuffmanCodes)
PrefixCodeBlockCountsInsertAndCopyLengths = 20
PrefixCodeBlockCountsInsertAndCopyLengths_data = 0 # (HuffmanCodes)
FirstBlockCountInsertAndCopyLengths = 21
FirstBlockCountInsertAndCopyLengths_data = 0
NBltypesD = 22
NBltypesD_data = 0 # (NBltypes)
PrefixCodeBlockTypesDistances = 23
PrefixCodeBlockTypesDistances_data = 0 # (HuffmanCodes)
PrefixCodeBlockCountsDistances = 24
PrefixCodeBlockCountsDistances_data = 0 # (HuffmanCodes)
FirstBlockCountDistances = 25
FirstBlockCountDistances_data = 0 #(BLen)
NPostfix = 26
NPostfix_data = 0
NDirect = 27
NDirect_data = 0
ContextModesLiterals = 28
ContextModesLiterals_data = 0 # (ContextModes)
NTreesL = 29
NTreesL_data = 0 # (NTrees)
NTreesD = 30
NTreesD_data = 0 #(NTrees)
ContextMapDistances = 31
ContextMapDistances_data = 0 # (ContextMap)
ContextMapLiterals = 32
ContextMapLiterals_data = 0 # (ContextMap)
PrefixCodesLiterals = 33
PrefixCodesLiterals_data = 0 # (Vec<HuffmanCodes>)
PrefixCodesInsertAndCopyLengths = 34
PrefixCodesInsertAndCopyLengths_data = 0 # (Vec<HuffmanCodes>)
PrefixCodesDistances = 35
PrefixCodesDistances_data = 0 # (Vec<HuffmanCodes>)
DataMetaBlockBegin = 36
InsertAndCopyLength = 37
InsertAndCopyLength_data = 0
InsertLengthAndCopyLength = 38
InsertLengthAndCopyLength_data_co_len = NONE
InsertLengthAndCopyLength_data_in_len = NONE
InsertLiterals = 39
InsertLiterals_data = 0 #(Literals)
DistanceCode = 40
DistanceCode_data = 0 #(DistanceCode)
Distance = 41
Distance_data = 0 # (Distance)
CopyLiterals = 42
CopyLiterals_data = 0 # (Literals)
DataMetaBlockEnd = 43
MetaBlockEnd = 44
StreamEnd = 45

t_array = alloc_pH(255)
i = 0
while i < 255:
  t_array[i] = NONE
  i += 1
t_array[1] = 16
t_array[24] = 21
t_array[25] = 19
t_array[26] = 23
t_array[27] = 18
t_array[28] = 22
t_array[29] = 20
t_array[30] = 24
t_array[191] = 17
t_array[192] = 12
t_array[193] = 10
t_array[194] = 14
t_array[196] = 13
t_array[197] = 11
t_array[198] = 15
header_wbits_codes = tree_from_raw_data(t_array, 15, 24)

t_array = alloc_pH(31)
i = 0
while i < 31:
  t_array[i] = NONE
  i += 1
t_array[3] = 0
t_array[4] = 3
t_array[5] = 4
t_array[13] = 2
t_array[29] = 1
t_array[30] = 5
header_bit_lengths_code = tree_from_raw_data(t_array, 6, 5)

t_array = alloc_pH(31)
i = 0
while i < 31:
  t_array[i] = NONE
  i += 1
t_array[1] = 1
t_array[23] = 2
t_array[24] = 17
t_array[25] = 5
t_array[26] = 65
t_array[27] = 3
t_array[28] = 33
t_array[29] = 9
t_array[30] = 129
header_bltype_codes = tree_from_raw_data(t_array, 9, 129)

header_wbits = NONE
header_window_size = NONE
output_window = NONE # RingBuffer []
output_window_pointer = 0
count_output = 0 # Decompressor.count_output
distance_buf = alloc_pH(4)
distance_buf[0] = 16  # reversed!
distance_buf[1] = 15
distance_buf[2] = 11
distance_buf[3] = 4
distance_buf_pointer = 3
literal_buf = alloc_pM(2)
literal_buf[0] = 0
literal_buf[1] = 0
literal_buf_pointer = 0
meta_block_header_is_last = NONE
meta_block_header_is_last_empty = NONE
meta_block_header_m_nibbles = NONE
meta_block_header_m_skip_bytes = NONE
meta_block_header_m_skip_len = NONE
meta_block_header_m_len = NONE
meta_block_header_is_uncompressed = NONE
meta_block_header_n_bltypes_l = NONE
meta_block_header_n_bltypes_i = NONE
meta_block_header_n_bltypes_d = NONE
meta_block_header_n_postfix = NONE
meta_block_header_n_direct = NONE
meta_block_header_n_trees_l = NONE
meta_block_header_n_trees_d = NONE
meta_block_header_c_map_l = NONE
meta_block_header_c_map_d = NONE
meta_block_prefix_tree_block_types_literals = NONE
meta_block_prefix_tree_block_counts_literals = NONE
meta_block_prefix_trees_literals = NONE
meta_block_count_output = 0
meta_block_btype_l = 0
meta_block_btype_l_prev = 1
meta_block_blen_l = NONE
meta_block_blen_i = NONE
meta_block_blen_d = NONE
meta_block_btype_i = 0
meta_block_btype_i_prev = 1
meta_block_btype_d = 0
meta_block_btype_d_prev = 1
meta_block_prefix_tree_block_types_insert_and_copy_lengths = NONE
meta_block_prefix_tree_block_counts_insert_and_copy_lengths = NONE
meta_block_prefix_tree_block_types_distances = NONE
meta_block_prefix_tree_block_counts_distances = NONE
meta_block_prefix_trees_insert_and_copy_lengths = NONE
meta_block_prefix_trees_distances = NONE
meta_block_context_modes_literals = NONE
meta_block_insert_and_copy_length = NONE
meta_block_copy_length = NONE
meta_block_insert_length = NONE
meta_block_distance = NONE
meta_block_distance_code = NONE


state = StreamBegin

def parse_wbits():
  return lookup_symbol(header_wbits_codes)

def parse_is_last():
  global IsLast_data
  if read_bit():
    error() # eof
  else:
    IsLast_data = read_bit_result
    return IsLast

def parse_is_last_empty():
  global IsLastEmpty_data
  if read_bit():
    error() # eof
  else:
    IsLastEmpty_data = read_bit_result
    return IsLastEmpty

def parse_m_nibbles():
  global MNibbles_data
  if read_u32_from_n_bits(2):
    error() # eof
  if read_u32_from_n_bits_result == 3:
    MNibbles_data = 0
    return MNibbles
  else:
    MNibbles_data = read_u32_from_n_bits_result + 4
    return MNibbles

def parse_m_skip_bytes():
  global MSkipBytes_data
  if read_u32_from_n_bits(2):
    error() # eof
  MSkipBytes_data = read_u32_from_n_bits_result
  return MSkipBytes

def parse_m_skip_len():
    global MSkipLen_data
    bytes_ = read_fixed_length_string(meta_block_header_m_skip_bytes)
    if bytes_ == NONE:
      error() # eof
    if meta_block_header_m_skip_bytes > 1 and bytes_[meta_block_header_m_skip_bytes - 1] == 0:
      error()
    MSkipLen_data = 0
    i = 0
    while i < meta_block_header_m_skip_bytes:
      MSkipLen_data = MSkipLen_data | (bytes_[i] << i)  # u32!
      i += 1
    return MSkipLen

def parse_m_len():
    global MLen_data
    if read_u32_from_n_nibbles(meta_block_header_m_nibbles):
      error()
    if meta_block_header_m_nibbles > 4 and (read_u32_from_n_nibbles_result >> ((meta_block_header_m_nibbles - 1)*4) == 0):
      error() # NonZeroTrailerNibble
    MLen_data = read_u32_from_n_nibbles_result + 1
    return MLen

def parse_is_uncompressed():
    global IsUncompressed_data
    if read_bit():
      error()
    IsUncompressed_data = read_bit_result
    return IsUncompressed

def parse_mlen_literals():
    global MLenLiterals_data
    MLenLiterals_data = read_fixed_length_string(meta_block_header_m_len)
    if MLenLiterals_data == NONE:
      error()
    return MLenLiterals

def parse_n_bltypes():
  value = lookup_symbol(header_bltype_codes)
  if value == 1 or value == 2:
    extra_bits = 0
  elif value == 3:
    extra_bits = 1
  elif value == 5:
    extra_bits = 2
  elif value == 9:
    extra_bits = 3
  elif value == 17:
    extra_bits = 4
  elif value == 33:
    extra_bits = 5
  elif value == 65:
    extra_bits = 6
  elif value == 129:
    extra_bits = 7
  if extra_bits > 0:
    if read_u32_from_n_bits(extra_bits):
      error()
    return value + read_u32_from_n_bits_result
  else:
    return value

def parse_n_bltypes_l():
  global NBltypesL_data
  NBltypesL_data = parse_n_bltypes()
  if NBltypesL_data == NONE:
    error()
  return NBltypesL

def parse_n_bltypes_i():
  global NBltypesI_data
  NBltypesI_data = parse_n_bltypes()
  if NBltypesI_data == NONE:
    error()
  return NBltypesI

def parse_n_bltypes_d():
  global NBltypesD_data
  NBltypesD_data = parse_n_bltypes()
  if NBltypesD_data == NONE:
    error()
  return NBltypesD

def parse_n_postfix():
  global NPostfix_data
  if read_u32_from_n_bits(2):
    error()
  NPostfix_data = read_u32_from_n_bits_result
  return NPostfix

def parse_n_direct():
  global NDirect_data
  if read_u32_from_n_bits(4):
    error()
  NDirect_data = read_u32_from_n_bits_result << meta_block_header_n_postfix
  return NDirect

def parse_context_modes_literals():
  global ContextModesLiterals_data
  ContextModesLiterals_data = alloc_pM(meta_block_header_n_bltypes_l)
  i = 0
  while i < meta_block_header_n_bltypes_l:
    if read_u32_from_n_bits(2):
      error()
    ContextModesLiterals_data[i] = read_u32_from_n_bits_result
    i += 1
  return ContextModesLiterals

def parse_n_trees_l():
  global NTreesL_data
  NTreesL_data = parse_n_bltypes()
  if NTreesL_data == NONE:
    error()
  return NTreesL

def parse_n_trees_d():
  global NTreesD_data
  NTreesD_data = parse_n_bltypes()
  if NTreesD_data == NONE:
    error()
  return NTreesD

def parse_prefix_code_kind():
  global PrefixCodeKind_Complex_data
  if read_u32_from_n_bits(2):
    error()
  if read_u32_from_n_bits_result == 1:
    return PrefixCodeKind_Simple
  PrefixCodeKind_Complex_data = read_u32_from_n_bits_result
  return PrefixCodeKind_Complex

def parse_simple_prefix_code(alphabet_size):
  #import ipdb; ipdb.set_trace()
  bit_width = alphabet_size - 1
  n = 0
  # count leading zeros
  if bit_width == 0:
    n = 16
  else:
    while True:
        if bit_width >= 32768:  # 2**15
          break
        n += 1
        bit_width <<= 1
  bit_width = 16 - n
  if read_u32_from_n_bits(2):
    error()
  n_sym = read_u32_from_n_bits_result + 1
  symbols = alloc_pH(n_sym)
  i = 0
  while i < n_sym:
    if read_u32_from_n_bits(bit_width):
      error()
    if read_u32_from_n_bits_result < alphabet_size:
      symbols[i] = read_u32_from_n_bits_result
    else:
      error()  # InvalidSymbol
    i += 1
  i = 0
  while i < n_sym - 1:
    j = i+1
    while j < n_sym:
      if symbols[i] == symbols[j]:
        error() # InvalidSymbol
      j += 1
    i += 1
  if n_sym == 4:
    if read_bit():
      error() # eof
    tree_select = read_bit_result
  else:
    tree_select = NONE
  if n_sym == 1 and tree_select == NONE:
    code_lengths = alloc_pM(1)
    code_lengths[0] = 0
  elif n_sym == 2 and tree_select == NONE:
    tmp_ = symbols[0]
    if tmp_ > symbols[1]:
      symbols[0] = symbols[1]
      symbols[1] = tmp_
    code_lengths = alloc_pM(2)
    code_lengths[0] = 1
    code_lengths[1] = 1
  elif n_sym == 3 and tree_select == NONE:
    # [1..3]rust  sort ind 1...2
    tmp_ = symbols[1]
    if tmp_ > symbols[2]:
      symbols[1] = symbols[2]
      symbols[2] = tmp_
    code_lengths = alloc_pM(3)
    code_lengths[0] = 1
    code_lengths[1] = 2
    code_lengths[2] = 2
  elif n_sym == 4 and tree_select == 0:
    # sort all in-place with insertion sort
    i = 1
    while i < n_sym:
      x = symbols[i]
      j = i - 1
      while j >= 0 and symbols[j] > x:
          symbols[j+1] = symbols[j]
          j = j - 1
      symbols[j+1] = x
      i += 1
    code_lengths = alloc_pM(4)
    code_lengths[0] = 2
    code_lengths[1] = 2
    code_lengths[2] = 2
    code_lengths[3] = 2
  elif n_sym == 4 and tree_select == 1:
    # [2..4]rust  sort ind 2...3
    tmp_ = symbols[2]
    if tmp_ > symbols[3]:
      symbols[2] = symbols[3]
      symbols[3] = tmp_
    code_lengths = alloc_pM(4)
    code_lengths[0] = 1
    code_lengths[1] = 2
    code_lengths[2] = 3
    code_lengths[3] = 3
  else:
    error()  # unreachable as len(symbols)<=4
  ret = codes_from_lengths_and_symbols(code_lengths, symbols)
  return ret

def parse_complex_prefix_code(h_skip, alphabet_size):
  #import ipdb; ipdb.set_trace()
  # symbols = [1, 2, 3, 4, 0, 5, 17, 6, 16, 7, 8, 9, 10, 11, 12, 13, 14, 15]
  bit_lengths_code = header_bit_lengths_code
  code_lengths = alloc_pM(18)
  i = 0
  while i < 18:
    code_lengths[i] = 0
    i += 1
  sum_ = 0
  len_non_zero_codelengths = 0
  i = h_skip
  while i < 18:
    code_length = lookup_symbol(bit_lengths_code)
    if code_length == NONE:
      error()
    code_lengths[i] = code_length
    if code_length > 0:
        sum_ = sum_ + (32 >> code_length)
        len_non_zero_codelengths += 1
        #
        # print("code length = ", code_lengths[i])
        # print("32 >> code length = ", 32 >> code_lengths[i])
        # print("sum = ", sum_)
        #
        if sum_ == 32:
          break
        if sum_ > 32:
          error() # CodeLengthsChecksum
    i += 1
  if len_non_zero_codelengths == 0:
    error()  # NoCodeLength
  if len_non_zero_codelengths >= 2 and sum_ < 32:
    error()  # CodeLengthsChecksum
  new_code_lengths = alloc_pM(18)
  new_code_lengths[0] = code_lengths[4]
  new_code_lengths[1] = code_lengths[0]
  new_code_lengths[2] = code_lengths[1]
  new_code_lengths[3] = code_lengths[2]
  new_code_lengths[4] = code_lengths[3]
  new_code_lengths[5] = code_lengths[5]
  new_code_lengths[6] = code_lengths[7]
  new_code_lengths[7] = code_lengths[9]
  new_code_lengths[8] = code_lengths[10]
  new_code_lengths[9] = code_lengths[11]
  new_code_lengths[10] = code_lengths[12]
  new_code_lengths[11] = code_lengths[13]
  new_code_lengths[12] = code_lengths[14]
  new_code_lengths[13] = code_lengths[15]
  new_code_lengths[14] = code_lengths[16]
  new_code_lengths[15] = code_lengths[17]
  new_code_lengths[16] = code_lengths[8]
  new_code_lengths[17] = code_lengths[6]
  code_lengths = new_code_lengths
  symbols = alloc_pH(18)
  i = 0
  while i < 18:
    symbols[i] = i
    i += 1
  prefix_code_code_lengths = codes_from_lengths_and_symbols(code_lengths, symbols)
  actual_code_lengths = alloc_pM(alphabet_size)
  i = 0
  while i < alphabet_size:
    actual_code_lengths[i] = 0
    i += 1
  sum_ = 0
  last_symbol = NONE
  last_repeat = NONE
  last_non_zero_codelength = 8
  i = 0
  while i < alphabet_size:
    code_length_code = lookup_symbol(prefix_code_code_lengths)
    if code_length_code == NONE:
      error()
    if code_length_code >= 0 and code_length_code <= 15:
      actual_code_lengths[i] = code_length_code
      i += 1
      last_symbol = code_length_code
      last_repeat = NONE
      if code_length_code > 0:
        last_non_zero_codelength = code_length_code
        sum_ += 32768 >> code_length_code
        if sum_ == 32768:
          break
        elif sum_ > 32768:
          error()  # CodeLengthsChecksum
    elif code_length_code == 16:
      if read_u32_from_n_bits(2):
        error()  # UnexpectedEOF
      extra_bits = read_u32_from_n_bits_result
      if last_symbol == 16 and last_repeat != NONE:
        new_repeat = 4 * (last_repeat - 2) + extra_bits + 3
        if i + new_repeat - last_repeat > alphabet_size:
          error()  # ParseErrorComplexPrefixCodeLengths
        j = 0
        while j < new_repeat - last_repeat:
          actual_code_lengths[i] = last_non_zero_codelength
          i += 1
          sum_ += 32768 >> last_non_zero_codelength
          j += 1
        if sum_ == 32768:
          break
        elif sum_ > 32768:
          error()  # CodeLengthsChecksum
        last_repeat = new_repeat
      else:
        repeat = 3 + extra_bits
        if i + repeat > alphabet_size:
          error()  # ParseErrorComplexPrefixCodeLengths
        j = 0
        while j < repeat:
          actual_code_lengths[i] = last_non_zero_codelength
          i += 1
          sum_ += 32768 >> last_non_zero_codelength
          j += 1
        if sum_ == 32768:
          break
        elif sum_ > 32768:
          error()  # CodeLengthsChecksum
        last_repeat = repeat
      last_symbol = 16
    elif code_length_code == 17:
      if read_u32_from_n_bits(3):
        error()  # UnexpectedEOF
      extra_bits = read_u32_from_n_bits_result
      if last_symbol == 17 and last_repeat != NONE:
        new_repeat = (8 * (last_repeat - 2)) + extra_bits + 3
        i += new_repeat - last_repeat
        last_repeat = new_repeat
      else:
        repeat = 3 + extra_bits
        i += repeat
        last_repeat = repeat
      if i > alphabet_size:
        error()  # ParseErrorComplexPrefixCodeLengths
      last_symbol = 17
    else:
      error()   # unreachable OR ParseErrorComplexPrefixCodeLengths
  tmp_ = 0
  i = 0
  while i < alphabet_size:
    if actual_code_lengths[i] > 0:
      tmp_ += 1
    i += 1
  if tmp_ < 2:
    error()  # LessThanTwoNonZeroCodeLengths
  ret = codes_from_lengths(actual_code_lengths)
  return ret

def parse_prefix_code(alphabet_size):
  prefix_code_kind = parse_prefix_code_kind()
  if prefix_code_kind == NONE:
    error()
  if prefix_code_kind == PrefixCodeKind_Complex:
    return parse_complex_prefix_code(PrefixCodeKind_Complex_data, alphabet_size)
  elif prefix_code_kind == PrefixCodeKind_Simple:
    return parse_simple_prefix_code(alphabet_size)
  else:
    return NONE # unreachable

def parse_prefix_code_block_types_literals():
  global PrefixCodeBlockTypesLiterals_data
  alphabet_size = meta_block_header_n_bltypes_l + 2
  tmp_ = parse_prefix_code(alphabet_size)
  if tmp_ == NONE:
    error()
  PrefixCodeBlockTypesLiterals_data = tmp_
  return PrefixCodeBlockTypesLiterals

def parse_prefix_code_block_counts_literals():
  global PrefixCodeBlockCountsLiterals_data
  tmp_ = parse_prefix_code(26)
  if tmp_ == NONE:
    error()
  PrefixCodeBlockCountsLiterals_data = tmp_
  return PrefixCodeBlockCountsLiterals

def parse_prefix_code_block_types_insert_and_copy_lengths():
  global PrefixCodeBlockTypesInsertAndCopyLengths_data
  alphabet_size = meta_block_header_n_bltypes_i + 2
  tmp_ = parse_prefix_code(alphabet_size)
  if tmp_ == NONE:
    error()
  PrefixCodeBlockTypesInsertAndCopyLengths_data = tmp_
  return PrefixCodeBlockTypesInsertAndCopyLengths

def parse_prefix_code_block_counts_insert_and_copy_lengths():
  global PrefixCodeBlockCountsInsertAndCopyLengths_data
  tmp_ = parse_prefix_code(26)
  if tmp_ == NONE:
    error()
  PrefixCodeBlockCountsInsertAndCopyLengths_data = tmp_
  return PrefixCodeBlockCountsInsertAndCopyLengths

def parse_prefix_code_block_types_distances():
  global PrefixCodeBlockTypesDistances_data
  alphabet_size = meta_block_header_n_bltypes_d + 2
  tmp_ = parse_prefix_code(alphabet_size)
  if tmp_ == NONE:
    error()
  PrefixCodeBlockTypesDistances_data = tmp_
  return PrefixCodeBlockTypesDistances

def parse_prefix_code_block_counts_distances():
  global PrefixCodeBlockCountsDistances_data
  tmp_ = parse_prefix_code(26)
  if tmp_ == NONE:
    error()
  PrefixCodeBlockCountsDistances_data = tmp_
  return PrefixCodeBlockCountsDistances

def parse_block_count(prefix_code):  # HuffmanCodes
  symbol = lookup_symbol(prefix_code)
  if symbol >= 0 and symbol <= 3:
    base_length = 1 + (symbol << 2)
    extra_bits = 2
  elif symbol >= 4 and symbol <= 7:
    base_length = 17 + ((symbol - 4) << 3)
    extra_bits = 3
  elif symbol >= 8 and symbol <= 11:
    base_length = 49 + ((symbol - 8) << 4)
    extra_bits = 4
  elif symbol >= 12 and symbol <= 15:
    base_length = 113 + ((symbol - 12) << 5)
    extra_bits = 5
  elif symbol >= 16 and symbol <= 17:
    base_length = 241 + ((symbol - 16) << 6)
    extra_bits = 6
  elif symbol == 18:
    base_length = 369
    extra_bits = 7
  elif symbol == 19:
    base_length = 497
    extra_bits = 8
  elif symbol == 20:
    base_length = 753
    extra_bits = 9
  elif symbol == 21:
    base_length = 1265
    extra_bits = 10
  elif symbol == 22:
    base_length = 2289
    extra_bits = 11
  elif symbol == 23:
    base_length = 4337
    extra_bits = 12
  elif symbol == 24:
    base_length = 8433
    extra_bits = 13
  elif symbol == 25:
    base_length = 16625
    extra_bits = 24
  else:
    error() # err EOF OR InvalidBlockCountCode
  if read_u32_from_n_bits(extra_bits):
    error() # err EOF
  return base_length + read_u32_from_n_bits_result

def parse_first_block_count_literals():
  global FirstBlockCountLiterals_data
  prefix_code = meta_block_prefix_tree_block_counts_literals
  FirstBlockCountLiterals_data = parse_block_count(prefix_code)
  if FirstBlockCountLiterals_data == NONE:
    error()
  return FirstBlockCountLiterals

def parse_first_block_count_insert_and_copy_lengths():
  global FirstBlockCountInsertAndCopyLengths_data
  prefix_code = meta_block_prefix_tree_block_counts_insert_and_copy_lengths
  FirstBlockCountInsertAndCopyLengths_data = parse_block_count(prefix_code)
  if FirstBlockCountInsertAndCopyLengths_data == NONE:
    error()
  return FirstBlockCountInsertAndCopyLengths

def parse_first_block_count_distances():
  global FirstBlockCountDistances_data
  prefix_code = meta_block_prefix_tree_block_counts_distances
  FirstBlockCountDistances_data = parse_block_count(prefix_code)
  if FirstBlockCountDistances_data == NONE:
    error()
  return FirstBlockCountDistances

def parse_prefix_codes_literals():
  global PrefixCodesLiterals_data
  n_trees_l = meta_block_header_n_trees_l
  prefix_codes = alloc_L(n_trees_l)
  alphabet_size = 256
  j = 0
  while j < n_trees_l:
    prefix_codes[j] = parse_prefix_code(alphabet_size)
    if prefix_codes[j] == NONE:
      error()
    j += 1
  PrefixCodesLiterals_data = prefix_codes
  return PrefixCodesLiterals

def parse_prefix_codes_insert_and_copy_lengths():
  global PrefixCodesInsertAndCopyLengths_data
  n_bltypes_i = meta_block_header_n_bltypes_i
  prefix_codes = alloc_L(n_bltypes_i)
  alphabet_size = 704
  j = 0
  while j < n_bltypes_i:
    prefix_codes[j] = parse_prefix_code(alphabet_size)
    if prefix_codes[j] == NONE:
      error()
    j += 1
  PrefixCodesInsertAndCopyLengths_data = prefix_codes
  return PrefixCodesInsertAndCopyLengths

def parse_prefix_codes_distances():
  global PrefixCodesDistances_data
  n_trees_d = meta_block_header_n_trees_d
  prefix_codes = alloc_L(n_trees_d)
  alphabet_size = 16 + meta_block_header_n_direct + (48 << meta_block_header_n_postfix)
  j = 0
  while j < n_trees_d:
    prefix_codes[j] = parse_prefix_code(alphabet_size)
    if prefix_codes[j] == NONE:
      error()
    j += 1
  PrefixCodesDistances_data = prefix_codes
  return PrefixCodesDistances

def parse_context_map(n_trees, len_):
  if read_bit():
    error() # err eof
  rlemax = read_bit_result
  if rlemax:
    if read_u32_from_n_bits(4):
      error() # err eof
    rlemax = read_u32_from_n_bits_result + 1
  alphabet_size = rlemax + n_trees
  prefix_tree = parse_prefix_code(alphabet_size)
  if prefix_tree == NONE:
    error()  # err
  c_map = alloc_pM(len_)
  c_pushed = 0
  while c_pushed < len_:
    run_length_code = lookup_symbol(prefix_tree)
    if run_length_code == NONE:
      error()  # err eof OR ParseErrorContextMap
    if run_length_code > 0 and run_length_code <= rlemax:
      if read_u32_from_n_bits(run_length_code):
        error() # err eof
      repeat = (1 << run_length_code) + read_u32_from_n_bits_result
      j = 0
      while j < repeat:
        c_map[c_pushed] = 0
        c_pushed += 1
        if c_pushed > len_:
          error()  # RunLengthExceededSizeOfContextMap
        j += 1
    else:
      if run_length_code == 0:
        c_map[c_pushed] = 0
      else:
        c_map[c_pushed] = run_length_code - rlemax
      c_pushed += 1
  if read_bit():
    error()  # err eof
  imtf_bit = read_bit_result
  if imtf_bit:
    inverse_move_to_front_transform(c_map) # mut c_map
  return c_map

def parse_context_map_literals():
  global ContextMapLiterals_data
  n_trees = meta_block_header_n_trees_l
  len_ = meta_block_header_n_bltypes_l * 64
  ContextMapLiterals_data = parse_context_map(n_trees, len_)
  if ContextMapLiterals_data == NONE:
    error() # err
  return ContextMapLiterals

def parse_context_map_distances():
  global ContextMapDistances_data
  n_trees = meta_block_header_n_trees_d
  len_ = meta_block_header_n_bltypes_d * 4
  ContextMapDistances_data = parse_context_map(n_trees, len_)
  if ContextMapDistances_data == NONE:
    error() # err
  return ContextMapDistances

def inverse_move_to_front_transform(v): # modifies v
  mtf = alloc_pM(256)
  i = 0
  while i < 256:
    mtf[i] = i
    i += 1
  i = 0
  while i < len(v):
    index = v[i]
    value = mtf[index]
    v[i] = value
    j = index
    while j > 0:
      mtf[j] = mtf[j - 1]
      j -= 1
    mtf[0] = value
    i += 1

def decode_insert_and_copy_length():
  global InsertLengthAndCopyLength_data_co_len, InsertLengthAndCopyLength_data_in_len
  insert_length = INSERT_LENGTHS_AND_COPY_LENGTHS[0 + meta_block_insert_and_copy_length*4]
  extra_bits_insert = INSERT_LENGTHS_AND_COPY_LENGTHS[1 + meta_block_insert_and_copy_length*4]
  copy_length = INSERT_LENGTHS_AND_COPY_LENGTHS[2 + meta_block_insert_and_copy_length*4]
  extra_bits_copy = INSERT_LENGTHS_AND_COPY_LENGTHS[3 + meta_block_insert_and_copy_length*4]
  if read_u32_from_n_bits(extra_bits_insert):
    error() # err eof
  insert_length += read_u32_from_n_bits_result
  if read_u32_from_n_bits(extra_bits_copy):
    error() # err eof
  copy_length += read_u32_from_n_bits_result
  InsertLengthAndCopyLength_data_co_len = copy_length
  InsertLengthAndCopyLength_data_in_len = insert_length
  return InsertLengthAndCopyLength


parse_block_switch_command_block_type = NONE
parse_block_switch_command_block_count = NONE
def parse_block_switch_command(prefix_tree_types, btype, btype_prev, n_bltypes, prefix_tree_counts): # 1:HuffmanCodes,2-4:nr,5:HuffmanCodes
  global parse_block_switch_command_block_type, parse_block_switch_command_block_count
  block_type_code = lookup_symbol(prefix_tree_types)
  if block_type_code == NONE:
    error() # decompr err
  if block_type_code == 0:
    block_type = btype_prev
  elif block_type_code == 1:
    block_type = (btype + 1) % n_bltypes
  elif block_type_code >= 2 and block_type_code <= 258:
    block_type = block_type_code - 2
  else:
    return NONE # unreachable
  block_count = parse_block_count(prefix_tree_counts)
  if block_count == NONE:
    error() # err
  parse_block_switch_command_block_type = block_type
  parse_block_switch_command_block_count = block_count
  return 0

parse_block_switch_command_literals_block_type = NONE
parse_block_switch_command_literals_block_count = NONE
def parse_block_switch_command_literals():
  global parse_block_switch_command_literals_block_type, parse_block_switch_command_literals_block_count
  prefix_tree_types = meta_block_prefix_tree_block_types_literals
  btype = meta_block_btype_l
  btype_prev = meta_block_btype_l_prev
  n_bltypes = meta_block_header_n_bltypes_l
  prefix_tree_counts = meta_block_prefix_tree_block_counts_literals
  if parse_block_switch_command(prefix_tree_types, btype, btype_prev, n_bltypes, prefix_tree_counts):
    error() # err
  parse_block_switch_command_literals_block_type = parse_block_switch_command_block_type
  parse_block_switch_command_literals_block_count = parse_block_switch_command_block_count
  return 0

parse_block_switch_command_insert_and_copy_lengths_block_type = NONE
parse_block_switch_command_insert_and_copy_lengths_block_count = NONE
def parse_block_switch_command_insert_and_copy_lengths():
  global parse_block_switch_command_insert_and_copy_lengths_block_type, parse_block_switch_command_insert_and_copy_lengths_block_count
  prefix_tree_types = meta_block_prefix_tree_block_types_insert_and_copy_lengths
  btype = meta_block_btype_i
  btype_prev = meta_block_btype_i_prev
  n_bltypes = meta_block_header_n_bltypes_i
  prefix_tree_counts = meta_block_prefix_tree_block_counts_insert_and_copy_lengths
  if parse_block_switch_command(prefix_tree_types, btype, btype_prev, n_bltypes, prefix_tree_counts):
    error() # err
  parse_block_switch_command_insert_and_copy_lengths_block_type = parse_block_switch_command_block_type
  parse_block_switch_command_insert_and_copy_lengths_block_count = parse_block_switch_command_block_count
  return 0

def parse_insert_and_copy_length():
  global meta_block_btype_i_prev, meta_block_blen_i, meta_block_btype_i, InsertAndCopyLength_data
  if meta_block_blen_i == NONE:
    pass
  elif meta_block_blen_i == 0:
    if parse_block_switch_command_insert_and_copy_lengths():
      error() # err
    meta_block_btype_i_prev = meta_block_btype_i
    meta_block_btype_i = parse_block_switch_command_insert_and_copy_lengths_block_type
    meta_block_blen_i = parse_block_switch_command_insert_and_copy_lengths_block_count - 1
  else:
    meta_block_blen_i -= 1
  btype = meta_block_btype_i
  InsertAndCopyLength_data = lookup_symbol(meta_block_prefix_trees_insert_and_copy_lengths[btype])
  if InsertAndCopyLength_data == NONE:
    error() # err eof OR ParseErrorInsertAndCopyLength
  return InsertAndCopyLength

parse_block_switch_command_distances_block_type = NONE
parse_block_switch_command_distances_block_count = NONE
def parse_block_switch_command_distances():
  global parse_block_switch_command_distances_block_type, parse_block_switch_command_distances_block_count
  prefix_tree_types = meta_block_prefix_tree_block_types_distances
  btype = meta_block_btype_d
  btype_prev = meta_block_btype_d_prev
  n_bltypes = meta_block_header_n_bltypes_d
  prefix_tree_counts = meta_block_prefix_tree_block_counts_distances
  if parse_block_switch_command(prefix_tree_types, btype, btype_prev, n_bltypes, prefix_tree_counts):
    error() # err
  parse_block_switch_command_distances_block_type = parse_block_switch_command_block_type
  parse_block_switch_command_distances_block_count = parse_block_switch_command_block_count
  return 0

def parse_insert_literals():
  global literal_buf_pointer, meta_block_btype_l_prev, meta_block_btype_l, meta_block_blen_l, InsertLiterals_data
  insert_length = meta_block_insert_length
  literals = alloc_pM(insert_length)
  j = 0
  while j < insert_length:
    if meta_block_blen_l == NONE:
      pass
    elif meta_block_blen_l == 0:
      if parse_block_switch_command_literals():
        error()
      meta_block_btype_l_prev = meta_block_btype_l
      meta_block_btype_l = parse_block_switch_command_literals_block_type
      meta_block_blen_l = parse_block_switch_command_literals_block_count - 1
    else:
      meta_block_blen_l -= 1
    btype = meta_block_btype_l
    context_mode = meta_block_context_modes_literals[btype]
    p1 = literal_buf[literal_buf_pointer]
    p2 = literal_buf[(literal_buf_pointer+1) % 2]
    if context_mode == 0:
      cid = p1 & 63
    elif context_mode == 1:
      cid = p1 >> 2
    elif context_mode == 2:
      cid = LUT_0[p1] | LUT_1[p2]
    elif context_mode == 3:
      cid = (LUT_2[p1] << 3) | LUT_2[p2]
    else:
      return NONE # unreachable
    index = meta_block_header_c_map_l[btype * 64 + cid]
    tmp_ = lookup_symbol(meta_block_prefix_trees_literals[index])
    if tmp_ == NONE:
      error() # err eof OR ParseErrorInsertLiterals
    literals[j] = tmp_
    literal_buf_pointer = (literal_buf_pointer+1) % 2
    literal_buf[literal_buf_pointer] = tmp_
    j += 1
  InsertLiterals_data = literals
  return InsertLiterals

def parse_distance_code():
  global meta_block_btype_d_prev, meta_block_btype_d, meta_block_blen_d, DistanceCode_data
  if meta_block_distance == 0:
    DistanceCode_data = 0
    return DistanceCode
  elif meta_block_distance == NONE:
    pass
  else:
    return NONE # unreachable
  if meta_block_blen_d == NONE:
    pass
  elif meta_block_blen_d == 0:
    if parse_block_switch_command_distances():
      error() # err
    meta_block_btype_d_prev = meta_block_btype_d
    meta_block_btype_d = parse_block_switch_command_distances_block_type
    meta_block_blen_d = parse_block_switch_command_distances_block_count - 1
  else:
    meta_block_blen_d -= 1
  if meta_block_copy_length == 0 or meta_block_copy_length == 1:
    error() # unreachable
  elif meta_block_copy_length == 2 or meta_block_copy_length == 3 or meta_block_copy_length == 4:
    cid = meta_block_copy_length - 2
  else:
    cid = 3
  index = meta_block_header_c_map_d[meta_block_btype_d * 4 + cid]
  DistanceCode_data = lookup_symbol(meta_block_prefix_trees_distances[index])
  if DistanceCode_data == NONE:
    error() # err decompr ParseErrorDistanceCode OR eof
  return DistanceCode

def decode_distance():
  global Distance_data, distance_buf_pointer
  if meta_block_distance_code == NONE:
    error() # unreachable
  elif meta_block_distance_code >= 0 and meta_block_distance_code <= 3:
    distance = distance_buf[(4 + distance_buf_pointer - meta_block_distance_code) % 4]
    #if distance == NONE:
    #  error() # RingBufferError
  elif meta_block_distance_code >= 4 and meta_block_distance_code <= 9:
    distance = distance_buf[distance_buf_pointer]
    sign = meta_block_distance_code % 2
    d = (meta_block_distance_code - 2) >> 1
    if sign:  # case +
      distance = distance + d
    else:  # case -
      if distance <= d:
        error() # InvalidNonPositiveDistance
      distance = distance - d
  elif meta_block_distance_code >= 10 and meta_block_distance_code <= 15:
    distance = distance_buf[(3 + distance_buf_pointer) % 4]
    sign = meta_block_distance_code % 2
    d = (meta_block_distance_code - 8) >> 1
    if sign:  # case +
      distance = distance + d
    else:  # case -
      if distance <= d:
        error() # InvalidNonPositiveDistance
      distance = distance - d
  elif meta_block_distance_code <= (15 + meta_block_header_n_direct):
    distance = meta_block_distance_code - 15
  else:
    n_direct = meta_block_header_n_direct
    n_postfix = meta_block_header_n_postfix
    ndistbits = 1 + ((meta_block_distance_code - n_direct - 16) >> (n_postfix + 1))
    if read_u32_from_n_bits(ndistbits):
      error() # eof err
    dextra = read_u32_from_n_bits_result
    hcode = (meta_block_distance_code - n_direct - 16) >> n_postfix
    postfix_mask = (1 << n_postfix) - 1
    lcode = (meta_block_distance_code - n_direct - 16) & postfix_mask
    offset = ((2 + (hcode & 1)) << ndistbits) - 4
    distance = ((offset + dextra) << n_postfix) + lcode + n_direct + 1
  if meta_block_distance_code > 0 and distance <= header_window_size and distance <= count_output:
    distance_buf_pointer = (distance_buf_pointer + 1) % 4
    distance_buf[distance_buf_pointer] = distance
  Distance_data = distance
  return Distance

def copy_literals():
  global CopyLiterals_data
  window_size = header_window_size
  copy_length = meta_block_copy_length
  distance = meta_block_distance
  max_allowed_distance = count_output
  if window_size < max_allowed_distance:
    max_allowed_distance = window_size
  if distance <= max_allowed_distance:
    window = alloc_pM(copy_length)
    l = distance
    if copy_length < l:
      l = copy_length
    # output_window.slice_tail(distance - 1, &mut window)
    n = distance - 1
    i = 0
    while i < copy_length:
      t = (output_window_pointer + len(output_window) - n + i) % len(output_window)
      window[i] = output_window[t]
      i += 1
    i = 0
    while i < copy_length:
      window[i] = window[i % l]
      i += 1
    CopyLiterals_data = window
    return CopyLiterals
  else:
    if copy_length < 4 or copy_length > 24:
      error()  # InvalidLengthInStaticDictionary
    word_id = distance - max_allowed_distance - 1
    if copy_length < 4:
      n_words_length = 0
    else:
      n_words_length = 1 << BROTLI_DICTIONARY_SIZE_BITS_BY_LENGTH[copy_length]
    index = word_id % n_words_length
    offset_from = BROTLI_DICTIONARY_OFFSETS_BY_LENGTH[copy_length] + index * copy_length
    offset_to = BROTLI_DICTIONARY_OFFSETS_BY_LENGTH[copy_length] + (index + 1) * copy_length
    base_word = alloc_pM(offset_to-offset_from)
    i = 0
    while i < offset_to-offset_from:
      base_word[i] = BROTLI_DICTIONARY[i + offset_from]
      i += 1
    transform_id = word_id >> BROTLI_DICTIONARY_SIZE_BITS_BY_LENGTH[copy_length]
    if transform_id > 120:
      error() # InvalidTransformId
    # print(bytes(eval('array.'+str(base_word))))  # remove
    CopyLiterals_data = transformation(transform_id, base_word)
    # print(transform_id, bytes(eval('array.'+str(CopyLiterals_data))))  # remove
    return CopyLiterals


def brotlidec(pinput, outb, cmpbuf=None):
  """pinput: input buffer, needs to support len() and []
     outb: output buffer, needs to support .append()
     returns bytes(outb)"""
  global count_output, header_wbits, header_window_size, literal_buf_pointer, meta_block_blen_d
  global meta_block_blen_i, meta_block_blen_l, meta_block_context_modes_literals, meta_block_copy_length
  global meta_block_count_output, meta_block_distance, meta_block_distance_code, meta_block_header_c_map_d
  global meta_block_btype_l_prev, meta_block_btype_l, meta_block_btype_i, meta_block_btype_i_prev
  global meta_block_btype_d, meta_block_btype_d_prev
  global meta_block_header_c_map_l, meta_block_header_is_last, meta_block_header_is_last_empty
  global meta_block_header_is_uncompressed, meta_block_header_m_len, meta_block_header_m_nibbles
  global meta_block_header_m_skip_bytes, meta_block_header_m_skip_len, meta_block_header_n_bltypes_d
  global meta_block_header_n_bltypes_i, meta_block_header_n_bltypes_l, meta_block_header_n_direct
  global meta_block_header_n_postfix, meta_block_header_n_trees_d, meta_block_header_n_trees_l
  global meta_block_insert_and_copy_length, meta_block_insert_length, meta_block_prefix_tree_block_counts_distances
  global meta_block_prefix_tree_block_counts_insert_and_copy_lengths, meta_block_prefix_tree_block_counts_literals
  global meta_block_prefix_tree_block_types_distances, meta_block_prefix_tree_block_types_insert_and_copy_lengths
  global meta_block_prefix_tree_block_types_literals, meta_block_prefix_trees_distances
  global meta_block_prefix_trees_insert_and_copy_lengths, meta_block_prefix_trees_literals
  global output_window, output_window_pointer, state, WBits_data, BROTLI_DICTIONARY
  global distance_buf, distance_buf_pointer, literal_buf
  global bit_pos, current_byte, global_bit_pos
  global input_buf, input_buf_pos, output_buf, gcmpbuf, cmpbuf_pos
  input_buf_pos = 0
  input_buf = pinput
  output_buf = outb
  gcmpbuf = cmpbuf
  if cmpbuf is not None:
    cmpbuf_pos = 0
  # import ipdb; ipdb.set_trace() # r
  state = StreamBegin
  while True:
    # print("state",state)
    # import ipdb; ipdb.set_trace() # c
    if state == StreamBegin:
      state = HeaderBegin
      distance_buf[0] = 16  # reversed!
      distance_buf[1] = 15
      distance_buf[2] = 11
      distance_buf[3] = 4
      distance_buf_pointer = 3
      literal_buf[0] = 0
      literal_buf[1] = 0
      literal_buf_pointer = 0
      count_output = 0
      bit_pos = 0
      current_byte = NONE
      global_bit_pos = 0
    elif state == NONE: # dec err
      error()
      return
    elif state == HeaderBegin:
      state = WBits
      WBits_data = parse_wbits()
    elif state == WBits:
      header_wbits = WBits_data
      header_window_size = (1 << WBits_data) - 16
      output_window = alloc_pM(header_window_size)
      output_window_pointer = 0
      state = HeaderEnd
    elif state == HeaderEnd:
      state = HeaderMetaBlockBegin
    elif state == HeaderMetaBlockBegin:
      meta_block_header_is_last = NONE
      meta_block_header_is_last_empty = NONE
      meta_block_header_m_nibbles = NONE
      meta_block_header_m_skip_bytes = NONE
      meta_block_header_m_skip_len = NONE
      meta_block_header_m_len = NONE
      meta_block_header_is_uncompressed = NONE
      meta_block_header_n_bltypes_l = NONE
      meta_block_header_n_bltypes_i = NONE
      meta_block_header_n_bltypes_d = NONE
      meta_block_header_n_postfix = NONE
      meta_block_header_n_direct = NONE
      meta_block_header_n_trees_l = NONE
      meta_block_header_n_trees_d = NONE
      meta_block_header_c_map_l = NONE
      meta_block_header_c_map_d = NONE
      meta_block_prefix_tree_block_types_literals = NONE
      meta_block_prefix_tree_block_counts_literals = NONE
      meta_block_prefix_trees_literals = NONE
      meta_block_count_output = 0
      meta_block_btype_l = 0
      meta_block_btype_l_prev = 1
      meta_block_blen_l = NONE
      meta_block_blen_i = NONE
      meta_block_blen_d = NONE
      meta_block_btype_i = 0
      meta_block_btype_i_prev = 1
      meta_block_btype_d = 0
      meta_block_btype_d_prev = 1
      meta_block_prefix_tree_block_types_insert_and_copy_lengths = NONE
      meta_block_prefix_tree_block_counts_insert_and_copy_lengths = NONE
      meta_block_prefix_tree_block_types_distances = NONE
      meta_block_prefix_tree_block_counts_distances = NONE
      meta_block_prefix_trees_insert_and_copy_lengths = NONE
      meta_block_prefix_trees_distances = NONE
      meta_block_context_modes_literals = NONE
      meta_block_insert_and_copy_length = NONE
      meta_block_copy_length = NONE
      meta_block_insert_length = NONE
      meta_block_distance = NONE
      meta_block_distance_code = NONE
      state = parse_is_last()
    elif state == IsLast and IsLast_data == 1:
      meta_block_header_is_last = 1
      state = parse_is_last_empty()
    elif state == IsLast and IsLast_data == 0:
      meta_block_header_is_last = 0
      state = parse_m_nibbles()
    elif state == IsLastEmpty and IsLastEmpty_data == 1:
      meta_block_header_is_last_empty = 1
      state = StreamEnd
    elif state == IsLastEmpty and IsLastEmpty_data == 0:
      meta_block_header_is_last_empty = 0
      state = parse_m_nibbles()
    elif state == MNibbles and MNibbles_data == 0:
      if read_bit():
        error() # eof
      if read_bit_result:
        error() # NonZeroReservedBit
        return
      meta_block_header_m_nibbles = 0
      state = parse_m_skip_bytes()
    elif state == MNibbles:
      meta_block_header_m_nibbles = MNibbles_data
      state = parse_m_len()
    elif state == MSkipBytes and MSkipBytes_data == 0:
      meta_block_header_m_skip_bytes = 0
      if read_u8_from_byte_tail() != 0:
        error() # NonZeroFillBit
        return
      state = MetaBlockEnd
    elif state == MSkipBytes:
      meta_block_header_m_skip_bytes = MSkipBytes_data
      state = parse_m_skip_len()
    elif state == MSkipLen:
      meta_block_header_m_skip_len = MSkipLen_data
      if read_u8_from_byte_tail() != 0:
        error() # NonZeroFillBit
        return
      state = MetaBlockEnd
    elif state == MLen:
      meta_block_header_m_len = MLen_data
      if meta_block_header_is_last:
        state = parse_n_bltypes_l()
      else:
        state = parse_is_uncompressed()
    elif state == IsUncompressed and IsUncompressed_data == 1:
      meta_block_header_is_uncompressed = 1
      if read_u8_from_byte_tail() != 0:
        error() # NonZeroFillBit
      state = parse_mlen_literals()
    elif state == MLenLiterals:
      i = 0
      while i < len(MLenLiterals_data):
        literal = MLenLiterals_data[i]
        out(literal)
        output_window_pointer = (output_window_pointer + 1) % len(output_window)
        output_window[output_window_pointer] = literal
        literal_buf_pointer = (literal_buf_pointer + 1) % 2
        literal_buf[literal_buf_pointer] = literal
        count_output += 1
        i += 1
      state = MetaBlockEnd
    elif state == IsUncompressed and IsUncompressed_data == 0:
      meta_block_header_is_uncompressed = 0
      state = parse_n_bltypes_l()
    elif state == NBltypesL:
      meta_block_header_n_bltypes_l = NBltypesL_data
      if NBltypesL_data >= 2:
        state = parse_prefix_code_block_types_literals()
      else:
        state = parse_n_bltypes_i()
    elif state == PrefixCodeBlockTypesLiterals:
      meta_block_prefix_tree_block_types_literals = PrefixCodeBlockTypesLiterals_data
      state = parse_prefix_code_block_counts_literals()
    elif state == PrefixCodeBlockCountsLiterals:
      meta_block_prefix_tree_block_counts_literals = PrefixCodeBlockCountsLiterals_data
      state = parse_first_block_count_literals()
    elif state == FirstBlockCountLiterals:
      meta_block_blen_l = FirstBlockCountLiterals_data
      state = parse_n_bltypes_i()
    elif state == NBltypesI:
      meta_block_header_n_bltypes_i = NBltypesI_data
      if NBltypesI_data >= 2:
        state = parse_prefix_code_block_types_insert_and_copy_lengths()
      else:
        state = parse_n_bltypes_d()
    elif state == PrefixCodeBlockTypesInsertAndCopyLengths:
      meta_block_prefix_tree_block_types_insert_and_copy_lengths = PrefixCodeBlockTypesInsertAndCopyLengths_data
      state = parse_prefix_code_block_counts_insert_and_copy_lengths()
    elif state == PrefixCodeBlockCountsInsertAndCopyLengths:
      meta_block_prefix_tree_block_counts_insert_and_copy_lengths = PrefixCodeBlockCountsInsertAndCopyLengths_data
      state = parse_first_block_count_insert_and_copy_lengths()
    elif state == FirstBlockCountInsertAndCopyLengths:
      meta_block_blen_i = FirstBlockCountInsertAndCopyLengths_data
      state = parse_n_bltypes_d()
    elif state == NBltypesD:
      meta_block_header_n_bltypes_d = NBltypesD_data
      if NBltypesD_data >= 2:
        state = parse_prefix_code_block_types_distances()
      else:
        state = parse_n_postfix()
    elif state == PrefixCodeBlockTypesDistances:
      meta_block_prefix_tree_block_types_distances = PrefixCodeBlockTypesDistances_data
      state = parse_prefix_code_block_counts_distances()
    elif state == PrefixCodeBlockCountsDistances:
      meta_block_prefix_tree_block_counts_distances = PrefixCodeBlockCountsDistances_data
      state = parse_first_block_count_distances()
    elif state == FirstBlockCountDistances:
      meta_block_blen_d = FirstBlockCountDistances_data
      state = parse_n_postfix()
    elif state == NPostfix:
      meta_block_header_n_postfix = NPostfix_data
      state = parse_n_direct()
    elif state == NDirect:
      meta_block_header_n_direct = NDirect_data
      state = parse_context_modes_literals()
    elif state == ContextModesLiterals:
      meta_block_context_modes_literals = ContextModesLiterals_data
      state = parse_n_trees_l()
    elif state == NTreesL:
      meta_block_header_n_trees_l = NTreesL_data
      meta_block_header_c_map_l = alloc_pM(64 * meta_block_header_n_bltypes_l)
      if NTreesL_data >= 2:
        state = parse_context_map_literals()
      else:
        state = parse_n_trees_d()
    elif state == ContextMapLiterals:
      meta_block_header_c_map_l = ContextMapLiterals_data
      state = parse_n_trees_d()
    elif state == NTreesD:
      meta_block_header_n_trees_d = NTreesD_data
      meta_block_header_c_map_d = alloc_pM(4 * meta_block_header_n_bltypes_d)
      if NTreesD_data >= 2:
        state = parse_context_map_distances()
      else:
        state = parse_prefix_codes_literals()
    elif state == ContextMapDistances:
      meta_block_header_c_map_d = ContextMapDistances_data
      state = parse_prefix_codes_literals()
    elif state == PrefixCodesLiterals:
      meta_block_prefix_trees_literals = PrefixCodesLiterals_data
      state = parse_prefix_codes_insert_and_copy_lengths()
    elif state == PrefixCodesInsertAndCopyLengths:
      meta_block_prefix_trees_insert_and_copy_lengths = PrefixCodesInsertAndCopyLengths_data
      state = parse_prefix_codes_distances()
    elif state == PrefixCodesDistances:
      meta_block_prefix_trees_distances = PrefixCodesDistances_data
      state = DataMetaBlockBegin
    elif state == DataMetaBlockBegin:
      state = parse_insert_and_copy_length()
    elif state == InsertAndCopyLength:
      meta_block_insert_and_copy_length = InsertAndCopyLength_data
      if InsertAndCopyLength_data >= 0 and InsertAndCopyLength_data <= 127:
        meta_block_distance = 0
      else:
        meta_block_distance = NONE
      state = decode_insert_and_copy_length()
    elif state == InsertLengthAndCopyLength:
      m_len = meta_block_header_m_len
      meta_block_insert_length = InsertLengthAndCopyLength_data_in_len
      meta_block_copy_length = InsertLengthAndCopyLength_data_co_len
      if m_len < meta_block_count_output + meta_block_insert_length:  # or (m_len > meta_block_count_output + meta_block_insert_length and m_len < meta_block_count_output + meta_block_insert_length + meta_block_copy_length)
        error() # ExceededExpectedBytes
      state = parse_insert_literals()
    elif state == InsertLiterals:
      m_len = meta_block_header_m_len
      if m_len < meta_block_count_output + len(InsertLiterals_data):
        error() # ExceededExpectedBytes
      i = 0
      while i < len(InsertLiterals_data):
        literal = InsertLiterals_data[i]
        out(literal)
        output_window_pointer = (output_window_pointer + 1) % len(output_window)
        output_window[output_window_pointer] = literal
        count_output += 1
        meta_block_count_output += 1
        i += 1
      if meta_block_header_m_len == meta_block_count_output:
        state = DataMetaBlockEnd
      else:
        state = parse_distance_code()
    elif state == DistanceCode:
      meta_block_distance_code = DistanceCode_data
      state = decode_distance()
    elif state == Distance:
      meta_block_distance = Distance_data
      state = copy_literals()
    elif state == CopyLiterals:
      m_len = meta_block_header_m_len
      if m_len < meta_block_count_output + len(CopyLiterals_data):
        error() # err ExceededExpectedBytes
      i = 0
      while i < len(CopyLiterals_data):
        literal = CopyLiterals_data[i]
        out(literal)
        literal_buf_pointer = (literal_buf_pointer + 1) % 2
        literal_buf[literal_buf_pointer] = literal
        output_window_pointer = (output_window_pointer + 1) % len(output_window)
        output_window[output_window_pointer] = literal
        count_output += 1
        meta_block_count_output += 1
        i += 1
      if meta_block_header_m_len == meta_block_count_output:
        state = DataMetaBlockEnd
      else:
        state = DataMetaBlockBegin
    elif state == DataMetaBlockEnd:
      state = MetaBlockEnd
    elif state == MetaBlockEnd:
      if meta_block_header_is_last:
        state = StreamEnd
      else:
        state = HeaderMetaBlockBegin
    elif state == StreamEnd:
      if read_u8_from_byte_tail() != 0:
        error() # NonZeroTrailerBit
      if read_u8() == NONE: # i.e. BitReaderError
        state = StreamBegin
        tmbuf = output_buf
        output_buf = []
        input_buf = []
        return bytes(tmbuf)


def main():
  import argparse
  parser = argparse.ArgumentParser()
  parser.add_argument('input', nargs='?', type=argparse.FileType('rb'), default=sys.stdin.buffer, help='input file')
  parser.add_argument('--append', type=argparse.FileType('rb'), dest='addseg', default=[], metavar='FILE', action='append', help='additional input files')
  parser.add_argument('--compare', type=argparse.FileType('rb'), dest='compare', default=None, metavar='EXPECTEDFILE', help='compare output and run ipdb for mismatch')
  parser.add_argument('output', nargs='*', type=argparse.FileType('wb'), default=[sys.stdout.buffer], help='output file')
  args = parser.parse_args()
  cmpbuf = args.compare.read() if args.compare else None
  outb = brotlidec(args.input.read(), [], cmpbuf=cmpbuf)
  args.output[0].write(bytes(outb))
  for additional_segment in args.addseg:
    if len(args.output) > 1:
      args.output.pop(0)
    outb = brotlidec(additional_segment.read(), [])
    args.output[0].write(bytes(outb))

if __name__ == '__main__':
    main()

