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 
_GetDWord_LSBFirst(uint8_t * p)18 FX_DWORD _GetDWord_LSBFirst(uint8_t* p) {
19   return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
20 }
_GetWord_LSBFirst(uint8_t * p)21 FX_WORD _GetWord_LSBFirst(uint8_t* p) {
22   return p[0] | (p[1] << 8);
23 }
_SetDWord_LSBFirst(uint8_t * p,FX_DWORD v)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 }
_SetWord_LSBFirst(uint8_t * p,FX_WORD v)30 void _SetWord_LSBFirst(uint8_t* p, FX_WORD v) {
31   p[0] = (uint8_t)v;
32   p[1] = (uint8_t)(v >> 8);
33 }
_bmp_error(bmp_decompress_struct_p bmp_ptr,const FX_CHAR * err_msg)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 }
_bmp_create_decompress()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 }
_bmp_destroy_decompress(bmp_decompress_struct_pp bmp_ptr_ptr)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 }
_bmp_read_header(bmp_decompress_struct_p bmp_ptr)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 }
_bmp_decode_image(bmp_decompress_struct_p bmp_ptr)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 }
_bmp_decode_rgb(bmp_decompress_struct_p bmp_ptr)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 }
_bmp_decode_rle8(bmp_decompress_struct_p bmp_ptr)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 }
_bmp_decode_rle4(bmp_decompress_struct_p bmp_ptr)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 }
_bmp_read_data(bmp_decompress_struct_p bmp_ptr,uint8_t ** des_buf_pp,FX_DWORD data_size)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 }
_bmp_save_decoding_status(bmp_decompress_struct_p bmp_ptr,int32_t status)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 }
_bmp_input_buffer(bmp_decompress_struct_p bmp_ptr,uint8_t * src_buf,FX_DWORD src_size)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 }
_bmp_get_avail_input(bmp_decompress_struct_p bmp_ptr,uint8_t ** avial_buf_ptr)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 }
_bmp_create_compress()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 }
_bmp_destroy_compress(bmp_compress_struct_p bmp_ptr)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 }
WriteFileHeader(BmpFileHeaderPtr head_ptr,uint8_t * dst_buf)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 }
WriteInfoHeader(BmpInfoHeaderPtr info_head_ptr,uint8_t * dst_buf)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
_bmp_encode_bitfields(bmp_compress_struct_p bmp_ptr,uint8_t * & dst_buf,FX_DWORD & dst_size)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
_bmp_encode_rgb(bmp_compress_struct_p bmp_ptr,uint8_t * & dst_buf,FX_DWORD & dst_size)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 }
_bmp_rle8_search(const uint8_t * buf,int32_t len)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 }
_bmp_encode_rle8(bmp_compress_struct_p bmp_ptr,uint8_t * & dst_buf,FX_DWORD & dst_size)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 }
_bmp_rle4_search(const uint8_t * buf,int32_t len)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 }
_bmp_encode_rle4(bmp_compress_struct_p bmp_ptr,uint8_t * & dst_buf,FX_DWORD & dst_size)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 }
_bmp_encode_image(bmp_compress_struct_p bmp_ptr,uint8_t * & dst_buf,FX_DWORD & dst_size)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