summaryrefslogtreecommitdiff
path: root/core/fxcodec/jbig2/JBig2_Context.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'core/fxcodec/jbig2/JBig2_Context.cpp')
-rw-r--r--core/fxcodec/jbig2/JBig2_Context.cpp1439
1 files changed, 1439 insertions, 0 deletions
diff --git a/core/fxcodec/jbig2/JBig2_Context.cpp b/core/fxcodec/jbig2/JBig2_Context.cpp
new file mode 100644
index 0000000000..0a17fff328
--- /dev/null
+++ b/core/fxcodec/jbig2/JBig2_Context.cpp
@@ -0,0 +1,1439 @@
+// 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 "core/fxcodec/jbig2/JBig2_Context.h"
+
+#include <algorithm>
+#include <list>
+#include <utility>
+#include <vector>
+
+#include "core/fxcodec/jbig2/JBig2_ArithDecoder.h"
+#include "core/fxcodec/jbig2/JBig2_BitStream.h"
+#include "core/fxcodec/jbig2/JBig2_GrdProc.h"
+#include "core/fxcodec/jbig2/JBig2_GrrdProc.h"
+#include "core/fxcodec/jbig2/JBig2_HtrdProc.h"
+#include "core/fxcodec/jbig2/JBig2_HuffmanTable_Standard.h"
+#include "core/fxcodec/jbig2/JBig2_PddProc.h"
+#include "core/fxcodec/jbig2/JBig2_SddProc.h"
+#include "core/fxcodec/jbig2/JBig2_TrdProc.h"
+#include "core/include/fpdfapi/cpdf_stream.h"
+#include "third_party/base/stl_util.h"
+
+namespace {
+
+size_t GetHuffContextSize(uint8_t val) {
+ return val == 0 ? 65536 : val == 1 ? 8192 : 1024;
+}
+
+size_t GetRefAggContextSize(FX_BOOL val) {
+ return val ? 1024 : 8192;
+}
+
+} // namespace
+
+// 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.
+static const int kSymbolDictCacheMaxSize = 2;
+
+CJBig2_Context* CJBig2_Context::CreateContext(
+ CPDF_StreamAcc* pGlobalStream,
+ CPDF_StreamAcc* pSrcStream,
+ std::list<CJBig2_CachePair>* pSymbolDictCache,
+ IFX_Pause* pPause) {
+ return new CJBig2_Context(pGlobalStream, pSrcStream, pSymbolDictCache, pPause,
+ false);
+}
+
+void CJBig2_Context::DestroyContext(CJBig2_Context* pContext) {
+ delete pContext;
+}
+
+CJBig2_Context::CJBig2_Context(CPDF_StreamAcc* pGlobalStream,
+ CPDF_StreamAcc* pSrcStream,
+ std::list<CJBig2_CachePair>* pSymbolDictCache,
+ IFX_Pause* pPause,
+ bool bIsGlobal)
+ : m_nSegmentDecoded(0),
+ m_bInPage(false),
+ m_bBufSpecified(false),
+ m_PauseStep(10),
+ m_pPause(pPause),
+ m_ProcessingStatus(FXCODEC_STATUS_FRAME_READY),
+ m_gbContext(NULL),
+ m_dwOffset(0),
+ m_pSymbolDictCache(pSymbolDictCache),
+ m_bIsGlobal(bIsGlobal) {
+ if (pGlobalStream && (pGlobalStream->GetSize() > 0)) {
+ m_pGlobalContext = new CJBig2_Context(nullptr, pGlobalStream,
+ pSymbolDictCache, pPause, true);
+ } else {
+ m_pGlobalContext = nullptr;
+ }
+
+ m_pStream.reset(new CJBig2_BitStream(pSrcStream));
+}
+
+CJBig2_Context::~CJBig2_Context() {
+ FX_Free(m_gbContext);
+ m_gbContext = NULL;
+ delete m_pGlobalContext;
+ m_pGlobalContext = NULL;
+}
+
+int32_t CJBig2_Context::decode_SquentialOrgnazation(IFX_Pause* pPause) {
+ int32_t nRet;
+ if (m_pStream->getByteLeft() <= 0)
+ return JBIG2_END_OF_FILE;
+
+ while (m_pStream->getByteLeft() >= JBIG2_MIN_SEGMENT_SIZE) {
+ if (!m_pSegment) {
+ m_pSegment.reset(new CJBig2_Segment);
+ nRet = parseSegmentHeader(m_pSegment.get());
+ if (nRet != JBIG2_SUCCESS) {
+ m_pSegment.reset();
+ return nRet;
+ }
+ m_dwOffset = m_pStream->getOffset();
+ }
+ nRet = parseSegmentData(m_pSegment.get(), pPause);
+ if (m_ProcessingStatus == FXCODEC_STATUS_DECODE_TOBECONTINUE) {
+ m_ProcessingStatus = FXCODEC_STATUS_DECODE_TOBECONTINUE;
+ m_PauseStep = 2;
+ return JBIG2_SUCCESS;
+ }
+ if (nRet == JBIG2_END_OF_PAGE || nRet == JBIG2_END_OF_FILE) {
+ m_pSegment.reset();
+ return JBIG2_SUCCESS;
+ }
+ if (nRet != JBIG2_SUCCESS) {
+ m_pSegment.reset();
+ return nRet;
+ }
+ if (m_pSegment->m_dwData_length != 0xffffffff) {
+ m_dwOffset += m_pSegment->m_dwData_length;
+ m_pStream->setOffset(m_dwOffset);
+ } else {
+ m_pStream->offset(4);
+ }
+ m_SegmentList.push_back(m_pSegment.release());
+ if (m_pStream->getByteLeft() > 0 && m_pPage && pPause &&
+ pPause->NeedToPauseNow()) {
+ m_ProcessingStatus = FXCODEC_STATUS_DECODE_TOBECONTINUE;
+ m_PauseStep = 2;
+ return JBIG2_SUCCESS;
+ }
+ }
+ 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) {
+ int32_t nRet;
+ while (m_pStream->getByteLeft() > JBIG2_MIN_SEGMENT_SIZE) {
+ std::unique_ptr<CJBig2_Segment> pSegment(new CJBig2_Segment);
+ nRet = parseSegmentHeader(pSegment.get());
+ if (nRet != JBIG2_SUCCESS) {
+ return nRet;
+ } else if (pSegment->m_cFlags.s.type == 51) {
+ break;
+ }
+ m_SegmentList.push_back(pSegment.release());
+ if (pPause && m_pPause && pPause->NeedToPauseNow()) {
+ m_PauseStep = 3;
+ m_ProcessingStatus = FXCODEC_STATUS_DECODE_TOBECONTINUE;
+ return JBIG2_SUCCESS;
+ }
+ }
+ m_nSegmentDecoded = 0;
+ return decode_RandomOrgnazation(pPause);
+}
+int32_t CJBig2_Context::decode_RandomOrgnazation(IFX_Pause* pPause) {
+ for (; m_nSegmentDecoded < m_SegmentList.size(); ++m_nSegmentDecoded) {
+ int32_t nRet =
+ parseSegmentData(m_SegmentList.get(m_nSegmentDecoded), pPause);
+ if (nRet == JBIG2_END_OF_PAGE || nRet == JBIG2_END_OF_FILE)
+ return JBIG2_SUCCESS;
+
+ if (nRet != JBIG2_SUCCESS)
+ return nRet;
+
+ if (m_pPage && pPause && pPause->NeedToPauseNow()) {
+ m_PauseStep = 4;
+ m_ProcessingStatus = 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_ProcessingStatus = FXCODEC_STATUS_ERROR;
+ return nRet;
+ }
+ }
+ m_PauseStep = 0;
+ m_pPage.reset(new CJBig2_Image(width, height, stride, pBuf));
+ m_bBufSpecified = true;
+ if (pPause && pPause->NeedToPauseNow()) {
+ m_PauseStep = 1;
+ m_ProcessingStatus = FXCODEC_STATUS_DECODE_TOBECONTINUE;
+ return nRet;
+ }
+ return Continue(pPause);
+}
+int32_t CJBig2_Context::Continue(IFX_Pause* pPause) {
+ m_ProcessingStatus = FXCODEC_STATUS_DECODE_READY;
+ int32_t nRet;
+ if (m_PauseStep <= 1) {
+ nRet = decode_EmbedOrgnazation(pPause);
+ } 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_ProcessingStatus = FXCODEC_STATUS_DECODE_FINISH;
+ return JBIG2_SUCCESS;
+ }
+ if (m_ProcessingStatus == FXCODEC_STATUS_DECODE_TOBECONTINUE) {
+ return nRet;
+ }
+ m_PauseStep = 5;
+ if (!m_bBufSpecified && nRet == JBIG2_SUCCESS) {
+ m_ProcessingStatus = FXCODEC_STATUS_DECODE_FINISH;
+ return JBIG2_SUCCESS;
+ }
+ if (nRet == JBIG2_SUCCESS) {
+ m_ProcessingStatus = FXCODEC_STATUS_DECODE_FINISH;
+ } else {
+ m_ProcessingStatus = FXCODEC_STATUS_ERROR;
+ }
+ return nRet;
+}
+
+CJBig2_Segment* CJBig2_Context::findSegmentByNumber(FX_DWORD dwNumber) {
+ if (m_pGlobalContext) {
+ CJBig2_Segment* pSeg = m_pGlobalContext->findSegmentByNumber(dwNumber);
+ if (pSeg) {
+ return pSeg;
+ }
+ }
+ for (size_t i = 0; i < m_SegmentList.size(); ++i) {
+ CJBig2_Segment* pSeg = m_SegmentList.get(i);
+ if (pSeg->m_dwNumber == dwNumber) {
+ return pSeg;
+ }
+ }
+ return nullptr;
+}
+CJBig2_Segment* CJBig2_Context::findReferredSegmentByTypeAndIndex(
+ CJBig2_Segment* pSegment,
+ uint8_t cType,
+ int32_t nIndex) {
+ int32_t count = 0;
+ for (int32_t i = 0; i < pSegment->m_nReferred_to_segment_count; ++i) {
+ CJBig2_Segment* pSeg =
+ findSegmentByNumber(pSegment->m_pReferred_to_segment_numbers[i]);
+ if (pSeg && pSeg->m_cFlags.s.type == cType) {
+ if (count == nIndex)
+ return pSeg;
+ ++count;
+ }
+ }
+ return NULL;
+}
+int32_t CJBig2_Context::parseSegmentHeader(CJBig2_Segment* pSegment) {
+ if (m_pStream->readInteger(&pSegment->m_dwNumber) != 0 ||
+ m_pStream->read1Byte(&pSegment->m_cFlags.c) != 0) {
+ return JBIG2_ERROR_TOO_SHORT;
+ }
+
+ FX_DWORD dwTemp;
+ uint8_t cTemp = m_pStream->getCurByte();
+ if ((cTemp >> 5) == 7) {
+ if (m_pStream->readInteger(
+ (FX_DWORD*)&pSegment->m_nReferred_to_segment_count) != 0) {
+ return JBIG2_ERROR_TOO_SHORT;
+ }
+ pSegment->m_nReferred_to_segment_count &= 0x1fffffff;
+ if (pSegment->m_nReferred_to_segment_count >
+ JBIG2_MAX_REFERRED_SEGMENT_COUNT) {
+ return JBIG2_ERROR_LIMIT;
+ }
+ dwTemp = 5 + 4 + (pSegment->m_nReferred_to_segment_count + 1) / 8;
+ } else {
+ if (m_pStream->read1Byte(&cTemp) != 0)
+ return JBIG2_ERROR_TOO_SHORT;
+
+ pSegment->m_nReferred_to_segment_count = cTemp >> 5;
+ dwTemp = 5 + 1;
+ }
+ uint8_t cSSize =
+ pSegment->m_dwNumber > 65536 ? 4 : pSegment->m_dwNumber > 256 ? 2 : 1;
+ uint8_t cPSize = pSegment->m_cFlags.s.page_association_size ? 4 : 1;
+ if (pSegment->m_nReferred_to_segment_count) {
+ pSegment->m_pReferred_to_segment_numbers =
+ FX_Alloc(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)
+ return JBIG2_ERROR_TOO_SHORT;
+
+ pSegment->m_pReferred_to_segment_numbers[i] = cTemp;
+ break;
+ case 2:
+ FX_WORD wTemp;
+ if (m_pStream->readShortInteger(&wTemp) != 0)
+ return JBIG2_ERROR_TOO_SHORT;
+
+ pSegment->m_pReferred_to_segment_numbers[i] = wTemp;
+ break;
+ case 4:
+ if (m_pStream->readInteger(&dwTemp) != 0)
+ return JBIG2_ERROR_TOO_SHORT;
+
+ pSegment->m_pReferred_to_segment_numbers[i] = dwTemp;
+ break;
+ }
+ if (pSegment->m_pReferred_to_segment_numbers[i] >= pSegment->m_dwNumber)
+ return JBIG2_ERROR_TOO_SHORT;
+ }
+ }
+ if (cPSize == 1) {
+ if (m_pStream->read1Byte(&cTemp) != 0)
+ return JBIG2_ERROR_TOO_SHORT;
+ pSegment->m_dwPage_association = cTemp;
+ } else {
+ if (m_pStream->readInteger(&pSegment->m_dwPage_association) != 0) {
+ return JBIG2_ERROR_TOO_SHORT;
+ }
+ }
+ if (m_pStream->readInteger(&pSegment->m_dwData_length) != 0)
+ return JBIG2_ERROR_TOO_SHORT;
+
+ pSegment->m_dwObjNum = m_pStream->getObjNum();
+ pSegment->m_dwDataOffset = m_pStream->getOffset();
+ pSegment->m_State = JBIG2_SEGMENT_DATA_UNPARSED;
+ return JBIG2_SUCCESS;
+}
+
+int32_t CJBig2_Context::parseSegmentData(CJBig2_Segment* pSegment,
+ IFX_Pause* pPause) {
+ int32_t ret = ProcessingParseSegmentData(pSegment, pPause);
+ while (m_ProcessingStatus == FXCODEC_STATUS_DECODE_TOBECONTINUE &&
+ m_pStream->getByteLeft() > 0) {
+ ret = ProcessingParseSegmentData(pSegment, pPause);
+ }
+ return ret;
+}
+
+int32_t CJBig2_Context::ProcessingParseSegmentData(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_bInPage)
+ return JBIG2_ERROR_FATAL;
+ return parseTextRegion(pSegment);
+ case 16:
+ return parsePatternDict(pSegment, pPause);
+ case 20:
+ case 22:
+ case 23:
+ if (!m_bInPage)
+ return JBIG2_ERROR_FATAL;
+ return parseHalftoneRegion(pSegment, pPause);
+ case 36:
+ case 38:
+ case 39:
+ if (!m_bInPage)
+ return JBIG2_ERROR_FATAL;
+ return parseGenericRegion(pSegment, pPause);
+ case 40:
+ case 42:
+ case 43:
+ if (!m_bInPage)
+ return JBIG2_ERROR_FATAL;
+ return parseGenericRefinementRegion(pSegment);
+ case 48: {
+ FX_WORD wTemp;
+ std::unique_ptr<JBig2PageInfo> pPageInfo(new 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) {
+ return JBIG2_ERROR_TOO_SHORT;
+ }
+ pPageInfo->m_bIsStriped = !!(wTemp & 0x8000);
+ pPageInfo->m_wMaxStripeSize = wTemp & 0x7fff;
+ bool bMaxHeight = (pPageInfo->m_dwHeight == 0xffffffff);
+ if (bMaxHeight && pPageInfo->m_bIsStriped != TRUE)
+ pPageInfo->m_bIsStriped = TRUE;
+
+ if (!m_bBufSpecified) {
+ FX_DWORD height =
+ bMaxHeight ? pPageInfo->m_wMaxStripeSize : pPageInfo->m_dwHeight;
+ m_pPage.reset(new CJBig2_Image(pPageInfo->m_dwWidth, height));
+ }
+
+ if (!m_pPage->m_pData) {
+ m_ProcessingStatus = FXCODEC_STATUS_ERROR;
+ return JBIG2_ERROR_TOO_SHORT;
+ }
+
+ m_pPage->fill((pPageInfo->m_cFlags & 4) ? 1 : 0);
+ m_PageInfoList.push_back(pPageInfo.release());
+ m_bInPage = true;
+ } break;
+ case 49:
+ m_bInPage = false;
+ 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;
+}
+
+int32_t CJBig2_Context::parseSymbolDict(CJBig2_Segment* pSegment,
+ IFX_Pause* pPause) {
+ FX_WORD wFlags;
+ if (m_pStream->readShortInteger(&wFlags) != 0)
+ return JBIG2_ERROR_TOO_SHORT;
+
+ std::unique_ptr<CJBig2_SDDProc> pSymbolDictDecoder(new CJBig2_SDDProc);
+ pSymbolDictDecoder->SDHUFF = wFlags & 0x0001;
+ pSymbolDictDecoder->SDREFAGG = (wFlags >> 1) & 0x0001;
+ pSymbolDictDecoder->SDTEMPLATE = (wFlags >> 10) & 0x0003;
+ pSymbolDictDecoder->SDRTEMPLATE = (wFlags >> 12) & 0x0003;
+ uint8_t cSDHUFFDH = (wFlags >> 2) & 0x0003;
+ uint8_t cSDHUFFDW = (wFlags >> 4) & 0x0003;
+ uint8_t cSDHUFFBMSIZE = (wFlags >> 6) & 0x0001;
+ uint8_t cSDHUFFAGGINST = (wFlags >> 7) & 0x0001;
+ if (pSymbolDictDecoder->SDHUFF == 0) {
+ const FX_DWORD dwTemp = (pSymbolDictDecoder->SDTEMPLATE == 0) ? 8 : 2;
+ for (FX_DWORD i = 0; i < dwTemp; ++i) {
+ if (m_pStream->read1Byte((uint8_t*)&pSymbolDictDecoder->SDAT[i]) != 0)
+ return JBIG2_ERROR_TOO_SHORT;
+ }
+ }
+ if (pSymbolDictDecoder->SDREFAGG == 1 &&
+ pSymbolDictDecoder->SDRTEMPLATE == 0) {
+ for (int32_t i = 0; i < 4; ++i) {
+ if (m_pStream->read1Byte((uint8_t*)&pSymbolDictDecoder->SDRAT[i]) != 0)
+ return JBIG2_ERROR_TOO_SHORT;
+ }
+ }
+ if (m_pStream->readInteger(&pSymbolDictDecoder->SDNUMEXSYMS) != 0 ||
+ m_pStream->readInteger(&pSymbolDictDecoder->SDNUMNEWSYMS) != 0) {
+ return JBIG2_ERROR_TOO_SHORT;
+ }
+ if (pSymbolDictDecoder->SDNUMEXSYMS > JBIG2_MAX_EXPORT_SYSMBOLS ||
+ pSymbolDictDecoder->SDNUMNEWSYMS > JBIG2_MAX_NEW_SYSMBOLS) {
+ return JBIG2_ERROR_LIMIT;
+ }
+ for (int32_t i = 0; i < pSegment->m_nReferred_to_segment_count; ++i) {
+ if (!findSegmentByNumber(pSegment->m_pReferred_to_segment_numbers[i]))
+ return JBIG2_ERROR_FATAL;
+ }
+ CJBig2_Segment* pLRSeg = nullptr;
+ pSymbolDictDecoder->SDNUMINSYMS = 0;
+ for (int32_t i = 0; i < pSegment->m_nReferred_to_segment_count; ++i) {
+ CJBig2_Segment* pSeg =
+ findSegmentByNumber(pSegment->m_pReferred_to_segment_numbers[i]);
+ if (pSeg->m_cFlags.s.type == 0) {
+ pSymbolDictDecoder->SDNUMINSYMS += pSeg->m_Result.sd->NumImages();
+ pLRSeg = pSeg;
+ }
+ }
+
+ std::unique_ptr<CJBig2_Image*, FxFreeDeleter> SDINSYMS;
+ if (pSymbolDictDecoder->SDNUMINSYMS != 0) {
+ SDINSYMS.reset(FX_Alloc(CJBig2_Image*, pSymbolDictDecoder->SDNUMINSYMS));
+ FX_DWORD dwTemp = 0;
+ for (int32_t i = 0; i < pSegment->m_nReferred_to_segment_count; ++i) {
+ CJBig2_Segment* pSeg =
+ findSegmentByNumber(pSegment->m_pReferred_to_segment_numbers[i]);
+ if (pSeg->m_cFlags.s.type == 0) {
+ const CJBig2_SymbolDict& dict = *pSeg->m_Result.sd;
+ for (size_t j = 0; j < dict.NumImages(); ++j)
+ SDINSYMS.get()[dwTemp + j] = dict.GetImage(j);
+ dwTemp += dict.NumImages();
+ }
+ }
+ }
+ pSymbolDictDecoder->SDINSYMS = SDINSYMS.get();
+
+ std::unique_ptr<CJBig2_HuffmanTable> Table_B1;
+ std::unique_ptr<CJBig2_HuffmanTable> Table_B2;
+ std::unique_ptr<CJBig2_HuffmanTable> Table_B3;
+ std::unique_ptr<CJBig2_HuffmanTable> Table_B4;
+ std::unique_ptr<CJBig2_HuffmanTable> Table_B5;
+ if (pSymbolDictDecoder->SDHUFF == 1) {
+ if (cSDHUFFDH == 2 || cSDHUFFDW == 2)
+ return JBIG2_ERROR_FATAL;
+
+ int32_t nIndex = 0;
+ if (cSDHUFFDH == 0) {
+ Table_B4.reset(new CJBig2_HuffmanTable(HuffmanTable_B4,
+ FX_ArraySize(HuffmanTable_B4),
+ HuffmanTable_HTOOB_B4));
+ pSymbolDictDecoder->SDHUFFDH = Table_B4.get();
+ } else if (cSDHUFFDH == 1) {
+ Table_B5.reset(new CJBig2_HuffmanTable(HuffmanTable_B5,
+ FX_ArraySize(HuffmanTable_B5),
+ HuffmanTable_HTOOB_B5));
+ pSymbolDictDecoder->SDHUFFDH = Table_B5.get();
+ } else {
+ CJBig2_Segment* pSeg =
+ findReferredSegmentByTypeAndIndex(pSegment, 53, nIndex++);
+ if (!pSeg)
+ return JBIG2_ERROR_FATAL;
+ pSymbolDictDecoder->SDHUFFDH = pSeg->m_Result.ht;
+ }
+ if (cSDHUFFDW == 0) {
+ Table_B2.reset(new CJBig2_HuffmanTable(HuffmanTable_B2,
+ FX_ArraySize(HuffmanTable_B2),
+ HuffmanTable_HTOOB_B2));
+ pSymbolDictDecoder->SDHUFFDW = Table_B2.get();
+ } else if (cSDHUFFDW == 1) {
+ Table_B3.reset(new CJBig2_HuffmanTable(HuffmanTable_B3,
+ FX_ArraySize(HuffmanTable_B3),
+ HuffmanTable_HTOOB_B3));
+ pSymbolDictDecoder->SDHUFFDW = Table_B3.get();
+ } else {
+ CJBig2_Segment* pSeg =
+ findReferredSegmentByTypeAndIndex(pSegment, 53, nIndex++);
+ if (!pSeg)
+ return JBIG2_ERROR_FATAL;
+ pSymbolDictDecoder->SDHUFFDW = pSeg->m_Result.ht;
+ }
+ if (cSDHUFFBMSIZE == 0) {
+ Table_B1.reset(new CJBig2_HuffmanTable(HuffmanTable_B1,
+ FX_ArraySize(HuffmanTable_B1),
+ HuffmanTable_HTOOB_B1));
+ pSymbolDictDecoder->SDHUFFBMSIZE = Table_B1.get();
+ } else {
+ CJBig2_Segment* pSeg =
+ findReferredSegmentByTypeAndIndex(pSegment, 53, nIndex++);
+ if (!pSeg)
+ return JBIG2_ERROR_FATAL;
+ pSymbolDictDecoder->SDHUFFBMSIZE = pSeg->m_Result.ht;
+ }
+ if (pSymbolDictDecoder->SDREFAGG == 1) {
+ if (cSDHUFFAGGINST == 0) {
+ if (!Table_B1) {
+ Table_B1.reset(new CJBig2_HuffmanTable(HuffmanTable_B1,
+ FX_ArraySize(HuffmanTable_B1),
+ HuffmanTable_HTOOB_B1));
+ }
+ pSymbolDictDecoder->SDHUFFAGGINST = Table_B1.get();
+ } else {
+ CJBig2_Segment* pSeg =
+ findReferredSegmentByTypeAndIndex(pSegment, 53, nIndex++);
+ if (!pSeg)
+ return JBIG2_ERROR_FATAL;
+ pSymbolDictDecoder->SDHUFFAGGINST = pSeg->m_Result.ht;
+ }
+ }
+ }
+
+ const bool bUseGbContext = (pSymbolDictDecoder->SDHUFF == 0);
+ const bool bUseGrContext = (pSymbolDictDecoder->SDREFAGG == 1);
+ const size_t gbContextSize =
+ GetHuffContextSize(pSymbolDictDecoder->SDTEMPLATE);
+ const size_t grContextSize =
+ GetRefAggContextSize(pSymbolDictDecoder->SDRTEMPLATE);
+ std::vector<JBig2ArithCtx> gbContext;
+ std::vector<JBig2ArithCtx> grContext;
+ if ((wFlags & 0x0100) && pLRSeg) {
+ if (bUseGbContext) {
+ gbContext = pLRSeg->m_Result.sd->GbContext();
+ if (gbContext.size() != gbContextSize)
+ return JBIG2_ERROR_FATAL;
+ }
+ if (bUseGrContext) {
+ grContext = pLRSeg->m_Result.sd->GrContext();
+ if (grContext.size() != grContextSize)
+ return JBIG2_ERROR_FATAL;
+ }
+ } else {
+ if (bUseGbContext)
+ gbContext.resize(gbContextSize);
+ if (bUseGrContext)
+ grContext.resize(grContextSize);
+ }
+
+ CJBig2_CacheKey key =
+ CJBig2_CacheKey(pSegment->m_dwObjNum, pSegment->m_dwDataOffset);
+ FX_BOOL cache_hit = false;
+ pSegment->m_nResultType = JBIG2_SYMBOL_DICT_POINTER;
+ if (m_bIsGlobal && key.first != 0) {
+ for (auto it = m_pSymbolDictCache->begin(); it != m_pSymbolDictCache->end();
+ ++it) {
+ if (it->first == key) {
+ std::unique_ptr<CJBig2_SymbolDict> copy(it->second->DeepCopy());
+ pSegment->m_Result.sd = copy.release();
+ m_pSymbolDictCache->push_front(*it);
+ m_pSymbolDictCache->erase(it);
+ cache_hit = true;
+ break;
+ }
+ }
+ }
+ if (!cache_hit) {
+ if (bUseGbContext) {
+ std::unique_ptr<CJBig2_ArithDecoder> pArithDecoder(
+ new CJBig2_ArithDecoder(m_pStream.get()));
+ pSegment->m_Result.sd = pSymbolDictDecoder->decode_Arith(
+ pArithDecoder.get(), &gbContext, &grContext);
+ if (!pSegment->m_Result.sd)
+ return JBIG2_ERROR_FATAL;
+
+ m_pStream->alignByte();
+ m_pStream->offset(2);
+ } else {
+ pSegment->m_Result.sd = pSymbolDictDecoder->decode_Huffman(
+ m_pStream.get(), &gbContext, &grContext, pPause);
+ if (!pSegment->m_Result.sd)
+ return JBIG2_ERROR_FATAL;
+ m_pStream->alignByte();
+ }
+ if (m_bIsGlobal && kSymbolDictCacheMaxSize > 0) {
+ std::unique_ptr<CJBig2_SymbolDict> value =
+ pSegment->m_Result.sd->DeepCopy();
+ int size = pdfium::CollectionSize<int>(*m_pSymbolDictCache);
+ while (size >= kSymbolDictCacheMaxSize) {
+ delete m_pSymbolDictCache->back().second;
+ m_pSymbolDictCache->pop_back();
+ --size;
+ }
+ m_pSymbolDictCache->push_front(CJBig2_CachePair(key, value.release()));
+ }
+ }
+ if (wFlags & 0x0200) {
+ if (bUseGbContext)
+ pSegment->m_Result.sd->SetGbContext(gbContext);
+ if (bUseGrContext)
+ pSegment->m_Result.sd->SetGrContext(grContext);
+ }
+ return JBIG2_SUCCESS;
+}
+
+int32_t CJBig2_Context::parseTextRegion(CJBig2_Segment* pSegment) {
+ FX_WORD wFlags;
+ JBig2RegionInfo ri;
+ if (parseRegionInfo(&ri) != JBIG2_SUCCESS ||
+ m_pStream->readShortInteger(&wFlags) != 0) {
+ return JBIG2_ERROR_TOO_SHORT;
+ }
+
+ std::unique_ptr<CJBig2_TRDProc> pTRD(new CJBig2_TRDProc);
+ pTRD->SBW = ri.width;
+ pTRD->SBH = ri.height;
+ pTRD->SBHUFF = wFlags & 0x0001;
+ pTRD->SBREFINE = (wFlags >> 1) & 0x0001;
+ FX_DWORD 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;
+
+ uint8_t cSBHUFFFS;
+ uint8_t cSBHUFFDS;
+ uint8_t cSBHUFFDT;
+ uint8_t cSBHUFFRDW;
+ uint8_t cSBHUFFRDH;
+ uint8_t cSBHUFFRDX;
+ uint8_t cSBHUFFRDY;
+ uint8_t cSBHUFFRSIZE;
+ if (pTRD->SBHUFF == 1) {
+ if (m_pStream->readShortInteger(&wFlags) != 0)
+ return JBIG2_ERROR_TOO_SHORT;
+
+ 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 (int32_t i = 0; i < 4; ++i) {
+ if (m_pStream->read1Byte((uint8_t*)&pTRD->SBRAT[i]) != 0)
+ return JBIG2_ERROR_TOO_SHORT;
+ }
+ }
+ if (m_pStream->readInteger(&pTRD->SBNUMINSTANCES) != 0)
+ return JBIG2_ERROR_TOO_SHORT;
+
+ for (int32_t i = 0; i < pSegment->m_nReferred_to_segment_count; ++i) {
+ if (!findSegmentByNumber(pSegment->m_pReferred_to_segment_numbers[i]))
+ return JBIG2_ERROR_FATAL;
+ }
+
+ pTRD->SBNUMSYMS = 0;
+ for (int32_t i = 0; i < pSegment->m_nReferred_to_segment_count; ++i) {
+ CJBig2_Segment* pSeg =
+ findSegmentByNumber(pSegment->m_pReferred_to_segment_numbers[i]);
+ if (pSeg->m_cFlags.s.type == 0) {
+ pTRD->SBNUMSYMS += pSeg->m_Result.sd->NumImages();
+ }
+ }
+
+ std::unique_ptr<CJBig2_Image*, FxFreeDeleter> SBSYMS;
+ if (pTRD->SBNUMSYMS > 0) {
+ SBSYMS.reset(FX_Alloc(CJBig2_Image*, pTRD->SBNUMSYMS));
+ dwTemp = 0;
+ for (int32_t i = 0; i < pSegment->m_nReferred_to_segment_count; ++i) {
+ CJBig2_Segment* pSeg =
+ findSegmentByNumber(pSegment->m_pReferred_to_segment_numbers[i]);
+ if (pSeg->m_cFlags.s.type == 0) {
+ const CJBig2_SymbolDict& dict = *pSeg->m_Result.sd;
+ for (size_t j = 0; j < dict.NumImages(); ++j)
+ SBSYMS.get()[dwTemp + j] = dict.GetImage(j);
+ dwTemp += dict.NumImages();
+ }
+ }
+ pTRD->SBSYMS = SBSYMS.get();
+ } else {
+ pTRD->SBSYMS = NULL;
+ }
+
+ std::unique_ptr<JBig2HuffmanCode, FxFreeDeleter> SBSYMCODES;
+ if (pTRD->SBHUFF == 1) {
+ SBSYMCODES.reset(
+ decodeSymbolIDHuffmanTable(m_pStream.get(), pTRD->SBNUMSYMS));
+ if (!SBSYMCODES)
+ return JBIG2_ERROR_FATAL;
+
+ m_pStream->alignByte();
+ pTRD->SBSYMCODES = SBSYMCODES.get();
+ } else {
+ dwTemp = 0;
+ while ((FX_DWORD)(1 << dwTemp) < pTRD->SBNUMSYMS) {
+ ++dwTemp;
+ }
+ pTRD->SBSYMCODELEN = (uint8_t)dwTemp;
+ }
+
+ std::unique_ptr<CJBig2_HuffmanTable> Table_B1;
+ std::unique_ptr<CJBig2_HuffmanTable> Table_B6;
+ std::unique_ptr<CJBig2_HuffmanTable> Table_B7;
+ std::unique_ptr<CJBig2_HuffmanTable> Table_B8;
+ std::unique_ptr<CJBig2_HuffmanTable> Table_B9;
+ std::unique_ptr<CJBig2_HuffmanTable> Table_B10;
+ std::unique_ptr<CJBig2_HuffmanTable> Table_B11;
+ std::unique_ptr<CJBig2_HuffmanTable> Table_B12;
+ std::unique_ptr<CJBig2_HuffmanTable> Table_B13;
+ std::unique_ptr<CJBig2_HuffmanTable> Table_B14;
+ std::unique_ptr<CJBig2_HuffmanTable> Table_B15;
+ if (pTRD->SBHUFF == 1) {
+ if (cSBHUFFFS == 2 || cSBHUFFRDW == 2 || cSBHUFFRDH == 2 ||
+ cSBHUFFRDX == 2 || cSBHUFFRDY == 2) {
+ return JBIG2_ERROR_FATAL;
+ }
+ int32_t nIndex = 0;
+ if (cSBHUFFFS == 0) {
+ Table_B6.reset(new CJBig2_HuffmanTable(HuffmanTable_B6,
+ FX_ArraySize(HuffmanTable_B6),
+ HuffmanTable_HTOOB_B6));
+ pTRD->SBHUFFFS = Table_B6.get();
+ } else if (cSBHUFFFS == 1) {
+ Table_B7.reset(new CJBig2_HuffmanTable(HuffmanTable_B7,
+ FX_ArraySize(HuffmanTable_B7),
+ HuffmanTable_HTOOB_B7));
+ pTRD->SBHUFFFS = Table_B7.get();
+ } else {
+ CJBig2_Segment* pSeg =
+ findReferredSegmentByTypeAndIndex(pSegment, 53, nIndex++);
+ if (!pSeg)
+ return JBIG2_ERROR_FATAL;
+ pTRD->SBHUFFFS = pSeg->m_Result.ht;
+ }
+ if (cSBHUFFDS == 0) {
+ Table_B8.reset(new CJBig2_HuffmanTable(HuffmanTable_B8,
+ FX_ArraySize(HuffmanTable_B8),
+ HuffmanTable_HTOOB_B8));
+ pTRD->SBHUFFDS = Table_B8.get();
+ } else if (cSBHUFFDS == 1) {
+ Table_B9.reset(new CJBig2_HuffmanTable(HuffmanTable_B9,
+ FX_ArraySize(HuffmanTable_B9),
+ HuffmanTable_HTOOB_B9));
+ pTRD->SBHUFFDS = Table_B9.get();
+ } else if (cSBHUFFDS == 2) {
+ Table_B10.reset(new CJBig2_HuffmanTable(HuffmanTable_B10,
+ FX_ArraySize(HuffmanTable_B10),
+ HuffmanTable_HTOOB_B10));
+ pTRD->SBHUFFDS = Table_B10.get();
+ } else {
+ CJBig2_Segment* pSeg =
+ findReferredSegmentByTypeAndIndex(pSegment, 53, nIndex++);
+ if (!pSeg)
+ return JBIG2_ERROR_FATAL;
+ pTRD->SBHUFFDS = pSeg->m_Result.ht;
+ }
+ if (cSBHUFFDT == 0) {
+ Table_B11.reset(new CJBig2_HuffmanTable(HuffmanTable_B11,
+ FX_ArraySize(HuffmanTable_B11),
+ HuffmanTable_HTOOB_B11));
+ pTRD->SBHUFFDT = Table_B11.get();
+ } else if (cSBHUFFDT == 1) {
+ Table_B12.reset(new CJBig2_HuffmanTable(HuffmanTable_B12,
+ FX_ArraySize(HuffmanTable_B12),
+ HuffmanTable_HTOOB_B12));
+ pTRD->SBHUFFDT = Table_B12.get();
+ } else if (cSBHUFFDT == 2) {
+ Table_B13.reset(new CJBig2_HuffmanTable(HuffmanTable_B13,
+ FX_ArraySize(HuffmanTable_B13),
+ HuffmanTable_HTOOB_B13));
+ pTRD->SBHUFFDT = Table_B13.get();
+ } else {
+ CJBig2_Segment* pSeg =
+ findReferredSegmentByTypeAndIndex(pSegment, 53, nIndex++);
+ if (!pSeg)
+ return JBIG2_ERROR_FATAL;
+ pTRD->SBHUFFDT = pSeg->m_Result.ht;
+ }
+ if (cSBHUFFRDW == 0) {
+ Table_B14.reset(new CJBig2_HuffmanTable(HuffmanTable_B14,
+ FX_ArraySize(HuffmanTable_B14),
+ HuffmanTable_HTOOB_B14));
+ pTRD->SBHUFFRDW = Table_B14.get();
+ } else if (cSBHUFFRDW == 1) {
+ Table_B15.reset(new CJBig2_HuffmanTable(HuffmanTable_B15,
+ FX_ArraySize(HuffmanTable_B15),
+ HuffmanTable_HTOOB_B15));
+ pTRD->SBHUFFRDW = Table_B15.get();
+ } else {
+ CJBig2_Segment* pSeg =
+ findReferredSegmentByTypeAndIndex(pSegment, 53, nIndex++);
+ if (!pSeg)
+ return JBIG2_ERROR_FATAL;
+ pTRD->SBHUFFRDW = pSeg->m_Result.ht;
+ }
+ if (cSBHUFFRDH == 0) {
+ if (!Table_B14) {
+ Table_B14.reset(new CJBig2_HuffmanTable(HuffmanTable_B14,
+ FX_ArraySize(HuffmanTable_B14),
+ HuffmanTable_HTOOB_B14));
+ }
+ pTRD->SBHUFFRDH = Table_B14.get();
+ } else if (cSBHUFFRDH == 1) {
+ if (!Table_B15) {
+ Table_B15.reset(new CJBig2_HuffmanTable(HuffmanTable_B15,
+ FX_ArraySize(HuffmanTable_B15),
+ HuffmanTable_HTOOB_B15));
+ }
+ pTRD->SBHUFFRDH = Table_B15.get();
+ } else {
+ CJBig2_Segment* pSeg =
+ findReferredSegmentByTypeAndIndex(pSegment, 53, nIndex++);
+ if (!pSeg)
+ return JBIG2_ERROR_FATAL;
+ pTRD->SBHUFFRDH = pSeg->m_Result.ht;
+ }
+ if (cSBHUFFRDX == 0) {
+ if (!Table_B14) {
+ Table_B14.reset(new CJBig2_HuffmanTable(HuffmanTable_B14,
+ FX_ArraySize(HuffmanTable_B14),
+ HuffmanTable_HTOOB_B14));
+ }
+ pTRD->SBHUFFRDX = Table_B14.get();
+ } else if (cSBHUFFRDX == 1) {
+ if (!Table_B15) {
+ Table_B15.reset(new CJBig2_HuffmanTable(HuffmanTable_B15,
+ FX_ArraySize(HuffmanTable_B15),
+ HuffmanTable_HTOOB_B15));
+ }
+ pTRD->SBHUFFRDX = Table_B15.get();
+ } else {
+ CJBig2_Segment* pSeg =
+ findReferredSegmentByTypeAndIndex(pSegment, 53, nIndex++);
+ if (!pSeg)
+ return JBIG2_ERROR_FATAL;
+ pTRD->SBHUFFRDX = pSeg->m_Result.ht;
+ }
+ if (cSBHUFFRDY == 0) {
+ if (!Table_B14) {
+ Table_B14.reset(new CJBig2_HuffmanTable(HuffmanTable_B14,
+ FX_ArraySize(HuffmanTable_B14),
+ HuffmanTable_HTOOB_B14));
+ }
+ pTRD->SBHUFFRDY = Table_B14.get();
+ } else if (cSBHUFFRDY == 1) {
+ if (!Table_B15) {
+ Table_B15.reset(new CJBig2_HuffmanTable(HuffmanTable_B15,
+ FX_ArraySize(HuffmanTable_B15),
+ HuffmanTable_HTOOB_B15));
+ }
+ pTRD->SBHUFFRDY = Table_B15.get();
+ } else {
+ CJBig2_Segment* pSeg =
+ findReferredSegmentByTypeAndIndex(pSegment, 53, nIndex++);
+ if (!pSeg)
+ return JBIG2_ERROR_FATAL;
+ pTRD->SBHUFFRDY = pSeg->m_Result.ht;
+ }
+ if (cSBHUFFRSIZE == 0) {
+ Table_B1.reset(new CJBig2_HuffmanTable(HuffmanTable_B1,
+ FX_ArraySize(HuffmanTable_B1),
+ HuffmanTable_HTOOB_B1));
+ pTRD->SBHUFFRSIZE = Table_B1.get();
+ } else {
+ CJBig2_Segment* pSeg =
+ findReferredSegmentByTypeAndIndex(pSegment, 53, nIndex++);
+ if (!pSeg)
+ return JBIG2_ERROR_FATAL;
+ pTRD->SBHUFFRSIZE = pSeg->m_Result.ht;
+ }
+ }
+ std::unique_ptr<JBig2ArithCtx, FxFreeDeleter> grContext;
+ if (pTRD->SBREFINE == 1) {
+ const size_t size = GetRefAggContextSize(pTRD->SBRTEMPLATE);
+ grContext.reset(FX_Alloc(JBig2ArithCtx, size));
+ JBIG2_memset(grContext.get(), 0, sizeof(JBig2ArithCtx) * size);
+ }
+ if (pTRD->SBHUFF == 0) {
+ std::unique_ptr<CJBig2_ArithDecoder> pArithDecoder(
+ new CJBig2_ArithDecoder(m_pStream.get()));
+ pSegment->m_nResultType = JBIG2_IMAGE_POINTER;
+ pSegment->m_Result.im =
+ pTRD->decode_Arith(pArithDecoder.get(), grContext.get(), nullptr);
+ if (!pSegment->m_Result.im)
+ return JBIG2_ERROR_FATAL;
+ m_pStream->alignByte();
+ m_pStream->offset(2);
+ } else {
+ pSegment->m_nResultType = JBIG2_IMAGE_POINTER;
+ pSegment->m_Result.im =
+ pTRD->decode_Huffman(m_pStream.get(), grContext.get());
+ if (!pSegment->m_Result.im)
+ return JBIG2_ERROR_FATAL;
+ m_pStream->alignByte();
+ }
+ if (pSegment->m_cFlags.s.type != 4) {
+ if (!m_bBufSpecified) {
+ JBig2PageInfo* pPageInfo = m_PageInfoList.back();
+ 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;
+ }
+ return JBIG2_SUCCESS;
+}
+
+int32_t CJBig2_Context::parsePatternDict(CJBig2_Segment* pSegment,
+ IFX_Pause* pPause) {
+ uint8_t cFlags;
+ std::unique_ptr<CJBig2_PDDProc> pPDD(new 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) {
+ return JBIG2_ERROR_TOO_SHORT;
+ }
+ if (pPDD->GRAYMAX > JBIG2_MAX_PATTERN_INDEX)
+ return JBIG2_ERROR_LIMIT;
+
+ pPDD->HDMMR = cFlags & 0x01;
+ pPDD->HDTEMPLATE = (cFlags >> 1) & 0x03;
+ pSegment->m_nResultType = JBIG2_PATTERN_DICT_POINTER;
+ if (pPDD->HDMMR == 0) {
+ const size_t size = GetHuffContextSize(pPDD->HDTEMPLATE);
+ std::unique_ptr<JBig2ArithCtx, FxFreeDeleter> gbContext(
+ FX_Alloc(JBig2ArithCtx, size));
+ JBIG2_memset(gbContext.get(), 0, sizeof(JBig2ArithCtx) * size);
+ std::unique_ptr<CJBig2_ArithDecoder> pArithDecoder(
+ new CJBig2_ArithDecoder(m_pStream.get()));
+ pSegment->m_Result.pd =
+ pPDD->decode_Arith(pArithDecoder.get(), gbContext.get(), pPause);
+ if (!pSegment->m_Result.pd)
+ return JBIG2_ERROR_FATAL;
+
+ m_pStream->alignByte();
+ m_pStream->offset(2);
+ } else {
+ pSegment->m_Result.pd = pPDD->decode_MMR(m_pStream.get(), pPause);
+ if (!pSegment->m_Result.pd)
+ return JBIG2_ERROR_FATAL;
+ m_pStream->alignByte();
+ }
+ return JBIG2_SUCCESS;
+}
+
+int32_t CJBig2_Context::parseHalftoneRegion(CJBig2_Segment* pSegment,
+ IFX_Pause* pPause) {
+ uint8_t cFlags;
+ JBig2RegionInfo ri;
+ std::unique_ptr<CJBig2_HTRDProc> pHRD(new 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) {
+ return JBIG2_ERROR_TOO_SHORT;
+ }
+
+ if (pHRD->HGW == 0 || pHRD->HGH == 0)
+ return JBIG2_ERROR_FATAL;
+
+ 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)
+ return JBIG2_ERROR_FATAL;
+
+ CJBig2_Segment* pSeg =
+ findSegmentByNumber(pSegment->m_pReferred_to_segment_numbers[0]);
+ if (!pSeg || (pSeg->m_cFlags.s.type != 16))
+ return JBIG2_ERROR_FATAL;
+
+ CJBig2_PatternDict* pPatternDict = pSeg->m_Result.pd;
+ if (!pPatternDict || (pPatternDict->NUMPATS == 0))
+ return JBIG2_ERROR_FATAL;
+
+ 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) {
+ const size_t size = GetHuffContextSize(pHRD->HTEMPLATE);
+ std::unique_ptr<JBig2ArithCtx, FxFreeDeleter> gbContext(
+ FX_Alloc(JBig2ArithCtx, size));
+ JBIG2_memset(gbContext.get(), 0, sizeof(JBig2ArithCtx) * size);
+ std::unique_ptr<CJBig2_ArithDecoder> pArithDecoder(
+ new CJBig2_ArithDecoder(m_pStream.get()));
+ pSegment->m_Result.im =
+ pHRD->decode_Arith(pArithDecoder.get(), gbContext.get(), pPause);
+ if (!pSegment->m_Result.im)
+ return JBIG2_ERROR_FATAL;
+
+ m_pStream->alignByte();
+ m_pStream->offset(2);
+ } else {
+ pSegment->m_Result.im = pHRD->decode_MMR(m_pStream.get(), pPause);
+ if (!pSegment->m_Result.im)
+ return JBIG2_ERROR_FATAL;
+ m_pStream->alignByte();
+ }
+ if (pSegment->m_cFlags.s.type != 20) {
+ if (!m_bBufSpecified) {
+ JBig2PageInfo* pPageInfo = m_PageInfoList.back();
+ 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;
+ }
+ return JBIG2_SUCCESS;
+}
+
+int32_t CJBig2_Context::parseGenericRegion(CJBig2_Segment* pSegment,
+ IFX_Pause* pPause) {
+ if (!m_pGRD) {
+ std::unique_ptr<CJBig2_GRDProc> pGRD(new CJBig2_GRDProc);
+ uint8_t cFlags;
+ if (parseRegionInfo(&m_ri) != JBIG2_SUCCESS ||
+ m_pStream->read1Byte(&cFlags) != 0) {
+ return JBIG2_ERROR_TOO_SHORT;
+ }
+ if (m_ri.height < 0 || m_ri.width < 0)
+ return JBIG2_FAILED;
+
+ pGRD->GBW = m_ri.width;
+ pGRD->GBH = m_ri.height;
+ pGRD->MMR = cFlags & 0x01;
+ pGRD->GBTEMPLATE = (cFlags >> 1) & 0x03;
+ pGRD->TPGDON = (cFlags >> 3) & 0x01;
+ if (pGRD->MMR == 0) {
+ if (pGRD->GBTEMPLATE == 0) {
+ for (int32_t i = 0; i < 8; ++i) {
+ if (m_pStream->read1Byte((uint8_t*)&pGRD->GBAT[i]) != 0) {
+ return JBIG2_ERROR_TOO_SHORT;
+ }
+ }
+ } else {
+ for (int32_t i = 0; i < 2; ++i) {
+ if (m_pStream->read1Byte((uint8_t*)&pGRD->GBAT[i]) != 0) {
+ return JBIG2_ERROR_TOO_SHORT;
+ }
+ }
+ }
+ }
+ pGRD->USESKIP = 0;
+ m_pGRD = std::move(pGRD);
+ }
+ pSegment->m_nResultType = JBIG2_IMAGE_POINTER;
+ if (m_pGRD->MMR == 0) {
+ if (!m_gbContext) {
+ const size_t size = GetHuffContextSize(m_pGRD->GBTEMPLATE);
+ m_gbContext = FX_Alloc(JBig2ArithCtx, size);
+ JBIG2_memset(m_gbContext, 0, sizeof(JBig2ArithCtx) * size);
+ }
+ if (!m_pArithDecoder) {
+ m_pArithDecoder.reset(new CJBig2_ArithDecoder(m_pStream.get()));
+ m_ProcessingStatus = m_pGRD->Start_decode_Arith(
+ &pSegment->m_Result.im, m_pArithDecoder.get(), m_gbContext, pPause);
+ } else {
+ m_ProcessingStatus = m_pGRD->Continue_decode(pPause);
+ }
+ if (m_ProcessingStatus == FXCODEC_STATUS_DECODE_TOBECONTINUE) {
+ if (pSegment->m_cFlags.s.type != 36) {
+ if (!m_bBufSpecified) {
+ JBig2PageInfo* pPageInfo = m_PageInfoList.back();
+ 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 {
+ m_pArithDecoder.reset();
+ FX_Free(m_gbContext);
+ m_gbContext = NULL;
+ if (!pSegment->m_Result.im) {
+ m_ProcessingStatus = FXCODEC_STATUS_ERROR;
+ m_pGRD.reset();
+ return JBIG2_ERROR_FATAL;
+ }
+ m_pStream->alignByte();
+ m_pStream->offset(2);
+ }
+ } else {
+ FXCODEC_STATUS status = m_pGRD->Start_decode_MMR(&pSegment->m_Result.im,
+ m_pStream.get(), pPause);
+ while (status == FXCODEC_STATUS_DECODE_TOBECONTINUE) {
+ m_pGRD->Continue_decode(pPause);
+ }
+ if (!pSegment->m_Result.im) {
+ m_pGRD.reset();
+ return JBIG2_ERROR_FATAL;
+ }
+ m_pStream->alignByte();
+ }
+ if (pSegment->m_cFlags.s.type != 36) {
+ if (!m_bBufSpecified) {
+ JBig2PageInfo* pPageInfo = m_PageInfoList.back();
+ 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;
+ }
+ m_pGRD.reset();
+ return JBIG2_SUCCESS;
+}
+
+int32_t CJBig2_Context::parseGenericRefinementRegion(CJBig2_Segment* pSegment) {
+ JBig2RegionInfo ri;
+ uint8_t cFlags;
+ if (parseRegionInfo(&ri) != JBIG2_SUCCESS ||
+ m_pStream->read1Byte(&cFlags) != 0) {
+ return JBIG2_ERROR_TOO_SHORT;
+ }
+ std::unique_ptr<CJBig2_GRRDProc> pGRRD(new CJBig2_GRRDProc);
+ pGRRD->GRW = ri.width;
+ pGRRD->GRH = ri.height;
+ pGRRD->GRTEMPLATE = cFlags & 0x01;
+ pGRRD->TPGRON = (cFlags >> 1) & 0x01;
+ if (pGRRD->GRTEMPLATE == 0) {
+ for (int32_t i = 0; i < 4; ++i) {
+ if (m_pStream->read1Byte((uint8_t*)&pGRRD->GRAT[i]) != 0)
+ return JBIG2_ERROR_TOO_SHORT;
+ }
+ }
+ CJBig2_Segment* pSeg = nullptr;
+ if (pSegment->m_nReferred_to_segment_count > 0) {
+ int32_t i;
+ for (i = 0; i < pSegment->m_nReferred_to_segment_count; ++i) {
+ pSeg = findSegmentByNumber(pSegment->m_pReferred_to_segment_numbers[0]);
+ if (!pSeg)
+ return JBIG2_ERROR_FATAL;
+
+ 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)
+ return JBIG2_ERROR_FATAL;
+
+ pGRRD->GRREFERENCE = pSeg->m_Result.im;
+ } else {
+ pGRRD->GRREFERENCE = m_pPage.get();
+ }
+ pGRRD->GRREFERENCEDX = 0;
+ pGRRD->GRREFERENCEDY = 0;
+ const size_t size = GetRefAggContextSize(pGRRD->GRTEMPLATE);
+ std::unique_ptr<JBig2ArithCtx, FxFreeDeleter> grContext(
+ FX_Alloc(JBig2ArithCtx, size));
+ JBIG2_memset(grContext.get(), 0, sizeof(JBig2ArithCtx) * size);
+ std::unique_ptr<CJBig2_ArithDecoder> pArithDecoder(
+ new CJBig2_ArithDecoder(m_pStream.get()));
+ pSegment->m_nResultType = JBIG2_IMAGE_POINTER;
+ pSegment->m_Result.im = pGRRD->decode(pArithDecoder.get(), grContext.get());
+ if (!pSegment->m_Result.im)
+ return JBIG2_ERROR_FATAL;
+
+ m_pStream->alignByte();
+ m_pStream->offset(2);
+ if (pSegment->m_cFlags.s.type != 40) {
+ if (!m_bBufSpecified) {
+ JBig2PageInfo* pPageInfo = m_PageInfoList.back();
+ 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;
+ }
+ return JBIG2_SUCCESS;
+}
+
+int32_t CJBig2_Context::parseTable(CJBig2_Segment* pSegment) {
+ pSegment->m_nResultType = JBIG2_HUFFMAN_TABLE_POINTER;
+ pSegment->m_Result.ht = nullptr;
+ std::unique_ptr<CJBig2_HuffmanTable> pHuff(
+ new CJBig2_HuffmanTable(m_pStream.get()));
+ if (!pHuff->IsOK())
+ return JBIG2_ERROR_FATAL;
+
+ pSegment->m_Result.ht = pHuff.release();
+ 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) {
+ const size_t kRunCodesSize = 35;
+ int32_t runcodes[kRunCodesSize];
+ int32_t runcodes_len[kRunCodesSize];
+ for (int32_t i = 0; i < kRunCodesSize; ++i) {
+ if (pStream->readNBits(4, &runcodes_len[i]) != 0)
+ return nullptr;
+ }
+ huffman_assign_code(runcodes, runcodes_len, kRunCodesSize);
+
+ std::unique_ptr<JBig2HuffmanCode, FxFreeDeleter> SBSYMCODES(
+ FX_Alloc(JBig2HuffmanCode, SBNUMSYMS));
+ int32_t run;
+ int32_t i = 0;
+ while (i < (int)SBNUMSYMS) {
+ int32_t j;
+ int32_t nVal = 0;
+ int32_t nBits = 0;
+ FX_DWORD nTemp;
+ while (true) {
+ if (pStream->read1Bit(&nTemp) != 0)
+ return nullptr;
+
+ nVal = (nVal << 1) | nTemp;
+ ++nBits;
+ for (j = 0; j < kRunCodesSize; ++j) {
+ if (nBits == runcodes_len[j] && nVal == runcodes[j]) {
+ break;
+ }
+ }
+ if (j < kRunCodesSize) {
+ break;
+ }
+ }
+ int32_t runcode = j;
+ if (runcode < 32) {
+ SBSYMCODES.get()[i].codelen = runcode;
+ run = 0;
+ } else if (runcode == 32) {
+ if (pStream->readNBits(2, &nTemp) != 0)
+ return nullptr;
+ run = nTemp + 3;
+ } else if (runcode == 33) {
+ if (pStream->readNBits(3, &nTemp) != 0)
+ return nullptr;
+ run = nTemp + 3;
+ } else if (runcode == 34) {
+ if (pStream->readNBits(7, &nTemp) != 0)
+ return nullptr;
+ run = nTemp + 11;
+ }
+ if (run > 0) {
+ if (i + run > (int)SBNUMSYMS)
+ return nullptr;
+ for (j = 0; j < run; ++j) {
+ if (runcode == 32 && i > 0) {
+ SBSYMCODES.get()[i + j].codelen = SBSYMCODES.get()[i - 1].codelen;
+ } else {
+ SBSYMCODES.get()[i + j].codelen = 0;
+ }
+ }
+ i += run;
+ } else {
+ ++i;
+ }
+ }
+ huffman_assign_code(SBSYMCODES.get(), SBNUMSYMS);
+ return SBSYMCODES.release();
+}
+
+void CJBig2_Context::huffman_assign_code(int* CODES, int* PREFLEN, int NTEMP) {
+ // TODO(thestig) CJBig2_HuffmanTable::parseFromCodedBuffer() has similar code.
+ 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 = FX_Alloc(int, LENMAX + 1);
+ JBIG2_memset(LENCOUNT, 0, sizeof(int) * (LENMAX + 1));
+ FIRSTCODE = FX_Alloc(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;
+ }
+ FX_Free(LENCOUNT);
+ FX_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 = FX_Alloc(int, (LENMAX + 1));
+ JBIG2_memset(LENCOUNT, 0, sizeof(int) * (LENMAX + 1));
+ FIRSTCODE = FX_Alloc(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;
+ }
+ FX_Free(LENCOUNT);
+ FX_Free(FIRSTCODE);
+}