Various changes to JBig2 cache:
[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 >> 15) & 1) ? TRUE : FALSE;
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   nonstd::unique_ptr<JBig2ArithCtx, FxFreeDeleter> gbContext;
572   nonstd::unique_ptr<JBig2ArithCtx, FxFreeDeleter> grContext;
573   if ((wFlags & 0x0100) && pLRSeg && pLRSeg->m_Result.sd->m_bContextRetained) {
574     if (pSymbolDictDecoder->SDHUFF == 0) {
575       const size_t size = GetHuffContextSize(pSymbolDictDecoder->SDTEMPLATE);
576       gbContext.reset(FX_Alloc(JBig2ArithCtx, size));
577       JBIG2_memcpy(gbContext.get(), pLRSeg->m_Result.sd->m_gbContext,
578                    sizeof(JBig2ArithCtx) * size);
579     }
580     if (pSymbolDictDecoder->SDREFAGG == 1) {
581       const size_t size = GetRefAggContextSize(pSymbolDictDecoder->SDRTEMPLATE);
582       grContext.reset(FX_Alloc(JBig2ArithCtx, size));
583       JBIG2_memcpy(grContext.get(), pLRSeg->m_Result.sd->m_grContext,
584                    sizeof(JBig2ArithCtx) * size);
585     }
586   } else {
587     if (pSymbolDictDecoder->SDHUFF == 0) {
588       const size_t size = GetHuffContextSize(pSymbolDictDecoder->SDTEMPLATE);
589       gbContext.reset(FX_Alloc(JBig2ArithCtx, size));
590       JBIG2_memset(gbContext.get(), 0, sizeof(JBig2ArithCtx) * size);
591     }
592     if (pSymbolDictDecoder->SDREFAGG == 1) {
593       const size_t size = GetRefAggContextSize(pSymbolDictDecoder->SDRTEMPLATE);
594       grContext.reset(FX_Alloc(JBig2ArithCtx, size));
595       JBIG2_memset(grContext.get(), 0, sizeof(JBig2ArithCtx) * size);
596     }
597   }
598   CJBig2_CacheKey key =
599       CJBig2_CacheKey(pSegment->m_dwObjNum, pSegment->m_dwDataOffset);
600   FX_BOOL cache_hit = false;
601   pSegment->m_nResultType = JBIG2_SYMBOL_DICT_POINTER;
602   if (m_bIsGlobal && key.first != 0) {
603     for (auto it = m_pSymbolDictCache->begin(); it != m_pSymbolDictCache->end();
604          ++it) {
605       if (it->first == key) {
606         nonstd::unique_ptr<CJBig2_SymbolDict> copy(it->second->DeepCopy());
607         pSegment->m_Result.sd = copy.release();
608         m_pSymbolDictCache->push_front(*it);
609         m_pSymbolDictCache->erase(it);
610         cache_hit = true;
611         break;
612       }
613     }
614   }
615   if (!cache_hit) {
616     if (pSymbolDictDecoder->SDHUFF == 0) {
617       nonstd::unique_ptr<CJBig2_ArithDecoder> pArithDecoder(
618           new CJBig2_ArithDecoder(m_pStream.get()));
619       pSegment->m_Result.sd = pSymbolDictDecoder->decode_Arith(
620           pArithDecoder.get(), gbContext.get(), grContext.get());
621       if (!pSegment->m_Result.sd)
622         return JBIG2_ERROR_FATAL;
623
624       m_pStream->alignByte();
625       m_pStream->offset(2);
626     } else {
627       pSegment->m_Result.sd = pSymbolDictDecoder->decode_Huffman(
628           m_pStream.get(), gbContext.get(), grContext.get(), pPause);
629       if (!pSegment->m_Result.sd)
630         return JBIG2_ERROR_FATAL;
631       m_pStream->alignByte();
632     }
633     if (m_bIsGlobal && kSymbolDictCacheMaxSize > 0) {
634       nonstd::unique_ptr<CJBig2_SymbolDict> value =
635           pSegment->m_Result.sd->DeepCopy();
636       if (value) {
637         while (m_pSymbolDictCache->size() >= kSymbolDictCacheMaxSize) {
638           delete m_pSymbolDictCache->back().second;
639           m_pSymbolDictCache->pop_back();
640         }
641         m_pSymbolDictCache->push_front(CJBig2_CachePair(key, value.release()));
642       }
643     }
644   }
645   if (wFlags & 0x0200) {
646     pSegment->m_Result.sd->m_bContextRetained = TRUE;
647     if (pSymbolDictDecoder->SDHUFF == 0) {
648       pSegment->m_Result.sd->m_gbContext = gbContext.release();
649     }
650     if (pSymbolDictDecoder->SDREFAGG == 1) {
651       pSegment->m_Result.sd->m_grContext = grContext.release();
652     }
653   }
654   return JBIG2_SUCCESS;
655 }
656
657 int32_t CJBig2_Context::parseTextRegion(CJBig2_Segment* pSegment) {
658   FX_WORD wFlags;
659   JBig2RegionInfo ri;
660   if (parseRegionInfo(&ri) != JBIG2_SUCCESS ||
661       m_pStream->readShortInteger(&wFlags) != 0) {
662     return JBIG2_ERROR_TOO_SHORT;
663   }
664
665   nonstd::unique_ptr<CJBig2_TRDProc> pTRD(new CJBig2_TRDProc);
666   pTRD->SBW = ri.width;
667   pTRD->SBH = ri.height;
668   pTRD->SBHUFF = wFlags & 0x0001;
669   pTRD->SBREFINE = (wFlags >> 1) & 0x0001;
670   FX_DWORD dwTemp = (wFlags >> 2) & 0x0003;
671   pTRD->SBSTRIPS = 1 << dwTemp;
672   pTRD->REFCORNER = (JBig2Corner)((wFlags >> 4) & 0x0003);
673   pTRD->TRANSPOSED = (wFlags >> 6) & 0x0001;
674   pTRD->SBCOMBOP = (JBig2ComposeOp)((wFlags >> 7) & 0x0003);
675   pTRD->SBDEFPIXEL = (wFlags >> 9) & 0x0001;
676   pTRD->SBDSOFFSET = (wFlags >> 10) & 0x001f;
677   if (pTRD->SBDSOFFSET >= 0x0010) {
678     pTRD->SBDSOFFSET = pTRD->SBDSOFFSET - 0x0020;
679   }
680   pTRD->SBRTEMPLATE = (wFlags >> 15) & 0x0001;
681
682   uint8_t cSBHUFFFS;
683   uint8_t cSBHUFFDS;
684   uint8_t cSBHUFFDT;
685   uint8_t cSBHUFFRDW;
686   uint8_t cSBHUFFRDH;
687   uint8_t cSBHUFFRDX;
688   uint8_t cSBHUFFRDY;
689   uint8_t cSBHUFFRSIZE;
690   if (pTRD->SBHUFF == 1) {
691     if (m_pStream->readShortInteger(&wFlags) != 0)
692       return JBIG2_ERROR_TOO_SHORT;
693
694     cSBHUFFFS = wFlags & 0x0003;
695     cSBHUFFDS = (wFlags >> 2) & 0x0003;
696     cSBHUFFDT = (wFlags >> 4) & 0x0003;
697     cSBHUFFRDW = (wFlags >> 6) & 0x0003;
698     cSBHUFFRDH = (wFlags >> 8) & 0x0003;
699     cSBHUFFRDX = (wFlags >> 10) & 0x0003;
700     cSBHUFFRDY = (wFlags >> 12) & 0x0003;
701     cSBHUFFRSIZE = (wFlags >> 14) & 0x0001;
702   }
703   if (pTRD->SBREFINE == 1 && pTRD->SBRTEMPLATE == 0) {
704     for (int32_t i = 0; i < 4; ++i) {
705       if (m_pStream->read1Byte((uint8_t*)&pTRD->SBRAT[i]) != 0)
706         return JBIG2_ERROR_TOO_SHORT;
707     }
708   }
709   if (m_pStream->readInteger(&pTRD->SBNUMINSTANCES) != 0)
710     return JBIG2_ERROR_TOO_SHORT;
711
712   for (int32_t i = 0; i < pSegment->m_nReferred_to_segment_count; ++i) {
713     if (!findSegmentByNumber(pSegment->m_pReferred_to_segment_numbers[i]))
714       return JBIG2_ERROR_FATAL;
715   }
716
717   pTRD->SBNUMSYMS = 0;
718   for (int32_t i = 0; i < pSegment->m_nReferred_to_segment_count; ++i) {
719     CJBig2_Segment* pSeg =
720         findSegmentByNumber(pSegment->m_pReferred_to_segment_numbers[i]);
721     if (pSeg->m_cFlags.s.type == 0) {
722       pTRD->SBNUMSYMS += pSeg->m_Result.sd->NumImages();
723     }
724   }
725
726   nonstd::unique_ptr<CJBig2_Image*, FxFreeDeleter> SBSYMS;
727   if (pTRD->SBNUMSYMS > 0) {
728     SBSYMS.reset(FX_Alloc(CJBig2_Image*, pTRD->SBNUMSYMS));
729     dwTemp = 0;
730     for (int32_t i = 0; i < pSegment->m_nReferred_to_segment_count; ++i) {
731       CJBig2_Segment* pSeg =
732           findSegmentByNumber(pSegment->m_pReferred_to_segment_numbers[i]);
733       if (pSeg->m_cFlags.s.type == 0) {
734         const CJBig2_SymbolDict& dict = *pSeg->m_Result.sd;
735         for (size_t j = 0; j < dict.NumImages(); ++j)
736           SBSYMS.get()[dwTemp + j] = dict.GetImage(j);
737         dwTemp += dict.NumImages();
738       }
739     }
740     pTRD->SBSYMS = SBSYMS.get();
741   } else {
742     pTRD->SBSYMS = NULL;
743   }
744
745   nonstd::unique_ptr<JBig2HuffmanCode, FxFreeDeleter> SBSYMCODES;
746   if (pTRD->SBHUFF == 1) {
747     SBSYMCODES.reset(
748         decodeSymbolIDHuffmanTable(m_pStream.get(), pTRD->SBNUMSYMS));
749     if (!SBSYMCODES)
750       return JBIG2_ERROR_FATAL;
751
752     m_pStream->alignByte();
753     pTRD->SBSYMCODES = SBSYMCODES.get();
754   } else {
755     dwTemp = 0;
756     while ((FX_DWORD)(1 << dwTemp) < pTRD->SBNUMSYMS) {
757       ++dwTemp;
758     }
759     pTRD->SBSYMCODELEN = (uint8_t)dwTemp;
760   }
761
762   nonstd::unique_ptr<CJBig2_HuffmanTable> Table_B1;
763   nonstd::unique_ptr<CJBig2_HuffmanTable> Table_B6;
764   nonstd::unique_ptr<CJBig2_HuffmanTable> Table_B7;
765   nonstd::unique_ptr<CJBig2_HuffmanTable> Table_B8;
766   nonstd::unique_ptr<CJBig2_HuffmanTable> Table_B9;
767   nonstd::unique_ptr<CJBig2_HuffmanTable> Table_B10;
768   nonstd::unique_ptr<CJBig2_HuffmanTable> Table_B11;
769   nonstd::unique_ptr<CJBig2_HuffmanTable> Table_B12;
770   nonstd::unique_ptr<CJBig2_HuffmanTable> Table_B13;
771   nonstd::unique_ptr<CJBig2_HuffmanTable> Table_B14;
772   nonstd::unique_ptr<CJBig2_HuffmanTable> Table_B15;
773   if (pTRD->SBHUFF == 1) {
774     if (cSBHUFFFS == 2 || cSBHUFFRDW == 2 || cSBHUFFRDH == 2 ||
775         cSBHUFFRDX == 2 || cSBHUFFRDY == 2) {
776       return JBIG2_ERROR_FATAL;
777     }
778     int32_t nIndex = 0;
779     if (cSBHUFFFS == 0) {
780       Table_B6.reset(new CJBig2_HuffmanTable(HuffmanTable_B6,
781                                              FX_ArraySize(HuffmanTable_B6),
782                                              HuffmanTable_HTOOB_B6));
783       pTRD->SBHUFFFS = Table_B6.get();
784     } else if (cSBHUFFFS == 1) {
785       Table_B7.reset(new CJBig2_HuffmanTable(HuffmanTable_B7,
786                                              FX_ArraySize(HuffmanTable_B7),
787                                              HuffmanTable_HTOOB_B7));
788       pTRD->SBHUFFFS = Table_B7.get();
789     } else {
790       CJBig2_Segment* pSeg =
791           findReferredSegmentByTypeAndIndex(pSegment, 53, ++nIndex);
792       if (!pSeg)
793         return JBIG2_ERROR_FATAL;
794       pTRD->SBHUFFFS = pSeg->m_Result.ht;
795     }
796     if (cSBHUFFDS == 0) {
797       Table_B8.reset(new CJBig2_HuffmanTable(HuffmanTable_B8,
798                                              FX_ArraySize(HuffmanTable_B8),
799                                              HuffmanTable_HTOOB_B8));
800       pTRD->SBHUFFDS = Table_B8.get();
801     } else if (cSBHUFFDS == 1) {
802       Table_B9.reset(new CJBig2_HuffmanTable(HuffmanTable_B9,
803                                              FX_ArraySize(HuffmanTable_B9),
804                                              HuffmanTable_HTOOB_B9));
805       pTRD->SBHUFFDS = Table_B9.get();
806     } else if (cSBHUFFDS == 2) {
807       Table_B10.reset(new CJBig2_HuffmanTable(HuffmanTable_B10,
808                                               FX_ArraySize(HuffmanTable_B10),
809                                               HuffmanTable_HTOOB_B10));
810       pTRD->SBHUFFDS = Table_B10.get();
811     } else {
812       CJBig2_Segment* pSeg =
813           findReferredSegmentByTypeAndIndex(pSegment, 53, ++nIndex);
814       if (!pSeg)
815         return JBIG2_ERROR_FATAL;
816       pTRD->SBHUFFDS = pSeg->m_Result.ht;
817     }
818     if (cSBHUFFDT == 0) {
819       Table_B11.reset(new CJBig2_HuffmanTable(HuffmanTable_B11,
820                                               FX_ArraySize(HuffmanTable_B11),
821                                               HuffmanTable_HTOOB_B11));
822       pTRD->SBHUFFDT = Table_B11.get();
823     } else if (cSBHUFFDT == 1) {
824       Table_B12.reset(new CJBig2_HuffmanTable(HuffmanTable_B12,
825                                               FX_ArraySize(HuffmanTable_B12),
826                                               HuffmanTable_HTOOB_B12));
827       pTRD->SBHUFFDT = Table_B12.get();
828     } else if (cSBHUFFDT == 2) {
829       Table_B13.reset(new CJBig2_HuffmanTable(HuffmanTable_B13,
830                                               FX_ArraySize(HuffmanTable_B13),
831                                               HuffmanTable_HTOOB_B13));
832       pTRD->SBHUFFDT = Table_B13.get();
833     } else {
834       CJBig2_Segment* pSeg =
835           findReferredSegmentByTypeAndIndex(pSegment, 53, ++nIndex);
836       if (!pSeg)
837         return JBIG2_ERROR_FATAL;
838       pTRD->SBHUFFDT = pSeg->m_Result.ht;
839     }
840     if (cSBHUFFRDW == 0) {
841       Table_B14.reset(new CJBig2_HuffmanTable(HuffmanTable_B14,
842                                               FX_ArraySize(HuffmanTable_B14),
843                                               HuffmanTable_HTOOB_B14));
844       pTRD->SBHUFFRDW = Table_B14.get();
845     } else if (cSBHUFFRDW == 1) {
846       Table_B15.reset(new CJBig2_HuffmanTable(HuffmanTable_B15,
847                                               FX_ArraySize(HuffmanTable_B15),
848                                               HuffmanTable_HTOOB_B15));
849       pTRD->SBHUFFRDW = Table_B15.get();
850     } else {
851       CJBig2_Segment* pSeg =
852           findReferredSegmentByTypeAndIndex(pSegment, 53, ++nIndex);
853       if (!pSeg)
854         return JBIG2_ERROR_FATAL;
855       pTRD->SBHUFFRDW = pSeg->m_Result.ht;
856     }
857     if (cSBHUFFRDH == 0) {
858       if (!Table_B14) {
859         Table_B14.reset(new CJBig2_HuffmanTable(HuffmanTable_B14,
860                                                 FX_ArraySize(HuffmanTable_B14),
861                                                 HuffmanTable_HTOOB_B14));
862       }
863       pTRD->SBHUFFRDH = Table_B14.get();
864     } else if (cSBHUFFRDH == 1) {
865       if (!Table_B15) {
866         Table_B15.reset(new CJBig2_HuffmanTable(HuffmanTable_B15,
867                                                 FX_ArraySize(HuffmanTable_B15),
868                                                 HuffmanTable_HTOOB_B15));
869       }
870       pTRD->SBHUFFRDH = Table_B15.get();
871     } else {
872       CJBig2_Segment* pSeg =
873           findReferredSegmentByTypeAndIndex(pSegment, 53, ++nIndex);
874       if (!pSeg)
875         return JBIG2_ERROR_FATAL;
876       pTRD->SBHUFFRDH = pSeg->m_Result.ht;
877     }
878     if (cSBHUFFRDX == 0) {
879       if (!Table_B14) {
880         Table_B14.reset(new CJBig2_HuffmanTable(HuffmanTable_B14,
881                                                 FX_ArraySize(HuffmanTable_B14),
882                                                 HuffmanTable_HTOOB_B14));
883       }
884       pTRD->SBHUFFRDX = Table_B14.get();
885     } else if (cSBHUFFRDX == 1) {
886       if (!Table_B15) {
887         Table_B15.reset(new CJBig2_HuffmanTable(HuffmanTable_B15,
888                                                 FX_ArraySize(HuffmanTable_B15),
889                                                 HuffmanTable_HTOOB_B15));
890       }
891       pTRD->SBHUFFRDX = Table_B15.get();
892     } else {
893       CJBig2_Segment* pSeg =
894           findReferredSegmentByTypeAndIndex(pSegment, 53, ++nIndex);
895       if (!pSeg)
896         return JBIG2_ERROR_FATAL;
897       pTRD->SBHUFFRDX = pSeg->m_Result.ht;
898     }
899     if (cSBHUFFRDY == 0) {
900       if (!Table_B14) {
901         Table_B14.reset(new CJBig2_HuffmanTable(HuffmanTable_B14,
902                                                 FX_ArraySize(HuffmanTable_B14),
903                                                 HuffmanTable_HTOOB_B14));
904       }
905       pTRD->SBHUFFRDY = Table_B14.get();
906     } else if (cSBHUFFRDY == 1) {
907       if (!Table_B15) {
908         Table_B15.reset(new CJBig2_HuffmanTable(HuffmanTable_B15,
909                                                 FX_ArraySize(HuffmanTable_B15),
910                                                 HuffmanTable_HTOOB_B15));
911       }
912       pTRD->SBHUFFRDY = Table_B15.get();
913     } else {
914       CJBig2_Segment* pSeg =
915           findReferredSegmentByTypeAndIndex(pSegment, 53, ++nIndex);
916       if (!pSeg)
917         return JBIG2_ERROR_FATAL;
918       pTRD->SBHUFFRDY = pSeg->m_Result.ht;
919     }
920     if (cSBHUFFRSIZE == 0) {
921       Table_B1.reset(new CJBig2_HuffmanTable(HuffmanTable_B1,
922                                              FX_ArraySize(HuffmanTable_B1),
923                                              HuffmanTable_HTOOB_B1));
924       pTRD->SBHUFFRSIZE = Table_B1.get();
925     } else {
926       CJBig2_Segment* pSeg =
927           findReferredSegmentByTypeAndIndex(pSegment, 53, ++nIndex);
928       if (!pSeg)
929         return JBIG2_ERROR_FATAL;
930       pTRD->SBHUFFRSIZE = pSeg->m_Result.ht;
931     }
932   }
933   nonstd::unique_ptr<JBig2ArithCtx, FxFreeDeleter> grContext;
934   if (pTRD->SBREFINE == 1) {
935     const size_t size = GetRefAggContextSize(pTRD->SBRTEMPLATE);
936     grContext.reset(FX_Alloc(JBig2ArithCtx, size));
937     JBIG2_memset(grContext.get(), 0, sizeof(JBig2ArithCtx) * size);
938   }
939   if (pTRD->SBHUFF == 0) {
940     nonstd::unique_ptr<CJBig2_ArithDecoder> pArithDecoder(
941         new CJBig2_ArithDecoder(m_pStream.get()));
942     pSegment->m_nResultType = JBIG2_IMAGE_POINTER;
943     pSegment->m_Result.im =
944         pTRD->decode_Arith(pArithDecoder.get(), grContext.get());
945     if (!pSegment->m_Result.im)
946       return JBIG2_ERROR_FATAL;
947     m_pStream->alignByte();
948     m_pStream->offset(2);
949   } else {
950     pSegment->m_nResultType = JBIG2_IMAGE_POINTER;
951     pSegment->m_Result.im =
952         pTRD->decode_Huffman(m_pStream.get(), grContext.get());
953     if (!pSegment->m_Result.im)
954       return JBIG2_ERROR_FATAL;
955     m_pStream->alignByte();
956   }
957   if (pSegment->m_cFlags.s.type != 4) {
958     if (!m_bBufSpecified) {
959       JBig2PageInfo* pPageInfo = m_PageInfoList.back();
960       if ((pPageInfo->m_bIsStriped == 1) &&
961           (ri.y + ri.height > m_pPage->m_nHeight)) {
962         m_pPage->expand(ri.y + ri.height, (pPageInfo->m_cFlags & 4) ? 1 : 0);
963       }
964     }
965     m_pPage->composeFrom(ri.x, ri.y, pSegment->m_Result.im,
966                          (JBig2ComposeOp)(ri.flags & 0x03));
967     delete pSegment->m_Result.im;
968     pSegment->m_Result.im = NULL;
969   }
970   return JBIG2_SUCCESS;
971 }
972
973 int32_t CJBig2_Context::parsePatternDict(CJBig2_Segment* pSegment,
974                                          IFX_Pause* pPause) {
975   uint8_t cFlags;
976   nonstd::unique_ptr<CJBig2_PDDProc> pPDD(new CJBig2_PDDProc);
977   if (m_pStream->read1Byte(&cFlags) != 0 ||
978       m_pStream->read1Byte(&pPDD->HDPW) != 0 ||
979       m_pStream->read1Byte(&pPDD->HDPH) != 0 ||
980       m_pStream->readInteger(&pPDD->GRAYMAX) != 0) {
981     return JBIG2_ERROR_TOO_SHORT;
982   }
983   if (pPDD->GRAYMAX > JBIG2_MAX_PATTERN_INDEX)
984     return JBIG2_ERROR_LIMIT;
985
986   pPDD->HDMMR = cFlags & 0x01;
987   pPDD->HDTEMPLATE = (cFlags >> 1) & 0x03;
988   pSegment->m_nResultType = JBIG2_PATTERN_DICT_POINTER;
989   if (pPDD->HDMMR == 0) {
990     const size_t size = GetHuffContextSize(pPDD->HDTEMPLATE);
991     nonstd::unique_ptr<JBig2ArithCtx, FxFreeDeleter> gbContext(
992         FX_Alloc(JBig2ArithCtx, size));
993     JBIG2_memset(gbContext.get(), 0, sizeof(JBig2ArithCtx) * size);
994     nonstd::unique_ptr<CJBig2_ArithDecoder> pArithDecoder(
995         new CJBig2_ArithDecoder(m_pStream.get()));
996     pSegment->m_Result.pd =
997         pPDD->decode_Arith(pArithDecoder.get(), gbContext.get(), pPause);
998     if (!pSegment->m_Result.pd)
999       return JBIG2_ERROR_FATAL;
1000
1001     m_pStream->alignByte();
1002     m_pStream->offset(2);
1003   } else {
1004     pSegment->m_Result.pd = pPDD->decode_MMR(m_pStream.get(), pPause);
1005     if (!pSegment->m_Result.pd)
1006       return JBIG2_ERROR_FATAL;
1007     m_pStream->alignByte();
1008   }
1009   return JBIG2_SUCCESS;
1010 }
1011
1012 int32_t CJBig2_Context::parseHalftoneRegion(CJBig2_Segment* pSegment,
1013                                             IFX_Pause* pPause) {
1014   uint8_t cFlags;
1015   JBig2RegionInfo ri;
1016   nonstd::unique_ptr<CJBig2_HTRDProc> pHRD(new CJBig2_HTRDProc);
1017   if (parseRegionInfo(&ri) != JBIG2_SUCCESS ||
1018       m_pStream->read1Byte(&cFlags) != 0 ||
1019       m_pStream->readInteger(&pHRD->HGW) != 0 ||
1020       m_pStream->readInteger(&pHRD->HGH) != 0 ||
1021       m_pStream->readInteger((FX_DWORD*)&pHRD->HGX) != 0 ||
1022       m_pStream->readInteger((FX_DWORD*)&pHRD->HGY) != 0 ||
1023       m_pStream->readShortInteger(&pHRD->HRX) != 0 ||
1024       m_pStream->readShortInteger(&pHRD->HRY) != 0) {
1025     return JBIG2_ERROR_TOO_SHORT;
1026   }
1027
1028   if (pHRD->HGW == 0 || pHRD->HGH == 0)
1029     return JBIG2_ERROR_FATAL;
1030
1031   pHRD->HBW = ri.width;
1032   pHRD->HBH = ri.height;
1033   pHRD->HMMR = cFlags & 0x01;
1034   pHRD->HTEMPLATE = (cFlags >> 1) & 0x03;
1035   pHRD->HENABLESKIP = (cFlags >> 3) & 0x01;
1036   pHRD->HCOMBOP = (JBig2ComposeOp)((cFlags >> 4) & 0x07);
1037   pHRD->HDEFPIXEL = (cFlags >> 7) & 0x01;
1038   if (pSegment->m_nReferred_to_segment_count != 1)
1039     return JBIG2_ERROR_FATAL;
1040
1041   CJBig2_Segment* pSeg =
1042       findSegmentByNumber(pSegment->m_pReferred_to_segment_numbers[0]);
1043   if (!pSeg || (pSeg->m_cFlags.s.type != 16))
1044     return JBIG2_ERROR_FATAL;
1045
1046   CJBig2_PatternDict* pPatternDict = pSeg->m_Result.pd;
1047   if (!pPatternDict || (pPatternDict->NUMPATS == 0))
1048     return JBIG2_ERROR_FATAL;
1049
1050   pHRD->HNUMPATS = pPatternDict->NUMPATS;
1051   pHRD->HPATS = pPatternDict->HDPATS;
1052   pHRD->HPW = pPatternDict->HDPATS[0]->m_nWidth;
1053   pHRD->HPH = pPatternDict->HDPATS[0]->m_nHeight;
1054   pSegment->m_nResultType = JBIG2_IMAGE_POINTER;
1055   if (pHRD->HMMR == 0) {
1056     const size_t size = GetHuffContextSize(pHRD->HTEMPLATE);
1057     nonstd::unique_ptr<JBig2ArithCtx, FxFreeDeleter> gbContext(
1058         FX_Alloc(JBig2ArithCtx, size));
1059     JBIG2_memset(gbContext.get(), 0, sizeof(JBig2ArithCtx) * size);
1060     nonstd::unique_ptr<CJBig2_ArithDecoder> pArithDecoder(
1061         new CJBig2_ArithDecoder(m_pStream.get()));
1062     pSegment->m_Result.im =
1063         pHRD->decode_Arith(pArithDecoder.get(), gbContext.get(), pPause);
1064     if (!pSegment->m_Result.im)
1065       return JBIG2_ERROR_FATAL;
1066
1067     m_pStream->alignByte();
1068     m_pStream->offset(2);
1069   } else {
1070     pSegment->m_Result.im = pHRD->decode_MMR(m_pStream.get(), pPause);
1071     if (!pSegment->m_Result.im)
1072       return JBIG2_ERROR_FATAL;
1073     m_pStream->alignByte();
1074   }
1075   if (pSegment->m_cFlags.s.type != 20) {
1076     if (!m_bBufSpecified) {
1077       JBig2PageInfo* pPageInfo = m_PageInfoList.back();
1078       if (pPageInfo->m_bIsStriped == 1 &&
1079           ri.y + ri.height > m_pPage->m_nHeight) {
1080         m_pPage->expand(ri.y + ri.height, (pPageInfo->m_cFlags & 4) ? 1 : 0);
1081       }
1082     }
1083     m_pPage->composeFrom(ri.x, ri.y, pSegment->m_Result.im,
1084                          (JBig2ComposeOp)(ri.flags & 0x03));
1085     delete pSegment->m_Result.im;
1086     pSegment->m_Result.im = NULL;
1087   }
1088   return JBIG2_SUCCESS;
1089 }
1090
1091 int32_t CJBig2_Context::parseGenericRegion(CJBig2_Segment* pSegment,
1092                                            IFX_Pause* pPause) {
1093   if (!m_pGRD) {
1094     nonstd::unique_ptr<CJBig2_GRDProc> pGRD(new CJBig2_GRDProc);
1095     uint8_t cFlags;
1096     if (parseRegionInfo(&m_ri) != JBIG2_SUCCESS ||
1097         m_pStream->read1Byte(&cFlags) != 0) {
1098       return JBIG2_ERROR_TOO_SHORT;
1099     }
1100     if (m_ri.height < 0 || m_ri.width < 0)
1101       return JBIG2_FAILED;
1102
1103     pGRD->GBW = m_ri.width;
1104     pGRD->GBH = m_ri.height;
1105     pGRD->MMR = cFlags & 0x01;
1106     pGRD->GBTEMPLATE = (cFlags >> 1) & 0x03;
1107     pGRD->TPGDON = (cFlags >> 3) & 0x01;
1108     if (pGRD->MMR == 0) {
1109       if (pGRD->GBTEMPLATE == 0) {
1110         for (int32_t i = 0; i < 8; ++i) {
1111           if (m_pStream->read1Byte((uint8_t*)&pGRD->GBAT[i]) != 0) {
1112             return JBIG2_ERROR_TOO_SHORT;
1113           }
1114         }
1115       } else {
1116         for (int32_t i = 0; i < 2; ++i) {
1117           if (m_pStream->read1Byte((uint8_t*)&pGRD->GBAT[i]) != 0) {
1118             return JBIG2_ERROR_TOO_SHORT;
1119           }
1120         }
1121       }
1122     }
1123     pGRD->USESKIP = 0;
1124     m_pGRD = nonstd::move(pGRD);
1125   }
1126   pSegment->m_nResultType = JBIG2_IMAGE_POINTER;
1127   if (m_pGRD->MMR == 0) {
1128     if (!m_gbContext) {
1129       const size_t size = GetHuffContextSize(m_pGRD->GBTEMPLATE);
1130       m_gbContext = FX_Alloc(JBig2ArithCtx, size);
1131       JBIG2_memset(m_gbContext, 0, sizeof(JBig2ArithCtx) * size);
1132     }
1133     if (!m_pArithDecoder) {
1134       m_pArithDecoder.reset(new CJBig2_ArithDecoder(m_pStream.get()));
1135       m_ProcessingStatus = m_pGRD->Start_decode_Arith(
1136           &pSegment->m_Result.im, m_pArithDecoder.get(), m_gbContext, pPause);
1137     } else {
1138       m_ProcessingStatus = m_pGRD->Continue_decode(pPause);
1139     }
1140     if (m_ProcessingStatus == FXCODEC_STATUS_DECODE_TOBECONTINUE) {
1141       if (pSegment->m_cFlags.s.type != 36) {
1142         if (!m_bBufSpecified) {
1143           JBig2PageInfo* pPageInfo = m_PageInfoList.back();
1144           if ((pPageInfo->m_bIsStriped == 1) &&
1145               (m_ri.y + m_ri.height > m_pPage->m_nHeight)) {
1146             m_pPage->expand(m_ri.y + m_ri.height,
1147                             (pPageInfo->m_cFlags & 4) ? 1 : 0);
1148           }
1149         }
1150         FX_RECT Rect = m_pGRD->GetReplaceRect();
1151         m_pPage->composeFrom(m_ri.x + Rect.left, m_ri.y + Rect.top,
1152                              pSegment->m_Result.im,
1153                              (JBig2ComposeOp)(m_ri.flags & 0x03), &Rect);
1154       }
1155       return JBIG2_SUCCESS;
1156     } else {
1157       m_pArithDecoder.reset();
1158       FX_Free(m_gbContext);
1159       m_gbContext = NULL;
1160       if (!pSegment->m_Result.im) {
1161         m_ProcessingStatus = FXCODEC_STATUS_ERROR;
1162         m_pGRD.reset();
1163         return JBIG2_ERROR_FATAL;
1164       }
1165       m_pStream->alignByte();
1166       m_pStream->offset(2);
1167     }
1168   } else {
1169     FXCODEC_STATUS status = m_pGRD->Start_decode_MMR(&pSegment->m_Result.im,
1170                                                      m_pStream.get(), pPause);
1171     while (status == FXCODEC_STATUS_DECODE_TOBECONTINUE) {
1172       m_pGRD->Continue_decode(pPause);
1173     }
1174     if (!pSegment->m_Result.im) {
1175       m_pGRD.reset();
1176       return JBIG2_ERROR_FATAL;
1177     }
1178     m_pStream->alignByte();
1179   }
1180   if (pSegment->m_cFlags.s.type != 36) {
1181     if (!m_bBufSpecified) {
1182       JBig2PageInfo* pPageInfo = m_PageInfoList.back();
1183       if ((pPageInfo->m_bIsStriped == 1) &&
1184           (m_ri.y + m_ri.height > m_pPage->m_nHeight)) {
1185         m_pPage->expand(m_ri.y + m_ri.height,
1186                         (pPageInfo->m_cFlags & 4) ? 1 : 0);
1187       }
1188     }
1189     FX_RECT Rect = m_pGRD->GetReplaceRect();
1190     m_pPage->composeFrom(m_ri.x + Rect.left, m_ri.y + Rect.top,
1191                          pSegment->m_Result.im,
1192                          (JBig2ComposeOp)(m_ri.flags & 0x03), &Rect);
1193     delete pSegment->m_Result.im;
1194     pSegment->m_Result.im = NULL;
1195   }
1196   m_pGRD.reset();
1197   return JBIG2_SUCCESS;
1198 }
1199
1200 int32_t CJBig2_Context::parseGenericRefinementRegion(CJBig2_Segment* pSegment) {
1201   JBig2RegionInfo ri;
1202   uint8_t cFlags;
1203   if (parseRegionInfo(&ri) != JBIG2_SUCCESS ||
1204       m_pStream->read1Byte(&cFlags) != 0) {
1205     return JBIG2_ERROR_TOO_SHORT;
1206   }
1207   nonstd::unique_ptr<CJBig2_GRRDProc> pGRRD(new CJBig2_GRRDProc);
1208   pGRRD->GRW = ri.width;
1209   pGRRD->GRH = ri.height;
1210   pGRRD->GRTEMPLATE = cFlags & 0x01;
1211   pGRRD->TPGRON = (cFlags >> 1) & 0x01;
1212   if (pGRRD->GRTEMPLATE == 0) {
1213     for (int32_t i = 0; i < 4; ++i) {
1214       if (m_pStream->read1Byte((uint8_t*)&pGRRD->GRAT[i]) != 0)
1215         return JBIG2_ERROR_TOO_SHORT;
1216     }
1217   }
1218   CJBig2_Segment* pSeg = nullptr;
1219   if (pSegment->m_nReferred_to_segment_count > 0) {
1220     int32_t i;
1221     for (i = 0; i < pSegment->m_nReferred_to_segment_count; ++i) {
1222       pSeg = findSegmentByNumber(pSegment->m_pReferred_to_segment_numbers[0]);
1223       if (!pSeg)
1224         return JBIG2_ERROR_FATAL;
1225
1226       if (pSeg->m_cFlags.s.type == 4 || pSeg->m_cFlags.s.type == 20 ||
1227           pSeg->m_cFlags.s.type == 36 || pSeg->m_cFlags.s.type == 40) {
1228         break;
1229       }
1230     }
1231     if (i >= pSegment->m_nReferred_to_segment_count)
1232       return JBIG2_ERROR_FATAL;
1233
1234     pGRRD->GRREFERENCE = pSeg->m_Result.im;
1235   } else {
1236     pGRRD->GRREFERENCE = m_pPage.get();
1237   }
1238   pGRRD->GRREFERENCEDX = 0;
1239   pGRRD->GRREFERENCEDY = 0;
1240   const size_t size = GetRefAggContextSize(pGRRD->GRTEMPLATE);
1241   nonstd::unique_ptr<JBig2ArithCtx, FxFreeDeleter> grContext(
1242       FX_Alloc(JBig2ArithCtx, size));
1243   JBIG2_memset(grContext.get(), 0, sizeof(JBig2ArithCtx) * size);
1244   nonstd::unique_ptr<CJBig2_ArithDecoder> pArithDecoder(
1245       new CJBig2_ArithDecoder(m_pStream.get()));
1246   pSegment->m_nResultType = JBIG2_IMAGE_POINTER;
1247   pSegment->m_Result.im = pGRRD->decode(pArithDecoder.get(), grContext.get());
1248   if (!pSegment->m_Result.im)
1249     return JBIG2_ERROR_FATAL;
1250
1251   m_pStream->alignByte();
1252   m_pStream->offset(2);
1253   if (pSegment->m_cFlags.s.type != 40) {
1254     if (!m_bBufSpecified) {
1255       JBig2PageInfo* pPageInfo = m_PageInfoList.back();
1256       if ((pPageInfo->m_bIsStriped == 1) &&
1257           (ri.y + ri.height > m_pPage->m_nHeight)) {
1258         m_pPage->expand(ri.y + ri.height, (pPageInfo->m_cFlags & 4) ? 1 : 0);
1259       }
1260     }
1261     m_pPage->composeFrom(ri.x, ri.y, pSegment->m_Result.im,
1262                          (JBig2ComposeOp)(ri.flags & 0x03));
1263     delete pSegment->m_Result.im;
1264     pSegment->m_Result.im = NULL;
1265   }
1266   return JBIG2_SUCCESS;
1267 }
1268
1269 int32_t CJBig2_Context::parseTable(CJBig2_Segment* pSegment) {
1270   pSegment->m_nResultType = JBIG2_HUFFMAN_TABLE_POINTER;
1271   pSegment->m_Result.ht = new CJBig2_HuffmanTable(m_pStream.get());
1272   if (!pSegment->m_Result.ht->isOK()) {
1273     delete pSegment->m_Result.ht;
1274     pSegment->m_Result.ht = NULL;
1275     return JBIG2_ERROR_FATAL;
1276   }
1277   m_pStream->alignByte();
1278   return JBIG2_SUCCESS;
1279 }
1280
1281 int32_t CJBig2_Context::parseRegionInfo(JBig2RegionInfo* pRI) {
1282   if (m_pStream->readInteger((FX_DWORD*)&pRI->width) != 0 ||
1283       m_pStream->readInteger((FX_DWORD*)&pRI->height) != 0 ||
1284       m_pStream->readInteger((FX_DWORD*)&pRI->x) != 0 ||
1285       m_pStream->readInteger((FX_DWORD*)&pRI->y) != 0 ||
1286       m_pStream->read1Byte(&pRI->flags) != 0) {
1287     return JBIG2_ERROR_TOO_SHORT;
1288   }
1289   return JBIG2_SUCCESS;
1290 }
1291
1292 JBig2HuffmanCode* CJBig2_Context::decodeSymbolIDHuffmanTable(
1293     CJBig2_BitStream* pStream,
1294     FX_DWORD SBNUMSYMS) {
1295   const size_t kRunCodesSize = 35;
1296   int32_t runcodes[kRunCodesSize];
1297   int32_t runcodes_len[kRunCodesSize];
1298   for (int32_t i = 0; i < kRunCodesSize; ++i) {
1299     if (pStream->readNBits(4, &runcodes_len[i]) != 0)
1300       return nullptr;
1301   }
1302   huffman_assign_code(runcodes, runcodes_len, kRunCodesSize);
1303
1304   nonstd::unique_ptr<JBig2HuffmanCode, FxFreeDeleter> SBSYMCODES(
1305       FX_Alloc(JBig2HuffmanCode, SBNUMSYMS));
1306   int32_t run;
1307   int32_t i = 0;
1308   while (i < (int)SBNUMSYMS) {
1309     int32_t j;
1310     int32_t nVal = 0;
1311     int32_t nBits = 0;
1312     FX_DWORD nTemp;
1313     while (true) {
1314       if (pStream->read1Bit(&nTemp) != 0)
1315         return nullptr;
1316
1317       nVal = (nVal << 1) | nTemp;
1318       ++nBits;
1319       for (j = 0; j < kRunCodesSize; ++j) {
1320         if (nBits == runcodes_len[j] && nVal == runcodes[j]) {
1321           break;
1322         }
1323       }
1324       if (j < kRunCodesSize) {
1325         break;
1326       }
1327     }
1328     int32_t runcode = j;
1329     if (runcode < 32) {
1330       SBSYMCODES.get()[i].codelen = runcode;
1331       run = 0;
1332     } else if (runcode == 32) {
1333       if (pStream->readNBits(2, &nTemp) != 0)
1334         return nullptr;
1335       run = nTemp + 3;
1336     } else if (runcode == 33) {
1337       if (pStream->readNBits(3, &nTemp) != 0)
1338         return nullptr;
1339       run = nTemp + 3;
1340     } else if (runcode == 34) {
1341       if (pStream->readNBits(7, &nTemp) != 0)
1342         return nullptr;
1343       run = nTemp + 11;
1344     }
1345     if (run > 0) {
1346       if (i + run > (int)SBNUMSYMS)
1347         return nullptr;
1348       for (j = 0; j < run; ++j) {
1349         if (runcode == 32 && i > 0) {
1350           SBSYMCODES.get()[i + j].codelen = SBSYMCODES.get()[i - 1].codelen;
1351         } else {
1352           SBSYMCODES.get()[i + j].codelen = 0;
1353         }
1354       }
1355       i += run;
1356     } else {
1357       ++i;
1358     }
1359   }
1360   huffman_assign_code(SBSYMCODES.get(), SBNUMSYMS);
1361   return SBSYMCODES.release();
1362 }
1363
1364 void CJBig2_Context::huffman_assign_code(int* CODES, int* PREFLEN, int NTEMP) {
1365   // TODO(thestig) CJBig2_HuffmanTable::parseFromCodedBuffer() has similar code.
1366   int CURLEN, LENMAX, CURCODE, CURTEMP, i;
1367   int* LENCOUNT;
1368   int* FIRSTCODE;
1369   LENMAX = 0;
1370   for (i = 0; i < NTEMP; ++i) {
1371     if (PREFLEN[i] > LENMAX) {
1372       LENMAX = PREFLEN[i];
1373     }
1374   }
1375   LENCOUNT = FX_Alloc(int, LENMAX + 1);
1376   JBIG2_memset(LENCOUNT, 0, sizeof(int) * (LENMAX + 1));
1377   FIRSTCODE = FX_Alloc(int, LENMAX + 1);
1378   for (i = 0; i < NTEMP; ++i) {
1379     ++LENCOUNT[PREFLEN[i]];
1380   }
1381   CURLEN = 1;
1382   FIRSTCODE[0] = 0;
1383   LENCOUNT[0] = 0;
1384   while (CURLEN <= LENMAX) {
1385     FIRSTCODE[CURLEN] = (FIRSTCODE[CURLEN - 1] + LENCOUNT[CURLEN - 1]) << 1;
1386     CURCODE = FIRSTCODE[CURLEN];
1387     CURTEMP = 0;
1388     while (CURTEMP < NTEMP) {
1389       if (PREFLEN[CURTEMP] == CURLEN) {
1390         CODES[CURTEMP] = CURCODE;
1391         CURCODE = CURCODE + 1;
1392       }
1393       CURTEMP = CURTEMP + 1;
1394     }
1395     CURLEN = CURLEN + 1;
1396   }
1397   FX_Free(LENCOUNT);
1398   FX_Free(FIRSTCODE);
1399 }
1400 void CJBig2_Context::huffman_assign_code(JBig2HuffmanCode* SBSYMCODES,
1401                                          int NTEMP) {
1402   int CURLEN, LENMAX, CURCODE, CURTEMP, i;
1403   int* LENCOUNT;
1404   int* FIRSTCODE;
1405   LENMAX = 0;
1406   for (i = 0; i < NTEMP; ++i) {
1407     if (SBSYMCODES[i].codelen > LENMAX) {
1408       LENMAX = SBSYMCODES[i].codelen;
1409     }
1410   }
1411   LENCOUNT = FX_Alloc(int, (LENMAX + 1));
1412   JBIG2_memset(LENCOUNT, 0, sizeof(int) * (LENMAX + 1));
1413   FIRSTCODE = FX_Alloc(int, (LENMAX + 1));
1414   for (i = 0; i < NTEMP; ++i) {
1415     ++LENCOUNT[SBSYMCODES[i].codelen];
1416   }
1417   CURLEN = 1;
1418   FIRSTCODE[0] = 0;
1419   LENCOUNT[0] = 0;
1420   while (CURLEN <= LENMAX) {
1421     FIRSTCODE[CURLEN] = (FIRSTCODE[CURLEN - 1] + LENCOUNT[CURLEN - 1]) << 1;
1422     CURCODE = FIRSTCODE[CURLEN];
1423     CURTEMP = 0;
1424     while (CURTEMP < NTEMP) {
1425       if (SBSYMCODES[CURTEMP].codelen == CURLEN) {
1426         SBSYMCODES[CURTEMP].code = CURCODE;
1427         CURCODE = CURCODE + 1;
1428       }
1429       CURTEMP = CURTEMP + 1;
1430     }
1431     CURLEN = CURLEN + 1;
1432   }
1433   FX_Free(LENCOUNT);
1434   FX_Free(FIRSTCODE);
1435 }