# Copyright 2021 <NAME> All Rights Reserved.
# Distributed under MIT license.
# See file LICENSE for detail or copy at https://opensource.org/licenses/MIT


class BrotliBitReader:
    """Wrap a bytes buffer to enable reading 0 < n <=24 bits at a time, or transfer of arbitrary number of bytes"""

    kBitMask = [
        0x000000, 0x000001, 0x000003, 0x000007, 0x00000f, 0x00001f, 0x00003f, 0x00007f,
        0x0000ff, 0x0001ff, 0x0003ff, 0x0007ff, 0x000fff, 0x001fff, 0x003fff, 0x007fff,
        0x00ffff, 0x01ffff, 0x03ffff, 0x07ffff, 0x0fffff, 0x1fffff, 0x3fffff, 0x7fffff,
        0xffffff
    ]

    def __init__(self, input_buffer):
        self.buf_ = bytearray(input_buffer)
        self.buf_len_ = len(input_buffer)
        self.pos_ = 0          # byte position in stream
        self.bit_pos_ = 0      # current bit-reading position in current byte (number bits already read from byte, 0-7)

    def reset(self):
        """Reset an initialized BrotliBitReader to start of input buffer"""
        self.pos_ = 0
        self.bit_pos_ = 0

    def read_bits(self, n_bits, bits_to_skip=None):
        """Get n_bits unsigned integer treating input as little-endian byte stream, maybe advancing input buffer pointer
        n_bits: is number of bits to read from input buffer. Set to None or 0 to seek ahead ignoring the value
        bits_to_skip: number of bits to advance in input_buffer, defaults to n_bits if it is None
           pass in 0 to peek at the next n_bits of value without advancing
        It is ok to have n_bits and bits_to_skip be different non-zero values if that is what is wanted
        Returns: the next n_bits from the buffer as a little-endian integer, 0 if n_bits is None or 0
        """
        val = 0
        if bits_to_skip is None:
            bits_to_skip = n_bits
        if n_bits:
            bytes_shift = 0
            buf_pos = self.pos_
            bit_pos_when_done = n_bits + self.bit_pos_
            while bytes_shift < bit_pos_when_done:
                if buf_pos >= self.buf_len_:
                    break  # if hit end of buffer, this simulates zero padding after end, which is correct
                val |= self.buf_[buf_pos] << bytes_shift
                bytes_shift += 8
                buf_pos += 1
            val = (val >> self.bit_pos_) & self.kBitMask[n_bits]
        if bits_to_skip:
            next_in_bits = self.bit_pos_ + bits_to_skip
            self.bit_pos_ = next_in_bits & 7
            self.pos_ += next_in_bits >> 3
        return val

    def copy_bytes(self, dest_buffer, dest_pos, n_bytes):
        """Copy bytes from input buffer. This will first skip to next byte boundary if not already on one"""
        if self.bit_pos_ != 0:
            self.bit_pos_ = 0
            self.pos_ += 1
        if n_bytes > 0:  # call with n_bytes == 0 to just skip to next byte boundary
            new_pos = self.pos_ + n_bytes
            memoryview(dest_buffer)[dest_pos:dest_pos+n_bytes] = self.buf_[self.pos_:new_pos]
            self.pos_ = new_pos

# Copyright 2021 <NAME> All Rights Reserved.
# Distributed under MIT license.
# See file LICENSE for detail or copy at https://opensource.org/licenses/MIT


class BrotliBitReader:
    """Wrap a bytes buffer to enable reading 0 < n <=24 bits at a time, or transfer of arbitrary number of bytes"""

    kBitMask = [
        0x000000, 0x000001, 0x000003, 0x000007, 0x00000f, 0x00001f, 0x00003f, 0x00007f,
        0x0000ff, 0x0001ff, 0x0003ff, 0x0007ff, 0x000fff, 0x001fff, 0x003fff, 0x007fff,
        0x00ffff, 0x01ffff, 0x03ffff, 0x07ffff, 0x0fffff, 0x1fffff, 0x3fffff, 0x7fffff,
        0xffffff
    ]

    def __init__(self, input_buffer):
        self.buf_ = bytearray(input_buffer)
        self.buf_len_ = len(input_buffer)
        self.pos_ = 0          # byte position in stream
        self.bit_pos_ = 0      # current bit-reading position in current byte (number bits already read from byte, 0-7)

    def reset(self):
        """Reset an initialized BrotliBitReader to start of input buffer"""
        self.pos_ = 0
        self.bit_pos_ = 0

    def read_bits(self, n_bits, bits_to_skip=None):
        """Get n_bits unsigned integer treating input as little-endian byte stream, maybe advancing input buffer pointer
        n_bits: is number of bits to read from input buffer. Set to None or 0 to seek ahead ignoring the value
        bits_to_skip: number of bits to advance in input_buffer, defaults to n_bits if it is None
           pass in 0 to peek at the next n_bits of value without advancing
        It is ok to have n_bits and bits_to_skip be different non-zero values if that is what is wanted
        Returns: the next n_bits from the buffer as a little-endian integer, 0 if n_bits is None or 0
        """
        val = 0
        if bits_to_skip is None:
            bits_to_skip = n_bits
        if n_bits:
            bytes_shift = 0
            buf_pos = self.pos_
            bit_pos_when_done = n_bits + self.bit_pos_
            while bytes_shift < bit_pos_when_done:
                if buf_pos >= self.buf_len_:
                    break  # if hit end of buffer, this simulates zero padding after end, which is correct
                val |= self.buf_[buf_pos] << bytes_shift
                bytes_shift += 8
                buf_pos += 1
            val = (val >> self.bit_pos_) & self.kBitMask[n_bits]
        if bits_to_skip:
            next_in_bits = self.bit_pos_ + bits_to_skip
            self.bit_pos_ = next_in_bits & 7
            self.pos_ += next_in_bits >> 3
        return val

    def copy_bytes(self, dest_buffer, dest_pos, n_bytes):
        """Copy bytes from input buffer. This will first skip to next byte boundary if not already on one"""
        if self.bit_pos_ != 0:
            self.bit_pos_ = 0
            self.pos_ += 1
        if n_bytes > 0:  # call with n_bytes == 0 to just skip to next byte boundary
            new_pos = self.pos_ + n_bytes
            memoryview(dest_buffer)[dest_pos:dest_pos+n_bytes] = self.buf_[self.pos_:new_pos]
            self.pos_ = new_pos

# Copyright 2021 <NAME> All Rights Reserved. # Distributed under MIT license. # See file LICENSE for detail or copy at https://opensource.org/licenses/MIT Wrap a bytes buffer to enable reading 0 < n <=24 bits at a time, or transfer of arbitrary number of bytes # byte position in stream # current bit-reading position in current byte (number bits already read from byte, 0-7) Reset an initialized BrotliBitReader to start of input buffer Get n_bits unsigned integer treating input as little-endian byte stream, maybe advancing input buffer pointer         n_bits: is number of bits to read from input buffer. Set to None or 0 to seek ahead ignoring the value         bits_to_skip: number of bits to advance in input_buffer, defaults to n_bits if it is None            pass in 0 to peek at the next n_bits of value without advancing         It is ok to have n_bits and bits_to_skip be different non-zero values if that is what is wanted         Returns: the next n_bits from the buffer as a little-endian integer, 0 if n_bits is None or 0 # if hit end of buffer, this simulates zero padding after end, which is correct Copy bytes from input buffer. This will first skip to next byte boundary if not already on one # call with n_bytes == 0 to just skip to next byte boundary