Merge to XFA: Add safe FX_Alloc2D() macro
[pdfium.git] / core / src / fpdfapi / fpdf_parser / fpdf_parser_filters.cpp
index 76a79f6..6fa7419 100644 (file)
-// Copyright 2014 PDFium Authors. All rights reserved.\r
-// Use of this source code is governed by a BSD-style license that can be\r
-// found in the LICENSE file.\r
\r
-// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com\r
-\r
-#include "../../fx_zlib.h"\r
-#include "../../../include/fpdfapi/fpdf_parser.h"\r
-#include "../../../include/fxcodec/fx_codec.h"\r
-#include "../../../include/fpdfapi/fpdf_module.h"\r
-#include "filters_int.h"\r
-CFX_DataFilter::CFX_DataFilter()\r
-{\r
-    m_bEOF = FALSE;\r
-    m_pDestFilter = NULL;\r
-    m_SrcPos = 0;\r
-}\r
-CFX_DataFilter::~CFX_DataFilter()\r
-{\r
-    if (m_pDestFilter) {\r
-        delete m_pDestFilter;\r
-    }\r
-}\r
-void CFX_DataFilter::SetDestFilter(CFX_DataFilter* pFilter)\r
-{\r
-    if (m_pDestFilter) {\r
-        m_pDestFilter->SetDestFilter(pFilter);\r
-    } else {\r
-        m_pDestFilter = pFilter;\r
-    }\r
-}\r
-void CFX_DataFilter::FilterIn(FX_LPCBYTE src_buf, FX_DWORD src_size, CFX_BinaryBuf& dest_buf)\r
-{\r
-    if (m_bEOF) {\r
-        return;\r
-    }\r
-    m_SrcPos += src_size;\r
-    if (m_pDestFilter) {\r
-        CFX_BinaryBuf temp_buf;\r
-        temp_buf.EstimateSize(FPDF_FILTER_BUFFER_SIZE, FPDF_FILTER_BUFFER_SIZE);\r
-        v_FilterIn(src_buf, src_size, temp_buf);\r
-        m_pDestFilter->FilterIn(temp_buf.GetBuffer(), temp_buf.GetSize(), dest_buf);\r
-    } else {\r
-        v_FilterIn(src_buf, src_size, dest_buf);\r
-    }\r
-}\r
-void CFX_DataFilter::FilterFinish(CFX_BinaryBuf& dest_buf)\r
-{\r
-    if (m_pDestFilter) {\r
-        CFX_BinaryBuf temp_buf;\r
-        v_FilterFinish(temp_buf);\r
-        if (temp_buf.GetSize()) {\r
-            m_pDestFilter->FilterIn(temp_buf.GetBuffer(), temp_buf.GetSize(), dest_buf);\r
-        }\r
-        m_pDestFilter->FilterFinish(dest_buf);\r
-    } else {\r
-        v_FilterFinish(dest_buf);\r
-    }\r
-    m_bEOF = TRUE;\r
-}\r
-void CFX_DataFilter::ReportEOF(FX_DWORD left_input)\r
-{\r
-    if (m_bEOF) {\r
-        return;\r
-    }\r
-    m_bEOF = TRUE;\r
-    m_SrcPos -= left_input;\r
-}\r
-CFX_DataFilter* FPDF_CreateFilter(FX_BSTR name, const CPDF_Dictionary* pParam, int width, int height)\r
-{\r
-    FX_DWORD id = name.GetID();\r
-    switch (id) {\r
-        case FXBSTR_ID('F', 'l', 'a', 't'):\r
-        case FXBSTR_ID('F', 'l', 0, 0):\r
-        case FXBSTR_ID('L', 'Z', 'W', 'D'):\r
-        case FXBSTR_ID('L', 'Z', 'W', 0): {\r
-                CFX_DataFilter* pFilter;\r
-                if (id == FXBSTR_ID('L', 'Z', 'W', 'D') || id == FXBSTR_ID('L', 'Z', 'W', 0)) {\r
-                    pFilter = FX_NEW CPDF_LzwFilter(pParam->GetInteger("EarlyChange", 1));\r
-                } else {\r
-                    pFilter = FX_NEW CPDF_FlateFilter;\r
-                }\r
-                if (pParam->GetInteger("Predictor", 1) > 1) {\r
-                    CFX_DataFilter* pPredictor = FX_NEW CPDF_PredictorFilter(pParam->GetInteger(FX_BSTRC("Predictor"), 1),\r
-                                                 pParam->GetInteger(FX_BSTRC("Colors"), 1), pParam->GetInteger(FX_BSTRC("BitsPerComponent"), 8),\r
-                                                 pParam->GetInteger(FX_BSTRC("Columns"), 1));\r
-                    pFilter->SetDestFilter(pPredictor);\r
-                }\r
-                return pFilter;\r
-            }\r
-        case FXBSTR_ID('A', 'S', 'C', 'I'):\r
-            if (name == "ASCIIHexDecode") {\r
-                return FX_NEW CPDF_AsciiHexFilter;\r
-            }\r
-            return FX_NEW CPDF_Ascii85Filter;\r
-        case FXBSTR_ID('A', 'H', 'x', 0):\r
-            return FX_NEW CPDF_AsciiHexFilter;\r
-        case FXBSTR_ID('A', '8', '5', 0):\r
-            return FX_NEW CPDF_Ascii85Filter;\r
-        case FXBSTR_ID('R', 'u', 'n', 'L'):\r
-            return FX_NEW CPDF_RunLenFilter;\r
-        case FXBSTR_ID('C', 'C', 'I', 'T'): {\r
-                int Encoding = 0;\r
-                int bEndOfLine = FALSE;\r
-                int bByteAlign = FALSE;\r
-                int bBlack = FALSE;\r
-                int nRows = 0;\r
-                int nColumns = 1728;\r
-                if (pParam) {\r
-                    Encoding = pParam->GetInteger(FX_BSTRC("K"));\r
-                    bEndOfLine = pParam->GetInteger(FX_BSTRC("EndOfLine"));\r
-                    bByteAlign = pParam->GetInteger(FX_BSTRC("EncodedByteAlign"));\r
-                    bBlack = pParam->GetInteger(FX_BSTRC("BlackIs1"));\r
-                    nColumns = pParam->GetInteger(FX_BSTRC("Columns"), 1728);\r
-                    nRows = pParam->GetInteger(FX_BSTRC("Rows"));\r
-                }\r
-                if (nColumns == 0) {\r
-                    nColumns = width;\r
-                }\r
-                if (nRows == 0) {\r
-                    nRows = height;\r
-                }\r
-                CPDF_FaxFilter* pFilter = FX_NEW CPDF_FaxFilter();\r
-                pFilter->Initialize(Encoding, bEndOfLine, bByteAlign, bBlack, nRows, nColumns);\r
-                return pFilter;\r
-            }\r
-        case FXBSTR_ID('D', 'C', 'T', 'D'):\r
-            return FX_NEW CPDF_JpegFilter;\r
-        default:\r
-            return NULL;\r
-    }\r
-}\r
-CFX_DataFilter* _FPDF_CreateFilterFromDict(CPDF_Dictionary* pDict)\r
-{\r
-    CPDF_Object* pDecoder = pDict->GetElementValue("Filter");\r
-    if (pDecoder == NULL) {\r
-        return NULL;\r
-    }\r
-    CFX_DataFilter* pFirstFilter = NULL;\r
-    int width = pDict->GetInteger(FX_BSTRC("Width")), height = pDict->GetInteger(FX_BSTRC("Height"));\r
-    CPDF_Object* pParams = pDict->GetElementValue("DecodeParms");\r
-    if (pDecoder->GetType() == PDFOBJ_ARRAY) {\r
-        if (pParams && pParams->GetType() != PDFOBJ_ARRAY) {\r
-            pParams = NULL;\r
-        }\r
-        for (FX_DWORD i = 0; i < ((CPDF_Array*)pDecoder)->GetCount(); i ++) {\r
-            CFX_ByteString name = ((CPDF_Array*)pDecoder)->GetString(i);\r
-            CPDF_Dictionary* pParam = NULL;\r
-            if (pParams) {\r
-                pParam = ((CPDF_Array*)pParams)->GetDict(i);\r
-            }\r
-            CFX_DataFilter* pDestFilter = FPDF_CreateFilter(name, pParam, width, height);\r
-            if (pDestFilter) {\r
-                if (pFirstFilter == NULL) {\r
-                    pFirstFilter = pDestFilter;\r
-                } else {\r
-                    pFirstFilter->SetDestFilter(pDestFilter);\r
-                }\r
-            }\r
-        }\r
-    } else {\r
-        if (pParams && pParams->GetType() != PDFOBJ_DICTIONARY) {\r
-            pParams = NULL;\r
-        }\r
-        pFirstFilter = FPDF_CreateFilter(pDecoder->GetString(), (CPDF_Dictionary*)pParams, width, height);\r
-    }\r
-    return pFirstFilter;\r
-}\r
-CPDF_StreamFilter* CPDF_Stream::GetStreamFilter(FX_BOOL bRaw) const\r
-{\r
-    CFX_DataFilter* pFirstFilter = NULL;\r
-    if (m_pCryptoHandler) {\r
-        pFirstFilter = FX_NEW CPDF_DecryptFilter(m_pCryptoHandler, m_ObjNum, m_GenNum);\r
-    }\r
-    if (!bRaw) {\r
-        CFX_DataFilter* pFilter = _FPDF_CreateFilterFromDict(m_pDict);\r
-        if (pFilter) {\r
-            if (pFirstFilter == NULL) {\r
-                pFirstFilter = pFilter;\r
-            } else {\r
-                pFirstFilter->SetDestFilter(pFilter);\r
-            }\r
-        }\r
-    }\r
-    CPDF_StreamFilter* pStreamFilter = FX_NEW CPDF_StreamFilter;\r
-    pStreamFilter->m_pStream = this;\r
-    pStreamFilter->m_pFilter = pFirstFilter;\r
-    pStreamFilter->m_pBuffer = NULL;\r
-    pStreamFilter->m_SrcOffset = 0;\r
-    return pStreamFilter;\r
-}\r
-CPDF_StreamFilter::~CPDF_StreamFilter()\r
-{\r
-    if (m_pFilter) {\r
-        delete m_pFilter;\r
-    }\r
-    if (m_pBuffer) {\r
-        delete m_pBuffer;\r
-    }\r
-}\r
-#define FPDF_FILTER_BUFFER_IN_SIZE     FPDF_FILTER_BUFFER_SIZE\r
-FX_DWORD CPDF_StreamFilter::ReadBlock(FX_LPBYTE buffer, FX_DWORD buf_size)\r
-{\r
-    if (m_pFilter == NULL) {\r
-        FX_DWORD read_size = m_pStream->GetRawSize() - m_SrcOffset;\r
-        if (read_size == 0) {\r
-            return 0;\r
-        }\r
-        if (read_size > buf_size) {\r
-            read_size = buf_size;\r
-        }\r
-        m_pStream->ReadRawData(m_SrcOffset, buffer, read_size);\r
-        m_SrcOffset += read_size;\r
-        return read_size;\r
-    }\r
-    FX_DWORD read_size = 0;\r
-    if (m_pBuffer) {\r
-        read_size = ReadLeftOver(buffer, buf_size);\r
-        if (read_size == buf_size) {\r
-            return read_size;\r
-        }\r
-        buffer += read_size;\r
-        buf_size -= read_size;\r
-    }\r
-    ASSERT(m_pBuffer == NULL);\r
-    if (m_pFilter->IsEOF()) {\r
-        return read_size;\r
-    }\r
-    m_pBuffer = FX_NEW CFX_BinaryBuf;\r
-    m_pBuffer->EstimateSize(FPDF_FILTER_BUFFER_SIZE, FPDF_FILTER_BUFFER_SIZE);\r
-    m_BufOffset = 0;\r
-    while (1) {\r
-        int src_size = m_pStream->GetRawSize() - m_SrcOffset;\r
-        if (src_size == 0) {\r
-            m_pFilter->FilterFinish(*m_pBuffer);\r
-            break;\r
-        }\r
-        if (src_size > FPDF_FILTER_BUFFER_IN_SIZE) {\r
-            src_size = FPDF_FILTER_BUFFER_IN_SIZE;\r
-        }\r
-        if (!m_pStream->ReadRawData(m_SrcOffset, m_SrcBuffer, src_size)) {\r
-            return 0;\r
-        }\r
-        m_SrcOffset += src_size;\r
-        m_pFilter->FilterIn(m_SrcBuffer, src_size, *m_pBuffer);\r
-        if (m_pBuffer->GetSize() >= (int)buf_size) {\r
-            break;\r
-        }\r
-    }\r
-    return read_size + ReadLeftOver(buffer, buf_size);\r
-}\r
-FX_DWORD CPDF_StreamFilter::ReadLeftOver(FX_LPBYTE buffer, FX_DWORD buf_size)\r
-{\r
-    FX_DWORD read_size = m_pBuffer->GetSize() - m_BufOffset;\r
-    if (read_size > buf_size) {\r
-        read_size = buf_size;\r
-    }\r
-    FXSYS_memcpy32(buffer, m_pBuffer->GetBuffer() + m_BufOffset, read_size);\r
-    m_BufOffset += read_size;\r
-    if (m_BufOffset == (FX_DWORD)m_pBuffer->GetSize()) {\r
-        delete m_pBuffer;\r
-        m_pBuffer = NULL;\r
-    }\r
-    return read_size;\r
-}\r
-CPDF_DecryptFilter::CPDF_DecryptFilter(CPDF_CryptoHandler* pCryptoHandler, FX_DWORD objnum, FX_DWORD gennum)\r
-{\r
-    m_pCryptoHandler = pCryptoHandler;\r
-    m_pContext = NULL;\r
-    m_ObjNum = objnum;\r
-    m_GenNum = gennum;\r
-}\r
-CPDF_DecryptFilter::~CPDF_DecryptFilter()\r
-{\r
-    CFX_BinaryBuf buf;\r
-    if (m_pContext) {\r
-        m_pCryptoHandler->DecryptFinish(m_pContext, buf);\r
-    }\r
-}\r
-void CPDF_DecryptFilter::v_FilterIn(FX_LPCBYTE src_buf, FX_DWORD src_size, CFX_BinaryBuf& dest_buf)\r
-{\r
-    if (m_pContext == NULL) {\r
-        m_pContext = m_pCryptoHandler->DecryptStart(m_ObjNum, m_GenNum);\r
-    }\r
-    m_pCryptoHandler->DecryptStream(m_pContext, src_buf, src_size, dest_buf);\r
-}\r
-void CPDF_DecryptFilter::v_FilterFinish(CFX_BinaryBuf& dest_buf)\r
-{\r
-    m_bEOF = TRUE;\r
-    if (m_pContext == NULL) {\r
-        return;\r
-    }\r
-    m_pCryptoHandler->DecryptFinish(m_pContext, dest_buf);\r
-    m_pContext = NULL;\r
-}\r
-extern "C" {\r
-    static void* my_alloc_func (void* opaque, unsigned int items, unsigned int size)\r
-    {\r
-        return FX_Alloc(FX_BYTE, items * size);\r
-    }\r
-    static void   my_free_func  (void* opaque, void* address)\r
-    {\r
-        FX_Free(address);\r
-    }\r
-    void* FPDFAPI_FlateInit(void* (*alloc_func)(void*, unsigned int, unsigned int),\r
-                            void (*free_func)(void*, void*));\r
-    void FPDFAPI_FlateInput(void* context, const unsigned char* src_buf, unsigned int src_size);\r
-    int FPDFAPI_FlateOutput(void* context, unsigned char* dest_buf, unsigned int dest_size);\r
-    int FPDFAPI_FlateGetAvailIn(void* context);\r
-    int FPDFAPI_FlateGetAvailOut(void* context);\r
-    void FPDFAPI_FlateEnd(void* context);\r
-}\r
-CPDF_FlateFilter::CPDF_FlateFilter()\r
-{\r
-    m_pContext = NULL;\r
-}\r
-CPDF_FlateFilter::~CPDF_FlateFilter()\r
-{\r
-    if (m_pContext) {\r
-        FPDFAPI_FlateEnd(m_pContext);\r
-    }\r
-}\r
-void CPDF_FlateFilter::v_FilterIn(FX_LPCBYTE src_buf, FX_DWORD src_size, CFX_BinaryBuf& dest_buf)\r
-{\r
-    if (m_pContext == NULL) {\r
-        m_pContext = FPDFAPI_FlateInit(my_alloc_func, my_free_func);\r
-    }\r
-    FPDFAPI_FlateInput(m_pContext, src_buf, src_size);\r
-    while (1) {\r
-        int ret = FPDFAPI_FlateOutput(m_pContext, m_DestBuffer, FPDF_FILTER_BUFFER_SIZE);\r
-        int out_size = FPDF_FILTER_BUFFER_SIZE - FPDFAPI_FlateGetAvailOut(m_pContext);\r
-        dest_buf.AppendBlock(m_DestBuffer, out_size);\r
-        if (ret == Z_BUF_ERROR) {\r
-            break;\r
-        }\r
-        if (ret != Z_OK) {\r
-            ReportEOF(FPDFAPI_FlateGetAvailIn(m_pContext));\r
-            break;\r
-        }\r
-    }\r
-}\r
-CPDF_LzwFilter::CPDF_LzwFilter(FX_BOOL bEarlyChange)\r
-{\r
-    m_bEarlyChange = bEarlyChange ? 1 : 0;\r
-    m_CodeLen = 9;\r
-    m_nCodes = 0;\r
-    m_nLeftBits = 0;\r
-    m_LeftBits = 0;\r
-    m_OldCode = (FX_DWORD) - 1;\r
-}\r
-void CPDF_LzwFilter::v_FilterIn(FX_LPCBYTE src_buf, FX_DWORD src_size, CFX_BinaryBuf& dest_buf)\r
-{\r
-    for (FX_DWORD i = 0; i < src_size; i ++) {\r
-        if (m_nLeftBits + 8 < m_CodeLen) {\r
-            m_nLeftBits += 8;\r
-            m_LeftBits = (m_LeftBits << 8) | src_buf[i];\r
-            continue;\r
-        }\r
-        FX_DWORD new_bits = m_CodeLen - m_nLeftBits;\r
-        FX_DWORD code = (m_LeftBits << new_bits) | (src_buf[i] >> (8 - new_bits));\r
-        m_nLeftBits = 8 - new_bits;\r
-        m_LeftBits = src_buf[i] % (1 << m_nLeftBits);\r
-        if (code < 256) {\r
-            dest_buf.AppendByte((FX_BYTE)code);\r
-            m_LastChar = (FX_BYTE)code;\r
-            if (m_OldCode != -1) {\r
-                AddCode(m_OldCode, m_LastChar);\r
-            }\r
-            m_OldCode = code;\r
-        } else if (code == 256) {\r
-            m_CodeLen = 9;\r
-            m_nCodes = 0;\r
-            m_OldCode = (FX_DWORD) - 1;\r
-        } else if (code == 257) {\r
-            ReportEOF(src_size - i - 1);\r
-            return;\r
-        } else {\r
-            if (m_OldCode == -1) {\r
-                ReportEOF(src_size - i - 1);\r
-                return;\r
-            }\r
-            m_StackLen = 0;\r
-            if (code >= m_nCodes + 258) {\r
-                if (m_StackLen < sizeof(m_DecodeStack)) {\r
-                    m_DecodeStack[m_StackLen++] = m_LastChar;\r
-                }\r
-                DecodeString(m_OldCode);\r
-            } else {\r
-                DecodeString(code);\r
-            }\r
-            dest_buf.AppendBlock(NULL, m_StackLen);\r
-            FX_LPBYTE pOutput = dest_buf.GetBuffer() + dest_buf.GetSize() - m_StackLen;\r
-            for (FX_DWORD cc = 0; cc < m_StackLen; cc ++) {\r
-                pOutput[cc] = m_DecodeStack[m_StackLen - cc - 1];\r
-            }\r
-            m_LastChar = m_DecodeStack[m_StackLen - 1];\r
-            if (m_OldCode < 256) {\r
-                AddCode(m_OldCode, m_LastChar);\r
-            } else if (m_OldCode - 258 >= m_nCodes) {\r
-                ReportEOF(src_size - i - 1);\r
-                return;\r
-            } else {\r
-                AddCode(m_OldCode, m_LastChar);\r
-            }\r
-            m_OldCode = code;\r
-        }\r
-    }\r
-}\r
-void CPDF_LzwFilter::AddCode(FX_DWORD prefix_code, FX_BYTE append_char)\r
-{\r
-    if (m_nCodes + m_bEarlyChange == 4094) {\r
-        return;\r
-    }\r
-    m_CodeArray[m_nCodes ++] = (prefix_code << 16) | append_char;\r
-    if (m_nCodes + m_bEarlyChange == 512 - 258) {\r
-        m_CodeLen = 10;\r
-    } else if (m_nCodes + m_bEarlyChange == 1024 - 258) {\r
-        m_CodeLen = 11;\r
-    } else if (m_nCodes + m_bEarlyChange == 2048 - 258) {\r
-        m_CodeLen = 12;\r
-    }\r
-}\r
-void CPDF_LzwFilter::DecodeString(FX_DWORD code)\r
-{\r
-    while (1) {\r
-        int index = code - 258;\r
-        if (index < 0 || index >= (int)m_nCodes) {\r
-            break;\r
-        }\r
-        FX_DWORD data = m_CodeArray[index];\r
-        if (m_StackLen >= sizeof(m_DecodeStack)) {\r
-            return;\r
-        }\r
-        m_DecodeStack[m_StackLen++] = (FX_BYTE)data;\r
-        code = data >> 16;\r
-    }\r
-    if (m_StackLen >= sizeof(m_DecodeStack)) {\r
-        return;\r
-    }\r
-    m_DecodeStack[m_StackLen++] = (FX_BYTE)code;\r
-}\r
-CPDF_PredictorFilter::CPDF_PredictorFilter(int predictor, int colors, int bpc, int cols)\r
-{\r
-    m_bTiff = predictor < 10;\r
-    m_pRefLine = NULL;\r
-    m_pCurLine = NULL;\r
-    m_iLine = 0;\r
-    m_LineInSize = 0;\r
-    m_Bpp = (colors * bpc + 7) / 8;\r
-    m_Pitch = (colors * bpc * cols + 7) / 8;\r
-    if (!m_bTiff) {\r
-        m_Pitch ++;\r
-    }\r
-}\r
-CPDF_PredictorFilter::~CPDF_PredictorFilter()\r
-{\r
-    if (m_pCurLine) {\r
-        FX_Free(m_pCurLine);\r
-    }\r
-    if (m_pRefLine) {\r
-        FX_Free(m_pRefLine);\r
-    }\r
-}\r
-static FX_BYTE PaethPredictor(int a, int b, int c)\r
-{\r
-    int p = a + b - c;\r
-    int pa = FXSYS_abs(p - a);\r
-    int pb = FXSYS_abs(p - b);\r
-    int pc = FXSYS_abs(p - c);\r
-    if (pa <= pb && pa <= pc) {\r
-        return (FX_BYTE)a;\r
-    }\r
-    if (pb <= pc) {\r
-        return (FX_BYTE)b;\r
-    }\r
-    return (FX_BYTE)c;\r
-}\r
-static void PNG_PredictorLine(FX_LPBYTE cur_buf, FX_LPBYTE ref_buf, int pitch, int Bpp)\r
-{\r
-    FX_BYTE tag = cur_buf[0];\r
-    if (tag == 0) {\r
-        return;\r
-    }\r
-    cur_buf ++;\r
-    if (ref_buf) {\r
-        ref_buf ++;\r
-    }\r
-    for (int byte = 0; byte < pitch; byte ++) {\r
-        FX_BYTE raw_byte = cur_buf[byte];\r
-        switch (tag) {\r
-            case 1:    {\r
-                    FX_BYTE left = 0;\r
-                    if (byte >= Bpp) {\r
-                        left = cur_buf[byte - Bpp];\r
-                    }\r
-                    cur_buf[byte] = raw_byte + left;\r
-                    break;\r
-                }\r
-            case 2: {\r
-                    FX_BYTE up = 0;\r
-                    if (ref_buf) {\r
-                        up = ref_buf[byte];\r
-                    }\r
-                    cur_buf[byte] = raw_byte + up;\r
-                    break;\r
-                }\r
-            case 3: {\r
-                    FX_BYTE left = 0;\r
-                    if (byte >= Bpp) {\r
-                        left = cur_buf[byte - Bpp];\r
-                    }\r
-                    FX_BYTE up = 0;\r
-                    if (ref_buf) {\r
-                        up = ref_buf[byte];\r
-                    }\r
-                    cur_buf[byte] = raw_byte + (up + left) / 2;\r
-                    break;\r
-                }\r
-            case 4: {\r
-                    FX_BYTE left = 0;\r
-                    if (byte >= Bpp) {\r
-                        left = cur_buf[byte - Bpp];\r
-                    }\r
-                    FX_BYTE up = 0;\r
-                    if (ref_buf) {\r
-                        up = ref_buf[byte];\r
-                    }\r
-                    FX_BYTE upper_left = 0;\r
-                    if (byte >= Bpp && ref_buf) {\r
-                        upper_left = ref_buf[byte - Bpp];\r
-                    }\r
-                    cur_buf[byte] = raw_byte + PaethPredictor(left, up, upper_left);\r
-                    break;\r
-                }\r
-        }\r
-    }\r
-}\r
-void CPDF_PredictorFilter::v_FilterIn(FX_LPCBYTE src_buf, FX_DWORD src_size, CFX_BinaryBuf& dest_buf)\r
-{\r
-    if (m_pCurLine == NULL) {\r
-        m_pCurLine = FX_Alloc(FX_BYTE, m_Pitch);\r
-        if (!m_bTiff) {\r
-            m_pRefLine = FX_Alloc(FX_BYTE, m_Pitch);\r
-        }\r
-    }\r
-    while (1) {\r
-        FX_DWORD read_size = m_Pitch - m_LineInSize;\r
-        if (read_size > src_size) {\r
-            read_size = src_size;\r
-        }\r
-        FXSYS_memcpy32(m_pCurLine + m_LineInSize, src_buf, read_size);\r
-        m_LineInSize += read_size;\r
-        if (m_LineInSize < m_Pitch) {\r
-            break;\r
-        }\r
-        src_buf += read_size;\r
-        src_size -= read_size;\r
-        if (m_bTiff) {\r
-            for (FX_DWORD byte = m_Bpp; byte < m_Pitch; byte ++) {\r
-                m_pCurLine[byte] += m_pCurLine[byte - m_Bpp];\r
-            }\r
-            dest_buf.AppendBlock(m_pCurLine, m_Pitch);\r
-        } else {\r
-            PNG_PredictorLine(m_pCurLine, m_iLine ? m_pRefLine : NULL, m_Pitch - 1, m_Bpp);\r
-            dest_buf.AppendBlock(m_pCurLine + 1, m_Pitch - 1);\r
-            m_iLine ++;\r
-            FX_LPBYTE temp = m_pCurLine;\r
-            m_pCurLine = m_pRefLine;\r
-            m_pRefLine = temp;\r
-        }\r
-        m_LineInSize = 0;\r
-    }\r
-}\r
-CPDF_Ascii85Filter::CPDF_Ascii85Filter()\r
-{\r
-    m_State = 0;\r
-    m_CharCount = 0;\r
-}\r
-extern const FX_LPCSTR _PDF_CharType;\r
-void CPDF_Ascii85Filter::v_FilterIn(FX_LPCBYTE src_buf, FX_DWORD src_size, CFX_BinaryBuf& dest_buf)\r
-{\r
-    for (FX_DWORD i = 0; i < src_size; i ++) {\r
-        FX_BYTE byte = src_buf[i];\r
-        if (_PDF_CharType[byte] == 'W') {\r
-            continue;\r
-        }\r
-        switch (m_State) {\r
-            case 0:\r
-                if (byte >= '!' && byte <= 'u') {\r
-                    int digit = byte - '!';\r
-                    m_CurDWord = digit;\r
-                    m_CharCount = 1;\r
-                    m_State = 1;\r
-                } else if (byte == 'z') {\r
-                    int zero = 0;\r
-                    dest_buf.AppendBlock(&zero, 4);\r
-                } else if (byte == '~') {\r
-                    m_State = 2;\r
-                }\r
-                break;\r
-            case 1: {\r
-                    if (byte >= '!' && byte <= 'u') {\r
-                        int digit = byte - '!';\r
-                        m_CurDWord = m_CurDWord * 85 + digit;\r
-                        m_CharCount ++;\r
-                        if (m_CharCount == 5) {\r
-                            for (int i = 0; i < 4; i ++) {\r
-                                dest_buf.AppendByte((FX_BYTE)(m_CurDWord >> (3 - i) * 8));\r
-                            }\r
-                            m_State = 0;\r
-                        }\r
-                    } else if (byte == '~') {\r
-                        if (m_CharCount > 1) {\r
-                            int i;\r
-                            for (i = m_CharCount; i < 5; i ++) {\r
-                                m_CurDWord = m_CurDWord * 85 + 84;\r
-                            }\r
-                            for (i = 0; i < m_CharCount - 1; i ++) {\r
-                                dest_buf.AppendByte((FX_BYTE)(m_CurDWord >> (3 - i) * 8));\r
-                            }\r
-                        }\r
-                        m_State = 2;\r
-                    }\r
-                    break;\r
-                }\r
-            case 2:\r
-                if (byte == '>') {\r
-                    ReportEOF(src_size - i - 1);\r
-                    return;\r
-                }\r
-                break;\r
-        }\r
-    }\r
-}\r
-CPDF_AsciiHexFilter::CPDF_AsciiHexFilter()\r
-{\r
-    m_State = 0;\r
-}\r
-void CPDF_AsciiHexFilter::v_FilterIn(FX_LPCBYTE src_buf, FX_DWORD src_size, CFX_BinaryBuf& dest_buf)\r
-{\r
-    for (FX_DWORD i = 0; i < src_size; i ++) {\r
-        FX_BYTE byte = src_buf[i];\r
-        if (_PDF_CharType[byte] == 'W') {\r
-            continue;\r
-        }\r
-        int digit;\r
-        if (byte >= '0' && byte <= '9') {\r
-            digit = byte - '0';\r
-        } else if (byte >= 'a' && byte <= 'f') {\r
-            digit = byte - 'a' + 10;\r
-        } else if (byte >= 'A' && byte <= 'F') {\r
-            digit = byte - 'A' + 10;\r
-        } else {\r
-            if (m_State) {\r
-                dest_buf.AppendByte(m_FirstDigit * 16);\r
-            }\r
-            ReportEOF(src_size - i - 1);\r
-            return;\r
-        }\r
-        if (m_State == 0) {\r
-            m_FirstDigit = digit;\r
-            m_State ++;\r
-        } else {\r
-            dest_buf.AppendByte(m_FirstDigit * 16 + digit);\r
-            m_State --;\r
-        }\r
-    }\r
-}\r
-CPDF_RunLenFilter::CPDF_RunLenFilter()\r
-{\r
-    m_State = 0;\r
-    m_Count = 0;\r
-}\r
-void CPDF_RunLenFilter::v_FilterIn(FX_LPCBYTE src_buf, FX_DWORD src_size, CFX_BinaryBuf& dest_buf)\r
-{\r
-    for (FX_DWORD i = 0; i < src_size; i ++) {\r
-        FX_BYTE byte = src_buf[i];\r
-        switch (m_State) {\r
-            case 0:\r
-                if (byte < 128) {\r
-                    m_State = 1;\r
-                    m_Count = byte + 1;\r
-                } else if (byte == 128) {\r
-                    ReportEOF(src_size - i - 1);\r
-                    return;\r
-                } else {\r
-                    m_State = 2;\r
-                    m_Count = 257 - byte;\r
-                }\r
-                break;\r
-            case 1:\r
-                dest_buf.AppendByte(byte);\r
-                m_Count --;\r
-                if (m_Count == 0) {\r
-                    m_State = 0;\r
-                }\r
-                break;\r
-            case 2:    {\r
-                    dest_buf.AppendBlock(NULL, m_Count);\r
-                    FXSYS_memset8(dest_buf.GetBuffer() + dest_buf.GetSize() - m_Count, byte, m_Count);\r
-                    m_State = 0;\r
-                    break;\r
-                }\r
-        }\r
-    }\r
-}\r
-CPDF_JpegFilter::CPDF_JpegFilter()\r
-{\r
-    m_pContext = NULL;\r
-    m_bGotHeader = FALSE;\r
-    m_pScanline = NULL;\r
-    m_iLine = 0;\r
-}\r
-CPDF_JpegFilter::~CPDF_JpegFilter()\r
-{\r
-    if (m_pScanline) {\r
-        FX_Free(m_pScanline);\r
-    }\r
-    if (m_pContext) {\r
-        CPDF_ModuleMgr::Get()->GetJpegModule()->Finish(m_pContext);\r
-    }\r
-}\r
-void CPDF_JpegFilter::v_FilterIn(FX_LPCBYTE src_buf, FX_DWORD src_size, CFX_BinaryBuf& dest_buf)\r
-{\r
-    if (m_pContext == NULL) {\r
-        m_pContext = CPDF_ModuleMgr::Get()->GetJpegModule()->Start();\r
-    }\r
-    FX_LPCBYTE jpeg_src_buf;\r
-    FX_DWORD jpeg_src_size;\r
-    CFX_BinaryBuf temp_buf;\r
-    if (m_InputBuf.GetSize()) {\r
-        temp_buf.EstimateSize(m_InputBuf.GetSize() + src_size);\r
-        temp_buf.AppendBlock(m_InputBuf.GetBuffer(), m_InputBuf.GetSize());\r
-        m_InputBuf.Clear();\r
-        temp_buf.AppendBlock(src_buf, src_size);\r
-        jpeg_src_buf = temp_buf.GetBuffer();\r
-        jpeg_src_size = temp_buf.GetSize();\r
-    } else {\r
-        jpeg_src_buf = src_buf;\r
-        jpeg_src_size = src_size;\r
-    }\r
-    CPDF_ModuleMgr::Get()->GetJpegModule()->Input(m_pContext, jpeg_src_buf, jpeg_src_size);\r
-    if (!m_bGotHeader) {\r
-        int ret = CPDF_ModuleMgr::Get()->GetJpegModule()->ReadHeader(m_pContext, &m_Width, &m_Height, &m_nComps);\r
-        int left_size = CPDF_ModuleMgr::Get()->GetJpegModule()->GetAvailInput(m_pContext);\r
-        if (ret == 1) {\r
-            ReportEOF(left_size);\r
-            return;\r
-        }\r
-        if (ret == 2) {\r
-            m_InputBuf.AppendBlock(jpeg_src_buf + jpeg_src_size - left_size, left_size);\r
-            return;\r
-        }\r
-        CPDF_ModuleMgr::Get()->GetJpegModule()->StartScanline(m_pContext, 1);\r
-        m_bGotHeader = TRUE;\r
-        m_Pitch = m_Width * m_nComps;\r
-    }\r
-    if (m_pScanline == NULL) {\r
-        m_pScanline = FX_Alloc(FX_BYTE, m_Pitch + 4);\r
-    }\r
-    while (1) {\r
-        if (!CPDF_ModuleMgr::Get()->GetJpegModule()->ReadScanline(m_pContext, m_pScanline)) {\r
-            int left_size = CPDF_ModuleMgr::Get()->GetJpegModule()->GetAvailInput(m_pContext);\r
-            m_InputBuf.AppendBlock(jpeg_src_buf + jpeg_src_size - left_size, left_size);\r
-            break;\r
-        }\r
-        dest_buf.AppendBlock(m_pScanline, m_Pitch);\r
-        m_iLine ++;\r
-        if (m_iLine == m_Height) {\r
-            ReportEOF(CPDF_ModuleMgr::Get()->GetJpegModule()->GetAvailInput(m_pContext));\r
-            return;\r
-        }\r
-    }\r
-}\r
-CPDF_FaxFilter::CPDF_FaxFilter()\r
-{\r
-    m_Encoding = 0;\r
-    m_bEndOfLine = FALSE;\r
-    m_bByteAlign = FALSE;\r
-    m_bBlack = FALSE;\r
-    m_nRows = 0;\r
-    m_nColumns = 0;\r
-    m_Pitch = 0;\r
-    m_pScanlineBuf = NULL;\r
-    m_pRefBuf = NULL;\r
-    m_iRow = 0;\r
-    m_InputBitPos = 0;\r
-}\r
-CPDF_FaxFilter::~CPDF_FaxFilter()\r
-{\r
-    if (m_pScanlineBuf) {\r
-        FX_Free(m_pScanlineBuf);\r
-    }\r
-    if (m_pRefBuf) {\r
-        FX_Free(m_pRefBuf);\r
-    }\r
-}\r
-FX_BOOL CPDF_FaxFilter::Initialize(int Encoding, int bEndOfLine, int bByteAlign, int bBlack, int nRows, int nColumns)\r
-{\r
-    m_Encoding = Encoding;\r
-    m_bEndOfLine = bEndOfLine;\r
-    m_bByteAlign = bByteAlign;\r
-    m_bBlack = bBlack;\r
-    m_nRows = nRows;\r
-    m_nColumns = nColumns;\r
-    m_Pitch = (m_nColumns + 7) / 8;\r
-    m_pScanlineBuf = FX_Alloc(FX_BYTE, m_Pitch);\r
-    m_pRefBuf = FX_Alloc(FX_BYTE, m_Pitch);\r
-    FXSYS_memset8(m_pScanlineBuf, 0xff, m_Pitch);\r
-    FXSYS_memset8(m_pRefBuf, 0xff, m_Pitch);\r
-    m_iRow = 0;\r
-    m_InputBitPos = 0;\r
-    return TRUE;\r
-}\r
-void CPDF_FaxFilter::v_FilterIn(FX_LPCBYTE src_buf, FX_DWORD src_size, CFX_BinaryBuf& dest_buf)\r
-{\r
-    FX_LPCBYTE fax_src_buf;\r
-    FX_DWORD fax_src_size;\r
-    CFX_BinaryBuf temp_buf;\r
-    int bitpos;\r
-    if (m_InputBuf.GetSize()) {\r
-        temp_buf.EstimateSize(m_InputBuf.GetSize() + src_size);\r
-        temp_buf.AppendBlock(m_InputBuf.GetBuffer(), m_InputBuf.GetSize());\r
-        m_InputBuf.Clear();\r
-        temp_buf.AppendBlock(src_buf, src_size);\r
-        fax_src_buf = temp_buf.GetBuffer();\r
-        fax_src_size = temp_buf.GetSize();\r
-        bitpos = m_InputBitPos;\r
-    } else {\r
-        fax_src_buf = src_buf;\r
-        fax_src_size = src_size;\r
-        bitpos = 0;\r
-    }\r
-    ProcessData(fax_src_buf, fax_src_size, bitpos, FALSE, dest_buf);\r
-    int left_bits = fax_src_size * 8 - bitpos;\r
-    m_InputBuf.AppendBlock(fax_src_buf + bitpos / 8, (left_bits + 7) / 8);\r
-    m_InputBitPos = bitpos % 8;\r
-}\r
-void CPDF_FaxFilter::v_FilterFinish(CFX_BinaryBuf& dest_buf)\r
-{\r
-    ProcessData(m_InputBuf.GetBuffer(), m_InputBuf.GetSize(), m_InputBitPos, TRUE, dest_buf);\r
-}\r
-FX_BOOL _FaxSkipEOL(const FX_BYTE* src_buf, int bitsize, int& bitpos);\r
-FX_BOOL _FaxG4GetRow(const FX_BYTE* src_buf, int bitsize, int& bitpos, FX_LPBYTE dest_buf, const FX_BYTE* ref_buf, int columns);\r
-FX_BOOL _FaxGet1DLine(const FX_BYTE* src_buf, int bitsize, int& bitpos, FX_LPBYTE dest_buf, int columns);\r
-void CPDF_FaxFilter::ProcessData(FX_LPCBYTE src_buf, FX_DWORD src_size, int& bitpos, FX_BOOL bFinish,\r
-                                 CFX_BinaryBuf& dest_buf)\r
-{\r
-    int bitsize = src_size * 8;\r
-    while (1) {\r
-        if ((bitsize < bitpos + 256) && !bFinish) {\r
-            return;\r
-        }\r
-        int start_bitpos = bitpos;\r
-        FXSYS_memset8(m_pScanlineBuf, 0xff, m_Pitch);\r
-        if (!ReadLine(src_buf, bitsize, bitpos)) {\r
-            bitpos = start_bitpos;\r
-            return;\r
-        }\r
-        if (m_Encoding) {\r
-            FXSYS_memcpy32(m_pRefBuf, m_pScanlineBuf, m_Pitch);\r
-        }\r
-        if (m_bBlack) {\r
-            for (int i = 0; i < m_Pitch; i ++) {\r
-                m_pScanlineBuf[i] = ~m_pScanlineBuf[i];\r
-            }\r
-        }\r
-        dest_buf.AppendBlock(m_pScanlineBuf, m_Pitch);\r
-        m_iRow ++;\r
-        if (m_iRow == m_nRows) {\r
-            ReportEOF(src_size - (bitpos + 7) / 8);\r
-            return;\r
-        }\r
-    }\r
-}\r
-FX_BOOL CPDF_FaxFilter::ReadLine(FX_LPCBYTE src_buf, int bitsize, int& bitpos)\r
-{\r
-    if (!_FaxSkipEOL(src_buf, bitsize, bitpos)) {\r
-        return FALSE;\r
-    }\r
-    FX_BOOL ret;\r
-    if (m_Encoding < 0) {\r
-        ret = _FaxG4GetRow(src_buf, bitsize, bitpos, m_pScanlineBuf, m_pRefBuf, m_nColumns);\r
-    } else if (m_Encoding == 0) {\r
-        ret = _FaxGet1DLine(src_buf, bitsize, bitpos, m_pScanlineBuf, m_nColumns);\r
-    } else {\r
-        if (bitpos == bitsize) {\r
-            return FALSE;\r
-        }\r
-        FX_BOOL bNext1D = src_buf[bitpos / 8] & (1 << (7 - bitpos % 8));\r
-        bitpos ++;\r
-        if (bNext1D) {\r
-            ret = _FaxGet1DLine(src_buf, bitsize, bitpos, m_pScanlineBuf, m_nColumns);\r
-        } else {\r
-            ret = _FaxG4GetRow(src_buf, bitsize, bitpos, m_pScanlineBuf, m_pRefBuf, m_nColumns);\r
-        }\r
-    }\r
-    if (!ret) {\r
-        return FALSE;\r
-    }\r
-    if (m_bEndOfLine)\r
-        if (!_FaxSkipEOL(src_buf, bitsize, bitpos)) {\r
-            return FALSE;\r
-        }\r
-    if (m_bByteAlign) {\r
-        bitpos = (bitpos + 7) / 8 * 8;\r
-    }\r
-    return TRUE;\r
-}\r
+// 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 "../../fx_zlib.h"
+#include "../../../include/fpdfapi/fpdf_parser.h"
+#include "../../../include/fxcodec/fx_codec.h"
+#include "../../../include/fpdfapi/fpdf_module.h"
+#include "filters_int.h"
+CFX_DataFilter::CFX_DataFilter()
+{
+    m_bEOF = FALSE;
+    m_pDestFilter = NULL;
+    m_SrcPos = 0;
+}
+CFX_DataFilter::~CFX_DataFilter()
+{
+    if (m_pDestFilter) {
+        delete m_pDestFilter;
+    }
+}
+void CFX_DataFilter::SetDestFilter(CFX_DataFilter* pFilter)
+{
+    if (m_pDestFilter) {
+        m_pDestFilter->SetDestFilter(pFilter);
+    } else {
+        m_pDestFilter = pFilter;
+    }
+}
+void CFX_DataFilter::FilterIn(FX_LPCBYTE src_buf, FX_DWORD src_size, CFX_BinaryBuf& dest_buf)
+{
+    if (m_bEOF) {
+        return;
+    }
+    m_SrcPos += src_size;
+    if (m_pDestFilter) {
+        CFX_BinaryBuf temp_buf;
+        temp_buf.EstimateSize(FPDF_FILTER_BUFFER_SIZE, FPDF_FILTER_BUFFER_SIZE);
+        v_FilterIn(src_buf, src_size, temp_buf);
+        m_pDestFilter->FilterIn(temp_buf.GetBuffer(), temp_buf.GetSize(), dest_buf);
+    } else {
+        v_FilterIn(src_buf, src_size, dest_buf);
+    }
+}
+void CFX_DataFilter::FilterFinish(CFX_BinaryBuf& dest_buf)
+{
+    if (m_pDestFilter) {
+        CFX_BinaryBuf temp_buf;
+        v_FilterFinish(temp_buf);
+        if (temp_buf.GetSize()) {
+            m_pDestFilter->FilterIn(temp_buf.GetBuffer(), temp_buf.GetSize(), dest_buf);
+        }
+        m_pDestFilter->FilterFinish(dest_buf);
+    } else {
+        v_FilterFinish(dest_buf);
+    }
+    m_bEOF = TRUE;
+}
+void CFX_DataFilter::ReportEOF(FX_DWORD left_input)
+{
+    if (m_bEOF) {
+        return;
+    }
+    m_bEOF = TRUE;
+    m_SrcPos -= left_input;
+}
+CFX_DataFilter* FPDF_CreateFilter(FX_BSTR name, const CPDF_Dictionary* pParam, int width, int height)
+{
+    FX_DWORD id = name.GetID();
+    switch (id) {
+        case FXBSTR_ID('F', 'l', 'a', 't'):
+        case FXBSTR_ID('F', 'l', 0, 0):
+        case FXBSTR_ID('L', 'Z', 'W', 'D'):
+        case FXBSTR_ID('L', 'Z', 'W', 0): {
+                CFX_DataFilter* pFilter;
+                if (id == FXBSTR_ID('L', 'Z', 'W', 'D') || id == FXBSTR_ID('L', 'Z', 'W', 0)) {
+                    pFilter = new CPDF_LzwFilter(pParam ? pParam->GetInteger("EarlyChange", 1) : 1);
+                } else {
+                    pFilter = new CPDF_FlateFilter;
+                }
+                if ((pParam ? pParam->GetInteger("Predictor", 1) : 1) > 1) {
+                    CFX_DataFilter* pPredictor = new CPDF_PredictorFilter(pParam->GetInteger(FX_BSTRC("Predictor"), 1),
+                                                 pParam->GetInteger(FX_BSTRC("Colors"), 1), pParam->GetInteger(FX_BSTRC("BitsPerComponent"), 8),
+                                                 pParam->GetInteger(FX_BSTRC("Columns"), 1));
+                    pFilter->SetDestFilter(pPredictor);
+                }
+                return pFilter;
+            }
+        case FXBSTR_ID('A', 'S', 'C', 'I'):
+            if (name == "ASCIIHexDecode") {
+                return new CPDF_AsciiHexFilter;
+            }
+            return new CPDF_Ascii85Filter;
+        case FXBSTR_ID('A', 'H', 'x', 0):
+            return new CPDF_AsciiHexFilter;
+        case FXBSTR_ID('A', '8', '5', 0):
+            return new CPDF_Ascii85Filter;
+        case FXBSTR_ID('R', 'u', 'n', 'L'):
+            return new CPDF_RunLenFilter;
+        case FXBSTR_ID('C', 'C', 'I', 'T'): {
+                int Encoding = 0;
+                int bEndOfLine = FALSE;
+                int bByteAlign = FALSE;
+                int bBlack = FALSE;
+                int nRows = 0;
+                int nColumns = 1728;
+                if (pParam) {
+                    Encoding = pParam->GetInteger(FX_BSTRC("K"));
+                    bEndOfLine = pParam->GetInteger(FX_BSTRC("EndOfLine"));
+                    bByteAlign = pParam->GetInteger(FX_BSTRC("EncodedByteAlign"));
+                    bBlack = pParam->GetInteger(FX_BSTRC("BlackIs1"));
+                    nColumns = pParam->GetInteger(FX_BSTRC("Columns"), 1728);
+                    nRows = pParam->GetInteger(FX_BSTRC("Rows"));
+                }
+                if (nColumns == 0) {
+                    nColumns = width;
+                }
+                if (nRows == 0) {
+                    nRows = height;
+                }
+                CPDF_FaxFilter* pFilter = new CPDF_FaxFilter();
+                pFilter->Initialize(Encoding, bEndOfLine, bByteAlign, bBlack, nRows, nColumns);
+                return pFilter;
+            }
+        case FXBSTR_ID('D', 'C', 'T', 'D'):
+            return new CPDF_JpegFilter;
+        default:
+            return NULL;
+    }
+}
+CFX_DataFilter* _FPDF_CreateFilterFromDict(CPDF_Dictionary* pDict)
+{
+    CPDF_Object* pDecoder = pDict->GetElementValue("Filter");
+    if (pDecoder == NULL) {
+        return NULL;
+    }
+    CFX_DataFilter* pFirstFilter = NULL;
+    int width = pDict->GetInteger(FX_BSTRC("Width")), height = pDict->GetInteger(FX_BSTRC("Height"));
+    CPDF_Object* pParams = pDict->GetElementValue("DecodeParms");
+    if (pDecoder->GetType() == PDFOBJ_ARRAY) {
+        if (pParams && pParams->GetType() != PDFOBJ_ARRAY) {
+            pParams = NULL;
+        }
+        for (FX_DWORD i = 0; i < ((CPDF_Array*)pDecoder)->GetCount(); i ++) {
+            CFX_ByteString name = ((CPDF_Array*)pDecoder)->GetString(i);
+            CPDF_Dictionary* pParam = NULL;
+            if (pParams) {
+                pParam = ((CPDF_Array*)pParams)->GetDict(i);
+            }
+            CFX_DataFilter* pDestFilter = FPDF_CreateFilter(name, pParam, width, height);
+            if (pDestFilter) {
+                if (pFirstFilter == NULL) {
+                    pFirstFilter = pDestFilter;
+                } else {
+                    pFirstFilter->SetDestFilter(pDestFilter);
+                }
+            }
+        }
+    } else {
+        if (pParams && pParams->GetType() != PDFOBJ_DICTIONARY) {
+            pParams = NULL;
+        }
+        pFirstFilter = FPDF_CreateFilter(pDecoder->GetString(), (CPDF_Dictionary*)pParams, width, height);
+    }
+    return pFirstFilter;
+}
+CPDF_StreamFilter* CPDF_Stream::GetStreamFilter(FX_BOOL bRaw) const
+{
+    CFX_DataFilter* pFirstFilter = NULL;
+    if (m_pCryptoHandler) {
+        pFirstFilter = new CPDF_DecryptFilter(m_pCryptoHandler, m_ObjNum, m_GenNum);
+    }
+    if (!bRaw) {
+        CFX_DataFilter* pFilter = _FPDF_CreateFilterFromDict(m_pDict);
+        if (pFilter) {
+            if (pFirstFilter == NULL) {
+                pFirstFilter = pFilter;
+            } else {
+                pFirstFilter->SetDestFilter(pFilter);
+            }
+        }
+    }
+    CPDF_StreamFilter* pStreamFilter = new CPDF_StreamFilter;
+    pStreamFilter->m_pStream = this;
+    pStreamFilter->m_pFilter = pFirstFilter;
+    pStreamFilter->m_pBuffer = NULL;
+    pStreamFilter->m_SrcOffset = 0;
+    return pStreamFilter;
+}
+CPDF_StreamFilter::~CPDF_StreamFilter()
+{
+    if (m_pFilter) {
+        delete m_pFilter;
+    }
+    if (m_pBuffer) {
+        delete m_pBuffer;
+    }
+}
+#define FPDF_FILTER_BUFFER_IN_SIZE     FPDF_FILTER_BUFFER_SIZE
+FX_DWORD CPDF_StreamFilter::ReadBlock(FX_LPBYTE buffer, FX_DWORD buf_size)
+{
+    if (m_pFilter == NULL) {
+        FX_DWORD read_size = m_pStream->GetRawSize() - m_SrcOffset;
+        if (read_size == 0) {
+            return 0;
+        }
+        if (read_size > buf_size) {
+            read_size = buf_size;
+        }
+        m_pStream->ReadRawData(m_SrcOffset, buffer, read_size);
+        m_SrcOffset += read_size;
+        return read_size;
+    }
+    FX_DWORD read_size = 0;
+    if (m_pBuffer) {
+        read_size = ReadLeftOver(buffer, buf_size);
+        if (read_size == buf_size) {
+            return read_size;
+        }
+        buffer += read_size;
+        buf_size -= read_size;
+    }
+    ASSERT(m_pBuffer == NULL);
+    if (m_pFilter->IsEOF()) {
+        return read_size;
+    }
+    m_pBuffer = new CFX_BinaryBuf;
+    m_pBuffer->EstimateSize(FPDF_FILTER_BUFFER_SIZE, FPDF_FILTER_BUFFER_SIZE);
+    m_BufOffset = 0;
+    while (1) {
+        int src_size = m_pStream->GetRawSize() - m_SrcOffset;
+        if (src_size == 0) {
+            m_pFilter->FilterFinish(*m_pBuffer);
+            break;
+        }
+        if (src_size > FPDF_FILTER_BUFFER_IN_SIZE) {
+            src_size = FPDF_FILTER_BUFFER_IN_SIZE;
+        }
+        if (!m_pStream->ReadRawData(m_SrcOffset, m_SrcBuffer, src_size)) {
+            return 0;
+        }
+        m_SrcOffset += src_size;
+        m_pFilter->FilterIn(m_SrcBuffer, src_size, *m_pBuffer);
+        if (m_pBuffer->GetSize() >= (int)buf_size) {
+            break;
+        }
+    }
+    return read_size + ReadLeftOver(buffer, buf_size);
+}
+FX_DWORD CPDF_StreamFilter::ReadLeftOver(FX_LPBYTE buffer, FX_DWORD buf_size)
+{
+    FX_DWORD read_size = m_pBuffer->GetSize() - m_BufOffset;
+    if (read_size > buf_size) {
+        read_size = buf_size;
+    }
+    FXSYS_memcpy32(buffer, m_pBuffer->GetBuffer() + m_BufOffset, read_size);
+    m_BufOffset += read_size;
+    if (m_BufOffset == (FX_DWORD)m_pBuffer->GetSize()) {
+        delete m_pBuffer;
+        m_pBuffer = NULL;
+    }
+    return read_size;
+}
+CPDF_DecryptFilter::CPDF_DecryptFilter(CPDF_CryptoHandler* pCryptoHandler, FX_DWORD objnum, FX_DWORD gennum)
+{
+    m_pCryptoHandler = pCryptoHandler;
+    m_pContext = NULL;
+    m_ObjNum = objnum;
+    m_GenNum = gennum;
+}
+CPDF_DecryptFilter::~CPDF_DecryptFilter()
+{
+    CFX_BinaryBuf buf;
+    if (m_pContext) {
+        m_pCryptoHandler->DecryptFinish(m_pContext, buf);
+    }
+}
+void CPDF_DecryptFilter::v_FilterIn(FX_LPCBYTE src_buf, FX_DWORD src_size, CFX_BinaryBuf& dest_buf)
+{
+    if (m_pContext == NULL) {
+        m_pContext = m_pCryptoHandler->DecryptStart(m_ObjNum, m_GenNum);
+    }
+    m_pCryptoHandler->DecryptStream(m_pContext, src_buf, src_size, dest_buf);
+}
+void CPDF_DecryptFilter::v_FilterFinish(CFX_BinaryBuf& dest_buf)
+{
+    m_bEOF = TRUE;
+    if (m_pContext == NULL) {
+        return;
+    }
+    m_pCryptoHandler->DecryptFinish(m_pContext, dest_buf);
+    m_pContext = NULL;
+}
+extern "C" {
+    static void* my_alloc_func (void* opaque, unsigned int items, unsigned int size)
+    {
+        return FX_Alloc2D(FX_BYTE, items, size);
+    }
+    static void   my_free_func  (void* opaque, void* address)
+    {
+        FX_Free(address);
+    }
+    void* FPDFAPI_FlateInit(void* (*alloc_func)(void*, unsigned int, unsigned int),
+                            void (*free_func)(void*, void*));
+    void FPDFAPI_FlateInput(void* context, const unsigned char* src_buf, unsigned int src_size);
+    int FPDFAPI_FlateOutput(void* context, unsigned char* dest_buf, unsigned int dest_size);
+    int FPDFAPI_FlateGetAvailIn(void* context);
+    int FPDFAPI_FlateGetAvailOut(void* context);
+    void FPDFAPI_FlateEnd(void* context);
+}
+CPDF_FlateFilter::CPDF_FlateFilter()
+{
+    m_pContext = NULL;
+}
+CPDF_FlateFilter::~CPDF_FlateFilter()
+{
+    if (m_pContext) {
+        FPDFAPI_FlateEnd(m_pContext);
+    }
+}
+void CPDF_FlateFilter::v_FilterIn(FX_LPCBYTE src_buf, FX_DWORD src_size, CFX_BinaryBuf& dest_buf)
+{
+    if (m_pContext == NULL) {
+        m_pContext = FPDFAPI_FlateInit(my_alloc_func, my_free_func);
+    }
+    FPDFAPI_FlateInput(m_pContext, src_buf, src_size);
+    while (1) {
+        int ret = FPDFAPI_FlateOutput(m_pContext, m_DestBuffer, FPDF_FILTER_BUFFER_SIZE);
+        int out_size = FPDF_FILTER_BUFFER_SIZE - FPDFAPI_FlateGetAvailOut(m_pContext);
+        dest_buf.AppendBlock(m_DestBuffer, out_size);
+        if (ret == Z_BUF_ERROR) {
+            break;
+        }
+        if (ret != Z_OK) {
+            ReportEOF(FPDFAPI_FlateGetAvailIn(m_pContext));
+            break;
+        }
+    }
+}
+CPDF_LzwFilter::CPDF_LzwFilter(FX_BOOL bEarlyChange)
+{
+    m_bEarlyChange = bEarlyChange ? 1 : 0;
+    m_CodeLen = 9;
+    m_nCodes = 0;
+    m_nLeftBits = 0;
+    m_LeftBits = 0;
+    m_OldCode = (FX_DWORD) - 1;
+}
+void CPDF_LzwFilter::v_FilterIn(FX_LPCBYTE src_buf, FX_DWORD src_size, CFX_BinaryBuf& dest_buf)
+{
+    for (FX_DWORD i = 0; i < src_size; i ++) {
+        if (m_nLeftBits + 8 < m_CodeLen) {
+            m_nLeftBits += 8;
+            m_LeftBits = (m_LeftBits << 8) | src_buf[i];
+            continue;
+        }
+        FX_DWORD new_bits = m_CodeLen - m_nLeftBits;
+        FX_DWORD code = (m_LeftBits << new_bits) | (src_buf[i] >> (8 - new_bits));
+        m_nLeftBits = 8 - new_bits;
+        m_LeftBits = src_buf[i] % (1 << m_nLeftBits);
+        if (code < 256) {
+            dest_buf.AppendByte((FX_BYTE)code);
+            m_LastChar = (FX_BYTE)code;
+            if (m_OldCode != -1) {
+                AddCode(m_OldCode, m_LastChar);
+            }
+            m_OldCode = code;
+        } else if (code == 256) {
+            m_CodeLen = 9;
+            m_nCodes = 0;
+            m_OldCode = (FX_DWORD) - 1;
+        } else if (code == 257) {
+            ReportEOF(src_size - i - 1);
+            return;
+        } else {
+            if (m_OldCode == -1) {
+                ReportEOF(src_size - i - 1);
+                return;
+            }
+            m_StackLen = 0;
+            if (code >= m_nCodes + 258) {
+                if (m_StackLen < sizeof(m_DecodeStack)) {
+                    m_DecodeStack[m_StackLen++] = m_LastChar;
+                }
+                DecodeString(m_OldCode);
+            } else {
+                DecodeString(code);
+            }
+            dest_buf.AppendBlock(NULL, m_StackLen);
+            FX_LPBYTE pOutput = dest_buf.GetBuffer() + dest_buf.GetSize() - m_StackLen;
+            for (FX_DWORD cc = 0; cc < m_StackLen; cc ++) {
+                pOutput[cc] = m_DecodeStack[m_StackLen - cc - 1];
+            }
+            m_LastChar = m_DecodeStack[m_StackLen - 1];
+            if (m_OldCode < 256) {
+                AddCode(m_OldCode, m_LastChar);
+            } else if (m_OldCode - 258 >= m_nCodes) {
+                ReportEOF(src_size - i - 1);
+                return;
+            } else {
+                AddCode(m_OldCode, m_LastChar);
+            }
+            m_OldCode = code;
+        }
+    }
+}
+void CPDF_LzwFilter::AddCode(FX_DWORD prefix_code, FX_BYTE append_char)
+{
+    if (m_nCodes + m_bEarlyChange == 4094) {
+        return;
+    }
+    m_CodeArray[m_nCodes ++] = (prefix_code << 16) | append_char;
+    if (m_nCodes + m_bEarlyChange == 512 - 258) {
+        m_CodeLen = 10;
+    } else if (m_nCodes + m_bEarlyChange == 1024 - 258) {
+        m_CodeLen = 11;
+    } else if (m_nCodes + m_bEarlyChange == 2048 - 258) {
+        m_CodeLen = 12;
+    }
+}
+void CPDF_LzwFilter::DecodeString(FX_DWORD code)
+{
+    while (1) {
+        int index = code - 258;
+        if (index < 0 || index >= (int)m_nCodes) {
+            break;
+        }
+        FX_DWORD data = m_CodeArray[index];
+        if (m_StackLen >= sizeof(m_DecodeStack)) {
+            return;
+        }
+        m_DecodeStack[m_StackLen++] = (FX_BYTE)data;
+        code = data >> 16;
+    }
+    if (m_StackLen >= sizeof(m_DecodeStack)) {
+        return;
+    }
+    m_DecodeStack[m_StackLen++] = (FX_BYTE)code;
+}
+CPDF_PredictorFilter::CPDF_PredictorFilter(int predictor, int colors, int bpc, int cols)
+{
+    m_bTiff = predictor < 10;
+    m_pRefLine = NULL;
+    m_pCurLine = NULL;
+    m_iLine = 0;
+    m_LineInSize = 0;
+    m_Bpp = (colors * bpc + 7) / 8;
+    m_Pitch = (colors * bpc * cols + 7) / 8;
+    if (!m_bTiff) {
+        m_Pitch ++;
+    }
+}
+CPDF_PredictorFilter::~CPDF_PredictorFilter()
+{
+    if (m_pCurLine) {
+        FX_Free(m_pCurLine);
+    }
+    if (m_pRefLine) {
+        FX_Free(m_pRefLine);
+    }
+}
+static FX_BYTE PaethPredictor(int a, int b, int c)
+{
+    int p = a + b - c;
+    int pa = FXSYS_abs(p - a);
+    int pb = FXSYS_abs(p - b);
+    int pc = FXSYS_abs(p - c);
+    if (pa <= pb && pa <= pc) {
+        return (FX_BYTE)a;
+    }
+    if (pb <= pc) {
+        return (FX_BYTE)b;
+    }
+    return (FX_BYTE)c;
+}
+static void PNG_PredictorLine(FX_LPBYTE cur_buf, FX_LPBYTE ref_buf, int pitch, int Bpp)
+{
+    FX_BYTE tag = cur_buf[0];
+    if (tag == 0) {
+        return;
+    }
+    cur_buf ++;
+    if (ref_buf) {
+        ref_buf ++;
+    }
+    for (int byte = 0; byte < pitch; byte ++) {
+        FX_BYTE raw_byte = cur_buf[byte];
+        switch (tag) {
+            case 1:    {
+                    FX_BYTE left = 0;
+                    if (byte >= Bpp) {
+                        left = cur_buf[byte - Bpp];
+                    }
+                    cur_buf[byte] = raw_byte + left;
+                    break;
+                }
+            case 2: {
+                    FX_BYTE up = 0;
+                    if (ref_buf) {
+                        up = ref_buf[byte];
+                    }
+                    cur_buf[byte] = raw_byte + up;
+                    break;
+                }
+            case 3: {
+                    FX_BYTE left = 0;
+                    if (byte >= Bpp) {
+                        left = cur_buf[byte - Bpp];
+                    }
+                    FX_BYTE up = 0;
+                    if (ref_buf) {
+                        up = ref_buf[byte];
+                    }
+                    cur_buf[byte] = raw_byte + (up + left) / 2;
+                    break;
+                }
+            case 4: {
+                    FX_BYTE left = 0;
+                    if (byte >= Bpp) {
+                        left = cur_buf[byte - Bpp];
+                    }
+                    FX_BYTE up = 0;
+                    if (ref_buf) {
+                        up = ref_buf[byte];
+                    }
+                    FX_BYTE upper_left = 0;
+                    if (byte >= Bpp && ref_buf) {
+                        upper_left = ref_buf[byte - Bpp];
+                    }
+                    cur_buf[byte] = raw_byte + PaethPredictor(left, up, upper_left);
+                    break;
+                }
+        }
+    }
+}
+void CPDF_PredictorFilter::v_FilterIn(FX_LPCBYTE src_buf, FX_DWORD src_size, CFX_BinaryBuf& dest_buf)
+{
+    if (m_pCurLine == NULL) {
+        m_pCurLine = FX_Alloc(FX_BYTE, m_Pitch);
+        if (!m_bTiff) {
+            m_pRefLine = FX_Alloc(FX_BYTE, m_Pitch);
+        }
+    }
+    while (1) {
+        FX_DWORD read_size = m_Pitch - m_LineInSize;
+        if (read_size > src_size) {
+            read_size = src_size;
+        }
+        FXSYS_memcpy32(m_pCurLine + m_LineInSize, src_buf, read_size);
+        m_LineInSize += read_size;
+        if (m_LineInSize < m_Pitch) {
+            break;
+        }
+        src_buf += read_size;
+        src_size -= read_size;
+        if (m_bTiff) {
+            for (FX_DWORD byte = m_Bpp; byte < m_Pitch; byte ++) {
+                m_pCurLine[byte] += m_pCurLine[byte - m_Bpp];
+            }
+            dest_buf.AppendBlock(m_pCurLine, m_Pitch);
+        } else {
+            PNG_PredictorLine(m_pCurLine, m_iLine ? m_pRefLine : NULL, m_Pitch - 1, m_Bpp);
+            dest_buf.AppendBlock(m_pCurLine + 1, m_Pitch - 1);
+            m_iLine ++;
+            FX_LPBYTE temp = m_pCurLine;
+            m_pCurLine = m_pRefLine;
+            m_pRefLine = temp;
+        }
+        m_LineInSize = 0;
+    }
+}
+CPDF_Ascii85Filter::CPDF_Ascii85Filter()
+{
+    m_State = 0;
+    m_CharCount = 0;
+}
+void CPDF_Ascii85Filter::v_FilterIn(FX_LPCBYTE src_buf, FX_DWORD src_size, CFX_BinaryBuf& dest_buf)
+{
+    for (FX_DWORD i = 0; i < src_size; i ++) {
+        FX_BYTE byte = src_buf[i];
+        if (PDF_CharType[byte] == 'W') {
+            continue;
+        }
+        switch (m_State) {
+            case 0:
+                if (byte >= '!' && byte <= 'u') {
+                    int digit = byte - '!';
+                    m_CurDWord = digit;
+                    m_CharCount = 1;
+                    m_State = 1;
+                } else if (byte == 'z') {
+                    int zero = 0;
+                    dest_buf.AppendBlock(&zero, 4);
+                } else if (byte == '~') {
+                    m_State = 2;
+                }
+                break;
+            case 1: {
+                    if (byte >= '!' && byte <= 'u') {
+                        int digit = byte - '!';
+                        m_CurDWord = m_CurDWord * 85 + digit;
+                        m_CharCount ++;
+                        if (m_CharCount == 5) {
+                            for (int i = 0; i < 4; i ++) {
+                                dest_buf.AppendByte((FX_BYTE)(m_CurDWord >> (3 - i) * 8));
+                            }
+                            m_State = 0;
+                        }
+                    } else if (byte == '~') {
+                        if (m_CharCount > 1) {
+                            int i;
+                            for (i = m_CharCount; i < 5; i ++) {
+                                m_CurDWord = m_CurDWord * 85 + 84;
+                            }
+                            for (i = 0; i < m_CharCount - 1; i ++) {
+                                dest_buf.AppendByte((FX_BYTE)(m_CurDWord >> (3 - i) * 8));
+                            }
+                        }
+                        m_State = 2;
+                    }
+                    break;
+                }
+            case 2:
+                if (byte == '>') {
+                    ReportEOF(src_size - i - 1);
+                    return;
+                }
+                break;
+        }
+    }
+}
+CPDF_AsciiHexFilter::CPDF_AsciiHexFilter()
+{
+    m_State = 0;
+}
+void CPDF_AsciiHexFilter::v_FilterIn(FX_LPCBYTE src_buf, FX_DWORD src_size, CFX_BinaryBuf& dest_buf)
+{
+    for (FX_DWORD i = 0; i < src_size; i ++) {
+        FX_BYTE byte = src_buf[i];
+        if (PDF_CharType[byte] == 'W') {
+            continue;
+        }
+        int digit;
+        if (byte >= '0' && byte <= '9') {
+            digit = byte - '0';
+        } else if (byte >= 'a' && byte <= 'f') {
+            digit = byte - 'a' + 10;
+        } else if (byte >= 'A' && byte <= 'F') {
+            digit = byte - 'A' + 10;
+        } else {
+            if (m_State) {
+                dest_buf.AppendByte(m_FirstDigit * 16);
+            }
+            ReportEOF(src_size - i - 1);
+            return;
+        }
+        if (m_State == 0) {
+            m_FirstDigit = digit;
+            m_State ++;
+        } else {
+            dest_buf.AppendByte(m_FirstDigit * 16 + digit);
+            m_State --;
+        }
+    }
+}
+CPDF_RunLenFilter::CPDF_RunLenFilter()
+{
+    m_State = 0;
+    m_Count = 0;
+}
+void CPDF_RunLenFilter::v_FilterIn(FX_LPCBYTE src_buf, FX_DWORD src_size, CFX_BinaryBuf& dest_buf)
+{
+    for (FX_DWORD i = 0; i < src_size; i ++) {
+        FX_BYTE byte = src_buf[i];
+        switch (m_State) {
+            case 0:
+                if (byte < 128) {
+                    m_State = 1;
+                    m_Count = byte + 1;
+                } else if (byte == 128) {
+                    ReportEOF(src_size - i - 1);
+                    return;
+                } else {
+                    m_State = 2;
+                    m_Count = 257 - byte;
+                }
+                break;
+            case 1:
+                dest_buf.AppendByte(byte);
+                m_Count --;
+                if (m_Count == 0) {
+                    m_State = 0;
+                }
+                break;
+            case 2:    {
+                    dest_buf.AppendBlock(NULL, m_Count);
+                    FXSYS_memset8(dest_buf.GetBuffer() + dest_buf.GetSize() - m_Count, byte, m_Count);
+                    m_State = 0;
+                    break;
+                }
+        }
+    }
+}
+CPDF_JpegFilter::CPDF_JpegFilter()
+{
+    m_pContext = NULL;
+    m_bGotHeader = FALSE;
+    m_pScanline = NULL;
+    m_iLine = 0;
+}
+CPDF_JpegFilter::~CPDF_JpegFilter()
+{
+    if (m_pScanline) {
+        FX_Free(m_pScanline);
+    }
+    if (m_pContext) {
+        CPDF_ModuleMgr::Get()->GetJpegModule()->Finish(m_pContext);
+    }
+}
+void CPDF_JpegFilter::v_FilterIn(FX_LPCBYTE src_buf, FX_DWORD src_size, CFX_BinaryBuf& dest_buf)
+{
+    if (m_pContext == NULL) {
+        m_pContext = CPDF_ModuleMgr::Get()->GetJpegModule()->Start();
+    }
+    FX_LPCBYTE jpeg_src_buf;
+    FX_DWORD jpeg_src_size;
+    CFX_BinaryBuf temp_buf;
+    if (m_InputBuf.GetSize()) {
+        temp_buf.EstimateSize(m_InputBuf.GetSize() + src_size);
+        temp_buf.AppendBlock(m_InputBuf.GetBuffer(), m_InputBuf.GetSize());
+        m_InputBuf.Clear();
+        temp_buf.AppendBlock(src_buf, src_size);
+        jpeg_src_buf = temp_buf.GetBuffer();
+        jpeg_src_size = temp_buf.GetSize();
+    } else {
+        jpeg_src_buf = src_buf;
+        jpeg_src_size = src_size;
+    }
+    CPDF_ModuleMgr::Get()->GetJpegModule()->Input(m_pContext, jpeg_src_buf, jpeg_src_size);
+    if (!m_bGotHeader) {
+        int ret = CPDF_ModuleMgr::Get()->GetJpegModule()->ReadHeader(m_pContext, &m_Width, &m_Height, &m_nComps);
+        int left_size = CPDF_ModuleMgr::Get()->GetJpegModule()->GetAvailInput(m_pContext);
+        if (ret == 1) {
+            ReportEOF(left_size);
+            return;
+        }
+        if (ret == 2) {
+            m_InputBuf.AppendBlock(jpeg_src_buf + jpeg_src_size - left_size, left_size);
+            return;
+        }
+        CPDF_ModuleMgr::Get()->GetJpegModule()->StartScanline(m_pContext, 1);
+        m_bGotHeader = TRUE;
+        m_Pitch = m_Width * m_nComps;
+    }
+    if (m_pScanline == NULL) {
+        m_pScanline = FX_Alloc(FX_BYTE, m_Pitch + 4);
+    }
+    while (1) {
+        if (!CPDF_ModuleMgr::Get()->GetJpegModule()->ReadScanline(m_pContext, m_pScanline)) {
+            int left_size = CPDF_ModuleMgr::Get()->GetJpegModule()->GetAvailInput(m_pContext);
+            m_InputBuf.AppendBlock(jpeg_src_buf + jpeg_src_size - left_size, left_size);
+            break;
+        }
+        dest_buf.AppendBlock(m_pScanline, m_Pitch);
+        m_iLine ++;
+        if (m_iLine == m_Height) {
+            ReportEOF(CPDF_ModuleMgr::Get()->GetJpegModule()->GetAvailInput(m_pContext));
+            return;
+        }
+    }
+}
+CPDF_FaxFilter::CPDF_FaxFilter()
+{
+    m_Encoding = 0;
+    m_bEndOfLine = FALSE;
+    m_bByteAlign = FALSE;
+    m_bBlack = FALSE;
+    m_nRows = 0;
+    m_nColumns = 0;
+    m_Pitch = 0;
+    m_pScanlineBuf = NULL;
+    m_pRefBuf = NULL;
+    m_iRow = 0;
+    m_InputBitPos = 0;
+}
+CPDF_FaxFilter::~CPDF_FaxFilter()
+{
+    if (m_pScanlineBuf) {
+        FX_Free(m_pScanlineBuf);
+    }
+    if (m_pRefBuf) {
+        FX_Free(m_pRefBuf);
+    }
+}
+FX_BOOL CPDF_FaxFilter::Initialize(int Encoding, int bEndOfLine, int bByteAlign, int bBlack, int nRows, int nColumns)
+{
+    m_Encoding = Encoding;
+    m_bEndOfLine = bEndOfLine;
+    m_bByteAlign = bByteAlign;
+    m_bBlack = bBlack;
+    m_nRows = nRows;
+    m_nColumns = nColumns;
+    m_Pitch = (m_nColumns + 7) / 8;
+    m_pScanlineBuf = FX_Alloc(FX_BYTE, m_Pitch);
+    m_pRefBuf = FX_Alloc(FX_BYTE, m_Pitch);
+    FXSYS_memset8(m_pScanlineBuf, 0xff, m_Pitch);
+    FXSYS_memset8(m_pRefBuf, 0xff, m_Pitch);
+    m_iRow = 0;
+    m_InputBitPos = 0;
+    return TRUE;
+}
+void CPDF_FaxFilter::v_FilterIn(FX_LPCBYTE src_buf, FX_DWORD src_size, CFX_BinaryBuf& dest_buf)
+{
+    FX_LPCBYTE fax_src_buf;
+    FX_DWORD fax_src_size;
+    CFX_BinaryBuf temp_buf;
+    int bitpos;
+    if (m_InputBuf.GetSize()) {
+        temp_buf.EstimateSize(m_InputBuf.GetSize() + src_size);
+        temp_buf.AppendBlock(m_InputBuf.GetBuffer(), m_InputBuf.GetSize());
+        m_InputBuf.Clear();
+        temp_buf.AppendBlock(src_buf, src_size);
+        fax_src_buf = temp_buf.GetBuffer();
+        fax_src_size = temp_buf.GetSize();
+        bitpos = m_InputBitPos;
+    } else {
+        fax_src_buf = src_buf;
+        fax_src_size = src_size;
+        bitpos = 0;
+    }
+    ProcessData(fax_src_buf, fax_src_size, bitpos, FALSE, dest_buf);
+    int left_bits = fax_src_size * 8 - bitpos;
+    m_InputBuf.AppendBlock(fax_src_buf + bitpos / 8, (left_bits + 7) / 8);
+    m_InputBitPos = bitpos % 8;
+}
+void CPDF_FaxFilter::v_FilterFinish(CFX_BinaryBuf& dest_buf)
+{
+    ProcessData(m_InputBuf.GetBuffer(), m_InputBuf.GetSize(), m_InputBitPos, TRUE, dest_buf);
+}
+FX_BOOL _FaxSkipEOL(const FX_BYTE* src_buf, int bitsize, int& bitpos);
+FX_BOOL _FaxG4GetRow(const FX_BYTE* src_buf, int bitsize, int& bitpos, FX_LPBYTE dest_buf, const FX_BYTE* ref_buf, int columns);
+FX_BOOL _FaxGet1DLine(const FX_BYTE* src_buf, int bitsize, int& bitpos, FX_LPBYTE dest_buf, int columns);
+void CPDF_FaxFilter::ProcessData(FX_LPCBYTE src_buf, FX_DWORD src_size, int& bitpos, FX_BOOL bFinish,
+                                 CFX_BinaryBuf& dest_buf)
+{
+    int bitsize = src_size * 8;
+    while (1) {
+        if ((bitsize < bitpos + 256) && !bFinish) {
+            return;
+        }
+        int start_bitpos = bitpos;
+        FXSYS_memset8(m_pScanlineBuf, 0xff, m_Pitch);
+        if (!ReadLine(src_buf, bitsize, bitpos)) {
+            bitpos = start_bitpos;
+            return;
+        }
+        if (m_Encoding) {
+            FXSYS_memcpy32(m_pRefBuf, m_pScanlineBuf, m_Pitch);
+        }
+        if (m_bBlack) {
+            for (int i = 0; i < m_Pitch; i ++) {
+                m_pScanlineBuf[i] = ~m_pScanlineBuf[i];
+            }
+        }
+        dest_buf.AppendBlock(m_pScanlineBuf, m_Pitch);
+        m_iRow ++;
+        if (m_iRow == m_nRows) {
+            ReportEOF(src_size - (bitpos + 7) / 8);
+            return;
+        }
+    }
+}
+FX_BOOL CPDF_FaxFilter::ReadLine(FX_LPCBYTE src_buf, int bitsize, int& bitpos)
+{
+    if (!_FaxSkipEOL(src_buf, bitsize, bitpos)) {
+        return FALSE;
+    }
+    FX_BOOL ret;
+    if (m_Encoding < 0) {
+        ret = _FaxG4GetRow(src_buf, bitsize, bitpos, m_pScanlineBuf, m_pRefBuf, m_nColumns);
+    } else if (m_Encoding == 0) {
+        ret = _FaxGet1DLine(src_buf, bitsize, bitpos, m_pScanlineBuf, m_nColumns);
+    } else {
+        if (bitpos == bitsize) {
+            return FALSE;
+        }
+        FX_BOOL bNext1D = src_buf[bitpos / 8] & (1 << (7 - bitpos % 8));
+        bitpos ++;
+        if (bNext1D) {
+            ret = _FaxGet1DLine(src_buf, bitsize, bitpos, m_pScanlineBuf, m_nColumns);
+        } else {
+            ret = _FaxG4GetRow(src_buf, bitsize, bitpos, m_pScanlineBuf, m_pRefBuf, m_nColumns);
+        }
+    }
+    if (!ret) {
+        return FALSE;
+    }
+    if (m_bEndOfLine)
+        if (!_FaxSkipEOL(src_buf, bitsize, bitpos)) {
+            return FALSE;
+        }
+    if (m_bByteAlign) {
+        bitpos = (bitpos + 7) / 8 * 8;
+    }
+    return TRUE;
+}