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"
Input(uint8_t * src_buf,FX_DWORD src_size)8 void CGifLZWDecoder::Input(uint8_t* src_buf, FX_DWORD src_size) {
9   next_in = src_buf;
10   avail_in = src_size;
11 }
GetAvailInput()12 FX_DWORD CGifLZWDecoder::GetAvailInput() {
13   return avail_in;
14 }
InitTable(uint8_t code_len)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 }
ClearTable()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 }
DecodeString(FX_WORD code)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 }
AddCode(FX_WORD prefix_code,uint8_t append_char)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 }
Decode(uint8_t * des_buf,FX_DWORD & des_size)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 }
_gif_grow_buf(uint8_t * & dst_buf,FX_DWORD & dst_len,FX_DWORD size)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 }
_gif_cut_index(uint8_t & val,FX_DWORD index,uint8_t index_bit,uint8_t index_bit_use,uint8_t bit_use)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 }
_gif_cut_buf(const uint8_t * buf,FX_DWORD & offset,uint8_t bit_cut,uint8_t & bit_offset,FX_DWORD & bit_num)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 }
CGifLZWEncoder()196 CGifLZWEncoder::CGifLZWEncoder() {
197   FXSYS_memset(this, 0, sizeof(CGifLZWEncoder));
198 }
~CGifLZWEncoder()199 CGifLZWEncoder::~CGifLZWEncoder() {}
ClearTable()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 }
Start(uint8_t code_len,const uint8_t * src_buf,uint8_t * & dst_buf,FX_DWORD & offset)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 }
WriteBlock(uint8_t * & dst_buf,FX_DWORD & dst_len,FX_DWORD & offset)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 }
EncodeString(FX_DWORD index,uint8_t * & dst_buf,FX_DWORD & dst_len,FX_DWORD & offset)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 }
Encode(const uint8_t * src_buf,FX_DWORD src_len,uint8_t * & dst_buf,FX_DWORD & dst_len,FX_DWORD & offset)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 }
LookUpInTable(const uint8_t * buf,FX_DWORD & offset,uint8_t & bit_offset)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 }
Finish(uint8_t * & dst_buf,FX_DWORD & dst_len,FX_DWORD & offset)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 }
_gif_create_decompress()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 }
_gif_destroy_decompress(gif_decompress_struct_pp gif_ptr_ptr)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 }
_gif_create_compress()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 }
_gif_destroy_compress(gif_compress_struct_pp gif_ptr_ptr)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 }
_gif_error(gif_decompress_struct_p gif_ptr,const FX_CHAR * err_msg)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 }
_gif_warn(gif_decompress_struct_p gif_ptr,const FX_CHAR * err_msg)559 void _gif_warn(gif_decompress_struct_p gif_ptr, const FX_CHAR* err_msg) {}
_gif_read_header(gif_decompress_struct_p gif_ptr)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 }
_gif_get_frame(gif_decompress_struct_p gif_ptr)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 }
_gif_takeover_gce_ptr(gif_decompress_struct_p gif_ptr,GifGCE ** gce_ptr_ptr)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 }
_gif_decode_extension(gif_decompress_struct_p gif_ptr)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 }
_gif_decode_image_info(gif_decompress_struct_p gif_ptr)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 }
_gif_load_frame(gif_decompress_struct_p gif_ptr,int32_t frame_num)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 }
_gif_save_decoding_status(gif_decompress_struct_p gif_ptr,int32_t status)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 }
_gif_read_data(gif_decompress_struct_p gif_ptr,uint8_t ** des_buf_pp,FX_DWORD data_size)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 }
_gif_input_buffer(gif_decompress_struct_p gif_ptr,uint8_t * src_buf,FX_DWORD src_size)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 }
_gif_get_avail_input(gif_decompress_struct_p gif_ptr,uint8_t ** avial_buf_ptr)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 }
_gif_get_frame_num(gif_decompress_struct_p gif_ptr)1190 int32_t _gif_get_frame_num(gif_decompress_struct_p gif_ptr) {
1191   return gif_ptr->img_ptr_arr_ptr->GetSize();
1192 }
_gif_write_header(gif_compress_struct_p gif_ptr,uint8_t * & dst_buf,FX_DWORD & dst_len)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 }
interlace_buf(const uint8_t * buf,FX_DWORD pitch,FX_DWORD height)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 }
_gif_write_block_data(const uint8_t * src_buf,FX_DWORD src_len,uint8_t * & dst_buf,FX_DWORD & dst_len,FX_DWORD & dst_offset)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 }
_gif_write_data(gif_compress_struct_p gif_ptr,uint8_t * & dst_buf,FX_DWORD & dst_len)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 }
_gif_encode(gif_compress_struct_p gif_ptr,uint8_t * & dst_buf,FX_DWORD & dst_len)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