| // Copyright 2014 PDFium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com |
| |
| #include "core/fxcodec/lbmp/fx_bmp.h" |
| |
| #include <algorithm> |
| #include <limits> |
| |
| #include "core/fxcrt/fx_system.h" |
| #include "third_party/base/logging.h" |
| #include "third_party/base/ptr_util.h" |
| |
| static_assert(sizeof(BmpFileHeader) == 14, |
| "BmpFileHeader should have a size of 14"); |
| |
| namespace { |
| |
| const size_t kBmpCoreHeaderSize = 12; |
| const size_t kBmpInfoHeaderSize = 40; |
| |
| uint8_t HalfRoundUp(uint8_t value) { |
| uint16_t value16 = value; |
| return static_cast<uint8_t>((value16 + 1) / 2); |
| } |
| |
| } // namespace |
| |
| BMPDecompressor::BMPDecompressor() |
| : context_ptr(nullptr), |
| next_in(nullptr), |
| header_offset(0), |
| width(0), |
| height(0), |
| compress_flag(0), |
| components(0), |
| src_row_bytes(0), |
| out_row_bytes(0), |
| bitCounts(0), |
| color_used(0), |
| imgTB_flag(false), |
| pal_num(0), |
| pal_type(0), |
| data_size(0), |
| img_data_offset(0), |
| img_ifh_size(0), |
| row_num(0), |
| col_num(0), |
| dpi_x(0), |
| dpi_y(0), |
| mask_red(0), |
| mask_green(0), |
| mask_blue(0), |
| avail_in(0), |
| skip_size(0), |
| decode_status(BMP_D_STATUS_HEADER) {} |
| |
| BMPDecompressor::~BMPDecompressor() {} |
| |
| void BMPDecompressor::Error() { |
| longjmp(jmpbuf, 1); |
| } |
| |
| void BMPDecompressor::ReadScanline(uint32_t row_num, |
| const std::vector<uint8_t>& row_buf) { |
| auto* p = reinterpret_cast<CBmpContext*>(context_ptr); |
| p->m_pDelegate->BmpReadScanline(row_num, row_buf); |
| } |
| |
| bool BMPDecompressor::GetDataPosition(uint32_t rcd_pos) { |
| auto* p = reinterpret_cast<CBmpContext*>(context_ptr); |
| return p->m_pDelegate->BmpInputImagePositionBuf(rcd_pos); |
| } |
| |
| int32_t BMPDecompressor::ReadHeader() { |
| uint32_t skip_size_org = skip_size; |
| if (decode_status == BMP_D_STATUS_HEADER) { |
| BmpFileHeader* pBmp_header = nullptr; |
| if (!ReadData(reinterpret_cast<uint8_t**>(&pBmp_header), |
| sizeof(BmpFileHeader))) { |
| return 2; |
| } |
| |
| pBmp_header->bfType = |
| FXWORD_GET_LSBFIRST(reinterpret_cast<uint8_t*>(&pBmp_header->bfType)); |
| pBmp_header->bfOffBits = FXDWORD_GET_LSBFIRST( |
| reinterpret_cast<uint8_t*>(&pBmp_header->bfOffBits)); |
| data_size = |
| FXDWORD_GET_LSBFIRST(reinterpret_cast<uint8_t*>(&pBmp_header->bfSize)); |
| if (pBmp_header->bfType != BMP_SIGNATURE) { |
| Error(); |
| NOTREACHED(); |
| } |
| if (avail_in < sizeof(uint32_t)) { |
| skip_size = skip_size_org; |
| return 2; |
| } |
| img_ifh_size = |
| FXDWORD_GET_LSBFIRST(static_cast<uint8_t*>(next_in + skip_size)); |
| pal_type = 0; |
| static_assert(sizeof(BmpCoreHeader) == kBmpCoreHeaderSize, |
| "BmpCoreHeader has wrong size"); |
| static_assert(sizeof(BmpInfoHeader) == kBmpInfoHeaderSize, |
| "BmpInfoHeader has wrong size"); |
| switch (img_ifh_size) { |
| case kBmpCoreHeaderSize: { |
| pal_type = 1; |
| BmpCoreHeader* pBmp_core_header = nullptr; |
| if (!ReadData(reinterpret_cast<uint8_t**>(&pBmp_core_header), |
| img_ifh_size)) { |
| skip_size = skip_size_org; |
| return 2; |
| } |
| width = FXWORD_GET_LSBFIRST( |
| reinterpret_cast<uint8_t*>(&pBmp_core_header->bcWidth)); |
| height = FXWORD_GET_LSBFIRST( |
| reinterpret_cast<uint8_t*>(&pBmp_core_header->bcHeight)); |
| bitCounts = FXWORD_GET_LSBFIRST( |
| reinterpret_cast<uint8_t*>(&pBmp_core_header->bcBitCount)); |
| compress_flag = BMP_RGB; |
| imgTB_flag = false; |
| } break; |
| case kBmpInfoHeaderSize: { |
| BmpInfoHeader* pBmp_info_header = nullptr; |
| if (!ReadData(reinterpret_cast<uint8_t**>(&pBmp_info_header), |
| img_ifh_size)) { |
| skip_size = skip_size_org; |
| return 2; |
| } |
| width = FXDWORD_GET_LSBFIRST( |
| reinterpret_cast<uint8_t*>(&pBmp_info_header->biWidth)); |
| int32_t signed_height = FXDWORD_GET_LSBFIRST( |
| reinterpret_cast<uint8_t*>(&pBmp_info_header->biHeight)); |
| bitCounts = FXWORD_GET_LSBFIRST( |
| reinterpret_cast<uint8_t*>(&pBmp_info_header->biBitCount)); |
| compress_flag = FXDWORD_GET_LSBFIRST( |
| reinterpret_cast<uint8_t*>(&pBmp_info_header->biCompression)); |
| color_used = FXDWORD_GET_LSBFIRST( |
| reinterpret_cast<uint8_t*>(&pBmp_info_header->biClrUsed)); |
| dpi_x = static_cast<int32_t>(FXDWORD_GET_LSBFIRST( |
| reinterpret_cast<uint8_t*>(&pBmp_info_header->biXPelsPerMeter))); |
| dpi_y = static_cast<int32_t>(FXDWORD_GET_LSBFIRST( |
| reinterpret_cast<uint8_t*>(&pBmp_info_header->biYPelsPerMeter))); |
| SetHeight(signed_height); |
| } break; |
| default: { |
| if (img_ifh_size > |
| std::min(kBmpInfoHeaderSize, sizeof(BmpInfoHeader))) { |
| BmpInfoHeader* pBmp_info_header = nullptr; |
| if (!ReadData(reinterpret_cast<uint8_t**>(&pBmp_info_header), |
| img_ifh_size)) { |
| skip_size = skip_size_org; |
| return 2; |
| } |
| uint16_t biPlanes; |
| width = FXDWORD_GET_LSBFIRST( |
| reinterpret_cast<uint8_t*>(&pBmp_info_header->biWidth)); |
| int32_t signed_height = FXDWORD_GET_LSBFIRST( |
| reinterpret_cast<uint8_t*>(&pBmp_info_header->biHeight)); |
| bitCounts = FXWORD_GET_LSBFIRST( |
| reinterpret_cast<uint8_t*>(&pBmp_info_header->biBitCount)); |
| compress_flag = FXDWORD_GET_LSBFIRST( |
| reinterpret_cast<uint8_t*>(&pBmp_info_header->biCompression)); |
| color_used = FXDWORD_GET_LSBFIRST( |
| reinterpret_cast<uint8_t*>(&pBmp_info_header->biClrUsed)); |
| biPlanes = FXWORD_GET_LSBFIRST( |
| reinterpret_cast<uint8_t*>(&pBmp_info_header->biPlanes)); |
| dpi_x = FXDWORD_GET_LSBFIRST( |
| reinterpret_cast<uint8_t*>(&pBmp_info_header->biXPelsPerMeter)); |
| dpi_y = FXDWORD_GET_LSBFIRST( |
| reinterpret_cast<uint8_t*>(&pBmp_info_header->biYPelsPerMeter)); |
| SetHeight(signed_height); |
| if (compress_flag == BMP_RGB && biPlanes == 1 && color_used == 0) |
| break; |
| } |
| Error(); |
| NOTREACHED(); |
| } |
| } |
| if (width > BMP_MAX_WIDTH || compress_flag > BMP_BITFIELDS) { |
| Error(); |
| NOTREACHED(); |
| } |
| switch (bitCounts) { |
| case 1: |
| case 4: |
| case 8: |
| case 16: |
| case 24: { |
| if (color_used > 1U << bitCounts) { |
| Error(); |
| NOTREACHED(); |
| } |
| } |
| case 32: |
| break; |
| default: |
| Error(); |
| NOTREACHED(); |
| } |
| src_row_bytes = BMP_WIDTHBYTES(width, bitCounts); |
| switch (bitCounts) { |
| case 1: |
| case 4: |
| case 8: |
| out_row_bytes = BMP_WIDTHBYTES(width, 8); |
| components = 1; |
| break; |
| case 16: |
| case 24: |
| out_row_bytes = BMP_WIDTHBYTES(width, 24); |
| components = 3; |
| break; |
| case 32: |
| out_row_bytes = src_row_bytes; |
| components = 4; |
| break; |
| } |
| out_row_buffer.clear(); |
| |
| if (out_row_bytes <= 0) { |
| Error(); |
| NOTREACHED(); |
| } |
| |
| out_row_buffer.resize(out_row_bytes); |
| SaveDecodingStatus(BMP_D_STATUS_PAL); |
| } |
| if (decode_status == BMP_D_STATUS_PAL) { |
| skip_size_org = skip_size; |
| if (compress_flag == BMP_BITFIELDS) { |
| if (bitCounts != 16 && bitCounts != 32) { |
| Error(); |
| NOTREACHED(); |
| } |
| uint32_t* mask; |
| if (ReadData(reinterpret_cast<uint8_t**>(&mask), 3 * sizeof(uint32_t)) == |
| nullptr) { |
| skip_size = skip_size_org; |
| return 2; |
| } |
| mask_red = FXDWORD_GET_LSBFIRST(reinterpret_cast<uint8_t*>(&mask[0])); |
| mask_green = FXDWORD_GET_LSBFIRST(reinterpret_cast<uint8_t*>(&mask[1])); |
| mask_blue = FXDWORD_GET_LSBFIRST(reinterpret_cast<uint8_t*>(&mask[2])); |
| if (mask_red & mask_green || mask_red & mask_blue || |
| mask_green & mask_blue) { |
| Error(); |
| NOTREACHED(); |
| } |
| header_offset = std::max(header_offset, 26 + img_ifh_size); |
| SaveDecodingStatus(BMP_D_STATUS_DATA_PRE); |
| return 1; |
| } else if (bitCounts == 16) { |
| mask_red = 0x7C00; |
| mask_green = 0x03E0; |
| mask_blue = 0x001F; |
| } |
| pal_num = 0; |
| if (bitCounts < 16) { |
| pal_num = 1 << bitCounts; |
| if (color_used != 0) |
| pal_num = color_used; |
| uint8_t* src_pal_ptr = nullptr; |
| uint32_t src_pal_size = pal_num * (pal_type ? 3 : 4); |
| if (ReadData(&src_pal_ptr, src_pal_size) == nullptr) { |
| skip_size = skip_size_org; |
| return 2; |
| } |
| palette.resize(pal_num); |
| int32_t src_pal_index = 0; |
| if (pal_type == BMP_PAL_OLD) { |
| while (src_pal_index < pal_num) { |
| palette[src_pal_index++] = BMP_PAL_ENCODE( |
| 0x00, src_pal_ptr[2], src_pal_ptr[1], src_pal_ptr[0]); |
| src_pal_ptr += 3; |
| } |
| } else { |
| while (src_pal_index < pal_num) { |
| palette[src_pal_index++] = BMP_PAL_ENCODE( |
| src_pal_ptr[3], src_pal_ptr[2], src_pal_ptr[1], src_pal_ptr[0]); |
| src_pal_ptr += 4; |
| } |
| } |
| } |
| header_offset = std::max(header_offset, |
| 14 + img_ifh_size + pal_num * (pal_type ? 3 : 4)); |
| SaveDecodingStatus(BMP_D_STATUS_DATA_PRE); |
| } |
| return 1; |
| } |
| |
| bool BMPDecompressor::ValidateFlag() const { |
| switch (compress_flag) { |
| case BMP_RGB: |
| case BMP_BITFIELDS: |
| case BMP_RLE8: |
| case BMP_RLE4: |
| return true; |
| default: |
| return false; |
| } |
| } |
| |
| int32_t BMPDecompressor::DecodeImage() { |
| if (decode_status == BMP_D_STATUS_DATA_PRE) { |
| avail_in = 0; |
| if (!GetDataPosition(header_offset)) { |
| decode_status = BMP_D_STATUS_TAIL; |
| Error(); |
| NOTREACHED(); |
| } |
| row_num = 0; |
| SaveDecodingStatus(BMP_D_STATUS_DATA); |
| } |
| if (decode_status != BMP_D_STATUS_DATA || !ValidateFlag()) { |
| Error(); |
| NOTREACHED(); |
| } |
| switch (compress_flag) { |
| case BMP_RGB: |
| case BMP_BITFIELDS: |
| return DecodeRGB(); |
| case BMP_RLE8: |
| return DecodeRLE8(); |
| case BMP_RLE4: |
| return DecodeRLE4(); |
| default: |
| return 0; |
| } |
| } |
| |
| bool BMPDecompressor::ValidateColorIndex(uint8_t val) { |
| if (val >= pal_num) { |
| Error(); |
| NOTREACHED(); |
| } |
| return true; |
| } |
| |
| int32_t BMPDecompressor::DecodeRGB() { |
| uint8_t* des_buf = nullptr; |
| while (row_num < height) { |
| size_t idx = 0; |
| if (!ReadData(&des_buf, src_row_bytes)) |
| return 2; |
| |
| SaveDecodingStatus(BMP_D_STATUS_DATA); |
| switch (bitCounts) { |
| case 1: { |
| for (uint32_t col = 0; col < width; ++col) |
| out_row_buffer[idx++] = |
| des_buf[col >> 3] & (0x80 >> (col % 8)) ? 0x01 : 0x00; |
| } break; |
| case 4: { |
| for (uint32_t col = 0; col < width; ++col) { |
| out_row_buffer[idx++] = (col & 0x01) |
| ? (des_buf[col >> 1] & 0x0F) |
| : ((des_buf[col >> 1] & 0xF0) >> 4); |
| } |
| } break; |
| case 16: { |
| uint16_t* buf = (uint16_t*)des_buf; |
| uint8_t blue_bits = 0; |
| uint8_t green_bits = 0; |
| uint8_t red_bits = 0; |
| for (int32_t i = 0; i < 16; i++) { |
| if ((mask_blue >> i) & 0x01) |
| blue_bits++; |
| if ((mask_green >> i) & 0x01) |
| green_bits++; |
| if ((mask_red >> i) & 0x01) |
| red_bits++; |
| } |
| green_bits += blue_bits; |
| red_bits += green_bits; |
| if (blue_bits > 8 || green_bits < 8 || red_bits < 8) |
| return 2; |
| blue_bits = 8 - blue_bits; |
| green_bits -= 8; |
| red_bits -= 8; |
| for (uint32_t col = 0; col < width; ++col) { |
| *buf = FXWORD_GET_LSBFIRST(reinterpret_cast<uint8_t*>(buf)); |
| out_row_buffer[idx++] = |
| static_cast<uint8_t>((*buf & mask_blue) << blue_bits); |
| out_row_buffer[idx++] = |
| static_cast<uint8_t>((*buf & mask_green) >> green_bits); |
| out_row_buffer[idx++] = |
| static_cast<uint8_t>((*buf++ & mask_red) >> red_bits); |
| } |
| } break; |
| case 8: |
| case 24: |
| case 32: |
| std::copy(des_buf, des_buf + src_row_bytes, out_row_buffer.begin()); |
| idx += src_row_bytes; |
| break; |
| } |
| for (uint8_t byte : out_row_buffer) { |
| if (!ValidateColorIndex(byte)) |
| return 0; |
| } |
| ReadScanline(imgTB_flag ? row_num++ : (height - 1 - row_num++), |
| out_row_buffer); |
| } |
| SaveDecodingStatus(BMP_D_STATUS_TAIL); |
| return 1; |
| } |
| |
| int32_t BMPDecompressor::DecodeRLE8() { |
| uint8_t* first_byte_ptr = nullptr; |
| uint8_t* second_byte_ptr = nullptr; |
| col_num = 0; |
| while (true) { |
| uint32_t skip_size_org = skip_size; |
| if (!ReadData(&first_byte_ptr, 1)) |
| return 2; |
| |
| switch (*first_byte_ptr) { |
| case RLE_MARKER: { |
| if (!ReadData(&first_byte_ptr, 1)) { |
| skip_size = skip_size_org; |
| return 2; |
| } |
| switch (*first_byte_ptr) { |
| case RLE_EOL: { |
| if (row_num >= height) { |
| SaveDecodingStatus(BMP_D_STATUS_TAIL); |
| Error(); |
| NOTREACHED(); |
| } |
| ReadScanline(imgTB_flag ? row_num++ : (height - 1 - row_num++), |
| out_row_buffer); |
| col_num = 0; |
| std::fill(out_row_buffer.begin(), out_row_buffer.end(), 0); |
| SaveDecodingStatus(BMP_D_STATUS_DATA); |
| continue; |
| } |
| case RLE_EOI: { |
| if (row_num < height) { |
| ReadScanline(imgTB_flag ? row_num++ : (height - 1 - row_num++), |
| out_row_buffer); |
| } |
| SaveDecodingStatus(BMP_D_STATUS_TAIL); |
| return 1; |
| } |
| case RLE_DELTA: { |
| uint8_t* delta_ptr; |
| if (!ReadData(&delta_ptr, 2)) { |
| skip_size = skip_size_org; |
| return 2; |
| } |
| col_num += delta_ptr[0]; |
| size_t bmp_row_num_next = row_num + delta_ptr[1]; |
| if (col_num >= out_row_bytes || bmp_row_num_next >= height) { |
| Error(); |
| NOTREACHED(); |
| } |
| while (row_num < bmp_row_num_next) { |
| std::fill(out_row_buffer.begin(), out_row_buffer.end(), 0); |
| ReadScanline(imgTB_flag ? row_num++ : (height - 1 - row_num++), |
| out_row_buffer); |
| } |
| } break; |
| default: { |
| int32_t avail_size = out_row_bytes - col_num; |
| if (!avail_size || |
| static_cast<int32_t>(*first_byte_ptr) > avail_size) { |
| Error(); |
| NOTREACHED(); |
| } |
| if (!ReadData(&second_byte_ptr, *first_byte_ptr & 1 |
| ? *first_byte_ptr + 1 |
| : *first_byte_ptr)) { |
| skip_size = skip_size_org; |
| return 2; |
| } |
| std::copy(second_byte_ptr, second_byte_ptr + *first_byte_ptr, |
| out_row_buffer.begin() + col_num); |
| for (size_t i = col_num; i < col_num + *first_byte_ptr; ++i) { |
| if (!ValidateColorIndex(out_row_buffer[i])) |
| return 0; |
| } |
| col_num += *first_byte_ptr; |
| } |
| } |
| } break; |
| default: { |
| int32_t avail_size = out_row_bytes - col_num; |
| if (!avail_size || static_cast<int32_t>(*first_byte_ptr) > avail_size) { |
| Error(); |
| NOTREACHED(); |
| } |
| if (!ReadData(&second_byte_ptr, 1)) { |
| skip_size = skip_size_org; |
| return 2; |
| } |
| std::fill(out_row_buffer.begin() + col_num, |
| out_row_buffer.begin() + col_num + *first_byte_ptr, |
| *second_byte_ptr); |
| if (!ValidateColorIndex(out_row_buffer[col_num])) |
| return 0; |
| col_num += *first_byte_ptr; |
| } |
| } |
| } |
| Error(); |
| NOTREACHED(); |
| } |
| |
| int32_t BMPDecompressor::DecodeRLE4() { |
| uint8_t* first_byte_ptr = nullptr; |
| uint8_t* second_byte_ptr = nullptr; |
| col_num = 0; |
| while (true) { |
| uint32_t skip_size_org = skip_size; |
| if (!ReadData(&first_byte_ptr, 1)) |
| return 2; |
| |
| switch (*first_byte_ptr) { |
| case RLE_MARKER: { |
| if (!ReadData(&first_byte_ptr, 1)) { |
| skip_size = skip_size_org; |
| return 2; |
| } |
| switch (*first_byte_ptr) { |
| case RLE_EOL: { |
| if (row_num >= height) { |
| SaveDecodingStatus(BMP_D_STATUS_TAIL); |
| Error(); |
| NOTREACHED(); |
| } |
| ReadScanline(imgTB_flag ? row_num++ : (height - 1 - row_num++), |
| out_row_buffer); |
| col_num = 0; |
| std::fill(out_row_buffer.begin(), out_row_buffer.end(), 0); |
| SaveDecodingStatus(BMP_D_STATUS_DATA); |
| continue; |
| } |
| case RLE_EOI: { |
| if (row_num < height) { |
| ReadScanline(imgTB_flag ? row_num++ : (height - 1 - row_num++), |
| out_row_buffer); |
| } |
| SaveDecodingStatus(BMP_D_STATUS_TAIL); |
| return 1; |
| } |
| case RLE_DELTA: { |
| uint8_t* delta_ptr; |
| if (!ReadData(&delta_ptr, 2)) { |
| skip_size = skip_size_org; |
| return 2; |
| } |
| col_num += delta_ptr[0]; |
| size_t bmp_row_num_next = row_num + delta_ptr[1]; |
| if (col_num >= out_row_bytes || bmp_row_num_next >= height) { |
| Error(); |
| NOTREACHED(); |
| } |
| while (row_num < bmp_row_num_next) { |
| std::fill(out_row_buffer.begin(), out_row_buffer.end(), 0); |
| ReadScanline(imgTB_flag ? row_num++ : (height - 1 - row_num++), |
| out_row_buffer); |
| } |
| } break; |
| default: { |
| int32_t avail_size = out_row_bytes - col_num; |
| if (!avail_size) { |
| Error(); |
| NOTREACHED(); |
| } |
| uint8_t size = HalfRoundUp(*first_byte_ptr); |
| if (static_cast<int32_t>(*first_byte_ptr) > avail_size) { |
| if (size + (col_num >> 1) > src_row_bytes) { |
| Error(); |
| NOTREACHED(); |
| } |
| *first_byte_ptr = avail_size - 1; |
| } |
| if (!ReadData(&second_byte_ptr, size & 1 ? size + 1 : size)) { |
| skip_size = skip_size_org; |
| return 2; |
| } |
| for (uint8_t i = 0; i < *first_byte_ptr; i++) { |
| uint8_t color = (i & 0x01) ? (*second_byte_ptr++ & 0x0F) |
| : (*second_byte_ptr & 0xF0) >> 4; |
| if (!ValidateColorIndex(color)) |
| return 0; |
| |
| out_row_buffer[col_num++] = color; |
| } |
| } |
| } |
| } break; |
| default: { |
| int32_t avail_size = out_row_bytes - col_num; |
| if (!avail_size) { |
| Error(); |
| NOTREACHED(); |
| } |
| if (static_cast<int32_t>(*first_byte_ptr) > avail_size) { |
| uint8_t size = HalfRoundUp(*first_byte_ptr); |
| if (size + (col_num >> 1) > src_row_bytes) { |
| Error(); |
| NOTREACHED(); |
| } |
| *first_byte_ptr = avail_size - 1; |
| } |
| if (!ReadData(&second_byte_ptr, 1)) { |
| skip_size = skip_size_org; |
| return 2; |
| } |
| for (uint8_t i = 0; i < *first_byte_ptr; i++) { |
| uint8_t second_byte = *second_byte_ptr; |
| second_byte = |
| i & 0x01 ? (second_byte & 0x0F) : (second_byte & 0xF0) >> 4; |
| if (!ValidateColorIndex(second_byte)) |
| return 0; |
| out_row_buffer[col_num++] = second_byte; |
| } |
| } |
| } |
| } |
| Error(); |
| NOTREACHED(); |
| } |
| |
| uint8_t* BMPDecompressor::ReadData(uint8_t** des_buf, uint32_t data_size) { |
| if (avail_in < skip_size + data_size) |
| return nullptr; |
| |
| *des_buf = next_in + skip_size; |
| skip_size += data_size; |
| return *des_buf; |
| } |
| |
| void BMPDecompressor::SaveDecodingStatus(int32_t status) { |
| decode_status = status; |
| next_in += skip_size; |
| avail_in -= skip_size; |
| skip_size = 0; |
| } |
| |
| void BMPDecompressor::SetInputBuffer(uint8_t* src_buf, uint32_t src_size) { |
| next_in = src_buf; |
| avail_in = src_size; |
| skip_size = 0; |
| } |
| |
| uint32_t BMPDecompressor::GetAvailInput(uint8_t** avail_buf) { |
| if (avail_buf) { |
| *avail_buf = nullptr; |
| if (avail_in > 0) |
| *avail_buf = next_in; |
| } |
| return avail_in; |
| } |
| |
| void BMPDecompressor::SetHeight(int32_t signed_height) { |
| if (signed_height >= 0) { |
| height = signed_height; |
| return; |
| } |
| if (signed_height == std::numeric_limits<int>::min()) { |
| Error(); |
| NOTREACHED(); |
| } |
| height = -signed_height; |
| imgTB_flag = true; |
| } |