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