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