Home | History | Annotate | Download | only in jbig2
      1 // Copyright 2014 PDFium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
      6 
      7 #include "core/fxcodec/jbig2/JBig2_Context.h"
      8 
      9 #include <algorithm>
     10 #include <limits>
     11 #include <list>
     12 #include <utility>
     13 #include <vector>
     14 
     15 #include "core/fpdfapi/parser/cpdf_stream.h"
     16 #include "core/fpdfapi/parser/cpdf_stream_acc.h"
     17 #include "core/fxcodec/jbig2/JBig2_ArithDecoder.h"
     18 #include "core/fxcodec/jbig2/JBig2_BitStream.h"
     19 #include "core/fxcodec/jbig2/JBig2_GrdProc.h"
     20 #include "core/fxcodec/jbig2/JBig2_GrrdProc.h"
     21 #include "core/fxcodec/jbig2/JBig2_HtrdProc.h"
     22 #include "core/fxcodec/jbig2/JBig2_HuffmanTable_Standard.h"
     23 #include "core/fxcodec/jbig2/JBig2_PddProc.h"
     24 #include "core/fxcodec/jbig2/JBig2_SddProc.h"
     25 #include "core/fxcodec/jbig2/JBig2_TrdProc.h"
     26 #include "core/fxcrt/ifx_pauseindicator.h"
     27 #include "third_party/base/ptr_util.h"
     28 
     29 namespace {
     30 
     31 size_t GetHuffContextSize(uint8_t val) {
     32   return val == 0 ? 65536 : val == 1 ? 8192 : 1024;
     33 }
     34 
     35 size_t GetRefAggContextSize(bool val) {
     36   return val ? 1024 : 8192;
     37 }
     38 
     39 }  // namespace
     40 
     41 // Implement a very small least recently used (LRU) cache. It is very
     42 // common for a JBIG2 dictionary to span multiple pages in a PDF file,
     43 // and we do not want to decode the same dictionary over and over
     44 // again. We key off of the memory location of the dictionary. The
     45 // list keeps track of the freshness of entries, with freshest ones
     46 // at the front. Even a tiny cache size like 2 makes a dramatic
     47 // difference for typical JBIG2 documents.
     48 static const size_t kSymbolDictCacheMaxSize = 2;
     49 static_assert(kSymbolDictCacheMaxSize > 0,
     50               "Symbol Dictionary Cache must have non-zero size");
     51 
     52 CJBig2_Context::CJBig2_Context(const RetainPtr<CPDF_StreamAcc>& pGlobalStream,
     53                                const RetainPtr<CPDF_StreamAcc>& pSrcStream,
     54                                std::list<CJBig2_CachePair>* pSymbolDictCache,
     55                                bool bIsGlobal)
     56     : m_nSegmentDecoded(0),
     57       m_bInPage(false),
     58       m_bBufSpecified(false),
     59       m_PauseStep(10),
     60       m_ProcessingStatus(FXCODEC_STATUS_FRAME_READY),
     61       m_dwOffset(0),
     62       m_pSymbolDictCache(pSymbolDictCache),
     63       m_bIsGlobal(bIsGlobal) {
     64   if (pGlobalStream && pGlobalStream->GetSize() > 0) {
     65     m_pGlobalContext = pdfium::MakeUnique<CJBig2_Context>(
     66         nullptr, pGlobalStream, pSymbolDictCache, true);
     67   }
     68   m_pStream = pdfium::MakeUnique<CJBig2_BitStream>(pSrcStream);
     69 }
     70 
     71 CJBig2_Context::~CJBig2_Context() {}
     72 
     73 int32_t CJBig2_Context::decodeSequential(IFX_PauseIndicator* pPause) {
     74   int32_t nRet;
     75   if (m_pStream->getByteLeft() <= 0)
     76     return JBIG2_END_OF_FILE;
     77 
     78   while (m_pStream->getByteLeft() >= JBIG2_MIN_SEGMENT_SIZE) {
     79     if (!m_pSegment) {
     80       m_pSegment = pdfium::MakeUnique<CJBig2_Segment>();
     81       nRet = parseSegmentHeader(m_pSegment.get());
     82       if (nRet != JBIG2_SUCCESS) {
     83         m_pSegment.reset();
     84         return nRet;
     85       }
     86       m_dwOffset = m_pStream->getOffset();
     87     }
     88     nRet = parseSegmentData(m_pSegment.get(), pPause);
     89     if (m_ProcessingStatus == FXCODEC_STATUS_DECODE_TOBECONTINUE) {
     90       m_ProcessingStatus = FXCODEC_STATUS_DECODE_TOBECONTINUE;
     91       m_PauseStep = 2;
     92       return JBIG2_SUCCESS;
     93     }
     94     if (nRet == JBIG2_END_OF_PAGE || nRet == JBIG2_END_OF_FILE) {
     95       m_pSegment.reset();
     96       return JBIG2_SUCCESS;
     97     }
     98     if (nRet != JBIG2_SUCCESS) {
     99       m_pSegment.reset();
    100       return nRet;
    101     }
    102     if (m_pSegment->m_dwData_length != 0xffffffff) {
    103       m_dwOffset += m_pSegment->m_dwData_length;
    104       if (!m_dwOffset.IsValid())
    105         return JBIG2_ERROR_FATAL;
    106 
    107       m_pStream->setOffset(m_dwOffset.ValueOrDie());
    108     } else {
    109       m_pStream->offset(4);
    110     }
    111     m_SegmentList.push_back(std::move(m_pSegment));
    112     if (m_pStream->getByteLeft() > 0 && m_pPage && pPause &&
    113         pPause->NeedToPauseNow()) {
    114       m_ProcessingStatus = FXCODEC_STATUS_DECODE_TOBECONTINUE;
    115       m_PauseStep = 2;
    116       return JBIG2_SUCCESS;
    117     }
    118   }
    119   return JBIG2_SUCCESS;
    120 }
    121 
    122 int32_t CJBig2_Context::decodeRandomFirstPage(IFX_PauseIndicator* pPause) {
    123   int32_t nRet;
    124   while (m_pStream->getByteLeft() > JBIG2_MIN_SEGMENT_SIZE) {
    125     auto pSegment = pdfium::MakeUnique<CJBig2_Segment>();
    126     nRet = parseSegmentHeader(pSegment.get());
    127     if (nRet != JBIG2_SUCCESS)
    128       return nRet;
    129 
    130     if (pSegment->m_cFlags.s.type == 51)
    131       break;
    132 
    133     m_SegmentList.push_back(std::move(pSegment));
    134     if (pPause && pPause->NeedToPauseNow()) {
    135       m_PauseStep = 3;
    136       m_ProcessingStatus = FXCODEC_STATUS_DECODE_TOBECONTINUE;
    137       return JBIG2_SUCCESS;
    138     }
    139   }
    140   m_nSegmentDecoded = 0;
    141   return decodeRandom(pPause);
    142 }
    143 
    144 int32_t CJBig2_Context::decodeRandom(IFX_PauseIndicator* pPause) {
    145   for (; m_nSegmentDecoded < m_SegmentList.size(); ++m_nSegmentDecoded) {
    146     int32_t nRet =
    147         parseSegmentData(m_SegmentList[m_nSegmentDecoded].get(), pPause);
    148     if (nRet == JBIG2_END_OF_PAGE || nRet == JBIG2_END_OF_FILE)
    149       return JBIG2_SUCCESS;
    150 
    151     if (nRet != JBIG2_SUCCESS)
    152       return nRet;
    153 
    154     if (m_pPage && pPause && pPause->NeedToPauseNow()) {
    155       m_PauseStep = 4;
    156       m_ProcessingStatus = FXCODEC_STATUS_DECODE_TOBECONTINUE;
    157       return JBIG2_SUCCESS;
    158     }
    159   }
    160   return JBIG2_SUCCESS;
    161 }
    162 
    163 int32_t CJBig2_Context::getFirstPage(uint8_t* pBuf,
    164                                      int32_t width,
    165                                      int32_t height,
    166                                      int32_t stride,
    167                                      IFX_PauseIndicator* pPause) {
    168   int32_t nRet = 0;
    169   if (m_pGlobalContext) {
    170     nRet = m_pGlobalContext->decodeSequential(pPause);
    171     if (nRet != JBIG2_SUCCESS) {
    172       m_ProcessingStatus = FXCODEC_STATUS_ERROR;
    173       return nRet;
    174     }
    175   }
    176   m_PauseStep = 0;
    177   m_pPage = pdfium::MakeUnique<CJBig2_Image>(width, height, stride, pBuf);
    178   m_bBufSpecified = true;
    179   if (pPause && pPause->NeedToPauseNow()) {
    180     m_PauseStep = 1;
    181     m_ProcessingStatus = FXCODEC_STATUS_DECODE_TOBECONTINUE;
    182     return nRet;
    183   }
    184   return Continue(pPause);
    185 }
    186 
    187 int32_t CJBig2_Context::Continue(IFX_PauseIndicator* pPause) {
    188   m_ProcessingStatus = FXCODEC_STATUS_DECODE_READY;
    189   int32_t nRet = 0;
    190   if (m_PauseStep <= 2) {
    191     nRet = decodeSequential(pPause);
    192   } else if (m_PauseStep == 3) {
    193     nRet = decodeRandomFirstPage(pPause);
    194   } else if (m_PauseStep == 4) {
    195     nRet = decodeRandom(pPause);
    196   } else if (m_PauseStep == 5) {
    197     m_ProcessingStatus = FXCODEC_STATUS_DECODE_FINISH;
    198     return JBIG2_SUCCESS;
    199   }
    200   if (m_ProcessingStatus == FXCODEC_STATUS_DECODE_TOBECONTINUE)
    201     return nRet;
    202 
    203   m_PauseStep = 5;
    204   if (!m_bBufSpecified && nRet == JBIG2_SUCCESS) {
    205     m_ProcessingStatus = FXCODEC_STATUS_DECODE_FINISH;
    206     return JBIG2_SUCCESS;
    207   }
    208   m_ProcessingStatus = nRet == JBIG2_SUCCESS ? FXCODEC_STATUS_DECODE_FINISH
    209                                              : FXCODEC_STATUS_ERROR;
    210   return nRet;
    211 }
    212 
    213 CJBig2_Segment* CJBig2_Context::findSegmentByNumber(uint32_t dwNumber) {
    214   if (m_pGlobalContext) {
    215     CJBig2_Segment* pSeg = m_pGlobalContext->findSegmentByNumber(dwNumber);
    216     if (pSeg)
    217       return pSeg;
    218   }
    219   for (const auto& pSeg : m_SegmentList) {
    220     if (pSeg->m_dwNumber == dwNumber)
    221       return pSeg.get();
    222   }
    223   return nullptr;
    224 }
    225 
    226 CJBig2_Segment* CJBig2_Context::findReferredSegmentByTypeAndIndex(
    227     CJBig2_Segment* pSegment,
    228     uint8_t cType,
    229     int32_t nIndex) {
    230   int32_t count = 0;
    231   for (int32_t i = 0; i < pSegment->m_nReferred_to_segment_count; ++i) {
    232     CJBig2_Segment* pSeg =
    233         findSegmentByNumber(pSegment->m_Referred_to_segment_numbers[i]);
    234     if (pSeg && pSeg->m_cFlags.s.type == cType) {
    235       if (count == nIndex)
    236         return pSeg;
    237       ++count;
    238     }
    239   }
    240   return nullptr;
    241 }
    242 
    243 int32_t CJBig2_Context::parseSegmentHeader(CJBig2_Segment* pSegment) {
    244   if (m_pStream->readInteger(&pSegment->m_dwNumber) != 0 ||
    245       m_pStream->read1Byte(&pSegment->m_cFlags.c) != 0) {
    246     return JBIG2_ERROR_TOO_SHORT;
    247   }
    248 
    249   uint32_t dwTemp;
    250   uint8_t cTemp = m_pStream->getCurByte();
    251   if ((cTemp >> 5) == 7) {
    252     if (m_pStream->readInteger(
    253             (uint32_t*)&pSegment->m_nReferred_to_segment_count) != 0) {
    254       return JBIG2_ERROR_TOO_SHORT;
    255     }
    256     pSegment->m_nReferred_to_segment_count &= 0x1fffffff;
    257     if (pSegment->m_nReferred_to_segment_count >
    258         JBIG2_MAX_REFERRED_SEGMENT_COUNT) {
    259       return JBIG2_ERROR_LIMIT;
    260     }
    261     dwTemp = 5 + 4 + (pSegment->m_nReferred_to_segment_count + 1) / 8;
    262   } else {
    263     if (m_pStream->read1Byte(&cTemp) != 0)
    264       return JBIG2_ERROR_TOO_SHORT;
    265 
    266     pSegment->m_nReferred_to_segment_count = cTemp >> 5;
    267     dwTemp = 5 + 1;
    268   }
    269   uint8_t cSSize =
    270       pSegment->m_dwNumber > 65536 ? 4 : pSegment->m_dwNumber > 256 ? 2 : 1;
    271   uint8_t cPSize = pSegment->m_cFlags.s.page_association_size ? 4 : 1;
    272   if (pSegment->m_nReferred_to_segment_count) {
    273     pSegment->m_Referred_to_segment_numbers.resize(
    274         pSegment->m_nReferred_to_segment_count);
    275     for (int32_t i = 0; i < pSegment->m_nReferred_to_segment_count; ++i) {
    276       switch (cSSize) {
    277         case 1:
    278           if (m_pStream->read1Byte(&cTemp) != 0)
    279             return JBIG2_ERROR_TOO_SHORT;
    280 
    281           pSegment->m_Referred_to_segment_numbers[i] = cTemp;
    282           break;
    283         case 2:
    284           uint16_t wTemp;
    285           if (m_pStream->readShortInteger(&wTemp) != 0)
    286             return JBIG2_ERROR_TOO_SHORT;
    287 
    288           pSegment->m_Referred_to_segment_numbers[i] = wTemp;
    289           break;
    290         case 4:
    291           if (m_pStream->readInteger(&dwTemp) != 0)
    292             return JBIG2_ERROR_TOO_SHORT;
    293 
    294           pSegment->m_Referred_to_segment_numbers[i] = dwTemp;
    295           break;
    296       }
    297       if (pSegment->m_Referred_to_segment_numbers[i] >= pSegment->m_dwNumber)
    298         return JBIG2_ERROR_TOO_SHORT;
    299     }
    300   }
    301   if (cPSize == 1) {
    302     if (m_pStream->read1Byte(&cTemp) != 0)
    303       return JBIG2_ERROR_TOO_SHORT;
    304     pSegment->m_dwPage_association = cTemp;
    305   } else {
    306     if (m_pStream->readInteger(&pSegment->m_dwPage_association) != 0) {
    307       return JBIG2_ERROR_TOO_SHORT;
    308     }
    309   }
    310   if (m_pStream->readInteger(&pSegment->m_dwData_length) != 0)
    311     return JBIG2_ERROR_TOO_SHORT;
    312 
    313   pSegment->m_dwObjNum = m_pStream->getObjNum();
    314   pSegment->m_dwDataOffset = m_pStream->getOffset();
    315   pSegment->m_State = JBIG2_SEGMENT_DATA_UNPARSED;
    316   return JBIG2_SUCCESS;
    317 }
    318 
    319 int32_t CJBig2_Context::parseSegmentData(CJBig2_Segment* pSegment,
    320                                          IFX_PauseIndicator* pPause) {
    321   int32_t ret = ProcessingParseSegmentData(pSegment, pPause);
    322   while (m_ProcessingStatus == FXCODEC_STATUS_DECODE_TOBECONTINUE &&
    323          m_pStream->getByteLeft() > 0) {
    324     ret = ProcessingParseSegmentData(pSegment, pPause);
    325   }
    326   return ret;
    327 }
    328 
    329 int32_t CJBig2_Context::ProcessingParseSegmentData(CJBig2_Segment* pSegment,
    330                                                    IFX_PauseIndicator* pPause) {
    331   switch (pSegment->m_cFlags.s.type) {
    332     case 0:
    333       return parseSymbolDict(pSegment);
    334     case 4:
    335     case 6:
    336     case 7:
    337       if (!m_bInPage)
    338         return JBIG2_ERROR_FATAL;
    339       return parseTextRegion(pSegment);
    340     case 16:
    341       return parsePatternDict(pSegment, pPause);
    342     case 20:
    343     case 22:
    344     case 23:
    345       if (!m_bInPage)
    346         return JBIG2_ERROR_FATAL;
    347       return parseHalftoneRegion(pSegment, pPause);
    348     case 36:
    349     case 38:
    350     case 39:
    351       if (!m_bInPage)
    352         return JBIG2_ERROR_FATAL;
    353       return parseGenericRegion(pSegment, pPause);
    354     case 40:
    355     case 42:
    356     case 43:
    357       if (!m_bInPage)
    358         return JBIG2_ERROR_FATAL;
    359       return parseGenericRefinementRegion(pSegment);
    360     case 48: {
    361       uint16_t wTemp;
    362       auto pPageInfo = pdfium::MakeUnique<JBig2PageInfo>();
    363       if (m_pStream->readInteger(&pPageInfo->m_dwWidth) != 0 ||
    364           m_pStream->readInteger(&pPageInfo->m_dwHeight) != 0 ||
    365           m_pStream->readInteger(&pPageInfo->m_dwResolutionX) != 0 ||
    366           m_pStream->readInteger(&pPageInfo->m_dwResolutionY) != 0 ||
    367           m_pStream->read1Byte(&pPageInfo->m_cFlags) != 0 ||
    368           m_pStream->readShortInteger(&wTemp) != 0) {
    369         return JBIG2_ERROR_TOO_SHORT;
    370       }
    371       pPageInfo->m_bIsStriped = !!(wTemp & 0x8000);
    372       pPageInfo->m_wMaxStripeSize = wTemp & 0x7fff;
    373       bool bMaxHeight = (pPageInfo->m_dwHeight == 0xffffffff);
    374       if (bMaxHeight && pPageInfo->m_bIsStriped != true)
    375         pPageInfo->m_bIsStriped = true;
    376 
    377       if (!m_bBufSpecified) {
    378         uint32_t height =
    379             bMaxHeight ? pPageInfo->m_wMaxStripeSize : pPageInfo->m_dwHeight;
    380         m_pPage =
    381             pdfium::MakeUnique<CJBig2_Image>(pPageInfo->m_dwWidth, height);
    382       }
    383 
    384       if (!m_pPage->data()) {
    385         m_ProcessingStatus = FXCODEC_STATUS_ERROR;
    386         return JBIG2_ERROR_TOO_SHORT;
    387       }
    388 
    389       m_pPage->fill((pPageInfo->m_cFlags & 4) ? 1 : 0);
    390       m_PageInfoList.push_back(std::move(pPageInfo));
    391       m_bInPage = true;
    392     } break;
    393     case 49:
    394       m_bInPage = false;
    395       return JBIG2_END_OF_PAGE;
    396       break;
    397     case 50:
    398       m_pStream->offset(pSegment->m_dwData_length);
    399       break;
    400     case 51:
    401       return JBIG2_END_OF_FILE;
    402     case 52:
    403       m_pStream->offset(pSegment->m_dwData_length);
    404       break;
    405     case 53:
    406       return parseTable(pSegment);
    407     case 62:
    408       m_pStream->offset(pSegment->m_dwData_length);
    409       break;
    410     default:
    411       break;
    412   }
    413   return JBIG2_SUCCESS;
    414 }
    415 
    416 int32_t CJBig2_Context::parseSymbolDict(CJBig2_Segment* pSegment) {
    417   uint16_t wFlags;
    418   if (m_pStream->readShortInteger(&wFlags) != 0)
    419     return JBIG2_ERROR_TOO_SHORT;
    420 
    421   auto pSymbolDictDecoder = pdfium::MakeUnique<CJBig2_SDDProc>();
    422   pSymbolDictDecoder->SDHUFF = wFlags & 0x0001;
    423   pSymbolDictDecoder->SDREFAGG = (wFlags >> 1) & 0x0001;
    424   pSymbolDictDecoder->SDTEMPLATE = (wFlags >> 10) & 0x0003;
    425   pSymbolDictDecoder->SDRTEMPLATE = !!((wFlags >> 12) & 0x0003);
    426   uint8_t cSDHUFFDH = (wFlags >> 2) & 0x0003;
    427   uint8_t cSDHUFFDW = (wFlags >> 4) & 0x0003;
    428   uint8_t cSDHUFFBMSIZE = (wFlags >> 6) & 0x0001;
    429   uint8_t cSDHUFFAGGINST = (wFlags >> 7) & 0x0001;
    430   if (pSymbolDictDecoder->SDHUFF == 0) {
    431     const uint32_t dwTemp = (pSymbolDictDecoder->SDTEMPLATE == 0) ? 8 : 2;
    432     for (uint32_t i = 0; i < dwTemp; ++i) {
    433       if (m_pStream->read1Byte((uint8_t*)&pSymbolDictDecoder->SDAT[i]) != 0)
    434         return JBIG2_ERROR_TOO_SHORT;
    435     }
    436   }
    437   if (pSymbolDictDecoder->SDREFAGG == 1 && !pSymbolDictDecoder->SDRTEMPLATE) {
    438     for (int32_t i = 0; i < 4; ++i) {
    439       if (m_pStream->read1Byte((uint8_t*)&pSymbolDictDecoder->SDRAT[i]) != 0)
    440         return JBIG2_ERROR_TOO_SHORT;
    441     }
    442   }
    443   if (m_pStream->readInteger(&pSymbolDictDecoder->SDNUMEXSYMS) != 0 ||
    444       m_pStream->readInteger(&pSymbolDictDecoder->SDNUMNEWSYMS) != 0) {
    445     return JBIG2_ERROR_TOO_SHORT;
    446   }
    447   if (pSymbolDictDecoder->SDNUMEXSYMS > JBIG2_MAX_EXPORT_SYSMBOLS ||
    448       pSymbolDictDecoder->SDNUMNEWSYMS > JBIG2_MAX_NEW_SYSMBOLS) {
    449     return JBIG2_ERROR_LIMIT;
    450   }
    451   for (int32_t i = 0; i < pSegment->m_nReferred_to_segment_count; ++i) {
    452     if (!findSegmentByNumber(pSegment->m_Referred_to_segment_numbers[i]))
    453       return JBIG2_ERROR_FATAL;
    454   }
    455   CJBig2_Segment* pLRSeg = nullptr;
    456   pSymbolDictDecoder->SDNUMINSYMS = 0;
    457   for (int32_t i = 0; i < pSegment->m_nReferred_to_segment_count; ++i) {
    458     CJBig2_Segment* pSeg =
    459         findSegmentByNumber(pSegment->m_Referred_to_segment_numbers[i]);
    460     if (pSeg->m_cFlags.s.type == 0) {
    461       pSymbolDictDecoder->SDNUMINSYMS += pSeg->m_SymbolDict->NumImages();
    462       pLRSeg = pSeg;
    463     }
    464   }
    465 
    466   std::unique_ptr<CJBig2_Image*, FxFreeDeleter> SDINSYMS;
    467   if (pSymbolDictDecoder->SDNUMINSYMS != 0) {
    468     SDINSYMS.reset(FX_Alloc(CJBig2_Image*, pSymbolDictDecoder->SDNUMINSYMS));
    469     uint32_t dwTemp = 0;
    470     for (int32_t i = 0; i < pSegment->m_nReferred_to_segment_count; ++i) {
    471       CJBig2_Segment* pSeg =
    472           findSegmentByNumber(pSegment->m_Referred_to_segment_numbers[i]);
    473       if (pSeg->m_cFlags.s.type == 0) {
    474         const CJBig2_SymbolDict& dict = *pSeg->m_SymbolDict.get();
    475         for (size_t j = 0; j < dict.NumImages(); ++j)
    476           SDINSYMS.get()[dwTemp + j] = dict.GetImage(j);
    477         dwTemp += dict.NumImages();
    478       }
    479     }
    480   }
    481   pSymbolDictDecoder->SDINSYMS = SDINSYMS.get();
    482 
    483   std::unique_ptr<CJBig2_HuffmanTable> Table_B1;
    484   std::unique_ptr<CJBig2_HuffmanTable> Table_B2;
    485   std::unique_ptr<CJBig2_HuffmanTable> Table_B3;
    486   std::unique_ptr<CJBig2_HuffmanTable> Table_B4;
    487   std::unique_ptr<CJBig2_HuffmanTable> Table_B5;
    488   if (pSymbolDictDecoder->SDHUFF == 1) {
    489     if (cSDHUFFDH == 2 || cSDHUFFDW == 2)
    490       return JBIG2_ERROR_FATAL;
    491 
    492     int32_t nIndex = 0;
    493     if (cSDHUFFDH == 0) {
    494       Table_B4 = pdfium::MakeUnique<CJBig2_HuffmanTable>(
    495           HuffmanTable_B4, HuffmanTable_B4_Size, HuffmanTable_HTOOB_B4);
    496       pSymbolDictDecoder->SDHUFFDH = Table_B4.get();
    497     } else if (cSDHUFFDH == 1) {
    498       Table_B5 = pdfium::MakeUnique<CJBig2_HuffmanTable>(
    499           HuffmanTable_B5, HuffmanTable_B5_Size, HuffmanTable_HTOOB_B5);
    500       pSymbolDictDecoder->SDHUFFDH = Table_B5.get();
    501     } else {
    502       CJBig2_Segment* pSeg =
    503           findReferredSegmentByTypeAndIndex(pSegment, 53, nIndex++);
    504       if (!pSeg)
    505         return JBIG2_ERROR_FATAL;
    506       pSymbolDictDecoder->SDHUFFDH = pSeg->m_HuffmanTable.get();
    507     }
    508     if (cSDHUFFDW == 0) {
    509       Table_B2 = pdfium::MakeUnique<CJBig2_HuffmanTable>(
    510           HuffmanTable_B2, HuffmanTable_B2_Size, HuffmanTable_HTOOB_B2);
    511       pSymbolDictDecoder->SDHUFFDW = Table_B2.get();
    512     } else if (cSDHUFFDW == 1) {
    513       Table_B3 = pdfium::MakeUnique<CJBig2_HuffmanTable>(
    514           HuffmanTable_B3, HuffmanTable_B3_Size, HuffmanTable_HTOOB_B3);
    515       pSymbolDictDecoder->SDHUFFDW = Table_B3.get();
    516     } else {
    517       CJBig2_Segment* pSeg =
    518           findReferredSegmentByTypeAndIndex(pSegment, 53, nIndex++);
    519       if (!pSeg)
    520         return JBIG2_ERROR_FATAL;
    521       pSymbolDictDecoder->SDHUFFDW = pSeg->m_HuffmanTable.get();
    522     }
    523     if (cSDHUFFBMSIZE == 0) {
    524       Table_B1 = pdfium::MakeUnique<CJBig2_HuffmanTable>(
    525           HuffmanTable_B1, HuffmanTable_B1_Size, HuffmanTable_HTOOB_B1);
    526       pSymbolDictDecoder->SDHUFFBMSIZE = Table_B1.get();
    527     } else {
    528       CJBig2_Segment* pSeg =
    529           findReferredSegmentByTypeAndIndex(pSegment, 53, nIndex++);
    530       if (!pSeg)
    531         return JBIG2_ERROR_FATAL;
    532       pSymbolDictDecoder->SDHUFFBMSIZE = pSeg->m_HuffmanTable.get();
    533     }
    534     if (pSymbolDictDecoder->SDREFAGG == 1) {
    535       if (cSDHUFFAGGINST == 0) {
    536         if (!Table_B1) {
    537           Table_B1 = pdfium::MakeUnique<CJBig2_HuffmanTable>(
    538               HuffmanTable_B1, HuffmanTable_B1_Size, HuffmanTable_HTOOB_B1);
    539         }
    540         pSymbolDictDecoder->SDHUFFAGGINST = Table_B1.get();
    541       } else {
    542         CJBig2_Segment* pSeg =
    543             findReferredSegmentByTypeAndIndex(pSegment, 53, nIndex++);
    544         if (!pSeg)
    545           return JBIG2_ERROR_FATAL;
    546         pSymbolDictDecoder->SDHUFFAGGINST = pSeg->m_HuffmanTable.get();
    547       }
    548     }
    549   }
    550 
    551   const bool bUseGbContext = (pSymbolDictDecoder->SDHUFF == 0);
    552   const bool bUseGrContext = (pSymbolDictDecoder->SDREFAGG == 1);
    553   const size_t gbContextSize =
    554       GetHuffContextSize(pSymbolDictDecoder->SDTEMPLATE);
    555   const size_t grContextSize =
    556       GetRefAggContextSize(pSymbolDictDecoder->SDRTEMPLATE);
    557   std::vector<JBig2ArithCtx> gbContext;
    558   std::vector<JBig2ArithCtx> grContext;
    559   if ((wFlags & 0x0100) && pLRSeg) {
    560     if (bUseGbContext) {
    561       gbContext = pLRSeg->m_SymbolDict->GbContext();
    562       if (gbContext.size() != gbContextSize)
    563         return JBIG2_ERROR_FATAL;
    564     }
    565     if (bUseGrContext) {
    566       grContext = pLRSeg->m_SymbolDict->GrContext();
    567       if (grContext.size() != grContextSize)
    568         return JBIG2_ERROR_FATAL;
    569     }
    570   } else {
    571     if (bUseGbContext)
    572       gbContext.resize(gbContextSize);
    573     if (bUseGrContext)
    574       grContext.resize(grContextSize);
    575   }
    576 
    577   CJBig2_CacheKey key =
    578       CJBig2_CacheKey(pSegment->m_dwObjNum, pSegment->m_dwDataOffset);
    579   bool cache_hit = false;
    580   pSegment->m_nResultType = JBIG2_SYMBOL_DICT_POINTER;
    581   if (m_bIsGlobal && key.first != 0) {
    582     for (auto it = m_pSymbolDictCache->begin(); it != m_pSymbolDictCache->end();
    583          ++it) {
    584       if (it->first == key) {
    585         pSegment->m_SymbolDict = it->second->DeepCopy();
    586         m_pSymbolDictCache->push_front(
    587             CJBig2_CachePair(key, std::move(it->second)));
    588         m_pSymbolDictCache->erase(it);
    589         cache_hit = true;
    590         break;
    591       }
    592     }
    593   }
    594   if (!cache_hit) {
    595     if (bUseGbContext) {
    596       auto pArithDecoder =
    597           pdfium::MakeUnique<CJBig2_ArithDecoder>(m_pStream.get());
    598       pSegment->m_SymbolDict = pSymbolDictDecoder->decode_Arith(
    599           pArithDecoder.get(), &gbContext, &grContext);
    600       if (!pSegment->m_SymbolDict)
    601         return JBIG2_ERROR_FATAL;
    602 
    603       m_pStream->alignByte();
    604       m_pStream->offset(2);
    605     } else {
    606       pSegment->m_SymbolDict = pSymbolDictDecoder->decode_Huffman(
    607           m_pStream.get(), &gbContext, &grContext);
    608       if (!pSegment->m_SymbolDict)
    609         return JBIG2_ERROR_FATAL;
    610       m_pStream->alignByte();
    611     }
    612     if (m_bIsGlobal) {
    613       std::unique_ptr<CJBig2_SymbolDict> value =
    614           pSegment->m_SymbolDict->DeepCopy();
    615       size_t size = m_pSymbolDictCache->size();
    616       while (size >= kSymbolDictCacheMaxSize) {
    617         m_pSymbolDictCache->pop_back();
    618         --size;
    619       }
    620       m_pSymbolDictCache->push_front(CJBig2_CachePair(key, std::move(value)));
    621     }
    622   }
    623   if (wFlags & 0x0200) {
    624     if (bUseGbContext)
    625       pSegment->m_SymbolDict->SetGbContext(gbContext);
    626     if (bUseGrContext)
    627       pSegment->m_SymbolDict->SetGrContext(grContext);
    628   }
    629   return JBIG2_SUCCESS;
    630 }
    631 
    632 int32_t CJBig2_Context::parseTextRegion(CJBig2_Segment* pSegment) {
    633   uint16_t wFlags;
    634   JBig2RegionInfo ri;
    635   if (parseRegionInfo(&ri) != JBIG2_SUCCESS ||
    636       m_pStream->readShortInteger(&wFlags) != 0) {
    637     return JBIG2_ERROR_TOO_SHORT;
    638   }
    639 
    640   auto pTRD = pdfium::MakeUnique<CJBig2_TRDProc>();
    641   pTRD->SBW = ri.width;
    642   pTRD->SBH = ri.height;
    643   pTRD->SBHUFF = wFlags & 0x0001;
    644   pTRD->SBREFINE = (wFlags >> 1) & 0x0001;
    645   uint32_t dwTemp = (wFlags >> 2) & 0x0003;
    646   pTRD->SBSTRIPS = 1 << dwTemp;
    647   pTRD->REFCORNER = (JBig2Corner)((wFlags >> 4) & 0x0003);
    648   pTRD->TRANSPOSED = (wFlags >> 6) & 0x0001;
    649   pTRD->SBCOMBOP = (JBig2ComposeOp)((wFlags >> 7) & 0x0003);
    650   pTRD->SBDEFPIXEL = (wFlags >> 9) & 0x0001;
    651   pTRD->SBDSOFFSET = (wFlags >> 10) & 0x001f;
    652   if (pTRD->SBDSOFFSET >= 0x0010) {
    653     pTRD->SBDSOFFSET = pTRD->SBDSOFFSET - 0x0020;
    654   }
    655   pTRD->SBRTEMPLATE = !!((wFlags >> 15) & 0x0001);
    656 
    657   uint8_t cSBHUFFFS = 0;
    658   uint8_t cSBHUFFDS = 0;
    659   uint8_t cSBHUFFDT = 0;
    660   uint8_t cSBHUFFRDW = 0;
    661   uint8_t cSBHUFFRDH = 0;
    662   uint8_t cSBHUFFRDX = 0;
    663   uint8_t cSBHUFFRDY = 0;
    664   uint8_t cSBHUFFRSIZE = 0;
    665   if (pTRD->SBHUFF == 1) {
    666     if (m_pStream->readShortInteger(&wFlags) != 0)
    667       return JBIG2_ERROR_TOO_SHORT;
    668 
    669     cSBHUFFFS = wFlags & 0x0003;
    670     cSBHUFFDS = (wFlags >> 2) & 0x0003;
    671     cSBHUFFDT = (wFlags >> 4) & 0x0003;
    672     cSBHUFFRDW = (wFlags >> 6) & 0x0003;
    673     cSBHUFFRDH = (wFlags >> 8) & 0x0003;
    674     cSBHUFFRDX = (wFlags >> 10) & 0x0003;
    675     cSBHUFFRDY = (wFlags >> 12) & 0x0003;
    676     cSBHUFFRSIZE = (wFlags >> 14) & 0x0001;
    677   }
    678   if (pTRD->SBREFINE == 1 && !pTRD->SBRTEMPLATE) {
    679     for (int32_t i = 0; i < 4; ++i) {
    680       if (m_pStream->read1Byte((uint8_t*)&pTRD->SBRAT[i]) != 0)
    681         return JBIG2_ERROR_TOO_SHORT;
    682     }
    683   }
    684   if (m_pStream->readInteger(&pTRD->SBNUMINSTANCES) != 0)
    685     return JBIG2_ERROR_TOO_SHORT;
    686 
    687   for (int32_t i = 0; i < pSegment->m_nReferred_to_segment_count; ++i) {
    688     if (!findSegmentByNumber(pSegment->m_Referred_to_segment_numbers[i]))
    689       return JBIG2_ERROR_FATAL;
    690   }
    691 
    692   pTRD->SBNUMSYMS = 0;
    693   for (int32_t i = 0; i < pSegment->m_nReferred_to_segment_count; ++i) {
    694     CJBig2_Segment* pSeg =
    695         findSegmentByNumber(pSegment->m_Referred_to_segment_numbers[i]);
    696     if (pSeg->m_cFlags.s.type == 0) {
    697       pTRD->SBNUMSYMS += pSeg->m_SymbolDict->NumImages();
    698     }
    699   }
    700 
    701   std::unique_ptr<CJBig2_Image*, FxFreeDeleter> SBSYMS;
    702   if (pTRD->SBNUMSYMS > 0) {
    703     SBSYMS.reset(FX_Alloc(CJBig2_Image*, pTRD->SBNUMSYMS));
    704     dwTemp = 0;
    705     for (int32_t i = 0; i < pSegment->m_nReferred_to_segment_count; ++i) {
    706       CJBig2_Segment* pSeg =
    707           findSegmentByNumber(pSegment->m_Referred_to_segment_numbers[i]);
    708       if (pSeg->m_cFlags.s.type == 0) {
    709         const CJBig2_SymbolDict& dict = *pSeg->m_SymbolDict.get();
    710         for (size_t j = 0; j < dict.NumImages(); ++j)
    711           SBSYMS.get()[dwTemp + j] = dict.GetImage(j);
    712         dwTemp += dict.NumImages();
    713       }
    714     }
    715     pTRD->SBSYMS = SBSYMS.get();
    716   } else {
    717     pTRD->SBSYMS = nullptr;
    718   }
    719 
    720   if (pTRD->SBHUFF == 1) {
    721     std::vector<JBig2HuffmanCode> SBSYMCODES =
    722         decodeSymbolIDHuffmanTable(m_pStream.get(), pTRD->SBNUMSYMS);
    723     if (SBSYMCODES.empty())
    724       return JBIG2_ERROR_FATAL;
    725 
    726     m_pStream->alignByte();
    727     pTRD->SBSYMCODES = std::move(SBSYMCODES);
    728   } else {
    729     dwTemp = 0;
    730     while ((uint32_t)(1 << dwTemp) < pTRD->SBNUMSYMS) {
    731       ++dwTemp;
    732     }
    733     pTRD->SBSYMCODELEN = (uint8_t)dwTemp;
    734   }
    735 
    736   std::unique_ptr<CJBig2_HuffmanTable> Table_B1;
    737   std::unique_ptr<CJBig2_HuffmanTable> Table_B6;
    738   std::unique_ptr<CJBig2_HuffmanTable> Table_B7;
    739   std::unique_ptr<CJBig2_HuffmanTable> Table_B8;
    740   std::unique_ptr<CJBig2_HuffmanTable> Table_B9;
    741   std::unique_ptr<CJBig2_HuffmanTable> Table_B10;
    742   std::unique_ptr<CJBig2_HuffmanTable> Table_B11;
    743   std::unique_ptr<CJBig2_HuffmanTable> Table_B12;
    744   std::unique_ptr<CJBig2_HuffmanTable> Table_B13;
    745   std::unique_ptr<CJBig2_HuffmanTable> Table_B14;
    746   std::unique_ptr<CJBig2_HuffmanTable> Table_B15;
    747   if (pTRD->SBHUFF == 1) {
    748     if (cSBHUFFFS == 2 || cSBHUFFRDW == 2 || cSBHUFFRDH == 2 ||
    749         cSBHUFFRDX == 2 || cSBHUFFRDY == 2) {
    750       return JBIG2_ERROR_FATAL;
    751     }
    752     int32_t nIndex = 0;
    753     if (cSBHUFFFS == 0) {
    754       Table_B6 = pdfium::MakeUnique<CJBig2_HuffmanTable>(
    755           HuffmanTable_B6, HuffmanTable_B6_Size, HuffmanTable_HTOOB_B6);
    756       pTRD->SBHUFFFS = Table_B6.get();
    757     } else if (cSBHUFFFS == 1) {
    758       Table_B7 = pdfium::MakeUnique<CJBig2_HuffmanTable>(
    759           HuffmanTable_B7, HuffmanTable_B7_Size, HuffmanTable_HTOOB_B7);
    760       pTRD->SBHUFFFS = Table_B7.get();
    761     } else {
    762       CJBig2_Segment* pSeg =
    763           findReferredSegmentByTypeAndIndex(pSegment, 53, nIndex++);
    764       if (!pSeg)
    765         return JBIG2_ERROR_FATAL;
    766       pTRD->SBHUFFFS = pSeg->m_HuffmanTable.get();
    767     }
    768     if (cSBHUFFDS == 0) {
    769       Table_B8 = pdfium::MakeUnique<CJBig2_HuffmanTable>(
    770           HuffmanTable_B8, HuffmanTable_B8_Size, HuffmanTable_HTOOB_B8);
    771       pTRD->SBHUFFDS = Table_B8.get();
    772     } else if (cSBHUFFDS == 1) {
    773       Table_B9 = pdfium::MakeUnique<CJBig2_HuffmanTable>(
    774           HuffmanTable_B9, HuffmanTable_B9_Size, HuffmanTable_HTOOB_B9);
    775       pTRD->SBHUFFDS = Table_B9.get();
    776     } else if (cSBHUFFDS == 2) {
    777       Table_B10 = pdfium::MakeUnique<CJBig2_HuffmanTable>(
    778           HuffmanTable_B10, HuffmanTable_B10_Size, HuffmanTable_HTOOB_B10);
    779       pTRD->SBHUFFDS = Table_B10.get();
    780     } else {
    781       CJBig2_Segment* pSeg =
    782           findReferredSegmentByTypeAndIndex(pSegment, 53, nIndex++);
    783       if (!pSeg)
    784         return JBIG2_ERROR_FATAL;
    785       pTRD->SBHUFFDS = pSeg->m_HuffmanTable.get();
    786     }
    787     if (cSBHUFFDT == 0) {
    788       Table_B11 = pdfium::MakeUnique<CJBig2_HuffmanTable>(
    789           HuffmanTable_B11, HuffmanTable_B11_Size, HuffmanTable_HTOOB_B11);
    790       pTRD->SBHUFFDT = Table_B11.get();
    791     } else if (cSBHUFFDT == 1) {
    792       Table_B12 = pdfium::MakeUnique<CJBig2_HuffmanTable>(
    793           HuffmanTable_B12, HuffmanTable_B12_Size, HuffmanTable_HTOOB_B12);
    794       pTRD->SBHUFFDT = Table_B12.get();
    795     } else if (cSBHUFFDT == 2) {
    796       Table_B13 = pdfium::MakeUnique<CJBig2_HuffmanTable>(
    797           HuffmanTable_B13, HuffmanTable_B13_Size, HuffmanTable_HTOOB_B13);
    798       pTRD->SBHUFFDT = Table_B13.get();
    799     } else {
    800       CJBig2_Segment* pSeg =
    801           findReferredSegmentByTypeAndIndex(pSegment, 53, nIndex++);
    802       if (!pSeg)
    803         return JBIG2_ERROR_FATAL;
    804       pTRD->SBHUFFDT = pSeg->m_HuffmanTable.get();
    805     }
    806     if (cSBHUFFRDW == 0) {
    807       Table_B14 = pdfium::MakeUnique<CJBig2_HuffmanTable>(
    808           HuffmanTable_B14, HuffmanTable_B14_Size, HuffmanTable_HTOOB_B14);
    809       pTRD->SBHUFFRDW = Table_B14.get();
    810     } else if (cSBHUFFRDW == 1) {
    811       Table_B15 = pdfium::MakeUnique<CJBig2_HuffmanTable>(
    812           HuffmanTable_B15, HuffmanTable_B15_Size, HuffmanTable_HTOOB_B15);
    813       pTRD->SBHUFFRDW = Table_B15.get();
    814     } else {
    815       CJBig2_Segment* pSeg =
    816           findReferredSegmentByTypeAndIndex(pSegment, 53, nIndex++);
    817       if (!pSeg)
    818         return JBIG2_ERROR_FATAL;
    819       pTRD->SBHUFFRDW = pSeg->m_HuffmanTable.get();
    820     }
    821     if (cSBHUFFRDH == 0) {
    822       if (!Table_B14) {
    823         Table_B14 = pdfium::MakeUnique<CJBig2_HuffmanTable>(
    824             HuffmanTable_B14, HuffmanTable_B14_Size, HuffmanTable_HTOOB_B14);
    825       }
    826       pTRD->SBHUFFRDH = Table_B14.get();
    827     } else if (cSBHUFFRDH == 1) {
    828       if (!Table_B15) {
    829         Table_B15 = pdfium::MakeUnique<CJBig2_HuffmanTable>(
    830             HuffmanTable_B15, HuffmanTable_B15_Size, HuffmanTable_HTOOB_B15);
    831       }
    832       pTRD->SBHUFFRDH = Table_B15.get();
    833     } else {
    834       CJBig2_Segment* pSeg =
    835           findReferredSegmentByTypeAndIndex(pSegment, 53, nIndex++);
    836       if (!pSeg)
    837         return JBIG2_ERROR_FATAL;
    838       pTRD->SBHUFFRDH = pSeg->m_HuffmanTable.get();
    839     }
    840     if (cSBHUFFRDX == 0) {
    841       if (!Table_B14) {
    842         Table_B14 = pdfium::MakeUnique<CJBig2_HuffmanTable>(
    843             HuffmanTable_B14, HuffmanTable_B14_Size, HuffmanTable_HTOOB_B14);
    844       }
    845       pTRD->SBHUFFRDX = Table_B14.get();
    846     } else if (cSBHUFFRDX == 1) {
    847       if (!Table_B15) {
    848         Table_B15 = pdfium::MakeUnique<CJBig2_HuffmanTable>(
    849             HuffmanTable_B15, HuffmanTable_B15_Size, HuffmanTable_HTOOB_B15);
    850       }
    851       pTRD->SBHUFFRDX = Table_B15.get();
    852     } else {
    853       CJBig2_Segment* pSeg =
    854           findReferredSegmentByTypeAndIndex(pSegment, 53, nIndex++);
    855       if (!pSeg)
    856         return JBIG2_ERROR_FATAL;
    857       pTRD->SBHUFFRDX = pSeg->m_HuffmanTable.get();
    858     }
    859     if (cSBHUFFRDY == 0) {
    860       if (!Table_B14) {
    861         Table_B14 = pdfium::MakeUnique<CJBig2_HuffmanTable>(
    862             HuffmanTable_B14, HuffmanTable_B14_Size, HuffmanTable_HTOOB_B14);
    863       }
    864       pTRD->SBHUFFRDY = Table_B14.get();
    865     } else if (cSBHUFFRDY == 1) {
    866       if (!Table_B15) {
    867         Table_B15 = pdfium::MakeUnique<CJBig2_HuffmanTable>(
    868             HuffmanTable_B15, HuffmanTable_B15_Size, HuffmanTable_HTOOB_B15);
    869       }
    870       pTRD->SBHUFFRDY = Table_B15.get();
    871     } else {
    872       CJBig2_Segment* pSeg =
    873           findReferredSegmentByTypeAndIndex(pSegment, 53, nIndex++);
    874       if (!pSeg)
    875         return JBIG2_ERROR_FATAL;
    876       pTRD->SBHUFFRDY = pSeg->m_HuffmanTable.get();
    877     }
    878     if (cSBHUFFRSIZE == 0) {
    879       Table_B1 = pdfium::MakeUnique<CJBig2_HuffmanTable>(
    880           HuffmanTable_B1, HuffmanTable_B1_Size, HuffmanTable_HTOOB_B1);
    881       pTRD->SBHUFFRSIZE = Table_B1.get();
    882     } else {
    883       CJBig2_Segment* pSeg =
    884           findReferredSegmentByTypeAndIndex(pSegment, 53, nIndex++);
    885       if (!pSeg)
    886         return JBIG2_ERROR_FATAL;
    887       pTRD->SBHUFFRSIZE = pSeg->m_HuffmanTable.get();
    888     }
    889   }
    890   std::unique_ptr<JBig2ArithCtx, FxFreeDeleter> grContext;
    891   if (pTRD->SBREFINE == 1) {
    892     const size_t size = GetRefAggContextSize(pTRD->SBRTEMPLATE);
    893     grContext.reset(FX_Alloc(JBig2ArithCtx, size));
    894     JBIG2_memset(grContext.get(), 0, sizeof(JBig2ArithCtx) * size);
    895   }
    896   if (pTRD->SBHUFF == 0) {
    897     auto pArithDecoder =
    898         pdfium::MakeUnique<CJBig2_ArithDecoder>(m_pStream.get());
    899     pSegment->m_nResultType = JBIG2_IMAGE_POINTER;
    900     pSegment->m_Image =
    901         pTRD->decode_Arith(pArithDecoder.get(), grContext.get(), nullptr);
    902     if (!pSegment->m_Image)
    903       return JBIG2_ERROR_FATAL;
    904     m_pStream->alignByte();
    905     m_pStream->offset(2);
    906   } else {
    907     pSegment->m_nResultType = JBIG2_IMAGE_POINTER;
    908     pSegment->m_Image = pTRD->decode_Huffman(m_pStream.get(), grContext.get());
    909     if (!pSegment->m_Image)
    910       return JBIG2_ERROR_FATAL;
    911     m_pStream->alignByte();
    912   }
    913   if (pSegment->m_cFlags.s.type != 4) {
    914     if (!m_bBufSpecified) {
    915       const auto& pPageInfo = m_PageInfoList.back();
    916       if ((pPageInfo->m_bIsStriped == 1) &&
    917           (ri.y + ri.height > m_pPage->height())) {
    918         m_pPage->expand(ri.y + ri.height, (pPageInfo->m_cFlags & 4) ? 1 : 0);
    919       }
    920     }
    921     m_pPage->composeFrom(ri.x, ri.y, pSegment->m_Image.get(),
    922                          (JBig2ComposeOp)(ri.flags & 0x03));
    923     pSegment->m_Image.reset();
    924   }
    925   return JBIG2_SUCCESS;
    926 }
    927 
    928 int32_t CJBig2_Context::parsePatternDict(CJBig2_Segment* pSegment,
    929                                          IFX_PauseIndicator* pPause) {
    930   uint8_t cFlags;
    931   auto pPDD = pdfium::MakeUnique<CJBig2_PDDProc>();
    932   if (m_pStream->read1Byte(&cFlags) != 0 ||
    933       m_pStream->read1Byte(&pPDD->HDPW) != 0 ||
    934       m_pStream->read1Byte(&pPDD->HDPH) != 0 ||
    935       m_pStream->readInteger(&pPDD->GRAYMAX) != 0) {
    936     return JBIG2_ERROR_TOO_SHORT;
    937   }
    938   if (pPDD->GRAYMAX > JBIG2_MAX_PATTERN_INDEX)
    939     return JBIG2_ERROR_LIMIT;
    940 
    941   pPDD->HDMMR = cFlags & 0x01;
    942   pPDD->HDTEMPLATE = (cFlags >> 1) & 0x03;
    943   pSegment->m_nResultType = JBIG2_PATTERN_DICT_POINTER;
    944   if (pPDD->HDMMR == 0) {
    945     const size_t size = GetHuffContextSize(pPDD->HDTEMPLATE);
    946     std::unique_ptr<JBig2ArithCtx, FxFreeDeleter> gbContext(
    947         FX_Alloc(JBig2ArithCtx, size));
    948     JBIG2_memset(gbContext.get(), 0, sizeof(JBig2ArithCtx) * size);
    949     auto pArithDecoder =
    950         pdfium::MakeUnique<CJBig2_ArithDecoder>(m_pStream.get());
    951     pSegment->m_PatternDict =
    952         pPDD->decode_Arith(pArithDecoder.get(), gbContext.get(), pPause);
    953     if (!pSegment->m_PatternDict)
    954       return JBIG2_ERROR_FATAL;
    955 
    956     m_pStream->alignByte();
    957     m_pStream->offset(2);
    958   } else {
    959     pSegment->m_PatternDict = pPDD->decode_MMR(m_pStream.get());
    960     if (!pSegment->m_PatternDict)
    961       return JBIG2_ERROR_FATAL;
    962     m_pStream->alignByte();
    963   }
    964   return JBIG2_SUCCESS;
    965 }
    966 
    967 int32_t CJBig2_Context::parseHalftoneRegion(CJBig2_Segment* pSegment,
    968                                             IFX_PauseIndicator* pPause) {
    969   uint8_t cFlags;
    970   JBig2RegionInfo ri;
    971   auto pHRD = pdfium::MakeUnique<CJBig2_HTRDProc>();
    972   if (parseRegionInfo(&ri) != JBIG2_SUCCESS ||
    973       m_pStream->read1Byte(&cFlags) != 0 ||
    974       m_pStream->readInteger(&pHRD->HGW) != 0 ||
    975       m_pStream->readInteger(&pHRD->HGH) != 0 ||
    976       m_pStream->readInteger((uint32_t*)&pHRD->HGX) != 0 ||
    977       m_pStream->readInteger((uint32_t*)&pHRD->HGY) != 0 ||
    978       m_pStream->readShortInteger(&pHRD->HRX) != 0 ||
    979       m_pStream->readShortInteger(&pHRD->HRY) != 0) {
    980     return JBIG2_ERROR_TOO_SHORT;
    981   }
    982 
    983   if (pHRD->HGW == 0 || pHRD->HGH == 0)
    984     return JBIG2_ERROR_FATAL;
    985 
    986   pHRD->HBW = ri.width;
    987   pHRD->HBH = ri.height;
    988   pHRD->HMMR = cFlags & 0x01;
    989   pHRD->HTEMPLATE = (cFlags >> 1) & 0x03;
    990   pHRD->HENABLESKIP = (cFlags >> 3) & 0x01;
    991   pHRD->HCOMBOP = (JBig2ComposeOp)((cFlags >> 4) & 0x07);
    992   pHRD->HDEFPIXEL = (cFlags >> 7) & 0x01;
    993   if (pSegment->m_nReferred_to_segment_count != 1)
    994     return JBIG2_ERROR_FATAL;
    995 
    996   CJBig2_Segment* pSeg =
    997       findSegmentByNumber(pSegment->m_Referred_to_segment_numbers[0]);
    998   if (!pSeg || (pSeg->m_cFlags.s.type != 16))
    999     return JBIG2_ERROR_FATAL;
   1000 
   1001   const CJBig2_PatternDict* pPatternDict = pSeg->m_PatternDict.get();
   1002   if (!pPatternDict || (pPatternDict->NUMPATS == 0))
   1003     return JBIG2_ERROR_FATAL;
   1004 
   1005   pHRD->HNUMPATS = pPatternDict->NUMPATS;
   1006   pHRD->HPATS = &pPatternDict->HDPATS;
   1007   pHRD->HPW = pPatternDict->HDPATS[0]->width();
   1008   pHRD->HPH = pPatternDict->HDPATS[0]->height();
   1009   pSegment->m_nResultType = JBIG2_IMAGE_POINTER;
   1010   if (pHRD->HMMR == 0) {
   1011     const size_t size = GetHuffContextSize(pHRD->HTEMPLATE);
   1012     std::unique_ptr<JBig2ArithCtx, FxFreeDeleter> gbContext(
   1013         FX_Alloc(JBig2ArithCtx, size));
   1014     JBIG2_memset(gbContext.get(), 0, sizeof(JBig2ArithCtx) * size);
   1015     auto pArithDecoder =
   1016         pdfium::MakeUnique<CJBig2_ArithDecoder>(m_pStream.get());
   1017     pSegment->m_Image =
   1018         pHRD->decode_Arith(pArithDecoder.get(), gbContext.get(), pPause);
   1019     if (!pSegment->m_Image)
   1020       return JBIG2_ERROR_FATAL;
   1021 
   1022     m_pStream->alignByte();
   1023     m_pStream->offset(2);
   1024   } else {
   1025     pSegment->m_Image = pHRD->decode_MMR(m_pStream.get());
   1026     if (!pSegment->m_Image)
   1027       return JBIG2_ERROR_FATAL;
   1028     m_pStream->alignByte();
   1029   }
   1030   if (pSegment->m_cFlags.s.type != 20) {
   1031     if (!m_bBufSpecified) {
   1032       const auto& pPageInfo = m_PageInfoList.back();
   1033       if (pPageInfo->m_bIsStriped == 1 &&
   1034           ri.y + ri.height > m_pPage->height()) {
   1035         m_pPage->expand(ri.y + ri.height, (pPageInfo->m_cFlags & 4) ? 1 : 0);
   1036       }
   1037     }
   1038     m_pPage->composeFrom(ri.x, ri.y, pSegment->m_Image.get(),
   1039                          (JBig2ComposeOp)(ri.flags & 0x03));
   1040     pSegment->m_Image.reset();
   1041   }
   1042   return JBIG2_SUCCESS;
   1043 }
   1044 
   1045 int32_t CJBig2_Context::parseGenericRegion(CJBig2_Segment* pSegment,
   1046                                            IFX_PauseIndicator* pPause) {
   1047   if (!m_pGRD) {
   1048     auto pGRD = pdfium::MakeUnique<CJBig2_GRDProc>();
   1049     uint8_t cFlags;
   1050     if (parseRegionInfo(&m_ri) != JBIG2_SUCCESS ||
   1051         m_pStream->read1Byte(&cFlags) != 0) {
   1052       return JBIG2_ERROR_TOO_SHORT;
   1053     }
   1054     if (m_ri.height < 0 || m_ri.width < 0)
   1055       return JBIG2_FAILED;
   1056     pGRD->GBW = m_ri.width;
   1057     pGRD->GBH = m_ri.height;
   1058     pGRD->MMR = cFlags & 0x01;
   1059     pGRD->GBTEMPLATE = (cFlags >> 1) & 0x03;
   1060     pGRD->TPGDON = (cFlags >> 3) & 0x01;
   1061     if (pGRD->MMR == 0) {
   1062       if (pGRD->GBTEMPLATE == 0) {
   1063         for (int32_t i = 0; i < 8; ++i) {
   1064           if (m_pStream->read1Byte((uint8_t*)&pGRD->GBAT[i]) != 0)
   1065             return JBIG2_ERROR_TOO_SHORT;
   1066         }
   1067       } else {
   1068         for (int32_t i = 0; i < 2; ++i) {
   1069           if (m_pStream->read1Byte((uint8_t*)&pGRD->GBAT[i]) != 0)
   1070             return JBIG2_ERROR_TOO_SHORT;
   1071         }
   1072       }
   1073     }
   1074     pGRD->USESKIP = 0;
   1075     m_pGRD = std::move(pGRD);
   1076   }
   1077   pSegment->m_nResultType = JBIG2_IMAGE_POINTER;
   1078   if (m_pGRD->MMR == 0) {
   1079     if (m_gbContext.empty())
   1080       m_gbContext.resize(GetHuffContextSize(m_pGRD->GBTEMPLATE));
   1081     if (!m_pArithDecoder) {
   1082       m_pArithDecoder =
   1083           pdfium::MakeUnique<CJBig2_ArithDecoder>(m_pStream.get());
   1084       m_ProcessingStatus = m_pGRD->Start_decode_Arith(
   1085           &pSegment->m_Image, m_pArithDecoder.get(), &m_gbContext[0], pPause);
   1086     } else {
   1087       m_ProcessingStatus =
   1088           m_pGRD->Continue_decode(pPause, m_pArithDecoder.get());
   1089     }
   1090     if (m_ProcessingStatus == FXCODEC_STATUS_DECODE_TOBECONTINUE) {
   1091       if (pSegment->m_cFlags.s.type != 36) {
   1092         if (!m_bBufSpecified) {
   1093           const auto& pPageInfo = m_PageInfoList.back();
   1094           if ((pPageInfo->m_bIsStriped == 1) &&
   1095               (m_ri.y + m_ri.height > m_pPage->height())) {
   1096             m_pPage->expand(m_ri.y + m_ri.height,
   1097                             (pPageInfo->m_cFlags & 4) ? 1 : 0);
   1098           }
   1099         }
   1100         FX_RECT Rect = m_pGRD->GetReplaceRect();
   1101         m_pPage->composeFrom(m_ri.x + Rect.left, m_ri.y + Rect.top,
   1102                              pSegment->m_Image.get(),
   1103                              (JBig2ComposeOp)(m_ri.flags & 0x03), &Rect);
   1104       }
   1105       return JBIG2_SUCCESS;
   1106     }
   1107     m_pArithDecoder.reset();
   1108     m_gbContext.clear();
   1109     if (!pSegment->m_Image) {
   1110       m_ProcessingStatus = FXCODEC_STATUS_ERROR;
   1111       m_pGRD.reset();
   1112       return JBIG2_ERROR_FATAL;
   1113     }
   1114     m_pStream->alignByte();
   1115     m_pStream->offset(2);
   1116   } else {
   1117     m_pGRD->Start_decode_MMR(&pSegment->m_Image, m_pStream.get());
   1118     if (!pSegment->m_Image) {
   1119       m_pGRD.reset();
   1120       return JBIG2_ERROR_FATAL;
   1121     }
   1122     m_pStream->alignByte();
   1123   }
   1124   if (pSegment->m_cFlags.s.type != 36) {
   1125     if (!m_bBufSpecified) {
   1126       JBig2PageInfo* pPageInfo = m_PageInfoList.back().get();
   1127       if ((pPageInfo->m_bIsStriped == 1) &&
   1128           (m_ri.y + m_ri.height > m_pPage->height())) {
   1129         m_pPage->expand(m_ri.y + m_ri.height,
   1130                         (pPageInfo->m_cFlags & 4) ? 1 : 0);
   1131       }
   1132     }
   1133     FX_RECT Rect = m_pGRD->GetReplaceRect();
   1134     m_pPage->composeFrom(m_ri.x + Rect.left, m_ri.y + Rect.top,
   1135                          pSegment->m_Image.get(),
   1136                          (JBig2ComposeOp)(m_ri.flags & 0x03), &Rect);
   1137     pSegment->m_Image.reset();
   1138   }
   1139   m_pGRD.reset();
   1140   return JBIG2_SUCCESS;
   1141 }
   1142 
   1143 int32_t CJBig2_Context::parseGenericRefinementRegion(CJBig2_Segment* pSegment) {
   1144   JBig2RegionInfo ri;
   1145   uint8_t cFlags;
   1146   if (parseRegionInfo(&ri) != JBIG2_SUCCESS ||
   1147       m_pStream->read1Byte(&cFlags) != 0) {
   1148     return JBIG2_ERROR_TOO_SHORT;
   1149   }
   1150   auto pGRRD = pdfium::MakeUnique<CJBig2_GRRDProc>();
   1151   pGRRD->GRW = ri.width;
   1152   pGRRD->GRH = ri.height;
   1153   pGRRD->GRTEMPLATE = !!(cFlags & 0x01);
   1154   pGRRD->TPGRON = (cFlags >> 1) & 0x01;
   1155   if (!pGRRD->GRTEMPLATE) {
   1156     for (int32_t i = 0; i < 4; ++i) {
   1157       if (m_pStream->read1Byte((uint8_t*)&pGRRD->GRAT[i]) != 0)
   1158         return JBIG2_ERROR_TOO_SHORT;
   1159     }
   1160   }
   1161   CJBig2_Segment* pSeg = nullptr;
   1162   if (pSegment->m_nReferred_to_segment_count > 0) {
   1163     int32_t i;
   1164     for (i = 0; i < pSegment->m_nReferred_to_segment_count; ++i) {
   1165       pSeg = findSegmentByNumber(pSegment->m_Referred_to_segment_numbers[0]);
   1166       if (!pSeg)
   1167         return JBIG2_ERROR_FATAL;
   1168 
   1169       if (pSeg->m_cFlags.s.type == 4 || pSeg->m_cFlags.s.type == 20 ||
   1170           pSeg->m_cFlags.s.type == 36 || pSeg->m_cFlags.s.type == 40) {
   1171         break;
   1172       }
   1173     }
   1174     if (i >= pSegment->m_nReferred_to_segment_count)
   1175       return JBIG2_ERROR_FATAL;
   1176 
   1177     pGRRD->GRREFERENCE = pSeg->m_Image.get();
   1178   } else {
   1179     pGRRD->GRREFERENCE = m_pPage.get();
   1180   }
   1181   pGRRD->GRREFERENCEDX = 0;
   1182   pGRRD->GRREFERENCEDY = 0;
   1183   const size_t size = GetRefAggContextSize(pGRRD->GRTEMPLATE);
   1184   std::unique_ptr<JBig2ArithCtx, FxFreeDeleter> grContext(
   1185       FX_Alloc(JBig2ArithCtx, size));
   1186   JBIG2_memset(grContext.get(), 0, sizeof(JBig2ArithCtx) * size);
   1187   auto pArithDecoder = pdfium::MakeUnique<CJBig2_ArithDecoder>(m_pStream.get());
   1188   pSegment->m_nResultType = JBIG2_IMAGE_POINTER;
   1189   pSegment->m_Image = pGRRD->decode(pArithDecoder.get(), grContext.get());
   1190   if (!pSegment->m_Image)
   1191     return JBIG2_ERROR_FATAL;
   1192 
   1193   m_pStream->alignByte();
   1194   m_pStream->offset(2);
   1195   if (pSegment->m_cFlags.s.type != 40) {
   1196     if (!m_bBufSpecified) {
   1197       JBig2PageInfo* pPageInfo = m_PageInfoList.back().get();
   1198       if ((pPageInfo->m_bIsStriped == 1) &&
   1199           (ri.y + ri.height > m_pPage->height())) {
   1200         m_pPage->expand(ri.y + ri.height, (pPageInfo->m_cFlags & 4) ? 1 : 0);
   1201       }
   1202     }
   1203     m_pPage->composeFrom(ri.x, ri.y, pSegment->m_Image.get(),
   1204                          (JBig2ComposeOp)(ri.flags & 0x03));
   1205     pSegment->m_Image.reset();
   1206   }
   1207   return JBIG2_SUCCESS;
   1208 }
   1209 
   1210 int32_t CJBig2_Context::parseTable(CJBig2_Segment* pSegment) {
   1211   pSegment->m_nResultType = JBIG2_HUFFMAN_TABLE_POINTER;
   1212   pSegment->m_HuffmanTable.reset();
   1213   auto pHuff = pdfium::MakeUnique<CJBig2_HuffmanTable>(m_pStream.get());
   1214   if (!pHuff->IsOK())
   1215     return JBIG2_ERROR_FATAL;
   1216 
   1217   pSegment->m_HuffmanTable = std::move(pHuff);
   1218   m_pStream->alignByte();
   1219   return JBIG2_SUCCESS;
   1220 }
   1221 
   1222 int32_t CJBig2_Context::parseRegionInfo(JBig2RegionInfo* pRI) {
   1223   if (m_pStream->readInteger((uint32_t*)&pRI->width) != 0 ||
   1224       m_pStream->readInteger((uint32_t*)&pRI->height) != 0 ||
   1225       m_pStream->readInteger((uint32_t*)&pRI->x) != 0 ||
   1226       m_pStream->readInteger((uint32_t*)&pRI->y) != 0 ||
   1227       m_pStream->read1Byte(&pRI->flags) != 0) {
   1228     return JBIG2_ERROR_TOO_SHORT;
   1229   }
   1230   return JBIG2_SUCCESS;
   1231 }
   1232 
   1233 std::vector<JBig2HuffmanCode> CJBig2_Context::decodeSymbolIDHuffmanTable(
   1234     CJBig2_BitStream* pStream,
   1235     uint32_t SBNUMSYMS) {
   1236   const size_t kRunCodesSize = 35;
   1237   JBig2HuffmanCode huffman_codes[kRunCodesSize];
   1238   for (size_t i = 0; i < kRunCodesSize; ++i) {
   1239     if (pStream->readNBits(4, &huffman_codes[i].codelen) != 0)
   1240       return std::vector<JBig2HuffmanCode>();
   1241   }
   1242   huffman_assign_code(huffman_codes, kRunCodesSize);
   1243 
   1244   std::vector<JBig2HuffmanCode> SBSYMCODES(SBNUMSYMS);
   1245   int32_t run = 0;
   1246   int32_t i = 0;
   1247   while (i < static_cast<int>(SBNUMSYMS)) {
   1248     size_t j;
   1249     int32_t nVal = 0;
   1250     int32_t nBits = 0;
   1251     uint32_t nTemp;
   1252     while (true) {
   1253       if (nVal > std::numeric_limits<int32_t>::max() / 2 ||
   1254           pStream->read1Bit(&nTemp) != 0) {
   1255         return std::vector<JBig2HuffmanCode>();
   1256       }
   1257 
   1258       nVal = (nVal << 1) | nTemp;
   1259       ++nBits;
   1260       for (j = 0; j < kRunCodesSize; ++j) {
   1261         if (nBits == huffman_codes[j].codelen && nVal == huffman_codes[j].code)
   1262           break;
   1263       }
   1264       if (j < kRunCodesSize)
   1265         break;
   1266     }
   1267     int32_t runcode = static_cast<int32_t>(j);
   1268     if (runcode < 32) {
   1269       SBSYMCODES[i].codelen = runcode;
   1270       run = 0;
   1271     } else if (runcode == 32) {
   1272       if (pStream->readNBits(2, &nTemp) != 0)
   1273         return std::vector<JBig2HuffmanCode>();
   1274       run = nTemp + 3;
   1275     } else if (runcode == 33) {
   1276       if (pStream->readNBits(3, &nTemp) != 0)
   1277         return std::vector<JBig2HuffmanCode>();
   1278       run = nTemp + 3;
   1279     } else if (runcode == 34) {
   1280       if (pStream->readNBits(7, &nTemp) != 0)
   1281         return std::vector<JBig2HuffmanCode>();
   1282       run = nTemp + 11;
   1283     }
   1284     if (run > 0) {
   1285       if (i + run > (int)SBNUMSYMS)
   1286         return std::vector<JBig2HuffmanCode>();
   1287       for (int32_t k = 0; k < run; ++k) {
   1288         if (runcode == 32 && i > 0)
   1289           SBSYMCODES[i + k].codelen = SBSYMCODES[i - 1].codelen;
   1290         else
   1291           SBSYMCODES[i + k].codelen = 0;
   1292       }
   1293       i += run;
   1294     } else {
   1295       ++i;
   1296     }
   1297   }
   1298   huffman_assign_code(SBSYMCODES.data(), SBNUMSYMS);
   1299   return SBSYMCODES;
   1300 }
   1301 
   1302 void CJBig2_Context::huffman_assign_code(JBig2HuffmanCode* SBSYMCODES,
   1303                                          int NTEMP) {
   1304   // TODO(thestig) CJBig2_HuffmanTable::parseFromCodedBuffer() has similar code.
   1305   int LENMAX = 0;
   1306   for (int i = 0; i < NTEMP; ++i)
   1307     LENMAX = std::max(LENMAX, SBSYMCODES[i].codelen);
   1308   std::vector<int> LENCOUNT(LENMAX + 1);
   1309   std::vector<int> FIRSTCODE(LENMAX + 1);
   1310   for (int i = 0; i < NTEMP; ++i)
   1311     ++LENCOUNT[SBSYMCODES[i].codelen];
   1312   LENCOUNT[0] = 0;
   1313   for (int CURLEN = 1; CURLEN <= LENMAX; ++CURLEN) {
   1314     FIRSTCODE[CURLEN] = (FIRSTCODE[CURLEN - 1] + LENCOUNT[CURLEN - 1]) << 1;
   1315     int CURCODE = FIRSTCODE[CURLEN];
   1316     for (int CURTEMP = 0; CURTEMP < NTEMP; ++CURTEMP) {
   1317       if (SBSYMCODES[CURTEMP].codelen == CURLEN) {
   1318         SBSYMCODES[CURTEMP].code = CURCODE;
   1319         CURCODE = CURCODE + 1;
   1320       }
   1321     }
   1322   }
   1323 }
   1324