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