diff options
author | Dan Sinclair <dsinclair@chromium.org> | 2016-03-14 13:35:12 -0400 |
---|---|---|
committer | Dan Sinclair <dsinclair@chromium.org> | 2016-03-14 13:35:12 -0400 |
commit | 764ec513eecbebd12781bcc96ce81ed5e736ee92 (patch) | |
tree | 12763fde4be1f10ea1183d92185917b2b587e00b /core/fxcodec/jbig2 | |
parent | 97da97662417085774f75c26e535c6fbe70266ae (diff) | |
download | pdfium-764ec513eecbebd12781bcc96ce81ed5e736ee92.tar.xz |
Move core/src/ up to core/.
This CL moves the core/src/ files up to core/ and fixes up the include guards,
includes and build files.
R=tsepez@chromium.org
Review URL: https://codereview.chromium.org/1800523005 .
Diffstat (limited to 'core/fxcodec/jbig2')
38 files changed, 7523 insertions, 0 deletions
diff --git a/core/fxcodec/jbig2/JBig2_ArithDecoder.cpp b/core/fxcodec/jbig2/JBig2_ArithDecoder.cpp new file mode 100644 index 0000000000..1673110c7e --- /dev/null +++ b/core/fxcodec/jbig2/JBig2_ArithDecoder.cpp @@ -0,0 +1,120 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "core/fxcodec/jbig2/JBig2_ArithDecoder.h" + +#include "core/fxcodec/jbig2/JBig2_BitStream.h" +#include "core/include/fxcrt/fx_basic.h" + +namespace { + +struct JBig2ArithQe { + unsigned int Qe; + unsigned int NMPS; + unsigned int NLPS; + unsigned int nSwitch; +}; + +const JBig2ArithQe kQeTable[] = { + // Stupid hack to keep clang-format from reformatting this badly. + {0x5601, 1, 1, 1}, {0x3401, 2, 6, 0}, {0x1801, 3, 9, 0}, + {0x0AC1, 4, 12, 0}, {0x0521, 5, 29, 0}, {0x0221, 38, 33, 0}, + {0x5601, 7, 6, 1}, {0x5401, 8, 14, 0}, {0x4801, 9, 14, 0}, + {0x3801, 10, 14, 0}, {0x3001, 11, 17, 0}, {0x2401, 12, 18, 0}, + {0x1C01, 13, 20, 0}, {0x1601, 29, 21, 0}, {0x5601, 15, 14, 1}, + {0x5401, 16, 14, 0}, {0x5101, 17, 15, 0}, {0x4801, 18, 16, 0}, + {0x3801, 19, 17, 0}, {0x3401, 20, 18, 0}, {0x3001, 21, 19, 0}, + {0x2801, 22, 19, 0}, {0x2401, 23, 20, 0}, {0x2201, 24, 21, 0}, + {0x1C01, 25, 22, 0}, {0x1801, 26, 23, 0}, {0x1601, 27, 24, 0}, + {0x1401, 28, 25, 0}, {0x1201, 29, 26, 0}, {0x1101, 30, 27, 0}, + {0x0AC1, 31, 28, 0}, {0x09C1, 32, 29, 0}, {0x08A1, 33, 30, 0}, + {0x0521, 34, 31, 0}, {0x0441, 35, 32, 0}, {0x02A1, 36, 33, 0}, + {0x0221, 37, 34, 0}, {0x0141, 38, 35, 0}, {0x0111, 39, 36, 0}, + {0x0085, 40, 37, 0}, {0x0049, 41, 38, 0}, {0x0025, 42, 39, 0}, + {0x0015, 43, 40, 0}, {0x0009, 44, 41, 0}, {0x0005, 45, 42, 0}, + {0x0001, 45, 43, 0}, {0x5601, 46, 46, 0}}; + +const unsigned int kDefaultAValue = 0x8000; + +int DecodeNMPS(JBig2ArithCtx* pCX, const JBig2ArithQe& qe) { + pCX->I = qe.NMPS; + return pCX->MPS; +} + +int DecodeNLPS(JBig2ArithCtx* pCX, const JBig2ArithQe& qe) { + // TODO(thestig): |D|, |MPS| and friends probably should be booleans. + int D = 1 - pCX->MPS; + if (qe.nSwitch == 1) + pCX->MPS = 1 - pCX->MPS; + pCX->I = qe.NLPS; + return D; +} + +} // namespace + +CJBig2_ArithDecoder::CJBig2_ArithDecoder(CJBig2_BitStream* pStream) + : m_pStream(pStream) { + m_B = m_pStream->getCurByte_arith(); + m_C = (m_B ^ 0xff) << 16; + BYTEIN(); + m_C = m_C << 7; + m_CT = m_CT - 7; + m_A = kDefaultAValue; +} + +CJBig2_ArithDecoder::~CJBig2_ArithDecoder() {} + +int CJBig2_ArithDecoder::DECODE(JBig2ArithCtx* pCX) { + if (!pCX || pCX->I >= FX_ArraySize(kQeTable)) + return 0; + + const JBig2ArithQe& qe = kQeTable[pCX->I]; + m_A -= qe.Qe; + if ((m_C >> 16) < m_A) { + if (m_A & kDefaultAValue) + return pCX->MPS; + + const int D = m_A < qe.Qe ? DecodeNLPS(pCX, qe) : DecodeNMPS(pCX, qe); + ReadValueA(); + return D; + } + + m_C -= m_A << 16; + const int D = m_A < qe.Qe ? DecodeNMPS(pCX, qe) : DecodeNLPS(pCX, qe); + m_A = qe.Qe; + ReadValueA(); + return D; +} + +void CJBig2_ArithDecoder::BYTEIN() { + unsigned char B1; + if (m_B == 0xff) { + B1 = m_pStream->getNextByte_arith(); + if (B1 > 0x8f) { + m_CT = 8; + } else { + m_pStream->incByteIdx(); + m_B = B1; + m_C = m_C + 0xfe00 - (m_B << 9); + m_CT = 7; + } + } else { + m_pStream->incByteIdx(); + m_B = m_pStream->getCurByte_arith(); + m_C = m_C + 0xff00 - (m_B << 8); + m_CT = 8; + } +} + +void CJBig2_ArithDecoder::ReadValueA() { + do { + if (m_CT == 0) + BYTEIN(); + m_A <<= 1; + m_C <<= 1; + --m_CT; + } while ((m_A & kDefaultAValue) == 0); +} diff --git a/core/fxcodec/jbig2/JBig2_ArithDecoder.h b/core/fxcodec/jbig2/JBig2_ArithDecoder.h new file mode 100644 index 0000000000..a8ab5dd730 --- /dev/null +++ b/core/fxcodec/jbig2/JBig2_ArithDecoder.h @@ -0,0 +1,38 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#ifndef CORE_FXCODEC_JBIG2_JBIG2_ARITHDECODER_H_ +#define CORE_FXCODEC_JBIG2_JBIG2_ARITHDECODER_H_ + +class CJBig2_BitStream; + +struct JBig2ArithCtx { + JBig2ArithCtx() : MPS(0), I(0) {} + + unsigned int MPS; + unsigned int I; +}; + +class CJBig2_ArithDecoder { + public: + explicit CJBig2_ArithDecoder(CJBig2_BitStream* pStream); + + ~CJBig2_ArithDecoder(); + + int DECODE(JBig2ArithCtx* pCX); + + private: + void BYTEIN(); + void ReadValueA(); + + unsigned char m_B; + unsigned int m_C; + unsigned int m_A; + unsigned int m_CT; + CJBig2_BitStream* const m_pStream; +}; + +#endif // CORE_FXCODEC_JBIG2_JBIG2_ARITHDECODER_H_ diff --git a/core/fxcodec/jbig2/JBig2_ArithIntDecoder.cpp b/core/fxcodec/jbig2/JBig2_ArithIntDecoder.cpp new file mode 100644 index 0000000000..63594672c7 --- /dev/null +++ b/core/fxcodec/jbig2/JBig2_ArithIntDecoder.cpp @@ -0,0 +1,92 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "core/fxcodec/jbig2/JBig2_ArithIntDecoder.h" + +#include <vector> + +#include "core/include/fxcrt/fx_basic.h" + +namespace { + +int ShiftOr(int val, int bitwise_or_val) { + return (val << 1) | bitwise_or_val; +} + +const struct ArithIntDecodeData { + int nNeedBits; + int nValue; +} g_ArithIntDecodeData[] = { + {2, 0}, {4, 4}, {6, 20}, {8, 84}, {12, 340}, {32, 4436}, +}; + +size_t RecursiveDecode(CJBig2_ArithDecoder* decoder, + std::vector<JBig2ArithCtx>* context, + int* prev, + size_t depth) { + static const size_t kDepthEnd = FX_ArraySize(g_ArithIntDecodeData) - 1; + if (depth == kDepthEnd) + return kDepthEnd; + + JBig2ArithCtx* pCX = &(*context)[*prev]; + int D = decoder->DECODE(pCX); + *prev = ShiftOr(*prev, D); + if (!D) + return depth; + return RecursiveDecode(decoder, context, prev, depth + 1); +} + +} // namespace + +CJBig2_ArithIntDecoder::CJBig2_ArithIntDecoder() { + m_IAx.resize(512); +} + +CJBig2_ArithIntDecoder::~CJBig2_ArithIntDecoder() {} + +bool CJBig2_ArithIntDecoder::decode(CJBig2_ArithDecoder* pArithDecoder, + int* nResult) { + int PREV = 1; + const int S = pArithDecoder->DECODE(&m_IAx[PREV]); + PREV = ShiftOr(PREV, S); + + const size_t nDecodeDataIndex = + RecursiveDecode(pArithDecoder, &m_IAx, &PREV, 0); + + int nTemp = 0; + for (int i = 0; i < g_ArithIntDecodeData[nDecodeDataIndex].nNeedBits; ++i) { + int D = pArithDecoder->DECODE(&m_IAx[PREV]); + PREV = ShiftOr(PREV, D); + if (PREV >= 256) + PREV = (PREV & 511) | 256; + nTemp = ShiftOr(nTemp, D); + } + int nValue = g_ArithIntDecodeData[nDecodeDataIndex].nValue; + nValue += nTemp; + if (S == 1 && nValue > 0) + nValue = -nValue; + + *nResult = nValue; + return S != 1 || nValue != 0; +} + +CJBig2_ArithIaidDecoder::CJBig2_ArithIaidDecoder(unsigned char SBSYMCODELENA) + : SBSYMCODELEN(SBSYMCODELENA) { + m_IAID.resize(1 << SBSYMCODELEN); +} + +CJBig2_ArithIaidDecoder::~CJBig2_ArithIaidDecoder() {} + +void CJBig2_ArithIaidDecoder::decode(CJBig2_ArithDecoder* pArithDecoder, + FX_DWORD* nResult) { + int PREV = 1; + for (unsigned char i = 0; i < SBSYMCODELEN; ++i) { + JBig2ArithCtx* pCX = &m_IAID[PREV]; + int D = pArithDecoder->DECODE(pCX); + PREV = ShiftOr(PREV, D); + } + *nResult = PREV - (1 << SBSYMCODELEN); +} diff --git a/core/fxcodec/jbig2/JBig2_ArithIntDecoder.h b/core/fxcodec/jbig2/JBig2_ArithIntDecoder.h new file mode 100644 index 0000000000..9a04504ca7 --- /dev/null +++ b/core/fxcodec/jbig2/JBig2_ArithIntDecoder.h @@ -0,0 +1,41 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#ifndef CORE_FXCODEC_JBIG2_JBIG2_ARITHINTDECODER_H_ +#define CORE_FXCODEC_JBIG2_JBIG2_ARITHINTDECODER_H_ + +#include <vector> + +#include "core/fxcodec/jbig2/JBig2_ArithDecoder.h" +#include "core/include/fxcrt/fx_system.h" + +class CJBig2_ArithIntDecoder { + public: + CJBig2_ArithIntDecoder(); + ~CJBig2_ArithIntDecoder(); + + // Returns true on success, and false when an OOB condition occurs. Many + // callers can tolerate OOB and do not check the return value. + bool decode(CJBig2_ArithDecoder* pArithDecoder, int* nResult); + + private: + std::vector<JBig2ArithCtx> m_IAx; +}; + +class CJBig2_ArithIaidDecoder { + public: + explicit CJBig2_ArithIaidDecoder(unsigned char SBSYMCODELENA); + ~CJBig2_ArithIaidDecoder(); + + void decode(CJBig2_ArithDecoder* pArithDecoder, FX_DWORD* nResult); + + private: + std::vector<JBig2ArithCtx> m_IAID; + + const unsigned char SBSYMCODELEN; +}; + +#endif // CORE_FXCODEC_JBIG2_JBIG2_ARITHINTDECODER_H_ diff --git a/core/fxcodec/jbig2/JBig2_BitStream.cpp b/core/fxcodec/jbig2/JBig2_BitStream.cpp new file mode 100644 index 0000000000..87451c2d72 --- /dev/null +++ b/core/fxcodec/jbig2/JBig2_BitStream.cpp @@ -0,0 +1,188 @@ +// Copyright 2015 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "core/fxcodec/jbig2/JBig2_BitStream.h" + +#include <algorithm> + +#include "core/include/fpdfapi/cpdf_stream.h" + +CJBig2_BitStream::CJBig2_BitStream(CPDF_StreamAcc* pSrcStream) + : m_pBuf(pSrcStream->GetData()), + m_dwLength(pSrcStream->GetSize()), + m_dwByteIdx(0), + m_dwBitIdx(0), + m_dwObjNum(pSrcStream->GetStream() ? pSrcStream->GetStream()->GetObjNum() + : 0) { + if (m_dwLength > 256 * 1024 * 1024) { + m_dwLength = 0; + m_pBuf = nullptr; + } +} + +CJBig2_BitStream::~CJBig2_BitStream() {} + +int32_t CJBig2_BitStream::readNBits(FX_DWORD dwBits, FX_DWORD* dwResult) { + FX_DWORD dwBitPos = getBitPos(); + if (dwBitPos > LengthInBits()) + return -1; + + *dwResult = 0; + if (dwBitPos + dwBits <= LengthInBits()) + dwBitPos = dwBits; + else + dwBitPos = LengthInBits() - dwBitPos; + + for (; dwBitPos > 0; --dwBitPos) { + *dwResult = + (*dwResult << 1) | ((m_pBuf[m_dwByteIdx] >> (7 - m_dwBitIdx)) & 0x01); + AdvanceBit(); + } + return 0; +} + +int32_t CJBig2_BitStream::readNBits(FX_DWORD dwBits, int32_t* nResult) { + FX_DWORD dwBitPos = getBitPos(); + if (dwBitPos > LengthInBits()) + return -1; + + *nResult = 0; + if (dwBitPos + dwBits <= LengthInBits()) + dwBitPos = dwBits; + else + dwBitPos = LengthInBits() - dwBitPos; + + for (; dwBitPos > 0; --dwBitPos) { + *nResult = + (*nResult << 1) | ((m_pBuf[m_dwByteIdx] >> (7 - m_dwBitIdx)) & 0x01); + AdvanceBit(); + } + return 0; +} + +int32_t CJBig2_BitStream::read1Bit(FX_DWORD* dwResult) { + if (!IsInBound()) + return -1; + + *dwResult = (m_pBuf[m_dwByteIdx] >> (7 - m_dwBitIdx)) & 0x01; + AdvanceBit(); + return 0; +} + +int32_t CJBig2_BitStream::read1Bit(FX_BOOL* bResult) { + if (!IsInBound()) + return -1; + + *bResult = (m_pBuf[m_dwByteIdx] >> (7 - m_dwBitIdx)) & 0x01; + AdvanceBit(); + return 0; +} + +int32_t CJBig2_BitStream::read1Byte(uint8_t* cResult) { + if (!IsInBound()) + return -1; + + *cResult = m_pBuf[m_dwByteIdx]; + ++m_dwByteIdx; + return 0; +} + +int32_t CJBig2_BitStream::readInteger(FX_DWORD* dwResult) { + if (m_dwByteIdx + 3 >= m_dwLength) + return -1; + + *dwResult = (m_pBuf[m_dwByteIdx] << 24) | (m_pBuf[m_dwByteIdx + 1] << 16) | + (m_pBuf[m_dwByteIdx + 2] << 8) | m_pBuf[m_dwByteIdx + 3]; + m_dwByteIdx += 4; + return 0; +} + +int32_t CJBig2_BitStream::readShortInteger(FX_WORD* dwResult) { + if (m_dwByteIdx + 1 >= m_dwLength) + return -1; + + *dwResult = (m_pBuf[m_dwByteIdx] << 8) | m_pBuf[m_dwByteIdx + 1]; + m_dwByteIdx += 2; + return 0; +} + +void CJBig2_BitStream::alignByte() { + if (m_dwBitIdx != 0) { + ++m_dwByteIdx; + m_dwBitIdx = 0; + } +} + +uint8_t CJBig2_BitStream::getCurByte() const { + return IsInBound() ? m_pBuf[m_dwByteIdx] : 0; +} + +void CJBig2_BitStream::incByteIdx() { + if (IsInBound()) + ++m_dwByteIdx; +} + +uint8_t CJBig2_BitStream::getCurByte_arith() const { + return IsInBound() ? m_pBuf[m_dwByteIdx] : 0xFF; +} + +uint8_t CJBig2_BitStream::getNextByte_arith() const { + return m_dwByteIdx + 1 < m_dwLength ? m_pBuf[m_dwByteIdx + 1] : 0xFF; +} + +FX_DWORD CJBig2_BitStream::getOffset() const { + return m_dwByteIdx; +} + +void CJBig2_BitStream::setOffset(FX_DWORD dwOffset) { + m_dwByteIdx = std::min(dwOffset, m_dwLength); +} + +FX_DWORD CJBig2_BitStream::getBitPos() const { + return (m_dwByteIdx << 3) + m_dwBitIdx; +} + +void CJBig2_BitStream::setBitPos(FX_DWORD dwBitPos) { + m_dwByteIdx = dwBitPos >> 3; + m_dwBitIdx = dwBitPos & 7; +} + +const uint8_t* CJBig2_BitStream::getBuf() const { + return m_pBuf; +} + +const uint8_t* CJBig2_BitStream::getPointer() const { + return m_pBuf + m_dwByteIdx; +} + +void CJBig2_BitStream::offset(FX_DWORD dwOffset) { + m_dwByteIdx += dwOffset; +} + +FX_DWORD CJBig2_BitStream::getByteLeft() const { + return m_dwLength - m_dwByteIdx; +} + +void CJBig2_BitStream::AdvanceBit() { + if (m_dwBitIdx == 7) { + ++m_dwByteIdx; + m_dwBitIdx = 0; + } else { + ++m_dwBitIdx; + } +} + +bool CJBig2_BitStream::IsInBound() const { + return m_dwByteIdx < m_dwLength; +} + +FX_DWORD CJBig2_BitStream::LengthInBits() const { + return m_dwLength << 3; +} + +FX_DWORD CJBig2_BitStream::getObjNum() const { + return m_dwObjNum; +} diff --git a/core/fxcodec/jbig2/JBig2_BitStream.h b/core/fxcodec/jbig2/JBig2_BitStream.h new file mode 100644 index 0000000000..c24fedfba1 --- /dev/null +++ b/core/fxcodec/jbig2/JBig2_BitStream.h @@ -0,0 +1,58 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#ifndef CORE_FXCODEC_JBIG2_JBIG2_BITSTREAM_H_ +#define CORE_FXCODEC_JBIG2_JBIG2_BITSTREAM_H_ + +#include "core/include/fxcrt/fx_basic.h" + +class CPDF_StreamAcc; + +class CJBig2_BitStream { + public: + explicit CJBig2_BitStream(CPDF_StreamAcc* pSrcStream); + ~CJBig2_BitStream(); + + // TODO(thestig): readFoo() should return bool. + int32_t readNBits(FX_DWORD nBits, FX_DWORD* dwResult); + int32_t readNBits(FX_DWORD nBits, int32_t* nResult); + int32_t read1Bit(FX_DWORD* dwResult); + int32_t read1Bit(FX_BOOL* bResult); + int32_t read1Byte(uint8_t* cResult); + int32_t readInteger(FX_DWORD* dwResult); + int32_t readShortInteger(FX_WORD* wResult); + void alignByte(); + uint8_t getCurByte() const; + void incByteIdx(); + uint8_t getCurByte_arith() const; + uint8_t getNextByte_arith() const; + FX_DWORD getOffset() const; + void setOffset(FX_DWORD dwOffset); + FX_DWORD getBitPos() const; + void setBitPos(FX_DWORD dwBitPos); + const uint8_t* getBuf() const; + FX_DWORD getLength() const { return m_dwLength; } + const uint8_t* getPointer() const; + void offset(FX_DWORD dwOffset); + FX_DWORD getByteLeft() const; + FX_DWORD getObjNum() const; + + private: + void AdvanceBit(); + bool IsInBound() const; + FX_DWORD LengthInBits() const; + + const uint8_t* m_pBuf; + FX_DWORD m_dwLength; + FX_DWORD m_dwByteIdx; + FX_DWORD m_dwBitIdx; + const FX_DWORD m_dwObjNum; + + CJBig2_BitStream(const CJBig2_BitStream&) = delete; + void operator=(const CJBig2_BitStream&) = delete; +}; + +#endif // CORE_FXCODEC_JBIG2_JBIG2_BITSTREAM_H_ diff --git a/core/fxcodec/jbig2/JBig2_Context.cpp b/core/fxcodec/jbig2/JBig2_Context.cpp new file mode 100644 index 0000000000..0a17fff328 --- /dev/null +++ b/core/fxcodec/jbig2/JBig2_Context.cpp @@ -0,0 +1,1439 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "core/fxcodec/jbig2/JBig2_Context.h" + +#include <algorithm> +#include <list> +#include <utility> +#include <vector> + +#include "core/fxcodec/jbig2/JBig2_ArithDecoder.h" +#include "core/fxcodec/jbig2/JBig2_BitStream.h" +#include "core/fxcodec/jbig2/JBig2_GrdProc.h" +#include "core/fxcodec/jbig2/JBig2_GrrdProc.h" +#include "core/fxcodec/jbig2/JBig2_HtrdProc.h" +#include "core/fxcodec/jbig2/JBig2_HuffmanTable_Standard.h" +#include "core/fxcodec/jbig2/JBig2_PddProc.h" +#include "core/fxcodec/jbig2/JBig2_SddProc.h" +#include "core/fxcodec/jbig2/JBig2_TrdProc.h" +#include "core/include/fpdfapi/cpdf_stream.h" +#include "third_party/base/stl_util.h" + +namespace { + +size_t GetHuffContextSize(uint8_t val) { + return val == 0 ? 65536 : val == 1 ? 8192 : 1024; +} + +size_t GetRefAggContextSize(FX_BOOL val) { + return val ? 1024 : 8192; +} + +} // namespace + +// Implement a very small least recently used (LRU) cache. It is very +// common for a JBIG2 dictionary to span multiple pages in a PDF file, +// and we do not want to decode the same dictionary over and over +// again. We key off of the memory location of the dictionary. The +// list keeps track of the freshness of entries, with freshest ones +// at the front. Even a tiny cache size like 2 makes a dramatic +// difference for typical JBIG2 documents. +static const int kSymbolDictCacheMaxSize = 2; + +CJBig2_Context* CJBig2_Context::CreateContext( + CPDF_StreamAcc* pGlobalStream, + CPDF_StreamAcc* pSrcStream, + std::list<CJBig2_CachePair>* pSymbolDictCache, + IFX_Pause* pPause) { + return new CJBig2_Context(pGlobalStream, pSrcStream, pSymbolDictCache, pPause, + false); +} + +void CJBig2_Context::DestroyContext(CJBig2_Context* pContext) { + delete pContext; +} + +CJBig2_Context::CJBig2_Context(CPDF_StreamAcc* pGlobalStream, + CPDF_StreamAcc* pSrcStream, + std::list<CJBig2_CachePair>* pSymbolDictCache, + IFX_Pause* pPause, + bool bIsGlobal) + : m_nSegmentDecoded(0), + m_bInPage(false), + m_bBufSpecified(false), + m_PauseStep(10), + m_pPause(pPause), + m_ProcessingStatus(FXCODEC_STATUS_FRAME_READY), + m_gbContext(NULL), + m_dwOffset(0), + m_pSymbolDictCache(pSymbolDictCache), + m_bIsGlobal(bIsGlobal) { + if (pGlobalStream && (pGlobalStream->GetSize() > 0)) { + m_pGlobalContext = new CJBig2_Context(nullptr, pGlobalStream, + pSymbolDictCache, pPause, true); + } else { + m_pGlobalContext = nullptr; + } + + m_pStream.reset(new CJBig2_BitStream(pSrcStream)); +} + +CJBig2_Context::~CJBig2_Context() { + FX_Free(m_gbContext); + m_gbContext = NULL; + delete m_pGlobalContext; + m_pGlobalContext = NULL; +} + +int32_t CJBig2_Context::decode_SquentialOrgnazation(IFX_Pause* pPause) { + int32_t nRet; + if (m_pStream->getByteLeft() <= 0) + return JBIG2_END_OF_FILE; + + while (m_pStream->getByteLeft() >= JBIG2_MIN_SEGMENT_SIZE) { + if (!m_pSegment) { + m_pSegment.reset(new CJBig2_Segment); + nRet = parseSegmentHeader(m_pSegment.get()); + if (nRet != JBIG2_SUCCESS) { + m_pSegment.reset(); + return nRet; + } + m_dwOffset = m_pStream->getOffset(); + } + nRet = parseSegmentData(m_pSegment.get(), pPause); + if (m_ProcessingStatus == FXCODEC_STATUS_DECODE_TOBECONTINUE) { + m_ProcessingStatus = FXCODEC_STATUS_DECODE_TOBECONTINUE; + m_PauseStep = 2; + return JBIG2_SUCCESS; + } + if (nRet == JBIG2_END_OF_PAGE || nRet == JBIG2_END_OF_FILE) { + m_pSegment.reset(); + return JBIG2_SUCCESS; + } + if (nRet != JBIG2_SUCCESS) { + m_pSegment.reset(); + return nRet; + } + if (m_pSegment->m_dwData_length != 0xffffffff) { + m_dwOffset += m_pSegment->m_dwData_length; + m_pStream->setOffset(m_dwOffset); + } else { + m_pStream->offset(4); + } + m_SegmentList.push_back(m_pSegment.release()); + if (m_pStream->getByteLeft() > 0 && m_pPage && pPause && + pPause->NeedToPauseNow()) { + m_ProcessingStatus = FXCODEC_STATUS_DECODE_TOBECONTINUE; + m_PauseStep = 2; + return JBIG2_SUCCESS; + } + } + return JBIG2_SUCCESS; +} +int32_t CJBig2_Context::decode_EmbedOrgnazation(IFX_Pause* pPause) { + return decode_SquentialOrgnazation(pPause); +} +int32_t CJBig2_Context::decode_RandomOrgnazation_FirstPage(IFX_Pause* pPause) { + int32_t nRet; + while (m_pStream->getByteLeft() > JBIG2_MIN_SEGMENT_SIZE) { + std::unique_ptr<CJBig2_Segment> pSegment(new CJBig2_Segment); + nRet = parseSegmentHeader(pSegment.get()); + if (nRet != JBIG2_SUCCESS) { + return nRet; + } else if (pSegment->m_cFlags.s.type == 51) { + break; + } + m_SegmentList.push_back(pSegment.release()); + if (pPause && m_pPause && pPause->NeedToPauseNow()) { + m_PauseStep = 3; + m_ProcessingStatus = FXCODEC_STATUS_DECODE_TOBECONTINUE; + return JBIG2_SUCCESS; + } + } + m_nSegmentDecoded = 0; + return decode_RandomOrgnazation(pPause); +} +int32_t CJBig2_Context::decode_RandomOrgnazation(IFX_Pause* pPause) { + for (; m_nSegmentDecoded < m_SegmentList.size(); ++m_nSegmentDecoded) { + int32_t nRet = + parseSegmentData(m_SegmentList.get(m_nSegmentDecoded), pPause); + if (nRet == JBIG2_END_OF_PAGE || nRet == JBIG2_END_OF_FILE) + return JBIG2_SUCCESS; + + if (nRet != JBIG2_SUCCESS) + return nRet; + + if (m_pPage && pPause && pPause->NeedToPauseNow()) { + m_PauseStep = 4; + m_ProcessingStatus = FXCODEC_STATUS_DECODE_TOBECONTINUE; + return JBIG2_SUCCESS; + } + } + return JBIG2_SUCCESS; +} +int32_t CJBig2_Context::getFirstPage(uint8_t* pBuf, + int32_t width, + int32_t height, + int32_t stride, + IFX_Pause* pPause) { + int32_t nRet = 0; + if (m_pGlobalContext) { + nRet = m_pGlobalContext->decode_EmbedOrgnazation(pPause); + if (nRet != JBIG2_SUCCESS) { + m_ProcessingStatus = FXCODEC_STATUS_ERROR; + return nRet; + } + } + m_PauseStep = 0; + m_pPage.reset(new CJBig2_Image(width, height, stride, pBuf)); + m_bBufSpecified = true; + if (pPause && pPause->NeedToPauseNow()) { + m_PauseStep = 1; + m_ProcessingStatus = FXCODEC_STATUS_DECODE_TOBECONTINUE; + return nRet; + } + return Continue(pPause); +} +int32_t CJBig2_Context::Continue(IFX_Pause* pPause) { + m_ProcessingStatus = FXCODEC_STATUS_DECODE_READY; + int32_t nRet; + if (m_PauseStep <= 1) { + nRet = decode_EmbedOrgnazation(pPause); + } else if (m_PauseStep == 2) { + nRet = decode_SquentialOrgnazation(pPause); + } else if (m_PauseStep == 3) { + nRet = decode_RandomOrgnazation_FirstPage(pPause); + } else if (m_PauseStep == 4) { + nRet = decode_RandomOrgnazation(pPause); + } else if (m_PauseStep == 5) { + m_ProcessingStatus = FXCODEC_STATUS_DECODE_FINISH; + return JBIG2_SUCCESS; + } + if (m_ProcessingStatus == FXCODEC_STATUS_DECODE_TOBECONTINUE) { + return nRet; + } + m_PauseStep = 5; + if (!m_bBufSpecified && nRet == JBIG2_SUCCESS) { + m_ProcessingStatus = FXCODEC_STATUS_DECODE_FINISH; + return JBIG2_SUCCESS; + } + if (nRet == JBIG2_SUCCESS) { + m_ProcessingStatus = FXCODEC_STATUS_DECODE_FINISH; + } else { + m_ProcessingStatus = FXCODEC_STATUS_ERROR; + } + return nRet; +} + +CJBig2_Segment* CJBig2_Context::findSegmentByNumber(FX_DWORD dwNumber) { + if (m_pGlobalContext) { + CJBig2_Segment* pSeg = m_pGlobalContext->findSegmentByNumber(dwNumber); + if (pSeg) { + return pSeg; + } + } + for (size_t i = 0; i < m_SegmentList.size(); ++i) { + CJBig2_Segment* pSeg = m_SegmentList.get(i); + if (pSeg->m_dwNumber == dwNumber) { + return pSeg; + } + } + return nullptr; +} +CJBig2_Segment* CJBig2_Context::findReferredSegmentByTypeAndIndex( + CJBig2_Segment* pSegment, + uint8_t cType, + int32_t nIndex) { + int32_t count = 0; + for (int32_t i = 0; i < pSegment->m_nReferred_to_segment_count; ++i) { + CJBig2_Segment* pSeg = + findSegmentByNumber(pSegment->m_pReferred_to_segment_numbers[i]); + if (pSeg && pSeg->m_cFlags.s.type == cType) { + if (count == nIndex) + return pSeg; + ++count; + } + } + return NULL; +} +int32_t CJBig2_Context::parseSegmentHeader(CJBig2_Segment* pSegment) { + if (m_pStream->readInteger(&pSegment->m_dwNumber) != 0 || + m_pStream->read1Byte(&pSegment->m_cFlags.c) != 0) { + return JBIG2_ERROR_TOO_SHORT; + } + + FX_DWORD dwTemp; + uint8_t cTemp = m_pStream->getCurByte(); + if ((cTemp >> 5) == 7) { + if (m_pStream->readInteger( + (FX_DWORD*)&pSegment->m_nReferred_to_segment_count) != 0) { + return JBIG2_ERROR_TOO_SHORT; + } + pSegment->m_nReferred_to_segment_count &= 0x1fffffff; + if (pSegment->m_nReferred_to_segment_count > + JBIG2_MAX_REFERRED_SEGMENT_COUNT) { + return JBIG2_ERROR_LIMIT; + } + dwTemp = 5 + 4 + (pSegment->m_nReferred_to_segment_count + 1) / 8; + } else { + if (m_pStream->read1Byte(&cTemp) != 0) + return JBIG2_ERROR_TOO_SHORT; + + pSegment->m_nReferred_to_segment_count = cTemp >> 5; + dwTemp = 5 + 1; + } + uint8_t cSSize = + pSegment->m_dwNumber > 65536 ? 4 : pSegment->m_dwNumber > 256 ? 2 : 1; + uint8_t cPSize = pSegment->m_cFlags.s.page_association_size ? 4 : 1; + if (pSegment->m_nReferred_to_segment_count) { + pSegment->m_pReferred_to_segment_numbers = + FX_Alloc(FX_DWORD, pSegment->m_nReferred_to_segment_count); + for (int32_t i = 0; i < pSegment->m_nReferred_to_segment_count; ++i) { + switch (cSSize) { + case 1: + if (m_pStream->read1Byte(&cTemp) != 0) + return JBIG2_ERROR_TOO_SHORT; + + pSegment->m_pReferred_to_segment_numbers[i] = cTemp; + break; + case 2: + FX_WORD wTemp; + if (m_pStream->readShortInteger(&wTemp) != 0) + return JBIG2_ERROR_TOO_SHORT; + + pSegment->m_pReferred_to_segment_numbers[i] = wTemp; + break; + case 4: + if (m_pStream->readInteger(&dwTemp) != 0) + return JBIG2_ERROR_TOO_SHORT; + + pSegment->m_pReferred_to_segment_numbers[i] = dwTemp; + break; + } + if (pSegment->m_pReferred_to_segment_numbers[i] >= pSegment->m_dwNumber) + return JBIG2_ERROR_TOO_SHORT; + } + } + if (cPSize == 1) { + if (m_pStream->read1Byte(&cTemp) != 0) + return JBIG2_ERROR_TOO_SHORT; + pSegment->m_dwPage_association = cTemp; + } else { + if (m_pStream->readInteger(&pSegment->m_dwPage_association) != 0) { + return JBIG2_ERROR_TOO_SHORT; + } + } + if (m_pStream->readInteger(&pSegment->m_dwData_length) != 0) + return JBIG2_ERROR_TOO_SHORT; + + pSegment->m_dwObjNum = m_pStream->getObjNum(); + pSegment->m_dwDataOffset = m_pStream->getOffset(); + pSegment->m_State = JBIG2_SEGMENT_DATA_UNPARSED; + return JBIG2_SUCCESS; +} + +int32_t CJBig2_Context::parseSegmentData(CJBig2_Segment* pSegment, + IFX_Pause* pPause) { + int32_t ret = ProcessingParseSegmentData(pSegment, pPause); + while (m_ProcessingStatus == FXCODEC_STATUS_DECODE_TOBECONTINUE && + m_pStream->getByteLeft() > 0) { + ret = ProcessingParseSegmentData(pSegment, pPause); + } + return ret; +} + +int32_t CJBig2_Context::ProcessingParseSegmentData(CJBig2_Segment* pSegment, + IFX_Pause* pPause) { + switch (pSegment->m_cFlags.s.type) { + case 0: + return parseSymbolDict(pSegment, pPause); + case 4: + case 6: + case 7: + if (!m_bInPage) + return JBIG2_ERROR_FATAL; + return parseTextRegion(pSegment); + case 16: + return parsePatternDict(pSegment, pPause); + case 20: + case 22: + case 23: + if (!m_bInPage) + return JBIG2_ERROR_FATAL; + return parseHalftoneRegion(pSegment, pPause); + case 36: + case 38: + case 39: + if (!m_bInPage) + return JBIG2_ERROR_FATAL; + return parseGenericRegion(pSegment, pPause); + case 40: + case 42: + case 43: + if (!m_bInPage) + return JBIG2_ERROR_FATAL; + return parseGenericRefinementRegion(pSegment); + case 48: { + FX_WORD wTemp; + std::unique_ptr<JBig2PageInfo> pPageInfo(new JBig2PageInfo); + if (m_pStream->readInteger(&pPageInfo->m_dwWidth) != 0 || + m_pStream->readInteger(&pPageInfo->m_dwHeight) != 0 || + m_pStream->readInteger(&pPageInfo->m_dwResolutionX) != 0 || + m_pStream->readInteger(&pPageInfo->m_dwResolutionY) != 0 || + m_pStream->read1Byte(&pPageInfo->m_cFlags) != 0 || + m_pStream->readShortInteger(&wTemp) != 0) { + return JBIG2_ERROR_TOO_SHORT; + } + pPageInfo->m_bIsStriped = !!(wTemp & 0x8000); + pPageInfo->m_wMaxStripeSize = wTemp & 0x7fff; + bool bMaxHeight = (pPageInfo->m_dwHeight == 0xffffffff); + if (bMaxHeight && pPageInfo->m_bIsStriped != TRUE) + pPageInfo->m_bIsStriped = TRUE; + + if (!m_bBufSpecified) { + FX_DWORD height = + bMaxHeight ? pPageInfo->m_wMaxStripeSize : pPageInfo->m_dwHeight; + m_pPage.reset(new CJBig2_Image(pPageInfo->m_dwWidth, height)); + } + + if (!m_pPage->m_pData) { + m_ProcessingStatus = FXCODEC_STATUS_ERROR; + return JBIG2_ERROR_TOO_SHORT; + } + + m_pPage->fill((pPageInfo->m_cFlags & 4) ? 1 : 0); + m_PageInfoList.push_back(pPageInfo.release()); + m_bInPage = true; + } break; + case 49: + m_bInPage = false; + return JBIG2_END_OF_PAGE; + break; + case 50: + m_pStream->offset(pSegment->m_dwData_length); + break; + case 51: + return JBIG2_END_OF_FILE; + case 52: + m_pStream->offset(pSegment->m_dwData_length); + break; + case 53: + return parseTable(pSegment); + case 62: + m_pStream->offset(pSegment->m_dwData_length); + break; + default: + break; + } + return JBIG2_SUCCESS; +} + +int32_t CJBig2_Context::parseSymbolDict(CJBig2_Segment* pSegment, + IFX_Pause* pPause) { + FX_WORD wFlags; + if (m_pStream->readShortInteger(&wFlags) != 0) + return JBIG2_ERROR_TOO_SHORT; + + std::unique_ptr<CJBig2_SDDProc> pSymbolDictDecoder(new CJBig2_SDDProc); + pSymbolDictDecoder->SDHUFF = wFlags & 0x0001; + pSymbolDictDecoder->SDREFAGG = (wFlags >> 1) & 0x0001; + pSymbolDictDecoder->SDTEMPLATE = (wFlags >> 10) & 0x0003; + pSymbolDictDecoder->SDRTEMPLATE = (wFlags >> 12) & 0x0003; + uint8_t cSDHUFFDH = (wFlags >> 2) & 0x0003; + uint8_t cSDHUFFDW = (wFlags >> 4) & 0x0003; + uint8_t cSDHUFFBMSIZE = (wFlags >> 6) & 0x0001; + uint8_t cSDHUFFAGGINST = (wFlags >> 7) & 0x0001; + if (pSymbolDictDecoder->SDHUFF == 0) { + const FX_DWORD dwTemp = (pSymbolDictDecoder->SDTEMPLATE == 0) ? 8 : 2; + for (FX_DWORD i = 0; i < dwTemp; ++i) { + if (m_pStream->read1Byte((uint8_t*)&pSymbolDictDecoder->SDAT[i]) != 0) + return JBIG2_ERROR_TOO_SHORT; + } + } + if (pSymbolDictDecoder->SDREFAGG == 1 && + pSymbolDictDecoder->SDRTEMPLATE == 0) { + for (int32_t i = 0; i < 4; ++i) { + if (m_pStream->read1Byte((uint8_t*)&pSymbolDictDecoder->SDRAT[i]) != 0) + return JBIG2_ERROR_TOO_SHORT; + } + } + if (m_pStream->readInteger(&pSymbolDictDecoder->SDNUMEXSYMS) != 0 || + m_pStream->readInteger(&pSymbolDictDecoder->SDNUMNEWSYMS) != 0) { + return JBIG2_ERROR_TOO_SHORT; + } + if (pSymbolDictDecoder->SDNUMEXSYMS > JBIG2_MAX_EXPORT_SYSMBOLS || + pSymbolDictDecoder->SDNUMNEWSYMS > JBIG2_MAX_NEW_SYSMBOLS) { + return JBIG2_ERROR_LIMIT; + } + for (int32_t i = 0; i < pSegment->m_nReferred_to_segment_count; ++i) { + if (!findSegmentByNumber(pSegment->m_pReferred_to_segment_numbers[i])) + return JBIG2_ERROR_FATAL; + } + CJBig2_Segment* pLRSeg = nullptr; + pSymbolDictDecoder->SDNUMINSYMS = 0; + for (int32_t i = 0; i < pSegment->m_nReferred_to_segment_count; ++i) { + CJBig2_Segment* pSeg = + findSegmentByNumber(pSegment->m_pReferred_to_segment_numbers[i]); + if (pSeg->m_cFlags.s.type == 0) { + pSymbolDictDecoder->SDNUMINSYMS += pSeg->m_Result.sd->NumImages(); + pLRSeg = pSeg; + } + } + + std::unique_ptr<CJBig2_Image*, FxFreeDeleter> SDINSYMS; + if (pSymbolDictDecoder->SDNUMINSYMS != 0) { + SDINSYMS.reset(FX_Alloc(CJBig2_Image*, pSymbolDictDecoder->SDNUMINSYMS)); + FX_DWORD dwTemp = 0; + for (int32_t i = 0; i < pSegment->m_nReferred_to_segment_count; ++i) { + CJBig2_Segment* pSeg = + findSegmentByNumber(pSegment->m_pReferred_to_segment_numbers[i]); + if (pSeg->m_cFlags.s.type == 0) { + const CJBig2_SymbolDict& dict = *pSeg->m_Result.sd; + for (size_t j = 0; j < dict.NumImages(); ++j) + SDINSYMS.get()[dwTemp + j] = dict.GetImage(j); + dwTemp += dict.NumImages(); + } + } + } + pSymbolDictDecoder->SDINSYMS = SDINSYMS.get(); + + std::unique_ptr<CJBig2_HuffmanTable> Table_B1; + std::unique_ptr<CJBig2_HuffmanTable> Table_B2; + std::unique_ptr<CJBig2_HuffmanTable> Table_B3; + std::unique_ptr<CJBig2_HuffmanTable> Table_B4; + std::unique_ptr<CJBig2_HuffmanTable> Table_B5; + if (pSymbolDictDecoder->SDHUFF == 1) { + if (cSDHUFFDH == 2 || cSDHUFFDW == 2) + return JBIG2_ERROR_FATAL; + + int32_t nIndex = 0; + if (cSDHUFFDH == 0) { + Table_B4.reset(new CJBig2_HuffmanTable(HuffmanTable_B4, + FX_ArraySize(HuffmanTable_B4), + HuffmanTable_HTOOB_B4)); + pSymbolDictDecoder->SDHUFFDH = Table_B4.get(); + } else if (cSDHUFFDH == 1) { + Table_B5.reset(new CJBig2_HuffmanTable(HuffmanTable_B5, + FX_ArraySize(HuffmanTable_B5), + HuffmanTable_HTOOB_B5)); + pSymbolDictDecoder->SDHUFFDH = Table_B5.get(); + } else { + CJBig2_Segment* pSeg = + findReferredSegmentByTypeAndIndex(pSegment, 53, nIndex++); + if (!pSeg) + return JBIG2_ERROR_FATAL; + pSymbolDictDecoder->SDHUFFDH = pSeg->m_Result.ht; + } + if (cSDHUFFDW == 0) { + Table_B2.reset(new CJBig2_HuffmanTable(HuffmanTable_B2, + FX_ArraySize(HuffmanTable_B2), + HuffmanTable_HTOOB_B2)); + pSymbolDictDecoder->SDHUFFDW = Table_B2.get(); + } else if (cSDHUFFDW == 1) { + Table_B3.reset(new CJBig2_HuffmanTable(HuffmanTable_B3, + FX_ArraySize(HuffmanTable_B3), + HuffmanTable_HTOOB_B3)); + pSymbolDictDecoder->SDHUFFDW = Table_B3.get(); + } else { + CJBig2_Segment* pSeg = + findReferredSegmentByTypeAndIndex(pSegment, 53, nIndex++); + if (!pSeg) + return JBIG2_ERROR_FATAL; + pSymbolDictDecoder->SDHUFFDW = pSeg->m_Result.ht; + } + if (cSDHUFFBMSIZE == 0) { + Table_B1.reset(new CJBig2_HuffmanTable(HuffmanTable_B1, + FX_ArraySize(HuffmanTable_B1), + HuffmanTable_HTOOB_B1)); + pSymbolDictDecoder->SDHUFFBMSIZE = Table_B1.get(); + } else { + CJBig2_Segment* pSeg = + findReferredSegmentByTypeAndIndex(pSegment, 53, nIndex++); + if (!pSeg) + return JBIG2_ERROR_FATAL; + pSymbolDictDecoder->SDHUFFBMSIZE = pSeg->m_Result.ht; + } + if (pSymbolDictDecoder->SDREFAGG == 1) { + if (cSDHUFFAGGINST == 0) { + if (!Table_B1) { + Table_B1.reset(new CJBig2_HuffmanTable(HuffmanTable_B1, + FX_ArraySize(HuffmanTable_B1), + HuffmanTable_HTOOB_B1)); + } + pSymbolDictDecoder->SDHUFFAGGINST = Table_B1.get(); + } else { + CJBig2_Segment* pSeg = + findReferredSegmentByTypeAndIndex(pSegment, 53, nIndex++); + if (!pSeg) + return JBIG2_ERROR_FATAL; + pSymbolDictDecoder->SDHUFFAGGINST = pSeg->m_Result.ht; + } + } + } + + const bool bUseGbContext = (pSymbolDictDecoder->SDHUFF == 0); + const bool bUseGrContext = (pSymbolDictDecoder->SDREFAGG == 1); + const size_t gbContextSize = + GetHuffContextSize(pSymbolDictDecoder->SDTEMPLATE); + const size_t grContextSize = + GetRefAggContextSize(pSymbolDictDecoder->SDRTEMPLATE); + std::vector<JBig2ArithCtx> gbContext; + std::vector<JBig2ArithCtx> grContext; + if ((wFlags & 0x0100) && pLRSeg) { + if (bUseGbContext) { + gbContext = pLRSeg->m_Result.sd->GbContext(); + if (gbContext.size() != gbContextSize) + return JBIG2_ERROR_FATAL; + } + if (bUseGrContext) { + grContext = pLRSeg->m_Result.sd->GrContext(); + if (grContext.size() != grContextSize) + return JBIG2_ERROR_FATAL; + } + } else { + if (bUseGbContext) + gbContext.resize(gbContextSize); + if (bUseGrContext) + grContext.resize(grContextSize); + } + + CJBig2_CacheKey key = + CJBig2_CacheKey(pSegment->m_dwObjNum, pSegment->m_dwDataOffset); + FX_BOOL cache_hit = false; + pSegment->m_nResultType = JBIG2_SYMBOL_DICT_POINTER; + if (m_bIsGlobal && key.first != 0) { + for (auto it = m_pSymbolDictCache->begin(); it != m_pSymbolDictCache->end(); + ++it) { + if (it->first == key) { + std::unique_ptr<CJBig2_SymbolDict> copy(it->second->DeepCopy()); + pSegment->m_Result.sd = copy.release(); + m_pSymbolDictCache->push_front(*it); + m_pSymbolDictCache->erase(it); + cache_hit = true; + break; + } + } + } + if (!cache_hit) { + if (bUseGbContext) { + std::unique_ptr<CJBig2_ArithDecoder> pArithDecoder( + new CJBig2_ArithDecoder(m_pStream.get())); + pSegment->m_Result.sd = pSymbolDictDecoder->decode_Arith( + pArithDecoder.get(), &gbContext, &grContext); + if (!pSegment->m_Result.sd) + return JBIG2_ERROR_FATAL; + + m_pStream->alignByte(); + m_pStream->offset(2); + } else { + pSegment->m_Result.sd = pSymbolDictDecoder->decode_Huffman( + m_pStream.get(), &gbContext, &grContext, pPause); + if (!pSegment->m_Result.sd) + return JBIG2_ERROR_FATAL; + m_pStream->alignByte(); + } + if (m_bIsGlobal && kSymbolDictCacheMaxSize > 0) { + std::unique_ptr<CJBig2_SymbolDict> value = + pSegment->m_Result.sd->DeepCopy(); + int size = pdfium::CollectionSize<int>(*m_pSymbolDictCache); + while (size >= kSymbolDictCacheMaxSize) { + delete m_pSymbolDictCache->back().second; + m_pSymbolDictCache->pop_back(); + --size; + } + m_pSymbolDictCache->push_front(CJBig2_CachePair(key, value.release())); + } + } + if (wFlags & 0x0200) { + if (bUseGbContext) + pSegment->m_Result.sd->SetGbContext(gbContext); + if (bUseGrContext) + pSegment->m_Result.sd->SetGrContext(grContext); + } + return JBIG2_SUCCESS; +} + +int32_t CJBig2_Context::parseTextRegion(CJBig2_Segment* pSegment) { + FX_WORD wFlags; + JBig2RegionInfo ri; + if (parseRegionInfo(&ri) != JBIG2_SUCCESS || + m_pStream->readShortInteger(&wFlags) != 0) { + return JBIG2_ERROR_TOO_SHORT; + } + + std::unique_ptr<CJBig2_TRDProc> pTRD(new CJBig2_TRDProc); + pTRD->SBW = ri.width; + pTRD->SBH = ri.height; + pTRD->SBHUFF = wFlags & 0x0001; + pTRD->SBREFINE = (wFlags >> 1) & 0x0001; + FX_DWORD dwTemp = (wFlags >> 2) & 0x0003; + pTRD->SBSTRIPS = 1 << dwTemp; + pTRD->REFCORNER = (JBig2Corner)((wFlags >> 4) & 0x0003); + pTRD->TRANSPOSED = (wFlags >> 6) & 0x0001; + pTRD->SBCOMBOP = (JBig2ComposeOp)((wFlags >> 7) & 0x0003); + pTRD->SBDEFPIXEL = (wFlags >> 9) & 0x0001; + pTRD->SBDSOFFSET = (wFlags >> 10) & 0x001f; + if (pTRD->SBDSOFFSET >= 0x0010) { + pTRD->SBDSOFFSET = pTRD->SBDSOFFSET - 0x0020; + } + pTRD->SBRTEMPLATE = (wFlags >> 15) & 0x0001; + + uint8_t cSBHUFFFS; + uint8_t cSBHUFFDS; + uint8_t cSBHUFFDT; + uint8_t cSBHUFFRDW; + uint8_t cSBHUFFRDH; + uint8_t cSBHUFFRDX; + uint8_t cSBHUFFRDY; + uint8_t cSBHUFFRSIZE; + if (pTRD->SBHUFF == 1) { + if (m_pStream->readShortInteger(&wFlags) != 0) + return JBIG2_ERROR_TOO_SHORT; + + cSBHUFFFS = wFlags & 0x0003; + cSBHUFFDS = (wFlags >> 2) & 0x0003; + cSBHUFFDT = (wFlags >> 4) & 0x0003; + cSBHUFFRDW = (wFlags >> 6) & 0x0003; + cSBHUFFRDH = (wFlags >> 8) & 0x0003; + cSBHUFFRDX = (wFlags >> 10) & 0x0003; + cSBHUFFRDY = (wFlags >> 12) & 0x0003; + cSBHUFFRSIZE = (wFlags >> 14) & 0x0001; + } + if (pTRD->SBREFINE == 1 && pTRD->SBRTEMPLATE == 0) { + for (int32_t i = 0; i < 4; ++i) { + if (m_pStream->read1Byte((uint8_t*)&pTRD->SBRAT[i]) != 0) + return JBIG2_ERROR_TOO_SHORT; + } + } + if (m_pStream->readInteger(&pTRD->SBNUMINSTANCES) != 0) + return JBIG2_ERROR_TOO_SHORT; + + for (int32_t i = 0; i < pSegment->m_nReferred_to_segment_count; ++i) { + if (!findSegmentByNumber(pSegment->m_pReferred_to_segment_numbers[i])) + return JBIG2_ERROR_FATAL; + } + + pTRD->SBNUMSYMS = 0; + for (int32_t i = 0; i < pSegment->m_nReferred_to_segment_count; ++i) { + CJBig2_Segment* pSeg = + findSegmentByNumber(pSegment->m_pReferred_to_segment_numbers[i]); + if (pSeg->m_cFlags.s.type == 0) { + pTRD->SBNUMSYMS += pSeg->m_Result.sd->NumImages(); + } + } + + std::unique_ptr<CJBig2_Image*, FxFreeDeleter> SBSYMS; + if (pTRD->SBNUMSYMS > 0) { + SBSYMS.reset(FX_Alloc(CJBig2_Image*, pTRD->SBNUMSYMS)); + dwTemp = 0; + for (int32_t i = 0; i < pSegment->m_nReferred_to_segment_count; ++i) { + CJBig2_Segment* pSeg = + findSegmentByNumber(pSegment->m_pReferred_to_segment_numbers[i]); + if (pSeg->m_cFlags.s.type == 0) { + const CJBig2_SymbolDict& dict = *pSeg->m_Result.sd; + for (size_t j = 0; j < dict.NumImages(); ++j) + SBSYMS.get()[dwTemp + j] = dict.GetImage(j); + dwTemp += dict.NumImages(); + } + } + pTRD->SBSYMS = SBSYMS.get(); + } else { + pTRD->SBSYMS = NULL; + } + + std::unique_ptr<JBig2HuffmanCode, FxFreeDeleter> SBSYMCODES; + if (pTRD->SBHUFF == 1) { + SBSYMCODES.reset( + decodeSymbolIDHuffmanTable(m_pStream.get(), pTRD->SBNUMSYMS)); + if (!SBSYMCODES) + return JBIG2_ERROR_FATAL; + + m_pStream->alignByte(); + pTRD->SBSYMCODES = SBSYMCODES.get(); + } else { + dwTemp = 0; + while ((FX_DWORD)(1 << dwTemp) < pTRD->SBNUMSYMS) { + ++dwTemp; + } + pTRD->SBSYMCODELEN = (uint8_t)dwTemp; + } + + std::unique_ptr<CJBig2_HuffmanTable> Table_B1; + std::unique_ptr<CJBig2_HuffmanTable> Table_B6; + std::unique_ptr<CJBig2_HuffmanTable> Table_B7; + std::unique_ptr<CJBig2_HuffmanTable> Table_B8; + std::unique_ptr<CJBig2_HuffmanTable> Table_B9; + std::unique_ptr<CJBig2_HuffmanTable> Table_B10; + std::unique_ptr<CJBig2_HuffmanTable> Table_B11; + std::unique_ptr<CJBig2_HuffmanTable> Table_B12; + std::unique_ptr<CJBig2_HuffmanTable> Table_B13; + std::unique_ptr<CJBig2_HuffmanTable> Table_B14; + std::unique_ptr<CJBig2_HuffmanTable> Table_B15; + if (pTRD->SBHUFF == 1) { + if (cSBHUFFFS == 2 || cSBHUFFRDW == 2 || cSBHUFFRDH == 2 || + cSBHUFFRDX == 2 || cSBHUFFRDY == 2) { + return JBIG2_ERROR_FATAL; + } + int32_t nIndex = 0; + if (cSBHUFFFS == 0) { + Table_B6.reset(new CJBig2_HuffmanTable(HuffmanTable_B6, + FX_ArraySize(HuffmanTable_B6), + HuffmanTable_HTOOB_B6)); + pTRD->SBHUFFFS = Table_B6.get(); + } else if (cSBHUFFFS == 1) { + Table_B7.reset(new CJBig2_HuffmanTable(HuffmanTable_B7, + FX_ArraySize(HuffmanTable_B7), + HuffmanTable_HTOOB_B7)); + pTRD->SBHUFFFS = Table_B7.get(); + } else { + CJBig2_Segment* pSeg = + findReferredSegmentByTypeAndIndex(pSegment, 53, nIndex++); + if (!pSeg) + return JBIG2_ERROR_FATAL; + pTRD->SBHUFFFS = pSeg->m_Result.ht; + } + if (cSBHUFFDS == 0) { + Table_B8.reset(new CJBig2_HuffmanTable(HuffmanTable_B8, + FX_ArraySize(HuffmanTable_B8), + HuffmanTable_HTOOB_B8)); + pTRD->SBHUFFDS = Table_B8.get(); + } else if (cSBHUFFDS == 1) { + Table_B9.reset(new CJBig2_HuffmanTable(HuffmanTable_B9, + FX_ArraySize(HuffmanTable_B9), + HuffmanTable_HTOOB_B9)); + pTRD->SBHUFFDS = Table_B9.get(); + } else if (cSBHUFFDS == 2) { + Table_B10.reset(new CJBig2_HuffmanTable(HuffmanTable_B10, + FX_ArraySize(HuffmanTable_B10), + HuffmanTable_HTOOB_B10)); + pTRD->SBHUFFDS = Table_B10.get(); + } else { + CJBig2_Segment* pSeg = + findReferredSegmentByTypeAndIndex(pSegment, 53, nIndex++); + if (!pSeg) + return JBIG2_ERROR_FATAL; + pTRD->SBHUFFDS = pSeg->m_Result.ht; + } + if (cSBHUFFDT == 0) { + Table_B11.reset(new CJBig2_HuffmanTable(HuffmanTable_B11, + FX_ArraySize(HuffmanTable_B11), + HuffmanTable_HTOOB_B11)); + pTRD->SBHUFFDT = Table_B11.get(); + } else if (cSBHUFFDT == 1) { + Table_B12.reset(new CJBig2_HuffmanTable(HuffmanTable_B12, + FX_ArraySize(HuffmanTable_B12), + HuffmanTable_HTOOB_B12)); + pTRD->SBHUFFDT = Table_B12.get(); + } else if (cSBHUFFDT == 2) { + Table_B13.reset(new CJBig2_HuffmanTable(HuffmanTable_B13, + FX_ArraySize(HuffmanTable_B13), + HuffmanTable_HTOOB_B13)); + pTRD->SBHUFFDT = Table_B13.get(); + } else { + CJBig2_Segment* pSeg = + findReferredSegmentByTypeAndIndex(pSegment, 53, nIndex++); + if (!pSeg) + return JBIG2_ERROR_FATAL; + pTRD->SBHUFFDT = pSeg->m_Result.ht; + } + if (cSBHUFFRDW == 0) { + Table_B14.reset(new CJBig2_HuffmanTable(HuffmanTable_B14, + FX_ArraySize(HuffmanTable_B14), + HuffmanTable_HTOOB_B14)); + pTRD->SBHUFFRDW = Table_B14.get(); + } else if (cSBHUFFRDW == 1) { + Table_B15.reset(new CJBig2_HuffmanTable(HuffmanTable_B15, + FX_ArraySize(HuffmanTable_B15), + HuffmanTable_HTOOB_B15)); + pTRD->SBHUFFRDW = Table_B15.get(); + } else { + CJBig2_Segment* pSeg = + findReferredSegmentByTypeAndIndex(pSegment, 53, nIndex++); + if (!pSeg) + return JBIG2_ERROR_FATAL; + pTRD->SBHUFFRDW = pSeg->m_Result.ht; + } + if (cSBHUFFRDH == 0) { + if (!Table_B14) { + Table_B14.reset(new CJBig2_HuffmanTable(HuffmanTable_B14, + FX_ArraySize(HuffmanTable_B14), + HuffmanTable_HTOOB_B14)); + } + pTRD->SBHUFFRDH = Table_B14.get(); + } else if (cSBHUFFRDH == 1) { + if (!Table_B15) { + Table_B15.reset(new CJBig2_HuffmanTable(HuffmanTable_B15, + FX_ArraySize(HuffmanTable_B15), + HuffmanTable_HTOOB_B15)); + } + pTRD->SBHUFFRDH = Table_B15.get(); + } else { + CJBig2_Segment* pSeg = + findReferredSegmentByTypeAndIndex(pSegment, 53, nIndex++); + if (!pSeg) + return JBIG2_ERROR_FATAL; + pTRD->SBHUFFRDH = pSeg->m_Result.ht; + } + if (cSBHUFFRDX == 0) { + if (!Table_B14) { + Table_B14.reset(new CJBig2_HuffmanTable(HuffmanTable_B14, + FX_ArraySize(HuffmanTable_B14), + HuffmanTable_HTOOB_B14)); + } + pTRD->SBHUFFRDX = Table_B14.get(); + } else if (cSBHUFFRDX == 1) { + if (!Table_B15) { + Table_B15.reset(new CJBig2_HuffmanTable(HuffmanTable_B15, + FX_ArraySize(HuffmanTable_B15), + HuffmanTable_HTOOB_B15)); + } + pTRD->SBHUFFRDX = Table_B15.get(); + } else { + CJBig2_Segment* pSeg = + findReferredSegmentByTypeAndIndex(pSegment, 53, nIndex++); + if (!pSeg) + return JBIG2_ERROR_FATAL; + pTRD->SBHUFFRDX = pSeg->m_Result.ht; + } + if (cSBHUFFRDY == 0) { + if (!Table_B14) { + Table_B14.reset(new CJBig2_HuffmanTable(HuffmanTable_B14, + FX_ArraySize(HuffmanTable_B14), + HuffmanTable_HTOOB_B14)); + } + pTRD->SBHUFFRDY = Table_B14.get(); + } else if (cSBHUFFRDY == 1) { + if (!Table_B15) { + Table_B15.reset(new CJBig2_HuffmanTable(HuffmanTable_B15, + FX_ArraySize(HuffmanTable_B15), + HuffmanTable_HTOOB_B15)); + } + pTRD->SBHUFFRDY = Table_B15.get(); + } else { + CJBig2_Segment* pSeg = + findReferredSegmentByTypeAndIndex(pSegment, 53, nIndex++); + if (!pSeg) + return JBIG2_ERROR_FATAL; + pTRD->SBHUFFRDY = pSeg->m_Result.ht; + } + if (cSBHUFFRSIZE == 0) { + Table_B1.reset(new CJBig2_HuffmanTable(HuffmanTable_B1, + FX_ArraySize(HuffmanTable_B1), + HuffmanTable_HTOOB_B1)); + pTRD->SBHUFFRSIZE = Table_B1.get(); + } else { + CJBig2_Segment* pSeg = + findReferredSegmentByTypeAndIndex(pSegment, 53, nIndex++); + if (!pSeg) + return JBIG2_ERROR_FATAL; + pTRD->SBHUFFRSIZE = pSeg->m_Result.ht; + } + } + std::unique_ptr<JBig2ArithCtx, FxFreeDeleter> grContext; + if (pTRD->SBREFINE == 1) { + const size_t size = GetRefAggContextSize(pTRD->SBRTEMPLATE); + grContext.reset(FX_Alloc(JBig2ArithCtx, size)); + JBIG2_memset(grContext.get(), 0, sizeof(JBig2ArithCtx) * size); + } + if (pTRD->SBHUFF == 0) { + std::unique_ptr<CJBig2_ArithDecoder> pArithDecoder( + new CJBig2_ArithDecoder(m_pStream.get())); + pSegment->m_nResultType = JBIG2_IMAGE_POINTER; + pSegment->m_Result.im = + pTRD->decode_Arith(pArithDecoder.get(), grContext.get(), nullptr); + if (!pSegment->m_Result.im) + return JBIG2_ERROR_FATAL; + m_pStream->alignByte(); + m_pStream->offset(2); + } else { + pSegment->m_nResultType = JBIG2_IMAGE_POINTER; + pSegment->m_Result.im = + pTRD->decode_Huffman(m_pStream.get(), grContext.get()); + if (!pSegment->m_Result.im) + return JBIG2_ERROR_FATAL; + m_pStream->alignByte(); + } + if (pSegment->m_cFlags.s.type != 4) { + if (!m_bBufSpecified) { + JBig2PageInfo* pPageInfo = m_PageInfoList.back(); + if ((pPageInfo->m_bIsStriped == 1) && + (ri.y + ri.height > m_pPage->m_nHeight)) { + m_pPage->expand(ri.y + ri.height, (pPageInfo->m_cFlags & 4) ? 1 : 0); + } + } + m_pPage->composeFrom(ri.x, ri.y, pSegment->m_Result.im, + (JBig2ComposeOp)(ri.flags & 0x03)); + delete pSegment->m_Result.im; + pSegment->m_Result.im = NULL; + } + return JBIG2_SUCCESS; +} + +int32_t CJBig2_Context::parsePatternDict(CJBig2_Segment* pSegment, + IFX_Pause* pPause) { + uint8_t cFlags; + std::unique_ptr<CJBig2_PDDProc> pPDD(new CJBig2_PDDProc); + if (m_pStream->read1Byte(&cFlags) != 0 || + m_pStream->read1Byte(&pPDD->HDPW) != 0 || + m_pStream->read1Byte(&pPDD->HDPH) != 0 || + m_pStream->readInteger(&pPDD->GRAYMAX) != 0) { + return JBIG2_ERROR_TOO_SHORT; + } + if (pPDD->GRAYMAX > JBIG2_MAX_PATTERN_INDEX) + return JBIG2_ERROR_LIMIT; + + pPDD->HDMMR = cFlags & 0x01; + pPDD->HDTEMPLATE = (cFlags >> 1) & 0x03; + pSegment->m_nResultType = JBIG2_PATTERN_DICT_POINTER; + if (pPDD->HDMMR == 0) { + const size_t size = GetHuffContextSize(pPDD->HDTEMPLATE); + std::unique_ptr<JBig2ArithCtx, FxFreeDeleter> gbContext( + FX_Alloc(JBig2ArithCtx, size)); + JBIG2_memset(gbContext.get(), 0, sizeof(JBig2ArithCtx) * size); + std::unique_ptr<CJBig2_ArithDecoder> pArithDecoder( + new CJBig2_ArithDecoder(m_pStream.get())); + pSegment->m_Result.pd = + pPDD->decode_Arith(pArithDecoder.get(), gbContext.get(), pPause); + if (!pSegment->m_Result.pd) + return JBIG2_ERROR_FATAL; + + m_pStream->alignByte(); + m_pStream->offset(2); + } else { + pSegment->m_Result.pd = pPDD->decode_MMR(m_pStream.get(), pPause); + if (!pSegment->m_Result.pd) + return JBIG2_ERROR_FATAL; + m_pStream->alignByte(); + } + return JBIG2_SUCCESS; +} + +int32_t CJBig2_Context::parseHalftoneRegion(CJBig2_Segment* pSegment, + IFX_Pause* pPause) { + uint8_t cFlags; + JBig2RegionInfo ri; + std::unique_ptr<CJBig2_HTRDProc> pHRD(new CJBig2_HTRDProc); + if (parseRegionInfo(&ri) != JBIG2_SUCCESS || + m_pStream->read1Byte(&cFlags) != 0 || + m_pStream->readInteger(&pHRD->HGW) != 0 || + m_pStream->readInteger(&pHRD->HGH) != 0 || + m_pStream->readInteger((FX_DWORD*)&pHRD->HGX) != 0 || + m_pStream->readInteger((FX_DWORD*)&pHRD->HGY) != 0 || + m_pStream->readShortInteger(&pHRD->HRX) != 0 || + m_pStream->readShortInteger(&pHRD->HRY) != 0) { + return JBIG2_ERROR_TOO_SHORT; + } + + if (pHRD->HGW == 0 || pHRD->HGH == 0) + return JBIG2_ERROR_FATAL; + + pHRD->HBW = ri.width; + pHRD->HBH = ri.height; + pHRD->HMMR = cFlags & 0x01; + pHRD->HTEMPLATE = (cFlags >> 1) & 0x03; + pHRD->HENABLESKIP = (cFlags >> 3) & 0x01; + pHRD->HCOMBOP = (JBig2ComposeOp)((cFlags >> 4) & 0x07); + pHRD->HDEFPIXEL = (cFlags >> 7) & 0x01; + if (pSegment->m_nReferred_to_segment_count != 1) + return JBIG2_ERROR_FATAL; + + CJBig2_Segment* pSeg = + findSegmentByNumber(pSegment->m_pReferred_to_segment_numbers[0]); + if (!pSeg || (pSeg->m_cFlags.s.type != 16)) + return JBIG2_ERROR_FATAL; + + CJBig2_PatternDict* pPatternDict = pSeg->m_Result.pd; + if (!pPatternDict || (pPatternDict->NUMPATS == 0)) + return JBIG2_ERROR_FATAL; + + pHRD->HNUMPATS = pPatternDict->NUMPATS; + pHRD->HPATS = pPatternDict->HDPATS; + pHRD->HPW = pPatternDict->HDPATS[0]->m_nWidth; + pHRD->HPH = pPatternDict->HDPATS[0]->m_nHeight; + pSegment->m_nResultType = JBIG2_IMAGE_POINTER; + if (pHRD->HMMR == 0) { + const size_t size = GetHuffContextSize(pHRD->HTEMPLATE); + std::unique_ptr<JBig2ArithCtx, FxFreeDeleter> gbContext( + FX_Alloc(JBig2ArithCtx, size)); + JBIG2_memset(gbContext.get(), 0, sizeof(JBig2ArithCtx) * size); + std::unique_ptr<CJBig2_ArithDecoder> pArithDecoder( + new CJBig2_ArithDecoder(m_pStream.get())); + pSegment->m_Result.im = + pHRD->decode_Arith(pArithDecoder.get(), gbContext.get(), pPause); + if (!pSegment->m_Result.im) + return JBIG2_ERROR_FATAL; + + m_pStream->alignByte(); + m_pStream->offset(2); + } else { + pSegment->m_Result.im = pHRD->decode_MMR(m_pStream.get(), pPause); + if (!pSegment->m_Result.im) + return JBIG2_ERROR_FATAL; + m_pStream->alignByte(); + } + if (pSegment->m_cFlags.s.type != 20) { + if (!m_bBufSpecified) { + JBig2PageInfo* pPageInfo = m_PageInfoList.back(); + if (pPageInfo->m_bIsStriped == 1 && + ri.y + ri.height > m_pPage->m_nHeight) { + m_pPage->expand(ri.y + ri.height, (pPageInfo->m_cFlags & 4) ? 1 : 0); + } + } + m_pPage->composeFrom(ri.x, ri.y, pSegment->m_Result.im, + (JBig2ComposeOp)(ri.flags & 0x03)); + delete pSegment->m_Result.im; + pSegment->m_Result.im = NULL; + } + return JBIG2_SUCCESS; +} + +int32_t CJBig2_Context::parseGenericRegion(CJBig2_Segment* pSegment, + IFX_Pause* pPause) { + if (!m_pGRD) { + std::unique_ptr<CJBig2_GRDProc> pGRD(new CJBig2_GRDProc); + uint8_t cFlags; + if (parseRegionInfo(&m_ri) != JBIG2_SUCCESS || + m_pStream->read1Byte(&cFlags) != 0) { + return JBIG2_ERROR_TOO_SHORT; + } + if (m_ri.height < 0 || m_ri.width < 0) + return JBIG2_FAILED; + + pGRD->GBW = m_ri.width; + pGRD->GBH = m_ri.height; + pGRD->MMR = cFlags & 0x01; + pGRD->GBTEMPLATE = (cFlags >> 1) & 0x03; + pGRD->TPGDON = (cFlags >> 3) & 0x01; + if (pGRD->MMR == 0) { + if (pGRD->GBTEMPLATE == 0) { + for (int32_t i = 0; i < 8; ++i) { + if (m_pStream->read1Byte((uint8_t*)&pGRD->GBAT[i]) != 0) { + return JBIG2_ERROR_TOO_SHORT; + } + } + } else { + for (int32_t i = 0; i < 2; ++i) { + if (m_pStream->read1Byte((uint8_t*)&pGRD->GBAT[i]) != 0) { + return JBIG2_ERROR_TOO_SHORT; + } + } + } + } + pGRD->USESKIP = 0; + m_pGRD = std::move(pGRD); + } + pSegment->m_nResultType = JBIG2_IMAGE_POINTER; + if (m_pGRD->MMR == 0) { + if (!m_gbContext) { + const size_t size = GetHuffContextSize(m_pGRD->GBTEMPLATE); + m_gbContext = FX_Alloc(JBig2ArithCtx, size); + JBIG2_memset(m_gbContext, 0, sizeof(JBig2ArithCtx) * size); + } + if (!m_pArithDecoder) { + m_pArithDecoder.reset(new CJBig2_ArithDecoder(m_pStream.get())); + m_ProcessingStatus = m_pGRD->Start_decode_Arith( + &pSegment->m_Result.im, m_pArithDecoder.get(), m_gbContext, pPause); + } else { + m_ProcessingStatus = m_pGRD->Continue_decode(pPause); + } + if (m_ProcessingStatus == FXCODEC_STATUS_DECODE_TOBECONTINUE) { + if (pSegment->m_cFlags.s.type != 36) { + if (!m_bBufSpecified) { + JBig2PageInfo* pPageInfo = m_PageInfoList.back(); + if ((pPageInfo->m_bIsStriped == 1) && + (m_ri.y + m_ri.height > m_pPage->m_nHeight)) { + m_pPage->expand(m_ri.y + m_ri.height, + (pPageInfo->m_cFlags & 4) ? 1 : 0); + } + } + FX_RECT Rect = m_pGRD->GetReplaceRect(); + m_pPage->composeFrom(m_ri.x + Rect.left, m_ri.y + Rect.top, + pSegment->m_Result.im, + (JBig2ComposeOp)(m_ri.flags & 0x03), &Rect); + } + return JBIG2_SUCCESS; + } else { + m_pArithDecoder.reset(); + FX_Free(m_gbContext); + m_gbContext = NULL; + if (!pSegment->m_Result.im) { + m_ProcessingStatus = FXCODEC_STATUS_ERROR; + m_pGRD.reset(); + return JBIG2_ERROR_FATAL; + } + m_pStream->alignByte(); + m_pStream->offset(2); + } + } else { + FXCODEC_STATUS status = m_pGRD->Start_decode_MMR(&pSegment->m_Result.im, + m_pStream.get(), pPause); + while (status == FXCODEC_STATUS_DECODE_TOBECONTINUE) { + m_pGRD->Continue_decode(pPause); + } + if (!pSegment->m_Result.im) { + m_pGRD.reset(); + return JBIG2_ERROR_FATAL; + } + m_pStream->alignByte(); + } + if (pSegment->m_cFlags.s.type != 36) { + if (!m_bBufSpecified) { + JBig2PageInfo* pPageInfo = m_PageInfoList.back(); + if ((pPageInfo->m_bIsStriped == 1) && + (m_ri.y + m_ri.height > m_pPage->m_nHeight)) { + m_pPage->expand(m_ri.y + m_ri.height, + (pPageInfo->m_cFlags & 4) ? 1 : 0); + } + } + FX_RECT Rect = m_pGRD->GetReplaceRect(); + m_pPage->composeFrom(m_ri.x + Rect.left, m_ri.y + Rect.top, + pSegment->m_Result.im, + (JBig2ComposeOp)(m_ri.flags & 0x03), &Rect); + delete pSegment->m_Result.im; + pSegment->m_Result.im = NULL; + } + m_pGRD.reset(); + return JBIG2_SUCCESS; +} + +int32_t CJBig2_Context::parseGenericRefinementRegion(CJBig2_Segment* pSegment) { + JBig2RegionInfo ri; + uint8_t cFlags; + if (parseRegionInfo(&ri) != JBIG2_SUCCESS || + m_pStream->read1Byte(&cFlags) != 0) { + return JBIG2_ERROR_TOO_SHORT; + } + std::unique_ptr<CJBig2_GRRDProc> pGRRD(new CJBig2_GRRDProc); + pGRRD->GRW = ri.width; + pGRRD->GRH = ri.height; + pGRRD->GRTEMPLATE = cFlags & 0x01; + pGRRD->TPGRON = (cFlags >> 1) & 0x01; + if (pGRRD->GRTEMPLATE == 0) { + for (int32_t i = 0; i < 4; ++i) { + if (m_pStream->read1Byte((uint8_t*)&pGRRD->GRAT[i]) != 0) + return JBIG2_ERROR_TOO_SHORT; + } + } + CJBig2_Segment* pSeg = nullptr; + if (pSegment->m_nReferred_to_segment_count > 0) { + int32_t i; + for (i = 0; i < pSegment->m_nReferred_to_segment_count; ++i) { + pSeg = findSegmentByNumber(pSegment->m_pReferred_to_segment_numbers[0]); + if (!pSeg) + return JBIG2_ERROR_FATAL; + + if (pSeg->m_cFlags.s.type == 4 || pSeg->m_cFlags.s.type == 20 || + pSeg->m_cFlags.s.type == 36 || pSeg->m_cFlags.s.type == 40) { + break; + } + } + if (i >= pSegment->m_nReferred_to_segment_count) + return JBIG2_ERROR_FATAL; + + pGRRD->GRREFERENCE = pSeg->m_Result.im; + } else { + pGRRD->GRREFERENCE = m_pPage.get(); + } + pGRRD->GRREFERENCEDX = 0; + pGRRD->GRREFERENCEDY = 0; + const size_t size = GetRefAggContextSize(pGRRD->GRTEMPLATE); + std::unique_ptr<JBig2ArithCtx, FxFreeDeleter> grContext( + FX_Alloc(JBig2ArithCtx, size)); + JBIG2_memset(grContext.get(), 0, sizeof(JBig2ArithCtx) * size); + std::unique_ptr<CJBig2_ArithDecoder> pArithDecoder( + new CJBig2_ArithDecoder(m_pStream.get())); + pSegment->m_nResultType = JBIG2_IMAGE_POINTER; + pSegment->m_Result.im = pGRRD->decode(pArithDecoder.get(), grContext.get()); + if (!pSegment->m_Result.im) + return JBIG2_ERROR_FATAL; + + m_pStream->alignByte(); + m_pStream->offset(2); + if (pSegment->m_cFlags.s.type != 40) { + if (!m_bBufSpecified) { + JBig2PageInfo* pPageInfo = m_PageInfoList.back(); + if ((pPageInfo->m_bIsStriped == 1) && + (ri.y + ri.height > m_pPage->m_nHeight)) { + m_pPage->expand(ri.y + ri.height, (pPageInfo->m_cFlags & 4) ? 1 : 0); + } + } + m_pPage->composeFrom(ri.x, ri.y, pSegment->m_Result.im, + (JBig2ComposeOp)(ri.flags & 0x03)); + delete pSegment->m_Result.im; + pSegment->m_Result.im = NULL; + } + return JBIG2_SUCCESS; +} + +int32_t CJBig2_Context::parseTable(CJBig2_Segment* pSegment) { + pSegment->m_nResultType = JBIG2_HUFFMAN_TABLE_POINTER; + pSegment->m_Result.ht = nullptr; + std::unique_ptr<CJBig2_HuffmanTable> pHuff( + new CJBig2_HuffmanTable(m_pStream.get())); + if (!pHuff->IsOK()) + return JBIG2_ERROR_FATAL; + + pSegment->m_Result.ht = pHuff.release(); + m_pStream->alignByte(); + return JBIG2_SUCCESS; +} + +int32_t CJBig2_Context::parseRegionInfo(JBig2RegionInfo* pRI) { + if (m_pStream->readInteger((FX_DWORD*)&pRI->width) != 0 || + m_pStream->readInteger((FX_DWORD*)&pRI->height) != 0 || + m_pStream->readInteger((FX_DWORD*)&pRI->x) != 0 || + m_pStream->readInteger((FX_DWORD*)&pRI->y) != 0 || + m_pStream->read1Byte(&pRI->flags) != 0) { + return JBIG2_ERROR_TOO_SHORT; + } + return JBIG2_SUCCESS; +} + +JBig2HuffmanCode* CJBig2_Context::decodeSymbolIDHuffmanTable( + CJBig2_BitStream* pStream, + FX_DWORD SBNUMSYMS) { + const size_t kRunCodesSize = 35; + int32_t runcodes[kRunCodesSize]; + int32_t runcodes_len[kRunCodesSize]; + for (int32_t i = 0; i < kRunCodesSize; ++i) { + if (pStream->readNBits(4, &runcodes_len[i]) != 0) + return nullptr; + } + huffman_assign_code(runcodes, runcodes_len, kRunCodesSize); + + std::unique_ptr<JBig2HuffmanCode, FxFreeDeleter> SBSYMCODES( + FX_Alloc(JBig2HuffmanCode, SBNUMSYMS)); + int32_t run; + int32_t i = 0; + while (i < (int)SBNUMSYMS) { + int32_t j; + int32_t nVal = 0; + int32_t nBits = 0; + FX_DWORD nTemp; + while (true) { + if (pStream->read1Bit(&nTemp) != 0) + return nullptr; + + nVal = (nVal << 1) | nTemp; + ++nBits; + for (j = 0; j < kRunCodesSize; ++j) { + if (nBits == runcodes_len[j] && nVal == runcodes[j]) { + break; + } + } + if (j < kRunCodesSize) { + break; + } + } + int32_t runcode = j; + if (runcode < 32) { + SBSYMCODES.get()[i].codelen = runcode; + run = 0; + } else if (runcode == 32) { + if (pStream->readNBits(2, &nTemp) != 0) + return nullptr; + run = nTemp + 3; + } else if (runcode == 33) { + if (pStream->readNBits(3, &nTemp) != 0) + return nullptr; + run = nTemp + 3; + } else if (runcode == 34) { + if (pStream->readNBits(7, &nTemp) != 0) + return nullptr; + run = nTemp + 11; + } + if (run > 0) { + if (i + run > (int)SBNUMSYMS) + return nullptr; + for (j = 0; j < run; ++j) { + if (runcode == 32 && i > 0) { + SBSYMCODES.get()[i + j].codelen = SBSYMCODES.get()[i - 1].codelen; + } else { + SBSYMCODES.get()[i + j].codelen = 0; + } + } + i += run; + } else { + ++i; + } + } + huffman_assign_code(SBSYMCODES.get(), SBNUMSYMS); + return SBSYMCODES.release(); +} + +void CJBig2_Context::huffman_assign_code(int* CODES, int* PREFLEN, int NTEMP) { + // TODO(thestig) CJBig2_HuffmanTable::parseFromCodedBuffer() has similar code. + int CURLEN, LENMAX, CURCODE, CURTEMP, i; + int* LENCOUNT; + int* FIRSTCODE; + LENMAX = 0; + for (i = 0; i < NTEMP; ++i) { + if (PREFLEN[i] > LENMAX) { + LENMAX = PREFLEN[i]; + } + } + LENCOUNT = FX_Alloc(int, LENMAX + 1); + JBIG2_memset(LENCOUNT, 0, sizeof(int) * (LENMAX + 1)); + FIRSTCODE = FX_Alloc(int, LENMAX + 1); + for (i = 0; i < NTEMP; ++i) { + ++LENCOUNT[PREFLEN[i]]; + } + CURLEN = 1; + FIRSTCODE[0] = 0; + LENCOUNT[0] = 0; + while (CURLEN <= LENMAX) { + FIRSTCODE[CURLEN] = (FIRSTCODE[CURLEN - 1] + LENCOUNT[CURLEN - 1]) << 1; + CURCODE = FIRSTCODE[CURLEN]; + CURTEMP = 0; + while (CURTEMP < NTEMP) { + if (PREFLEN[CURTEMP] == CURLEN) { + CODES[CURTEMP] = CURCODE; + CURCODE = CURCODE + 1; + } + CURTEMP = CURTEMP + 1; + } + CURLEN = CURLEN + 1; + } + FX_Free(LENCOUNT); + FX_Free(FIRSTCODE); +} +void CJBig2_Context::huffman_assign_code(JBig2HuffmanCode* SBSYMCODES, + int NTEMP) { + int CURLEN, LENMAX, CURCODE, CURTEMP, i; + int* LENCOUNT; + int* FIRSTCODE; + LENMAX = 0; + for (i = 0; i < NTEMP; ++i) { + if (SBSYMCODES[i].codelen > LENMAX) { + LENMAX = SBSYMCODES[i].codelen; + } + } + LENCOUNT = FX_Alloc(int, (LENMAX + 1)); + JBIG2_memset(LENCOUNT, 0, sizeof(int) * (LENMAX + 1)); + FIRSTCODE = FX_Alloc(int, (LENMAX + 1)); + for (i = 0; i < NTEMP; ++i) { + ++LENCOUNT[SBSYMCODES[i].codelen]; + } + CURLEN = 1; + FIRSTCODE[0] = 0; + LENCOUNT[0] = 0; + while (CURLEN <= LENMAX) { + FIRSTCODE[CURLEN] = (FIRSTCODE[CURLEN - 1] + LENCOUNT[CURLEN - 1]) << 1; + CURCODE = FIRSTCODE[CURLEN]; + CURTEMP = 0; + while (CURTEMP < NTEMP) { + if (SBSYMCODES[CURTEMP].codelen == CURLEN) { + SBSYMCODES[CURTEMP].code = CURCODE; + CURCODE = CURCODE + 1; + } + CURTEMP = CURTEMP + 1; + } + CURLEN = CURLEN + 1; + } + FX_Free(LENCOUNT); + FX_Free(FIRSTCODE); +} diff --git a/core/fxcodec/jbig2/JBig2_Context.h b/core/fxcodec/jbig2/JBig2_Context.h new file mode 100644 index 0000000000..f09b8fc1ab --- /dev/null +++ b/core/fxcodec/jbig2/JBig2_Context.h @@ -0,0 +1,134 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#ifndef CORE_FXCODEC_JBIG2_JBIG2_CONTEXT_H_ +#define CORE_FXCODEC_JBIG2_JBIG2_CONTEXT_H_ + +#include <list> +#include <memory> +#include <utility> + +#include "core/fxcodec/jbig2/JBig2_List.h" +#include "core/fxcodec/jbig2/JBig2_Page.h" +#include "core/fxcodec/jbig2/JBig2_Segment.h" +#include "core/include/fpdfapi/cpdf_object.h" +#include "core/include/fxcodec/fx_codec_def.h" + +class CJBig2_ArithDecoder; +class CJBig2_GRDProc; +class CPDF_StreamAcc; +class IFX_Pause; + +// Cache is keyed by the ObjNum of a stream and an index within the stream. +using CJBig2_CacheKey = std::pair<FX_DWORD, FX_DWORD>; +// NB: CJBig2_SymbolDict* is owned. +using CJBig2_CachePair = std::pair<CJBig2_CacheKey, CJBig2_SymbolDict*>; + +#define JBIG2_SUCCESS 0 +#define JBIG2_FAILED -1 +#define JBIG2_ERROR_TOO_SHORT -2 +#define JBIG2_ERROR_FATAL -3 +#define JBIG2_END_OF_PAGE 2 +#define JBIG2_END_OF_FILE 3 +#define JBIG2_ERROR_FILE_FORMAT -4 +#define JBIG2_ERROR_STREAM_TYPE -5 +#define JBIG2_ERROR_LIMIT -6 +#define JBIG2_MIN_SEGMENT_SIZE 11 + +class CJBig2_Context { + public: + static CJBig2_Context* CreateContext( + CPDF_StreamAcc* pGlobalStream, + CPDF_StreamAcc* pSrcStream, + std::list<CJBig2_CachePair>* pSymbolDictCache, + IFX_Pause* pPause = NULL); + + static void DestroyContext(CJBig2_Context* pContext); + + int32_t getFirstPage(uint8_t* pBuf, + int32_t width, + int32_t height, + int32_t stride, + IFX_Pause* pPause); + + int32_t Continue(IFX_Pause* pPause); + FXCODEC_STATUS GetProcessingStatus() { return m_ProcessingStatus; } + + private: + CJBig2_Context(CPDF_StreamAcc* pGlobalStream, + CPDF_StreamAcc* pSrcStream, + std::list<CJBig2_CachePair>* pSymbolDictCache, + IFX_Pause* pPause, + bool bIsGlobal); + + ~CJBig2_Context(); + + int32_t decode_SquentialOrgnazation(IFX_Pause* pPause); + + int32_t decode_EmbedOrgnazation(IFX_Pause* pPause); + + int32_t decode_RandomOrgnazation_FirstPage(IFX_Pause* pPause); + + int32_t decode_RandomOrgnazation(IFX_Pause* pPause); + + CJBig2_Segment* findSegmentByNumber(FX_DWORD dwNumber); + + CJBig2_Segment* findReferredSegmentByTypeAndIndex(CJBig2_Segment* pSegment, + uint8_t cType, + int32_t nIndex); + + int32_t parseSegmentHeader(CJBig2_Segment* pSegment); + + int32_t parseSegmentData(CJBig2_Segment* pSegment, IFX_Pause* pPause); + int32_t ProcessingParseSegmentData(CJBig2_Segment* pSegment, + IFX_Pause* pPause); + + int32_t parseSymbolDict(CJBig2_Segment* pSegment, IFX_Pause* pPause); + + int32_t parseTextRegion(CJBig2_Segment* pSegment); + + int32_t parsePatternDict(CJBig2_Segment* pSegment, IFX_Pause* pPause); + + int32_t parseHalftoneRegion(CJBig2_Segment* pSegment, IFX_Pause* pPause); + + int32_t parseGenericRegion(CJBig2_Segment* pSegment, IFX_Pause* pPause); + + int32_t parseGenericRefinementRegion(CJBig2_Segment* pSegment); + + int32_t parseTable(CJBig2_Segment* pSegment); + + int32_t parseRegionInfo(JBig2RegionInfo* pRI); + + JBig2HuffmanCode* decodeSymbolIDHuffmanTable(CJBig2_BitStream* pStream, + FX_DWORD SBNUMSYMS); + + void huffman_assign_code(int* CODES, int* PREFLEN, int NTEMP); + + void huffman_assign_code(JBig2HuffmanCode* SBSYMCODES, int NTEMP); + + private: + CJBig2_Context* m_pGlobalContext; + std::unique_ptr<CJBig2_BitStream> m_pStream; + CJBig2_List<CJBig2_Segment> m_SegmentList; + CJBig2_List<JBig2PageInfo> m_PageInfoList; + std::unique_ptr<CJBig2_Image> m_pPage; + size_t m_nSegmentDecoded; + bool m_bInPage; + bool m_bBufSpecified; + int32_t m_PauseStep; + IFX_Pause* m_pPause; + FXCODEC_STATUS m_ProcessingStatus; + std::unique_ptr<CJBig2_ArithDecoder> m_pArithDecoder; + std::unique_ptr<CJBig2_GRDProc> m_pGRD; + JBig2ArithCtx* m_gbContext; + std::unique_ptr<CJBig2_Segment> m_pSegment; + FX_DWORD m_dwOffset; + JBig2RegionInfo m_ri; + std::list<CJBig2_CachePair>* const m_pSymbolDictCache; + bool m_bIsGlobal; +}; + +#endif // CORE_FXCODEC_JBIG2_JBIG2_CONTEXT_H_ diff --git a/core/fxcodec/jbig2/JBig2_Define.h b/core/fxcodec/jbig2/JBig2_Define.h new file mode 100644 index 0000000000..5149c19ef2 --- /dev/null +++ b/core/fxcodec/jbig2/JBig2_Define.h @@ -0,0 +1,36 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#ifndef CORE_FXCODEC_JBIG2_JBIG2_DEFINE_H_ +#define CORE_FXCODEC_JBIG2_JBIG2_DEFINE_H_ + +#include "core/include/fxcrt/fx_system.h" + +#define JBIG2_memset FXSYS_memset +#define JBIG2_memcmp FXSYS_memcmp +#define JBIG2_memcpy FXSYS_memcpy +#define JBIG2_OOB 1 + +struct JBig2RegionInfo { + int32_t width; + int32_t height; + int32_t x; + int32_t y; + uint8_t flags; +}; + +struct JBig2HuffmanCode { + int32_t codelen; + int32_t code; +}; + +#define JBIG2_MAX_REFERRED_SEGMENT_COUNT 64 +#define JBIG2_MAX_EXPORT_SYSMBOLS 65535 +#define JBIG2_MAX_NEW_SYSMBOLS 65535 +#define JBIG2_MAX_PATTERN_INDEX 65535 +#define JBIG2_MAX_IMAGE_SIZE 65535 + +#endif // CORE_FXCODEC_JBIG2_JBIG2_DEFINE_H_ diff --git a/core/fxcodec/jbig2/JBig2_GrdProc.cpp b/core/fxcodec/jbig2/JBig2_GrdProc.cpp new file mode 100644 index 0000000000..a3fc33c2be --- /dev/null +++ b/core/fxcodec/jbig2/JBig2_GrdProc.cpp @@ -0,0 +1,1259 @@ +// Copyright 2015 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "core/fxcodec/jbig2/JBig2_GrdProc.h" + +#include <memory> + +#include "core/fxcodec/jbig2/JBig2_ArithDecoder.h" +#include "core/fxcodec/jbig2/JBig2_BitStream.h" +#include "core/fxcodec/jbig2/JBig2_Image.h" +#include "core/include/fxcodec/fx_codec.h" + +CJBig2_GRDProc::CJBig2_GRDProc() + : m_loopIndex(0), + m_pLine(nullptr), + m_pPause(nullptr), + m_DecodeType(0), + LTP(0) { + m_ReplaceRect.left = 0; + m_ReplaceRect.bottom = 0; + m_ReplaceRect.top = 0; + m_ReplaceRect.right = 0; +} + +bool CJBig2_GRDProc::UseTemplate0Opt3() const { + return (GBAT[0] == 3) && (GBAT[1] == -1) && (GBAT[2] == -3) && + (GBAT[3] == -1) && (GBAT[4] == 2) && (GBAT[5] == -2) && + (GBAT[6] == -2) && (GBAT[7] == -2); +} + +bool CJBig2_GRDProc::UseTemplate1Opt3() const { + return (GBAT[0] == 3) && (GBAT[1] == -1); +} + +bool CJBig2_GRDProc::UseTemplate23Opt3() const { + return (GBAT[0] == 2) && (GBAT[1] == -1); +} + +CJBig2_Image* CJBig2_GRDProc::decode_Arith(CJBig2_ArithDecoder* pArithDecoder, + JBig2ArithCtx* gbContext) { + if (GBW == 0 || GBH == 0) + return new CJBig2_Image(GBW, GBH); + + if (GBTEMPLATE == 0) { + if (UseTemplate0Opt3()) + return decode_Arith_Template0_opt3(pArithDecoder, gbContext); + return decode_Arith_Template0_unopt(pArithDecoder, gbContext); + } else if (GBTEMPLATE == 1) { + if (UseTemplate1Opt3()) + return decode_Arith_Template1_opt3(pArithDecoder, gbContext); + return decode_Arith_Template1_unopt(pArithDecoder, gbContext); + } else if (GBTEMPLATE == 2) { + if (UseTemplate23Opt3()) + return decode_Arith_Template2_opt3(pArithDecoder, gbContext); + return decode_Arith_Template2_unopt(pArithDecoder, gbContext); + } else { + if (UseTemplate23Opt3()) + return decode_Arith_Template3_opt3(pArithDecoder, gbContext); + return decode_Arith_Template3_unopt(pArithDecoder, gbContext); + } +} +CJBig2_Image* CJBig2_GRDProc::decode_Arith_Template0_opt3( + CJBig2_ArithDecoder* pArithDecoder, + JBig2ArithCtx* gbContext) { + FX_BOOL LTP, SLTP, bVal; + FX_DWORD CONTEXT; + FX_DWORD line1, line2; + uint8_t *pLine, *pLine1, *pLine2, cVal; + int32_t nStride, nStride2, k; + int32_t nLineBytes, nBitsLeft, cc; + LTP = 0; + std::unique_ptr<CJBig2_Image> GBREG(new CJBig2_Image(GBW, GBH)); + if (!GBREG->m_pData) + return nullptr; + + pLine = GBREG->m_pData; + nStride = GBREG->m_nStride; + nStride2 = nStride << 1; + nLineBytes = ((GBW + 7) >> 3) - 1; + nBitsLeft = GBW - (nLineBytes << 3); + FX_DWORD height = GBH & 0x7fffffff; + for (FX_DWORD h = 0; h < height; h++) { + if (TPGDON) { + SLTP = pArithDecoder->DECODE(&gbContext[0x9b25]); + LTP = LTP ^ SLTP; + } + if (LTP == 1) { + GBREG->copyLine(h, h - 1); + } else { + if (h > 1) { + pLine1 = pLine - nStride2; + pLine2 = pLine - nStride; + line1 = (*pLine1++) << 6; + line2 = *pLine2++; + CONTEXT = ((line1 & 0xf800) | (line2 & 0x07f0)); + for (cc = 0; cc < nLineBytes; cc++) { + line1 = (line1 << 8) | ((*pLine1++) << 6); + line2 = (line2 << 8) | (*pLine2++); + cVal = 0; + for (k = 7; k >= 0; k--) { + bVal = pArithDecoder->DECODE(&gbContext[CONTEXT]); + cVal |= bVal << k; + CONTEXT = (((CONTEXT & 0x7bf7) << 1) | bVal | + ((line1 >> k) & 0x0800) | ((line2 >> k) & 0x0010)); + } + pLine[cc] = cVal; + } + line1 <<= 8; + line2 <<= 8; + cVal = 0; + for (k = 0; k < nBitsLeft; k++) { + bVal = pArithDecoder->DECODE(&gbContext[CONTEXT]); + cVal |= bVal << (7 - k); + CONTEXT = + (((CONTEXT & 0x7bf7) << 1) | bVal | + ((line1 >> (7 - k)) & 0x0800) | ((line2 >> (7 - k)) & 0x0010)); + } + pLine[nLineBytes] = cVal; + } else { + pLine2 = pLine - nStride; + line2 = (h & 1) ? (*pLine2++) : 0; + CONTEXT = (line2 & 0x07f0); + for (cc = 0; cc < nLineBytes; cc++) { + if (h & 1) { + line2 = (line2 << 8) | (*pLine2++); + } + cVal = 0; + for (k = 7; k >= 0; k--) { + bVal = pArithDecoder->DECODE(&gbContext[CONTEXT]); + cVal |= bVal << k; + CONTEXT = + (((CONTEXT & 0x7bf7) << 1) | bVal | ((line2 >> k) & 0x0010)); + } + pLine[cc] = cVal; + } + line2 <<= 8; + cVal = 0; + for (k = 0; k < nBitsLeft; k++) { + bVal = pArithDecoder->DECODE(&gbContext[CONTEXT]); + cVal |= bVal << (7 - k); + CONTEXT = (((CONTEXT & 0x7bf7) << 1) | bVal | + (((line2 >> (7 - k))) & 0x0010)); + } + pLine[nLineBytes] = cVal; + } + } + pLine += nStride; + } + return GBREG.release(); +} + +CJBig2_Image* CJBig2_GRDProc::decode_Arith_Template0_unopt( + CJBig2_ArithDecoder* pArithDecoder, + JBig2ArithCtx* gbContext) { + FX_BOOL LTP, SLTP, bVal; + FX_DWORD CONTEXT; + FX_DWORD line1, line2, line3; + LTP = 0; + std::unique_ptr<CJBig2_Image> GBREG(new CJBig2_Image(GBW, GBH)); + GBREG->fill(0); + for (FX_DWORD h = 0; h < GBH; h++) { + if (TPGDON) { + SLTP = pArithDecoder->DECODE(&gbContext[0x9b25]); + LTP = LTP ^ SLTP; + } + if (LTP == 1) { + GBREG->copyLine(h, h - 1); + } else { + line1 = GBREG->getPixel(1, h - 2); + line1 |= GBREG->getPixel(0, h - 2) << 1; + line2 = GBREG->getPixel(2, h - 1); + line2 |= GBREG->getPixel(1, h - 1) << 1; + line2 |= GBREG->getPixel(0, h - 1) << 2; + line3 = 0; + for (FX_DWORD w = 0; w < GBW; w++) { + if (USESKIP && SKIP->getPixel(w, h)) { + bVal = 0; + } else { + CONTEXT = line3; + CONTEXT |= GBREG->getPixel(w + GBAT[0], h + GBAT[1]) << 4; + CONTEXT |= line2 << 5; + CONTEXT |= GBREG->getPixel(w + GBAT[2], h + GBAT[3]) << 10; + CONTEXT |= GBREG->getPixel(w + GBAT[4], h + GBAT[5]) << 11; + CONTEXT |= line1 << 12; + CONTEXT |= GBREG->getPixel(w + GBAT[6], h + GBAT[7]) << 15; + bVal = pArithDecoder->DECODE(&gbContext[CONTEXT]); + } + if (bVal) { + GBREG->setPixel(w, h, bVal); + } + line1 = ((line1 << 1) | GBREG->getPixel(w + 2, h - 2)) & 0x07; + line2 = ((line2 << 1) | GBREG->getPixel(w + 3, h - 1)) & 0x1f; + line3 = ((line3 << 1) | bVal) & 0x0f; + } + } + } + return GBREG.release(); +} + +CJBig2_Image* CJBig2_GRDProc::decode_Arith_Template1_opt3( + CJBig2_ArithDecoder* pArithDecoder, + JBig2ArithCtx* gbContext) { + FX_BOOL LTP, SLTP, bVal; + FX_DWORD CONTEXT; + FX_DWORD line1, line2; + uint8_t *pLine, *pLine1, *pLine2, cVal; + int32_t nStride, nStride2, k; + int32_t nLineBytes, nBitsLeft, cc; + LTP = 0; + std::unique_ptr<CJBig2_Image> GBREG(new CJBig2_Image(GBW, GBH)); + if (!GBREG->m_pData) + return nullptr; + + pLine = GBREG->m_pData; + nStride = GBREG->m_nStride; + nStride2 = nStride << 1; + nLineBytes = ((GBW + 7) >> 3) - 1; + nBitsLeft = GBW - (nLineBytes << 3); + for (FX_DWORD h = 0; h < GBH; h++) { + if (TPGDON) { + SLTP = pArithDecoder->DECODE(&gbContext[0x0795]); + LTP = LTP ^ SLTP; + } + if (LTP == 1) { + GBREG->copyLine(h, h - 1); + } else { + if (h > 1) { + pLine1 = pLine - nStride2; + pLine2 = pLine - nStride; + line1 = (*pLine1++) << 4; + line2 = *pLine2++; + CONTEXT = (line1 & 0x1e00) | ((line2 >> 1) & 0x01f8); + for (cc = 0; cc < nLineBytes; cc++) { + line1 = (line1 << 8) | ((*pLine1++) << 4); + line2 = (line2 << 8) | (*pLine2++); + cVal = 0; + for (k = 7; k >= 0; k--) { + bVal = pArithDecoder->DECODE(&gbContext[CONTEXT]); + cVal |= bVal << k; + CONTEXT = ((CONTEXT & 0x0efb) << 1) | bVal | + ((line1 >> k) & 0x0200) | ((line2 >> (k + 1)) & 0x0008); + } + pLine[cc] = cVal; + } + line1 <<= 8; + line2 <<= 8; + cVal = 0; + for (k = 0; k < nBitsLeft; k++) { + bVal = pArithDecoder->DECODE(&gbContext[CONTEXT]); + cVal |= bVal << (7 - k); + CONTEXT = ((CONTEXT & 0x0efb) << 1) | bVal | + ((line1 >> (7 - k)) & 0x0200) | + ((line2 >> (8 - k)) & 0x0008); + } + pLine[nLineBytes] = cVal; + } else { + pLine2 = pLine - nStride; + line2 = (h & 1) ? (*pLine2++) : 0; + CONTEXT = (line2 >> 1) & 0x01f8; + for (cc = 0; cc < nLineBytes; cc++) { + if (h & 1) { + line2 = (line2 << 8) | (*pLine2++); + } + cVal = 0; + for (k = 7; k >= 0; k--) { + bVal = pArithDecoder->DECODE(&gbContext[CONTEXT]); + cVal |= bVal << k; + CONTEXT = ((CONTEXT & 0x0efb) << 1) | bVal | + ((line2 >> (k + 1)) & 0x0008); + } + pLine[cc] = cVal; + } + line2 <<= 8; + cVal = 0; + for (k = 0; k < nBitsLeft; k++) { + bVal = pArithDecoder->DECODE(&gbContext[CONTEXT]); + cVal |= bVal << (7 - k); + CONTEXT = + ((CONTEXT & 0x0efb) << 1) | bVal | ((line2 >> (8 - k)) & 0x0008); + } + pLine[nLineBytes] = cVal; + } + } + pLine += nStride; + } + return GBREG.release(); +} + +CJBig2_Image* CJBig2_GRDProc::decode_Arith_Template1_unopt( + CJBig2_ArithDecoder* pArithDecoder, + JBig2ArithCtx* gbContext) { + FX_BOOL LTP, SLTP, bVal; + FX_DWORD CONTEXT; + FX_DWORD line1, line2, line3; + LTP = 0; + std::unique_ptr<CJBig2_Image> GBREG(new CJBig2_Image(GBW, GBH)); + GBREG->fill(0); + for (FX_DWORD h = 0; h < GBH; h++) { + if (TPGDON) { + SLTP = pArithDecoder->DECODE(&gbContext[0x0795]); + LTP = LTP ^ SLTP; + } + if (LTP == 1) { + GBREG->copyLine(h, h - 1); + } else { + line1 = GBREG->getPixel(2, h - 2); + line1 |= GBREG->getPixel(1, h - 2) << 1; + line1 |= GBREG->getPixel(0, h - 2) << 2; + line2 = GBREG->getPixel(2, h - 1); + line2 |= GBREG->getPixel(1, h - 1) << 1; + line2 |= GBREG->getPixel(0, h - 1) << 2; + line3 = 0; + for (FX_DWORD w = 0; w < GBW; w++) { + if (USESKIP && SKIP->getPixel(w, h)) { + bVal = 0; + } else { + CONTEXT = line3; + CONTEXT |= GBREG->getPixel(w + GBAT[0], h + GBAT[1]) << 3; + CONTEXT |= line2 << 4; + CONTEXT |= line1 << 9; + bVal = pArithDecoder->DECODE(&gbContext[CONTEXT]); + } + if (bVal) { + GBREG->setPixel(w, h, bVal); + } + line1 = ((line1 << 1) | GBREG->getPixel(w + 3, h - 2)) & 0x0f; + line2 = ((line2 << 1) | GBREG->getPixel(w + 3, h - 1)) & 0x1f; + line3 = ((line3 << 1) | bVal) & 0x07; + } + } + } + return GBREG.release(); +} +CJBig2_Image* CJBig2_GRDProc::decode_Arith_Template2_opt3( + CJBig2_ArithDecoder* pArithDecoder, + JBig2ArithCtx* gbContext) { + FX_BOOL LTP, SLTP, bVal; + FX_DWORD CONTEXT; + FX_DWORD line1, line2; + uint8_t *pLine, *pLine1, *pLine2, cVal; + int32_t nStride, nStride2, k; + int32_t nLineBytes, nBitsLeft, cc; + LTP = 0; + std::unique_ptr<CJBig2_Image> GBREG(new CJBig2_Image(GBW, GBH)); + if (!GBREG->m_pData) + return nullptr; + + pLine = GBREG->m_pData; + nStride = GBREG->m_nStride; + nStride2 = nStride << 1; + nLineBytes = ((GBW + 7) >> 3) - 1; + nBitsLeft = GBW - (nLineBytes << 3); + for (FX_DWORD h = 0; h < GBH; h++) { + if (TPGDON) { + SLTP = pArithDecoder->DECODE(&gbContext[0x00e5]); + LTP = LTP ^ SLTP; + } + if (LTP == 1) { + GBREG->copyLine(h, h - 1); + } else { + if (h > 1) { + pLine1 = pLine - nStride2; + pLine2 = pLine - nStride; + line1 = (*pLine1++) << 1; + line2 = *pLine2++; + CONTEXT = (line1 & 0x0380) | ((line2 >> 3) & 0x007c); + for (cc = 0; cc < nLineBytes; cc++) { + line1 = (line1 << 8) | ((*pLine1++) << 1); + line2 = (line2 << 8) | (*pLine2++); + cVal = 0; + for (k = 7; k >= 0; k--) { + bVal = pArithDecoder->DECODE(&gbContext[CONTEXT]); + cVal |= bVal << k; + CONTEXT = ((CONTEXT & 0x01bd) << 1) | bVal | + ((line1 >> k) & 0x0080) | ((line2 >> (k + 3)) & 0x0004); + } + pLine[cc] = cVal; + } + line1 <<= 8; + line2 <<= 8; + cVal = 0; + for (k = 0; k < nBitsLeft; k++) { + bVal = pArithDecoder->DECODE(&gbContext[CONTEXT]); + cVal |= bVal << (7 - k); + CONTEXT = ((CONTEXT & 0x01bd) << 1) | bVal | + ((line1 >> (7 - k)) & 0x0080) | + ((line2 >> (10 - k)) & 0x0004); + } + pLine[nLineBytes] = cVal; + } else { + pLine2 = pLine - nStride; + line2 = (h & 1) ? (*pLine2++) : 0; + CONTEXT = (line2 >> 3) & 0x007c; + for (cc = 0; cc < nLineBytes; cc++) { + if (h & 1) { + line2 = (line2 << 8) | (*pLine2++); + } + cVal = 0; + for (k = 7; k >= 0; k--) { + bVal = pArithDecoder->DECODE(&gbContext[CONTEXT]); + cVal |= bVal << k; + CONTEXT = ((CONTEXT & 0x01bd) << 1) | bVal | + ((line2 >> (k + 3)) & 0x0004); + } + pLine[cc] = cVal; + } + line2 <<= 8; + cVal = 0; + for (k = 0; k < nBitsLeft; k++) { + bVal = pArithDecoder->DECODE(&gbContext[CONTEXT]); + cVal |= bVal << (7 - k); + CONTEXT = ((CONTEXT & 0x01bd) << 1) | bVal | + (((line2 >> (10 - k))) & 0x0004); + } + pLine[nLineBytes] = cVal; + } + } + pLine += nStride; + } + return GBREG.release(); +} + +CJBig2_Image* CJBig2_GRDProc::decode_Arith_Template2_unopt( + CJBig2_ArithDecoder* pArithDecoder, + JBig2ArithCtx* gbContext) { + FX_BOOL LTP, SLTP, bVal; + FX_DWORD CONTEXT; + FX_DWORD line1, line2, line3; + LTP = 0; + std::unique_ptr<CJBig2_Image> GBREG(new CJBig2_Image(GBW, GBH)); + GBREG->fill(0); + for (FX_DWORD h = 0; h < GBH; h++) { + if (TPGDON) { + SLTP = pArithDecoder->DECODE(&gbContext[0x00e5]); + LTP = LTP ^ SLTP; + } + if (LTP == 1) { + GBREG->copyLine(h, h - 1); + } else { + line1 = GBREG->getPixel(1, h - 2); + line1 |= GBREG->getPixel(0, h - 2) << 1; + line2 = GBREG->getPixel(1, h - 1); + line2 |= GBREG->getPixel(0, h - 1) << 1; + line3 = 0; + for (FX_DWORD w = 0; w < GBW; w++) { + if (USESKIP && SKIP->getPixel(w, h)) { + bVal = 0; + } else { + CONTEXT = line3; + CONTEXT |= GBREG->getPixel(w + GBAT[0], h + GBAT[1]) << 2; + CONTEXT |= line2 << 3; + CONTEXT |= line1 << 7; + bVal = pArithDecoder->DECODE(&gbContext[CONTEXT]); + } + if (bVal) { + GBREG->setPixel(w, h, bVal); + } + line1 = ((line1 << 1) | GBREG->getPixel(w + 2, h - 2)) & 0x07; + line2 = ((line2 << 1) | GBREG->getPixel(w + 2, h - 1)) & 0x0f; + line3 = ((line3 << 1) | bVal) & 0x03; + } + } + } + return GBREG.release(); +} + +CJBig2_Image* CJBig2_GRDProc::decode_Arith_Template3_opt3( + CJBig2_ArithDecoder* pArithDecoder, + JBig2ArithCtx* gbContext) { + FX_BOOL LTP, SLTP, bVal; + FX_DWORD CONTEXT; + FX_DWORD line1; + uint8_t *pLine, *pLine1, cVal; + int32_t nStride, k; + int32_t nLineBytes, nBitsLeft, cc; + LTP = 0; + std::unique_ptr<CJBig2_Image> GBREG(new CJBig2_Image(GBW, GBH)); + if (!GBREG->m_pData) + return nullptr; + + pLine = GBREG->m_pData; + nStride = GBREG->m_nStride; + nLineBytes = ((GBW + 7) >> 3) - 1; + nBitsLeft = GBW - (nLineBytes << 3); + for (FX_DWORD h = 0; h < GBH; h++) { + if (TPGDON) { + SLTP = pArithDecoder->DECODE(&gbContext[0x0195]); + LTP = LTP ^ SLTP; + } + if (LTP == 1) { + GBREG->copyLine(h, h - 1); + } else { + if (h > 0) { + pLine1 = pLine - nStride; + line1 = *pLine1++; + CONTEXT = (line1 >> 1) & 0x03f0; + for (cc = 0; cc < nLineBytes; cc++) { + line1 = (line1 << 8) | (*pLine1++); + cVal = 0; + for (k = 7; k >= 0; k--) { + bVal = pArithDecoder->DECODE(&gbContext[CONTEXT]); + cVal |= bVal << k; + CONTEXT = ((CONTEXT & 0x01f7) << 1) | bVal | + ((line1 >> (k + 1)) & 0x0010); + } + pLine[cc] = cVal; + } + line1 <<= 8; + cVal = 0; + for (k = 0; k < nBitsLeft; k++) { + bVal = pArithDecoder->DECODE(&gbContext[CONTEXT]); + cVal |= bVal << (7 - k); + CONTEXT = + ((CONTEXT & 0x01f7) << 1) | bVal | ((line1 >> (8 - k)) & 0x0010); + } + pLine[nLineBytes] = cVal; + } else { + CONTEXT = 0; + for (cc = 0; cc < nLineBytes; cc++) { + cVal = 0; + for (k = 7; k >= 0; k--) { + bVal = pArithDecoder->DECODE(&gbContext[CONTEXT]); + cVal |= bVal << k; + CONTEXT = ((CONTEXT & 0x01f7) << 1) | bVal; + } + pLine[cc] = cVal; + } + cVal = 0; + for (k = 0; k < nBitsLeft; k++) { + bVal = pArithDecoder->DECODE(&gbContext[CONTEXT]); + cVal |= bVal << (7 - k); + CONTEXT = ((CONTEXT & 0x01f7) << 1) | bVal; + } + pLine[nLineBytes] = cVal; + } + } + pLine += nStride; + } + return GBREG.release(); +} + +CJBig2_Image* CJBig2_GRDProc::decode_Arith_Template3_unopt( + CJBig2_ArithDecoder* pArithDecoder, + JBig2ArithCtx* gbContext) { + FX_BOOL LTP, SLTP, bVal; + FX_DWORD CONTEXT; + FX_DWORD line1, line2; + LTP = 0; + std::unique_ptr<CJBig2_Image> GBREG(new CJBig2_Image(GBW, GBH)); + GBREG->fill(0); + for (FX_DWORD h = 0; h < GBH; h++) { + if (TPGDON) { + SLTP = pArithDecoder->DECODE(&gbContext[0x0195]); + LTP = LTP ^ SLTP; + } + if (LTP == 1) { + GBREG->copyLine(h, h - 1); + } else { + line1 = GBREG->getPixel(1, h - 1); + line1 |= GBREG->getPixel(0, h - 1) << 1; + line2 = 0; + for (FX_DWORD w = 0; w < GBW; w++) { + if (USESKIP && SKIP->getPixel(w, h)) { + bVal = 0; + } else { + CONTEXT = line2; + CONTEXT |= GBREG->getPixel(w + GBAT[0], h + GBAT[1]) << 4; + CONTEXT |= line1 << 5; + bVal = pArithDecoder->DECODE(&gbContext[CONTEXT]); + } + if (bVal) { + GBREG->setPixel(w, h, bVal); + } + line1 = ((line1 << 1) | GBREG->getPixel(w + 2, h - 1)) & 0x1f; + line2 = ((line2 << 1) | bVal) & 0x0f; + } + } + } + return GBREG.release(); +} + +FXCODEC_STATUS CJBig2_GRDProc::Start_decode_Arith( + CJBig2_Image** pImage, + CJBig2_ArithDecoder* pArithDecoder, + JBig2ArithCtx* gbContext, + IFX_Pause* pPause) { + if (GBW == 0 || GBH == 0) { + m_ProssiveStatus = FXCODEC_STATUS_DECODE_FINISH; + return FXCODEC_STATUS_DECODE_FINISH; + } + m_ProssiveStatus = FXCODEC_STATUS_DECODE_READY; + m_pPause = pPause; + if (!*pImage) + *pImage = new CJBig2_Image(GBW, GBH); + if (!(*pImage)->m_pData) { + delete *pImage; + *pImage = nullptr; + m_ProssiveStatus = FXCODEC_STATUS_ERROR; + return FXCODEC_STATUS_ERROR; + } + m_DecodeType = 1; + m_pImage = pImage; + (*m_pImage)->fill(0); + m_pArithDecoder = pArithDecoder; + m_gbContext = gbContext; + LTP = 0; + m_pLine = nullptr; + m_loopIndex = 0; + return decode_Arith(pPause); +} + +FXCODEC_STATUS CJBig2_GRDProc::decode_Arith(IFX_Pause* pPause) { + int iline = m_loopIndex; + CJBig2_Image* pImage = *m_pImage; + if (GBTEMPLATE == 0) { + if (UseTemplate0Opt3()) { + m_ProssiveStatus = decode_Arith_Template0_opt3(pImage, m_pArithDecoder, + m_gbContext, pPause); + } else { + m_ProssiveStatus = decode_Arith_Template0_unopt(pImage, m_pArithDecoder, + m_gbContext, pPause); + } + } else if (GBTEMPLATE == 1) { + if (UseTemplate1Opt3()) { + m_ProssiveStatus = decode_Arith_Template1_opt3(pImage, m_pArithDecoder, + m_gbContext, pPause); + } else { + m_ProssiveStatus = decode_Arith_Template1_unopt(pImage, m_pArithDecoder, + m_gbContext, pPause); + } + } else if (GBTEMPLATE == 2) { + if (UseTemplate23Opt3()) { + m_ProssiveStatus = decode_Arith_Template2_opt3(pImage, m_pArithDecoder, + m_gbContext, pPause); + } else { + m_ProssiveStatus = decode_Arith_Template2_unopt(pImage, m_pArithDecoder, + m_gbContext, pPause); + } + } else { + if (UseTemplate23Opt3()) { + m_ProssiveStatus = decode_Arith_Template3_opt3(pImage, m_pArithDecoder, + m_gbContext, pPause); + } else { + m_ProssiveStatus = decode_Arith_Template3_unopt(pImage, m_pArithDecoder, + m_gbContext, pPause); + } + } + m_ReplaceRect.left = 0; + m_ReplaceRect.right = pImage->m_nWidth; + m_ReplaceRect.top = iline; + m_ReplaceRect.bottom = m_loopIndex; + if (m_ProssiveStatus == FXCODEC_STATUS_DECODE_FINISH) { + m_loopIndex = 0; + } + return m_ProssiveStatus; +} + +FXCODEC_STATUS CJBig2_GRDProc::Start_decode_MMR(CJBig2_Image** pImage, + CJBig2_BitStream* pStream, + IFX_Pause* pPause) { + int bitpos, i; + *pImage = new CJBig2_Image(GBW, GBH); + if (!(*pImage)->m_pData) { + delete (*pImage); + (*pImage) = nullptr; + m_ProssiveStatus = FXCODEC_STATUS_ERROR; + return m_ProssiveStatus; + } + bitpos = (int)pStream->getBitPos(); + FaxG4Decode(pStream->getBuf(), pStream->getLength(), &bitpos, + (*pImage)->m_pData, GBW, GBH, (*pImage)->m_nStride); + pStream->setBitPos(bitpos); + for (i = 0; (FX_DWORD)i < (*pImage)->m_nStride * GBH; i++) { + (*pImage)->m_pData[i] = ~(*pImage)->m_pData[i]; + } + m_ProssiveStatus = FXCODEC_STATUS_DECODE_FINISH; + return m_ProssiveStatus; +} + +FXCODEC_STATUS CJBig2_GRDProc::Continue_decode(IFX_Pause* pPause) { + if (m_ProssiveStatus != FXCODEC_STATUS_DECODE_TOBECONTINUE) + return m_ProssiveStatus; + + if (m_DecodeType != 1) { + m_ProssiveStatus = FXCODEC_STATUS_ERROR; + return m_ProssiveStatus; + } + + return decode_Arith(pPause); +} + +FXCODEC_STATUS CJBig2_GRDProc::decode_Arith_Template0_opt3( + CJBig2_Image* pImage, + CJBig2_ArithDecoder* pArithDecoder, + JBig2ArithCtx* gbContext, + IFX_Pause* pPause) { + FX_BOOL SLTP, bVal; + FX_DWORD CONTEXT; + FX_DWORD line1, line2; + uint8_t *pLine1, *pLine2, cVal; + int32_t nStride, nStride2, k; + int32_t nLineBytes, nBitsLeft, cc; + if (!m_pLine) { + m_pLine = pImage->m_pData; + } + nStride = pImage->m_nStride; + nStride2 = nStride << 1; + nLineBytes = ((GBW + 7) >> 3) - 1; + nBitsLeft = GBW - (nLineBytes << 3); + FX_DWORD height = GBH & 0x7fffffff; + for (; m_loopIndex < height; m_loopIndex++) { + if (TPGDON) { + SLTP = pArithDecoder->DECODE(&gbContext[0x9b25]); + LTP = LTP ^ SLTP; + } + if (LTP == 1) { + pImage->copyLine(m_loopIndex, m_loopIndex - 1); + } else { + if (m_loopIndex > 1) { + pLine1 = m_pLine - nStride2; + pLine2 = m_pLine - nStride; + line1 = (*pLine1++) << 6; + line2 = *pLine2++; + CONTEXT = ((line1 & 0xf800) | (line2 & 0x07f0)); + for (cc = 0; cc < nLineBytes; cc++) { + line1 = (line1 << 8) | ((*pLine1++) << 6); + line2 = (line2 << 8) | (*pLine2++); + cVal = 0; + for (k = 7; k >= 0; k--) { + bVal = pArithDecoder->DECODE(&gbContext[CONTEXT]); + cVal |= bVal << k; + CONTEXT = (((CONTEXT & 0x7bf7) << 1) | bVal | + ((line1 >> k) & 0x0800) | ((line2 >> k) & 0x0010)); + } + m_pLine[cc] = cVal; + } + line1 <<= 8; + line2 <<= 8; + cVal = 0; + for (k = 0; k < nBitsLeft; k++) { + bVal = pArithDecoder->DECODE(&gbContext[CONTEXT]); + cVal |= bVal << (7 - k); + CONTEXT = + (((CONTEXT & 0x7bf7) << 1) | bVal | + ((line1 >> (7 - k)) & 0x0800) | ((line2 >> (7 - k)) & 0x0010)); + } + m_pLine[nLineBytes] = cVal; + } else { + pLine2 = m_pLine - nStride; + line2 = (m_loopIndex & 1) ? (*pLine2++) : 0; + CONTEXT = (line2 & 0x07f0); + for (cc = 0; cc < nLineBytes; cc++) { + if (m_loopIndex & 1) { + line2 = (line2 << 8) | (*pLine2++); + } + cVal = 0; + for (k = 7; k >= 0; k--) { + bVal = pArithDecoder->DECODE(&gbContext[CONTEXT]); + cVal |= bVal << k; + CONTEXT = + (((CONTEXT & 0x7bf7) << 1) | bVal | ((line2 >> k) & 0x0010)); + } + m_pLine[cc] = cVal; + } + line2 <<= 8; + cVal = 0; + for (k = 0; k < nBitsLeft; k++) { + bVal = pArithDecoder->DECODE(&gbContext[CONTEXT]); + cVal |= bVal << (7 - k); + CONTEXT = (((CONTEXT & 0x7bf7) << 1) | bVal | + ((line2 >> (7 - k)) & 0x0010)); + } + m_pLine[nLineBytes] = cVal; + } + } + m_pLine += nStride; + if (pPause && pPause->NeedToPauseNow()) { + m_loopIndex++; + m_ProssiveStatus = FXCODEC_STATUS_DECODE_TOBECONTINUE; + return FXCODEC_STATUS_DECODE_TOBECONTINUE; + } + } + m_ProssiveStatus = FXCODEC_STATUS_DECODE_FINISH; + return FXCODEC_STATUS_DECODE_FINISH; +} + +FXCODEC_STATUS CJBig2_GRDProc::decode_Arith_Template0_unopt( + CJBig2_Image* pImage, + CJBig2_ArithDecoder* pArithDecoder, + JBig2ArithCtx* gbContext, + IFX_Pause* pPause) { + FX_BOOL SLTP, bVal; + FX_DWORD CONTEXT; + FX_DWORD line1, line2, line3; + for (; m_loopIndex < GBH; m_loopIndex++) { + if (TPGDON) { + SLTP = pArithDecoder->DECODE(&gbContext[0x9b25]); + LTP = LTP ^ SLTP; + } + if (LTP == 1) { + pImage->copyLine(m_loopIndex, m_loopIndex - 1); + } else { + line1 = pImage->getPixel(1, m_loopIndex - 2); + line1 |= pImage->getPixel(0, m_loopIndex - 2) << 1; + line2 = pImage->getPixel(2, m_loopIndex - 1); + line2 |= pImage->getPixel(1, m_loopIndex - 1) << 1; + line2 |= pImage->getPixel(0, m_loopIndex - 1) << 2; + line3 = 0; + for (FX_DWORD w = 0; w < GBW; w++) { + if (USESKIP && SKIP->getPixel(w, m_loopIndex)) { + bVal = 0; + } else { + CONTEXT = line3; + CONTEXT |= pImage->getPixel(w + GBAT[0], m_loopIndex + GBAT[1]) << 4; + CONTEXT |= line2 << 5; + CONTEXT |= pImage->getPixel(w + GBAT[2], m_loopIndex + GBAT[3]) << 10; + CONTEXT |= pImage->getPixel(w + GBAT[4], m_loopIndex + GBAT[5]) << 11; + CONTEXT |= line1 << 12; + CONTEXT |= pImage->getPixel(w + GBAT[6], m_loopIndex + GBAT[7]) << 15; + bVal = pArithDecoder->DECODE(&gbContext[CONTEXT]); + } + if (bVal) { + pImage->setPixel(w, m_loopIndex, bVal); + } + line1 = + ((line1 << 1) | pImage->getPixel(w + 2, m_loopIndex - 2)) & 0x07; + line2 = + ((line2 << 1) | pImage->getPixel(w + 3, m_loopIndex - 1)) & 0x1f; + line3 = ((line3 << 1) | bVal) & 0x0f; + } + } + if (pPause && pPause->NeedToPauseNow()) { + m_loopIndex++; + m_ProssiveStatus = FXCODEC_STATUS_DECODE_TOBECONTINUE; + return FXCODEC_STATUS_DECODE_TOBECONTINUE; + } + } + m_ProssiveStatus = FXCODEC_STATUS_DECODE_FINISH; + return FXCODEC_STATUS_DECODE_FINISH; +} + +FXCODEC_STATUS CJBig2_GRDProc::decode_Arith_Template1_opt3( + CJBig2_Image* pImage, + CJBig2_ArithDecoder* pArithDecoder, + JBig2ArithCtx* gbContext, + IFX_Pause* pPause) { + FX_BOOL SLTP, bVal; + FX_DWORD CONTEXT; + FX_DWORD line1, line2; + uint8_t *pLine1, *pLine2, cVal; + int32_t nStride, nStride2, k; + int32_t nLineBytes, nBitsLeft, cc; + if (!m_pLine) { + m_pLine = pImage->m_pData; + } + nStride = pImage->m_nStride; + nStride2 = nStride << 1; + nLineBytes = ((GBW + 7) >> 3) - 1; + nBitsLeft = GBW - (nLineBytes << 3); + for (; m_loopIndex < GBH; m_loopIndex++) { + if (TPGDON) { + SLTP = pArithDecoder->DECODE(&gbContext[0x0795]); + LTP = LTP ^ SLTP; + } + if (LTP == 1) { + pImage->copyLine(m_loopIndex, m_loopIndex - 1); + } else { + if (m_loopIndex > 1) { + pLine1 = m_pLine - nStride2; + pLine2 = m_pLine - nStride; + line1 = (*pLine1++) << 4; + line2 = *pLine2++; + CONTEXT = (line1 & 0x1e00) | ((line2 >> 1) & 0x01f8); + for (cc = 0; cc < nLineBytes; cc++) { + line1 = (line1 << 8) | ((*pLine1++) << 4); + line2 = (line2 << 8) | (*pLine2++); + cVal = 0; + for (k = 7; k >= 0; k--) { + bVal = pArithDecoder->DECODE(&gbContext[CONTEXT]); + cVal |= bVal << k; + CONTEXT = ((CONTEXT & 0x0efb) << 1) | bVal | + ((line1 >> k) & 0x0200) | ((line2 >> (k + 1)) & 0x0008); + } + m_pLine[cc] = cVal; + } + line1 <<= 8; + line2 <<= 8; + cVal = 0; + for (k = 0; k < nBitsLeft; k++) { + bVal = pArithDecoder->DECODE(&gbContext[CONTEXT]); + cVal |= bVal << (7 - k); + CONTEXT = ((CONTEXT & 0x0efb) << 1) | bVal | + ((line1 >> (7 - k)) & 0x0200) | + ((line2 >> (8 - k)) & 0x0008); + } + m_pLine[nLineBytes] = cVal; + } else { + pLine2 = m_pLine - nStride; + line2 = (m_loopIndex & 1) ? (*pLine2++) : 0; + CONTEXT = (line2 >> 1) & 0x01f8; + for (cc = 0; cc < nLineBytes; cc++) { + if (m_loopIndex & 1) { + line2 = (line2 << 8) | (*pLine2++); + } + cVal = 0; + for (k = 7; k >= 0; k--) { + bVal = pArithDecoder->DECODE(&gbContext[CONTEXT]); + cVal |= bVal << k; + CONTEXT = ((CONTEXT & 0x0efb) << 1) | bVal | + ((line2 >> (k + 1)) & 0x0008); + } + m_pLine[cc] = cVal; + } + line2 <<= 8; + cVal = 0; + for (k = 0; k < nBitsLeft; k++) { + bVal = pArithDecoder->DECODE(&gbContext[CONTEXT]); + cVal |= bVal << (7 - k); + CONTEXT = + ((CONTEXT & 0x0efb) << 1) | bVal | ((line2 >> (8 - k)) & 0x0008); + } + m_pLine[nLineBytes] = cVal; + } + } + m_pLine += nStride; + if (pPause && pPause->NeedToPauseNow()) { + m_loopIndex++; + m_ProssiveStatus = FXCODEC_STATUS_DECODE_TOBECONTINUE; + return FXCODEC_STATUS_DECODE_TOBECONTINUE; + } + } + m_ProssiveStatus = FXCODEC_STATUS_DECODE_FINISH; + return FXCODEC_STATUS_DECODE_FINISH; +} + +FXCODEC_STATUS CJBig2_GRDProc::decode_Arith_Template1_unopt( + CJBig2_Image* pImage, + CJBig2_ArithDecoder* pArithDecoder, + JBig2ArithCtx* gbContext, + IFX_Pause* pPause) { + FX_BOOL SLTP, bVal; + FX_DWORD CONTEXT; + FX_DWORD line1, line2, line3; + for (FX_DWORD h = 0; h < GBH; h++) { + if (TPGDON) { + SLTP = pArithDecoder->DECODE(&gbContext[0x0795]); + LTP = LTP ^ SLTP; + } + if (LTP == 1) { + pImage->copyLine(h, h - 1); + } else { + line1 = pImage->getPixel(2, h - 2); + line1 |= pImage->getPixel(1, h - 2) << 1; + line1 |= pImage->getPixel(0, h - 2) << 2; + line2 = pImage->getPixel(2, h - 1); + line2 |= pImage->getPixel(1, h - 1) << 1; + line2 |= pImage->getPixel(0, h - 1) << 2; + line3 = 0; + for (FX_DWORD w = 0; w < GBW; w++) { + if (USESKIP && SKIP->getPixel(w, h)) { + bVal = 0; + } else { + CONTEXT = line3; + CONTEXT |= pImage->getPixel(w + GBAT[0], h + GBAT[1]) << 3; + CONTEXT |= line2 << 4; + CONTEXT |= line1 << 9; + bVal = pArithDecoder->DECODE(&gbContext[CONTEXT]); + } + if (bVal) { + pImage->setPixel(w, h, bVal); + } + line1 = ((line1 << 1) | pImage->getPixel(w + 3, h - 2)) & 0x0f; + line2 = ((line2 << 1) | pImage->getPixel(w + 3, h - 1)) & 0x1f; + line3 = ((line3 << 1) | bVal) & 0x07; + } + } + if (pPause && pPause->NeedToPauseNow()) { + m_loopIndex++; + m_ProssiveStatus = FXCODEC_STATUS_DECODE_TOBECONTINUE; + return FXCODEC_STATUS_DECODE_TOBECONTINUE; + } + } + m_ProssiveStatus = FXCODEC_STATUS_DECODE_FINISH; + return FXCODEC_STATUS_DECODE_FINISH; +} + +FXCODEC_STATUS CJBig2_GRDProc::decode_Arith_Template2_opt3( + CJBig2_Image* pImage, + CJBig2_ArithDecoder* pArithDecoder, + JBig2ArithCtx* gbContext, + IFX_Pause* pPause) { + FX_BOOL SLTP, bVal; + FX_DWORD CONTEXT; + FX_DWORD line1, line2; + uint8_t *pLine1, *pLine2, cVal; + int32_t nStride, nStride2, k; + int32_t nLineBytes, nBitsLeft, cc; + if (!m_pLine) { + m_pLine = pImage->m_pData; + } + nStride = pImage->m_nStride; + nStride2 = nStride << 1; + nLineBytes = ((GBW + 7) >> 3) - 1; + nBitsLeft = GBW - (nLineBytes << 3); + for (; m_loopIndex < GBH; m_loopIndex++) { + if (TPGDON) { + SLTP = pArithDecoder->DECODE(&gbContext[0x00e5]); + LTP = LTP ^ SLTP; + } + if (LTP == 1) { + pImage->copyLine(m_loopIndex, m_loopIndex - 1); + } else { + if (m_loopIndex > 1) { + pLine1 = m_pLine - nStride2; + pLine2 = m_pLine - nStride; + line1 = (*pLine1++) << 1; + line2 = *pLine2++; + CONTEXT = (line1 & 0x0380) | ((line2 >> 3) & 0x007c); + for (cc = 0; cc < nLineBytes; cc++) { + line1 = (line1 << 8) | ((*pLine1++) << 1); + line2 = (line2 << 8) | (*pLine2++); + cVal = 0; + for (k = 7; k >= 0; k--) { + bVal = pArithDecoder->DECODE(&gbContext[CONTEXT]); + cVal |= bVal << k; + CONTEXT = ((CONTEXT & 0x01bd) << 1) | bVal | + ((line1 >> k) & 0x0080) | ((line2 >> (k + 3)) & 0x0004); + } + m_pLine[cc] = cVal; + } + line1 <<= 8; + line2 <<= 8; + cVal = 0; + for (k = 0; k < nBitsLeft; k++) { + bVal = pArithDecoder->DECODE(&gbContext[CONTEXT]); + cVal |= bVal << (7 - k); + CONTEXT = ((CONTEXT & 0x01bd) << 1) | bVal | + ((line1 >> (7 - k)) & 0x0080) | + ((line2 >> (10 - k)) & 0x0004); + } + m_pLine[nLineBytes] = cVal; + } else { + pLine2 = m_pLine - nStride; + line2 = (m_loopIndex & 1) ? (*pLine2++) : 0; + CONTEXT = (line2 >> 3) & 0x007c; + for (cc = 0; cc < nLineBytes; cc++) { + if (m_loopIndex & 1) { + line2 = (line2 << 8) | (*pLine2++); + } + cVal = 0; + for (k = 7; k >= 0; k--) { + bVal = pArithDecoder->DECODE(&gbContext[CONTEXT]); + cVal |= bVal << k; + CONTEXT = ((CONTEXT & 0x01bd) << 1) | bVal | + ((line2 >> (k + 3)) & 0x0004); + } + m_pLine[cc] = cVal; + } + line2 <<= 8; + cVal = 0; + for (k = 0; k < nBitsLeft; k++) { + bVal = pArithDecoder->DECODE(&gbContext[CONTEXT]); + cVal |= bVal << (7 - k); + CONTEXT = ((CONTEXT & 0x01bd) << 1) | bVal | + (((line2 >> (10 - k))) & 0x0004); + } + m_pLine[nLineBytes] = cVal; + } + } + m_pLine += nStride; + if (pPause && m_loopIndex % 50 == 0 && pPause->NeedToPauseNow()) { + m_loopIndex++; + m_ProssiveStatus = FXCODEC_STATUS_DECODE_TOBECONTINUE; + return FXCODEC_STATUS_DECODE_TOBECONTINUE; + } + } + m_ProssiveStatus = FXCODEC_STATUS_DECODE_FINISH; + return FXCODEC_STATUS_DECODE_FINISH; +} + +FXCODEC_STATUS CJBig2_GRDProc::decode_Arith_Template2_unopt( + CJBig2_Image* pImage, + CJBig2_ArithDecoder* pArithDecoder, + JBig2ArithCtx* gbContext, + IFX_Pause* pPause) { + FX_BOOL SLTP, bVal; + FX_DWORD CONTEXT; + FX_DWORD line1, line2, line3; + for (; m_loopIndex < GBH; m_loopIndex++) { + if (TPGDON) { + SLTP = pArithDecoder->DECODE(&gbContext[0x00e5]); + LTP = LTP ^ SLTP; + } + if (LTP == 1) { + pImage->copyLine(m_loopIndex, m_loopIndex - 1); + } else { + line1 = pImage->getPixel(1, m_loopIndex - 2); + line1 |= pImage->getPixel(0, m_loopIndex - 2) << 1; + line2 = pImage->getPixel(1, m_loopIndex - 1); + line2 |= pImage->getPixel(0, m_loopIndex - 1) << 1; + line3 = 0; + for (FX_DWORD w = 0; w < GBW; w++) { + if (USESKIP && SKIP->getPixel(w, m_loopIndex)) { + bVal = 0; + } else { + CONTEXT = line3; + CONTEXT |= pImage->getPixel(w + GBAT[0], m_loopIndex + GBAT[1]) << 2; + CONTEXT |= line2 << 3; + CONTEXT |= line1 << 7; + bVal = pArithDecoder->DECODE(&gbContext[CONTEXT]); + } + if (bVal) { + pImage->setPixel(w, m_loopIndex, bVal); + } + line1 = + ((line1 << 1) | pImage->getPixel(w + 2, m_loopIndex - 2)) & 0x07; + line2 = + ((line2 << 1) | pImage->getPixel(w + 2, m_loopIndex - 1)) & 0x0f; + line3 = ((line3 << 1) | bVal) & 0x03; + } + } + if (pPause && pPause->NeedToPauseNow()) { + m_loopIndex++; + m_ProssiveStatus = FXCODEC_STATUS_DECODE_TOBECONTINUE; + return FXCODEC_STATUS_DECODE_TOBECONTINUE; + } + } + m_ProssiveStatus = FXCODEC_STATUS_DECODE_FINISH; + return FXCODEC_STATUS_DECODE_FINISH; +} + +FXCODEC_STATUS CJBig2_GRDProc::decode_Arith_Template3_opt3( + CJBig2_Image* pImage, + CJBig2_ArithDecoder* pArithDecoder, + JBig2ArithCtx* gbContext, + IFX_Pause* pPause) { + FX_BOOL SLTP, bVal; + FX_DWORD CONTEXT; + FX_DWORD line1; + uint8_t *pLine1, cVal; + int32_t nStride, k; + int32_t nLineBytes, nBitsLeft, cc; + if (!m_pLine) { + m_pLine = pImage->m_pData; + } + nStride = pImage->m_nStride; + nLineBytes = ((GBW + 7) >> 3) - 1; + nBitsLeft = GBW - (nLineBytes << 3); + for (; m_loopIndex < GBH; m_loopIndex++) { + if (TPGDON) { + SLTP = pArithDecoder->DECODE(&gbContext[0x0195]); + LTP = LTP ^ SLTP; + } + if (LTP == 1) { + pImage->copyLine(m_loopIndex, m_loopIndex - 1); + } else { + if (m_loopIndex > 0) { + pLine1 = m_pLine - nStride; + line1 = *pLine1++; + CONTEXT = (line1 >> 1) & 0x03f0; + for (cc = 0; cc < nLineBytes; cc++) { + line1 = (line1 << 8) | (*pLine1++); + cVal = 0; + for (k = 7; k >= 0; k--) { + bVal = pArithDecoder->DECODE(&gbContext[CONTEXT]); + cVal |= bVal << k; + CONTEXT = ((CONTEXT & 0x01f7) << 1) | bVal | + ((line1 >> (k + 1)) & 0x0010); + } + m_pLine[cc] = cVal; + } + line1 <<= 8; + cVal = 0; + for (k = 0; k < nBitsLeft; k++) { + bVal = pArithDecoder->DECODE(&gbContext[CONTEXT]); + cVal |= bVal << (7 - k); + CONTEXT = + ((CONTEXT & 0x01f7) << 1) | bVal | ((line1 >> (8 - k)) & 0x0010); + } + m_pLine[nLineBytes] = cVal; + } else { + CONTEXT = 0; + for (cc = 0; cc < nLineBytes; cc++) { + cVal = 0; + for (k = 7; k >= 0; k--) { + bVal = pArithDecoder->DECODE(&gbContext[CONTEXT]); + cVal |= bVal << k; + CONTEXT = ((CONTEXT & 0x01f7) << 1) | bVal; + } + m_pLine[cc] = cVal; + } + cVal = 0; + for (k = 0; k < nBitsLeft; k++) { + bVal = pArithDecoder->DECODE(&gbContext[CONTEXT]); + cVal |= bVal << (7 - k); + CONTEXT = ((CONTEXT & 0x01f7) << 1) | bVal; + } + m_pLine[nLineBytes] = cVal; + } + } + m_pLine += nStride; + if (pPause && pPause->NeedToPauseNow()) { + m_loopIndex++; + m_ProssiveStatus = FXCODEC_STATUS_DECODE_TOBECONTINUE; + return FXCODEC_STATUS_DECODE_TOBECONTINUE; + } + } + m_ProssiveStatus = FXCODEC_STATUS_DECODE_FINISH; + return FXCODEC_STATUS_DECODE_FINISH; +} + +FXCODEC_STATUS CJBig2_GRDProc::decode_Arith_Template3_unopt( + CJBig2_Image* pImage, + CJBig2_ArithDecoder* pArithDecoder, + JBig2ArithCtx* gbContext, + IFX_Pause* pPause) { + FX_BOOL SLTP, bVal; + FX_DWORD CONTEXT; + FX_DWORD line1, line2; + for (; m_loopIndex < GBH; m_loopIndex++) { + if (TPGDON) { + SLTP = pArithDecoder->DECODE(&gbContext[0x0195]); + LTP = LTP ^ SLTP; + } + if (LTP == 1) { + pImage->copyLine(m_loopIndex, m_loopIndex - 1); + } else { + line1 = pImage->getPixel(1, m_loopIndex - 1); + line1 |= pImage->getPixel(0, m_loopIndex - 1) << 1; + line2 = 0; + for (FX_DWORD w = 0; w < GBW; w++) { + if (USESKIP && SKIP->getPixel(w, m_loopIndex)) { + bVal = 0; + } else { + CONTEXT = line2; + CONTEXT |= pImage->getPixel(w + GBAT[0], m_loopIndex + GBAT[1]) << 4; + CONTEXT |= line1 << 5; + bVal = pArithDecoder->DECODE(&gbContext[CONTEXT]); + } + if (bVal) { + pImage->setPixel(w, m_loopIndex, bVal); + } + line1 = + ((line1 << 1) | pImage->getPixel(w + 2, m_loopIndex - 1)) & 0x1f; + line2 = ((line2 << 1) | bVal) & 0x0f; + } + } + if (pPause && pPause->NeedToPauseNow()) { + m_loopIndex++; + m_ProssiveStatus = FXCODEC_STATUS_DECODE_TOBECONTINUE; + return FXCODEC_STATUS_DECODE_TOBECONTINUE; + } + } + m_ProssiveStatus = FXCODEC_STATUS_DECODE_FINISH; + return FXCODEC_STATUS_DECODE_FINISH; +} diff --git a/core/fxcodec/jbig2/JBig2_GrdProc.h b/core/fxcodec/jbig2/JBig2_GrdProc.h new file mode 100644 index 0000000000..2a181b1822 --- /dev/null +++ b/core/fxcodec/jbig2/JBig2_GrdProc.h @@ -0,0 +1,124 @@ +// Copyright 2015 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#ifndef CORE_FXCODEC_JBIG2_JBIG2_GRDPROC_H_ +#define CORE_FXCODEC_JBIG2_JBIG2_GRDPROC_H_ + +#include "core/include/fxcodec/fx_codec_def.h" +#include "core/include/fxcrt/fx_coordinates.h" +#include "core/include/fxcrt/fx_system.h" + +class CJBig2_ArithDecoder; +class CJBig2_BitStream; +class CJBig2_Image; +class IFX_Pause; +struct JBig2ArithCtx; + +class CJBig2_GRDProc { + public: + CJBig2_GRDProc(); + + CJBig2_Image* decode_Arith(CJBig2_ArithDecoder* pArithDecoder, + JBig2ArithCtx* gbContext); + + FXCODEC_STATUS Start_decode_Arith(CJBig2_Image** pImage, + CJBig2_ArithDecoder* pArithDecoder, + JBig2ArithCtx* gbContext, + IFX_Pause* pPause); + FXCODEC_STATUS Start_decode_MMR(CJBig2_Image** pImage, + CJBig2_BitStream* pStream, + IFX_Pause* pPause); + FXCODEC_STATUS Continue_decode(IFX_Pause* pPause); + FX_RECT GetReplaceRect() const { return m_ReplaceRect; } + + FX_BOOL MMR; + FX_DWORD GBW; + FX_DWORD GBH; + uint8_t GBTEMPLATE; + FX_BOOL TPGDON; + FX_BOOL USESKIP; + CJBig2_Image* SKIP; + int8_t GBAT[8]; + + private: + bool UseTemplate0Opt3() const; + bool UseTemplate1Opt3() const; + bool UseTemplate23Opt3() const; + + FXCODEC_STATUS decode_Arith(IFX_Pause* pPause); + FXCODEC_STATUS decode_Arith_Template0_opt3(CJBig2_Image* pImage, + CJBig2_ArithDecoder* pArithDecoder, + JBig2ArithCtx* gbContext, + IFX_Pause* pPause); + FXCODEC_STATUS decode_Arith_Template0_unopt( + CJBig2_Image* pImage, + CJBig2_ArithDecoder* pArithDecoder, + JBig2ArithCtx* gbContext, + IFX_Pause* pPause); + FXCODEC_STATUS decode_Arith_Template1_opt3(CJBig2_Image* pImage, + CJBig2_ArithDecoder* pArithDecoder, + JBig2ArithCtx* gbContext, + IFX_Pause* pPause); + FXCODEC_STATUS decode_Arith_Template1_unopt( + CJBig2_Image* pImage, + CJBig2_ArithDecoder* pArithDecoder, + JBig2ArithCtx* gbContext, + IFX_Pause* pPause); + FXCODEC_STATUS decode_Arith_Template2_opt3(CJBig2_Image* pImage, + CJBig2_ArithDecoder* pArithDecoder, + JBig2ArithCtx* gbContext, + IFX_Pause* pPause); + FXCODEC_STATUS decode_Arith_Template2_unopt( + CJBig2_Image* pImage, + CJBig2_ArithDecoder* pArithDecoder, + JBig2ArithCtx* gbContext, + IFX_Pause* pPause); + FXCODEC_STATUS decode_Arith_Template3_opt3(CJBig2_Image* pImage, + CJBig2_ArithDecoder* pArithDecoder, + JBig2ArithCtx* gbContext, + IFX_Pause* pPause); + FXCODEC_STATUS decode_Arith_Template3_unopt( + CJBig2_Image* pImage, + CJBig2_ArithDecoder* pArithDecoder, + JBig2ArithCtx* gbContext, + IFX_Pause* pPause); + CJBig2_Image* decode_Arith_Template0_opt3(CJBig2_ArithDecoder* pArithDecoder, + JBig2ArithCtx* gbContext); + + CJBig2_Image* decode_Arith_Template0_unopt(CJBig2_ArithDecoder* pArithDecoder, + JBig2ArithCtx* gbContext); + + CJBig2_Image* decode_Arith_Template1_opt3(CJBig2_ArithDecoder* pArithDecoder, + JBig2ArithCtx* gbContext); + + CJBig2_Image* decode_Arith_Template1_unopt(CJBig2_ArithDecoder* pArithDecoder, + JBig2ArithCtx* gbContext); + + CJBig2_Image* decode_Arith_Template2_opt3(CJBig2_ArithDecoder* pArithDecoder, + JBig2ArithCtx* gbContext); + + CJBig2_Image* decode_Arith_Template2_unopt(CJBig2_ArithDecoder* pArithDecoder, + JBig2ArithCtx* gbContext); + + CJBig2_Image* decode_Arith_Template3_opt3(CJBig2_ArithDecoder* pArithDecoder, + JBig2ArithCtx* gbContext); + + CJBig2_Image* decode_Arith_Template3_unopt(CJBig2_ArithDecoder* pArithDecoder, + JBig2ArithCtx* gbContext); + + FX_DWORD m_loopIndex; + uint8_t* m_pLine; + IFX_Pause* m_pPause; + FXCODEC_STATUS m_ProssiveStatus; + CJBig2_Image** m_pImage; + CJBig2_ArithDecoder* m_pArithDecoder; + JBig2ArithCtx* m_gbContext; + FX_WORD m_DecodeType; + FX_BOOL LTP; + FX_RECT m_ReplaceRect; +}; + +#endif // CORE_FXCODEC_JBIG2_JBIG2_GRDPROC_H_ diff --git a/core/fxcodec/jbig2/JBig2_GrrdProc.cpp b/core/fxcodec/jbig2/JBig2_GrrdProc.cpp new file mode 100644 index 0000000000..c6ff3dd647 --- /dev/null +++ b/core/fxcodec/jbig2/JBig2_GrrdProc.cpp @@ -0,0 +1,516 @@ +// Copyright 2015 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "core/fxcodec/jbig2/JBig2_GrrdProc.h" + +#include <memory> + +#include "core/fxcodec/jbig2/JBig2_ArithDecoder.h" +#include "core/fxcodec/jbig2/JBig2_BitStream.h" +#include "core/fxcodec/jbig2/JBig2_Image.h" + +CJBig2_Image* CJBig2_GRRDProc::decode(CJBig2_ArithDecoder* pArithDecoder, + JBig2ArithCtx* grContext) { + if (GRW == 0 || GRH == 0) + return new CJBig2_Image(GRW, GRH); + + if (GRTEMPLATE == 0) { + if ((GRAT[0] == -1) && (GRAT[1] == -1) && (GRAT[2] == -1) && + (GRAT[3] == -1) && (GRREFERENCEDX == 0) && + (GRW == (FX_DWORD)GRREFERENCE->m_nWidth)) { + return decode_Template0_opt(pArithDecoder, grContext); + } + return decode_Template0_unopt(pArithDecoder, grContext); + } + + if ((GRREFERENCEDX == 0) && (GRW == (FX_DWORD)GRREFERENCE->m_nWidth)) + return decode_Template1_opt(pArithDecoder, grContext); + return decode_Template1_unopt(pArithDecoder, grContext); +} + +CJBig2_Image* CJBig2_GRRDProc::decode_Template0_unopt( + CJBig2_ArithDecoder* pArithDecoder, + JBig2ArithCtx* grContext) { + FX_BOOL LTP, SLTP, bVal; + FX_DWORD CONTEXT; + FX_DWORD line1, line2, line3, line4, line5; + LTP = 0; + std::unique_ptr<CJBig2_Image> GRREG(new CJBig2_Image(GRW, GRH)); + GRREG->fill(0); + for (FX_DWORD h = 0; h < GRH; h++) { + if (TPGRON) { + SLTP = pArithDecoder->DECODE(&grContext[0x0010]); + LTP = LTP ^ SLTP; + } + if (LTP == 0) { + line1 = GRREG->getPixel(1, h - 1); + line1 |= GRREG->getPixel(0, h - 1) << 1; + line2 = 0; + line3 = GRREFERENCE->getPixel(-GRREFERENCEDX + 1, h - GRREFERENCEDY - 1); + line3 |= GRREFERENCE->getPixel(-GRREFERENCEDX, h - GRREFERENCEDY - 1) + << 1; + line4 = GRREFERENCE->getPixel(-GRREFERENCEDX + 1, h - GRREFERENCEDY); + line4 |= GRREFERENCE->getPixel(-GRREFERENCEDX, h - GRREFERENCEDY) << 1; + line4 |= GRREFERENCE->getPixel(-GRREFERENCEDX - 1, h - GRREFERENCEDY) + << 2; + line5 = GRREFERENCE->getPixel(-GRREFERENCEDX + 1, h - GRREFERENCEDY + 1); + line5 |= GRREFERENCE->getPixel(-GRREFERENCEDX, h - GRREFERENCEDY + 1) + << 1; + line5 |= GRREFERENCE->getPixel(-GRREFERENCEDX - 1, h - GRREFERENCEDY + 1) + << 2; + for (FX_DWORD w = 0; w < GRW; w++) { + CONTEXT = line5; + CONTEXT |= line4 << 3; + CONTEXT |= line3 << 6; + CONTEXT |= GRREFERENCE->getPixel(w - GRREFERENCEDX + GRAT[2], + h - GRREFERENCEDY + GRAT[3]) + << 8; + CONTEXT |= line2 << 9; + CONTEXT |= line1 << 10; + CONTEXT |= GRREG->getPixel(w + GRAT[0], h + GRAT[1]) << 12; + bVal = pArithDecoder->DECODE(&grContext[CONTEXT]); + GRREG->setPixel(w, h, bVal); + line1 = ((line1 << 1) | GRREG->getPixel(w + 2, h - 1)) & 0x03; + line2 = ((line2 << 1) | bVal) & 0x01; + line3 = ((line3 << 1) | + GRREFERENCE->getPixel(w - GRREFERENCEDX + 2, + h - GRREFERENCEDY - 1)) & + 0x03; + line4 = + ((line4 << 1) | + GRREFERENCE->getPixel(w - GRREFERENCEDX + 2, h - GRREFERENCEDY)) & + 0x07; + line5 = ((line5 << 1) | + GRREFERENCE->getPixel(w - GRREFERENCEDX + 2, + h - GRREFERENCEDY + 1)) & + 0x07; + } + } else { + line1 = GRREG->getPixel(1, h - 1); + line1 |= GRREG->getPixel(0, h - 1) << 1; + line2 = 0; + line3 = GRREFERENCE->getPixel(-GRREFERENCEDX + 1, h - GRREFERENCEDY - 1); + line3 |= GRREFERENCE->getPixel(-GRREFERENCEDX, h - GRREFERENCEDY - 1) + << 1; + line4 = GRREFERENCE->getPixel(-GRREFERENCEDX + 1, h - GRREFERENCEDY); + line4 |= GRREFERENCE->getPixel(-GRREFERENCEDX, h - GRREFERENCEDY) << 1; + line4 |= GRREFERENCE->getPixel(-GRREFERENCEDX - 1, h - GRREFERENCEDY) + << 2; + line5 = GRREFERENCE->getPixel(-GRREFERENCEDX + 1, h - GRREFERENCEDY + 1); + line5 |= GRREFERENCE->getPixel(-GRREFERENCEDX, h - GRREFERENCEDY + 1) + << 1; + line5 |= GRREFERENCE->getPixel(-GRREFERENCEDX - 1, h - GRREFERENCEDY + 1) + << 2; + for (FX_DWORD w = 0; w < GRW; w++) { + bVal = GRREFERENCE->getPixel(w, h); + if (!(TPGRON && (bVal == GRREFERENCE->getPixel(w - 1, h - 1)) && + (bVal == GRREFERENCE->getPixel(w, h - 1)) && + (bVal == GRREFERENCE->getPixel(w + 1, h - 1)) && + (bVal == GRREFERENCE->getPixel(w - 1, h)) && + (bVal == GRREFERENCE->getPixel(w + 1, h)) && + (bVal == GRREFERENCE->getPixel(w - 1, h + 1)) && + (bVal == GRREFERENCE->getPixel(w, h + 1)) && + (bVal == GRREFERENCE->getPixel(w + 1, h + 1)))) { + CONTEXT = line5; + CONTEXT |= line4 << 3; + CONTEXT |= line3 << 6; + CONTEXT |= GRREFERENCE->getPixel(w - GRREFERENCEDX + GRAT[2], + h - GRREFERENCEDY + GRAT[3]) + << 8; + CONTEXT |= line2 << 9; + CONTEXT |= line1 << 10; + CONTEXT |= GRREG->getPixel(w + GRAT[0], h + GRAT[1]) << 12; + bVal = pArithDecoder->DECODE(&grContext[CONTEXT]); + } + GRREG->setPixel(w, h, bVal); + line1 = ((line1 << 1) | GRREG->getPixel(w + 2, h - 1)) & 0x03; + line2 = ((line2 << 1) | bVal) & 0x01; + line3 = ((line3 << 1) | + GRREFERENCE->getPixel(w - GRREFERENCEDX + 2, + h - GRREFERENCEDY - 1)) & + 0x03; + line4 = + ((line4 << 1) | + GRREFERENCE->getPixel(w - GRREFERENCEDX + 2, h - GRREFERENCEDY)) & + 0x07; + line5 = ((line5 << 1) | + GRREFERENCE->getPixel(w - GRREFERENCEDX + 2, + h - GRREFERENCEDY + 1)) & + 0x07; + } + } + } + return GRREG.release(); +} + +CJBig2_Image* CJBig2_GRRDProc::decode_Template0_opt( + CJBig2_ArithDecoder* pArithDecoder, + JBig2ArithCtx* grContext) { + if (!GRREFERENCE->m_pData) + return nullptr; + + FX_BOOL LTP, SLTP, bVal; + FX_DWORD CONTEXT; + FX_DWORD line1, line1_r, line2_r, line3_r; + uint8_t *pLine, *pLineR, cVal; + intptr_t nStride, nStrideR, nOffset; + int32_t k, nBits; + int32_t GRWR, GRHR; + int32_t GRW, GRH; + GRW = (int32_t)CJBig2_GRRDProc::GRW; + GRH = (int32_t)CJBig2_GRRDProc::GRH; + LTP = 0; + std::unique_ptr<CJBig2_Image> GRREG(new CJBig2_Image(GRW, GRH)); + if (!GRREG->m_pData) + return nullptr; + + pLine = GRREG->m_pData; + pLineR = GRREFERENCE->m_pData; + nStride = GRREG->m_nStride; + nStrideR = GRREFERENCE->m_nStride; + GRWR = (int32_t)GRREFERENCE->m_nWidth; + GRHR = (int32_t)GRREFERENCE->m_nHeight; + if (GRREFERENCEDY < -GRHR + 1 || GRREFERENCEDY > GRHR - 1) { + GRREFERENCEDY = 0; + } + nOffset = -GRREFERENCEDY * nStrideR; + for (int32_t h = 0; h < GRH; h++) { + if (TPGRON) { + SLTP = pArithDecoder->DECODE(&grContext[0x0010]); + LTP = LTP ^ SLTP; + } + line1 = (h > 0) ? pLine[-nStride] << 4 : 0; + int32_t reference_h = h - GRREFERENCEDY; + FX_BOOL line1_r_ok = (reference_h > 0 && reference_h < GRHR + 1); + FX_BOOL line2_r_ok = (reference_h > -1 && reference_h < GRHR); + FX_BOOL line3_r_ok = (reference_h > -2 && reference_h < GRHR - 1); + line1_r = line1_r_ok ? pLineR[nOffset - nStrideR] : 0; + line2_r = line2_r_ok ? pLineR[nOffset] : 0; + line3_r = line3_r_ok ? pLineR[nOffset + nStrideR] : 0; + if (LTP == 0) { + CONTEXT = (line1 & 0x1c00) | (line1_r & 0x01c0) | + ((line2_r >> 3) & 0x0038) | ((line3_r >> 6) & 0x0007); + for (int32_t w = 0; w < GRW; w += 8) { + nBits = GRW - w > 8 ? 8 : GRW - w; + if (h > 0) + line1 = (line1 << 8) | + (w + 8 < GRW ? pLine[-nStride + (w >> 3) + 1] << 4 : 0); + if (h > GRHR + GRREFERENCEDY + 1) { + line1_r = 0; + line2_r = 0; + line3_r = 0; + } else { + if (line1_r_ok) + line1_r = + (line1_r << 8) | + (w + 8 < GRWR ? pLineR[nOffset - nStrideR + (w >> 3) + 1] : 0); + if (line2_r_ok) + line2_r = (line2_r << 8) | + (w + 8 < GRWR ? pLineR[nOffset + (w >> 3) + 1] : 0); + if (line3_r_ok) { + line3_r = + (line3_r << 8) | + (w + 8 < GRWR ? pLineR[nOffset + nStrideR + (w >> 3) + 1] : 0); + } else { + line3_r = 0; + } + } + cVal = 0; + for (k = 0; k < nBits; k++) { + bVal = pArithDecoder->DECODE(&grContext[CONTEXT]); + cVal |= bVal << (7 - k); + CONTEXT = ((CONTEXT & 0x0cdb) << 1) | (bVal << 9) | + ((line1 >> (7 - k)) & 0x0400) | + ((line1_r >> (7 - k)) & 0x0040) | + ((line2_r >> (10 - k)) & 0x0008) | + ((line3_r >> (13 - k)) & 0x0001); + } + pLine[w >> 3] = cVal; + } + } else { + CONTEXT = (line1 & 0x1c00) | (line1_r & 0x01c0) | + ((line2_r >> 3) & 0x0038) | ((line3_r >> 6) & 0x0007); + for (int32_t w = 0; w < GRW; w += 8) { + nBits = GRW - w > 8 ? 8 : GRW - w; + if (h > 0) + line1 = (line1 << 8) | + (w + 8 < GRW ? pLine[-nStride + (w >> 3) + 1] << 4 : 0); + if (line1_r_ok) + line1_r = + (line1_r << 8) | + (w + 8 < GRWR ? pLineR[nOffset - nStrideR + (w >> 3) + 1] : 0); + if (line2_r_ok) + line2_r = (line2_r << 8) | + (w + 8 < GRWR ? pLineR[nOffset + (w >> 3) + 1] : 0); + if (line3_r_ok) { + line3_r = + (line3_r << 8) | + (w + 8 < GRWR ? pLineR[nOffset + nStrideR + (w >> 3) + 1] : 0); + } else { + line3_r = 0; + } + cVal = 0; + for (k = 0; k < nBits; k++) { + bVal = GRREFERENCE->getPixel(w + k, h); + if (!(TPGRON && (bVal == GRREFERENCE->getPixel(w + k - 1, h - 1)) && + (bVal == GRREFERENCE->getPixel(w + k, h - 1)) && + (bVal == GRREFERENCE->getPixel(w + k + 1, h - 1)) && + (bVal == GRREFERENCE->getPixel(w + k - 1, h)) && + (bVal == GRREFERENCE->getPixel(w + k + 1, h)) && + (bVal == GRREFERENCE->getPixel(w + k - 1, h + 1)) && + (bVal == GRREFERENCE->getPixel(w + k, h + 1)) && + (bVal == GRREFERENCE->getPixel(w + k + 1, h + 1)))) { + bVal = pArithDecoder->DECODE(&grContext[CONTEXT]); + } + cVal |= bVal << (7 - k); + CONTEXT = ((CONTEXT & 0x0cdb) << 1) | (bVal << 9) | + ((line1 >> (7 - k)) & 0x0400) | + ((line1_r >> (7 - k)) & 0x0040) | + ((line2_r >> (10 - k)) & 0x0008) | + ((line3_r >> (13 - k)) & 0x0001); + } + pLine[w >> 3] = cVal; + } + } + pLine += nStride; + if (h < GRHR + GRREFERENCEDY) { + pLineR += nStrideR; + } + } + return GRREG.release(); +} + +CJBig2_Image* CJBig2_GRRDProc::decode_Template1_unopt( + CJBig2_ArithDecoder* pArithDecoder, + JBig2ArithCtx* grContext) { + FX_BOOL LTP, SLTP, bVal; + FX_DWORD CONTEXT; + FX_DWORD line1, line2, line3, line4, line5; + LTP = 0; + std::unique_ptr<CJBig2_Image> GRREG(new CJBig2_Image(GRW, GRH)); + GRREG->fill(0); + for (FX_DWORD h = 0; h < GRH; h++) { + if (TPGRON) { + SLTP = pArithDecoder->DECODE(&grContext[0x0008]); + LTP = LTP ^ SLTP; + } + if (LTP == 0) { + line1 = GRREG->getPixel(1, h - 1); + line1 |= GRREG->getPixel(0, h - 1) << 1; + line1 |= GRREG->getPixel(-1, h - 1) << 2; + line2 = 0; + line3 = GRREFERENCE->getPixel(-GRREFERENCEDX, h - GRREFERENCEDY - 1); + line4 = GRREFERENCE->getPixel(-GRREFERENCEDX + 1, h - GRREFERENCEDY); + line4 |= GRREFERENCE->getPixel(-GRREFERENCEDX, h - GRREFERENCEDY) << 1; + line4 |= GRREFERENCE->getPixel(-GRREFERENCEDX - 1, h - GRREFERENCEDY) + << 2; + line5 = GRREFERENCE->getPixel(-GRREFERENCEDX + 1, h - GRREFERENCEDY + 1); + line5 |= GRREFERENCE->getPixel(-GRREFERENCEDX, h - GRREFERENCEDY + 1) + << 1; + for (FX_DWORD w = 0; w < GRW; w++) { + CONTEXT = line5; + CONTEXT |= line4 << 2; + CONTEXT |= line3 << 5; + CONTEXT |= line2 << 6; + CONTEXT |= line1 << 7; + bVal = pArithDecoder->DECODE(&grContext[CONTEXT]); + GRREG->setPixel(w, h, bVal); + line1 = ((line1 << 1) | GRREG->getPixel(w + 2, h - 1)) & 0x07; + line2 = ((line2 << 1) | bVal) & 0x01; + line3 = ((line3 << 1) | + GRREFERENCE->getPixel(w - GRREFERENCEDX + 1, + h - GRREFERENCEDY - 1)) & + 0x01; + line4 = + ((line4 << 1) | + GRREFERENCE->getPixel(w - GRREFERENCEDX + 2, h - GRREFERENCEDY)) & + 0x07; + line5 = ((line5 << 1) | + GRREFERENCE->getPixel(w - GRREFERENCEDX + 2, + h - GRREFERENCEDY + 1)) & + 0x03; + } + } else { + line1 = GRREG->getPixel(1, h - 1); + line1 |= GRREG->getPixel(0, h - 1) << 1; + line1 |= GRREG->getPixel(-1, h - 1) << 2; + line2 = 0; + line3 = GRREFERENCE->getPixel(-GRREFERENCEDX, h - GRREFERENCEDY - 1); + line4 = GRREFERENCE->getPixel(-GRREFERENCEDX + 1, h - GRREFERENCEDY); + line4 |= GRREFERENCE->getPixel(-GRREFERENCEDX, h - GRREFERENCEDY) << 1; + line4 |= GRREFERENCE->getPixel(-GRREFERENCEDX - 1, h - GRREFERENCEDY) + << 2; + line5 = GRREFERENCE->getPixel(-GRREFERENCEDX + 1, h - GRREFERENCEDY + 1); + line5 |= GRREFERENCE->getPixel(-GRREFERENCEDX, h - GRREFERENCEDY + 1) + << 1; + for (FX_DWORD w = 0; w < GRW; w++) { + bVal = GRREFERENCE->getPixel(w, h); + if (!(TPGRON && (bVal == GRREFERENCE->getPixel(w - 1, h - 1)) && + (bVal == GRREFERENCE->getPixel(w, h - 1)) && + (bVal == GRREFERENCE->getPixel(w + 1, h - 1)) && + (bVal == GRREFERENCE->getPixel(w - 1, h)) && + (bVal == GRREFERENCE->getPixel(w + 1, h)) && + (bVal == GRREFERENCE->getPixel(w - 1, h + 1)) && + (bVal == GRREFERENCE->getPixel(w, h + 1)) && + (bVal == GRREFERENCE->getPixel(w + 1, h + 1)))) { + CONTEXT = line5; + CONTEXT |= line4 << 2; + CONTEXT |= line3 << 5; + CONTEXT |= line2 << 6; + CONTEXT |= line1 << 7; + bVal = pArithDecoder->DECODE(&grContext[CONTEXT]); + } + GRREG->setPixel(w, h, bVal); + line1 = ((line1 << 1) | GRREG->getPixel(w + 2, h - 1)) & 0x07; + line2 = ((line2 << 1) | bVal) & 0x01; + line3 = ((line3 << 1) | + GRREFERENCE->getPixel(w - GRREFERENCEDX + 1, + h - GRREFERENCEDY - 1)) & + 0x01; + line4 = + ((line4 << 1) | + GRREFERENCE->getPixel(w - GRREFERENCEDX + 2, h - GRREFERENCEDY)) & + 0x07; + line5 = ((line5 << 1) | + GRREFERENCE->getPixel(w - GRREFERENCEDX + 2, + h - GRREFERENCEDY + 1)) & + 0x03; + } + } + } + return GRREG.release(); +} + +CJBig2_Image* CJBig2_GRRDProc::decode_Template1_opt( + CJBig2_ArithDecoder* pArithDecoder, + JBig2ArithCtx* grContext) { + if (!GRREFERENCE->m_pData) + return nullptr; + + FX_BOOL LTP, SLTP, bVal; + FX_DWORD CONTEXT; + FX_DWORD line1, line1_r, line2_r, line3_r; + uint8_t *pLine, *pLineR, cVal; + intptr_t nStride, nStrideR, nOffset; + int32_t k, nBits; + int32_t GRWR, GRHR; + int32_t GRW, GRH; + GRW = (int32_t)CJBig2_GRRDProc::GRW; + GRH = (int32_t)CJBig2_GRRDProc::GRH; + LTP = 0; + std::unique_ptr<CJBig2_Image> GRREG(new CJBig2_Image(GRW, GRH)); + if (!GRREG->m_pData) + return nullptr; + + pLine = GRREG->m_pData; + pLineR = GRREFERENCE->m_pData; + nStride = GRREG->m_nStride; + nStrideR = GRREFERENCE->m_nStride; + GRWR = (int32_t)GRREFERENCE->m_nWidth; + GRHR = (int32_t)GRREFERENCE->m_nHeight; + if (GRREFERENCEDY < -GRHR + 1 || GRREFERENCEDY > GRHR - 1) { + GRREFERENCEDY = 0; + } + nOffset = -GRREFERENCEDY * nStrideR; + for (int32_t h = 0; h < GRH; h++) { + if (TPGRON) { + SLTP = pArithDecoder->DECODE(&grContext[0x0008]); + LTP = LTP ^ SLTP; + } + line1 = (h > 0) ? pLine[-nStride] << 1 : 0; + int32_t reference_h = h - GRREFERENCEDY; + FX_BOOL line1_r_ok = (reference_h > 0 && reference_h < GRHR + 1); + FX_BOOL line2_r_ok = (reference_h > -1 && reference_h < GRHR); + FX_BOOL line3_r_ok = (reference_h > -2 && reference_h < GRHR - 1); + line1_r = line1_r_ok ? pLineR[nOffset - nStrideR] : 0; + line2_r = line2_r_ok ? pLineR[nOffset] : 0; + line3_r = line3_r_ok ? pLineR[nOffset + nStrideR] : 0; + if (LTP == 0) { + CONTEXT = (line1 & 0x0380) | ((line1_r >> 2) & 0x0020) | + ((line2_r >> 4) & 0x001c) | ((line3_r >> 6) & 0x0003); + for (int32_t w = 0; w < GRW; w += 8) { + nBits = GRW - w > 8 ? 8 : GRW - w; + if (h > 0) + line1 = (line1 << 8) | + (w + 8 < GRW ? pLine[-nStride + (w >> 3) + 1] << 1 : 0); + if (line1_r_ok) + line1_r = + (line1_r << 8) | + (w + 8 < GRWR ? pLineR[nOffset - nStrideR + (w >> 3) + 1] : 0); + if (line2_r_ok) + line2_r = (line2_r << 8) | + (w + 8 < GRWR ? pLineR[nOffset + (w >> 3) + 1] : 0); + if (line3_r_ok) { + line3_r = + (line3_r << 8) | + (w + 8 < GRWR ? pLineR[nOffset + nStrideR + (w >> 3) + 1] : 0); + } else { + line3_r = 0; + } + cVal = 0; + for (k = 0; k < nBits; k++) { + bVal = pArithDecoder->DECODE(&grContext[CONTEXT]); + cVal |= bVal << (7 - k); + CONTEXT = ((CONTEXT & 0x018d) << 1) | (bVal << 6) | + ((line1 >> (7 - k)) & 0x0080) | + ((line1_r >> (9 - k)) & 0x0020) | + ((line2_r >> (11 - k)) & 0x0004) | + ((line3_r >> (13 - k)) & 0x0001); + } + pLine[w >> 3] = cVal; + } + } else { + CONTEXT = (line1 & 0x0380) | ((line1_r >> 2) & 0x0020) | + ((line2_r >> 4) & 0x001c) | ((line3_r >> 6) & 0x0003); + for (int32_t w = 0; w < GRW; w += 8) { + nBits = GRW - w > 8 ? 8 : GRW - w; + if (h > 0) + line1 = (line1 << 8) | + (w + 8 < GRW ? pLine[-nStride + (w >> 3) + 1] << 1 : 0); + if (line1_r_ok) + line1_r = + (line1_r << 8) | + (w + 8 < GRWR ? pLineR[nOffset - nStrideR + (w >> 3) + 1] : 0); + if (line2_r_ok) + line2_r = (line2_r << 8) | + (w + 8 < GRWR ? pLineR[nOffset + (w >> 3) + 1] : 0); + if (line3_r_ok) { + line3_r = + (line3_r << 8) | + (w + 8 < GRWR ? pLineR[nOffset + nStrideR + (w >> 3) + 1] : 0); + } else { + line3_r = 0; + } + cVal = 0; + for (k = 0; k < nBits; k++) { + bVal = GRREFERENCE->getPixel(w + k, h); + if (!(TPGRON && (bVal == GRREFERENCE->getPixel(w + k - 1, h - 1)) && + (bVal == GRREFERENCE->getPixel(w + k, h - 1)) && + (bVal == GRREFERENCE->getPixel(w + k + 1, h - 1)) && + (bVal == GRREFERENCE->getPixel(w + k - 1, h)) && + (bVal == GRREFERENCE->getPixel(w + k + 1, h)) && + (bVal == GRREFERENCE->getPixel(w + k - 1, h + 1)) && + (bVal == GRREFERENCE->getPixel(w + k, h + 1)) && + (bVal == GRREFERENCE->getPixel(w + k + 1, h + 1)))) { + bVal = pArithDecoder->DECODE(&grContext[CONTEXT]); + } + cVal |= bVal << (7 - k); + CONTEXT = ((CONTEXT & 0x018d) << 1) | (bVal << 6) | + ((line1 >> (7 - k)) & 0x0080) | + ((line1_r >> (9 - k)) & 0x0020) | + ((line2_r >> (11 - k)) & 0x0004) | + ((line3_r >> (13 - k)) & 0x0001); + } + pLine[w >> 3] = cVal; + } + } + pLine += nStride; + if (h < GRHR + GRREFERENCEDY) { + pLineR += nStrideR; + } + } + return GRREG.release(); +} diff --git a/core/fxcodec/jbig2/JBig2_GrrdProc.h b/core/fxcodec/jbig2/JBig2_GrrdProc.h new file mode 100644 index 0000000000..36cfdcae3c --- /dev/null +++ b/core/fxcodec/jbig2/JBig2_GrrdProc.h @@ -0,0 +1,43 @@ +// Copyright 2015 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#ifndef CORE_FXCODEC_JBIG2_JBIG2_GRRDPROC_H_ +#define CORE_FXCODEC_JBIG2_JBIG2_GRRDPROC_H_ + +#include "core/include/fxcrt/fx_system.h" + +class CJBig2_ArithDecoder; +class CJBig2_Image; +struct JBig2ArithCtx; + +class CJBig2_GRRDProc { + public: + CJBig2_Image* decode(CJBig2_ArithDecoder* pArithDecoder, + JBig2ArithCtx* grContext); + + CJBig2_Image* decode_Template0_unopt(CJBig2_ArithDecoder* pArithDecoder, + JBig2ArithCtx* grContext); + + CJBig2_Image* decode_Template0_opt(CJBig2_ArithDecoder* pArithDecoder, + JBig2ArithCtx* grContext); + + CJBig2_Image* decode_Template1_unopt(CJBig2_ArithDecoder* pArithDecoder, + JBig2ArithCtx* grContext); + + CJBig2_Image* decode_Template1_opt(CJBig2_ArithDecoder* pArithDecoder, + JBig2ArithCtx* grContext); + + FX_DWORD GRW; + FX_DWORD GRH; + FX_BOOL GRTEMPLATE; + CJBig2_Image* GRREFERENCE; + int32_t GRREFERENCEDX; + int32_t GRREFERENCEDY; + FX_BOOL TPGRON; + int8_t GRAT[4]; +}; + +#endif // CORE_FXCODEC_JBIG2_JBIG2_GRRDPROC_H_ diff --git a/core/fxcodec/jbig2/JBig2_GsidProc.cpp b/core/fxcodec/jbig2/JBig2_GsidProc.cpp new file mode 100644 index 0000000000..92532d7238 --- /dev/null +++ b/core/fxcodec/jbig2/JBig2_GsidProc.cpp @@ -0,0 +1,123 @@ +// Copyright 2015 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "core/fxcodec/jbig2/JBig2_GsidProc.h" + +#include <memory> + +#include "core/fxcodec/jbig2/JBig2_BitStream.h" +#include "core/fxcodec/jbig2/JBig2_GrdProc.h" +#include "core/fxcodec/jbig2/JBig2_Image.h" +#include "core/fxcodec/jbig2/JBig2_List.h" +#include "core/include/fxcrt/fx_basic.h" + +FX_DWORD* CJBig2_GSIDProc::decode_Arith(CJBig2_ArithDecoder* pArithDecoder, + JBig2ArithCtx* gbContext, + IFX_Pause* pPause) { + std::unique_ptr<CJBig2_GRDProc> pGRD(new CJBig2_GRDProc()); + pGRD->MMR = GSMMR; + pGRD->GBW = GSW; + pGRD->GBH = GSH; + pGRD->GBTEMPLATE = GSTEMPLATE; + pGRD->TPGDON = 0; + pGRD->USESKIP = GSUSESKIP; + pGRD->SKIP = GSKIP; + if (GSTEMPLATE <= 1) { + pGRD->GBAT[0] = 3; + } else { + pGRD->GBAT[0] = 2; + } + pGRD->GBAT[1] = -1; + if (pGRD->GBTEMPLATE == 0) { + pGRD->GBAT[2] = -3; + pGRD->GBAT[3] = -1; + pGRD->GBAT[4] = 2; + pGRD->GBAT[5] = -2; + pGRD->GBAT[6] = -2; + pGRD->GBAT[7] = -2; + } + + CJBig2_List<CJBig2_Image> GSPLANES(GSBPP); + for (int32_t i = GSBPP - 1; i >= 0; --i) { + CJBig2_Image* pImage = nullptr; + FXCODEC_STATUS status = + pGRD->Start_decode_Arith(&pImage, pArithDecoder, gbContext, nullptr); + while (status == FXCODEC_STATUS_DECODE_TOBECONTINUE) + pGRD->Continue_decode(pPause); + + if (!pImage) + return nullptr; + + GSPLANES.set(i, pImage); + + if (i < GSBPP - 1) + pImage->composeFrom(0, 0, GSPLANES.get(i + 1), JBIG2_COMPOSE_XOR); + } + std::unique_ptr<FX_DWORD, FxFreeDeleter> GSVALS( + FX_Alloc2D(FX_DWORD, GSW, GSH)); + JBIG2_memset(GSVALS.get(), 0, sizeof(FX_DWORD) * GSW * GSH); + for (FX_DWORD y = 0; y < GSH; ++y) { + for (FX_DWORD x = 0; x < GSW; ++x) { + for (int32_t i = 0; i < GSBPP; ++i) { + GSVALS.get()[y * GSW + x] |= GSPLANES.get(i)->getPixel(x, y) << i; + } + } + } + return GSVALS.release(); +} + +FX_DWORD* CJBig2_GSIDProc::decode_MMR(CJBig2_BitStream* pStream, + IFX_Pause* pPause) { + std::unique_ptr<CJBig2_GRDProc> pGRD(new CJBig2_GRDProc()); + pGRD->MMR = GSMMR; + pGRD->GBW = GSW; + pGRD->GBH = GSH; + + std::unique_ptr<CJBig2_Image*> GSPLANES(FX_Alloc(CJBig2_Image*, GSBPP)); + JBIG2_memset(GSPLANES.get(), 0, sizeof(CJBig2_Image*) * GSBPP); + FXCODEC_STATUS status = + pGRD->Start_decode_MMR(&GSPLANES.get()[GSBPP - 1], pStream, nullptr); + while (status == FXCODEC_STATUS_DECODE_TOBECONTINUE) { + pGRD->Continue_decode(pPause); + } + if (!GSPLANES.get()[GSBPP - 1]) + return nullptr; + + pStream->alignByte(); + pStream->offset(3); + int32_t J = GSBPP - 2; + while (J >= 0) { + FXCODEC_STATUS status = + pGRD->Start_decode_MMR(&GSPLANES.get()[J], pStream, nullptr); + while (status == FXCODEC_STATUS_DECODE_TOBECONTINUE) { + pGRD->Continue_decode(pPause); + } + if (!GSPLANES.get()[J]) { + for (int32_t K = GSBPP - 1; K > J; --K) { + delete GSPLANES.get()[K]; + return nullptr; + } + } + pStream->alignByte(); + pStream->offset(3); + GSPLANES.get()[J]->composeFrom(0, 0, GSPLANES.get()[J + 1], + JBIG2_COMPOSE_XOR); + J = J - 1; + } + std::unique_ptr<FX_DWORD> GSVALS(FX_Alloc2D(FX_DWORD, GSW, GSH)); + JBIG2_memset(GSVALS.get(), 0, sizeof(FX_DWORD) * GSW * GSH); + for (FX_DWORD y = 0; y < GSH; ++y) { + for (FX_DWORD x = 0; x < GSW; ++x) { + for (J = 0; J < GSBPP; ++J) { + GSVALS.get()[y * GSW + x] |= GSPLANES.get()[J]->getPixel(x, y) << J; + } + } + } + for (J = 0; J < GSBPP; ++J) { + delete GSPLANES.get()[J]; + } + return GSVALS.release(); +} diff --git a/core/fxcodec/jbig2/JBig2_GsidProc.h b/core/fxcodec/jbig2/JBig2_GsidProc.h new file mode 100644 index 0000000000..50c24eaa60 --- /dev/null +++ b/core/fxcodec/jbig2/JBig2_GsidProc.h @@ -0,0 +1,36 @@ +// Copyright 2015 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#ifndef CORE_FXCODEC_JBIG2_JBIG2_GSIDPROC_H_ +#define CORE_FXCODEC_JBIG2_JBIG2_GSIDPROC_H_ + +#include "core/include/fxcrt/fx_system.h" + +class CJBig2_ArithDecoder; +class CJBig2_BitStream; +class CJBig2_Image; +class IFX_Pause; +struct JBig2ArithCtx; + +class CJBig2_GSIDProc { + public: + FX_DWORD* decode_Arith(CJBig2_ArithDecoder* pArithDecoder, + JBig2ArithCtx* gbContext, + IFX_Pause* pPause); + + FX_DWORD* decode_MMR(CJBig2_BitStream* pStream, IFX_Pause* pPause); + + public: + FX_BOOL GSMMR; + FX_BOOL GSUSESKIP; + uint8_t GSBPP; + FX_DWORD GSW; + FX_DWORD GSH; + uint8_t GSTEMPLATE; + CJBig2_Image* GSKIP; +}; + +#endif // CORE_FXCODEC_JBIG2_JBIG2_GSIDPROC_H_ diff --git a/core/fxcodec/jbig2/JBig2_HtrdProc.cpp b/core/fxcodec/jbig2/JBig2_HtrdProc.cpp new file mode 100644 index 0000000000..daee067d74 --- /dev/null +++ b/core/fxcodec/jbig2/JBig2_HtrdProc.cpp @@ -0,0 +1,104 @@ +// Copyright 2015 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "core/fxcodec/jbig2/JBig2_HtrdProc.h" + +#include <memory> + +#include "core/fxcodec/jbig2/JBig2_GsidProc.h" +#include "core/include/fxcrt/fx_basic.h" + +CJBig2_Image* CJBig2_HTRDProc::decode_Arith(CJBig2_ArithDecoder* pArithDecoder, + JBig2ArithCtx* gbContext, + IFX_Pause* pPause) { + FX_DWORD ng, mg; + int32_t x, y; + FX_DWORD HBPP; + FX_DWORD* GI; + std::unique_ptr<CJBig2_Image> HSKIP; + std::unique_ptr<CJBig2_Image> HTREG(new CJBig2_Image(HBW, HBH)); + HTREG->fill(HDEFPIXEL); + if (HENABLESKIP == 1) { + HSKIP.reset(new CJBig2_Image(HGW, HGH)); + for (mg = 0; mg < HGH; mg++) { + for (ng = 0; ng < HGW; ng++) { + x = (HGX + mg * HRY + ng * HRX) >> 8; + y = (HGY + mg * HRX - ng * HRY) >> 8; + if ((x + HPW <= 0) | (x >= (int32_t)HBW) | (y + HPH <= 0) | + (y >= (int32_t)HPH)) { + HSKIP->setPixel(ng, mg, 1); + } else { + HSKIP->setPixel(ng, mg, 0); + } + } + } + } + HBPP = 1; + while ((FX_DWORD)(1 << HBPP) < HNUMPATS) { + HBPP++; + } + std::unique_ptr<CJBig2_GSIDProc> pGID(new CJBig2_GSIDProc()); + pGID->GSMMR = HMMR; + pGID->GSW = HGW; + pGID->GSH = HGH; + pGID->GSBPP = (uint8_t)HBPP; + pGID->GSUSESKIP = HENABLESKIP; + pGID->GSKIP = HSKIP.get(); + pGID->GSTEMPLATE = HTEMPLATE; + GI = pGID->decode_Arith(pArithDecoder, gbContext, pPause); + if (!GI) + return nullptr; + + for (mg = 0; mg < HGH; mg++) { + for (ng = 0; ng < HGW; ng++) { + x = (HGX + mg * HRY + ng * HRX) >> 8; + y = (HGY + mg * HRX - ng * HRY) >> 8; + FX_DWORD pat_index = GI[mg * HGW + ng]; + if (pat_index >= HNUMPATS) { + pat_index = HNUMPATS - 1; + } + HTREG->composeFrom(x, y, HPATS[pat_index], HCOMBOP); + } + } + FX_Free(GI); + return HTREG.release(); +} + +CJBig2_Image* CJBig2_HTRDProc::decode_MMR(CJBig2_BitStream* pStream, + IFX_Pause* pPause) { + FX_DWORD ng, mg; + int32_t x, y; + FX_DWORD* GI; + std::unique_ptr<CJBig2_Image> HTREG(new CJBig2_Image(HBW, HBH)); + HTREG->fill(HDEFPIXEL); + FX_DWORD HBPP = 1; + while ((FX_DWORD)(1 << HBPP) < HNUMPATS) { + HBPP++; + } + std::unique_ptr<CJBig2_GSIDProc> pGID(new CJBig2_GSIDProc()); + pGID->GSMMR = HMMR; + pGID->GSW = HGW; + pGID->GSH = HGH; + pGID->GSBPP = (uint8_t)HBPP; + pGID->GSUSESKIP = 0; + GI = pGID->decode_MMR(pStream, pPause); + if (!GI) + return nullptr; + + for (mg = 0; mg < HGH; mg++) { + for (ng = 0; ng < HGW; ng++) { + x = (HGX + mg * HRY + ng * HRX) >> 8; + y = (HGY + mg * HRX - ng * HRY) >> 8; + FX_DWORD pat_index = GI[mg * HGW + ng]; + if (pat_index >= HNUMPATS) { + pat_index = HNUMPATS - 1; + } + HTREG->composeFrom(x, y, HPATS[pat_index], HCOMBOP); + } + } + FX_Free(GI); + return HTREG.release(); +} diff --git a/core/fxcodec/jbig2/JBig2_HtrdProc.h b/core/fxcodec/jbig2/JBig2_HtrdProc.h new file mode 100644 index 0000000000..583145b5ca --- /dev/null +++ b/core/fxcodec/jbig2/JBig2_HtrdProc.h @@ -0,0 +1,46 @@ +// Copyright 2015 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#ifndef CORE_FXCODEC_JBIG2_JBIG2_HTRDPROC_H_ +#define CORE_FXCODEC_JBIG2_JBIG2_HTRDPROC_H_ + +#include "core/fxcodec/jbig2/JBig2_Image.h" +#include "core/include/fxcrt/fx_system.h" + +class CJBig2_ArithDecoder; +class CJBig2_BitStream; +class IFX_Pause; +struct JBig2ArithCtx; + +class CJBig2_HTRDProc { + public: + CJBig2_Image* decode_Arith(CJBig2_ArithDecoder* pArithDecoder, + JBig2ArithCtx* gbContext, + IFX_Pause* pPause); + + CJBig2_Image* decode_MMR(CJBig2_BitStream* pStream, IFX_Pause* pPause); + + public: + FX_DWORD HBW; + FX_DWORD HBH; + FX_BOOL HMMR; + uint8_t HTEMPLATE; + FX_DWORD HNUMPATS; + CJBig2_Image** HPATS; + FX_BOOL HDEFPIXEL; + JBig2ComposeOp HCOMBOP; + FX_BOOL HENABLESKIP; + FX_DWORD HGW; + FX_DWORD HGH; + int32_t HGX; + int32_t HGY; + FX_WORD HRX; + FX_WORD HRY; + uint8_t HPW; + uint8_t HPH; +}; + +#endif // CORE_FXCODEC_JBIG2_JBIG2_HTRDPROC_H_ diff --git a/core/fxcodec/jbig2/JBig2_HuffmanDecoder.cpp b/core/fxcodec/jbig2/JBig2_HuffmanDecoder.cpp new file mode 100644 index 0000000000..afcc17a55e --- /dev/null +++ b/core/fxcodec/jbig2/JBig2_HuffmanDecoder.cpp @@ -0,0 +1,45 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "core/fxcodec/jbig2/JBig2_HuffmanDecoder.h" + +#include "core/fxcodec/jbig2/JBig2_Define.h" + +CJBig2_HuffmanDecoder::CJBig2_HuffmanDecoder(CJBig2_BitStream* pStream) + : m_pStream(pStream) {} + +CJBig2_HuffmanDecoder::~CJBig2_HuffmanDecoder() {} + +int CJBig2_HuffmanDecoder::decodeAValue(CJBig2_HuffmanTable* pTable, + int* nResult) { + int nVal = 0; + int nBits = 0; + while (1) { + FX_DWORD nTmp; + if (m_pStream->read1Bit(&nTmp) == -1) + break; + + nVal = (nVal << 1) | nTmp; + ++nBits; + for (FX_DWORD i = 0; i < pTable->Size(); ++i) { + if (pTable->GetPREFLEN()[i] == nBits && pTable->GetCODES()[i] == nVal) { + if (pTable->IsHTOOB() && i == pTable->Size() - 1) + return JBIG2_OOB; + + if (m_pStream->readNBits(pTable->GetRANGELEN()[i], &nTmp) == -1) + return -1; + + FX_DWORD offset = pTable->IsHTOOB() ? 3 : 2; + if (i == pTable->Size() - offset) + *nResult = pTable->GetRANGELOW()[i] - nTmp; + else + *nResult = pTable->GetRANGELOW()[i] + nTmp; + return 0; + } + } + } + return -1; +} diff --git a/core/fxcodec/jbig2/JBig2_HuffmanDecoder.h b/core/fxcodec/jbig2/JBig2_HuffmanDecoder.h new file mode 100644 index 0000000000..c72346ac18 --- /dev/null +++ b/core/fxcodec/jbig2/JBig2_HuffmanDecoder.h @@ -0,0 +1,24 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#ifndef CORE_FXCODEC_JBIG2_JBIG2_HUFFMANDECODER_H_ +#define CORE_FXCODEC_JBIG2_JBIG2_HUFFMANDECODER_H_ + +#include "core/fxcodec/jbig2/JBig2_BitStream.h" +#include "core/fxcodec/jbig2/JBig2_HuffmanTable.h" +class CJBig2_HuffmanDecoder { + public: + explicit CJBig2_HuffmanDecoder(CJBig2_BitStream* pStream); + + ~CJBig2_HuffmanDecoder(); + + int decodeAValue(CJBig2_HuffmanTable* pTable, int* nResult); + + private: + CJBig2_BitStream* const m_pStream; +}; + +#endif // CORE_FXCODEC_JBIG2_JBIG2_HUFFMANDECODER_H_ diff --git a/core/fxcodec/jbig2/JBig2_HuffmanTable.cpp b/core/fxcodec/jbig2/JBig2_HuffmanTable.cpp new file mode 100644 index 0000000000..f4a838eb24 --- /dev/null +++ b/core/fxcodec/jbig2/JBig2_HuffmanTable.cpp @@ -0,0 +1,136 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "core/fxcodec/jbig2/JBig2_HuffmanTable.h" + +#include <algorithm> +#include <vector> + +#include "core/fxcodec/jbig2/JBig2_BitStream.h" +#include "core/fxcodec/jbig2/JBig2_Define.h" +#include "core/fxcodec/jbig2/JBig2_HuffmanTable_Standard.h" +#include "core/include/fxcrt/fx_memory.h" + +CJBig2_HuffmanTable::CJBig2_HuffmanTable(const JBig2TableLine* pTable, + FX_DWORD nLines, + bool bHTOOB) + : m_bOK(true), HTOOB(bHTOOB), NTEMP(nLines) { + ParseFromStandardTable(pTable); +} + +CJBig2_HuffmanTable::CJBig2_HuffmanTable(CJBig2_BitStream* pStream) + : HTOOB(false), NTEMP(0) { + m_bOK = ParseFromCodedBuffer(pStream); +} + +CJBig2_HuffmanTable::~CJBig2_HuffmanTable() {} + +void CJBig2_HuffmanTable::ParseFromStandardTable(const JBig2TableLine* pTable) { + PREFLEN.resize(NTEMP); + RANGELEN.resize(NTEMP); + RANGELOW.resize(NTEMP); + for (FX_DWORD i = 0; i < NTEMP; ++i) { + PREFLEN[i] = pTable[i].PREFLEN; + RANGELEN[i] = pTable[i].RANDELEN; + RANGELOW[i] = pTable[i].RANGELOW; + } + InitCodes(); +} + +bool CJBig2_HuffmanTable::ParseFromCodedBuffer(CJBig2_BitStream* pStream) { + unsigned char cTemp; + if (pStream->read1Byte(&cTemp) == -1) + return false; + + HTOOB = !!(cTemp & 0x01); + unsigned char HTPS = ((cTemp >> 1) & 0x07) + 1; + unsigned char HTRS = ((cTemp >> 4) & 0x07) + 1; + FX_DWORD HTLOW; + FX_DWORD HTHIGH; + if (pStream->readInteger(&HTLOW) == -1 || + pStream->readInteger(&HTHIGH) == -1) { + return false; + } + + const int low = static_cast<int>(HTLOW); + const int high = static_cast<int>(HTHIGH); + if (low > high) + return false; + + ExtendBuffers(false); + int cur_low = low; + do { + if ((pStream->readNBits(HTPS, &PREFLEN[NTEMP]) == -1) || + (pStream->readNBits(HTRS, &RANGELEN[NTEMP]) == -1)) { + return false; + } + RANGELOW[NTEMP] = cur_low; + cur_low += (1 << RANGELEN[NTEMP]); + ExtendBuffers(true); + } while (cur_low < high); + + if (pStream->readNBits(HTPS, &PREFLEN[NTEMP]) == -1) + return false; + + RANGELEN[NTEMP] = 32; + RANGELOW[NTEMP] = low - 1; + ExtendBuffers(true); + + if (pStream->readNBits(HTPS, &PREFLEN[NTEMP]) == -1) + return false; + + RANGELEN[NTEMP] = 32; + RANGELOW[NTEMP] = high; + ExtendBuffers(true); + + if (HTOOB) { + if (pStream->readNBits(HTPS, &PREFLEN[NTEMP]) == -1) + return false; + + ++NTEMP; + } + + InitCodes(); + return true; +} + +void CJBig2_HuffmanTable::InitCodes() { + int lenmax = 0; + for (FX_DWORD i = 0; i < NTEMP; ++i) + lenmax = std::max(PREFLEN[i], lenmax); + + CODES.resize(NTEMP); + std::vector<int> LENCOUNT(lenmax + 1); + std::vector<int> FIRSTCODE(lenmax + 1); + for (int len : PREFLEN) + ++LENCOUNT[len]; + + FIRSTCODE[0] = 0; + LENCOUNT[0] = 0; + for (int i = 1; i <= lenmax; ++i) { + FIRSTCODE[i] = (FIRSTCODE[i - 1] + LENCOUNT[i - 1]) << 1; + int CURCODE = FIRSTCODE[i]; + for (FX_DWORD j = 0; j < NTEMP; ++j) { + if (PREFLEN[j] == i) + CODES[j] = CURCODE++; + } + } +} + +void CJBig2_HuffmanTable::ExtendBuffers(bool increment) { + if (increment) + ++NTEMP; + + size_t size = PREFLEN.size(); + if (NTEMP < size) + return; + + size += 16; + ASSERT(NTEMP < size); + PREFLEN.resize(size); + RANGELEN.resize(size); + RANGELOW.resize(size); +} diff --git a/core/fxcodec/jbig2/JBig2_HuffmanTable.h b/core/fxcodec/jbig2/JBig2_HuffmanTable.h new file mode 100644 index 0000000000..892c19e9d6 --- /dev/null +++ b/core/fxcodec/jbig2/JBig2_HuffmanTable.h @@ -0,0 +1,50 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#ifndef CORE_FXCODEC_JBIG2_JBIG2_HUFFMANTABLE_H_ +#define CORE_FXCODEC_JBIG2_JBIG2_HUFFMANTABLE_H_ + +#include <vector> + +#include "core/include/fxcrt/fx_system.h" + +class CJBig2_BitStream; +struct JBig2TableLine; + +class CJBig2_HuffmanTable { + public: + CJBig2_HuffmanTable(const JBig2TableLine* pTable, + FX_DWORD nLines, + bool bHTOOB); + + explicit CJBig2_HuffmanTable(CJBig2_BitStream* pStream); + + ~CJBig2_HuffmanTable(); + + bool IsHTOOB() const { return HTOOB; } + FX_DWORD Size() const { return NTEMP; } + const std::vector<int>& GetCODES() const { return CODES; } + const std::vector<int>& GetPREFLEN() const { return PREFLEN; } + const std::vector<int>& GetRANGELEN() const { return RANGELEN; } + const std::vector<int>& GetRANGELOW() const { return RANGELOW; } + bool IsOK() const { return m_bOK; } + + private: + void ParseFromStandardTable(const JBig2TableLine* pTable); + bool ParseFromCodedBuffer(CJBig2_BitStream* pStream); + void InitCodes(); + void ExtendBuffers(bool increment); + + bool m_bOK; + bool HTOOB; + FX_DWORD NTEMP; + std::vector<int> CODES; + std::vector<int> PREFLEN; + std::vector<int> RANGELEN; + std::vector<int> RANGELOW; +}; + +#endif // CORE_FXCODEC_JBIG2_JBIG2_HUFFMANTABLE_H_ diff --git a/core/fxcodec/jbig2/JBig2_HuffmanTable_Standard.h b/core/fxcodec/jbig2/JBig2_HuffmanTable_Standard.h new file mode 100644 index 0000000000..0b768654f5 --- /dev/null +++ b/core/fxcodec/jbig2/JBig2_HuffmanTable_Standard.h @@ -0,0 +1,98 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#ifndef CORE_FXCODEC_JBIG2_JBIG2_HUFFMANTABLE_STANDARD_H_ +#define CORE_FXCODEC_JBIG2_JBIG2_HUFFMANTABLE_STANDARD_H_ + +#include "core/include/fxcrt/fx_system.h" + +struct JBig2TableLine { + int PREFLEN; + int RANDELEN; + int RANGELOW; +}; + +const bool HuffmanTable_HTOOB_B1 = false; +const JBig2TableLine HuffmanTable_B1[] = {{1, 4, 0}, + {2, 8, 16}, + {3, 16, 272}, + {0, 32, -1}, + {3, 32, 65808}}; +const bool HuffmanTable_HTOOB_B2 = true; +const JBig2TableLine HuffmanTable_B2[] = {{1, 0, 0}, {2, 0, 1}, {3, 0, 2}, + {4, 3, 3}, {5, 6, 11}, {0, 32, -1}, + {6, 32, 75}, {6, 0, 0}}; +const bool HuffmanTable_HTOOB_B3 = true; +const JBig2TableLine HuffmanTable_B3[] = { + {8, 8, -256}, {1, 0, 0}, {2, 0, 1}, {3, 0, 2}, {4, 3, 3}, + {5, 6, 11}, {8, 32, -257}, {7, 32, 75}, {6, 0, 0}}; +const bool HuffmanTable_HTOOB_B4 = false; +const JBig2TableLine HuffmanTable_B4[] = { + {1, 0, 1}, {2, 0, 2}, {3, 0, 3}, {4, 3, 4}, + {5, 6, 12}, {0, 32, -1}, {5, 32, 76}, +}; +const bool HuffmanTable_HTOOB_B5 = false; +const JBig2TableLine HuffmanTable_B5[] = {{7, 8, -255}, {1, 0, 1}, {2, 0, 2}, + {3, 0, 3}, {4, 3, 4}, {5, 6, 12}, + {7, 32, -256}, {6, 32, 76}}; +const bool HuffmanTable_HTOOB_B6 = false; +const JBig2TableLine HuffmanTable_B6[] = { + {5, 10, -2048}, {4, 9, -1024}, {4, 8, -512}, {4, 7, -256}, {5, 6, -128}, + {5, 5, -64}, {4, 5, -32}, {2, 7, 0}, {3, 7, 128}, {3, 8, 256}, + {4, 9, 512}, {4, 10, 1024}, {6, 32, -2049}, {6, 32, 2048}}; +const bool HuffmanTable_HTOOB_B7 = false; +const JBig2TableLine HuffmanTable_B7[] = { + {4, 9, -1024}, {3, 8, -512}, {4, 7, -256}, {5, 6, -128}, {5, 5, -64}, + {4, 5, -32}, {4, 5, 0}, {5, 5, 32}, {5, 6, 64}, {4, 7, 128}, + {3, 8, 256}, {3, 9, 512}, {3, 10, 1024}, {5, 32, -1025}, {5, 32, 2048}, +}; +const bool HuffmanTable_HTOOB_B8 = true; +const JBig2TableLine HuffmanTable_B8[] = { + {8, 3, -15}, {9, 1, -7}, {8, 1, -5}, {9, 0, -3}, {7, 0, -2}, + {4, 0, -1}, {2, 1, 0}, {5, 0, 2}, {6, 0, 3}, {3, 4, 4}, + {6, 1, 20}, {4, 4, 22}, {4, 5, 38}, {5, 6, 70}, {5, 7, 134}, + {6, 7, 262}, {7, 8, 390}, {6, 10, 646}, {9, 32, -16}, {9, 32, 1670}, + {2, 0, 0}}; +const bool HuffmanTable_HTOOB_B9 = true; +const JBig2TableLine HuffmanTable_B9[] = { + {8, 4, -31}, {9, 2, -15}, {8, 2, -11}, {9, 1, -7}, {7, 1, -5}, + {4, 1, -3}, {3, 1, -1}, {3, 1, 1}, {5, 1, 3}, {6, 1, 5}, + {3, 5, 7}, {6, 2, 39}, {4, 5, 43}, {4, 6, 75}, {5, 7, 139}, + {5, 8, 267}, {6, 8, 523}, {7, 9, 779}, {6, 11, 1291}, {9, 32, -32}, + {9, 32, 3339}, {2, 0, 0}}; +const bool HuffmanTable_HTOOB_B10 = true; +const JBig2TableLine HuffmanTable_B10[] = { + {7, 4, -21}, {8, 0, -5}, {7, 0, -4}, {5, 0, -3}, {2, 2, -2}, + {5, 0, 2}, {6, 0, 3}, {7, 0, 4}, {8, 0, 5}, {2, 6, 6}, + {5, 5, 70}, {6, 5, 102}, {6, 6, 134}, {6, 7, 198}, {6, 8, 326}, + {6, 9, 582}, {6, 10, 1094}, {7, 11, 2118}, {8, 32, -22}, {8, 32, 4166}, + {2, 0, 0}}; +const bool HuffmanTable_HTOOB_B11 = false; +const JBig2TableLine HuffmanTable_B11[] = { + {1, 0, 1}, {2, 1, 2}, {4, 0, 4}, {4, 1, 5}, {5, 1, 7}, + {5, 2, 9}, {6, 2, 13}, {7, 2, 17}, {7, 3, 21}, {7, 4, 29}, + {7, 5, 45}, {7, 6, 77}, {0, 32, 0}, {7, 32, 141}}; +const bool HuffmanTable_HTOOB_B12 = false; +const JBig2TableLine HuffmanTable_B12[] = { + {1, 0, 1}, {2, 0, 2}, {3, 1, 3}, {5, 0, 5}, {5, 1, 6}, + {6, 1, 8}, {7, 0, 10}, {7, 1, 11}, {7, 2, 13}, {7, 3, 17}, + {7, 4, 25}, {8, 5, 41}, {0, 32, 0}, {8, 32, 73}}; +const bool HuffmanTable_HTOOB_B13 = false; +const JBig2TableLine HuffmanTable_B13[] = { + {1, 0, 1}, {3, 0, 2}, {4, 0, 3}, {5, 0, 4}, {4, 1, 5}, + {3, 3, 7}, {6, 1, 15}, {6, 2, 17}, {6, 3, 21}, {6, 4, 29}, + {6, 5, 45}, {7, 6, 77}, {0, 32, 0}, {7, 32, 141}}; +const bool HuffmanTable_HTOOB_B14 = false; +const JBig2TableLine HuffmanTable_B14[] = {{3, 0, -2}, {3, 0, -1}, {1, 0, 0}, + {3, 0, 1}, {3, 0, 2}, {0, 32, -3}, + {0, 32, 3}}; +const bool HuffmanTable_HTOOB_B15 = false; +const JBig2TableLine HuffmanTable_B15[] = { + {7, 4, -24}, {6, 2, -8}, {5, 1, -4}, {4, 0, -2}, {3, 0, -1}, + {1, 0, 0}, {3, 0, 1}, {4, 0, 2}, {5, 1, 3}, {6, 2, 5}, + {7, 4, 9}, {7, 32, -25}, {7, 32, 25}}; + +#endif // CORE_FXCODEC_JBIG2_JBIG2_HUFFMANTABLE_STANDARD_H_ diff --git a/core/fxcodec/jbig2/JBig2_Image.cpp b/core/fxcodec/jbig2/JBig2_Image.cpp new file mode 100644 index 0000000000..311c38270e --- /dev/null +++ b/core/fxcodec/jbig2/JBig2_Image.cpp @@ -0,0 +1,1099 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include <limits.h> + +#include "core/fxcodec/jbig2/JBig2_Image.h" +#include "core/include/fxcrt/fx_coordinates.h" +#include "core/include/fxcrt/fx_safe_types.h" + +CJBig2_Image::CJBig2_Image(int32_t w, int32_t h) { + m_nWidth = w; + m_nHeight = h; + if (m_nWidth <= 0 || m_nHeight <= 0 || m_nWidth > INT_MAX - 31) { + m_pData = NULL; + m_bNeedFree = FALSE; + return; + } + m_nStride = ((w + 31) >> 5) << 2; + if (m_nStride * m_nHeight > 0 && 104857600 / (int)m_nStride > m_nHeight) { + m_pData = FX_Alloc2D(uint8_t, m_nStride, m_nHeight); + } else { + m_pData = NULL; + } + m_bNeedFree = TRUE; +} +CJBig2_Image::CJBig2_Image(int32_t w, + int32_t h, + int32_t stride, + uint8_t* pBuf) { + m_nWidth = w; + m_nHeight = h; + m_nStride = stride; + m_pData = pBuf; + m_bNeedFree = FALSE; +} +CJBig2_Image::CJBig2_Image(const CJBig2_Image& im) { + m_nWidth = im.m_nWidth; + m_nHeight = im.m_nHeight; + m_nStride = im.m_nStride; + if (im.m_pData) { + m_pData = FX_Alloc2D(uint8_t, m_nStride, m_nHeight); + JBIG2_memcpy(m_pData, im.m_pData, m_nStride * m_nHeight); + } else { + m_pData = NULL; + } + m_bNeedFree = TRUE; +} +CJBig2_Image::~CJBig2_Image() { + if (m_bNeedFree) { + FX_Free(m_pData); + } +} +FX_BOOL CJBig2_Image::getPixel(int32_t x, int32_t y) { + if (!m_pData) { + return 0; + } + int32_t m, n; + if (x < 0 || x >= m_nWidth) { + return 0; + } + if (y < 0 || y >= m_nHeight) { + return 0; + } + m = y * m_nStride + (x >> 3); + n = x & 7; + return ((m_pData[m] >> (7 - n)) & 1); +} + +int32_t CJBig2_Image::setPixel(int32_t x, int32_t y, FX_BOOL v) { + if (!m_pData) { + return 0; + } + int32_t m, n; + if (x < 0 || x >= m_nWidth) { + return 0; + } + if (y < 0 || y >= m_nHeight) { + return 0; + } + m = y * m_nStride + (x >> 3); + n = x & 7; + if (v) { + m_pData[m] |= 1 << (7 - n); + } else { + m_pData[m] &= ~(1 << (7 - n)); + } + return 1; +} +void CJBig2_Image::copyLine(int32_t hTo, int32_t hFrom) { + if (!m_pData) { + return; + } + if (hFrom < 0 || hFrom >= m_nHeight) { + JBIG2_memset(m_pData + hTo * m_nStride, 0, m_nStride); + } else { + JBIG2_memcpy(m_pData + hTo * m_nStride, m_pData + hFrom * m_nStride, + m_nStride); + } +} +void CJBig2_Image::fill(FX_BOOL v) { + if (!m_pData) { + return; + } + JBIG2_memset(m_pData, v ? 0xff : 0, m_nStride * m_nHeight); +} +FX_BOOL CJBig2_Image::composeTo(CJBig2_Image* pDst, + int32_t x, + int32_t y, + JBig2ComposeOp op) { + if (!m_pData) { + return FALSE; + } + return composeTo_opt2(pDst, x, y, op); +} +FX_BOOL CJBig2_Image::composeTo(CJBig2_Image* pDst, + int32_t x, + int32_t y, + JBig2ComposeOp op, + const FX_RECT* pSrcRect) { + if (!m_pData) { + return FALSE; + } + if (NULL == pSrcRect || *pSrcRect == FX_RECT(0, 0, m_nWidth, m_nHeight)) { + return composeTo_opt2(pDst, x, y, op); + } + return composeTo_opt2(pDst, x, y, op, pSrcRect); +} + +FX_BOOL CJBig2_Image::composeFrom(int32_t x, + int32_t y, + CJBig2_Image* pSrc, + JBig2ComposeOp op) { + if (!m_pData) { + return FALSE; + } + return pSrc->composeTo(this, x, y, op); +} +FX_BOOL CJBig2_Image::composeFrom(int32_t x, + int32_t y, + CJBig2_Image* pSrc, + JBig2ComposeOp op, + const FX_RECT* pSrcRect) { + if (!m_pData) { + return FALSE; + } + return pSrc->composeTo(this, x, y, op, pSrcRect); +} +#define JBIG2_GETDWORD(buf) \ + ((FX_DWORD)(((buf)[0] << 24) | ((buf)[1] << 16) | ((buf)[2] << 8) | (buf)[3])) +CJBig2_Image* CJBig2_Image::subImage(int32_t x, + int32_t y, + int32_t w, + int32_t h) { + int32_t m, n, j; + uint8_t *pLineSrc, *pLineDst; + FX_DWORD wTmp; + uint8_t *pSrc, *pSrcEnd, *pDst, *pDstEnd; + if (w == 0 || h == 0) { + return NULL; + } + CJBig2_Image* pImage = new CJBig2_Image(w, h); + if (!m_pData) { + pImage->fill(0); + return pImage; + } + if (!pImage->m_pData) { + return pImage; + } + pLineSrc = m_pData + m_nStride * y; + pLineDst = pImage->m_pData; + m = (x >> 5) << 2; + n = x & 31; + if (n == 0) { + for (j = 0; j < h; j++) { + pSrc = pLineSrc + m; + pSrcEnd = pLineSrc + m_nStride; + pDst = pLineDst; + pDstEnd = pLineDst + pImage->m_nStride; + for (; pDst < pDstEnd; pSrc += 4, pDst += 4) { + *((FX_DWORD*)pDst) = *((FX_DWORD*)pSrc); + } + pLineSrc += m_nStride; + pLineDst += pImage->m_nStride; + } + } else { + for (j = 0; j < h; j++) { + pSrc = pLineSrc + m; + pSrcEnd = pLineSrc + m_nStride; + pDst = pLineDst; + pDstEnd = pLineDst + pImage->m_nStride; + for (; pDst < pDstEnd; pSrc += 4, pDst += 4) { + if (pSrc + 4 < pSrcEnd) { + wTmp = (JBIG2_GETDWORD(pSrc) << n) | + (JBIG2_GETDWORD(pSrc + 4) >> (32 - n)); + } else { + wTmp = JBIG2_GETDWORD(pSrc) << n; + } + pDst[0] = (uint8_t)(wTmp >> 24); + pDst[1] = (uint8_t)(wTmp >> 16); + pDst[2] = (uint8_t)(wTmp >> 8); + pDst[3] = (uint8_t)wTmp; + } + pLineSrc += m_nStride; + pLineDst += pImage->m_nStride; + } + } + return pImage; +} +void CJBig2_Image::expand(int32_t h, FX_BOOL v) { + if (!m_pData || h <= m_nHeight) { + return; + } + FX_DWORD dwH = pdfium::base::checked_cast<FX_DWORD>(h); + FX_DWORD dwStride = pdfium::base::checked_cast<FX_DWORD>(m_nStride); + FX_DWORD dwHeight = pdfium::base::checked_cast<FX_DWORD>(m_nHeight); + FX_SAFE_DWORD safeMemSize = dwH; + safeMemSize *= dwStride; + if (!safeMemSize.IsValid()) { + return; + } + // The guaranteed reallocated memory is to be < 4GB (unsigned int). + m_pData = FX_Realloc(uint8_t, m_pData, safeMemSize.ValueOrDie()); + + // The result of dwHeight * dwStride doesn't overflow after the + // checking of safeMemSize. + // The same as the result of (dwH - dwHeight) * dwStride) because + // dwH - dwHeight is always less than dwH(h) which is checked in + // the calculation of dwH * dwStride. + JBIG2_memset(m_pData + dwHeight * dwStride, v ? 0xff : 0, + (dwH - dwHeight) * dwStride); + m_nHeight = h; +} +FX_BOOL CJBig2_Image::composeTo_opt2(CJBig2_Image* pDst, + int32_t x, + int32_t y, + JBig2ComposeOp op) { + int32_t xs0 = 0, ys0 = 0, xs1 = 0, ys1 = 0, xd0 = 0, yd0 = 0, xd1 = 0, + yd1 = 0, xx = 0, yy = 0, w = 0, h = 0, middleDwords = 0, lineLeft = 0; + + FX_DWORD s1 = 0, d1 = 0, d2 = 0, shift = 0, shift1 = 0, shift2 = 0, tmp = 0, + tmp1 = 0, tmp2 = 0, maskL = 0, maskR = 0, maskM = 0; + + uint8_t *lineSrc = NULL, *lineDst = NULL, *sp = NULL, *dp = NULL; + + if (!m_pData) { + return FALSE; + } + if (x < -1048576 || x > 1048576 || y < -1048576 || y > 1048576) { + return FALSE; + } + if (y < 0) { + ys0 = -y; + } + if (y + m_nHeight > pDst->m_nHeight) { + ys1 = pDst->m_nHeight - y; + } else { + ys1 = m_nHeight; + } + if (x < 0) { + xs0 = -x; + } + if (x + m_nWidth > pDst->m_nWidth) { + xs1 = pDst->m_nWidth - x; + } else { + xs1 = m_nWidth; + } + if ((ys0 >= ys1) || (xs0 >= xs1)) { + return 0; + } + w = xs1 - xs0; + h = ys1 - ys0; + if (y >= 0) { + yd0 = y; + } + if (x >= 0) { + xd0 = x; + } + xd1 = xd0 + w; + yd1 = yd0 + h; + d1 = xd0 & 31; + d2 = xd1 & 31; + s1 = xs0 & 31; + maskL = 0xffffffff >> d1; + maskR = 0xffffffff << ((32 - (xd1 & 31)) % 32); + maskM = maskL & maskR; + lineSrc = m_pData + ys0 * m_nStride + ((xs0 >> 5) << 2); + lineLeft = m_nStride - ((xs0 >> 5) << 2); + lineDst = pDst->m_pData + yd0 * pDst->m_nStride + ((xd0 >> 5) << 2); + if ((xd0 & ~31) == ((xd1 - 1) & ~31)) { + if ((xs0 & ~31) == ((xs1 - 1) & ~31)) { + if (s1 > d1) { + shift = s1 - d1; + for (yy = yd0; yy < yd1; yy++) { + tmp1 = JBIG2_GETDWORD(lineSrc) << shift; + tmp2 = JBIG2_GETDWORD(lineDst); + switch (op) { + case JBIG2_COMPOSE_OR: + tmp = (tmp2 & ~maskM) | ((tmp1 | tmp2) & maskM); + break; + case JBIG2_COMPOSE_AND: + tmp = (tmp2 & ~maskM) | ((tmp1 & tmp2) & maskM); + break; + case JBIG2_COMPOSE_XOR: + tmp = (tmp2 & ~maskM) | ((tmp1 ^ tmp2) & maskM); + break; + case JBIG2_COMPOSE_XNOR: + tmp = (tmp2 & ~maskM) | ((~(tmp1 ^ tmp2)) & maskM); + break; + case JBIG2_COMPOSE_REPLACE: + tmp = (tmp2 & ~maskM) | (tmp1 & maskM); + break; + } + lineDst[0] = (uint8_t)(tmp >> 24); + lineDst[1] = (uint8_t)(tmp >> 16); + lineDst[2] = (uint8_t)(tmp >> 8); + lineDst[3] = (uint8_t)tmp; + lineSrc += m_nStride; + lineDst += pDst->m_nStride; + } + } else { + shift = d1 - s1; + for (yy = yd0; yy < yd1; yy++) { + tmp1 = JBIG2_GETDWORD(lineSrc) >> shift; + tmp2 = JBIG2_GETDWORD(lineDst); + switch (op) { + case JBIG2_COMPOSE_OR: + tmp = (tmp2 & ~maskM) | ((tmp1 | tmp2) & maskM); + break; + case JBIG2_COMPOSE_AND: + tmp = (tmp2 & ~maskM) | ((tmp1 & tmp2) & maskM); + break; + case JBIG2_COMPOSE_XOR: + tmp = (tmp2 & ~maskM) | ((tmp1 ^ tmp2) & maskM); + break; + case JBIG2_COMPOSE_XNOR: + tmp = (tmp2 & ~maskM) | ((~(tmp1 ^ tmp2)) & maskM); + break; + case JBIG2_COMPOSE_REPLACE: + tmp = (tmp2 & ~maskM) | (tmp1 & maskM); + break; + } + lineDst[0] = (uint8_t)(tmp >> 24); + lineDst[1] = (uint8_t)(tmp >> 16); + lineDst[2] = (uint8_t)(tmp >> 8); + lineDst[3] = (uint8_t)tmp; + lineSrc += m_nStride; + lineDst += pDst->m_nStride; + } + } + } else { + shift1 = s1 - d1; + shift2 = 32 - shift1; + for (yy = yd0; yy < yd1; yy++) { + tmp1 = (JBIG2_GETDWORD(lineSrc) << shift1) | + (JBIG2_GETDWORD(lineSrc + 4) >> shift2); + tmp2 = JBIG2_GETDWORD(lineDst); + switch (op) { + case JBIG2_COMPOSE_OR: + tmp = (tmp2 & ~maskM) | ((tmp1 | tmp2) & maskM); + break; + case JBIG2_COMPOSE_AND: + tmp = (tmp2 & ~maskM) | ((tmp1 & tmp2) & maskM); + break; + case JBIG2_COMPOSE_XOR: + tmp = (tmp2 & ~maskM) | ((tmp1 ^ tmp2) & maskM); + break; + case JBIG2_COMPOSE_XNOR: + tmp = (tmp2 & ~maskM) | ((~(tmp1 ^ tmp2)) & maskM); + break; + case JBIG2_COMPOSE_REPLACE: + tmp = (tmp2 & ~maskM) | (tmp1 & maskM); + break; + } + lineDst[0] = (uint8_t)(tmp >> 24); + lineDst[1] = (uint8_t)(tmp >> 16); + lineDst[2] = (uint8_t)(tmp >> 8); + lineDst[3] = (uint8_t)tmp; + lineSrc += m_nStride; + lineDst += pDst->m_nStride; + } + } + } else { + if (s1 > d1) { + shift1 = s1 - d1; + shift2 = 32 - shift1; + middleDwords = (xd1 >> 5) - ((xd0 + 31) >> 5); + for (yy = yd0; yy < yd1; yy++) { + sp = lineSrc; + dp = lineDst; + if (d1 != 0) { + tmp1 = (JBIG2_GETDWORD(sp) << shift1) | + (JBIG2_GETDWORD(sp + 4) >> shift2); + tmp2 = JBIG2_GETDWORD(dp); + switch (op) { + case JBIG2_COMPOSE_OR: + tmp = (tmp2 & ~maskL) | ((tmp1 | tmp2) & maskL); + break; + case JBIG2_COMPOSE_AND: + tmp = (tmp2 & ~maskL) | ((tmp1 & tmp2) & maskL); + break; + case JBIG2_COMPOSE_XOR: + tmp = (tmp2 & ~maskL) | ((tmp1 ^ tmp2) & maskL); + break; + case JBIG2_COMPOSE_XNOR: + tmp = (tmp2 & ~maskL) | ((~(tmp1 ^ tmp2)) & maskL); + break; + case JBIG2_COMPOSE_REPLACE: + tmp = (tmp2 & ~maskL) | (tmp1 & maskL); + break; + } + dp[0] = (uint8_t)(tmp >> 24); + dp[1] = (uint8_t)(tmp >> 16); + dp[2] = (uint8_t)(tmp >> 8); + dp[3] = (uint8_t)tmp; + sp += 4; + dp += 4; + } + for (xx = 0; xx < middleDwords; xx++) { + tmp1 = (JBIG2_GETDWORD(sp) << shift1) | + (JBIG2_GETDWORD(sp + 4) >> shift2); + tmp2 = JBIG2_GETDWORD(dp); + switch (op) { + case JBIG2_COMPOSE_OR: + tmp = tmp1 | tmp2; + break; + case JBIG2_COMPOSE_AND: + tmp = tmp1 & tmp2; + break; + case JBIG2_COMPOSE_XOR: + tmp = tmp1 ^ tmp2; + break; + case JBIG2_COMPOSE_XNOR: + tmp = ~(tmp1 ^ tmp2); + break; + case JBIG2_COMPOSE_REPLACE: + tmp = tmp1; + break; + } + dp[0] = (uint8_t)(tmp >> 24); + dp[1] = (uint8_t)(tmp >> 16); + dp[2] = (uint8_t)(tmp >> 8); + dp[3] = (uint8_t)tmp; + sp += 4; + dp += 4; + } + if (d2 != 0) { + tmp1 = + (JBIG2_GETDWORD(sp) << shift1) | + (((sp + 4) < lineSrc + lineLeft ? JBIG2_GETDWORD(sp + 4) : 0) >> + shift2); + tmp2 = JBIG2_GETDWORD(dp); + switch (op) { + case JBIG2_COMPOSE_OR: + tmp = (tmp2 & ~maskR) | ((tmp1 | tmp2) & maskR); + break; + case JBIG2_COMPOSE_AND: + tmp = (tmp2 & ~maskR) | ((tmp1 & tmp2) & maskR); + break; + case JBIG2_COMPOSE_XOR: + tmp = (tmp2 & ~maskR) | ((tmp1 ^ tmp2) & maskR); + break; + case JBIG2_COMPOSE_XNOR: + tmp = (tmp2 & ~maskR) | ((~(tmp1 ^ tmp2)) & maskR); + break; + case JBIG2_COMPOSE_REPLACE: + tmp = (tmp2 & ~maskR) | (tmp1 & maskR); + break; + } + dp[0] = (uint8_t)(tmp >> 24); + dp[1] = (uint8_t)(tmp >> 16); + dp[2] = (uint8_t)(tmp >> 8); + dp[3] = (uint8_t)tmp; + } + lineSrc += m_nStride; + lineDst += pDst->m_nStride; + } + } else if (s1 == d1) { + middleDwords = (xd1 >> 5) - ((xd0 + 31) >> 5); + for (yy = yd0; yy < yd1; yy++) { + sp = lineSrc; + dp = lineDst; + if (d1 != 0) { + tmp1 = JBIG2_GETDWORD(sp); + tmp2 = JBIG2_GETDWORD(dp); + switch (op) { + case JBIG2_COMPOSE_OR: + tmp = (tmp2 & ~maskL) | ((tmp1 | tmp2) & maskL); + break; + case JBIG2_COMPOSE_AND: + tmp = (tmp2 & ~maskL) | ((tmp1 & tmp2) & maskL); + break; + case JBIG2_COMPOSE_XOR: + tmp = (tmp2 & ~maskL) | ((tmp1 ^ tmp2) & maskL); + break; + case JBIG2_COMPOSE_XNOR: + tmp = (tmp2 & ~maskL) | ((~(tmp1 ^ tmp2)) & maskL); + break; + case JBIG2_COMPOSE_REPLACE: + tmp = (tmp2 & ~maskL) | (tmp1 & maskL); + break; + } + dp[0] = (uint8_t)(tmp >> 24); + dp[1] = (uint8_t)(tmp >> 16); + dp[2] = (uint8_t)(tmp >> 8); + dp[3] = (uint8_t)tmp; + sp += 4; + dp += 4; + } + for (xx = 0; xx < middleDwords; xx++) { + tmp1 = JBIG2_GETDWORD(sp); + tmp2 = JBIG2_GETDWORD(dp); + switch (op) { + case JBIG2_COMPOSE_OR: + tmp = tmp1 | tmp2; + break; + case JBIG2_COMPOSE_AND: + tmp = tmp1 & tmp2; + break; + case JBIG2_COMPOSE_XOR: + tmp = tmp1 ^ tmp2; + break; + case JBIG2_COMPOSE_XNOR: + tmp = ~(tmp1 ^ tmp2); + break; + case JBIG2_COMPOSE_REPLACE: + tmp = tmp1; + break; + } + dp[0] = (uint8_t)(tmp >> 24); + dp[1] = (uint8_t)(tmp >> 16); + dp[2] = (uint8_t)(tmp >> 8); + dp[3] = (uint8_t)tmp; + sp += 4; + dp += 4; + } + if (d2 != 0) { + tmp1 = JBIG2_GETDWORD(sp); + tmp2 = JBIG2_GETDWORD(dp); + switch (op) { + case JBIG2_COMPOSE_OR: + tmp = (tmp2 & ~maskR) | ((tmp1 | tmp2) & maskR); + break; + case JBIG2_COMPOSE_AND: + tmp = (tmp2 & ~maskR) | ((tmp1 & tmp2) & maskR); + break; + case JBIG2_COMPOSE_XOR: + tmp = (tmp2 & ~maskR) | ((tmp1 ^ tmp2) & maskR); + break; + case JBIG2_COMPOSE_XNOR: + tmp = (tmp2 & ~maskR) | ((~(tmp1 ^ tmp2)) & maskR); + break; + case JBIG2_COMPOSE_REPLACE: + tmp = (tmp2 & ~maskR) | (tmp1 & maskR); + break; + } + dp[0] = (uint8_t)(tmp >> 24); + dp[1] = (uint8_t)(tmp >> 16); + dp[2] = (uint8_t)(tmp >> 8); + dp[3] = (uint8_t)tmp; + } + lineSrc += m_nStride; + lineDst += pDst->m_nStride; + } + } else { + shift1 = d1 - s1; + shift2 = 32 - shift1; + middleDwords = (xd1 >> 5) - ((xd0 + 31) >> 5); + for (yy = yd0; yy < yd1; yy++) { + sp = lineSrc; + dp = lineDst; + if (d1 != 0) { + tmp1 = JBIG2_GETDWORD(sp) >> shift1; + tmp2 = JBIG2_GETDWORD(dp); + switch (op) { + case JBIG2_COMPOSE_OR: + tmp = (tmp2 & ~maskL) | ((tmp1 | tmp2) & maskL); + break; + case JBIG2_COMPOSE_AND: + tmp = (tmp2 & ~maskL) | ((tmp1 & tmp2) & maskL); + break; + case JBIG2_COMPOSE_XOR: + tmp = (tmp2 & ~maskL) | ((tmp1 ^ tmp2) & maskL); + break; + case JBIG2_COMPOSE_XNOR: + tmp = (tmp2 & ~maskL) | ((~(tmp1 ^ tmp2)) & maskL); + break; + case JBIG2_COMPOSE_REPLACE: + tmp = (tmp2 & ~maskL) | (tmp1 & maskL); + break; + } + dp[0] = (uint8_t)(tmp >> 24); + dp[1] = (uint8_t)(tmp >> 16); + dp[2] = (uint8_t)(tmp >> 8); + dp[3] = (uint8_t)tmp; + dp += 4; + } + for (xx = 0; xx < middleDwords; xx++) { + tmp1 = (JBIG2_GETDWORD(sp) << shift2) | + ((JBIG2_GETDWORD(sp + 4)) >> shift1); + tmp2 = JBIG2_GETDWORD(dp); + switch (op) { + case JBIG2_COMPOSE_OR: + tmp = tmp1 | tmp2; + break; + case JBIG2_COMPOSE_AND: + tmp = tmp1 & tmp2; + break; + case JBIG2_COMPOSE_XOR: + tmp = tmp1 ^ tmp2; + break; + case JBIG2_COMPOSE_XNOR: + tmp = ~(tmp1 ^ tmp2); + break; + case JBIG2_COMPOSE_REPLACE: + tmp = tmp1; + break; + } + dp[0] = (uint8_t)(tmp >> 24); + dp[1] = (uint8_t)(tmp >> 16); + dp[2] = (uint8_t)(tmp >> 8); + dp[3] = (uint8_t)tmp; + sp += 4; + dp += 4; + } + if (d2 != 0) { + tmp1 = + (JBIG2_GETDWORD(sp) << shift2) | + (((sp + 4) < lineSrc + lineLeft ? JBIG2_GETDWORD(sp + 4) : 0) >> + shift1); + tmp2 = JBIG2_GETDWORD(dp); + switch (op) { + case JBIG2_COMPOSE_OR: + tmp = (tmp2 & ~maskR) | ((tmp1 | tmp2) & maskR); + break; + case JBIG2_COMPOSE_AND: + tmp = (tmp2 & ~maskR) | ((tmp1 & tmp2) & maskR); + break; + case JBIG2_COMPOSE_XOR: + tmp = (tmp2 & ~maskR) | ((tmp1 ^ tmp2) & maskR); + break; + case JBIG2_COMPOSE_XNOR: + tmp = (tmp2 & ~maskR) | ((~(tmp1 ^ tmp2)) & maskR); + break; + case JBIG2_COMPOSE_REPLACE: + tmp = (tmp2 & ~maskR) | (tmp1 & maskR); + break; + } + dp[0] = (uint8_t)(tmp >> 24); + dp[1] = (uint8_t)(tmp >> 16); + dp[2] = (uint8_t)(tmp >> 8); + dp[3] = (uint8_t)tmp; + } + lineSrc += m_nStride; + lineDst += pDst->m_nStride; + } + } + } + return 1; +} +FX_BOOL CJBig2_Image::composeTo_opt2(CJBig2_Image* pDst, + int32_t x, + int32_t y, + JBig2ComposeOp op, + const FX_RECT* pSrcRect) { + int32_t xs0, ys0, xs1, ys1, xd0, yd0, xd1, yd1, xx, yy, w, h, middleDwords, + lineLeft; + FX_DWORD s1, d1, d2, shift, shift1, shift2, tmp, tmp1, tmp2, maskL, maskR, + maskM; + uint8_t *lineSrc, *lineDst, *sp, *dp; + int32_t sw, sh; + if (!m_pData) { + return FALSE; + } + if (x < -1048576 || x > 1048576 || y < -1048576 || y > 1048576) { + return FALSE; + } + sw = pSrcRect->Width(); + sh = pSrcRect->Height(); + if (y < 0) { + ys0 = -y; + } else { + ys0 = 0; + } + if (y + sh > pDst->m_nHeight) { + ys1 = pDst->m_nHeight - y; + } else { + ys1 = sh; + } + if (x < 0) { + xs0 = -x; + } else { + xs0 = 0; + } + if (x + sw > pDst->m_nWidth) { + xs1 = pDst->m_nWidth - x; + } else { + xs1 = sw; + } + if ((ys0 >= ys1) || (xs0 >= xs1)) { + return 0; + } + w = xs1 - xs0; + h = ys1 - ys0; + if (y < 0) { + yd0 = 0; + } else { + yd0 = y; + } + if (x < 0) { + xd0 = 0; + } else { + xd0 = x; + } + xd1 = xd0 + w; + yd1 = yd0 + h; + d1 = xd0 & 31; + d2 = xd1 & 31; + s1 = xs0 & 31; + maskL = 0xffffffff >> d1; + maskR = 0xffffffff << ((32 - (xd1 & 31)) % 32); + maskM = maskL & maskR; + lineSrc = m_pData + (pSrcRect->top + ys0) * m_nStride + + (((xs0 + pSrcRect->left) >> 5) << 2); + lineLeft = m_nStride - ((xs0 >> 5) << 2); + lineDst = pDst->m_pData + yd0 * pDst->m_nStride + ((xd0 >> 5) << 2); + if ((xd0 & ~31) == ((xd1 - 1) & ~31)) { + if ((xs0 & ~31) == ((xs1 - 1) & ~31)) { + if (s1 > d1) { + shift = s1 - d1; + for (yy = yd0; yy < yd1; yy++) { + tmp1 = JBIG2_GETDWORD(lineSrc) << shift; + tmp2 = JBIG2_GETDWORD(lineDst); + switch (op) { + case JBIG2_COMPOSE_OR: + tmp = (tmp2 & ~maskM) | ((tmp1 | tmp2) & maskM); + break; + case JBIG2_COMPOSE_AND: + tmp = (tmp2 & ~maskM) | ((tmp1 & tmp2) & maskM); + break; + case JBIG2_COMPOSE_XOR: + tmp = (tmp2 & ~maskM) | ((tmp1 ^ tmp2) & maskM); + break; + case JBIG2_COMPOSE_XNOR: + tmp = (tmp2 & ~maskM) | ((~(tmp1 ^ tmp2)) & maskM); + break; + case JBIG2_COMPOSE_REPLACE: + tmp = (tmp2 & ~maskM) | (tmp1 & maskM); + break; + } + lineDst[0] = (uint8_t)(tmp >> 24); + lineDst[1] = (uint8_t)(tmp >> 16); + lineDst[2] = (uint8_t)(tmp >> 8); + lineDst[3] = (uint8_t)tmp; + lineSrc += m_nStride; + lineDst += pDst->m_nStride; + } + } else { + shift = d1 - s1; + for (yy = yd0; yy < yd1; yy++) { + tmp1 = JBIG2_GETDWORD(lineSrc) >> shift; + tmp2 = JBIG2_GETDWORD(lineDst); + switch (op) { + case JBIG2_COMPOSE_OR: + tmp = (tmp2 & ~maskM) | ((tmp1 | tmp2) & maskM); + break; + case JBIG2_COMPOSE_AND: + tmp = (tmp2 & ~maskM) | ((tmp1 & tmp2) & maskM); + break; + case JBIG2_COMPOSE_XOR: + tmp = (tmp2 & ~maskM) | ((tmp1 ^ tmp2) & maskM); + break; + case JBIG2_COMPOSE_XNOR: + tmp = (tmp2 & ~maskM) | ((~(tmp1 ^ tmp2)) & maskM); + break; + case JBIG2_COMPOSE_REPLACE: + tmp = (tmp2 & ~maskM) | (tmp1 & maskM); + break; + } + lineDst[0] = (uint8_t)(tmp >> 24); + lineDst[1] = (uint8_t)(tmp >> 16); + lineDst[2] = (uint8_t)(tmp >> 8); + lineDst[3] = (uint8_t)tmp; + lineSrc += m_nStride; + lineDst += pDst->m_nStride; + } + } + } else { + shift1 = s1 - d1; + shift2 = 32 - shift1; + for (yy = yd0; yy < yd1; yy++) { + tmp1 = (JBIG2_GETDWORD(lineSrc) << shift1) | + (JBIG2_GETDWORD(lineSrc + 4) >> shift2); + tmp2 = JBIG2_GETDWORD(lineDst); + switch (op) { + case JBIG2_COMPOSE_OR: + tmp = (tmp2 & ~maskM) | ((tmp1 | tmp2) & maskM); + break; + case JBIG2_COMPOSE_AND: + tmp = (tmp2 & ~maskM) | ((tmp1 & tmp2) & maskM); + break; + case JBIG2_COMPOSE_XOR: + tmp = (tmp2 & ~maskM) | ((tmp1 ^ tmp2) & maskM); + break; + case JBIG2_COMPOSE_XNOR: + tmp = (tmp2 & ~maskM) | ((~(tmp1 ^ tmp2)) & maskM); + break; + case JBIG2_COMPOSE_REPLACE: + tmp = (tmp2 & ~maskM) | (tmp1 & maskM); + break; + } + lineDst[0] = (uint8_t)(tmp >> 24); + lineDst[1] = (uint8_t)(tmp >> 16); + lineDst[2] = (uint8_t)(tmp >> 8); + lineDst[3] = (uint8_t)tmp; + lineSrc += m_nStride; + lineDst += pDst->m_nStride; + } + } + } else { + if (s1 > d1) { + shift1 = s1 - d1; + shift2 = 32 - shift1; + middleDwords = (xd1 >> 5) - ((xd0 + 31) >> 5); + for (yy = yd0; yy < yd1; yy++) { + sp = lineSrc; + dp = lineDst; + if (d1 != 0) { + tmp1 = (JBIG2_GETDWORD(sp) << shift1) | + (JBIG2_GETDWORD(sp + 4) >> shift2); + tmp2 = JBIG2_GETDWORD(dp); + switch (op) { + case JBIG2_COMPOSE_OR: + tmp = (tmp2 & ~maskL) | ((tmp1 | tmp2) & maskL); + break; + case JBIG2_COMPOSE_AND: + tmp = (tmp2 & ~maskL) | ((tmp1 & tmp2) & maskL); + break; + case JBIG2_COMPOSE_XOR: + tmp = (tmp2 & ~maskL) | ((tmp1 ^ tmp2) & maskL); + break; + case JBIG2_COMPOSE_XNOR: + tmp = (tmp2 & ~maskL) | ((~(tmp1 ^ tmp2)) & maskL); + break; + case JBIG2_COMPOSE_REPLACE: + tmp = (tmp2 & ~maskL) | (tmp1 & maskL); + break; + } + dp[0] = (uint8_t)(tmp >> 24); + dp[1] = (uint8_t)(tmp >> 16); + dp[2] = (uint8_t)(tmp >> 8); + dp[3] = (uint8_t)tmp; + sp += 4; + dp += 4; + } + for (xx = 0; xx < middleDwords; xx++) { + tmp1 = (JBIG2_GETDWORD(sp) << shift1) | + (JBIG2_GETDWORD(sp + 4) >> shift2); + tmp2 = JBIG2_GETDWORD(dp); + switch (op) { + case JBIG2_COMPOSE_OR: + tmp = tmp1 | tmp2; + break; + case JBIG2_COMPOSE_AND: + tmp = tmp1 & tmp2; + break; + case JBIG2_COMPOSE_XOR: + tmp = tmp1 ^ tmp2; + break; + case JBIG2_COMPOSE_XNOR: + tmp = ~(tmp1 ^ tmp2); + break; + case JBIG2_COMPOSE_REPLACE: + tmp = tmp1; + break; + } + dp[0] = (uint8_t)(tmp >> 24); + dp[1] = (uint8_t)(tmp >> 16); + dp[2] = (uint8_t)(tmp >> 8); + dp[3] = (uint8_t)tmp; + sp += 4; + dp += 4; + } + if (d2 != 0) { + tmp1 = + (JBIG2_GETDWORD(sp) << shift1) | + (((sp + 4) < lineSrc + lineLeft ? JBIG2_GETDWORD(sp + 4) : 0) >> + shift2); + tmp2 = JBIG2_GETDWORD(dp); + switch (op) { + case JBIG2_COMPOSE_OR: + tmp = (tmp2 & ~maskR) | ((tmp1 | tmp2) & maskR); + break; + case JBIG2_COMPOSE_AND: + tmp = (tmp2 & ~maskR) | ((tmp1 & tmp2) & maskR); + break; + case JBIG2_COMPOSE_XOR: + tmp = (tmp2 & ~maskR) | ((tmp1 ^ tmp2) & maskR); + break; + case JBIG2_COMPOSE_XNOR: + tmp = (tmp2 & ~maskR) | ((~(tmp1 ^ tmp2)) & maskR); + break; + case JBIG2_COMPOSE_REPLACE: + tmp = (tmp2 & ~maskR) | (tmp1 & maskR); + break; + } + dp[0] = (uint8_t)(tmp >> 24); + dp[1] = (uint8_t)(tmp >> 16); + dp[2] = (uint8_t)(tmp >> 8); + dp[3] = (uint8_t)tmp; + } + lineSrc += m_nStride; + lineDst += pDst->m_nStride; + } + } else if (s1 == d1) { + middleDwords = (xd1 >> 5) - ((xd0 + 31) >> 5); + for (yy = yd0; yy < yd1; yy++) { + sp = lineSrc; + dp = lineDst; + if (d1 != 0) { + tmp1 = JBIG2_GETDWORD(sp); + tmp2 = JBIG2_GETDWORD(dp); + switch (op) { + case JBIG2_COMPOSE_OR: + tmp = (tmp2 & ~maskL) | ((tmp1 | tmp2) & maskL); + break; + case JBIG2_COMPOSE_AND: + tmp = (tmp2 & ~maskL) | ((tmp1 & tmp2) & maskL); + break; + case JBIG2_COMPOSE_XOR: + tmp = (tmp2 & ~maskL) | ((tmp1 ^ tmp2) & maskL); + break; + case JBIG2_COMPOSE_XNOR: + tmp = (tmp2 & ~maskL) | ((~(tmp1 ^ tmp2)) & maskL); + break; + case JBIG2_COMPOSE_REPLACE: + tmp = (tmp2 & ~maskL) | (tmp1 & maskL); + break; + } + dp[0] = (uint8_t)(tmp >> 24); + dp[1] = (uint8_t)(tmp >> 16); + dp[2] = (uint8_t)(tmp >> 8); + dp[3] = (uint8_t)tmp; + sp += 4; + dp += 4; + } + for (xx = 0; xx < middleDwords; xx++) { + tmp1 = JBIG2_GETDWORD(sp); + tmp2 = JBIG2_GETDWORD(dp); + switch (op) { + case JBIG2_COMPOSE_OR: + tmp = tmp1 | tmp2; + break; + case JBIG2_COMPOSE_AND: + tmp = tmp1 & tmp2; + break; + case JBIG2_COMPOSE_XOR: + tmp = tmp1 ^ tmp2; + break; + case JBIG2_COMPOSE_XNOR: + tmp = ~(tmp1 ^ tmp2); + break; + case JBIG2_COMPOSE_REPLACE: + tmp = tmp1; + break; + } + dp[0] = (uint8_t)(tmp >> 24); + dp[1] = (uint8_t)(tmp >> 16); + dp[2] = (uint8_t)(tmp >> 8); + dp[3] = (uint8_t)tmp; + sp += 4; + dp += 4; + } + if (d2 != 0) { + tmp1 = JBIG2_GETDWORD(sp); + tmp2 = JBIG2_GETDWORD(dp); + switch (op) { + case JBIG2_COMPOSE_OR: + tmp = (tmp2 & ~maskR) | ((tmp1 | tmp2) & maskR); + break; + case JBIG2_COMPOSE_AND: + tmp = (tmp2 & ~maskR) | ((tmp1 & tmp2) & maskR); + break; + case JBIG2_COMPOSE_XOR: + tmp = (tmp2 & ~maskR) | ((tmp1 ^ tmp2) & maskR); + break; + case JBIG2_COMPOSE_XNOR: + tmp = (tmp2 & ~maskR) | ((~(tmp1 ^ tmp2)) & maskR); + break; + case JBIG2_COMPOSE_REPLACE: + tmp = (tmp2 & ~maskR) | (tmp1 & maskR); + break; + } + dp[0] = (uint8_t)(tmp >> 24); + dp[1] = (uint8_t)(tmp >> 16); + dp[2] = (uint8_t)(tmp >> 8); + dp[3] = (uint8_t)tmp; + } + lineSrc += m_nStride; + lineDst += pDst->m_nStride; + } + } else { + shift1 = d1 - s1; + shift2 = 32 - shift1; + middleDwords = (xd1 >> 5) - ((xd0 + 31) >> 5); + for (yy = yd0; yy < yd1; yy++) { + sp = lineSrc; + dp = lineDst; + if (d1 != 0) { + tmp1 = JBIG2_GETDWORD(sp) >> shift1; + tmp2 = JBIG2_GETDWORD(dp); + switch (op) { + case JBIG2_COMPOSE_OR: + tmp = (tmp2 & ~maskL) | ((tmp1 | tmp2) & maskL); + break; + case JBIG2_COMPOSE_AND: + tmp = (tmp2 & ~maskL) | ((tmp1 & tmp2) & maskL); + break; + case JBIG2_COMPOSE_XOR: + tmp = (tmp2 & ~maskL) | ((tmp1 ^ tmp2) & maskL); + break; + case JBIG2_COMPOSE_XNOR: + tmp = (tmp2 & ~maskL) | ((~(tmp1 ^ tmp2)) & maskL); + break; + case JBIG2_COMPOSE_REPLACE: + tmp = (tmp2 & ~maskL) | (tmp1 & maskL); + break; + } + dp[0] = (uint8_t)(tmp >> 24); + dp[1] = (uint8_t)(tmp >> 16); + dp[2] = (uint8_t)(tmp >> 8); + dp[3] = (uint8_t)tmp; + dp += 4; + } + for (xx = 0; xx < middleDwords; xx++) { + tmp1 = (JBIG2_GETDWORD(sp) << shift2) | + ((JBIG2_GETDWORD(sp + 4)) >> shift1); + tmp2 = JBIG2_GETDWORD(dp); + switch (op) { + case JBIG2_COMPOSE_OR: + tmp = tmp1 | tmp2; + break; + case JBIG2_COMPOSE_AND: + tmp = tmp1 & tmp2; + break; + case JBIG2_COMPOSE_XOR: + tmp = tmp1 ^ tmp2; + break; + case JBIG2_COMPOSE_XNOR: + tmp = ~(tmp1 ^ tmp2); + break; + case JBIG2_COMPOSE_REPLACE: + tmp = tmp1; + break; + } + dp[0] = (uint8_t)(tmp >> 24); + dp[1] = (uint8_t)(tmp >> 16); + dp[2] = (uint8_t)(tmp >> 8); + dp[3] = (uint8_t)tmp; + sp += 4; + dp += 4; + } + if (d2 != 0) { + tmp1 = + (JBIG2_GETDWORD(sp) << shift2) | + (((sp + 4) < lineSrc + lineLeft ? JBIG2_GETDWORD(sp + 4) : 0) >> + shift1); + tmp2 = JBIG2_GETDWORD(dp); + switch (op) { + case JBIG2_COMPOSE_OR: + tmp = (tmp2 & ~maskR) | ((tmp1 | tmp2) & maskR); + break; + case JBIG2_COMPOSE_AND: + tmp = (tmp2 & ~maskR) | ((tmp1 & tmp2) & maskR); + break; + case JBIG2_COMPOSE_XOR: + tmp = (tmp2 & ~maskR) | ((tmp1 ^ tmp2) & maskR); + break; + case JBIG2_COMPOSE_XNOR: + tmp = (tmp2 & ~maskR) | ((~(tmp1 ^ tmp2)) & maskR); + break; + case JBIG2_COMPOSE_REPLACE: + tmp = (tmp2 & ~maskR) | (tmp1 & maskR); + break; + } + dp[0] = (uint8_t)(tmp >> 24); + dp[1] = (uint8_t)(tmp >> 16); + dp[2] = (uint8_t)(tmp >> 8); + dp[3] = (uint8_t)tmp; + } + lineSrc += m_nStride; + lineDst += pDst->m_nStride; + } + } + } + return 1; +} diff --git a/core/fxcodec/jbig2/JBig2_Image.h b/core/fxcodec/jbig2/JBig2_Image.h new file mode 100644 index 0000000000..a18a95d596 --- /dev/null +++ b/core/fxcodec/jbig2/JBig2_Image.h @@ -0,0 +1,85 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#ifndef CORE_FXCODEC_JBIG2_JBIG2_IMAGE_H_ +#define CORE_FXCODEC_JBIG2_JBIG2_IMAGE_H_ + +#include "core/fxcodec/jbig2/JBig2_Define.h" + +enum JBig2ComposeOp { + JBIG2_COMPOSE_OR = 0, + JBIG2_COMPOSE_AND = 1, + JBIG2_COMPOSE_XOR = 2, + JBIG2_COMPOSE_XNOR = 3, + JBIG2_COMPOSE_REPLACE = 4 +}; + +struct FX_RECT; +class CJBig2_Image { + public: + CJBig2_Image(int32_t w, int32_t h); + + CJBig2_Image(int32_t w, int32_t h, int32_t stride, uint8_t* pBuf); + + CJBig2_Image(const CJBig2_Image& im); + + ~CJBig2_Image(); + + FX_BOOL getPixel(int32_t x, int32_t y); + + int32_t setPixel(int32_t x, int32_t y, FX_BOOL v); + + void copyLine(int32_t hTo, int32_t hFrom); + + void fill(FX_BOOL v); + + FX_BOOL composeTo(CJBig2_Image* pDst, + int32_t x, + int32_t y, + JBig2ComposeOp op); + FX_BOOL composeTo(CJBig2_Image* pDst, + int32_t x, + int32_t y, + JBig2ComposeOp op, + const FX_RECT* pSrcRect); + + FX_BOOL composeTo_opt2(CJBig2_Image* pDst, + int32_t x, + int32_t y, + JBig2ComposeOp op); + FX_BOOL composeTo_opt2(CJBig2_Image* pDst, + int32_t x, + int32_t y, + JBig2ComposeOp op, + const FX_RECT* pSrcRect); + + FX_BOOL composeFrom(int32_t x, + int32_t y, + CJBig2_Image* pSrc, + JBig2ComposeOp op); + FX_BOOL composeFrom(int32_t x, + int32_t y, + CJBig2_Image* pSrc, + JBig2ComposeOp op, + const FX_RECT* pSrcRect); + + CJBig2_Image* subImage(int32_t x, int32_t y, int32_t w, int32_t h); + + void expand(int32_t h, FX_BOOL v); + + public: + int32_t m_nWidth; + + int32_t m_nHeight; + + int32_t m_nStride; + + uint8_t* m_pData; + + FX_BOOL m_bNeedFree; +}; + +#endif // CORE_FXCODEC_JBIG2_JBIG2_IMAGE_H_ diff --git a/core/fxcodec/jbig2/JBig2_List.h b/core/fxcodec/jbig2/JBig2_List.h new file mode 100644 index 0000000000..b021ac3375 --- /dev/null +++ b/core/fxcodec/jbig2/JBig2_List.h @@ -0,0 +1,54 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#ifndef CORE_FXCODEC_JBIG2_JBIG2_LIST_H_ +#define CORE_FXCODEC_JBIG2_JBIG2_LIST_H_ + +#include <stdlib.h> + +#include <vector> + +// A poor man's ScopedVector for pointers of TYPE. +// Owns all the pointers contained within and deletes them on destruction. +template <class TYPE> +class CJBig2_List { + public: + CJBig2_List() {} + explicit CJBig2_List(size_t count) { resize(count); } + + ~CJBig2_List() { clear(); } + + TYPE* get(size_t index) const { return m_vector[index]; } + TYPE* back() const { return m_vector.back(); } + size_t size() const { return m_vector.size(); } + + // Deletes all the pointers contained within. + void clear() { + for (size_t i = 0; i < m_vector.size(); ++i) + delete m_vector[i]; + m_vector.clear(); + } + + // Takes ownership of |pItem|. + void push_back(TYPE* pItem) { m_vector.push_back(pItem); } + + // Takes ownership of |pItem|. + void set(size_t index, TYPE* pItem) { + delete m_vector[index]; + m_vector[index] = pItem; + } + + void resize(size_t count) { + for (size_t i = count; i < size(); ++i) + delete m_vector[i]; + m_vector.resize(count); + } + + private: + std::vector<TYPE*> m_vector; +}; + +#endif // CORE_FXCODEC_JBIG2_JBIG2_LIST_H_ diff --git a/core/fxcodec/jbig2/JBig2_Page.h b/core/fxcodec/jbig2/JBig2_Page.h new file mode 100644 index 0000000000..b3e09d8ae0 --- /dev/null +++ b/core/fxcodec/jbig2/JBig2_Page.h @@ -0,0 +1,22 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#ifndef CORE_FXCODEC_JBIG2_JBIG2_PAGE_H_ +#define CORE_FXCODEC_JBIG2_JBIG2_PAGE_H_ + +#include "core/include/fxcrt/fx_system.h" + +struct JBig2PageInfo { + FX_DWORD m_dwWidth; + FX_DWORD m_dwHeight; + FX_DWORD m_dwResolutionX; + FX_DWORD m_dwResolutionY; + uint8_t m_cFlags; + FX_BOOL m_bIsStriped; + FX_WORD m_wMaxStripeSize; +}; + +#endif // CORE_FXCODEC_JBIG2_JBIG2_PAGE_H_ diff --git a/core/fxcodec/jbig2/JBig2_PatternDict.cpp b/core/fxcodec/jbig2/JBig2_PatternDict.cpp new file mode 100644 index 0000000000..58157ef13a --- /dev/null +++ b/core/fxcodec/jbig2/JBig2_PatternDict.cpp @@ -0,0 +1,23 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "core/fxcodec/jbig2/JBig2_PatternDict.h" + +#include "core/include/fxcrt/fx_memory.h" + +CJBig2_PatternDict::CJBig2_PatternDict() { + NUMPATS = 0; + HDPATS = NULL; +} + +CJBig2_PatternDict::~CJBig2_PatternDict() { + if (HDPATS) { + for (FX_DWORD i = 0; i < NUMPATS; i++) { + delete HDPATS[i]; + } + FX_Free(HDPATS); + } +} diff --git a/core/fxcodec/jbig2/JBig2_PatternDict.h b/core/fxcodec/jbig2/JBig2_PatternDict.h new file mode 100644 index 0000000000..3196fcaaf3 --- /dev/null +++ b/core/fxcodec/jbig2/JBig2_PatternDict.h @@ -0,0 +1,23 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#ifndef CORE_FXCODEC_JBIG2_JBIG2_PATTERNDICT_H_ +#define CORE_FXCODEC_JBIG2_JBIG2_PATTERNDICT_H_ + +#include "core/fxcodec/jbig2/JBig2_Define.h" +#include "core/fxcodec/jbig2/JBig2_Image.h" + +class CJBig2_PatternDict { + public: + CJBig2_PatternDict(); + + ~CJBig2_PatternDict(); + + FX_DWORD NUMPATS; + CJBig2_Image** HDPATS; +}; + +#endif // CORE_FXCODEC_JBIG2_JBIG2_PATTERNDICT_H_ diff --git a/core/fxcodec/jbig2/JBig2_PddProc.cpp b/core/fxcodec/jbig2/JBig2_PddProc.cpp new file mode 100644 index 0000000000..5b67aadb57 --- /dev/null +++ b/core/fxcodec/jbig2/JBig2_PddProc.cpp @@ -0,0 +1,87 @@ +// Copyright 2015 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "core/fxcodec/jbig2/JBig2_PddProc.h" + +#include <memory> + +#include "core/fxcodec/jbig2/JBig2_GrdProc.h" +#include "core/fxcodec/jbig2/JBig2_Image.h" +#include "core/fxcodec/jbig2/JBig2_PatternDict.h" + +CJBig2_PatternDict* CJBig2_PDDProc::decode_Arith( + CJBig2_ArithDecoder* pArithDecoder, + JBig2ArithCtx* gbContext, + IFX_Pause* pPause) { + FX_DWORD GRAY; + CJBig2_Image* BHDC = nullptr; + std::unique_ptr<CJBig2_PatternDict> pDict(new CJBig2_PatternDict()); + pDict->NUMPATS = GRAYMAX + 1; + pDict->HDPATS = FX_Alloc(CJBig2_Image*, pDict->NUMPATS); + JBIG2_memset(pDict->HDPATS, 0, sizeof(CJBig2_Image*) * pDict->NUMPATS); + + std::unique_ptr<CJBig2_GRDProc> pGRD(new CJBig2_GRDProc()); + pGRD->MMR = HDMMR; + pGRD->GBW = (GRAYMAX + 1) * HDPW; + pGRD->GBH = HDPH; + pGRD->GBTEMPLATE = HDTEMPLATE; + pGRD->TPGDON = 0; + pGRD->USESKIP = 0; + pGRD->GBAT[0] = -(int32_t)HDPW; + pGRD->GBAT[1] = 0; + if (pGRD->GBTEMPLATE == 0) { + pGRD->GBAT[2] = -3; + pGRD->GBAT[3] = -1; + pGRD->GBAT[4] = 2; + pGRD->GBAT[5] = -2; + pGRD->GBAT[6] = -2; + pGRD->GBAT[7] = -2; + } + FXCODEC_STATUS status = + pGRD->Start_decode_Arith(&BHDC, pArithDecoder, gbContext, nullptr); + while (status == FXCODEC_STATUS_DECODE_TOBECONTINUE) { + pGRD->Continue_decode(pPause); + } + if (!BHDC) + return nullptr; + + GRAY = 0; + while (GRAY <= GRAYMAX) { + pDict->HDPATS[GRAY] = BHDC->subImage(HDPW * GRAY, 0, HDPW, HDPH); + GRAY = GRAY + 1; + } + delete BHDC; + return pDict.release(); +} + +CJBig2_PatternDict* CJBig2_PDDProc::decode_MMR(CJBig2_BitStream* pStream, + IFX_Pause* pPause) { + FX_DWORD GRAY; + CJBig2_Image* BHDC = nullptr; + std::unique_ptr<CJBig2_PatternDict> pDict(new CJBig2_PatternDict()); + pDict->NUMPATS = GRAYMAX + 1; + pDict->HDPATS = FX_Alloc(CJBig2_Image*, pDict->NUMPATS); + JBIG2_memset(pDict->HDPATS, 0, sizeof(CJBig2_Image*) * pDict->NUMPATS); + + std::unique_ptr<CJBig2_GRDProc> pGRD(new CJBig2_GRDProc()); + pGRD->MMR = HDMMR; + pGRD->GBW = (GRAYMAX + 1) * HDPW; + pGRD->GBH = HDPH; + FXCODEC_STATUS status = pGRD->Start_decode_MMR(&BHDC, pStream, nullptr); + while (status == FXCODEC_STATUS_DECODE_TOBECONTINUE) { + pGRD->Continue_decode(pPause); + } + if (!BHDC) + return nullptr; + + GRAY = 0; + while (GRAY <= GRAYMAX) { + pDict->HDPATS[GRAY] = BHDC->subImage(HDPW * GRAY, 0, HDPW, HDPH); + GRAY = GRAY + 1; + } + delete BHDC; + return pDict.release(); +} diff --git a/core/fxcodec/jbig2/JBig2_PddProc.h b/core/fxcodec/jbig2/JBig2_PddProc.h new file mode 100644 index 0000000000..25f941235f --- /dev/null +++ b/core/fxcodec/jbig2/JBig2_PddProc.h @@ -0,0 +1,34 @@ +// Copyright 2015 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#ifndef CORE_FXCODEC_JBIG2_JBIG2_PDDPROC_H_ +#define CORE_FXCODEC_JBIG2_JBIG2_PDDPROC_H_ + +#include "core/include/fxcrt/fx_system.h" + +class CJBig2_ArithDecoder; +class CJBig2_BitStream; +class CJBig2_PatternDict; +class IFX_Pause; +struct JBig2ArithCtx; + +class CJBig2_PDDProc { + public: + CJBig2_PatternDict* decode_Arith(CJBig2_ArithDecoder* pArithDecoder, + JBig2ArithCtx* gbContext, + IFX_Pause* pPause); + + CJBig2_PatternDict* decode_MMR(CJBig2_BitStream* pStream, IFX_Pause* pPause); + + public: + FX_BOOL HDMMR; + uint8_t HDPW; + uint8_t HDPH; + FX_DWORD GRAYMAX; + uint8_t HDTEMPLATE; +}; + +#endif // CORE_FXCODEC_JBIG2_JBIG2_PDDPROC_H_ diff --git a/core/fxcodec/jbig2/JBig2_SddProc.cpp b/core/fxcodec/jbig2/JBig2_SddProc.cpp new file mode 100644 index 0000000000..80079b93a5 --- /dev/null +++ b/core/fxcodec/jbig2/JBig2_SddProc.cpp @@ -0,0 +1,624 @@ +// Copyright 2015 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "core/fxcodec/jbig2/JBig2_SddProc.h" + +#include <memory> +#include <vector> + +#include "core/fxcodec/jbig2/JBig2_ArithIntDecoder.h" +#include "core/fxcodec/jbig2/JBig2_GrdProc.h" +#include "core/fxcodec/jbig2/JBig2_GrrdProc.h" +#include "core/fxcodec/jbig2/JBig2_HuffmanDecoder.h" +#include "core/fxcodec/jbig2/JBig2_HuffmanTable.h" +#include "core/fxcodec/jbig2/JBig2_HuffmanTable_Standard.h" +#include "core/fxcodec/jbig2/JBig2_SymbolDict.h" +#include "core/fxcodec/jbig2/JBig2_TrdProc.h" +#include "core/include/fxcrt/fx_basic.h" + +CJBig2_SymbolDict* CJBig2_SDDProc::decode_Arith( + CJBig2_ArithDecoder* pArithDecoder, + std::vector<JBig2ArithCtx>* gbContext, + std::vector<JBig2ArithCtx>* grContext) { + CJBig2_Image** SDNEWSYMS; + FX_DWORD HCHEIGHT, NSYMSDECODED; + int32_t HCDH; + FX_DWORD SYMWIDTH, TOTWIDTH; + int32_t DW; + CJBig2_Image* BS; + FX_DWORD I, J, REFAGGNINST; + FX_BOOL* EXFLAGS; + FX_DWORD EXINDEX; + FX_BOOL CUREXFLAG; + FX_DWORD EXRUNLENGTH; + FX_DWORD nTmp; + FX_DWORD SBNUMSYMS; + uint8_t SBSYMCODELEN; + int32_t RDXI, RDYI; + CJBig2_Image** SBSYMS; + std::unique_ptr<CJBig2_ArithIaidDecoder> IAID; + std::unique_ptr<CJBig2_SymbolDict> pDict; + std::unique_ptr<CJBig2_ArithIntDecoder> IADH(new CJBig2_ArithIntDecoder); + std::unique_ptr<CJBig2_ArithIntDecoder> IADW(new CJBig2_ArithIntDecoder); + std::unique_ptr<CJBig2_ArithIntDecoder> IAAI(new CJBig2_ArithIntDecoder); + std::unique_ptr<CJBig2_ArithIntDecoder> IARDX(new CJBig2_ArithIntDecoder); + std::unique_ptr<CJBig2_ArithIntDecoder> IARDY(new CJBig2_ArithIntDecoder); + std::unique_ptr<CJBig2_ArithIntDecoder> IAEX(new CJBig2_ArithIntDecoder); + std::unique_ptr<CJBig2_ArithIntDecoder> IADT(new CJBig2_ArithIntDecoder); + std::unique_ptr<CJBig2_ArithIntDecoder> IAFS(new CJBig2_ArithIntDecoder); + std::unique_ptr<CJBig2_ArithIntDecoder> IADS(new CJBig2_ArithIntDecoder); + std::unique_ptr<CJBig2_ArithIntDecoder> IAIT(new CJBig2_ArithIntDecoder); + std::unique_ptr<CJBig2_ArithIntDecoder> IARI(new CJBig2_ArithIntDecoder); + std::unique_ptr<CJBig2_ArithIntDecoder> IARDW(new CJBig2_ArithIntDecoder); + std::unique_ptr<CJBig2_ArithIntDecoder> IARDH(new CJBig2_ArithIntDecoder); + nTmp = 0; + while ((FX_DWORD)(1 << nTmp) < (SDNUMINSYMS + SDNUMNEWSYMS)) { + nTmp++; + } + IAID.reset(new CJBig2_ArithIaidDecoder((uint8_t)nTmp)); + SDNEWSYMS = FX_Alloc(CJBig2_Image*, SDNUMNEWSYMS); + FXSYS_memset(SDNEWSYMS, 0, SDNUMNEWSYMS * sizeof(CJBig2_Image*)); + + HCHEIGHT = 0; + NSYMSDECODED = 0; + while (NSYMSDECODED < SDNUMNEWSYMS) { + BS = nullptr; + IADH->decode(pArithDecoder, &HCDH); + HCHEIGHT = HCHEIGHT + HCDH; + if ((int)HCHEIGHT < 0 || (int)HCHEIGHT > JBIG2_MAX_IMAGE_SIZE) { + goto failed; + } + SYMWIDTH = 0; + TOTWIDTH = 0; + for (;;) { + if (!IADW->decode(pArithDecoder, &DW)) + break; + + if (NSYMSDECODED >= SDNUMNEWSYMS) + goto failed; + + SYMWIDTH = SYMWIDTH + DW; + if ((int)SYMWIDTH < 0 || (int)SYMWIDTH > JBIG2_MAX_IMAGE_SIZE) + goto failed; + + if (HCHEIGHT == 0 || SYMWIDTH == 0) { + TOTWIDTH = TOTWIDTH + SYMWIDTH; + SDNEWSYMS[NSYMSDECODED] = nullptr; + NSYMSDECODED = NSYMSDECODED + 1; + continue; + } + TOTWIDTH = TOTWIDTH + SYMWIDTH; + if (SDREFAGG == 0) { + std::unique_ptr<CJBig2_GRDProc> pGRD(new CJBig2_GRDProc()); + pGRD->MMR = 0; + pGRD->GBW = SYMWIDTH; + pGRD->GBH = HCHEIGHT; + pGRD->GBTEMPLATE = SDTEMPLATE; + pGRD->TPGDON = 0; + pGRD->USESKIP = 0; + pGRD->GBAT[0] = SDAT[0]; + pGRD->GBAT[1] = SDAT[1]; + pGRD->GBAT[2] = SDAT[2]; + pGRD->GBAT[3] = SDAT[3]; + pGRD->GBAT[4] = SDAT[4]; + pGRD->GBAT[5] = SDAT[5]; + pGRD->GBAT[6] = SDAT[6]; + pGRD->GBAT[7] = SDAT[7]; + BS = pGRD->decode_Arith(pArithDecoder, gbContext->data()); + if (!BS) { + goto failed; + } + } else { + IAAI->decode(pArithDecoder, (int*)&REFAGGNINST); + if (REFAGGNINST > 1) { + std::unique_ptr<CJBig2_TRDProc> pDecoder(new CJBig2_TRDProc()); + pDecoder->SBHUFF = SDHUFF; + pDecoder->SBREFINE = 1; + pDecoder->SBW = SYMWIDTH; + pDecoder->SBH = HCHEIGHT; + pDecoder->SBNUMINSTANCES = REFAGGNINST; + pDecoder->SBSTRIPS = 1; + pDecoder->SBNUMSYMS = SDNUMINSYMS + NSYMSDECODED; + SBNUMSYMS = pDecoder->SBNUMSYMS; + nTmp = 0; + while ((FX_DWORD)(1 << nTmp) < SBNUMSYMS) { + nTmp++; + } + SBSYMCODELEN = (uint8_t)nTmp; + pDecoder->SBSYMCODELEN = SBSYMCODELEN; + SBSYMS = FX_Alloc(CJBig2_Image*, SBNUMSYMS); + JBIG2_memcpy(SBSYMS, SDINSYMS, SDNUMINSYMS * sizeof(CJBig2_Image*)); + JBIG2_memcpy(SBSYMS + SDNUMINSYMS, SDNEWSYMS, + NSYMSDECODED * sizeof(CJBig2_Image*)); + pDecoder->SBSYMS = SBSYMS; + pDecoder->SBDEFPIXEL = 0; + pDecoder->SBCOMBOP = JBIG2_COMPOSE_OR; + pDecoder->TRANSPOSED = 0; + pDecoder->REFCORNER = JBIG2_CORNER_TOPLEFT; + pDecoder->SBDSOFFSET = 0; + std::unique_ptr<CJBig2_HuffmanTable> SBHUFFFS(new CJBig2_HuffmanTable( + HuffmanTable_B6, FX_ArraySize(HuffmanTable_B6), + HuffmanTable_HTOOB_B6)); + std::unique_ptr<CJBig2_HuffmanTable> SBHUFFDS(new CJBig2_HuffmanTable( + HuffmanTable_B8, FX_ArraySize(HuffmanTable_B8), + HuffmanTable_HTOOB_B8)); + std::unique_ptr<CJBig2_HuffmanTable> SBHUFFDT(new CJBig2_HuffmanTable( + HuffmanTable_B11, FX_ArraySize(HuffmanTable_B11), + HuffmanTable_HTOOB_B11)); + std::unique_ptr<CJBig2_HuffmanTable> SBHUFFRDW( + new CJBig2_HuffmanTable(HuffmanTable_B15, + FX_ArraySize(HuffmanTable_B15), + HuffmanTable_HTOOB_B15)); + std::unique_ptr<CJBig2_HuffmanTable> SBHUFFRDH( + new CJBig2_HuffmanTable(HuffmanTable_B15, + FX_ArraySize(HuffmanTable_B15), + HuffmanTable_HTOOB_B15)); + std::unique_ptr<CJBig2_HuffmanTable> SBHUFFRDX( + new CJBig2_HuffmanTable(HuffmanTable_B15, + FX_ArraySize(HuffmanTable_B15), + HuffmanTable_HTOOB_B15)); + std::unique_ptr<CJBig2_HuffmanTable> SBHUFFRDY( + new CJBig2_HuffmanTable(HuffmanTable_B15, + FX_ArraySize(HuffmanTable_B15), + HuffmanTable_HTOOB_B15)); + std::unique_ptr<CJBig2_HuffmanTable> SBHUFFRSIZE( + new CJBig2_HuffmanTable(HuffmanTable_B1, + FX_ArraySize(HuffmanTable_B1), + HuffmanTable_HTOOB_B1)); + pDecoder->SBHUFFFS = SBHUFFFS.get(); + pDecoder->SBHUFFDS = SBHUFFDS.get(); + pDecoder->SBHUFFDT = SBHUFFDT.get(); + pDecoder->SBHUFFRDW = SBHUFFRDW.get(); + pDecoder->SBHUFFRDH = SBHUFFRDH.get(); + pDecoder->SBHUFFRDX = SBHUFFRDX.get(); + pDecoder->SBHUFFRDY = SBHUFFRDY.get(); + pDecoder->SBHUFFRSIZE = SBHUFFRSIZE.get(); + pDecoder->SBRTEMPLATE = SDRTEMPLATE; + pDecoder->SBRAT[0] = SDRAT[0]; + pDecoder->SBRAT[1] = SDRAT[1]; + pDecoder->SBRAT[2] = SDRAT[2]; + pDecoder->SBRAT[3] = SDRAT[3]; + JBig2IntDecoderState ids; + ids.IADT = IADT.get(); + ids.IAFS = IAFS.get(); + ids.IADS = IADS.get(); + ids.IAIT = IAIT.get(); + ids.IARI = IARI.get(); + ids.IARDW = IARDW.get(); + ids.IARDH = IARDH.get(); + ids.IARDX = IARDX.get(); + ids.IARDY = IARDY.get(); + ids.IAID = IAID.get(); + BS = pDecoder->decode_Arith(pArithDecoder, grContext->data(), &ids); + if (!BS) { + FX_Free(SBSYMS); + goto failed; + } + FX_Free(SBSYMS); + } else if (REFAGGNINST == 1) { + SBNUMSYMS = SDNUMINSYMS + NSYMSDECODED; + FX_DWORD IDI; + IAID->decode(pArithDecoder, &IDI); + IARDX->decode(pArithDecoder, &RDXI); + IARDY->decode(pArithDecoder, &RDYI); + if (IDI >= SBNUMSYMS) { + goto failed; + } + SBSYMS = FX_Alloc(CJBig2_Image*, SBNUMSYMS); + JBIG2_memcpy(SBSYMS, SDINSYMS, SDNUMINSYMS * sizeof(CJBig2_Image*)); + JBIG2_memcpy(SBSYMS + SDNUMINSYMS, SDNEWSYMS, + NSYMSDECODED * sizeof(CJBig2_Image*)); + if (!SBSYMS[IDI]) { + FX_Free(SBSYMS); + goto failed; + } + std::unique_ptr<CJBig2_GRRDProc> pGRRD(new CJBig2_GRRDProc()); + pGRRD->GRW = SYMWIDTH; + pGRRD->GRH = HCHEIGHT; + pGRRD->GRTEMPLATE = SDRTEMPLATE; + pGRRD->GRREFERENCE = SBSYMS[IDI]; + pGRRD->GRREFERENCEDX = RDXI; + pGRRD->GRREFERENCEDY = RDYI; + pGRRD->TPGRON = 0; + pGRRD->GRAT[0] = SDRAT[0]; + pGRRD->GRAT[1] = SDRAT[1]; + pGRRD->GRAT[2] = SDRAT[2]; + pGRRD->GRAT[3] = SDRAT[3]; + BS = pGRRD->decode(pArithDecoder, grContext->data()); + if (!BS) { + FX_Free(SBSYMS); + goto failed; + } + FX_Free(SBSYMS); + } + } + SDNEWSYMS[NSYMSDECODED] = BS; + BS = nullptr; + NSYMSDECODED = NSYMSDECODED + 1; + } + } + EXINDEX = 0; + CUREXFLAG = 0; + EXFLAGS = FX_Alloc(FX_BOOL, SDNUMINSYMS + SDNUMNEWSYMS); + while (EXINDEX < SDNUMINSYMS + SDNUMNEWSYMS) { + IAEX->decode(pArithDecoder, (int*)&EXRUNLENGTH); + if (EXINDEX + EXRUNLENGTH > SDNUMINSYMS + SDNUMNEWSYMS) { + FX_Free(EXFLAGS); + goto failed; + } + if (EXRUNLENGTH != 0) { + for (I = EXINDEX; I < EXINDEX + EXRUNLENGTH; I++) { + EXFLAGS[I] = CUREXFLAG; + } + } + EXINDEX = EXINDEX + EXRUNLENGTH; + CUREXFLAG = !CUREXFLAG; + } + pDict.reset(new CJBig2_SymbolDict); + I = J = 0; + for (I = 0; I < SDNUMINSYMS + SDNUMNEWSYMS; I++) { + if (EXFLAGS[I] && J < SDNUMEXSYMS) { + if (I < SDNUMINSYMS) { + pDict->AddImage(SDINSYMS[I] ? new CJBig2_Image(*SDINSYMS[I]) : nullptr); + } else { + pDict->AddImage(SDNEWSYMS[I - SDNUMINSYMS]); + } + ++J; + } else if (!EXFLAGS[I] && I >= SDNUMINSYMS) { + delete SDNEWSYMS[I - SDNUMINSYMS]; + } + } + FX_Free(EXFLAGS); + FX_Free(SDNEWSYMS); + return pDict.release(); +failed: + for (I = 0; I < NSYMSDECODED; I++) { + if (SDNEWSYMS[I]) { + delete SDNEWSYMS[I]; + SDNEWSYMS[I] = nullptr; + } + } + FX_Free(SDNEWSYMS); + return nullptr; +} + +CJBig2_SymbolDict* CJBig2_SDDProc::decode_Huffman( + CJBig2_BitStream* pStream, + std::vector<JBig2ArithCtx>* gbContext, + std::vector<JBig2ArithCtx>* grContext, + IFX_Pause* pPause) { + CJBig2_Image** SDNEWSYMS; + FX_DWORD* SDNEWSYMWIDTHS; + FX_DWORD HCHEIGHT, NSYMSDECODED; + int32_t HCDH; + FX_DWORD SYMWIDTH, TOTWIDTH, HCFIRSTSYM; + int32_t DW; + CJBig2_Image *BS, *BHC; + FX_DWORD I, J, REFAGGNINST; + FX_BOOL* EXFLAGS; + FX_DWORD EXINDEX; + FX_BOOL CUREXFLAG; + FX_DWORD EXRUNLENGTH; + int32_t nVal, nBits; + FX_DWORD nTmp; + FX_DWORD SBNUMSYMS; + uint8_t SBSYMCODELEN; + JBig2HuffmanCode* SBSYMCODES; + FX_DWORD IDI; + int32_t RDXI, RDYI; + FX_DWORD BMSIZE; + FX_DWORD stride; + CJBig2_Image** SBSYMS; + std::unique_ptr<CJBig2_HuffmanDecoder> pHuffmanDecoder( + new CJBig2_HuffmanDecoder(pStream)); + SDNEWSYMS = FX_Alloc(CJBig2_Image*, SDNUMNEWSYMS); + FXSYS_memset(SDNEWSYMS, 0, SDNUMNEWSYMS * sizeof(CJBig2_Image*)); + SDNEWSYMWIDTHS = nullptr; + BHC = nullptr; + if (SDREFAGG == 0) { + SDNEWSYMWIDTHS = FX_Alloc(FX_DWORD, SDNUMNEWSYMS); + FXSYS_memset(SDNEWSYMWIDTHS, 0, SDNUMNEWSYMS * sizeof(FX_DWORD)); + } + std::unique_ptr<CJBig2_SymbolDict> pDict(new CJBig2_SymbolDict()); + std::unique_ptr<CJBig2_HuffmanTable> pTable; + + HCHEIGHT = 0; + NSYMSDECODED = 0; + BS = nullptr; + while (NSYMSDECODED < SDNUMNEWSYMS) { + if (pHuffmanDecoder->decodeAValue(SDHUFFDH, &HCDH) != 0) { + goto failed; + } + HCHEIGHT = HCHEIGHT + HCDH; + if ((int)HCHEIGHT < 0 || (int)HCHEIGHT > JBIG2_MAX_IMAGE_SIZE) { + goto failed; + } + SYMWIDTH = 0; + TOTWIDTH = 0; + HCFIRSTSYM = NSYMSDECODED; + for (;;) { + nVal = pHuffmanDecoder->decodeAValue(SDHUFFDW, &DW); + if (nVal == JBIG2_OOB) { + break; + } else if (nVal != 0) { + goto failed; + } else { + if (NSYMSDECODED >= SDNUMNEWSYMS) { + goto failed; + } + SYMWIDTH = SYMWIDTH + DW; + if ((int)SYMWIDTH < 0 || (int)SYMWIDTH > JBIG2_MAX_IMAGE_SIZE) { + goto failed; + } else if (HCHEIGHT == 0 || SYMWIDTH == 0) { + TOTWIDTH = TOTWIDTH + SYMWIDTH; + SDNEWSYMS[NSYMSDECODED] = nullptr; + NSYMSDECODED = NSYMSDECODED + 1; + continue; + } + TOTWIDTH = TOTWIDTH + SYMWIDTH; + } + if (SDREFAGG == 1) { + if (pHuffmanDecoder->decodeAValue(SDHUFFAGGINST, (int*)&REFAGGNINST) != + 0) { + goto failed; + } + BS = nullptr; + if (REFAGGNINST > 1) { + std::unique_ptr<CJBig2_TRDProc> pDecoder(new CJBig2_TRDProc()); + pDecoder->SBHUFF = SDHUFF; + pDecoder->SBREFINE = 1; + pDecoder->SBW = SYMWIDTH; + pDecoder->SBH = HCHEIGHT; + pDecoder->SBNUMINSTANCES = REFAGGNINST; + pDecoder->SBSTRIPS = 1; + pDecoder->SBNUMSYMS = SDNUMINSYMS + NSYMSDECODED; + SBNUMSYMS = pDecoder->SBNUMSYMS; + SBSYMCODES = FX_Alloc(JBig2HuffmanCode, SBNUMSYMS); + nTmp = 1; + while ((FX_DWORD)(1 << nTmp) < SBNUMSYMS) { + nTmp++; + } + for (I = 0; I < SBNUMSYMS; I++) { + SBSYMCODES[I].codelen = nTmp; + SBSYMCODES[I].code = I; + } + pDecoder->SBSYMCODES = SBSYMCODES; + SBSYMS = FX_Alloc(CJBig2_Image*, SBNUMSYMS); + JBIG2_memcpy(SBSYMS, SDINSYMS, SDNUMINSYMS * sizeof(CJBig2_Image*)); + JBIG2_memcpy(SBSYMS + SDNUMINSYMS, SDNEWSYMS, + NSYMSDECODED * sizeof(CJBig2_Image*)); + pDecoder->SBSYMS = SBSYMS; + pDecoder->SBDEFPIXEL = 0; + pDecoder->SBCOMBOP = JBIG2_COMPOSE_OR; + pDecoder->TRANSPOSED = 0; + pDecoder->REFCORNER = JBIG2_CORNER_TOPLEFT; + pDecoder->SBDSOFFSET = 0; + std::unique_ptr<CJBig2_HuffmanTable> SBHUFFFS(new CJBig2_HuffmanTable( + HuffmanTable_B6, FX_ArraySize(HuffmanTable_B6), + HuffmanTable_HTOOB_B6)); + std::unique_ptr<CJBig2_HuffmanTable> SBHUFFDS(new CJBig2_HuffmanTable( + HuffmanTable_B8, FX_ArraySize(HuffmanTable_B8), + HuffmanTable_HTOOB_B8)); + std::unique_ptr<CJBig2_HuffmanTable> SBHUFFDT(new CJBig2_HuffmanTable( + HuffmanTable_B11, FX_ArraySize(HuffmanTable_B11), + HuffmanTable_HTOOB_B11)); + std::unique_ptr<CJBig2_HuffmanTable> SBHUFFRDW( + new CJBig2_HuffmanTable(HuffmanTable_B15, + FX_ArraySize(HuffmanTable_B15), + HuffmanTable_HTOOB_B15)); + std::unique_ptr<CJBig2_HuffmanTable> SBHUFFRDH( + new CJBig2_HuffmanTable(HuffmanTable_B15, + FX_ArraySize(HuffmanTable_B15), + HuffmanTable_HTOOB_B15)); + std::unique_ptr<CJBig2_HuffmanTable> SBHUFFRDX( + new CJBig2_HuffmanTable(HuffmanTable_B15, + FX_ArraySize(HuffmanTable_B15), + HuffmanTable_HTOOB_B15)); + std::unique_ptr<CJBig2_HuffmanTable> SBHUFFRDY( + new CJBig2_HuffmanTable(HuffmanTable_B15, + FX_ArraySize(HuffmanTable_B15), + HuffmanTable_HTOOB_B15)); + std::unique_ptr<CJBig2_HuffmanTable> SBHUFFRSIZE( + new CJBig2_HuffmanTable(HuffmanTable_B1, + FX_ArraySize(HuffmanTable_B1), + HuffmanTable_HTOOB_B1)); + pDecoder->SBHUFFFS = SBHUFFFS.get(); + pDecoder->SBHUFFDS = SBHUFFDS.get(); + pDecoder->SBHUFFDT = SBHUFFDT.get(); + pDecoder->SBHUFFRDW = SBHUFFRDW.get(); + pDecoder->SBHUFFRDH = SBHUFFRDH.get(); + pDecoder->SBHUFFRDX = SBHUFFRDX.get(); + pDecoder->SBHUFFRDY = SBHUFFRDY.get(); + pDecoder->SBHUFFRSIZE = SBHUFFRSIZE.get(); + pDecoder->SBRTEMPLATE = SDRTEMPLATE; + pDecoder->SBRAT[0] = SDRAT[0]; + pDecoder->SBRAT[1] = SDRAT[1]; + pDecoder->SBRAT[2] = SDRAT[2]; + pDecoder->SBRAT[3] = SDRAT[3]; + BS = pDecoder->decode_Huffman(pStream, grContext->data()); + if (!BS) { + FX_Free(SBSYMCODES); + FX_Free(SBSYMS); + goto failed; + } + FX_Free(SBSYMCODES); + FX_Free(SBSYMS); + } else if (REFAGGNINST == 1) { + SBNUMSYMS = SDNUMINSYMS + SDNUMNEWSYMS; + nTmp = 1; + while ((FX_DWORD)(1 << nTmp) < SBNUMSYMS) { + nTmp++; + } + SBSYMCODELEN = (uint8_t)nTmp; + SBSYMCODES = FX_Alloc(JBig2HuffmanCode, SBNUMSYMS); + for (I = 0; I < SBNUMSYMS; I++) { + SBSYMCODES[I].codelen = SBSYMCODELEN; + SBSYMCODES[I].code = I; + } + nVal = 0; + nBits = 0; + for (;;) { + if (pStream->read1Bit(&nTmp) != 0) { + FX_Free(SBSYMCODES); + goto failed; + } + nVal = (nVal << 1) | nTmp; + for (IDI = 0; IDI < SBNUMSYMS; IDI++) { + if ((nVal == SBSYMCODES[IDI].code) && + (nBits == SBSYMCODES[IDI].codelen)) { + break; + } + } + if (IDI < SBNUMSYMS) { + break; + } + } + FX_Free(SBSYMCODES); + std::unique_ptr<CJBig2_HuffmanTable> SBHUFFRDX( + new CJBig2_HuffmanTable(HuffmanTable_B15, + FX_ArraySize(HuffmanTable_B15), + HuffmanTable_HTOOB_B15)); + std::unique_ptr<CJBig2_HuffmanTable> SBHUFFRSIZE( + new CJBig2_HuffmanTable(HuffmanTable_B1, + FX_ArraySize(HuffmanTable_B1), + HuffmanTable_HTOOB_B1)); + if ((pHuffmanDecoder->decodeAValue(SBHUFFRDX.get(), &RDXI) != 0) || + (pHuffmanDecoder->decodeAValue(SBHUFFRDX.get(), &RDYI) != 0) || + (pHuffmanDecoder->decodeAValue(SBHUFFRSIZE.get(), &nVal) != 0)) { + goto failed; + } + pStream->alignByte(); + nTmp = pStream->getOffset(); + SBSYMS = FX_Alloc(CJBig2_Image*, SBNUMSYMS); + JBIG2_memcpy(SBSYMS, SDINSYMS, SDNUMINSYMS * sizeof(CJBig2_Image*)); + JBIG2_memcpy(SBSYMS + SDNUMINSYMS, SDNEWSYMS, + NSYMSDECODED * sizeof(CJBig2_Image*)); + std::unique_ptr<CJBig2_GRRDProc> pGRRD(new CJBig2_GRRDProc()); + pGRRD->GRW = SYMWIDTH; + pGRRD->GRH = HCHEIGHT; + pGRRD->GRTEMPLATE = SDRTEMPLATE; + pGRRD->GRREFERENCE = SBSYMS[IDI]; + pGRRD->GRREFERENCEDX = RDXI; + pGRRD->GRREFERENCEDY = RDYI; + pGRRD->TPGRON = 0; + pGRRD->GRAT[0] = SDRAT[0]; + pGRRD->GRAT[1] = SDRAT[1]; + pGRRD->GRAT[2] = SDRAT[2]; + pGRRD->GRAT[3] = SDRAT[3]; + std::unique_ptr<CJBig2_ArithDecoder> pArithDecoder( + new CJBig2_ArithDecoder(pStream)); + BS = pGRRD->decode(pArithDecoder.get(), grContext->data()); + if (!BS) { + FX_Free(SBSYMS); + goto failed; + } + pStream->alignByte(); + pStream->offset(2); + if ((FX_DWORD)nVal != (pStream->getOffset() - nTmp)) { + delete BS; + FX_Free(SBSYMS); + goto failed; + } + FX_Free(SBSYMS); + } + SDNEWSYMS[NSYMSDECODED] = BS; + } + if (SDREFAGG == 0) { + SDNEWSYMWIDTHS[NSYMSDECODED] = SYMWIDTH; + } + NSYMSDECODED = NSYMSDECODED + 1; + } + if (SDREFAGG == 0) { + if (pHuffmanDecoder->decodeAValue(SDHUFFBMSIZE, (int32_t*)&BMSIZE) != 0) { + goto failed; + } + pStream->alignByte(); + if (BMSIZE == 0) { + stride = (TOTWIDTH + 7) >> 3; + if (pStream->getByteLeft() >= stride * HCHEIGHT) { + BHC = new CJBig2_Image(TOTWIDTH, HCHEIGHT); + for (I = 0; I < HCHEIGHT; I++) { + JBIG2_memcpy(BHC->m_pData + I * BHC->m_nStride, + pStream->getPointer(), stride); + pStream->offset(stride); + } + } else { + goto failed; + } + } else { + std::unique_ptr<CJBig2_GRDProc> pGRD(new CJBig2_GRDProc()); + pGRD->MMR = 1; + pGRD->GBW = TOTWIDTH; + pGRD->GBH = HCHEIGHT; + FXCODEC_STATUS status = pGRD->Start_decode_MMR(&BHC, pStream, nullptr); + while (status == FXCODEC_STATUS_DECODE_TOBECONTINUE) { + pGRD->Continue_decode(pPause); + } + pStream->alignByte(); + } + nTmp = 0; + if (!BHC) { + continue; + } + for (I = HCFIRSTSYM; I < NSYMSDECODED; I++) { + SDNEWSYMS[I] = BHC->subImage(nTmp, 0, SDNEWSYMWIDTHS[I], HCHEIGHT); + nTmp += SDNEWSYMWIDTHS[I]; + } + delete BHC; + BHC = nullptr; + } + } + EXINDEX = 0; + CUREXFLAG = 0; + pTable.reset(new CJBig2_HuffmanTable( + HuffmanTable_B1, FX_ArraySize(HuffmanTable_B1), HuffmanTable_HTOOB_B1)); + EXFLAGS = FX_Alloc(FX_BOOL, SDNUMINSYMS + SDNUMNEWSYMS); + while (EXINDEX < SDNUMINSYMS + SDNUMNEWSYMS) { + if (pHuffmanDecoder->decodeAValue(pTable.get(), (int*)&EXRUNLENGTH) != 0) { + FX_Free(EXFLAGS); + goto failed; + } + if (EXINDEX + EXRUNLENGTH > SDNUMINSYMS + SDNUMNEWSYMS) { + FX_Free(EXFLAGS); + goto failed; + } + if (EXRUNLENGTH != 0) { + for (I = EXINDEX; I < EXINDEX + EXRUNLENGTH; I++) { + EXFLAGS[I] = CUREXFLAG; + } + } + EXINDEX = EXINDEX + EXRUNLENGTH; + CUREXFLAG = !CUREXFLAG; + } + I = J = 0; + for (I = 0; I < SDNUMINSYMS + SDNUMNEWSYMS; I++) { + if (EXFLAGS[I] && J < SDNUMEXSYMS) { + if (I < SDNUMINSYMS) { + pDict->AddImage(SDINSYMS[I] ? new CJBig2_Image(*SDINSYMS[I]) : nullptr); + } else { + pDict->AddImage(SDNEWSYMS[I - SDNUMINSYMS]); + } + ++J; + } else if (!EXFLAGS[I] && I >= SDNUMINSYMS) { + delete SDNEWSYMS[I - SDNUMINSYMS]; + } + } + FX_Free(EXFLAGS); + FX_Free(SDNEWSYMS); + if (SDREFAGG == 0) { + FX_Free(SDNEWSYMWIDTHS); + } + return pDict.release(); +failed: + for (I = 0; I < NSYMSDECODED; I++) { + delete SDNEWSYMS[I]; + } + FX_Free(SDNEWSYMS); + if (SDREFAGG == 0) { + FX_Free(SDNEWSYMWIDTHS); + } + return nullptr; +} diff --git a/core/fxcodec/jbig2/JBig2_SddProc.h b/core/fxcodec/jbig2/JBig2_SddProc.h new file mode 100644 index 0000000000..fa1211b4b4 --- /dev/null +++ b/core/fxcodec/jbig2/JBig2_SddProc.h @@ -0,0 +1,49 @@ +// Copyright 2015 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#ifndef CORE_FXCODEC_JBIG2_JBIG2_SDDPROC_H_ +#define CORE_FXCODEC_JBIG2_JBIG2_SDDPROC_H_ + +#include <vector> + +#include "core/fxcodec/jbig2/JBig2_ArithDecoder.h" +#include "core/include/fxcrt/fx_system.h" + +class CJBig2_BitStream; +class CJBig2_HuffmanTable; +class CJBig2_Image; +class CJBig2_SymbolDict; +class IFX_Pause; + +class CJBig2_SDDProc { + public: + CJBig2_SymbolDict* decode_Arith(CJBig2_ArithDecoder* pArithDecoder, + std::vector<JBig2ArithCtx>* gbContext, + std::vector<JBig2ArithCtx>* grContext); + + CJBig2_SymbolDict* decode_Huffman(CJBig2_BitStream* pStream, + std::vector<JBig2ArithCtx>* gbContext, + std::vector<JBig2ArithCtx>* grContext, + IFX_Pause* pPause); + + public: + FX_BOOL SDHUFF; + FX_BOOL SDREFAGG; + FX_DWORD SDNUMINSYMS; + CJBig2_Image** SDINSYMS; + FX_DWORD SDNUMNEWSYMS; + FX_DWORD SDNUMEXSYMS; + CJBig2_HuffmanTable* SDHUFFDH; + CJBig2_HuffmanTable* SDHUFFDW; + CJBig2_HuffmanTable* SDHUFFBMSIZE; + CJBig2_HuffmanTable* SDHUFFAGGINST; + uint8_t SDTEMPLATE; + int8_t SDAT[8]; + FX_BOOL SDRTEMPLATE; + int8_t SDRAT[4]; +}; + +#endif // CORE_FXCODEC_JBIG2_JBIG2_SDDPROC_H_ diff --git a/core/fxcodec/jbig2/JBig2_Segment.cpp b/core/fxcodec/jbig2/JBig2_Segment.cpp new file mode 100644 index 0000000000..a6bac36141 --- /dev/null +++ b/core/fxcodec/jbig2/JBig2_Segment.cpp @@ -0,0 +1,44 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "core/fxcodec/jbig2/JBig2_Segment.h" + +#include "core/include/fxcrt/fx_memory.h" + +CJBig2_Segment::CJBig2_Segment() { + m_dwNumber = 0; + m_cFlags.c = 0; + m_nReferred_to_segment_count = 0; + m_pReferred_to_segment_numbers = NULL; + m_dwPage_association = 0; + m_dwData_length = 0; + m_dwHeader_Length = 0; + m_dwObjNum = 0; + m_dwDataOffset = 0; + m_State = JBIG2_SEGMENT_HEADER_UNPARSED; + m_nResultType = JBIG2_VOID_POINTER; + m_Result.vd = NULL; +} +CJBig2_Segment::~CJBig2_Segment() { + FX_Free(m_pReferred_to_segment_numbers); + + switch (m_nResultType) { + case JBIG2_IMAGE_POINTER: + delete m_Result.im; + break; + case JBIG2_SYMBOL_DICT_POINTER: + delete m_Result.sd; + break; + case JBIG2_PATTERN_DICT_POINTER: + delete m_Result.pd; + break; + case JBIG2_HUFFMAN_TABLE_POINTER: + delete m_Result.ht; + break; + default: + FX_Free(m_Result.vd); + } +} diff --git a/core/fxcodec/jbig2/JBig2_Segment.h b/core/fxcodec/jbig2/JBig2_Segment.h new file mode 100644 index 0000000000..61550ada09 --- /dev/null +++ b/core/fxcodec/jbig2/JBig2_Segment.h @@ -0,0 +1,66 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#ifndef CORE_FXCODEC_JBIG2_JBIG2_SEGMENT_H_ +#define CORE_FXCODEC_JBIG2_JBIG2_SEGMENT_H_ + +#include "core/fxcodec/jbig2/JBig2_Define.h" +#include "core/fxcodec/jbig2/JBig2_HuffmanTable.h" +#include "core/fxcodec/jbig2/JBig2_PatternDict.h" +#include "core/fxcodec/jbig2/JBig2_SymbolDict.h" + +#define JBIG2_GET_INT32(buf) \ + (((buf)[0] << 24) | ((buf)[1] << 16) | ((buf)[2] << 8) | (buf)[3]) +#define JBIG2_GET_INT16(buf) (((buf)[0] << 8) | (buf)[1]) +typedef enum { + JBIG2_SEGMENT_HEADER_UNPARSED, + JBIG2_SEGMENT_DATA_UNPARSED, + JBIG2_SEGMENT_PARSE_COMPLETE, + JBIG2_SEGMENT_PAUSED, + JBIG2_SEGMENT_ERROR +} JBig2_SegmentState; +typedef enum { + JBIG2_VOID_POINTER = 0, + JBIG2_IMAGE_POINTER, + JBIG2_SYMBOL_DICT_POINTER, + JBIG2_PATTERN_DICT_POINTER, + JBIG2_HUFFMAN_TABLE_POINTER +} JBig2_ResultType; +class CJBig2_Segment { + public: + CJBig2_Segment(); + + ~CJBig2_Segment(); + + FX_DWORD m_dwNumber; + union { + struct { + uint8_t type : 6; + uint8_t page_association_size : 1; + uint8_t deferred_non_retain : 1; + } s; + uint8_t c; + } m_cFlags; + int32_t m_nReferred_to_segment_count; + FX_DWORD* m_pReferred_to_segment_numbers; + FX_DWORD m_dwPage_association; + FX_DWORD m_dwData_length; + + FX_DWORD m_dwHeader_Length; + FX_DWORD m_dwObjNum; + FX_DWORD m_dwDataOffset; + JBig2_SegmentState m_State; + JBig2_ResultType m_nResultType; + union { + CJBig2_SymbolDict* sd; + CJBig2_PatternDict* pd; + CJBig2_Image* im; + CJBig2_HuffmanTable* ht; + void* vd; + } m_Result; +}; + +#endif // CORE_FXCODEC_JBIG2_JBIG2_SEGMENT_H_ diff --git a/core/fxcodec/jbig2/JBig2_SymbolDict.cpp b/core/fxcodec/jbig2/JBig2_SymbolDict.cpp new file mode 100644 index 0000000000..9fe3d54a0c --- /dev/null +++ b/core/fxcodec/jbig2/JBig2_SymbolDict.cpp @@ -0,0 +1,26 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "core/fxcodec/jbig2/JBig2_SymbolDict.h" + +#include "core/fxcodec/jbig2/JBig2_Image.h" +#include "core/include/fxcrt/fx_memory.h" + +CJBig2_SymbolDict::CJBig2_SymbolDict() {} + +CJBig2_SymbolDict::~CJBig2_SymbolDict() {} + +std::unique_ptr<CJBig2_SymbolDict> CJBig2_SymbolDict::DeepCopy() const { + const CJBig2_SymbolDict* src = this; + std::unique_ptr<CJBig2_SymbolDict> dst(new CJBig2_SymbolDict); + for (size_t i = 0; i < src->m_SDEXSYMS.size(); ++i) { + CJBig2_Image* image = src->m_SDEXSYMS.get(i); + dst->m_SDEXSYMS.push_back(image ? new CJBig2_Image(*image) : nullptr); + } + dst->m_gbContext = src->m_gbContext; + dst->m_grContext = src->m_grContext; + return dst; +} diff --git a/core/fxcodec/jbig2/JBig2_SymbolDict.h b/core/fxcodec/jbig2/JBig2_SymbolDict.h new file mode 100644 index 0000000000..64ab881596 --- /dev/null +++ b/core/fxcodec/jbig2/JBig2_SymbolDict.h @@ -0,0 +1,48 @@ +// Copyright 2014 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#ifndef CORE_FXCODEC_JBIG2_JBIG2_SYMBOLDICT_H_ +#define CORE_FXCODEC_JBIG2_JBIG2_SYMBOLDICT_H_ + +#include <memory> +#include <vector> + +#include "core/fxcodec/jbig2/JBig2_ArithDecoder.h" +#include "core/fxcodec/jbig2/JBig2_List.h" +#include "core/include/fxcrt/fx_basic.h" + +class CJBig2_Image; + +class CJBig2_SymbolDict { + public: + CJBig2_SymbolDict(); + ~CJBig2_SymbolDict(); + + std::unique_ptr<CJBig2_SymbolDict> DeepCopy() const; + + // Takes ownership of |image|. + void AddImage(CJBig2_Image* image) { m_SDEXSYMS.push_back(image); } + + size_t NumImages() const { return m_SDEXSYMS.size(); } + CJBig2_Image* GetImage(size_t index) const { return m_SDEXSYMS.get(index); } + + const std::vector<JBig2ArithCtx>& GbContext() const { return m_gbContext; } + const std::vector<JBig2ArithCtx>& GrContext() const { return m_grContext; } + + void SetGbContext(const std::vector<JBig2ArithCtx>& gbContext) { + m_gbContext = gbContext; + } + void SetGrContext(const std::vector<JBig2ArithCtx>& grContext) { + m_grContext = grContext; + } + + private: + std::vector<JBig2ArithCtx> m_gbContext; + std::vector<JBig2ArithCtx> m_grContext; + CJBig2_List<CJBig2_Image> m_SDEXSYMS; +}; + +#endif // CORE_FXCODEC_JBIG2_JBIG2_SYMBOLDICT_H_ diff --git a/core/fxcodec/jbig2/JBig2_TrdProc.cpp b/core/fxcodec/jbig2/JBig2_TrdProc.cpp new file mode 100644 index 0000000000..401249e3f2 --- /dev/null +++ b/core/fxcodec/jbig2/JBig2_TrdProc.cpp @@ -0,0 +1,407 @@ +// Copyright 2015 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "core/fxcodec/jbig2/JBig2_TrdProc.h" + +#include <memory> + +#include "core/fxcodec/jbig2/JBig2_ArithDecoder.h" +#include "core/fxcodec/jbig2/JBig2_ArithIntDecoder.h" +#include "core/fxcodec/jbig2/JBig2_GrrdProc.h" +#include "core/fxcodec/jbig2/JBig2_HuffmanDecoder.h" + +CJBig2_Image* CJBig2_TRDProc::decode_Huffman(CJBig2_BitStream* pStream, + JBig2ArithCtx* grContext) { + int32_t STRIPT, FIRSTS; + FX_DWORD NINSTANCES; + int32_t DT, DFS, CURS; + int32_t SI, TI; + CJBig2_Image* IBI; + FX_DWORD WI, HI; + int32_t IDS; + FX_BOOL RI; + int32_t RDWI, RDHI, RDXI, RDYI; + CJBig2_Image* IBOI; + FX_DWORD WOI, HOI; + FX_BOOL bFirst; + FX_DWORD nTmp; + int32_t nVal, nBits; + std::unique_ptr<CJBig2_HuffmanDecoder> pHuffmanDecoder( + new CJBig2_HuffmanDecoder(pStream)); + std::unique_ptr<CJBig2_Image> SBREG(new CJBig2_Image(SBW, SBH)); + SBREG->fill(SBDEFPIXEL); + if (pHuffmanDecoder->decodeAValue(SBHUFFDT, &STRIPT) != 0) + return nullptr; + + STRIPT *= SBSTRIPS; + STRIPT = -STRIPT; + FIRSTS = 0; + NINSTANCES = 0; + while (NINSTANCES < SBNUMINSTANCES) { + if (pHuffmanDecoder->decodeAValue(SBHUFFDT, &DT) != 0) + return nullptr; + + DT *= SBSTRIPS; + STRIPT = STRIPT + DT; + bFirst = TRUE; + for (;;) { + if (bFirst) { + if (pHuffmanDecoder->decodeAValue(SBHUFFFS, &DFS) != 0) + return nullptr; + + FIRSTS = FIRSTS + DFS; + CURS = FIRSTS; + bFirst = FALSE; + } else { + nVal = pHuffmanDecoder->decodeAValue(SBHUFFDS, &IDS); + if (nVal == JBIG2_OOB) { + break; + } else if (nVal != 0) { + return nullptr; + } else { + CURS = CURS + IDS + SBDSOFFSET; + } + } + uint8_t CURT = 0; + if (SBSTRIPS != 1) { + nTmp = 1; + while ((FX_DWORD)(1 << nTmp) < SBSTRIPS) { + nTmp++; + } + if (pStream->readNBits(nTmp, &nVal) != 0) + return nullptr; + + CURT = nVal; + } + TI = STRIPT + CURT; + nVal = 0; + nBits = 0; + FX_DWORD IDI; + for (;;) { + if (pStream->read1Bit(&nTmp) != 0) + return nullptr; + + nVal = (nVal << 1) | nTmp; + nBits++; + for (IDI = 0; IDI < SBNUMSYMS; IDI++) { + if ((nBits == SBSYMCODES[IDI].codelen) && + (nVal == SBSYMCODES[IDI].code)) { + break; + } + } + if (IDI < SBNUMSYMS) { + break; + } + } + if (SBREFINE == 0) { + RI = 0; + } else { + if (pStream->read1Bit(&RI) != 0) { + return nullptr; + } + } + if (RI == 0) { + IBI = SBSYMS[IDI]; + } else { + if ((pHuffmanDecoder->decodeAValue(SBHUFFRDW, &RDWI) != 0) || + (pHuffmanDecoder->decodeAValue(SBHUFFRDH, &RDHI) != 0) || + (pHuffmanDecoder->decodeAValue(SBHUFFRDX, &RDXI) != 0) || + (pHuffmanDecoder->decodeAValue(SBHUFFRDY, &RDYI) != 0) || + (pHuffmanDecoder->decodeAValue(SBHUFFRSIZE, &nVal) != 0)) { + return nullptr; + } + pStream->alignByte(); + nTmp = pStream->getOffset(); + IBOI = SBSYMS[IDI]; + if (!IBOI) + return nullptr; + + WOI = IBOI->m_nWidth; + HOI = IBOI->m_nHeight; + if ((int)(WOI + RDWI) < 0 || (int)(HOI + RDHI) < 0) + return nullptr; + + std::unique_ptr<CJBig2_GRRDProc> pGRRD(new CJBig2_GRRDProc()); + pGRRD->GRW = WOI + RDWI; + pGRRD->GRH = HOI + RDHI; + pGRRD->GRTEMPLATE = SBRTEMPLATE; + pGRRD->GRREFERENCE = IBOI; + pGRRD->GRREFERENCEDX = (RDWI >> 2) + RDXI; + pGRRD->GRREFERENCEDY = (RDHI >> 2) + RDYI; + pGRRD->TPGRON = 0; + pGRRD->GRAT[0] = SBRAT[0]; + pGRRD->GRAT[1] = SBRAT[1]; + pGRRD->GRAT[2] = SBRAT[2]; + pGRRD->GRAT[3] = SBRAT[3]; + + { + std::unique_ptr<CJBig2_ArithDecoder> pArithDecoder( + new CJBig2_ArithDecoder(pStream)); + IBI = pGRRD->decode(pArithDecoder.get(), grContext); + if (!IBI) + return nullptr; + } + + pStream->alignByte(); + pStream->offset(2); + if ((FX_DWORD)nVal != (pStream->getOffset() - nTmp)) { + delete IBI; + return nullptr; + } + } + if (!IBI) { + continue; + } + WI = IBI->m_nWidth; + HI = IBI->m_nHeight; + if (TRANSPOSED == 0 && ((REFCORNER == JBIG2_CORNER_TOPRIGHT) || + (REFCORNER == JBIG2_CORNER_BOTTOMRIGHT))) { + CURS = CURS + WI - 1; + } else if (TRANSPOSED == 1 && ((REFCORNER == JBIG2_CORNER_BOTTOMLEFT) || + (REFCORNER == JBIG2_CORNER_BOTTOMRIGHT))) { + CURS = CURS + HI - 1; + } + SI = CURS; + if (TRANSPOSED == 0) { + switch (REFCORNER) { + case JBIG2_CORNER_TOPLEFT: + SBREG->composeFrom(SI, TI, IBI, SBCOMBOP); + break; + case JBIG2_CORNER_TOPRIGHT: + SBREG->composeFrom(SI - WI + 1, TI, IBI, SBCOMBOP); + break; + case JBIG2_CORNER_BOTTOMLEFT: + SBREG->composeFrom(SI, TI - HI + 1, IBI, SBCOMBOP); + break; + case JBIG2_CORNER_BOTTOMRIGHT: + SBREG->composeFrom(SI - WI + 1, TI - HI + 1, IBI, SBCOMBOP); + break; + } + } else { + switch (REFCORNER) { + case JBIG2_CORNER_TOPLEFT: + SBREG->composeFrom(TI, SI, IBI, SBCOMBOP); + break; + case JBIG2_CORNER_TOPRIGHT: + SBREG->composeFrom(TI - WI + 1, SI, IBI, SBCOMBOP); + break; + case JBIG2_CORNER_BOTTOMLEFT: + SBREG->composeFrom(TI, SI - HI + 1, IBI, SBCOMBOP); + break; + case JBIG2_CORNER_BOTTOMRIGHT: + SBREG->composeFrom(TI - WI + 1, SI - HI + 1, IBI, SBCOMBOP); + break; + } + } + if (RI != 0) { + delete IBI; + } + if (TRANSPOSED == 0 && ((REFCORNER == JBIG2_CORNER_TOPLEFT) || + (REFCORNER == JBIG2_CORNER_BOTTOMLEFT))) { + CURS = CURS + WI - 1; + } else if (TRANSPOSED == 1 && ((REFCORNER == JBIG2_CORNER_TOPLEFT) || + (REFCORNER == JBIG2_CORNER_TOPRIGHT))) { + CURS = CURS + HI - 1; + } + NINSTANCES = NINSTANCES + 1; + } + } + return SBREG.release(); +} + +CJBig2_Image* CJBig2_TRDProc::decode_Arith(CJBig2_ArithDecoder* pArithDecoder, + JBig2ArithCtx* grContext, + JBig2IntDecoderState* pIDS) { + std::unique_ptr<CJBig2_ArithIntDecoder> IADT; + std::unique_ptr<CJBig2_ArithIntDecoder> IAFS; + std::unique_ptr<CJBig2_ArithIntDecoder> IADS; + std::unique_ptr<CJBig2_ArithIntDecoder> IAIT; + std::unique_ptr<CJBig2_ArithIntDecoder> IARI; + std::unique_ptr<CJBig2_ArithIntDecoder> IARDW; + std::unique_ptr<CJBig2_ArithIntDecoder> IARDH; + std::unique_ptr<CJBig2_ArithIntDecoder> IARDX; + std::unique_ptr<CJBig2_ArithIntDecoder> IARDY; + std::unique_ptr<CJBig2_ArithIaidDecoder> IAID; + CJBig2_ArithIntDecoder* pIADT; + CJBig2_ArithIntDecoder* pIAFS; + CJBig2_ArithIntDecoder* pIADS; + CJBig2_ArithIntDecoder* pIAIT; + CJBig2_ArithIntDecoder* pIARI; + CJBig2_ArithIntDecoder* pIARDW; + CJBig2_ArithIntDecoder* pIARDH; + CJBig2_ArithIntDecoder* pIARDX; + CJBig2_ArithIntDecoder* pIARDY; + CJBig2_ArithIaidDecoder* pIAID; + if (pIDS) { + pIADT = pIDS->IADT; + pIAFS = pIDS->IAFS; + pIADS = pIDS->IADS; + pIAIT = pIDS->IAIT; + pIARI = pIDS->IARI; + pIARDW = pIDS->IARDW; + pIARDH = pIDS->IARDH; + pIARDX = pIDS->IARDX; + pIARDY = pIDS->IARDY; + pIAID = pIDS->IAID; + } else { + IADT.reset(new CJBig2_ArithIntDecoder()); + IAFS.reset(new CJBig2_ArithIntDecoder()); + IADS.reset(new CJBig2_ArithIntDecoder()); + IAIT.reset(new CJBig2_ArithIntDecoder()); + IARI.reset(new CJBig2_ArithIntDecoder()); + IARDW.reset(new CJBig2_ArithIntDecoder()); + IARDH.reset(new CJBig2_ArithIntDecoder()); + IARDX.reset(new CJBig2_ArithIntDecoder()); + IARDY.reset(new CJBig2_ArithIntDecoder()); + IAID.reset(new CJBig2_ArithIaidDecoder(SBSYMCODELEN)); + pIADT = IADT.get(); + pIAFS = IAFS.get(); + pIADS = IADS.get(); + pIAIT = IAIT.get(); + pIARI = IARI.get(); + pIARDW = IARDW.get(); + pIARDH = IARDH.get(); + pIARDX = IARDX.get(); + pIARDY = IARDY.get(); + pIAID = IAID.get(); + } + std::unique_ptr<CJBig2_Image> SBREG(new CJBig2_Image(SBW, SBH)); + SBREG->fill(SBDEFPIXEL); + int32_t STRIPT; + pIADT->decode(pArithDecoder, &STRIPT); + STRIPT *= SBSTRIPS; + STRIPT = -STRIPT; + int32_t FIRSTS = 0; + FX_DWORD NINSTANCES = 0; + while (NINSTANCES < SBNUMINSTANCES) { + int32_t CURS; + int32_t DT; + pIADT->decode(pArithDecoder, &DT); + DT *= SBSTRIPS; + STRIPT += DT; + bool bFirst = true; + for (;;) { + if (bFirst) { + int32_t DFS; + pIAFS->decode(pArithDecoder, &DFS); + FIRSTS += DFS; + CURS = FIRSTS; + bFirst = false; + } else { + int32_t IDS; + if (!pIADS->decode(pArithDecoder, &IDS)) + break; + CURS += IDS + SBDSOFFSET; + } + if (NINSTANCES >= SBNUMINSTANCES) { + break; + } + int CURT = 0; + if (SBSTRIPS != 1) + pIAIT->decode(pArithDecoder, &CURT); + + int32_t TI = STRIPT + CURT; + FX_DWORD IDI; + pIAID->decode(pArithDecoder, &IDI); + if (IDI >= SBNUMSYMS) + return nullptr; + + int RI; + if (SBREFINE == 0) + RI = 0; + else + pIARI->decode(pArithDecoder, &RI); + + std::unique_ptr<CJBig2_Image> IBI; + CJBig2_Image* pIBI; + if (RI == 0) { + pIBI = SBSYMS[IDI]; + } else { + int32_t RDWI; + int32_t RDHI; + int32_t RDXI; + int32_t RDYI; + pIARDW->decode(pArithDecoder, &RDWI); + pIARDH->decode(pArithDecoder, &RDHI); + pIARDX->decode(pArithDecoder, &RDXI); + pIARDY->decode(pArithDecoder, &RDYI); + CJBig2_Image* IBOI = SBSYMS[IDI]; + FX_DWORD WOI = IBOI->m_nWidth; + FX_DWORD HOI = IBOI->m_nHeight; + if ((int)(WOI + RDWI) < 0 || (int)(HOI + RDHI) < 0) { + return nullptr; + } + std::unique_ptr<CJBig2_GRRDProc> pGRRD(new CJBig2_GRRDProc()); + pGRRD->GRW = WOI + RDWI; + pGRRD->GRH = HOI + RDHI; + pGRRD->GRTEMPLATE = SBRTEMPLATE; + pGRRD->GRREFERENCE = IBOI; + pGRRD->GRREFERENCEDX = (RDWI >> 1) + RDXI; + pGRRD->GRREFERENCEDY = (RDHI >> 1) + RDYI; + pGRRD->TPGRON = 0; + pGRRD->GRAT[0] = SBRAT[0]; + pGRRD->GRAT[1] = SBRAT[1]; + pGRRD->GRAT[2] = SBRAT[2]; + pGRRD->GRAT[3] = SBRAT[3]; + IBI.reset(pGRRD->decode(pArithDecoder, grContext)); + pIBI = IBI.get(); + } + if (!pIBI) + return nullptr; + + FX_DWORD WI = pIBI->m_nWidth; + FX_DWORD HI = pIBI->m_nHeight; + if (TRANSPOSED == 0 && ((REFCORNER == JBIG2_CORNER_TOPRIGHT) || + (REFCORNER == JBIG2_CORNER_BOTTOMRIGHT))) { + CURS += WI - 1; + } else if (TRANSPOSED == 1 && ((REFCORNER == JBIG2_CORNER_BOTTOMLEFT) || + (REFCORNER == JBIG2_CORNER_BOTTOMRIGHT))) { + CURS += HI - 1; + } + int32_t SI = CURS; + if (TRANSPOSED == 0) { + switch (REFCORNER) { + case JBIG2_CORNER_TOPLEFT: + SBREG->composeFrom(SI, TI, pIBI, SBCOMBOP); + break; + case JBIG2_CORNER_TOPRIGHT: + SBREG->composeFrom(SI - WI + 1, TI, pIBI, SBCOMBOP); + break; + case JBIG2_CORNER_BOTTOMLEFT: + SBREG->composeFrom(SI, TI - HI + 1, pIBI, SBCOMBOP); + break; + case JBIG2_CORNER_BOTTOMRIGHT: + SBREG->composeFrom(SI - WI + 1, TI - HI + 1, pIBI, SBCOMBOP); + break; + } + } else { + switch (REFCORNER) { + case JBIG2_CORNER_TOPLEFT: + SBREG->composeFrom(TI, SI, pIBI, SBCOMBOP); + break; + case JBIG2_CORNER_TOPRIGHT: + SBREG->composeFrom(TI - WI + 1, SI, pIBI, SBCOMBOP); + break; + case JBIG2_CORNER_BOTTOMLEFT: + SBREG->composeFrom(TI, SI - HI + 1, pIBI, SBCOMBOP); + break; + case JBIG2_CORNER_BOTTOMRIGHT: + SBREG->composeFrom(TI - WI + 1, SI - HI + 1, pIBI, SBCOMBOP); + break; + } + } + if (TRANSPOSED == 0 && ((REFCORNER == JBIG2_CORNER_TOPLEFT) || + (REFCORNER == JBIG2_CORNER_BOTTOMLEFT))) { + CURS += WI - 1; + } else if (TRANSPOSED == 1 && ((REFCORNER == JBIG2_CORNER_TOPLEFT) || + (REFCORNER == JBIG2_CORNER_TOPRIGHT))) { + CURS += HI - 1; + } + ++NINSTANCES; + } + } + return SBREG.release(); +} diff --git a/core/fxcodec/jbig2/JBig2_TrdProc.h b/core/fxcodec/jbig2/JBig2_TrdProc.h new file mode 100644 index 0000000000..090e564726 --- /dev/null +++ b/core/fxcodec/jbig2/JBig2_TrdProc.h @@ -0,0 +1,82 @@ +// Copyright 2015 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#ifndef CORE_FXCODEC_JBIG2_JBIG2_TRDPROC_H_ +#define CORE_FXCODEC_JBIG2_JBIG2_TRDPROC_H_ + +#include "core/fxcodec/jbig2/JBig2_Image.h" +#include "core/include/fxcrt/fx_system.h" + +class CJBig2_ArithDecoder; +class CJBig2_ArithIaidDecoder; +class CJBig2_ArithIntDecoder; +class CJBig2_BitStream; +class CJBig2_HuffmanTable; +struct JBig2ArithCtx; +struct JBig2HuffmanCode; + +struct JBig2IntDecoderState { + CJBig2_ArithIntDecoder* IADT; + CJBig2_ArithIntDecoder* IAFS; + CJBig2_ArithIntDecoder* IADS; + CJBig2_ArithIntDecoder* IAIT; + CJBig2_ArithIntDecoder* IARI; + CJBig2_ArithIntDecoder* IARDW; + CJBig2_ArithIntDecoder* IARDH; + CJBig2_ArithIntDecoder* IARDX; + CJBig2_ArithIntDecoder* IARDY; + CJBig2_ArithIaidDecoder* IAID; +}; + +enum JBig2Corner { + JBIG2_CORNER_BOTTOMLEFT = 0, + JBIG2_CORNER_TOPLEFT = 1, + JBIG2_CORNER_BOTTOMRIGHT = 2, + JBIG2_CORNER_TOPRIGHT = 3 +}; + +class CJBig2_TRDProc { + public: + CJBig2_Image* decode_Huffman(CJBig2_BitStream* pStream, + JBig2ArithCtx* grContext); + + CJBig2_Image* decode_Arith(CJBig2_ArithDecoder* pArithDecoder, + JBig2ArithCtx* grContext, + JBig2IntDecoderState* pIDS); + + public: + FX_BOOL SBHUFF; + FX_BOOL SBREFINE; + FX_DWORD SBW; + FX_DWORD SBH; + FX_DWORD SBNUMINSTANCES; + FX_DWORD SBSTRIPS; + FX_DWORD SBNUMSYMS; + + JBig2HuffmanCode* SBSYMCODES; + uint8_t SBSYMCODELEN; + + CJBig2_Image** SBSYMS; + FX_BOOL SBDEFPIXEL; + + JBig2ComposeOp SBCOMBOP; + FX_BOOL TRANSPOSED; + + JBig2Corner REFCORNER; + int8_t SBDSOFFSET; + CJBig2_HuffmanTable* SBHUFFFS; + CJBig2_HuffmanTable* SBHUFFDS; + CJBig2_HuffmanTable* SBHUFFDT; + CJBig2_HuffmanTable* SBHUFFRDW; + CJBig2_HuffmanTable* SBHUFFRDH; + CJBig2_HuffmanTable* SBHUFFRDX; + CJBig2_HuffmanTable* SBHUFFRDY; + CJBig2_HuffmanTable* SBHUFFRSIZE; + FX_BOOL SBRTEMPLATE; + int8_t SBRAT[4]; +}; + +#endif // CORE_FXCODEC_JBIG2_JBIG2_TRDPROC_H_ |