1 // Copyright 2014 The PDFium Authors
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/fxcodec/jbig2/JBig2_ArithDecoder.h"
16 #include "core/fxcodec/jbig2/JBig2_BitStream.h"
17 #include "core/fxcodec/jbig2/JBig2_GrdProc.h"
18 #include "core/fxcodec/jbig2/JBig2_GrrdProc.h"
19 #include "core/fxcodec/jbig2/JBig2_HtrdProc.h"
20 #include "core/fxcodec/jbig2/JBig2_PddProc.h"
21 #include "core/fxcodec/jbig2/JBig2_SddProc.h"
22 #include "core/fxcodec/jbig2/JBig2_TrdProc.h"
23 #include "core/fxcrt/check.h"
24 #include "core/fxcrt/fixed_size_data_vector.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 "core/fxcrt/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,uint64_t global_key,pdfium::span<const uint8_t> pSrcSpan,uint64_t src_key,std::list<CJBig2_CachePair> * pSymbolDictCache)54 std::unique_ptr<CJBig2_Context> CJBig2_Context::Create(
55     pdfium::span<const uint8_t> pGlobalSpan,
56     uint64_t global_key,
57     pdfium::span<const uint8_t> pSrcSpan,
58     uint64_t src_key,
59     std::list<CJBig2_CachePair>* pSymbolDictCache) {
60   auto result = pdfium::WrapUnique(
61       new CJBig2_Context(pSrcSpan, src_key, pSymbolDictCache, false));
62   if (!pGlobalSpan.empty()) {
63     result->m_pGlobalContext = pdfium::WrapUnique(
64         new CJBig2_Context(pGlobalSpan, global_key, pSymbolDictCache, true));
65   }
66   return result;
67 }
68 
CJBig2_Context(pdfium::span<const uint8_t> pSrcSpan,uint64_t src_key,std::list<CJBig2_CachePair> * pSymbolDictCache,bool bIsGlobal)69 CJBig2_Context::CJBig2_Context(pdfium::span<const uint8_t> pSrcSpan,
70                                uint64_t src_key,
71                                std::list<CJBig2_CachePair>* pSymbolDictCache,
72                                bool bIsGlobal)
73     : m_pStream(std::make_unique<CJBig2_BitStream>(pSrcSpan, src_key)),
74       m_HuffmanTables(CJBig2_HuffmanTable::kNumHuffmanTables),
75       m_bIsGlobal(bIsGlobal),
76       m_pSymbolDictCache(pSymbolDictCache) {}
77 
78 CJBig2_Context::~CJBig2_Context() = default;
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 = std::make_unique<CJBig2_Segment>();
88       nRet = ParseSegmentHeader(m_pSegment.get());
89       if (nRet != JBig2_Result::kSuccess) {
90         m_pSegment.reset();
91         return nRet;
92       }
93       m_nOffset = m_pStream->getOffset();
94     }
95     nRet = ParseSegmentData(m_pSegment.get(), pPause);
96     if (m_ProcessingStatus == FXCODEC_STATUS::kDecodeToBeContinued) {
97       m_PauseStep = 2;
98       return JBig2_Result::kSuccess;
99     }
100     if (nRet == JBig2_Result::kEndReached) {
101       m_pSegment.reset();
102       return JBig2_Result::kSuccess;
103     }
104     if (nRet != JBig2_Result::kSuccess) {
105       m_pSegment.reset();
106       return nRet;
107     }
108     if (m_pSegment->m_dwData_length != 0xffffffff) {
109       FX_SAFE_UINT32 new_offset = m_nOffset;
110       new_offset += m_pSegment->m_dwData_length;
111       if (!new_offset.IsValid())
112         return JBig2_Result::kFailure;
113       m_nOffset = new_offset.ValueOrDie();
114       m_pStream->setOffset(m_nOffset);
115     } else {
116       m_pStream->addOffset(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::kDecodeToBeContinued;
122       m_PauseStep = 2;
123       return JBig2_Result::kSuccess;
124     }
125   }
126   return JBig2_Result::kSuccess;
127 }
128 
GetFirstPage(pdfium::span<uint8_t> pBuf,int32_t width,int32_t height,int32_t stride,PauseIndicatorIface * pPause)129 bool CJBig2_Context::GetFirstPage(pdfium::span<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::kError;
138       return nRet == JBig2_Result::kSuccess;
139     }
140   }
141   m_PauseStep = 0;
142   m_pPage = std::make_unique<CJBig2_Image>(width, height, stride, pBuf);
143   m_bBufSpecified = true;
144   if (pPause && pPause->NeedToPauseNow()) {
145     m_PauseStep = 1;
146     m_ProcessingStatus = FXCODEC_STATUS::kDecodeToBeContinued;
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::kDecodeReady;
154   JBig2_Result nRet = JBig2_Result::kSuccess;
155   if (m_PauseStep == 5) {
156     m_ProcessingStatus = FXCODEC_STATUS::kDecodeFinished;
157     return true;
158   }
159 
160   if (m_PauseStep <= 2)
161     nRet = DecodeSequential(pPause);
162   if (m_ProcessingStatus == FXCODEC_STATUS::kDecodeToBeContinued)
163     return nRet == JBig2_Result::kSuccess;
164 
165   m_PauseStep = 5;
166   if (!m_bBufSpecified && nRet == JBig2_Result::kSuccess) {
167     m_ProcessingStatus = FXCODEC_STATUS::kDecodeFinished;
168     return true;
169   }
170   m_ProcessingStatus = nRet == JBig2_Result::kSuccess
171                            ? FXCODEC_STATUS::kDecodeFinished
172                            : FXCODEC_STATUS::kError;
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         kJBig2MaxReferredSegmentCount) {
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_Key = m_pStream->getKey();
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::kDecodeToBeContinued &&
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       uint8_t segment_flags;
322       uint16_t striping_info;
323       auto pPageInfo = std::make_unique<JBig2PageInfo>();
324       if (m_pStream->readInteger(&pPageInfo->m_dwWidth) != 0 ||
325           m_pStream->readInteger(&pPageInfo->m_dwHeight) != 0 ||
326           m_pStream->readInteger(&pPageInfo->m_dwResolutionX) != 0 ||
327           m_pStream->readInteger(&pPageInfo->m_dwResolutionY) != 0 ||
328           m_pStream->read1Byte(&segment_flags) != 0 ||
329           m_pStream->readShortInteger(&striping_info) != 0) {
330         return JBig2_Result::kFailure;
331       }
332 
333       pPageInfo->m_bDefaultPixelValue = !!(segment_flags & 4);
334       pPageInfo->m_bIsStriped = !!(striping_info & 0x8000);
335       pPageInfo->m_wMaxStripeSize = striping_info & 0x7fff;
336       bool bMaxHeight = (pPageInfo->m_dwHeight == 0xffffffff);
337       if (bMaxHeight && !pPageInfo->m_bIsStriped)
338         pPageInfo->m_bIsStriped = true;
339 
340       if (!m_bBufSpecified) {
341         uint32_t height =
342             bMaxHeight ? pPageInfo->m_wMaxStripeSize : pPageInfo->m_dwHeight;
343         m_pPage = std::make_unique<CJBig2_Image>(pPageInfo->m_dwWidth, height);
344       }
345 
346       if (!m_pPage->data()) {
347         m_ProcessingStatus = FXCODEC_STATUS::kError;
348         return JBig2_Result::kFailure;
349       }
350 
351       m_pPage->Fill(pPageInfo->m_bDefaultPixelValue);
352       m_PageInfoList.push_back(std::move(pPageInfo));
353       m_bInPage = true;
354       break;
355     }
356     case 49:
357       m_bInPage = false;
358       return JBig2_Result::kEndReached;
359     case 50:
360       m_pStream->addOffset(pSegment->m_dwData_length);
361       break;
362     case 51:
363       return JBig2_Result::kEndReached;
364     case 52:
365       m_pStream->addOffset(pSegment->m_dwData_length);
366       break;
367     case 53:
368       return ParseTable(pSegment);
369     case 62:
370       m_pStream->addOffset(pSegment->m_dwData_length);
371       break;
372     default:
373       break;
374   }
375   return JBig2_Result::kSuccess;
376 }
377 
ParseSymbolDict(CJBig2_Segment * pSegment)378 JBig2_Result CJBig2_Context::ParseSymbolDict(CJBig2_Segment* pSegment) {
379   uint16_t wFlags;
380   if (m_pStream->readShortInteger(&wFlags) != 0)
381     return JBig2_Result::kFailure;
382 
383   auto pSymbolDictDecoder = std::make_unique<CJBig2_SDDProc>();
384   pSymbolDictDecoder->SDHUFF = wFlags & 0x0001;
385   pSymbolDictDecoder->SDREFAGG = (wFlags >> 1) & 0x0001;
386   pSymbolDictDecoder->SDTEMPLATE = (wFlags >> 10) & 0x0003;
387   pSymbolDictDecoder->SDRTEMPLATE = !!((wFlags >> 12) & 0x0003);
388   if (!pSymbolDictDecoder->SDHUFF) {
389     const uint32_t dwTemp = (pSymbolDictDecoder->SDTEMPLATE == 0) ? 8 : 2;
390     for (uint32_t i = 0; i < dwTemp; ++i) {
391       if (m_pStream->read1Byte((uint8_t*)&pSymbolDictDecoder->SDAT[i]) != 0)
392         return JBig2_Result::kFailure;
393     }
394   }
395   if (pSymbolDictDecoder->SDREFAGG && !pSymbolDictDecoder->SDRTEMPLATE) {
396     for (int32_t i = 0; i < 4; ++i) {
397       if (m_pStream->read1Byte((uint8_t*)&pSymbolDictDecoder->SDRAT[i]) != 0)
398         return JBig2_Result::kFailure;
399     }
400   }
401   if (m_pStream->readInteger(&pSymbolDictDecoder->SDNUMEXSYMS) != 0 ||
402       m_pStream->readInteger(&pSymbolDictDecoder->SDNUMNEWSYMS) != 0) {
403     return JBig2_Result::kFailure;
404   }
405   if (pSymbolDictDecoder->SDNUMEXSYMS > kJBig2MaxExportSymbols ||
406       pSymbolDictDecoder->SDNUMNEWSYMS > kJBig2MaxNewSymbols) {
407     return JBig2_Result::kFailure;
408   }
409   for (int32_t i = 0; i < pSegment->m_nReferred_to_segment_count; ++i) {
410     if (!FindSegmentByNumber(pSegment->m_Referred_to_segment_numbers[i]))
411       return JBig2_Result::kFailure;
412   }
413   CJBig2_Segment* pLRSeg = nullptr;
414   FX_SAFE_UINT32 dwNumSyms = 0;
415   for (int32_t i = 0; i < pSegment->m_nReferred_to_segment_count; ++i) {
416     CJBig2_Segment* pSeg =
417         FindSegmentByNumber(pSegment->m_Referred_to_segment_numbers[i]);
418     if (pSeg->m_cFlags.s.type == 0) {
419       dwNumSyms += pSeg->m_SymbolDict->NumImages();
420       pLRSeg = pSeg;
421     }
422   }
423   pSymbolDictDecoder->SDNUMINSYMS = dwNumSyms.ValueOrDie();
424 
425   std::vector<UnownedPtr<CJBig2_Image>> SDINSYMS(
426       pSymbolDictDecoder->SDNUMINSYMS);
427   if (!SDINSYMS.empty()) {
428     dwNumSyms = 0;
429     for (int32_t i = 0; i < pSegment->m_nReferred_to_segment_count; ++i) {
430       CJBig2_Segment* pSeg =
431           FindSegmentByNumber(pSegment->m_Referred_to_segment_numbers[i]);
432       if (pSeg->m_cFlags.s.type == 0) {
433         const CJBig2_SymbolDict& dict = *pSeg->m_SymbolDict;
434         for (uint32_t j = 0; j < dict.NumImages(); ++j) {
435           uint32_t dwTemp = (dwNumSyms + j).ValueOrDie();
436           SDINSYMS[dwTemp] = dict.GetImage(j);
437         }
438         dwNumSyms += dict.NumImages();
439       }
440     }
441   }
442   pSymbolDictDecoder->SDINSYMS = std::move(SDINSYMS);
443 
444   uint8_t cSDHUFFDH = (wFlags >> 2) & 0x0003;
445   uint8_t cSDHUFFDW = (wFlags >> 4) & 0x0003;
446   if (pSymbolDictDecoder->SDHUFF) {
447     if (cSDHUFFDH == 2 || cSDHUFFDW == 2)
448       return JBig2_Result::kFailure;
449 
450     int32_t nIndex = 0;
451     if (cSDHUFFDH == 0) {
452       pSymbolDictDecoder->SDHUFFDH = GetHuffmanTable(4);
453     } else if (cSDHUFFDH == 1) {
454       pSymbolDictDecoder->SDHUFFDH = GetHuffmanTable(5);
455     } else {
456       CJBig2_Segment* pSeg =
457           FindReferredTableSegmentByIndex(pSegment, nIndex++);
458       if (!pSeg)
459         return JBig2_Result::kFailure;
460       pSymbolDictDecoder->SDHUFFDH = pSeg->m_HuffmanTable.get();
461     }
462     if (cSDHUFFDW == 0) {
463       pSymbolDictDecoder->SDHUFFDW = GetHuffmanTable(2);
464     } else if (cSDHUFFDW == 1) {
465       pSymbolDictDecoder->SDHUFFDW = GetHuffmanTable(3);
466     } else {
467       CJBig2_Segment* pSeg =
468           FindReferredTableSegmentByIndex(pSegment, nIndex++);
469       if (!pSeg)
470         return JBig2_Result::kFailure;
471       pSymbolDictDecoder->SDHUFFDW = pSeg->m_HuffmanTable.get();
472     }
473     uint8_t cSDHUFFBMSIZE = (wFlags >> 6) & 0x0001;
474     if (cSDHUFFBMSIZE == 0) {
475       pSymbolDictDecoder->SDHUFFBMSIZE = GetHuffmanTable(1);
476     } else {
477       CJBig2_Segment* pSeg =
478           FindReferredTableSegmentByIndex(pSegment, nIndex++);
479       if (!pSeg)
480         return JBig2_Result::kFailure;
481       pSymbolDictDecoder->SDHUFFBMSIZE = pSeg->m_HuffmanTable.get();
482     }
483     if (pSymbolDictDecoder->SDREFAGG) {
484       uint8_t cSDHUFFAGGINST = (wFlags >> 7) & 0x0001;
485       if (cSDHUFFAGGINST == 0) {
486         pSymbolDictDecoder->SDHUFFAGGINST = GetHuffmanTable(1);
487       } else {
488         CJBig2_Segment* pSeg =
489             FindReferredTableSegmentByIndex(pSegment, nIndex++);
490         if (!pSeg)
491           return JBig2_Result::kFailure;
492         pSymbolDictDecoder->SDHUFFAGGINST = pSeg->m_HuffmanTable.get();
493       }
494     }
495   }
496 
497   const bool bUseGbContext = !pSymbolDictDecoder->SDHUFF;
498   const bool bUseGrContext = pSymbolDictDecoder->SDREFAGG;
499   const size_t gbContextSize =
500       GetHuffContextSize(pSymbolDictDecoder->SDTEMPLATE);
501   const size_t grContextSize =
502       GetRefAggContextSize(pSymbolDictDecoder->SDRTEMPLATE);
503   std::vector<JBig2ArithCtx> gbContexts;
504   std::vector<JBig2ArithCtx> grContexts;
505   if ((wFlags & 0x0100) && pLRSeg) {
506     if (bUseGbContext) {
507       gbContexts = pLRSeg->m_SymbolDict->GbContexts();
508       if (gbContexts.size() != gbContextSize) {
509         return JBig2_Result::kFailure;
510       }
511     }
512     if (bUseGrContext) {
513       grContexts = pLRSeg->m_SymbolDict->GrContexts();
514       if (grContexts.size() != grContextSize) {
515         return JBig2_Result::kFailure;
516       }
517     }
518   } else {
519     if (bUseGbContext)
520       gbContexts.resize(gbContextSize);
521     if (bUseGrContext)
522       grContexts.resize(grContextSize);
523   }
524 
525   CJBig2_CompoundKey key(pSegment->m_Key, pSegment->m_dwDataOffset);
526   bool cache_hit = false;
527   pSegment->m_nResultType = JBIG2_SYMBOL_DICT_POINTER;
528   if (m_bIsGlobal && key.first != 0) {
529     for (auto it = m_pSymbolDictCache->begin(); it != m_pSymbolDictCache->end();
530          ++it) {
531       if (it->first == key) {
532         pSegment->m_SymbolDict = it->second->DeepCopy();
533         m_pSymbolDictCache->emplace_front(key, std::move(it->second));
534         m_pSymbolDictCache->erase(it);
535         cache_hit = true;
536         break;
537       }
538     }
539   }
540   if (!cache_hit) {
541     if (bUseGbContext) {
542       auto pArithDecoder =
543           std::make_unique<CJBig2_ArithDecoder>(m_pStream.get());
544       pSegment->m_SymbolDict = pSymbolDictDecoder->DecodeArith(
545           pArithDecoder.get(), gbContexts, grContexts);
546       if (!pSegment->m_SymbolDict)
547         return JBig2_Result::kFailure;
548 
549       m_pStream->alignByte();
550       m_pStream->addOffset(2);
551     } else {
552       pSegment->m_SymbolDict = pSymbolDictDecoder->DecodeHuffman(
553           m_pStream.get(), gbContexts, grContexts);
554       if (!pSegment->m_SymbolDict)
555         return JBig2_Result::kFailure;
556       m_pStream->alignByte();
557     }
558     if (m_bIsGlobal) {
559       std::unique_ptr<CJBig2_SymbolDict> value =
560           pSegment->m_SymbolDict->DeepCopy();
561       size_t size = m_pSymbolDictCache->size();
562       while (size >= kSymbolDictCacheMaxSize) {
563         m_pSymbolDictCache->pop_back();
564         --size;
565       }
566       m_pSymbolDictCache->emplace_front(key, std::move(value));
567     }
568   }
569   if (wFlags & 0x0200) {
570     if (bUseGbContext)
571       pSegment->m_SymbolDict->SetGbContexts(std::move(gbContexts));
572     if (bUseGrContext)
573       pSegment->m_SymbolDict->SetGrContexts(std::move(grContexts));
574   }
575   return JBig2_Result::kSuccess;
576 }
577 
ParseTextRegion(CJBig2_Segment * pSegment)578 JBig2_Result CJBig2_Context::ParseTextRegion(CJBig2_Segment* pSegment) {
579   uint16_t wFlags;
580   JBig2RegionInfo ri;
581   if (ParseRegionInfo(&ri) != JBig2_Result::kSuccess ||
582       m_pStream->readShortInteger(&wFlags) != 0) {
583     return JBig2_Result::kFailure;
584   }
585   if (!CJBig2_Image::IsValidImageSize(ri.width, ri.height))
586     return JBig2_Result::kFailure;
587 
588   auto pTRD = std::make_unique<CJBig2_TRDProc>();
589   pTRD->SBW = ri.width;
590   pTRD->SBH = ri.height;
591   pTRD->SBHUFF = wFlags & 0x0001;
592   pTRD->SBREFINE = (wFlags >> 1) & 0x0001;
593   uint32_t dwTemp = (wFlags >> 2) & 0x0003;
594   pTRD->SBSTRIPS = 1 << dwTemp;
595   pTRD->REFCORNER = (JBig2Corner)((wFlags >> 4) & 0x0003);
596   pTRD->TRANSPOSED = (wFlags >> 6) & 0x0001;
597   pTRD->SBCOMBOP = (JBig2ComposeOp)((wFlags >> 7) & 0x0003);
598   pTRD->SBDEFPIXEL = (wFlags >> 9) & 0x0001;
599   pTRD->SBDSOFFSET = (wFlags >> 10) & 0x001f;
600   if (pTRD->SBDSOFFSET >= 0x0010) {
601     pTRD->SBDSOFFSET = pTRD->SBDSOFFSET - 0x0020;
602   }
603   pTRD->SBRTEMPLATE = !!((wFlags >> 15) & 0x0001);
604 
605   if (pTRD->SBHUFF && m_pStream->readShortInteger(&wFlags) != 0) {
606     return JBig2_Result::kFailure;
607   }
608   if (pTRD->SBREFINE && !pTRD->SBRTEMPLATE) {
609     for (int32_t i = 0; i < 4; ++i) {
610       if (m_pStream->read1Byte((uint8_t*)&pTRD->SBRAT[i]) != 0)
611         return JBig2_Result::kFailure;
612     }
613   }
614   if (m_pStream->readInteger(&pTRD->SBNUMINSTANCES) != 0)
615     return JBig2_Result::kFailure;
616 
617   // Assume each instance takes at least 0.25 bits when encoded. That means for
618   // a stream of length N bytes, there can be at most 32N instances. This is a
619   // conservative estimate just to sanitize the |SBNUMINSTANCES| value.
620   // Use FX_SAFE_INT32 to be safe, though it should never overflow because PDFs
621   // have a maximum size of roughly 11 GB.
622   FX_SAFE_INT32 nMaxStripInstances = m_pStream->getBufSpan().size();
623   nMaxStripInstances *= 32;
624   if (pTRD->SBNUMINSTANCES > nMaxStripInstances.ValueOrDie())
625     return JBig2_Result::kFailure;
626 
627   for (int32_t i = 0; i < pSegment->m_nReferred_to_segment_count; ++i) {
628     if (!FindSegmentByNumber(pSegment->m_Referred_to_segment_numbers[i]))
629       return JBig2_Result::kFailure;
630   }
631 
632   FX_SAFE_UINT32 dwNumSyms = 0;
633   for (int32_t i = 0; i < pSegment->m_nReferred_to_segment_count; ++i) {
634     CJBig2_Segment* pSeg =
635         FindSegmentByNumber(pSegment->m_Referred_to_segment_numbers[i]);
636     if (pSeg->m_cFlags.s.type == 0) {
637       dwNumSyms += pSeg->m_SymbolDict->NumImages();
638     }
639   }
640   pTRD->SBNUMSYMS = dwNumSyms.ValueOrDie();
641 
642   std::vector<UnownedPtr<CJBig2_Image>> SBSYMS(pTRD->SBNUMSYMS);
643   if (!SBSYMS.empty()) {
644     dwNumSyms = 0;
645     for (int32_t i = 0; i < pSegment->m_nReferred_to_segment_count; ++i) {
646       CJBig2_Segment* pSeg =
647           FindSegmentByNumber(pSegment->m_Referred_to_segment_numbers[i]);
648       if (pSeg->m_cFlags.s.type == 0) {
649         const CJBig2_SymbolDict& dict = *pSeg->m_SymbolDict;
650         for (uint32_t j = 0; j < dict.NumImages(); ++j) {
651           uint32_t dwIndex = (dwNumSyms + j).ValueOrDie();
652           SBSYMS[dwIndex] = dict.GetImage(j);
653         }
654         dwNumSyms += dict.NumImages();
655       }
656     }
657   }
658   pTRD->SBSYMS = std::move(SBSYMS);
659 
660   if (pTRD->SBHUFF) {
661     std::vector<JBig2HuffmanCode> SBSYMCODES =
662         DecodeSymbolIDHuffmanTable(pTRD->SBNUMSYMS);
663     if (SBSYMCODES.empty())
664       return JBig2_Result::kFailure;
665 
666     m_pStream->alignByte();
667     pTRD->SBSYMCODES = std::move(SBSYMCODES);
668   } else {
669     dwTemp = 0;
670     while ((uint32_t)(1 << dwTemp) < pTRD->SBNUMSYMS) {
671       ++dwTemp;
672     }
673     pTRD->SBSYMCODELEN = (uint8_t)dwTemp;
674   }
675 
676   if (pTRD->SBHUFF) {
677     uint8_t cSBHUFFFS = wFlags & 0x0003;
678     uint8_t cSBHUFFDS = (wFlags >> 2) & 0x0003;
679     uint8_t cSBHUFFDT = (wFlags >> 4) & 0x0003;
680     uint8_t cSBHUFFRDW = (wFlags >> 6) & 0x0003;
681     uint8_t cSBHUFFRDH = (wFlags >> 8) & 0x0003;
682     uint8_t cSBHUFFRDX = (wFlags >> 10) & 0x0003;
683     uint8_t cSBHUFFRDY = (wFlags >> 12) & 0x0003;
684     uint8_t cSBHUFFRSIZE = (wFlags >> 14) & 0x0001;
685     if (cSBHUFFFS == 2 || cSBHUFFRDW == 2 || cSBHUFFRDH == 2 ||
686         cSBHUFFRDX == 2 || cSBHUFFRDY == 2) {
687       return JBig2_Result::kFailure;
688     }
689     int32_t nIndex = 0;
690     if (cSBHUFFFS == 0) {
691       pTRD->SBHUFFFS = GetHuffmanTable(6);
692     } else if (cSBHUFFFS == 1) {
693       pTRD->SBHUFFFS = GetHuffmanTable(7);
694     } else {
695       CJBig2_Segment* pSeg =
696           FindReferredTableSegmentByIndex(pSegment, nIndex++);
697       if (!pSeg)
698         return JBig2_Result::kFailure;
699       pTRD->SBHUFFFS = pSeg->m_HuffmanTable.get();
700     }
701     if (cSBHUFFDS == 0) {
702       pTRD->SBHUFFDS = GetHuffmanTable(8);
703     } else if (cSBHUFFDS == 1) {
704       pTRD->SBHUFFDS = GetHuffmanTable(9);
705     } else if (cSBHUFFDS == 2) {
706       pTRD->SBHUFFDS = GetHuffmanTable(10);
707     } else {
708       CJBig2_Segment* pSeg =
709           FindReferredTableSegmentByIndex(pSegment, nIndex++);
710       if (!pSeg)
711         return JBig2_Result::kFailure;
712       pTRD->SBHUFFDS = pSeg->m_HuffmanTable.get();
713     }
714     if (cSBHUFFDT == 0) {
715       pTRD->SBHUFFDT = GetHuffmanTable(11);
716     } else if (cSBHUFFDT == 1) {
717       pTRD->SBHUFFDT = GetHuffmanTable(12);
718     } else if (cSBHUFFDT == 2) {
719       pTRD->SBHUFFDT = GetHuffmanTable(13);
720     } else {
721       CJBig2_Segment* pSeg =
722           FindReferredTableSegmentByIndex(pSegment, nIndex++);
723       if (!pSeg)
724         return JBig2_Result::kFailure;
725       pTRD->SBHUFFDT = pSeg->m_HuffmanTable.get();
726     }
727     if (cSBHUFFRDW == 0) {
728       pTRD->SBHUFFRDW = GetHuffmanTable(14);
729     } else if (cSBHUFFRDW == 1) {
730       pTRD->SBHUFFRDW = GetHuffmanTable(15);
731     } else {
732       CJBig2_Segment* pSeg =
733           FindReferredTableSegmentByIndex(pSegment, nIndex++);
734       if (!pSeg)
735         return JBig2_Result::kFailure;
736       pTRD->SBHUFFRDW = pSeg->m_HuffmanTable.get();
737     }
738     if (cSBHUFFRDH == 0) {
739       pTRD->SBHUFFRDH = GetHuffmanTable(14);
740     } else if (cSBHUFFRDH == 1) {
741       pTRD->SBHUFFRDH = GetHuffmanTable(15);
742     } else {
743       CJBig2_Segment* pSeg =
744           FindReferredTableSegmentByIndex(pSegment, nIndex++);
745       if (!pSeg)
746         return JBig2_Result::kFailure;
747       pTRD->SBHUFFRDH = pSeg->m_HuffmanTable.get();
748     }
749     if (cSBHUFFRDX == 0) {
750       pTRD->SBHUFFRDX = GetHuffmanTable(14);
751     } else if (cSBHUFFRDX == 1) {
752       pTRD->SBHUFFRDX = GetHuffmanTable(15);
753     } else {
754       CJBig2_Segment* pSeg =
755           FindReferredTableSegmentByIndex(pSegment, nIndex++);
756       if (!pSeg)
757         return JBig2_Result::kFailure;
758       pTRD->SBHUFFRDX = pSeg->m_HuffmanTable.get();
759     }
760     if (cSBHUFFRDY == 0) {
761       pTRD->SBHUFFRDY = GetHuffmanTable(14);
762     } else if (cSBHUFFRDY == 1) {
763       pTRD->SBHUFFRDY = GetHuffmanTable(15);
764     } else {
765       CJBig2_Segment* pSeg =
766           FindReferredTableSegmentByIndex(pSegment, nIndex++);
767       if (!pSeg)
768         return JBig2_Result::kFailure;
769       pTRD->SBHUFFRDY = pSeg->m_HuffmanTable.get();
770     }
771     if (cSBHUFFRSIZE == 0) {
772       pTRD->SBHUFFRSIZE = GetHuffmanTable(1);
773     } else {
774       CJBig2_Segment* pSeg =
775           FindReferredTableSegmentByIndex(pSegment, nIndex++);
776       if (!pSeg)
777         return JBig2_Result::kFailure;
778       pTRD->SBHUFFRSIZE = pSeg->m_HuffmanTable.get();
779     }
780   }
781   FixedSizeDataVector<JBig2ArithCtx> grContexts;
782   if (pTRD->SBREFINE) {
783     const size_t size = GetRefAggContextSize(pTRD->SBRTEMPLATE);
784     grContexts = FixedSizeDataVector<JBig2ArithCtx>::Zeroed(size);
785   }
786   pSegment->m_nResultType = JBIG2_IMAGE_POINTER;
787   if (pTRD->SBHUFF) {
788     pSegment->m_Image = pTRD->DecodeHuffman(m_pStream.get(), grContexts);
789     if (!pSegment->m_Image)
790       return JBig2_Result::kFailure;
791     m_pStream->alignByte();
792   } else {
793     auto pArithDecoder = std::make_unique<CJBig2_ArithDecoder>(m_pStream.get());
794     pSegment->m_Image =
795         pTRD->DecodeArith(pArithDecoder.get(), grContexts, nullptr);
796     if (!pSegment->m_Image)
797       return JBig2_Result::kFailure;
798     m_pStream->alignByte();
799     m_pStream->addOffset(2);
800   }
801   if (pSegment->m_cFlags.s.type != 4) {
802     if (!m_bBufSpecified) {
803       const auto& pPageInfo = m_PageInfoList.back();
804       if (pPageInfo->m_bIsStriped && ri.y + ri.height > m_pPage->height())
805         m_pPage->Expand(ri.y + ri.height, pPageInfo->m_bDefaultPixelValue);
806     }
807     m_pPage->ComposeFrom(ri.x, ri.y, pSegment->m_Image.get(),
808                          (JBig2ComposeOp)(ri.flags & 0x03));
809     pSegment->m_Image.reset();
810   }
811   return JBig2_Result::kSuccess;
812 }
813 
ParsePatternDict(CJBig2_Segment * pSegment,PauseIndicatorIface * pPause)814 JBig2_Result CJBig2_Context::ParsePatternDict(CJBig2_Segment* pSegment,
815                                               PauseIndicatorIface* pPause) {
816   uint8_t cFlags;
817   auto pPDD = std::make_unique<CJBig2_PDDProc>();
818   if (m_pStream->read1Byte(&cFlags) != 0 ||
819       m_pStream->read1Byte(&pPDD->HDPW) != 0 ||
820       m_pStream->read1Byte(&pPDD->HDPH) != 0 ||
821       m_pStream->readInteger(&pPDD->GRAYMAX) != 0) {
822     return JBig2_Result::kFailure;
823   }
824   if (pPDD->GRAYMAX > kJBig2MaxPatternIndex)
825     return JBig2_Result::kFailure;
826 
827   pPDD->HDMMR = cFlags & 0x01;
828   pPDD->HDTEMPLATE = (cFlags >> 1) & 0x03;
829   pSegment->m_nResultType = JBIG2_PATTERN_DICT_POINTER;
830   if (pPDD->HDMMR) {
831     pSegment->m_PatternDict = pPDD->DecodeMMR(m_pStream.get());
832     if (!pSegment->m_PatternDict)
833       return JBig2_Result::kFailure;
834     m_pStream->alignByte();
835   } else {
836     const size_t size = GetHuffContextSize(pPDD->HDTEMPLATE);
837     auto gbContexts = FixedSizeDataVector<JBig2ArithCtx>::Zeroed(size);
838     auto pArithDecoder = std::make_unique<CJBig2_ArithDecoder>(m_pStream.get());
839     pSegment->m_PatternDict =
840         pPDD->DecodeArith(pArithDecoder.get(), gbContexts, pPause);
841     if (!pSegment->m_PatternDict)
842       return JBig2_Result::kFailure;
843 
844     m_pStream->alignByte();
845     m_pStream->addOffset(2);
846   }
847   return JBig2_Result::kSuccess;
848 }
849 
ParseHalftoneRegion(CJBig2_Segment * pSegment,PauseIndicatorIface * pPause)850 JBig2_Result CJBig2_Context::ParseHalftoneRegion(CJBig2_Segment* pSegment,
851                                                  PauseIndicatorIface* pPause) {
852   uint8_t cFlags;
853   JBig2RegionInfo ri;
854   auto pHRD = std::make_unique<CJBig2_HTRDProc>();
855   if (ParseRegionInfo(&ri) != JBig2_Result::kSuccess ||
856       m_pStream->read1Byte(&cFlags) != 0 ||
857       m_pStream->readInteger(&pHRD->HGW) != 0 ||
858       m_pStream->readInteger(&pHRD->HGH) != 0 ||
859       m_pStream->readInteger((uint32_t*)&pHRD->HGX) != 0 ||
860       m_pStream->readInteger((uint32_t*)&pHRD->HGY) != 0 ||
861       m_pStream->readShortInteger(&pHRD->HRX) != 0 ||
862       m_pStream->readShortInteger(&pHRD->HRY) != 0) {
863     return JBig2_Result::kFailure;
864   }
865 
866   if (!CJBig2_Image::IsValidImageSize(pHRD->HGW, pHRD->HGH))
867     return JBig2_Result::kFailure;
868 
869   if (!CJBig2_Image::IsValidImageSize(ri.width, ri.height))
870     return JBig2_Result::kFailure;
871 
872   pHRD->HBW = ri.width;
873   pHRD->HBH = ri.height;
874   pHRD->HMMR = cFlags & 0x01;
875   pHRD->HTEMPLATE = (cFlags >> 1) & 0x03;
876   pHRD->HENABLESKIP = (cFlags >> 3) & 0x01;
877   pHRD->HCOMBOP = (JBig2ComposeOp)((cFlags >> 4) & 0x07);
878   pHRD->HDEFPIXEL = (cFlags >> 7) & 0x01;
879   if (pSegment->m_nReferred_to_segment_count != 1)
880     return JBig2_Result::kFailure;
881 
882   CJBig2_Segment* pSeg =
883       FindSegmentByNumber(pSegment->m_Referred_to_segment_numbers[0]);
884   if (!pSeg || (pSeg->m_cFlags.s.type != 16))
885     return JBig2_Result::kFailure;
886 
887   const CJBig2_PatternDict* pPatternDict = pSeg->m_PatternDict.get();
888   if (!pPatternDict || (pPatternDict->NUMPATS == 0))
889     return JBig2_Result::kFailure;
890 
891   pHRD->HNUMPATS = pPatternDict->NUMPATS;
892   pHRD->HPATS = &pPatternDict->HDPATS;
893   pHRD->HPW = pPatternDict->HDPATS[0]->width();
894   pHRD->HPH = pPatternDict->HDPATS[0]->height();
895   pSegment->m_nResultType = JBIG2_IMAGE_POINTER;
896   if (pHRD->HMMR) {
897     pSegment->m_Image = pHRD->DecodeMMR(m_pStream.get());
898     if (!pSegment->m_Image)
899       return JBig2_Result::kFailure;
900     m_pStream->alignByte();
901   } else {
902     const size_t size = GetHuffContextSize(pHRD->HTEMPLATE);
903     auto gbContexts = FixedSizeDataVector<JBig2ArithCtx>::Zeroed(size);
904     auto pArithDecoder = std::make_unique<CJBig2_ArithDecoder>(m_pStream.get());
905     pSegment->m_Image =
906         pHRD->DecodeArith(pArithDecoder.get(), gbContexts, pPause);
907     if (!pSegment->m_Image)
908       return JBig2_Result::kFailure;
909 
910     m_pStream->alignByte();
911     m_pStream->addOffset(2);
912   }
913   if (pSegment->m_cFlags.s.type != 20) {
914     if (!m_bBufSpecified) {
915       const auto& pPageInfo = m_PageInfoList.back();
916       if (pPageInfo->m_bIsStriped && ri.y + ri.height > m_pPage->height())
917         m_pPage->Expand(ri.y + ri.height, pPageInfo->m_bDefaultPixelValue);
918     }
919     m_pPage->ComposeFrom(ri.x, ri.y, pSegment->m_Image.get(),
920                          (JBig2ComposeOp)(ri.flags & 0x03));
921     pSegment->m_Image.reset();
922   }
923   return JBig2_Result::kSuccess;
924 }
925 
ParseGenericRegion(CJBig2_Segment * pSegment,PauseIndicatorIface * pPause)926 JBig2_Result CJBig2_Context::ParseGenericRegion(CJBig2_Segment* pSegment,
927                                                 PauseIndicatorIface* pPause) {
928   if (!m_pGRD) {
929     auto pGRD = std::make_unique<CJBig2_GRDProc>();
930     uint8_t cFlags;
931     if (ParseRegionInfo(&m_ri) != JBig2_Result::kSuccess ||
932         m_pStream->read1Byte(&cFlags) != 0) {
933       return JBig2_Result::kFailure;
934     }
935     if (m_ri.height < 0 || m_ri.width < 0)
936       return JBig2_Result::kFailure;
937     pGRD->GBW = m_ri.width;
938     pGRD->GBH = m_ri.height;
939     pGRD->MMR = cFlags & 0x01;
940     pGRD->GBTEMPLATE = (cFlags >> 1) & 0x03;
941     pGRD->TPGDON = (cFlags >> 3) & 0x01;
942     if (!pGRD->MMR) {
943       if (pGRD->GBTEMPLATE == 0) {
944         for (int32_t i = 0; i < 8; ++i) {
945           if (m_pStream->read1Byte((uint8_t*)&pGRD->GBAT[i]) != 0)
946             return JBig2_Result::kFailure;
947         }
948       } else {
949         for (int32_t i = 0; i < 2; ++i) {
950           if (m_pStream->read1Byte((uint8_t*)&pGRD->GBAT[i]) != 0)
951             return JBig2_Result::kFailure;
952         }
953       }
954     }
955     pGRD->USESKIP = false;
956     m_pGRD = std::move(pGRD);
957   }
958   pSegment->m_nResultType = JBIG2_IMAGE_POINTER;
959   if (m_pGRD->MMR) {
960     m_pGRD->StartDecodeMMR(&pSegment->m_Image, m_pStream.get());
961     if (!pSegment->m_Image) {
962       m_pGRD.reset();
963       return JBig2_Result::kFailure;
964     }
965     m_pStream->alignByte();
966   } else {
967     if (m_gbContexts.empty()) {
968       m_gbContexts.resize(GetHuffContextSize(m_pGRD->GBTEMPLATE));
969     }
970 
971     bool bStart = !m_pArithDecoder;
972     if (bStart) {
973       m_pArithDecoder = std::make_unique<CJBig2_ArithDecoder>(m_pStream.get());
974     }
975     {
976       // |state.gbContexts| can't exist when m_gbContexts.clear() called below.
977       CJBig2_GRDProc::ProgressiveArithDecodeState state;
978       state.pImage = &pSegment->m_Image;
979       state.pArithDecoder = m_pArithDecoder.get();
980       state.gbContexts = m_gbContexts;
981       state.pPause = pPause;
982       m_ProcessingStatus = bStart ? m_pGRD->StartDecodeArith(&state)
983                                   : m_pGRD->ContinueDecode(&state);
984       if (m_ProcessingStatus == FXCODEC_STATUS::kDecodeToBeContinued) {
985         if (pSegment->m_cFlags.s.type != 36) {
986           if (!m_bBufSpecified) {
987             const auto& pPageInfo = m_PageInfoList.back();
988             if (pPageInfo->m_bIsStriped &&
989                 m_ri.y + m_ri.height > m_pPage->height()) {
990               m_pPage->Expand(m_ri.y + m_ri.height,
991                               pPageInfo->m_bDefaultPixelValue);
992             }
993           }
994           const FX_RECT& rect = m_pGRD->GetReplaceRect();
995           m_pPage->ComposeFromWithRect(m_ri.x + rect.left, m_ri.y + rect.top,
996                                        pSegment->m_Image.get(), rect,
997                                        (JBig2ComposeOp)(m_ri.flags & 0x03));
998         }
999         return JBig2_Result::kSuccess;
1000       }
1001     }
1002     m_pArithDecoder.reset();
1003     m_gbContexts.clear();
1004     if (!pSegment->m_Image) {
1005       m_ProcessingStatus = FXCODEC_STATUS::kError;
1006       m_pGRD.reset();
1007       return JBig2_Result::kFailure;
1008     }
1009     m_pStream->alignByte();
1010     m_pStream->addOffset(2);
1011   }
1012   if (pSegment->m_cFlags.s.type != 36) {
1013     if (!m_bBufSpecified) {
1014       JBig2PageInfo* pPageInfo = m_PageInfoList.back().get();
1015       if (pPageInfo->m_bIsStriped && m_ri.y + m_ri.height > m_pPage->height())
1016         m_pPage->Expand(m_ri.y + m_ri.height, pPageInfo->m_bDefaultPixelValue);
1017     }
1018     const FX_RECT& rect = m_pGRD->GetReplaceRect();
1019     m_pPage->ComposeFromWithRect(m_ri.x + rect.left, m_ri.y + rect.top,
1020                                  pSegment->m_Image.get(), rect,
1021                                  (JBig2ComposeOp)(m_ri.flags & 0x03));
1022     pSegment->m_Image.reset();
1023   }
1024   m_pGRD.reset();
1025   return JBig2_Result::kSuccess;
1026 }
1027 
ParseGenericRefinementRegion(CJBig2_Segment * pSegment)1028 JBig2_Result CJBig2_Context::ParseGenericRefinementRegion(
1029     CJBig2_Segment* pSegment) {
1030   JBig2RegionInfo ri;
1031   uint8_t cFlags;
1032   if (ParseRegionInfo(&ri) != JBig2_Result::kSuccess ||
1033       m_pStream->read1Byte(&cFlags) != 0) {
1034     return JBig2_Result::kFailure;
1035   }
1036   if (!CJBig2_Image::IsValidImageSize(ri.width, ri.height))
1037     return JBig2_Result::kFailure;
1038 
1039   auto pGRRD = std::make_unique<CJBig2_GRRDProc>();
1040   pGRRD->GRW = ri.width;
1041   pGRRD->GRH = ri.height;
1042   pGRRD->GRTEMPLATE = !!(cFlags & 0x01);
1043   pGRRD->TPGRON = (cFlags >> 1) & 0x01;
1044   if (!pGRRD->GRTEMPLATE) {
1045     for (int32_t i = 0; i < 4; ++i) {
1046       if (m_pStream->read1Byte((uint8_t*)&pGRRD->GRAT[i]) != 0)
1047         return JBig2_Result::kFailure;
1048     }
1049   }
1050   CJBig2_Segment* pSeg = nullptr;
1051   if (pSegment->m_nReferred_to_segment_count > 0) {
1052     int32_t i;
1053     for (i = 0; i < pSegment->m_nReferred_to_segment_count; ++i) {
1054       pSeg = FindSegmentByNumber(pSegment->m_Referred_to_segment_numbers[0]);
1055       if (!pSeg)
1056         return JBig2_Result::kFailure;
1057 
1058       if (pSeg->m_cFlags.s.type == 4 || pSeg->m_cFlags.s.type == 20 ||
1059           pSeg->m_cFlags.s.type == 36 || pSeg->m_cFlags.s.type == 40) {
1060         break;
1061       }
1062     }
1063     if (i >= pSegment->m_nReferred_to_segment_count)
1064       return JBig2_Result::kFailure;
1065 
1066     pGRRD->GRREFERENCE = pSeg->m_Image.get();
1067   } else {
1068     pGRRD->GRREFERENCE = m_pPage.get();
1069   }
1070   pGRRD->GRREFERENCEDX = 0;
1071   pGRRD->GRREFERENCEDY = 0;
1072   const size_t size = GetRefAggContextSize(pGRRD->GRTEMPLATE);
1073   auto grContexts = FixedSizeDataVector<JBig2ArithCtx>::Zeroed(size);
1074   auto pArithDecoder = std::make_unique<CJBig2_ArithDecoder>(m_pStream.get());
1075   pSegment->m_nResultType = JBIG2_IMAGE_POINTER;
1076   pSegment->m_Image = pGRRD->Decode(pArithDecoder.get(), grContexts);
1077   if (!pSegment->m_Image)
1078     return JBig2_Result::kFailure;
1079 
1080   m_pStream->alignByte();
1081   m_pStream->addOffset(2);
1082   if (pSegment->m_cFlags.s.type != 40) {
1083     if (!m_bBufSpecified) {
1084       JBig2PageInfo* pPageInfo = m_PageInfoList.back().get();
1085       if (pPageInfo->m_bIsStriped && ri.y + ri.height > m_pPage->height())
1086         m_pPage->Expand(ri.y + ri.height, pPageInfo->m_bDefaultPixelValue);
1087     }
1088     m_pPage->ComposeFrom(ri.x, ri.y, pSegment->m_Image.get(),
1089                          (JBig2ComposeOp)(ri.flags & 0x03));
1090     pSegment->m_Image.reset();
1091   }
1092   return JBig2_Result::kSuccess;
1093 }
1094 
ParseTable(CJBig2_Segment * pSegment)1095 JBig2_Result CJBig2_Context::ParseTable(CJBig2_Segment* pSegment) {
1096   pSegment->m_nResultType = JBIG2_HUFFMAN_TABLE_POINTER;
1097   pSegment->m_HuffmanTable.reset();
1098   auto pHuff = std::make_unique<CJBig2_HuffmanTable>(m_pStream.get());
1099   if (!pHuff->IsOK())
1100     return JBig2_Result::kFailure;
1101 
1102   pSegment->m_HuffmanTable = std::move(pHuff);
1103   m_pStream->alignByte();
1104   return JBig2_Result::kSuccess;
1105 }
1106 
ParseRegionInfo(JBig2RegionInfo * pRI)1107 JBig2_Result CJBig2_Context::ParseRegionInfo(JBig2RegionInfo* pRI) {
1108   if (m_pStream->readInteger((uint32_t*)&pRI->width) != 0 ||
1109       m_pStream->readInteger((uint32_t*)&pRI->height) != 0 ||
1110       m_pStream->readInteger((uint32_t*)&pRI->x) != 0 ||
1111       m_pStream->readInteger((uint32_t*)&pRI->y) != 0 ||
1112       m_pStream->read1Byte(&pRI->flags) != 0) {
1113     return JBig2_Result::kFailure;
1114   }
1115   return JBig2_Result::kSuccess;
1116 }
1117 
DecodeSymbolIDHuffmanTable(uint32_t SBNUMSYMS)1118 std::vector<JBig2HuffmanCode> CJBig2_Context::DecodeSymbolIDHuffmanTable(
1119     uint32_t SBNUMSYMS) {
1120   const size_t kRunCodesSize = 35;
1121   std::array<JBig2HuffmanCode, kRunCodesSize> huffman_codes;
1122   for (size_t i = 0; i < kRunCodesSize; ++i) {
1123     if (m_pStream->readNBits(4, &huffman_codes[i].codelen) != 0)
1124       return std::vector<JBig2HuffmanCode>();
1125   }
1126   if (!HuffmanAssignCode(huffman_codes)) {
1127     return std::vector<JBig2HuffmanCode>();
1128   }
1129 
1130   std::vector<JBig2HuffmanCode> SBSYMCODES(SBNUMSYMS);
1131   int32_t run = 0;
1132   int32_t i = 0;
1133   while (i < static_cast<int>(SBNUMSYMS)) {
1134     size_t j;
1135     FX_SAFE_INT32 nSafeVal = 0;
1136     int32_t nBits = 0;
1137     uint32_t nTemp;
1138     while (true) {
1139       if (m_pStream->read1Bit(&nTemp) != 0)
1140         return std::vector<JBig2HuffmanCode>();
1141 
1142       nSafeVal <<= 1;
1143       if (!nSafeVal.IsValid())
1144         return std::vector<JBig2HuffmanCode>();
1145 
1146       nSafeVal |= nTemp;
1147       ++nBits;
1148       const int32_t nVal = nSafeVal.ValueOrDie();
1149       for (j = 0; j < kRunCodesSize; ++j) {
1150         if (nBits == huffman_codes[j].codelen && nVal == huffman_codes[j].code)
1151           break;
1152       }
1153       if (j < kRunCodesSize)
1154         break;
1155     }
1156     int32_t runcode = static_cast<int32_t>(j);
1157     if (runcode < 32) {
1158       SBSYMCODES[i].codelen = runcode;
1159       run = 0;
1160     } else if (runcode == 32) {
1161       if (m_pStream->readNBits(2, &nTemp) != 0)
1162         return std::vector<JBig2HuffmanCode>();
1163       run = nTemp + 3;
1164     } else if (runcode == 33) {
1165       if (m_pStream->readNBits(3, &nTemp) != 0)
1166         return std::vector<JBig2HuffmanCode>();
1167       run = nTemp + 3;
1168     } else if (runcode == 34) {
1169       if (m_pStream->readNBits(7, &nTemp) != 0)
1170         return std::vector<JBig2HuffmanCode>();
1171       run = nTemp + 11;
1172     }
1173     if (run > 0) {
1174       if (i + run > (int)SBNUMSYMS)
1175         return std::vector<JBig2HuffmanCode>();
1176       for (int32_t k = 0; k < run; ++k) {
1177         if (runcode == 32 && i > 0)
1178           SBSYMCODES[i + k].codelen = SBSYMCODES[i - 1].codelen;
1179         else
1180           SBSYMCODES[i + k].codelen = 0;
1181       }
1182       i += run;
1183     } else {
1184       ++i;
1185     }
1186   }
1187   if (!HuffmanAssignCode(SBSYMCODES)) {
1188     return std::vector<JBig2HuffmanCode>();
1189   }
1190   return SBSYMCODES;
1191 }
1192 
GetHuffmanTable(size_t idx)1193 const CJBig2_HuffmanTable* CJBig2_Context::GetHuffmanTable(size_t idx) {
1194   DCHECK(idx > 0);
1195   DCHECK(idx < CJBig2_HuffmanTable::kNumHuffmanTables);
1196   if (!m_HuffmanTables[idx].get())
1197     m_HuffmanTables[idx] = std::make_unique<CJBig2_HuffmanTable>(idx);
1198   return m_HuffmanTables[idx].get();
1199 }
1200 
1201 // static
HuffmanAssignCode(pdfium::span<JBig2HuffmanCode> symcodes)1202 bool CJBig2_Context::HuffmanAssignCode(
1203     pdfium::span<JBig2HuffmanCode> symcodes) {
1204   int lenmax = 0;
1205   for (const auto& symcode : symcodes) {
1206     lenmax = std::max(symcode.codelen, lenmax);
1207   }
1208   std::vector<int> lencounts(lenmax + 1);
1209   std::vector<int> firstcodes(lenmax + 1);
1210   for (const auto& symcode : symcodes) {
1211     ++lencounts[symcode.codelen];
1212   }
1213   lencounts[0] = 0;
1214   for (int i = 1; i <= lenmax; ++i) {
1215     FX_SAFE_INT32 shifted = firstcodes[i - 1];
1216     shifted += lencounts[i - 1];
1217     shifted <<= 1;
1218     if (!shifted.IsValid()) {
1219       return false;
1220     }
1221     firstcodes[i] = shifted.ValueOrDie();
1222     int curcode = firstcodes[i];
1223     for (auto& symcode : symcodes) {
1224       if (symcode.codelen == i) {
1225         symcode.code = curcode++;
1226       }
1227     }
1228   }
1229   return true;
1230 }
1231