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