317 lines
6.1 KiB
C++
317 lines
6.1 KiB
C++
#include <mdiwin/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(const char *pathFileName)
|
||
: IStream(pathFileName),
|
||
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)
|
||
{
|
||
|
||
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;
|
||
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;
|
||
}
|
||
|
||
LZWDecompression::~LZWDecompression()
|
||
{
|
||
if(!mIsConstructed)return;
|
||
cleanup();
|
||
}
|
||
|
||
void LZWDecompression::unpackData(USHORT imageWide,USHORT imageDeep,USHORT isInterlaced,USHORT bitsPerPixel)
|
||
{
|
||
USHORT clearCode;
|
||
USHORT pixelSize;
|
||
USHORT endOfInput;
|
||
CHAR firstCode;
|
||
|
||
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;
|
||
}
|
||
|
||
void LZWDecompression::putx(SHORT code,SHORT pixelSize)
|
||
{
|
||
SHORT tempCode;
|
||
UCHAR FAR *lpStack=mlpStack;
|
||
Index 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(Index 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);
|
||
}
|
||
if(mhGlobalctLast)
|
||
{
|
||
::GlobalUnlock(mhGlobalctLast);
|
||
::GlobalFree(mhGlobalctLast);
|
||
}
|
||
if(mhGlobalctLink)
|
||
{
|
||
::GlobalUnlock(mhGlobalctLink);
|
||
::GlobalFree(mhGlobalctLink);
|
||
}
|
||
if(mhGlobalOutRow)
|
||
{
|
||
::GlobalUnlock(mhGlobalOutRow);
|
||
::GlobalFree(mhGlobalOutRow);
|
||
}
|
||
if(mhGlobalStack)
|
||
{
|
||
::GlobalUnlock(mhGlobalStack);
|
||
::GlobalFree(mhGlobalStack);
|
||
}
|
||
}
|
||
|
||
// VIRTUALS
|
||
|
||
void LZWDecompression::showHandler(UCHAR FAR */*lpOutRow*/,USHORT /*yLocation*/)
|
||
{
|
||
}
|
||
|
||
void LZWDecompression::errorHandler(CHAR */*errorMessage*/)
|
||
{
|
||
}
|
||
|
||
|