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