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