Files
Work/gif/LZW.CPP
2024-08-07 09:16:27 -04:00

339 lines
6.5 KiB
C++

#include <gif/lzw.hpp>
USHORT LZWDecompression::mStartTable[LZWDecompression::STARTTABLESIZE]=
{0x00,0x04,0x02,0x01,0x00};
USHORT LZWDecompression::mIncTable[LZWDecompression::INCTABLESIZE]=
{0x08,0x08,0x04,0x02,0x00};
USHORT LZWDecompression::mcMask[LZWDecompression::CMASKSIZE]=
{0x00,0x01,0x03,0x07,0x0F,0x1F,0x3F,0x7F,0xFF};
CHAR LZWDecompression::errorMessage[]="Error reading data.";
LZWDecompression::LZWDecompression(void)
: mhGlobalctFirst(0), mhGlobalctLast(0), mhGlobalctLink(0),
mhGlobalOutRow(0), mhGlobalStack(0), mlpctFirst(0), mlpctLast(0),
mlpctLink(0), mlpOutRow(0), mlpStack(0), mNextCode(0), mNextLimit(0),
mBufferCount(0), mRemct(0), mRem(0), mPass(0), mxLocation(0),
myLocation(0), mRowCount(0), mIsConstructed(FALSE), mReqct(0), mCode(0)
{
initialize();
}
LZWDecompression::~LZWDecompression()
{
if(!mIsConstructed)return;
cleanup();
}
BOOL LZWDecompression::initialize(void)
{
cleanup();
mhGlobalctFirst=::GlobalAlloc(GMEM_FIXED,CTSIZE);
mhGlobalctLast=::GlobalAlloc(GMEM_FIXED,CTSIZE);
mhGlobalctLink=::GlobalAlloc(GMEM_FIXED,CTSIZE*sizeof(USHORT));
mhGlobalOutRow=::GlobalAlloc(GMEM_FIXED,OUTROWSIZE);
mhGlobalStack=::GlobalAlloc(GMEM_FIXED,STACKSIZE);
if(!mhGlobalctFirst||!mhGlobalctLast||!mhGlobalctLink||!mhGlobalOutRow||!mhGlobalStack)return FALSE;
mlpctFirst=(CHAR FAR *)::GlobalLock(mhGlobalctFirst);
mlpctLast=(CHAR FAR *)::GlobalLock(mhGlobalctLast);
mlpctLink=(SHORT FAR *)::GlobalLock(mhGlobalctLink);
mlpOutRow=(UCHAR FAR *)::GlobalLock(mhGlobalOutRow);
mlpStack=(UCHAR FAR *)::GlobalLock(mhGlobalStack);
::memset(mlpctFirst,0,CTSIZE);
::memset(mlpctLast,0,CTSIZE);
::memset(mlpctLink,0,CTSIZE*sizeof(USHORT));
::memset(mlpOutRow,0,OUTROWSIZE);
::memset(mlpStack,0,STACKSIZE);
mIsConstructed=TRUE;
return TRUE;
}
BOOL LZWDecompression::unpackData(USHORT imageWide,USHORT imageDeep,USHORT isInterlaced,USHORT bitsPerPixel)
{
USHORT clearCode;
USHORT pixelSize;
USHORT endOfInput;
CHAR firstCode;
initialize();
firstCode=currentChar();
mImageWide=imageWide;
mImageDeep=imageDeep;
mIsInterlaced=isInterlaced;
pixelSize=bitsPerPixel;
clearCode=(1<<currentChar());
endOfInput=(1<<currentChar())+1;
mReqct=currentChar()+1;
initializeTable(clearCode);
mOldCode=0xFFFF;
mPass=0x0000;
mRowCount=mImageWide;
mxLocation=0x0000;
myLocation=0x0000;
while(TRUE)
{
mCode=getCode(mReqct);
if(mCode==clearCode)
{
initializeTable(clearCode);
mReqct=firstCode+1;
mOldCode=0xFFFF;
}
else
{
if(mCode==endOfInput)
{
flush();
break;
}
else
{
if(0xFFFE!=(USHORT)*(mlpctLink+mCode))
{
if(0xFFFF!=mOldCode)if(!insertCode(mCode))break;
}
else if(!insertCode(mOldCode))break;
}
putx(mCode,pixelSize);
mOldCode=mCode;
}
}
return TRUE;
}
void LZWDecompression::putx(SHORT code,SHORT pixelSize)
{
SHORT tempCode;
UCHAR FAR *lpStack=mlpStack;
int i=0;
while(TRUE)
{
*lpStack=*(mlpctLast+code);
lpStack++;
i++;
code=*(mlpctLink+code);
if(-1>=code)break;
}
if(1==pixelSize)
{
while(i>0)
{
lpStack--;
tempCode=(*lpStack)&0x0001;
doPixel(tempCode);
tempCode=(*lpStack)&0x00FF;
tempCode>>=1;
doPixel(tempCode);
i--;
}
}
else
{
while(i>0)
{
lpStack--;
tempCode=(*lpStack)&0x00FF;
doPixel(tempCode);
i--;
}
}
}
void LZWDecompression::doPixel(CHAR tempCode)
{
*(mlpOutRow+mxLocation)=tempCode;
mxLocation++;
mRowCount--;
if(0!=mRowCount)return;
showHandler(mlpOutRow,myLocation);
mxLocation=0;
mRowCount=mImageWide;
if(!mIsInterlaced)
{
myLocation++;
if(myLocation>=mImageDeep)myLocation=0;
}
else
{
myLocation+=mIncTable[mPass];
if(myLocation<mImageDeep)return;
myLocation=mStartTable[++mPass];
}
return;
}
void LZWDecompression::initializeTable(SHORT clearCode)
{
mNextCode=clearCode+2;
mNextLimit=(clearCode<<1);
for(int i=0;i<CTSIZE;i++)
{
if(i<clearCode)
{
*(mlpctFirst+i)=i;
*(mlpctLast+i)=i;
*(mlpctLink+i)=-1;
}
else *(mlpctLink+i)=-2;
}
}
UCHAR LZWDecompression::getGB(void)
{
if(0!=mBufferCount)
{
if(!getChar())
{
errorHandler(errorMessage);
return currentChar();
}
mBufferCount--;
return currentChar();
}
if(!getChar())
{
errorHandler(errorMessage);
return currentChar();
}
mBufferCount=currentChar();
if(!mBufferCount)errorHandler(errorMessage);
if(!getChar())return currentChar();
mBufferCount--;
return currentChar();
}
USHORT LZWDecompression::getBCode(USHORT code)
{
USHORT tempCode;
USHORT temp;
if(0==mRemct)
{
mRem=getGB();
mRemct=8;
}
if(mRemct<code)
{
tempCode=getGB();
tempCode<<=mRemct;
mRem|=tempCode;
mRemct+=8;
}
temp=mcMask[code];
temp&=0x00FF;
tempCode=mRem;
tempCode&=temp;
mRemct-=code;
mRem>>=(code&0x00FF);
return tempCode;
}
USHORT LZWDecompression::getCode(USHORT reqct)
{
USHORT tempCode1;
USHORT tempCode2;
if(reqct<=8)return getBCode(reqct);
tempCode1=getBCode(8);
tempCode2=getBCode(reqct-8);
tempCode2<<=8;
tempCode2|=tempCode1;
return tempCode2;
}
WORD LZWDecompression::insertCode(SHORT code)
{
if(mNextCode>=CTSIZE)return FALSE;
*(mlpctLink+mNextCode)=mOldCode;
*(mlpctLast+mNextCode)=*(mlpctFirst+code);
*(mlpctFirst+mNextCode)=*(mlpctFirst+mOldCode);
mNextCode++;
if(mNextCode!=mNextLimit)return TRUE;
if(mReqct>=12)return TRUE;
mReqct++;
mNextLimit<<=1;
return TRUE;
}
void LZWDecompression::flush(void)
{
while(TRUE)
{
if(0==mBufferCount)
{
if(!getChar())return;
mBufferCount=currentChar();
if(0==mBufferCount)return;
}
else
{
if(!getChar())return;
mBufferCount--;
}
}
}
void LZWDecompression::cleanup(void)
{
if(mhGlobalctFirst)
{
::GlobalUnlock(mhGlobalctFirst);
::GlobalFree(mhGlobalctFirst);
mhGlobalctFirst=0;
}
if(mhGlobalctLast)
{
::GlobalUnlock(mhGlobalctLast);
::GlobalFree(mhGlobalctLast);
mhGlobalctLast=0;
}
if(mhGlobalctLink)
{
::GlobalUnlock(mhGlobalctLink);
::GlobalFree(mhGlobalctLink);
mhGlobalctLink=0;
}
if(mhGlobalOutRow)
{
::GlobalUnlock(mhGlobalOutRow);
::GlobalFree(mhGlobalOutRow);
mhGlobalOutRow=0;
}
if(mhGlobalStack)
{
::GlobalUnlock(mhGlobalStack);
::GlobalFree(mhGlobalStack);
mhGlobalStack=0;
}
mIsConstructed=FALSE;
mlpctFirst=0;
mlpctLast=0;
mlpctLink=0;
mlpOutRow=0;
mlpStack=0;
mNextCode=0;
mNextLimit=0;
mBufferCount=0;
mRemct=0;
mRem=0;
mPass=0;
mxLocation=0;
myLocation=0;
mRowCount=0;
mReqct=0;
mCode=0;
}
// VIRTUALS
void LZWDecompression::showHandler(UCHAR FAR * /*lpOutRow*/,USHORT /*yLocation*/)
{
}
void LZWDecompression::errorHandler(CHAR * /*errorMessage*/)
{
}