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