OpenCores
URL https://opencores.org/ocsvn/lzrw1-compressor-core/lzrw1-compressor-core/trunk

Subversion Repositories lzrw1-compressor-core

[/] [lzrw1-compressor-core/] [trunk/] [LZRW1Decoder.java] - Rev 2

Compare with Previous | Blame | View Log

/**************************************************************************************************************
*
*    L Z R W 1   E N C O D E R   C O R E
*
*  A high throughput loss less data compression core.
* 
* Copyright 2012-2013   Lukas Schrittwieser (LS)
*
*    This program is free software: you can redistribute it and/or modify
*    it under the terms of the GNU General Public License as published by
*    the Free Software Foundation, either version 2 of the License, or
*    (at your option) any later version.
*
*    This program is distributed in the hope that it will be useful,
*    but WITHOUT ANY WARRANTY; without even the implied warranty of
*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*    GNU General Public License for more details.
*
*    You should have received a copy of the GNU General Public License
*    along with this program; if not, write to the Free Software
*    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*    Or see <http://www.gnu.org/licenses/>
*
***************************************************************************************************************
*
* Change Log:
*
* Version 1.0 - 2013/04/05 - LS
*   released
*
***************************************************************************************************************
*
* This is an example decoder (decompressor) for which can be used to decompress data encoded by the core.
*                                                                                                                    
***************************************************************************************************************/   
 
package org.sump.analyzer;
import java.io.IOException;
 
class LZRW1Decoder
{
	final static boolean DEBUG = false;		// set this to true for detailed debug output to the console
 
	final static int HISTORY_LEN = 4096;	// buffer length in bytes 
	final static int LOOK_AHEAD_LEN = 16;	// look ahead buffer length in bytes
	final static int HASH_BIT_LEN = 11;     // number of bits for the index in the hash table
 
	/* configer the number of items (offset-length-tuples or literals) per frame */
	public final int ITEMS_PER_FRAME = 8;
 
	public LZRW1Decoder ()
	{
		// allocate the history buffer
		buffer = new int[HISTORY_LEN];
		validBufferLen = 0;
		histWrInd = 0;
		flags = 0;
		frameItemCnt = 0;
		offset = -1;
		copyCnt = 0;
		readIndex = 0;
		endOfData = false;
		if (DEBUG)
			System.out.println("LZRW1Decoder constructed");
	}
 
	/**
	* Loads a block of compressed data into the module. Decoding will start at a given offset.
	* @param cd		The data to be decompressed
	* @param o		Index of the first byte of encoded data in cd
	*/
	void loadCompressedData (byte [] cd, int o)
	{
		compressed = cd;
		// reset all internal states for a new stream
		validBufferLen = 0;
		histWrInd = 0;
		flags = 0;
		frameItemCnt = 0;
		offset = -1;
		copyCnt = 0;
		readIndex = o;
		endOfData = false;
		if (DEBUG)
			System.out.println("compressed data loaded");
	}
 
	/**
	* Decompresses one byte of data stored in source block and returns it. If no source data is available an
	* exception will be created. If the end-of-data symbol is encountered -1 will be returned. If the compressed
	* data ends without an end-of-data symbol an exception will be created as well. Any data after an end-of-data
	* symbol will be ignored and can not be decoded. However the method may still be called, it will keep returning
	* -1 to indicated the end of the decoded data.
	* @return	The next byte in the stream of decoded data. -1 if end-of-data was reached
	* @throws IOException if an error is found in the encoded data
	*/
	int decodeNextByte () throws IOException
	{
		int ch = 0;		// decoded char (to be returned)
 
		// make sure that we have data
		if (compressed == null)
			throw new IOException("no compressed data loaded");
 
		if (endOfData)
			return -1;
 
		// check wether we can copy data from the stream history (due to a offset/length pair found earlier)
		if (copyCnt > 0)
		{	
			ch = readFromHistory();
			copyCnt--;
			// the byte is decoded, it becomes part of the stream history
			insertIntoHistBuf(ch);
			return ch;
		}
 
		// get next byte from compressed data stream
		if (readIndex >= compressed.length)
			throw new IOException("encountered end of compressed data without end-of-data symbol (data corrupt)");
		ch = compressed[readIndex++];	
 
		// load a new header if necessary
		if (frameItemCnt==0)
		{
			flags = ch&0xff;
			if (DEBUG)
				System.out.printf("   found header: %02x\n",flags);
			frameItemCnt = 8;
			// load the next byte
			if (readIndex >= compressed.length)
				throw new IOException("encountered end of compressed data without end-of-data symbol (data corrupt)");
			ch = compressed[readIndex++];	
		}
 
		// check whether we have a pair or not
		if ((flags&0x01) == 1)
		{
			// this is a length-offset pair, load the second byte
			if (readIndex >= compressed.length)
				throw new IOException("encountered end of compressed data without end-of-data symbol (data corrupt)");
			int lowByte = compressed[readIndex++];	
			int highByte = ch;
			// decode the pair into offset and length
			copyCnt = (highByte>>4) & 0x0f;
			offset = ((highByte<<8)&0x0f00) + (lowByte&0xff);
			// check for the end-of-data symbol
			if ((offset==0) && (copyCnt==0))
			{
				if (DEBUG)
					System.out.println("   found end of data symbol");
				endOfData = true;
				// check that there is no data left in the encoded input
				/*if (readIndex < compressed.length)
					throw new IOException("compressed data after end-of-data symbol (data corrupt) "+readIndex+"  "+compressed.length);*/
				return -1;
			}	
			copyCnt++;	// Note: the encoder saves the number of byte to be copied minus 1 to save some space (2 means copy 3 bytes, and so on)
			if (DEBUG)
				System.out.println("len:"+copyCnt+" off:"+offset);
			// load the first copy byte from the history buffer
			ch = readFromHistory();
			copyCnt--;	// one byte copied
			// this byte is decoded, it becomes part of the stream history
			insertIntoHistBuf(ch);
		}
		else
		{
			// convert the signed char (-128..127) to an unsigned value
			//if (ch < 0)
			//	ch += 256;
			ch &= 0xff;
 
			// this is a literal
			if (DEBUG)
				System.out.printf("lit: '%c'=%02x\n",ch,ch);
			// save this byte in the history buffer
			insertIntoHistBuf(ch);
		}
 
		// shift header for next byte
		frameItemCnt--;
		flags >>= 1;
		return ch;
	}
 
	/**
	* read one byte from the history buffer from the position defined by offset.
	*/
	private int readFromHistory() throws IOException
	{
		if (offset >= validBufferLen)
			throw new IOException("offset is pointing to a location before the beginning of the data (data corrupt)");
		// calculate index (move back offset bytes) from last one (-1 because histWrInd point to next free location)	
		int ind = histWrInd-offset-1;	
		if (ind < 0)	// wrap around (ring buffer)
			ind += HISTORY_LEN;
		if (ind < 0)
			// index is still negative, this is an error in the encoded data
			throw new IOException("Offset wraps more than once in history buffer (data corrupt)");
		// load the byte from the histroy buffer	
		return buffer[ind];
	}
 
	private void insertIntoHistBuf (int ch)
	{
		buffer[histWrInd++] = ch;
		if (histWrInd >= buffer.length)
			histWrInd = 0;
		// count the number of valid bytes in the histroy buffer
		if (validBufferLen < HISTORY_LEN)
			validBufferLen++;
	}
 
	int [] buffer;
	int validBufferLen;
	int histWrInd;
	int flags;
	int frameItemCnt;	
	int offset;
	int copyCnt;
	byte [] compressed;	// holds the compressed data
	int readIndex;
	boolean endOfData;	
}
 
 
 

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.