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