1ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Copyright 2014 PDFium Authors. All rights reserved.
2ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Use of this source code is governed by a BSD-style license that can be
3ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// found in the LICENSE file.
4ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
5ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
7ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#include "../../fx_zlib.h"
8ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#include "../../../include/fxcodec/fx_codec.h"
9ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#include "codec_int.h"
10ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovextern "C"
11ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
12ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    static void* my_alloc_func (void* opaque, unsigned int items, unsigned int size)
13ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
14ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        return FX_Alloc(FX_BYTE, items * size);
15ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
16ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    static void   my_free_func  (void* opaque, void* address)
17ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
18ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        FX_Free(address);
19ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
20ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    void* FPDFAPI_FlateInit(void* (*alloc_func)(void*, unsigned int, unsigned int),
21ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                            void (*free_func)(void*, void*))
22ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
23ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        z_stream* p = (z_stream*)alloc_func(0, 1, sizeof(z_stream));
24ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if (p == NULL) {
25ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            return NULL;
26ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
27ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        FXSYS_memset32(p, 0, sizeof(z_stream));
28ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        p->zalloc = alloc_func;
29ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        p->zfree = free_func;
30ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        inflateInit(p);
31ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        return p;
32ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
33ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    void FPDFAPI_FlateInput(void* context, const unsigned char* src_buf, unsigned int src_size)
34ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
35ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        ((z_stream*)context)->next_in = (unsigned char*)src_buf;
36ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        ((z_stream*)context)->avail_in = src_size;
37ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
38ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    int FPDFAPI_FlateGetTotalOut(void* context)
39ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
40ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        return ((z_stream*)context)->total_out;
41ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
42ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    int FPDFAPI_FlateOutput(void* context, unsigned char* dest_buf, unsigned int dest_size)
43ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
44ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        ((z_stream*)context)->next_out = dest_buf;
45ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        ((z_stream*)context)->avail_out = dest_size;
46ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        unsigned int pre_pos = (unsigned int)FPDFAPI_FlateGetTotalOut(context);
47ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        int ret = inflate((z_stream*)context, Z_SYNC_FLUSH);
48ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        unsigned int post_pos = (unsigned int)FPDFAPI_FlateGetTotalOut(context);
49ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        unsigned int written = post_pos - pre_pos;
50ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if (written < dest_size) {
51ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            FXSYS_memset8(dest_buf + written, '\0', dest_size - written);
52ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
53ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        return ret;
54ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
55ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    int FPDFAPI_FlateGetTotalIn(void* context)
56ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
57ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        return ((z_stream*)context)->total_in;
58ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
59ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    int FPDFAPI_FlateGetAvailOut(void* context)
60ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
61ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        return ((z_stream*)context)->avail_out;
62ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
63ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    int FPDFAPI_FlateGetAvailIn(void* context)
64ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
65ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        return ((z_stream*)context)->avail_in;
66ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
67ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    void FPDFAPI_FlateEnd(void* context)
68ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
69ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        inflateEnd((z_stream*)context);
70ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        ((z_stream*)context)->zfree(0, context);
71ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
72ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    void FPDFAPI_FlateCompress(unsigned char* dest_buf, unsigned long* dest_size, const unsigned char* src_buf, unsigned long src_size)
73ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
74ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        compress(dest_buf, dest_size, src_buf, src_size);
75ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
76ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
77ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovclass CLZWDecoder : public CFX_Object
78ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
79ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovpublic:
80ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FX_BOOL Decode(FX_LPBYTE output, FX_DWORD& outlen, const FX_BYTE* input, FX_DWORD& size, FX_BOOL bEarlyChange);
81ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovprivate:
82ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FX_DWORD	m_InPos;
83ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FX_DWORD	m_OutPos;
84ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FX_LPBYTE	m_pOutput;
85ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    const FX_BYTE*	m_pInput;
86ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FX_BOOL		m_Early;
87ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    void		AddCode(FX_DWORD prefix_code, FX_BYTE append_char);
88ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FX_DWORD	m_CodeArray[5021];
89ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FX_DWORD	m_nCodes;
90ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FX_BYTE		m_DecodeStack[4000];
91ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FX_DWORD	m_StackLen;
92ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    void		DecodeString(FX_DWORD code);
93ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    int			m_CodeLen;
94ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov};
95ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovvoid CLZWDecoder::AddCode(FX_DWORD prefix_code, FX_BYTE append_char)
96ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
97ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (m_nCodes + m_Early == 4094) {
98ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        return;
99ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
100ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    m_CodeArray[m_nCodes ++] = (prefix_code << 16) | append_char;
101ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (m_nCodes + m_Early == 512 - 258) {
102ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        m_CodeLen = 10;
103ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    } else if (m_nCodes + m_Early == 1024 - 258) {
104ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        m_CodeLen = 11;
105ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    } else if (m_nCodes + m_Early == 2048 - 258) {
106ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        m_CodeLen = 12;
107ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
108ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
109ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovvoid CLZWDecoder::DecodeString(FX_DWORD code)
110ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
111ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    while (1) {
112ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        int index = code - 258;
113ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if (index < 0 || index >= (int)m_nCodes) {
114ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            break;
115ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
116ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        FX_DWORD data = m_CodeArray[index];
117ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if (m_StackLen >= sizeof(m_DecodeStack)) {
118ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            return;
119ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
120ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        m_DecodeStack[m_StackLen++] = (FX_BYTE)data;
121ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        code = data >> 16;
122ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
123ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (m_StackLen >= sizeof(m_DecodeStack)) {
124ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        return;
125ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
126ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    m_DecodeStack[m_StackLen++] = (FX_BYTE)code;
127ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
128ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovint CLZWDecoder::Decode(FX_LPBYTE dest_buf, FX_DWORD& dest_size, const FX_BYTE* src_buf, FX_DWORD& src_size, FX_BOOL bEarlyChange)
129ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
130ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    m_CodeLen = 9;
131ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    m_InPos = 0;
132ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    m_OutPos = 0;
133ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    m_pInput = src_buf;
134ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    m_pOutput = dest_buf;
135ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    m_Early = bEarlyChange ? 1 : 0;
136ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    m_nCodes = 0;
137ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FX_DWORD old_code = (FX_DWORD) - 1;
138ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FX_BYTE last_char;
139ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    while (1) {
140ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if (m_InPos + m_CodeLen > src_size * 8) {
141ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            break;
142ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
143ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        int byte_pos = m_InPos / 8;
144ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        int bit_pos = m_InPos % 8, bit_left = m_CodeLen;
145ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        FX_DWORD code = 0;
146ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if (bit_pos) {
147ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            bit_left -= 8 - bit_pos;
148ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            code = (m_pInput[byte_pos++] & ((1 << (8 - bit_pos)) - 1)) << bit_left;
149ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
150ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if (bit_left < 8) {
151ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            code |= m_pInput[byte_pos] >> (8 - bit_left);
152ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        } else {
153ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            bit_left -= 8;
154ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            code |= m_pInput[byte_pos++] << bit_left;
155ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if (bit_left) {
156ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                code |= m_pInput[byte_pos] >> (8 - bit_left);
157ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            }
158ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
159ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        m_InPos += m_CodeLen;
160ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if (code < 256) {
161ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if (m_OutPos == dest_size) {
162ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                return -5;
163ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            }
164ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if (m_pOutput) {
165ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                m_pOutput[m_OutPos] = (FX_BYTE)code;
166ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            }
167ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            m_OutPos ++;
168ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            last_char = (FX_BYTE)code;
169ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if (old_code != (FX_DWORD) - 1) {
170ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                AddCode(old_code, last_char);
171ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            }
172ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            old_code = code;
173ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        } else if (code == 256) {
174ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            m_CodeLen = 9;
175ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            m_nCodes = 0;
176ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            old_code = (FX_DWORD) - 1;
177ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        } else if (code == 257) {
178ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            break;
179ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        } else {
180ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if (old_code == (FX_DWORD) - 1) {
181ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                return 2;
182ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            }
183ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            m_StackLen = 0;
184ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if (code >= m_nCodes + 258) {
185ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                if (m_StackLen < sizeof(m_DecodeStack)) {
186ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    m_DecodeStack[m_StackLen++] = last_char;
187ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                }
188ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                DecodeString(old_code);
189ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            } else {
190ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                DecodeString(code);
191ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            }
192ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if (m_OutPos + m_StackLen > dest_size) {
193ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                return -5;
194ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            }
195ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if (m_pOutput) {
196ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                for (FX_DWORD i = 0; i < m_StackLen; i ++) {
197ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    m_pOutput[m_OutPos + i] = m_DecodeStack[m_StackLen - i - 1];
198ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                }
199ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            }
200ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            m_OutPos += m_StackLen;
201ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            last_char = m_DecodeStack[m_StackLen - 1];
202ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if (old_code < 256) {
203ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                AddCode(old_code, last_char);
204ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            } else if (old_code - 258 >= m_nCodes) {
205ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                dest_size = m_OutPos;
206ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                src_size = (m_InPos + 7) / 8;
207ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                return 0;
208ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            } else {
209ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                AddCode(old_code, last_char);
210ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            }
211ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            old_code = code;
212ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
213ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
214ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    dest_size = m_OutPos;
215ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    src_size = (m_InPos + 7) / 8;
216ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return 0;
217ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
218ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic FX_BYTE PaethPredictor(int a, int b, int c)
219ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
220ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    int p = a + b - c;
221ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    int pa = FXSYS_abs(p - a);
222ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    int pb = FXSYS_abs(p - b);
223ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    int pc = FXSYS_abs(p - c);
224ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (pa <= pb && pa <= pc) {
225ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        return (FX_BYTE)a;
226ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
227ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (pb <= pc) {
228ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        return (FX_BYTE)b;
229ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
230ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return (FX_BYTE)c;
231ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
232ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic void PNG_PredictorEncode(FX_LPBYTE& data_buf, FX_DWORD& data_size, int predictor, int Colors, int BitsPerComponent, int Columns)
233ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
234ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    int BytesPerPixel = (Colors * BitsPerComponent + 7) / 8;
235ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    int row_size = (Colors * BitsPerComponent * Columns + 7) / 8;
236ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    int row_count = (data_size + row_size - 1) / row_size;
237ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    int last_row_size = data_size % row_size;
238ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FX_LPBYTE dest_buf = FX_Alloc( FX_BYTE, (row_size + 1) * row_count);
239ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (dest_buf == NULL) {
240ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        return;
241ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
242ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    int byte_cnt = 0;
243ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FX_LPBYTE pSrcData = data_buf;
244ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FX_LPBYTE pDestData = dest_buf;
245ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    for (int row = 0; row < row_count; row++) {
246ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if (predictor == 10) {
247ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            pDestData[0] = 0;
248ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            int move_size = row_size;
249ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if (move_size * (row + 1) > (int)data_size) {
250ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                move_size = data_size - (move_size * row);
251ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            }
252ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            FXSYS_memmove32(pDestData + 1, pSrcData, move_size);
253ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            pDestData += (move_size + 1);
254ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            pSrcData += move_size;
255ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            byte_cnt += move_size;
256ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            continue;
257ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
258ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        for (int byte = 0; byte < row_size && byte_cnt < (int)data_size; byte++) {
259ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            switch (predictor) {
260ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                case 11: {
261ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                        pDestData[0] = 1;
262ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                        FX_BYTE left = 0;
263ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                        if (byte >= BytesPerPixel) {
264ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                            left = pSrcData[byte - BytesPerPixel];
265ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                        }
266ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                        pDestData[byte + 1] = pSrcData[byte] - left;
267ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    }
268ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    break;
269ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                case 12: {
270ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                        pDestData[0] = 2;
271ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                        FX_BYTE up = 0;
272ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                        if (row) {
273ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                            up = pSrcData[byte - row_size];
274ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                        }
275ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                        pDestData[byte + 1] = pSrcData[byte] - up;
276ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    }
277ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    break;
278ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                case 13: {
279ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                        pDestData[0] = 3;
280ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                        FX_BYTE left = 0;
281ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                        if (byte >= BytesPerPixel) {
282ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                            left = pSrcData[byte - BytesPerPixel];
283ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                        }
284ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                        FX_BYTE up = 0;
285ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                        if (row) {
286ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                            up = pSrcData[byte - row_size];
287ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                        }
288ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                        pDestData[byte + 1] = pSrcData[byte] - (left + up) / 2;
289ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    }
290ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    break;
291ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                case 14: {
292ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                        pDestData[0] = 4;
293ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                        FX_BYTE left = 0;
294ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                        if (byte >= BytesPerPixel) {
295ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                            left = pSrcData[byte - BytesPerPixel];
296ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                        }
297ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                        FX_BYTE up = 0;
298ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                        if (row) {
299ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                            up = pSrcData[byte - row_size];
300ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                        }
301ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                        FX_BYTE upper_left = 0;
302ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                        if (byte >= BytesPerPixel && row) {
303ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                            upper_left = pSrcData[byte - row_size - BytesPerPixel];
304ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                        }
305ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                        pDestData[byte + 1] = pSrcData[byte] - PaethPredictor(left, up, upper_left);
306ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    }
307ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    break;
308ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                default: {
309ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                        pDestData[byte + 1] = pSrcData[byte];
310ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    }
311ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    break;
312ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            }
313ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            byte_cnt++;
314ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
315ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        pDestData += (row_size + 1);
316ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        pSrcData += row_size;
317ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
318ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FX_Free(data_buf);
319ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    data_buf = dest_buf;
320ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    data_size = (row_size + 1) * row_count - (last_row_size > 0 ? (row_size - last_row_size) : 0);
321ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
322ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic void PNG_PredictLine(FX_LPBYTE pDestData, FX_LPCBYTE pSrcData, FX_LPCBYTE pLastLine,
323ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                            int bpc, int nColors, int nPixels)
324ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
325ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    int row_size = (nPixels * bpc * nColors + 7) / 8;
326ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    int BytesPerPixel = (bpc * nColors + 7) / 8;
327ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FX_BYTE tag = pSrcData[0];
328ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (tag == 0) {
329ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        FXSYS_memmove32(pDestData, pSrcData + 1, row_size);
330ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        return;
331ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
332ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    for (int byte = 0; byte < row_size; byte ++) {
333ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        FX_BYTE raw_byte = pSrcData[byte + 1];
334ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        switch (tag) {
335ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            case 1:	{
336ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    FX_BYTE left = 0;
337ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    if (byte >= BytesPerPixel) {
338ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                        left = pDestData[byte - BytesPerPixel];
339ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    }
340ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    pDestData[byte] = raw_byte + left;
341ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    break;
342ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                }
343ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            case 2: {
344ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    FX_BYTE up = 0;
345ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    if (pLastLine) {
346ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                        up = pLastLine[byte];
347ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    }
348ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    pDestData[byte] = raw_byte + up;
349ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    break;
350ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                }
351ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            case 3: {
352ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    FX_BYTE left = 0;
353ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    if (byte >= BytesPerPixel) {
354ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                        left = pDestData[byte - BytesPerPixel];
355ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    }
356ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    FX_BYTE up = 0;
357ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    if (pLastLine) {
358ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                        up = pLastLine[byte];
359ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    }
360ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    pDestData[byte] = raw_byte + (up + left) / 2;
361ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    break;
362ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                }
363ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            case 4: {
364ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    FX_BYTE left = 0;
365ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    if (byte >= BytesPerPixel) {
366ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                        left = pDestData[byte - BytesPerPixel];
367ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    }
368ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    FX_BYTE up = 0;
369ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    if (pLastLine) {
370ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                        up = pLastLine[byte];
371ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    }
372ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    FX_BYTE upper_left = 0;
373ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    if (byte >= BytesPerPixel && pLastLine) {
374ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                        upper_left = pLastLine[byte - BytesPerPixel];
375ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    }
376ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    pDestData[byte] = raw_byte + PaethPredictor(left, up, upper_left);
377ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    break;
378ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                }
379ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            default:
380ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                pDestData[byte] = raw_byte;
381ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                break;
382ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
383ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
384ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
385ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic void PNG_Predictor(FX_LPBYTE& data_buf, FX_DWORD& data_size,
386ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                          int Colors, int BitsPerComponent, int Columns)
387ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
388ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    int BytesPerPixel = (Colors * BitsPerComponent + 7) / 8;
389ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    int row_size = (Colors * BitsPerComponent * Columns + 7) / 8;
390ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    int row_count = (data_size + row_size) / (row_size + 1);
391ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    int last_row_size = data_size % (row_size + 1);
392ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FX_LPBYTE dest_buf = FX_Alloc( FX_BYTE, row_size * row_count);
393ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (dest_buf == NULL) {
394ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        return;
395ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
396ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    int byte_cnt = 0;
397ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FX_LPBYTE pSrcData = data_buf;
398ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FX_LPBYTE pDestData = dest_buf;
399ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    for (int row = 0; row < row_count; row ++) {
400ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        FX_BYTE tag = pSrcData[0];
401ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if (tag == 0) {
402ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            int move_size = row_size;
403ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if ((row + 1) * (move_size + 1) > (int)data_size) {
404ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                move_size = last_row_size - 1;
405ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            }
406ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            FXSYS_memmove32(pDestData, pSrcData + 1, move_size);
407ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            pSrcData += move_size + 1;
408ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            pDestData += move_size;
409ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            byte_cnt += move_size + 1;
410ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            continue;
411ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
412ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        for (int byte = 0; byte < row_size && byte_cnt < (int)data_size; byte ++) {
413ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            FX_BYTE raw_byte = pSrcData[byte + 1];
414ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            switch (tag) {
415ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                case 1:	{
416ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                        FX_BYTE left = 0;
417ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                        if (byte >= BytesPerPixel) {
418ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                            left = pDestData[byte - BytesPerPixel];
419ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                        }
420ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                        pDestData[byte] = raw_byte + left;
421ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                        break;
422ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    }
423ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                case 2: {
424ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                        FX_BYTE up = 0;
425ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                        if (row) {
426ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                            up = pDestData[byte - row_size];
427ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                        }
428ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                        pDestData[byte] = raw_byte + up;
429ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                        break;
430ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    }
431ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                case 3: {
432ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                        FX_BYTE left = 0;
433ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                        if (byte >= BytesPerPixel) {
434ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                            left = pDestData[byte - BytesPerPixel];
435ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                        }
436ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                        FX_BYTE up = 0;
437ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                        if (row) {
438ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                            up = pDestData[byte - row_size];
439ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                        }
440ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                        pDestData[byte] = raw_byte + (up + left) / 2;
441ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                        break;
442ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    }
443ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                case 4: {
444ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                        FX_BYTE left = 0;
445ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                        if (byte >= BytesPerPixel) {
446ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                            left = pDestData[byte - BytesPerPixel];
447ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                        }
448ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                        FX_BYTE up = 0;
449ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                        if (row) {
450ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                            up = pDestData[byte - row_size];
451ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                        }
452ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                        FX_BYTE upper_left = 0;
453ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                        if (byte >= BytesPerPixel && row) {
454ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                            upper_left = pDestData[byte - row_size - BytesPerPixel];
455ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                        }
456ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                        pDestData[byte] = raw_byte + PaethPredictor(left, up, upper_left);
457ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                        break;
458ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    }
459ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                default:
460ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    pDestData[byte] = raw_byte;
461ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    break;
462ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            }
463ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            byte_cnt++;
464ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
465ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        pSrcData += row_size + 1;
466ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        pDestData += row_size;
467ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        byte_cnt++;
468ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
469ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FX_Free(data_buf);
470ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    data_buf = dest_buf;
471ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    data_size = row_size * row_count - (last_row_size > 0 ? (row_size + 1 - last_row_size) : 0);
472ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
473ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic void TIFF_PredictorEncodeLine(FX_LPBYTE dest_buf, int row_size, int BitsPerComponent, int Colors, int Columns)
474ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
475ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    int BytesPerPixel = BitsPerComponent * Colors / 8;
476ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (BitsPerComponent < 8) {
477ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        FX_BYTE mask = 0x01;
478ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if (BitsPerComponent == 2) {
479ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            mask = 0x03;
480ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        } else if (BitsPerComponent == 4) {
481ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            mask = 0x0F;
482ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
483ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        int row_bits = Colors * BitsPerComponent * Columns;
484ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        for (int i = row_bits - BitsPerComponent; i >= BitsPerComponent; i -= BitsPerComponent) {
485ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            int col = i % 8;
486ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            int index = i / 8;
487ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            int col_pre = (col == 0) ? (8 - BitsPerComponent) : (col - BitsPerComponent);
488ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            int index_pre = (col == 0) ? (index - 1) : index;
489ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            FX_BYTE cur = (dest_buf[index] >> (8 - col - BitsPerComponent)) & mask;
490ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            FX_BYTE left = (dest_buf[index_pre] >> (8 - col_pre - BitsPerComponent)) & mask;
491ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            cur -= left;
492ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            cur &= mask;
493ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            cur <<= (8 - col - BitsPerComponent);
494ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            dest_buf[index] &= ~(mask << ((8 - col - BitsPerComponent)));
495ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            dest_buf[index] |= cur;
496ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
497ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    } else if (BitsPerComponent == 8) {
498ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        for (int i = row_size - 1; i >= BytesPerPixel; i--) {
499ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            dest_buf[i] -= dest_buf[i - BytesPerPixel];
500ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
501ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    } else {
502ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        for (int i = row_size - BytesPerPixel; i >= BytesPerPixel; i -= BytesPerPixel) {
503ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            FX_WORD pixel = (dest_buf[i] << 8) | dest_buf[i + 1];
504ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            pixel -= (dest_buf[i - BytesPerPixel] << 8) | dest_buf[i - BytesPerPixel + 1];
505ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            dest_buf[i] = pixel >> 8;
506ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            dest_buf[i + 1] = (FX_BYTE)pixel;
507ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
508ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
509ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
510ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic void TIFF_PredictorEncode(FX_LPBYTE& data_buf, FX_DWORD& data_size,
511ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                 int Colors, int BitsPerComponent, int Columns)
512ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
513ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    int row_size = (Colors * BitsPerComponent * Columns + 7) / 8;
514ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    int row_count = (data_size + row_size - 1) / row_size;
515ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    int last_row_size = data_size % row_size;
516ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    for (int row = 0; row < row_count; row++) {
517ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        FX_LPBYTE scan_line = data_buf + row * row_size;
518ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if ((row + 1) * row_size > (int)data_size) {
519ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            row_size = last_row_size;
520ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
521ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        TIFF_PredictorEncodeLine(scan_line, row_size, BitsPerComponent, Colors, Columns);
522ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
523ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
524ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic void TIFF_PredictLine(FX_LPBYTE dest_buf, int row_size, int BitsPerComponent, int Colors, int Columns)
525ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
526ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (BitsPerComponent == 1) {
527ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        int row_bits = BitsPerComponent * Colors * Columns;
528ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        for(int i = 1; i < row_bits; i ++) {
529ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            int col = i % 8;
530ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            int index = i / 8;
531ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            int index_pre = (col == 0) ? (index - 1) : index;
532ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            int col_pre = (col == 0) ? 8 : col;
533ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if( ((dest_buf[index] >> (7 - col)) & 1) ^ ((dest_buf[index_pre] >> (8 - col_pre)) & 1) ) {
534ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                dest_buf[index] |= 1 << (7 - col);
535ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            } else {
536ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                dest_buf[index] &= ~(1 << (7 - col));
537ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            }
538ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
539ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        return;
540ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
541ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    int BytesPerPixel = BitsPerComponent * Colors / 8;
542ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (BitsPerComponent == 16) {
543ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        for (int i = BytesPerPixel; i < row_size; i += 2) {
544ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            FX_WORD pixel = (dest_buf[i - BytesPerPixel] << 8) | dest_buf[i - BytesPerPixel + 1];
545ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            pixel += (dest_buf[i] << 8) | dest_buf[i + 1];
546ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            dest_buf[i] = pixel >> 8;
547ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            dest_buf[i + 1] = (FX_BYTE)pixel;
548ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
549ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    } else {
550ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        for (int i = BytesPerPixel; i < row_size; i ++) {
551ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            dest_buf[i] += dest_buf[i - BytesPerPixel];
552ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
553ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
554ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
555ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic void TIFF_Predictor(FX_LPBYTE& data_buf, FX_DWORD& data_size,
556ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                           int Colors, int BitsPerComponent, int Columns)
557ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
558ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    int row_size = (Colors * BitsPerComponent * Columns + 7) / 8;
559ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    int row_count = (data_size + row_size - 1) / row_size;
560ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    int last_row_size = data_size % row_size;
561ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    for (int row = 0; row < row_count; row ++) {
562ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        FX_LPBYTE scan_line = data_buf + row * row_size;
563ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if ((row + 1) * row_size > (int)data_size) {
564ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            row_size = last_row_size;
565ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
566ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        TIFF_PredictLine(scan_line, row_size, BitsPerComponent, Colors, Columns);
567ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
568ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
569ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovclass CCodec_FlateScanlineDecoder : public CCodec_ScanlineDecoder
570ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
571ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovpublic:
572ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    CCodec_FlateScanlineDecoder();
573ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    ~CCodec_FlateScanlineDecoder();
574ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FX_BOOL		Create(FX_LPCBYTE src_buf, FX_DWORD src_size, int width, int height, int nComps, int bpc,
575ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                       int predictor, int Colors, int BitsPerComponent, int Columns);
576ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    virtual void		Destroy()
577ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
578ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        delete this;
579ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
580ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    virtual void		v_DownScale(int dest_width, int dest_height) {}
581ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    virtual FX_BOOL		v_Rewind();
582ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    virtual FX_LPBYTE	v_GetNextLine();
583ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    virtual FX_DWORD	GetSrcOffset();
584ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    void*				m_pFlate;
585ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FX_LPCBYTE			m_SrcBuf;
586ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FX_DWORD			m_SrcSize;
587ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FX_LPBYTE			m_pScanline;
588ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FX_LPBYTE			m_pLastLine;
589ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FX_LPBYTE			m_pPredictBuffer;
590ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FX_LPBYTE			m_pPredictRaw;
591ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    int					m_Predictor;
592ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    int					m_Colors, m_BitsPerComponent, m_Columns, m_PredictPitch, m_LeftOver;
593ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov};
594ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovCCodec_FlateScanlineDecoder::CCodec_FlateScanlineDecoder()
595ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
596ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    m_pFlate = NULL;
597ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    m_pScanline = NULL;
598ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    m_pLastLine = NULL;
599ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    m_pPredictBuffer = NULL;
600ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    m_pPredictRaw = NULL;
601ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    m_LeftOver = 0;
602ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
603ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovCCodec_FlateScanlineDecoder::~CCodec_FlateScanlineDecoder()
604ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
605ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (m_pScanline) {
606ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        FX_Free(m_pScanline);
607ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
608ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (m_pLastLine) {
609ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        FX_Free(m_pLastLine);
610ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
611ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (m_pPredictBuffer) {
612ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        FX_Free(m_pPredictBuffer);
613ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
614ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (m_pPredictRaw) {
615ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        FX_Free(m_pPredictRaw);
616ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
617ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (m_pFlate) {
618ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        FPDFAPI_FlateEnd(m_pFlate);
619ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
620ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
621ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovFX_BOOL CCodec_FlateScanlineDecoder::Create(FX_LPCBYTE src_buf, FX_DWORD src_size, int width, int height,
622ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        int nComps, int bpc, int predictor, int Colors, int BitsPerComponent, int Columns)
623ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
624ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    m_SrcBuf = src_buf;
625ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    m_SrcSize = src_size;
626ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    m_OutputWidth = m_OrigWidth = width;
627ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    m_OutputHeight = m_OrigHeight = height;
628ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    m_nComps = nComps;
629ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    m_bpc = bpc;
630ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    m_bColorTransformed = FALSE;
631ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    m_Pitch = (width * nComps * bpc + 7) / 8;
632ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    m_pScanline = FX_Alloc(FX_BYTE, m_Pitch);
633ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (m_pScanline == NULL) {
634ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        return FALSE;
635ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
636ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    m_Predictor = 0;
637ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (predictor) {
638ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if (predictor >= 10) {
639ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            m_Predictor = 2;
640ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        } else if (predictor == 2) {
641ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            m_Predictor = 1;
642ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
643ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if (m_Predictor) {
644ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if (BitsPerComponent * Colors * Columns == 0) {
645ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                BitsPerComponent = m_bpc;
646ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                Colors = m_nComps;
647ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                Columns = m_OrigWidth;
648ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            }
649ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            m_Colors = Colors;
650ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            m_BitsPerComponent = BitsPerComponent;
651ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            m_Columns = Columns;
652ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            m_PredictPitch = (m_BitsPerComponent * m_Colors * m_Columns + 7) / 8;
653ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            m_pLastLine = FX_Alloc(FX_BYTE, m_PredictPitch);
654ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if (m_pLastLine == NULL) {
655ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                return FALSE;
656ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            }
657ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            FXSYS_memset32(m_pLastLine, 0, m_PredictPitch);
658ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            m_pPredictRaw = FX_Alloc(FX_BYTE, m_PredictPitch + 1);
659ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if (m_pPredictRaw == NULL) {
660ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                return FALSE;
661ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            }
662ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            m_pPredictBuffer = FX_Alloc(FX_BYTE, m_PredictPitch);
663ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if (m_pPredictBuffer == NULL) {
664ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                return FALSE;
665ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            }
666ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
667ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
668ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return TRUE;
669ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
670ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovFX_BOOL CCodec_FlateScanlineDecoder::v_Rewind()
671ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
672ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (m_pFlate) {
673ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        FPDFAPI_FlateEnd(m_pFlate);
674ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
675ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    m_pFlate = FPDFAPI_FlateInit(my_alloc_func, my_free_func);
676ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (m_pFlate == NULL) {
677ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        return FALSE;
678ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
679ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FPDFAPI_FlateInput(m_pFlate, m_SrcBuf, m_SrcSize);
680ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    m_LeftOver = 0;
681ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return TRUE;
682ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
683ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovFX_LPBYTE CCodec_FlateScanlineDecoder::v_GetNextLine()
684ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
685ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (m_Predictor) {
686ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if (m_Pitch == m_PredictPitch) {
687ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if (m_Predictor == 2) {
688ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                FPDFAPI_FlateOutput(m_pFlate, m_pPredictRaw, m_PredictPitch + 1);
689ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                PNG_PredictLine(m_pScanline, m_pPredictRaw, m_pLastLine, m_BitsPerComponent, m_Colors, m_Columns);
690ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                FXSYS_memcpy32(m_pLastLine, m_pScanline, m_PredictPitch);
691ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            } else {
692ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                FPDFAPI_FlateOutput(m_pFlate, m_pScanline, m_Pitch);
693ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                TIFF_PredictLine(m_pScanline, m_PredictPitch, m_bpc, m_nComps, m_OutputWidth);
694ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            }
695ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        } else {
696ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            int bytes_to_go = m_Pitch;
697ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            int read_leftover = m_LeftOver > bytes_to_go ? bytes_to_go : m_LeftOver;
698ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if (read_leftover) {
699ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                FXSYS_memcpy32(m_pScanline, m_pPredictBuffer + m_PredictPitch - m_LeftOver, read_leftover);
700ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                m_LeftOver -= read_leftover;
701ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                bytes_to_go -= read_leftover;
702ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            }
703ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            while (bytes_to_go) {
704ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                if (m_Predictor == 2) {
705ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    FPDFAPI_FlateOutput(m_pFlate, m_pPredictRaw, m_PredictPitch + 1);
706ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    PNG_PredictLine(m_pPredictBuffer, m_pPredictRaw, m_pLastLine, m_BitsPerComponent, m_Colors, m_Columns);
707ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    FXSYS_memcpy32(m_pLastLine, m_pPredictBuffer, m_PredictPitch);
708ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                } else {
709ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    FPDFAPI_FlateOutput(m_pFlate, m_pPredictBuffer, m_PredictPitch);
710ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    TIFF_PredictLine(m_pPredictBuffer, m_PredictPitch, m_BitsPerComponent, m_Colors, m_Columns);
711ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                }
712ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                int read_bytes = m_PredictPitch > bytes_to_go ? bytes_to_go : m_PredictPitch;
713ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                FXSYS_memcpy32(m_pScanline + m_Pitch - bytes_to_go, m_pPredictBuffer, read_bytes);
714ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                m_LeftOver += m_PredictPitch - read_bytes;
715ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                bytes_to_go -= read_bytes;
716ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            }
717ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
718ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    } else {
719ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        FPDFAPI_FlateOutput(m_pFlate, m_pScanline, m_Pitch);
720ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
721ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return m_pScanline;
722ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
723ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovFX_DWORD CCodec_FlateScanlineDecoder::GetSrcOffset()
724ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
725ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return FPDFAPI_FlateGetTotalIn(m_pFlate);
726ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
727ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganovstatic void FlateUncompress(FX_LPCBYTE src_buf, FX_DWORD src_size, FX_DWORD orig_size,
728ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                            FX_LPBYTE& dest_buf, FX_DWORD& dest_size, FX_DWORD& offset)
729ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
730ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FX_DWORD guess_size = orig_size ? orig_size : src_size * 2;
731ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FX_DWORD alloc_step = orig_size ? 10240 : (src_size < 10240 ? 10240 : src_size);
732ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    static const FX_DWORD kMaxInitialAllocSize = 10000000;
733ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (guess_size > kMaxInitialAllocSize) {
734ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        guess_size = kMaxInitialAllocSize;
735ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        alloc_step = kMaxInitialAllocSize;
736ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
737ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FX_LPBYTE guess_buf = FX_Alloc(FX_BYTE, guess_size + 1);
738ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (!guess_buf) {
739ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        dest_buf = NULL;
740ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        dest_size = 0;
741ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        return;
742ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
743ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    guess_buf[guess_size] = '\0';
744ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FX_BOOL useOldImpl = src_size < 10240;
745ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    void* context = FPDFAPI_FlateInit(my_alloc_func, my_free_func);
746ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (context == NULL) {
747ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        dest_buf = NULL;
748ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        dest_size = 0;
749ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        return ;
750ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
751ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FPDFAPI_FlateInput(context, src_buf, src_size);
752ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    CFX_ArrayTemplate<FX_LPBYTE> result_tmp_bufs;
753ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FX_LPBYTE buf = guess_buf;
754ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FX_DWORD buf_size = guess_size;
755ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FX_DWORD last_buf_size = buf_size;
756ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    while (1) {
757ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        FX_INT32 ret = FPDFAPI_FlateOutput(context, buf, buf_size);
758ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        FX_INT32 avail_buf_size = FPDFAPI_FlateGetAvailOut(context);
759ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if (!useOldImpl) {
760ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if (ret != Z_OK) {
761ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                last_buf_size = buf_size - avail_buf_size;
762ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                result_tmp_bufs.Add(buf);
763ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                break;
764ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            }
765ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if (avail_buf_size == 0) {
766ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                result_tmp_bufs.Add(buf);
767ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                buf = NULL;
768ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                buf = FX_Alloc(FX_BYTE, buf_size + 1);
769ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                if (!buf) {
770ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    dest_buf = NULL;
771ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    dest_size = 0;
772ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    return;
773ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                }
774ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                buf[buf_size] = '\0';
775ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            } else {
776ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                last_buf_size = buf_size - avail_buf_size;
777ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                result_tmp_bufs.Add(buf);
778ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                buf = NULL;
779ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                break;
780ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            }
781ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        } else {
782ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if (ret != Z_OK) {
783ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                break;
784ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            }
785ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if (avail_buf_size == 0) {
786ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                FX_DWORD old_size = guess_size;
787ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                guess_size += alloc_step;
788ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                if (guess_size < old_size || guess_size + 1 < guess_size) {
789ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    dest_buf = NULL;
790ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    dest_size = 0;
791ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    return;
792ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                }
793ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                guess_buf = FX_Realloc(FX_BYTE, guess_buf, guess_size + 1);
794ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                if (!guess_buf) {
795ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    dest_buf = NULL;
796ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    dest_size = 0;
797ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    return;
798ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                }
799ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                guess_buf[guess_size] = '\0';
800ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                buf = guess_buf + old_size;
801ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                buf_size = guess_size - old_size;
802ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            } else {
803ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                break;
804ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            }
805ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
806ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
807ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    dest_size = FPDFAPI_FlateGetTotalOut(context);
808ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    offset = FPDFAPI_FlateGetTotalIn(context);
809ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (!useOldImpl) {
810ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if (result_tmp_bufs.GetSize() == 1) {
811ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            dest_buf = result_tmp_bufs[0];
812ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        } else {
813ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            FX_LPBYTE result_buf = FX_Alloc(FX_BYTE, dest_size);
814ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if (!result_buf) {
815ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                dest_buf = NULL;
816ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                dest_size = 0;
817ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                return;
818ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            }
819ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            FX_DWORD result_pos = 0;
820ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            for (FX_INT32 i = 0; i < result_tmp_bufs.GetSize(); i++) {
821ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                FX_LPBYTE tmp_buf = result_tmp_bufs[i];
822ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                FX_DWORD tmp_buf_size = buf_size;
823ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                if (i == result_tmp_bufs.GetSize() - 1) {
824ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    tmp_buf_size = last_buf_size;
825ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                }
826ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                FXSYS_memcpy32(result_buf + result_pos, tmp_buf, tmp_buf_size);
827ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                result_pos += tmp_buf_size;
828ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                FX_Free(tmp_buf);
829ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                tmp_buf = NULL;
830ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                result_tmp_bufs[i] = NULL;
831ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            }
832ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            dest_buf = result_buf;
833ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
834ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    } else {
835ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if (guess_size / 2 > dest_size) {
836ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            guess_buf = FX_Realloc(FX_BYTE, guess_buf, dest_size + 1);
837ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            if (!guess_buf) {
838ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                dest_buf = NULL;
839ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                dest_size = 0;
840ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                return;
841ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            }
842ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            guess_size = dest_size;
843ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            guess_buf[guess_size] = '\0';
844ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
845ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        dest_buf = guess_buf;
846ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
847ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FPDFAPI_FlateEnd(context);
848ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    context = NULL;
849ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
850ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovICodec_ScanlineDecoder*	CCodec_FlateModule::CreateDecoder(FX_LPCBYTE src_buf, FX_DWORD src_size, int width, int height,
851ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        int nComps, int bpc, int predictor, int Colors, int BitsPerComponent, int Columns)
852ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
853ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    CCodec_FlateScanlineDecoder* pDecoder = FX_NEW CCodec_FlateScanlineDecoder;
854ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (pDecoder == NULL) {
855ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        return NULL;
856ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
857ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    pDecoder->Create(src_buf, src_size, width, height, nComps, bpc, predictor, Colors, BitsPerComponent, Columns);
858ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return pDecoder;
859ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
860ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovFX_DWORD CCodec_FlateModule::FlateOrLZWDecode(FX_BOOL bLZW, const FX_BYTE* src_buf, FX_DWORD src_size, FX_BOOL bEarlyChange,
861ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        int predictor, int Colors, int BitsPerComponent, int Columns,
862ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        FX_DWORD estimated_size, FX_LPBYTE& dest_buf, FX_DWORD& dest_size)
863ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
864ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    CLZWDecoder* pDecoder = NULL;
865ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    dest_buf = NULL;
866ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FX_DWORD offset = 0;
867ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    int predictor_type = 0;
868ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (predictor) {
869ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if (predictor >= 10) {
870ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            predictor_type = 2;
871ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        } else if (predictor == 2) {
872ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            predictor_type = 1;
873ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
874ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
875ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (bLZW) {
876ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        pDecoder = FX_NEW CLZWDecoder;
877ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if (pDecoder == NULL) {
878ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            return -1;
879ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
880ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        dest_size = (FX_DWORD) - 1;
881ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        offset = src_size;
882ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        int err = pDecoder->Decode(NULL, dest_size, src_buf, offset, bEarlyChange);
883ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        delete pDecoder;
884ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if (err || dest_size == 0 || dest_size + 1 < dest_size) {
885ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            return (FX_DWORD) - 1;
886ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
887ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        pDecoder = FX_NEW CLZWDecoder;
888ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if (pDecoder == NULL) {
889ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            return -1;
890ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
891ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        dest_buf = FX_Alloc( FX_BYTE, dest_size + 1);
892ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if (dest_buf == NULL) {
893ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            return -1;
894ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
895ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        dest_buf[dest_size] = '\0';
896ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        pDecoder->Decode(dest_buf, dest_size, src_buf, offset, bEarlyChange);
897ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        delete pDecoder;
898ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    } else {
899ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        FlateUncompress(src_buf, src_size, estimated_size, dest_buf, dest_size, offset);
900ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
901ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (predictor_type == 0) {
902ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        return offset;
903ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
904ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (predictor_type == 2) {
905ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        PNG_Predictor(dest_buf, dest_size, Colors, BitsPerComponent, Columns);
906ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    } else if (predictor_type == 1) {
907ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        TIFF_Predictor(dest_buf, dest_size, Colors, BitsPerComponent, Columns);
908ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
909ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return offset;
910ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
911ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovFX_BOOL CCodec_FlateModule::Encode(const FX_BYTE* src_buf, FX_DWORD src_size,
912ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                   int predictor, int Colors, int BitsPerComponent, int Columns,
913ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                                   FX_LPBYTE& dest_buf, FX_DWORD& dest_size)
914ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
915ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (predictor != 2 && predictor < 10) {
916ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        return Encode(src_buf, src_size, dest_buf, dest_size);
917ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
918ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FX_BOOL ret = FALSE;
919ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FX_LPBYTE pSrcBuf = NULL;
920ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    pSrcBuf = FX_Alloc(FX_BYTE, src_size);
921ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (pSrcBuf == NULL) {
922ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        return FALSE;
923ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
924ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FXSYS_memcpy32(pSrcBuf, src_buf, src_size);
925ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (predictor == 2) {
926ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        TIFF_PredictorEncode(pSrcBuf, src_size, Colors, BitsPerComponent, Columns);
927ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    } else if (predictor >= 10) {
928ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        PNG_PredictorEncode(pSrcBuf, src_size, predictor, Colors, BitsPerComponent, Columns);
929ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
930ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    ret = Encode(pSrcBuf, src_size, dest_buf, dest_size);
931ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FX_Free(pSrcBuf);
932ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return ret;
933ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
934ee451cb395940862dad63c85adfe8f2fd55e864cSvet GanovFX_BOOL CCodec_FlateModule::Encode(FX_LPCBYTE src_buf, FX_DWORD src_size, FX_LPBYTE& dest_buf, FX_DWORD& dest_size)
935ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov{
936ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    dest_size = src_size + src_size / 1000 + 12;
937ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    dest_buf = FX_Alloc( FX_BYTE, dest_size);
938ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if (dest_buf == NULL) {
939ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        return FALSE;
940ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
941ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    unsigned long temp_size = dest_size;
942ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FPDFAPI_FlateCompress(dest_buf, &temp_size, src_buf, src_size);
943ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    dest_size = (FX_DWORD)temp_size;
944ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return TRUE;
945ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov}
946