xref: /aosp_15_r20/external/giflib/gifinto.c (revision 324bb76b8d05e2a05aa88511fff61cf3f9ca5892)
1 /*****************************************************************************
2 
3 gifinto - save GIF on stdin to file if size over set threshold
4 
5 SPDX-License-Identifier: MIT
6 
7 *****************************************************************************/
8 
9 #include <ctype.h>
10 #include <fcntl.h>
11 #include <stdbool.h>
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15 
16 #ifdef _WIN32
17 #include <io.h>
18 #else
19 #include <unistd.h>
20 #endif /* _WIN32 */
21 
22 #include "getarg.h"
23 #include "gif_lib.h"
24 
25 #define PROGRAM_NAME "gifinto"
26 
27 #define STRLEN 512
28 
29 #define DEFAULT_MIN_FILE_SIZE 14 /* More than GIF stamp + screen desc. */
30 #define DEFAULT_OUT_NAME "GifInto.Gif"
31 #define DEFAULT_TMP_NAME "TempInto.XXXXXX"
32 
33 static char *VersionStr = PROGRAM_NAME VERSION_COOKIE
34     "	Gershon Elber,	" __DATE__ ",   " __TIME__ "\n"
35     "(C) Copyright 1989 Gershon Elber.\n";
36 static char *CtrlStr = PROGRAM_NAME " v%- s%-MinFileSize!d h%- GifFile!*s";
37 
38 static int MinFileSize = DEFAULT_MIN_FILE_SIZE;
39 
40 #ifdef _WIN32
41 #include <errno.h>
42 #include <sys/stat.h>
mkstemp(char * tpl)43 int mkstemp(char *tpl) {
44 	int fd = -1;
45 	char *p;
46 	int e = errno;
47 
48 	errno = 0;
49 	p = _mktemp(tpl);
50 	if (*p && errno == 0) {
51 		errno = e;
52 		fd = _open(p, _O_RDWR | _O_CREAT | _O_EXCL | _O_BINARY,
53 		           _S_IREAD | _S_IWRITE);
54 	}
55 	return fd;
56 }
57 #endif
58 
59 /******************************************************************************
60  This is simply: read until EOF, then close the output, test its length, and
61  if non zero then rename it.
62 ******************************************************************************/
main(int argc,char ** argv)63 int main(int argc, char **argv) {
64 	int FD;
65 	int NumFiles;
66 	bool Error, MinSizeFlag = false, HelpFlag = false,
67 	            GifNoisyPrint = false;
68 	char **FileName = NULL, FoutTmpName[STRLEN + 1], FullPath[STRLEN + 1],
69 	     *p;
70 	FILE *Fin, *Fout;
71 
72 	if ((Error = GAGetArgs(argc, argv, CtrlStr, &GifNoisyPrint,
73 	                       &MinSizeFlag, &MinFileSize, &HelpFlag, &NumFiles,
74 	                       &FileName)) != false ||
75 	    (NumFiles > 1 && !HelpFlag)) {
76 		if (Error) {
77 			GAPrintErrMsg(Error);
78 		} else if (NumFiles != 1) {
79 			GIF_MESSAGE("Error in command line parsing - one GIF "
80 			            "file please.");
81 		}
82 		GAPrintHowTo(CtrlStr);
83 		exit(EXIT_FAILURE);
84 	}
85 
86 	if (HelpFlag) {
87 		(void)fprintf(stderr, VersionStr, GIFLIB_MAJOR, GIFLIB_MINOR);
88 		GAPrintHowTo(CtrlStr);
89 		exit(EXIT_SUCCESS);
90 	}
91 
92 	/* Open the stdin in binary mode and increase its buffer size: */
93 #ifdef _WIN32
94 	_setmode(0, O_BINARY); /* Make sure it is in binary mode. */
95 #endif
96 
97 	Fin = fdopen(0, "rb"); /* Make it into a stream: */
98 
99 	if (Fin == NULL) {
100 		GIF_EXIT("Failed to open input.");
101 	}
102 
103 	/* Isolate the directory where our destination is, and set tmp file name
104 	 */
105 	/* in the very same directory. This code is isecure because it creates
106 	 */
107 	/* predictable names, but it's not worth the effort and risk to fix. */
108 	if (*FileName == NULL) {
109 		GIF_EXIT("No valid Filename given.");
110 	}
111 	if (strlen(*FileName) > STRLEN - 1) {
112 		GIF_EXIT("Filename too long.");
113 	}
114 	memset(FullPath, '\0', sizeof(FullPath));
115 	strncpy(FullPath, *FileName, STRLEN);
116 	if ((p = strrchr(FullPath, '/')) != NULL ||
117 	    (p = strrchr(FullPath, '\\')) != NULL) {
118 		p[1] = 0;
119 	} else if ((p = strrchr(FullPath, ':')) != NULL) {
120 		p[1] = 0;
121 	} else {
122 		FullPath[0] = 0; /* No directory or disk specified. */
123 	}
124 	if (strlen(FullPath) > STRLEN - 1) {
125 		GIF_EXIT("Filename too long.");
126 	}
127 	strncpy(FoutTmpName, FullPath, STRLEN); /* First setup the Path */
128 	/* then add a name for the tempfile */
129 	if ((strlen(FoutTmpName) + strlen(DEFAULT_TMP_NAME)) > STRLEN - 1) {
130 		GIF_EXIT("Filename too long.");
131 	}
132 	strcat(FoutTmpName, DEFAULT_TMP_NAME);
133 #ifdef _WIN32
134 	char *tmpFN = _mktemp(FoutTmpName);
135 	if (tmpFN) {
136 		FD = open(tmpFN, O_CREAT | O_EXCL | O_WRONLY);
137 	} else {
138 		FD = -1;
139 	}
140 #else
141 	FD = mkstemp(FoutTmpName); /* returns filedescriptor */
142 #endif
143 	if (FD == -1) {
144 		GIF_EXIT("Failed to open output.");
145 	}
146 	Fout = fdopen(FD, "wb"); /* returns a stream with FD */
147 	if (Fout == NULL) {
148 		GIF_EXIT("Failed to open output.");
149 	}
150 
151 	while (1) {
152 		int c = getc(Fin);
153 
154 		if (feof(Fin)) {
155 			break;
156 		}
157 		if (putc(c, Fout) == EOF) {
158 			GIF_EXIT("Failed to write output.");
159 		}
160 	}
161 
162 	fclose(Fin);
163 	if (ftell(Fout) >= (long)MinFileSize) {
164 		fclose(Fout);
165 		unlink(*FileName);
166 		if (rename(FoutTmpName, *FileName) != 0) {
167 			char DefaultName[STRLEN + 1];
168 			memset(DefaultName, '\0', sizeof(DefaultName));
169 			if ((strlen(FullPath) + strlen(DEFAULT_OUT_NAME)) >
170 			    STRLEN - 1) {
171 				GIF_EXIT("Filename too long.");
172 			}
173 			strncpy(DefaultName, FullPath, STRLEN);
174 			strcat(DefaultName, DEFAULT_OUT_NAME);
175 			if (rename(FoutTmpName, DefaultName) == 0) {
176 				char s[STRLEN];
177 				snprintf(
178 				    s, STRLEN,
179 				    "Failed to rename out file - left as %s.",
180 				    DefaultName);
181 				GIF_MESSAGE(s);
182 			} else {
183 				unlink(FoutTmpName);
184 				GIF_MESSAGE(
185 				    "Failed to rename out file - deleted.");
186 			}
187 		}
188 	} else {
189 		fclose(Fout);
190 		unlink(FoutTmpName);
191 		GIF_MESSAGE("File too small - not renamed.");
192 	}
193 
194 	return 0;
195 }
196 
197 /* end */
198