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