1 /*
2  * OpenBOR - http://www.chronocrash.com
3  * -----------------------------------------------------------------------
4  * All rights reserved, see LICENSE in OpenBOR root for details.
5  *
6  * Copyright (c) 2004 - 2014 OpenBOR Team
7  */
8 
9 // Animated GIF player.
10 
11 #include <stdio.h>
12 #include <string.h>
13 #include "packfile.h"
14 #include "borendian.h"
15 #include "types.h"
16 #include "screen.h"
17 #include "anigif.h"
18 
19 // Animated GIF player.
20 
21 
readbyte(int handle)22 static unsigned char readbyte(int handle)
23 {
24     unsigned char c = 0;
25     readpackfile(handle, &c, 1);
26     return c;
27 }
28 
passgifblock(anigif_info * info,int n)29 static void passgifblock(anigif_info *info, int n)
30 {
31     int len;
32 
33     // Skip all contained blocks
34     while((len = readbyte(info->info[n].handle)) != 0)
35     {
36         seekpackfile(info->info[n].handle, len, SEEK_CUR);
37     }
38 }
39 
handle_gfx_control(anigif_info * info,int n)40 static void handle_gfx_control(anigif_info *info, int n)
41 {
42     int len;
43     int skip;
44     unsigned char buf[4];
45 
46     // Handle all contained blocks
47     while((len = readbyte(info->info[n].handle)) != 0)
48     {
49         skip = len - 4;
50         if(len > 4)
51         {
52             len = 4;
53         }
54         readpackfile(info->info[n].handle, buf, len);
55         if(skip > 0)
56         {
57             seekpackfile(info->info[n].handle, skip, SEEK_CUR);
58         }
59 
60         if(buf[0] & 1)
61         {
62             info->info[n].transparent = buf[3];
63         }
64         info->info[n].lastdelay = (buf[2] << 8) | buf[1];
65 
66         // disposal = (buf[0]>>2) & 7;
67         // inputflag = (buf[0]>>1) & 1;
68     }
69 }
70 
gifextension(anigif_info * info,int n)71 static void gifextension(anigif_info *info, int n)
72 {
73     int function;
74 
75     // Get extension function code
76     function = readbyte(info->info[n].handle);
77 
78     // Note: function may be repeated multiple times (size, data, size, data)
79     switch(function)
80     {
81     case 0xF9:
82         // Graphic control
83         handle_gfx_control(info, n);
84         return;
85     default:
86         // 0x01 = text
87         // 0xFF = app. extension
88         // 0xFE = comment
89         passgifblock(info, n);
90         return;
91     }
92 }
93 
decodegifblock(anigif_info * info,gifblockstruct * gb,int n)94 static int decodegifblock(anigif_info *info, gifblockstruct *gb, int n)
95 {
96 
97     unsigned char bits;
98     short bits2;
99     short codesize;
100     short codesize2;
101     short nextcode;
102     short thiscode;
103     short oldtoken;
104     short currentcode;
105     short oldcode;
106     short bitsleft;
107     short blocksize;
108     int line = 0, lineb;
109     int byte = gb->left;
110     int pass = 0;
111     int transparent = info->info[n].transparent;
112     int handle = info->info[n].handle;
113     s_screen *buf = info->gifbuffer[n];
114     int width = buf->width;
115     int height = buf->height;
116     unsigned char *pal = info->info[n].local_pal ? info->info[n].local_pal : info->info[n].global_pal;
117 
118     unsigned char *p;
119     unsigned char *u;
120 
121     unsigned char *q;
122     unsigned char b[255];
123 
124     static unsigned char firstcodestack[4096];
125     static unsigned char lastcodestack[4096];
126     static short codestack[4096];
127 
128     static short wordmasktable[] = {0x0000, 0x0001, 0x0003, 0x0007,
129                                     0x000f, 0x001f, 0x003f, 0x007f,
130                                     0x00ff, 0x01ff, 0x03ff, 0x07ff,
131                                     0x0fff, 0x1fff, 0x3fff, 0x7fff
132                                    };
133 
134     static short inctable[] = { 8, 8, 4, 2, 0 };
135     static short startable[] = { 0, 4, 2, 1, 0 };
136 
137 
138     // get the initial LZW code bits
139     bits = readbyte(handle);
140     if(bits < 2 || bits > 8)
141     {
142         return 0;
143     }
144 
145     p = q = b;
146     bitsleft = 8;
147 
148     bits2 = 1 << bits;
149     nextcode = bits2 + 2;
150     codesize2 = 1 << (codesize = bits + 1);
151     oldcode = oldtoken = NO_CODE;
152 
153     lineb = gb->top * width;
154 
155     // loop until something breaks
156     for(;;)
157     {
158         if(bitsleft == 8)
159         {
160             if(++p >= q && (((blocksize = readbyte(handle)) < 1) ||
161                             (q = (p = b) + readpackfile(handle, b, blocksize)) < (b + blocksize)))
162             {
163                 return 1;	// Done
164             }
165             bitsleft = 0;
166         }
167         thiscode = *p;
168         if((currentcode = (codesize + bitsleft)) <= 8)
169         {
170             *p >>= codesize;
171             bitsleft = currentcode;
172         }
173         else
174         {
175             if(++p >= q && (((blocksize = readbyte(handle)) < 1) ||
176                             (q = (p = b) + readpackfile(handle, b, blocksize)) < (b + blocksize)))
177             {
178                 return 1;	// Done
179             }
180 
181             thiscode |= *p << (8 - bitsleft);
182             if(currentcode <= 16)
183             {
184                 *p >>= (bitsleft = currentcode - 8);
185             }
186             else
187             {
188                 if(++p >= q && (((blocksize = readbyte(handle)) < 1) ||
189                                 (q = (p = b) + readpackfile(handle, b, blocksize)) < (b + blocksize)))
190                 {
191                     return 1;	// Done
192                 }
193 
194                 thiscode |= *p << (16 - bitsleft);
195                 *p >>= (bitsleft = currentcode - 16);
196             }
197         }
198         thiscode &= wordmasktable[codesize];
199         currentcode = thiscode;
200 
201         if(thiscode == (bits2 + 1))
202         {
203             break;
204         }
205         if(thiscode > nextcode)
206         {
207             return 0;			// Bad code
208         }
209 
210         if(thiscode == bits2)
211         {
212             nextcode = bits2 + 2;
213             codesize2 = 1 << (codesize = (bits + 1));
214             oldtoken = oldcode = NO_CODE;
215             continue;
216         }
217 
218         u = firstcodestack;
219 
220         if(thiscode == nextcode)
221         {
222             if(oldcode == NO_CODE)
223             {
224                 return 0;		// Bad code
225             }
226             *u++ = oldtoken;
227             thiscode = oldcode;
228         }
229 
230         while(thiscode >= bits2)
231         {
232             *u++ = lastcodestack [thiscode];
233             thiscode = codestack[thiscode];
234         }
235 
236         oldtoken = thiscode;
237         do
238         {
239             if(byte < width && byte >= 0 && gb->top + line >= 0 && line < (height - gb->top) && thiscode != transparent)
240             {
241                 switch(buf->pixelformat)
242                 {
243                 case PIXEL_8:
244                     ((unsigned char *)buf->data)[lineb + byte] = thiscode;
245                     break;
246                 case PIXEL_16:
247                     ((unsigned short *)buf->data)[lineb + byte] = ((unsigned short *)pal)[thiscode & 0xff];
248                     break;
249                 case PIXEL_32:
250                     ((unsigned *)buf->data)[lineb + byte] = ((unsigned *)pal)[thiscode & 0xff];
251                     //printf("%08x, %02x, %ld\n", ((unsigned*)buf->data)[lineb + byte], thiscode&0xff, info->handle);
252                     break;
253                 }
254             }
255             byte++;
256             if(byte >= gb->left + gb->width)
257             {
258                 byte = gb->left;
259                 // check for interlaced image
260                 if(gb->flags & 0x40)
261                 {
262                     line += inctable[pass];
263                     if(line >= gb->height)
264                     {
265                         line = startable[++pass];
266                     }
267                 }
268                 else
269                 {
270                     ++line;
271                 }
272                 lineb = width * (gb->top + line);
273             }
274             if (u <= firstcodestack)
275             {
276                 break;
277             }
278             thiscode = *--u;
279         }
280         while(1);
281 
282         if(nextcode < 4096 && oldcode != NO_CODE)
283         {
284             codestack[nextcode] = oldcode;
285             lastcodestack[nextcode] = oldtoken;
286             if(++nextcode >= codesize2 && codesize < 12)
287             {
288                 codesize2 = 1 << ++codesize;
289             }
290         }
291         oldcode = currentcode;
292     }
293 
294     return 1;
295 }
296 
297 
anigif_close(anigif_info * info)298 void anigif_close(anigif_info *info)
299 {
300     int i;
301     for(i = 0; i < 3; i++)
302     {
303         if(info->info[i].handle >= 0)
304         {
305             closepackfile(info->info[i].handle);
306             info->info[i].handle = -1;
307         }
308         if(info->info[i].global_pal)
309         {
310             free(info->info[i].global_pal);
311             info->info[i].global_pal = NULL;
312         }
313         if(info->info[i].local_pal)
314         {
315             free(info->info[i].local_pal);
316             info->info[i].local_pal = NULL;
317         }
318         if(info->gifbuffer[i])
319         {
320             freescreen(&info->gifbuffer[i]);
321         }
322 
323     }
324     if(info->backbuffer)
325     {
326         freescreen(&info->backbuffer);
327     }
328 }
329 
test_anigif_open(anigif_info * info,char * tname,char * packfilename,int n)330 static int test_anigif_open(anigif_info *info, char *tname, char *packfilename, int n)
331 {
332     int i, j;
333     unsigned char tpal[1024];
334     unsigned char *pal;
335     if(
336         (info->info[n].handle = openpackfile(tname, packfilename)) == -1 ||
337         readpackfile(info->info[n].handle, &info->info[n].gif_header, sizeof_gifheaderstruct) != sizeof_gifheaderstruct ||
338         info->info[n].gif_header.magic[0] != 'G' || info->info[n].gif_header.magic[1] != 'I' || info->info[n].gif_header.magic[2] != 'F'
339     )
340     {
341         anigif_close(info);
342         return 0;
343     }
344 
345     info->info[n].gif_header.screenwidth = SwapLSB16(info->info[n].gif_header.screenwidth);
346     info->info[n].gif_header.screenheight = SwapLSB16(info->info[n].gif_header.screenheight);
347 
348     if(info->info[n].gif_header.flags & 0x80)
349     {
350         info->info[n].bitdepth = (info->info[n].gif_header.flags & 7) + 1;
351         info->info[n].numcolours = 1 << info->info[n].bitdepth ;
352     }
353     else
354     {
355         info->info[n].bitdepth = 8;
356         info->info[n].numcolours = 0;
357     }
358     info->info[n].lastdelay = 1;
359     info->info[n].code = ANIGIF_DECODE_RETRY;
360 
361     //info->current_res[0] = SwapLSB16(info->gif_header.screenwidth);
362     //info->current_res[1] = SwapLSB16(info->gif_header.screenheight);
363 
364     //printf("numcolours:%d\n", info->numcolours);
365 
366     // Get global palette, if present and if wanted
367     if(info->info[n].gif_header.flags & 0x80)
368     {
369         pal = info->info[n].global_pal = calloc(1, PAL_BYTES);
370 
371         if(readpackfile(info->info[n].handle, tpal, info->info[n].numcolours * 3) != info->info[n].numcolours * 3)
372         {
373             anigif_close(info);
374             return 0;
375         }
376         if(!info->isRGB)
377         {
378             tpal[0] = tpal[1] = tpal[2] = 0;
379         }
380         switch(PAL_BYTES)
381         {
382         case 768:
383             memcpy(pal, tpal, 768);
384             break;
385         case 1024:
386             for(i = 0, j = 0; i < 1024; i += 4, j += 3)
387             {
388                 *(unsigned *)(pal + i) = colour32(tpal[j], tpal[j + 1], tpal[j + 2]);
389             }
390             break;
391         case 512:
392             for(i = 0, j = 0; i < 512; i += 2, j += 3)
393             {
394                 *(unsigned short *)(pal + i) = colour16(tpal[j], tpal[j + 1], tpal[j + 2]);
395             }
396             break;
397         }
398     }
399     return 1;
400 
401 }
402 
403 
404 // Returns true on success
anigif_open(char * filename,char * packfilename,anigif_info * info)405 int anigif_open(char *filename, char *packfilename, anigif_info *info)
406 {
407     char tname[256] = {""};
408     int i;
409 
410     memset(info, 0, sizeof(anigif_info));
411     info->isRGB = (pixelformat == PIXEL_x8);
412     strcpy(tname, filename);
413     if(stricmp(tname + strlen(tname) - 4, ".gif") == 0)
414     {
415         tname[strlen(tname) - 4] = 0;
416     }
417 
418     strcat(tname, "_.gif");
419 
420     if(info->isRGB)
421     {
422         tname[strlen(tname) - 5] = 'r';
423         if(testpackfile(tname, packfilename) < 0)
424         {
425             info->isRGB = 0;
426         }
427         tname[strlen(tname) - 5] = 'g';
428         if(testpackfile(tname, packfilename) < 0)
429         {
430             info->isRGB = 0;
431         }
432         tname[strlen(tname) - 5] = 'b';
433         if(testpackfile(tname, packfilename) < 0)
434         {
435             info->isRGB = 0;
436         }
437     }
438 
439     for(i = 0; i < 3; i++)
440     {
441         info->info[i].handle = -1;
442         info->info[i].transparent = -1;
443     }
444 
445     if(info->isRGB)
446     {
447         tname[strlen(tname) - 5] = 'r';
448         if(!test_anigif_open(info, tname, packfilename, 0))
449         {
450             return 0;
451         }
452         tname[strlen(tname) - 5] = 'g';
453         if(!test_anigif_open(info, tname, packfilename, 1))
454         {
455             return 0;
456         }
457         tname[strlen(tname) - 5] = 'b';
458         if(!test_anigif_open(info, tname, packfilename, 2))
459         {
460             return 0;
461         }
462     }
463     else
464     {
465         if(!test_anigif_open(info, filename, packfilename, 0))
466         {
467             return 0;
468         }
469     }
470 
471     if(info->isRGB)
472     {
473         info->backbuffer = allocscreen(info->info[0].gif_header.screenwidth, info->info[0].gif_header.screenheight, screenformat);
474         clearscreen(info->backbuffer);
475     }
476     for(i = info->isRGB ? 2 : 0; i >= 0; i--)
477     {
478         info->gifbuffer[i] = allocscreen(info->info[0].gif_header.screenwidth, info->info[0].gif_header.screenheight, screenformat);
479         clearscreen(info->gifbuffer[i]);
480     }
481     info->frame = -1;
482     return 1;
483 }
484 
485 
486 // Returns type of action to take (frame, retry, end)
anigif_decode(anigif_info * info,int n)487 int anigif_decode(anigif_info *info, int n)
488 {
489 
490     gifblockstruct iblock;
491     unsigned char tpal[1024];
492     unsigned char *pal;
493     unsigned char c;
494     int i, j, numcolours;
495 
496     if(info->info[n].handle < 0 || info->gifbuffer[n] == NULL ||
497             readpackfile(info->info[n].handle, &c, 1) != 1)
498     {
499         goto decode_end;
500     }
501 
502     switch(c)
503     {
504     case ',':
505         // An image block
506         if(readpackfile(info->info[n].handle, &iblock, sizeof_iblock) != sizeof_iblock)
507         {
508             goto decode_end;
509         }
510 
511         if(iblock.flags & 0x80)
512         {
513             if(!info->info[n].local_pal)
514             {
515                 info->info[n].local_pal = calloc(1, PAL_BYTES);
516             }
517             pal = info->info[n].local_pal;
518             numcolours = 1 << ((iblock.flags & 7) + 1);
519             if(readpackfile(info->info[n].handle, tpal, numcolours * 3) != numcolours * 3)
520             {
521                 goto decode_end;
522             }
523             if(!info->isRGB)
524             {
525                 tpal[0] = tpal[1] = tpal[2] = 0;
526             }
527             switch(PAL_BYTES)
528             {
529             case 768:
530                 memcpy(pal, tpal, 768);
531                 break;
532             case 1024:
533                 for(i = 0, j = 0; i < 1024; i += 4, j += 3)
534                 {
535                     *(unsigned *)(pal + i) = colour32(tpal[j], tpal[j + 1], tpal[j + 2]);
536                 }
537                 break;
538             case 512:
539                 for(i = 0, j = 0; i < 512; i += 2, j += 3)
540                 {
541                     *(unsigned short *)(pal + i) = colour16(tpal[j], tpal[j + 1], tpal[j + 2]);
542                     //printf("%d*", *(unsigned short*)(pal+i));
543                 }
544                 break;
545             }
546         }
547         else if (info->info[n].local_pal)
548         {
549             free(info->info[n].local_pal);
550             info->info[n].local_pal = NULL;
551         }
552 
553         iblock.left = SwapLSB16(iblock.left);
554         iblock.top = SwapLSB16(iblock.top);
555         iblock.width = SwapLSB16(iblock.width);
556         iblock.height = SwapLSB16(iblock.height);
557 
558         decodegifblock(info, &iblock, n);
559 
560         // lastdelay = 0;
561 
562         return ANIGIF_DECODE_FRAME | ((iblock.flags & 0x80) ? ANIGIF_DECODE_PAL : 0);
563 
564     case '!':
565         // Handle GIF extension
566         gifextension(info, n);
567         // if(delay) *delay = lastdelay;
568         // lastdelay = 0;
569         return ANIGIF_DECODE_RETRY;
570 
571 //		case 0:
572     default:
573         // Isn't this an EOF?
574         return ANIGIF_DECODE_RETRY;
575 //			anigif_close();
576 //			return ANIGIF_DECODE_END;
577     }
578 
579 decode_end:
580     //anigif_close(info);
581     return ANIGIF_DECODE_END;
582 }
583 
anigif_updatebuffer(anigif_info * info)584 static void anigif_updatebuffer(anigif_info *info)
585 {
586     s_screen *backbuffer = info->backbuffer;
587     s_screen **gifbuffer = info->gifbuffer;
588     int i, l = backbuffer->width * backbuffer->height;
589     unsigned short *ps16, *ppr16, *ppg16, *ppb16;
590     unsigned int *ps32, *ppr32, *ppg32, *ppb32;
591     switch(screenformat)
592     {
593     case PIXEL_16:
594         ps16 = (unsigned short *)(backbuffer->data);
595         ppr16 = (unsigned short *)(gifbuffer[0]->data);
596         ppg16 = (unsigned short *)(gifbuffer[1]->data);
597         ppb16 = (unsigned short *)(gifbuffer[2]->data);
598         for(i = 0; i < l; i++)
599         {
600             ps16[i] =  ppr16[i] | ppg16[i] | ppb16[i];
601         }
602         break;
603     case PIXEL_32:
604         ps32 = (unsigned int *)(backbuffer->data);
605         ppr32 = (unsigned int *)(gifbuffer[0]->data);
606         ppg32 = (unsigned int *)(gifbuffer[1]->data);
607         ppb32 = (unsigned int *)(gifbuffer[2]->data);
608         for(i = 0; i < l; i++)
609         {
610             ps32[i] = ppr32[i] | ppg32[i] | ppb32[i];
611             //printf(" %u %u %u\n", ppr32[i], ppg32[i], ppb32[i]);
612         }
613         break;
614     }
615 
616 }
617 
anigif_decode_frame(anigif_info * info)618 int anigif_decode_frame(anigif_info *info)
619 {
620     int n, num = info->isRGB ? 3 : 1;
621     if(!info->done)
622     {
623         for(n = 0; n < num; n++)
624         {
625             if(info->info[n].code != ANIGIF_DECODE_END)
626             {
627                 while((info->info[n].code = anigif_decode(info, n)) == ANIGIF_DECODE_RETRY);
628                 info->info[n].nextframe += info->info[n].lastdelay * 10;
629             }
630             if(info->info[n].code == ANIGIF_DECODE_END)
631             {
632                 info->done = 1;
633                 break;
634             }
635         }
636         if(!info->done)
637         {
638             if(info->isRGB)
639             {
640                 anigif_updatebuffer(info);
641             }
642             info->frame++;
643         }
644     }
645     return info->done;
646 }
647 
648 
anigif_getbuffer(anigif_info * info)649 s_screen *anigif_getbuffer(anigif_info *info)
650 {
651     s_screen *buffer = info->isRGB ? info->backbuffer : info->gifbuffer[0];
652     if(buffer)
653     {
654         buffer->palette = info->isRGB ? NULL : (info->info[0].local_pal ? info->info[0].local_pal : info->info[0].global_pal);
655     }
656     return buffer;
657 }
658 
659 
660