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