Home | History | Annotate | Download | only in lbmp
      1 // Copyright 2014 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/lbmp/fx_bmp.h"
      8 
      9 #include <algorithm>
     10 
     11 namespace {
     12 
     13 const size_t kBmpCoreHeaderSize = 12;
     14 const size_t kBmpInfoHeaderSize = 40;
     15 
     16 // TODO(thestig): Replace with FXDWORD_GET_LSBFIRST?
     17 uint32_t GetDWord_LSBFirst(uint8_t* p) {
     18   return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
     19 }
     20 
     21 void SetDWord_LSBFirst(uint8_t* p, uint32_t v) {
     22   p[0] = (uint8_t)v;
     23   p[1] = (uint8_t)(v >> 8);
     24   p[2] = (uint8_t)(v >> 16);
     25   p[3] = (uint8_t)(v >> 24);
     26 }
     27 }  // namespace
     28 
     29 uint16_t GetWord_LSBFirst(uint8_t* p) {
     30   return p[0] | (p[1] << 8);
     31 }
     32 void SetWord_LSBFirst(uint8_t* p, uint16_t v) {
     33   p[0] = (uint8_t)v;
     34   p[1] = (uint8_t)(v >> 8);
     35 }
     36 void bmp_error(bmp_decompress_struct_p bmp_ptr, const FX_CHAR* err_msg) {
     37   if (bmp_ptr && bmp_ptr->bmp_error_fn) {
     38     bmp_ptr->bmp_error_fn(bmp_ptr, err_msg);
     39   }
     40 }
     41 bmp_decompress_struct_p bmp_create_decompress() {
     42   bmp_decompress_struct_p bmp_ptr = FX_Alloc(bmp_decompress_struct, 1);
     43   FXSYS_memset(bmp_ptr, 0, sizeof(bmp_decompress_struct));
     44   bmp_ptr->decode_status = BMP_D_STATUS_HEADER;
     45   bmp_ptr->bmp_header_ptr = FX_Alloc(BmpFileHeader, 1);
     46   return bmp_ptr;
     47 }
     48 void bmp_destroy_decompress(bmp_decompress_struct_pp bmp_ptr_ptr) {
     49   if (!bmp_ptr_ptr || !*bmp_ptr_ptr)
     50     return;
     51 
     52   bmp_decompress_struct_p bmp_ptr = *bmp_ptr_ptr;
     53   *bmp_ptr_ptr = nullptr;
     54   if (bmp_ptr->out_row_buffer) {
     55     FX_Free(bmp_ptr->out_row_buffer);
     56   }
     57   FX_Free(bmp_ptr->pal_ptr);
     58   FX_Free(bmp_ptr->bmp_header_ptr);
     59   FX_Free(bmp_ptr);
     60 }
     61 int32_t bmp_read_header(bmp_decompress_struct_p bmp_ptr) {
     62   if (!bmp_ptr)
     63     return 0;
     64 
     65   uint32_t skip_size_org = bmp_ptr->skip_size;
     66   if (bmp_ptr->decode_status == BMP_D_STATUS_HEADER) {
     67     ASSERT(sizeof(BmpFileHeader) == 14);
     68     BmpFileHeader* bmp_header_ptr = nullptr;
     69     if (!bmp_read_data(bmp_ptr, (uint8_t**)&bmp_header_ptr, 14))
     70       return 2;
     71 
     72     bmp_ptr->bmp_header_ptr->bfType =
     73         GetWord_LSBFirst((uint8_t*)&bmp_header_ptr->bfType);
     74     bmp_ptr->bmp_header_ptr->bfOffBits =
     75         GetDWord_LSBFirst((uint8_t*)&bmp_header_ptr->bfOffBits);
     76     bmp_ptr->data_size = GetDWord_LSBFirst((uint8_t*)&bmp_header_ptr->bfSize);
     77     if (bmp_ptr->bmp_header_ptr->bfType != BMP_SIGNATURE) {
     78       bmp_error(bmp_ptr, "Not A Bmp Image");
     79       return 0;
     80     }
     81     if (bmp_ptr->avail_in < sizeof(uint32_t)) {
     82       bmp_ptr->skip_size = skip_size_org;
     83       return 2;
     84     }
     85     bmp_ptr->img_ifh_size =
     86         GetDWord_LSBFirst(bmp_ptr->next_in + bmp_ptr->skip_size);
     87     bmp_ptr->pal_type = 0;
     88     static_assert(sizeof(BmpCoreHeader) == kBmpCoreHeaderSize,
     89                   "BmpCoreHeader has wrong size");
     90     static_assert(sizeof(BmpInfoHeader) == kBmpInfoHeaderSize,
     91                   "BmpInfoHeader has wrong size");
     92     switch (bmp_ptr->img_ifh_size) {
     93       case kBmpCoreHeaderSize: {
     94         bmp_ptr->pal_type = 1;
     95         BmpCoreHeaderPtr bmp_core_header_ptr = nullptr;
     96         if (!bmp_read_data(bmp_ptr, (uint8_t**)&bmp_core_header_ptr,
     97                            bmp_ptr->img_ifh_size)) {
     98           bmp_ptr->skip_size = skip_size_org;
     99           return 2;
    100         }
    101         bmp_ptr->width =
    102             GetWord_LSBFirst((uint8_t*)&bmp_core_header_ptr->bcWidth);
    103         bmp_ptr->height =
    104             GetWord_LSBFirst((uint8_t*)&bmp_core_header_ptr->bcHeight);
    105         bmp_ptr->bitCounts =
    106             GetWord_LSBFirst((uint8_t*)&bmp_core_header_ptr->bcBitCount);
    107         bmp_ptr->compress_flag = BMP_RGB;
    108         bmp_ptr->imgTB_flag = false;
    109       } break;
    110       case kBmpInfoHeaderSize: {
    111         BmpInfoHeaderPtr bmp_info_header_ptr = nullptr;
    112         if (!bmp_read_data(bmp_ptr, (uint8_t**)&bmp_info_header_ptr,
    113                            bmp_ptr->img_ifh_size)) {
    114           bmp_ptr->skip_size = skip_size_org;
    115           return 2;
    116         }
    117         bmp_ptr->width =
    118             GetDWord_LSBFirst((uint8_t*)&bmp_info_header_ptr->biWidth);
    119         bmp_ptr->height =
    120             GetDWord_LSBFirst((uint8_t*)&bmp_info_header_ptr->biHeight);
    121         bmp_ptr->bitCounts =
    122             GetWord_LSBFirst((uint8_t*)&bmp_info_header_ptr->biBitCount);
    123         bmp_ptr->compress_flag =
    124             GetDWord_LSBFirst((uint8_t*)&bmp_info_header_ptr->biCompression);
    125         bmp_ptr->color_used =
    126             GetDWord_LSBFirst((uint8_t*)&bmp_info_header_ptr->biClrUsed);
    127         bmp_ptr->dpi_x = (int32_t)GetDWord_LSBFirst(
    128             (uint8_t*)&bmp_info_header_ptr->biXPelsPerMeter);
    129         bmp_ptr->dpi_y = (int32_t)GetDWord_LSBFirst(
    130             (uint8_t*)&bmp_info_header_ptr->biYPelsPerMeter);
    131         if (bmp_ptr->height < 0) {
    132           bmp_ptr->height = -bmp_ptr->height;
    133           bmp_ptr->imgTB_flag = true;
    134         }
    135       } break;
    136       default: {
    137         if (bmp_ptr->img_ifh_size >
    138             std::min(kBmpInfoHeaderSize, sizeof(BmpInfoHeader))) {
    139           BmpInfoHeaderPtr bmp_info_header_ptr = nullptr;
    140           if (!bmp_read_data(bmp_ptr, (uint8_t**)&bmp_info_header_ptr,
    141                              bmp_ptr->img_ifh_size)) {
    142             bmp_ptr->skip_size = skip_size_org;
    143             return 2;
    144           }
    145           uint16_t biPlanes;
    146           bmp_ptr->width =
    147               GetDWord_LSBFirst((uint8_t*)&bmp_info_header_ptr->biWidth);
    148           bmp_ptr->height =
    149               GetDWord_LSBFirst((uint8_t*)&bmp_info_header_ptr->biHeight);
    150           bmp_ptr->bitCounts =
    151               GetWord_LSBFirst((uint8_t*)&bmp_info_header_ptr->biBitCount);
    152           bmp_ptr->compress_flag =
    153               GetDWord_LSBFirst((uint8_t*)&bmp_info_header_ptr->biCompression);
    154           bmp_ptr->color_used =
    155               GetDWord_LSBFirst((uint8_t*)&bmp_info_header_ptr->biClrUsed);
    156           biPlanes = GetWord_LSBFirst((uint8_t*)&bmp_info_header_ptr->biPlanes);
    157           bmp_ptr->dpi_x = GetDWord_LSBFirst(
    158               (uint8_t*)&bmp_info_header_ptr->biXPelsPerMeter);
    159           bmp_ptr->dpi_y = GetDWord_LSBFirst(
    160               (uint8_t*)&bmp_info_header_ptr->biYPelsPerMeter);
    161           if (bmp_ptr->height < 0) {
    162             bmp_ptr->height = -bmp_ptr->height;
    163             bmp_ptr->imgTB_flag = true;
    164           }
    165           if (bmp_ptr->compress_flag == BMP_RGB && biPlanes == 1 &&
    166               bmp_ptr->color_used == 0) {
    167             break;
    168           }
    169         }
    170         bmp_error(bmp_ptr, "Unsupported Bmp File");
    171         return 0;
    172       }
    173     }
    174     if (bmp_ptr->width <= 0 || bmp_ptr->compress_flag > BMP_BITFIELDS) {
    175       bmp_error(bmp_ptr, "The Bmp File Is Corrupt");
    176       return 0;
    177     }
    178     switch (bmp_ptr->bitCounts) {
    179       case 1:
    180       case 4:
    181       case 8:
    182       case 16:
    183       case 24: {
    184         if (bmp_ptr->color_used > ((uint32_t)1) << bmp_ptr->bitCounts) {
    185           bmp_error(bmp_ptr, "The Bmp File Is Corrupt");
    186           return 0;
    187         }
    188       }
    189       case 32:
    190         break;
    191       default:
    192         bmp_error(bmp_ptr, "The Bmp File Is Corrupt");
    193         return 0;
    194     }
    195     bmp_ptr->src_row_bytes = BMP_WIDTHBYTES(bmp_ptr->width, bmp_ptr->bitCounts);
    196     switch (bmp_ptr->bitCounts) {
    197       case 1:
    198       case 4:
    199       case 8:
    200         bmp_ptr->out_row_bytes = BMP_WIDTHBYTES(bmp_ptr->width, 8);
    201         bmp_ptr->components = 1;
    202         break;
    203       case 16:
    204       case 24:
    205         bmp_ptr->out_row_bytes = BMP_WIDTHBYTES(bmp_ptr->width, 24);
    206         bmp_ptr->components = 3;
    207         break;
    208       case 32:
    209         bmp_ptr->out_row_bytes = bmp_ptr->src_row_bytes;
    210         bmp_ptr->components = 4;
    211         break;
    212     }
    213     FX_Free(bmp_ptr->out_row_buffer);
    214 
    215     if (bmp_ptr->out_row_bytes <= 0) {
    216       bmp_error(bmp_ptr, "The Bmp File Is Corrupt");
    217       return 0;
    218     }
    219 
    220     bmp_ptr->out_row_buffer = FX_Alloc(uint8_t, bmp_ptr->out_row_bytes);
    221     FXSYS_memset(bmp_ptr->out_row_buffer, 0, bmp_ptr->out_row_bytes);
    222     bmp_save_decoding_status(bmp_ptr, BMP_D_STATUS_PAL);
    223   }
    224   if (bmp_ptr->decode_status == BMP_D_STATUS_PAL) {
    225     skip_size_org = bmp_ptr->skip_size;
    226     if (bmp_ptr->compress_flag == BMP_BITFIELDS) {
    227       if (bmp_ptr->bitCounts != 16 && bmp_ptr->bitCounts != 32) {
    228         bmp_error(bmp_ptr, "The Bmp File Is Corrupt");
    229         return 0;
    230       }
    231       uint32_t* mask;
    232       if (bmp_read_data(bmp_ptr, (uint8_t**)&mask, 3 * sizeof(uint32_t)) ==
    233           nullptr) {
    234         bmp_ptr->skip_size = skip_size_org;
    235         return 2;
    236       }
    237       bmp_ptr->mask_red = GetDWord_LSBFirst((uint8_t*)&mask[0]);
    238       bmp_ptr->mask_green = GetDWord_LSBFirst((uint8_t*)&mask[1]);
    239       bmp_ptr->mask_blue = GetDWord_LSBFirst((uint8_t*)&mask[2]);
    240       if (bmp_ptr->mask_red & bmp_ptr->mask_green ||
    241           bmp_ptr->mask_red & bmp_ptr->mask_blue ||
    242           bmp_ptr->mask_green & bmp_ptr->mask_blue) {
    243         bmp_error(bmp_ptr, "The Bitfield Bmp File Is Corrupt");
    244         return 0;
    245       }
    246       if (bmp_ptr->bmp_header_ptr->bfOffBits < 26 + bmp_ptr->img_ifh_size) {
    247         bmp_ptr->bmp_header_ptr->bfOffBits = 26 + bmp_ptr->img_ifh_size;
    248       }
    249       bmp_save_decoding_status(bmp_ptr, BMP_D_STATUS_DATA_PRE);
    250       return 1;
    251     } else if (bmp_ptr->bitCounts == 16) {
    252       bmp_ptr->mask_red = 0x7C00;
    253       bmp_ptr->mask_green = 0x03E0;
    254       bmp_ptr->mask_blue = 0x001F;
    255     }
    256     bmp_ptr->pal_num = 0;
    257     if (bmp_ptr->bitCounts < 16) {
    258       bmp_ptr->pal_num = 1 << bmp_ptr->bitCounts;
    259       if (bmp_ptr->color_used != 0) {
    260         bmp_ptr->pal_num = bmp_ptr->color_used;
    261       }
    262       uint8_t* src_pal_ptr = nullptr;
    263       uint32_t src_pal_size = bmp_ptr->pal_num * (bmp_ptr->pal_type ? 3 : 4);
    264       if (bmp_read_data(bmp_ptr, (uint8_t**)&src_pal_ptr, src_pal_size) ==
    265           nullptr) {
    266         bmp_ptr->skip_size = skip_size_org;
    267         return 2;
    268       }
    269       FX_Free(bmp_ptr->pal_ptr);
    270       bmp_ptr->pal_ptr = FX_Alloc(uint32_t, bmp_ptr->pal_num);
    271       int32_t src_pal_index = 0;
    272       if (bmp_ptr->pal_type == BMP_PAL_OLD) {
    273         while (src_pal_index < bmp_ptr->pal_num) {
    274           bmp_ptr->pal_ptr[src_pal_index++] = BMP_PAL_ENCODE(
    275               0x00, src_pal_ptr[2], src_pal_ptr[1], src_pal_ptr[0]);
    276           src_pal_ptr += 3;
    277         }
    278       } else {
    279         while (src_pal_index < bmp_ptr->pal_num) {
    280           bmp_ptr->pal_ptr[src_pal_index++] = BMP_PAL_ENCODE(
    281               src_pal_ptr[3], src_pal_ptr[2], src_pal_ptr[1], src_pal_ptr[0]);
    282           src_pal_ptr += 4;
    283         }
    284       }
    285     }
    286     if (bmp_ptr->bmp_header_ptr->bfOffBits <
    287         14 + bmp_ptr->img_ifh_size +
    288             bmp_ptr->pal_num * (bmp_ptr->pal_type ? 3 : 4)) {
    289       bmp_ptr->bmp_header_ptr->bfOffBits =
    290           14 + bmp_ptr->img_ifh_size +
    291           bmp_ptr->pal_num * (bmp_ptr->pal_type ? 3 : 4);
    292     }
    293     bmp_save_decoding_status(bmp_ptr, BMP_D_STATUS_DATA_PRE);
    294   }
    295   return 1;
    296 }
    297 int32_t bmp_decode_image(bmp_decompress_struct_p bmp_ptr) {
    298   if (bmp_ptr->decode_status == BMP_D_STATUS_DATA_PRE) {
    299     bmp_ptr->avail_in = 0;
    300     if (!bmp_ptr->bmp_get_data_position_fn(
    301             bmp_ptr, bmp_ptr->bmp_header_ptr->bfOffBits)) {
    302       bmp_ptr->decode_status = BMP_D_STATUS_TAIL;
    303       bmp_error(bmp_ptr, "The Bmp File Is Corrupt, Unexpected Stream Offset");
    304       return 0;
    305     }
    306     bmp_ptr->row_num = 0;
    307     bmp_save_decoding_status(bmp_ptr, BMP_D_STATUS_DATA);
    308   }
    309   if (bmp_ptr->decode_status == BMP_D_STATUS_DATA) {
    310     switch (bmp_ptr->compress_flag) {
    311       case BMP_RGB:
    312       case BMP_BITFIELDS:
    313         return bmp_decode_rgb(bmp_ptr);
    314       case BMP_RLE8:
    315         return bmp_decode_rle8(bmp_ptr);
    316       case BMP_RLE4:
    317         return bmp_decode_rle4(bmp_ptr);
    318     }
    319   }
    320   bmp_error(bmp_ptr, "Any Uncontrol Error");
    321   return 0;
    322 }
    323 int32_t bmp_decode_rgb(bmp_decompress_struct_p bmp_ptr) {
    324   uint8_t* row_buf = bmp_ptr->out_row_buffer;
    325   uint8_t* des_buf = nullptr;
    326   while (bmp_ptr->row_num < bmp_ptr->height) {
    327     if (!bmp_read_data(bmp_ptr, &des_buf, bmp_ptr->src_row_bytes))
    328       return 2;
    329 
    330     bmp_save_decoding_status(bmp_ptr, BMP_D_STATUS_DATA);
    331     switch (bmp_ptr->bitCounts) {
    332       case 1: {
    333         for (int32_t col = 0; col < bmp_ptr->width; col++) {
    334           *row_buf++ = des_buf[col >> 3] & (0x80 >> (col % 8)) ? 0x01 : 0x00;
    335         }
    336       } break;
    337       case 4: {
    338         for (int32_t col = 0; col < bmp_ptr->width; col++) {
    339           *row_buf++ = (col & 0x01) ? (des_buf[col >> 1] & 0x0F)
    340                                     : ((des_buf[col >> 1] & 0xF0) >> 4);
    341         }
    342       } break;
    343       case 16: {
    344         uint16_t* buf = (uint16_t*)des_buf;
    345         uint8_t blue_bits = 0;
    346         uint8_t green_bits = 0;
    347         uint8_t red_bits = 0;
    348         for (int32_t i = 0; i < 16; i++) {
    349           if ((bmp_ptr->mask_blue >> i) & 0x01) {
    350             blue_bits++;
    351           }
    352           if ((bmp_ptr->mask_green >> i) & 0x01) {
    353             green_bits++;
    354           }
    355           if ((bmp_ptr->mask_red >> i) & 0x01) {
    356             red_bits++;
    357           }
    358         }
    359         green_bits += blue_bits;
    360         red_bits += green_bits;
    361         if (blue_bits > 8 || green_bits < 8 || red_bits < 8)
    362           return 2;
    363         blue_bits = 8 - blue_bits;
    364         green_bits -= 8;
    365         red_bits -= 8;
    366         for (int32_t col = 0; col < bmp_ptr->width; col++) {
    367           *buf = GetWord_LSBFirst((uint8_t*)buf);
    368           *row_buf++ = (uint8_t)((*buf & bmp_ptr->mask_blue) << blue_bits);
    369           *row_buf++ = (uint8_t)((*buf & bmp_ptr->mask_green) >> green_bits);
    370           *row_buf++ = (uint8_t)((*buf++ & bmp_ptr->mask_red) >> red_bits);
    371         }
    372       } break;
    373       case 8:
    374       case 24:
    375       case 32:
    376         FXSYS_memcpy(bmp_ptr->out_row_buffer, des_buf, bmp_ptr->src_row_bytes);
    377         break;
    378     }
    379     row_buf = bmp_ptr->out_row_buffer;
    380     bmp_ptr->bmp_get_row_fn(bmp_ptr,
    381                             bmp_ptr->imgTB_flag
    382                                 ? bmp_ptr->row_num++
    383                                 : (bmp_ptr->height - 1 - bmp_ptr->row_num++),
    384                             bmp_ptr->out_row_buffer);
    385   }
    386   bmp_save_decoding_status(bmp_ptr, BMP_D_STATUS_TAIL);
    387   return 1;
    388 }
    389 int32_t bmp_decode_rle8(bmp_decompress_struct_p bmp_ptr) {
    390   uint8_t* first_byte_ptr = nullptr;
    391   uint8_t* second_byte_ptr = nullptr;
    392   bmp_ptr->col_num = 0;
    393   while (true) {
    394     uint32_t skip_size_org = bmp_ptr->skip_size;
    395     if (!bmp_read_data(bmp_ptr, &first_byte_ptr, 1))
    396       return 2;
    397 
    398     switch (*first_byte_ptr) {
    399       case RLE_MARKER: {
    400         if (!bmp_read_data(bmp_ptr, &first_byte_ptr, 1)) {
    401           bmp_ptr->skip_size = skip_size_org;
    402           return 2;
    403         }
    404         switch (*first_byte_ptr) {
    405           case RLE_EOL: {
    406             if (bmp_ptr->row_num >= bmp_ptr->height) {
    407               bmp_save_decoding_status(bmp_ptr, BMP_D_STATUS_TAIL);
    408               bmp_error(bmp_ptr, "The Bmp File Is Corrupt");
    409               return 0;
    410             }
    411             bmp_ptr->bmp_get_row_fn(
    412                 bmp_ptr, bmp_ptr->imgTB_flag
    413                              ? bmp_ptr->row_num++
    414                              : (bmp_ptr->height - 1 - bmp_ptr->row_num++),
    415                 bmp_ptr->out_row_buffer);
    416             bmp_ptr->col_num = 0;
    417             FXSYS_memset(bmp_ptr->out_row_buffer, 0, bmp_ptr->out_row_bytes);
    418             bmp_save_decoding_status(bmp_ptr, BMP_D_STATUS_DATA);
    419             continue;
    420           }
    421           case RLE_EOI: {
    422             if (bmp_ptr->row_num < bmp_ptr->height) {
    423               bmp_ptr->bmp_get_row_fn(
    424                   bmp_ptr, bmp_ptr->imgTB_flag
    425                                ? bmp_ptr->row_num++
    426                                : (bmp_ptr->height - 1 - bmp_ptr->row_num++),
    427                   bmp_ptr->out_row_buffer);
    428             }
    429             bmp_save_decoding_status(bmp_ptr, BMP_D_STATUS_TAIL);
    430             return 1;
    431           }
    432           case RLE_DELTA: {
    433             uint8_t* delta_ptr;
    434             if (!bmp_read_data(bmp_ptr, &delta_ptr, 2)) {
    435               bmp_ptr->skip_size = skip_size_org;
    436               return 2;
    437             }
    438             bmp_ptr->col_num += (int32_t)delta_ptr[0];
    439             int32_t bmp_row_num_next = bmp_ptr->row_num + (int32_t)delta_ptr[1];
    440             if (bmp_ptr->col_num >= bmp_ptr->out_row_bytes ||
    441                 bmp_row_num_next >= bmp_ptr->height) {
    442               bmp_error(bmp_ptr, "The Bmp File Is Corrupt Or Not Supported");
    443               return 0;
    444             }
    445             while (bmp_ptr->row_num < bmp_row_num_next) {
    446               FXSYS_memset(bmp_ptr->out_row_buffer, 0, bmp_ptr->out_row_bytes);
    447               bmp_ptr->bmp_get_row_fn(
    448                   bmp_ptr, bmp_ptr->imgTB_flag
    449                                ? bmp_ptr->row_num++
    450                                : (bmp_ptr->height - 1 - bmp_ptr->row_num++),
    451                   bmp_ptr->out_row_buffer);
    452             }
    453           } break;
    454           default: {
    455             if ((int32_t)(*first_byte_ptr) >
    456                 bmp_ptr->src_row_bytes - bmp_ptr->col_num) {
    457               bmp_error(bmp_ptr, "The Bmp File Is Corrupt");
    458               return 0;
    459             }
    460             if (!bmp_read_data(bmp_ptr, &second_byte_ptr,
    461                                *first_byte_ptr & 1 ? *first_byte_ptr + 1
    462                                                    : *first_byte_ptr)) {
    463               bmp_ptr->skip_size = skip_size_org;
    464               return 2;
    465             }
    466             FXSYS_memcpy(bmp_ptr->out_row_buffer + bmp_ptr->col_num,
    467                          second_byte_ptr, *first_byte_ptr);
    468             bmp_ptr->col_num += (int32_t)(*first_byte_ptr);
    469           }
    470         }
    471       } break;
    472       default: {
    473         if (!bmp_read_data(bmp_ptr, &second_byte_ptr, 1)) {
    474           bmp_ptr->skip_size = skip_size_org;
    475           return 2;
    476         }
    477         if ((int32_t)(*first_byte_ptr) >
    478             bmp_ptr->src_row_bytes - bmp_ptr->col_num) {
    479           bmp_error(bmp_ptr, "The Bmp File Is Corrupt");
    480           return 0;
    481         }
    482         FXSYS_memset(bmp_ptr->out_row_buffer + bmp_ptr->col_num,
    483                      *second_byte_ptr, *first_byte_ptr);
    484         bmp_ptr->col_num += (int32_t)(*first_byte_ptr);
    485       }
    486     }
    487   }
    488   bmp_error(bmp_ptr, "Any Uncontrol Error");
    489   return 0;
    490 }
    491 int32_t bmp_decode_rle4(bmp_decompress_struct_p bmp_ptr) {
    492   uint8_t* first_byte_ptr = nullptr;
    493   uint8_t* second_byte_ptr = nullptr;
    494   bmp_ptr->col_num = 0;
    495   while (true) {
    496     uint32_t skip_size_org = bmp_ptr->skip_size;
    497     if (!bmp_read_data(bmp_ptr, &first_byte_ptr, 1))
    498       return 2;
    499 
    500     switch (*first_byte_ptr) {
    501       case RLE_MARKER: {
    502         if (!bmp_read_data(bmp_ptr, &first_byte_ptr, 1)) {
    503           bmp_ptr->skip_size = skip_size_org;
    504           return 2;
    505         }
    506         switch (*first_byte_ptr) {
    507           case RLE_EOL: {
    508             if (bmp_ptr->row_num >= bmp_ptr->height) {
    509               bmp_save_decoding_status(bmp_ptr, BMP_D_STATUS_TAIL);
    510               bmp_error(bmp_ptr, "The Bmp File Is Corrupt");
    511               return 0;
    512             }
    513             bmp_ptr->bmp_get_row_fn(
    514                 bmp_ptr, bmp_ptr->imgTB_flag
    515                              ? bmp_ptr->row_num++
    516                              : (bmp_ptr->height - 1 - bmp_ptr->row_num++),
    517                 bmp_ptr->out_row_buffer);
    518             bmp_ptr->col_num = 0;
    519             FXSYS_memset(bmp_ptr->out_row_buffer, 0, bmp_ptr->out_row_bytes);
    520             bmp_save_decoding_status(bmp_ptr, BMP_D_STATUS_DATA);
    521             continue;
    522           }
    523           case RLE_EOI: {
    524             if (bmp_ptr->row_num < bmp_ptr->height) {
    525               bmp_ptr->bmp_get_row_fn(
    526                   bmp_ptr, bmp_ptr->imgTB_flag
    527                                ? bmp_ptr->row_num++
    528                                : (bmp_ptr->height - 1 - bmp_ptr->row_num++),
    529                   bmp_ptr->out_row_buffer);
    530             }
    531             bmp_save_decoding_status(bmp_ptr, BMP_D_STATUS_TAIL);
    532             return 1;
    533           }
    534           case RLE_DELTA: {
    535             uint8_t* delta_ptr;
    536             if (!bmp_read_data(bmp_ptr, &delta_ptr, 2)) {
    537               bmp_ptr->skip_size = skip_size_org;
    538               return 2;
    539             }
    540             bmp_ptr->col_num += (int32_t)delta_ptr[0];
    541             int32_t bmp_row_num_next = bmp_ptr->row_num + (int32_t)delta_ptr[1];
    542             if (bmp_ptr->col_num >= bmp_ptr->out_row_bytes ||
    543                 bmp_row_num_next >= bmp_ptr->height) {
    544               bmp_error(bmp_ptr, "The Bmp File Is Corrupt Or Not Supported");
    545               return 0;
    546             }
    547             while (bmp_ptr->row_num < bmp_row_num_next) {
    548               FXSYS_memset(bmp_ptr->out_row_buffer, 0, bmp_ptr->out_row_bytes);
    549               bmp_ptr->bmp_get_row_fn(
    550                   bmp_ptr, bmp_ptr->imgTB_flag
    551                                ? bmp_ptr->row_num++
    552                                : (bmp_ptr->height - 1 - bmp_ptr->row_num++),
    553                   bmp_ptr->out_row_buffer);
    554             }
    555           } break;
    556           default: {
    557             uint8_t size = (uint8_t)(((uint16_t)(*first_byte_ptr) + 1) >> 1);
    558             if ((int32_t)*first_byte_ptr >=
    559                 bmp_ptr->out_row_bytes - bmp_ptr->col_num) {
    560               if (size + (bmp_ptr->col_num >> 1) > bmp_ptr->src_row_bytes) {
    561                 bmp_error(bmp_ptr, "The Bmp File Is Corrupt");
    562                 return 0;
    563               }
    564               *first_byte_ptr = bmp_ptr->out_row_bytes - bmp_ptr->col_num - 1;
    565             }
    566             if (!bmp_read_data(bmp_ptr, &second_byte_ptr,
    567                                size & 1 ? size + 1 : size)) {
    568               bmp_ptr->skip_size = skip_size_org;
    569               return 2;
    570             }
    571             for (uint8_t i = 0; i < *first_byte_ptr; i++) {
    572               if (i & 0x01) {
    573                 *(bmp_ptr->out_row_buffer + bmp_ptr->col_num++) =
    574                     (*second_byte_ptr++ & 0x0F);
    575               } else {
    576                 *(bmp_ptr->out_row_buffer + bmp_ptr->col_num++) =
    577                     ((*second_byte_ptr & 0xF0) >> 4);
    578               }
    579             }
    580           }
    581         }
    582       } break;
    583       default: {
    584         if (!bmp_read_data(bmp_ptr, &second_byte_ptr, 1)) {
    585           bmp_ptr->skip_size = skip_size_org;
    586           return 2;
    587         }
    588         if ((int32_t)*first_byte_ptr >
    589             bmp_ptr->out_row_bytes - bmp_ptr->col_num) {
    590           uint8_t size = (uint8_t)(((uint16_t)(*first_byte_ptr) + 1) >> 1);
    591           if (size + (bmp_ptr->col_num >> 1) > bmp_ptr->src_row_bytes) {
    592             bmp_error(bmp_ptr, "The Bmp File Is Corrupt");
    593             return 0;
    594           }
    595           *first_byte_ptr = bmp_ptr->out_row_bytes - bmp_ptr->col_num - 1;
    596         }
    597         for (uint8_t i = 0; i < *first_byte_ptr; i++) {
    598           if (i & 0x01) {
    599             *(bmp_ptr->out_row_buffer + bmp_ptr->col_num++) =
    600                 (*second_byte_ptr & 0x0F);
    601           } else {
    602             *(bmp_ptr->out_row_buffer + bmp_ptr->col_num++) =
    603                 ((*second_byte_ptr & 0xF0) >> 4);
    604           }
    605         }
    606       }
    607     }
    608   }
    609   bmp_error(bmp_ptr, "Any Uncontrol Error");
    610   return 0;
    611 }
    612 uint8_t* bmp_read_data(bmp_decompress_struct_p bmp_ptr,
    613                        uint8_t** des_buf_pp,
    614                        uint32_t data_size) {
    615   if (!bmp_ptr || bmp_ptr->avail_in < bmp_ptr->skip_size + data_size)
    616     return nullptr;
    617 
    618   *des_buf_pp = bmp_ptr->next_in + bmp_ptr->skip_size;
    619   bmp_ptr->skip_size += data_size;
    620   return *des_buf_pp;
    621 }
    622 void bmp_save_decoding_status(bmp_decompress_struct_p bmp_ptr, int32_t status) {
    623   bmp_ptr->decode_status = status;
    624   bmp_ptr->next_in += bmp_ptr->skip_size;
    625   bmp_ptr->avail_in -= bmp_ptr->skip_size;
    626   bmp_ptr->skip_size = 0;
    627 }
    628 void bmp_input_buffer(bmp_decompress_struct_p bmp_ptr,
    629                       uint8_t* src_buf,
    630                       uint32_t src_size) {
    631   bmp_ptr->next_in = src_buf;
    632   bmp_ptr->avail_in = src_size;
    633   bmp_ptr->skip_size = 0;
    634 }
    635 uint32_t bmp_get_avail_input(bmp_decompress_struct_p bmp_ptr,
    636                              uint8_t** avail_buf_ptr) {
    637   if (avail_buf_ptr) {
    638     *avail_buf_ptr = nullptr;
    639     if (bmp_ptr->avail_in > 0) {
    640       *avail_buf_ptr = bmp_ptr->next_in;
    641     }
    642   }
    643   return bmp_ptr->avail_in;
    644 }
    645 bmp_compress_struct_p bmp_create_compress() {
    646   bmp_compress_struct_p bmp_ptr;
    647   bmp_ptr = FX_Alloc(bmp_compress_struct, 1);
    648   if (bmp_ptr) {
    649     FXSYS_memset(bmp_ptr, 0, sizeof(bmp_compress_struct));
    650   }
    651   return bmp_ptr;
    652 }
    653 void bmp_destroy_compress(bmp_compress_struct_p bmp_ptr) {
    654   if (bmp_ptr) {
    655     if (bmp_ptr->src_free && bmp_ptr->src_buf) {
    656       FX_Free(bmp_ptr->src_buf);
    657     }
    658     FX_Free(bmp_ptr);
    659   }
    660 }
    661 static void WriteFileHeader(BmpFileHeaderPtr head_ptr, uint8_t* dst_buf) {
    662   uint32_t offset;
    663   offset = 0;
    664   SetWord_LSBFirst(&dst_buf[offset], head_ptr->bfType);
    665   offset += 2;
    666   SetDWord_LSBFirst(&dst_buf[offset], head_ptr->bfSize);
    667   offset += 4;
    668   SetWord_LSBFirst(&dst_buf[offset], head_ptr->bfReserved1);
    669   offset += 2;
    670   SetWord_LSBFirst(&dst_buf[offset], head_ptr->bfReserved2);
    671   offset += 2;
    672   SetDWord_LSBFirst(&dst_buf[offset], head_ptr->bfOffBits);
    673   offset += 4;
    674 }
    675 static void WriteInfoHeader(BmpInfoHeaderPtr info_head_ptr, uint8_t* dst_buf) {
    676   uint32_t offset;
    677   offset = sizeof(BmpFileHeader);
    678   SetDWord_LSBFirst(&dst_buf[offset], info_head_ptr->biSize);
    679   offset += 4;
    680   SetDWord_LSBFirst(&dst_buf[offset], info_head_ptr->biWidth);
    681   offset += 4;
    682   SetDWord_LSBFirst(&dst_buf[offset], info_head_ptr->biHeight);
    683   offset += 4;
    684   SetWord_LSBFirst(&dst_buf[offset], info_head_ptr->biPlanes);
    685   offset += 2;
    686   SetWord_LSBFirst(&dst_buf[offset], info_head_ptr->biBitCount);
    687   offset += 2;
    688   SetDWord_LSBFirst(&dst_buf[offset], info_head_ptr->biCompression);
    689   offset += 4;
    690   SetDWord_LSBFirst(&dst_buf[offset], info_head_ptr->biSizeImage);
    691   offset += 4;
    692   SetDWord_LSBFirst(&dst_buf[offset], info_head_ptr->biXPelsPerMeter);
    693   offset += 4;
    694   SetDWord_LSBFirst(&dst_buf[offset], info_head_ptr->biYPelsPerMeter);
    695   offset += 4;
    696   SetDWord_LSBFirst(&dst_buf[offset], info_head_ptr->biClrUsed);
    697   offset += 4;
    698   SetDWord_LSBFirst(&dst_buf[offset], info_head_ptr->biClrImportant);
    699   offset += 4;
    700 }
    701 static void bmp_encode_bitfields(bmp_compress_struct_p bmp_ptr,
    702                                  uint8_t*& dst_buf,
    703                                  uint32_t& dst_size) {
    704   if (bmp_ptr->info_header.biBitCount != 16 &&
    705       bmp_ptr->info_header.biBitCount != 32) {
    706     return;
    707   }
    708   uint32_t size, dst_pos, i;
    709   size = bmp_ptr->src_pitch * bmp_ptr->src_row *
    710          bmp_ptr->info_header.biBitCount / 16;
    711   dst_pos = bmp_ptr->file_header.bfOffBits;
    712   dst_size += size;
    713   dst_buf = FX_Realloc(uint8_t, dst_buf, dst_size);
    714   FXSYS_memset(&dst_buf[dst_pos], 0, size);
    715   uint32_t mask_red;
    716   uint32_t mask_green;
    717   uint32_t mask_blue;
    718   mask_red = 0x7C00;
    719   mask_green = 0x03E0;
    720   mask_blue = 0x001F;
    721   if (bmp_ptr->info_header.biCompression == BMP_BITFIELDS) {
    722     if (bmp_ptr->bit_type == BMP_BIT_565) {
    723       mask_red = 0xF800;
    724       mask_green = 0x07E0;
    725       mask_blue = 0x001F;
    726     }
    727     if (bmp_ptr->info_header.biBitCount == 32) {
    728       mask_red = 0xFF0000;
    729       mask_green = 0x00FF00;
    730       mask_blue = 0x0000FF;
    731     }
    732     SetDWord_LSBFirst(&dst_buf[dst_pos], mask_red);
    733     dst_pos += 4;
    734     SetDWord_LSBFirst(&dst_buf[dst_pos], mask_green);
    735     dst_pos += 4;
    736     SetDWord_LSBFirst(&dst_buf[dst_pos], mask_blue);
    737     dst_pos += 4;
    738     bmp_ptr->file_header.bfOffBits = dst_pos;
    739   }
    740   uint8_t blue_bits = 0;
    741   uint8_t green_bits = 0;
    742   uint8_t red_bits = 0;
    743   for (i = 0; i < bmp_ptr->info_header.biBitCount; i++) {
    744     if ((mask_blue >> i) & 0x01) {
    745       blue_bits++;
    746     }
    747     if ((mask_green >> i) & 0x01) {
    748       green_bits++;
    749     }
    750     if ((mask_red >> i) & 0x01) {
    751       red_bits++;
    752     }
    753   }
    754   green_bits += blue_bits;
    755   red_bits += green_bits;
    756   blue_bits = 8 - blue_bits;
    757   green_bits -= 8;
    758   red_bits -= 8;
    759   i = 0;
    760   for (int32_t row_num = bmp_ptr->src_row - 1; row_num > -1; row_num--, i = 0) {
    761     while (i < bmp_ptr->src_width * bmp_ptr->src_bpp / 8) {
    762       uint8_t b = bmp_ptr->src_buf[row_num * bmp_ptr->src_pitch + i++];
    763       uint8_t g = bmp_ptr->src_buf[row_num * bmp_ptr->src_pitch + i++];
    764       uint8_t r = bmp_ptr->src_buf[row_num * bmp_ptr->src_pitch + i++];
    765       if (bmp_ptr->src_bpp == 32) {
    766         i++;
    767       }
    768       uint32_t pix_val = 0;
    769       pix_val |= (b >> blue_bits) & mask_blue;
    770       pix_val |= (g << green_bits) & mask_green;
    771       pix_val |= (r << red_bits) & mask_red;
    772       if (bmp_ptr->info_header.biBitCount == 16) {
    773         SetWord_LSBFirst(&dst_buf[dst_pos], pix_val);
    774         dst_pos += 2;
    775       } else {
    776         SetDWord_LSBFirst(&dst_buf[dst_pos], pix_val);
    777         dst_pos += 4;
    778       }
    779     }
    780   }
    781   dst_size = dst_pos;
    782 }
    783 
    784 static void bmp_encode_rgb(bmp_compress_struct_p bmp_ptr,
    785                            uint8_t*& dst_buf,
    786                            uint32_t& dst_size) {
    787   if (bmp_ptr->info_header.biBitCount == 16) {
    788     bmp_encode_bitfields(bmp_ptr, dst_buf, dst_size);
    789     return;
    790   }
    791   uint32_t size, dst_pos;
    792   uint32_t dst_pitch =
    793       (bmp_ptr->src_width * bmp_ptr->info_header.biBitCount + 31) / 32 * 4;
    794   size = dst_pitch * bmp_ptr->src_row;
    795   dst_pos = bmp_ptr->file_header.bfOffBits;
    796   dst_size += size;
    797   dst_buf = FX_Realloc(uint8_t, dst_buf, dst_size);
    798   FXSYS_memset(&dst_buf[dst_pos], 0, size);
    799   for (int32_t row_num = bmp_ptr->src_row - 1; row_num > -1; row_num--) {
    800     FXSYS_memcpy(&dst_buf[dst_pos],
    801                  &bmp_ptr->src_buf[row_num * bmp_ptr->src_pitch],
    802                  bmp_ptr->src_pitch);
    803     dst_pos += dst_pitch;
    804   }
    805   dst_size = dst_pos;
    806 }
    807 static uint8_t bmp_rle8_search(const uint8_t* buf, int32_t len) {
    808   uint8_t num;
    809   num = 1;
    810   while (num < len) {
    811     if (buf[num - 1] != buf[num] || num == 0xFF) {
    812       break;
    813     }
    814     num++;
    815   }
    816   return num;
    817 }
    818 static void bmp_encode_rle8(bmp_compress_struct_p bmp_ptr,
    819                             uint8_t*& dst_buf,
    820                             uint32_t& dst_size) {
    821   uint32_t size, dst_pos, index;
    822   uint8_t rle[2] = {0};
    823   size = bmp_ptr->src_pitch * bmp_ptr->src_row * 2;
    824   dst_pos = bmp_ptr->file_header.bfOffBits;
    825   dst_size += size;
    826   dst_buf = FX_Realloc(uint8_t, dst_buf, dst_size);
    827   FXSYS_memset(&dst_buf[dst_pos], 0, size);
    828   for (int32_t row_num = bmp_ptr->src_row - 1, i = 0; row_num > -1;) {
    829     index = row_num * bmp_ptr->src_pitch;
    830     rle[0] = bmp_rle8_search(&bmp_ptr->src_buf[index + i], size - index - i);
    831     rle[1] = bmp_ptr->src_buf[index + i];
    832     if (i + rle[0] >= (int32_t)bmp_ptr->src_pitch) {
    833       rle[0] = uint8_t(bmp_ptr->src_pitch - i);
    834       if (rle[0]) {
    835         dst_buf[dst_pos++] = rle[0];
    836         dst_buf[dst_pos++] = rle[1];
    837       }
    838       dst_buf[dst_pos++] = RLE_MARKER;
    839       dst_buf[dst_pos++] = RLE_EOL;
    840       i = 0;
    841       row_num--;
    842     } else {
    843       i += rle[0];
    844       dst_buf[dst_pos++] = rle[0];
    845       dst_buf[dst_pos++] = rle[1];
    846     }
    847   }
    848   dst_buf[dst_pos++] = RLE_MARKER;
    849   dst_buf[dst_pos++] = RLE_EOI;
    850   dst_size = dst_pos;
    851 }
    852 static uint8_t bmp_rle4_search(const uint8_t* buf, int32_t len) {
    853   uint8_t num;
    854   num = 2;
    855   while (num < len) {
    856     if (buf[num - 2] != buf[num] || num == 0xFF) {
    857       break;
    858     }
    859     num++;
    860   }
    861   return num;
    862 }
    863 static void bmp_encode_rle4(bmp_compress_struct_p bmp_ptr,
    864                             uint8_t*& dst_buf,
    865                             uint32_t& dst_size) {
    866   uint32_t size, dst_pos, index;
    867   uint8_t rle[2] = {0};
    868   size = bmp_ptr->src_pitch * bmp_ptr->src_row;
    869   dst_pos = bmp_ptr->file_header.bfOffBits;
    870   dst_size += size;
    871   dst_buf = FX_Realloc(uint8_t, dst_buf, dst_size);
    872   FXSYS_memset(&dst_buf[dst_pos], 0, size);
    873   for (int32_t row_num = bmp_ptr->src_row - 1, i = 0; row_num > -1;
    874        rle[1] = 0) {
    875     index = row_num * bmp_ptr->src_pitch;
    876     rle[0] = bmp_rle4_search(&bmp_ptr->src_buf[index + i], size - index - i);
    877     rle[1] |= (bmp_ptr->src_buf[index + i] & 0x0f) << 4;
    878     rle[1] |= bmp_ptr->src_buf[index + i + 1] & 0x0f;
    879     if (i + rle[0] >= (int32_t)bmp_ptr->src_pitch) {
    880       rle[0] = uint8_t(bmp_ptr->src_pitch - i);
    881       if (rle[0]) {
    882         dst_buf[dst_pos++] = rle[0];
    883         dst_buf[dst_pos++] = rle[1];
    884       }
    885       dst_buf[dst_pos++] = RLE_MARKER;
    886       dst_buf[dst_pos++] = RLE_EOL;
    887       i = 0;
    888       row_num--;
    889     } else {
    890       i += rle[0];
    891       dst_buf[dst_pos++] = rle[0];
    892       dst_buf[dst_pos++] = rle[1];
    893     }
    894   }
    895   dst_buf[dst_pos++] = RLE_MARKER;
    896   dst_buf[dst_pos++] = RLE_EOI;
    897   dst_size = dst_pos;
    898 }
    899 bool bmp_encode_image(bmp_compress_struct_p bmp_ptr,
    900                       uint8_t*& dst_buf,
    901                       uint32_t& dst_size) {
    902   uint32_t head_size = sizeof(BmpFileHeader) + sizeof(BmpInfoHeader);
    903   uint32_t pal_size = sizeof(uint32_t) * bmp_ptr->pal_num;
    904   if (bmp_ptr->info_header.biClrUsed > 0 &&
    905       bmp_ptr->info_header.biClrUsed < bmp_ptr->pal_num) {
    906     pal_size = sizeof(uint32_t) * bmp_ptr->info_header.biClrUsed;
    907   }
    908   dst_size = head_size + sizeof(uint32_t) * bmp_ptr->pal_num;
    909   dst_buf = FX_TryAlloc(uint8_t, dst_size);
    910   if (!dst_buf)
    911     return false;
    912 
    913   FXSYS_memset(dst_buf, 0, dst_size);
    914   bmp_ptr->file_header.bfOffBits = head_size;
    915   if (bmp_ptr->pal_ptr && pal_size) {
    916     FXSYS_memcpy(&dst_buf[head_size], bmp_ptr->pal_ptr, pal_size);
    917     bmp_ptr->file_header.bfOffBits += pal_size;
    918   }
    919   WriteInfoHeader(&bmp_ptr->info_header, dst_buf);
    920   switch (bmp_ptr->info_header.biCompression) {
    921     case BMP_RGB:
    922       bmp_encode_rgb(bmp_ptr, dst_buf, dst_size);
    923       break;
    924     case BMP_BITFIELDS:
    925       bmp_encode_bitfields(bmp_ptr, dst_buf, dst_size);
    926       break;
    927     case BMP_RLE8:
    928       bmp_encode_rle8(bmp_ptr, dst_buf, dst_size);
    929       break;
    930     case BMP_RLE4:
    931       bmp_encode_rle4(bmp_ptr, dst_buf, dst_size);
    932       break;
    933     default:
    934       break;
    935   }
    936   bmp_ptr->file_header.bfSize = dst_size;
    937   WriteFileHeader(&bmp_ptr->file_header, dst_buf);
    938   return true;
    939 }
    940