279 lines
6.9 KiB
C++
279 lines
6.9 KiB
C++
// Decoder classes
|
|
//
|
|
// This file is part of sfftobmp, a program to convert
|
|
// structured fax files (sff) to windows bitmap files (bmp),
|
|
// portable bitmap graphics (pbm), tagged image file format (tiff)
|
|
// or JPEG (jpg).
|
|
//
|
|
// Copyright (C) 1998-2012 Peter Schaefer-Hutter and contributors ("THE AUTHORS")
|
|
//
|
|
// Permission to use, copy, modify, distribute, and sell this software and
|
|
// its documentation for any purpose is hereby granted without fee.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
|
|
// EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
|
|
// WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
|
|
//
|
|
// IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL,
|
|
// INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY
|
|
// DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
|
|
// WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY
|
|
// THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE
|
|
// OR PERFORMANCE OF THIS SOFTWARE.
|
|
//
|
|
// Contributor(s):
|
|
// None
|
|
//
|
|
// You can contact the original author by email at peter.schaefer@gmx.de.
|
|
//
|
|
// I'm always pleased to hear that somebody is actually using my software.
|
|
// If you can manage it, e-mail me a quick notice. Thanks!
|
|
//
|
|
/*-RCS-Info----------------------------------------------------
|
|
|
|
$Id$
|
|
|
|
---RCS-Info--------------------------------------------------*/
|
|
|
|
#include <iostream>
|
|
|
|
#include "sfftypes.h"
|
|
#include "common.h"
|
|
|
|
#include "codes.h"
|
|
#include "decoder.h"
|
|
|
|
using namespace std;
|
|
|
|
//-Types-----------------------------------------------------------
|
|
|
|
typedef enum {
|
|
NEED_WHITE,
|
|
NEED_BLACK,
|
|
NEED_WHITETERM,
|
|
NEED_BLACKTERM
|
|
} TDecoderState;
|
|
|
|
//-----------------------------------------------------------------
|
|
|
|
void CBitSource::NeedBits(int nCount)
|
|
{
|
|
while ((m_dwByteCount > 0) && (m_wBitsAvail < nCount)) {
|
|
m_dwAccu |= ((*m_pBuffer) << m_wBitsAvail);
|
|
m_wBitsAvail += 8;
|
|
--m_dwByteCount;
|
|
++m_pBuffer;
|
|
}
|
|
}
|
|
|
|
void CBitSource::ClrBits(int nCount)
|
|
{
|
|
m_wBitsAvail -= nCount;
|
|
m_dwAccu = (m_dwAccu >> nCount);
|
|
}
|
|
|
|
sff_word CBitSource::GetBits(int nCount)
|
|
{
|
|
return (sff_word)(m_dwAccu & ((1<<(nCount))-1)); // mask lower x bits out
|
|
}
|
|
|
|
bool CBitSource::NoMoreBits()
|
|
{
|
|
return ((m_dwByteCount <= 0) && (m_dwAccu == 0));
|
|
}
|
|
|
|
CBitSource::CBitSource(void *pBuffer, sff_dword nByteCount) :
|
|
m_pBuffer((sff_byte *)pBuffer),
|
|
m_wBitsAvail(0),
|
|
m_dwAccu(0),
|
|
m_dwByteCount(nByteCount)
|
|
{
|
|
/* sonst nix */
|
|
}
|
|
|
|
//-----------------------------------------------------------------
|
|
|
|
void CBitSink::SetBits(int nCount)
|
|
{
|
|
sff_byte *p;
|
|
|
|
p = m_pBuffer + (m_dwBitPos >> 3);
|
|
sff_byte mask = 0x80 >> (m_dwBitPos % 8);
|
|
m_dwBitPos += nCount;
|
|
while (mask && nCount) {
|
|
*p |= mask;
|
|
mask >>= 1;
|
|
nCount--;
|
|
}
|
|
p++;
|
|
while (nCount >= 8) {
|
|
*p++ = 0xff;
|
|
nCount -= 8;
|
|
}
|
|
mask = 0x80;
|
|
while (nCount) {
|
|
*p |= mask;
|
|
mask >>= 1;
|
|
nCount--;
|
|
}
|
|
}
|
|
|
|
void CBitSink::ClearBits(int nCount)
|
|
{
|
|
m_dwBitPos += nCount;
|
|
}
|
|
|
|
CBitSink::CBitSink(void *pBuffer, sff_dword nByteCount) :
|
|
m_pBuffer((sff_byte *)pBuffer),
|
|
m_dwBitPos(0),
|
|
m_dwByteCount(nByteCount),
|
|
m_dwBitCount(nByteCount * 8)
|
|
{
|
|
}
|
|
|
|
void CBitSink::Reset()
|
|
{
|
|
m_dwBitPos = 0;
|
|
}
|
|
|
|
//-----------------------------------------------------------------
|
|
|
|
void CByteSink::SetBits(int nCount)
|
|
{
|
|
sff_byte *p;
|
|
|
|
p = m_pBuffer;
|
|
p += m_dwBitPos;
|
|
for (int i=0; i<nCount; i++)
|
|
*p++ = 0;
|
|
m_dwBitPos += nCount;
|
|
};
|
|
|
|
//-----------------------------------------------------------------
|
|
|
|
int CHuffDecoder::FindToken(LPTABENTRY pTable)
|
|
{
|
|
sff_word bits;
|
|
while (pTable->code) {
|
|
bits = GetBits(pTable->bits);
|
|
if (bits == pTable->code) {
|
|
ClrBits(pTable->bits);
|
|
return pTable->run;
|
|
}
|
|
pTable++;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
int CHuffDecoder::DecodeLine(CBitSink& aBitSink)
|
|
{
|
|
int iRunlength;
|
|
m_dwRunlength = 0;
|
|
TDecoderState state = NEED_WHITE;
|
|
|
|
for (;;)
|
|
{
|
|
switch (state) {
|
|
case NEED_WHITE :
|
|
// we expect white_term or white_markup
|
|
NeedBits(12);
|
|
iRunlength = FindToken(aTermWhite);
|
|
if ( iRunlength == RL_EOL) {
|
|
goto exit; // EOL
|
|
}
|
|
if ( iRunlength >= 0 ) {
|
|
if ( iRunlength > 0 ) {
|
|
m_dwRunlength += iRunlength;
|
|
aBitSink.ClearBits(iRunlength);
|
|
}
|
|
state = NEED_BLACK;
|
|
} else {
|
|
iRunlength = FindToken(aMarkUpWhite);
|
|
if ( iRunlength == RL_EOL) {
|
|
goto exit; // EOL
|
|
}
|
|
if (iRunlength >= 0) {
|
|
if ( iRunlength > 0 ) {
|
|
m_dwRunlength += iRunlength;
|
|
aBitSink.ClearBits(iRunlength);
|
|
}
|
|
state = NEED_WHITETERM;
|
|
} else {
|
|
throw CSimpleException(CSimpleException::err_nowhitestart);
|
|
}
|
|
}
|
|
break;
|
|
case NEED_BLACK :
|
|
// we expect black_term or black_markup
|
|
NeedBits(13);
|
|
iRunlength = FindToken(aTermBlack);
|
|
if ( iRunlength == RL_EOL) {
|
|
goto exit; // EOL
|
|
}
|
|
if (iRunlength >= 0) {
|
|
if (iRunlength > 0 ) {
|
|
m_dwRunlength += iRunlength;
|
|
aBitSink.SetBits(iRunlength);
|
|
}
|
|
state = NEED_WHITE;
|
|
} else {
|
|
iRunlength = FindToken(aMarkUpBlack);
|
|
if (iRunlength == RL_EOL) {
|
|
goto exit; // EOL
|
|
}
|
|
if (iRunlength >= 0) {
|
|
if (iRunlength > 0) {
|
|
m_dwRunlength += iRunlength;
|
|
aBitSink.SetBits(iRunlength);
|
|
}
|
|
state = NEED_BLACKTERM;
|
|
} else {
|
|
state = NEED_WHITE;
|
|
// throw CSimpleException(CSimpleException::err_noblackcode);
|
|
// [PS] changed to allow further decoding...
|
|
// currently no problems known, but we'll see...
|
|
}
|
|
}
|
|
break;
|
|
case NEED_WHITETERM :
|
|
// expect White_Term only
|
|
NeedBits(8);
|
|
iRunlength = FindToken(aTermWhite);
|
|
if (iRunlength == RL_EOL) {
|
|
goto exit; // EOL
|
|
}
|
|
if (iRunlength >= 0) {
|
|
if ( iRunlength > 0 ) {
|
|
aBitSink.ClearBits(iRunlength);
|
|
m_dwRunlength += iRunlength;
|
|
}
|
|
state = NEED_BLACK;
|
|
} else {
|
|
throw CSimpleException(CSimpleException::err_nowhiteterm);
|
|
}
|
|
break;
|
|
case NEED_BLACKTERM :
|
|
// expect Black_Term only
|
|
NeedBits(12);
|
|
iRunlength = FindToken(aTermBlack);
|
|
if (iRunlength == RL_EOL) {
|
|
goto exit; // EOL
|
|
}
|
|
if (iRunlength >= 0) {
|
|
if ( iRunlength > 0 ) {
|
|
m_dwRunlength += iRunlength;
|
|
aBitSink.SetBits(iRunlength);
|
|
}
|
|
state = NEED_WHITE;
|
|
} else {
|
|
throw CSimpleException(CSimpleException::err_noblackterm);
|
|
}
|
|
break;
|
|
}
|
|
if (NoMoreBits())
|
|
break;
|
|
}
|
|
exit:
|
|
return m_dwRunlength;
|
|
}
|