Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
JBig2_Context.cpp
Go to the documentation of this file.
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
31namespace {
32
33size_t GetHuffContextSize(uint8_t val) {
34 return val == 0 ? 65536 : val == 1 ? 8192 : 1024;
35}
36
37size_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.
51static_assert(kSymbolDictCacheMaxSize > 0,
52 "Symbol Dictionary Cache must have non-zero size");
53
54// static
55std::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
70CJBig2_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
79CJBig2_Context::~CJBig2_Context() = default;
80
81JBig2_Result CJBig2_Context::DecodeSequential(PauseIndicatorIface* pPause) {
82 if (m_pStream->getByteLeft() <= 0)
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;
100 }
101 if (nRet == JBig2_Result::kEndReached) {
102 m_pSegment.reset();
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())
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;
125 }
126 }
128}
129
130bool 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
154 m_ProcessingStatus = FXCODEC_STATUS::kDecodeReady;
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
174 return nRet == JBig2_Result::kSuccess;
175}
176
177CJBig2_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
190CJBig2_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
207JBig2_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) {
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) {
218 }
219 pSegment->m_nReferred_to_segment_count &= 0x1fffffff;
223 }
224 } else {
225 if (m_pStream->read1Byte(&cTemp) != 0)
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(
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)
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)
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)
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)
261 }
262 }
263 if (cPSize == 1) {
264 if (m_pStream->read1Byte(&cTemp) != 0)
266 pSegment->m_dwPage_association = cTemp;
267 } else if (m_pStream->readInteger(&pSegment->m_dwPage_association) != 0) {
269 }
270 if (m_pStream->readInteger(&pSegment->m_dwData_length) != 0)
272
273 pSegment->m_Key = m_pStream->getKey();
274 pSegment->m_dwDataOffset = m_pStream->getOffset();
277}
278
279JBig2_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
289JBig2_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)
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)
308 return ParseHalftoneRegion(pSegment, pPause);
309 case 36:
310 case 38:
311 case 39:
312 if (!m_bInPage)
314 return ParseGenericRegion(pSegment, pPause);
315 case 40:
316 case 42:
317 case 43:
318 if (!m_bInPage)
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) {
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;
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;
360 case 50:
361 m_pStream->offset(pSegment->m_dwData_length);
362 break;
363 case 51:
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 }
377}
378
379JBig2_Result CJBig2_Context::ParseSymbolDict(CJBig2_Segment* pSegment) {
380 uint16_t wFlags;
381 if (m_pStream->readShortInteger(&wFlags) != 0)
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)
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)
400 }
401 }
402 if (m_pStream->readInteger(&pSymbolDictDecoder->SDNUMEXSYMS) != 0 ||
403 m_pStream->readInteger(&pSymbolDictDecoder->SDNUMNEWSYMS) != 0) {
405 }
406 if (pSymbolDictDecoder->SDNUMEXSYMS > kJBig2MaxExportSymbols ||
407 pSymbolDictDecoder->SDNUMNEWSYMS > kJBig2MaxNewSymbols) {
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]))
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)
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)
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)
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)
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)
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)
511 }
512 if (bUseGrContext) {
513 grContext = pLRSeg->m_SymbolDict->GrContext();
514 if (grContext.size() != grContextSize)
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;
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->emplace_front(key, std::move(it->second));
533 m_pSymbolDictCache->erase(it);
534 cache_hit = true;
535 break;
536 }
537 }
538 }
539 if (!cache_hit) {
540 if (bUseGbContext) {
541 auto pArithDecoder =
542 std::make_unique<CJBig2_ArithDecoder>(m_pStream.get());
543 pSegment->m_SymbolDict = pSymbolDictDecoder->DecodeArith(
544 pArithDecoder.get(), &gbContext, &grContext);
545 if (!pSegment->m_SymbolDict)
547
548 m_pStream->alignByte();
549 m_pStream->offset(2);
550 } else {
551 pSegment->m_SymbolDict = pSymbolDictDecoder->DecodeHuffman(
552 m_pStream.get(), &gbContext, &grContext);
553 if (!pSegment->m_SymbolDict)
555 m_pStream->alignByte();
556 }
557 if (m_bIsGlobal) {
558 std::unique_ptr<CJBig2_SymbolDict> value =
559 pSegment->m_SymbolDict->DeepCopy();
560 size_t size = m_pSymbolDictCache->size();
561 while (size >= kSymbolDictCacheMaxSize) {
562 m_pSymbolDictCache->pop_back();
563 --size;
564 }
565 m_pSymbolDictCache->emplace_front(key, std::move(value));
566 }
567 }
568 if (wFlags & 0x0200) {
569 if (bUseGbContext)
570 pSegment->m_SymbolDict->SetGbContext(std::move(gbContext));
571 if (bUseGrContext)
572 pSegment->m_SymbolDict->SetGrContext(std::move(grContext));
573 }
575}
576
577JBig2_Result CJBig2_Context::ParseTextRegion(CJBig2_Segment* pSegment) {
578 uint16_t wFlags;
580 if (ParseRegionInfo(&ri) != JBig2_Result::kSuccess ||
581 m_pStream->readShortInteger(&wFlags) != 0) {
583 }
586
587 auto pTRD = std::make_unique<CJBig2_TRDProc>();
588 pTRD->SBW = ri.width;
589 pTRD->SBH = ri.height;
590 pTRD->SBHUFF = wFlags & 0x0001;
591 pTRD->SBREFINE = (wFlags >> 1) & 0x0001;
592 uint32_t dwTemp = (wFlags >> 2) & 0x0003;
593 pTRD->SBSTRIPS = 1 << dwTemp;
594 pTRD->REFCORNER = (JBig2Corner)((wFlags >> 4) & 0x0003);
595 pTRD->TRANSPOSED = (wFlags >> 6) & 0x0001;
596 pTRD->SBCOMBOP = (JBig2ComposeOp)((wFlags >> 7) & 0x0003);
597 pTRD->SBDEFPIXEL = (wFlags >> 9) & 0x0001;
598 pTRD->SBDSOFFSET = (wFlags >> 10) & 0x001f;
599 if (pTRD->SBDSOFFSET >= 0x0010) {
600 pTRD->SBDSOFFSET = pTRD->SBDSOFFSET - 0x0020;
601 }
602 pTRD->SBRTEMPLATE = !!((wFlags >> 15) & 0x0001);
603
604 if (pTRD->SBHUFF && m_pStream->readShortInteger(&wFlags) != 0) {
606 }
607 if (pTRD->SBREFINE && !pTRD->SBRTEMPLATE) {
608 for (int32_t i = 0; i < 4; ++i) {
609 if (m_pStream->read1Byte((uint8_t*)&pTRD->SBRAT[i]) != 0)
611 }
612 }
613 if (m_pStream->readInteger(&pTRD->SBNUMINSTANCES) != 0)
615
616 // Assume each instance takes at least 0.25 bits when encoded. That means for
617 // a stream of length N bytes, there can be at most 32N instances. This is a
618 // conservative estimate just to sanitize the |SBNUMINSTANCES| value.
619 // Use FX_SAFE_INT32 to be safe, though it should never overflow because PDFs
620 // have a maximum size of roughly 11 GB.
621 FX_SAFE_INT32 nMaxStripInstances = m_pStream->getLength();
622 nMaxStripInstances *= 32;
623 if (pTRD->SBNUMINSTANCES > nMaxStripInstances.ValueOrDie())
625
626 for (int32_t i = 0; i < pSegment->m_nReferred_to_segment_count; ++i) {
627 if (!FindSegmentByNumber(pSegment->m_Referred_to_segment_numbers[i]))
629 }
630
631 FX_SAFE_UINT32 dwNumSyms = 0;
632 for (int32_t i = 0; i < pSegment->m_nReferred_to_segment_count; ++i) {
633 CJBig2_Segment* pSeg =
634 FindSegmentByNumber(pSegment->m_Referred_to_segment_numbers[i]);
635 if (pSeg->m_cFlags.s.type == 0) {
636 dwNumSyms += pSeg->m_SymbolDict->NumImages();
637 }
638 }
639 pTRD->SBNUMSYMS = dwNumSyms.ValueOrDie();
640
641 std::unique_ptr<CJBig2_Image*, FxFreeDeleter> SBSYMS;
642 if (pTRD->SBNUMSYMS > 0) {
643 SBSYMS.reset(FX_Alloc(CJBig2_Image*, pTRD->SBNUMSYMS));
644 dwNumSyms = 0;
645 for (int32_t i = 0; i < pSegment->m_nReferred_to_segment_count; ++i) {
646 CJBig2_Segment* pSeg =
647 FindSegmentByNumber(pSegment->m_Referred_to_segment_numbers[i]);
648 if (pSeg->m_cFlags.s.type == 0) {
649 const CJBig2_SymbolDict& dict = *pSeg->m_SymbolDict;
650 for (uint32_t j = 0; j < dict.NumImages(); ++j) {
651 uint32_t dwIndex = (dwNumSyms + j).ValueOrDie();
652 SBSYMS.get()[dwIndex] = dict.GetImage(j);
653 }
654 dwNumSyms += dict.NumImages();
655 }
656 }
657 pTRD->SBSYMS = SBSYMS.get();
658 } else {
659 pTRD->SBSYMS = nullptr;
660 }
661
662 if (pTRD->SBHUFF) {
663 std::vector<JBig2HuffmanCode> SBSYMCODES =
664 DecodeSymbolIDHuffmanTable(pTRD->SBNUMSYMS);
665 if (SBSYMCODES.empty())
667
668 m_pStream->alignByte();
669 pTRD->SBSYMCODES = std::move(SBSYMCODES);
670 } else {
671 dwTemp = 0;
672 while ((uint32_t)(1 << dwTemp) < pTRD->SBNUMSYMS) {
673 ++dwTemp;
674 }
675 pTRD->SBSYMCODELEN = (uint8_t)dwTemp;
676 }
677
678 if (pTRD->SBHUFF) {
679 uint8_t cSBHUFFFS = wFlags & 0x0003;
680 uint8_t cSBHUFFDS = (wFlags >> 2) & 0x0003;
681 uint8_t cSBHUFFDT = (wFlags >> 4) & 0x0003;
682 uint8_t cSBHUFFRDW = (wFlags >> 6) & 0x0003;
683 uint8_t cSBHUFFRDH = (wFlags >> 8) & 0x0003;
684 uint8_t cSBHUFFRDX = (wFlags >> 10) & 0x0003;
685 uint8_t cSBHUFFRDY = (wFlags >> 12) & 0x0003;
686 uint8_t cSBHUFFRSIZE = (wFlags >> 14) & 0x0001;
687 if (cSBHUFFFS == 2 || cSBHUFFRDW == 2 || cSBHUFFRDH == 2 ||
688 cSBHUFFRDX == 2 || cSBHUFFRDY == 2) {
690 }
691 int32_t nIndex = 0;
692 if (cSBHUFFFS == 0) {
693 pTRD->SBHUFFFS = GetHuffmanTable(6);
694 } else if (cSBHUFFFS == 1) {
695 pTRD->SBHUFFFS = GetHuffmanTable(7);
696 } else {
697 CJBig2_Segment* pSeg =
698 FindReferredTableSegmentByIndex(pSegment, nIndex++);
699 if (!pSeg)
701 pTRD->SBHUFFFS = pSeg->m_HuffmanTable.get();
702 }
703 if (cSBHUFFDS == 0) {
704 pTRD->SBHUFFDS = GetHuffmanTable(8);
705 } else if (cSBHUFFDS == 1) {
706 pTRD->SBHUFFDS = GetHuffmanTable(9);
707 } else if (cSBHUFFDS == 2) {
708 pTRD->SBHUFFDS = GetHuffmanTable(10);
709 } else {
710 CJBig2_Segment* pSeg =
711 FindReferredTableSegmentByIndex(pSegment, nIndex++);
712 if (!pSeg)
714 pTRD->SBHUFFDS = pSeg->m_HuffmanTable.get();
715 }
716 if (cSBHUFFDT == 0) {
717 pTRD->SBHUFFDT = GetHuffmanTable(11);
718 } else if (cSBHUFFDT == 1) {
719 pTRD->SBHUFFDT = GetHuffmanTable(12);
720 } else if (cSBHUFFDT == 2) {
721 pTRD->SBHUFFDT = GetHuffmanTable(13);
722 } else {
723 CJBig2_Segment* pSeg =
724 FindReferredTableSegmentByIndex(pSegment, nIndex++);
725 if (!pSeg)
727 pTRD->SBHUFFDT = pSeg->m_HuffmanTable.get();
728 }
729 if (cSBHUFFRDW == 0) {
730 pTRD->SBHUFFRDW = GetHuffmanTable(14);
731 } else if (cSBHUFFRDW == 1) {
732 pTRD->SBHUFFRDW = GetHuffmanTable(15);
733 } else {
734 CJBig2_Segment* pSeg =
735 FindReferredTableSegmentByIndex(pSegment, nIndex++);
736 if (!pSeg)
738 pTRD->SBHUFFRDW = pSeg->m_HuffmanTable.get();
739 }
740 if (cSBHUFFRDH == 0) {
741 pTRD->SBHUFFRDH = GetHuffmanTable(14);
742 } else if (cSBHUFFRDH == 1) {
743 pTRD->SBHUFFRDH = GetHuffmanTable(15);
744 } else {
745 CJBig2_Segment* pSeg =
746 FindReferredTableSegmentByIndex(pSegment, nIndex++);
747 if (!pSeg)
749 pTRD->SBHUFFRDH = pSeg->m_HuffmanTable.get();
750 }
751 if (cSBHUFFRDX == 0) {
752 pTRD->SBHUFFRDX = GetHuffmanTable(14);
753 } else if (cSBHUFFRDX == 1) {
754 pTRD->SBHUFFRDX = GetHuffmanTable(15);
755 } else {
756 CJBig2_Segment* pSeg =
757 FindReferredTableSegmentByIndex(pSegment, nIndex++);
758 if (!pSeg)
760 pTRD->SBHUFFRDX = pSeg->m_HuffmanTable.get();
761 }
762 if (cSBHUFFRDY == 0) {
763 pTRD->SBHUFFRDY = GetHuffmanTable(14);
764 } else if (cSBHUFFRDY == 1) {
765 pTRD->SBHUFFRDY = GetHuffmanTable(15);
766 } else {
767 CJBig2_Segment* pSeg =
768 FindReferredTableSegmentByIndex(pSegment, nIndex++);
769 if (!pSeg)
771 pTRD->SBHUFFRDY = pSeg->m_HuffmanTable.get();
772 }
773 if (cSBHUFFRSIZE == 0) {
774 pTRD->SBHUFFRSIZE = GetHuffmanTable(1);
775 } else {
776 CJBig2_Segment* pSeg =
777 FindReferredTableSegmentByIndex(pSegment, nIndex++);
778 if (!pSeg)
780 pTRD->SBHUFFRSIZE = pSeg->m_HuffmanTable.get();
781 }
782 }
783 std::unique_ptr<JBig2ArithCtx, FxFreeDeleter> grContext;
784 if (pTRD->SBREFINE) {
785 const size_t size = GetRefAggContextSize(pTRD->SBRTEMPLATE);
786 grContext.reset(FX_Alloc(JBig2ArithCtx, size));
787 }
789 if (pTRD->SBHUFF) {
790 pSegment->m_Image = pTRD->DecodeHuffman(m_pStream.get(), grContext.get());
791 if (!pSegment->m_Image)
793 m_pStream->alignByte();
794 } else {
795 auto pArithDecoder = std::make_unique<CJBig2_ArithDecoder>(m_pStream.get());
796 pSegment->m_Image =
797 pTRD->DecodeArith(pArithDecoder.get(), grContext.get(), nullptr);
798 if (!pSegment->m_Image)
800 m_pStream->alignByte();
801 m_pStream->offset(2);
802 }
803 if (pSegment->m_cFlags.s.type != 4) {
804 if (!m_bBufSpecified) {
805 const auto& pPageInfo = m_PageInfoList.back();
806 if (pPageInfo->m_bIsStriped && ri.y + ri.height > m_pPage->height())
807 m_pPage->Expand(ri.y + ri.height, pPageInfo->m_bDefaultPixelValue);
808 }
809 m_pPage->ComposeFrom(ri.x, ri.y, pSegment->m_Image.get(),
810 (JBig2ComposeOp)(ri.flags & 0x03));
811 pSegment->m_Image.reset();
812 }
814}
815
816JBig2_Result CJBig2_Context::ParsePatternDict(CJBig2_Segment* pSegment,
817 PauseIndicatorIface* pPause) {
818 uint8_t cFlags;
819 auto pPDD = std::make_unique<CJBig2_PDDProc>();
820 if (m_pStream->read1Byte(&cFlags) != 0 ||
821 m_pStream->read1Byte(&pPDD->HDPW) != 0 ||
822 m_pStream->read1Byte(&pPDD->HDPH) != 0 ||
823 m_pStream->readInteger(&pPDD->GRAYMAX) != 0) {
825 }
826 if (pPDD->GRAYMAX > kJBig2MaxPatternIndex)
828
829 pPDD->HDMMR = cFlags & 0x01;
830 pPDD->HDTEMPLATE = (cFlags >> 1) & 0x03;
832 if (pPDD->HDMMR) {
833 pSegment->m_PatternDict = pPDD->DecodeMMR(m_pStream.get());
834 if (!pSegment->m_PatternDict)
836 m_pStream->alignByte();
837 } else {
838 const size_t size = GetHuffContextSize(pPDD->HDTEMPLATE);
839 std::unique_ptr<JBig2ArithCtx, FxFreeDeleter> gbContext(
840 FX_Alloc(JBig2ArithCtx, size));
841 auto pArithDecoder = std::make_unique<CJBig2_ArithDecoder>(m_pStream.get());
842 pSegment->m_PatternDict =
843 pPDD->DecodeArith(pArithDecoder.get(), gbContext.get(), pPause);
844 if (!pSegment->m_PatternDict)
846
847 m_pStream->alignByte();
848 m_pStream->offset(2);
849 }
851}
852
853JBig2_Result CJBig2_Context::ParseHalftoneRegion(CJBig2_Segment* pSegment,
854 PauseIndicatorIface* pPause) {
855 uint8_t cFlags;
857 auto pHRD = std::make_unique<CJBig2_HTRDProc>();
858 if (ParseRegionInfo(&ri) != JBig2_Result::kSuccess ||
859 m_pStream->read1Byte(&cFlags) != 0 ||
860 m_pStream->readInteger(&pHRD->HGW) != 0 ||
861 m_pStream->readInteger(&pHRD->HGH) != 0 ||
862 m_pStream->readInteger((uint32_t*)&pHRD->HGX) != 0 ||
863 m_pStream->readInteger((uint32_t*)&pHRD->HGY) != 0 ||
864 m_pStream->readShortInteger(&pHRD->HRX) != 0 ||
865 m_pStream->readShortInteger(&pHRD->HRY) != 0) {
867 }
868
869 if (!CJBig2_Image::IsValidImageSize(pHRD->HGW, pHRD->HGH))
871
874
875 pHRD->HBW = ri.width;
876 pHRD->HBH = ri.height;
877 pHRD->HMMR = cFlags & 0x01;
878 pHRD->HTEMPLATE = (cFlags >> 1) & 0x03;
879 pHRD->HENABLESKIP = (cFlags >> 3) & 0x01;
880 pHRD->HCOMBOP = (JBig2ComposeOp)((cFlags >> 4) & 0x07);
881 pHRD->HDEFPIXEL = (cFlags >> 7) & 0x01;
882 if (pSegment->m_nReferred_to_segment_count != 1)
884
885 CJBig2_Segment* pSeg =
886 FindSegmentByNumber(pSegment->m_Referred_to_segment_numbers[0]);
887 if (!pSeg || (pSeg->m_cFlags.s.type != 16))
889
890 const CJBig2_PatternDict* pPatternDict = pSeg->m_PatternDict.get();
891 if (!pPatternDict || (pPatternDict->NUMPATS == 0))
893
894 pHRD->HNUMPATS = pPatternDict->NUMPATS;
895 pHRD->HPATS = &pPatternDict->HDPATS;
896 pHRD->HPW = pPatternDict->HDPATS[0]->width();
897 pHRD->HPH = pPatternDict->HDPATS[0]->height();
899 if (pHRD->HMMR) {
900 pSegment->m_Image = pHRD->DecodeMMR(m_pStream.get());
901 if (!pSegment->m_Image)
903 m_pStream->alignByte();
904 } else {
905 const size_t size = GetHuffContextSize(pHRD->HTEMPLATE);
906 std::unique_ptr<JBig2ArithCtx, FxFreeDeleter> gbContext(
907 FX_Alloc(JBig2ArithCtx, size));
908 auto pArithDecoder = std::make_unique<CJBig2_ArithDecoder>(m_pStream.get());
909 pSegment->m_Image =
910 pHRD->DecodeArith(pArithDecoder.get(), gbContext.get(), pPause);
911 if (!pSegment->m_Image)
913
914 m_pStream->alignByte();
915 m_pStream->offset(2);
916 }
917 if (pSegment->m_cFlags.s.type != 20) {
918 if (!m_bBufSpecified) {
919 const auto& pPageInfo = m_PageInfoList.back();
920 if (pPageInfo->m_bIsStriped && ri.y + ri.height > m_pPage->height())
921 m_pPage->Expand(ri.y + ri.height, pPageInfo->m_bDefaultPixelValue);
922 }
923 m_pPage->ComposeFrom(ri.x, ri.y, pSegment->m_Image.get(),
924 (JBig2ComposeOp)(ri.flags & 0x03));
925 pSegment->m_Image.reset();
926 }
928}
929
930JBig2_Result CJBig2_Context::ParseGenericRegion(CJBig2_Segment* pSegment,
931 PauseIndicatorIface* pPause) {
932 if (!m_pGRD) {
933 auto pGRD = std::make_unique<CJBig2_GRDProc>();
934 uint8_t cFlags;
935 if (ParseRegionInfo(&m_ri) != JBig2_Result::kSuccess ||
936 m_pStream->read1Byte(&cFlags) != 0) {
938 }
939 if (m_ri.height < 0 || m_ri.width < 0)
941 pGRD->GBW = m_ri.width;
942 pGRD->GBH = m_ri.height;
943 pGRD->MMR = cFlags & 0x01;
944 pGRD->GBTEMPLATE = (cFlags >> 1) & 0x03;
945 pGRD->TPGDON = (cFlags >> 3) & 0x01;
946 if (!pGRD->MMR) {
947 if (pGRD->GBTEMPLATE == 0) {
948 for (int32_t i = 0; i < 8; ++i) {
949 if (m_pStream->read1Byte((uint8_t*)&pGRD->GBAT[i]) != 0)
951 }
952 } else {
953 for (int32_t i = 0; i < 2; ++i) {
954 if (m_pStream->read1Byte((uint8_t*)&pGRD->GBAT[i]) != 0)
956 }
957 }
958 }
959 pGRD->USESKIP = false;
960 m_pGRD = std::move(pGRD);
961 }
963 if (m_pGRD->MMR) {
964 m_pGRD->StartDecodeMMR(&pSegment->m_Image, m_pStream.get());
965 if (!pSegment->m_Image) {
966 m_pGRD.reset();
968 }
969 m_pStream->alignByte();
970 } else {
971 if (m_gbContext.empty())
972 m_gbContext.resize(GetHuffContextSize(m_pGRD->GBTEMPLATE));
973
974 bool bStart = !m_pArithDecoder;
975 if (bStart) {
976 m_pArithDecoder = std::make_unique<CJBig2_ArithDecoder>(m_pStream.get());
977 }
978 {
979 // |state.gbContext| can't exist when m_gbContext.clear() called below.
981 state.pImage = &pSegment->m_Image;
982 state.pArithDecoder = m_pArithDecoder.get();
983 state.gbContext = m_gbContext.data();
984 state.pPause = pPause;
985 m_ProcessingStatus = bStart ? m_pGRD->StartDecodeArith(&state)
986 : m_pGRD->ContinueDecode(&state);
987 if (m_ProcessingStatus == FXCODEC_STATUS::kDecodeToBeContinued) {
988 if (pSegment->m_cFlags.s.type != 36) {
989 if (!m_bBufSpecified) {
990 const auto& pPageInfo = m_PageInfoList.back();
991 if (pPageInfo->m_bIsStriped &&
992 m_ri.y + m_ri.height > m_pPage->height()) {
993 m_pPage->Expand(m_ri.y + m_ri.height,
994 pPageInfo->m_bDefaultPixelValue);
995 }
996 }
997 const FX_RECT& rect = m_pGRD->GetReplaceRect();
998 m_pPage->ComposeFromWithRect(m_ri.x + rect.left, m_ri.y + rect.top,
999 pSegment->m_Image.get(), rect,
1000 (JBig2ComposeOp)(m_ri.flags & 0x03));
1001 }
1003 }
1004 }
1005 m_pArithDecoder.reset();
1006 m_gbContext.clear();
1007 if (!pSegment->m_Image) {
1008 m_ProcessingStatus = FXCODEC_STATUS::kError;
1009 m_pGRD.reset();
1011 }
1012 m_pStream->alignByte();
1013 m_pStream->offset(2);
1014 }
1015 if (pSegment->m_cFlags.s.type != 36) {
1016 if (!m_bBufSpecified) {
1017 JBig2PageInfo* pPageInfo = m_PageInfoList.back().get();
1018 if (pPageInfo->m_bIsStriped && m_ri.y + m_ri.height > m_pPage->height())
1019 m_pPage->Expand(m_ri.y + m_ri.height, pPageInfo->m_bDefaultPixelValue);
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();
1029}
1030
1031JBig2_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) {
1038 }
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)
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)
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)
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());
1080 pSegment->m_Image = pGRRD->Decode(pArithDecoder.get(), grContext.get());
1081 if (!pSegment->m_Image)
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 && ri.y + ri.height > m_pPage->height())
1090 m_pPage->Expand(ri.y + ri.height, pPageInfo->m_bDefaultPixelValue);
1091 }
1092 m_pPage->ComposeFrom(ri.x, ri.y, pSegment->m_Image.get(),
1093 (JBig2ComposeOp)(ri.flags & 0x03));
1094 pSegment->m_Image.reset();
1095 }
1097}
1098
1099JBig2_Result CJBig2_Context::ParseTable(CJBig2_Segment* pSegment) {
1101 pSegment->m_HuffmanTable.reset();
1102 auto pHuff = std::make_unique<CJBig2_HuffmanTable>(m_pStream.get());
1103 if (!pHuff->IsOK())
1105
1106 pSegment->m_HuffmanTable = std::move(pHuff);
1107 m_pStream->alignByte();
1109}
1110
1111JBig2_Result CJBig2_Context::ParseRegionInfo(JBig2RegionInfo* pRI) {
1112 if (m_pStream->readInteger((uint32_t*)&pRI->width) != 0 ||
1113 m_pStream->readInteger((uint32_t*)&pRI->height) != 0 ||
1114 m_pStream->readInteger((uint32_t*)&pRI->x) != 0 ||
1115 m_pStream->readInteger((uint32_t*)&pRI->y) != 0 ||
1116 m_pStream->read1Byte(&pRI->flags) != 0) {
1118 }
1120}
1121
1122std::vector<JBig2HuffmanCode> CJBig2_Context::DecodeSymbolIDHuffmanTable(
1123 uint32_t SBNUMSYMS) {
1124 const size_t kRunCodesSize = 35;
1125 JBig2HuffmanCode huffman_codes[kRunCodesSize];
1126 for (size_t i = 0; i < kRunCodesSize; ++i) {
1127 if (m_pStream->readNBits(4, &huffman_codes[i].codelen) != 0)
1128 return std::vector<JBig2HuffmanCode>();
1129 }
1130 if (!HuffmanAssignCode(huffman_codes, kRunCodesSize))
1131 return std::vector<JBig2HuffmanCode>();
1132
1133 std::vector<JBig2HuffmanCode> SBSYMCODES(SBNUMSYMS);
1134 int32_t run = 0;
1135 int32_t i = 0;
1136 while (i < static_cast<int>(SBNUMSYMS)) {
1137 size_t j;
1138 FX_SAFE_INT32 nSafeVal = 0;
1139 int32_t nBits = 0;
1140 uint32_t nTemp;
1141 while (true) {
1142 if (m_pStream->read1Bit(&nTemp) != 0)
1143 return std::vector<JBig2HuffmanCode>();
1144
1145 nSafeVal <<= 1;
1146 if (!nSafeVal.IsValid())
1147 return std::vector<JBig2HuffmanCode>();
1148
1149 nSafeVal |= nTemp;
1150 ++nBits;
1151 const int32_t nVal = nSafeVal.ValueOrDie();
1152 for (j = 0; j < kRunCodesSize; ++j) {
1153 if (nBits == huffman_codes[j].codelen && nVal == huffman_codes[j].code)
1154 break;
1155 }
1156 if (j < kRunCodesSize)
1157 break;
1158 }
1159 int32_t runcode = static_cast<int32_t>(j);
1160 if (runcode < 32) {
1161 SBSYMCODES[i].codelen = runcode;
1162 run = 0;
1163 } else if (runcode == 32) {
1164 if (m_pStream->readNBits(2, &nTemp) != 0)
1165 return std::vector<JBig2HuffmanCode>();
1166 run = nTemp + 3;
1167 } else if (runcode == 33) {
1168 if (m_pStream->readNBits(3, &nTemp) != 0)
1169 return std::vector<JBig2HuffmanCode>();
1170 run = nTemp + 3;
1171 } else if (runcode == 34) {
1172 if (m_pStream->readNBits(7, &nTemp) != 0)
1173 return std::vector<JBig2HuffmanCode>();
1174 run = nTemp + 11;
1175 }
1176 if (run > 0) {
1177 if (i + run > (int)SBNUMSYMS)
1178 return std::vector<JBig2HuffmanCode>();
1179 for (int32_t k = 0; k < run; ++k) {
1180 if (runcode == 32 && i > 0)
1181 SBSYMCODES[i + k].codelen = SBSYMCODES[i - 1].codelen;
1182 else
1183 SBSYMCODES[i + k].codelen = 0;
1184 }
1185 i += run;
1186 } else {
1187 ++i;
1188 }
1189 }
1190 if (!HuffmanAssignCode(SBSYMCODES.data(), SBNUMSYMS))
1191 return std::vector<JBig2HuffmanCode>();
1192 return SBSYMCODES;
1193}
1194
1195const CJBig2_HuffmanTable* CJBig2_Context::GetHuffmanTable(size_t idx) {
1196 DCHECK(idx > 0);
1197 DCHECK(idx < CJBig2_HuffmanTable::kNumHuffmanTables);
1198 if (!m_HuffmanTables[idx].get())
1199 m_HuffmanTables[idx] = std::make_unique<CJBig2_HuffmanTable>(idx);
1200 return m_HuffmanTables[idx].get();
1201}
1202
1203// static
1205 uint32_t NTEMP) {
1206 int LENMAX = 0;
1207 for (uint32_t i = 0; i < NTEMP; ++i)
1208 LENMAX = std::max(SBSYMCODES[i].codelen, LENMAX);
1209
1210 std::vector<int> LENCOUNT(LENMAX + 1);
1211 std::vector<int> FIRSTCODE(LENMAX + 1);
1212 for (uint32_t i = 0; i < NTEMP; ++i)
1213 ++LENCOUNT[SBSYMCODES[i].codelen];
1214 LENCOUNT[0] = 0;
1215
1216 for (int i = 1; i <= LENMAX; ++i) {
1217 FX_SAFE_INT32 shifted = FIRSTCODE[i - 1];
1218 shifted += LENCOUNT[i - 1];
1219 shifted <<= 1;
1220 if (!shifted.IsValid())
1221 return false;
1222
1223 FIRSTCODE[i] = shifted.ValueOrDie();
1224 int CURCODE = FIRSTCODE[i];
1225 for (uint32_t j = 0; j < NTEMP; ++j) {
1226 if (SBSYMCODES[j].codelen == i)
1227 SBSYMCODES[j].code = CURCODE++;
1228 }
1229 }
1230 return true;
1231}
static const size_t kSymbolDictCacheMaxSize
JBig2_Result
#define JBIG2_MIN_SEGMENT_SIZE
constexpr uint32_t kJBig2MaxNewSymbols
constexpr int32_t kJBig2MaxReferredSegmentCount
constexpr uint32_t kJBig2MaxExportSymbols
constexpr uint32_t kJBig2MaxPatternIndex
JBig2ComposeOp
Definition JBig2_Image.h:19
@ JBIG2_IMAGE_POINTER
@ JBIG2_HUFFMAN_TABLE_POINTER
@ JBIG2_SYMBOL_DICT_POINTER
@ JBIG2_PATTERN_DICT_POINTER
@ JBIG2_SEGMENT_DATA_UNPARSED
JBig2Corner
static bool HuffmanAssignCode(JBig2HuffmanCode *SBSYMCODES, uint32_t NTEMP)
bool GetFirstPage(pdfium::span< uint8_t > pBuf, int32_t width, int32_t height, int32_t stride, PauseIndicatorIface *pPause)
bool Continue(PauseIndicatorIface *pPause)
static bool IsValidImageSize(int32_t w, int32_t h)
JBig2_SegmentState m_State
JBig2_ResultType m_nResultType
uint8_t page_association_size
int32_t m_nReferred_to_segment_count
uint32_t m_dwPage_association
uint32_t m_dwNumber
virtual bool NeedToPauseNow()=0
FXCODEC_STATUS