4260309380010e955c424bff7fba9b9302098e10
[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 class CCodec_FaxDecoder : public CCodec_ScanlineDecoder {
459  public:
460   CCodec_FaxDecoder();
461   virtual ~CCodec_FaxDecoder();
462   FX_BOOL Create(const uint8_t* src_buf,
463                  FX_DWORD src_size,
464                  int width,
465                  int height,
466                  int K,
467                  FX_BOOL EndOfLine,
468                  FX_BOOL EncodedByteAlign,
469                  FX_BOOL BlackIs1,
470                  int Columns,
471                  int Rows);
472   virtual void v_DownScale(int dest_width, int dest_height) {}
473   virtual FX_BOOL v_Rewind();
474   virtual uint8_t* v_GetNextLine();
475   virtual FX_DWORD GetSrcOffset();
476   int m_Encoding, m_bEndOfLine, m_bByteAlign, m_bBlack;
477   int bitpos;
478   const uint8_t* m_pSrcBuf;
479   FX_DWORD m_SrcSize;
480   uint8_t* m_pScanlineBuf;
481   uint8_t* m_pRefBuf;
482 };
483 CCodec_FaxDecoder::CCodec_FaxDecoder() {
484   m_pScanlineBuf = NULL;
485   m_pRefBuf = NULL;
486 }
487 CCodec_FaxDecoder::~CCodec_FaxDecoder() {
488   if (m_pScanlineBuf) {
489     FX_Free(m_pScanlineBuf);
490   }
491   if (m_pRefBuf) {
492     FX_Free(m_pRefBuf);
493   }
494 }
495 FX_BOOL CCodec_FaxDecoder::Create(const uint8_t* src_buf,
496                                   FX_DWORD src_size,
497                                   int width,
498                                   int height,
499                                   int K,
500                                   FX_BOOL EndOfLine,
501                                   FX_BOOL EncodedByteAlign,
502                                   FX_BOOL BlackIs1,
503                                   int Columns,
504                                   int Rows) {
505   m_Encoding = K;
506   m_bEndOfLine = EndOfLine;
507   m_bByteAlign = EncodedByteAlign;
508   m_bBlack = BlackIs1;
509   m_OrigWidth = Columns;
510   m_OrigHeight = Rows;
511   if (m_OrigWidth == 0) {
512     m_OrigWidth = width;
513   }
514   if (m_OrigHeight == 0) {
515     m_OrigHeight = height;
516   }
517   m_Pitch = (m_OrigWidth + 31) / 32 * 4;
518   m_OutputWidth = m_OrigWidth;
519   m_OutputHeight = m_OrigHeight;
520   m_pScanlineBuf = FX_Alloc(uint8_t, m_Pitch);
521   m_pRefBuf = FX_Alloc(uint8_t, m_Pitch);
522   m_pSrcBuf = src_buf;
523   m_SrcSize = src_size;
524   m_nComps = 1;
525   m_bpc = 1;
526   m_bColorTransformed = FALSE;
527   return TRUE;
528 }
529 FX_BOOL CCodec_FaxDecoder::v_Rewind() {
530   FXSYS_memset(m_pRefBuf, 0xff, m_Pitch);
531   bitpos = 0;
532   return TRUE;
533 }
534 uint8_t* CCodec_FaxDecoder::v_GetNextLine() {
535   int bitsize = m_SrcSize * 8;
536   _FaxSkipEOL(m_pSrcBuf, bitsize, bitpos);
537   if (bitpos >= bitsize) {
538     return NULL;
539   }
540   FXSYS_memset(m_pScanlineBuf, 0xff, m_Pitch);
541   if (m_Encoding < 0) {
542     _FaxG4GetRow(m_pSrcBuf, bitsize, bitpos, m_pScanlineBuf, m_pRefBuf,
543                  m_OrigWidth);
544     FXSYS_memcpy(m_pRefBuf, m_pScanlineBuf, m_Pitch);
545   } else if (m_Encoding == 0) {
546     _FaxGet1DLine(m_pSrcBuf, bitsize, bitpos, m_pScanlineBuf, m_OrigWidth);
547   } else {
548     FX_BOOL bNext1D = m_pSrcBuf[bitpos / 8] & (1 << (7 - bitpos % 8));
549     bitpos++;
550     if (bNext1D) {
551       _FaxGet1DLine(m_pSrcBuf, bitsize, bitpos, m_pScanlineBuf, m_OrigWidth);
552     } else {
553       _FaxG4GetRow(m_pSrcBuf, bitsize, bitpos, m_pScanlineBuf, m_pRefBuf,
554                    m_OrigWidth);
555     }
556     FXSYS_memcpy(m_pRefBuf, m_pScanlineBuf, m_Pitch);
557   }
558   if (m_bEndOfLine) {
559     _FaxSkipEOL(m_pSrcBuf, bitsize, bitpos);
560   }
561   if (m_bByteAlign && bitpos < bitsize) {
562     int bitpos0 = bitpos;
563     int bitpos1 = (bitpos + 7) / 8 * 8;
564     while (m_bByteAlign && bitpos0 < bitpos1) {
565       int bit = m_pSrcBuf[bitpos0 / 8] & (1 << (7 - bitpos0 % 8));
566       if (bit != 0) {
567         m_bByteAlign = FALSE;
568       } else {
569         bitpos0++;
570       }
571     }
572     if (m_bByteAlign) {
573       bitpos = bitpos1;
574     }
575   }
576   if (m_bBlack) {
577     for (int i = 0; i < m_Pitch; i++) {
578       m_pScanlineBuf[i] = ~m_pScanlineBuf[i];
579     }
580   }
581   return m_pScanlineBuf;
582 }
583 FX_DWORD CCodec_FaxDecoder::GetSrcOffset() {
584   FX_DWORD ret = (bitpos + 7) / 8;
585   if (ret > m_SrcSize) {
586     ret = m_SrcSize;
587   }
588   return ret;
589 }
590 extern "C" {
591 void _FaxG4Decode(void*,
592                   const uint8_t* src_buf,
593                   FX_DWORD src_size,
594                   int* pbitpos,
595                   uint8_t* dest_buf,
596                   int width,
597                   int height,
598                   int pitch) {
599   if (pitch == 0) {
600     pitch = (width + 7) / 8;
601   }
602   uint8_t* ref_buf = FX_Alloc(uint8_t, pitch);
603   FXSYS_memset(ref_buf, 0xff, pitch);
604   int bitpos = *pbitpos;
605   for (int iRow = 0; iRow < height; iRow++) {
606     uint8_t* line_buf = dest_buf + iRow * pitch;
607     FXSYS_memset(line_buf, 0xff, pitch);
608     _FaxG4GetRow(src_buf, src_size << 3, bitpos, line_buf, ref_buf, width);
609     FXSYS_memcpy(ref_buf, line_buf, pitch);
610   }
611   FX_Free(ref_buf);
612   *pbitpos = bitpos;
613 }
614 };
615 static const uint8_t BlackRunTerminator[128] = {
616     0x37, 10, 0x02, 3,  0x03, 2,  0x02, 2,  0x03, 3,  0x03, 4,  0x02, 4,
617     0x03, 5,  0x05, 6,  0x04, 6,  0x04, 7,  0x05, 7,  0x07, 7,  0x04, 8,
618     0x07, 8,  0x18, 9,  0x17, 10, 0x18, 10, 0x08, 10, 0x67, 11, 0x68, 11,
619     0x6c, 11, 0x37, 11, 0x28, 11, 0x17, 11, 0x18, 11, 0xca, 12, 0xcb, 12,
620     0xcc, 12, 0xcd, 12, 0x68, 12, 0x69, 12, 0x6a, 12, 0x6b, 12, 0xd2, 12,
621     0xd3, 12, 0xd4, 12, 0xd5, 12, 0xd6, 12, 0xd7, 12, 0x6c, 12, 0x6d, 12,
622     0xda, 12, 0xdb, 12, 0x54, 12, 0x55, 12, 0x56, 12, 0x57, 12, 0x64, 12,
623     0x65, 12, 0x52, 12, 0x53, 12, 0x24, 12, 0x37, 12, 0x38, 12, 0x27, 12,
624     0x28, 12, 0x58, 12, 0x59, 12, 0x2b, 12, 0x2c, 12, 0x5a, 12, 0x66, 12,
625     0x67, 12,
626 };
627 static const uint8_t BlackRunMarkup[80] = {
628     0x0f, 10, 0xc8, 12, 0xc9, 12, 0x5b, 12, 0x33, 12, 0x34, 12, 0x35, 12,
629     0x6c, 13, 0x6d, 13, 0x4a, 13, 0x4b, 13, 0x4c, 13, 0x4d, 13, 0x72, 13,
630     0x73, 13, 0x74, 13, 0x75, 13, 0x76, 13, 0x77, 13, 0x52, 13, 0x53, 13,
631     0x54, 13, 0x55, 13, 0x5a, 13, 0x5b, 13, 0x64, 13, 0x65, 13, 0x08, 11,
632     0x0c, 11, 0x0d, 11, 0x12, 12, 0x13, 12, 0x14, 12, 0x15, 12, 0x16, 12,
633     0x17, 12, 0x1c, 12, 0x1d, 12, 0x1e, 12, 0x1f, 12,
634 };
635 static const uint8_t WhiteRunTerminator[128] = {
636     0x35, 8, 0x07, 6, 0x07, 4, 0x08, 4, 0x0B, 4, 0x0C, 4, 0x0E, 4, 0x0F, 4,
637     0x13, 5, 0x14, 5, 0x07, 5, 0x08, 5, 0x08, 6, 0x03, 6, 0x34, 6, 0x35, 6,
638     0x2a, 6, 0x2B, 6, 0x27, 7, 0x0c, 7, 0x08, 7, 0x17, 7, 0x03, 7, 0x04, 7,
639     0x28, 7, 0x2B, 7, 0x13, 7, 0x24, 7, 0x18, 7, 0x02, 8, 0x03, 8, 0x1a, 8,
640     0x1b, 8, 0x12, 8, 0x13, 8, 0x14, 8, 0x15, 8, 0x16, 8, 0x17, 8, 0x28, 8,
641     0x29, 8, 0x2a, 8, 0x2b, 8, 0x2c, 8, 0x2d, 8, 0x04, 8, 0x05, 8, 0x0a, 8,
642     0x0b, 8, 0x52, 8, 0x53, 8, 0x54, 8, 0x55, 8, 0x24, 8, 0x25, 8, 0x58, 8,
643     0x59, 8, 0x5a, 8, 0x5b, 8, 0x4a, 8, 0x4b, 8, 0x32, 8, 0x33, 8, 0x34, 8,
644 };
645 static const uint8_t WhiteRunMarkup[80] = {
646     0x1b, 5,  0x12, 5,  0x17, 6,  0x37, 7,  0x36, 8,  0x37, 8,  0x64, 8,
647     0x65, 8,  0x68, 8,  0x67, 8,  0xcc, 9,  0xcd, 9,  0xd2, 9,  0xd3, 9,
648     0xd4, 9,  0xd5, 9,  0xd6, 9,  0xd7, 9,  0xd8, 9,  0xd9, 9,  0xda, 9,
649     0xdb, 9,  0x98, 9,  0x99, 9,  0x9a, 9,  0x18, 6,  0x9b, 9,  0x08, 11,
650     0x0c, 11, 0x0d, 11, 0x12, 12, 0x13, 12, 0x14, 12, 0x15, 12, 0x16, 12,
651     0x17, 12, 0x1c, 12, 0x1d, 12, 0x1e, 12, 0x1f, 12,
652 };
653 static void _AddBitStream(uint8_t* dest_buf,
654                           int& dest_bitpos,
655                           int data,
656                           int bitlen) {
657   for (int i = bitlen - 1; i >= 0; i--) {
658     if (data & (1 << i)) {
659       dest_buf[dest_bitpos / 8] |= 1 << (7 - dest_bitpos % 8);
660     }
661     dest_bitpos++;
662   }
663 }
664 static void _FaxEncodeRun(uint8_t* dest_buf,
665                           int& dest_bitpos,
666                           int run,
667                           FX_BOOL bWhite) {
668   while (run >= 2560) {
669     _AddBitStream(dest_buf, dest_bitpos, 0x1f, 12);
670     run -= 2560;
671   }
672   if (run >= 64) {
673     int markup = run - run % 64;
674     const uint8_t* p = bWhite ? WhiteRunMarkup : BlackRunMarkup;
675     p += (markup / 64 - 1) * 2;
676     _AddBitStream(dest_buf, dest_bitpos, *p, p[1]);
677   }
678   run %= 64;
679   const uint8_t* p = bWhite ? WhiteRunTerminator : BlackRunTerminator;
680   p += run * 2;
681   _AddBitStream(dest_buf, dest_bitpos, *p, p[1]);
682 }
683 static void _FaxEncode2DLine(uint8_t* dest_buf,
684                              int& dest_bitpos,
685                              const uint8_t* src_buf,
686                              const uint8_t* ref_buf,
687                              int cols) {
688   int a0 = -1, a0color = 1;
689   while (1) {
690     int a1 = _FindBit(src_buf, cols, a0 + 1, 1 - a0color);
691     int b1, b2;
692     _FaxG4FindB1B2(ref_buf, cols, a0, a0color, b1, b2);
693     if (b2 < a1) {
694       dest_bitpos += 3;
695       dest_buf[dest_bitpos / 8] |= 1 << (7 - dest_bitpos % 8);
696       dest_bitpos++;
697       a0 = b2;
698     } else if (a1 - b1 <= 3 && b1 - a1 <= 3) {
699       int delta = a1 - b1;
700       switch (delta) {
701         case 0:
702           dest_buf[dest_bitpos / 8] |= 1 << (7 - dest_bitpos % 8);
703           break;
704         case 1:
705         case 2:
706         case 3:
707           dest_bitpos += delta == 1 ? 1 : delta + 2;
708           dest_buf[dest_bitpos / 8] |= 1 << (7 - dest_bitpos % 8);
709           dest_bitpos++;
710           dest_buf[dest_bitpos / 8] |= 1 << (7 - dest_bitpos % 8);
711           break;
712         case -1:
713         case -2:
714         case -3:
715           dest_bitpos += delta == -1 ? 1 : -delta + 2;
716           dest_buf[dest_bitpos / 8] |= 1 << (7 - dest_bitpos % 8);
717           dest_bitpos++;
718           break;
719       }
720       dest_bitpos++;
721       a0 = a1;
722       a0color = 1 - a0color;
723     } else {
724       int a2 = _FindBit(src_buf, cols, a1 + 1, a0color);
725       dest_bitpos++;
726       dest_bitpos++;
727       dest_buf[dest_bitpos / 8] |= 1 << (7 - dest_bitpos % 8);
728       dest_bitpos++;
729       if (a0 < 0) {
730         a0 = 0;
731       }
732       _FaxEncodeRun(dest_buf, dest_bitpos, a1 - a0, a0color);
733       _FaxEncodeRun(dest_buf, dest_bitpos, a2 - a1, 1 - a0color);
734       a0 = a2;
735     }
736     if (a0 >= cols) {
737       return;
738     }
739   }
740 }
741 class CCodec_FaxEncoder {
742  public:
743   CCodec_FaxEncoder(const uint8_t* src_buf, int width, int height, int pitch);
744   ~CCodec_FaxEncoder();
745   void Encode(uint8_t*& dest_buf, FX_DWORD& dest_size);
746   void Encode2DLine(const uint8_t* scan_line);
747   CFX_BinaryBuf m_DestBuf;
748   uint8_t* m_pRefLine;
749   uint8_t* m_pLineBuf;
750   int m_Cols, m_Rows, m_Pitch;
751   const uint8_t* m_pSrcBuf;
752 };
753 CCodec_FaxEncoder::CCodec_FaxEncoder(const uint8_t* src_buf,
754                                      int width,
755                                      int height,
756                                      int pitch) {
757   m_pSrcBuf = src_buf;
758   m_Cols = width;
759   m_Rows = height;
760   m_Pitch = pitch;
761   m_pRefLine = FX_Alloc(uint8_t, m_Pitch);
762   FXSYS_memset(m_pRefLine, 0xff, m_Pitch);
763   m_pLineBuf = FX_Alloc2D(uint8_t, m_Pitch, 8);
764   m_DestBuf.EstimateSize(0, 10240);
765 }
766 CCodec_FaxEncoder::~CCodec_FaxEncoder() {
767   if (m_pRefLine) {
768     FX_Free(m_pRefLine);
769   }
770   if (m_pLineBuf) {
771     FX_Free(m_pLineBuf);
772   }
773 }
774 void CCodec_FaxEncoder::Encode(uint8_t*& dest_buf, FX_DWORD& dest_size) {
775   int dest_bitpos = 0;
776   uint8_t last_byte = 0;
777   for (int i = 0; i < m_Rows; i++) {
778     const uint8_t* scan_line = m_pSrcBuf + i * m_Pitch;
779     FXSYS_memset(m_pLineBuf, 0, m_Pitch * 8);
780     m_pLineBuf[0] = last_byte;
781     _FaxEncode2DLine(m_pLineBuf, dest_bitpos, scan_line, m_pRefLine, m_Cols);
782     m_DestBuf.AppendBlock(m_pLineBuf, dest_bitpos / 8);
783     last_byte = m_pLineBuf[dest_bitpos / 8];
784     dest_bitpos %= 8;
785     FXSYS_memcpy(m_pRefLine, scan_line, m_Pitch);
786   }
787   if (dest_bitpos) {
788     m_DestBuf.AppendByte(last_byte);
789   }
790   dest_buf = m_DestBuf.GetBuffer();
791   dest_size = m_DestBuf.GetSize();
792   m_DestBuf.DetachBuffer();
793 }
794 FX_BOOL CCodec_FaxModule::Encode(const uint8_t* src_buf,
795                                  int width,
796                                  int height,
797                                  int pitch,
798                                  uint8_t*& dest_buf,
799                                  FX_DWORD& dest_size) {
800   CCodec_FaxEncoder encoder(src_buf, width, height, pitch);
801   encoder.Encode(dest_buf, dest_size);
802   return TRUE;
803 }
804 ICodec_ScanlineDecoder* CCodec_FaxModule::CreateDecoder(
805     const uint8_t* src_buf,
806     FX_DWORD src_size,
807     int width,
808     int height,
809     int K,
810     FX_BOOL EndOfLine,
811     FX_BOOL EncodedByteAlign,
812     FX_BOOL BlackIs1,
813     int Columns,
814     int Rows) {
815   CCodec_FaxDecoder* pDecoder = new CCodec_FaxDecoder;
816   pDecoder->Create(src_buf, src_size, width, height, K, EndOfLine,
817                    EncodedByteAlign, BlackIs1, Columns, Rows);
818   return pDecoder;
819 }