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