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