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