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