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