1 /****************************************************************************
2 *
3 * makeswf - a command line actionscript compiler
4 *
5 * Copyright (C) 2003-2009 "Sandro Santilli" <strk@keybit.net>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 *
21 ****************************************************************************
22 *
23 * Utility functions for 'makeswf'
24 *
25 ***************************************************************************/
26
27 /* This is needed to get vasprintf definition */
28 #define _GNU_SOURCE 1
29
30 #include <stdio.h>
31 #include <string.h>
32 #include <stdarg.h>
33 #include <errno.h>
34 #include <unistd.h>
35 #include <stdlib.h>
36 #include <sys/types.h>
37 #include <sys/stat.h>
38 #include <limits.h>
39 #include <ming.h>
40 #include "makeswf.h"
41 #ifdef HAVE_GETOPT_H
42 #include <getopt.h>
43 #endif
44 #include "vasprintf.h"
45
46 // Cheating, but it works (not sure why the above ifdef for getopt isn't)
47 #ifdef _WIN32
48 #include <getopt.h>
49 #endif
50
51 #define DEFSWFVERSION 6
52 #define DEFSWFCOMPRESSION 9
53
54 //#define CPP "cpp -P -C -Wall"
55 /* we don't need comments, do we ? */
56 #define CPP "cpp -xc++ -P -Wall"
57 #define MAXERRORMSG 1024
58
59 /* prototypes */
60 static int makeswf_preprocess (const char *file, const char *out);
61 static char *makeswf_readfile (const char *file);
62 static void compileError(const char *fmt, ...);
63 static void printCompileMessage(SWFMsgFunc);
64
65 /* data */
66 static char lastcompilemessage[MAXERRORMSG];
67 static int lastcompilefailed = 0;
68 static int swfversion = DEFSWFVERSION;
69
70 #define MAXCPPARGS 1024
71
72 static char cppargs[MAXCPPARGS];
73 static int dopreprocess = 1; /* use preprocessor by default */
74
75 void
makeswf_append_cpparg(const char * buf)76 makeswf_append_cpparg(const char* buf)
77 {
78 strncat(cppargs, buf, MAXCPPARGS-1);
79 }
80
81 void
makeswf_set_dopreprocess(int value)82 makeswf_set_dopreprocess(int value)
83 {
84 dopreprocess=value;
85 }
86
87 void
makeswf_set_swfversion(int value)88 makeswf_set_swfversion(int value)
89 {
90 swfversion=value;
91 }
92
93 SWFAction
makeswf_compile_source(const char * filename,const char * ppfile,int debug)94 makeswf_compile_source(const char* filename, const char* ppfile, int debug)
95 {
96 SWFAction ac;
97 char *code;
98 char ppfile_fallback[PATH_MAX]; /* preprocessed file */
99 SWFMsgFunc old_error_func;
100 int length;
101 if ( dopreprocess )
102 {
103 if ( ! ppfile )
104 {
105 sprintf(ppfile_fallback, "%s.pp", filename);
106 ppfile = ppfile_fallback;
107 }
108
109 // TODO: make sure ppfile is writable
110
111
112 printf("Preprocessing %s... ", filename);
113 fflush(stdout);
114 if ( ! makeswf_preprocess(filename, ppfile) )
115 {
116 return NULL;
117 }
118 //unlink(ppfile);
119 filename = ppfile;
120 printf("done.\n");
121 }
122 if ( ! (code=makeswf_readfile(filename)) )
123 {
124 return NULL;
125 }
126
127 old_error_func = Ming_setErrorFunction(compileError);
128
129 printf("Compiling `%s'... ", filename);
130 ac = newSWFAction(code);
131 SWFAction_setDebug(ac, debug);
132 if (SWFAction_compile(ac, swfversion, &length) || lastcompilefailed)
133 {
134 printf("failed:\n");
135 printCompileMessage(old_error_func);
136 return NULL;
137 }
138 else
139 {
140 printf("successfully compiled %i bytes bytecode.\n", length);
141 }
142 free(code);
143
144 Ming_setErrorFunction(old_error_func);
145
146 return ac;
147 }
148
149 /*
150 * Should translate preprocessed file's line number to
151 * original file's line number (seems not so easy)
152 */
153 static void
printCompileMessage(SWFMsgFunc func)154 printCompileMessage(SWFMsgFunc func)
155 {
156 char *ptr1;
157
158 fprintf(stderr, " %s\n", strtok(lastcompilemessage, "\n"));
159 while ( (ptr1=strtok(NULL, "\n")) )
160 {
161 fprintf(stderr, " %s\n", ptr1);
162 }
163 func("\n");
164 }
165
166
167 /*
168 * This is here to handle line number reporting
169 * due to preprocessor scrambling of it
170 */
171 static void
compileError(const char * fmt,...)172 compileError(const char *fmt, ...)
173 {
174 char *msg;
175 va_list ap;
176 size_t msglen;
177
178 va_start (ap, fmt);
179
180 lastcompilefailed++;
181
182 /*
183 * This is a GNU extension.
184 * Dunno how to handle errors here.
185 */
186 if ( ! vasprintf(&msg, fmt, ap) )
187 {
188 fprintf(stderr, "vasnprintf allocated 0 bytes\n");
189 va_end(ap);
190 return;
191 }
192 va_end(ap);
193
194 msglen = strlen(msg);
195 if ( msglen > MAXERRORMSG-1 ) msglen = MAXERRORMSG-1;
196 memcpy(lastcompilemessage, msg, msglen);
197 free(msg);
198 lastcompilemessage[MAXERRORMSG-1] = '\0';
199
200 return;
201 }
202
203 static char *
makeswf_readfile(const char * file)204 makeswf_readfile (const char *file)
205 {
206 FILE *fd;
207 struct stat buf;
208 int size;
209 char *ret;
210
211 fd = fopen(file, "r");
212 if ( ! fd )
213 {
214 perror(file);
215 return NULL;
216 }
217 fstat(fileno(fd), &buf);
218 size = buf.st_size;
219 ret = (char *) malloc( size+1 );
220 if ( ! ret )
221 {
222 perror("readfile");
223 return NULL;
224 }
225 if(fread(ret, 1, size, fd) != size)
226 {
227 fprintf(stderr, "makeswf_readfile: failed\n");
228 fclose(fd);
229 free(ret);
230 return NULL;
231 }
232 ret[size] = '\0';
233 fclose(fd);
234
235 return ret;
236 }
237
238 static int
makeswf_preprocess(const char * file,const char * out)239 makeswf_preprocess (const char *file, const char *out)
240 {
241 char buf[1024];
242 int ret;
243 struct stat statbuf;
244
245 if ( -1 == stat(file, &statbuf) )
246 {
247 perror(file);
248 exit(EXIT_FAILURE);
249 }
250
251 sprintf(buf, "%s -D__SWF_VERSION__=%d %s %s > %s", CPP,
252 swfversion, cppargs, file, out);
253 /*printf("preprocess[%s]\n", buf);*/
254
255 ret = system(buf);
256 if ( ret )
257 {
258 exit(EXIT_FAILURE);
259 }
260
261 return 1;
262 }
263
264 /**************************************************************
265 *
266 * $Log$
267 * Revision 1.14 2010/04/28 12:09:58 strk
268 * Don't trust SWFAction_compile return code to be the only sign of failure.
269 *
270 * Revision 1.13 2009/09/08 22:26:17 strk
271 * Update copyright notice (and FSF address)
272 *
273 * Revision 1.12 2008/10/13 21:57:19 krechert
274 * fix warning
275 *
276 * Revision 1.11 2008/06/26 19:36:12 krechert
277 * fix linker error and make enabling SWFAction's debug mode generic
278 *
279 * Revision 1.10 2007/12/17 17:28:26 strk
280 * Check existance of input file before attempting to preprocess it
281 *
282 * Revision 1.9 2007/11/02 10:18:08 krechert
283 * fix warnings
284 *
285 * Revision 1.8 2007/10/31 16:53:29 krechert
286 * x
287 *
288 * Revision 1.7 2007/10/27 15:12:58 krechert
289 * pass through real swf version
290 *
291 * Revision 1.6 2007/10/27 15:03:14 krechert
292 * handle compile errors. do not output empty swf files
293 *
294 * Revision 1.5 2007/04/30 09:58:32 strk
295 * Don't include getopt.h if it's not found. Patch by Nils Goroll <nils.goroll@mcs.de>.
296 *
297 * Revision 1.4 2007/04/14 16:58:46 strk
298 * Removed unused CPP define from makeswf.c, fix the *used* one in makeswf_utils.
299 * Thanks to Bastiaan Jacques for finding this out.
300 *
301 * Revision 1.3 2007/03/22 10:59:20 strk
302 * Updated to use newSWFAction() instead of compileSWFActionCode()
303 *
304 * Revision 1.2 2006/07/10 16:11:26 strk
305 * Changed makeswf_compile_source signature to accept path to preprocessor output file. Changed preprocessed file paths to (<output>.frame#.pp) to reduce probability of filesystem permission problems.
306 *
307 * Revision 1.1 2006/07/08 13:47:18 strk
308 * Split makeswf general functionalities in a separate file, for use by unit testers
309 *
310 *
311 **************************************************************/
312