예제 #1
0
        private uint ReadHuffSym(ushort[] table, byte[] lengths, uint nsyms, uint nbits, BitBuffer bitbuf)
        {
            uint i, j;

            bitbuf.EnsureBits(16);
            if ((i = table[bitbuf.PeekBits((byte)nbits)]) >= nsyms)
            {
                j = (uint)(1 << (int)(sizeof(uint) * 8 - nbits));
                do
                {
                    j >>= 1;
                    i <<= 1;
                    i  |= (bitbuf.GetBuffer() & j) != 0 ? (uint)1 : 0;
                    if (j == 0)
                    {
                        return(0);        // TODO throw proper exception
                    }
                } while ((i = table[i]) >= nsyms);
            }

            j = lengths[i];
            bitbuf.RemoveBits((byte)j);

            return(i);
        }
예제 #2
0
        private static uint ReadHuffSym(ushort[] table, byte[] lengths, uint nsyms, uint nbits, BitBuffer bitbuf)
        {
            uint i, j;

            bitbuf.EnsureBits(16);
            if ((i = table[bitbuf.PeekBits((byte)nbits)]) >= nsyms)
            {
                j = (uint)(1 << (int)((sizeof(uint) * 8) - nbits));
                do
                {
                    j >>= 1;
                    i <<= 1;
                    i  |= (bitbuf.bit_buffer & j) != 0 ? (uint)1 : 0;
                    if (j == 0)
                    {
                        return(0);
                    }
                } while ((i = table[i]) >= nsyms);
            }
            j = lengths[i];
            bitbuf.RemoveBits((byte)j);

            return(i);
        }
예제 #3
0
        public int Decompress(Stream inData, int inLen, Stream outData, int outLen)
        {
            BitBuffer bitbuf   = new BitBuffer(inData);
            long      startpos = inData.Position;
            long      endpos   = inData.Position + inLen;

            byte[] window = m_state.window;

            uint window_posn = m_state.window_posn;
            uint window_size = m_state.window_size;
            uint R0 = m_state.R0;
            uint R1 = m_state.R1;
            uint R2 = m_state.R2;
            uint i, j;

            int togo = outLen, this_run, main_element, match_length, match_offset, length_footer, extra, verbatim_bits;
            int rundest, runsrc, copy_length, aligned_bits;

            bitbuf.InitBitStream();

            /* read header if necessary */
            if (m_state.header_read == 0)
            {
                uint intel = bitbuf.ReadBits(1);
                if (intel != 0)
                {
                    // read the filesize
                    i = bitbuf.ReadBits(16); j = bitbuf.ReadBits(16);
                    m_state.intel_filesize = (int)((i << 16) | j);
                }
                m_state.header_read = 1;
            }

            /* main decoding loop */
            while (togo > 0)
            {
                /* last block finished, new block expected */
                if (m_state.block_remaining == 0)
                {
                    // TODO may screw something up here
                    if (m_state.block_type == LzxConstants.BLOCKTYPE.UNCOMPRESSED)
                    {
                        if ((m_state.block_length & 1) == 1)
                        {
                            inData.ReadByte();                                                         /* realign bitstream to word */
                        }
                        bitbuf.InitBitStream();
                    }

                    m_state.block_type = (LzxConstants.BLOCKTYPE)bitbuf.ReadBits(3);;
                    i = bitbuf.ReadBits(16);
                    j = bitbuf.ReadBits(8);
                    m_state.block_remaining = m_state.block_length = (uint)((i << 8) | j);

                    switch (m_state.block_type)
                    {
                    case LzxConstants.BLOCKTYPE.ALIGNED:
                        for (i = 0, j = 0; i < 8; i++)
                        {
                            j = bitbuf.ReadBits(3); m_state.ALIGNED_len[i] = (byte)j;
                        }
                        MakeDecodeTable(LzxConstants.ALIGNED_MAXSYMBOLS, LzxConstants.ALIGNED_TABLEBITS,
                                        m_state.ALIGNED_len, m_state.ALIGNED_table);
                        /* rest of aligned header is same as verbatim */
                        goto case LzxConstants.BLOCKTYPE.VERBATIM;

                    case LzxConstants.BLOCKTYPE.VERBATIM:
                        ReadLengths(m_state.MAINTREE_len, 0, 256, bitbuf);
                        ReadLengths(m_state.MAINTREE_len, 256, m_state.main_elements, bitbuf);
                        MakeDecodeTable(LzxConstants.MAINTREE_MAXSYMBOLS, LzxConstants.MAINTREE_TABLEBITS,
                                        m_state.MAINTREE_len, m_state.MAINTREE_table);
                        if (m_state.MAINTREE_len[0xE8] != 0)
                        {
                            m_state.intel_started = 1;
                        }

                        ReadLengths(m_state.LENGTH_len, 0, LzxConstants.NUM_SECONDARY_LENGTHS, bitbuf);
                        MakeDecodeTable(LzxConstants.LENGTH_MAXSYMBOLS, LzxConstants.LENGTH_TABLEBITS,
                                        m_state.LENGTH_len, m_state.LENGTH_table);
                        break;

                    case LzxConstants.BLOCKTYPE.UNCOMPRESSED:
                        m_state.intel_started = 1;                     /* because we can't assume otherwise */
                        bitbuf.EnsureBits(16);                         /* get up to 16 pad bits into the buffer */
                        if (bitbuf.GetBitsLeft() > 16)
                        {
                            inData.Seek(-2, SeekOrigin.Current);                                                   /* and align the bitstream! */
                        }
                        byte hi, mh, ml, lo;
                        lo = (byte)inData.ReadByte(); ml = (byte)inData.ReadByte(); mh = (byte)inData.ReadByte(); hi = (byte)inData.ReadByte();
                        R0 = (uint)(lo | ml << 8 | mh << 16 | hi << 24);
                        lo = (byte)inData.ReadByte(); ml = (byte)inData.ReadByte(); mh = (byte)inData.ReadByte(); hi = (byte)inData.ReadByte();
                        R1 = (uint)(lo | ml << 8 | mh << 16 | hi << 24);
                        lo = (byte)inData.ReadByte(); ml = (byte)inData.ReadByte(); mh = (byte)inData.ReadByte(); hi = (byte)inData.ReadByte();
                        R2 = (uint)(lo | ml << 8 | mh << 16 | hi << 24);
                        break;

                    default:
                        return(-1);                        // TODO throw proper exception
                    }
                }

                /* buffer exhaustion check */
                if (inData.Position > (startpos + inLen))
                {
                    /* it's possible to have a file where the next run is less than
                     * 16 bits in size. In this case, the READ_HUFFSYM() macro used
                     * in building the tables will exhaust the buffer, so we should
                     * allow for this, but not allow those accidentally read bits to
                     * be used (so we check that there are at least 16 bits
                     * remaining - in this boundary case they aren't really part of
                     * the compressed data)
                     */
                    //Debug.WriteLine("WTF");

                    if (inData.Position > (startpos + inLen + 2) || bitbuf.GetBitsLeft() < 16)
                    {
                        return(-1);                                                                                      //TODO throw proper exception
                    }
                }

                while ((this_run = (int)m_state.block_remaining) > 0 && togo > 0)
                {
                    if (this_run > togo)
                    {
                        this_run = togo;
                    }
                    togo -= this_run;
                    m_state.block_remaining -= (uint)this_run;

                    /* apply 2^x-1 mask */
                    window_posn &= window_size - 1;
                    /* runs can't straddle the window wraparound */
                    if ((window_posn + this_run) > window_size)
                    {
                        return(-1);                        //TODO throw proper exception
                    }
                    switch (m_state.block_type)
                    {
                    case LzxConstants.BLOCKTYPE.VERBATIM:
                        while (this_run > 0)
                        {
                            main_element = (int)ReadHuffSym(m_state.MAINTREE_table, m_state.MAINTREE_len,
                                                            LzxConstants.MAINTREE_MAXSYMBOLS, LzxConstants.MAINTREE_TABLEBITS,
                                                            bitbuf);
                            if (main_element < LzxConstants.NUM_CHARS)
                            {
                                /* literal: 0 to NUM_CHARS-1 */
                                window[window_posn++] = (byte)main_element;
                                this_run--;
                            }
                            else
                            {
                                /* match: NUM_CHARS + ((slot<<3) | length_header (3 bits)) */
                                main_element -= LzxConstants.NUM_CHARS;

                                match_length = main_element & LzxConstants.NUM_PRIMARY_LENGTHS;
                                if (match_length == LzxConstants.NUM_PRIMARY_LENGTHS)
                                {
                                    length_footer = (int)ReadHuffSym(m_state.LENGTH_table, m_state.LENGTH_len,
                                                                     LzxConstants.LENGTH_MAXSYMBOLS, LzxConstants.LENGTH_TABLEBITS,
                                                                     bitbuf);
                                    match_length += length_footer;
                                }
                                match_length += LzxConstants.MIN_MATCH;

                                match_offset = main_element >> 3;

                                if (match_offset > 2)
                                {
                                    /* not repeated offset */
                                    if (match_offset != 3)
                                    {
                                        extra         = extra_bits[match_offset];
                                        verbatim_bits = (int)bitbuf.ReadBits((byte)extra);
                                        match_offset  = (int)position_base[match_offset] - 2 + verbatim_bits;
                                    }
                                    else
                                    {
                                        match_offset = 1;
                                    }

                                    /* update repeated offset LRU queue */
                                    R2 = R1; R1 = R0; R0 = (uint)match_offset;
                                }
                                else if (match_offset == 0)
                                {
                                    match_offset = (int)R0;
                                }
                                else if (match_offset == 1)
                                {
                                    match_offset = (int)R1;
                                    R1           = R0; R0 = (uint)match_offset;
                                }
                                else                                 /* match_offset == 2 */
                                {
                                    match_offset = (int)R2;
                                    R2           = R0; R0 = (uint)match_offset;
                                }

                                rundest   = (int)window_posn;
                                this_run -= match_length;

                                /* copy any wrapped around source data */
                                if (window_posn >= match_offset)
                                {
                                    /* no wrap */
                                    runsrc = rundest - match_offset;
                                }
                                else
                                {
                                    runsrc      = rundest + ((int)window_size - match_offset);
                                    copy_length = match_offset - (int)window_posn;
                                    if (copy_length < match_length)
                                    {
                                        match_length -= copy_length;
                                        window_posn  += (uint)copy_length;
                                        while (copy_length-- > 0)
                                        {
                                            window[rundest++] = window[runsrc++];
                                        }
                                        runsrc = 0;
                                    }
                                }
                                window_posn += (uint)match_length;

                                /* copy match data - no worries about destination wraps */
                                while (match_length-- > 0)
                                {
                                    window[rundest++] = window[runsrc++];
                                }
                            }
                        }
                        break;

                    case LzxConstants.BLOCKTYPE.ALIGNED:
                        while (this_run > 0)
                        {
                            main_element = (int)ReadHuffSym(m_state.MAINTREE_table, m_state.MAINTREE_len,
                                                            LzxConstants.MAINTREE_MAXSYMBOLS, LzxConstants.MAINTREE_TABLEBITS,
                                                            bitbuf);

                            if (main_element < LzxConstants.NUM_CHARS)
                            {
                                /* literal 0 to NUM_CHARS-1 */
                                window[window_posn++] = (byte)main_element;
                                this_run--;
                            }
                            else
                            {
                                /* match: NUM_CHARS + ((slot<<3) | length_header (3 bits)) */
                                main_element -= LzxConstants.NUM_CHARS;

                                match_length = main_element & LzxConstants.NUM_PRIMARY_LENGTHS;
                                if (match_length == LzxConstants.NUM_PRIMARY_LENGTHS)
                                {
                                    length_footer = (int)ReadHuffSym(m_state.LENGTH_table, m_state.LENGTH_len,
                                                                     LzxConstants.LENGTH_MAXSYMBOLS, LzxConstants.LENGTH_TABLEBITS,
                                                                     bitbuf);
                                    match_length += length_footer;
                                }
                                match_length += LzxConstants.MIN_MATCH;

                                match_offset = main_element >> 3;

                                if (match_offset > 2)
                                {
                                    /* not repeated offset */
                                    extra        = extra_bits[match_offset];
                                    match_offset = (int)position_base[match_offset] - 2;
                                    if (extra > 3)
                                    {
                                        /* verbatim and aligned bits */
                                        extra        -= 3;
                                        verbatim_bits = (int)bitbuf.ReadBits((byte)extra);
                                        match_offset += (verbatim_bits << 3);
                                        aligned_bits  = (int)ReadHuffSym(m_state.ALIGNED_table, m_state.ALIGNED_len,
                                                                         LzxConstants.ALIGNED_MAXSYMBOLS, LzxConstants.ALIGNED_TABLEBITS,
                                                                         bitbuf);
                                        match_offset += aligned_bits;
                                    }
                                    else if (extra == 3)
                                    {
                                        /* aligned bits only */
                                        aligned_bits = (int)ReadHuffSym(m_state.ALIGNED_table, m_state.ALIGNED_len,
                                                                        LzxConstants.ALIGNED_MAXSYMBOLS, LzxConstants.ALIGNED_TABLEBITS,
                                                                        bitbuf);
                                        match_offset += aligned_bits;
                                    }
                                    else if (extra > 0)                                     /* extra==1, extra==2 */
                                    {
                                        /* verbatim bits only */
                                        verbatim_bits = (int)bitbuf.ReadBits((byte)extra);
                                        match_offset += verbatim_bits;
                                    }
                                    else                                     /* extra == 0 */
                                    {
                                        /* ??? */
                                        match_offset = 1;
                                    }

                                    /* update repeated offset LRU queue */
                                    R2 = R1; R1 = R0; R0 = (uint)match_offset;
                                }
                                else if (match_offset == 0)
                                {
                                    match_offset = (int)R0;
                                }
                                else if (match_offset == 1)
                                {
                                    match_offset = (int)R1;
                                    R1           = R0; R0 = (uint)match_offset;
                                }
                                else                                 /* match_offset == 2 */
                                {
                                    match_offset = (int)R2;
                                    R2           = R0; R0 = (uint)match_offset;
                                }

                                rundest   = (int)window_posn;
                                this_run -= match_length;

                                /* copy any wrapped around source data */
                                if (window_posn >= match_offset)
                                {
                                    /* no wrap */
                                    runsrc = rundest - match_offset;
                                }
                                else
                                {
                                    runsrc      = rundest + ((int)window_size - match_offset);
                                    copy_length = match_offset - (int)window_posn;
                                    if (copy_length < match_length)
                                    {
                                        match_length -= copy_length;
                                        window_posn  += (uint)copy_length;
                                        while (copy_length-- > 0)
                                        {
                                            window[rundest++] = window[runsrc++];
                                        }
                                        runsrc = 0;
                                    }
                                }
                                window_posn += (uint)match_length;

                                /* copy match data - no worries about destination wraps */
                                while (match_length-- > 0)
                                {
                                    window[rundest++] = window[runsrc++];
                                }
                            }
                        }
                        break;

                    case LzxConstants.BLOCKTYPE.UNCOMPRESSED:
                        if ((inData.Position + this_run) > endpos)
                        {
                            return(-1);                                                              //TODO throw proper exception
                        }
                        byte[] temp_buffer = new byte[this_run];
                        inData.Read(temp_buffer, 0, this_run);
                        temp_buffer.CopyTo(window, (int)window_posn);
                        window_posn += (uint)this_run;
                        break;

                    default:
                        return(-1);                        //TODO throw proper exception
                    }
                }
            }

            if (togo != 0)
            {
                return(-1);                      //TODO throw proper exception
            }
            int start_window_pos = (int)window_posn;

            if (start_window_pos == 0)
            {
                start_window_pos = (int)window_size;
            }
            start_window_pos -= outLen;
            outData.Write(window, start_window_pos, outLen);

            m_state.window_posn = window_posn;
            m_state.R0          = R0;
            m_state.R1          = R1;
            m_state.R2          = R2;

            // TODO finish intel E8 decoding
            /* intel E8 decoding */
            if ((m_state.frames_read++ < 32768) && m_state.intel_filesize != 0)
            {
                if (outLen <= 6 || m_state.intel_started == 0)
                {
                    m_state.intel_curpos += outLen;
                }
                else
                {
                    int  dataend  = outLen - 10;
                    uint curpos   = (uint)m_state.intel_curpos;
                    uint filesize = (uint)m_state.intel_filesize;
                    //uint abs_off, rel_off;

                    m_state.intel_curpos = (int)curpos + outLen;

                    while (outData.Position < dataend)
                    {
                        if (outData.ReadByte() != 0xE8)
                        {
                            curpos++; continue;
                        }
                        //abs_off =
                    }
                }
                return(-1);
            }
            return(0);
        }
예제 #4
0
		private uint ReadHuffSym(ushort[] table, byte[] lengths, uint nsyms, uint nbits, BitBuffer bitbuf)
		{
			uint i, j;
			bitbuf.EnsureBits(16);
			if((i = table[bitbuf.PeekBits((byte)nbits)]) >= nsyms)
			{
				j = (uint)(1 << (int)((sizeof(uint)*8) - nbits));
				do
				{
					j >>= 1; i <<= 1; i |= (bitbuf.GetBuffer() & j) != 0 ? (uint)1 : 0;
					if(j == 0) return 0; // TODO throw proper exception
				} while((i = table[i]) >= nsyms);
			}
			j = lengths[i];
			bitbuf.RemoveBits((byte)j);
			
			return i;
		}
예제 #5
0
		public int Decompress(Stream inData, int inLen, Stream outData, int outLen)
		{
			BitBuffer bitbuf = new BitBuffer(inData);
			long startpos = inData.Position;
			long endpos = inData.Position + inLen;
			
			byte[] window = m_state.window;
			
			uint window_posn = m_state.window_posn;
			uint window_size = m_state.window_size;
			uint R0 = m_state.R0;
			uint R1 = m_state.R1;
			uint R2 = m_state.R2;
			uint i, j;
			
			int togo = outLen, this_run, main_element, match_length, match_offset, length_footer, extra, verbatim_bits;
			int rundest, runsrc, copy_length, aligned_bits;
			
			bitbuf.InitBitStream();
			
			/* read header if necessary */
			if(m_state.header_read == 0)
			{
				uint intel = bitbuf.ReadBits(1);
				if(intel != 0)
				{
					// read the filesize
					i = bitbuf.ReadBits(16); j = bitbuf.ReadBits(16);
					m_state.intel_filesize = (int)((i << 16) | j);
				}
				m_state.header_read = 1;
			}
			
			/* main decoding loop */
			while(togo > 0)
			{
				/* last block finished, new block expected */
				if(m_state.block_remaining == 0)
				{
					// TODO may screw something up here
					if(m_state.block_type == LzxConstants.BLOCKTYPE.UNCOMPRESSED) {
						if((m_state.block_length & 1) == 1) inData.ReadByte(); /* realign bitstream to word */
						bitbuf.InitBitStream();
					}
					
					m_state.block_type = (LzxConstants.BLOCKTYPE)bitbuf.ReadBits(3);;
					i = bitbuf.ReadBits(16);
					j = bitbuf.ReadBits(8);
					m_state.block_remaining = m_state.block_length = (uint)((i << 8) | j);
					
					switch(m_state.block_type)
					{
					case LzxConstants.BLOCKTYPE.ALIGNED:
						for(i = 0, j = 0; i < 8; i++) { j = bitbuf.ReadBits(3); m_state.ALIGNED_len[i] = (byte)j; }
						MakeDecodeTable(LzxConstants.ALIGNED_MAXSYMBOLS, LzxConstants.ALIGNED_TABLEBITS,
						                m_state.ALIGNED_len, m_state.ALIGNED_table);
						/* rest of aligned header is same as verbatim */
						goto case LzxConstants.BLOCKTYPE.VERBATIM;
						
					case LzxConstants.BLOCKTYPE.VERBATIM:
						ReadLengths(m_state.MAINTREE_len, 0, 256, bitbuf);
						ReadLengths(m_state.MAINTREE_len, 256, m_state.main_elements, bitbuf);
						MakeDecodeTable(LzxConstants.MAINTREE_MAXSYMBOLS, LzxConstants.MAINTREE_TABLEBITS,
						                m_state.MAINTREE_len, m_state.MAINTREE_table);
						if(m_state.MAINTREE_len[0xE8] != 0) m_state.intel_started = 1;
						
						ReadLengths(m_state.LENGTH_len, 0, LzxConstants.NUM_SECONDARY_LENGTHS, bitbuf);
						MakeDecodeTable(LzxConstants.LENGTH_MAXSYMBOLS, LzxConstants.LENGTH_TABLEBITS,
						                m_state.LENGTH_len, m_state.LENGTH_table);
						break;
						
					case LzxConstants.BLOCKTYPE.UNCOMPRESSED:
						m_state.intel_started = 1; /* because we can't assume otherwise */
						bitbuf.EnsureBits(16); /* get up to 16 pad bits into the buffer */
						if(bitbuf.GetBitsLeft() > 16) inData.Seek(-2, SeekOrigin.Current); /* and align the bitstream! */
						byte hi, mh, ml, lo;
						lo = (byte)inData.ReadByte(); ml = (byte)inData.ReadByte(); mh = (byte)inData.ReadByte(); hi = (byte)inData.ReadByte();
						R0 = (uint)(lo | ml << 8 | mh << 16 | hi << 24);
						lo = (byte)inData.ReadByte(); ml = (byte)inData.ReadByte(); mh = (byte)inData.ReadByte(); hi = (byte)inData.ReadByte();
						R1 = (uint)(lo | ml << 8 | mh << 16 | hi << 24);
						lo = (byte)inData.ReadByte(); ml = (byte)inData.ReadByte(); mh = (byte)inData.ReadByte(); hi = (byte)inData.ReadByte();
						R2 = (uint)(lo | ml << 8 | mh << 16 | hi << 24);
						break;
						
					default:
						return -1; // TODO throw proper exception
					}
				}
				
				/* buffer exhaustion check */
				if(inData.Position > (startpos + inLen))
				{
					/* it's possible to have a file where the next run is less than
				     * 16 bits in size. In this case, the READ_HUFFSYM() macro used
				     * in building the tables will exhaust the buffer, so we should
				     * allow for this, but not allow those accidentally read bits to
				     * be used (so we check that there are at least 16 bits
				     * remaining - in this boundary case they aren't really part of
				     * the compressed data)
					 */
					Console.WriteLine("WTF");
					if(inData.Position > (startpos+inLen+2) || bitbuf.GetBitsLeft() < 16) return -1; //TODO throw proper exception
				}
				
				while((this_run = (int)m_state.block_remaining) > 0 && togo > 0)
				{
					if(this_run > togo) this_run = togo;
					togo -= this_run;
					m_state.block_remaining -= (uint)this_run;
					
					/* apply 2^x-1 mask */
					window_posn &= window_size - 1;
					/* runs can't straddle the window wraparound */
					if((window_posn + this_run) > window_size)
						return -1; //TODO throw proper exception
					
					switch(m_state.block_type)
					{
					case LzxConstants.BLOCKTYPE.VERBATIM:
						while(this_run > 0)
						{
							main_element = (int)ReadHuffSym(m_state.MAINTREE_table, m_state.MAINTREE_len,
							                           LzxConstants.MAINTREE_MAXSYMBOLS, LzxConstants.MAINTREE_TABLEBITS,
							                           bitbuf);
							if(main_element < LzxConstants.NUM_CHARS)
							{
								/* literal: 0 to NUM_CHARS-1 */
								window[window_posn++] = (byte)main_element;
								this_run--;
							}
							else
							{
								/* match: NUM_CHARS + ((slot<<3) | length_header (3 bits)) */
								main_element -= LzxConstants.NUM_CHARS;
								
								match_length = main_element & LzxConstants.NUM_PRIMARY_LENGTHS;
								if(match_length == LzxConstants.NUM_PRIMARY_LENGTHS)
								{
									length_footer = (int)ReadHuffSym(m_state.LENGTH_table, m_state.LENGTH_len,
									                            LzxConstants.LENGTH_MAXSYMBOLS, LzxConstants.LENGTH_TABLEBITS,
									                            bitbuf);
									match_length += length_footer;
								}
								match_length += LzxConstants.MIN_MATCH;
								
								match_offset = main_element >> 3;
								
								if(match_offset > 2)
								{
									/* not repeated offset */
									if(match_offset != 3)
									{
										extra = extra_bits[match_offset];
										verbatim_bits = (int)bitbuf.ReadBits((byte)extra);
										match_offset = (int)position_base[match_offset] - 2 + verbatim_bits;
									}
									else
									{
										match_offset = 1;
									}
									
									/* update repeated offset LRU queue */
									R2 = R1; R1 = R0; R0 = (uint)match_offset;
								}
								else if(match_offset == 0)
								{
									match_offset = (int)R0;
								}
								else if(match_offset == 1)
								{
									match_offset = (int)R1;
									R1 = R0; R0 = (uint)match_offset;
								}
								else /* match_offset == 2 */
								{
									match_offset = (int)R2;
									R2 = R0; R0 = (uint)match_offset;
								}
								
								rundest = (int)window_posn;
								this_run -= match_length;
								
								/* copy any wrapped around source data */
								if(window_posn >= match_offset)
								{
									/* no wrap */
									runsrc = rundest - match_offset;
								}
								else
								{
									runsrc = rundest + ((int)window_size - match_offset);
									copy_length = match_offset - (int)window_posn;
									if(copy_length < match_length)
									{
										match_length -= copy_length;
										window_posn += (uint)copy_length;
										while(copy_length-- > 0) window[rundest++] = window[runsrc++];
										runsrc = 0;
									}
								}
								window_posn += (uint)match_length;
								
								/* copy match data - no worries about destination wraps */
								while(match_length-- > 0) window[rundest++] = window[runsrc++];
							}
						}
						break;
					
					case LzxConstants.BLOCKTYPE.ALIGNED:
						while(this_run > 0)
						{
							main_element = (int)ReadHuffSym(m_state.MAINTREE_table, m_state.MAINTREE_len,
							                           				  LzxConstants.MAINTREE_MAXSYMBOLS, LzxConstants.MAINTREE_TABLEBITS,
							                           				  bitbuf);
							
							if(main_element < LzxConstants.NUM_CHARS)
							{
								/* literal 0 to NUM_CHARS-1 */
								window[window_posn++] = (byte)main_element;
								this_run--;
							}
							else
							{
								/* match: NUM_CHARS + ((slot<<3) | length_header (3 bits)) */
								main_element -= LzxConstants.NUM_CHARS;
								
								match_length = main_element & LzxConstants.NUM_PRIMARY_LENGTHS;
								if(match_length == LzxConstants.NUM_PRIMARY_LENGTHS)
								{
									length_footer = (int)ReadHuffSym(m_state.LENGTH_table, m_state.LENGTH_len,
									                            	 LzxConstants.LENGTH_MAXSYMBOLS, LzxConstants.LENGTH_TABLEBITS,
									                            	 bitbuf);
									match_length += length_footer;
								}
								match_length += LzxConstants.MIN_MATCH;
								
								match_offset = main_element >> 3;
								
								if(match_offset > 2)
								{
									/* not repeated offset */
									extra = extra_bits[match_offset];
									match_offset = (int)position_base[match_offset] - 2;
									if(extra > 3)
									{
										/* verbatim and aligned bits */
										extra -= 3;
										verbatim_bits = (int)bitbuf.ReadBits((byte)extra);
										match_offset += (verbatim_bits << 3);
										aligned_bits = (int)ReadHuffSym(m_state.ALIGNED_table, m_state.ALIGNED_len,
										                           LzxConstants.ALIGNED_MAXSYMBOLS, LzxConstants.ALIGNED_TABLEBITS,
										                           bitbuf);
										match_offset += aligned_bits;
									}
									else if(extra == 3)
									{
										/* aligned bits only */
										aligned_bits = (int)ReadHuffSym(m_state.ALIGNED_table, m_state.ALIGNED_len,
										                           LzxConstants.ALIGNED_MAXSYMBOLS, LzxConstants.ALIGNED_TABLEBITS,
										                           bitbuf);
										match_offset += aligned_bits;
									}
									else if (extra > 0) /* extra==1, extra==2 */
									{
										/* verbatim bits only */
										verbatim_bits = (int)bitbuf.ReadBits((byte)extra);
										match_offset += verbatim_bits;
									}
									else /* extra == 0 */
									{
										/* ??? */
										match_offset = 1;
									}
									
									/* update repeated offset LRU queue */
									R2 = R1; R1 = R0; R0 = (uint)match_offset;
								}
								else if( match_offset == 0)
								{
									match_offset = (int)R0;
								}
								else if(match_offset == 1)
								{
									match_offset = (int)R1;
									R1 = R0; R0 = (uint)match_offset;
								}
								else /* match_offset == 2 */
								{
									match_offset = (int)R2;
									R2 = R0; R0 = (uint)match_offset;
								}
								
								rundest = (int)window_posn;
								this_run -= match_length;
								
								/* copy any wrapped around source data */
								if(window_posn >= match_offset)
								{
									/* no wrap */
									runsrc = rundest - match_offset;
								}
								else
								{
									runsrc = rundest + ((int)window_size - match_offset);
									copy_length = match_offset - (int)window_posn;
									if(copy_length < match_length)
									{
										match_length -= copy_length;
										window_posn += (uint)copy_length;
										while(copy_length-- > 0) window[rundest++] = window[runsrc++];
										runsrc = 0;
									}
								}
								window_posn += (uint)match_length;
								
								/* copy match data - no worries about destination wraps */
								while(match_length-- > 0) window[rundest++] = window[runsrc++];
							}
						}
						break;
						
					case LzxConstants.BLOCKTYPE.UNCOMPRESSED:
						if((inData.Position + this_run) > endpos) return -1; //TODO throw proper exception
						byte[] temp_buffer = new byte[this_run];
						inData.Read(temp_buffer, 0, this_run);
						temp_buffer.CopyTo(window, window_posn);
						window_posn += (uint)this_run;
						break;
						
					default:
						return -1; //TODO throw proper exception
					}
				}
			}
			
			if(togo != 0) return -1; //TODO throw proper exception
			int start_window_pos = (int)window_posn;
			if(start_window_pos == 0) start_window_pos = (int)window_size;
			start_window_pos -= outLen;
			outData.Write(window, start_window_pos, outLen);
			
			m_state.window_posn = window_posn;
			m_state.R0 = R0;
			m_state.R1 = R1;
			m_state.R2 = R2;
			
			// TODO finish intel E8 decoding
			/* intel E8 decoding */
			if((m_state.frames_read++ < 32768) && m_state.intel_filesize != 0)
			{
				if(outLen <= 6 || m_state.intel_started == 0)
				{
					m_state.intel_curpos += outLen;
				}
				else
				{
					int dataend = outLen - 10;
					uint curpos = (uint)m_state.intel_curpos;
					uint filesize = (uint)m_state.intel_filesize;
					uint abs_off, rel_off;
					
					m_state.intel_curpos = (int)curpos + outLen;
					
					while(outData.Position < dataend)
					{
						if(outData.ReadByte() != 0xE8) { curpos++; continue; }
						//abs_off = 
					}
				}
				return -1;
			}
			return 0;
		}
예제 #6
0
파일: LzxDecoder.cs 프로젝트: nemerle/reko
        public int Decompress(Stream inData, int inLen, Stream outData, int outLen)
        {
            BitBuffer bitbuf   = new BitBuffer(inData);
            long      startpos = inData.Position;
            long      endpos   = inData.Position + inLen;

            byte[] window = m_state.window;

            uint window_posn = m_state.window_posn;
            uint window_size = m_state.window_size;
            uint R0 = m_state.R0;
            uint R1 = m_state.R1;
            uint R2 = m_state.R2;
            uint i, j;

            int togo = outLen, this_run, main_element, match_length, match_offset, length_footer, extra, verbatim_bits;
            int rundest, runsrc, copy_length, aligned_bits;

            bitbuf.InitBitStream();

            /* read header if necessary */
            if (m_state.header_read == 0)
            {
                uint intel = bitbuf.ReadBits(1);
                if (intel != 0)
                {
                    // read the filesize
                    i = bitbuf.ReadBits(16); j = bitbuf.ReadBits(16);
                    m_state.intel_filesize = (int)((i << 16) | j);
                }
                m_state.header_read = 1;
            }

            /* main decoding loop */
            while (togo > 0)
            {
                /* last block finished, new block expected */
                if (m_state.block_remaining == 0)
                {
                    // TODO may screw something up here
                    if (m_state.block_type == LzxConstants.BLOCKTYPE.UNCOMPRESSED)
                    {
                        if ((m_state.block_length & 1) == 1)
                        {
                            inData.ReadByte();                                  /* realign bitstream to word */
                        }
                        bitbuf.InitBitStream();
                    }

                    m_state.block_type = (LzxConstants.BLOCKTYPE)bitbuf.ReadBits(3);;
                    i = bitbuf.ReadBits(16);
                    j = bitbuf.ReadBits(8);
                    m_state.block_remaining = m_state.block_length = (uint)((i << 8) | j);

                    switch (m_state.block_type)
                    {
                    case LzxConstants.BLOCKTYPE.ALIGNED:
                        for (i = 0, j = 0; i < 8; i++)
                        {
                            j = bitbuf.ReadBits(3); m_state.ALIGNED_len[i] = (byte)j;
                        }
                        MakeDecodeTable(LzxConstants.ALIGNED_MAXSYMBOLS, LzxConstants.ALIGNED_TABLEBITS,
                                        m_state.ALIGNED_len, m_state.ALIGNED_table);
                        /* rest of aligned header is same as verbatim */
                        goto case LzxConstants.BLOCKTYPE.VERBATIM;

                    case LzxConstants.BLOCKTYPE.VERBATIM:
                        ReadLengths(m_state.MAINTREE_len, 0, 256, bitbuf);
                        ReadLengths(m_state.MAINTREE_len, 256, m_state.main_elements, bitbuf);
                        MakeDecodeTable(LzxConstants.MAINTREE_MAXSYMBOLS, LzxConstants.MAINTREE_TABLEBITS,
                                        m_state.MAINTREE_len, m_state.MAINTREE_table);
                        if (m_state.MAINTREE_len[0xE8] != 0)
                        {
                            m_state.intel_started = 1;
                        }

                        ReadLengths(m_state.LENGTH_len, 0, LzxConstants.NUM_SECONDARY_LENGTHS, bitbuf);
                        MakeDecodeTable(LzxConstants.LENGTH_MAXSYMBOLS, LzxConstants.LENGTH_TABLEBITS,
                                        m_state.LENGTH_len, m_state.LENGTH_table);
                        break;

                    case LzxConstants.BLOCKTYPE.UNCOMPRESSED:
                        m_state.intel_started = 1; /* because we can't assume otherwise */
                        bitbuf.EnsureBits(16);     /* get up to 16 pad bits into the buffer */
                        if (bitbuf.GetBitsLeft() > 16)
                        {
                            inData.Seek(-2, SeekOrigin.Current);                                /* and align the bitstream! */
                        }
                        byte hi, mh, ml, lo;
                        lo = (byte)inData.ReadByte(); ml = (byte)inData.ReadByte(); mh = (byte)inData.ReadByte(); hi = (byte)inData.ReadByte();
                        R0 = (uint)(lo | ml << 8 | mh << 16 | hi << 24);
                        lo = (byte)inData.ReadByte(); ml = (byte)inData.ReadByte(); mh = (byte)inData.ReadByte(); hi = (byte)inData.ReadByte();
                        R1 = (uint)(lo | ml << 8 | mh << 16 | hi << 24);
                        lo = (byte)inData.ReadByte(); ml = (byte)inData.ReadByte(); mh = (byte)inData.ReadByte(); hi = (byte)inData.ReadByte();
                        R2 = (uint)(lo | ml << 8 | mh << 16 | hi << 24);
                        break;

                    default:
                        return(-1);    // TODO throw proper exception
                    }
                }

                /* buffer exhaustion check */
                if (inData.Position > (startpos + inLen))
                {
                    /* it's possible to have a file where the next run is less than
                     * 16 bits in size. In this case, the READ_HUFFSYM() macro used
                     * in building the tables will exhaust the buffer, so we should
                     * allow for this, but not allow those accidentally read bits to
                     * be used (so we check that there are at least 16 bits
                     * remaining - in this boundary case they aren't really part of
                     * the compressed data)
                     */
                    //Debug.WriteLine("WTF");

                    if (inData.Position > (startpos + inLen + 2) || bitbuf.GetBitsLeft() < 16)
                    {
                        return(-1);                                                                       //TODO throw proper exception
                    }
                }

                while ((this_run = (int)m_state.block_remaining) > 0 && togo > 0)
                {
                    if (this_run > togo)
                    {
                        this_run = togo;
                    }
                    togo -= this_run;
                    m_state.block_remaining -= (uint)this_run;

                    /* apply 2^x-1 mask */
                    window_posn &= window_size - 1;
                    /* runs can't straddle the window wraparound */
                    if ((window_posn + this_run) > window_size)
                    {
                        return(-1); //TODO throw proper exception
                    }
                    switch (m_state.block_type)
                    {
                    case LzxConstants.BLOCKTYPE.VERBATIM:
                        while (this_run > 0)
                        {
                            main_element = (int)ReadHuffSym(m_state.MAINTREE_table, m_state.MAINTREE_len,
                                                            LzxConstants.MAINTREE_MAXSYMBOLS, LzxConstants.MAINTREE_TABLEBITS,
                                                            bitbuf);
                            if (main_element < LzxConstants.NUM_CHARS)
                            {
                                /* literal: 0 to NUM_CHARS-1 */
                                window[window_posn++] = (byte)main_element;
                                this_run--;
                            }
                            else
                            {
                                /* match: NUM_CHARS + ((slot<<3) | length_header (3 bits)) */
                                main_element -= LzxConstants.NUM_CHARS;

                                match_length = main_element & LzxConstants.NUM_PRIMARY_LENGTHS;
                                if (match_length == LzxConstants.NUM_PRIMARY_LENGTHS)
                                {
                                    length_footer = (int)ReadHuffSym(m_state.LENGTH_table, m_state.LENGTH_len,
                                                                     LzxConstants.LENGTH_MAXSYMBOLS, LzxConstants.LENGTH_TABLEBITS,
                                                                     bitbuf);
                                    match_length += length_footer;
                                }
                                match_length += LzxConstants.MIN_MATCH;

                                match_offset = main_element >> 3;

                                if (match_offset > 2)
                                {
                                    /* not repeated offset */
                                    if (match_offset != 3)
                                    {
                                        extra         = extra_bits ![match_offset];
예제 #7
0
        public void Decompress(byte[] outBuf, int outLen, byte[] inBuf, int inLen)
        {
            BitBuffer bitbuf = new BitBuffer(inBuf, inLen);

            byte[] window = m_state.window;

            uint window_posn = m_state.window_posn;
            uint window_size = m_state.window_size;
            uint R0 = m_state.R0;
            uint R1 = m_state.R1;
            uint R2 = m_state.R2;
            uint i, j;

            int togo = outLen, this_run, main_element, match_length, match_offset, length_footer, extra, verbatim_bits;
            int rundest, runsrc, copy_length, aligned_bits;

            /* read header if necessary */
            if (!m_state.header_read)
            {
                uint intel = bitbuf.ReadBits(1);
                if (intel != 0)
                {
                    i = bitbuf.ReadBits(16);
                    j = bitbuf.ReadBits(8);
                    throw new InvalidOperationException("DECR_INTELTRANSFORM");
                }
                m_state.header_read = true;
            }

            /* main decoding loop */
            while (togo > 0)
            {
                /* last block finished, new block expected */
                if (m_state.block_remaining == 0)
                {
                    m_state.block_type = (LzxConstants.BLOCKTYPE)bitbuf.ReadBits(3);
                    i = bitbuf.ReadBits(16);
                    j = bitbuf.ReadBits(8);
                    m_state.block_remaining = m_state.block_length = (uint)((i << 8) | j);

                    switch (m_state.block_type)
                    {
                    case LzxConstants.BLOCKTYPE.ALIGNED:
                        for (i = 0, j = 0; i < 8; i++)
                        {
                            j = bitbuf.ReadBits(3);
                            m_state.ALIGNED_len[i] = (byte)j;
                        }
                        MakeDecodeTable(LzxConstants.ALIGNED_MAXSYMBOLS, LzxConstants.ALIGNED_TABLEBITS,
                                        m_state.ALIGNED_len, m_state.ALIGNED_table);
                        /* rest of aligned header is same as verbatim */
                        goto case LzxConstants.BLOCKTYPE.VERBATIM;

                    case LzxConstants.BLOCKTYPE.VERBATIM:
                        ReadLengths(m_state.MAINTREE_len, 0, 256, bitbuf);
                        ReadLengths(m_state.MAINTREE_len, 256, m_state.main_elements, bitbuf);
                        MakeDecodeTable(LzxConstants.MAINTREE_MAXSYMBOLS, LzxConstants.MAINTREE_TABLEBITS,
                                        m_state.MAINTREE_len, m_state.MAINTREE_table);

                        ReadLengths(m_state.LENGTH_len, 0, LzxConstants.NUM_SECONDARY_LENGTHS, bitbuf);
                        MakeDecodeTable(LzxConstants.LENGTH_MAXSYMBOLS, LzxConstants.LENGTH_TABLEBITS,
                                        m_state.LENGTH_len, m_state.LENGTH_table);
                        break;

                    case LzxConstants.BLOCKTYPE.UNCOMPRESSED:
                        bitbuf.EnsureBits(16);     /* get up to 16 pad bits into the buffer */
                        if (bitbuf.bits_left > 16)
                        {
                            bitbuf.inpos -= 2;     /* and align the bitstream! */
                        }
                        R0 = bitbuf.ReadDWord();
                        R1 = bitbuf.ReadDWord();
                        R2 = bitbuf.ReadDWord();
                        break;

                    default:
                        throw new InvalidOperationException("DECR_ILLEGALDATA");
                    }
                }

                /* buffer exhaustion check */
                if (bitbuf.inpos > inLen)
                {
                    /* it's possible to have a file where the next run is less than
                     * 16 bits in size. In this case, the READ_HUFFSYM() macro used
                     * in building the tables will exhaust the buffer, so we should
                     * allow for this, but not allow those accidentally read bits to
                     * be used (so we check that there are at least 16 bits
                     * remaining - in this boundary case they aren't really part of
                     * the compressed data)
                     */
                    if (bitbuf.inpos > (inLen + 2) || bitbuf.bits_left < 16)
                    {
                        throw new InvalidOperationException("DECR_ILLEGALDATA");
                    }
                }

                while ((this_run = (int)m_state.block_remaining) > 0 && togo > 0)
                {
                    if (this_run > togo)
                    {
                        this_run = togo;
                    }
                    togo -= this_run;
                    m_state.block_remaining -= (uint)this_run;

                    /* apply 2^x-1 mask */
                    window_posn &= window_size - 1;
                    /* runs can't straddle the window wraparound */
                    if ((window_posn + this_run) > window_size)
                    {
                        throw new InvalidOperationException("DECR_DATAFORMAT");
                    }

                    switch (m_state.block_type)
                    {
                    case LzxConstants.BLOCKTYPE.VERBATIM:
                        while (this_run > 0)
                        {
                            main_element = (int)ReadHuffSym(m_state.MAINTREE_table, m_state.MAINTREE_len,
                                                            LzxConstants.MAINTREE_MAXSYMBOLS, LzxConstants.MAINTREE_TABLEBITS, bitbuf);
                            if (main_element < LzxConstants.NUM_CHARS)
                            {
                                /* literal: 0 to NUM_CHARS-1 */
                                window[window_posn++] = (byte)main_element;
                                this_run--;
                            }
                            else
                            {
                                /* match: NUM_CHARS + ((slot<<3) | length_header (3 bits)) */
                                main_element -= LzxConstants.NUM_CHARS;

                                match_length = main_element & LzxConstants.NUM_PRIMARY_LENGTHS;
                                if (match_length == LzxConstants.NUM_PRIMARY_LENGTHS)
                                {
                                    length_footer = (int)ReadHuffSym(m_state.LENGTH_table, m_state.LENGTH_len,
                                                                     LzxConstants.LENGTH_MAXSYMBOLS, LzxConstants.LENGTH_TABLEBITS, bitbuf);
                                    match_length += length_footer;
                                }
                                match_length += LzxConstants.MIN_MATCH;

                                match_offset = main_element >> 3;

                                if (match_offset > 2)
                                {
                                    /* not repeated offset */
                                    if (match_offset != 3)
                                    {
                                        extra         = extra_bits[match_offset];
                                        verbatim_bits = (int)bitbuf.ReadBits((byte)extra);
                                        match_offset  = (int)position_base[match_offset] - 2 + verbatim_bits;
                                    }
                                    else
                                    {
                                        match_offset = 1;
                                    }

                                    /* update repeated offset LRU queue */
                                    R2 = R1;
                                    R1 = R0;
                                    R0 = (uint)match_offset;
                                }
                                else if (match_offset == 0)
                                {
                                    match_offset = (int)R0;
                                }
                                else if (match_offset == 1)
                                {
                                    match_offset = (int)R1;
                                    R1           = R0;
                                    R0           = (uint)match_offset;
                                }
                                else     /* match_offset == 2 */
                                {
                                    match_offset = (int)R2;
                                    R2           = R0;
                                    R0           = (uint)match_offset;
                                }

                                rundest   = (int)window_posn;
                                this_run -= match_length;

                                /* copy any wrapped around source data */
                                if (window_posn >= match_offset)
                                {
                                    /* no wrap */
                                    runsrc = rundest - match_offset;
                                }
                                else
                                {
                                    runsrc      = rundest + ((int)window_size - match_offset);
                                    copy_length = match_offset - (int)window_posn;
                                    if (copy_length < match_length)
                                    {
                                        match_length -= copy_length;
                                        window_posn  += (uint)copy_length;
                                        while (copy_length-- > 0)
                                        {
                                            window[rundest++] = window[runsrc++];
                                        }
                                        runsrc = 0;
                                    }
                                }
                                window_posn += (uint)match_length;

                                /* copy match data - no worries about destination wraps */
                                while (match_length-- > 0)
                                {
                                    window[rundest++] = window[runsrc++];
                                }
                            }
                        }
                        break;

                    case LzxConstants.BLOCKTYPE.ALIGNED:
                        while (this_run > 0)
                        {
                            main_element = (int)ReadHuffSym(m_state.MAINTREE_table, m_state.MAINTREE_len,
                                                            LzxConstants.MAINTREE_MAXSYMBOLS, LzxConstants.MAINTREE_TABLEBITS, bitbuf);

                            if (main_element < LzxConstants.NUM_CHARS)
                            {
                                /* literal 0 to NUM_CHARS-1 */
                                window[window_posn++] = (byte)main_element;
                                this_run--;
                            }
                            else
                            {
                                /* match: NUM_CHARS + ((slot<<3) | length_header (3 bits)) */
                                main_element -= LzxConstants.NUM_CHARS;

                                match_length = main_element & LzxConstants.NUM_PRIMARY_LENGTHS;
                                if (match_length == LzxConstants.NUM_PRIMARY_LENGTHS)
                                {
                                    length_footer = (int)ReadHuffSym(m_state.LENGTH_table, m_state.LENGTH_len,
                                                                     LzxConstants.LENGTH_MAXSYMBOLS, LzxConstants.LENGTH_TABLEBITS, bitbuf);
                                    match_length += length_footer;
                                }
                                match_length += LzxConstants.MIN_MATCH;

                                match_offset = main_element >> 3;

                                if (match_offset > 2)
                                {
                                    /* not repeated offset */
                                    extra        = extra_bits[match_offset];
                                    match_offset = (int)position_base[match_offset] - 2;
                                    if (extra > 3)
                                    {
                                        /* verbatim and aligned bits */
                                        extra        -= 3;
                                        verbatim_bits = (int)bitbuf.ReadBits((byte)extra);
                                        match_offset += (verbatim_bits << 3);
                                        aligned_bits  = (int)ReadHuffSym(m_state.ALIGNED_table, m_state.ALIGNED_len,
                                                                         LzxConstants.ALIGNED_MAXSYMBOLS, LzxConstants.ALIGNED_TABLEBITS,
                                                                         bitbuf);
                                        match_offset += aligned_bits;
                                    }
                                    else if (extra == 3)
                                    {
                                        /* aligned bits only */
                                        aligned_bits = (int)ReadHuffSym(m_state.ALIGNED_table, m_state.ALIGNED_len,
                                                                        LzxConstants.ALIGNED_MAXSYMBOLS, LzxConstants.ALIGNED_TABLEBITS,
                                                                        bitbuf);
                                        match_offset += aligned_bits;
                                    }
                                    else if (extra > 0)     /* extra==1, extra==2 */
                                    {
                                        /* verbatim bits only */
                                        verbatim_bits = (int)bitbuf.ReadBits((byte)extra);
                                        match_offset += verbatim_bits;
                                    }
                                    else     /* extra == 0 */
                                    {
                                        /* ??? */
                                        match_offset = 1;
                                    }

                                    /* update repeated offset LRU queue */
                                    R2 = R1;
                                    R1 = R0;
                                    R0 = (uint)match_offset;
                                }
                                else if (match_offset == 0)
                                {
                                    match_offset = (int)R0;
                                }
                                else if (match_offset == 1)
                                {
                                    match_offset = (int)R1;
                                    R1           = R0;
                                    R0           = (uint)match_offset;
                                }
                                else     /* match_offset == 2 */
                                {
                                    match_offset = (int)R2;
                                    R2           = R0;
                                    R0           = (uint)match_offset;
                                }

                                rundest   = (int)window_posn;
                                this_run -= match_length;

                                /* copy any wrapped around source data */
                                if (window_posn >= match_offset)
                                {
                                    /* no wrap */
                                    runsrc = rundest - match_offset;
                                }
                                else
                                {
                                    runsrc      = rundest + ((int)window_size - match_offset);
                                    copy_length = match_offset - (int)window_posn;
                                    if (copy_length < match_length)
                                    {
                                        match_length -= copy_length;
                                        window_posn  += (uint)copy_length;
                                        while (copy_length-- > 0)
                                        {
                                            window[rundest++] = window[runsrc++];
                                        }
                                        runsrc = 0;
                                    }
                                }
                                window_posn += (uint)match_length;

                                /* copy match data - no worries about destination wraps */
                                while (match_length-- > 0)
                                {
                                    window[rundest++] = window[runsrc++];
                                }
                            }
                        }
                        break;

                    case LzxConstants.BLOCKTYPE.UNCOMPRESSED:
                        if ((bitbuf.inpos + this_run) > inLen)
                        {
                            throw new InvalidOperationException("DECR_ILLEGALDATA");
                        }
                        Array.Copy(inBuf, bitbuf.inpos, window, window_posn, this_run);
                        bitbuf.inpos += (uint)this_run;
                        window_posn  += (uint)this_run;
                        break;

                    default:
                        throw new InvalidOperationException("DECR_ILLEGALDATA");
                    }
                }
            }

            if (togo != 0)
            {
                throw new InvalidOperationException("DECR_ILLEGALDATA");
            }
            int start_window_pos = (int)window_posn;

            if (start_window_pos == 0)
            {
                start_window_pos = (int)window_size;
            }
            start_window_pos -= outLen;
            Array.Copy(window, start_window_pos, outBuf, 0, outLen);

            m_state.window_posn = window_posn;
            m_state.R0          = R0;
            m_state.R1          = R1;
            m_state.R2          = R2;
        }