1 /******************************************************************************
2 
3 giffilter.c - skeleton file for generic GIF `filter' program
4 
5 Sequentially read GIF records from stdin, process them, send them out.
6 Most of the junk above `int main' isn't needed for the skeleton, but
7 is likely to be for what you'll do with it.
8 
9 If you compile this, it will turn into an expensive GIF copying routine;
10 stdin to stdout with no changes and minimal validation.  Well, it's a
11 decent test of the low-level routines, anyway.
12 
13 Note: due to the vicissitudes of Lempel-Ziv compression, the output of this
14 copier may not be bitwise identical to its input.  This can happen if you
15 copy an image from a much more (or much *less*) memory-limited system; your
16 compression may use more (or fewer) bits.  The uncompressed rasters should,
17 however, be identical (you can check this with gifbuild -d).
18 
19 SPDX-License-Identifier: MIT
20 
21 ******************************************************************************/
22 
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <fcntl.h>
27 
28 #include "gif_lib.h"
29 #include "getarg.h"
30 
31 #define PROGRAM_NAME	"giffilter"
32 
33 /******************************************************************************
34  Close both input and output file (if open), and exit.
35 ******************************************************************************/
QuitGifError(GifFileType * GifFileIn,GifFileType * GifFileOut)36 static void QuitGifError(GifFileType *GifFileIn, GifFileType *GifFileOut)
37 {
38     if (GifFileIn != NULL) {
39 	PrintGifError(GifFileIn->Error);
40 	EGifCloseFile(GifFileIn, NULL);
41     }
42     if (GifFileOut != NULL) {
43 	PrintGifError(GifFileOut->Error);
44 	EGifCloseFile(GifFileOut, NULL);
45     }
46     exit(EXIT_FAILURE);
47 }
48 
49 /******************************************************************************
50  Main sequence
51 ******************************************************************************/
main(int argc,char ** argv)52 int main(int argc, char **argv)
53 {
54     GifFileType *GifFileIn = NULL, *GifFileOut = NULL;
55     GifRecordType RecordType;
56     int CodeSize, ExtCode, ErrorCode;
57     GifByteType *CodeBlock, *Extension;
58 
59     /*
60      * Command-line processing goes here.
61      */
62 
63     /* Use stdin as input (note this also read screen descriptor in: */
64     if ((GifFileIn = DGifOpenFileHandle(0, &ErrorCode)) == NULL) {
65 	PrintGifError(ErrorCode);
66 	exit(EXIT_FAILURE);
67     }
68 
69     /* Use the stdout as output: */
70     if ((GifFileOut = EGifOpenFileHandle(1, &ErrorCode)) == NULL) {
71 	PrintGifError(ErrorCode);
72 	exit(EXIT_FAILURE);
73     }
74 
75     /* And dump out its screen information: */
76     if (EGifPutScreenDesc(GifFileOut,
77 	GifFileIn->SWidth, GifFileIn->SHeight,
78 	GifFileIn->SColorResolution, GifFileIn->SBackGroundColor,
79 	GifFileIn->SColorMap) == GIF_ERROR)
80 	QuitGifError(GifFileIn, GifFileOut);
81 
82     /* Scan the content of the input GIF file and load the image(s) in: */
83     do {
84 	if (DGifGetRecordType(GifFileIn, &RecordType) == GIF_ERROR)
85 	    QuitGifError(GifFileIn, GifFileOut);
86 
87 	switch (RecordType) {
88 	    case IMAGE_DESC_RECORD_TYPE:
89 		if (DGifGetImageDesc(GifFileIn) == GIF_ERROR)
90 		    QuitGifError(GifFileIn, GifFileOut);
91 		/* Put image descriptor to out file: */
92 		if (EGifPutImageDesc(GifFileOut,
93 		    GifFileIn->Image.Left, GifFileIn->Image.Top,
94 		    GifFileIn->Image.Width, GifFileIn->Image.Height,
95 		    GifFileIn->Image.Interlace,
96 		    GifFileIn->Image.ColorMap) == GIF_ERROR)
97 		    QuitGifError(GifFileIn, GifFileOut);
98 
99 		/* Now read image itself in decoded form as we dont really   */
100 		/* care what we have there, and this is much faster.	     */
101 		if (DGifGetCode(GifFileIn, &CodeSize, &CodeBlock) == GIF_ERROR ||
102 		    EGifPutCode(GifFileOut, CodeSize, CodeBlock) == GIF_ERROR)
103 		    QuitGifError(GifFileIn, GifFileOut);
104 		while (CodeBlock != NULL) {
105 		    if (DGifGetCodeNext(GifFileIn, &CodeBlock) == GIF_ERROR ||
106 			EGifPutCodeNext(GifFileOut, CodeBlock) == GIF_ERROR)
107 		    QuitGifError(GifFileIn, GifFileOut);
108 		}
109 		break;
110 	    case EXTENSION_RECORD_TYPE:
111 		/* pass through extension records */
112 		if (DGifGetExtension(GifFileIn, &ExtCode, &Extension) == GIF_ERROR || Extension == NULL)
113 		    QuitGifError(GifFileIn, GifFileOut);
114 		if (EGifPutExtensionLeader(GifFileOut, ExtCode) == GIF_ERROR)
115 		    QuitGifError(GifFileIn, GifFileOut);
116 		if (EGifPutExtensionBlock(GifFileOut,
117 					  Extension[0],
118 					  Extension + 1) == GIF_ERROR)
119 		    QuitGifError(GifFileIn, GifFileOut);
120 		while (Extension != NULL) {
121 		    if (DGifGetExtensionNext(GifFileIn, &Extension)==GIF_ERROR)
122 			QuitGifError(GifFileIn, GifFileOut);
123 		    if (Extension != NULL)
124 			if (EGifPutExtensionBlock(GifFileOut,
125 						  Extension[0],
126 						  Extension + 1) == GIF_ERROR)
127 			    QuitGifError(GifFileIn, GifFileOut);
128 		}
129 		if (EGifPutExtensionTrailer(GifFileOut) == GIF_ERROR)
130 		    QuitGifError(GifFileIn, GifFileOut);
131 		break;
132 	    case TERMINATE_RECORD_TYPE:
133 		break;
134 	    default:	     /* Should be trapped by DGifGetRecordType */
135 		break;
136 	}
137     }
138     while (RecordType != TERMINATE_RECORD_TYPE);
139 
140     if (DGifCloseFile(GifFileIn, &ErrorCode) == GIF_ERROR)
141     {
142 	PrintGifError(ErrorCode);
143 	exit(EXIT_FAILURE);
144     }
145     if (EGifCloseFile(GifFileOut, &ErrorCode) == GIF_ERROR)
146     {
147 	PrintGifError(ErrorCode);
148 	exit(EXIT_FAILURE);
149     }
150 
151     return 0;
152 }
153 
154 /* end */
155