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