Imported Upstream version 5.1.9 into tizen
[platform/upstream/giflib.git] / gifbuild.c
1 /*****************************************************************************
2
3 gifbuild - dump GIF data in a textual format, or undump it to a GIF
4
5 *****************************************************************************/
6
7 #include <stdlib.h>
8 #include <stdlib.h>
9 #include <stdio.h>
10 #include <string.h>
11 #include <ctype.h>
12 #include <stdbool.h>
13
14 #include "gif_lib.h"
15 #include "getarg.h"
16
17 #define PROGRAM_NAME    "gifbuild"
18
19 __attribute__((__section__(".tizen.build-id")))
20 static char
21     VersionStr[] =
22         PROGRAM_NAME
23         VERSION_COOKIE
24         "       Eric Raymond,   "
25         __DATE__ ",   " __TIME__ "\n"
26         "(C) Copyright 1992 Eric Raymond.\n";
27 static char
28     *CtrlStr =
29         PROGRAM_NAME
30         " v%- d%- t%-Characters!s h%- GifFile(s)!*s";
31
32 static char KeyLetters[] = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!\"#$%&'()*+,-./:<=>?@[\\]^_`{|}~";
33 #define PRINTABLES      (sizeof(KeyLetters) - 1)
34
35 static void Icon2Gif(char *FileName, FILE *txtin, int fdout);
36 static void Gif2Icon(char *FileName,
37                      int fdin, int fdout,
38                      char NameTable[]);
39 static int EscapeString(char *cp, char *tp);
40
41 /******************************************************************************
42  Main sequence
43 ******************************************************************************/
44 int main(int argc, char **argv)
45 {
46     int NumFiles;
47     bool Error, DisasmFlag = false, HelpFlag = false, TextLineFlag = false;
48     char **FileNames = NULL;
49     char *TextLines[1];
50
51     if ((Error = GAGetArgs(argc, argv, CtrlStr,
52                 &GifNoisyPrint, &DisasmFlag, &TextLineFlag, &TextLines[0],
53                 &HelpFlag, &NumFiles, &FileNames)) != false) {
54         GAPrintErrMsg(Error);
55         GAPrintHowTo(CtrlStr);
56         exit(EXIT_FAILURE);
57     }
58
59     if (HelpFlag) {
60         (void)fprintf(stderr, VersionStr, GIFLIB_MAJOR, GIFLIB_MINOR);
61         GAPrintHowTo(CtrlStr);
62         exit(EXIT_SUCCESS);
63     }
64
65     if (!DisasmFlag && NumFiles > 1) {
66         GIF_MESSAGE("Error in command line parsing - one  text input please.");
67         GAPrintHowTo(CtrlStr);
68         exit(EXIT_FAILURE);
69     }
70
71     if (!DisasmFlag && TextLineFlag) {
72         GIF_MESSAGE("Error in command line parsing - -t invalid without -d.");
73         GAPrintHowTo(CtrlStr);
74         exit(EXIT_FAILURE);
75     }
76
77
78     if (NumFiles == 0)
79     {
80         if (DisasmFlag)
81             Gif2Icon("Stdin", 0, 1, TextLineFlag ? TextLines[0] : KeyLetters);
82         else
83             Icon2Gif("Stdin", stdin, 1);
84     }
85     else 
86     {
87         int i;
88         for (i = 0; i < NumFiles; i++)
89         {
90             FILE        *fp;
91
92             if ((fp = fopen(FileNames[i], "r")) == (FILE *)NULL)
93             {
94                 (void) fprintf(stderr, "Can't open %s\n", FileNames[i]);
95                 exit(EXIT_FAILURE);
96             }
97
98             if (DisasmFlag)
99             {
100                 printf("#\n# GIF information from %s\n", FileNames[i]);
101                 Gif2Icon(FileNames[i], -1, 1, TextLineFlag ? TextLines[0] : KeyLetters);
102             }
103             else
104             {
105                 Icon2Gif(FileNames[i], fp, 1);
106             }
107
108             (void) fclose(fp);
109         }
110     }
111
112     return 0;
113 }
114
115 /******************************************************************************
116  Parse image directives
117 ******************************************************************************/
118 #define PARSE_ERROR(str)  (void) fprintf(stderr,"%s:%d: %s\n",FileName,LineNum,str);
119
120 static void Icon2Gif(char *FileName, FILE *txtin, int fdout)
121 {
122     unsigned int        ColorMapSize = 0;
123     GifColorType GlobalColorMap[256], LocalColorMap[256],
124         *ColorMap = GlobalColorMap;
125     char GlobalColorKeys[PRINTABLES], LocalColorKeys[PRINTABLES],
126         *KeyTable = GlobalColorKeys;
127     bool SortFlag = false;
128     unsigned int ExtCode, intval;
129     int red, green, blue, n;
130     char buf[BUFSIZ * 2], InclusionFile[64];
131     GifFileType *GifFileOut;
132     SavedImage *NewImage = NULL;
133     int LeadingExtensionBlockCount = 0;
134     ExtensionBlock *LeadingExtensionBlocks = NULL;
135     int ErrorCode, LineNum = 0;
136
137     if ((GifFileOut = EGifOpenFileHandle(fdout, &ErrorCode)) == NULL) {
138         PrintGifError(ErrorCode);
139         exit(EXIT_FAILURE);
140     }
141
142     /* OK, interpret directives */
143     /* coverity[tainted_data_transitive] */
144     while (fgets(buf, sizeof(buf), txtin) != (char *)NULL)
145     {
146         char    *cp;
147
148         ++LineNum;
149
150         /*
151          * Skip lines consisting only of whitespace and comments
152          */
153         for (cp = buf; isspace((int)(*cp)); cp++)
154             continue;
155         if (*cp == '#' || *cp == '\0')
156             continue;
157
158         /*
159          * If there's a trailing comment, nuke it and all preceding whitespace.
160          * But preserve the EOL.
161          */
162         if ((cp = strchr(buf, '#')) && (cp == strrchr(cp, '#')))
163         {
164             while (isspace((int)(*--cp)))
165                 continue;
166             *++cp = '\n';
167             *++cp = '\0';
168         }
169
170         /*
171          * Explicit header declarations
172          */
173
174         if (sscanf(buf, "screen width %d\n", &GifFileOut->SWidth) == 1)
175             continue;
176
177         else if (sscanf(buf, "screen height %d\n", &GifFileOut->SHeight) == 1)
178             continue;
179
180         else if (sscanf(buf, "screen colors %d\n", &n) == 1)
181         {
182             int ResBits = GifBitSize(n);
183
184             if (n > 256 || n < 0 || n != (1 << ResBits))
185             {
186                 PARSE_ERROR("Invalid color resolution value.");
187                 exit(EXIT_FAILURE);
188             }
189
190             GifFileOut->SColorResolution = ResBits;
191             continue;
192         }
193
194         else if (sscanf(buf,
195                         "screen background %d\n",
196                         &GifFileOut->SBackGroundColor) == 1)
197             continue;
198
199         else if (sscanf(buf, "pixel aspect byte %u\n", &intval) == 1) {
200             GifFileOut->AspectByte = (GifByteType)(intval & 0xff);
201             continue;
202         }
203
204         /*
205          * Color table parsing
206          */
207
208         else if (strcmp(buf, "screen map\n") == 0)
209         {
210             if (GifFileOut->SColorMap != NULL)
211             {
212                 PARSE_ERROR("You've already declared a global color map.");
213                 exit(EXIT_FAILURE);
214             }
215
216             ColorMapSize = 0;
217             ColorMap = GlobalColorMap;
218             SortFlag = false;
219             KeyTable = GlobalColorKeys;
220             memset(GlobalColorKeys, '\0', sizeof(GlobalColorKeys));
221         }
222
223         else if (strcmp(buf, "image map\n") == 0)
224         {
225             if (NewImage == NULL)
226             {
227                 PARSE_ERROR("No previous image declaration.");
228                 exit(EXIT_FAILURE);
229             }
230
231             ColorMapSize = 0;
232             ColorMap = LocalColorMap;
233             KeyTable = LocalColorKeys;
234             memset(LocalColorKeys, '\0', sizeof(LocalColorKeys));
235         }
236
237         else if (sscanf(buf, "  rgb %d %d %d is %c",
238                    &red, &green, &blue, &KeyTable[ColorMapSize]) == 4)
239         {
240             ColorMap[ColorMapSize].Red = red;
241             ColorMap[ColorMapSize].Green = green;
242             ColorMap[ColorMapSize].Blue = blue;
243             ColorMapSize++;
244         }
245
246         else if (sscanf(buf, "  rgb %d %d %d", &red, &green, &blue) == 3)
247         {
248             ColorMap[ColorMapSize].Red = red;
249             ColorMap[ColorMapSize].Green = green;
250             ColorMap[ColorMapSize].Blue = blue;
251             ColorMapSize++;
252         }
253
254         else if (strcmp(buf, "  sort flag on\n") == 0)
255             SortFlag = true;
256
257         else if (strcmp(buf, "  sort flag off\n") == 0)
258             SortFlag = false;
259
260         else if (strcmp(buf, "end\n") == 0)
261         {
262             ColorMapObject      *NewMap;
263
264             NewMap = GifMakeMapObject(1 << GifBitSize(ColorMapSize), ColorMap);
265             if (NewMap == (ColorMapObject *)NULL)
266             {
267                 PARSE_ERROR("Out of memory while allocating new color map.");
268                 exit(EXIT_FAILURE);
269             }
270
271             NewMap->SortFlag = SortFlag;
272
273             if (NewImage)
274                 NewImage->ImageDesc.ColorMap = NewMap;
275             else
276                 GifFileOut->SColorMap = NewMap;
277         }
278
279         /* GIF inclusion */
280         /* ugly magic number is because scanf has no */
281         else if (sscanf(buf, "include %63s", InclusionFile) == 1)
282         {
283             int         ErrorCode;
284             bool        DoTranslation;
285             GifPixelType        Translation[256];
286
287             GifFileType *Inclusion;
288             SavedImage  *CopyFrom;
289
290             if ((Inclusion = DGifOpenFileName(InclusionFile, &ErrorCode)) == NULL) {
291                 PrintGifError(ErrorCode);
292                 exit(EXIT_FAILURE);
293             }
294
295             if (DGifSlurp(Inclusion) == GIF_ERROR)
296             {
297                 PARSE_ERROR("Inclusion read failed.");
298                 if (Inclusion != NULL) {
299                     PrintGifError(Inclusion->Error);
300                     DGifCloseFile(Inclusion, NULL);
301                 }
302                 if (GifFileOut != NULL) {
303                     EGifCloseFile(GifFileOut, NULL);
304                 };
305                 exit(EXIT_FAILURE);
306             }
307
308             //cppcheck-suppress nullPointerRedundantCheck
309             if ((DoTranslation = (GifFileOut->SColorMap!=(ColorMapObject*)NULL)))
310             {
311                 ColorMapObject  *UnionMap;
312
313                 //cppcheck-suppress nullPointerRedundantCheck
314                 UnionMap = GifUnionColorMap(GifFileOut->SColorMap, Inclusion->SColorMap, Translation);
315
316                 if (UnionMap == NULL)
317                 {
318                     PARSE_ERROR("Inclusion failed --- global map conflict.");
319                     //cppcheck-suppress nullPointerRedundantCheck
320                     PrintGifError(GifFileOut->Error);
321                     if (Inclusion != NULL) DGifCloseFile(Inclusion, NULL);
322                     if (GifFileOut != NULL) EGifCloseFile(GifFileOut, NULL);
323                     exit(EXIT_FAILURE);
324                 }
325
326                 GifFreeMapObject(GifFileOut->SColorMap);
327                 GifFileOut->SColorMap = UnionMap;
328             }
329
330             //cppcheck-suppress nullPointerRedundantCheck
331             for (CopyFrom = Inclusion->SavedImages;
332                  //cppcheck-suppress nullPointerRedundantCheck
333                  CopyFrom < Inclusion->SavedImages + Inclusion->ImageCount;
334                  CopyFrom++)
335             {
336                 SavedImage      *NewImage;
337                 if ((NewImage = GifMakeSavedImage(GifFileOut, CopyFrom)) == NULL)
338                 {
339                     PARSE_ERROR("Inclusion failed --- out of memory.");
340                     //cppcheck-suppress nullPointerRedundantCheck
341                     PrintGifError(GifFileOut->Error);
342                     if (Inclusion != NULL) DGifCloseFile(Inclusion, NULL);
343                     if (GifFileOut != NULL) EGifCloseFile(GifFileOut, NULL);
344                     exit(EXIT_FAILURE);
345                 }
346                 else if (DoTranslation)
347                     GifApplyTranslation(NewImage, Translation);
348
349                 GifQprintf(
350                         "%s: Image %d at (%d, %d) [%dx%d]: from %s\n",
351                         PROGRAM_NAME, GifFileOut->ImageCount,
352                         NewImage->ImageDesc.Left, NewImage->ImageDesc.Top,
353                         NewImage->ImageDesc.Width, NewImage->ImageDesc.Height,
354                         InclusionFile);
355             }
356
357             (void) DGifCloseFile(Inclusion, NULL);
358         }
359
360         /*
361          * Extension blocks.
362          */
363         else if (strcmp(buf, "comment\n") == 0)
364         {
365             int bc = 0;
366             while (fgets(buf, sizeof(buf), txtin) != (char *)NULL)
367                 if (strcmp(buf, "end\n") == 0)
368                     break;
369                 else
370                 {
371                     int Len;
372
373                     buf[strlen(buf) - 1] = '\0';
374                     Len = EscapeString(buf, buf);
375                     if (GifAddExtensionBlock(&LeadingExtensionBlockCount,
376                                              &LeadingExtensionBlocks,
377                                              bc++ == CONTINUE_EXT_FUNC_CODE ? COMMENT_EXT_FUNC_CODE : 0,
378                                              Len,
379                                              (unsigned char *)buf) == GIF_ERROR) {
380                         PARSE_ERROR("out of memory while adding comment block.");
381                         exit(EXIT_FAILURE);
382                     }
383                 }
384         }
385         else if (strcmp(buf, "plaintext\n") == 0)
386         {
387             int bc = 0;
388             while (fgets(buf, sizeof(buf), txtin) != (char *)NULL)
389                 if (strcmp(buf, "end\n") == 0)
390                     break;
391                 else
392                 {
393                     int Len;
394
395                     buf[strlen(buf) - 1] = '\0';
396                     Len = EscapeString(buf, buf);
397                     if (GifAddExtensionBlock(&LeadingExtensionBlockCount,
398                                              &LeadingExtensionBlocks,
399                                              bc++ == CONTINUE_EXT_FUNC_CODE ? PLAINTEXT_EXT_FUNC_CODE : 0,
400                                              Len, 
401                                              (unsigned char *)buf) == GIF_ERROR) {
402                         PARSE_ERROR("out of memory while adding plaintext block.");
403                         exit(EXIT_FAILURE);
404                     }
405                 }
406         }
407         else if (strcmp(buf, "graphics control\n") == 0)
408         {
409             GraphicsControlBlock gcb;
410             size_t Len;
411
412             memset(&gcb, '\0', sizeof(gcb));
413             gcb.TransparentColor = NO_TRANSPARENT_COLOR;
414             while (fgets(buf, sizeof(buf), txtin) != (char *)NULL)
415                 if (strcmp(buf, "end\n") == 0)
416                     break;
417                 else
418                 {
419                     char *tp = buf;
420
421                     while (isspace(*tp))
422                         tp++;
423                     if (sscanf(tp, "disposal mode %d\n", &gcb.DisposalMode))
424                         continue;
425                     if (strcmp(tp, "user input flag on\n") == 0) {
426                         gcb.UserInputFlag = true;
427                         continue;
428                     }
429                     if (strcmp(tp, "user input flag off\n") == 0) {
430                         gcb.UserInputFlag = false;
431                         continue;
432                     }
433                     if (sscanf(tp, "delay %d\n", &gcb.DelayTime))
434                         continue;
435                     if (sscanf(tp, "transparent index %d\n",
436                                &gcb.TransparentColor))
437                         continue;
438                     (void) fputs(tp, stderr);
439                     PARSE_ERROR("unrecognized directive in GCB block.");
440                     exit(EXIT_FAILURE);
441                 }
442             Len = EGifGCBToExtension(&gcb, (GifByteType *)buf);
443             if (GifAddExtensionBlock(&LeadingExtensionBlockCount,
444                                      &LeadingExtensionBlocks,
445                                      GRAPHICS_EXT_FUNC_CODE,
446                                      Len,
447                                      (unsigned char *)buf) == GIF_ERROR) {
448                 PARSE_ERROR("out of memory while adding GCB.");
449                 exit(EXIT_FAILURE);
450             }
451
452         }
453         else if (sscanf(buf, "netscape loop %u", &intval))
454         {
455             unsigned char params[3] = {1, 0, 0};
456             /* Create a Netscape 2.0 loop block */
457             if (GifAddExtensionBlock(&LeadingExtensionBlockCount,
458                                      &LeadingExtensionBlocks,
459                                      APPLICATION_EXT_FUNC_CODE,
460                                      11,
461                                      (unsigned char *)"NETSCAPE2.0")==GIF_ERROR) {
462                 PARSE_ERROR("out of memory while adding loop block.");
463                 exit(EXIT_FAILURE);
464             }
465             params[1] = (intval & 0xff);
466             params[2] = (intval >> 8) & 0xff;
467             if (GifAddExtensionBlock(&LeadingExtensionBlockCount,
468                                      &LeadingExtensionBlocks,
469                                      0, sizeof(params), params) == GIF_ERROR) {
470                 PARSE_ERROR("out of memory while adding loop continuation.");
471                 exit(EXIT_FAILURE);
472             }
473             
474         }
475         else if (sscanf(buf, "extension %x", &ExtCode))
476         {
477             int bc = 0;
478             while (fgets(buf, sizeof(buf), txtin) != (char *)NULL)
479                 if (strcmp(buf, "end\n") == 0)
480                     break;
481                 else
482                 {
483                     int Len;
484
485                     buf[strlen(buf) - 1] = '\0';
486                     Len = EscapeString(buf, buf);
487                     if (GifAddExtensionBlock(&LeadingExtensionBlockCount,
488                                              &LeadingExtensionBlocks,
489                                              bc++ == CONTINUE_EXT_FUNC_CODE ? ExtCode : 0, 
490                                              Len,
491                                              (unsigned char *)buf) == GIF_ERROR) {
492                         PARSE_ERROR("out of memory while adding extension block.");
493                         exit(EXIT_FAILURE);
494                     }
495                 }
496         }
497
498         /*
499          * Explicit image declarations 
500          */
501
502         else if (strcmp(buf, "image\n") == 0)
503         {
504             if ((NewImage = GifMakeSavedImage(GifFileOut, NULL)) == (SavedImage *)NULL)
505             {
506                 PARSE_ERROR("Out of memory while allocating image block.");
507                 exit(EXIT_FAILURE);
508             }
509
510             /* use global table unless user specifies a local one */
511             ColorMap = GlobalColorMap;
512             KeyTable = GlobalColorKeys;
513
514             /* connect leading extension blocks */
515             NewImage->ExtensionBlockCount = LeadingExtensionBlockCount;
516             NewImage->ExtensionBlocks = LeadingExtensionBlocks;
517             LeadingExtensionBlockCount = 0;
518             LeadingExtensionBlocks = NULL;
519         }
520
521         /*
522          * Nothing past this point is valid unless we've seen a previous
523          * image declaration.
524          */
525         else if (NewImage == (SavedImage *)NULL)
526         {
527             (void) fputs(buf, stderr);
528             PARSE_ERROR("Syntax error in header block.");
529             exit(EXIT_FAILURE);
530         }
531
532         /*
533          * Accept image attributes
534          */
535         else if (sscanf(buf, "image top %d\n", &NewImage->ImageDesc.Top) == 1)
536             continue;
537
538         else if (sscanf(buf, "image left %d\n", &NewImage->ImageDesc.Left)== 1)
539             continue;
540
541         else if (strcmp(buf, "image interlaced\n") == 0)
542         {
543             NewImage->ImageDesc.Interlace = true;
544             continue;
545         }
546
547         else if (sscanf(buf,
548                         "image bits %d by %d",
549                         &NewImage->ImageDesc.Width,
550                         &NewImage->ImageDesc.Height) == 2)
551         {
552             int i, j;
553             static GifPixelType *Raster, *cp;
554             int c;
555             bool hex = (strstr(buf, "hex") != NULL);
556
557             /* coverity[overflow_sink] */
558             if ((Raster = (GifPixelType *) malloc(sizeof(GifPixelType) * NewImage->ImageDesc.Width * NewImage->ImageDesc.Height))
559                 == NULL) {
560                 PARSE_ERROR("Failed to allocate raster block, aborted.");
561                 exit(EXIT_FAILURE);
562             }
563
564             GifQprintf("%s: Image %d at (%d, %d) [%dx%d]:     ",
565                        PROGRAM_NAME, GifFileOut->ImageCount,
566                        NewImage->ImageDesc.Left, NewImage->ImageDesc.Top,
567                        NewImage->ImageDesc.Width, NewImage->ImageDesc.Height);
568
569             cp = Raster;
570             for (i = 0; i < NewImage->ImageDesc.Height; i++) {
571
572                 char    *dp;
573
574                 for (j = 0; j < NewImage->ImageDesc.Width; j++)
575                     if ((c = fgetc(txtin)) == EOF) {
576                         PARSE_ERROR("input file ended prematurely.");
577                         exit(EXIT_FAILURE);
578                     }
579                     else if (c == '\n')
580                     {
581                         --j;
582                         ++LineNum;
583                     }
584                     else if (isspace(c))
585                         --j;
586                     else if (hex) 
587                     {
588                         const static char *hexdigits = "0123456789ABCDEF";
589                         unsigned char hi, lo;
590                         dp = strchr(hexdigits, toupper(c));
591                         if (dp == NULL) {
592                             PARSE_ERROR("Invalid hex high byte.");
593                             exit(EXIT_FAILURE);
594                         }
595                         hi = (dp - hexdigits);
596                         if ((c = fgetc(txtin)) == EOF) {
597                             PARSE_ERROR("input file ended prematurely.");
598                             exit(EXIT_FAILURE);
599                         }
600                         dp = strchr(hexdigits, toupper(c));
601                         if (dp == NULL) {
602                             PARSE_ERROR("Invalid hex low byte.");
603                             exit(EXIT_FAILURE);
604                         }
605                         lo = (dp - hexdigits);
606                         *cp++ = (hi << 4) | lo;
607                     }
608                     else if ((dp = strchr(KeyTable, c)))
609                         *cp++ = (dp - KeyTable);
610                     else {
611                         PARSE_ERROR("Invalid ASCII pixel key.");
612                         exit(EXIT_FAILURE);
613                     }
614
615                 if (GifNoisyPrint)
616                     fprintf(stderr, "\b\b\b\b%-4d", i);
617             }
618
619             if (GifNoisyPrint)
620                 putc('\n', stderr);
621
622             NewImage->RasterBits = (unsigned char *) Raster;
623         }
624         else
625         {
626             (void) fputs(buf, stderr);
627             PARSE_ERROR("Syntax error in image description.");
628             exit(EXIT_FAILURE);
629         }
630     }
631
632     /* connect trailing extension blocks */
633     GifFileOut->ExtensionBlockCount = LeadingExtensionBlockCount;
634     GifFileOut->ExtensionBlocks = LeadingExtensionBlocks;
635     //LeadingExtensionBlockCount = 0;
636     LeadingExtensionBlocks = NULL;
637  
638     EGifSpew(GifFileOut);
639 }
640
641 static void VisibleDumpBuffer(GifByteType *buf, int len)
642 /* Visibilize a given string */
643 {
644     GifByteType *cp;
645
646     for (cp = buf; cp < buf + len; cp++)
647     {
648         if (isprint((int)(*cp)) || *cp == ' ')
649             putchar(*cp);
650         else if (*cp == '\n')
651         {
652             putchar('\\'); putchar('n');
653         }
654         else if (*cp == '\r')
655         {
656             putchar('\\'); putchar('r');
657         }
658         else if (*cp == '\b')
659         {
660             putchar('\\'); putchar('b');
661         }
662         else if (*cp < ' ')
663         {
664             putchar('\\'); putchar('^'); putchar('@' + *cp);
665         }
666         else
667             printf("\\0x%02x", *cp);
668     }
669 }
670
671 static void DumpExtensions(GifFileType *GifFileOut, 
672                            int ExtensionBlockCount,
673                            ExtensionBlock *ExtensionBlocks)
674 {
675     ExtensionBlock *ep;
676
677     for (ep = ExtensionBlocks; 
678          ep < ExtensionBlocks + ExtensionBlockCount;
679          ep++) {
680         bool last = (ep - ExtensionBlocks == (ExtensionBlockCount - 1));
681         if (ep->Function == COMMENT_EXT_FUNC_CODE) {
682             printf("comment\n");
683             VisibleDumpBuffer(ep->Bytes, ep->ByteCount);
684             putchar('\n');
685             while (!last && ep[1].Function == CONTINUE_EXT_FUNC_CODE) {
686                 ++ep;
687                 last = (ep - ExtensionBlocks == (ExtensionBlockCount - 1));
688                 VisibleDumpBuffer(ep->Bytes, ep->ByteCount);
689                 putchar('\n');
690             }
691             printf("end\n\n");
692         }
693         else if (ep->Function == PLAINTEXT_EXT_FUNC_CODE) {
694             printf("plaintext\n");
695             VisibleDumpBuffer(ep->Bytes, ep->ByteCount);
696             putchar('\n');
697             while (!last && ep[1].Function == CONTINUE_EXT_FUNC_CODE) {
698                 ++ep;
699                 last = (ep - ExtensionBlocks == (ExtensionBlockCount - 1));
700                 VisibleDumpBuffer(ep->Bytes, ep->ByteCount);
701                 putchar('\n');
702             }
703             printf("end\n\n");
704         }
705         else if (ep->Function == GRAPHICS_EXT_FUNC_CODE)
706         {
707             GraphicsControlBlock gcb;
708             printf("graphics control\n");
709             if (DGifExtensionToGCB(ep->ByteCount, ep->Bytes, &gcb) == GIF_ERROR) {
710                 GIF_MESSAGE("invalid graphics control block");
711                 exit(EXIT_FAILURE);
712             }
713             printf("\tdisposal mode %d\n", gcb.DisposalMode);
714             printf("\tuser input flag %s\n", 
715                    gcb.UserInputFlag ? "on" : "off");
716             printf("\tdelay %d\n", gcb.DelayTime);
717             printf("\ttransparent index %d\n", gcb.TransparentColor);
718             printf("end\n\n");
719         }
720         else if (!last
721                  && ep->Function == APPLICATION_EXT_FUNC_CODE
722                  && ep->ByteCount >= 11
723                  && (ep+1)->ByteCount >= 3
724                  && memcmp(ep->Bytes, "NETSCAPE2.0", 11) == 0) {
725             unsigned char *params = (++ep)->Bytes;
726             unsigned int loopcount = params[1] | (params[2] << 8);
727             printf("netscape loop %u\n\n", loopcount);
728         }
729         else {
730             printf("extension 0x%02x\n", ep->Function);
731             VisibleDumpBuffer(ep->Bytes, ep->ByteCount);
732             while (!last && ep[1].Function == CONTINUE_EXT_FUNC_CODE) {
733                 ++ep;
734                 last = (ep - ExtensionBlocks == (ExtensionBlockCount - 1));
735                 VisibleDumpBuffer(ep->Bytes, ep->ByteCount);
736                 putchar('\n');
737             }
738             printf("end\n\n");
739         }
740     }
741 }
742
743 static void Gif2Icon(char *FileName,
744                      int fdin, int fdout,
745                      char NameTable[])
746 {
747     int ErrorCode, im, i, j, ColorCount = 0;
748     GifFileType *GifFile;
749
750     if (fdin == -1) {
751         if ((GifFile = DGifOpenFileName(FileName, &ErrorCode)) == NULL) {
752             PrintGifError(ErrorCode);
753             exit(EXIT_FAILURE);
754         }
755     }
756     else {
757         /* Use stdin instead: */
758         if ((GifFile = DGifOpenFileHandle(fdin, &ErrorCode)) == NULL) {
759             PrintGifError(ErrorCode);
760             exit(EXIT_FAILURE);
761         }
762     }
763
764     if (DGifSlurp(GifFile) == GIF_ERROR) {
765         PrintGifError(GifFile->Error);
766         exit(EXIT_FAILURE);
767     }
768
769     printf("screen width %d\nscreen height %d\n",
770            GifFile->SWidth, GifFile->SHeight);
771
772     printf("screen colors %d\nscreen background %d\npixel aspect byte %u\n\n",
773            1 << GifFile->SColorResolution,
774            GifFile->SBackGroundColor,
775            (unsigned)GifFile->AspectByte);
776
777     if (GifFile->SColorMap)
778     {
779         printf("screen map\n");
780
781         printf("\tsort flag %s\n", GifFile->SColorMap->SortFlag ? "on" : "off");
782
783         for (i = 0; i < GifFile->SColorMap->ColorCount; i++)
784             if (GifFile->SColorMap->ColorCount < PRINTABLES)
785                 printf("\trgb %03d %03d %03d is %c\n",
786                        GifFile->SColorMap ->Colors[i].Red,
787                        GifFile->SColorMap ->Colors[i].Green,
788                        GifFile->SColorMap ->Colors[i].Blue,
789                        NameTable[i]);
790             else
791                 printf("\trgb %03d %03d %03d\n",
792                        GifFile->SColorMap ->Colors[i].Red,
793                        GifFile->SColorMap ->Colors[i].Green,
794                        GifFile->SColorMap ->Colors[i].Blue);
795         printf("end\n\n");
796     }
797
798     for (im = 0; im < GifFile->ImageCount; im++) {
799         SavedImage *image = &GifFile->SavedImages[im];
800
801         DumpExtensions(GifFile, 
802                        image->ExtensionBlockCount, image->ExtensionBlocks);
803
804         printf("image # %d\nimage left %d\nimage top %d\n",
805                im+1, image->ImageDesc.Left, image->ImageDesc.Top);
806         if (image->ImageDesc.Interlace)
807             printf("image interlaced\n");
808
809         if (image->ImageDesc.ColorMap)
810         {
811             printf("image map\n");
812
813             printf("\tsort flag %s\n", 
814                    image->ImageDesc.ColorMap->SortFlag ? "on" : "off");
815
816             if (image->ImageDesc.ColorMap->ColorCount < PRINTABLES)
817                 for (i = 0; i < image->ImageDesc.ColorMap->ColorCount; i++)
818                     printf("\trgb %03d %03d %03d is %c\n",
819                            image->ImageDesc.ColorMap ->Colors[i].Red,
820                            image->ImageDesc.ColorMap ->Colors[i].Green,
821                            image->ImageDesc.ColorMap ->Colors[i].Blue,
822                            NameTable[i]);
823             else
824                 for (i = 0; i < image->ImageDesc.ColorMap->ColorCount; i++)
825                     printf("\trgb %03d %03d %03d\n",
826                            image->ImageDesc.ColorMap ->Colors[i].Red,
827                            image->ImageDesc.ColorMap ->Colors[i].Green,
828                            image->ImageDesc.ColorMap ->Colors[i].Blue);
829             printf("end\n\n");
830         }
831
832         /* one of these conditions has to be true */
833         if (image->ImageDesc.ColorMap)
834             ColorCount = image->ImageDesc.ColorMap->ColorCount;
835         else if (GifFile->SColorMap)
836             ColorCount = GifFile->SColorMap->ColorCount;
837
838         if (ColorCount < PRINTABLES)
839             printf("image bits %d by %d\n",
840                    image->ImageDesc.Width, image->ImageDesc.Height);
841         else
842             printf("image bits %d by %d hex\n",
843                    image->ImageDesc.Width, image->ImageDesc.Height);
844         for (i = 0; i < image->ImageDesc.Height; i++) {
845             for (j = 0; j < image->ImageDesc.Width; j++) {
846                 GifByteType ch = image->RasterBits[i*image->ImageDesc.Width + j];
847                 if (ColorCount < PRINTABLES && ch < PRINTABLES)
848                     putchar(NameTable[ch]);
849                 else
850                     printf("%02x", ch);
851             }
852             putchar('\n');
853         }
854         putchar('\n');
855     }
856
857     DumpExtensions(GifFile, 
858                    GifFile->ExtensionBlockCount, GifFile->ExtensionBlocks);
859
860     /* Tell EMACS this is a picture... */
861     printf("# The following sets edit modes for GNU EMACS\n");
862     printf("# Local ");         /* ...break this up, so that EMACS doesn't */
863     printf("Variables:\n");     /* get confused when visiting *this* file! */
864     printf("# mode:picture\n");
865     printf("# truncate-lines:t\n");
866     printf("# End:\n");
867
868     if (fdin == -1)
869         (void) printf("# End of %s dump\n", FileName);
870
871
872     /*
873      * Sanity checks.
874      */
875
876     /* check that the background color isn't garbage (SF bug #87) */
877     if (GifFile->SBackGroundColor < 0
878             || GifFile->SBackGroundColor >= GifFile->SColorMap->ColorCount) {
879         fprintf(stderr, "gifbuild: background color invalid for screen colormap.\n");
880     }
881
882     if (DGifCloseFile(GifFile, &ErrorCode) == GIF_ERROR) {
883         PrintGifError(ErrorCode);
884         exit(EXIT_FAILURE);
885     }
886 }
887
888 static int EscapeString(char *cp, char *tp)
889 /* process standard C-style escape sequences in a string */
890 {
891     char *StartAddr = tp;
892
893     while (*cp)
894     {
895         int     cval = 0;
896
897         if (*cp == '\\' && strchr("0123456789xX", cp[1]))
898         {
899             int dcount = 0;
900
901             if (*++cp == 'x' || *cp == 'X') {
902                 char *dp, *hex = "00112233445566778899aAbBcCdDeEfF";
903                 for (++cp; (dp = strchr(hex, *cp)) && (dcount++ < 2); cp++)
904                     cval = (cval * 16) + (dp - hex) / 2;
905             } else if (*cp == '0')
906                 while (strchr("01234567",*cp) != (char*)NULL && (dcount++ < 3))
907                     cval = (cval * 8) + (*cp++ - '0');
908             else
909                 while ((strchr("0123456789",*cp)!=(char*)NULL)&&(dcount++ < 3))
910                     cval = (cval * 10) + (*cp++ - '0');
911         }
912         else if (*cp == '\\')           /* C-style character escapes */
913         {
914             switch (*++cp)
915             {
916             case '\\': cval = '\\'; break;
917             case 'n': cval = '\n'; break;
918             case 't': cval = '\t'; break;
919             case 'b': cval = '\b'; break;
920             case 'r': cval = '\r'; break;
921             default: cval = *cp;
922             }
923             cp++;
924         }
925         else if (*cp == '^')            /* expand control-character syntax */
926         {
927             cval = (*++cp & 0x1f);
928             cp++;
929         }
930         else
931             cval = *cp++;
932         *tp++ = cval;
933     }
934
935     return(tp - StartAddr);
936 }
937
938 /* end */
939