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