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