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