# SDK Pullenti Unitext, version 4.33, fabruary 2026. Copyright (c) 2013-2026, Pullenti. All rights reserved.
# Non-Commercial Freeware and Commercial Software.
# This class is generated using the converter UniSharping (www.unisharping.ru) from Pullenti C# project.
# The latest version of the code is available on the site www.pullenti.ru

from pullenti.unisharp.Utils import Utils
from pullenti.unisharp.Streams import MemoryStream
from pullenti.unisharp.Streams import Stream

class LzwDecoder:
    
    def __init__(self) -> None:
        self.__m_and_table = [511, 1023, 2047, 4095]
        self.__m_string_table = None;
        self.__m_data = None;
        self.__m_table_index = 0
        self.__m_bits_to_get = 9
        self.__m_byte_pointer = 0
        self.__m_data_buffer = 0
        self.__m_next_bits = 0
    
    def decode(self, data : bytearray) -> bytearray:
        output_stream = MemoryStream()
        self.__initialize_dictionary()
        self.__m_data = data
        self.__m_byte_pointer = 0
        self.__m_data_buffer = 0
        self.__m_next_bits = 0
        code = 0
        old_code = 0
        str0_ = [ ]
        inits = 0
        while True:
            code = self.__get_next_code()
            if (((code)) != 257): pass
            else: 
                break
            if (code == 256): 
                self.__initialize_dictionary()
                inits += 1
                code = self.__get_next_code()
                if (code == 257): 
                    break
                if (code == 256): 
                    pass
                output_stream.write(self.__m_string_table[code], 0, len(self.__m_string_table[code]))
                old_code = code
            elif (code < self.__m_table_index): 
                str0_ = self.__m_string_table[code]
                output_stream.write(str0_, 0, len(str0_))
                self.__add_entry(self.__m_string_table[old_code], str0_[0])
                old_code = code
            else: 
                str0_ = self.__m_string_table[old_code]
                output_stream.write(str0_, 0, len(str0_))
                self.__add_entry(str0_, str0_[0])
                output_stream.writebyte(str0_[0])
                old_code = code
        if (output_stream.length > (0)): 
            return output_stream.toarray()
        return None
    
    def __initialize_dictionary(self) -> None:
        if (self.__m_string_table is None): 
            self.__m_string_table = list()
            for i in range(8192):
                self.__m_string_table.append(None)
            for i in range(256):
                self.__m_string_table[i] = Utils.newArrayOfBytes(1, 0)
                self.__m_string_table[i][0] = (i)
        else: 
            i = 256
            while i < len(self.__m_string_table): 
                self.__m_string_table[i] = (None)
                i += 1
        self.__m_table_index = 258
        self.__m_bits_to_get = 9
    
    def __add_entry(self, oldstring : bytearray, newstring : int) -> None:
        length = len(oldstring)
        str0_ = Utils.newArrayOfBytes(length + 1, 0)
        Utils.copyArray(oldstring, 0, str0_, 0, length)
        str0_[length] = newstring
        self.__m_string_table[self.__m_table_index] = str0_
        self.__m_table_index += 1
        if (self.__m_table_index == 511): 
            self.__m_bits_to_get = 10
        elif (self.__m_table_index == 1023): 
            self.__m_bits_to_get = 11
        elif (self.__m_table_index == 2047): 
            self.__m_bits_to_get = 12
    
    def __get_next_code(self) -> int:
        if (self.__m_byte_pointer >= len(self.__m_data)): 
            return 257
        self.__m_data_buffer = (((self.__m_data_buffer << 8)) | (((self.__m_data[self.__m_byte_pointer]) & 0xff)))
        self.__m_byte_pointer += 1
        self.__m_next_bits += 8
        if (self.__m_next_bits < self.__m_bits_to_get): 
            if (self.__m_byte_pointer >= len(self.__m_data)): 
                return 257
            self.__m_data_buffer = (((self.__m_data_buffer << 8)) | (((self.__m_data[self.__m_byte_pointer]) & 0xff)))
            self.__m_byte_pointer += 1
            self.__m_next_bits += 8
        code = ((self.__m_data_buffer >> ((self.__m_next_bits - self.__m_bits_to_get)))) & self.__m_and_table[self.__m_bits_to_get - 9]
        self.__m_next_bits -= self.__m_bits_to_get
        if (code == 256): 
            pass
        return code