7#include "core/fxcodec/jbig2/JBig2_Context.h"
15#include "core/fxcodec/jbig2/JBig2_ArithDecoder.h"
16#include "core/fxcodec/jbig2/JBig2_BitStream.h"
17#include "core/fxcodec/jbig2/JBig2_GrdProc.h"
18#include "core/fxcodec/jbig2/JBig2_GrrdProc.h"
19#include "core/fxcodec/jbig2/JBig2_HtrdProc.h"
20#include "core/fxcodec/jbig2/JBig2_PddProc.h"
21#include "core/fxcodec/jbig2/JBig2_SddProc.h"
22#include "core/fxcodec/jbig2/JBig2_TrdProc.h"
23#include "core/fxcrt/check.h"
24#include "core/fxcrt/fixed_size_data_vector.h"
25#include "core/fxcrt/fx_memory_wrappers.h"
26#include "core/fxcrt/fx_safe_types.h"
27#include "core/fxcrt/pauseindicator_iface.h"
28#include "core/fxcrt/ptr_util.h"
32size_t GetHuffContextSize(uint8_t val) {
33 return val == 0 ? 65536 : val == 1 ? 8192 : 1024;
36size_t GetRefAggContextSize(
bool val) {
37 return val ? 1024 : 8192;
50static_assert(kSymbolDictCacheMaxSize > 0,
51 "Symbol Dictionary Cache must have non-zero size");
55 pdfium::span<
const uint8_t> pGlobalSpan,
57 pdfium::span<
const uint8_t> pSrcSpan,
59 std::list<CJBig2_CachePair>* pSymbolDictCache) {
60 auto result =
pdfium::WrapUnique(
62 if (!pGlobalSpan.empty()) {
63 result->m_pGlobalContext =
pdfium::WrapUnique(
64 new CJBig2_Context(pGlobalSpan, global_key, pSymbolDictCache,
true));
69CJBig2_Context::CJBig2_Context(pdfium::span<
const uint8_t> pSrcSpan,
71 std::list<CJBig2_CachePair>* pSymbolDictCache,
73 : m_pStream(std::make_unique<CJBig2_BitStream>(pSrcSpan, src_key)),
74 m_HuffmanTables(CJBig2_HuffmanTable::kNumHuffmanTables),
75 m_bIsGlobal(bIsGlobal),
76 m_pSymbolDictCache(pSymbolDictCache) {}
81 if (m_pStream->getByteLeft() <= 0)
87 m_pSegment = std::make_unique<CJBig2_Segment>();
88 nRet = ParseSegmentHeader(m_pSegment.get());
93 m_nOffset = m_pStream->getOffset();
95 nRet = ParseSegmentData(m_pSegment.get(), pPause);
108 if (m_pSegment->m_dwData_length != 0xffffffff) {
110 new_offset += m_pSegment->m_dwData_length;
111 if (!new_offset.IsValid())
113 m_nOffset = new_offset.ValueOrDie();
114 m_pStream->setOffset(m_nOffset);
116 m_pStream->addOffset(4);
118 m_SegmentList.push_back(std::move(m_pSegment));
119 if (m_pStream->getByteLeft() > 0 && m_pPage && pPause &&
120 pPause->NeedToPauseNow()) {
134 if (m_pGlobalContext) {
135 JBig2_Result nRet = m_pGlobalContext->DecodeSequential(pPause);
142 m_pPage = std::make_unique<CJBig2_Image>(width, height, stride, pBuf);
143 m_bBufSpecified =
true;
155 if (m_PauseStep == 5) {
160 if (m_PauseStep <= 2)
161 nRet = DecodeSequential(pPause);
177 if (m_pGlobalContext) {
178 CJBig2_Segment* pSeg = m_pGlobalContext->FindSegmentByNumber(dwNumber);
182 for (
const auto& pSeg : m_SegmentList) {
183 if (pSeg->m_dwNumber == dwNumber)
192 static const uint8_t kTableType = 53;
196 FindSegmentByNumber(pSegment->m_Referred_to_segment_numbers[i]);
197 if (pSeg && pSeg->m_cFlags.s
.type == kTableType) {
207 if (m_pStream->readInteger(&pSegment->m_dwNumber) != 0 ||
208 m_pStream->read1Byte(&pSegment->m_cFlags.c) != 0) {
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) {
224 if (m_pStream->read1Byte(&cTemp) != 0)
233 pSegment->m_Referred_to_segment_numbers.resize(
238 if (m_pStream->read1Byte(&cTemp) != 0)
241 pSegment->m_Referred_to_segment_numbers[i] = cTemp;
245 if (m_pStream->readShortInteger(&wTemp) != 0)
248 pSegment->m_Referred_to_segment_numbers[i] = wTemp;
252 if (m_pStream->readInteger(&dwTemp) != 0)
255 pSegment->m_Referred_to_segment_numbers[i] = dwTemp;
258 if (pSegment->m_Referred_to_segment_numbers[i] >= pSegment
->m_dwNumber)
263 if (m_pStream->read1Byte(&cTemp) != 0)
266 }
else if (m_pStream->readInteger(&pSegment->m_dwPage_association) != 0) {
269 if (m_pStream->readInteger(&pSegment->m_dwData_length) != 0)
272 pSegment->m_Key = m_pStream->getKey();
273 pSegment->m_dwDataOffset = m_pStream->getOffset();
280 JBig2_Result ret = ProcessingParseSegmentData(pSegment, pPause);
281 while (m_ProcessingStatus == FXCODEC_STATUS::kDecodeToBeContinued &&
282 m_pStream->getByteLeft() > 0) {
283 ret = ProcessingParseSegmentData(pSegment, pPause);
291 switch (pSegment->m_cFlags.s
.type) {
293 return ParseSymbolDict(pSegment);
299 return ParseTextRegion(pSegment);
301 return ParsePatternDict(pSegment, pPause);
307 return ParseHalftoneRegion(pSegment, pPause);
313 return ParseGenericRegion(pSegment, pPause);
319 return ParseGenericRefinementRegion(pSegment);
321 uint8_t segment_flags;
322 uint16_t striping_info;
324 if (m_pStream->readInteger(&pPageInfo->m_dwWidth) != 0 ||
325 m_pStream->readInteger(&pPageInfo->m_dwHeight) != 0 ||
326 m_pStream->readInteger(&pPageInfo->m_dwResolutionX) != 0 ||
327 m_pStream->readInteger(&pPageInfo->m_dwResolutionY) != 0 ||
328 m_pStream->read1Byte(&segment_flags) != 0 ||
329 m_pStream->readShortInteger(&striping_info) != 0) {
333 pPageInfo->m_bDefaultPixelValue = !!(segment_flags & 4);
334 pPageInfo->m_bIsStriped = !!(striping_info & 0x8000);
335 pPageInfo->m_wMaxStripeSize = striping_info & 0x7fff;
336 bool bMaxHeight = (pPageInfo->m_dwHeight == 0xffffffff);
337 if (bMaxHeight && !pPageInfo->m_bIsStriped)
338 pPageInfo->m_bIsStriped =
true;
340 if (!m_bBufSpecified) {
342 bMaxHeight ? pPageInfo->m_wMaxStripeSize : pPageInfo->m_dwHeight;
343 m_pPage = std::make_unique<CJBig2_Image>(pPageInfo->m_dwWidth, height);
346 if (!m_pPage->data()) {
351 m_pPage->Fill(pPageInfo->m_bDefaultPixelValue);
352 m_PageInfoList.push_back(std::move(pPageInfo));
360 m_pStream->addOffset(pSegment->m_dwData_length);
365 m_pStream->addOffset(pSegment->m_dwData_length);
368 return ParseTable(pSegment);
370 m_pStream->addOffset(pSegment->m_dwData_length);
380 if (m_pStream->readShortInteger(&wFlags) != 0)
384 pSymbolDictDecoder->SDHUFF = wFlags & 0x0001;
385 pSymbolDictDecoder->SDREFAGG = (wFlags >> 1) & 0x0001;
386 pSymbolDictDecoder->SDTEMPLATE = (wFlags >> 10) & 0x0003;
387 pSymbolDictDecoder->SDRTEMPLATE = !!((wFlags >> 12) & 0x0003);
388 if (!pSymbolDictDecoder->SDHUFF) {
389 const uint32_t dwTemp = (pSymbolDictDecoder->SDTEMPLATE == 0) ? 8 : 2;
390 for (uint32_t i = 0; i < dwTemp; ++i) {
391 if (m_pStream->read1Byte((uint8_t*)&pSymbolDictDecoder->SDAT[i]) != 0)
395 if (pSymbolDictDecoder->SDREFAGG && !pSymbolDictDecoder->SDRTEMPLATE) {
396 for (int32_t i = 0; i < 4; ++i) {
397 if (m_pStream->read1Byte((uint8_t*)&pSymbolDictDecoder->SDRAT[i]) != 0)
401 if (m_pStream->readInteger(&pSymbolDictDecoder->SDNUMEXSYMS) != 0 ||
402 m_pStream->readInteger(&pSymbolDictDecoder->SDNUMNEWSYMS) != 0) {
410 if (!FindSegmentByNumber(pSegment->m_Referred_to_segment_numbers[i]))
417 FindSegmentByNumber(pSegment->m_Referred_to_segment_numbers[i]);
418 if (pSeg->m_cFlags.s
.type == 0) {
419 dwNumSyms += pSeg->m_SymbolDict->NumImages();
423 pSymbolDictDecoder->SDNUMINSYMS = dwNumSyms.ValueOrDie();
425 std::vector<UnownedPtr<CJBig2_Image>> SDINSYMS(
426 pSymbolDictDecoder->SDNUMINSYMS);
427 if (!SDINSYMS.empty()) {
431 FindSegmentByNumber(pSegment->m_Referred_to_segment_numbers[i]);
432 if (pSeg->m_cFlags.s
.type == 0) {
434 for (uint32_t j = 0; j < dict.NumImages(); ++j) {
435 uint32_t dwTemp = (dwNumSyms + j).ValueOrDie();
436 SDINSYMS[dwTemp] = dict.GetImage(j);
438 dwNumSyms += dict.NumImages();
442 pSymbolDictDecoder->SDINSYMS =
std::move(SDINSYMS);
444 uint8_t cSDHUFFDH = (wFlags >> 2) & 0x0003;
445 uint8_t cSDHUFFDW = (wFlags >> 4) & 0x0003;
446 if (pSymbolDictDecoder->SDHUFF) {
447 if (cSDHUFFDH == 2 || cSDHUFFDW == 2)
451 if (cSDHUFFDH == 0) {
452 pSymbolDictDecoder->SDHUFFDH = GetHuffmanTable(4);
453 }
else if (cSDHUFFDH == 1) {
454 pSymbolDictDecoder->SDHUFFDH = GetHuffmanTable(5);
457 FindReferredTableSegmentByIndex(pSegment, nIndex++);
460 pSymbolDictDecoder->SDHUFFDH = pSeg->m_HuffmanTable.get();
462 if (cSDHUFFDW == 0) {
463 pSymbolDictDecoder->SDHUFFDW = GetHuffmanTable(2);
464 }
else if (cSDHUFFDW == 1) {
465 pSymbolDictDecoder->SDHUFFDW = GetHuffmanTable(3);
468 FindReferredTableSegmentByIndex(pSegment, nIndex++);
471 pSymbolDictDecoder->SDHUFFDW = pSeg->m_HuffmanTable.get();
473 uint8_t cSDHUFFBMSIZE = (wFlags >> 6) & 0x0001;
474 if (cSDHUFFBMSIZE == 0) {
475 pSymbolDictDecoder->SDHUFFBMSIZE = GetHuffmanTable(1);
478 FindReferredTableSegmentByIndex(pSegment, nIndex++);
481 pSymbolDictDecoder->SDHUFFBMSIZE = pSeg->m_HuffmanTable.get();
483 if (pSymbolDictDecoder->SDREFAGG) {
484 uint8_t cSDHUFFAGGINST = (wFlags >> 7) & 0x0001;
485 if (cSDHUFFAGGINST == 0) {
486 pSymbolDictDecoder->SDHUFFAGGINST = GetHuffmanTable(1);
489 FindReferredTableSegmentByIndex(pSegment, nIndex++);
492 pSymbolDictDecoder->SDHUFFAGGINST = pSeg->m_HuffmanTable.get();
497 const bool bUseGbContext = !pSymbolDictDecoder->SDHUFF;
498 const bool bUseGrContext = pSymbolDictDecoder->SDREFAGG;
499 const size_t gbContextSize =
500 GetHuffContextSize(pSymbolDictDecoder->SDTEMPLATE);
501 const size_t grContextSize =
502 GetRefAggContextSize(pSymbolDictDecoder->SDRTEMPLATE);
503 std::vector<JBig2ArithCtx> gbContexts;
504 std::vector<JBig2ArithCtx> grContexts;
505 if ((wFlags & 0x0100) && pLRSeg) {
507 gbContexts = pLRSeg->m_SymbolDict->GbContexts();
508 if (gbContexts.size() != gbContextSize) {
513 grContexts = pLRSeg->m_SymbolDict->GrContexts();
514 if (grContexts.size() != grContextSize) {
520 gbContexts.resize(gbContextSize);
522 grContexts.resize(grContextSize);
526 bool cache_hit =
false;
528 if (m_bIsGlobal && key.first != 0) {
529 for (
auto it = m_pSymbolDictCache->begin(); it != m_pSymbolDictCache->end();
531 if (it->first == key) {
532 pSegment->m_SymbolDict = it->second->DeepCopy();
533 m_pSymbolDictCache->emplace_front(key, std::move(it->second));
534 m_pSymbolDictCache->erase(it);
543 std::make_unique<CJBig2_ArithDecoder>(m_pStream.get());
544 pSegment->m_SymbolDict = pSymbolDictDecoder->DecodeArith(
545 pArithDecoder.get(), gbContexts, grContexts);
546 if (!pSegment->m_SymbolDict)
549 m_pStream->alignByte();
550 m_pStream->addOffset(2);
552 pSegment->m_SymbolDict = pSymbolDictDecoder->DecodeHuffman(
553 m_pStream.get(), gbContexts, grContexts);
554 if (!pSegment->m_SymbolDict)
556 m_pStream->alignByte();
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();
566 m_pSymbolDictCache->emplace_front(key, std::move(value));
569 if (wFlags & 0x0200) {
571 pSegment->m_SymbolDict->SetGbContexts(
std::move(gbContexts));
573 pSegment->m_SymbolDict->SetGrContexts(
std::move(grContexts));
581 if (ParseRegionInfo(&ri) != JBig2_Result::kSuccess ||
582 m_pStream->readShortInteger(&wFlags) != 0) {
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;
598 pTRD->SBDEFPIXEL = (wFlags >> 9) & 0x0001;
599 pTRD->SBDSOFFSET = (wFlags >> 10) & 0x001f;
600 if (pTRD->SBDSOFFSET >= 0x0010) {
601 pTRD->SBDSOFFSET = pTRD->SBDSOFFSET - 0x0020;
603 pTRD->SBRTEMPLATE = !!((wFlags >> 15) & 0x0001);
605 if (pTRD->SBHUFF && m_pStream->readShortInteger(&wFlags) != 0) {
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)
614 if (m_pStream->readInteger(&pTRD->SBNUMINSTANCES) != 0)
622 FX_SAFE_INT32 nMaxStripInstances = m_pStream->getBufSpan().size();
623 nMaxStripInstances *= 32;
624 if (pTRD->SBNUMINSTANCES > nMaxStripInstances.ValueOrDie())
628 if (!FindSegmentByNumber(pSegment->m_Referred_to_segment_numbers[i]))
635 FindSegmentByNumber(pSegment->m_Referred_to_segment_numbers[i]);
636 if (pSeg->m_cFlags.s
.type == 0) {
637 dwNumSyms += pSeg->m_SymbolDict->NumImages();
640 pTRD->SBNUMSYMS = dwNumSyms.ValueOrDie();
642 std::vector<UnownedPtr<CJBig2_Image>> SBSYMS(pTRD->SBNUMSYMS);
643 if (!SBSYMS.empty()) {
647 FindSegmentByNumber(pSegment->m_Referred_to_segment_numbers[i]);
648 if (pSeg->m_cFlags.s
.type == 0) {
650 for (uint32_t j = 0; j < dict.NumImages(); ++j) {
651 uint32_t dwIndex = (dwNumSyms + j).ValueOrDie();
652 SBSYMS[dwIndex] = dict.GetImage(j);
654 dwNumSyms += dict.NumImages();
658 pTRD->SBSYMS =
std::move(SBSYMS);
661 std::vector<JBig2HuffmanCode> SBSYMCODES =
662 DecodeSymbolIDHuffmanTable(pTRD->SBNUMSYMS);
663 if (SBSYMCODES.empty())
666 m_pStream->alignByte();
667 pTRD->SBSYMCODES =
std::move(SBSYMCODES);
670 while ((uint32_t)(1 << dwTemp) < pTRD->SBNUMSYMS) {
673 pTRD->SBSYMCODELEN = (uint8_t)dwTemp;
677 uint8_t cSBHUFFFS = wFlags & 0x0003;
678 uint8_t cSBHUFFDS = (wFlags >> 2) & 0x0003;
679 uint8_t cSBHUFFDT = (wFlags >> 4) & 0x0003;
680 uint8_t cSBHUFFRDW = (wFlags >> 6) & 0x0003;
681 uint8_t cSBHUFFRDH = (wFlags >> 8) & 0x0003;
682 uint8_t cSBHUFFRDX = (wFlags >> 10) & 0x0003;
683 uint8_t cSBHUFFRDY = (wFlags >> 12) & 0x0003;
684 uint8_t cSBHUFFRSIZE = (wFlags >> 14) & 0x0001;
685 if (cSBHUFFFS == 2 || cSBHUFFRDW == 2 || cSBHUFFRDH == 2 ||
686 cSBHUFFRDX == 2 || cSBHUFFRDY == 2) {
690 if (cSBHUFFFS == 0) {
691 pTRD->SBHUFFFS = GetHuffmanTable(6);
692 }
else if (cSBHUFFFS == 1) {
693 pTRD->SBHUFFFS = GetHuffmanTable(7);
696 FindReferredTableSegmentByIndex(pSegment, nIndex++);
699 pTRD->SBHUFFFS = pSeg->m_HuffmanTable.get();
701 if (cSBHUFFDS == 0) {
702 pTRD->SBHUFFDS = GetHuffmanTable(8);
703 }
else if (cSBHUFFDS == 1) {
704 pTRD->SBHUFFDS = GetHuffmanTable(9);
705 }
else if (cSBHUFFDS == 2) {
706 pTRD->SBHUFFDS = GetHuffmanTable(10);
709 FindReferredTableSegmentByIndex(pSegment, nIndex++);
712 pTRD->SBHUFFDS = pSeg->m_HuffmanTable.get();
714 if (cSBHUFFDT == 0) {
715 pTRD->SBHUFFDT = GetHuffmanTable(11);
716 }
else if (cSBHUFFDT == 1) {
717 pTRD->SBHUFFDT = GetHuffmanTable(12);
718 }
else if (cSBHUFFDT == 2) {
719 pTRD->SBHUFFDT = GetHuffmanTable(13);
722 FindReferredTableSegmentByIndex(pSegment, nIndex++);
725 pTRD->SBHUFFDT = pSeg->m_HuffmanTable.get();
727 if (cSBHUFFRDW == 0) {
728 pTRD->SBHUFFRDW = GetHuffmanTable(14);
729 }
else if (cSBHUFFRDW == 1) {
730 pTRD->SBHUFFRDW = GetHuffmanTable(15);
733 FindReferredTableSegmentByIndex(pSegment, nIndex++);
736 pTRD->SBHUFFRDW = pSeg->m_HuffmanTable.get();
738 if (cSBHUFFRDH == 0) {
739 pTRD->SBHUFFRDH = GetHuffmanTable(14);
740 }
else if (cSBHUFFRDH == 1) {
741 pTRD->SBHUFFRDH = GetHuffmanTable(15);
744 FindReferredTableSegmentByIndex(pSegment, nIndex++);
747 pTRD->SBHUFFRDH = pSeg->m_HuffmanTable.get();
749 if (cSBHUFFRDX == 0) {
750 pTRD->SBHUFFRDX = GetHuffmanTable(14);
751 }
else if (cSBHUFFRDX == 1) {
752 pTRD->SBHUFFRDX = GetHuffmanTable(15);
755 FindReferredTableSegmentByIndex(pSegment, nIndex++);
758 pTRD->SBHUFFRDX = pSeg->m_HuffmanTable.get();
760 if (cSBHUFFRDY == 0) {
761 pTRD->SBHUFFRDY = GetHuffmanTable(14);
762 }
else if (cSBHUFFRDY == 1) {
763 pTRD->SBHUFFRDY = GetHuffmanTable(15);
766 FindReferredTableSegmentByIndex(pSegment, nIndex++);
769 pTRD->SBHUFFRDY = pSeg->m_HuffmanTable.get();
771 if (cSBHUFFRSIZE == 0) {
772 pTRD->SBHUFFRSIZE = GetHuffmanTable(1);
775 FindReferredTableSegmentByIndex(pSegment, nIndex++);
778 pTRD->SBHUFFRSIZE = pSeg->m_HuffmanTable.get();
781 FixedSizeDataVector<JBig2ArithCtx> grContexts;
782 if (pTRD->SBREFINE) {
783 const size_t size = GetRefAggContextSize(pTRD->SBRTEMPLATE);
784 grContexts = FixedSizeDataVector<JBig2ArithCtx>::Zeroed(size);
788 pSegment->m_Image = pTRD->DecodeHuffman(m_pStream.get(), grContexts);
789 if (!pSegment->m_Image)
791 m_pStream->alignByte();
793 auto pArithDecoder = std::make_unique<CJBig2_ArithDecoder>(m_pStream.get());
795 pTRD->DecodeArith(pArithDecoder.get(), grContexts,
nullptr);
796 if (!pSegment->m_Image)
798 m_pStream->alignByte();
799 m_pStream->addOffset(2);
801 if (pSegment->m_cFlags.s
.type != 4) {
802 if (!m_bBufSpecified) {
803 const auto& pPageInfo = m_PageInfoList.back();
804 if (pPageInfo->m_bIsStriped && ri.y + ri.height > m_pPage->height())
805 m_pPage->Expand(ri.y + ri.height, pPageInfo->m_bDefaultPixelValue);
807 m_pPage->ComposeFrom(ri.x, ri.y, pSegment->m_Image.get(),
808 (JBig2ComposeOp)(ri.flags & 0x03));
809 pSegment->m_Image.reset();
818 if (m_pStream->read1Byte(&cFlags) != 0 ||
819 m_pStream->read1Byte(&pPDD->HDPW) != 0 ||
820 m_pStream->read1Byte(&pPDD->HDPH) != 0 ||
821 m_pStream->readInteger(&pPDD->GRAYMAX) != 0) {
827 pPDD->HDMMR = cFlags & 0x01;
828 pPDD->HDTEMPLATE = (cFlags >> 1) & 0x03;
831 pSegment->m_PatternDict = pPDD->DecodeMMR(m_pStream.get());
832 if (!pSegment->m_PatternDict)
834 m_pStream->alignByte();
836 const size_t size = GetHuffContextSize(pPDD->HDTEMPLATE);
837 auto gbContexts = FixedSizeDataVector<JBig2ArithCtx>::Zeroed(size);
838 auto pArithDecoder = std::make_unique<CJBig2_ArithDecoder>(m_pStream.get());
839 pSegment->m_PatternDict =
840 pPDD->DecodeArith(pArithDecoder.get(), gbContexts, pPause);
841 if (!pSegment->m_PatternDict)
844 m_pStream->alignByte();
845 m_pStream->addOffset(2);
855 if (ParseRegionInfo(&ri) != JBig2_Result::kSuccess ||
856 m_pStream->read1Byte(&cFlags) != 0 ||
857 m_pStream->readInteger(&pHRD->HGW) != 0 ||
858 m_pStream->readInteger(&pHRD->HGH) != 0 ||
859 m_pStream->readInteger((uint32_t*)&pHRD->HGX) != 0 ||
860 m_pStream->readInteger((uint32_t*)&pHRD->HGY) != 0 ||
861 m_pStream->readShortInteger(&pHRD->HRX) != 0 ||
862 m_pStream->readShortInteger(&pHRD->HRY) != 0) {
874 pHRD->HMMR = cFlags & 0x01;
875 pHRD->HTEMPLATE = (cFlags >> 1) & 0x03;
876 pHRD->HENABLESKIP = (cFlags >> 3) & 0x01;
878 pHRD->HDEFPIXEL = (cFlags >> 7) & 0x01;
883 FindSegmentByNumber(pSegment->m_Referred_to_segment_numbers[0]);
884 if (!pSeg || (pSeg->m_cFlags.s
.type != 16))
888 if (!pPatternDict || (pPatternDict
->NUMPATS == 0))
892 pHRD->HPATS = &pPatternDict->HDPATS;
893 pHRD->HPW = pPatternDict->HDPATS[0]->width();
894 pHRD->HPH = pPatternDict->HDPATS[0]->height();
897 pSegment->m_Image = pHRD->DecodeMMR(m_pStream.get());
898 if (!pSegment->m_Image)
900 m_pStream->alignByte();
902 const size_t size = GetHuffContextSize(pHRD->HTEMPLATE);
903 auto gbContexts = FixedSizeDataVector<JBig2ArithCtx>::Zeroed(size);
904 auto pArithDecoder = std::make_unique<CJBig2_ArithDecoder>(m_pStream.get());
906 pHRD->DecodeArith(pArithDecoder.get(), gbContexts, pPause);
907 if (!pSegment->m_Image)
910 m_pStream->alignByte();
911 m_pStream->addOffset(2);
913 if (pSegment->m_cFlags.s
.type != 20) {
914 if (!m_bBufSpecified) {
915 const auto& pPageInfo = m_PageInfoList.back();
916 if (pPageInfo->m_bIsStriped && ri.y + ri.height > m_pPage->height())
917 m_pPage->Expand(ri.y + ri.height, pPageInfo->m_bDefaultPixelValue);
919 m_pPage->ComposeFrom(ri.x, ri.y, pSegment->m_Image.get(),
920 (JBig2ComposeOp)(ri.flags & 0x03));
921 pSegment->m_Image.reset();
931 if (ParseRegionInfo(&m_ri) != JBig2_Result::kSuccess ||
932 m_pStream->read1Byte(&cFlags) != 0) {
939 pGRD->MMR = cFlags & 0x01;
940 pGRD->GBTEMPLATE = (cFlags >> 1) & 0x03;
941 pGRD->TPGDON = (cFlags >> 3) & 0x01;
943 if (pGRD->GBTEMPLATE == 0) {
944 for (int32_t i = 0; i < 8; ++i) {
945 if (m_pStream->read1Byte((uint8_t*)&pGRD->GBAT[i]) != 0)
949 for (int32_t i = 0; i < 2; ++i) {
950 if (m_pStream->read1Byte((uint8_t*)&pGRD->GBAT[i]) != 0)
955 pGRD->USESKIP =
false;
956 m_pGRD = std::move(pGRD);
960 m_pGRD->StartDecodeMMR(&pSegment->m_Image, m_pStream.get());
961 if (!pSegment->m_Image) {
965 m_pStream->alignByte();
967 if (m_gbContexts.empty()) {
968 m_gbContexts.resize(GetHuffContextSize(m_pGRD->GBTEMPLATE));
971 bool bStart = !m_pArithDecoder;
973 m_pArithDecoder = std::make_unique<CJBig2_ArithDecoder>(m_pStream.get());
978 state.pImage = &pSegment->m_Image;
979 state.pArithDecoder = m_pArithDecoder.get();
980 state.gbContexts = m_gbContexts;
981 state.pPause = pPause;
982 m_ProcessingStatus = bStart ? m_pGRD->StartDecodeArith(&state)
983 : m_pGRD->ContinueDecode(&state);
985 if (pSegment->m_cFlags.s
.type != 36) {
986 if (!m_bBufSpecified) {
987 const auto& pPageInfo = m_PageInfoList.back();
988 if (pPageInfo->m_bIsStriped &&
989 m_ri.y + m_ri.height > m_pPage->height()) {
990 m_pPage->Expand(m_ri.y + m_ri.height,
991 pPageInfo->m_bDefaultPixelValue);
994 const FX_RECT& rect = m_pGRD->GetReplaceRect();
995 m_pPage->ComposeFromWithRect(m_ri.x + rect.left, m_ri.y + rect.top,
996 pSegment->m_Image.get(), rect,
997 (JBig2ComposeOp)(m_ri.flags & 0x03));
1002 m_pArithDecoder.reset();
1003 m_gbContexts.clear();
1004 if (!pSegment->m_Image) {
1009 m_pStream->alignByte();
1010 m_pStream->addOffset(2);
1012 if (pSegment->m_cFlags.s
.type != 36) {
1013 if (!m_bBufSpecified) {
1015 if (pPageInfo->m_bIsStriped && m_ri.y + m_ri.height > m_pPage->height())
1016 m_pPage->Expand(m_ri.y + m_ri.height, pPageInfo->m_bDefaultPixelValue);
1018 const FX_RECT& rect = m_pGRD->GetReplaceRect();
1019 m_pPage->ComposeFromWithRect(m_ri.x + rect.left, m_ri.y + rect.top,
1020 pSegment->m_Image.get(), rect,
1021 (JBig2ComposeOp)(m_ri.flags & 0x03));
1022 pSegment->m_Image.reset();
1032 if (ParseRegionInfo(&ri) != JBig2_Result::kSuccess ||
1033 m_pStream->read1Byte(&cFlags) != 0) {
1042 pGRRD->GRTEMPLATE = !!(cFlags & 0x01);
1043 pGRRD->TPGRON = (cFlags >> 1) & 0x01;
1044 if (!pGRRD->GRTEMPLATE) {
1045 for (int32_t i = 0; i < 4; ++i) {
1046 if (m_pStream->read1Byte((uint8_t*)&pGRRD->GRAT[i]) != 0)
1054 pSeg = FindSegmentByNumber(pSegment->m_Referred_to_segment_numbers[0]);
1058 if (pSeg->m_cFlags.s
.type == 4 || pSeg->m_cFlags.s
.type == 20 ||
1059 pSeg->m_cFlags.s
.type == 36 || pSeg->m_cFlags.s
.type == 40) {
1066 pGRRD->GRREFERENCE = pSeg->m_Image.get();
1068 pGRRD->GRREFERENCE = m_pPage.get();
1070 pGRRD->GRREFERENCEDX = 0;
1071 pGRRD->GRREFERENCEDY = 0;
1072 const size_t size = GetRefAggContextSize(pGRRD->GRTEMPLATE);
1073 auto grContexts = FixedSizeDataVector<JBig2ArithCtx>::Zeroed(size);
1074 auto pArithDecoder = std::make_unique<CJBig2_ArithDecoder>(m_pStream.get());
1076 pSegment->m_Image = pGRRD->Decode(pArithDecoder.get(), grContexts);
1077 if (!pSegment->m_Image)
1080 m_pStream->alignByte();
1081 m_pStream->addOffset(2);
1082 if (pSegment->m_cFlags.s
.type != 40) {
1083 if (!m_bBufSpecified) {
1085 if (pPageInfo->m_bIsStriped && ri.y + ri.height > m_pPage->height())
1086 m_pPage->Expand(ri.y + ri.height, pPageInfo->m_bDefaultPixelValue);
1088 m_pPage->ComposeFrom(ri.x, ri.y, pSegment->m_Image.get(),
1089 (JBig2ComposeOp)(ri.flags & 0x03));
1090 pSegment->m_Image.reset();
1097 pSegment->m_HuffmanTable.reset();
1098 auto pHuff = std::make_unique<CJBig2_HuffmanTable>(m_pStream.get());
1102 pSegment->m_HuffmanTable =
std::move(pHuff);
1103 m_pStream->alignByte();
1108 if (m_pStream->readInteger((uint32_t*)&pRI->width) != 0 ||
1109 m_pStream->readInteger((uint32_t*)&pRI->height) != 0 ||
1110 m_pStream->readInteger((uint32_t*)&pRI->x) != 0 ||
1111 m_pStream->readInteger((uint32_t*)&pRI->y) != 0 ||
1112 m_pStream->read1Byte(&pRI->flags) != 0) {
1118std::vector<JBig2HuffmanCode>
CJBig2_Context::DecodeSymbolIDHuffmanTable(
1119 uint32_t SBNUMSYMS) {
1120 const size_t kRunCodesSize = 35;
1122 for (size_t i = 0; i < kRunCodesSize; ++i) {
1123 if (m_pStream->readNBits(4, &huffman_codes[i].codelen) != 0)
1124 return std::vector<JBig2HuffmanCode>();
1126 if (!HuffmanAssignCode(huffman_codes)) {
1127 return std::vector<JBig2HuffmanCode>();
1130 std::vector<JBig2HuffmanCode> SBSYMCODES(SBNUMSYMS);
1133 while (i <
static_cast<
int>(SBNUMSYMS)) {
1139 if (m_pStream->read1Bit(&nTemp) != 0)
1140 return std::vector<JBig2HuffmanCode>();
1143 if (!nSafeVal.IsValid())
1144 return std::vector<JBig2HuffmanCode>();
1148 const int32_t nVal = nSafeVal.ValueOrDie();
1149 for (j = 0; j < kRunCodesSize; ++j) {
1150 if (nBits == huffman_codes[j].codelen && nVal == huffman_codes[j].code)
1153 if (j < kRunCodesSize)
1156 int32_t runcode =
static_cast<int32_t>(j);
1158 SBSYMCODES[i].codelen = runcode;
1160 }
else if (runcode == 32) {
1161 if (m_pStream->readNBits(2, &nTemp) != 0)
1162 return std::vector<JBig2HuffmanCode>();
1164 }
else if (runcode == 33) {
1165 if (m_pStream->readNBits(3, &nTemp) != 0)
1166 return std::vector<JBig2HuffmanCode>();
1168 }
else if (runcode == 34) {
1169 if (m_pStream->readNBits(7, &nTemp) != 0)
1170 return std::vector<JBig2HuffmanCode>();
1174 if (i + run > (
int)SBNUMSYMS)
1175 return std::vector<JBig2HuffmanCode>();
1176 for (int32_t k = 0; k < run; ++k) {
1177 if (runcode == 32 && i > 0)
1178 SBSYMCODES[i + k].codelen = SBSYMCODES[i - 1].codelen;
1180 SBSYMCODES[i + k].codelen = 0;
1187 if (!HuffmanAssignCode(SBSYMCODES)) {
1188 return std::vector<JBig2HuffmanCode>();
1195 DCHECK(idx < CJBig2_HuffmanTable::kNumHuffmanTables);
1196 if (!m_HuffmanTables[idx].get())
1197 m_HuffmanTables[idx] = std::make_unique<CJBig2_HuffmanTable>(idx);
1198 return m_HuffmanTables[idx].get();
1203 pdfium::span<JBig2HuffmanCode> symcodes) {
1205 for (
const auto& symcode : symcodes) {
1206 lenmax = std::max(symcode.codelen, lenmax);
1208 std::vector<
int> lencounts(lenmax + 1);
1209 std::vector<
int> firstcodes(lenmax + 1);
1210 for (
const auto& symcode : symcodes) {
1211 ++lencounts[symcode.codelen];
1214 for (
int i = 1; i <= lenmax; ++i) {
1216 shifted += lencounts[i - 1];
1218 if (!shifted.IsValid()) {
1221 firstcodes[i] = shifted.ValueOrDie();
1222 int curcode = firstcodes[i];
1223 for (
auto& symcode : symcodes) {
1224 if (symcode.codelen == i) {
1225 symcode.code = curcode++;
static const size_t kSymbolDictCacheMaxSize
#define JBIG2_MIN_SEGMENT_SIZE
constexpr uint32_t kJBig2MaxNewSymbols
constexpr int32_t kJBig2MaxReferredSegmentCount
constexpr uint32_t kJBig2MaxExportSymbols
constexpr uint32_t kJBig2MaxPatternIndex
std::pair< uint64_t, uint32_t > CJBig2_CompoundKey
@ JBIG2_HUFFMAN_TABLE_POINTER
@ JBIG2_SYMBOL_DICT_POINTER
@ JBIG2_PATTERN_DICT_POINTER
@ JBIG2_SEGMENT_DATA_UNPARSED
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
virtual bool NeedToPauseNow()=0
pdfium::CheckedNumeric< uint32_t > FX_SAFE_UINT32
pdfium::CheckedNumeric< int32_t > FX_SAFE_INT32