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