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
11namespace {
12
13const size_t kBmpCoreHeaderSize = 12;
14const size_t kBmpInfoHeaderSize = 40;
15
16// TODO(thestig): Replace with FXDWORD_GET_LSBFIRST?
17uint32_t GetDWord_LSBFirst(uint8_t* p) {
18  return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
19}
20
21void 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
29uint16_t GetWord_LSBFirst(uint8_t* p) {
30  return p[0] | (p[1] << 8);
31}
32void SetWord_LSBFirst(uint8_t* p, uint16_t v) {
33  p[0] = (uint8_t)v;
34  p[1] = (uint8_t)(v >> 8);
35}
36void 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}
41bmp_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}
48void 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}
61int32_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}
297int32_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}
323int32_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}
389int32_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}
491int32_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}
612uint8_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}
622void 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}
628void 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}
635uint32_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}
645bmp_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}
653void 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}
661static 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}
675static 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}
701static 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
784static 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}
807static 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}
818static 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}
852static 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}
863static 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}
899bool 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