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 
GetHuffContextSize(uint8_t val)26 size_t GetHuffContextSize(uint8_t val) {
27   return val == 0 ? 65536 : val == 1 ? 8192 : 1024;
28 }
29 
GetRefAggContextSize(FX_BOOL val)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 
CreateContext(CPDF_StreamAcc * pGlobalStream,CPDF_StreamAcc * pSrcStream,std::list<CJBig2_CachePair> * pSymbolDictCache,IFX_Pause * pPause)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 
DestroyContext(CJBig2_Context * pContext)54 void CJBig2_Context::DestroyContext(CJBig2_Context* pContext) {
55   delete pContext;
56 }
57 
CJBig2_Context(CPDF_StreamAcc * pGlobalStream,CPDF_StreamAcc * pSrcStream,std::list<CJBig2_CachePair> * pSymbolDictCache,IFX_Pause * pPause,bool bIsGlobal)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 
~CJBig2_Context()83 CJBig2_Context::~CJBig2_Context() {
84   FX_Free(m_gbContext);
85   m_gbContext = NULL;
86   delete m_pGlobalContext;
87   m_pGlobalContext = NULL;
88 }
89 
decode_SquentialOrgnazation(IFX_Pause * pPause)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 }
decode_EmbedOrgnazation(IFX_Pause * pPause)135 int32_t CJBig2_Context::decode_EmbedOrgnazation(IFX_Pause* pPause) {
136   return decode_SquentialOrgnazation(pPause);
137 }
decode_RandomOrgnazation_FirstPage(IFX_Pause * pPause)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 }
decode_RandomOrgnazation(IFX_Pause * pPause)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 }
getFirstPage(uint8_t * pBuf,int32_t width,int32_t height,int32_t stride,IFX_Pause * pPause)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 }
Continue(IFX_Pause * pPause)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 
findSegmentByNumber(FX_DWORD dwNumber)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 }
findReferredSegmentByTypeAndIndex(CJBig2_Segment * pSegment,uint8_t cType,int32_t nIndex)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 }
parseSegmentHeader(CJBig2_Segment * pSegment)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 
parseSegmentData(CJBig2_Segment * pSegment,IFX_Pause * pPause)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 
ProcessingParseSegmentData(CJBig2_Segment * pSegment,IFX_Pause * pPause)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 
parseSymbolDict(CJBig2_Segment * pSegment,IFX_Pause * pPause)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 
parseTextRegion(CJBig2_Segment * pSegment)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 
parsePatternDict(CJBig2_Segment * pSegment,IFX_Pause * pPause)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 
parseHalftoneRegion(CJBig2_Segment * pSegment,IFX_Pause * pPause)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 
parseGenericRegion(CJBig2_Segment * pSegment,IFX_Pause * pPause)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 
parseGenericRefinementRegion(CJBig2_Segment * pSegment)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 
parseTable(CJBig2_Segment * pSegment)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 
parseRegionInfo(JBig2RegionInfo * pRI)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 
decodeSymbolIDHuffmanTable(CJBig2_BitStream * pStream,FX_DWORD SBNUMSYMS)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 
huffman_assign_code(int * CODES,int * PREFLEN,int NTEMP)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 }
huffman_assign_code(JBig2HuffmanCode * SBSYMCODES,int NTEMP)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