OLD | NEW |
---|---|
1 // Copyright 2014 PDFium Authors. All rights reserved. | 1 // Copyright 2014 PDFium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com | 5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com |
6 | 6 |
7 #include "JBig2_Context.h" | 7 #include "JBig2_Context.h" |
8 | 8 |
9 #include <list> | 9 #include <list> |
10 | 10 |
11 #include "JBig2_GrdProc.h" | 11 #include "JBig2_GrdProc.h" |
12 #include "JBig2_GrrdProc.h" | 12 #include "JBig2_GrrdProc.h" |
13 #include "JBig2_HtrdProc.h" | 13 #include "JBig2_HtrdProc.h" |
14 #include "JBig2_PddProc.h" | 14 #include "JBig2_PddProc.h" |
15 #include "JBig2_SddProc.h" | 15 #include "JBig2_SddProc.h" |
16 #include "JBig2_TrdProc.h" | 16 #include "JBig2_TrdProc.h" |
17 | 17 |
18 // Implement a very small least recently used (LRU) cache. It is very | 18 // Implement a very small least recently used (LRU) cache. It is very |
19 // common for a JBIG2 dictionary to span multiple pages in a PDF file, | 19 // common for a JBIG2 dictionary to span multiple pages in a PDF file, |
20 // and we do not want to decode the same dictionary over and over | 20 // and we do not want to decode the same dictionary over and over |
21 // again. We key off of the memory location of the dictionary. The | 21 // again. We key off of the memory location of the dictionary. The |
jbreiden
2015/10/07 17:50:16
not keying off memory location anymore.
| |
22 // list keeps track of the freshness of entries, with freshest ones | 22 // list keeps track of the freshness of entries, with freshest ones |
23 // at the front. Even a tiny cache size like 2 makes a dramatic | 23 // at the front. Even a tiny cache size like 2 makes a dramatic |
24 // difference for typical JBIG2 documents. | 24 // difference for typical JBIG2 documents. |
25 // | 25 // |
26 // Disabled until we can figure out how to clear cache between documents. | 26 // Disabled until we can figure out how to clear cache between documents. |
Lei Zhang
2015/10/06 22:40:24
This should be deleted too.
David Lattimore
2015/10/07 22:41:53
Done.
| |
27 // https://code.google.com/p/pdfium/issues/detail?id=207 | 27 // https://code.google.com/p/pdfium/issues/detail?id=207 |
28 #define DISABLE_SYMBOL_CACHE | |
29 #ifndef DISABLE_SYMBOL_CACHE | 28 #ifndef DISABLE_SYMBOL_CACHE |
Lei Zhang
2015/10/06 22:40:24
Do we still want to keep this then? With a proper
jbreiden
2015/10/07 17:50:17
I'd like to think that we can disable the cache an
Lei Zhang
2015/10/07 17:59:24
No, you can't. Setting it to 0 triggers compiler w
David Lattimore
2015/10/07 22:41:53
Removed DISABLE_SYMBOL_CACHE
Set cache size back
| |
30 static const int kSymbolDictCacheMaxSize = 2; | 29 static const int kSymbolDictCacheMaxSize = 1; |
31 #endif | 30 #endif |
32 | 31 |
33 CJBig2_Context* CJBig2_Context::CreateContext( | 32 CJBig2_Context* CJBig2_Context::CreateContext( |
34 const uint8_t* pGlobalData, | 33 CPDF_StreamAcc* pGlobalStream, |
35 FX_DWORD dwGlobalLength, | 34 CPDF_StreamAcc* pSrcStream, |
36 const uint8_t* pData, | |
37 FX_DWORD dwLength, | |
38 std::list<CJBig2_CachePair>* pSymbolDictCache, | 35 std::list<CJBig2_CachePair>* pSymbolDictCache, |
39 IFX_Pause* pPause) { | 36 IFX_Pause* pPause) { |
40 return new CJBig2_Context(pGlobalData, dwGlobalLength, pData, dwLength, | 37 return new CJBig2_Context(pGlobalStream, pSrcStream, pSymbolDictCache, pPause, |
41 pSymbolDictCache, pPause); | 38 false); |
42 } | 39 } |
43 | 40 |
44 void CJBig2_Context::DestroyContext(CJBig2_Context* pContext) { | 41 void CJBig2_Context::DestroyContext(CJBig2_Context* pContext) { |
45 delete pContext; | 42 delete pContext; |
46 } | 43 } |
47 | 44 |
48 CJBig2_Context::CJBig2_Context(const uint8_t* pGlobalData, | 45 CJBig2_Context::CJBig2_Context(CPDF_StreamAcc* pGlobalStream, |
49 FX_DWORD dwGlobalLength, | 46 CPDF_StreamAcc* pSrcStream, |
50 const uint8_t* pData, | |
51 FX_DWORD dwLength, | |
52 std::list<CJBig2_CachePair>* pSymbolDictCache, | 47 std::list<CJBig2_CachePair>* pSymbolDictCache, |
53 IFX_Pause* pPause) | 48 IFX_Pause* pPause, |
49 bool isGlobal) | |
54 : m_nSegmentDecoded(0), | 50 : m_nSegmentDecoded(0), |
55 m_bInPage(false), | 51 m_bInPage(false), |
56 m_bBufSpecified(false), | 52 m_bBufSpecified(false), |
57 m_PauseStep(10), | 53 m_PauseStep(10), |
58 m_pPause(pPause), | 54 m_pPause(pPause), |
59 m_ProcessingStatus(FXCODEC_STATUS_FRAME_READY), | 55 m_ProcessingStatus(FXCODEC_STATUS_FRAME_READY), |
60 m_pArithDecoder(NULL), | 56 m_pArithDecoder(NULL), |
61 m_gbContext(NULL), | 57 m_gbContext(NULL), |
62 m_dwOffset(0), | 58 m_dwOffset(0), |
63 m_pSymbolDictCache(pSymbolDictCache) { | 59 m_pSymbolDictCache(pSymbolDictCache), |
64 if (pGlobalData && (dwGlobalLength > 0)) { | 60 m_IsGlobal(isGlobal) { |
65 m_pGlobalContext = new CJBig2_Context( | 61 if (pGlobalStream && (pGlobalStream->GetSize() > 0)) { |
66 nullptr, 0, pGlobalData, dwGlobalLength, pSymbolDictCache, pPause); | 62 m_pGlobalContext = |
63 new CJBig2_Context(NULL, pGlobalStream, pSymbolDictCache, pPause, true); | |
67 } else { | 64 } else { |
68 m_pGlobalContext = nullptr; | 65 m_pGlobalContext = nullptr; |
69 } | 66 } |
70 | 67 |
71 m_pStream.reset(new CJBig2_BitStream(pData, dwLength)); | 68 m_pStream.reset(new CJBig2_BitStream(pSrcStream)); |
72 } | 69 } |
73 | 70 |
74 CJBig2_Context::~CJBig2_Context() { | 71 CJBig2_Context::~CJBig2_Context() { |
75 delete m_pArithDecoder; | 72 delete m_pArithDecoder; |
76 m_pArithDecoder = NULL; | 73 m_pArithDecoder = NULL; |
77 FX_Free(m_gbContext); | 74 FX_Free(m_gbContext); |
78 m_gbContext = NULL; | 75 m_gbContext = NULL; |
79 delete m_pGlobalContext; | 76 delete m_pGlobalContext; |
80 m_pGlobalContext = NULL; | 77 m_pGlobalContext = NULL; |
81 } | 78 } |
(...skipping 236 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
318 return JBIG2_ERROR_TOO_SHORT; | 315 return JBIG2_ERROR_TOO_SHORT; |
319 pSegment->m_dwPage_association = cTemp; | 316 pSegment->m_dwPage_association = cTemp; |
320 } else { | 317 } else { |
321 if (m_pStream->readInteger(&pSegment->m_dwPage_association) != 0) { | 318 if (m_pStream->readInteger(&pSegment->m_dwPage_association) != 0) { |
322 return JBIG2_ERROR_TOO_SHORT; | 319 return JBIG2_ERROR_TOO_SHORT; |
323 } | 320 } |
324 } | 321 } |
325 if (m_pStream->readInteger(&pSegment->m_dwData_length) != 0) | 322 if (m_pStream->readInteger(&pSegment->m_dwData_length) != 0) |
326 return JBIG2_ERROR_TOO_SHORT; | 323 return JBIG2_ERROR_TOO_SHORT; |
327 | 324 |
328 pSegment->m_pData = m_pStream->getPointer(); | 325 pSegment->m_dwObjNum = m_pStream->getObjNum(); |
326 pSegment->m_dwDataOffset = m_pStream->getOffset(); | |
329 pSegment->m_State = JBIG2_SEGMENT_DATA_UNPARSED; | 327 pSegment->m_State = JBIG2_SEGMENT_DATA_UNPARSED; |
330 return JBIG2_SUCCESS; | 328 return JBIG2_SUCCESS; |
331 } | 329 } |
332 | 330 |
333 int32_t CJBig2_Context::parseSegmentData(CJBig2_Segment* pSegment, | 331 int32_t CJBig2_Context::parseSegmentData(CJBig2_Segment* pSegment, |
334 IFX_Pause* pPause) { | 332 IFX_Pause* pPause) { |
335 int32_t ret = ProcessingParseSegmentData(pSegment, pPause); | 333 int32_t ret = ProcessingParseSegmentData(pSegment, pPause); |
336 while (m_ProcessingStatus == FXCODEC_STATUS_DECODE_TOBECONTINUE && | 334 while (m_ProcessingStatus == FXCODEC_STATUS_DECODE_TOBECONTINUE && |
337 m_pStream->getByteLeft() > 0) { | 335 m_pStream->getByteLeft() > 0) { |
338 ret = ProcessingParseSegmentData(pSegment, pPause); | 336 ret = ProcessingParseSegmentData(pSegment, pPause); |
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
438 CJBig2_HuffmanTable* Table_B5 = nullptr; | 436 CJBig2_HuffmanTable* Table_B5 = nullptr; |
439 int32_t i, nIndex, nRet; | 437 int32_t i, nIndex, nRet; |
440 CJBig2_Segment* pSeg = nullptr; | 438 CJBig2_Segment* pSeg = nullptr; |
441 CJBig2_Segment* pLRSeg = nullptr; | 439 CJBig2_Segment* pLRSeg = nullptr; |
442 FX_BOOL bUsed; | 440 FX_BOOL bUsed; |
443 CJBig2_Image** SDINSYMS = nullptr; | 441 CJBig2_Image** SDINSYMS = nullptr; |
444 JBig2ArithCtx* gbContext = nullptr; | 442 JBig2ArithCtx* gbContext = nullptr; |
445 JBig2ArithCtx* grContext = nullptr; | 443 JBig2ArithCtx* grContext = nullptr; |
446 CJBig2_ArithDecoder* pArithDecoder; | 444 CJBig2_ArithDecoder* pArithDecoder; |
447 CJBig2_SDDProc* pSymbolDictDecoder = new CJBig2_SDDProc(); | 445 CJBig2_SDDProc* pSymbolDictDecoder = new CJBig2_SDDProc(); |
448 const uint8_t* key = pSegment->m_pData; | 446 CJBig2_CacheKey key = |
447 CJBig2_CacheKey(pSegment->m_dwObjNum, pSegment->m_dwDataOffset); | |
449 FX_BOOL cache_hit = false; | 448 FX_BOOL cache_hit = false; |
450 if (m_pStream->readShortInteger(&wFlags) != 0) { | 449 if (m_pStream->readShortInteger(&wFlags) != 0) { |
451 nRet = JBIG2_ERROR_TOO_SHORT; | 450 nRet = JBIG2_ERROR_TOO_SHORT; |
452 goto failed; | 451 goto failed; |
453 } | 452 } |
454 pSymbolDictDecoder->SDHUFF = wFlags & 0x0001; | 453 pSymbolDictDecoder->SDHUFF = wFlags & 0x0001; |
455 pSymbolDictDecoder->SDREFAGG = (wFlags >> 1) & 0x0001; | 454 pSymbolDictDecoder->SDREFAGG = (wFlags >> 1) & 0x0001; |
456 pSymbolDictDecoder->SDTEMPLATE = (wFlags >> 10) & 0x0003; | 455 pSymbolDictDecoder->SDTEMPLATE = (wFlags >> 10) & 0x0003; |
457 pSymbolDictDecoder->SDRTEMPLATE = (wFlags >> 12) & 0x0003; | 456 pSymbolDictDecoder->SDRTEMPLATE = (wFlags >> 12) & 0x0003; |
458 cSDHUFFDH = (wFlags >> 2) & 0x0003; | 457 cSDHUFFDH = (wFlags >> 2) & 0x0003; |
(...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
616 gbContext = FX_Alloc(JBig2ArithCtx, dwTemp); | 615 gbContext = FX_Alloc(JBig2ArithCtx, dwTemp); |
617 JBIG2_memset(gbContext, 0, sizeof(JBig2ArithCtx) * dwTemp); | 616 JBIG2_memset(gbContext, 0, sizeof(JBig2ArithCtx) * dwTemp); |
618 } | 617 } |
619 if (pSymbolDictDecoder->SDREFAGG == 1) { | 618 if (pSymbolDictDecoder->SDREFAGG == 1) { |
620 dwTemp = pSymbolDictDecoder->SDRTEMPLATE ? 1 << 10 : 1 << 13; | 619 dwTemp = pSymbolDictDecoder->SDRTEMPLATE ? 1 << 10 : 1 << 13; |
621 grContext = FX_Alloc(JBig2ArithCtx, dwTemp); | 620 grContext = FX_Alloc(JBig2ArithCtx, dwTemp); |
622 JBIG2_memset(grContext, 0, sizeof(JBig2ArithCtx) * dwTemp); | 621 JBIG2_memset(grContext, 0, sizeof(JBig2ArithCtx) * dwTemp); |
623 } | 622 } |
624 } | 623 } |
625 pSegment->m_nResultType = JBIG2_SYMBOL_DICT_POINTER; | 624 pSegment->m_nResultType = JBIG2_SYMBOL_DICT_POINTER; |
626 for (std::list<CJBig2_CachePair>::iterator it = m_pSymbolDictCache->begin(); | 625 if (m_IsGlobal) { |
627 it != m_pSymbolDictCache->end(); ++it) { | 626 for (std::list<CJBig2_CachePair>::iterator it = m_pSymbolDictCache->begin(); |
Lei Zhang
2015/10/06 22:40:24
You can probaby use auto here.
David Lattimore
2015/10/07 22:41:53
Done.
| |
628 if (it->first == key) { | 627 it != m_pSymbolDictCache->end(); ++it) { |
629 nonstd::unique_ptr<CJBig2_SymbolDict> copy(it->second->DeepCopy()); | 628 if (it->first == key) { |
630 pSegment->m_Result.sd = copy.release(); | 629 nonstd::unique_ptr<CJBig2_SymbolDict> copy(it->second->DeepCopy()); |
631 m_pSymbolDictCache->push_front(*it); | 630 pSegment->m_Result.sd = copy.release(); |
632 m_pSymbolDictCache->erase(it); | 631 m_pSymbolDictCache->push_front(*it); |
633 cache_hit = true; | 632 m_pSymbolDictCache->erase(it); |
634 break; | 633 cache_hit = true; |
634 break; | |
635 } | |
635 } | 636 } |
636 } | 637 } |
637 if (!cache_hit) { | 638 if (!cache_hit) { |
638 if (pSymbolDictDecoder->SDHUFF == 0) { | 639 if (pSymbolDictDecoder->SDHUFF == 0) { |
639 pArithDecoder = new CJBig2_ArithDecoder(m_pStream.get()); | 640 pArithDecoder = new CJBig2_ArithDecoder(m_pStream.get()); |
640 pSegment->m_Result.sd = | 641 pSegment->m_Result.sd = |
641 pSymbolDictDecoder->decode_Arith(pArithDecoder, gbContext, grContext); | 642 pSymbolDictDecoder->decode_Arith(pArithDecoder, gbContext, grContext); |
642 delete pArithDecoder; | 643 delete pArithDecoder; |
643 if (pSegment->m_Result.sd == NULL) { | 644 if (pSegment->m_Result.sd == NULL) { |
644 nRet = JBIG2_ERROR_FATAL; | 645 nRet = JBIG2_ERROR_FATAL; |
645 goto failed; | 646 goto failed; |
646 } | 647 } |
647 m_pStream->alignByte(); | 648 m_pStream->alignByte(); |
648 m_pStream->offset(2); | 649 m_pStream->offset(2); |
649 } else { | 650 } else { |
650 pSegment->m_Result.sd = pSymbolDictDecoder->decode_Huffman( | 651 pSegment->m_Result.sd = pSymbolDictDecoder->decode_Huffman( |
651 m_pStream.get(), gbContext, grContext, pPause); | 652 m_pStream.get(), gbContext, grContext, pPause); |
652 if (pSegment->m_Result.sd == NULL) { | 653 if (pSegment->m_Result.sd == NULL) { |
653 nRet = JBIG2_ERROR_FATAL; | 654 nRet = JBIG2_ERROR_FATAL; |
654 goto failed; | 655 goto failed; |
655 } | 656 } |
656 m_pStream->alignByte(); | 657 m_pStream->alignByte(); |
657 } | 658 } |
658 #ifndef DISABLE_SYMBOL_CACHE | 659 #ifndef DISABLE_SYMBOL_CACHE |
jbreiden
2015/10/07 17:50:17
not sure why we have the ifdef
Lei Zhang
2015/10/07 17:59:24
Because the compiler sees a constant with a value
jbreiden
2015/10/07 19:22:51
Something seems wrong when a compiler pushes us to
Lei Zhang
2015/10/07 19:31:59
I agree Clang behaved unexpectedly in this case. I
David Lattimore
2015/10/07 22:41:53
Done.
| |
659 nonstd::unique_ptr<CJBig2_SymbolDict> value = | 660 if (m_IsGlobal && kSymbolDictCacheMaxSize > 0) { |
660 pSegment->m_Result.sd->DeepCopy(); | 661 nonstd::unique_ptr<CJBig2_SymbolDict> value = |
661 if (value && kSymbolDictCacheMaxSize > 0) { | 662 pSegment->m_Result.sd->DeepCopy(); |
662 while (m_pSymbolDictCache->size() >= kSymbolDictCacheMaxSize) { | 663 if (value) { |
663 delete m_pSymbolDictCache->back().second; | 664 while (m_pSymbolDictCache->size() >= kSymbolDictCacheMaxSize) { |
664 m_pSymbolDictCache->pop_back(); | 665 delete m_pSymbolDictCache->back().second; |
666 m_pSymbolDictCache->pop_back(); | |
667 } | |
668 m_pSymbolDictCache->push_front(CJBig2_CachePair(key, value.release())); | |
665 } | 669 } |
666 m_pSymbolDictCache->push_front(CJBig2_CachePair(key, value.release())); | |
667 } | 670 } |
668 #endif | 671 #endif |
669 } | 672 } |
670 if (wFlags & 0x0200) { | 673 if (wFlags & 0x0200) { |
671 pSegment->m_Result.sd->m_bContextRetained = TRUE; | 674 pSegment->m_Result.sd->m_bContextRetained = TRUE; |
672 if (pSymbolDictDecoder->SDHUFF == 0) { | 675 if (pSymbolDictDecoder->SDHUFF == 0) { |
673 pSegment->m_Result.sd->m_gbContext = gbContext; | 676 pSegment->m_Result.sd->m_gbContext = gbContext; |
674 } | 677 } |
675 if (pSymbolDictDecoder->SDREFAGG == 1) { | 678 if (pSymbolDictDecoder->SDREFAGG == 1) { |
676 pSegment->m_Result.sd->m_grContext = grContext; | 679 pSegment->m_Result.sd->m_grContext = grContext; |
(...skipping 902 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1579 SBSYMCODES[CURTEMP].code = CURCODE; | 1582 SBSYMCODES[CURTEMP].code = CURCODE; |
1580 CURCODE = CURCODE + 1; | 1583 CURCODE = CURCODE + 1; |
1581 } | 1584 } |
1582 CURTEMP = CURTEMP + 1; | 1585 CURTEMP = CURTEMP + 1; |
1583 } | 1586 } |
1584 CURLEN = CURLEN + 1; | 1587 CURLEN = CURLEN + 1; |
1585 } | 1588 } |
1586 FX_Free(LENCOUNT); | 1589 FX_Free(LENCOUNT); |
1587 FX_Free(FIRSTCODE); | 1590 FX_Free(FIRSTCODE); |
1588 } | 1591 } |
OLD | NEW |