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