339 lines
6.5 KiB
C++
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*/)
|
|
{
|
|
}
|