Home | History | Annotate | Download | only in lgif
      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_gif.h"
      8 void CGifLZWDecoder::Input(uint8_t* src_buf, FX_DWORD src_size) {
      9   next_in = src_buf;
     10   avail_in = src_size;
     11 }
     12 FX_DWORD CGifLZWDecoder::GetAvailInput() {
     13   return avail_in;
     14 }
     15 void CGifLZWDecoder::InitTable(uint8_t code_len) {
     16   code_size = code_len;
     17   code_clear = 1 << code_size;
     18   code_end = code_clear + 1;
     19   bits_left = 0;
     20   code_store = 0;
     21   next_in = NULL;
     22   avail_in = 0;
     23   stack_size = 0;
     24   code_first = 0;
     25   ClearTable();
     26 }
     27 void CGifLZWDecoder::ClearTable() {
     28   code_size_cur = code_size + 1;
     29   code_next = code_end + 1;
     30   code_old = (FX_WORD)-1;
     31   FXSYS_memset(code_table, 0, sizeof(tag_Table) * GIF_MAX_LZW_CODE);
     32   FXSYS_memset(stack, 0, GIF_MAX_LZW_CODE);
     33   for (FX_WORD i = 0; i < code_clear; i++) {
     34     code_table[i].suffix = (uint8_t)i;
     35   }
     36 }
     37 void CGifLZWDecoder::DecodeString(FX_WORD code) {
     38   stack_size = 0;
     39   while (TRUE) {
     40     ASSERT(code <= code_next);
     41     if (code < code_clear || code > code_next) {
     42       break;
     43     }
     44     stack[GIF_MAX_LZW_CODE - 1 - stack_size++] = code_table[code].suffix;
     45     code = code_table[code].prefix;
     46   }
     47   stack[GIF_MAX_LZW_CODE - 1 - stack_size++] = (uint8_t)code;
     48   code_first = (uint8_t)code;
     49 }
     50 void CGifLZWDecoder::AddCode(FX_WORD prefix_code, uint8_t append_char) {
     51   if (code_next == GIF_MAX_LZW_CODE) {
     52     return;
     53   }
     54   code_table[code_next].prefix = prefix_code;
     55   code_table[code_next].suffix = append_char;
     56   if (++code_next < GIF_MAX_LZW_CODE) {
     57     if (code_next >> code_size_cur) {
     58       code_size_cur++;
     59     }
     60   }
     61 }
     62 int32_t CGifLZWDecoder::Decode(uint8_t* des_buf, FX_DWORD& des_size) {
     63   if (des_size == 0) {
     64     return 3;
     65   }
     66   FX_DWORD i = 0;
     67   if (stack_size != 0) {
     68     if (des_size < stack_size) {
     69       FXSYS_memcpy(des_buf, &stack[GIF_MAX_LZW_CODE - stack_size], des_size);
     70       stack_size -= (FX_WORD)des_size;
     71       return 3;
     72     }
     73     FXSYS_memcpy(des_buf, &stack[GIF_MAX_LZW_CODE - stack_size], stack_size);
     74     des_buf += stack_size;
     75     i += stack_size;
     76     stack_size = 0;
     77   }
     78   FX_WORD code = 0;
     79   while (i <= des_size && (avail_in > 0 || bits_left >= code_size_cur)) {
     80     if (code_size_cur > 12) {
     81       if (err_msg_ptr) {
     82         FXSYS_strncpy(err_msg_ptr, "Code Length Out Of Range",
     83                       GIF_MAX_ERROR_SIZE - 1);
     84       }
     85       return 0;
     86     }
     87     if (avail_in > 0) {
     88       code_store |= (*next_in++) << bits_left;
     89       avail_in--;
     90       bits_left += 8;
     91     }
     92     while (bits_left >= code_size_cur) {
     93       code = (FX_WORD)code_store & ((1 << code_size_cur) - 1);
     94       code_store >>= code_size_cur;
     95       bits_left -= code_size_cur;
     96       if (code == code_clear) {
     97         ClearTable();
     98         continue;
     99       } else if (code == code_end) {
    100         des_size = i;
    101         return 1;
    102       } else {
    103         if (code_old != (FX_WORD)-1) {
    104           if (code_next < GIF_MAX_LZW_CODE) {
    105             if (code == code_next) {
    106               AddCode(code_old, code_first);
    107               DecodeString(code);
    108             } else if (code > code_next) {
    109               if (err_msg_ptr) {
    110                 FXSYS_strncpy(err_msg_ptr, "Decode Error, Out Of Range",
    111                               GIF_MAX_ERROR_SIZE - 1);
    112               }
    113               return 0;
    114             } else {
    115               DecodeString(code);
    116               uint8_t append_char = stack[GIF_MAX_LZW_CODE - stack_size];
    117               AddCode(code_old, append_char);
    118             }
    119           }
    120         } else {
    121           DecodeString(code);
    122         }
    123         code_old = code;
    124         if (i + stack_size > des_size) {
    125           FXSYS_memcpy(des_buf, &stack[GIF_MAX_LZW_CODE - stack_size],
    126                        des_size - i);
    127           stack_size -= (FX_WORD)(des_size - i);
    128           return 3;
    129         }
    130         FXSYS_memcpy(des_buf, &stack[GIF_MAX_LZW_CODE - stack_size],
    131                      stack_size);
    132         des_buf += stack_size;
    133         i += stack_size;
    134         stack_size = 0;
    135       }
    136     }
    137   }
    138   if (avail_in == 0) {
    139     des_size = i;
    140     return 2;
    141   }
    142   return 0;
    143 }
    144 static FX_BOOL _gif_grow_buf(uint8_t*& dst_buf,
    145                              FX_DWORD& dst_len,
    146                              FX_DWORD size) {
    147   if (dst_len < size) {
    148     FX_DWORD len_org = dst_len;
    149     while (dst_buf && dst_len < size) {
    150       dst_len <<= 1;
    151       dst_buf = FX_Realloc(uint8_t, dst_buf, dst_len);
    152     }
    153     if (dst_buf == NULL) {
    154       dst_len = size;
    155       dst_buf = FX_Realloc(uint8_t, dst_buf, dst_len);
    156       if (dst_buf == NULL) {
    157         return FALSE;
    158       }
    159     }
    160     FXSYS_memset(dst_buf + len_org, 0, dst_len - len_org);
    161     return dst_buf != NULL;
    162   }
    163   return TRUE;
    164 }
    165 static inline void _gif_cut_index(uint8_t& val,
    166                                   FX_DWORD index,
    167                                   uint8_t index_bit,
    168                                   uint8_t index_bit_use,
    169                                   uint8_t bit_use) {
    170   FX_DWORD cut = ((1 << (index_bit - index_bit_use)) - 1) << index_bit_use;
    171   val |= ((index & cut) >> index_bit_use) << bit_use;
    172 }
    173 static inline uint8_t _gif_cut_buf(const uint8_t* buf,
    174                                    FX_DWORD& offset,
    175                                    uint8_t bit_cut,
    176                                    uint8_t& bit_offset,
    177                                    FX_DWORD& bit_num) {
    178   if (bit_cut != 8) {
    179     FX_WORD index = 0;
    180     index |= ((1 << bit_cut) - 1) << (7 - bit_offset);
    181     uint8_t ret = ((index & buf[offset]) >> (7 - bit_offset));
    182     bit_offset += bit_cut;
    183     if (bit_offset >= 8) {
    184       if (bit_offset > 8) {
    185         ret |= ((index & (buf[offset + 1] << 8)) >> 8);
    186       }
    187       bit_offset -= 8;
    188       offset++;
    189     }
    190     bit_num += bit_cut;
    191     return ret;
    192   }
    193   bit_num += bit_cut;
    194   return buf[offset++];
    195 }
    196 CGifLZWEncoder::CGifLZWEncoder() {
    197   FXSYS_memset(this, 0, sizeof(CGifLZWEncoder));
    198 }
    199 CGifLZWEncoder::~CGifLZWEncoder() {}
    200 void CGifLZWEncoder::ClearTable() {
    201   index_bit_cur = code_size + 1;
    202   index_num = code_end + 1;
    203   table_cur = code_end + 1;
    204   for (FX_WORD i = 0; i < GIF_MAX_LZW_CODE; i++) {
    205     code_table[i].prefix = 0;
    206     code_table[i].suffix = 0;
    207   }
    208 }
    209 void CGifLZWEncoder::Start(uint8_t code_len,
    210                            const uint8_t* src_buf,
    211                            uint8_t*& dst_buf,
    212                            FX_DWORD& offset) {
    213   code_size = code_len + 1;
    214   src_bit_cut = code_size;
    215   if (code_len == 0) {
    216     src_bit_cut = 1;
    217     code_size = 2;
    218   }
    219   code_clear = 1 << code_size;
    220   code_end = code_clear + 1;
    221   dst_buf[offset++] = code_size;
    222   bit_offset = 0;
    223   ClearTable();
    224   src_offset = 0;
    225   src_bit_offset = 0;
    226   src_bit_num = 0;
    227   code_table[index_num].prefix = _gif_cut_buf(src_buf, src_offset, src_bit_cut,
    228                                               src_bit_offset, src_bit_num);
    229   code_table[index_num].suffix = _gif_cut_buf(src_buf, src_offset, src_bit_cut,
    230                                               src_bit_offset, src_bit_num);
    231 }
    232 void CGifLZWEncoder::WriteBlock(uint8_t*& dst_buf,
    233                                 FX_DWORD& dst_len,
    234                                 FX_DWORD& offset) {
    235   if (!_gif_grow_buf(dst_buf, dst_len, offset + GIF_DATA_BLOCK + 1)) {
    236     longjmp(jmp, 1);
    237   }
    238   dst_buf[offset++] = index_buf_len;
    239   FXSYS_memcpy(&dst_buf[offset], index_buf, index_buf_len);
    240   offset += index_buf_len;
    241   FXSYS_memset(index_buf, 0, GIF_DATA_BLOCK);
    242   index_buf_len = 0;
    243 }
    244 void CGifLZWEncoder::EncodeString(FX_DWORD index,
    245                                   uint8_t*& dst_buf,
    246                                   FX_DWORD& dst_len,
    247                                   FX_DWORD& offset) {
    248   uint8_t index_bit_use;
    249   index_bit_use = 0;
    250   if (index_buf_len == GIF_DATA_BLOCK) {
    251     WriteBlock(dst_buf, dst_len, offset);
    252   }
    253   _gif_cut_index(index_buf[index_buf_len], index, index_bit_cur, index_bit_use,
    254                  bit_offset);
    255   if (index_bit_cur <= (8 - bit_offset)) {
    256     bit_offset += index_bit_cur;
    257   } else if (index_bit_cur <= (16 - bit_offset)) {
    258     index_bit_use += (8 - bit_offset);
    259     bit_offset = 0;
    260     index_buf_len++;
    261     if (index_buf_len == GIF_DATA_BLOCK) {
    262       WriteBlock(dst_buf, dst_len, offset);
    263     }
    264     _gif_cut_index(index_buf[index_buf_len], index, index_bit_cur,
    265                    index_bit_use, bit_offset);
    266     bit_offset = index_bit_cur - index_bit_use;
    267   } else {
    268     index_bit_use += (8 - bit_offset);
    269     bit_offset = 0;
    270     index_buf_len++;
    271     if (index_buf_len == GIF_DATA_BLOCK) {
    272       WriteBlock(dst_buf, dst_len, offset);
    273     }
    274     _gif_cut_index(index_buf[index_buf_len], index, index_bit_cur,
    275                    index_bit_use, bit_offset);
    276     index_bit_use += 8;
    277     bit_offset = 0;
    278     index_buf_len++;
    279     if (index_buf_len == GIF_DATA_BLOCK) {
    280       WriteBlock(dst_buf, dst_len, offset);
    281     }
    282     _gif_cut_index(index_buf[index_buf_len], index, index_bit_cur,
    283                    index_bit_use, bit_offset);
    284     bit_offset = index_bit_cur - index_bit_use;
    285   }
    286   if (bit_offset == 8) {
    287     bit_offset = 0;
    288     index_buf_len++;
    289     if (index_buf_len == GIF_DATA_BLOCK) {
    290       WriteBlock(dst_buf, dst_len, offset);
    291     }
    292   }
    293   if (index == code_end) {
    294     index_buf_len++;
    295     WriteBlock(dst_buf, dst_len, offset);
    296   }
    297   if (index_num++ >> index_bit_cur) {
    298     index_bit_cur++;
    299   }
    300 }
    301 FX_BOOL CGifLZWEncoder::Encode(const uint8_t* src_buf,
    302                                FX_DWORD src_len,
    303                                uint8_t*& dst_buf,
    304                                FX_DWORD& dst_len,
    305                                FX_DWORD& offset) {
    306   uint8_t suffix;
    307   if (setjmp(jmp)) {
    308     return FALSE;
    309   }
    310   while (src_bit_num < src_len) {
    311     if (!LookUpInTable(src_buf, src_offset, src_bit_offset)) {
    312       EncodeString(code_table[index_num].prefix, dst_buf, dst_len, offset);
    313       if (index_num == GIF_MAX_LZW_CODE) {
    314         suffix = code_table[index_num - 1].suffix;
    315         EncodeString(code_clear, dst_buf, dst_len, offset);
    316         ClearTable();
    317         code_table[index_num].prefix = suffix;
    318         code_table[index_num].suffix = _gif_cut_buf(
    319             src_buf, src_offset, src_bit_cut, src_bit_offset, src_bit_num);
    320       } else {
    321         code_table[index_num].prefix = code_table[index_num - 1].suffix;
    322         code_table[index_num].suffix = _gif_cut_buf(
    323             src_buf, src_offset, src_bit_cut, src_bit_offset, src_bit_num);
    324       }
    325     }
    326   }
    327   src_offset = 0;
    328   src_bit_offset = 0;
    329   src_bit_num = 0;
    330   return TRUE;
    331 }
    332 FX_BOOL CGifLZWEncoder::LookUpInTable(const uint8_t* buf,
    333                                       FX_DWORD& offset,
    334                                       uint8_t& bit_offset) {
    335   for (FX_WORD i = table_cur; i < index_num; i++) {
    336     if (code_table[i].prefix == code_table[index_num].prefix &&
    337         code_table[i].suffix == code_table[index_num].suffix) {
    338       code_table[index_num].prefix = i;
    339       code_table[index_num].suffix =
    340           _gif_cut_buf(buf, offset, src_bit_cut, bit_offset, src_bit_num);
    341       table_cur = i;
    342       return TRUE;
    343     }
    344   }
    345   table_cur = code_end + 1;
    346   return FALSE;
    347 }
    348 void CGifLZWEncoder::Finish(uint8_t*& dst_buf,
    349                             FX_DWORD& dst_len,
    350                             FX_DWORD& offset) {
    351   EncodeString(code_table[index_num].prefix, dst_buf, dst_len, offset);
    352   EncodeString(code_end, dst_buf, dst_len, offset);
    353   bit_offset = 0;
    354   ClearTable();
    355 }
    356 gif_decompress_struct_p _gif_create_decompress() {
    357   gif_decompress_struct_p gif_ptr =
    358       (gif_decompress_struct*)FX_Alloc(uint8_t, sizeof(gif_decompress_struct));
    359   if (gif_ptr == NULL) {
    360     return NULL;
    361   }
    362   FXSYS_memset(gif_ptr, 0, sizeof(gif_decompress_struct));
    363   gif_ptr->decode_status = GIF_D_STATUS_SIG;
    364   gif_ptr->img_ptr_arr_ptr = new CFX_ArrayTemplate<GifImage*>;
    365 #ifdef GIF_SUPPORT_COMMENT_EXTENSION
    366   gif_ptr->cmt_data_ptr = new CFX_ByteString;
    367 #endif
    368 #ifdef GIF_SUPPORT_PLAIN_TEXT_EXTENSION
    369   gif_ptr->pt_ptr_arr_ptr = new CFX_ArrayTemplate<GifPlainText*>;
    370 #endif
    371   return gif_ptr;
    372 }
    373 void _gif_destroy_decompress(gif_decompress_struct_pp gif_ptr_ptr) {
    374   if (gif_ptr_ptr == NULL || *gif_ptr_ptr == NULL) {
    375     return;
    376   }
    377   gif_decompress_struct_p gif_ptr = *gif_ptr_ptr;
    378   *gif_ptr_ptr = NULL;
    379   if (gif_ptr->global_pal_ptr != NULL) {
    380     FX_Free(gif_ptr->global_pal_ptr);
    381   }
    382   if (gif_ptr->img_decoder_ptr != NULL) {
    383     delete gif_ptr->img_decoder_ptr;
    384   }
    385   if (gif_ptr->img_ptr_arr_ptr != NULL) {
    386     int32_t size_img_arr = gif_ptr->img_ptr_arr_ptr->GetSize();
    387     for (int32_t i = 0; i < size_img_arr; i++) {
    388       GifImage* p = gif_ptr->img_ptr_arr_ptr->GetAt(i);
    389       if (p->image_info_ptr != NULL) {
    390         FX_Free(p->image_info_ptr);
    391       }
    392       if (p->image_gce_ptr != NULL) {
    393         FX_Free(p->image_gce_ptr);
    394       }
    395       if (p->image_row_buf != NULL) {
    396         FX_Free(p->image_row_buf);
    397       }
    398       if (p->local_pal_ptr != NULL &&
    399           p->local_pal_ptr != gif_ptr->global_pal_ptr) {
    400         FX_Free(p->local_pal_ptr);
    401       }
    402       FX_Free(p);
    403     }
    404     gif_ptr->img_ptr_arr_ptr->RemoveAll();
    405     delete gif_ptr->img_ptr_arr_ptr;
    406   }
    407 #ifdef GIF_SUPPORT_APPLICATION_EXTENSION
    408   if (gif_ptr->app_data != NULL) {
    409     FX_Free(gif_ptr->app_data);
    410   }
    411 #endif
    412 #ifdef GIF_SUPPORT_COMMENT_EXTENSION
    413   if (gif_ptr->cmt_data_ptr != NULL) {
    414     delete gif_ptr->cmt_data_ptr;
    415   }
    416 #endif
    417 #ifdef GIF_SUPPORT_GRAPHIC_CONTROL_EXTENSION
    418   if (gif_ptr->gce_ptr != NULL) {
    419     FX_Free(gif_ptr->gce_ptr);
    420   }
    421 #endif
    422 #ifdef GIF_SUPPORT_PLAIN_TEXT_EXTENSION
    423   if (gif_ptr->pt_ptr_arr_ptr != NULL) {
    424     int32_t size_pt_arr = gif_ptr->pt_ptr_arr_ptr->GetSize();
    425     for (int32_t i = 0; i < size_pt_arr; i++) {
    426       GifPlainText* p = gif_ptr->pt_ptr_arr_ptr->GetAt(i);
    427       if (p->gce_ptr != NULL) {
    428         FX_Free(p->gce_ptr);
    429       }
    430       if (p->pte_ptr != NULL) {
    431         FX_Free(p->pte_ptr);
    432       }
    433       if (p->string_ptr != NULL) {
    434         delete p->string_ptr;
    435       }
    436     }
    437     gif_ptr->pt_ptr_arr_ptr->RemoveAll();
    438     delete gif_ptr->pt_ptr_arr_ptr;
    439   }
    440 #endif
    441   FX_Free(gif_ptr);
    442 }
    443 gif_compress_struct_p _gif_create_compress() {
    444   gif_compress_struct_p gif_ptr =
    445       (gif_compress_struct*)FX_Alloc(uint8_t, sizeof(gif_compress_struct));
    446   if (gif_ptr == NULL) {
    447     return NULL;
    448   }
    449   FXSYS_memset(gif_ptr, 0, sizeof(gif_compress_struct));
    450   gif_ptr->img_encoder_ptr = new CGifLZWEncoder;
    451   gif_ptr->header_ptr = (GifHeader*)FX_Alloc(uint8_t, sizeof(GifHeader));
    452   if (gif_ptr->header_ptr == NULL) {
    453     delete (gif_ptr->img_encoder_ptr);
    454     FX_Free(gif_ptr);
    455     return NULL;
    456   }
    457   FXSYS_memcpy(gif_ptr->header_ptr->signature, GIF_SIGNATURE, 3);
    458   FXSYS_memcpy(gif_ptr->header_ptr->version, "89a", 3);
    459   gif_ptr->lsd_ptr = (GifLSD*)FX_Alloc(uint8_t, sizeof(GifLSD));
    460   if (gif_ptr->lsd_ptr == NULL) {
    461     FX_Free(gif_ptr->header_ptr);
    462     delete (gif_ptr->img_encoder_ptr);
    463     FX_Free(gif_ptr);
    464     return NULL;
    465   }
    466   FXSYS_memset(gif_ptr->lsd_ptr, 0, sizeof(GifLSD));
    467   gif_ptr->image_info_ptr =
    468       (GifImageInfo*)FX_Alloc(uint8_t, sizeof(GifImageInfo));
    469   if (gif_ptr->image_info_ptr == NULL) {
    470     FX_Free(gif_ptr->lsd_ptr);
    471     FX_Free(gif_ptr->header_ptr);
    472     delete (gif_ptr->img_encoder_ptr);
    473     FX_Free(gif_ptr);
    474     return NULL;
    475   }
    476   FXSYS_memset(gif_ptr->image_info_ptr, 0, sizeof(GifImageInfo));
    477 #ifdef GIF_SUPPORT_APPLICATION_EXTENSION
    478   FXSYS_memcpy(gif_ptr->app_identify, "netscape", 8);
    479   FXSYS_memcpy(gif_ptr->app_authentication, "2.0", 3);
    480 #endif
    481 #ifdef GIF_SUPPORT_GRAPHIC_CONTROL_EXTENSION
    482   gif_ptr->gce_ptr = (GifGCE*)FX_Alloc(uint8_t, sizeof(GifGCE));
    483   if (gif_ptr->gce_ptr == NULL) {
    484     FX_Free(gif_ptr->image_info_ptr);
    485     FX_Free(gif_ptr->lsd_ptr);
    486     FX_Free(gif_ptr->header_ptr);
    487     delete (gif_ptr->img_encoder_ptr);
    488     FX_Free(gif_ptr);
    489     return NULL;
    490   }
    491 #endif
    492 #ifdef GIF_SUPPORT_PLAIN_TEXT_EXTENSION
    493   gif_ptr->pte_ptr = (GifPTE*)FX_Alloc(uint8_t, sizeof(GifPTE));
    494   if (gif_ptr->pte_ptr == NULL) {
    495     FX_Free(gif_ptr->gce_ptr);
    496     FX_Free(gif_ptr->image_info_ptr);
    497     FX_Free(gif_ptr->lsd_ptr);
    498     FX_Free(gif_ptr->header_ptr);
    499     delete (gif_ptr->img_encoder_ptr);
    500     FX_Free(gif_ptr);
    501     return NULL;
    502   }
    503   FXSYS_memset(gif_ptr->pte_ptr, 0, sizeof(GifPTE));
    504   gif_ptr->pte_ptr->block_size = 12;
    505 #endif
    506   return gif_ptr;
    507 }
    508 void _gif_destroy_compress(gif_compress_struct_pp gif_ptr_ptr) {
    509   if (gif_ptr_ptr == NULL || *gif_ptr_ptr == NULL) {
    510     return;
    511   }
    512   gif_compress_struct_p gif_ptr = *gif_ptr_ptr;
    513   *gif_ptr_ptr = NULL;
    514   if (gif_ptr->header_ptr != NULL) {
    515     FX_Free(gif_ptr->header_ptr);
    516   }
    517   if (gif_ptr->lsd_ptr != NULL) {
    518     FX_Free(gif_ptr->lsd_ptr);
    519   }
    520   if (gif_ptr->global_pal != NULL) {
    521     FX_Free(gif_ptr->global_pal);
    522   }
    523   if (gif_ptr->image_info_ptr != NULL) {
    524     FX_Free(gif_ptr->image_info_ptr);
    525   }
    526   if (gif_ptr->local_pal != NULL) {
    527     FX_Free(gif_ptr->local_pal);
    528   }
    529   if (gif_ptr->img_encoder_ptr != NULL) {
    530     delete gif_ptr->img_encoder_ptr;
    531   }
    532 #ifdef GIF_SUPPORT_APPLICATION_EXTENSION
    533   if (gif_ptr->app_data != NULL) {
    534     FX_Free(gif_ptr->app_data);
    535   }
    536 #endif
    537 #ifdef GIF_SUPPORT_GRAPHIC_CONTROL_EXTENSION
    538   if (gif_ptr->gce_ptr != NULL) {
    539     FX_Free(gif_ptr->gce_ptr);
    540   }
    541 #endif
    542 #ifdef GIF_SUPPORT_COMMENT_EXTENSION
    543   if (gif_ptr->cmt_data_ptr != NULL) {
    544     FX_Free(gif_ptr->cmt_data_ptr);
    545   }
    546 #endif
    547 #ifdef GIF_SUPPORT_PLAIN_TEXT_EXTENSION
    548   if (gif_ptr->pte_ptr != NULL) {
    549     FX_Free(gif_ptr->pte_ptr);
    550   }
    551 #endif
    552   FX_Free(gif_ptr);
    553 }
    554 void _gif_error(gif_decompress_struct_p gif_ptr, const FX_CHAR* err_msg) {
    555   if (gif_ptr != NULL && gif_ptr->_gif_error_fn != NULL) {
    556     gif_ptr->_gif_error_fn(gif_ptr, err_msg);
    557   }
    558 }
    559 void _gif_warn(gif_decompress_struct_p gif_ptr, const FX_CHAR* err_msg) {}
    560 int32_t _gif_read_header(gif_decompress_struct_p gif_ptr) {
    561   if (gif_ptr == NULL) {
    562     return 0;
    563   }
    564   FX_DWORD skip_size_org = gif_ptr->skip_size;
    565   ASSERT(sizeof(GifHeader) == 6);
    566   GifHeader* gif_header_ptr = NULL;
    567   if (_gif_read_data(gif_ptr, (uint8_t**)&gif_header_ptr, 6) == NULL) {
    568     return 2;
    569   }
    570   if (FXSYS_strncmp(gif_header_ptr->signature, GIF_SIGNATURE, 3) != 0 ||
    571       gif_header_ptr->version[0] != '8' || gif_header_ptr->version[2] != 'a') {
    572     _gif_error(gif_ptr, "Not A Gif Image");
    573     return 0;
    574   }
    575   ASSERT(sizeof(GifLSD) == 7);
    576   GifLSD* gif_lsd_ptr = NULL;
    577   if (_gif_read_data(gif_ptr, (uint8_t**)&gif_lsd_ptr, 7) == NULL) {
    578     gif_ptr->skip_size = skip_size_org;
    579     return 2;
    580   }
    581   if (((GifGF*)&gif_lsd_ptr->global_flag)->global_pal) {
    582     gif_ptr->global_pal_num = 2
    583                               << ((GifGF*)&gif_lsd_ptr->global_flag)->pal_bits;
    584     ASSERT(sizeof(GifPalette) == 3);
    585     int32_t global_pal_size = gif_ptr->global_pal_num * 3;
    586     uint8_t* global_pal_ptr = NULL;
    587     if (_gif_read_data(gif_ptr, &global_pal_ptr, global_pal_size) == NULL) {
    588       gif_ptr->skip_size = skip_size_org;
    589       return 2;
    590     }
    591     gif_ptr->global_sort_flag = ((GifGF*)&gif_lsd_ptr->global_flag)->sort_flag;
    592     gif_ptr->global_color_resolution =
    593         ((GifGF*)&gif_lsd_ptr->global_flag)->color_resolution;
    594     if (gif_ptr->global_pal_ptr != NULL) {
    595       FX_Free(gif_ptr->global_pal_ptr);
    596     }
    597     gif_ptr->global_pal_ptr = NULL;
    598     gif_ptr->global_pal_ptr = (GifPalette*)FX_Alloc(uint8_t, global_pal_size);
    599     GIF_PTR_NOT_NULL(gif_ptr->global_pal_ptr, gif_ptr);
    600     FXSYS_memcpy(gif_ptr->global_pal_ptr, global_pal_ptr, global_pal_size);
    601   }
    602   gif_ptr->width = (int)_GetWord_LSBFirst((uint8_t*)&gif_lsd_ptr->width);
    603   gif_ptr->height = (int)_GetWord_LSBFirst((uint8_t*)&gif_lsd_ptr->height);
    604   gif_ptr->bc_index = gif_lsd_ptr->bc_index;
    605   gif_ptr->pixel_aspect = gif_lsd_ptr->pixel_aspect;
    606   return 1;
    607 }
    608 int32_t _gif_get_frame(gif_decompress_struct_p gif_ptr) {
    609   if (gif_ptr == NULL) {
    610     return 0;
    611   }
    612   int32_t ret = 1;
    613   while (TRUE) {
    614     switch (gif_ptr->decode_status) {
    615       case GIF_D_STATUS_TAIL:
    616         return 1;
    617       case GIF_D_STATUS_SIG: {
    618         uint8_t* sig_ptr = NULL;
    619         if (_gif_read_data(gif_ptr, &sig_ptr, 1) == NULL) {
    620           return 2;
    621         }
    622         switch (*sig_ptr) {
    623           case GIF_SIG_EXTENSION:
    624             _gif_save_decoding_status(gif_ptr, GIF_D_STATUS_EXT);
    625             continue;
    626           case GIF_SIG_IMAGE:
    627             _gif_save_decoding_status(gif_ptr, GIF_D_STATUS_IMG_INFO);
    628             continue;
    629           case GIF_SIG_TRAILER:
    630             _gif_save_decoding_status(gif_ptr, GIF_D_STATUS_TAIL);
    631             return 1;
    632           default:
    633             if (gif_ptr->avail_in) {
    634               _gif_warn(gif_ptr, "The Gif File has non_standard Tag!");
    635               _gif_save_decoding_status(gif_ptr, GIF_D_STATUS_SIG);
    636               continue;
    637             }
    638             _gif_warn(gif_ptr, "The Gif File Doesn't have Trailer Tag!");
    639             return 1;
    640         }
    641       }
    642       case GIF_D_STATUS_EXT: {
    643         uint8_t* ext_ptr = NULL;
    644         if (_gif_read_data(gif_ptr, &ext_ptr, 1) == NULL) {
    645           return 2;
    646         }
    647         switch (*ext_ptr) {
    648 #ifdef GIF_SUPPORT_APPLICATION_EXTENSION
    649           case GIF_BLOCK_AE:
    650             _gif_save_decoding_status(gif_ptr, GIF_D_STATUS_EXT_AE);
    651             continue;
    652 #endif
    653 #ifdef GIF_SUPPORT_COMMENT_EXTENSION
    654           case GIF_BLOCK_CE:
    655             _gif_save_decoding_status(gif_ptr, GIF_D_STATUS_EXT_CE);
    656             continue;
    657 #endif
    658 #ifdef GIF_SUPPORT_GRAPHIC_CONTROL_EXTENSION
    659           case GIF_BLOCK_GCE:
    660             _gif_save_decoding_status(gif_ptr, GIF_D_STATUS_EXT_GCE);
    661             continue;
    662 #endif
    663 #ifdef GIF_SUPPORT_PLAIN_TEXT_EXTENSION
    664           case GIF_BLOCK_PTE:
    665             _gif_save_decoding_status(gif_ptr, GIF_D_STATUS_EXT_PTE);
    666             continue;
    667 #endif
    668           default: {
    669             int32_t status = GIF_D_STATUS_EXT_UNE;
    670 #ifndef GIF_SUPPORT_PLAIN_TEXT_EXTENSION
    671             if (*ext_ptr == GIF_BLOCK_PTE) {
    672               status = GIF_D_STATUS_EXT_PTE;
    673             }
    674 #endif
    675             _gif_save_decoding_status(gif_ptr, status);
    676             continue;
    677           }
    678         }
    679       }
    680       case GIF_D_STATUS_IMG_INFO: {
    681         ret = _gif_decode_image_info(gif_ptr);
    682         if (ret != 1) {
    683           return ret;
    684         }
    685         continue;
    686       }
    687       case GIF_D_STATUS_IMG_DATA: {
    688         uint8_t* data_size_ptr = NULL;
    689         uint8_t* data_ptr = NULL;
    690         FX_DWORD skip_size_org = gif_ptr->skip_size;
    691         if (_gif_read_data(gif_ptr, &data_size_ptr, 1) == NULL) {
    692           return 2;
    693         }
    694         while (*data_size_ptr != GIF_BLOCK_TERMINAL) {
    695           if (_gif_read_data(gif_ptr, &data_ptr, *data_size_ptr) == NULL) {
    696             gif_ptr->skip_size = skip_size_org;
    697             return 2;
    698           }
    699           _gif_save_decoding_status(gif_ptr, GIF_D_STATUS_IMG_DATA);
    700           skip_size_org = gif_ptr->skip_size;
    701           if (_gif_read_data(gif_ptr, &data_size_ptr, 1) == NULL) {
    702             return 2;
    703           }
    704         }
    705         _gif_save_decoding_status(gif_ptr, GIF_D_STATUS_SIG);
    706         continue;
    707       }
    708       default: {
    709         ret = _gif_decode_extension(gif_ptr);
    710         if (ret != 1) {
    711           return ret;
    712         }
    713         continue;
    714       }
    715     }
    716   }
    717   return 1;
    718 }
    719 void _gif_takeover_gce_ptr(gif_decompress_struct_p gif_ptr,
    720                            GifGCE** gce_ptr_ptr) {
    721   *gce_ptr_ptr = NULL;
    722 #ifdef GIF_SUPPORT_GRAPHIC_CONTROL_EXTENSION
    723   if (gif_ptr->gce_ptr != NULL && gce_ptr_ptr != NULL) {
    724     *gce_ptr_ptr = gif_ptr->gce_ptr;
    725     gif_ptr->gce_ptr = NULL;
    726   }
    727 #endif
    728 }
    729 int32_t _gif_decode_extension(gif_decompress_struct_p gif_ptr) {
    730   uint8_t* data_size_ptr = NULL;
    731   uint8_t* data_ptr = NULL;
    732   FX_DWORD skip_size_org = gif_ptr->skip_size;
    733   switch (gif_ptr->decode_status) {
    734 #ifdef GIF_SUPPORT_APPLICATION_EXTENSION
    735     case GIF_D_STATUS_EXT_AE: {
    736       ASSERT(sizeof(GifAE) == 12);
    737       GifAE* gif_ae_ptr = NULL;
    738       if (_gif_read_data(gif_ptr, (uint8_t**)&gif_ae_ptr, 12) == NULL) {
    739         return 2;
    740       }
    741       CFX_ByteString gif_ae_data_str;
    742       if (_gif_read_data(gif_ptr, &data_size_ptr, 1) == NULL) {
    743         gif_ptr->skip_size = skip_size_org;
    744         return 2;
    745       }
    746       while (*data_size_ptr != GIF_BLOCK_TERMINAL) {
    747         uint8_t data_size = *data_size_ptr;
    748         if (_gif_read_data(gif_ptr, &data_ptr, *data_size_ptr) == NULL ||
    749             _gif_read_data(gif_ptr, &data_size_ptr, 1) == NULL) {
    750           gif_ptr->skip_size = skip_size_org;
    751           return 2;
    752         }
    753         gif_ae_data_str += CFX_ByteString((const uint8_t*)data_ptr, data_size);
    754       }
    755       FXSYS_memcpy(gif_ptr->app_identify, gif_ae_ptr->app_identify, 8);
    756       FXSYS_memcpy(gif_ptr->app_authentication, gif_ae_ptr->app_authentication,
    757                    3);
    758       gif_ptr->app_data_size = gif_ae_data_str.GetLength();
    759       if (gif_ptr->app_data != NULL) {
    760         FX_Free(gif_ptr->app_data);
    761         gif_ptr->app_data = NULL;
    762       }
    763       gif_ptr->app_data = FX_Alloc(uint8_t, gif_ptr->app_data_size);
    764       GIF_PTR_NOT_NULL(gif_ptr->app_data, gif_ptr);
    765       FXSYS_memcpy(gif_ptr->app_data, const uint8_t*(gif_ae_data_str),
    766                    gif_ptr->app_data_size);
    767     } break;
    768 #endif
    769 #ifdef GIF_SUPPORT_COMMENT_EXTENSION
    770     case GIF_D_STATUS_EXT_CE: {
    771       if (_gif_read_data(gif_ptr, &data_size_ptr, 1) == NULL) {
    772         gif_ptr->skip_size = skip_size_org;
    773         return 2;
    774       }
    775       gif_ptr->cmt_data_ptr->Empty();
    776       while (*data_size_ptr != GIF_BLOCK_TERMINAL) {
    777         uint8_t data_size = *data_size_ptr;
    778         if (_gif_read_data(gif_ptr, &data_ptr, *data_size_ptr) == NULL ||
    779             _gif_read_data(gif_ptr, &data_size_ptr, 1) == NULL) {
    780           gif_ptr->skip_size = skip_size_org;
    781           return 2;
    782         }
    783         *(gif_ptr->cmt_data_ptr) +=
    784             CFX_ByteString((const FX_CHAR*)data_ptr, data_size);
    785       }
    786     } break;
    787 #endif
    788 #ifdef GIF_SUPPORT_PLAIN_TEXT_EXTENSION
    789     case GIF_D_STATUS_EXT_PTE: {
    790       ASSERT(sizeof(GifPTE) == 13);
    791       GifPTE* gif_pte_ptr = NULL;
    792       if (_gif_read_data(gif_ptr, (uint8_t**)&gif_pte_ptr, 13) == NULL) {
    793         return 2;
    794       }
    795       GifPlainText* gif_pt_ptr = FX_Alloc(GifPlainText, 1);
    796       GIF_PTR_NOT_NULL(gif_pt_ptr, gif_ptr);
    797       FXSYS_memset(gif_pt_ptr, 0, sizeof(GifPlainText));
    798       _gif_takeover_gce_ptr(gif_ptr, &gif_pt_ptr->gce_ptr);
    799       gif_pt_ptr->pte_ptr = (GifPTE*)FX_Alloc(uint8_t, sizeof(GifPTE));
    800       GIF_PTR_NOT_NULL(gif_pt_ptr->pte_ptr, gif_ptr);
    801       gif_pt_ptr->string_ptr = new CFX_ByteString;
    802       GIF_PTR_NOT_NULL(gif_pt_ptr->string_ptr, gif_ptr);
    803       gif_pt_ptr->pte_ptr->block_size = gif_pte_ptr->block_size;
    804       gif_pt_ptr->pte_ptr->grid_left =
    805           _GetWord_LSBFirst((uint8_t*)&gif_pte_ptr->grid_left);
    806       gif_pt_ptr->pte_ptr->grid_top =
    807           _GetWord_LSBFirst((uint8_t*)&gif_pte_ptr->grid_top);
    808       gif_pt_ptr->pte_ptr->grid_width =
    809           _GetWord_LSBFirst((uint8_t*)&gif_pte_ptr->grid_width);
    810       gif_pt_ptr->pte_ptr->grid_height =
    811           _GetWord_LSBFirst((uint8_t*)&gif_pte_ptr->grid_height);
    812       gif_pt_ptr->pte_ptr->char_width = gif_pte_ptr->char_width;
    813       gif_pt_ptr->pte_ptr->char_height = gif_pte_ptr->char_height;
    814       gif_pt_ptr->pte_ptr->fc_index = gif_pte_ptr->fc_index;
    815       gif_pt_ptr->pte_ptr->bc_index = gif_pte_ptr->bc_index;
    816       if (_gif_read_data(gif_ptr, &data_size_ptr, 1) == NULL) {
    817         gif_ptr->skip_size = skip_size_org;
    818         if (gif_pt_ptr != NULL) {
    819           if (gif_pt_ptr->gce_ptr != NULL) {
    820             FX_Free(gif_pt_ptr->gce_ptr);
    821           }
    822           if (gif_pt_ptr->pte_ptr != NULL) {
    823             FX_Free(gif_pt_ptr->pte_ptr);
    824           }
    825           if (gif_pt_ptr->string_ptr != NULL) {
    826             delete gif_pt_ptr->string_ptr;
    827           }
    828           FX_Free(gif_pt_ptr);
    829         }
    830         return 2;
    831       }
    832       while (*data_size_ptr != GIF_BLOCK_TERMINAL) {
    833         uint8_t data_size = *data_size_ptr;
    834         if (_gif_read_data(gif_ptr, &data_ptr, *data_size_ptr) == NULL ||
    835             _gif_read_data(gif_ptr, &data_size_ptr, 1) == NULL) {
    836           gif_ptr->skip_size = skip_size_org;
    837           if (gif_pt_ptr != NULL) {
    838             if (gif_pt_ptr->gce_ptr != NULL) {
    839               FX_Free(gif_pt_ptr->gce_ptr);
    840             }
    841             if (gif_pt_ptr->pte_ptr != NULL) {
    842               FX_Free(gif_pt_ptr->pte_ptr);
    843             }
    844             if (gif_pt_ptr->string_ptr != NULL) {
    845               delete gif_pt_ptr->string_ptr;
    846             }
    847             FX_Free(gif_pt_ptr);
    848           }
    849           return 2;
    850         }
    851         *(gif_pt_ptr->string_ptr) +=
    852             CFX_ByteString((const FX_CHAR*)data_ptr, data_size);
    853       }
    854       gif_ptr->pt_ptr_arr_ptr->Add(gif_pt_ptr);
    855     } break;
    856 #endif
    857 #ifdef GIF_SUPPORT_GRAPHIC_CONTROL_EXTENSION
    858     case GIF_D_STATUS_EXT_GCE: {
    859       ASSERT(sizeof(GifGCE) == 5);
    860       GifGCE* gif_gce_ptr = NULL;
    861       if (_gif_read_data(gif_ptr, (uint8_t**)&gif_gce_ptr, 6) == NULL) {
    862         return 2;
    863       }
    864       if (gif_ptr->gce_ptr == NULL) {
    865         gif_ptr->gce_ptr = (GifGCE*)FX_Alloc(uint8_t, sizeof(GifGCE));
    866         GIF_PTR_NOT_NULL(gif_ptr->gce_ptr, gif_ptr);
    867       }
    868       gif_ptr->gce_ptr->block_size = gif_gce_ptr->block_size;
    869       gif_ptr->gce_ptr->gce_flag = gif_gce_ptr->gce_flag;
    870       gif_ptr->gce_ptr->delay_time =
    871           _GetWord_LSBFirst((uint8_t*)&gif_gce_ptr->delay_time);
    872       gif_ptr->gce_ptr->trans_index = gif_gce_ptr->trans_index;
    873     } break;
    874 #endif
    875     default: {
    876 #ifndef GIF_SUPPORT_PLAIN_TEXT_EXTENSION
    877       if (gif_ptr->decode_status == GIF_D_STATUS_EXT_PTE) {
    878 #ifdef GIF_SUPPORT_GRAPHIC_CONTROL_EXTENSION
    879         if (gif_ptr->gce_ptr != NULL) {
    880           FX_Free(gif_ptr->gce_ptr);
    881           gif_ptr->gce_ptr = NULL;
    882         }
    883 #endif
    884       }
    885 #endif
    886       if (_gif_read_data(gif_ptr, &data_size_ptr, 1) == NULL) {
    887         return 2;
    888       }
    889       while (*data_size_ptr != GIF_BLOCK_TERMINAL) {
    890         if (_gif_read_data(gif_ptr, &data_ptr, *data_size_ptr) == NULL ||
    891             _gif_read_data(gif_ptr, &data_size_ptr, 1) == NULL) {
    892           gif_ptr->skip_size = skip_size_org;
    893           return 2;
    894         }
    895       }
    896     }
    897   }
    898   _gif_save_decoding_status(gif_ptr, GIF_D_STATUS_SIG);
    899   return 1;
    900 }
    901 int32_t _gif_decode_image_info(gif_decompress_struct_p gif_ptr) {
    902   if (gif_ptr->width == 0 || gif_ptr->height == 0) {
    903     _gif_error(gif_ptr, "No Image Header Info");
    904     return 0;
    905   }
    906   FX_DWORD skip_size_org = gif_ptr->skip_size;
    907   ASSERT(sizeof(GifImageInfo) == 9);
    908   GifImageInfo* gif_img_info_ptr = NULL;
    909   if (_gif_read_data(gif_ptr, (uint8_t**)&gif_img_info_ptr, 9) == NULL) {
    910     return 2;
    911   }
    912   GifImage* gif_image_ptr = (GifImage*)FX_Alloc(uint8_t, sizeof(GifImage));
    913   GIF_PTR_NOT_NULL(gif_image_ptr, gif_ptr);
    914   FXSYS_memset(gif_image_ptr, 0, sizeof(GifImage));
    915   gif_image_ptr->image_info_ptr =
    916       (GifImageInfo*)FX_Alloc(uint8_t, sizeof(GifImageInfo));
    917   GIF_PTR_NOT_NULL(gif_image_ptr->image_info_ptr, gif_ptr);
    918   gif_image_ptr->image_info_ptr->left =
    919       _GetWord_LSBFirst((uint8_t*)&gif_img_info_ptr->left);
    920   gif_image_ptr->image_info_ptr->top =
    921       _GetWord_LSBFirst((uint8_t*)&gif_img_info_ptr->top);
    922   gif_image_ptr->image_info_ptr->width =
    923       _GetWord_LSBFirst((uint8_t*)&gif_img_info_ptr->width);
    924   gif_image_ptr->image_info_ptr->height =
    925       _GetWord_LSBFirst((uint8_t*)&gif_img_info_ptr->height);
    926   gif_image_ptr->image_info_ptr->local_flag = gif_img_info_ptr->local_flag;
    927   if (gif_image_ptr->image_info_ptr->left +
    928               gif_image_ptr->image_info_ptr->width >
    929           gif_ptr->width ||
    930       gif_image_ptr->image_info_ptr->top +
    931               gif_image_ptr->image_info_ptr->height >
    932           gif_ptr->height) {
    933     if (gif_image_ptr->image_info_ptr != NULL) {
    934       FX_Free(gif_image_ptr->image_info_ptr);
    935     }
    936     if (gif_image_ptr->image_row_buf != NULL) {
    937       FX_Free(gif_image_ptr->image_row_buf);
    938     }
    939     FX_Free(gif_image_ptr);
    940     _gif_error(gif_ptr, "Image Data Out Of LSD, The File May Be Corrupt");
    941     return 0;
    942   }
    943   GifLF* gif_img_info_lf_ptr = (GifLF*)&gif_img_info_ptr->local_flag;
    944   if (gif_img_info_lf_ptr->local_pal) {
    945     ASSERT(sizeof(GifPalette) == 3);
    946     int32_t loc_pal_size = (2 << gif_img_info_lf_ptr->pal_bits) * 3;
    947     uint8_t* loc_pal_ptr = NULL;
    948     if (_gif_read_data(gif_ptr, &loc_pal_ptr, loc_pal_size) == NULL) {
    949       gif_ptr->skip_size = skip_size_org;
    950       if (gif_image_ptr->image_info_ptr != NULL) {
    951         FX_Free(gif_image_ptr->image_info_ptr);
    952       }
    953       if (gif_image_ptr->image_row_buf != NULL) {
    954         FX_Free(gif_image_ptr->image_row_buf);
    955       }
    956       FX_Free(gif_image_ptr);
    957       return 2;
    958     }
    959     gif_image_ptr->local_pal_ptr =
    960         (GifPalette*)gif_ptr->_gif_ask_buf_for_pal_fn(gif_ptr, loc_pal_size);
    961     if (gif_image_ptr->local_pal_ptr != NULL) {
    962       FXSYS_memcpy((uint8_t*)gif_image_ptr->local_pal_ptr, loc_pal_ptr,
    963                    loc_pal_size);
    964     }
    965   }
    966   uint8_t* code_size_ptr = NULL;
    967   if (_gif_read_data(gif_ptr, &code_size_ptr, 1) == NULL) {
    968     gif_ptr->skip_size = skip_size_org;
    969     if (gif_image_ptr->image_info_ptr != NULL) {
    970       FX_Free(gif_image_ptr->image_info_ptr);
    971     }
    972     if (gif_image_ptr->local_pal_ptr != NULL) {
    973       FX_Free(gif_image_ptr->local_pal_ptr);
    974     }
    975     if (gif_image_ptr->image_row_buf != NULL) {
    976       FX_Free(gif_image_ptr->image_row_buf);
    977     }
    978     FX_Free(gif_image_ptr);
    979     return 2;
    980   }
    981   gif_image_ptr->image_code_size = *code_size_ptr;
    982   gif_ptr->_gif_record_current_position_fn(gif_ptr,
    983                                            &gif_image_ptr->image_data_pos);
    984   gif_image_ptr->image_data_pos += gif_ptr->skip_size;
    985   _gif_takeover_gce_ptr(gif_ptr, &gif_image_ptr->image_gce_ptr);
    986   gif_ptr->img_ptr_arr_ptr->Add(gif_image_ptr);
    987   _gif_save_decoding_status(gif_ptr, GIF_D_STATUS_IMG_DATA);
    988   return 1;
    989 }
    990 int32_t _gif_load_frame(gif_decompress_struct_p gif_ptr, int32_t frame_num) {
    991   if (gif_ptr == NULL || frame_num < 0 ||
    992       frame_num >= gif_ptr->img_ptr_arr_ptr->GetSize()) {
    993     return 0;
    994   }
    995   uint8_t* data_size_ptr = NULL;
    996   uint8_t* data_ptr = NULL;
    997   FX_DWORD skip_size_org = gif_ptr->skip_size;
    998   GifImage* gif_image_ptr = gif_ptr->img_ptr_arr_ptr->GetAt(frame_num);
    999   FX_DWORD gif_img_row_bytes = gif_image_ptr->image_info_ptr->width;
   1000   if (gif_ptr->decode_status == GIF_D_STATUS_TAIL) {
   1001     if (gif_image_ptr->image_row_buf) {
   1002       FX_Free(gif_image_ptr->image_row_buf);
   1003       gif_image_ptr->image_row_buf = NULL;
   1004     }
   1005     gif_image_ptr->image_row_buf = FX_Alloc(uint8_t, gif_img_row_bytes);
   1006     GIF_PTR_NOT_NULL(gif_image_ptr->image_row_buf, gif_ptr);
   1007     GifGCE* gif_img_gce_ptr = gif_image_ptr->image_gce_ptr;
   1008     int32_t loc_pal_num =
   1009         ((GifLF*)&gif_image_ptr->image_info_ptr->local_flag)->local_pal
   1010             ? (2 << ((GifLF*)&gif_image_ptr->image_info_ptr->local_flag)
   1011                         ->pal_bits)
   1012             : 0;
   1013     gif_ptr->avail_in = 0;
   1014     if (gif_img_gce_ptr == NULL) {
   1015       FX_BOOL bRes = gif_ptr->_gif_get_record_position_fn(
   1016           gif_ptr, gif_image_ptr->image_data_pos,
   1017           gif_image_ptr->image_info_ptr->left,
   1018           gif_image_ptr->image_info_ptr->top,
   1019           gif_image_ptr->image_info_ptr->width,
   1020           gif_image_ptr->image_info_ptr->height, loc_pal_num,
   1021           gif_image_ptr->local_pal_ptr, 0, 0, -1, 0,
   1022           (FX_BOOL)((GifLF*)&gif_image_ptr->image_info_ptr->local_flag)
   1023               ->interlace);
   1024       if (!bRes) {
   1025         FX_Free(gif_image_ptr->image_row_buf);
   1026         gif_image_ptr->image_row_buf = NULL;
   1027         _gif_error(gif_ptr, "Error Read Record Position Data");
   1028         return 0;
   1029       }
   1030     } else {
   1031       FX_BOOL bRes = gif_ptr->_gif_get_record_position_fn(
   1032           gif_ptr, gif_image_ptr->image_data_pos,
   1033           gif_image_ptr->image_info_ptr->left,
   1034           gif_image_ptr->image_info_ptr->top,
   1035           gif_image_ptr->image_info_ptr->width,
   1036           gif_image_ptr->image_info_ptr->height, loc_pal_num,
   1037           gif_image_ptr->local_pal_ptr,
   1038           (int32_t)gif_image_ptr->image_gce_ptr->delay_time,
   1039           (FX_BOOL)((GifCEF*)&gif_image_ptr->image_gce_ptr->gce_flag)
   1040               ->user_input,
   1041           ((GifCEF*)&gif_image_ptr->image_gce_ptr->gce_flag)->transparency
   1042               ? (int32_t)gif_image_ptr->image_gce_ptr->trans_index
   1043               : -1,
   1044           (int32_t)((GifCEF*)&gif_image_ptr->image_gce_ptr->gce_flag)
   1045               ->disposal_method,
   1046           (FX_BOOL)((GifLF*)&gif_image_ptr->image_info_ptr->local_flag)
   1047               ->interlace);
   1048       if (!bRes) {
   1049         FX_Free(gif_image_ptr->image_row_buf);
   1050         gif_image_ptr->image_row_buf = NULL;
   1051         _gif_error(gif_ptr, "Error Read Record Position Data");
   1052         return 0;
   1053       }
   1054     }
   1055     if (gif_ptr->img_decoder_ptr == NULL) {
   1056       gif_ptr->img_decoder_ptr = new CGifLZWDecoder(gif_ptr->err_ptr);
   1057       GIF_PTR_NOT_NULL(gif_ptr->img_decoder_ptr, gif_ptr);
   1058     }
   1059     gif_ptr->img_decoder_ptr->InitTable(gif_image_ptr->image_code_size);
   1060     gif_ptr->img_row_offset = 0;
   1061     gif_ptr->img_row_avail_size = 0;
   1062     gif_ptr->img_pass_num = 0;
   1063     gif_image_ptr->image_row_num = 0;
   1064     _gif_save_decoding_status(gif_ptr, GIF_D_STATUS_IMG_DATA);
   1065   }
   1066   CGifLZWDecoder* img_decoder_ptr = gif_ptr->img_decoder_ptr;
   1067   if (gif_ptr->decode_status == GIF_D_STATUS_IMG_DATA) {
   1068     if (_gif_read_data(gif_ptr, &data_size_ptr, 1) == NULL) {
   1069       return 2;
   1070     }
   1071     if (*data_size_ptr != GIF_BLOCK_TERMINAL) {
   1072       if (_gif_read_data(gif_ptr, &data_ptr, *data_size_ptr) == NULL) {
   1073         gif_ptr->skip_size = skip_size_org;
   1074         return 2;
   1075       }
   1076       img_decoder_ptr->Input(data_ptr, *data_size_ptr);
   1077       _gif_save_decoding_status(gif_ptr, GIF_D_STATUS_IMG_DATA);
   1078       gif_ptr->img_row_offset += gif_ptr->img_row_avail_size;
   1079       gif_ptr->img_row_avail_size = gif_img_row_bytes - gif_ptr->img_row_offset;
   1080       int32_t ret = img_decoder_ptr->Decode(
   1081           gif_image_ptr->image_row_buf + gif_ptr->img_row_offset,
   1082           gif_ptr->img_row_avail_size);
   1083       if (ret == 0) {
   1084         FX_Free(gif_image_ptr->image_row_buf);
   1085         gif_image_ptr->image_row_buf = NULL;
   1086         _gif_save_decoding_status(gif_ptr, GIF_D_STATUS_TAIL);
   1087         _gif_error(gif_ptr, "Decode Image Data Error");
   1088         return 0;
   1089       }
   1090       while (ret != 0) {
   1091         if (ret == 1) {
   1092           gif_ptr->_gif_get_row_fn(gif_ptr, gif_image_ptr->image_row_num,
   1093                                    gif_image_ptr->image_row_buf);
   1094           FX_Free(gif_image_ptr->image_row_buf);
   1095           gif_image_ptr->image_row_buf = NULL;
   1096           _gif_save_decoding_status(gif_ptr, GIF_D_STATUS_TAIL);
   1097           return 1;
   1098         }
   1099         if (ret == 2) {
   1100           ASSERT(img_decoder_ptr->GetAvailInput() == 0);
   1101           skip_size_org = gif_ptr->skip_size;
   1102           if (_gif_read_data(gif_ptr, &data_size_ptr, 1) == NULL) {
   1103             return 2;
   1104           }
   1105           if (*data_size_ptr != GIF_BLOCK_TERMINAL) {
   1106             if (_gif_read_data(gif_ptr, &data_ptr, *data_size_ptr) == NULL) {
   1107               gif_ptr->skip_size = skip_size_org;
   1108               return 2;
   1109             }
   1110             img_decoder_ptr->Input(data_ptr, *data_size_ptr);
   1111             _gif_save_decoding_status(gif_ptr, GIF_D_STATUS_IMG_DATA);
   1112             gif_ptr->img_row_offset += gif_ptr->img_row_avail_size;
   1113             gif_ptr->img_row_avail_size =
   1114                 gif_img_row_bytes - gif_ptr->img_row_offset;
   1115             ret = img_decoder_ptr->Decode(
   1116                 gif_image_ptr->image_row_buf + gif_ptr->img_row_offset,
   1117                 gif_ptr->img_row_avail_size);
   1118           }
   1119         }
   1120         if (ret == 3) {
   1121           if (((GifLF*)&gif_image_ptr->image_info_ptr->local_flag)->interlace) {
   1122             gif_ptr->_gif_get_row_fn(gif_ptr, gif_image_ptr->image_row_num,
   1123                                      gif_image_ptr->image_row_buf);
   1124             gif_image_ptr->image_row_num +=
   1125                 s_gif_interlace_step[gif_ptr->img_pass_num];
   1126             if (gif_image_ptr->image_row_num >=
   1127                 (int32_t)gif_image_ptr->image_info_ptr->height) {
   1128               gif_ptr->img_pass_num++;
   1129               gif_image_ptr->image_row_num =
   1130                   s_gif_interlace_step[gif_ptr->img_pass_num] / 2;
   1131             }
   1132           } else {
   1133             gif_ptr->_gif_get_row_fn(gif_ptr, gif_image_ptr->image_row_num++,
   1134                                      gif_image_ptr->image_row_buf);
   1135           }
   1136           gif_ptr->img_row_offset = 0;
   1137           gif_ptr->img_row_avail_size = gif_img_row_bytes;
   1138           ret = img_decoder_ptr->Decode(
   1139               gif_image_ptr->image_row_buf + gif_ptr->img_row_offset,
   1140               gif_ptr->img_row_avail_size);
   1141         }
   1142         if (ret == 0) {
   1143           FX_Free(gif_image_ptr->image_row_buf);
   1144           gif_image_ptr->image_row_buf = NULL;
   1145           _gif_save_decoding_status(gif_ptr, GIF_D_STATUS_TAIL);
   1146           _gif_error(gif_ptr, "Decode Image Data Error");
   1147           return 0;
   1148         }
   1149       }
   1150     }
   1151     _gif_save_decoding_status(gif_ptr, GIF_D_STATUS_TAIL);
   1152   }
   1153   _gif_error(gif_ptr, "Decode Image Data Error");
   1154   return 0;
   1155 }
   1156 void _gif_save_decoding_status(gif_decompress_struct_p gif_ptr,
   1157                                int32_t status) {
   1158   gif_ptr->decode_status = status;
   1159   gif_ptr->next_in += gif_ptr->skip_size;
   1160   gif_ptr->avail_in -= gif_ptr->skip_size;
   1161   gif_ptr->skip_size = 0;
   1162 }
   1163 uint8_t* _gif_read_data(gif_decompress_struct_p gif_ptr,
   1164                         uint8_t** des_buf_pp,
   1165                         FX_DWORD data_size) {
   1166   if (gif_ptr == NULL || gif_ptr->avail_in < gif_ptr->skip_size + data_size) {
   1167     return NULL;
   1168   }
   1169   *des_buf_pp = gif_ptr->next_in + gif_ptr->skip_size;
   1170   gif_ptr->skip_size += data_size;
   1171   return *des_buf_pp;
   1172 }
   1173 void _gif_input_buffer(gif_decompress_struct_p gif_ptr,
   1174                        uint8_t* src_buf,
   1175                        FX_DWORD src_size) {
   1176   gif_ptr->next_in = src_buf;
   1177   gif_ptr->avail_in = src_size;
   1178   gif_ptr->skip_size = 0;
   1179 }
   1180 FX_DWORD _gif_get_avail_input(gif_decompress_struct_p gif_ptr,
   1181                               uint8_t** avial_buf_ptr) {
   1182   if (avial_buf_ptr != NULL) {
   1183     *avial_buf_ptr = NULL;
   1184     if (gif_ptr->avail_in > 0) {
   1185       *avial_buf_ptr = gif_ptr->next_in;
   1186     }
   1187   }
   1188   return gif_ptr->avail_in;
   1189 }
   1190 int32_t _gif_get_frame_num(gif_decompress_struct_p gif_ptr) {
   1191   return gif_ptr->img_ptr_arr_ptr->GetSize();
   1192 }
   1193 static FX_BOOL _gif_write_header(gif_compress_struct_p gif_ptr,
   1194                                  uint8_t*& dst_buf,
   1195                                  FX_DWORD& dst_len) {
   1196   if (gif_ptr->cur_offset) {
   1197     return TRUE;
   1198   }
   1199   dst_len = sizeof(GifHeader) + sizeof(GifLSD) + sizeof(GifGF);
   1200   dst_buf = FX_TryAlloc(uint8_t, dst_len);
   1201   if (dst_buf == NULL) {
   1202     return FALSE;
   1203   }
   1204   FXSYS_memset(dst_buf, 0, dst_len);
   1205   FXSYS_memcpy(dst_buf, gif_ptr->header_ptr, sizeof(GifHeader));
   1206   gif_ptr->cur_offset += sizeof(GifHeader);
   1207   _SetWord_LSBFirst(dst_buf + gif_ptr->cur_offset, gif_ptr->lsd_ptr->width);
   1208   gif_ptr->cur_offset += 2;
   1209   _SetWord_LSBFirst(dst_buf + gif_ptr->cur_offset, gif_ptr->lsd_ptr->height);
   1210   gif_ptr->cur_offset += 2;
   1211   dst_buf[gif_ptr->cur_offset++] = gif_ptr->lsd_ptr->global_flag;
   1212   dst_buf[gif_ptr->cur_offset++] = gif_ptr->lsd_ptr->bc_index;
   1213   dst_buf[gif_ptr->cur_offset++] = gif_ptr->lsd_ptr->pixel_aspect;
   1214   if (gif_ptr->global_pal) {
   1215     FX_WORD size = sizeof(GifPalette) * gif_ptr->gpal_num;
   1216     if (!_gif_grow_buf(dst_buf, dst_len, gif_ptr->cur_offset + size)) {
   1217       return FALSE;
   1218     }
   1219     FXSYS_memcpy(&dst_buf[gif_ptr->cur_offset], gif_ptr->global_pal, size);
   1220     gif_ptr->cur_offset += size;
   1221   }
   1222   return TRUE;
   1223 }
   1224 void interlace_buf(const uint8_t* buf, FX_DWORD pitch, FX_DWORD height) {
   1225   CFX_ArrayTemplate<uint8_t*> pass[4];
   1226   int i, j;
   1227   FX_DWORD row;
   1228   row = 0;
   1229   uint8_t* temp;
   1230   while (row < height) {
   1231     if (row % 8 == 0) {
   1232       j = 0;
   1233     } else if (row % 4 == 0) {
   1234       j = 1;
   1235     } else if (row % 2 == 0) {
   1236       j = 2;
   1237     } else {
   1238       j = 3;
   1239     }
   1240     temp = FX_Alloc(uint8_t, pitch);
   1241     if (temp == NULL) {
   1242       return;
   1243     }
   1244     FXSYS_memcpy(temp, &buf[pitch * row], pitch);
   1245     pass[j].Add(temp);
   1246     row++;
   1247   }
   1248   for (i = 0, row = 0; i < 4; i++) {
   1249     for (j = 0; j < pass[i].GetSize(); j++, row++) {
   1250       FXSYS_memcpy((uint8_t*)&buf[pitch * row], pass[i].GetAt(j), pitch);
   1251       FX_Free(pass[i].GetAt(j));
   1252     }
   1253   }
   1254 }
   1255 static void _gif_write_block_data(const uint8_t* src_buf,
   1256                                   FX_DWORD src_len,
   1257                                   uint8_t*& dst_buf,
   1258                                   FX_DWORD& dst_len,
   1259                                   FX_DWORD& dst_offset) {
   1260   FX_DWORD src_offset = 0;
   1261   while (src_len > GIF_DATA_BLOCK) {
   1262     dst_buf[dst_offset++] = GIF_DATA_BLOCK;
   1263     FXSYS_memcpy(&dst_buf[dst_offset], &src_buf[src_offset], GIF_DATA_BLOCK);
   1264     dst_offset += GIF_DATA_BLOCK;
   1265     src_offset += GIF_DATA_BLOCK;
   1266     src_len -= GIF_DATA_BLOCK;
   1267   }
   1268   dst_buf[dst_offset++] = (uint8_t)src_len;
   1269   FXSYS_memcpy(&dst_buf[dst_offset], &src_buf[src_offset], src_len);
   1270   dst_offset += src_len;
   1271 }
   1272 static FX_BOOL _gif_write_data(gif_compress_struct_p gif_ptr,
   1273                                uint8_t*& dst_buf,
   1274                                FX_DWORD& dst_len) {
   1275   if (!_gif_grow_buf(dst_buf, dst_len, gif_ptr->cur_offset + GIF_DATA_BLOCK)) {
   1276     return FALSE;
   1277   }
   1278 #ifdef GIF_SUPPORT_GRAPHIC_CONTROL_EXTENSION
   1279   if (FXSYS_memcmp(gif_ptr->header_ptr->version, "89a", 3) == 0) {
   1280     dst_buf[gif_ptr->cur_offset++] = GIF_SIG_EXTENSION;
   1281     dst_buf[gif_ptr->cur_offset++] = GIF_BLOCK_GCE;
   1282     gif_ptr->gce_ptr->block_size = 4;
   1283     dst_buf[gif_ptr->cur_offset++] = gif_ptr->gce_ptr->block_size;
   1284     gif_ptr->gce_ptr->gce_flag = 0;
   1285     dst_buf[gif_ptr->cur_offset++] = gif_ptr->gce_ptr->gce_flag;
   1286     gif_ptr->gce_ptr->delay_time = 10;
   1287     _SetWord_LSBFirst(dst_buf + gif_ptr->cur_offset,
   1288                       gif_ptr->gce_ptr->delay_time);
   1289     gif_ptr->cur_offset += 2;
   1290     gif_ptr->gce_ptr->trans_index = 0;
   1291     dst_buf[gif_ptr->cur_offset++] = gif_ptr->gce_ptr->trans_index;
   1292     dst_buf[gif_ptr->cur_offset++] = 0;
   1293   }
   1294 #endif
   1295   dst_buf[gif_ptr->cur_offset++] = GIF_SIG_IMAGE;
   1296   _SetWord_LSBFirst(dst_buf + gif_ptr->cur_offset,
   1297                     gif_ptr->image_info_ptr->left);
   1298   gif_ptr->cur_offset += 2;
   1299   _SetWord_LSBFirst(dst_buf + gif_ptr->cur_offset,
   1300                     gif_ptr->image_info_ptr->top);
   1301   gif_ptr->cur_offset += 2;
   1302   _SetWord_LSBFirst(dst_buf + gif_ptr->cur_offset,
   1303                     gif_ptr->image_info_ptr->width);
   1304   gif_ptr->cur_offset += 2;
   1305   _SetWord_LSBFirst(dst_buf + gif_ptr->cur_offset,
   1306                     gif_ptr->image_info_ptr->height);
   1307   gif_ptr->cur_offset += 2;
   1308   GifLF& lf = (GifLF&)gif_ptr->image_info_ptr->local_flag;
   1309   dst_buf[gif_ptr->cur_offset++] = gif_ptr->image_info_ptr->local_flag;
   1310   if (gif_ptr->local_pal) {
   1311     FX_DWORD pal_size = sizeof(GifPalette) * gif_ptr->lpal_num;
   1312     if (!_gif_grow_buf(dst_buf, dst_len, pal_size + gif_ptr->cur_offset)) {
   1313       return FALSE;
   1314     }
   1315     FXSYS_memcpy(&dst_buf[gif_ptr->cur_offset], gif_ptr->local_pal, pal_size);
   1316     gif_ptr->cur_offset += pal_size;
   1317   }
   1318   if (lf.interlace) {
   1319     interlace_buf(gif_ptr->src_buf, gif_ptr->src_pitch,
   1320                   gif_ptr->image_info_ptr->height);
   1321   }
   1322   uint8_t code_bit = lf.pal_bits;
   1323   if (lf.local_pal == 0) {
   1324     GifGF& gf = (GifGF&)gif_ptr->lsd_ptr->global_flag;
   1325     code_bit = gf.pal_bits;
   1326   }
   1327   gif_ptr->img_encoder_ptr->Start(code_bit, gif_ptr->src_buf, dst_buf,
   1328                                   gif_ptr->cur_offset);
   1329   FX_DWORD i;
   1330   for (i = 0; i < gif_ptr->src_row; i++) {
   1331     if (!gif_ptr->img_encoder_ptr->Encode(
   1332             &gif_ptr->src_buf[i * gif_ptr->src_pitch],
   1333             gif_ptr->src_width * (code_bit + 1), dst_buf, dst_len,
   1334             gif_ptr->cur_offset)) {
   1335       return FALSE;
   1336     }
   1337   }
   1338   gif_ptr->img_encoder_ptr->Finish(dst_buf, dst_len, gif_ptr->cur_offset);
   1339   dst_buf[gif_ptr->cur_offset++] = 0;
   1340 #ifdef GIF_SUPPORT_COMMENT_EXTENSION
   1341   if (FXSYS_memcmp(gif_ptr->header_ptr->version, "89a", 3) == 0 &&
   1342       gif_ptr->cmt_data_ptr) {
   1343     dst_buf[gif_ptr->cur_offset++] = GIF_SIG_EXTENSION;
   1344     dst_buf[gif_ptr->cur_offset++] = GIF_BLOCK_CE;
   1345     _gif_write_block_data(gif_ptr->cmt_data_ptr, gif_ptr->cmt_data_len, dst_buf,
   1346                           dst_len, gif_ptr->cur_offset);
   1347     dst_buf[gif_ptr->cur_offset++] = 0;
   1348   }
   1349 #endif
   1350 #ifdef GIF_SUPPORT_PLAIN_TEXT_EXTENSION
   1351   if (FXSYS_memcmp(gif_ptr->header_ptr->version, "89a", 3) == 0 &&
   1352       gif_ptr->pte_data_ptr) {
   1353     dst_buf[gif_ptr->cur_offset++] = GIF_SIG_EXTENSION;
   1354     dst_buf[gif_ptr->cur_offset++] = GIF_BLOCK_PTE;
   1355     dst_buf[gif_ptr->cur_offset++] = gif_ptr->pte_ptr->block_size;
   1356     _SetWord_LSBFirst(dst_buf + gif_ptr->cur_offset,
   1357                       gif_ptr->pte_ptr->grid_left);
   1358     gif_ptr->cur_offset += 2;
   1359     _SetWord_LSBFirst(dst_buf + gif_ptr->cur_offset,
   1360                       gif_ptr->pte_ptr->grid_top);
   1361     gif_ptr->cur_offset += 2;
   1362     _SetWord_LSBFirst(dst_buf + gif_ptr->cur_offset,
   1363                       gif_ptr->pte_ptr->grid_width);
   1364     gif_ptr->cur_offset += 2;
   1365     _SetWord_LSBFirst(dst_buf + gif_ptr->cur_offset,
   1366                       gif_ptr->pte_ptr->grid_height);
   1367     gif_ptr->cur_offset += 2;
   1368     _SetWord_LSBFirst(dst_buf + gif_ptr->cur_offset,
   1369                       gif_ptr->pte_ptr->char_width);
   1370     gif_ptr->cur_offset += 2;
   1371     _SetWord_LSBFirst(dst_buf + gif_ptr->cur_offset,
   1372                       gif_ptr->pte_ptr->char_height);
   1373     gif_ptr->cur_offset += 2;
   1374     _SetWord_LSBFirst(dst_buf + gif_ptr->cur_offset,
   1375                       gif_ptr->pte_ptr->fc_index);
   1376     gif_ptr->cur_offset += 2;
   1377     _SetWord_LSBFirst(dst_buf + gif_ptr->cur_offset,
   1378                       gif_ptr->pte_ptr->bc_index);
   1379     gif_ptr->cur_offset += 2;
   1380     _gif_write_block_data(gif_ptr->pte_data_ptr, gif_ptr->pte_data_len, dst_buf,
   1381                           dst_len, gif_ptr->cur_offset);
   1382     gif_ptr->cur_offset += gif_ptr->pte_data_len;
   1383     dst_buf[gif_ptr->cur_offset++] = 0;
   1384   }
   1385 #endif
   1386 #ifdef GIF_SUPPORT_APPLICATION_EXTENSION
   1387   if (FXSYS_memcmp(gif_ptr->header_ptr->version, "89a", 3) == 0 &&
   1388       gif_ptr->app_data) {
   1389     dst_buf[gif_ptr->cur_offset++] = GIF_SIG_EXTENSION;
   1390     dst_buf[gif_ptr->cur_offset++] = GIF_BLOCK_AE;
   1391     dst_buf[gif_ptr->cur_offset++] = 11;
   1392     FXSYS_memcpy(&dst_buf[gif_ptr->cur_offset], gif_ptr->app_identify, 8);
   1393     gif_ptr->cur_offset += 8;
   1394     FXSYS_memcpy(&dst_buf[gif_ptr->cur_offset], gif_ptr->app_authentication, 8);
   1395     gif_ptr->cur_offset += 3;
   1396     FXSYS_memcpy(&dst_buf[gif_ptr->cur_offset], gif_ptr->app_data,
   1397                  gif_ptr->app_data_size);
   1398     gif_ptr->cur_offset += gif_ptr->app_data_size;
   1399     dst_buf[gif_ptr->cur_offset++] = 0;
   1400   }
   1401 #endif
   1402   dst_buf[gif_ptr->cur_offset++] = GIF_SIG_TRAILER;
   1403   return TRUE;
   1404 }
   1405 FX_BOOL _gif_encode(gif_compress_struct_p gif_ptr,
   1406                     uint8_t*& dst_buf,
   1407                     FX_DWORD& dst_len) {
   1408   if (!_gif_write_header(gif_ptr, dst_buf, dst_len)) {
   1409     return FALSE;
   1410   }
   1411   FX_DWORD cur_offset = gif_ptr->cur_offset;
   1412   FX_BOOL res = TRUE;
   1413   if (gif_ptr->frames) {
   1414     gif_ptr->cur_offset--;
   1415   }
   1416   if (!_gif_write_data(gif_ptr, dst_buf, dst_len)) {
   1417     gif_ptr->cur_offset = cur_offset;
   1418     res = FALSE;
   1419   }
   1420   dst_len = gif_ptr->cur_offset;
   1421   dst_buf[dst_len - 1] = GIF_SIG_TRAILER;
   1422   if (res) {
   1423     gif_ptr->frames++;
   1424   }
   1425   return res;
   1426 }
   1427