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