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