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