blob: c66c2ebaea739b9a3059f0e8d3753d740eede183 [file] [log] [blame]
// Copyright 2014 PDFium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
#include <map>
#include <list>
#include "JBig2_Context.h"
// Implement a very small least recently used (LRU) cache. It is very
// common for a JBIG2 dictionary to span multiple pages in a PDF file,
// and we do not want to decode the same dictionary over and over
// again. We key off of the memory location of the dictionary. The
// list keeps track of the freshness of entries, with freshest ones
// at the front. Even a tiny cache size like 2 makes a dramatic
// difference for typical JBIG2 documents.
const int kSymbolDictCacheMaxSize = 2;
CJBig2_Context* CJBig2_Context::CreateContext(
CJBig2_Module* pModule,
uint8_t* pGlobalData,
FX_DWORD dwGlobalLength,
uint8_t* pData,
FX_DWORD dwLength,
int32_t nStreamType,
std::list<CJBig2_CachePair>* pSymbolDictCache,
IFX_Pause* pPause) {
return new (pModule)
CJBig2_Context(pGlobalData, dwGlobalLength, pData, dwLength, nStreamType,
pSymbolDictCache, pPause);
}
void CJBig2_Context::DestroyContext(CJBig2_Context* pContext) {
delete pContext;
}
CJBig2_Context::CJBig2_Context(uint8_t* pGlobalData,
FX_DWORD dwGlobalLength,
uint8_t* pData,
FX_DWORD dwLength,
int32_t nStreamType,
std::list<CJBig2_CachePair>* pSymbolDictCache,
IFX_Pause* pPause) {
if (pGlobalData && (dwGlobalLength > 0)) {
JBIG2_ALLOC(m_pGlobalContext,
CJBig2_Context(NULL, 0, pGlobalData, dwGlobalLength,
JBIG2_EMBED_STREAM, pSymbolDictCache, pPause));
} else {
m_pGlobalContext = NULL;
}
JBIG2_ALLOC(m_pStream, CJBig2_BitStream(pData, dwLength));
m_nStreamType = nStreamType;
m_nState = JBIG2_OUT_OF_PAGE;
JBIG2_ALLOC(m_pSegmentList, CJBig2_List<CJBig2_Segment>);
JBIG2_ALLOC(m_pPageInfoList, CJBig2_List<JBig2PageInfo>(1));
m_pPage = NULL;
m_bBufSpecified = FALSE;
m_pPause = pPause;
m_nSegmentDecoded = 0;
m_PauseStep = 10;
m_pArithDecoder = NULL;
m_pGRD = NULL;
m_gbContext = NULL;
m_pSegment = NULL;
m_dwOffset = 0;
m_ProcessiveStatus = FXCODEC_STATUS_FRAME_READY;
m_pSymbolDictCache = pSymbolDictCache;
}
CJBig2_Context::~CJBig2_Context() {
delete m_pArithDecoder;
m_pArithDecoder = NULL;
delete m_pGRD;
m_pGRD = NULL;
if (m_gbContext) {
m_pModule->JBig2_Free(m_gbContext);
}
m_gbContext = NULL;
delete m_pGlobalContext;
m_pGlobalContext = NULL;
delete m_pPageInfoList;
m_pPageInfoList = NULL;
if (m_bBufSpecified) {
delete m_pPage;
}
m_pPage = NULL;
delete m_pStream;
m_pStream = NULL;
delete m_pSegmentList;
m_pSegmentList = NULL;
}
int32_t CJBig2_Context::decodeFile(IFX_Pause* pPause) {
uint8_t cFlags;
FX_DWORD dwTemp;
const uint8_t fileID[] = {0x97, 0x4A, 0x42, 0x32, 0x0D, 0x0A, 0x1A, 0x0A};
int32_t nRet;
if (m_pStream->getByteLeft() < 8) {
m_pModule->JBig2_Error("file header too short.");
nRet = JBIG2_ERROR_TOO_SHORT;
goto failed;
}
if (JBIG2_memcmp(m_pStream->getPointer(), fileID, 8) != 0) {
m_pModule->JBig2_Error("not jbig2 file");
nRet = JBIG2_ERROR_FILE_FORMAT;
goto failed;
}
m_pStream->offset(8);
if (m_pStream->read1Byte(&cFlags) != 0) {
m_pModule->JBig2_Error("file header too short.");
nRet = JBIG2_ERROR_TOO_SHORT;
goto failed;
}
if (!(cFlags & 0x02)) {
if (m_pStream->readInteger(&dwTemp) != 0) {
m_pModule->JBig2_Error("file header too short.");
nRet = JBIG2_ERROR_TOO_SHORT;
goto failed;
}
if (dwTemp > 0) {
delete m_pPageInfoList;
JBIG2_ALLOC(m_pPageInfoList, CJBig2_List<JBig2PageInfo>(dwTemp));
}
}
if (cFlags & 0x01) {
m_nStreamType = JBIG2_SQUENTIAL_STREAM;
return decode_SquentialOrgnazation(pPause);
} else {
m_nStreamType = JBIG2_RANDOM_STREAM;
return decode_RandomOrgnazation_FirstPage(pPause);
}
failed:
return nRet;
}
int32_t CJBig2_Context::decode_SquentialOrgnazation(IFX_Pause* pPause) {
int32_t nRet;
if (m_pStream->getByteLeft() > 0) {
while (m_pStream->getByteLeft() >= JBIG2_MIN_SEGMENT_SIZE) {
if (m_pSegment == NULL) {
JBIG2_ALLOC(m_pSegment, CJBig2_Segment());
nRet = parseSegmentHeader(m_pSegment);
if (nRet != JBIG2_SUCCESS) {
delete m_pSegment;
m_pSegment = NULL;
return nRet;
}
m_dwOffset = m_pStream->getOffset();
}
nRet = parseSegmentData(m_pSegment, pPause);
if (m_ProcessiveStatus == FXCODEC_STATUS_DECODE_TOBECONTINUE) {
m_ProcessiveStatus = FXCODEC_STATUS_DECODE_TOBECONTINUE;
m_PauseStep = 2;
return JBIG2_SUCCESS;
}
if ((nRet == JBIG2_END_OF_PAGE) || (nRet == JBIG2_END_OF_FILE)) {
delete m_pSegment;
m_pSegment = NULL;
break;
} else if (nRet != JBIG2_SUCCESS) {
delete m_pSegment;
m_pSegment = NULL;
return nRet;
}
m_pSegmentList->addItem(m_pSegment);
if (m_pSegment->m_dwData_length != 0xffffffff) {
m_dwOffset = m_dwOffset + m_pSegment->m_dwData_length;
m_pStream->setOffset(m_dwOffset);
} else {
m_pStream->offset(4);
}
m_pSegment = NULL;
if (m_pStream->getByteLeft() > 0 && m_pPage && pPause &&
pPause->NeedToPauseNow()) {
m_ProcessiveStatus = FXCODEC_STATUS_DECODE_TOBECONTINUE;
m_PauseStep = 2;
return JBIG2_SUCCESS;
}
}
} else {
return JBIG2_END_OF_FILE;
}
return JBIG2_SUCCESS;
}
int32_t CJBig2_Context::decode_EmbedOrgnazation(IFX_Pause* pPause) {
return decode_SquentialOrgnazation(pPause);
}
int32_t CJBig2_Context::decode_RandomOrgnazation_FirstPage(IFX_Pause* pPause) {
CJBig2_Segment* pSegment;
int32_t nRet;
while (m_pStream->getByteLeft() > JBIG2_MIN_SEGMENT_SIZE) {
JBIG2_ALLOC(pSegment, CJBig2_Segment());
nRet = parseSegmentHeader(pSegment);
if (nRet != JBIG2_SUCCESS) {
delete pSegment;
return nRet;
} else if (pSegment->m_cFlags.s.type == 51) {
delete pSegment;
break;
}
m_pSegmentList->addItem(pSegment);
if (pPause && m_pPause && pPause->NeedToPauseNow()) {
m_PauseStep = 3;
m_ProcessiveStatus = FXCODEC_STATUS_DECODE_TOBECONTINUE;
return JBIG2_SUCCESS;
}
}
m_nSegmentDecoded = 0;
return decode_RandomOrgnazation(pPause);
}
int32_t CJBig2_Context::decode_RandomOrgnazation(IFX_Pause* pPause) {
int32_t nRet;
for (; m_nSegmentDecoded < m_pSegmentList->getLength(); m_nSegmentDecoded++) {
nRet = parseSegmentData(m_pSegmentList->getAt(m_nSegmentDecoded), pPause);
if ((nRet == JBIG2_END_OF_PAGE) || (nRet == JBIG2_END_OF_FILE)) {
break;
} else if (nRet != JBIG2_SUCCESS) {
return nRet;
}
if (m_pPage && pPause && pPause->NeedToPauseNow()) {
m_PauseStep = 4;
m_ProcessiveStatus = FXCODEC_STATUS_DECODE_TOBECONTINUE;
return JBIG2_SUCCESS;
}
}
return JBIG2_SUCCESS;
}
int32_t CJBig2_Context::getFirstPage(uint8_t* pBuf,
int32_t width,
int32_t height,
int32_t stride,
IFX_Pause* pPause) {
int32_t nRet = 0;
if (m_pGlobalContext) {
nRet = m_pGlobalContext->decode_EmbedOrgnazation(pPause);
if (nRet != JBIG2_SUCCESS) {
m_ProcessiveStatus = FXCODEC_STATUS_ERROR;
return nRet;
}
}
m_bFirstPage = TRUE;
m_PauseStep = 0;
delete m_pPage;
JBIG2_ALLOC(m_pPage, CJBig2_Image(width, height, stride, pBuf));
m_bBufSpecified = TRUE;
if (m_pPage && pPause && pPause->NeedToPauseNow()) {
m_PauseStep = 1;
m_ProcessiveStatus = FXCODEC_STATUS_DECODE_TOBECONTINUE;
return nRet;
}
int ret = Continue(pPause);
return ret;
}
int32_t CJBig2_Context::Continue(IFX_Pause* pPause) {
m_ProcessiveStatus = FXCODEC_STATUS_DECODE_READY;
int32_t nRet;
if (m_PauseStep <= 1) {
switch (m_nStreamType) {
case JBIG2_FILE_STREAM:
nRet = decodeFile(pPause);
break;
case JBIG2_SQUENTIAL_STREAM:
nRet = decode_SquentialOrgnazation(pPause);
break;
case JBIG2_RANDOM_STREAM:
if (m_bFirstPage) {
nRet = decode_RandomOrgnazation_FirstPage(pPause);
} else {
nRet = decode_RandomOrgnazation(pPause);
}
break;
case JBIG2_EMBED_STREAM:
nRet = decode_EmbedOrgnazation(pPause);
break;
default:
m_ProcessiveStatus = FXCODEC_STATUS_ERROR;
return JBIG2_ERROR_STREAM_TYPE;
}
} else if (m_PauseStep == 2) {
nRet = decode_SquentialOrgnazation(pPause);
} else if (m_PauseStep == 3) {
nRet = decode_RandomOrgnazation_FirstPage(pPause);
} else if (m_PauseStep == 4) {
nRet = decode_RandomOrgnazation(pPause);
} else if (m_PauseStep == 5) {
m_ProcessiveStatus = FXCODEC_STATUS_DECODE_FINISH;
return JBIG2_SUCCESS;
}
if (m_ProcessiveStatus == FXCODEC_STATUS_DECODE_TOBECONTINUE) {
return nRet;
}
m_PauseStep = 5;
if (!m_bBufSpecified && nRet == JBIG2_SUCCESS) {
m_ProcessiveStatus = FXCODEC_STATUS_DECODE_FINISH;
return JBIG2_SUCCESS;
}
if (nRet == JBIG2_SUCCESS) {
m_ProcessiveStatus = FXCODEC_STATUS_DECODE_FINISH;
} else {
m_ProcessiveStatus = FXCODEC_STATUS_ERROR;
}
return nRet;
}
int32_t CJBig2_Context::getFirstPage(CJBig2_Image** image, IFX_Pause* pPause) {
int32_t nRet;
m_bFirstPage = TRUE;
m_PauseStep = 0;
if (m_pGlobalContext) {
nRet = m_pGlobalContext->decode_EmbedOrgnazation(pPause);
if (nRet != JBIG2_SUCCESS) {
return nRet;
}
}
m_bBufSpecified = FALSE;
return Continue(pPause);
}
CJBig2_Segment* CJBig2_Context::findSegmentByNumber(FX_DWORD dwNumber) {
CJBig2_Segment* pSeg;
int32_t i;
if (m_pGlobalContext) {
pSeg = m_pGlobalContext->findSegmentByNumber(dwNumber);
if (pSeg) {
return pSeg;
}
}
for (i = 0; i < m_pSegmentList->getLength(); i++) {
pSeg = m_pSegmentList->getAt(i);
if (pSeg->m_dwNumber == dwNumber) {
return pSeg;
}
}
return NULL;
}
CJBig2_Segment* CJBig2_Context::findReferredSegmentByTypeAndIndex(
CJBig2_Segment* pSegment,
uint8_t cType,
int32_t nIndex) {
CJBig2_Segment* pSeg;
int32_t i, count;
count = 0;
for (i = 0; i < pSegment->m_nReferred_to_segment_count; i++) {
pSeg = findSegmentByNumber(pSegment->m_pReferred_to_segment_numbers[i]);
if (pSeg && pSeg->m_cFlags.s.type == cType) {
if (count == nIndex) {
return pSeg;
} else {
count++;
}
}
}
return NULL;
}
int32_t CJBig2_Context::parseSegmentHeader(CJBig2_Segment* pSegment) {
uint8_t cSSize, cPSize;
uint8_t cTemp;
FX_WORD wTemp;
FX_DWORD dwTemp;
if ((m_pStream->readInteger(&pSegment->m_dwNumber) != 0) ||
(m_pStream->read1Byte(&pSegment->m_cFlags.c) != 0)) {
goto failed;
}
cTemp = m_pStream->getCurByte();
if ((cTemp >> 5) == 7) {
if (m_pStream->readInteger(
(FX_DWORD*)&pSegment->m_nReferred_to_segment_count) != 0) {
goto failed;
}
pSegment->m_nReferred_to_segment_count &= 0x1fffffff;
if (pSegment->m_nReferred_to_segment_count >
JBIG2_MAX_REFERRED_SEGMENT_COUNT) {
m_pModule->JBig2_Error("Too many referred segments.");
return JBIG2_ERROR_LIMIT;
}
dwTemp = 5 + 4 + (pSegment->m_nReferred_to_segment_count + 1) / 8;
} else {
if (m_pStream->read1Byte(&cTemp) != 0) {
goto failed;
}
pSegment->m_nReferred_to_segment_count = cTemp >> 5;
dwTemp = 5 + 1;
}
cSSize =
pSegment->m_dwNumber > 65536 ? 4 : pSegment->m_dwNumber > 256 ? 2 : 1;
cPSize = pSegment->m_cFlags.s.page_association_size ? 4 : 1;
if (pSegment->m_nReferred_to_segment_count) {
pSegment->m_pReferred_to_segment_numbers =
(FX_DWORD*)m_pModule->JBig2_Malloc2(
sizeof(FX_DWORD), pSegment->m_nReferred_to_segment_count);
for (int32_t i = 0; i < pSegment->m_nReferred_to_segment_count; i++) {
switch (cSSize) {
case 1:
if (m_pStream->read1Byte(&cTemp) != 0) {
goto failed;
}
pSegment->m_pReferred_to_segment_numbers[i] = cTemp;
break;
case 2:
if (m_pStream->readShortInteger(&wTemp) != 0) {
goto failed;
}
pSegment->m_pReferred_to_segment_numbers[i] = wTemp;
break;
case 4:
if (m_pStream->readInteger(&dwTemp) != 0) {
goto failed;
}
pSegment->m_pReferred_to_segment_numbers[i] = dwTemp;
break;
}
if (pSegment->m_pReferred_to_segment_numbers[i] >= pSegment->m_dwNumber) {
m_pModule->JBig2_Error(
"The referred segment number is greater than this segment number.");
goto failed;
}
}
}
if (cPSize == 1) {
if (m_pStream->read1Byte(&cTemp) != 0) {
goto failed;
}
pSegment->m_dwPage_association = cTemp;
} else {
if (m_pStream->readInteger(&pSegment->m_dwPage_association) != 0) {
goto failed;
}
}
if (m_pStream->readInteger(&pSegment->m_dwData_length) != 0) {
goto failed;
}
pSegment->m_pData = m_pStream->getPointer();
pSegment->m_State = JBIG2_SEGMENT_DATA_UNPARSED;
return JBIG2_SUCCESS;
failed:
m_pModule->JBig2_Error("header too short.");
return JBIG2_ERROR_TOO_SHORT;
}
int32_t CJBig2_Context::parseSegmentData(CJBig2_Segment* pSegment,
IFX_Pause* pPause) {
int32_t ret = ProcessiveParseSegmentData(pSegment, pPause);
while (m_ProcessiveStatus == FXCODEC_STATUS_DECODE_TOBECONTINUE &&
m_pStream->getByteLeft() > 0) {
ret = ProcessiveParseSegmentData(pSegment, pPause);
}
return ret;
}
int32_t CJBig2_Context::ProcessiveParseSegmentData(CJBig2_Segment* pSegment,
IFX_Pause* pPause) {
switch (pSegment->m_cFlags.s.type) {
case 0:
return parseSymbolDict(pSegment, pPause);
case 4:
case 6:
case 7:
if (m_nState == JBIG2_OUT_OF_PAGE) {
goto failed2;
} else {
return parseTextRegion(pSegment);
}
case 16:
return parsePatternDict(pSegment, pPause);
case 20:
case 22:
case 23:
if (m_nState == JBIG2_OUT_OF_PAGE) {
goto failed2;
} else {
return parseHalftoneRegion(pSegment, pPause);
}
case 36:
case 38:
case 39:
if (m_nState == JBIG2_OUT_OF_PAGE) {
goto failed2;
} else {
return parseGenericRegion(pSegment, pPause);
}
case 40:
case 42:
case 43:
if (m_nState == JBIG2_OUT_OF_PAGE) {
goto failed2;
} else {
return parseGenericRefinementRegion(pSegment);
}
case 48: {
FX_WORD wTemp;
JBig2PageInfo* pPageInfo;
JBIG2_ALLOC(pPageInfo, JBig2PageInfo);
if ((m_pStream->readInteger(&pPageInfo->m_dwWidth) != 0) ||
(m_pStream->readInteger(&pPageInfo->m_dwHeight) != 0) ||
(m_pStream->readInteger(&pPageInfo->m_dwResolutionX) != 0) ||
(m_pStream->readInteger(&pPageInfo->m_dwResolutionY) != 0) ||
(m_pStream->read1Byte(&pPageInfo->m_cFlags) != 0) ||
(m_pStream->readShortInteger(&wTemp) != 0)) {
delete pPageInfo;
goto failed1;
}
pPageInfo->m_bIsStriped = ((wTemp >> 15) & 1) ? 1 : 0;
pPageInfo->m_wMaxStripeSize = wTemp & 0x7fff;
if ((pPageInfo->m_dwHeight == 0xffffffff) &&
(pPageInfo->m_bIsStriped != 1)) {
m_pModule->JBig2_Warn("page height = 0xffffffff buf stripe field is 0");
pPageInfo->m_bIsStriped = 1;
}
if (!m_bBufSpecified) {
delete m_pPage;
if (pPageInfo->m_dwHeight == 0xffffffff) {
JBIG2_ALLOC(m_pPage, CJBig2_Image(pPageInfo->m_dwWidth,
pPageInfo->m_wMaxStripeSize));
} else {
JBIG2_ALLOC(m_pPage, CJBig2_Image(pPageInfo->m_dwWidth,
pPageInfo->m_dwHeight));
}
}
m_pPage->fill((pPageInfo->m_cFlags & 4) ? 1 : 0);
m_pPageInfoList->addItem(pPageInfo);
m_nState = JBIG2_IN_PAGE;
} break;
case 49:
m_nState = JBIG2_OUT_OF_PAGE;
return JBIG2_END_OF_PAGE;
break;
case 50:
m_pStream->offset(pSegment->m_dwData_length);
break;
case 51:
return JBIG2_END_OF_FILE;
case 52:
m_pStream->offset(pSegment->m_dwData_length);
break;
case 53:
return parseTable(pSegment);
case 62:
m_pStream->offset(pSegment->m_dwData_length);
break;
default:
break;
}
return JBIG2_SUCCESS;
failed1:
m_pModule->JBig2_Error("segment data too short.");
return JBIG2_ERROR_TOO_SHORT;
failed2:
m_pModule->JBig2_Error("segment syntax error.");
return JBIG2_ERROR_FATAL;
}
int32_t CJBig2_Context::parseSymbolDict(CJBig2_Segment* pSegment,
IFX_Pause* pPause) {
FX_DWORD dwTemp;
FX_WORD wFlags;
uint8_t cSDHUFFDH, cSDHUFFDW, cSDHUFFBMSIZE, cSDHUFFAGGINST;
CJBig2_HuffmanTable *Table_B1 = NULL, *Table_B2 = NULL, *Table_B3 = NULL,
*Table_B4 = NULL, *Table_B5 = NULL;
int32_t i, nIndex, nRet;
CJBig2_Segment *pSeg = NULL, *pLRSeg = NULL;
FX_BOOL bUsed;
CJBig2_Image** SDINSYMS = NULL;
CJBig2_SDDProc* pSymbolDictDecoder;
JBig2ArithCtx *gbContext = NULL, *grContext = NULL;
CJBig2_ArithDecoder* pArithDecoder;
JBIG2_ALLOC(pSymbolDictDecoder, CJBig2_SDDProc());
uint8_t* key = pSegment->m_pData;
FX_BOOL cache_hit = false;
if (m_pStream->readShortInteger(&wFlags) != 0) {
m_pModule->JBig2_Error(
"symbol dictionary segment : data header too short.");
nRet = JBIG2_ERROR_TOO_SHORT;
goto failed;
}
pSymbolDictDecoder->SDHUFF = wFlags & 0x0001;
pSymbolDictDecoder->SDREFAGG = (wFlags >> 1) & 0x0001;
pSymbolDictDecoder->SDTEMPLATE = (wFlags >> 10) & 0x0003;
pSymbolDictDecoder->SDRTEMPLATE = (wFlags >> 12) & 0x0003;
cSDHUFFDH = (wFlags >> 2) & 0x0003;
cSDHUFFDW = (wFlags >> 4) & 0x0003;
cSDHUFFBMSIZE = (wFlags >> 6) & 0x0001;
cSDHUFFAGGINST = (wFlags >> 7) & 0x0001;
if (pSymbolDictDecoder->SDHUFF == 0) {
if (pSymbolDictDecoder->SDTEMPLATE == 0) {
dwTemp = 8;
} else {
dwTemp = 2;
}
for (i = 0; i < (int32_t)dwTemp; i++) {
if (m_pStream->read1Byte((uint8_t*)&pSymbolDictDecoder->SDAT[i]) != 0) {
m_pModule->JBig2_Error(
"symbol dictionary segment : data header too short.");
nRet = JBIG2_ERROR_TOO_SHORT;
goto failed;
}
}
}
if ((pSymbolDictDecoder->SDREFAGG == 1) &&
(pSymbolDictDecoder->SDRTEMPLATE == 0)) {
for (i = 0; i < 4; i++) {
if (m_pStream->read1Byte((uint8_t*)&pSymbolDictDecoder->SDRAT[i]) != 0) {
m_pModule->JBig2_Error(
"symbol dictionary segment : data header too short.");
nRet = JBIG2_ERROR_TOO_SHORT;
goto failed;
}
}
}
if ((m_pStream->readInteger(&pSymbolDictDecoder->SDNUMEXSYMS) != 0) ||
(m_pStream->readInteger(&pSymbolDictDecoder->SDNUMNEWSYMS) != 0)) {
m_pModule->JBig2_Error(
"symbol dictionary segment : data header too short.");
nRet = JBIG2_ERROR_TOO_SHORT;
goto failed;
}
if (pSymbolDictDecoder->SDNUMEXSYMS > JBIG2_MAX_EXPORT_SYSMBOLS ||
pSymbolDictDecoder->SDNUMNEWSYMS > JBIG2_MAX_NEW_SYSMBOLS) {
m_pModule->JBig2_Error(
"symbol dictionary segment : too many export/new symbols.");
nRet = JBIG2_ERROR_LIMIT;
goto failed;
}
for (i = 0; i < pSegment->m_nReferred_to_segment_count; i++) {
if (!findSegmentByNumber(pSegment->m_pReferred_to_segment_numbers[i])) {
m_pModule->JBig2_Error(
"symbol dictionary segment : can't find refered to segments");
nRet = JBIG2_ERROR_FATAL;
goto failed;
}
}
pSymbolDictDecoder->SDNUMINSYMS = 0;
for (i = 0; i < pSegment->m_nReferred_to_segment_count; i++) {
pSeg = findSegmentByNumber(pSegment->m_pReferred_to_segment_numbers[i]);
if (pSeg->m_cFlags.s.type == 0) {
pSymbolDictDecoder->SDNUMINSYMS += pSeg->m_Result.sd->SDNUMEXSYMS;
pLRSeg = pSeg;
}
}
if (pSymbolDictDecoder->SDNUMINSYMS == 0) {
SDINSYMS = NULL;
} else {
SDINSYMS = (CJBig2_Image**)m_pModule->JBig2_Malloc2(
sizeof(CJBig2_Image*), pSymbolDictDecoder->SDNUMINSYMS);
dwTemp = 0;
for (i = 0; i < pSegment->m_nReferred_to_segment_count; i++) {
pSeg = findSegmentByNumber(pSegment->m_pReferred_to_segment_numbers[i]);
if (pSeg->m_cFlags.s.type == 0) {
JBIG2_memcpy(SDINSYMS + dwTemp, pSeg->m_Result.sd->SDEXSYMS,
pSeg->m_Result.sd->SDNUMEXSYMS * sizeof(CJBig2_Image*));
dwTemp += pSeg->m_Result.sd->SDNUMEXSYMS;
}
}
}
pSymbolDictDecoder->SDINSYMS = SDINSYMS;
if (pSymbolDictDecoder->SDHUFF == 1) {
if ((cSDHUFFDH == 2) || (cSDHUFFDW == 2)) {
m_pModule->JBig2_Error(
"symbol dictionary segment : SDHUFFDH=2 or SDHUFFDW=2 is not "
"permitted.");
nRet = JBIG2_ERROR_FATAL;
goto failed;
}
nIndex = 0;
if (cSDHUFFDH == 0) {
JBIG2_ALLOC(Table_B4, CJBig2_HuffmanTable(HuffmanTable_B4,
sizeof(HuffmanTable_B4) /
sizeof(JBig2TableLine),
HuffmanTable_HTOOB_B4));
pSymbolDictDecoder->SDHUFFDH = Table_B4;
} else if (cSDHUFFDH == 1) {
JBIG2_ALLOC(Table_B5, CJBig2_HuffmanTable(HuffmanTable_B5,
sizeof(HuffmanTable_B5) /
sizeof(JBig2TableLine),
HuffmanTable_HTOOB_B5));
pSymbolDictDecoder->SDHUFFDH = Table_B5;
} else {
pSeg = findReferredSegmentByTypeAndIndex(pSegment, 53, nIndex++);
if (!pSeg) {
m_pModule->JBig2_Error(
"symbol dictionary segment : SDHUFFDH can't find user supplied "
"table.");
nRet = JBIG2_ERROR_FATAL;
goto failed;
}
pSymbolDictDecoder->SDHUFFDH = pSeg->m_Result.ht;
}
if (cSDHUFFDW == 0) {
JBIG2_ALLOC(Table_B2, CJBig2_HuffmanTable(HuffmanTable_B2,
sizeof(HuffmanTable_B2) /
sizeof(JBig2TableLine),
HuffmanTable_HTOOB_B2));
pSymbolDictDecoder->SDHUFFDW = Table_B2;
} else if (cSDHUFFDW == 1) {
JBIG2_ALLOC(Table_B3, CJBig2_HuffmanTable(HuffmanTable_B3,
sizeof(HuffmanTable_B3) /
sizeof(JBig2TableLine),
HuffmanTable_HTOOB_B3));
pSymbolDictDecoder->SDHUFFDW = Table_B3;
} else {
pSeg = findReferredSegmentByTypeAndIndex(pSegment, 53, nIndex++);
if (!pSeg) {
m_pModule->JBig2_Error(
"symbol dictionary segment : SDHUFFDW can't find user supplied "
"table.");
nRet = JBIG2_ERROR_FATAL;
goto failed;
}
pSymbolDictDecoder->SDHUFFDW = pSeg->m_Result.ht;
}
if (cSDHUFFBMSIZE == 0) {
JBIG2_ALLOC(Table_B1, CJBig2_HuffmanTable(HuffmanTable_B1,
sizeof(HuffmanTable_B1) /
sizeof(JBig2TableLine),
HuffmanTable_HTOOB_B1));
pSymbolDictDecoder->SDHUFFBMSIZE = Table_B1;
} else {
pSeg = findReferredSegmentByTypeAndIndex(pSegment, 53, nIndex++);
if (!pSeg) {
m_pModule->JBig2_Error(
"symbol dictionary segment : SDHUFFBMSIZE can't find user supplied "
"table.");
nRet = JBIG2_ERROR_FATAL;
goto failed;
}
pSymbolDictDecoder->SDHUFFBMSIZE = pSeg->m_Result.ht;
}
if (pSymbolDictDecoder->SDREFAGG == 1) {
if (cSDHUFFAGGINST == 0) {
if (!Table_B1) {
JBIG2_ALLOC(Table_B1, CJBig2_HuffmanTable(HuffmanTable_B1,
sizeof(HuffmanTable_B1) /
sizeof(JBig2TableLine),
HuffmanTable_HTOOB_B1));
}
pSymbolDictDecoder->SDHUFFAGGINST = Table_B1;
} else {
pSeg = findReferredSegmentByTypeAndIndex(pSegment, 53, nIndex++);
if (!pSeg) {
m_pModule->JBig2_Error(
"symbol dictionary segment : SDHUFFAGGINST can't find user "
"supplied table.");
nRet = JBIG2_ERROR_FATAL;
goto failed;
}
pSymbolDictDecoder->SDHUFFAGGINST = pSeg->m_Result.ht;
}
}
}
if ((wFlags & 0x0100) && pLRSeg && pLRSeg->m_Result.sd->m_bContextRetained) {
if (pSymbolDictDecoder->SDHUFF == 0) {
dwTemp = pSymbolDictDecoder->SDTEMPLATE == 0
? 65536
: pSymbolDictDecoder->SDTEMPLATE == 1 ? 8192 : 1024;
gbContext = (JBig2ArithCtx*)m_pModule->JBig2_Malloc2(
sizeof(JBig2ArithCtx), dwTemp);
JBIG2_memcpy(gbContext, pLRSeg->m_Result.sd->m_gbContext,
sizeof(JBig2ArithCtx) * dwTemp);
}
if (pSymbolDictDecoder->SDREFAGG == 1) {
dwTemp = pSymbolDictDecoder->SDRTEMPLATE ? 1 << 10 : 1 << 13;
grContext = (JBig2ArithCtx*)m_pModule->JBig2_Malloc2(
sizeof(JBig2ArithCtx), dwTemp);
JBIG2_memcpy(grContext, pLRSeg->m_Result.sd->m_grContext,
sizeof(JBig2ArithCtx) * dwTemp);
}
} else {
if (pSymbolDictDecoder->SDHUFF == 0) {
dwTemp = pSymbolDictDecoder->SDTEMPLATE == 0
? 65536
: pSymbolDictDecoder->SDTEMPLATE == 1 ? 8192 : 1024;
gbContext = (JBig2ArithCtx*)m_pModule->JBig2_Malloc2(
sizeof(JBig2ArithCtx), dwTemp);
JBIG2_memset(gbContext, 0, sizeof(JBig2ArithCtx) * dwTemp);
}
if (pSymbolDictDecoder->SDREFAGG == 1) {
dwTemp = pSymbolDictDecoder->SDRTEMPLATE ? 1 << 10 : 1 << 13;
grContext = (JBig2ArithCtx*)m_pModule->JBig2_Malloc2(
sizeof(JBig2ArithCtx), dwTemp);
JBIG2_memset(grContext, 0, sizeof(JBig2ArithCtx) * dwTemp);
}
}
pSegment->m_nResultType = JBIG2_SYMBOL_DICT_POINTER;
for (std::list<CJBig2_CachePair>::iterator it = m_pSymbolDictCache->begin();
it != m_pSymbolDictCache->end(); ++it) {
if (it->first == key) {
pSegment->m_Result.sd = it->second->DeepCopy();
m_pSymbolDictCache->push_front(*it);
m_pSymbolDictCache->erase(it);
cache_hit = true;
break;
}
}
if (!cache_hit) {
if (pSymbolDictDecoder->SDHUFF == 0) {
JBIG2_ALLOC(pArithDecoder, CJBig2_ArithDecoder(m_pStream));
pSegment->m_Result.sd =
pSymbolDictDecoder->decode_Arith(pArithDecoder, gbContext, grContext);
delete pArithDecoder;
if (pSegment->m_Result.sd == NULL) {
nRet = JBIG2_ERROR_FATAL;
goto failed;
}
m_pStream->alignByte();
m_pStream->offset(2);
} else {
pSegment->m_Result.sd = pSymbolDictDecoder->decode_Huffman(
m_pStream, gbContext, grContext, pPause);
if (pSegment->m_Result.sd == NULL) {
nRet = JBIG2_ERROR_FATAL;
goto failed;
}
m_pStream->alignByte();
}
CJBig2_SymbolDict* value = pSegment->m_Result.sd->DeepCopy();
if (value && kSymbolDictCacheMaxSize > 0) {
while (m_pSymbolDictCache->size() >= kSymbolDictCacheMaxSize) {
delete m_pSymbolDictCache->back().second;
m_pSymbolDictCache->pop_back();
}
m_pSymbolDictCache->push_front(CJBig2_CachePair(key, value));
}
}
if (wFlags & 0x0200) {
pSegment->m_Result.sd->m_bContextRetained = TRUE;
if (pSymbolDictDecoder->SDHUFF == 0) {
pSegment->m_Result.sd->m_gbContext = gbContext;
}
if (pSymbolDictDecoder->SDREFAGG == 1) {
pSegment->m_Result.sd->m_grContext = grContext;
}
bUsed = TRUE;
} else {
bUsed = FALSE;
}
delete pSymbolDictDecoder;
if (SDINSYMS) {
m_pModule->JBig2_Free(SDINSYMS);
}
delete Table_B1;
delete Table_B2;
delete Table_B3;
delete Table_B4;
delete Table_B5;
if (bUsed == FALSE) {
if (gbContext) {
m_pModule->JBig2_Free(gbContext);
}
if (grContext) {
m_pModule->JBig2_Free(grContext);
}
}
return JBIG2_SUCCESS;
failed:
delete pSymbolDictDecoder;
if (SDINSYMS) {
m_pModule->JBig2_Free(SDINSYMS);
}
delete Table_B1;
delete Table_B2;
delete Table_B3;
delete Table_B4;
delete Table_B5;
if (gbContext) {
m_pModule->JBig2_Free(gbContext);
}
if (grContext) {
m_pModule->JBig2_Free(grContext);
}
return nRet;
}
int32_t CJBig2_Context::parseTextRegion(CJBig2_Segment* pSegment) {
FX_DWORD dwTemp;
FX_WORD wFlags;
int32_t i, nIndex, nRet;
JBig2RegionInfo ri;
CJBig2_Segment* pSeg;
CJBig2_Image** SBSYMS = NULL;
JBig2HuffmanCode* SBSYMCODES = NULL;
uint8_t cSBHUFFFS, cSBHUFFDS, cSBHUFFDT, cSBHUFFRDW, cSBHUFFRDH, cSBHUFFRDX,
cSBHUFFRDY, cSBHUFFRSIZE;
CJBig2_HuffmanTable *Table_B1 = NULL, *Table_B6 = NULL, *Table_B7 = NULL,
*Table_B8 = NULL, *Table_B9 = NULL, *Table_B10 = NULL,
*Table_B11 = NULL, *Table_B12 = NULL, *Table_B13 = NULL,
*Table_B14 = NULL, *Table_B15 = NULL;
JBig2ArithCtx* grContext = NULL;
CJBig2_ArithDecoder* pArithDecoder;
CJBig2_TRDProc* pTRD;
JBIG2_ALLOC(pTRD, CJBig2_TRDProc());
if ((parseRegionInfo(&ri) != JBIG2_SUCCESS) ||
(m_pStream->readShortInteger(&wFlags) != 0)) {
m_pModule->JBig2_Error("text region segment : data header too short.");
nRet = JBIG2_ERROR_TOO_SHORT;
goto failed;
}
pTRD->SBW = ri.width;
pTRD->SBH = ri.height;
pTRD->SBHUFF = wFlags & 0x0001;
pTRD->SBREFINE = (wFlags >> 1) & 0x0001;
dwTemp = (wFlags >> 2) & 0x0003;
pTRD->SBSTRIPS = 1 << dwTemp;
pTRD->REFCORNER = (JBig2Corner)((wFlags >> 4) & 0x0003);
pTRD->TRANSPOSED = (wFlags >> 6) & 0x0001;
pTRD->SBCOMBOP = (JBig2ComposeOp)((wFlags >> 7) & 0x0003);
pTRD->SBDEFPIXEL = (wFlags >> 9) & 0x0001;
pTRD->SBDSOFFSET = (wFlags >> 10) & 0x001f;
if (pTRD->SBDSOFFSET >= 0x0010) {
pTRD->SBDSOFFSET = pTRD->SBDSOFFSET - 0x0020;
}
pTRD->SBRTEMPLATE = (wFlags >> 15) & 0x0001;
if (pTRD->SBHUFF == 1) {
if (m_pStream->readShortInteger(&wFlags) != 0) {
m_pModule->JBig2_Error("text region segment : data header too short.");
nRet = JBIG2_ERROR_TOO_SHORT;
goto failed;
}
cSBHUFFFS = wFlags & 0x0003;
cSBHUFFDS = (wFlags >> 2) & 0x0003;
cSBHUFFDT = (wFlags >> 4) & 0x0003;
cSBHUFFRDW = (wFlags >> 6) & 0x0003;
cSBHUFFRDH = (wFlags >> 8) & 0x0003;
cSBHUFFRDX = (wFlags >> 10) & 0x0003;
cSBHUFFRDY = (wFlags >> 12) & 0x0003;
cSBHUFFRSIZE = (wFlags >> 14) & 0x0001;
}
if ((pTRD->SBREFINE == 1) && (pTRD->SBRTEMPLATE == 0)) {
for (i = 0; i < 4; i++) {
if (m_pStream->read1Byte((uint8_t*)&pTRD->SBRAT[i]) != 0) {
m_pModule->JBig2_Error("text region segment : data header too short.");
nRet = JBIG2_ERROR_TOO_SHORT;
goto failed;
}
}
}
if (m_pStream->readInteger(&pTRD->SBNUMINSTANCES) != 0) {
m_pModule->JBig2_Error("text region segment : data header too short.");
nRet = JBIG2_ERROR_TOO_SHORT;
goto failed;
}
for (i = 0; i < pSegment->m_nReferred_to_segment_count; i++) {
if (!findSegmentByNumber(pSegment->m_pReferred_to_segment_numbers[i])) {
m_pModule->JBig2_Error(
"text region segment : can't find refered to segments");
nRet = JBIG2_ERROR_FATAL;
goto failed;
}
}
pTRD->SBNUMSYMS = 0;
for (i = 0; i < pSegment->m_nReferred_to_segment_count; i++) {
pSeg = findSegmentByNumber(pSegment->m_pReferred_to_segment_numbers[i]);
if (pSeg->m_cFlags.s.type == 0) {
pTRD->SBNUMSYMS += pSeg->m_Result.sd->SDNUMEXSYMS;
}
}
if (pTRD->SBNUMSYMS > 0) {
SBSYMS = (CJBig2_Image**)m_pModule->JBig2_Malloc2(sizeof(CJBig2_Image*),
pTRD->SBNUMSYMS);
dwTemp = 0;
for (i = 0; i < pSegment->m_nReferred_to_segment_count; i++) {
pSeg = findSegmentByNumber(pSegment->m_pReferred_to_segment_numbers[i]);
if (pSeg->m_cFlags.s.type == 0) {
JBIG2_memcpy(SBSYMS + dwTemp, pSeg->m_Result.sd->SDEXSYMS,
pSeg->m_Result.sd->SDNUMEXSYMS * sizeof(CJBig2_Image*));
dwTemp += pSeg->m_Result.sd->SDNUMEXSYMS;
}
}
pTRD->SBSYMS = SBSYMS;
} else {
pTRD->SBSYMS = NULL;
}
if (pTRD->SBHUFF == 1) {
SBSYMCODES = decodeSymbolIDHuffmanTable(m_pStream, pTRD->SBNUMSYMS);
if (SBSYMCODES == NULL) {
m_pModule->JBig2_Error(
"text region segment: symbol ID huffman table decode failure!");
nRet = JBIG2_ERROR_FATAL;
goto failed;
}
m_pStream->alignByte();
pTRD->SBSYMCODES = SBSYMCODES;
} else {
dwTemp = 0;
while ((FX_DWORD)(1 << dwTemp) < pTRD->SBNUMSYMS) {
dwTemp++;
}
pTRD->SBSYMCODELEN = (uint8_t)dwTemp;
}
if (pTRD->SBHUFF == 1) {
if ((cSBHUFFFS == 2) || (cSBHUFFRDW == 2) || (cSBHUFFRDH == 2) ||
(cSBHUFFRDX == 2) || (cSBHUFFRDY == 2)) {
m_pModule->JBig2_Error(
"text region segment : SBHUFFFS=2 or SBHUFFRDW=2 or "
"SBHUFFRDH=2 or SBHUFFRDX=2 or SBHUFFRDY=2 is not permitted");
nRet = JBIG2_ERROR_FATAL;
goto failed;
}
nIndex = 0;
if (cSBHUFFFS == 0) {
JBIG2_ALLOC(Table_B6, CJBig2_HuffmanTable(HuffmanTable_B6,
sizeof(HuffmanTable_B6) /
sizeof(JBig2TableLine),
HuffmanTable_HTOOB_B6));
pTRD->SBHUFFFS = Table_B6;
} else if (cSBHUFFFS == 1) {
JBIG2_ALLOC(Table_B7, CJBig2_HuffmanTable(HuffmanTable_B7,
sizeof(HuffmanTable_B7) /
sizeof(JBig2TableLine),
HuffmanTable_HTOOB_B7));
pTRD->SBHUFFFS = Table_B7;
} else {
pSeg = findReferredSegmentByTypeAndIndex(pSegment, 53, nIndex++);
if (!pSeg) {
m_pModule->JBig2_Error(
"text region segment : SBHUFFFS can't find user supplied table");
nRet = JBIG2_ERROR_FATAL;
goto failed;
}
pTRD->SBHUFFFS = pSeg->m_Result.ht;
}
if (cSBHUFFDS == 0) {
JBIG2_ALLOC(Table_B8, CJBig2_HuffmanTable(HuffmanTable_B8,
sizeof(HuffmanTable_B8) /
sizeof(JBig2TableLine),
HuffmanTable_HTOOB_B8));
pTRD->SBHUFFDS = Table_B8;
} else if (cSBHUFFDS == 1) {
JBIG2_ALLOC(Table_B9, CJBig2_HuffmanTable(HuffmanTable_B9,
sizeof(HuffmanTable_B9) /
sizeof(JBig2TableLine),
HuffmanTable_HTOOB_B9));
pTRD->SBHUFFDS = Table_B9;
} else if (cSBHUFFDS == 2) {
JBIG2_ALLOC(Table_B10, CJBig2_HuffmanTable(HuffmanTable_B10,
sizeof(HuffmanTable_B10) /
sizeof(JBig2TableLine),
HuffmanTable_HTOOB_B10));
pTRD->SBHUFFDS = Table_B10;
} else {
pSeg = findReferredSegmentByTypeAndIndex(pSegment, 53, nIndex++);
if (!pSeg) {
m_pModule->JBig2_Error(
"text region segment : SBHUFFDS can't find user supplied table");
nRet = JBIG2_ERROR_FATAL;
goto failed;
}
pTRD->SBHUFFDS = pSeg->m_Result.ht;
}
if (cSBHUFFDT == 0) {
JBIG2_ALLOC(Table_B11, CJBig2_HuffmanTable(HuffmanTable_B11,
sizeof(HuffmanTable_B11) /
sizeof(JBig2TableLine),
HuffmanTable_HTOOB_B11));
pTRD->SBHUFFDT = Table_B11;
} else if (cSBHUFFDT == 1) {
JBIG2_ALLOC(Table_B12, CJBig2_HuffmanTable(HuffmanTable_B12,
sizeof(HuffmanTable_B12) /
sizeof(JBig2TableLine),
HuffmanTable_HTOOB_B12));
pTRD->SBHUFFDT = Table_B12;
} else if (cSBHUFFDT == 2) {
JBIG2_ALLOC(Table_B13, CJBig2_HuffmanTable(HuffmanTable_B13,
sizeof(HuffmanTable_B13) /
sizeof(JBig2TableLine),
HuffmanTable_HTOOB_B13));
pTRD->SBHUFFDT = Table_B13;
} else {
pSeg = findReferredSegmentByTypeAndIndex(pSegment, 53, nIndex++);
if (!pSeg) {
m_pModule->JBig2_Error(
"text region segment : SBHUFFDT can't find user supplied table");
nRet = JBIG2_ERROR_FATAL;
goto failed;
}
pTRD->SBHUFFDT = pSeg->m_Result.ht;
}
if (cSBHUFFRDW == 0) {
JBIG2_ALLOC(Table_B14, CJBig2_HuffmanTable(HuffmanTable_B14,
sizeof(HuffmanTable_B14) /
sizeof(JBig2TableLine),
HuffmanTable_HTOOB_B14));
pTRD->SBHUFFRDW = Table_B14;
} else if (cSBHUFFRDW == 1) {
JBIG2_ALLOC(Table_B15, CJBig2_HuffmanTable(HuffmanTable_B15,
sizeof(HuffmanTable_B15) /
sizeof(JBig2TableLine),
HuffmanTable_HTOOB_B15));
pTRD->SBHUFFRDW = Table_B15;
} else {
pSeg = findReferredSegmentByTypeAndIndex(pSegment, 53, nIndex++);
if (!pSeg) {
m_pModule->JBig2_Error(
"text region segment : SBHUFFRDW can't find user supplied table");
nRet = JBIG2_ERROR_FATAL;
goto failed;
}
pTRD->SBHUFFRDW = pSeg->m_Result.ht;
}
if (cSBHUFFRDH == 0) {
if (!Table_B14) {
JBIG2_ALLOC(Table_B14, CJBig2_HuffmanTable(HuffmanTable_B14,
sizeof(HuffmanTable_B14) /
sizeof(JBig2TableLine),
HuffmanTable_HTOOB_B14));
}
pTRD->SBHUFFRDH = Table_B14;
} else if (cSBHUFFRDH == 1) {
if (!Table_B15) {
JBIG2_ALLOC(Table_B15, CJBig2_HuffmanTable(HuffmanTable_B15,
sizeof(HuffmanTable_B15) /
sizeof(JBig2TableLine),
HuffmanTable_HTOOB_B15));
}
pTRD->SBHUFFRDH = Table_B15;
} else {
pSeg = findReferredSegmentByTypeAndIndex(pSegment, 53, nIndex++);
if (!pSeg) {
m_pModule->JBig2_Error(
"text region segment : SBHUFFRDH can't find user supplied table");
nRet = JBIG2_ERROR_FATAL;
goto failed;
}
pTRD->SBHUFFRDH = pSeg->m_Result.ht;
}
if (cSBHUFFRDX == 0) {
if (!Table_B14) {
JBIG2_ALLOC(Table_B14, CJBig2_HuffmanTable(HuffmanTable_B14,
sizeof(HuffmanTable_B14) /
sizeof(JBig2TableLine),
HuffmanTable_HTOOB_B14));
}
pTRD->SBHUFFRDX = Table_B14;
} else if (cSBHUFFRDX == 1) {
if (!Table_B15) {
JBIG2_ALLOC(Table_B15, CJBig2_HuffmanTable(HuffmanTable_B15,
sizeof(HuffmanTable_B15) /
sizeof(JBig2TableLine),
HuffmanTable_HTOOB_B15));
}
pTRD->SBHUFFRDX = Table_B15;
} else {
pSeg = findReferredSegmentByTypeAndIndex(pSegment, 53, nIndex++);
if (!pSeg) {
m_pModule->JBig2_Error(
"text region segment : SBHUFFRDX can't find user supplied table");
nRet = JBIG2_ERROR_FATAL;
goto failed;
}
pTRD->SBHUFFRDX = pSeg->m_Result.ht;
}
if (cSBHUFFRDY == 0) {
if (!Table_B14) {
JBIG2_ALLOC(Table_B14, CJBig2_HuffmanTable(HuffmanTable_B14,
sizeof(HuffmanTable_B14) /
sizeof(JBig2TableLine),
HuffmanTable_HTOOB_B14));
}
pTRD->SBHUFFRDY = Table_B14;
} else if (cSBHUFFRDY == 1) {
if (!Table_B15) {
JBIG2_ALLOC(Table_B15, CJBig2_HuffmanTable(HuffmanTable_B15,
sizeof(HuffmanTable_B15) /
sizeof(JBig2TableLine),
HuffmanTable_HTOOB_B15));
}
pTRD->SBHUFFRDY = Table_B15;
} else {
pSeg = findReferredSegmentByTypeAndIndex(pSegment, 53, nIndex++);
if (!pSeg) {
m_pModule->JBig2_Error(
"text region segment : SBHUFFRDY can't find user supplied table");
nRet = JBIG2_ERROR_FATAL;
goto failed;
}
pTRD->SBHUFFRDY = pSeg->m_Result.ht;
}
if (cSBHUFFRSIZE == 0) {
JBIG2_ALLOC(Table_B1, CJBig2_HuffmanTable(HuffmanTable_B1,
sizeof(HuffmanTable_B1) /
sizeof(JBig2TableLine),
HuffmanTable_HTOOB_B1));
pTRD->SBHUFFRSIZE = Table_B1;
} else {
pSeg = findReferredSegmentByTypeAndIndex(pSegment, 53, nIndex++);
if (!pSeg) {
m_pModule->JBig2_Error(
"text region segment : SBHUFFRSIZE can't find user supplied table");
nRet = JBIG2_ERROR_FATAL;
goto failed;
}
pTRD->SBHUFFRSIZE = pSeg->m_Result.ht;
}
}
if (pTRD->SBREFINE == 1) {
dwTemp = pTRD->SBRTEMPLATE ? 1 << 10 : 1 << 13;
grContext =
(JBig2ArithCtx*)m_pModule->JBig2_Malloc2(sizeof(JBig2ArithCtx), dwTemp);
JBIG2_memset(grContext, 0, sizeof(JBig2ArithCtx) * dwTemp);
}
if (pTRD->SBHUFF == 0) {
JBIG2_ALLOC(pArithDecoder, CJBig2_ArithDecoder(m_pStream));
pSegment->m_nResultType = JBIG2_IMAGE_POINTER;
pSegment->m_Result.im = pTRD->decode_Arith(pArithDecoder, grContext);
delete pArithDecoder;
if (pSegment->m_Result.im == NULL) {
nRet = JBIG2_ERROR_FATAL;
goto failed;
}
m_pStream->alignByte();
m_pStream->offset(2);
} else {
pSegment->m_nResultType = JBIG2_IMAGE_POINTER;
pSegment->m_Result.im = pTRD->decode_Huffman(m_pStream, grContext);
if (pSegment->m_Result.im == NULL) {
nRet = JBIG2_ERROR_FATAL;
goto failed;
}
m_pStream->alignByte();
}
if (pSegment->m_cFlags.s.type != 4) {
if (!m_bBufSpecified) {
JBig2PageInfo* pPageInfo = m_pPageInfoList->getLast();
if ((pPageInfo->m_bIsStriped == 1) &&
(ri.y + ri.height > m_pPage->m_nHeight)) {
m_pPage->expand(ri.y + ri.height, (pPageInfo->m_cFlags & 4) ? 1 : 0);
}
}
m_pPage->composeFrom(ri.x, ri.y, pSegment->m_Result.im,
(JBig2ComposeOp)(ri.flags & 0x03));
delete pSegment->m_Result.im;
pSegment->m_Result.im = NULL;
}
delete pTRD;
if (SBSYMS) {
m_pModule->JBig2_Free(SBSYMS);
}
if (SBSYMCODES) {
m_pModule->JBig2_Free(SBSYMCODES);
}
if (grContext) {
m_pModule->JBig2_Free(grContext);
}
delete Table_B1;
delete Table_B6;
delete Table_B7;
delete Table_B8;
delete Table_B9;
delete Table_B10;
delete Table_B11;
delete Table_B12;
delete Table_B13;
delete Table_B14;
delete Table_B15;
return JBIG2_SUCCESS;
failed:
delete pTRD;
if (SBSYMS) {
m_pModule->JBig2_Free(SBSYMS);
}
if (SBSYMCODES) {
m_pModule->JBig2_Free(SBSYMCODES);
}
if (grContext) {
m_pModule->JBig2_Free(grContext);
}
delete Table_B1;
delete Table_B6;
delete Table_B7;
delete Table_B8;
delete Table_B9;
delete Table_B10;
delete Table_B11;
delete Table_B12;
delete Table_B13;
delete Table_B14;
delete Table_B15;
return nRet;
}
int32_t CJBig2_Context::parsePatternDict(CJBig2_Segment* pSegment,
IFX_Pause* pPause) {
FX_DWORD dwTemp;
uint8_t cFlags;
JBig2ArithCtx* gbContext;
CJBig2_ArithDecoder* pArithDecoder;
CJBig2_PDDProc* pPDD;
int32_t nRet;
JBIG2_ALLOC(pPDD, CJBig2_PDDProc());
if ((m_pStream->read1Byte(&cFlags) != 0) ||
(m_pStream->read1Byte(&pPDD->HDPW) != 0) ||
(m_pStream->read1Byte(&pPDD->HDPH) != 0) ||
(m_pStream->readInteger(&pPDD->GRAYMAX) != 0)) {
m_pModule->JBig2_Error(
"pattern dictionary segment : data header too short.");
nRet = JBIG2_ERROR_TOO_SHORT;
goto failed;
}
if (pPDD->GRAYMAX > JBIG2_MAX_PATTERN_INDEX) {
m_pModule->JBig2_Error("pattern dictionary segment : too max gray max.");
nRet = JBIG2_ERROR_LIMIT;
goto failed;
}
pPDD->HDMMR = cFlags & 0x01;
pPDD->HDTEMPLATE = (cFlags >> 1) & 0x03;
pSegment->m_nResultType = JBIG2_PATTERN_DICT_POINTER;
if (pPDD->HDMMR == 0) {
dwTemp =
pPDD->HDTEMPLATE == 0 ? 65536 : pPDD->HDTEMPLATE == 1 ? 8192 : 1024;
gbContext =
(JBig2ArithCtx*)m_pModule->JBig2_Malloc2(sizeof(JBig2ArithCtx), dwTemp);
JBIG2_memset(gbContext, 0, sizeof(JBig2ArithCtx) * dwTemp);
JBIG2_ALLOC(pArithDecoder, CJBig2_ArithDecoder(m_pStream));
pSegment->m_Result.pd =
pPDD->decode_Arith(pArithDecoder, gbContext, pPause);
delete pArithDecoder;
if (pSegment->m_Result.pd == NULL) {
m_pModule->JBig2_Free(gbContext);
nRet = JBIG2_ERROR_FATAL;
goto failed;
}
m_pModule->JBig2_Free(gbContext);
m_pStream->alignByte();
m_pStream->offset(2);
} else {
pSegment->m_Result.pd = pPDD->decode_MMR(m_pStream, pPause);
if (pSegment->m_Result.pd == NULL) {
nRet = JBIG2_ERROR_FATAL;
goto failed;
}
m_pStream->alignByte();
}
delete pPDD;
return JBIG2_SUCCESS;
failed:
delete pPDD;
return nRet;
}
int32_t CJBig2_Context::parseHalftoneRegion(CJBig2_Segment* pSegment,
IFX_Pause* pPause) {
FX_DWORD dwTemp;
uint8_t cFlags;
JBig2RegionInfo ri;
CJBig2_Segment* pSeg;
CJBig2_PatternDict* pPatternDict;
JBig2ArithCtx* gbContext;
CJBig2_ArithDecoder* pArithDecoder;
CJBig2_HTRDProc* pHRD;
int32_t nRet;
JBIG2_ALLOC(pHRD, CJBig2_HTRDProc());
if ((parseRegionInfo(&ri) != JBIG2_SUCCESS) ||
(m_pStream->read1Byte(&cFlags) != 0) ||
(m_pStream->readInteger(&pHRD->HGW) != 0) ||
(m_pStream->readInteger(&pHRD->HGH) != 0) ||
(m_pStream->readInteger((FX_DWORD*)&pHRD->HGX) != 0) ||
(m_pStream->readInteger((FX_DWORD*)&pHRD->HGY) != 0) ||
(m_pStream->readShortInteger(&pHRD->HRX) != 0) ||
(m_pStream->readShortInteger(&pHRD->HRY) != 0)) {
m_pModule->JBig2_Error("halftone region segment : data header too short.");
nRet = JBIG2_ERROR_TOO_SHORT;
goto failed;
}
pHRD->HBW = ri.width;
pHRD->HBH = ri.height;
pHRD->HMMR = cFlags & 0x01;
pHRD->HTEMPLATE = (cFlags >> 1) & 0x03;
pHRD->HENABLESKIP = (cFlags >> 3) & 0x01;
pHRD->HCOMBOP = (JBig2ComposeOp)((cFlags >> 4) & 0x07);
pHRD->HDEFPIXEL = (cFlags >> 7) & 0x01;
if (pSegment->m_nReferred_to_segment_count != 1) {
m_pModule->JBig2_Error(
"halftone region segment : refered to segment count not equals 1");
nRet = JBIG2_ERROR_FATAL;
goto failed;
}
pSeg = findSegmentByNumber(pSegment->m_pReferred_to_segment_numbers[0]);
if ((pSeg == NULL) || (pSeg->m_cFlags.s.type != 16)) {
m_pModule->JBig2_Error(
"halftone region segment : refered to segment is not pattern dict");
nRet = JBIG2_ERROR_FATAL;
goto failed;
}
pPatternDict = pSeg->m_Result.pd;
if ((pPatternDict == NULL) || (pPatternDict->NUMPATS == 0)) {
m_pModule->JBig2_Error("halftone region segment : has no patterns input");
nRet = JBIG2_ERROR_FATAL;
goto failed;
}
pHRD->HNUMPATS = pPatternDict->NUMPATS;
pHRD->HPATS = pPatternDict->HDPATS;
pHRD->HPW = pPatternDict->HDPATS[0]->m_nWidth;
pHRD->HPH = pPatternDict->HDPATS[0]->m_nHeight;
pSegment->m_nResultType = JBIG2_IMAGE_POINTER;
if (pHRD->HMMR == 0) {
dwTemp = pHRD->HTEMPLATE == 0 ? 65536 : pHRD->HTEMPLATE == 1 ? 8192 : 1024;
gbContext =
(JBig2ArithCtx*)m_pModule->JBig2_Malloc2(sizeof(JBig2ArithCtx), dwTemp);
JBIG2_memset(gbContext, 0, sizeof(JBig2ArithCtx) * dwTemp);
JBIG2_ALLOC(pArithDecoder, CJBig2_ArithDecoder(m_pStream));
pSegment->m_Result.im =
pHRD->decode_Arith(pArithDecoder, gbContext, pPause);
delete pArithDecoder;
if (pSegment->m_Result.im == NULL) {
m_pModule->JBig2_Free(gbContext);
nRet = JBIG2_ERROR_FATAL;
goto failed;
}
m_pModule->JBig2_Free(gbContext);
m_pStream->alignByte();
m_pStream->offset(2);
} else {
pSegment->m_Result.im = pHRD->decode_MMR(m_pStream, pPause);
if (pSegment->m_Result.im == NULL) {
nRet = JBIG2_ERROR_FATAL;
goto failed;
}
m_pStream->alignByte();
}
if (pSegment->m_cFlags.s.type != 20) {
if (!m_bBufSpecified) {
JBig2PageInfo* pPageInfo = m_pPageInfoList->getLast();
if ((pPageInfo->m_bIsStriped == 1) &&
(ri.y + ri.height > m_pPage->m_nHeight)) {
m_pPage->expand(ri.y + ri.height, (pPageInfo->m_cFlags & 4) ? 1 : 0);
}
}
m_pPage->composeFrom(ri.x, ri.y, pSegment->m_Result.im,
(JBig2ComposeOp)(ri.flags & 0x03));
delete pSegment->m_Result.im;
pSegment->m_Result.im = NULL;
}
delete pHRD;
return JBIG2_SUCCESS;
failed:
delete pHRD;
return nRet;
}
int32_t CJBig2_Context::parseGenericRegion(CJBig2_Segment* pSegment,
IFX_Pause* pPause) {
FX_DWORD dwTemp;
uint8_t cFlags;
int32_t i, nRet;
if (m_pGRD == NULL) {
JBIG2_ALLOC(m_pGRD, CJBig2_GRDProc());
if ((parseRegionInfo(&m_ri) != JBIG2_SUCCESS) ||
(m_pStream->read1Byte(&cFlags) != 0)) {
m_pModule->JBig2_Error("generic region segment : data header too short.");
nRet = JBIG2_ERROR_TOO_SHORT;
goto failed;
}
if (m_ri.height < 0 || m_ri.width < 0) {
m_pModule->JBig2_Error("generic region segment : wrong data.");
nRet = JBIG2_FAILED;
goto failed;
}
m_pGRD->GBW = m_ri.width;
m_pGRD->GBH = m_ri.height;
m_pGRD->MMR = cFlags & 0x01;
m_pGRD->GBTEMPLATE = (cFlags >> 1) & 0x03;
m_pGRD->TPGDON = (cFlags >> 3) & 0x01;
if (m_pGRD->MMR == 0) {
if (m_pGRD->GBTEMPLATE == 0) {
for (i = 0; i < 8; i++) {
if (m_pStream->read1Byte((uint8_t*)&m_pGRD->GBAT[i]) != 0) {
m_pModule->JBig2_Error(
"generic region segment : data header too short.");
nRet = JBIG2_ERROR_TOO_SHORT;
goto failed;
}
}
} else {
for (i = 0; i < 2; i++) {
if (m_pStream->read1Byte((uint8_t*)&m_pGRD->GBAT[i]) != 0) {
m_pModule->JBig2_Error(
"generic region segment : data header too short.");
nRet = JBIG2_ERROR_TOO_SHORT;
goto failed;
}
}
}
}
m_pGRD->USESKIP = 0;
}
pSegment->m_nResultType = JBIG2_IMAGE_POINTER;
if (m_pGRD->MMR == 0) {
dwTemp =
m_pGRD->GBTEMPLATE == 0 ? 65536 : m_pGRD->GBTEMPLATE == 1 ? 8192 : 1024;
if (m_gbContext == NULL) {
m_gbContext = (JBig2ArithCtx*)m_pModule->JBig2_Malloc(
sizeof(JBig2ArithCtx) * dwTemp);
JBIG2_memset(m_gbContext, 0, sizeof(JBig2ArithCtx) * dwTemp);
}
if (m_pArithDecoder == NULL) {
JBIG2_ALLOC(m_pArithDecoder, CJBig2_ArithDecoder(m_pStream));
m_ProcessiveStatus = m_pGRD->Start_decode_Arith(
&pSegment->m_Result.im, m_pArithDecoder, m_gbContext, pPause);
} else {
m_ProcessiveStatus = m_pGRD->Continue_decode(pPause);
}
if (m_ProcessiveStatus == FXCODEC_STATUS_DECODE_TOBECONTINUE) {
if (pSegment->m_cFlags.s.type != 36) {
if (!m_bBufSpecified) {
JBig2PageInfo* pPageInfo = m_pPageInfoList->getLast();
if ((pPageInfo->m_bIsStriped == 1) &&
(m_ri.y + m_ri.height > m_pPage->m_nHeight)) {
m_pPage->expand(m_ri.y + m_ri.height,
(pPageInfo->m_cFlags & 4) ? 1 : 0);
}
}
FX_RECT Rect = m_pGRD->GetReplaceRect();
m_pPage->composeFrom(m_ri.x + Rect.left, m_ri.y + Rect.top,
pSegment->m_Result.im,
(JBig2ComposeOp)(m_ri.flags & 0x03), &Rect);
}
return JBIG2_SUCCESS;
} else {
delete m_pArithDecoder;
m_pArithDecoder = NULL;
if (pSegment->m_Result.im == NULL) {
m_pModule->JBig2_Free(m_gbContext);
nRet = JBIG2_ERROR_FATAL;
m_gbContext = NULL;
m_ProcessiveStatus = FXCODEC_STATUS_ERROR;
goto failed;
}
m_pModule->JBig2_Free(m_gbContext);
m_gbContext = NULL;
m_pStream->alignByte();
m_pStream->offset(2);
}
} else {
FXCODEC_STATUS status =
m_pGRD->Start_decode_MMR(&pSegment->m_Result.im, m_pStream, pPause);
while (status == FXCODEC_STATUS_DECODE_TOBECONTINUE) {
m_pGRD->Continue_decode(pPause);
}
if (pSegment->m_Result.im == NULL) {
nRet = JBIG2_ERROR_FATAL;
goto failed;
}
m_pStream->alignByte();
}
if (pSegment->m_cFlags.s.type != 36) {
if (!m_bBufSpecified) {
JBig2PageInfo* pPageInfo = m_pPageInfoList->getLast();
if ((pPageInfo->m_bIsStriped == 1) &&
(m_ri.y + m_ri.height > m_pPage->m_nHeight)) {
m_pPage->expand(m_ri.y + m_ri.height,
(pPageInfo->m_cFlags & 4) ? 1 : 0);
}
}
FX_RECT Rect = m_pGRD->GetReplaceRect();
m_pPage->composeFrom(m_ri.x + Rect.left, m_ri.y + Rect.top,
pSegment->m_Result.im,
(JBig2ComposeOp)(m_ri.flags & 0x03), &Rect);
delete pSegment->m_Result.im;
pSegment->m_Result.im = NULL;
}
delete m_pGRD;
m_pGRD = NULL;
return JBIG2_SUCCESS;
failed:
delete m_pGRD;
m_pGRD = NULL;
return nRet;
}
int32_t CJBig2_Context::parseGenericRefinementRegion(CJBig2_Segment* pSegment) {
FX_DWORD dwTemp;
JBig2RegionInfo ri;
CJBig2_Segment* pSeg;
int32_t i, nRet;
uint8_t cFlags;
JBig2ArithCtx* grContext;
CJBig2_GRRDProc* pGRRD;
CJBig2_ArithDecoder* pArithDecoder;
JBIG2_ALLOC(pGRRD, CJBig2_GRRDProc());
if ((parseRegionInfo(&ri) != JBIG2_SUCCESS) ||
(m_pStream->read1Byte(&cFlags) != 0)) {
m_pModule->JBig2_Error(
"generic refinement region segment : data header too short.");
nRet = JBIG2_ERROR_TOO_SHORT;
goto failed;
}
pGRRD->GRW = ri.width;
pGRRD->GRH = ri.height;
pGRRD->GRTEMPLATE = cFlags & 0x01;
pGRRD->TPGRON = (cFlags >> 1) & 0x01;
if (pGRRD->GRTEMPLATE == 0) {
for (i = 0; i < 4; i++) {
if (m_pStream->read1Byte((uint8_t*)&pGRRD->GRAT[i]) != 0) {
m_pModule->JBig2_Error(
"generic refinement region segment : data header too short.");
nRet = JBIG2_ERROR_TOO_SHORT;
goto failed;
}
}
}
pSeg = NULL;
if (pSegment->m_nReferred_to_segment_count > 0) {
for (i = 0; i < pSegment->m_nReferred_to_segment_count; i++) {
pSeg = findSegmentByNumber(pSegment->m_pReferred_to_segment_numbers[0]);
if (pSeg == NULL) {
m_pModule->JBig2_Error(
"generic refinement region segment : can't find refered to "
"segments");
nRet = JBIG2_ERROR_FATAL;
goto failed;
}
if ((pSeg->m_cFlags.s.type == 4) || (pSeg->m_cFlags.s.type == 20) ||
(pSeg->m_cFlags.s.type == 36) || (pSeg->m_cFlags.s.type == 40)) {
break;
}
}
if (i >= pSegment->m_nReferred_to_segment_count) {
m_pModule->JBig2_Error(
"generic refinement region segment : can't find refered to "
"intermediate region");
nRet = JBIG2_ERROR_FATAL;
goto failed;
}
pGRRD->GRREFERENCE = pSeg->m_Result.im;
} else {
pGRRD->GRREFERENCE = m_pPage;
}
pGRRD->GRREFERENCEDX = 0;
pGRRD->GRREFERENCEDY = 0;
dwTemp = pGRRD->GRTEMPLATE ? 1 << 10 : 1 << 13;
grContext =
(JBig2ArithCtx*)m_pModule->JBig2_Malloc2(sizeof(JBig2ArithCtx), dwTemp);
JBIG2_memset(grContext, 0, sizeof(JBig2ArithCtx) * dwTemp);
JBIG2_ALLOC(pArithDecoder, CJBig2_ArithDecoder(m_pStream));
pSegment->m_nResultType = JBIG2_IMAGE_POINTER;
pSegment->m_Result.im = pGRRD->decode(pArithDecoder, grContext);
delete pArithDecoder;
if (pSegment->m_Result.im == NULL) {
m_pModule->JBig2_Free(grContext);
nRet = JBIG2_ERROR_FATAL;
goto failed;
}
m_pModule->JBig2_Free(grContext);
m_pStream->alignByte();
m_pStream->offset(2);
if (pSegment->m_cFlags.s.type != 40) {
if (!m_bBufSpecified) {
JBig2PageInfo* pPageInfo = m_pPageInfoList->getLast();
if ((pPageInfo->m_bIsStriped == 1) &&
(ri.y + ri.height > m_pPage->m_nHeight)) {
m_pPage->expand(ri.y + ri.height, (pPageInfo->m_cFlags & 4) ? 1 : 0);
}
}
m_pPage->composeFrom(ri.x, ri.y, pSegment->m_Result.im,
(JBig2ComposeOp)(ri.flags & 0x03));
delete pSegment->m_Result.im;
pSegment->m_Result.im = NULL;
}
delete pGRRD;
return JBIG2_SUCCESS;
failed:
delete pGRRD;
return nRet;
}
int32_t CJBig2_Context::parseTable(CJBig2_Segment* pSegment) {
pSegment->m_nResultType = JBIG2_HUFFMAN_TABLE_POINTER;
JBIG2_ALLOC(pSegment->m_Result.ht, CJBig2_HuffmanTable(m_pStream));
if (!pSegment->m_Result.ht->isOK()) {
delete pSegment->m_Result.ht;
pSegment->m_Result.ht = NULL;
return JBIG2_ERROR_FATAL;
}
m_pStream->alignByte();
return JBIG2_SUCCESS;
}
int32_t CJBig2_Context::parseRegionInfo(JBig2RegionInfo* pRI) {
if ((m_pStream->readInteger((FX_DWORD*)&pRI->width) != 0) ||
(m_pStream->readInteger((FX_DWORD*)&pRI->height) != 0) ||
(m_pStream->readInteger((FX_DWORD*)&pRI->x) != 0) ||
(m_pStream->readInteger((FX_DWORD*)&pRI->y) != 0) ||
(m_pStream->read1Byte(&pRI->flags) != 0)) {
return JBIG2_ERROR_TOO_SHORT;
}
return JBIG2_SUCCESS;
}
JBig2HuffmanCode* CJBig2_Context::decodeSymbolIDHuffmanTable(
CJBig2_BitStream* pStream,
FX_DWORD SBNUMSYMS) {
JBig2HuffmanCode* SBSYMCODES;
int32_t runcodes[35];
int32_t runcodes_len[35];
int32_t runcode;
int32_t i;
int32_t j;
int32_t nVal;
int32_t nBits;
int32_t run;
FX_DWORD nTemp;
SBSYMCODES = (JBig2HuffmanCode*)m_pModule->JBig2_Malloc2(
sizeof(JBig2HuffmanCode), SBNUMSYMS);
for (i = 0; i < 35; i++) {
if (pStream->readNBits(4, &runcodes_len[i]) != 0) {
goto failed;
}
}
huffman_assign_code(runcodes, runcodes_len, 35);
i = 0;
while (i < (int)SBNUMSYMS) {
nVal = 0;
nBits = 0;
for (;;) {
if (pStream->read1Bit(&nTemp) != 0) {
goto failed;
}
nVal = (nVal << 1) | nTemp;
nBits++;
for (j = 0; j < 35; j++) {
if ((nBits == runcodes_len[j]) && (nVal == runcodes[j])) {
break;
}
}
if (j < 35) {
break;
}
}
runcode = j;
if (runcode < 32) {
SBSYMCODES[i].codelen = runcode;
run = 0;
} else if (runcode == 32) {
if (pStream->readNBits(2, &nTemp) != 0) {
goto failed;
}
run = nTemp + 3;
} else if (runcode == 33) {
if (pStream->readNBits(3, &nTemp) != 0) {
goto failed;
}
run = nTemp + 3;
} else if (runcode == 34) {
if (pStream->readNBits(7, &nTemp) != 0) {
goto failed;
}
run = nTemp + 11;
}
if (run > 0) {
if (i + run > (int)SBNUMSYMS) {
goto failed;
}
for (j = 0; j < run; j++) {
if (runcode == 32 && i > 0) {
SBSYMCODES[i + j].codelen = SBSYMCODES[i - 1].codelen;
} else {
SBSYMCODES[i + j].codelen = 0;
}
}
i += run;
} else {
i++;
}
}
huffman_assign_code(SBSYMCODES, SBNUMSYMS);
return SBSYMCODES;
failed:
m_pModule->JBig2_Free(SBSYMCODES);
return NULL;
}
void CJBig2_Context::huffman_assign_code(int* CODES, int* PREFLEN, int NTEMP) {
int CURLEN, LENMAX, CURCODE, CURTEMP, i;
int* LENCOUNT;
int* FIRSTCODE;
LENMAX = 0;
for (i = 0; i < NTEMP; i++) {
if (PREFLEN[i] > LENMAX) {
LENMAX = PREFLEN[i];
}
}
LENCOUNT = (int*)m_pModule->JBig2_Malloc2(sizeof(int), (LENMAX + 1));
JBIG2_memset(LENCOUNT, 0, sizeof(int) * (LENMAX + 1));
FIRSTCODE = (int*)m_pModule->JBig2_Malloc2(sizeof(int), (LENMAX + 1));
for (i = 0; i < NTEMP; i++) {
LENCOUNT[PREFLEN[i]]++;
}
CURLEN = 1;
FIRSTCODE[0] = 0;
LENCOUNT[0] = 0;
while (CURLEN <= LENMAX) {
FIRSTCODE[CURLEN] = (FIRSTCODE[CURLEN - 1] + LENCOUNT[CURLEN - 1]) << 1;
CURCODE = FIRSTCODE[CURLEN];
CURTEMP = 0;
while (CURTEMP < NTEMP) {
if (PREFLEN[CURTEMP] == CURLEN) {
CODES[CURTEMP] = CURCODE;
CURCODE = CURCODE + 1;
}
CURTEMP = CURTEMP + 1;
}
CURLEN = CURLEN + 1;
}
m_pModule->JBig2_Free(LENCOUNT);
m_pModule->JBig2_Free(FIRSTCODE);
}
void CJBig2_Context::huffman_assign_code(JBig2HuffmanCode* SBSYMCODES,
int NTEMP) {
int CURLEN, LENMAX, CURCODE, CURTEMP, i;
int* LENCOUNT;
int* FIRSTCODE;
LENMAX = 0;
for (i = 0; i < NTEMP; i++) {
if (SBSYMCODES[i].codelen > LENMAX) {
LENMAX = SBSYMCODES[i].codelen;
}
}
LENCOUNT = (int*)m_pModule->JBig2_Malloc2(sizeof(int), (LENMAX + 1));
JBIG2_memset(LENCOUNT, 0, sizeof(int) * (LENMAX + 1));
FIRSTCODE = (int*)m_pModule->JBig2_Malloc2(sizeof(int), (LENMAX + 1));
for (i = 0; i < NTEMP; i++) {
LENCOUNT[SBSYMCODES[i].codelen]++;
}
CURLEN = 1;
FIRSTCODE[0] = 0;
LENCOUNT[0] = 0;
while (CURLEN <= LENMAX) {
FIRSTCODE[CURLEN] = (FIRSTCODE[CURLEN - 1] + LENCOUNT[CURLEN - 1]) << 1;
CURCODE = FIRSTCODE[CURLEN];
CURTEMP = 0;
while (CURTEMP < NTEMP) {
if (SBSYMCODES[CURTEMP].codelen == CURLEN) {
SBSYMCODES[CURTEMP].code = CURCODE;
CURCODE = CURCODE + 1;
}
CURTEMP = CURTEMP + 1;
}
CURLEN = CURLEN + 1;
}
m_pModule->JBig2_Free(LENCOUNT);
m_pModule->JBig2_Free(FIRSTCODE);
}