Files
core/PdfReader/Src/JBIG2Stream.cpp
Alexander.Trofimov beb64a6efa utf8 -> utf8 with BOM
2016-06-23 19:23:34 +03:00

3968 lines
95 KiB
C++

/*
* (c) Copyright Ascensio System SIA 2010-2016
*
* This program is a free software product. You can redistribute it and/or
* modify it under the terms of the GNU Affero General Public License (AGPL)
* version 3 as published by the Free Software Foundation. In accordance with
* Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
* that Ascensio System SIA expressly excludes the warranty of non-infringement
* of any third-party rights.
*
* This program is distributed WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For
* details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
*
* You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
* EU, LV-1021.
*
* The interactive user interfaces in modified source and object code versions
* of the Program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU AGPL version 3.
*
* Pursuant to Section 7(b) of the License you must retain the original Product
* logo when distributing the program. Pursuant to Section 7(e) we decline to
* grant you any rights under trademark law for use of our trademarks.
*
* All the Product's GUI elements, including illustrations and icon sets, as
* well as technical writing content are licensed under the terms of the
* Creative Commons Attribution-ShareAlike 4.0 International. See the License
* terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
*
*/
#include <stdlib.h>
#include <limits.h>
#include "List.h"
#include "JArithmeticDecoder.h"
#include "JBIG2Stream.h"
//~ share these tables
#include "CCITT-Tables.h"
namespace PdfReader
{
static int c_arrContextSize[4] ={ 16, 13, 10, 10 };
static int c_arrRefContextSize[2] ={ 13, 10 };
//------------------------------------------------------------------------
// JBIG2HuffmanTable
//------------------------------------------------------------------------
#define jbig2HuffmanLOW 0xfffffffd
#define jbig2HuffmanOOB 0xfffffffe
#define jbig2HuffmanEOT 0xffffffff
struct JBIG2HuffmanTable
{
int nValue;
unsigned int unPrefixLen;
unsigned int unRangeLen; // can also be LOW, OOB, or EOT
unsigned int unPrefix;
};
JBIG2HuffmanTable c_oHuffTableA[] =
{
{ 0, 1, 4, 0x000 },
{ 16, 2, 8, 0x002 },
{ 272, 3, 16, 0x006 },
{ 65808, 3, 32, 0x007 },
{ 0, 0, jbig2HuffmanEOT, 0 }
};
JBIG2HuffmanTable c_oHuffTableB[] =
{
{ 0, 1, 0, 0x000 },
{ 1, 2, 0, 0x002 },
{ 2, 3, 0, 0x006 },
{ 3, 4, 3, 0x00e },
{ 11, 5, 6, 0x01e },
{ 75, 6, 32, 0x03e },
{ 0, 6, jbig2HuffmanOOB, 0x03f },
{ 0, 0, jbig2HuffmanEOT, 0 }
};
JBIG2HuffmanTable c_oHuffTableC[] =
{
{ 0, 1, 0, 0x000 },
{ 1, 2, 0, 0x002 },
{ 2, 3, 0, 0x006 },
{ 3, 4, 3, 0x00e },
{ 11, 5, 6, 0x01e },
{ 0, 6, jbig2HuffmanOOB, 0x03e },
{ 75, 7, 32, 0x0fe },
{ -256, 8, 8, 0x0fe },
{ -257, 8, jbig2HuffmanLOW, 0x0ff },
{ 0, 0, jbig2HuffmanEOT, 0 }
};
JBIG2HuffmanTable c_oHuffTableD[] =
{
{ 1, 1, 0, 0x000 },
{ 2, 2, 0, 0x002 },
{ 3, 3, 0, 0x006 },
{ 4, 4, 3, 0x00e },
{ 12, 5, 6, 0x01e },
{ 76, 5, 32, 0x01f },
{ 0, 0, jbig2HuffmanEOT, 0 }
};
JBIG2HuffmanTable c_oHuffTableE[] =
{
{ 1, 1, 0, 0x000 },
{ 2, 2, 0, 0x002 },
{ 3, 3, 0, 0x006 },
{ 4, 4, 3, 0x00e },
{ 12, 5, 6, 0x01e },
{ 76, 6, 32, 0x03e },
{ -255, 7, 8, 0x07e },
{ -256, 7, jbig2HuffmanLOW, 0x07f },
{ 0, 0, jbig2HuffmanEOT, 0 }
};
JBIG2HuffmanTable c_oHuffTableF[] =
{
{ 0, 2, 7, 0x000 },
{ 128, 3, 7, 0x002 },
{ 256, 3, 8, 0x003 },
{ -1024, 4, 9, 0x008 },
{ -512, 4, 8, 0x009 },
{ -256, 4, 7, 0x00a },
{ -32, 4, 5, 0x00b },
{ 512, 4, 9, 0x00c },
{ 1024, 4, 10, 0x00d },
{ -2048, 5, 10, 0x01c },
{ -128, 5, 6, 0x01d },
{ -64, 5, 5, 0x01e },
{ -2049, 6, jbig2HuffmanLOW, 0x03e },
{ 2048, 6, 32, 0x03f },
{ 0, 0, jbig2HuffmanEOT, 0 }
};
JBIG2HuffmanTable c_oHuffTableG[] =
{
{ -512, 3, 8, 0x000 },
{ 256, 3, 8, 0x001 },
{ 512, 3, 9, 0x002 },
{ 1024, 3, 10, 0x003 },
{ -1024, 4, 9, 0x008 },
{ -256, 4, 7, 0x009 },
{ -32, 4, 5, 0x00a },
{ 0, 4, 5, 0x00b },
{ 128, 4, 7, 0x00c },
{ -128, 5, 6, 0x01a },
{ -64, 5, 5, 0x01b },
{ 32, 5, 5, 0x01c },
{ 64, 5, 6, 0x01d },
{ -1025, 5, jbig2HuffmanLOW, 0x01e },
{ 2048, 5, 32, 0x01f },
{ 0, 0, jbig2HuffmanEOT, 0 }
};
JBIG2HuffmanTable c_oHuffTableH[] =
{
{ 0, 2, 1, 0x000 },
{ 0, 2, jbig2HuffmanOOB, 0x001 },
{ 4, 3, 4, 0x004 },
{ -1, 4, 0, 0x00a },
{ 22, 4, 4, 0x00b },
{ 38, 4, 5, 0x00c },
{ 2, 5, 0, 0x01a },
{ 70, 5, 6, 0x01b },
{ 134, 5, 7, 0x01c },
{ 3, 6, 0, 0x03a },
{ 20, 6, 1, 0x03b },
{ 262, 6, 7, 0x03c },
{ 646, 6, 10, 0x03d },
{ -2, 7, 0, 0x07c },
{ 390, 7, 8, 0x07d },
{ -15, 8, 3, 0x0fc },
{ -5, 8, 1, 0x0fd },
{ -7, 9, 1, 0x1fc },
{ -3, 9, 0, 0x1fd },
{ -16, 9, jbig2HuffmanLOW, 0x1fe },
{ 1670, 9, 32, 0x1ff },
{ 0, 0, jbig2HuffmanEOT, 0 }
};
JBIG2HuffmanTable c_oHuffTableI[] =
{
{ 0, 2, jbig2HuffmanOOB, 0x000 },
{ -1, 3, 1, 0x002 },
{ 1, 3, 1, 0x003 },
{ 7, 3, 5, 0x004 },
{ -3, 4, 1, 0x00a },
{ 43, 4, 5, 0x00b },
{ 75, 4, 6, 0x00c },
{ 3, 5, 1, 0x01a },
{ 139, 5, 7, 0x01b },
{ 267, 5, 8, 0x01c },
{ 5, 6, 1, 0x03a },
{ 39, 6, 2, 0x03b },
{ 523, 6, 8, 0x03c },
{ 1291, 6, 11, 0x03d },
{ -5, 7, 1, 0x07c },
{ 779, 7, 9, 0x07d },
{ -31, 8, 4, 0x0fc },
{ -11, 8, 2, 0x0fd },
{ -15, 9, 2, 0x1fc },
{ -7, 9, 1, 0x1fd },
{ -32, 9, jbig2HuffmanLOW, 0x1fe },
{ 3339, 9, 32, 0x1ff },
{ 0, 0, jbig2HuffmanEOT, 0 }
};
JBIG2HuffmanTable c_oHuffTableJ[] =
{
{ -2, 2, 2, 0x000 },
{ 6, 2, 6, 0x001 },
{ 0, 2, jbig2HuffmanOOB, 0x002 },
{ -3, 5, 0, 0x018 },
{ 2, 5, 0, 0x019 },
{ 70, 5, 5, 0x01a },
{ 3, 6, 0, 0x036 },
{ 102, 6, 5, 0x037 },
{ 134, 6, 6, 0x038 },
{ 198, 6, 7, 0x039 },
{ 326, 6, 8, 0x03a },
{ 582, 6, 9, 0x03b },
{ 1094, 6, 10, 0x03c },
{ -21, 7, 4, 0x07a },
{ -4, 7, 0, 0x07b },
{ 4, 7, 0, 0x07c },
{ 2118, 7, 11, 0x07d },
{ -5, 8, 0, 0x0fc },
{ 5, 8, 0, 0x0fd },
{ -22, 8, jbig2HuffmanLOW, 0x0fe },
{ 4166, 8, 32, 0x0ff },
{ 0, 0, jbig2HuffmanEOT, 0 }
};
JBIG2HuffmanTable c_oHuffTableK[] =
{
{ 1, 1, 0, 0x000 },
{ 2, 2, 1, 0x002 },
{ 4, 4, 0, 0x00c },
{ 5, 4, 1, 0x00d },
{ 7, 5, 1, 0x01c },
{ 9, 5, 2, 0x01d },
{ 13, 6, 2, 0x03c },
{ 17, 7, 2, 0x07a },
{ 21, 7, 3, 0x07b },
{ 29, 7, 4, 0x07c },
{ 45, 7, 5, 0x07d },
{ 77, 7, 6, 0x07e },
{ 141, 7, 32, 0x07f },
{ 0, 0, jbig2HuffmanEOT, 0 }
};
JBIG2HuffmanTable c_oHuffTableL[] =
{
{ 1, 1, 0, 0x000 },
{ 2, 2, 0, 0x002 },
{ 3, 3, 1, 0x006 },
{ 5, 5, 0, 0x01c },
{ 6, 5, 1, 0x01d },
{ 8, 6, 1, 0x03c },
{ 10, 7, 0, 0x07a },
{ 11, 7, 1, 0x07b },
{ 13, 7, 2, 0x07c },
{ 17, 7, 3, 0x07d },
{ 25, 7, 4, 0x07e },
{ 41, 8, 5, 0x0fe },
{ 73, 8, 32, 0x0ff },
{ 0, 0, jbig2HuffmanEOT, 0 }
};
JBIG2HuffmanTable c_oHuffTableM[] =
{
{ 1, 1, 0, 0x000 },
{ 2, 3, 0, 0x004 },
{ 7, 3, 3, 0x005 },
{ 3, 4, 0, 0x00c },
{ 5, 4, 1, 0x00d },
{ 4, 5, 0, 0x01c },
{ 15, 6, 1, 0x03a },
{ 17, 6, 2, 0x03b },
{ 21, 6, 3, 0x03c },
{ 29, 6, 4, 0x03d },
{ 45, 6, 5, 0x03e },
{ 77, 7, 6, 0x07e },
{ 141, 7, 32, 0x07f },
{ 0, 0, jbig2HuffmanEOT, 0 }
};
JBIG2HuffmanTable c_oHuffTableN[] =
{
{ 0, 1, 0, 0x000 },
{ -2, 3, 0, 0x004 },
{ -1, 3, 0, 0x005 },
{ 1, 3, 0, 0x006 },
{ 2, 3, 0, 0x007 },
{ 0, 0, jbig2HuffmanEOT, 0 }
};
JBIG2HuffmanTable c_oHuffTableO[] =
{
{ 0, 1, 0, 0x000 },
{ -1, 3, 0, 0x004 },
{ 1, 3, 0, 0x005 },
{ -2, 4, 0, 0x00c },
{ 2, 4, 0, 0x00d },
{ -4, 5, 1, 0x01c },
{ 3, 5, 1, 0x01d },
{ -8, 6, 2, 0x03c },
{ 5, 6, 2, 0x03d },
{ -24, 7, 4, 0x07c },
{ 9, 7, 4, 0x07d },
{ -25, 7, jbig2HuffmanLOW, 0x07e },
{ 25, 7, 32, 0x07f },
{ 0, 0, jbig2HuffmanEOT, 0 }
};
//------------------------------------------------------------------------
// JBIG2HuffmanDecoder
//------------------------------------------------------------------------
class JBIG2HuffmanDecoder
{
public:
JBIG2HuffmanDecoder()
{
m_pStream = NULL;
Reset();
}
~JBIG2HuffmanDecoder()
{
}
void SetStream(Stream *pStream)
{
m_pStream = pStream;
}
void Reset()
{
unBuffer = 0;
unBufferLen = 0;
}
// Returns false for OOB, otherwise sets *<pnValue> and returns true.
//~ optimize this
bool DecodeInt(int *pnValue, JBIG2HuffmanTable *pTable)
{
unsigned int unIndex = 0, unPrefix = 0, unLen = 0;
while (pTable[unIndex].unRangeLen != jbig2HuffmanEOT)
{
while (unLen < pTable[unIndex].unPrefixLen)
{
unPrefix = (unPrefix << 1) | ReadBit();
++unLen;
}
if (unPrefix == pTable[unIndex].unPrefix)
{
if (pTable[unIndex].unRangeLen == jbig2HuffmanOOB)
{
return false;
}
if (pTable[unIndex].unRangeLen == jbig2HuffmanLOW)
{
*pnValue = pTable[unIndex].nValue - ReadBits(32);
}
else if (pTable[unIndex].unRangeLen > 0)
{
*pnValue = pTable[unIndex].nValue + ReadBits(pTable[unIndex].unRangeLen);
}
else
{
*pnValue = pTable[unIndex].nValue;
}
return true;
}
++unIndex;
}
return false;
}
unsigned int ReadBits(unsigned int unCount)
{
unsigned int unMask = (unCount == 32) ? 0xffffffff : ((1 << unCount) - 1);
unsigned int unValue;
if (unBufferLen >= unCount)
{
unValue = (unBuffer >> (unBufferLen - unCount)) & unMask;
unBufferLen -= unCount;
}
else
{
unValue = unBuffer & ((1 << unBufferLen) - 1);
unsigned int unLeftCount = unCount - unBufferLen;
unBufferLen = 0;
while (unLeftCount >= 8)
{
unValue = (unValue << 8) | (m_pStream->GetChar() & 0xff);
unLeftCount -= 8;
}
if (unLeftCount > 0)
{
unBuffer = m_pStream->GetChar();
unBufferLen = 8 - unLeftCount;
unValue = (unValue << unLeftCount) | ((unBuffer >> unBufferLen) & ((1 << unLeftCount) - 1));
}
}
return unValue;
}
unsigned int ReadBit()
{
if (unBufferLen == 0)
{
unBuffer = m_pStream->GetChar();
unBufferLen = 8;
}
--unBufferLen;
return (unBuffer >> unBufferLen) & 1;
}
// Sort the table by prefix length and assign prefix values.
void BuildTable(JBIG2HuffmanTable *pTable, unsigned int unLen)
{
// stable selection sort:
// - entries with prefixLen > 0, in ascending prefixLen order
// - entry with prefixLen = 0, rangeLen = EOT
// - all other entries with prefixLen = 0
// (on entry, table[len] has prefixLen = 0, rangeLen = EOT)
unsigned int unI, unJ, unK;
for (unI = 0; unI < unLen; ++unI)
{
for (unJ = unI; unJ < unLen && pTable[unJ].unPrefixLen == 0; ++unJ);
if (unJ == unLen)
{
break;
}
for (unK = unJ + 1; unK < unLen; ++unK)
{
if (pTable[unK].unPrefixLen > 0 && pTable[unK].unPrefixLen < pTable[unJ].unPrefixLen)
{
unJ = unK;
}
}
if (unJ != unI)
{
JBIG2HuffmanTable oTable = pTable[unJ];
for (unK = unJ; unK > unI; --unK)
{
pTable[unK] = pTable[unK - 1];
}
pTable[unI] = oTable;
}
}
pTable[unI] = pTable[unLen];
// assign prefixes
unI = 0;
unsigned int unPrefix = 0;
pTable[unI++].unPrefix = unPrefix++;
for (; pTable[unI].unRangeLen != jbig2HuffmanEOT; ++unI)
{
unPrefix <<= pTable[unI].unPrefixLen - pTable[unI - 1].unPrefixLen;
pTable[unI].unPrefix = unPrefix++;
}
}
private:
Stream *m_pStream;
unsigned int unBuffer;
unsigned int unBufferLen;
};
//------------------------------------------------------------------------
// JBIG2MMRDecoder
//------------------------------------------------------------------------
class JBIG2MMRDecoder
{
public:
JBIG2MMRDecoder()
{
m_pStream = NULL;
Reset();
}
~JBIG2MMRDecoder()
{
}
void SetStream(Stream *pStream)
{
m_pStream = pStream;
}
void Reset()
{
unBuffer = 0;
unBufferLen = 0;
unBytesReadCount = 0;
}
int Get2DCode()
{
CCITTCode *pCode = NULL;
if (unBufferLen == 0)
{
unBuffer = m_pStream->GetChar() & 0xff;
unBufferLen = 8;
++unBytesReadCount;
pCode = &c_arrTable2D[(unBuffer >> 1) & 0x7f];
}
else if (unBufferLen == 8)
{
pCode = &c_arrTable2D[(unBuffer >> 1) & 0x7f];
}
else
{
pCode = &c_arrTable2D[(unBuffer << (7 - unBufferLen)) & 0x7f];
if (pCode->nBitsCount < 0 || pCode->nBitsCount >(int)unBufferLen)
{
unBuffer = (unBuffer << 8) | (m_pStream->GetChar() & 0xff);
unBufferLen += 8;
++unBytesReadCount;
pCode = &c_arrTable2D[(unBuffer >> (unBufferLen - 7)) & 0x7f];
}
}
if (pCode->nBitsCount < 0)
{
return 0;
}
unBufferLen -= pCode->nBitsCount;
return pCode->nCode;
}
int GetWhiteCode()
{
if (unBufferLen == 0)
{
unBuffer = m_pStream->GetChar() & 0xff;
unBufferLen = 8;
++unBytesReadCount;
}
while (1)
{
CCITTCode *pCode = NULL;
if (unBufferLen >= 7 && ((unBuffer >> (unBufferLen - 7)) & 0x7f) == 0)
{
unsigned int unCode;
if (unBufferLen <= 12)
{
unCode = unBuffer << (12 - unBufferLen);
}
else
{
unCode = unBuffer >> (unBufferLen - 12);
}
pCode = &c_arrWhiteTable1[unCode & 0x1f];
}
else
{
unsigned int unCode;
if (unBufferLen <= 9)
{
unCode = unBuffer << (9 - unBufferLen);
}
else
{
unCode = unBuffer >> (unBufferLen - 9);
}
pCode = &c_arrWhiteTable2[unCode & 0x1ff];
}
if (pCode->nBitsCount > 0 && pCode->nBitsCount <= (int)unBufferLen)
{
unBufferLen -= pCode->nBitsCount;
return pCode->nCode;
}
if (unBufferLen >= 12)
{
break;
}
unBuffer = (unBuffer << 8) | (m_pStream->GetChar() & 0xff);
unBufferLen += 8;
++unBytesReadCount;
}
// eat a bit and return a positive number so that the caller doesn't
// go into an infinite loop
--unBufferLen;
return 1;
}
int GetBlackCode()
{
if (unBufferLen == 0)
{
unBuffer = m_pStream->GetChar() & 0xff;
unBufferLen = 8;
++unBytesReadCount;
}
while (1)
{
CCITTCode *pCode = NULL;
if (unBufferLen >= 6 && ((unBuffer >> (unBufferLen - 6)) & 0x3f) == 0)
{
unsigned int unCode;
if (unBufferLen <= 13)
{
unCode = unBuffer << (13 - unBufferLen);
}
else
{
unCode = unBuffer >> (unBufferLen - 13);
}
pCode = &c_arrBlackTable1[unCode & 0x7f];
}
else if (unBufferLen >= 4 && ((unBuffer >> (unBufferLen - 4)) & 0x0f) == 0)
{
unsigned int unCode;
if (unBufferLen <= 12)
{
unCode = unBuffer << (12 - unBufferLen);
}
else
{
unCode = unBuffer >> (unBufferLen - 12);
}
pCode = &c_arrBlackTable2[(unCode & 0xff) - 64];
}
else
{
unsigned int unCode;
if (unBufferLen <= 6)
{
unCode = unBuffer << (6 - unBufferLen);
}
else
{
unCode = unBuffer >> (unBufferLen - 6);
}
pCode = &c_arrBlackTable3[unCode & 0x3f];
}
if (pCode->nBitsCount > 0 && pCode->nBitsCount <= (int)unBufferLen)
{
unBufferLen -= pCode->nBitsCount;
return pCode->nCode;
}
if (unBufferLen >= 13)
{
break;
}
unBuffer = (unBuffer << 8) | (m_pStream->GetChar() & 0xff);
unBufferLen += 8;
++unBytesReadCount;
}
// eat a bit and return a positive number so that the caller doesn't
// go into an infinite loop
--unBufferLen;
return 1;
}
unsigned int Get24Bits()
{
while (unBufferLen < 24)
{
unBuffer = (unBuffer << 8) | (m_pStream->GetChar() & 0xff);
unBufferLen += 8;
++unBytesReadCount;
}
return (unBuffer >> (unBufferLen - 24)) & 0xffffff;
}
void SkipTo(unsigned int unLength)
{
while (unBytesReadCount < unLength)
{
m_pStream->GetChar();
++unBytesReadCount;
}
}
private:
Stream *m_pStream;
unsigned int unBuffer;
unsigned int unBufferLen;
unsigned int unBytesReadCount;
};
//------------------------------------------------------------------------
// JBIG2Segment
//------------------------------------------------------------------------
enum JBIG2SegmentType
{
jbig2SegBitmap,
jbig2SegSymbolDict,
jbig2SegPatternDict,
jbig2SegCodeTable
};
class JBIG2Segment
{
public:
JBIG2Segment(unsigned int unSegNum)
{
m_unSegNum = unSegNum;
}
virtual ~JBIG2Segment()
{
}
void SetSegNum(unsigned int unSegNum)
{
m_unSegNum = unSegNum;
}
unsigned int GetSegNum()
{
return m_unSegNum;
}
virtual JBIG2SegmentType GetType() = 0;
private:
unsigned int m_unSegNum;
};
//------------------------------------------------------------------------
// JBIG2Bitmap
//------------------------------------------------------------------------
struct JBIG2BitmapPtr
{
unsigned char *pDataPtr;
int nShift;
int nX;
};
class JBIG2Bitmap : public JBIG2Segment
{
public:
JBIG2Bitmap(unsigned int unSegNum, int nW, int nH) : JBIG2Segment(unSegNum)
{
m_nW = nW;
m_nH = nH;
m_nLine = (nW + 7) >> 3;
if (m_nW <= 0 || m_nH <= 0 || m_nLine <= 0 || m_nH >= (INT_MAX - 1) / m_nLine)
{
m_pData = NULL;
return;
}
// need to allocate one extra guard byte for use in Combine()
m_pData = (unsigned char *)MemUtilsMalloc(m_nH * m_nLine + 1);
m_pData[m_nH * m_nLine] = 0;
}
virtual ~JBIG2Bitmap()
{
MemUtilsFree(m_pData);
}
virtual JBIG2SegmentType GetType()
{
return jbig2SegBitmap;
}
JBIG2Bitmap *Copy()
{
return new JBIG2Bitmap(0, this);
}
//~ optimize this
JBIG2Bitmap *GetSlice(unsigned int unX, unsigned int unY, unsigned int unW, unsigned int unH)
{
JBIG2Bitmap *pSlice = new JBIG2Bitmap(0, unW, unH);
pSlice->ClearToZero();
for (unsigned int unCurY = 0; unCurY < unH; ++unCurY)
{
for (unsigned int unCurX = 0; unCurX < unW; ++unCurX)
{
if (GetPixel(unX + unCurX, unY + unCurY))
{
pSlice->SetPixel(unCurX, unCurY);
}
}
}
return pSlice;
}
void Expand(int nNewH, unsigned int unPixel)
{
if (nNewH <= m_nH || m_nLine <= 0 || nNewH >= (INT_MAX - 1) / m_nLine)
{
return;
}
// need to allocate one extra guard byte for use in combine()
m_pData = (unsigned char *)MemUtilsRealloc(m_pData, nNewH * m_nLine + 1);
if (unPixel)
{
memset(m_pData + m_nH * m_nLine, 0xff, (nNewH - m_nH) * m_nLine);
}
else
{
memset(m_pData + m_nH * m_nLine, 0x00, (nNewH - m_nH) * m_nLine);
}
m_nH = nNewH;
m_pData[m_nH * m_nLine] = 0;
}
void ClearToZero()
{
memset(m_pData, 0, m_nH * m_nLine);
}
void ClearToOne()
{
memset(m_pData, 0xff, m_nH * m_nLine);
}
int GetWidth()
{
return m_nW;
}
int GetHeight()
{
return m_nH;
}
int GetPixel(int nX, int nY)
{
return (nX < 0 || nX >= m_nW || nY < 0 || nY >= m_nH) ? 0 : (m_pData[nY * m_nLine + (nX >> 3)] >> (7 - (nX & 7))) & 1;
}
void SetPixel(int nX, int nY)
{
m_pData[nY * m_nLine + (nX >> 3)] |= 1 << (7 - (nX & 7));
}
void ClearPixel(int nX, int nY)
{
m_pData[nY * m_nLine + (nX >> 3)] &= 0x7f7f >> (nX & 7);
}
inline void GetPixelPtr(int nX, int nY, JBIG2BitmapPtr *pPtr)
{
if (nY < 0 || nY >= m_nH || nX >= m_nW)
{
pPtr->pDataPtr = NULL;
}
else if (nX < 0)
{
pPtr->pDataPtr = &m_pData[nY * m_nLine];
pPtr->nShift = 7;
pPtr->nX = nX;
}
else
{
pPtr->pDataPtr = &m_pData[nY * m_nLine + (nX >> 3)];
pPtr->nShift = 7 - (nX & 7);
pPtr->nX = nX;
}
}
inline int NextPixel(JBIG2BitmapPtr *pPtr)
{
int nPixel;
if (!pPtr->pDataPtr)
{
nPixel = 0;
}
else if (pPtr->nX < 0)
{
++pPtr->nX;
nPixel = 0;
}
else
{
nPixel = (*pPtr->pDataPtr >> pPtr->nShift) & 1;
if (++pPtr->nX == m_nW)
{
pPtr->pDataPtr = NULL;
}
else if (pPtr->nShift == 0)
{
++pPtr->pDataPtr;
pPtr->nShift = 7;
}
else
{
--pPtr->nShift;
}
}
return nPixel;
}
void DuplicateRow(int nDstY, int nSrcY)
{
memcpy(m_pData + nDstY * m_nLine, m_pData + nSrcY * m_nLine, m_nLine);
}
void Combine(JBIG2Bitmap *pBitmap, int nX, int nY, unsigned int unCombOp)
{
int nY0;
if (nY < 0)
{
nY0 = -nY;
}
else
{
nY0 = 0;
}
int nY1;
if (nY + pBitmap->m_nH > m_nH)
{
nY1 = m_nH - nY;
}
else
{
nY1 = pBitmap->m_nH;
}
if (nY0 >= nY1)
{
return;
}
int nX0;
if (nX >= 0)
{
nX0 = nX & ~7;
}
else
{
nX0 = 0;
}
int nX1 = nX + pBitmap->m_nW;
if (nX1 > m_nW)
{
nX1 = m_nW;
}
if (nX0 >= nX1)
{
return;
}
unsigned int unS1 = nX & 7;
unsigned int unS2 = 8 - unS1;
unsigned int unM1 = 0xff >> (nX1 & 7);
unsigned int unM2 = 0xff << (((nX1 & 7) == 0) ? 0 : 8 - (nX1 & 7));
unsigned int unM3 = (0xff >> unS1) & unM2;
bool bOneByte = (nX0 == ((nX1 - 1) & ~7));
unsigned char *pSrcPtr, *pDstPtr;
for (int nCurY = nY0; nCurY < nY1; ++nCurY)
{
// one byte per line -- need to mask both left and right side
if (bOneByte)
{
unsigned int unSrc1, unDst;
if (nX >= 0)
{
pDstPtr = m_pData + (nY + nCurY) * m_nLine + (nX >> 3);
pSrcPtr = pBitmap->m_pData + nCurY * pBitmap->m_nLine;
unDst = *pDstPtr;
unSrc1 = *pSrcPtr;
switch (unCombOp)
{
case 0: // or
unDst |= (unSrc1 >> unS1) & unM2;
break;
case 1: // and
unDst &= ((0xff00 | unSrc1) >> unS1) | unM1;
break;
case 2: // xor
unDst ^= (unSrc1 >> unS1) & unM2;
break;
case 3: // xnor
unDst ^= ((unSrc1 ^ 0xff) >> unS1) & unM2;
break;
case 4: // replace
unDst = (unDst & ~unM3) | ((unSrc1 >> unS1) & unM3);
break;
}
*pDstPtr = unDst;
}
else
{
pDstPtr = m_pData + (nY + nCurY) * m_nLine;
pSrcPtr = pBitmap->m_pData + nCurY * pBitmap->m_nLine + (-nX >> 3);
unDst = *pDstPtr;
unSrc1 = *pSrcPtr;
switch (unCombOp)
{
case 0: // or
unDst |= unSrc1 & unM2;
break;
case 1: // and
unDst &= unSrc1 | unM1;
break;
case 2: // xor
unDst ^= unSrc1 & unM2;
break;
case 3: // xnor
unDst ^= (unSrc1 ^ 0xff) & unM2;
break;
case 4: // replace
unDst = (unSrc1 & unM2) | (unDst & unM1);
break;
}
*pDstPtr = unDst;
}
}
else // multiple bytes per line -- need to mask left side of left-most byte and right side of right-most byte
{
int nCurX;
unsigned int unSrc0, unSrc1, unSrc, unDst;
if (nX >= 0) // left-most byte
{
pDstPtr = m_pData + (nY + nCurY) * m_nLine + (nX >> 3);
pSrcPtr = pBitmap->m_pData + nCurY * pBitmap->m_nLine;
unSrc1 = *pSrcPtr++;
unDst = *pDstPtr;
switch (unCombOp)
{
case 0: // or
unDst |= unSrc1 >> unS1;
break;
case 1: // and
unDst &= (0xff00 | unSrc1) >> unS1;
break;
case 2: // xor
unDst ^= unSrc1 >> unS1;
break;
case 3: // xnor
unDst ^= (unSrc1 ^ 0xff) >> unS1;
break;
case 4: // replace
unDst = (unDst & (0xff << unS2)) | (unSrc1 >> unS1);
break;
}
*pDstPtr++ = unDst;
nCurX = nX0 + 8;
}
else
{
pDstPtr = m_pData + (nY + nCurY) * m_nLine;
pSrcPtr = pBitmap->m_pData + nCurY * pBitmap->m_nLine + (-nX >> 3);
unSrc1 = *pSrcPtr++;
nCurX = nX0;
}
// middle bytes
for (; nCurX < nX1 - 8; nCurX += 8)
{
unDst = *pDstPtr;
unSrc0 = unSrc1;
unSrc1 = *pSrcPtr++;
unSrc = (((unSrc0 << 8) | unSrc1) >> unS1) & 0xff;
switch (unCombOp)
{
case 0: // or
unDst |= unSrc;
break;
case 1: // and
unDst &= unSrc;
break;
case 2: // xor
unDst ^= unSrc;
break;
case 3: // xnor
unDst ^= unSrc ^ 0xff;
break;
case 4: // replace
unDst = unSrc;
break;
}
*pDstPtr++ = unDst;
}
// right-most byte
// note: this last byte (src1) may not actually be used, depending
// on the values of s1, m1, and m2 - and in fact, it may be off
// the edge of the source bitmap, which means we need to allocate
// one extra guard byte at the end of each bitmap
unDst = *pDstPtr;
unSrc0 = unSrc1;
unSrc1 = *pSrcPtr++;
unSrc = (((unSrc0 << 8) | unSrc1) >> unS1) & 0xff;
switch (unCombOp)
{
case 0: // or
unDst |= unSrc & unM2;
break;
case 1: // and
unDst &= unSrc | unM1;
break;
case 2: // xor
unDst ^= unSrc & unM2;
break;
case 3: // xnor
unDst ^= (unSrc ^ 0xff) & unM2;
break;
case 4: // replace
unDst = (unSrc & unM2) | (unDst & unM1);
break;
}
*pDstPtr = unDst;
}
}
}
unsigned char *GetDataPtr()
{
return m_pData;
}
int GetDataSize()
{
return m_nH * m_nLine;
}
private:
JBIG2Bitmap(unsigned int unSegNum, JBIG2Bitmap *pBitmap) : JBIG2Segment(unSegNum)
{
m_nW = pBitmap->m_nW;
m_nH = pBitmap->m_nH;
m_nLine = pBitmap->m_nLine;
if (m_nW <= 0 || m_nH <= 0 || m_nLine <= 0 || m_nH >= (INT_MAX - 1) / m_nLine)
{
m_pData = NULL;
return;
}
// need to allocate one extra guard byte for use in Combine()
m_pData = (unsigned char *)MemUtilsMalloc(m_nH * m_nLine + 1);
memcpy(m_pData, pBitmap->m_pData, m_nH * m_nLine);
m_pData[m_nH * m_nLine] = 0;
}
private:
int m_nW;
int m_nH;
int m_nLine;
unsigned char *m_pData;
};
//------------------------------------------------------------------------
// JBIG2SymbolDict
//------------------------------------------------------------------------
class JBIG2SymbolDict : public JBIG2Segment
{
public:
JBIG2SymbolDict(unsigned int unSegNum, unsigned int unSize) : JBIG2Segment(unSegNum)
{
m_unSize = unSize;
m_ppBitmaps = (JBIG2Bitmap **)MemUtilsMallocArray(m_unSize, sizeof(JBIG2Bitmap *));
m_pGenericRegionStats = NULL;
m_pRefinementRegionStats = NULL;
}
virtual ~JBIG2SymbolDict()
{
for (unsigned int unIndex = 0; unIndex < m_unSize; ++unIndex)
{
delete m_ppBitmaps[unIndex];
}
MemUtilsFree(m_ppBitmaps);
if (m_pGenericRegionStats)
{
delete m_pGenericRegionStats;
}
if (m_pRefinementRegionStats)
{
delete m_pRefinementRegionStats;
}
}
virtual JBIG2SegmentType GetType()
{
return jbig2SegSymbolDict;
}
unsigned int GetSize()
{
return m_unSize;
}
void SetBitmap(unsigned int unIndex, JBIG2Bitmap *pBitmap)
{
m_ppBitmaps[unIndex] = pBitmap;
}
JBIG2Bitmap *GetBitmap(unsigned int unIndex)
{
return m_ppBitmaps[unIndex];
}
void SetGenericRegionStats(JArithmeticDecoderStats *pStats)
{
m_pGenericRegionStats = pStats;
}
void SetRefinementRegionStats(JArithmeticDecoderStats *pStats)
{
m_pRefinementRegionStats = pStats;
}
JArithmeticDecoderStats *GetGenericRegionStats()
{
return m_pGenericRegionStats;
}
JArithmeticDecoderStats *GetRefinementRegionStats()
{
return m_pRefinementRegionStats;
}
private:
unsigned int m_unSize;
JBIG2Bitmap **m_ppBitmaps;
JArithmeticDecoderStats *m_pGenericRegionStats;
JArithmeticDecoderStats *m_pRefinementRegionStats;
};
//------------------------------------------------------------------------
// JBIG2PatternDict
//------------------------------------------------------------------------
class JBIG2PatternDict : public JBIG2Segment
{
public:
JBIG2PatternDict(unsigned int unSegNum, unsigned int unSize) : JBIG2Segment(unSegNum)
{
m_unSize = unSize;
m_ppBitmaps = (JBIG2Bitmap **)MemUtilsMallocArray(m_unSize, sizeof(JBIG2Bitmap *));
}
virtual ~JBIG2PatternDict()
{
for (unsigned int unIndex = 0; unIndex < m_unSize; ++unIndex)
{
delete m_ppBitmaps[unIndex];
}
MemUtilsFree(m_ppBitmaps);
}
virtual JBIG2SegmentType GetType() { return jbig2SegPatternDict; }
unsigned int GetSize()
{
return m_unSize;
}
void SetBitmap(unsigned int unIndex, JBIG2Bitmap *pBitmap)
{
m_ppBitmaps[unIndex] = pBitmap;
}
JBIG2Bitmap *GetBitmap(unsigned int unIndex)
{
return m_ppBitmaps[unIndex];
}
private:
unsigned int m_unSize;
JBIG2Bitmap **m_ppBitmaps;
};
//------------------------------------------------------------------------
// JBIG2CodeTable
//------------------------------------------------------------------------
class JBIG2CodeTable : public JBIG2Segment
{
public:
JBIG2CodeTable(unsigned int unSegNum, JBIG2HuffmanTable *pTable) : JBIG2Segment(unSegNum)
{
m_pTable = pTable;
}
virtual ~JBIG2CodeTable()
{
MemUtilsFree(m_pTable);
}
virtual JBIG2SegmentType GetType()
{
return jbig2SegCodeTable;
}
JBIG2HuffmanTable *GetHuffTable()
{
return m_pTable;
}
private:
JBIG2HuffmanTable *m_pTable;
};
//------------------------------------------------------------------------
// JBIG2Stream
//------------------------------------------------------------------------
JBIG2Stream::JBIG2Stream(Stream *pStream, Object *pGlobalsStream) :
FilterStream(pStream)
{
m_pPageBitmap = NULL;
m_pArithDecoder = new JArithmeticDecoder();
m_pGenericRegionStats = new JArithmeticDecoderStats(1 << 1);
m_pRefinementRegionStats = new JArithmeticDecoderStats(1 << 1);
m_pIadhStats = new JArithmeticDecoderStats(1 << 9);
m_pIadwStats = new JArithmeticDecoderStats(1 << 9);
m_pIaexStats = new JArithmeticDecoderStats(1 << 9);
m_pIaaiStats = new JArithmeticDecoderStats(1 << 9);
m_pIadtStats = new JArithmeticDecoderStats(1 << 9);
m_pIaitStats = new JArithmeticDecoderStats(1 << 9);
m_pIafsStats = new JArithmeticDecoderStats(1 << 9);
m_pIadsStats = new JArithmeticDecoderStats(1 << 9);
m_pIardxStats = new JArithmeticDecoderStats(1 << 9);
m_pIardyStats = new JArithmeticDecoderStats(1 << 9);
m_pIardwStats = new JArithmeticDecoderStats(1 << 9);
m_pIardhStats = new JArithmeticDecoderStats(1 << 9);
m_pIariStats = new JArithmeticDecoderStats(1 << 9);
m_pIaidStats = new JArithmeticDecoderStats(1 << 1);
m_pHuffDecoder = new JBIG2HuffmanDecoder();
m_pMMrDecoder = new JBIG2MMRDecoder();
pGlobalsStream->Copy(&m_oGlobalsStream);
m_pSegments = m_pGlobalSegments = NULL;
m_pCurStream = NULL;
m_pDataPtr = m_pDataEnd = NULL;
}
JBIG2Stream::~JBIG2Stream()
{
Close();
m_oGlobalsStream.Free();
delete m_pArithDecoder;
delete m_pGenericRegionStats;
delete m_pRefinementRegionStats;
delete m_pIadhStats;
delete m_pIadwStats;
delete m_pIaexStats;
delete m_pIaaiStats;
delete m_pIadtStats;
delete m_pIaitStats;
delete m_pIafsStats;
delete m_pIadsStats;
delete m_pIardxStats;
delete m_pIardyStats;
delete m_pIardwStats;
delete m_pIardhStats;
delete m_pIariStats;
delete m_pIaidStats;
delete m_pHuffDecoder;
delete m_pMMrDecoder;
delete m_pStream;
}
void JBIG2Stream::Reset()
{
// read the globals stream
m_pGlobalSegments = new CList();
if (m_oGlobalsStream.IsStream())
{
m_pSegments = m_pGlobalSegments;
m_pCurStream = m_oGlobalsStream.GetStream();
m_pCurStream->Reset();
m_pArithDecoder->SetStream(m_pCurStream);
m_pHuffDecoder->SetStream(m_pCurStream);
m_pMMrDecoder->SetStream(m_pCurStream);
ReadSegments();
m_pCurStream->Close();
}
// read the main stream
m_pSegments = new CList();
m_pCurStream = m_pStream;
m_pCurStream->Reset();
m_pArithDecoder->SetStream(m_pCurStream);
m_pHuffDecoder->SetStream(m_pCurStream);
m_pMMrDecoder->SetStream(m_pCurStream);
ReadSegments();
if (m_pPageBitmap)
{
m_pDataPtr = m_pPageBitmap->GetDataPtr();
m_pDataEnd = m_pDataPtr + m_pPageBitmap->GetDataSize();
}
else
{
m_pDataPtr = m_pDataEnd = NULL;
}
}
void JBIG2Stream::Close()
{
if (m_pPageBitmap)
{
delete m_pPageBitmap;
m_pPageBitmap = NULL;
}
if (m_pSegments)
{
DeleteCList(m_pSegments, JBIG2Segment);
m_pSegments = NULL;
}
if (m_pGlobalSegments)
{
DeleteCList(m_pGlobalSegments, JBIG2Segment);
m_pGlobalSegments = NULL;
}
m_pDataPtr = m_pDataEnd = NULL;
FilterStream::Close();
}
int JBIG2Stream::GetChar()
{
if (m_pDataPtr && m_pDataPtr < m_pDataEnd)
{
return (*m_pDataPtr++ ^ 0xff) & 0xff;
}
return EOF;
}
int JBIG2Stream::LookChar()
{
if (m_pDataPtr && m_pDataPtr < m_pDataEnd)
{
return (*m_pDataPtr ^ 0xff) & 0xff;
}
return EOF;
}
StringExt *JBIG2Stream::GetPSFilter(int nPSLevel, char *sIndent)
{
return NULL;
}
bool JBIG2Stream::IsBinary(bool bLast)
{
return m_pStream->IsBinary(true);
}
void JBIG2Stream::ReadSegments()
{
unsigned int unSegNum;
while (ReadULong(&unSegNum))
{
// segment header flags
unsigned int unSegFlags;
if (!ReadUByte(&unSegFlags))
{
return;
}
unsigned int unSegType = unSegFlags & 0x3f;
// referred-to segment count and retention flags
unsigned int unRefFlags;
if (!ReadUByte(&unRefFlags))
{
return;
}
unsigned int unRefSegsCount = unRefFlags >> 5;
if (7 == unRefSegsCount)
{
int nChar1, nChar2, nChar3;
if (EOF == (nChar1 = m_pCurStream->GetChar()) || EOF == (nChar2 = m_pCurStream->GetChar()) || EOF == (nChar3 = m_pCurStream->GetChar()))
{
return;
}
unRefFlags = (unRefFlags << 24) | (nChar1 << 16) | (nChar2 << 8) | nChar3;
unRefSegsCount = unRefFlags & 0x1fffffff;
for (unsigned int unIndex = 0; unIndex < (unRefSegsCount + 9) >> 3; ++unIndex)
{
nChar1 = m_pCurStream->GetChar();
}
}
// referred-to segment numbers
unsigned int *punRefSegs = (unsigned int *)MemUtilsMallocArray(unRefSegsCount, sizeof(unsigned int));
if (unSegNum <= 256)
{
for (unsigned int unIndex = 0; unIndex < unRefSegsCount; ++unIndex)
{
if (!ReadUByte(&punRefSegs[unIndex]))
{
MemUtilsFree(punRefSegs);
return;
}
}
}
else if (unSegNum <= 65536)
{
for (unsigned int unIndex = 0; unIndex < unRefSegsCount; ++unIndex)
{
if (!ReadUWord(&punRefSegs[unIndex]))
{
MemUtilsFree(punRefSegs);
return;
}
}
}
else
{
for (unsigned int unIndex = 0; unIndex < unRefSegsCount; ++unIndex)
{
if (!ReadULong(&punRefSegs[unIndex]))
{
MemUtilsFree(punRefSegs);
return;
}
}
}
// segment page association
unsigned int unPage;
if (unSegFlags & 0x40)
{
if (!ReadULong(&unPage))
{
MemUtilsFree(punRefSegs);
return;
}
}
else
{
if (!ReadUByte(&unPage))
{
MemUtilsFree(punRefSegs);
return;
}
}
// segment data length
unsigned int unSegLength;
if (!ReadULong(&unSegLength))
{
MemUtilsFree(punRefSegs);
return;
}
// read the segment data
switch (unSegType)
{
case 0:
if (!ReadSymbolDictSegment(unSegNum, unSegLength, punRefSegs, unRefSegsCount))
{
MemUtilsFree(punRefSegs);
return;
}
break;
case 4:
ReadTextRegionSegment(unSegNum, false, false, unSegLength, punRefSegs, unRefSegsCount);
break;
case 6:
ReadTextRegionSegment(unSegNum, true, false, unSegLength, punRefSegs, unRefSegsCount);
break;
case 7:
ReadTextRegionSegment(unSegNum, true, true, unSegLength, punRefSegs, unRefSegsCount);
break;
case 16:
ReadPatternDictSegment(unSegNum, unSegLength);
break;
case 20:
ReadHalftoneRegionSegment(unSegNum, false, false, unSegLength, punRefSegs, unRefSegsCount);
break;
case 22:
ReadHalftoneRegionSegment(unSegNum, true, false, unSegLength, punRefSegs, unRefSegsCount);
break;
case 23:
ReadHalftoneRegionSegment(unSegNum, true, true, unSegLength, punRefSegs, unRefSegsCount);
break;
case 36:
ReadGenericRegionSegment(unSegNum, false, false, unSegLength);
break;
case 38:
ReadGenericRegionSegment(unSegNum, true, false, unSegLength);
break;
case 39:
ReadGenericRegionSegment(unSegNum, true, true, unSegLength);
break;
case 40:
ReadGenericRefinementRegionSegment(unSegNum, false, false, unSegLength, punRefSegs, unRefSegsCount);
break;
case 42:
ReadGenericRefinementRegionSegment(unSegNum, true, false, unSegLength, punRefSegs, unRefSegsCount);
break;
case 43:
ReadGenericRefinementRegionSegment(unSegNum, true, true, unSegLength, punRefSegs, unRefSegsCount);
break;
case 48:
ReadPageInfoSegment(unSegLength);
break;
case 50:
ReadEndOfStripeSegment(unSegLength);
break;
case 52:
ReadProfilesSegment(unSegLength);
break;
case 53:
ReadCodeTableSegment(unSegNum, unSegLength);
break;
case 62:
ReadExtensionSegment(unSegLength);
break;
default:
for (unsigned int unIndex = 0; unIndex < unSegLength; ++unIndex)
{
int nChar;
if (EOF == (nChar = m_pCurStream->GetChar()))
{
MemUtilsFree(punRefSegs);
return;
}
}
break;
}
MemUtilsFree(punRefSegs);
}
return;
}
bool JBIG2Stream::ReadSymbolDictSegment(unsigned int unSegNum, unsigned int unLength, unsigned int *punRefSegs, unsigned int unRefSegsCount)
{
// symbol dictionary flags
unsigned int unFlags;
if (!ReadUWord(&unFlags))
{
return false;
}
unsigned int unHuff = unFlags & 1;
unsigned int unRefAgg = (unFlags >> 1) & 1;
unsigned int unHuffDH = (unFlags >> 2) & 3;
unsigned int unHuffDW = (unFlags >> 4) & 3;
unsigned int unHuffBMSize = (unFlags >> 6) & 1;
unsigned int unHuffAggInst = (unFlags >> 7) & 1;
unsigned int unContextUsed = (unFlags >> 8) & 1;
unsigned int unContextRetained = (unFlags >> 9) & 1;
unsigned int unSDTemplate = (unFlags >> 10) & 3;
unsigned int unSDRTemplate = (unFlags >> 12) & 1;
// symbol dictionary AT flags
int arrSDATx[4], arrSDATy[4];
if (!unHuff)
{
if (unSDTemplate == 0)
{
if (!ReadByte(&arrSDATx[0]) || !ReadByte(&arrSDATy[0]) || !ReadByte(&arrSDATx[1]) || !ReadByte(&arrSDATy[1]) ||
!ReadByte(&arrSDATx[2]) || !ReadByte(&arrSDATy[2]) || !ReadByte(&arrSDATx[3]) || !ReadByte(&arrSDATy[3]))
{
return false;
}
}
else
{
if (!ReadByte(&arrSDATx[0]) || !ReadByte(&arrSDATy[0]))
{
return false;
}
}
}
// symbol dictionary refinement AT flags
int arrSDRATx[2], arrSDRATy[2];
if (unRefAgg && !unSDRTemplate)
{
if (!ReadByte(&arrSDRATx[0]) || !ReadByte(&arrSDRATy[0]) || !ReadByte(&arrSDRATx[1]) || !ReadByte(&arrSDRATy[1]))
{
return false;
}
}
// SDNUMEXSYMS and SDNUMNEWSYMS
unsigned int unNumExSyms, unNumNewSyms;
if (!ReadULong(&unNumExSyms) || !ReadULong(&unNumNewSyms))
{
return false;
}
// get referenced segments: input symbol dictionaries and code tables
CList *pCodeTables = new CList();
unsigned int unNumInputSyms = 0, unI;
for (unI = 0; unI < unRefSegsCount; ++unI)
{
JBIG2Segment *pSegment = FindSegment(punRefSegs[unI]);
if (pSegment->GetType() == jbig2SegSymbolDict)
{
unNumInputSyms += ((JBIG2SymbolDict *)pSegment)->GetSize();
}
else if (pSegment->GetType() == jbig2SegCodeTable)
{
pCodeTables->Append(pSegment);
}
}
// compute symbol code length
unsigned int unSymCodeLen = 0;
unI = 1;
while (unI < unNumInputSyms + unNumNewSyms)
{
++unSymCodeLen;
unI <<= 1;
}
// get the input symbol bitmaps
JBIG2Bitmap **ppBitmaps = (JBIG2Bitmap **)MemUtilsMallocArray(unNumInputSyms + unNumNewSyms, sizeof(JBIG2Bitmap *));
for (unI = 0; unI < unNumInputSyms + unNumNewSyms; ++unI)
{
ppBitmaps[unI] = NULL;
}
unsigned int unK = 0, unJ;
JBIG2SymbolDict *pInputSymbolDict = NULL;
for (unI = 0; unI < unRefSegsCount; ++unI)
{
JBIG2Segment *pSegment = FindSegment(punRefSegs[unI]);
if (pSegment->GetType() == jbig2SegSymbolDict)
{
pInputSymbolDict = (JBIG2SymbolDict *)pSegment;
for (unJ = 0; unJ < pInputSymbolDict->GetSize(); ++unJ)
{
ppBitmaps[unK++] = pInputSymbolDict->GetBitmap(unJ);
}
}
}
// get the Huffman tables
JBIG2HuffmanTable *pHuffDHTable = NULL, *pHuffDWTable = NULL, *pHuffBMSizeTable = NULL, *pHuffAggInstTable = NULL;
unI = 0;
if (unHuff)
{
if (unHuffDH == 0)
{
pHuffDHTable = c_oHuffTableD;
}
else if (unHuffDH == 1)
{
pHuffDHTable = c_oHuffTableE;
}
else
{
pHuffDHTable = ((JBIG2CodeTable *)pCodeTables->GetByIndex(unI++))->GetHuffTable();
}
if (unHuffDW == 0)
{
pHuffDWTable = c_oHuffTableB;
}
else if (unHuffDW == 1)
{
pHuffDWTable = c_oHuffTableC;
}
else
{
pHuffDWTable = ((JBIG2CodeTable *)pCodeTables->GetByIndex(unI++))->GetHuffTable();
}
if (unHuffBMSize == 0)
{
pHuffBMSizeTable = c_oHuffTableA;
}
else
{
pHuffBMSizeTable = ((JBIG2CodeTable *)pCodeTables->GetByIndex(unI++))->GetHuffTable();
}
if (unHuffAggInst == 0)
{
pHuffAggInstTable = c_oHuffTableA;
}
else
{
pHuffAggInstTable = ((JBIG2CodeTable *)pCodeTables->GetByIndex(unI++))->GetHuffTable();
}
}
delete pCodeTables;
// set up the Huffman decoder
if (unHuff)
{
m_pHuffDecoder->Reset();
}
else // set up the arithmetic decoder
{
if (unContextUsed && pInputSymbolDict)
{
ResetGenericStats(unSDTemplate, pInputSymbolDict->GetGenericRegionStats());
}
else
{
ResetGenericStats(unSDTemplate, NULL);
}
ResetIntStats(unSymCodeLen);
m_pArithDecoder->Start();
}
// set up the arithmetic decoder for refinement/aggregation
if (unRefAgg)
{
if (unContextUsed && pInputSymbolDict)
{
ResetRefinementStats(unSDRTemplate, pInputSymbolDict->GetRefinementRegionStats());
}
else
{
ResetRefinementStats(unSDRTemplate, NULL);
}
}
// allocate symbol widths storage
unsigned int *pSymWidths = NULL;
if (unHuff && !unRefAgg)
{
pSymWidths = (unsigned int *)MemUtilsMallocArray(unNumNewSyms, sizeof(unsigned int));
}
unsigned int unSymHeight = 0;
unI = 0;
while (unI < unNumNewSyms)
{
// read the height class delta height
int nDh;
if (unHuff)
{
m_pHuffDecoder->DecodeInt(&nDh, pHuffDHTable);
}
else
{
m_pArithDecoder->DecodeInt(&nDh, m_pIadhStats);
}
if (nDh < 0 && (unsigned int)-nDh >= unSymHeight)
{
// SyntaxError
for (unsigned int unIndex = 0; unIndex < unNumNewSyms; ++unIndex)
{
if (ppBitmaps[unNumInputSyms + unIndex])
{
delete ppBitmaps[unNumInputSyms + unIndex];
}
}
MemUtilsFree(ppBitmaps);
if (pSymWidths)
{
MemUtilsFree(pSymWidths);
}
return false;
}
unSymHeight += nDh;
unsigned int unSymWidth = 0, unTotalWidth = 0;
unJ = unI;
// read the symbols in this height class
while (1)
{
// read the delta width
int nDw;
if (unHuff)
{
if (!m_pHuffDecoder->DecodeInt(&nDw, pHuffDWTable))
{
break;
}
}
else
{
if (!m_pArithDecoder->DecodeInt(&nDw, m_pIadwStats))
{
break;
}
}
if (nDw < 0 && (unsigned int)-nDw >= unSymWidth)
{
// SyntaxError
for (unsigned int unIndex = 0; unIndex < unNumNewSyms; ++unIndex)
{
if (ppBitmaps[unNumInputSyms + unIndex])
{
delete ppBitmaps[unNumInputSyms + unIndex];
}
}
MemUtilsFree(ppBitmaps);
if (pSymWidths)
{
MemUtilsFree(pSymWidths);
}
return false;
}
unSymWidth += nDw;
// using a collective bitmap, so don't read a bitmap here
if (unHuff && !unRefAgg)
{
pSymWidths[unI] = unSymWidth;
unTotalWidth += unSymWidth;
}
else if (unRefAgg) // refinement/aggregate coding
{
int nRefAggNum;
if (unHuff)
{
if (!m_pHuffDecoder->DecodeInt(&nRefAggNum, pHuffAggInstTable))
{
break;
}
}
else
{
if (!m_pArithDecoder->DecodeInt(&nRefAggNum, m_pIaaiStats))
{
break;
}
}
#if 0 //~ This special case was added about a year before the final draft
//~ of the JBIG2 spec was released. I have encountered some old
//~ JBIG2 images that predate it.
if ( 0 )
{
#else
if (nRefAggNum == 1)
{
#endif
unsigned int unSymID;
int nRefDX, nRefDY, nBMSize;
if (unHuff)
{
unSymID = m_pHuffDecoder->ReadBits(unSymCodeLen);
m_pHuffDecoder->DecodeInt(&nRefDX, c_oHuffTableO);
m_pHuffDecoder->DecodeInt(&nRefDY, c_oHuffTableO);
m_pHuffDecoder->DecodeInt(&nBMSize, c_oHuffTableA);
m_pHuffDecoder->Reset();
m_pArithDecoder->Start();
}
else
{
unSymID = m_pArithDecoder->DecodeIAID(unSymCodeLen, m_pIaidStats);
m_pArithDecoder->DecodeInt(&nRefDX, m_pIardxStats);
m_pArithDecoder->DecodeInt(&nRefDY, m_pIardyStats);
}
JBIG2Bitmap *pRefBitmap = ppBitmaps[unSymID];
ppBitmaps[unNumInputSyms + unI] = ReadGenericRefinementRegion(unSymWidth, unSymHeight, unSDRTemplate, false, pRefBitmap, nRefDX, nRefDY, arrSDRATx, arrSDRATy);
}
else //~ do we need to use the bmSize value here (in Huffman mode)?
{
ppBitmaps[unNumInputSyms + unI] = ReadTextRegion(unHuff ? true : false, true, unSymWidth, unSymHeight, nRefAggNum, 0, unNumInputSyms + unI, NULL, unSymCodeLen, ppBitmaps, 0, 0, 0, 1, 0, c_oHuffTableF, c_oHuffTableH, c_oHuffTableK, c_oHuffTableO, c_oHuffTableO, c_oHuffTableO, c_oHuffTableO, c_oHuffTableA, unSDRTemplate, arrSDRATx, arrSDRATy);
}
}
else // non-ref/agg coding
{
ppBitmaps[unNumInputSyms + unI] = ReadGenericBitmap(false, unSymWidth, unSymHeight, unSDTemplate, false, false, NULL, arrSDATx, arrSDATy, 0);
}
++unI;
}
// read the collective bitmap
if (unHuff && !unRefAgg)
{
int nBMSize;
m_pHuffDecoder->DecodeInt(&nBMSize, pHuffBMSizeTable);
m_pHuffDecoder->Reset();
JBIG2Bitmap *pCollBitmap;
if (nBMSize == 0)
{
pCollBitmap = new JBIG2Bitmap(0, unTotalWidth, unSymHeight);
nBMSize = unSymHeight * ((unTotalWidth + 7) >> 3);
unsigned char *pDataPtr = pCollBitmap->GetDataPtr();
for (unK = 0; unK < (unsigned int)nBMSize; ++unK)
{
*pDataPtr++ = m_pCurStream->GetChar();
}
}
else
{
pCollBitmap = ReadGenericBitmap(true, unTotalWidth, unSymHeight, 0, false, false, NULL, NULL, NULL, nBMSize);
}
unsigned int unX = 0;
for (; unJ < unI; ++unJ)
{
ppBitmaps[unNumInputSyms + unJ] = pCollBitmap->GetSlice(unX, 0, pSymWidths[unJ], unSymHeight);
unX += pSymWidths[unJ];
}
delete pCollBitmap;
}
}
// create the symbol dict object
JBIG2SymbolDict *pSymbolDict = new JBIG2SymbolDict(unSegNum, unNumExSyms);
// exported symbol list
unI = unJ = 0;
bool bEx = false;
while (unI < unNumInputSyms + unNumNewSyms)
{
int nRun;
if (unHuff)
{
m_pHuffDecoder->DecodeInt(&nRun, c_oHuffTableA);
}
else
{
m_pArithDecoder->DecodeInt(&nRun, m_pIaexStats);
}
if (bEx)
{
for (int nCounter = 0; nCounter < nRun; ++nCounter)
{
pSymbolDict->SetBitmap(unJ++, ppBitmaps[unI++]->Copy());
}
}
else
{
unI += nRun;
}
bEx = !bEx;
}
for (unI = 0; unI < unNumNewSyms; ++unI)
{
delete ppBitmaps[unNumInputSyms + unI];
}
MemUtilsFree(ppBitmaps);
if (pSymWidths)
{
MemUtilsFree(pSymWidths);
}
// save the arithmetic decoder stats
if (!unHuff && unContextRetained)
{
pSymbolDict->SetGenericRegionStats(m_pGenericRegionStats->Copy());
if (unRefAgg)
{
pSymbolDict->SetRefinementRegionStats(m_pRefinementRegionStats->Copy());
}
}
// store the new symbol dict
m_pSegments->Append(pSymbolDict);
return true;
}
void JBIG2Stream::ReadTextRegionSegment(unsigned int unSegNum, bool bImm, bool bLossless, unsigned int unLength, unsigned int *punRefSegs, unsigned int unRefSegsCount)
{
// region segment info field
unsigned int unW, unH, unX, unY, unSegInfoFlags;
if (!ReadULong(&unW) || !ReadULong(&unH) || !ReadULong(&unX) || !ReadULong(&unY) || !ReadUByte(&unSegInfoFlags))
{
return;
}
unsigned int unExtCombOp = unSegInfoFlags & 7;
// rest of the text region header
unsigned int unFlags;
if (!ReadUWord(&unFlags))
{
return;
}
unsigned int unHuff = unFlags & 1;
unsigned int unRefine = (unFlags >> 1) & 1;
unsigned int unLogStrips = (unFlags >> 2) & 3;
unsigned int unRefCorner = (unFlags >> 4) & 3;
unsigned int unTransposed = (unFlags >> 6) & 1;
unsigned int unCombOp = (unFlags >> 7) & 3;
unsigned int unDefPixel = (unFlags >> 9) & 1;
int nSOffset = (unFlags >> 10) & 0x1f;
unsigned int unTempl = (unFlags >> 15) & 1;
if (nSOffset & 0x10)
{
nSOffset |= -1 - 0x0f;
}
unsigned int unHuffFS = 0, unHuffDS = 0, unHuffDT = 0, unHuffRDW = 0, unHuffRDH = 0, unHuffRDX = 0, unHuffRDY = 0, unHuffRSize = 0;
if (unHuff)
{
unsigned int unHuffFlags;
if (!ReadUWord(&unHuffFlags))
{
return;
}
unHuffFS = unHuffFlags & 3;
unHuffDS = (unHuffFlags >> 2) & 3;
unHuffDT = (unHuffFlags >> 4) & 3;
unHuffRDW = (unHuffFlags >> 6) & 3;
unHuffRDH = (unHuffFlags >> 8) & 3;
unHuffRDX = (unHuffFlags >> 10) & 3;
unHuffRDY = (unHuffFlags >> 12) & 3;
unHuffRSize = (unHuffFlags >> 14) & 1;
}
int arrATx[2], arrATy[2];
if (unRefine && unTempl == 0)
{
if (!ReadByte(&arrATx[0]) || !ReadByte(&arrATy[0]) || !ReadByte(&arrATx[1]) || !ReadByte(&arrATy[1]))
{
return;
}
}
unsigned int unNumInstances;
if (!ReadULong(&unNumInstances))
{
return;
}
// get symbol dictionaries and tables
CList *pCodeTables = new CList();
unsigned int unNumSyms = 0;
unsigned int unIndex;
for (unIndex = 0; unIndex < unRefSegsCount; ++unIndex)
{
JBIG2Segment *pSegment = NULL;
if ((pSegment = FindSegment(punRefSegs[unIndex])))
{
if (pSegment->GetType() == jbig2SegSymbolDict)
{
unNumSyms += ((JBIG2SymbolDict *)pSegment)->GetSize();
}
else if (pSegment->GetType() == jbig2SegCodeTable)
{
pCodeTables->Append(pSegment);
}
}
else
{
}
}
unsigned int unSymCodeLen = 0;
unIndex = 1;
while (unIndex < unNumSyms)
{
++unSymCodeLen;
unIndex <<= 1;
}
// get the symbol bitmaps
JBIG2Bitmap **ppSyms = (JBIG2Bitmap **)MemUtilsMallocArray(unNumSyms, sizeof(JBIG2Bitmap *));
unsigned int unSymsIndex = 0;
for (unIndex = 0; unIndex < unRefSegsCount; ++unIndex)
{
JBIG2Segment *pSegment = NULL;
if ((pSegment = FindSegment(punRefSegs[unIndex])))
{
if (pSegment->GetType() == jbig2SegSymbolDict)
{
JBIG2SymbolDict *pSymbolDict = (JBIG2SymbolDict *)pSegment;
for (unsigned int unK = 0; unK < pSymbolDict->GetSize(); ++unK)
{
ppSyms[unSymsIndex++] = pSymbolDict->GetBitmap(unK);
}
}
}
}
// get the Huffman tables
JBIG2HuffmanTable *pHuffFSTable = NULL, *pHuffDSTable = NULL, *pHuffDTTable = NULL, *pHuffRDWTable = NULL, *pHuffRDHTable = NULL, *pHuffRDXTable = NULL, *pHuffRDYTable = NULL, *pHuffRSizeTable = NULL;
unIndex = 0;
if (unHuff)
{
if (unHuffFS == 0)
{
pHuffFSTable = c_oHuffTableF;
}
else if (unHuffFS == 1)
{
pHuffFSTable = c_oHuffTableG;
}
else
{
pHuffFSTable = ((JBIG2CodeTable *)pCodeTables->GetByIndex(unIndex++))->GetHuffTable();
}
if (unHuffDS == 0)
{
pHuffDSTable = c_oHuffTableH;
}
else if (unHuffDS == 1)
{
pHuffDSTable = c_oHuffTableI;
}
else if (unHuffDS == 2)
{
pHuffDSTable = c_oHuffTableJ;
}
else
{
pHuffDSTable = ((JBIG2CodeTable *)pCodeTables->GetByIndex(unIndex++))->GetHuffTable();
}
if (unHuffDT == 0)
{
pHuffDTTable = c_oHuffTableK;
}
else if (unHuffDT == 1)
{
pHuffDTTable = c_oHuffTableL;
}
else if (unHuffDT == 2)
{
pHuffDTTable = c_oHuffTableM;
}
else
{
pHuffDTTable = ((JBIG2CodeTable *)pCodeTables->GetByIndex(unIndex++))->GetHuffTable();
}
if (unHuffRDW == 0)
{
pHuffRDWTable = c_oHuffTableN;
}
else if (unHuffRDW == 1)
{
pHuffRDWTable = c_oHuffTableO;
}
else
{
pHuffRDWTable = ((JBIG2CodeTable *)pCodeTables->GetByIndex(unIndex++))->GetHuffTable();
}
if (unHuffRDH == 0)
{
pHuffRDHTable = c_oHuffTableN;
}
else if (unHuffRDH == 1)
{
pHuffRDHTable = c_oHuffTableO;
}
else
{
pHuffRDHTable = ((JBIG2CodeTable *)pCodeTables->GetByIndex(unIndex++))->GetHuffTable();
}
if (unHuffRDX == 0)
{
pHuffRDXTable = c_oHuffTableN;
}
else if (unHuffRDX == 1)
{
pHuffRDXTable = c_oHuffTableO;
}
else
{
pHuffRDXTable = ((JBIG2CodeTable *)pCodeTables->GetByIndex(unIndex++))->GetHuffTable();
}
if (unHuffRDY == 0)
{
pHuffRDYTable = c_oHuffTableN;
}
else if (unHuffRDY == 1)
{
pHuffRDYTable = c_oHuffTableO;
}
else
{
pHuffRDYTable = ((JBIG2CodeTable *)pCodeTables->GetByIndex(unIndex++))->GetHuffTable();
}
if (unHuffRSize == 0)
{
pHuffRSizeTable = c_oHuffTableA;
}
else
{
pHuffRSizeTable = ((JBIG2CodeTable *)pCodeTables->GetByIndex(unIndex++))->GetHuffTable();
}
}
delete pCodeTables;
// symbol ID Huffman decoding table
JBIG2HuffmanTable *pSymCodeTab;
if (unHuff)
{
m_pHuffDecoder->Reset();
JBIG2HuffmanTable arrRunLengthTab[36];
for (unIndex = 0; unIndex < 32; ++unIndex)
{
arrRunLengthTab[unIndex].nValue = unIndex;
arrRunLengthTab[unIndex].unPrefixLen = m_pHuffDecoder->ReadBits(4);
arrRunLengthTab[unIndex].unRangeLen = 0;
}
arrRunLengthTab[32].nValue = 0x103;
arrRunLengthTab[32].unPrefixLen = m_pHuffDecoder->ReadBits(4);
arrRunLengthTab[32].unRangeLen = 2;
arrRunLengthTab[33].nValue = 0x203;
arrRunLengthTab[33].unPrefixLen = m_pHuffDecoder->ReadBits(4);
arrRunLengthTab[33].unRangeLen = 3;
arrRunLengthTab[34].nValue = 0x20b;
arrRunLengthTab[34].unPrefixLen = m_pHuffDecoder->ReadBits(4);
arrRunLengthTab[34].unRangeLen = 7;
arrRunLengthTab[35].unPrefixLen = 0;
arrRunLengthTab[35].unRangeLen = jbig2HuffmanEOT;
m_pHuffDecoder->BuildTable(arrRunLengthTab, 35);
pSymCodeTab = (JBIG2HuffmanTable *)MemUtilsMallocArray(unNumSyms + 1, sizeof(JBIG2HuffmanTable));
for (unIndex = 0; unIndex < unNumSyms; ++unIndex)
{
pSymCodeTab[unIndex].nValue = unIndex;
pSymCodeTab[unIndex].unRangeLen = 0;
}
unIndex = 0;
int nJ;
while (unIndex < unNumSyms)
{
m_pHuffDecoder->DecodeInt(&nJ, arrRunLengthTab);
if (nJ > 0x200)
{
for (nJ -= 0x200; nJ && unIndex < unNumSyms; --nJ)
{
pSymCodeTab[unIndex++].unPrefixLen = 0;
}
}
else if (nJ > 0x100)
{
for (nJ -= 0x100; nJ && unIndex < unNumSyms; --nJ)
{
pSymCodeTab[unIndex].unPrefixLen = pSymCodeTab[unIndex - 1].unPrefixLen;
++unIndex;
}
}
else
{
pSymCodeTab[unIndex++].unPrefixLen = nJ;
}
}
pSymCodeTab[unNumSyms].unPrefixLen = 0;
pSymCodeTab[unNumSyms].unRangeLen = jbig2HuffmanEOT;
m_pHuffDecoder->BuildTable(pSymCodeTab, unNumSyms);
m_pHuffDecoder->Reset();
}
else // set up the arithmetic decoder
{
pSymCodeTab = NULL;
ResetIntStats(unSymCodeLen);
m_pArithDecoder->Start();
}
if (unRefine)
{
ResetRefinementStats(unTempl, NULL);
}
JBIG2Bitmap *pBitmap = ReadTextRegion(unHuff ? true : false, unRefine ? true : false, unW, unH, unNumInstances, unLogStrips, unNumSyms, pSymCodeTab, unSymCodeLen, ppSyms, unDefPixel, unCombOp, unTransposed, unRefCorner, nSOffset, pHuffFSTable, pHuffDSTable, pHuffDTTable, pHuffRDWTable, pHuffRDHTable, pHuffRDXTable, pHuffRDYTable, pHuffRSizeTable, unTempl, arrATx, arrATy);
MemUtilsFree(ppSyms);
// combine the region bitmap into the page bitmap
if (bImm)
{
if (m_unPageH == 0xffffffff && unY + unH > m_unCurPageH)
{
m_pPageBitmap->Expand(unY + unH, m_unPageDefPixel);
}
m_pPageBitmap->Combine(pBitmap, unX, unY, unExtCombOp);
delete pBitmap;
}
else // store the region bitmap
{
pBitmap->SetSegNum(unSegNum);
m_pSegments->Append(pBitmap);
}
// clean up the Huffman decoder
if (unHuff)
{
MemUtilsFree(pSymCodeTab);
}
return;
}
JBIG2Bitmap *JBIG2Stream::ReadTextRegion(bool bHuff, bool bRefine, int nW, int nH, unsigned int unNumInstances, unsigned int unLogStrips, int nNumSyms, JBIG2HuffmanTable *pSymCodeTab, unsigned int unSymCodeLen, JBIG2Bitmap **ppSyms, unsigned int unDefPixel, unsigned int unCombOp, unsigned int transposed, unsigned int refCorner, int nSOffset, JBIG2HuffmanTable *pHuffFSTable, JBIG2HuffmanTable *pHuffDSTable, JBIG2HuffmanTable *pHuffDTTable, JBIG2HuffmanTable *pHuffRDWTable, JBIG2HuffmanTable *pHuffRDHTable, JBIG2HuffmanTable *pHuffRDXTable, JBIG2HuffmanTable *pHuffRDYTable, JBIG2HuffmanTable *pHuffRSizeTable, unsigned int unTempl, int *pnATx, int *pnATy)
{
unsigned int unStrips = 1 << unLogStrips;
// allocate the bitmap
JBIG2Bitmap *pBitmap = new JBIG2Bitmap(0, nW, nH);
if (unDefPixel)
{
pBitmap->ClearToOne();
}
else
{
pBitmap->ClearToZero();
}
// decode initial T value
int nT;
if (bHuff)
{
m_pHuffDecoder->DecodeInt(&nT, pHuffDTTable);
}
else
{
m_pArithDecoder->DecodeInt(&nT, m_pIadtStats);
}
nT *= -(int)unStrips;
unsigned int unInstance = 0;
int nSFirst = 0;
while (unInstance < unNumInstances)
{
// decode delta-T
int nDeltaT;
if (bHuff)
{
m_pHuffDecoder->DecodeInt(&nDeltaT, pHuffDTTable);
}
else
{
m_pArithDecoder->DecodeInt(&nDeltaT, m_pIadtStats);
}
nT += nDeltaT * unStrips;
// first S value
int nDS;
if (bHuff)
{
m_pHuffDecoder->DecodeInt(&nDS, pHuffFSTable);
}
else
{
m_pArithDecoder->DecodeInt(&nDS, m_pIafsStats);
}
nSFirst += nDS;
int nCurS = nSFirst;
// read the instances
while (1)
{
// T value
if (1 == unStrips)
{
nDeltaT = 0;
}
else if (bHuff)
{
nDeltaT = m_pHuffDecoder->ReadBits(unLogStrips);
}
else
{
m_pArithDecoder->DecodeInt(&nDeltaT, m_pIaitStats);
}
int nCurT = nT + nDeltaT;
// symbol ID
unsigned int unSymID;
if (bHuff)
{
if (pSymCodeTab)
{
int nTemp;
m_pHuffDecoder->DecodeInt(&nTemp, pSymCodeTab);
unSymID = (unsigned int)nTemp;
}
else
{
unSymID = m_pHuffDecoder->ReadBits(unSymCodeLen);
}
}
else
{
unSymID = m_pArithDecoder->DecodeIAID(unSymCodeLen, m_pIaidStats);
}
if (unSymID >= (unsigned int)nNumSyms)
{
}
else
{
// get the symbol bitmap
JBIG2Bitmap *pSymbolBitmap = NULL;
int nReadInt;
if (bRefine)
{
if (bHuff)
{
nReadInt = (int)m_pHuffDecoder->ReadBit();
}
else
{
m_pArithDecoder->DecodeInt(&nReadInt, m_pIariStats);
}
}
else
{
nReadInt = 0;
}
if (nReadInt)
{
int nRDW, nRDH, nRDX, nRDY, nBMSize;
if (bHuff)
{
m_pHuffDecoder->DecodeInt(&nRDW, pHuffRDWTable);
m_pHuffDecoder->DecodeInt(&nRDH, pHuffRDHTable);
m_pHuffDecoder->DecodeInt(&nRDX, pHuffRDXTable);
m_pHuffDecoder->DecodeInt(&nRDY, pHuffRDYTable);
m_pHuffDecoder->DecodeInt(&nBMSize, pHuffRSizeTable);
m_pHuffDecoder->Reset();
m_pArithDecoder->Start();
}
else
{
m_pArithDecoder->DecodeInt(&nRDW, m_pIardwStats);
m_pArithDecoder->DecodeInt(&nRDH, m_pIardhStats);
m_pArithDecoder->DecodeInt(&nRDX, m_pIardxStats);
m_pArithDecoder->DecodeInt(&nRDY, m_pIardyStats);
}
int nRefDX = ((nRDW >= 0) ? nRDW : nRDW - 1) / 2 + nRDX;
int nRefDY = ((nRDH >= 0) ? nRDH : nRDH - 1) / 2 + nRDY;
pSymbolBitmap = ReadGenericRefinementRegion(nRDW + ppSyms[unSymID]->GetWidth(), nRDH + ppSyms[unSymID]->GetHeight(), unTempl, false, ppSyms[unSymID], nRefDX, nRefDY, pnATx, pnATy);
}
else //~ do we need to use the bmSize value here (in Huffman mode)?
{
pSymbolBitmap = ppSyms[unSymID];
}
// combine the symbol bitmap into the region bitmap
//~ something is wrong here - refCorner shouldn't degenerate into
//~ two cases
unsigned int unBitmapW = pSymbolBitmap->GetWidth() - 1;
unsigned int unBitmapH = pSymbolBitmap->GetHeight() - 1;
if (transposed)
{
switch (refCorner)
{
case 0: // bottom left
pBitmap->Combine(pSymbolBitmap, nCurT, nCurS, unCombOp);
break;
case 1: // top left
pBitmap->Combine(pSymbolBitmap, nCurT, nCurS, unCombOp);
break;
case 2: // bottom right
pBitmap->Combine(pSymbolBitmap, nCurT - unBitmapW, nCurS, unCombOp);
break;
case 3: // top right
pBitmap->Combine(pSymbolBitmap, nCurT - unBitmapW, nCurS, unCombOp);
break;
}
nCurS += unBitmapH;
}
else
{
switch (refCorner)
{
case 0: // bottom left
pBitmap->Combine(pSymbolBitmap, nCurS, nCurT - unBitmapH, unCombOp);
break;
case 1: // top left
pBitmap->Combine(pSymbolBitmap, nCurS, nCurT, unCombOp);
break;
case 2: // bottom right
pBitmap->Combine(pSymbolBitmap, nCurS, nCurT - unBitmapH, unCombOp);
break;
case 3: // top right
pBitmap->Combine(pSymbolBitmap, nCurS, nCurT, unCombOp);
break;
}
nCurS += unBitmapW;
}
if (nReadInt)
{
delete pSymbolBitmap;
}
}
// next instance
++unInstance;
// next S value
if (bHuff)
{
if (!m_pHuffDecoder->DecodeInt(&nDS, pHuffDSTable))
{
break;
}
}
else
{
if (!m_pArithDecoder->DecodeInt(&nDS, m_pIadsStats))
{
break;
}
}
nCurS += nSOffset + nDS;
}
}
return pBitmap;
}
void JBIG2Stream::ReadPatternDictSegment(unsigned int unSegNum, unsigned int unLength)
{
// halftone dictionary flags, pattern width and height, max gray value
unsigned int unFlags, unPatternW, unPatternH, unGrayMax;
if (!ReadUByte(&unFlags) || !ReadUByte(&unPatternW) || !ReadUByte(&unPatternH) || !ReadULong(&unGrayMax))
{
return;
}
unsigned int unTempl = (unFlags >> 1) & 3;
unsigned int unMMR = unFlags & 1;
// set up the arithmetic decoder
if (!unMMR)
{
ResetGenericStats(unTempl, NULL);
m_pArithDecoder->Start();
}
// read the bitmap
int arrATx[4], arrATy[4];
arrATx[0] = -(int)unPatternW; arrATy[0] = 0;
arrATx[1] = -3; arrATy[1] = -1;
arrATx[2] = 2; arrATy[2] = -2;
arrATx[3] = -2; arrATy[3] = -2;
JBIG2Bitmap *pBitmap = ReadGenericBitmap(unMMR ? true : false, (unGrayMax + 1) * unPatternW, unPatternH, unTempl, false, false, NULL, arrATx, arrATy, unLength - 7);
// create the pattern dict object
JBIG2PatternDict *pPatternDict = new JBIG2PatternDict(unSegNum, unGrayMax + 1);
// split up the bitmap
unsigned int unX = 0;
for (unsigned int unIndex = 0; unIndex <= unGrayMax; ++unIndex)
{
pPatternDict->SetBitmap(unIndex, pBitmap->GetSlice(unX, 0, unPatternW, unPatternH));
unX += unPatternW;
}
// free memory
delete pBitmap;
// store the new pattern dict
m_pSegments->Append(pPatternDict);
return;
}
void JBIG2Stream::ReadHalftoneRegionSegment(unsigned int unSegNum, bool bImm, bool bLossless, unsigned int unLength, unsigned int *punRefSegs, unsigned int unRefSegsCount)
{
// region segment info field
unsigned int unW, unH, unX, unY, unSegInfoFlags;
if (!ReadULong(&unW) || !ReadULong(&unH) || !ReadULong(&unX) || !ReadULong(&unY) || !ReadUByte(&unSegInfoFlags))
{
return;
}
unsigned int unExtCombOp = unSegInfoFlags & 7;
// rest of the halftone region header
unsigned int unFlags;
if (!ReadUByte(&unFlags))
{
return;
}
unsigned int unMMR = unFlags & 1;
unsigned int unTempl = (unFlags >> 1) & 3;
unsigned int unEnableSkip = (unFlags >> 3) & 1;
unsigned int unCombOp = (unFlags >> 4) & 7;
unsigned int unGridW, unGridH, unStepX, unStepY;
int nGridX, nGridY;
if (!ReadULong(&unGridW) || !ReadULong(&unGridH) || !ReadLong(&nGridX) || !ReadLong(&nGridY) || !ReadUWord(&unStepX) || !ReadUWord(&unStepY))
{
return;
}
if (unW == 0 || unH == 0 || unW >= INT_MAX / unH)
{
return;
}
if (unGridH == 0 || unGridW >= INT_MAX / unGridH)
{
return;
}
// get pattern dictionary
if (unRefSegsCount != 1)
{
return;
}
JBIG2Segment *pSegment = FindSegment(punRefSegs[0]);
if (pSegment->GetType() != jbig2SegPatternDict)
{
return;
}
JBIG2PatternDict *pPatternDict = (JBIG2PatternDict *)pSegment;
unsigned int unBPP = 0;
unsigned int unIndex = 1;
while (unIndex < pPatternDict->GetSize())
{
++unBPP;
unIndex <<= 1;
}
unsigned int unPatternW = pPatternDict->GetBitmap(0)->GetWidth();
unsigned int unPatternH = pPatternDict->GetBitmap(0)->GetHeight();
// set up the arithmetic decoder
if (!unMMR)
{
ResetGenericStats(unTempl, NULL);
m_pArithDecoder->Start();
}
// allocate the bitmap
JBIG2Bitmap *pBitmap = new JBIG2Bitmap(unSegNum, unW, unH);
if (unFlags & 0x80) // HDEFPIXEL
{
pBitmap->ClearToOne();
}
else
{
pBitmap->ClearToZero();
}
// compute the skip bitmap
JBIG2Bitmap *pSkipBitmap = NULL;
if (unEnableSkip)
{
pSkipBitmap = new JBIG2Bitmap(0, unGridW, unGridH);
pSkipBitmap->ClearToZero();
for (unsigned int unM = 0; unM < unGridH; ++unM)
{
for (unsigned int unN = 0; unN < unGridW; ++unN)
{
int nCurX = nGridX + unM * unStepY + unN * unStepX;
int nCurY = nGridY + unM * unStepX - unN * unStepY;
if (((nCurX + (int)unPatternW) >> 8) <= 0 || (nCurX >> 8) >= (int)unW || ((nCurY + (int)unPatternH) >> 8) <= 0 || (nCurY >> 8) >= (int)unH)
{
pSkipBitmap->SetPixel(unN, unM);
}
}
}
}
// read the gray-scale image
unsigned int *pGrayImage = (unsigned int *)MemUtilsMallocArray(unGridW * unGridH, sizeof(unsigned int));
memset(pGrayImage, 0, unGridW * unGridH * sizeof(unsigned int));
int arrATx[4], arrATy[4];
arrATx[0] = unTempl <= 1 ? 3 : 2; arrATy[0] = -1;
arrATx[1] = -3; arrATy[1] = -1;
arrATx[2] = 2; arrATy[2] = -2;
arrATx[3] = -2; arrATy[3] = -2;
for (int nBitIndex = unBPP - 1; nBitIndex >= 0; --nBitIndex)
{
JBIG2Bitmap *pGrayBitmap = ReadGenericBitmap(0 != unMMR, unGridW, unGridH, unTempl, false, 0 != unEnableSkip, pSkipBitmap, arrATx, arrATy, -1);
unIndex = 0;
for (unsigned int unM = 0; unM < unGridH; ++unM)
{
for (unsigned int unN = 0; unN < unGridW; ++unN)
{
int nBit = pGrayBitmap->GetPixel(unN, unM) ^ (pGrayImage[unIndex] & 1);
pGrayImage[unIndex] = (pGrayImage[unIndex] << 1) | nBit;
++unIndex;
}
}
delete pGrayBitmap;
}
// decode the image
unIndex = 0;
for (unsigned int unM = 0; unM < unGridH; ++unM)
{
int nCurX = nGridX + unM * unStepY;
int nCurY = nGridY + unM * unStepX;
for (unsigned int unN = 0; unN < unGridW; ++unN)
{
if (!(unEnableSkip && pSkipBitmap->GetPixel(unN, unM)))
{
JBIG2Bitmap *pPatternBitmap = pPatternDict->GetBitmap(pGrayImage[unIndex]);
pBitmap->Combine(pPatternBitmap, nCurX >> 8, nCurY >> 8, unCombOp);
}
nCurX += unStepX;
nCurY -= unStepY;
++unIndex;
}
}
MemUtilsFree(pGrayImage);
if (pSkipBitmap)
{
delete pSkipBitmap;
}
// combine the region bitmap into the page bitmap
if (bImm)
{
if (m_unPageH == 0xffffffff && unY + unH > m_unCurPageH)
{
m_pPageBitmap->Expand(unY + unH, m_unPageDefPixel);
}
m_pPageBitmap->Combine(pBitmap, unX, unY, unExtCombOp);
delete pBitmap;
}
else // store the region bitmap
{
m_pSegments->Append(pBitmap);
}
return;
}
void JBIG2Stream::ReadGenericRegionSegment(unsigned int unSegNum, bool bImm, bool bLossless, unsigned int unLength)
{
// region segment info field
unsigned int unW, unH, unX, unY, unSegInfoFlags;
if (!ReadULong(&unW) || !ReadULong(&unH) || !ReadULong(&unX) || !ReadULong(&unY) || !ReadUByte(&unSegInfoFlags))
{
return;
}
unsigned int unExtCombOp = unSegInfoFlags & 7;
// rest of the generic region segment header
unsigned int unFlags;
if (!ReadUByte(&unFlags))
{
return;
}
unsigned int unMMR = unFlags & 1;
unsigned int unTempl = (unFlags >> 1) & 3;
unsigned int unTpgdOn = (unFlags >> 3) & 1;
// AT flags
int arrATx[4], arrATy[4];
if (!unMMR)
{
if (unTempl == 0)
{
if (!ReadByte(&arrATx[0]) || !ReadByte(&arrATy[0]) || !ReadByte(&arrATx[1]) || !ReadByte(&arrATy[1]) ||
!ReadByte(&arrATx[2]) || !ReadByte(&arrATy[2]) || !ReadByte(&arrATx[3]) || !ReadByte(&arrATy[3]))
{
return;
}
}
else
{
if (!ReadByte(&arrATx[0]) || !ReadByte(&arrATy[0]))
{
return;
}
}
}
// set up the arithmetic decoder
if (!unMMR)
{
ResetGenericStats(unTempl, NULL);
m_pArithDecoder->Start();
}
// read the bitmap
JBIG2Bitmap *pBitmap = ReadGenericBitmap(0 != unMMR, unW, unH, unTempl, 0 != unTpgdOn, false, NULL, arrATx, arrATy, unMMR ? 0 : unLength - 18);
// combine the region bitmap into the page bitmap
if (bImm)
{
if (m_unPageH == 0xffffffff && unY + unH > m_unCurPageH)
{
m_pPageBitmap->Expand(unY + unH, m_unPageDefPixel);
}
m_pPageBitmap->Combine(pBitmap, unX, unY, unExtCombOp);
delete pBitmap;
}
else // store the region bitmap
{
pBitmap->SetSegNum(unSegNum);
m_pSegments->Append(pBitmap);
}
return;
}
JBIG2Bitmap *JBIG2Stream::ReadGenericBitmap(bool bMMR, int nW, int nH, int unTempl, bool bTpgdOn, bool bUseSkip, JBIG2Bitmap *pSkip, int *pnATx, int *pnATy, int nMMrDataLength)
{
JBIG2Bitmap *pBitmap = new JBIG2Bitmap(0, nW, nH);
pBitmap->ClearToZero();
if (bMMR) //----- MMR decode
{
m_pMMrDecoder->Reset();
int *pRefLine = (int *)MemUtilsMallocArray(nW + 2, sizeof(int));
int *pCodingLine = (int *)MemUtilsMallocArray(nW + 2, sizeof(int));
pCodingLine[0] = pCodingLine[1] = nW;
for (int nY = 0; nY < nH; ++nY)
{
// copy coding line to ref line
int nIndex;
for (nIndex = 0; pCodingLine[nIndex] < nW; ++nIndex)
{
pRefLine[nIndex] = pCodingLine[nIndex];
}
pRefLine[nIndex] = pRefLine[nIndex + 1] = nW;
// decode a line
int nRefIndex = 0; // nB1 = pRefLine[refI]
int nCodingIndex = 0; // nA1 = pCodingLine[codingI]
int nA0 = 0;
do
{
int nCode1 = m_pMMrDecoder->Get2DCode();
switch (nCode1)
{
case Pass_2D:
if (pRefLine[nRefIndex] < nW)
{
nA0 = pRefLine[nRefIndex + 1];
nRefIndex += 2;
}
break;
case Horiz_2D:
{
int nCode2, nCode3;
if (nCodingIndex & 1)
{
nCode1 = 0;
do
{
nCode1 += nCode3 = m_pMMrDecoder->GetBlackCode();
} while (nCode3 >= 64);
nCode2 = 0;
do
{
nCode2 += nCode3 = m_pMMrDecoder->GetWhiteCode();
} while (nCode3 >= 64);
}
else
{
nCode1 = 0;
do
{
nCode1 += nCode3 = m_pMMrDecoder->GetWhiteCode();
} while (nCode3 >= 64);
nCode2 = 0;
do
{
nCode2 += nCode3 = m_pMMrDecoder->GetBlackCode();
} while (nCode3 >= 64);
}
if (nCode1 > 0 || nCode2 > 0)
{
nA0 = pCodingLine[nCodingIndex++] = nA0 + nCode1;
nA0 = pCodingLine[nCodingIndex++] = nA0 + nCode2;
while (pRefLine[nRefIndex] <= nA0 && pRefLine[nRefIndex] < nW)
{
nRefIndex += 2;
}
}
}
break;
case Vert0_2D:
nA0 = pCodingLine[nCodingIndex++] = pRefLine[nRefIndex];
if (pRefLine[nRefIndex] < nW)
{
++nRefIndex;
}
break;
case VertR1_2D:
nA0 = pCodingLine[nCodingIndex++] = pRefLine[nRefIndex] + 1;
if (pRefLine[nRefIndex] < nW)
{
++nRefIndex;
while (pRefLine[nRefIndex] <= nA0 && pRefLine[nRefIndex] < nW)
{
nRefIndex += 2;
}
}
break;
case VertR2_2D:
nA0 = pCodingLine[nCodingIndex++] = pRefLine[nRefIndex] + 2;
if (pRefLine[nRefIndex] < nW)
{
++nRefIndex;
while (pRefLine[nRefIndex] <= nA0 && pRefLine[nRefIndex] < nW)
{
nRefIndex += 2;
}
}
break;
case VertR3_2D:
nA0 = pCodingLine[nCodingIndex++] = pRefLine[nRefIndex] + 3;
if (pRefLine[nRefIndex] < nW)
{
++nRefIndex;
while (pRefLine[nRefIndex] <= nA0 && pRefLine[nRefIndex] < nW)
{
nRefIndex += 2;
}
}
break;
case VertL1_2D:
nA0 = pCodingLine[nCodingIndex++] = pRefLine[nRefIndex] - 1;
if (nRefIndex > 0)
{
--nRefIndex;
}
else
{
++nRefIndex;
}
while (pRefLine[nRefIndex] <= nA0 && pRefLine[nRefIndex] < nW)
{
nRefIndex += 2;
}
break;
case VertL2_2D:
nA0 = pCodingLine[nCodingIndex++] = pRefLine[nRefIndex] - 2;
if (nRefIndex > 0)
{
--nRefIndex;
}
else
{
++nRefIndex;
}
while (pRefLine[nRefIndex] <= nA0 && pRefLine[nRefIndex] < nW)
{
nRefIndex += 2;
}
break;
case VertL3_2D:
nA0 = pCodingLine[nCodingIndex++] = pRefLine[nRefIndex] - 3;
if (nRefIndex > 0)
{
--nRefIndex;
}
else
{
++nRefIndex;
}
while (pRefLine[nRefIndex] <= nA0 && pRefLine[nRefIndex] < nW)
{
nRefIndex += 2;
}
break;
default:
break;
}
} while (nA0 < nW);
pCodingLine[nCodingIndex++] = nW;
// convert the run lengths to a bitmap line
nIndex = 0;
while (pCodingLine[nIndex] < nW)
{
for (int nX = pCodingLine[nIndex]; nX < pCodingLine[nIndex + 1]; ++nX)
{
pBitmap->SetPixel(nX, nY);
}
nIndex += 2;
}
}
if (nMMrDataLength >= 0)
{
m_pMMrDecoder->SkipTo(nMMrDataLength);
}
else
{
if (m_pMMrDecoder->Get24Bits() != 0x001001)
{
}
}
MemUtilsFree(pRefLine);
MemUtilsFree(pCodingLine);
}
else //----- arithmetic decode
{
// set up the typical row context
unsigned int unLtpCX = 0;
if (bTpgdOn)
{
switch (unTempl)
{
case 0:
unLtpCX = 0x3953; // 001 11001 0101 0011
break;
case 1:
unLtpCX = 0x079a; // 0011 11001 101 0
break;
case 2:
unLtpCX = 0x0e3; // 001 1100 01 1
break;
case 3:
unLtpCX = 0x18a; // 01100 0101 1
break;
}
}
bool bLtp = 0;
unsigned int unCX = 0, unCX0 = 0, unCX1 = 0, unCX2 = 0;
JBIG2BitmapPtr oCXPtr0, oCXPtr1;
JBIG2BitmapPtr oATPtr0, oATPtr1, oATPtr2, oATPtr3;
for (int nY = 0; nY < nH; ++nY)
{
// check for a "typical" (duplicate) row
if (bTpgdOn)
{
if (m_pArithDecoder->DecodeBit(unLtpCX, m_pGenericRegionStats))
{
bLtp = !bLtp;
}
if (bLtp)
{
pBitmap->DuplicateRow(nY, nY - 1);
continue;
}
}
switch (unTempl)
{
case 0:
// set up the context
pBitmap->GetPixelPtr(0, nY - 2, &oCXPtr0);
unCX0 = pBitmap->NextPixel(&oCXPtr0);
unCX0 = (unCX0 << 1) | pBitmap->NextPixel(&oCXPtr0);
pBitmap->GetPixelPtr(0, nY - 1, &oCXPtr1);
unCX1 = pBitmap->NextPixel(&oCXPtr1);
unCX1 = (unCX1 << 1) | pBitmap->NextPixel(&oCXPtr1);
unCX1 = (unCX1 << 1) | pBitmap->NextPixel(&oCXPtr1);
unCX2 = 0;
pBitmap->GetPixelPtr(pnATx[0], nY + pnATy[0], &oATPtr0);
pBitmap->GetPixelPtr(pnATx[1], nY + pnATy[1], &oATPtr1);
pBitmap->GetPixelPtr(pnATx[2], nY + pnATy[2], &oATPtr2);
pBitmap->GetPixelPtr(pnATx[3], nY + pnATy[3], &oATPtr3);
// decode the row
for (int nX = 0; nX < nW; ++nX)
{
// build the context
unCX = (unCX0 << 13) | (unCX1 << 8) | (unCX2 << 4) | (pBitmap->NextPixel(&oATPtr0) << 3) | (pBitmap->NextPixel(&oATPtr1) << 2) | (pBitmap->NextPixel(&oATPtr2) << 1) | pBitmap->NextPixel(&oATPtr3);
int nPixel;
if (bUseSkip && pSkip->GetPixel(nX, nY)) // check for a skipped pixel
{
nPixel = 0;
}
else if ((nPixel = m_pArithDecoder->DecodeBit(unCX, m_pGenericRegionStats))) // decode the pixel
{
pBitmap->SetPixel(nX, nY);
}
// update the context
unCX0 = ((unCX0 << 1) | pBitmap->NextPixel(&oCXPtr0)) & 0x07;
unCX1 = ((unCX1 << 1) | pBitmap->NextPixel(&oCXPtr1)) & 0x1f;
unCX2 = ((unCX2 << 1) | nPixel) & 0x0f;
}
break;
case 1:
// set up the context
pBitmap->GetPixelPtr(0, nY - 2, &oCXPtr0);
unCX0 = pBitmap->NextPixel(&oCXPtr0);
unCX0 = (unCX0 << 1) | pBitmap->NextPixel(&oCXPtr0);
unCX0 = (unCX0 << 1) | pBitmap->NextPixel(&oCXPtr0);
pBitmap->GetPixelPtr(0, nY - 1, &oCXPtr1);
unCX1 = pBitmap->NextPixel(&oCXPtr1);
unCX1 = (unCX1 << 1) | pBitmap->NextPixel(&oCXPtr1);
unCX1 = (unCX1 << 1) | pBitmap->NextPixel(&oCXPtr1);
unCX2 = 0;
pBitmap->GetPixelPtr(pnATx[0], nY + pnATy[0], &oATPtr0);
// decode the row
for (int nX = 0; nX < nW; ++nX)
{
// build the context
unCX = (unCX0 << 9) | (unCX1 << 4) | (unCX2 << 1) | pBitmap->NextPixel(&oATPtr0);
int nPixel;
if (bUseSkip && pSkip->GetPixel(nX, nY)) // check for a skipped pixel
{
nPixel = 0;
}
else if ((nPixel = m_pArithDecoder->DecodeBit(unCX, m_pGenericRegionStats))) // decode the pixel
{
pBitmap->SetPixel(nX, nY);
}
// update the context
unCX0 = ((unCX0 << 1) | pBitmap->NextPixel(&oCXPtr0)) & 0x0f;
unCX1 = ((unCX1 << 1) | pBitmap->NextPixel(&oCXPtr1)) & 0x1f;
unCX2 = ((unCX2 << 1) | nPixel) & 0x07;
}
break;
case 2:
// set up the context
pBitmap->GetPixelPtr(0, nY - 2, &oCXPtr0);
unCX0 = pBitmap->NextPixel(&oCXPtr0);
unCX0 = (unCX0 << 1) | pBitmap->NextPixel(&oCXPtr0);
pBitmap->GetPixelPtr(0, nY - 1, &oCXPtr1);
unCX1 = pBitmap->NextPixel(&oCXPtr1);
unCX1 = (unCX1 << 1) | pBitmap->NextPixel(&oCXPtr1);
unCX2 = 0;
pBitmap->GetPixelPtr(pnATx[0], nY + pnATy[0], &oATPtr0);
// decode the row
for (int nX = 0; nX < nW; ++nX)
{
// build the context
unCX = (unCX0 << 7) | (unCX1 << 3) | (unCX2 << 1) | pBitmap->NextPixel(&oATPtr0);
int nPixel;
if (bUseSkip && pSkip->GetPixel(nX, nY)) // check for a skipped pixel
{
nPixel = 0;
}
else if ((nPixel = m_pArithDecoder->DecodeBit(unCX, m_pGenericRegionStats))) // decode the pixel
{
pBitmap->SetPixel(nX, nY);
}
// update the context
unCX0 = ((unCX0 << 1) | pBitmap->NextPixel(&oCXPtr0)) & 0x07;
unCX1 = ((unCX1 << 1) | pBitmap->NextPixel(&oCXPtr1)) & 0x0f;
unCX2 = ((unCX2 << 1) | nPixel) & 0x03;
}
break;
case 3:
// set up the context
pBitmap->GetPixelPtr(0, nY - 1, &oCXPtr1);
unCX1 = pBitmap->NextPixel(&oCXPtr1);
unCX1 = (unCX1 << 1) | pBitmap->NextPixel(&oCXPtr1);
unCX2 = 0;
pBitmap->GetPixelPtr(pnATx[0], nY + pnATy[0], &oATPtr0);
// decode the row
for (int nX = 0; nX < nW; ++nX)
{
// build the context
unCX = (unCX1 << 5) | (unCX2 << 1) | pBitmap->NextPixel(&oATPtr0);
int nPixel;
if (bUseSkip && pSkip->GetPixel(nX, nY)) // check for a skipped pixel
{
nPixel = 0;
}
else if ((nPixel = m_pArithDecoder->DecodeBit(unCX, m_pGenericRegionStats))) // decode the pixel
{
pBitmap->SetPixel(nX, nY);
}
// update the context
unCX1 = ((unCX1 << 1) | pBitmap->NextPixel(&oCXPtr1)) & 0x1f;
unCX2 = ((unCX2 << 1) | nPixel) & 0x0f;
}
break;
}
}
}
return pBitmap;
}
void JBIG2Stream::ReadGenericRefinementRegionSegment(unsigned int unSegNum, bool bImm, bool bLossless, unsigned int unLength, unsigned int *punRefSegs, unsigned int unRefSegsCount)
{
unsigned int unW, unH, unX, unY, unSegInfoFlags;
// region segment info field
if (!ReadULong(&unW) || !ReadULong(&unH) || !ReadULong(&unX) || !ReadULong(&unY) || !ReadUByte(&unSegInfoFlags))
{
return;
}
unsigned int unExtCombOp = unSegInfoFlags & 7;
// rest of the generic refinement region segment header
unsigned int unFlags;
if (!ReadUByte(&unFlags))
{
return;
}
unsigned int unTempl = unFlags & 1;
unsigned int unTpgrOn = (unFlags >> 1) & 1;
// AT flags
int arrATx[2], arrATy[2];
if (!unTempl)
{
if (!ReadByte(&arrATx[0]) || !ReadByte(&arrATy[0]) || !ReadByte(&arrATx[1]) || !ReadByte(&arrATy[1]))
{
return;
}
}
// resize the page bitmap if needed
if (unRefSegsCount == 0 || bImm)
{
if (m_unPageH == 0xffffffff && unY + unH > m_unCurPageH)
{
m_pPageBitmap->Expand(unY + unH, m_unPageDefPixel);
}
}
// get referenced bitmap
JBIG2Bitmap *pRefBitmap = NULL;
if (unRefSegsCount > 1)
{
return;
}
if (unRefSegsCount == 1)
{
JBIG2Segment *pSegment = FindSegment(punRefSegs[0]);
if (pSegment->GetType() != jbig2SegBitmap)
{
return;
}
pRefBitmap = (JBIG2Bitmap *)pSegment;
}
else
{
pRefBitmap = m_pPageBitmap->GetSlice(unX, unY, unW, unH);
}
// set up the arithmetic decoder
ResetRefinementStats(unTempl, NULL);
m_pArithDecoder->Start();
// read
JBIG2Bitmap *pBitmap = ReadGenericRefinementRegion(unW, unH, unTempl, 0 != unTpgrOn, pRefBitmap, 0, 0, arrATx, arrATy);
if (bImm) // combine the region bitmap into the page bitmap
{
m_pPageBitmap->Combine(pBitmap, unX, unY, unExtCombOp);
delete pBitmap;
}
else // store the region bitmap
{
pBitmap->SetSegNum(unSegNum);
m_pSegments->Append(pBitmap);
}
// delete the referenced bitmap
if (unRefSegsCount == 1)
{
DiscardSegment(punRefSegs[0]);
}
else
{
delete pRefBitmap;
}
return;
}
JBIG2Bitmap *JBIG2Stream::ReadGenericRefinementRegion(int nW, int nH, int nTempl, bool bTpgrOn, JBIG2Bitmap *pRefBitmap, int nRefDX, int nRefDY, int *pnAtx, int *pnAty)
{
JBIG2Bitmap *pBitmap = new JBIG2Bitmap(0, nW, nH);
pBitmap->ClearToZero();
// Typical row context
unsigned int unLtpCX;
if (nTempl)
{
unLtpCX = 0x008;
}
else
{
unLtpCX = 0x0010;
}
bool bLtp = 0;
unsigned int unCx0, unCx2, unCx3, unCx4;
JBIG2BitmapPtr oCxPtr0, oCxPtr1, oCxPtr2, oCxPtr3, oCxPtr4, oCxPtr5, oCxPtr6;
for (int nY = 0; nY < nH; ++nY)
{
if (nTempl)
{
// set up the context
pBitmap->GetPixelPtr(0, nY - 1, &oCxPtr0);
unCx0 = pBitmap->NextPixel(&oCxPtr0);
pBitmap->GetPixelPtr(-1, nY, &oCxPtr1);
pRefBitmap->GetPixelPtr(-nRefDX, nY - 1 - nRefDY, &oCxPtr2);
pRefBitmap->GetPixelPtr(-1 - nRefDX, nY - nRefDY, &oCxPtr3);
unCx3 = pRefBitmap->NextPixel(&oCxPtr3);
unCx3 = (unCx3 << 1) | pRefBitmap->NextPixel(&oCxPtr3);
pRefBitmap->GetPixelPtr(-nRefDX, nY + 1 - nRefDY, &oCxPtr4);
unCx4 = pRefBitmap->NextPixel(&oCxPtr4);
// set up the typical prediction context
unsigned int unTpgrCX0 = 0, unTpgrCX1 = 0, unTpgrCX2 = 0;
JBIG2BitmapPtr oTpgrCXPtr0, oTpgrCXPtr1, oTpgrCXPtr2;
if (bTpgrOn)
{
pRefBitmap->GetPixelPtr(-1 - nRefDX, nY - 1 - nRefDY, &oTpgrCXPtr0);
unTpgrCX0 = pRefBitmap->NextPixel(&oTpgrCXPtr0);
unTpgrCX0 = (unTpgrCX0 << 1) | pRefBitmap->NextPixel(&oTpgrCXPtr0);
unTpgrCX0 = (unTpgrCX0 << 1) | pRefBitmap->NextPixel(&oTpgrCXPtr0);
pRefBitmap->GetPixelPtr(-1 - nRefDX, nY - nRefDY, &oTpgrCXPtr1);
unTpgrCX1 = pRefBitmap->NextPixel(&oTpgrCXPtr1);
unTpgrCX1 = (unTpgrCX1 << 1) | pRefBitmap->NextPixel(&oTpgrCXPtr1);
unTpgrCX1 = (unTpgrCX1 << 1) | pRefBitmap->NextPixel(&oTpgrCXPtr1);
pRefBitmap->GetPixelPtr(-1 - nRefDX, nY + 1 - nRefDY, &oTpgrCXPtr2);
unTpgrCX2 = pRefBitmap->NextPixel(&oTpgrCXPtr2);
unTpgrCX2 = (unTpgrCX2 << 1) | pRefBitmap->NextPixel(&oTpgrCXPtr2);
unTpgrCX2 = (unTpgrCX2 << 1) | pRefBitmap->NextPixel(&oTpgrCXPtr2);
}
for (int nX = 0; nX < nW; ++nX)
{
// update the context
unCx0 = ((unCx0 << 1) | pBitmap->NextPixel(&oCxPtr0)) & 7;
unCx3 = ((unCx3 << 1) | pRefBitmap->NextPixel(&oCxPtr3)) & 7;
unCx4 = ((unCx4 << 1) | pRefBitmap->NextPixel(&oCxPtr4)) & 3;
if (bTpgrOn)
{
// update the typical predictor context
unTpgrCX0 = ((unTpgrCX0 << 1) | pRefBitmap->NextPixel(&oTpgrCXPtr0)) & 7;
unTpgrCX1 = ((unTpgrCX1 << 1) | pRefBitmap->NextPixel(&oTpgrCXPtr1)) & 7;
unTpgrCX2 = ((unTpgrCX2 << 1) | pRefBitmap->NextPixel(&oTpgrCXPtr2)) & 7;
// check for a "typical" pixel
if (m_pArithDecoder->DecodeBit(unLtpCX, m_pRefinementRegionStats))
{
bLtp = !bLtp;
}
if (unTpgrCX0 == 0 && unTpgrCX1 == 0 && unTpgrCX2 == 0)
{
pBitmap->ClearPixel(nX, nY);
continue;
}
else if (unTpgrCX0 == 7 && unTpgrCX1 == 7 && unTpgrCX2 == 7)
{
pBitmap->SetPixel(nX, nY);
continue;
}
}
// build the context
unsigned int unCx = (unCx0 << 7) | (pBitmap->NextPixel(&oCxPtr1) << 6) | (pRefBitmap->NextPixel(&oCxPtr2) << 5) | (unCx3 << 2) | unCx4;
// decode the pixel
int nPix;
if ((nPix = m_pArithDecoder->DecodeBit(unCx, m_pRefinementRegionStats)))
{
pBitmap->SetPixel(nX, nY);
}
}
}
else
{
// set up the context
pBitmap->GetPixelPtr(0, nY - 1, &oCxPtr0);
unCx0 = pBitmap->NextPixel(&oCxPtr0);
pBitmap->GetPixelPtr(-1, nY, &oCxPtr1);
pRefBitmap->GetPixelPtr(-nRefDX, nY - 1 - nRefDY, &oCxPtr2);
unCx2 = pRefBitmap->NextPixel(&oCxPtr2);
pRefBitmap->GetPixelPtr(-1 - nRefDX, nY - nRefDY, &oCxPtr3);
unCx3 = pRefBitmap->NextPixel(&oCxPtr3);
unCx3 = (unCx3 << 1) | pRefBitmap->NextPixel(&oCxPtr3);
pRefBitmap->GetPixelPtr(-1 - nRefDX, nY + 1 - nRefDY, &oCxPtr4);
unCx4 = pRefBitmap->NextPixel(&oCxPtr4);
unCx4 = (unCx4 << 1) | pRefBitmap->NextPixel(&oCxPtr4);
pBitmap->GetPixelPtr(pnAtx[0], nY + pnAty[0], &oCxPtr5);
pRefBitmap->GetPixelPtr(pnAtx[1] - nRefDX, nY + pnAty[1] - nRefDY, &oCxPtr6);
// set up the typical prediction context
unsigned int unTpgrCX0 = 0, unTpgrCX1 = 0, unTpgrCX2 = 0;
JBIG2BitmapPtr oTpgrCXPtr0, oTpgrCXPtr1, oTpgrCXPtr2;
if (bTpgrOn)
{
pRefBitmap->GetPixelPtr(-1 - nRefDX, nY - 1 - nRefDY, &oTpgrCXPtr0);
unTpgrCX0 = pRefBitmap->NextPixel(&oTpgrCXPtr0);
unTpgrCX0 = (unTpgrCX0 << 1) | pRefBitmap->NextPixel(&oTpgrCXPtr0);
unTpgrCX0 = (unTpgrCX0 << 1) | pRefBitmap->NextPixel(&oTpgrCXPtr0);
pRefBitmap->GetPixelPtr(-1 - nRefDX, nY - nRefDY, &oTpgrCXPtr1);
unTpgrCX1 = pRefBitmap->NextPixel(&oTpgrCXPtr1);
unTpgrCX1 = (unTpgrCX1 << 1) | pRefBitmap->NextPixel(&oTpgrCXPtr1);
unTpgrCX1 = (unTpgrCX1 << 1) | pRefBitmap->NextPixel(&oTpgrCXPtr1);
pRefBitmap->GetPixelPtr(-1 - nRefDX, nY + 1 - nRefDY, &oTpgrCXPtr2);
unTpgrCX2 = pRefBitmap->NextPixel(&oTpgrCXPtr2);
unTpgrCX2 = (unTpgrCX2 << 1) | pRefBitmap->NextPixel(&oTpgrCXPtr2);
unTpgrCX2 = (unTpgrCX2 << 1) | pRefBitmap->NextPixel(&oTpgrCXPtr2);
}
for (int nX = 0; nX < nW; ++nX)
{
// update the context
unCx0 = ((unCx0 << 1) | pBitmap->NextPixel(&oCxPtr0)) & 3;
unCx2 = ((unCx2 << 1) | pRefBitmap->NextPixel(&oCxPtr2)) & 3;
unCx3 = ((unCx3 << 1) | pRefBitmap->NextPixel(&oCxPtr3)) & 7;
unCx4 = ((unCx4 << 1) | pRefBitmap->NextPixel(&oCxPtr4)) & 7;
if (bTpgrOn)
{
// update the typical predictor context
unTpgrCX0 = ((unTpgrCX0 << 1) | pRefBitmap->NextPixel(&oTpgrCXPtr0)) & 7;
unTpgrCX1 = ((unTpgrCX1 << 1) | pRefBitmap->NextPixel(&oTpgrCXPtr1)) & 7;
unTpgrCX2 = ((unTpgrCX2 << 1) | pRefBitmap->NextPixel(&oTpgrCXPtr2)) & 7;
// check for a "typical" pixel
if (m_pArithDecoder->DecodeBit(unLtpCX, m_pRefinementRegionStats))
{
bLtp = !bLtp;
}
if (unTpgrCX0 == 0 && unTpgrCX1 == 0 && unTpgrCX2 == 0)
{
pBitmap->ClearPixel(nX, nY);
continue;
}
else if (unTpgrCX0 == 7 && unTpgrCX1 == 7 && unTpgrCX2 == 7)
{
pBitmap->SetPixel(nX, nY);
continue;
}
}
// build the context
unsigned int unCx = (unCx0 << 11) | (pBitmap->NextPixel(&oCxPtr1) << 10) | (unCx2 << 8) | (unCx3 << 5) | (unCx4 << 2) | (pBitmap->NextPixel(&oCxPtr5) << 1) | pRefBitmap->NextPixel(&oCxPtr6);
// decode the pixel
int nPix;
if ((nPix = m_pArithDecoder->DecodeBit(unCx, m_pRefinementRegionStats)))
{
pBitmap->SetPixel(nX, nY);
}
}
}
}
return pBitmap;
}
void JBIG2Stream::ReadPageInfoSegment(unsigned int unLength)
{
unsigned int unResX, unResY, unFlags, unStriping;
if (!ReadULong(&m_unPageW) || !ReadULong(&m_unPageH) || !ReadULong(&unResX) || !ReadULong(&unResY) || !ReadUByte(&unFlags) || !ReadUWord(&unStriping))
{
return;
}
m_unPageDefPixel = (unFlags >> 2) & 1;
m_unDefCombOp = (unFlags >> 3) & 3;
if (0xffffffff == m_unPageH)
{
m_unCurPageH = unStriping & 0x7fff;
}
else
{
m_unCurPageH = m_unPageH;
}
m_pPageBitmap = new JBIG2Bitmap(0, m_unPageW, m_unPageH);
// Очищаем картинку
if (m_unPageDefPixel)
{
m_pPageBitmap->ClearToOne();
}
else
{
m_pPageBitmap->ClearToZero();
}
return;
}
void JBIG2Stream::ReadEndOfStripeSegment(unsigned int unLength)
{
// Пропускаем данный сегмент
for (unsigned int unIndex = 0; unIndex < unLength; ++unIndex)
{
m_pCurStream->GetChar();
}
}
void JBIG2Stream::ReadProfilesSegment(unsigned int unLength)
{
// Пропускаем данный сегмент
for (unsigned int unIndex = 0; unIndex < unLength; ++unIndex)
{
m_pCurStream->GetChar();
}
}
void JBIG2Stream::ReadCodeTableSegment(unsigned int unSegNum, unsigned int unLength)
{
unsigned int unFlags;
int nLowVal, nHighVal;
if (!ReadUByte(&unFlags) || !ReadLong(&nLowVal) || !ReadLong(&nHighVal))
{
return;
}
unsigned int unOOB = unFlags & 1;
unsigned int unPrefixBits = ((unFlags >> 1) & 7) + 1;
unsigned int unRangeBits = ((unFlags >> 4) & 7) + 1;
m_pHuffDecoder->Reset();
unsigned int unHuffTabSize = 8;
JBIG2HuffmanTable *pHuffTable = (JBIG2HuffmanTable *)MemUtilsMallocArray(unHuffTabSize, sizeof(JBIG2HuffmanTable));
unsigned int unIndex = 0;
int nVal = nLowVal;
while (nVal < nHighVal)
{
if (unIndex == unHuffTabSize)
{
unHuffTabSize *= 2;
pHuffTable = (JBIG2HuffmanTable *)MemUtilsReallocArray(pHuffTable, unHuffTabSize, sizeof(JBIG2HuffmanTable));
}
pHuffTable[unIndex].nValue = nVal;
pHuffTable[unIndex].unPrefixLen = m_pHuffDecoder->ReadBits(unPrefixBits);
pHuffTable[unIndex].unRangeLen = m_pHuffDecoder->ReadBits(unRangeBits);
nVal += 1 << pHuffTable[unIndex].unRangeLen;
++unIndex;
}
if (unIndex + unOOB + 3 > unHuffTabSize)
{
unHuffTabSize = unIndex + unOOB + 3;
pHuffTable = (JBIG2HuffmanTable *)MemUtilsReallocArray(pHuffTable, unHuffTabSize, sizeof(JBIG2HuffmanTable));
}
pHuffTable[unIndex].nValue = nLowVal - 1;
pHuffTable[unIndex].unPrefixLen = m_pHuffDecoder->ReadBits(unPrefixBits);
pHuffTable[unIndex].unRangeLen = jbig2HuffmanLOW;
++unIndex;
pHuffTable[unIndex].nValue = nHighVal;
pHuffTable[unIndex].unPrefixLen = m_pHuffDecoder->ReadBits(unPrefixBits);
pHuffTable[unIndex].unRangeLen = 32;
++unIndex;
if (unOOB)
{
pHuffTable[unIndex].nValue = 0;
pHuffTable[unIndex].unPrefixLen = m_pHuffDecoder->ReadBits(unPrefixBits);
pHuffTable[unIndex].unRangeLen = jbig2HuffmanOOB;
++unIndex;
}
pHuffTable[unIndex].nValue = 0;
pHuffTable[unIndex].unPrefixLen = 0;
pHuffTable[unIndex].unRangeLen = jbig2HuffmanEOT;
m_pHuffDecoder->BuildTable(pHuffTable, unIndex);
// Создаем и сохраняем новый сегмент таблицы
m_pSegments->Append(new JBIG2CodeTable(unSegNum, pHuffTable));
return;
}
void JBIG2Stream::ReadExtensionSegment(unsigned int unLength)
{
// Пропускаем данный сегмент
for (unsigned int unIndex = 0; unIndex < unLength; ++unIndex)
{
m_pCurStream->GetChar();
}
}
JBIG2Segment *JBIG2Stream::FindSegment(unsigned int unSegNum)
{
JBIG2Segment *pSegment = NULL;
for (int nIndex = 0; nIndex < m_pGlobalSegments->GetLength(); ++nIndex)
{
pSegment = (JBIG2Segment *)m_pGlobalSegments->GetByIndex(nIndex);
if (pSegment->GetSegNum() == unSegNum)
{
return pSegment;
}
}
for (int nIndex = 0; nIndex < m_pSegments->GetLength(); ++nIndex)
{
pSegment = (JBIG2Segment *)m_pSegments->GetByIndex(nIndex);
if (pSegment->GetSegNum() == unSegNum)
{
return pSegment;
}
}
return NULL;
}
void JBIG2Stream::DiscardSegment(unsigned int unSegNum)
{
JBIG2Segment *pSegment = NULL;
for (int nIndex = 0; nIndex < m_pGlobalSegments->GetLength(); ++nIndex)
{
pSegment = (JBIG2Segment *)m_pGlobalSegments->GetByIndex(nIndex);
if (pSegment->GetSegNum() == unSegNum)
{
m_pGlobalSegments->Delete(nIndex);
return;
}
}
for (int nIndex = 0; nIndex < m_pSegments->GetLength(); ++nIndex)
{
pSegment = (JBIG2Segment *)m_pSegments->GetByIndex(nIndex);
if (pSegment->GetSegNum() == unSegNum)
{
m_pSegments->Delete(nIndex);
return;
}
}
}
void JBIG2Stream::ResetGenericStats(unsigned int unTempl, JArithmeticDecoderStats *pPrevStats)
{
int nSize = c_arrContextSize[unTempl];
if (pPrevStats && pPrevStats->GetContextSize() == nSize)
{
if (m_pGenericRegionStats->GetContextSize() == nSize)
{
m_pGenericRegionStats->CopyFrom(pPrevStats);
}
else
{
delete m_pGenericRegionStats;
m_pGenericRegionStats = pPrevStats->Copy();
}
}
else
{
if (m_pGenericRegionStats->GetContextSize() == nSize)
{
m_pGenericRegionStats->Reset();
}
else
{
delete m_pGenericRegionStats;
m_pGenericRegionStats = new JArithmeticDecoderStats(1 << nSize);
}
}
}
void JBIG2Stream::ResetRefinementStats(unsigned int unTempl, JArithmeticDecoderStats *pPrevStats)
{
int nSize = c_arrRefContextSize[unTempl];
if (pPrevStats && pPrevStats->GetContextSize() == nSize)
{
if (m_pRefinementRegionStats->GetContextSize() == nSize)
{
m_pRefinementRegionStats->CopyFrom(pPrevStats);
}
else
{
delete m_pRefinementRegionStats;
m_pRefinementRegionStats = pPrevStats->Copy();
}
}
else
{
if (m_pRefinementRegionStats->GetContextSize() == nSize)
{
m_pRefinementRegionStats->Reset();
}
else
{
delete m_pRefinementRegionStats;
m_pRefinementRegionStats = new JArithmeticDecoderStats(1 << nSize);
}
}
}
void JBIG2Stream::ResetIntStats(int nSymCodeLen)
{
m_pIadhStats->Reset();
m_pIadwStats->Reset();
m_pIaexStats->Reset();
m_pIaaiStats->Reset();
m_pIadtStats->Reset();
m_pIaitStats->Reset();
m_pIafsStats->Reset();
m_pIadsStats->Reset();
m_pIardxStats->Reset();
m_pIardyStats->Reset();
m_pIardwStats->Reset();
m_pIardhStats->Reset();
m_pIariStats->Reset();
if (m_pIaidStats->GetContextSize() == 1 << (nSymCodeLen + 1))
{
m_pIaidStats->Reset();
}
else
{
delete m_pIaidStats;
m_pIaidStats = new JArithmeticDecoderStats(1 << (nSymCodeLen + 1));
}
}
bool JBIG2Stream::ReadUByte(unsigned int *pBuffer)
{
int nChar;
if (EOF == (nChar = m_pCurStream->GetChar()))
{
return false;
}
*pBuffer = (unsigned int)nChar;
return true;
}
bool JBIG2Stream::ReadByte(int *pBuffer)
{
int nChar;
if (EOF == (nChar = m_pCurStream->GetChar()))
{
return false;
}
*pBuffer = nChar;
if (nChar & 0x80)
{
*pBuffer |= -1 - 0xff;
}
return true;
}
bool JBIG2Stream::ReadUWord(unsigned int *pBuffer)
{
int nChar0, nChar1;
if (EOF == (nChar0 = m_pCurStream->GetChar()) || EOF == (nChar1 = m_pCurStream->GetChar()))
{
return false;
}
*pBuffer = (unsigned int)((nChar0 << 8) | nChar1);
return true;
}
bool JBIG2Stream::ReadULong(unsigned int *pBuffer)
{
int nChar0, nChar1, nChar2, nChar3;
if (EOF == (nChar0 = m_pCurStream->GetChar()) || EOF == (nChar1 = m_pCurStream->GetChar()) ||
EOF == (nChar2 = m_pCurStream->GetChar()) || EOF == (nChar3 = m_pCurStream->GetChar()))
{
return false;
}
*pBuffer = (unsigned int)((nChar0 << 24) | (nChar1 << 16) | (nChar2 << 8) | nChar3);
return true;
}
bool JBIG2Stream::ReadLong(int *pBuffer)
{
int nChar0, nChar1, nChar2, nChar3;
if (EOF == (nChar0 = m_pCurStream->GetChar()) || EOF == (nChar1 = m_pCurStream->GetChar()) ||
EOF == (nChar2 = m_pCurStream->GetChar()) || EOF == (nChar3 = m_pCurStream->GetChar()))
{
return false;
}
*pBuffer = ((nChar0 << 24) | (nChar1 << 16) | (nChar2 << 8) | nChar3);
if (nChar0 & 0x80)
{
*pBuffer |= -1 - (int)0xffffffff;
}
return true;
}
}