1 // Copyright 2014 PDFium Authors. All rights reserved.
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/flate/flatemodule.h"
8
9 #include <algorithm>
10 #include <limits>
11 #include <memory>
12 #include <utility>
13 #include <vector>
14
15 #include "core/fxcodec/fx_codec.h"
16 #include "core/fxcodec/scanlinedecoder.h"
17 #include "core/fxcrt/fx_extension.h"
18 #include "core/fxcrt/fx_memory_wrappers.h"
19 #include "third_party/base/numerics/safe_conversions.h"
20 #include "third_party/base/ptr_util.h"
21 #include "third_party/base/span.h"
22
23 #if defined(USE_SYSTEM_ZLIB)
24 #include <zlib.h>
25 #else
26 #include "third_party/zlib/zlib.h"
27 #endif
28
29 extern "C" {
30
my_alloc_func(void * opaque,unsigned int items,unsigned int size)31 static void* my_alloc_func(void* opaque,
32 unsigned int items,
33 unsigned int size) {
34 return FX_Alloc2D(uint8_t, items, size);
35 }
36
my_free_func(void * opaque,void * address)37 static void my_free_func(void* opaque, void* address) {
38 FX_Free(address);
39 }
40
41 } // extern "C"
42
43 namespace fxcodec {
44
45 namespace {
46
47 static constexpr uint32_t kMaxTotalOutSize = 1024 * 1024 * 1024; // 1 GiB
48
FlateGetPossiblyTruncatedTotalOut(z_stream * context)49 uint32_t FlateGetPossiblyTruncatedTotalOut(z_stream* context) {
50 return std::min(pdfium::base::saturated_cast<uint32_t>(context->total_out),
51 kMaxTotalOutSize);
52 }
53
FlateGetPossiblyTruncatedTotalIn(z_stream * context)54 uint32_t FlateGetPossiblyTruncatedTotalIn(z_stream* context) {
55 return pdfium::base::saturated_cast<uint32_t>(context->total_in);
56 }
57
FlateCompress(unsigned char * dest_buf,unsigned long * dest_size,const unsigned char * src_buf,uint32_t src_size)58 bool FlateCompress(unsigned char* dest_buf,
59 unsigned long* dest_size,
60 const unsigned char* src_buf,
61 uint32_t src_size) {
62 return compress(dest_buf, dest_size, src_buf, src_size) == Z_OK;
63 }
64
FlateInit()65 z_stream* FlateInit() {
66 z_stream* p = FX_Alloc(z_stream, 1);
67 p->zalloc = my_alloc_func;
68 p->zfree = my_free_func;
69 inflateInit(p);
70 return p;
71 }
72
FlateInput(z_stream * context,pdfium::span<const uint8_t> src_buf)73 void FlateInput(z_stream* context, pdfium::span<const uint8_t> src_buf) {
74 context->next_in = const_cast<unsigned char*>(src_buf.data());
75 context->avail_in = static_cast<uint32_t>(src_buf.size());
76 }
77
FlateOutput(z_stream * context,unsigned char * dest_buf,uint32_t dest_size)78 uint32_t FlateOutput(z_stream* context,
79 unsigned char* dest_buf,
80 uint32_t dest_size) {
81 context->next_out = dest_buf;
82 context->avail_out = dest_size;
83 uint32_t pre_pos = FlateGetPossiblyTruncatedTotalOut(context);
84 int ret = inflate(static_cast<z_stream*>(context), Z_SYNC_FLUSH);
85
86 uint32_t post_pos = FlateGetPossiblyTruncatedTotalOut(context);
87 ASSERT(post_pos >= pre_pos);
88
89 uint32_t written = post_pos - pre_pos;
90 if (written < dest_size)
91 memset(dest_buf + written, '\0', dest_size - written);
92
93 return ret;
94 }
95
FlateGetAvailOut(z_stream * context)96 uint32_t FlateGetAvailOut(z_stream* context) {
97 return context->avail_out;
98 }
99
FlateEnd(z_stream * context)100 void FlateEnd(z_stream* context) {
101 inflateEnd(context);
102 FX_Free(context);
103 }
104
105 // For use with std::unique_ptr<z_stream>.
106 struct FlateDeleter {
operator ()fxcodec::__anon0f322ee60111::FlateDeleter107 inline void operator()(z_stream* context) { FlateEnd(context); }
108 };
109
110 class CLZWDecoder {
111 public:
112 CLZWDecoder(pdfium::span<const uint8_t> src_span, bool early_change);
113
114 bool Decode();
GetSrcSize() const115 uint32_t GetSrcSize() const { return (src_bit_pos_ + 7) / 8; }
GetDestSize() const116 uint32_t GetDestSize() const { return dest_byte_pos_; }
TakeDestBuf()117 std::unique_ptr<uint8_t, FxFreeDeleter> TakeDestBuf() {
118 return std::move(dest_buf_);
119 }
120
121 private:
122 void AddCode(uint32_t prefix_code, uint8_t append_char);
123 void DecodeString(uint32_t code);
124 void ExpandDestBuf(uint32_t additional_size);
125
126 pdfium::span<const uint8_t> const src_span_;
127 std::unique_ptr<uint8_t, FxFreeDeleter> dest_buf_;
128 uint32_t src_bit_pos_ = 0;
129 uint32_t dest_buf_size_ = 0; // Actual allocated size.
130 uint32_t dest_byte_pos_ = 0; // Size used.
131 uint32_t stack_len_ = 0;
132 uint8_t decode_stack_[4000];
133 const uint8_t early_change_;
134 uint8_t code_len_ = 9;
135 uint32_t current_code_ = 0;
136 uint32_t codes_[5021];
137 };
138
CLZWDecoder(pdfium::span<const uint8_t> src_span,bool early_change)139 CLZWDecoder::CLZWDecoder(pdfium::span<const uint8_t> src_span,
140 bool early_change)
141 : src_span_(src_span), early_change_(early_change ? 1 : 0) {}
142
AddCode(uint32_t prefix_code,uint8_t append_char)143 void CLZWDecoder::AddCode(uint32_t prefix_code, uint8_t append_char) {
144 if (current_code_ + early_change_ == 4094)
145 return;
146
147 codes_[current_code_++] = (prefix_code << 16) | append_char;
148 if (current_code_ + early_change_ == 512 - 258)
149 code_len_ = 10;
150 else if (current_code_ + early_change_ == 1024 - 258)
151 code_len_ = 11;
152 else if (current_code_ + early_change_ == 2048 - 258)
153 code_len_ = 12;
154 }
155
DecodeString(uint32_t code)156 void CLZWDecoder::DecodeString(uint32_t code) {
157 while (1) {
158 int index = code - 258;
159 if (index < 0 || static_cast<uint32_t>(index) >= current_code_)
160 break;
161
162 uint32_t data = codes_[index];
163 if (stack_len_ >= sizeof(decode_stack_))
164 return;
165
166 decode_stack_[stack_len_++] = static_cast<uint8_t>(data);
167 code = data >> 16;
168 }
169 if (stack_len_ >= sizeof(decode_stack_))
170 return;
171
172 decode_stack_[stack_len_++] = static_cast<uint8_t>(code);
173 }
174
ExpandDestBuf(uint32_t additional_size)175 void CLZWDecoder::ExpandDestBuf(uint32_t additional_size) {
176 FX_SAFE_UINT32 new_size = std::max(dest_buf_size_ / 2, additional_size);
177 new_size += dest_buf_size_;
178 if (!new_size.IsValid()) {
179 dest_buf_.reset();
180 return;
181 }
182
183 dest_buf_size_ = new_size.ValueOrDie();
184 dest_buf_.reset(FX_Realloc(uint8_t, dest_buf_.release(), dest_buf_size_));
185 }
186
Decode()187 bool CLZWDecoder::Decode() {
188 uint32_t old_code = 0xFFFFFFFF;
189 uint8_t last_char = 0;
190
191 // In one PDF test set, 40% of Decode() calls did not need to realloc with
192 // this size.
193 dest_buf_size_ = 512;
194 dest_buf_.reset(FX_Alloc(uint8_t, dest_buf_size_));
195 while (1) {
196 if (src_bit_pos_ + code_len_ > src_span_.size() * 8)
197 break;
198
199 int byte_pos = src_bit_pos_ / 8;
200 int bit_pos = src_bit_pos_ % 8;
201 uint8_t bit_left = code_len_;
202 uint32_t code = 0;
203 if (bit_pos) {
204 bit_left -= 8 - bit_pos;
205 code = (src_span_[byte_pos++] & ((1 << (8 - bit_pos)) - 1)) << bit_left;
206 }
207 if (bit_left < 8) {
208 code |= src_span_[byte_pos] >> (8 - bit_left);
209 } else {
210 bit_left -= 8;
211 code |= src_span_[byte_pos++] << bit_left;
212 if (bit_left)
213 code |= src_span_[byte_pos] >> (8 - bit_left);
214 }
215 src_bit_pos_ += code_len_;
216
217 if (code < 256) {
218 if (dest_byte_pos_ >= dest_buf_size_) {
219 ExpandDestBuf(dest_byte_pos_ - dest_buf_size_ + 1);
220 if (!dest_buf_)
221 return false;
222 }
223
224 dest_buf_.get()[dest_byte_pos_] = (uint8_t)code;
225 dest_byte_pos_++;
226 last_char = (uint8_t)code;
227 if (old_code != 0xFFFFFFFF)
228 AddCode(old_code, last_char);
229 old_code = code;
230 continue;
231 }
232 if (code == 256) {
233 code_len_ = 9;
234 current_code_ = 0;
235 old_code = 0xFFFFFFFF;
236 continue;
237 }
238 if (code == 257)
239 break;
240
241 // Case where |code| is 258 or greater.
242 if (old_code == 0xFFFFFFFF)
243 return false;
244
245 ASSERT(old_code < 256 || old_code >= 258);
246 stack_len_ = 0;
247 if (code - 258 >= current_code_) {
248 if (stack_len_ < sizeof(decode_stack_))
249 decode_stack_[stack_len_++] = last_char;
250 DecodeString(old_code);
251 } else {
252 DecodeString(code);
253 }
254
255 FX_SAFE_UINT32 safe_required_size = dest_byte_pos_;
256 safe_required_size += stack_len_;
257 if (!safe_required_size.IsValid())
258 return false;
259
260 uint32_t required_size = safe_required_size.ValueOrDie();
261 if (required_size > dest_buf_size_) {
262 ExpandDestBuf(required_size - dest_buf_size_);
263 if (!dest_buf_)
264 return false;
265 }
266
267 for (uint32_t i = 0; i < stack_len_; i++)
268 dest_buf_.get()[dest_byte_pos_ + i] = decode_stack_[stack_len_ - i - 1];
269 dest_byte_pos_ += stack_len_;
270 last_char = decode_stack_[stack_len_ - 1];
271 if (old_code >= 258 && old_code - 258 >= current_code_)
272 break;
273
274 AddCode(old_code, last_char);
275 old_code = code;
276 }
277 return dest_byte_pos_ != 0;
278 }
279
PathPredictor(int a,int b,int c)280 uint8_t PathPredictor(int a, int b, int c) {
281 int p = a + b - c;
282 int pa = abs(p - a);
283 int pb = abs(p - b);
284 int pc = abs(p - c);
285 if (pa <= pb && pa <= pc)
286 return (uint8_t)a;
287 if (pb <= pc)
288 return (uint8_t)b;
289 return (uint8_t)c;
290 }
291
PNG_PredictLine(uint8_t * pDestData,const uint8_t * pSrcData,const uint8_t * pLastLine,int bpc,int nColors,int nPixels)292 void PNG_PredictLine(uint8_t* pDestData,
293 const uint8_t* pSrcData,
294 const uint8_t* pLastLine,
295 int bpc,
296 int nColors,
297 int nPixels) {
298 const uint32_t row_size = CalculatePitch8(bpc, nColors, nPixels).ValueOrDie();
299 const uint32_t BytesPerPixel = (bpc * nColors + 7) / 8;
300 uint8_t tag = pSrcData[0];
301 if (tag == 0) {
302 memmove(pDestData, pSrcData + 1, row_size);
303 return;
304 }
305 for (uint32_t byte = 0; byte < row_size; ++byte) {
306 uint8_t raw_byte = pSrcData[byte + 1];
307 switch (tag) {
308 case 1: {
309 uint8_t left = 0;
310 if (byte >= BytesPerPixel) {
311 left = pDestData[byte - BytesPerPixel];
312 }
313 pDestData[byte] = raw_byte + left;
314 break;
315 }
316 case 2: {
317 uint8_t up = 0;
318 if (pLastLine) {
319 up = pLastLine[byte];
320 }
321 pDestData[byte] = raw_byte + up;
322 break;
323 }
324 case 3: {
325 uint8_t left = 0;
326 if (byte >= BytesPerPixel) {
327 left = pDestData[byte - BytesPerPixel];
328 }
329 uint8_t up = 0;
330 if (pLastLine) {
331 up = pLastLine[byte];
332 }
333 pDestData[byte] = raw_byte + (up + left) / 2;
334 break;
335 }
336 case 4: {
337 uint8_t left = 0;
338 if (byte >= BytesPerPixel) {
339 left = pDestData[byte - BytesPerPixel];
340 }
341 uint8_t up = 0;
342 if (pLastLine) {
343 up = pLastLine[byte];
344 }
345 uint8_t upper_left = 0;
346 if (byte >= BytesPerPixel && pLastLine) {
347 upper_left = pLastLine[byte - BytesPerPixel];
348 }
349 pDestData[byte] = raw_byte + PathPredictor(left, up, upper_left);
350 break;
351 }
352 default:
353 pDestData[byte] = raw_byte;
354 break;
355 }
356 }
357 }
358
PNG_Predictor(int Colors,int BitsPerComponent,int Columns,std::unique_ptr<uint8_t,FxFreeDeleter> * data_buf,uint32_t * data_size)359 bool PNG_Predictor(int Colors,
360 int BitsPerComponent,
361 int Columns,
362 std::unique_ptr<uint8_t, FxFreeDeleter>* data_buf,
363 uint32_t* data_size) {
364 // TODO(thestig): Look into using CalculatePitch8() here.
365 const int BytesPerPixel = (Colors * BitsPerComponent + 7) / 8;
366 const int row_size = (Colors * BitsPerComponent * Columns + 7) / 8;
367 if (row_size <= 0)
368 return false;
369 const int row_count = (*data_size + row_size) / (row_size + 1);
370 if (row_count <= 0)
371 return false;
372 const int last_row_size = *data_size % (row_size + 1);
373 std::unique_ptr<uint8_t, FxFreeDeleter> dest_buf(
374 FX_Alloc2D(uint8_t, row_size, row_count));
375 uint32_t byte_cnt = 0;
376 uint8_t* pSrcData = data_buf->get();
377 uint8_t* pDestData = dest_buf.get();
378 for (int row = 0; row < row_count; row++) {
379 uint8_t tag = pSrcData[0];
380 byte_cnt++;
381 if (tag == 0) {
382 int move_size = row_size;
383 if ((row + 1) * (move_size + 1) > static_cast<int>(*data_size)) {
384 move_size = last_row_size - 1;
385 }
386 memcpy(pDestData, pSrcData + 1, move_size);
387 pSrcData += move_size + 1;
388 pDestData += move_size;
389 byte_cnt += move_size;
390 continue;
391 }
392 for (int byte = 0; byte < row_size && byte_cnt < *data_size;
393 ++byte, ++byte_cnt) {
394 uint8_t raw_byte = pSrcData[byte + 1];
395 switch (tag) {
396 case 1: {
397 uint8_t left = 0;
398 if (byte >= BytesPerPixel) {
399 left = pDestData[byte - BytesPerPixel];
400 }
401 pDestData[byte] = raw_byte + left;
402 break;
403 }
404 case 2: {
405 uint8_t up = 0;
406 if (row) {
407 up = pDestData[byte - row_size];
408 }
409 pDestData[byte] = raw_byte + up;
410 break;
411 }
412 case 3: {
413 uint8_t left = 0;
414 if (byte >= BytesPerPixel) {
415 left = pDestData[byte - BytesPerPixel];
416 }
417 uint8_t up = 0;
418 if (row) {
419 up = pDestData[byte - row_size];
420 }
421 pDestData[byte] = raw_byte + (up + left) / 2;
422 break;
423 }
424 case 4: {
425 uint8_t left = 0;
426 if (byte >= BytesPerPixel) {
427 left = pDestData[byte - BytesPerPixel];
428 }
429 uint8_t up = 0;
430 if (row) {
431 up = pDestData[byte - row_size];
432 }
433 uint8_t upper_left = 0;
434 if (byte >= BytesPerPixel && row) {
435 upper_left = pDestData[byte - row_size - BytesPerPixel];
436 }
437 pDestData[byte] = raw_byte + PathPredictor(left, up, upper_left);
438 break;
439 }
440 default:
441 pDestData[byte] = raw_byte;
442 break;
443 }
444 }
445 pSrcData += row_size + 1;
446 pDestData += row_size;
447 }
448 *data_buf = std::move(dest_buf);
449 *data_size = row_size * row_count -
450 (last_row_size > 0 ? (row_size + 1 - last_row_size) : 0);
451 return true;
452 }
453
TIFF_PredictLine(uint8_t * dest_buf,uint32_t row_size,int BitsPerComponent,int Colors,int Columns)454 void TIFF_PredictLine(uint8_t* dest_buf,
455 uint32_t row_size,
456 int BitsPerComponent,
457 int Colors,
458 int Columns) {
459 if (BitsPerComponent == 1) {
460 int row_bits = std::min(BitsPerComponent * Colors * Columns,
461 pdfium::base::checked_cast<int>(row_size * 8));
462 int index_pre = 0;
463 int col_pre = 0;
464 for (int i = 1; i < row_bits; i++) {
465 int col = i % 8;
466 int index = i / 8;
467 if (((dest_buf[index] >> (7 - col)) & 1) ^
468 ((dest_buf[index_pre] >> (7 - col_pre)) & 1)) {
469 dest_buf[index] |= 1 << (7 - col);
470 } else {
471 dest_buf[index] &= ~(1 << (7 - col));
472 }
473 index_pre = index;
474 col_pre = col;
475 }
476 return;
477 }
478 int BytesPerPixel = BitsPerComponent * Colors / 8;
479 if (BitsPerComponent == 16) {
480 for (uint32_t i = BytesPerPixel; i + 1 < row_size; i += 2) {
481 uint16_t pixel =
482 (dest_buf[i - BytesPerPixel] << 8) | dest_buf[i - BytesPerPixel + 1];
483 pixel += (dest_buf[i] << 8) | dest_buf[i + 1];
484 dest_buf[i] = pixel >> 8;
485 dest_buf[i + 1] = (uint8_t)pixel;
486 }
487 } else {
488 for (uint32_t i = BytesPerPixel; i < row_size; i++) {
489 dest_buf[i] += dest_buf[i - BytesPerPixel];
490 }
491 }
492 }
493
TIFF_Predictor(int Colors,int BitsPerComponent,int Columns,std::unique_ptr<uint8_t,FxFreeDeleter> * data_buf,uint32_t * data_size)494 bool TIFF_Predictor(int Colors,
495 int BitsPerComponent,
496 int Columns,
497 std::unique_ptr<uint8_t, FxFreeDeleter>* data_buf,
498 uint32_t* data_size) {
499 int row_size = (Colors * BitsPerComponent * Columns + 7) / 8;
500 if (row_size == 0)
501 return false;
502 const int row_count = (*data_size + row_size - 1) / row_size;
503 const int last_row_size = *data_size % row_size;
504 for (int row = 0; row < row_count; row++) {
505 uint8_t* scan_line = data_buf->get() + row * row_size;
506 if ((row + 1) * row_size > static_cast<int>(*data_size)) {
507 row_size = last_row_size;
508 }
509 TIFF_PredictLine(scan_line, row_size, BitsPerComponent, Colors, Columns);
510 }
511 return true;
512 }
513
FlateUncompress(pdfium::span<const uint8_t> src_buf,uint32_t orig_size,std::unique_ptr<uint8_t,FxFreeDeleter> * dest_buf,uint32_t * dest_size,uint32_t * offset)514 void FlateUncompress(pdfium::span<const uint8_t> src_buf,
515 uint32_t orig_size,
516 std::unique_ptr<uint8_t, FxFreeDeleter>* dest_buf,
517 uint32_t* dest_size,
518 uint32_t* offset) {
519 dest_buf->reset();
520 *dest_size = 0;
521
522 std::unique_ptr<z_stream, FlateDeleter> context(FlateInit());
523 if (!context)
524 return;
525
526 FlateInput(context.get(), src_buf);
527
528 const uint32_t kMaxInitialAllocSize = 10000000;
529 uint32_t guess_size = orig_size ? orig_size : src_buf.size() * 2;
530 guess_size = std::min(guess_size, kMaxInitialAllocSize);
531
532 uint32_t buf_size = guess_size;
533 uint32_t last_buf_size = buf_size;
534 std::unique_ptr<uint8_t, FxFreeDeleter> guess_buf(
535 FX_Alloc(uint8_t, guess_size + 1));
536 guess_buf.get()[guess_size] = '\0';
537
538 std::vector<std::unique_ptr<uint8_t, FxFreeDeleter>> result_tmp_bufs;
539 {
540 std::unique_ptr<uint8_t, FxFreeDeleter> cur_buf = std::move(guess_buf);
541 while (1) {
542 uint32_t ret = FlateOutput(context.get(), cur_buf.get(), buf_size);
543 uint32_t avail_buf_size = FlateGetAvailOut(context.get());
544 if (ret != Z_OK || avail_buf_size != 0) {
545 last_buf_size = buf_size - avail_buf_size;
546 result_tmp_bufs.push_back(std::move(cur_buf));
547 break;
548 }
549 result_tmp_bufs.push_back(std::move(cur_buf));
550 cur_buf.reset(FX_Alloc(uint8_t, buf_size + 1));
551 cur_buf.get()[buf_size] = '\0';
552 }
553 }
554
555 // The TotalOut size returned from the library may not be big enough to
556 // handle the content the library returns. We can only handle items
557 // up to 4GB in size.
558 *dest_size = FlateGetPossiblyTruncatedTotalOut(context.get());
559 *offset = FlateGetPossiblyTruncatedTotalIn(context.get());
560 if (result_tmp_bufs.size() == 1) {
561 *dest_buf = std::move(result_tmp_bufs[0]);
562 return;
563 }
564
565 std::unique_ptr<uint8_t, FxFreeDeleter> result_buf(
566 FX_Alloc(uint8_t, *dest_size));
567 uint32_t result_pos = 0;
568 uint32_t remaining = *dest_size;
569 for (size_t i = 0; i < result_tmp_bufs.size(); i++) {
570 std::unique_ptr<uint8_t, FxFreeDeleter> tmp_buf =
571 std::move(result_tmp_bufs[i]);
572 uint32_t tmp_buf_size = buf_size;
573 if (i == result_tmp_bufs.size() - 1)
574 tmp_buf_size = last_buf_size;
575
576 uint32_t cp_size = std::min(tmp_buf_size, remaining);
577 memcpy(result_buf.get() + result_pos, tmp_buf.get(), cp_size);
578 result_pos += cp_size;
579 remaining -= cp_size;
580 }
581 *dest_buf = std::move(result_buf);
582 }
583
584 enum class PredictorType : uint8_t { kNone, kFlate, kPng };
GetPredictor(int predictor)585 static PredictorType GetPredictor(int predictor) {
586 if (predictor >= 10)
587 return PredictorType::kPng;
588 if (predictor == 2)
589 return PredictorType::kFlate;
590 return PredictorType::kNone;
591 }
592
593 class FlateScanlineDecoder : public ScanlineDecoder {
594 public:
595 FlateScanlineDecoder(pdfium::span<const uint8_t> src_span,
596 int width,
597 int height,
598 int nComps,
599 int bpc);
600 ~FlateScanlineDecoder() override;
601
602 // ScanlineDecoder:
603 bool v_Rewind() override;
604 uint8_t* v_GetNextLine() override;
605 uint32_t GetSrcOffset() override;
606
607 protected:
608 std::unique_ptr<z_stream, FlateDeleter> m_pFlate;
609 const pdfium::span<const uint8_t> m_SrcBuf;
610 std::unique_ptr<uint8_t, FxFreeDeleter> const m_pScanline;
611 };
612
FlateScanlineDecoder(pdfium::span<const uint8_t> src_span,int width,int height,int nComps,int bpc)613 FlateScanlineDecoder::FlateScanlineDecoder(pdfium::span<const uint8_t> src_span,
614 int width,
615 int height,
616 int nComps,
617 int bpc)
618 : ScanlineDecoder(width,
619 height,
620 width,
621 height,
622 nComps,
623 bpc,
624 CalculatePitch8(bpc, nComps, width).ValueOrDie()),
625 m_SrcBuf(src_span),
626 m_pScanline(FX_Alloc(uint8_t, m_Pitch)) {}
627
628 FlateScanlineDecoder::~FlateScanlineDecoder() = default;
629
v_Rewind()630 bool FlateScanlineDecoder::v_Rewind() {
631 m_pFlate.reset(FlateInit());
632 if (!m_pFlate)
633 return false;
634
635 FlateInput(m_pFlate.get(), m_SrcBuf);
636 return true;
637 }
638
v_GetNextLine()639 uint8_t* FlateScanlineDecoder::v_GetNextLine() {
640 FlateOutput(m_pFlate.get(), m_pScanline.get(), m_Pitch);
641 return m_pScanline.get();
642 }
643
GetSrcOffset()644 uint32_t FlateScanlineDecoder::GetSrcOffset() {
645 return FlateGetPossiblyTruncatedTotalIn(m_pFlate.get());
646 }
647
648 class FlatePredictorScanlineDecoder final : public FlateScanlineDecoder {
649 public:
650 FlatePredictorScanlineDecoder(pdfium::span<const uint8_t> src_span,
651 int width,
652 int height,
653 int comps,
654 int bpc,
655 PredictorType predictor,
656 int Colors,
657 int BitsPerComponent,
658 int Columns);
659 ~FlatePredictorScanlineDecoder() override;
660
661 // ScanlineDecoder:
662 bool v_Rewind() override;
663 uint8_t* v_GetNextLine() override;
664
665 private:
666 void GetNextLineWithPredictedPitch();
667 void GetNextLineWithoutPredictedPitch();
668
669 const PredictorType m_Predictor;
670 int m_Colors = 0;
671 int m_BitsPerComponent = 0;
672 int m_Columns = 0;
673 uint32_t m_PredictPitch = 0;
674 size_t m_LeftOver = 0;
675 std::vector<uint8_t, FxAllocAllocator<uint8_t>> m_LastLine;
676 std::vector<uint8_t, FxAllocAllocator<uint8_t>> m_PredictBuffer;
677 std::vector<uint8_t, FxAllocAllocator<uint8_t>> m_PredictRaw;
678 };
679
FlatePredictorScanlineDecoder(pdfium::span<const uint8_t> src_span,int width,int height,int comps,int bpc,PredictorType predictor,int Colors,int BitsPerComponent,int Columns)680 FlatePredictorScanlineDecoder::FlatePredictorScanlineDecoder(
681 pdfium::span<const uint8_t> src_span,
682 int width,
683 int height,
684 int comps,
685 int bpc,
686 PredictorType predictor,
687 int Colors,
688 int BitsPerComponent,
689 int Columns)
690 : FlateScanlineDecoder(src_span, width, height, comps, bpc),
691 m_Predictor(predictor) {
692 ASSERT(m_Predictor != PredictorType::kNone);
693 if (BitsPerComponent * Colors * Columns == 0) {
694 BitsPerComponent = m_bpc;
695 Colors = m_nComps;
696 Columns = m_OrigWidth;
697 }
698 m_Colors = Colors;
699 m_BitsPerComponent = BitsPerComponent;
700 m_Columns = Columns;
701 m_PredictPitch =
702 CalculatePitch8(m_BitsPerComponent, m_Colors, m_Columns).ValueOrDie();
703 m_LastLine.resize(m_PredictPitch);
704 m_PredictBuffer.resize(m_PredictPitch);
705 m_PredictRaw.resize(m_PredictPitch + 1);
706 }
707
708 FlatePredictorScanlineDecoder::~FlatePredictorScanlineDecoder() = default;
709
v_Rewind()710 bool FlatePredictorScanlineDecoder::v_Rewind() {
711 if (!FlateScanlineDecoder::v_Rewind())
712 return false;
713
714 m_LeftOver = 0;
715 return true;
716 }
717
v_GetNextLine()718 uint8_t* FlatePredictorScanlineDecoder::v_GetNextLine() {
719 if (m_Pitch == m_PredictPitch)
720 GetNextLineWithPredictedPitch();
721 else
722 GetNextLineWithoutPredictedPitch();
723 return m_pScanline.get();
724 }
725
GetNextLineWithPredictedPitch()726 void FlatePredictorScanlineDecoder::GetNextLineWithPredictedPitch() {
727 switch (m_Predictor) {
728 case PredictorType::kPng:
729 FlateOutput(m_pFlate.get(), m_PredictRaw.data(), m_PredictPitch + 1);
730 PNG_PredictLine(m_pScanline.get(), m_PredictRaw.data(), m_LastLine.data(),
731 m_BitsPerComponent, m_Colors, m_Columns);
732 memcpy(m_LastLine.data(), m_pScanline.get(), m_PredictPitch);
733 break;
734 case PredictorType::kFlate:
735 FlateOutput(m_pFlate.get(), m_pScanline.get(), m_Pitch);
736 TIFF_PredictLine(m_pScanline.get(), m_PredictPitch, m_bpc, m_nComps,
737 m_OutputWidth);
738 break;
739 default:
740 NOTREACHED();
741 break;
742 }
743 }
744
GetNextLineWithoutPredictedPitch()745 void FlatePredictorScanlineDecoder::GetNextLineWithoutPredictedPitch() {
746 size_t bytes_to_go = m_Pitch;
747 size_t read_leftover = m_LeftOver > bytes_to_go ? bytes_to_go : m_LeftOver;
748 if (read_leftover) {
749 memcpy(m_pScanline.get(), &m_PredictBuffer[m_PredictPitch - m_LeftOver],
750 read_leftover);
751 m_LeftOver -= read_leftover;
752 bytes_to_go -= read_leftover;
753 }
754 while (bytes_to_go) {
755 switch (m_Predictor) {
756 case PredictorType::kPng:
757 FlateOutput(m_pFlate.get(), m_PredictRaw.data(), m_PredictPitch + 1);
758 PNG_PredictLine(m_PredictBuffer.data(), m_PredictRaw.data(),
759 m_LastLine.data(), m_BitsPerComponent, m_Colors,
760 m_Columns);
761 memcpy(m_LastLine.data(), m_PredictBuffer.data(), m_PredictPitch);
762 break;
763 case PredictorType::kFlate:
764 FlateOutput(m_pFlate.get(), m_PredictBuffer.data(), m_PredictPitch);
765 TIFF_PredictLine(m_PredictBuffer.data(), m_PredictPitch,
766 m_BitsPerComponent, m_Colors, m_Columns);
767 break;
768 default:
769 NOTREACHED();
770 break;
771 }
772 size_t read_bytes =
773 m_PredictPitch > bytes_to_go ? bytes_to_go : m_PredictPitch;
774 memcpy(m_pScanline.get() + m_Pitch - bytes_to_go, m_PredictBuffer.data(),
775 read_bytes);
776 m_LeftOver += m_PredictPitch - read_bytes;
777 bytes_to_go -= read_bytes;
778 }
779 }
780
781 } // namespace
782
783 // static
CreateDecoder(pdfium::span<const uint8_t> src_span,int width,int height,int nComps,int bpc,int predictor,int Colors,int BitsPerComponent,int Columns)784 std::unique_ptr<ScanlineDecoder> FlateModule::CreateDecoder(
785 pdfium::span<const uint8_t> src_span,
786 int width,
787 int height,
788 int nComps,
789 int bpc,
790 int predictor,
791 int Colors,
792 int BitsPerComponent,
793 int Columns) {
794 PredictorType predictor_type = GetPredictor(predictor);
795 if (predictor_type == PredictorType::kNone) {
796 return pdfium::MakeUnique<FlateScanlineDecoder>(src_span, width, height,
797 nComps, bpc);
798 }
799 return pdfium::MakeUnique<FlatePredictorScanlineDecoder>(
800 src_span, width, height, nComps, bpc, predictor_type, Colors,
801 BitsPerComponent, Columns);
802 }
803
804 // static
FlateOrLZWDecode(bool bLZW,pdfium::span<const uint8_t> src_span,bool bEarlyChange,int predictor,int Colors,int BitsPerComponent,int Columns,uint32_t estimated_size,std::unique_ptr<uint8_t,FxFreeDeleter> * dest_buf,uint32_t * dest_size)805 uint32_t FlateModule::FlateOrLZWDecode(
806 bool bLZW,
807 pdfium::span<const uint8_t> src_span,
808 bool bEarlyChange,
809 int predictor,
810 int Colors,
811 int BitsPerComponent,
812 int Columns,
813 uint32_t estimated_size,
814 std::unique_ptr<uint8_t, FxFreeDeleter>* dest_buf,
815 uint32_t* dest_size) {
816 dest_buf->reset();
817 uint32_t offset = 0;
818 PredictorType predictor_type = GetPredictor(predictor);
819
820 if (bLZW) {
821 auto decoder = pdfium::MakeUnique<CLZWDecoder>(src_span, bEarlyChange);
822 if (!decoder->Decode())
823 return FX_INVALID_OFFSET;
824
825 offset = decoder->GetSrcSize();
826 *dest_size = decoder->GetDestSize();
827 *dest_buf = decoder->TakeDestBuf();
828 } else {
829 FlateUncompress(src_span, estimated_size, dest_buf, dest_size, &offset);
830 }
831
832 bool ret = false;
833 switch (predictor_type) {
834 case PredictorType::kNone:
835 return offset;
836 case PredictorType::kPng:
837 ret =
838 PNG_Predictor(Colors, BitsPerComponent, Columns, dest_buf, dest_size);
839 break;
840 case PredictorType::kFlate:
841 ret = TIFF_Predictor(Colors, BitsPerComponent, Columns, dest_buf,
842 dest_size);
843 break;
844 default:
845 NOTREACHED();
846 break;
847 }
848 return ret ? offset : FX_INVALID_OFFSET;
849 }
850
851 // static
Encode(const uint8_t * src_buf,uint32_t src_size,std::unique_ptr<uint8_t,FxFreeDeleter> * dest_buf,uint32_t * dest_size)852 bool FlateModule::Encode(const uint8_t* src_buf,
853 uint32_t src_size,
854 std::unique_ptr<uint8_t, FxFreeDeleter>* dest_buf,
855 uint32_t* dest_size) {
856 *dest_size = src_size + src_size / 1000 + 12;
857 dest_buf->reset(FX_Alloc(uint8_t, *dest_size));
858 unsigned long temp_size = *dest_size;
859 if (!FlateCompress(dest_buf->get(), &temp_size, src_buf, src_size))
860 return false;
861
862 *dest_size = (uint32_t)temp_size;
863 return true;
864 }
865
866 } // namespace fxcodec
867