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