1// Copyright 2014 PDFium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6
7#include "../../../include/fxcodec/fx_codec.h"
8#include "codec_int.h"
9extern const FX_BYTE OneLeadPos[256];
10extern const FX_BYTE ZeroLeadPos[256];
11int _FindBit(const FX_BYTE* data_buf, int max_pos, int start_pos, int bit)
12{
13    if (start_pos >= max_pos) {
14        return max_pos;
15    }
16    FX_LPCBYTE leading_pos = bit ? OneLeadPos : ZeroLeadPos;
17    if (start_pos % 8) {
18        FX_BYTE data = data_buf[start_pos / 8];
19        if (bit) {
20            data &= 0xff >> (start_pos % 8);
21        } else {
22            data |= 0xff << (8 - start_pos % 8);
23        }
24        if (leading_pos[data] < 8) {
25            return start_pos / 8 * 8 + leading_pos[data];
26        }
27        start_pos += 7;
28    }
29    FX_BYTE skip = bit ? 0x00 : 0xff;
30    int byte_pos = start_pos / 8;
31    int max_byte = (max_pos + 7) / 8;
32    while (byte_pos < max_byte) {
33        if (data_buf[byte_pos] != skip) {
34            break;
35        }
36        byte_pos ++;
37    }
38    if (byte_pos == max_byte) {
39        return max_pos;
40    }
41    int pos = leading_pos[data_buf[byte_pos]] + byte_pos * 8;
42    if (pos > max_pos) {
43        pos = max_pos;
44    }
45    return pos;
46}
47void _FaxG4FindB1B2(const FX_BYTE* ref_buf, int columns, int a0, FX_BOOL a0color, int& b1, int& b2)
48{
49    if (a0color) {
50        a0color = 1;
51    }
52    FX_BYTE first_bit = (a0 < 0) ? 1 : ((ref_buf[a0 / 8] & (1 << (7 - a0 % 8))) != 0);
53    b1 = _FindBit(ref_buf, columns, a0 + 1, !first_bit);
54    if (b1 >= columns) {
55        b1 = b2 = columns;
56        return;
57    }
58    if (first_bit == !a0color) {
59        b1 = _FindBit(ref_buf, columns, b1 + 1, first_bit);
60        first_bit = !first_bit;
61    }
62    if (b1 >= columns) {
63        b1 = b2 = columns;
64        return;
65    }
66    b2 = _FindBit(ref_buf, columns, b1 + 1, first_bit);
67}
68void _FaxFillBits(FX_LPBYTE dest_buf, int columns, int startpos, int endpos)
69{
70    if (startpos < 0) {
71        startpos = 0;
72    }
73    if (endpos < 0) {
74        endpos = 0;
75    }
76    if (endpos >= columns) {
77        endpos = columns;
78    }
79    if (startpos >= endpos) {
80        return;
81    }
82    int first_byte = startpos / 8;
83    int last_byte = (endpos - 1) / 8;
84    if (first_byte == last_byte) {
85        for (int i = startpos % 8; i <= (endpos - 1) % 8; i ++) {
86            dest_buf[first_byte] -= 1 << (7 - i);
87        }
88        return;
89    }
90    int i;
91    for (i = startpos % 8; i < 8; i ++) {
92        dest_buf[first_byte] -= 1 << (7 - i);
93    }
94    for (i = 0; i <= (endpos - 1) % 8; i ++) {
95        dest_buf[last_byte] -= 1 << (7 - i);
96    }
97    if (last_byte > first_byte + 1) {
98        FXSYS_memset32(dest_buf + first_byte + 1, 0, last_byte - first_byte - 1);
99    }
100}
101#define NEXTBIT src_buf[bitpos/8] & (1 << (7-bitpos%8)); bitpos ++;
102#define ADDBIT(code, bit) code = code << 1; if (bit) code ++;
103#define GETBIT(bitpos) src_buf[bitpos/8] & (1 << (7-bitpos%8))
104static const FX_BYTE FaxBlackRunIns[] = {
105    0,
106    2,
107    0x02, 3, 0,
108    0x03, 2, 0,
109    2,
110    0x02, 1, 0,
111    0x03, 4, 0,
112    2,
113    0x02, 6, 0,
114    0x03, 5, 0,
115    1,
116    0x03, 7, 0,
117    2,
118    0x04, 9, 0,
119    0x05, 8, 0,
120    3,
121    0x04, 10, 0,
122    0x05, 11, 0,
123    0x07, 12, 0,
124    2,
125    0x04, 13, 0,
126    0x07, 14, 0,
127    1,
128    0x18, 15, 0,
129    5,
130    0x08, 18, 0,
131    0x0f, 64, 0,
132    0x17, 16, 0,
133    0x18, 17, 0,
134    0x37, 0, 0,
135    10,
136    0x08, 0x00, 0x07,
137    0x0c, 0x40, 0x07,
138    0x0d, 0x80, 0x07,
139    0x17, 24, 0,
140    0x18, 25, 0,
141    0x28, 23, 0,
142    0x37, 22, 0,
143    0x67, 19, 0,
144    0x68, 20, 0,
145    0x6c, 21, 0,
146    54,
147    0x12, 1984 % 256, 1984 / 256,
148    0x13, 2048 % 256, 2048 / 256,
149    0x14, 2112 % 256, 2112 / 256,
150    0x15, 2176 % 256, 2176 / 256,
151    0x16, 2240 % 256, 2240 / 256,
152    0x17, 2304 % 256, 2304 / 256,
153    0x1c, 2368 % 256, 2368 / 256,
154    0x1d, 2432 % 256, 2432 / 256,
155    0x1e, 2496 % 256, 2496 / 256,
156    0x1f, 2560 % 256, 2560 / 256,
157    0x24, 52, 0,
158    0x27, 55, 0,
159    0x28, 56, 0,
160    0x2b, 59, 0,
161    0x2c, 60, 0,
162    0x33, 320 % 256, 320 / 256,
163    0x34, 384 % 256, 384 / 256,
164    0x35, 448 % 256, 448 / 256,
165    0x37, 53, 0,
166    0x38, 54, 0,
167    0x52, 50, 0,
168    0x53, 51, 0,
169    0x54, 44, 0,
170    0x55, 45, 0,
171    0x56, 46, 0,
172    0x57, 47, 0,
173    0x58, 57, 0,
174    0x59, 58, 0,
175    0x5a, 61, 0,
176    0x5b, 256 % 256, 256 / 256,
177    0x64, 48, 0,
178    0x65, 49, 0,
179    0x66, 62, 0,
180    0x67, 63, 0,
181    0x68, 30, 0,
182    0x69, 31, 0,
183    0x6a, 32, 0,
184    0x6b, 33, 0,
185    0x6c, 40, 0,
186    0x6d, 41, 0,
187    0xc8, 128, 0,
188    0xc9, 192, 0,
189    0xca, 26, 0,
190    0xcb, 27, 0,
191    0xcc, 28, 0,
192    0xcd, 29, 0,
193    0xd2, 34, 0,
194    0xd3, 35, 0,
195    0xd4, 36, 0,
196    0xd5, 37, 0,
197    0xd6, 38, 0,
198    0xd7, 39, 0,
199    0xda, 42, 0,
200    0xdb, 43, 0,
201    20,
202    0x4a, 640 % 256, 640 / 256,
203    0x4b, 704 % 256, 704 / 256,
204    0x4c, 768 % 256, 768 / 256,
205    0x4d, 832 % 256, 832 / 256,
206    0x52, 1280 % 256, 1280 / 256,
207    0x53, 1344 % 256, 1344 / 256,
208    0x54, 1408 % 256, 1408 / 256,
209    0x55, 1472 % 256, 1472 / 256,
210    0x5a, 1536 % 256, 1536 / 256,
211    0x5b, 1600 % 256, 1600 / 256,
212    0x64, 1664 % 256, 1664 / 256,
213    0x65, 1728 % 256, 1728 / 256,
214    0x6c, 512 % 256, 512 / 256,
215    0x6d, 576 % 256, 576 / 256,
216    0x72, 896 % 256, 896 / 256,
217    0x73, 960 % 256, 960 / 256,
218    0x74, 1024 % 256, 1024 / 256,
219    0x75, 1088 % 256, 1088 / 256,
220    0x76, 1152 % 256, 1152 / 256,
221    0x77, 1216 % 256, 1216 / 256,
222    0xff
223};
224static const FX_BYTE FaxWhiteRunIns[] = {
225    0,
226    0,
227    0,
228    6,
229    0x07, 2, 0,
230    0x08, 3, 0,
231    0x0B, 4, 0,
232    0x0C, 5, 0,
233    0x0E, 6, 0,
234    0x0F, 7, 0,
235    6,
236    0x07, 10, 0,
237    0x08, 11, 0,
238    0x12, 128, 0,
239    0x13, 8, 0,
240    0x14, 9, 0,
241    0x1b, 64, 0,
242    9,
243    0x03, 13, 0,
244    0x07, 1, 0,
245    0x08, 12, 0,
246    0x17, 192, 0,
247    0x18, 1664 % 256, 1664 / 256,
248    0x2a, 16, 0,
249    0x2B, 17, 0,
250    0x34, 14, 0,
251    0x35, 15, 0,
252    12,
253    0x03, 22, 0,
254    0x04, 23, 0,
255    0x08, 20, 0,
256    0x0c, 19, 0,
257    0x13, 26, 0,
258    0x17, 21, 0,
259    0x18, 28, 0,
260    0x24, 27, 0,
261    0x27, 18, 0,
262    0x28, 24, 0,
263    0x2B, 25, 0,
264    0x37, 256 % 256, 256 / 256,
265    42,
266    0x02, 29, 0,
267    0x03, 30, 0,
268    0x04, 45, 0,
269    0x05, 46, 0,
270    0x0a, 47, 0,
271    0x0b, 48, 0,
272    0x12, 33, 0,
273    0x13, 34, 0,
274    0x14, 35, 0,
275    0x15, 36, 0,
276    0x16, 37, 0,
277    0x17, 38, 0,
278    0x1a, 31, 0,
279    0x1b, 32, 0,
280    0x24, 53, 0,
281    0x25, 54, 0,
282    0x28, 39, 0,
283    0x29, 40, 0,
284    0x2a, 41, 0,
285    0x2b, 42, 0,
286    0x2c, 43, 0,
287    0x2d, 44, 0,
288    0x32, 61, 0,
289    0x33, 62, 0,
290    0x34, 63, 0,
291    0x35, 0, 0,
292    0x36, 320 % 256, 320 / 256,
293    0x37, 384 % 256, 384 / 256,
294    0x4a, 59, 0,
295    0x4b, 60, 0,
296    0x52, 49, 0,
297    0x53, 50, 0,
298    0x54, 51, 0,
299    0x55, 52, 0,
300    0x58, 55, 0,
301    0x59, 56, 0,
302    0x5a, 57, 0,
303    0x5b, 58, 0,
304    0x64, 448 % 256, 448 / 256,
305    0x65, 512 % 256, 512 / 256,
306    0x67, 640 % 256, 640 / 256,
307    0x68, 576 % 256, 576 / 256,
308    16,
309    0x98, 1472 % 256, 1472 / 256,
310    0x99, 1536 % 256, 1536 / 256,
311    0x9a, 1600 % 256, 1600 / 256,
312    0x9b, 1728 % 256, 1728 / 256,
313    0xcc, 704 % 256, 704 / 256,
314    0xcd, 768 % 256, 768 / 256,
315    0xd2, 832 % 256, 832 / 256,
316    0xd3, 896 % 256, 896 / 256,
317    0xd4, 960 % 256, 960 / 256,
318    0xd5, 1024 % 256, 1024 / 256,
319    0xd6, 1088 % 256, 1088 / 256,
320    0xd7, 1152 % 256, 1152 / 256,
321    0xd8, 1216 % 256, 1216 / 256,
322    0xd9, 1280 % 256, 1280 / 256,
323    0xda, 1344 % 256, 1344 / 256,
324    0xdb, 1408 % 256, 1408 / 256,
325    0,
326    3,
327    0x08, 1792 % 256, 1792 / 256,
328    0x0c, 1856 % 256, 1856 / 256,
329    0x0d, 1920 % 256, 1920 / 256,
330    10,
331    0x12, 1984 % 256, 1984 / 256,
332    0x13, 2048 % 256, 2048 / 256,
333    0x14, 2112 % 256, 2112 / 256,
334    0x15, 2176 % 256, 2176 / 256,
335    0x16, 2240 % 256, 2240 / 256,
336    0x17, 2304 % 256, 2304 / 256,
337    0x1c, 2368 % 256, 2368 / 256,
338    0x1d, 2432 % 256, 2432 / 256,
339    0x1e, 2496 % 256, 2496 / 256,
340    0x1f, 2560 % 256, 2560 / 256,
341    0xff,
342};
343int _FaxGetRun(FX_LPCBYTE ins_array, const FX_BYTE* src_buf, int& bitpos, int bitsize)
344{
345    FX_DWORD code = 0;
346    int ins_off = 0;
347    while (1) {
348        FX_BYTE ins = ins_array[ins_off++];
349        if (ins == 0xff) {
350            return -1;
351        }
352        if (bitpos >= bitsize) {
353            return -1;
354        }
355        code <<= 1;
356        if (src_buf[bitpos / 8] & (1 << (7 - bitpos % 8))) {
357            code ++;
358        }
359        bitpos ++;
360        int next_off = ins_off + ins * 3;
361        for (; ins_off < next_off; ins_off += 3) {
362            if (ins_array[ins_off] == code) {
363                return ins_array[ins_off + 1] + ins_array[ins_off + 2] * 256;
364            }
365        }
366    }
367}
368FX_BOOL _FaxG4GetRow(const FX_BYTE* src_buf, int bitsize, int& bitpos, FX_LPBYTE dest_buf, const FX_BYTE* ref_buf, int columns)
369{
370    int a0 = -1, a0color = 1;
371    while (1) {
372        if (bitpos >= bitsize) {
373            return FALSE;
374        }
375        int a1, a2, b1, b2;
376        _FaxG4FindB1B2(ref_buf, columns, a0, a0color, b1, b2);
377        FX_BOOL bit = NEXTBIT;
378        int v_delta = 0;
379        if (bit) {
380        } else {
381            if (bitpos >= bitsize) {
382                return FALSE;
383            }
384            FX_BOOL bit1 = NEXTBIT;
385            if (bitpos >= bitsize) {
386                return FALSE;
387            }
388            FX_BOOL bit2 = NEXTBIT;
389            if (bit1 && bit2) {
390                v_delta = 1;
391            } else if (bit1) {
392                v_delta = -1;
393            } else if (bit2) {
394                int run_len1 = 0;
395                while (1) {
396                    int run = _FaxGetRun(a0color ? FaxWhiteRunIns : FaxBlackRunIns, src_buf, bitpos, bitsize);
397                    run_len1 += run;
398                    if (run < 64) {
399                        break;
400                    }
401                }
402                if (a0 < 0) {
403                    run_len1 ++;
404                }
405                a1 = a0 + run_len1;
406                if (!a0color) {
407                    _FaxFillBits(dest_buf, columns, a0, a1);
408                }
409                int run_len2 = 0;
410                while (1) {
411                    int run = _FaxGetRun(a0color ? FaxBlackRunIns : FaxWhiteRunIns, src_buf, bitpos, bitsize);
412                    run_len2 += run;
413                    if (run < 64) {
414                        break;
415                    }
416                }
417                a2 = a1 + run_len2;
418                if (a0color) {
419                    _FaxFillBits(dest_buf, columns, a1, a2);
420                }
421                a0 = a2;
422                if (a0 < columns) {
423                    continue;
424                }
425                return TRUE;
426            } else {
427                if (bitpos >= bitsize) {
428                    return FALSE;
429                }
430                bit = NEXTBIT;
431                if (bit) {
432                    if (!a0color) {
433                        _FaxFillBits(dest_buf, columns, a0, b2);
434                    }
435                    if (b2 >= columns) {
436                        return TRUE;
437                    }
438                    a0 = b2;
439                    continue;
440                } else {
441                    if (bitpos >= bitsize) {
442                        return FALSE;
443                    }
444                    FX_BOOL bit1 = NEXTBIT;
445                    if (bitpos >= bitsize) {
446                        return FALSE;
447                    }
448                    FX_BOOL bit2 = NEXTBIT;
449                    if (bit1 && bit2) {
450                        v_delta = 2;
451                    } else if (bit1) {
452                        v_delta = -2;
453                    } else if (bit2) {
454                        if (bitpos >= bitsize) {
455                            return FALSE;
456                        }
457                        bit = NEXTBIT;
458                        if (bit) {
459                            v_delta = 3;
460                        } else {
461                            v_delta = -3;
462                        }
463                    } else {
464                        if (bitpos >= bitsize) {
465                            return FALSE;
466                        }
467                        bit = NEXTBIT;
468                        if (bit) {
469                            bitpos += 3;
470                            continue;
471                        } else {
472                            bitpos += 5;
473                            return TRUE;
474                        }
475                    }
476                }
477            }
478        }
479        a1 = b1 + v_delta;
480        if (!a0color) {
481            _FaxFillBits(dest_buf, columns, a0, a1);
482        }
483        if (a1 >= columns) {
484            return TRUE;
485        }
486        a0 = a1;
487        a0color = !a0color;
488    }
489}
490FX_BOOL _FaxSkipEOL(const FX_BYTE* src_buf, int bitsize, int& bitpos)
491{
492    int startbit = bitpos;
493    while (bitpos < bitsize) {
494        int bit = NEXTBIT;
495        if (bit) {
496            if (bitpos - startbit <= 11) {
497                bitpos = startbit;
498            }
499            return TRUE;
500        }
501    }
502    return FALSE;
503}
504FX_BOOL _FaxGet1DLine(const FX_BYTE* src_buf, int bitsize, int& bitpos, FX_LPBYTE dest_buf, int columns)
505{
506    int color = TRUE;
507    int startpos = 0;
508    while (1) {
509        if (bitpos >= bitsize) {
510            return FALSE;
511        }
512        int run_len = 0;
513        while (1) {
514            int run = _FaxGetRun(color ? FaxWhiteRunIns : FaxBlackRunIns, src_buf, bitpos, bitsize);
515            if (run < 0) {
516                while (bitpos < bitsize) {
517                    int bit = NEXTBIT;
518                    if (bit) {
519                        return TRUE;
520                    }
521                }
522                return FALSE;
523            }
524            run_len += run;
525            if (run < 64) {
526                break;
527            }
528        }
529        if (!color) {
530            _FaxFillBits(dest_buf, columns, startpos, startpos + run_len);
531        }
532        startpos += run_len;
533        if (startpos >= columns) {
534            break;
535        }
536        color = !color;
537    }
538    return TRUE;
539}
540class CCodec_FaxDecoder : public CCodec_ScanlineDecoder
541{
542public:
543    CCodec_FaxDecoder();
544    virtual ~CCodec_FaxDecoder();
545    FX_BOOL				Create(FX_LPCBYTE src_buf, FX_DWORD src_size, int width, int height,
546                               int K, FX_BOOL EndOfLine, FX_BOOL EncodedByteAlign, FX_BOOL BlackIs1, int Columns, int Rows);
547    virtual void		v_DownScale(int dest_width, int dest_height) {}
548    virtual FX_BOOL		v_Rewind();
549    virtual FX_LPBYTE	v_GetNextLine();
550    virtual FX_DWORD	GetSrcOffset();
551    int			m_Encoding, m_bEndOfLine, m_bByteAlign, m_bBlack;
552    int			bitpos;
553    FX_LPCBYTE	m_pSrcBuf;
554    FX_DWORD	m_SrcSize;
555    FX_LPBYTE	m_pScanlineBuf, m_pRefBuf;
556};
557CCodec_FaxDecoder::CCodec_FaxDecoder()
558{
559    m_pScanlineBuf = NULL;
560    m_pRefBuf = NULL;
561}
562CCodec_FaxDecoder::~CCodec_FaxDecoder()
563{
564    if (m_pScanlineBuf) {
565        FX_Free(m_pScanlineBuf);
566    }
567    if (m_pRefBuf) {
568        FX_Free(m_pRefBuf);
569    }
570}
571FX_BOOL CCodec_FaxDecoder::Create(FX_LPCBYTE src_buf, FX_DWORD src_size, int width, int height,
572                                  int K, FX_BOOL EndOfLine, FX_BOOL EncodedByteAlign, FX_BOOL BlackIs1, int Columns, int Rows)
573{
574    m_Encoding = K;
575    m_bEndOfLine = EndOfLine;
576    m_bByteAlign = EncodedByteAlign;
577    m_bBlack = BlackIs1;
578    m_OrigWidth = Columns;
579    m_OrigHeight = Rows;
580    if (m_OrigWidth == 0) {
581        m_OrigWidth = width;
582    }
583    if (m_OrigHeight == 0) {
584        m_OrigHeight = height;
585    }
586    m_Pitch = (m_OrigWidth + 31) / 32 * 4;
587    m_OutputWidth = m_OrigWidth;
588    m_OutputHeight = m_OrigHeight;
589    m_pScanlineBuf = FX_Alloc(FX_BYTE, m_Pitch);
590    if (m_pScanlineBuf == NULL) {
591        return FALSE;
592    }
593    m_pRefBuf = FX_Alloc(FX_BYTE, m_Pitch);
594    if (m_pRefBuf == NULL) {
595        return FALSE;
596    }
597    m_pSrcBuf = src_buf;
598    m_SrcSize = src_size;
599    m_nComps = 1;
600    m_bpc = 1;
601    m_bColorTransformed = FALSE;
602    return TRUE;
603}
604FX_BOOL CCodec_FaxDecoder::v_Rewind()
605{
606    FXSYS_memset8(m_pRefBuf, 0xff, m_Pitch);
607    bitpos = 0;
608    return TRUE;
609}
610FX_LPBYTE CCodec_FaxDecoder::v_GetNextLine()
611{
612    int bitsize = m_SrcSize * 8;
613    _FaxSkipEOL(m_pSrcBuf, bitsize, bitpos);
614    if (bitpos >= bitsize) {
615        return NULL;
616    }
617    FXSYS_memset8(m_pScanlineBuf, 0xff, m_Pitch);
618    if (m_Encoding < 0) {
619        _FaxG4GetRow(m_pSrcBuf, bitsize, bitpos, m_pScanlineBuf, m_pRefBuf, m_OrigWidth);
620        FXSYS_memcpy32(m_pRefBuf, m_pScanlineBuf, m_Pitch);
621    } else if (m_Encoding == 0) {
622        _FaxGet1DLine(m_pSrcBuf, bitsize, bitpos, m_pScanlineBuf, m_OrigWidth);
623    } else {
624        FX_BOOL bNext1D = m_pSrcBuf[bitpos / 8] & (1 << (7 - bitpos % 8));
625        bitpos ++;
626        if (bNext1D) {
627            _FaxGet1DLine(m_pSrcBuf, bitsize, bitpos, m_pScanlineBuf, m_OrigWidth);
628        } else {
629            _FaxG4GetRow(m_pSrcBuf, bitsize, bitpos, m_pScanlineBuf, m_pRefBuf, m_OrigWidth);
630        }
631        FXSYS_memcpy32(m_pRefBuf, m_pScanlineBuf, m_Pitch);
632    }
633    if (m_bEndOfLine) {
634        _FaxSkipEOL(m_pSrcBuf, bitsize, bitpos);
635    }
636    if (m_bByteAlign && bitpos < bitsize) {
637        int bitpos0 = bitpos;
638        int bitpos1 = (bitpos + 7) / 8 * 8;
639        while (m_bByteAlign && bitpos0 < bitpos1) {
640            int bit = m_pSrcBuf[bitpos0 / 8] & (1 << (7 - bitpos0 % 8));
641            if (bit != 0) {
642                m_bByteAlign = FALSE;
643            } else {
644                bitpos0 ++;
645            }
646        }
647        if (m_bByteAlign) {
648            bitpos = bitpos1;
649        }
650    }
651    if (m_bBlack) {
652        for (int i = 0; i < m_Pitch; i ++) {
653            m_pScanlineBuf[i] = ~m_pScanlineBuf[i];
654        }
655    }
656    return m_pScanlineBuf;
657}
658FX_DWORD CCodec_FaxDecoder::GetSrcOffset()
659{
660    FX_DWORD ret = (bitpos + 7) / 8;
661    if (ret > m_SrcSize) {
662        ret = m_SrcSize;
663    }
664    return ret;
665}
666extern "C" {
667    void _FaxG4Decode(void*, FX_LPCBYTE src_buf, FX_DWORD src_size, int* pbitpos, FX_LPBYTE dest_buf, int width, int height, int pitch)
668    {
669        if (pitch == 0) {
670            pitch = (width + 7) / 8;
671        }
672        FX_LPBYTE ref_buf = FX_Alloc(FX_BYTE, pitch);
673        if (ref_buf == NULL) {
674            return;
675        }
676        FXSYS_memset8(ref_buf, 0xff, pitch);
677        int bitpos = *pbitpos;
678        for (int iRow = 0; iRow < height; iRow ++) {
679            FX_LPBYTE line_buf = dest_buf + iRow * pitch;
680            FXSYS_memset8(line_buf, 0xff, pitch);
681            _FaxG4GetRow(src_buf, src_size << 3, bitpos, line_buf, ref_buf, width);
682            FXSYS_memcpy32(ref_buf, line_buf, pitch);
683        }
684        FX_Free(ref_buf);
685        *pbitpos = bitpos;
686    }
687};
688static const FX_BYTE BlackRunTerminator[128] = {
689    0x37, 10, 0x02, 3, 0x03, 2, 0x02, 2, 0x03, 3, 0x03, 4, 0x02, 4, 0x03, 5,
690    0x05, 6, 0x04, 6, 0x04, 7, 0x05, 7, 0x07, 7, 0x04, 8, 0x07, 8, 0x18, 9,
691    0x17, 10, 0x18, 10, 0x08, 10, 0x67, 11, 0x68, 11, 0x6c, 11, 0x37, 11, 0x28, 11,
692    0x17, 11, 0x18, 11, 0xca, 12, 0xcb, 12, 0xcc, 12, 0xcd, 12, 0x68, 12, 0x69, 12,
693    0x6a, 12, 0x6b, 12, 0xd2, 12, 0xd3, 12, 0xd4, 12, 0xd5, 12, 0xd6, 12, 0xd7, 12,
694    0x6c, 12, 0x6d, 12, 0xda, 12, 0xdb, 12, 0x54, 12, 0x55, 12, 0x56, 12, 0x57, 12,
695    0x64, 12, 0x65, 12, 0x52, 12, 0x53, 12, 0x24, 12, 0x37, 12, 0x38, 12, 0x27, 12,
696    0x28, 12, 0x58, 12, 0x59, 12, 0x2b, 12, 0x2c, 12, 0x5a, 12, 0x66, 12, 0x67, 12,
697};
698static const FX_BYTE BlackRunMarkup[80] = {
699    0x0f, 10, 0xc8, 12, 0xc9, 12, 0x5b, 12, 0x33, 12, 0x34, 12, 0x35, 12, 0x6c, 13,
700    0x6d, 13, 0x4a, 13, 0x4b, 13, 0x4c, 13, 0x4d, 13, 0x72, 13, 0x73, 13, 0x74, 13,
701    0x75, 13, 0x76, 13, 0x77, 13, 0x52, 13, 0x53, 13, 0x54, 13, 0x55, 13, 0x5a, 13,
702    0x5b, 13, 0x64, 13, 0x65, 13, 0x08, 11, 0x0c, 11, 0x0d, 11, 0x12, 12, 0x13, 12,
703    0x14, 12, 0x15, 12, 0x16, 12, 0x17, 12, 0x1c, 12, 0x1d, 12, 0x1e, 12, 0x1f, 12,
704};
705static const FX_BYTE WhiteRunTerminator[128] = {
706    0x35, 8,
707    0x07, 6,
708    0x07, 4,
709    0x08, 4,
710    0x0B, 4,
711    0x0C, 4,
712    0x0E, 4,
713    0x0F, 4,
714    0x13, 5,
715    0x14, 5,
716    0x07, 5,
717    0x08, 5,
718    0x08, 6,
719    0x03, 6,
720    0x34, 6,
721    0x35, 6,
722    0x2a, 6,
723    0x2B, 6,
724    0x27, 7,
725    0x0c, 7,
726    0x08, 7,
727    0x17, 7,
728    0x03, 7,
729    0x04, 7,
730    0x28, 7,
731    0x2B, 7,
732    0x13, 7,
733    0x24, 7,
734    0x18, 7,
735    0x02, 8,
736    0x03, 8,
737    0x1a, 8,
738    0x1b, 8,
739    0x12, 8,
740    0x13, 8,
741    0x14, 8,
742    0x15, 8,
743    0x16, 8,
744    0x17, 8,
745    0x28, 8,
746    0x29, 8,
747    0x2a, 8,
748    0x2b, 8,
749    0x2c, 8,
750    0x2d, 8,
751    0x04, 8,
752    0x05, 8,
753    0x0a, 8,
754    0x0b, 8,
755    0x52, 8,
756    0x53, 8,
757    0x54, 8,
758    0x55, 8,
759    0x24, 8,
760    0x25, 8,
761    0x58, 8,
762    0x59, 8,
763    0x5a, 8,
764    0x5b, 8,
765    0x4a, 8,
766    0x4b, 8,
767    0x32, 8,
768    0x33, 8,
769    0x34, 8,
770};
771static const FX_BYTE WhiteRunMarkup[80] = {
772    0x1b, 5,
773    0x12, 5,
774    0x17, 6,
775    0x37, 7,
776    0x36, 8,
777    0x37, 8,
778    0x64, 8,
779    0x65, 8,
780    0x68, 8,
781    0x67, 8,
782    0xcc, 9,
783    0xcd, 9,
784    0xd2, 9,
785    0xd3, 9,
786    0xd4, 9,
787    0xd5, 9,
788    0xd6, 9,
789    0xd7, 9,
790    0xd8, 9,
791    0xd9, 9,
792    0xda, 9,
793    0xdb, 9,
794    0x98, 9,
795    0x99, 9,
796    0x9a, 9,
797    0x18, 6,
798    0x9b, 9,
799    0x08, 11,
800    0x0c, 11,
801    0x0d, 11,
802    0x12, 12,
803    0x13, 12,
804    0x14, 12,
805    0x15, 12,
806    0x16, 12,
807    0x17, 12,
808    0x1c, 12,
809    0x1d, 12,
810    0x1e, 12,
811    0x1f, 12,
812};
813static void _AddBitStream(FX_LPBYTE dest_buf, int& dest_bitpos, int data, int bitlen)
814{
815    for (int i = bitlen - 1; i >= 0; i --) {
816        if (data & (1 << i)) {
817            dest_buf[dest_bitpos / 8] |= 1 << (7 - dest_bitpos % 8);
818        }
819        dest_bitpos ++;
820    }
821}
822static void _FaxEncodeRun(FX_LPBYTE dest_buf, int& dest_bitpos, int run, FX_BOOL bWhite)
823{
824    while (run >= 2560) {
825        _AddBitStream(dest_buf, dest_bitpos, 0x1f, 12);
826        run -= 2560;
827    }
828    if (run >= 64) {
829        int markup = run - run % 64;
830        FX_LPCBYTE p = bWhite ? WhiteRunMarkup : BlackRunMarkup;
831        p += (markup / 64 - 1) * 2;
832        _AddBitStream(dest_buf, dest_bitpos, *p, p[1]);
833    }
834    run %= 64;
835    FX_LPCBYTE p = bWhite ? WhiteRunTerminator : BlackRunTerminator;
836    p += run * 2;
837    _AddBitStream(dest_buf, dest_bitpos, *p, p[1]);
838}
839static void _FaxEncode2DLine(FX_LPBYTE dest_buf, int& dest_bitpos, FX_LPCBYTE src_buf, FX_LPCBYTE ref_buf, int cols)
840{
841    int a0 = -1, a0color = 1;
842    while (1) {
843        int a1 = _FindBit(src_buf, cols, a0 + 1, 1 - a0color);
844        int b1, b2;
845        _FaxG4FindB1B2(ref_buf, cols, a0, a0color, b1, b2);
846        if (b2 < a1) {
847            dest_bitpos += 3;
848            dest_buf[dest_bitpos / 8] |= 1 << (7 - dest_bitpos % 8);
849            dest_bitpos ++;
850            a0 = b2;
851        } else if (a1 - b1 <= 3 && b1 - a1 <= 3) {
852            int delta = a1 - b1;
853            switch (delta) {
854                case 0:
855                    dest_buf[dest_bitpos / 8] |= 1 << (7 - dest_bitpos % 8);
856                    break;
857                case 1:
858                case 2:
859                case 3:
860                    dest_bitpos += delta == 1 ? 1 : delta + 2;
861                    dest_buf[dest_bitpos / 8] |= 1 << (7 - dest_bitpos % 8);
862                    dest_bitpos ++;
863                    dest_buf[dest_bitpos / 8] |= 1 << (7 - dest_bitpos % 8);
864                    break;
865                case -1:
866                case -2:
867                case -3:
868                    dest_bitpos += delta == -1 ? 1 : -delta + 2;
869                    dest_buf[dest_bitpos / 8] |= 1 << (7 - dest_bitpos % 8);
870                    dest_bitpos ++;
871                    break;
872            }
873            dest_bitpos ++;
874            a0 = a1;
875            a0color = 1 - a0color;
876        } else {
877            int a2 = _FindBit(src_buf, cols, a1 + 1, a0color);
878            dest_bitpos ++;
879            dest_bitpos ++;
880            dest_buf[dest_bitpos / 8] |= 1 << (7 - dest_bitpos % 8);
881            dest_bitpos ++;
882            if (a0 < 0) {
883                a0 = 0;
884            }
885            _FaxEncodeRun(dest_buf, dest_bitpos, a1 - a0, a0color);
886            _FaxEncodeRun(dest_buf, dest_bitpos, a2 - a1, 1 - a0color);
887            a0 = a2;
888        }
889        if (a0 >= cols) {
890            return;
891        }
892    }
893}
894class CCodec_FaxEncoder : public CFX_Object
895{
896public:
897    CCodec_FaxEncoder(FX_LPCBYTE src_buf, int width, int height, int pitch);
898    ~CCodec_FaxEncoder();
899    void			Encode(FX_LPBYTE& dest_buf, FX_DWORD& dest_size);
900    void			Encode2DLine(FX_LPCBYTE scan_line);
901    CFX_BinaryBuf	m_DestBuf;
902    FX_LPBYTE		m_pRefLine, m_pLineBuf;
903    int				m_Cols, m_Rows, m_Pitch;
904    FX_LPCBYTE		m_pSrcBuf;
905};
906CCodec_FaxEncoder::CCodec_FaxEncoder(FX_LPCBYTE src_buf, int width, int height, int pitch)
907{
908    m_pSrcBuf = src_buf;
909    m_Cols = width;
910    m_Rows = height;
911    m_Pitch = pitch;
912    m_pRefLine = FX_Alloc(FX_BYTE, m_Pitch);
913    if (m_pRefLine == NULL) {
914        return;
915    }
916    FXSYS_memset8(m_pRefLine, 0xff, m_Pitch);
917    m_pLineBuf = FX_Alloc(FX_BYTE, m_Pitch * 8);
918    if (m_pLineBuf == NULL) {
919        return;
920    }
921    m_DestBuf.EstimateSize(0, 10240);
922}
923CCodec_FaxEncoder::~CCodec_FaxEncoder()
924{
925    if (m_pRefLine) {
926        FX_Free(m_pRefLine);
927    }
928    if (m_pLineBuf) {
929        FX_Free(m_pLineBuf);
930    }
931}
932void CCodec_FaxEncoder::Encode(FX_LPBYTE& dest_buf, FX_DWORD& dest_size)
933{
934    int dest_bitpos = 0;
935    FX_BYTE last_byte = 0;
936    for (int i = 0; i < m_Rows; i ++) {
937        FX_LPCBYTE scan_line = m_pSrcBuf + i * m_Pitch;
938        FXSYS_memset32(m_pLineBuf, 0, m_Pitch * 8);
939        m_pLineBuf[0] = last_byte;
940        _FaxEncode2DLine(m_pLineBuf, dest_bitpos, scan_line, m_pRefLine, m_Cols);
941        m_DestBuf.AppendBlock(m_pLineBuf, dest_bitpos / 8);
942        last_byte = m_pLineBuf[dest_bitpos / 8];
943        dest_bitpos %= 8;
944        FXSYS_memcpy32(m_pRefLine, scan_line, m_Pitch);
945    }
946    if (dest_bitpos) {
947        m_DestBuf.AppendByte(last_byte);
948    }
949    dest_buf = m_DestBuf.GetBuffer();
950    dest_size = m_DestBuf.GetSize();
951    m_DestBuf.DetachBuffer();
952}
953FX_BOOL	CCodec_FaxModule::Encode(FX_LPCBYTE src_buf, int width, int height, int pitch, FX_LPBYTE& dest_buf, FX_DWORD& dest_size)
954{
955    CCodec_FaxEncoder encoder(src_buf, width, height, pitch);
956    encoder.Encode(dest_buf, dest_size);
957    return TRUE;
958}
959ICodec_ScanlineDecoder*	CCodec_FaxModule::CreateDecoder(FX_LPCBYTE src_buf, FX_DWORD src_size, int width, int height,
960        int K, FX_BOOL EndOfLine, FX_BOOL EncodedByteAlign, FX_BOOL BlackIs1, int Columns, int Rows)
961{
962    CCodec_FaxDecoder* pDecoder = FX_NEW CCodec_FaxDecoder;
963    if (pDecoder == NULL) {
964        return NULL;
965    }
966    pDecoder->Create(src_buf, src_size, width, height, K, EndOfLine, EncodedByteAlign, BlackIs1, Columns, Rows);
967    return pDecoder;
968}
969