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