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