• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2018 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/bmp/cfx_bmpdecompressor.h"
8 
9 #include <stdint.h>
10 
11 #include <algorithm>
12 #include <limits>
13 #include <utility>
14 
15 #include "core/fxcodec/bmp/cfx_bmpcontext.h"
16 #include "core/fxcodec/cfx_codec_memory.h"
17 #include "core/fxcrt/byteorder.h"
18 #include "core/fxcrt/compiler_specific.h"
19 #include "core/fxcrt/data_vector.h"
20 #include "core/fxcrt/fx_safe_types.h"
21 #include "core/fxcrt/numerics/safe_math.h"
22 #include "core/fxcrt/span_util.h"
23 #include "core/fxcrt/stl_util.h"
24 #include "core/fxge/calculate_pitch.h"
25 
26 namespace fxcodec {
27 
28 namespace {
29 
30 constexpr size_t kBmpCoreHeaderSize = 12;
31 constexpr size_t kBmpInfoHeaderSize = 40;
32 
33 static_assert(sizeof(BmpCoreHeader) == kBmpCoreHeaderSize,
34               "BmpCoreHeader has wrong size");
35 static_assert(sizeof(BmpInfoHeader) == kBmpInfoHeaderSize,
36               "BmpInfoHeader has wrong size");
37 
38 constexpr uint16_t kBmpSignature = 0x4D42;
39 constexpr uint8_t kRleMarker = 0;
40 constexpr uint8_t kRleEol = 0;
41 constexpr uint8_t kRleEoi = 1;
42 constexpr uint8_t kRleDelta = 2;
43 constexpr uint32_t kBmpRgb = 0L;
44 constexpr uint32_t kBmpRle8 = 1L;
45 constexpr uint32_t kBmpRle4 = 2L;
46 constexpr uint32_t kBmpBitfields = 3L;
47 
48 // Limit of image dimension. Use the same limit as the JBIG2 codecs.
49 constexpr uint32_t kBmpMaxImageDimension = 65535;
50 
HalfRoundUp(uint8_t value)51 uint8_t HalfRoundUp(uint8_t value) {
52   uint16_t value16 = value;
53   return static_cast<uint8_t>((value16 + 1) / 2);
54 }
55 
56 }  // namespace
57 
CFX_BmpDecompressor(const CFX_BmpContext * context)58 CFX_BmpDecompressor::CFX_BmpDecompressor(const CFX_BmpContext* context)
59     : context_(context) {}
60 
61 CFX_BmpDecompressor::~CFX_BmpDecompressor() = default;
62 
ReadNextScanline()63 void CFX_BmpDecompressor::ReadNextScanline() {
64   uint32_t row = img_tb_flag_ ? row_num_ : (height_ - 1 - row_num_);
65   context_->m_pDelegate->BmpReadScanline(row, out_row_buffer_);
66   ++row_num_;
67 }
68 
GetDataPosition(uint32_t rcd_pos)69 bool CFX_BmpDecompressor::GetDataPosition(uint32_t rcd_pos) {
70   return context_->m_pDelegate->BmpInputImagePositionBuf(rcd_pos);
71 }
72 
ReadHeader()73 BmpDecoder::Status CFX_BmpDecompressor::ReadHeader() {
74   if (decode_status_ == DecodeStatus::kHeader) {
75     BmpDecoder::Status status = ReadBmpHeader();
76     if (status != BmpDecoder::Status::kSuccess)
77       return status;
78   }
79 
80   if (decode_status_ != DecodeStatus::kPal)
81     return BmpDecoder::Status::kSuccess;
82 
83   if (compress_flag_ == kBmpBitfields)
84     return ReadBmpBitfields();
85 
86   return ReadBmpPalette();
87 }
88 
ReadBmpHeader()89 BmpDecoder::Status CFX_BmpDecompressor::ReadBmpHeader() {
90   BmpFileHeader bmp_header;
91   if (!ReadAllOrNone(
92           pdfium::as_writable_bytes(pdfium::span_from_ref(bmp_header)))) {
93     return BmpDecoder::Status::kContinue;
94   }
95 
96   bmp_header.bfType = fxcrt::FromLE16(bmp_header.bfType);
97   data_offset_ = fxcrt::FromLE32(bmp_header.bfOffBits);
98   data_size_ = fxcrt::FromLE32(bmp_header.bfSize);
99   if (bmp_header.bfType != kBmpSignature)
100     return BmpDecoder::Status::kFail;
101 
102   size_t pos = input_buffer_->GetPosition();
103   if (!ReadAllOrNone(
104           pdfium::as_writable_bytes(pdfium::span_from_ref(img_ifh_size_)))) {
105     return BmpDecoder::Status::kContinue;
106   }
107   if (!input_buffer_->Seek(pos))
108     return BmpDecoder::Status::kFail;
109 
110   img_ifh_size_ = fxcrt::FromLE32(img_ifh_size_);
111   pal_type_ = PalType::kNew;
112   BmpDecoder::Status status = ReadBmpHeaderIfh();
113   if (status != BmpDecoder::Status::kSuccess)
114     return status;
115 
116   return ReadBmpHeaderDimensions();
117 }
118 
ReadBmpHeaderIfh()119 BmpDecoder::Status CFX_BmpDecompressor::ReadBmpHeaderIfh() {
120   if (img_ifh_size_ == kBmpCoreHeaderSize) {
121     pal_type_ = PalType::kOld;
122     BmpCoreHeader bmp_core_header;
123     if (!ReadAllOrNone(pdfium::as_writable_bytes(
124             pdfium::span_from_ref(bmp_core_header)))) {
125       return BmpDecoder::Status::kContinue;
126     }
127 
128     width_ = fxcrt::FromLE16(bmp_core_header.bcWidth);
129     height_ = fxcrt::FromLE16(bmp_core_header.bcHeight);
130     bit_counts_ = fxcrt::FromLE16(bmp_core_header.bcBitCount);
131     compress_flag_ = kBmpRgb;
132     img_tb_flag_ = false;
133     return BmpDecoder::Status::kSuccess;
134   }
135 
136   if (img_ifh_size_ == kBmpInfoHeaderSize) {
137     BmpInfoHeader bmp_info_header;
138     if (!ReadAllOrNone(pdfium::as_writable_bytes(
139             pdfium::span_from_ref(bmp_info_header)))) {
140       return BmpDecoder::Status::kContinue;
141     }
142 
143     width_ = fxcrt::FromLE32(bmp_info_header.biWidth);
144     bit_counts_ = fxcrt::FromLE16(bmp_info_header.biBitCount);
145     compress_flag_ = fxcrt::FromLE32(bmp_info_header.biCompression);
146     color_used_ = fxcrt::FromLE32(bmp_info_header.biClrUsed);
147     dpi_x_ =
148         static_cast<int32_t>(fxcrt::FromLE32(bmp_info_header.biXPelsPerMeter));
149     dpi_y_ =
150         static_cast<int32_t>(fxcrt::FromLE32(bmp_info_header.biYPelsPerMeter));
151 
152     int32_t signed_height = fxcrt::FromLE32(bmp_info_header.biHeight);
153     if (!SetHeight(signed_height)) {
154       return BmpDecoder::Status::kFail;
155     }
156     return BmpDecoder::Status::kSuccess;
157   }
158 
159   if (img_ifh_size_ <= sizeof(BmpInfoHeader))
160     return BmpDecoder::Status::kFail;
161 
162   FX_SAFE_SIZE_T new_pos = input_buffer_->GetPosition();
163   BmpInfoHeader bmp_info_header;
164   if (!ReadAllOrNone(
165           pdfium::as_writable_bytes(pdfium::span_from_ref(bmp_info_header)))) {
166     return BmpDecoder::Status::kContinue;
167   }
168 
169   new_pos += img_ifh_size_;
170   if (!new_pos.IsValid())
171     return BmpDecoder::Status::kFail;
172 
173   if (!input_buffer_->Seek(new_pos.ValueOrDie()))
174     return BmpDecoder::Status::kContinue;
175 
176   width_ = fxcrt::FromLE32(bmp_info_header.biWidth);
177   bit_counts_ = fxcrt::FromLE16(bmp_info_header.biBitCount);
178   compress_flag_ = fxcrt::FromLE32(bmp_info_header.biCompression);
179   color_used_ = fxcrt::FromLE32(bmp_info_header.biClrUsed);
180   dpi_x_ = fxcrt::FromLE32(bmp_info_header.biXPelsPerMeter);
181   dpi_y_ = fxcrt::FromLE32(bmp_info_header.biYPelsPerMeter);
182 
183   int32_t signed_height = fxcrt::FromLE32(bmp_info_header.biHeight);
184   if (!SetHeight(signed_height)) {
185     return BmpDecoder::Status::kFail;
186   }
187   uint16_t bi_planes = fxcrt::FromLE16(bmp_info_header.biPlanes);
188   if (compress_flag_ != kBmpRgb || bi_planes != 1 || color_used_ != 0) {
189     return BmpDecoder::Status::kFail;
190   }
191   return BmpDecoder::Status::kSuccess;
192 }
193 
ReadBmpHeaderDimensions()194 BmpDecoder::Status CFX_BmpDecompressor::ReadBmpHeaderDimensions() {
195   if (width_ > kBmpMaxImageDimension || height_ > kBmpMaxImageDimension ||
196       compress_flag_ > kBmpBitfields) {
197     return BmpDecoder::Status::kFail;
198   }
199 
200   switch (bit_counts_) {
201     case 1:
202     case 4:
203     case 8:
204     case 16:
205     case 24: {
206       if (color_used_ > 1U << bit_counts_)
207         return BmpDecoder::Status::kFail;
208       break;
209     }
210     case 32:
211       break;
212     default:
213       return BmpDecoder::Status::kFail;
214   }
215   std::optional<uint32_t> stride = fxge::CalculatePitch32(bit_counts_, width_);
216   if (!stride.has_value())
217     return BmpDecoder::Status::kFail;
218 
219   src_row_bytes_ = stride.value();
220   switch (bit_counts_) {
221     case 1:
222     case 4:
223     case 8:
224       stride = fxge::CalculatePitch32(8, width_);
225       if (!stride.has_value())
226         return BmpDecoder::Status::kFail;
227       out_row_bytes_ = stride.value();
228       components_ = 1;
229       break;
230     case 16:
231     case 24:
232       stride = fxge::CalculatePitch32(24, width_);
233       if (!stride.has_value())
234         return BmpDecoder::Status::kFail;
235       out_row_bytes_ = stride.value();
236       components_ = 3;
237       break;
238     case 32:
239       out_row_bytes_ = src_row_bytes_;
240       components_ = 4;
241       break;
242   }
243   out_row_buffer_.clear();
244 
245   if (out_row_bytes_ <= 0)
246     return BmpDecoder::Status::kFail;
247 
248   out_row_buffer_.resize(out_row_bytes_);
249   SaveDecodingStatus(DecodeStatus::kPal);
250   return BmpDecoder::Status::kSuccess;
251 }
252 
ReadBmpBitfields()253 BmpDecoder::Status CFX_BmpDecompressor::ReadBmpBitfields() {
254   if (bit_counts_ != 16 && bit_counts_ != 32)
255     return BmpDecoder::Status::kFail;
256 
257   uint32_t masks[3];
258   if (!ReadAllOrNone(pdfium::as_writable_byte_span(masks))) {
259     return BmpDecoder::Status::kContinue;
260   }
261 
262   mask_red_ = fxcrt::FromLE32(masks[0]);
263   mask_green_ = fxcrt::FromLE32(masks[1]);
264   mask_blue_ = fxcrt::FromLE32(masks[2]);
265   if (mask_red_ & mask_green_ || mask_red_ & mask_blue_ ||
266       mask_green_ & mask_blue_) {
267     return BmpDecoder::Status::kFail;
268   }
269   header_offset_ = std::max(header_offset_, 26 + img_ifh_size_);
270   SaveDecodingStatus(DecodeStatus::kDataPre);
271   return BmpDecoder::Status::kSuccess;
272 }
273 
ReadBmpPalette()274 BmpDecoder::Status CFX_BmpDecompressor::ReadBmpPalette() {
275   if (bit_counts_ == 16) {
276     mask_red_ = 0x7C00;
277     mask_green_ = 0x03E0;
278     mask_blue_ = 0x001F;
279   }
280   uint32_t palette_entries = 0;
281   if (bit_counts_ < 16) {
282     palette_entries = 1 << bit_counts_;
283     if (color_used_ != 0) {
284       palette_entries = color_used_;
285     }
286     size_t pal_bytes = palette_entries * PaletteChannelCount();
287     DataVector<uint8_t> src_pal(pal_bytes);
288     if (!ReadAllOrNone(src_pal))
289       return BmpDecoder::Status::kContinue;
290 
291     palette_.resize(palette_entries);
292     if (pal_type_ == PalType::kOld) {
293       auto src_pal_data =
294           fxcrt::reinterpret_span<FX_BGR_STRUCT<uint8_t>, uint8_t>(src_pal);
295       for (auto& dest : palette_) {
296         const auto& entry = src_pal_data.front();
297         dest = ArgbEncode(0x00, entry.red, entry.green, entry.blue);
298         src_pal_data = src_pal_data.subspan(1);
299       }
300     } else {
301       auto src_pal_data =
302           fxcrt::reinterpret_span<FX_BGRA_STRUCT<uint8_t>, uint8_t>(src_pal);
303       for (auto& dest : palette_) {
304         const auto& entry = src_pal_data.front();
305         dest = ArgbEncode(entry.alpha, entry.red, entry.green, entry.blue);
306         src_pal_data = src_pal_data.subspan(1);
307       }
308     }
309   }
310   header_offset_ =
311       std::max(header_offset_,
312                14 + img_ifh_size_ + palette_entries * PaletteChannelCount());
313   SaveDecodingStatus(DecodeStatus::kDataPre);
314   return BmpDecoder::Status::kSuccess;
315 }
316 
ValidateFlag() const317 bool CFX_BmpDecompressor::ValidateFlag() const {
318   switch (compress_flag_) {
319     case kBmpRgb:
320     case kBmpBitfields:
321     case kBmpRle8:
322     case kBmpRle4:
323       return true;
324     default:
325       return false;
326   }
327 }
328 
DecodeImage()329 BmpDecoder::Status CFX_BmpDecompressor::DecodeImage() {
330   if (decode_status_ == DecodeStatus::kDataPre) {
331     // In order to tolerate certain corrupt BMP files, use the header offset if
332     // the data offset would point into the header.
333     data_offset_ = std::max(header_offset_, data_offset_);
334 
335     input_buffer_->Seek(input_buffer_->GetSize());
336     if (!GetDataPosition(data_offset_)) {
337       decode_status_ = DecodeStatus::kTail;
338       return BmpDecoder::Status::kFail;
339     }
340 
341     row_num_ = 0;
342     SaveDecodingStatus(DecodeStatus::kData);
343   }
344   if (decode_status_ != DecodeStatus::kData || !ValidateFlag())
345     return BmpDecoder::Status::kFail;
346 
347   switch (compress_flag_) {
348     case kBmpRgb:
349     case kBmpBitfields:
350       return DecodeRGB();
351     case kBmpRle8:
352       return DecodeRLE8();
353     case kBmpRle4:
354       return DecodeRLE4();
355     default:
356       return BmpDecoder::Status::kFail;
357   }
358 }
359 
ValidateColorIndex(uint8_t val) const360 bool CFX_BmpDecompressor::ValidateColorIndex(uint8_t val) const {
361   return val < palette_.size();
362 }
363 
DecodeRGB()364 BmpDecoder::Status CFX_BmpDecompressor::DecodeRGB() {
365   DataVector<uint8_t> dest_buf(src_row_bytes_);
366   while (row_num_ < height_) {
367     size_t idx = 0;
368     if (!ReadAllOrNone(dest_buf))
369       return BmpDecoder::Status::kContinue;
370 
371     SaveDecodingStatus(DecodeStatus::kData);
372     switch (bit_counts_) {
373       case 1: {
374         for (uint32_t col = 0; col < width_; ++col) {
375           uint8_t index =
376               dest_buf[col >> 3] & (0x80 >> (col % 8)) ? 0x01 : 0x00;
377           if (!ValidateColorIndex(index))
378             return BmpDecoder::Status::kFail;
379           out_row_buffer_[idx++] = index;
380         }
381         break;
382       }
383       case 4: {
384         for (uint32_t col = 0; col < width_; ++col) {
385           uint8_t index = (col & 0x01) ? (dest_buf[col >> 1] & 0x0F)
386                                        : ((dest_buf[col >> 1] & 0xF0) >> 4);
387           if (!ValidateColorIndex(index))
388             return BmpDecoder::Status::kFail;
389           out_row_buffer_[idx++] = index;
390         }
391         break;
392       }
393       case 8: {
394         for (uint32_t col = 0; col < width_; ++col) {
395           uint8_t index = dest_buf[col];
396           if (!ValidateColorIndex(index))
397             return BmpDecoder::Status::kFail;
398           out_row_buffer_[idx++] = index;
399         }
400         break;
401       }
402       case 16: {
403         auto buf =
404             fxcrt::reinterpret_span<uint16_t>(pdfium::make_span(dest_buf));
405         uint8_t blue_bits = 0;
406         uint8_t green_bits = 0;
407         uint8_t red_bits = 0;
408         for (int32_t i = 0; i < 16; i++) {
409           if ((mask_blue_ >> i) & 0x01)
410             blue_bits++;
411           if ((mask_green_ >> i) & 0x01)
412             green_bits++;
413           if ((mask_red_ >> i) & 0x01)
414             red_bits++;
415         }
416         green_bits += blue_bits;
417         red_bits += green_bits;
418         if (blue_bits > 8 || green_bits < 8 || red_bits < 8)
419           return BmpDecoder::Status::kContinue;
420         blue_bits = 8 - blue_bits;
421         green_bits -= 8;
422         red_bits -= 8;
423         for (uint32_t col = 0; col < width_; ++col) {
424           buf.front() = fxcrt::FromLE16(buf.front());
425           out_row_buffer_[idx++] =
426               static_cast<uint8_t>((buf.front() & mask_blue_) << blue_bits);
427           out_row_buffer_[idx++] =
428               static_cast<uint8_t>((buf.front() & mask_green_) >> green_bits);
429           out_row_buffer_[idx++] =
430               static_cast<uint8_t>((buf.front() & mask_red_) >> red_bits);
431           buf = buf.subspan(1);
432         }
433         break;
434       }
435       case 24:
436       case 32:
437         // TODO(crbug.com/pdfium/1901): Apply bitfields.
438         fxcrt::Copy(pdfium::make_span(dest_buf).first(src_row_bytes_),
439                     out_row_buffer_);
440         idx += src_row_bytes_;
441         break;
442     }
443     ReadNextScanline();
444   }
445   SaveDecodingStatus(DecodeStatus::kTail);
446   return BmpDecoder::Status::kSuccess;
447 }
448 
DecodeRLE8()449 BmpDecoder::Status CFX_BmpDecompressor::DecodeRLE8() {
450   uint8_t first_part;
451   col_num_ = 0;
452   while (true) {
453     if (!ReadAllOrNone(pdfium::span_from_ref(first_part))) {
454       return BmpDecoder::Status::kContinue;
455     }
456 
457     switch (first_part) {
458       case kRleMarker: {
459         if (!ReadAllOrNone(pdfium::span_from_ref(first_part))) {
460           return BmpDecoder::Status::kContinue;
461         }
462 
463         switch (first_part) {
464           case kRleEol: {
465             if (row_num_ >= height_) {
466               SaveDecodingStatus(DecodeStatus::kTail);
467               return BmpDecoder::Status::kFail;
468             }
469 
470             ReadNextScanline();
471             col_num_ = 0;
472             fxcrt::Fill(out_row_buffer_, 0);
473             SaveDecodingStatus(DecodeStatus::kData);
474             continue;
475           }
476           case kRleEoi: {
477             if (row_num_ < height_)
478               ReadNextScanline();
479             SaveDecodingStatus(DecodeStatus::kTail);
480             return BmpDecoder::Status::kSuccess;
481           }
482           case kRleDelta: {
483             uint8_t delta[2];
484             if (!ReadAllOrNone(delta))
485               return BmpDecoder::Status::kContinue;
486 
487             col_num_ += delta[0];
488             size_t bmp_row_num__next = row_num_ + delta[1];
489             if (col_num_ >= out_row_bytes_ || bmp_row_num__next >= height_)
490               return BmpDecoder::Status::kFail;
491 
492             while (row_num_ < bmp_row_num__next) {
493               fxcrt::Fill(out_row_buffer_, 0);
494               ReadNextScanline();
495             }
496             break;
497           }
498           default: {
499             int32_t avail_size =
500                 pdfium::checked_cast<int32_t>(out_row_bytes_ - col_num_);
501             if (!avail_size || static_cast<int32_t>(first_part) > avail_size)
502               return BmpDecoder::Status::kFail;
503 
504             size_t second_part_size =
505                 first_part & 1 ? first_part + 1 : first_part;
506             DataVector<uint8_t> second_part(second_part_size);
507             if (!ReadAllOrNone(second_part))
508               return BmpDecoder::Status::kContinue;
509 
510             fxcrt::Copy(pdfium::make_span(second_part).first(first_part),
511                         pdfium::make_span(out_row_buffer_).subspan(col_num_));
512 
513             for (size_t i = col_num_; i < col_num_ + first_part; ++i) {
514               if (!ValidateColorIndex(out_row_buffer_[i]))
515                 return BmpDecoder::Status::kFail;
516             }
517             col_num_ += first_part;
518           }
519         }
520         break;
521       }
522       default: {
523         int32_t avail_size =
524             pdfium::checked_cast<int32_t>(out_row_bytes_ - col_num_);
525         if (!avail_size || static_cast<int32_t>(first_part) > avail_size)
526           return BmpDecoder::Status::kFail;
527 
528         uint8_t second_part;
529         if (!ReadAllOrNone(pdfium::span_from_ref(second_part))) {
530           return BmpDecoder::Status::kContinue;
531         }
532 
533         fxcrt::Fill(
534             pdfium::make_span(out_row_buffer_).subspan(col_num_, first_part),
535             second_part);
536 
537         if (!ValidateColorIndex(out_row_buffer_[col_num_]))
538           return BmpDecoder::Status::kFail;
539         col_num_ += first_part;
540       }
541     }
542   }
543 }
544 
DecodeRLE4()545 BmpDecoder::Status CFX_BmpDecompressor::DecodeRLE4() {
546   uint8_t first_part;
547   col_num_ = 0;
548   while (true) {
549     if (!ReadAllOrNone(pdfium::span_from_ref(first_part))) {
550       return BmpDecoder::Status::kContinue;
551     }
552 
553     switch (first_part) {
554       case kRleMarker: {
555         if (!ReadAllOrNone(pdfium::span_from_ref(first_part))) {
556           return BmpDecoder::Status::kContinue;
557         }
558 
559         switch (first_part) {
560           case kRleEol: {
561             if (row_num_ >= height_) {
562               SaveDecodingStatus(DecodeStatus::kTail);
563               return BmpDecoder::Status::kFail;
564             }
565 
566             ReadNextScanline();
567             col_num_ = 0;
568             fxcrt::Fill(out_row_buffer_, 0);
569             SaveDecodingStatus(DecodeStatus::kData);
570             continue;
571           }
572           case kRleEoi: {
573             if (row_num_ < height_)
574               ReadNextScanline();
575             SaveDecodingStatus(DecodeStatus::kTail);
576             return BmpDecoder::Status::kSuccess;
577           }
578           case kRleDelta: {
579             uint8_t delta[2];
580             if (!ReadAllOrNone(delta))
581               return BmpDecoder::Status::kContinue;
582 
583             col_num_ += delta[0];
584             size_t bmp_row_num__next = row_num_ + delta[1];
585             if (col_num_ >= out_row_bytes_ || bmp_row_num__next >= height_)
586               return BmpDecoder::Status::kFail;
587 
588             while (row_num_ < bmp_row_num__next) {
589               fxcrt::Fill(out_row_buffer_, 0);
590               ReadNextScanline();
591             }
592             break;
593           }
594           default: {
595             int32_t avail_size =
596                 pdfium::checked_cast<int32_t>(out_row_bytes_ - col_num_);
597             if (!avail_size)
598               return BmpDecoder::Status::kFail;
599             uint8_t size = HalfRoundUp(first_part);
600             if (static_cast<int32_t>(first_part) > avail_size) {
601               if (size + (col_num_ >> 1) > src_row_bytes_)
602                 return BmpDecoder::Status::kFail;
603 
604               first_part = avail_size - 1;
605             }
606             size_t second_part_size = size & 1 ? size + 1 : size;
607             DataVector<uint8_t> second_part(second_part_size);
608             uint8_t* second_part_data = second_part.data();
609             if (!ReadAllOrNone(second_part))
610               return BmpDecoder::Status::kContinue;
611 
612             for (uint8_t i = 0; i < first_part; i++) {
613               uint8_t color = (i & 0x01)
614                                   ? UNSAFE_TODO((*second_part_data++ & 0x0F))
615                                   : (*second_part_data & 0xF0) >> 4;
616               if (!ValidateColorIndex(color)) {
617                 return BmpDecoder::Status::kFail;
618               }
619               out_row_buffer_[col_num_++] = color;
620             }
621           }
622         }
623         break;
624       }
625       default: {
626         int32_t avail_size =
627             pdfium::checked_cast<int32_t>(out_row_bytes_ - col_num_);
628         if (!avail_size)
629           return BmpDecoder::Status::kFail;
630 
631         if (static_cast<int32_t>(first_part) > avail_size) {
632           uint8_t size = HalfRoundUp(first_part);
633           if (size + (col_num_ >> 1) > src_row_bytes_)
634             return BmpDecoder::Status::kFail;
635 
636           first_part = avail_size - 1;
637         }
638         uint8_t second_part;
639         if (!ReadAllOrNone(pdfium::span_from_ref(second_part))) {
640           return BmpDecoder::Status::kContinue;
641         }
642 
643         for (uint8_t i = 0; i < first_part; i++) {
644           uint8_t second_byte = second_part;
645           second_byte =
646               i & 0x01 ? (second_byte & 0x0F) : (second_byte & 0xF0) >> 4;
647           if (!ValidateColorIndex(second_byte))
648             return BmpDecoder::Status::kFail;
649 
650           out_row_buffer_[col_num_++] = second_byte;
651         }
652       }
653     }
654   }
655 }
656 
ReadAllOrNone(pdfium::span<uint8_t> buf)657 bool CFX_BmpDecompressor::ReadAllOrNone(pdfium::span<uint8_t> buf) {
658   if (!input_buffer_)
659     return false;
660 
661   size_t original_position = input_buffer_->GetPosition();
662   size_t read = input_buffer_->ReadBlock(buf);
663   if (read < buf.size()) {
664     input_buffer_->Seek(original_position);
665     return false;
666   }
667 
668   return true;
669 }
670 
SaveDecodingStatus(DecodeStatus status)671 void CFX_BmpDecompressor::SaveDecodingStatus(DecodeStatus status) {
672   decode_status_ = status;
673 }
674 
SetInputBuffer(RetainPtr<CFX_CodecMemory> codec_memory)675 void CFX_BmpDecompressor::SetInputBuffer(
676     RetainPtr<CFX_CodecMemory> codec_memory) {
677   input_buffer_ = std::move(codec_memory);
678 }
679 
GetAvailInput() const680 FX_FILESIZE CFX_BmpDecompressor::GetAvailInput() const {
681   if (!input_buffer_)
682     return 0;
683 
684   return input_buffer_->GetSize() - input_buffer_->GetPosition();
685 }
686 
SetHeight(int32_t signed_height)687 bool CFX_BmpDecompressor::SetHeight(int32_t signed_height) {
688   if (signed_height >= 0) {
689     height_ = signed_height;
690     return true;
691   }
692   if (signed_height != std::numeric_limits<int>::min()) {
693     height_ = -signed_height;
694     img_tb_flag_ = true;
695     return true;
696   }
697   return false;
698 }
699 
700 }  // namespace fxcodec
701