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