package uk.co.mmscomputing.io; import java.io.*; public class LZWInputStream extends BitInputStream{ private final static int MAXCODE = 4096; private int[] prefix=new int[MAXCODE]; private int[] suffix=new int[MAXCODE]; private int[] stack =new int[MAXCODE]; private int sp=0; private int dataSize=0; private int clearCode=0; private int eoiCode=0; // eoi code private int availCode=0; // next available code private int lastCode=MAXCODE; // last code, set to impossible value private int codeSize=0; private int codeMask=0; private int first=0; public LZWInputStream(InputStream in,int datasize,boolean nbms) throws IOException{ super(in,nbms); this.dataSize=datasize; sp=0; // reset stack pointer first=0; resetTables(); for(int i=0; i<clearCode; i++){ // initialize prefix[i]=MAXCODE; suffix[i]=i; } } private void resetTables(){ // GIF: datasize = 2..8 // TIFF LZW: datasize = 8 clearCode = 256 eoi = 257 clearCode = 1<<dataSize; eoiCode = clearCode+1; // eoi code availCode = clearCode+2; // next available code lastCode = MAXCODE; // last code, set to impossible value codeSize = dataSize+1; codeMask = (1<<codeSize)-1; //Log.msg("data size : 0x"+Integer.toHexString(dataSize)); //Log.msg("clear code : 0x"+Integer.toHexString(clearCode)); //Log.msg("avail code : 0x"+Integer.toHexString(availCode)); //Log.msg("last code : 0x"+Integer.toHexString(lastCode)); //Log.msg("code size : 0x"+Integer.toHexString(codeSize)); //Log.msg("code mask : 0x"+Integer.toHexString(codeMask)); //Log.msg("eoi code : 0x"+Integer.toHexString(eoiCode)); } public int read(byte[] b)throws IOException{ return read(b,0,b.length); } public int read(byte[] b,int off,int len)throws IOException{ for(int i=0;i<len;i++){ int c=read(); if(c<0){ return i; } b[off+i]=(byte)c; } return len; } public int read()throws IOException{ int code; if(sp>0){ return stack[--sp]; } while((code=readBits(codeSize))>=0){ if(code==eoiCode){ // code=super.read(); // read empty run // if(code!=0){ // throw new IOException(getClass().getName()+".read:\n\tMissing empty run !"); // } return -1; } decode(code); if(sp>0){ return stack[--sp]; } } throw new IOException(getClass().getName()+".read:\n\tMissing eoi code !"); } private void decode(int code)throws IOException{ if(code==clearCode){ // reset variables codeSize =dataSize+1; codeMask =(1<<codeSize)-1; availCode=clearCode+2; // next available code lastCode =MAXCODE; // last code, set to impossible value return; } if(code>availCode){ throw new IOException(getClass().getName()+"decode:\n\tIllegal LZW-Code ["+code+"] > ["+availCode+"]"); } if(lastCode==MAXCODE){ // first code first=suffix[code]; stack[sp++]=first; lastCode=code; return; } int inCode=code; // remember if(code==availCode){ stack[sp++]=first; code=lastCode; } while(code>clearCode){ stack[sp++]=suffix[code]; code=prefix[code]; } first=suffix[code]; stack[sp++]=first; prefix[availCode]=lastCode; // generate code table suffix[availCode]=first; if(availCode<4096){ // if(availCode==4096) a clear code will reset decoder availCode++; } /* if(((availCode&codeMask)==0)&&(availCode<4096)){ // GIF codeSize++; codeMask+=availCode; } */ if(availCode==codeMask){ // TIFF codeSize++; codeMask=(1<<codeSize)-1; } lastCode=inCode; } } // Grafikformate; Thomas W. Lipp; Microsoft Press 1997; ISBN 3-86063-391-0