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