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