1 /****************************************************************************
2  *
3  *  Copyright (C) 2005-2006 "Stuart R. Anderson" <anderson@netsweng.com>
4  *
5  *  This program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2 of the License, or
8  *  (at your option) any later version.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with this program; if not, write to the Free Software
17  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  *
19  ****************************************************************************/
20 
21 #include <stdlib.h>
22 #include <stdio.h>
23 #include <stdarg.h>
24 #include <math.h>
25 #include <string.h>
26 #include <limits.h>
27 #include <errno.h>
28 
29 //open()
30 #include <fcntl.h>
31 
32 //fstat()
33 #include <sys/types.h>
34 #include <sys/stat.h>
35 #include <unistd.h>
36 
37 #include "ming_config.h"
38 
39 //decompression
40 #ifdef USE_ZLIB
41 #include <zlib.h>
42 #endif
43 
44 #include "blocks/blocktypes.h"
45 #include "action.h"
46 #include "parser.h"
47 #include "read.h"
48 #include "swfoutput.h"
49 
50 SWF_Parserstruct *blockParse (FILE *f, int length, SWFBlocktype header);
51 const char *blockName (SWFBlocktype header);
52 
53 char *filename;
54 char tmp_name[PATH_MAX];
55 FILE *tempfile;
56 char *swftargetfile=NULL;
57 struct Movie m;
58 int verbose = 0;
59 
60 #if USE_ZLIB
61 /*
62  * Compressed swf-files have a 8 Byte uncompressed header and a
63  * zlib-compressed body.
64  */
65 int
cws2fws(FILE * f,uLong outsize)66 cws2fws(FILE *f, uLong outsize)
67 {
68 
69 	struct stat statbuffer;
70 	int insize, ret;
71 	int err,tmp_fd;
72 	Byte *inbuffer,*outbuffer;
73 
74 	sprintf(tmp_name, "/tmp/swftoscriptXXXXXX");
75 
76 #ifdef HAVE_MKSTEMP
77 	tmp_fd = mkstemp(tmp_name);
78 #endif
79 #ifndef HAVE_MKSTEMP
80 	tmp_fd = open(tmp_name, O_RDWR | O_CREAT | O_TRUNC , 0600);
81 #endif
82 
83 	if ( tmp_fd == -1 )
84 	{
85 		SWF_error("Couldn't create tempfile.\n");
86 	}
87 
88 	tempfile = fdopen(tmp_fd, "w+");
89 	if ( ! tempfile )
90 	{
91 		SWF_error("fdopen: %s", strerror(errno));
92 	}
93 
94 
95 	if( stat(filename, &statbuffer) == -1 )
96 	{
97 		SWF_error("stat() failed on input file");
98 	}
99 
100 	insize = statbuffer.st_size-8;
101 	inbuffer = malloc(insize);
102 	if(!inbuffer){ SWF_error("malloc() failed"); }
103 	if ( ! fread(inbuffer, insize, 1, f) )
104 	{
105 		SWF_error("Error reading input file");
106 	}
107 
108 	/* We don't trust the value in the swfheader. */
109 	outbuffer=NULL;
110 	do{
111 		outbuffer = realloc(outbuffer, outsize);
112 		if (!outbuffer) { SWF_error("malloc(%lu) failed",outsize); }
113 
114 		/* uncompress the data */
115 		err=uncompress(outbuffer,&outsize,inbuffer,insize);
116 		switch(err){
117 			case Z_MEM_ERROR:
118 				SWF_error("Not enough memory.\n");
119 				break;
120 			case Z_BUF_ERROR:
121 				SWF_warn("resizing outbuffer..\n");
122 				outsize*=2;
123 				continue;
124 			case Z_DATA_ERROR:
125 				SWF_error("Data corrupted. Couldn't uncompress.\n");
126 				break;
127 			case Z_OK:
128 				break;
129 			default:
130 				SWF_error("Unknown returnvalue of uncompress:%i\n",
131 					err);
132 				break;
133 		}
134 	} while(err == Z_BUF_ERROR);
135 
136 	/* Rebuild the header so the file offsets will be right */
137 	fputc('F',tempfile);
138 	fputc('W',tempfile);
139 	fputc('S',tempfile);
140 	fputc(m.version,tempfile);
141 	ret = fwrite(&m.size,sizeof(int),1,tempfile);
142 	if(ret != 1)
143 		SWF_error("cws2fws: failed writing file size\n");
144 
145 	if ( outsize != fwrite(outbuffer, 1, outsize, tempfile) )
146 	{
147 		SWF_error("Error writing uncompressed");
148 	}
149 
150 	rewind(tempfile);
151 	return (int)outsize;
152 }
153 #endif
154 
usage(char * prog)155 static void usage(char *prog)
156 {
157 #ifdef MAKE_FDB
158 	fprintf(stderr,"%s: [-v] inputfile\n", prog);
159 	fprintf(stderr,"<inputfile> should be a swf files containing font blocks (DEFINEFONT2).\n");
160 	fprintf(stderr,"For every fontblock found a .fdb file is wirtten with the associated font name.\n\n");
161 #else
162 	fprintf(stderr,"%s: [-v] inputfile [swftargetfile]\n", prog);
163 #endif
164 }
165 
filelen_check_fails(int minLength)166 static int filelen_check_fails(int minLength)
167 {
168 	if(m.size - fileOffset < minLength)
169 	{
170 		SWF_warn("sudden file end: read failed @%i fileSize %i, request %i\n",
171 				fileOffset, m.size, minLength);
172 		return -1;
173 	}
174 	return 0;
175 }
176 
readMovieHeader(FILE * f,int * compressed)177 static int readMovieHeader(FILE *f, int *compressed)
178 {
179 	char first;
180 	struct stat stat_buf;
181 
182 	first = readUInt8 (f);
183 	*compressed = (first == ('C')) ? 1 : 0;
184 	if (!((first == 'C' || first == 'F') && readUInt8 (f) == 'W'
185 		&& readUInt8 (f) == 'S'))
186 	{
187 		SWF_error ("Doesn't look like a swf file to me..\n");
188 	}
189 
190 	m.version = readUInt8 (f);
191 	m.size = readUInt32 (f);
192 	m.soundStreamFmt = -1;
193 	m.fonts = NULL;
194 	m.numFonts = 0;
195 	if (*compressed)
196 	{
197 #if USE_ZLIB
198 		int unzipped = cws2fws (f, m.size);
199 		if (m.size != (unzipped + 8))
200 		{
201 			SWF_warn ("m.size: %i != %i+8  Maybe wrong value in swfheader.\n", m.size, unzipped + 8);
202 			m.size = unzipped +8;
203 		}
204 		fclose (f);
205 		f = tempfile;
206 		fseek(f,8,SEEK_SET);
207 #else
208 
209 		/* No zlib, so we can't uncompress the data */
210 		SWF_error("No zlib support compiled in, "
211 			"cannot read compressed SWF");
212 #endif
213 	}
214 	else
215 	{
216 		if(fstat(fileno(f), &stat_buf) < 0) // verify file size!
217 		{
218 			perror("stat failed: ");
219 			return -1;
220 		}
221 		if(m.size != stat_buf.st_size)
222 		{
223 			SWF_warn("header indicates a filesize of %lu but filesize is %lu\n", m.size, stat_buf.st_size);
224 			m.size = stat_buf.st_size;
225 		}
226 	}
227 	readRect (f, &(m.frame));
228 
229 	m.rate = readUInt8 (f) / 256.0 + readUInt8 (f);
230 	m.nFrames = readUInt16 (f);
231 	outputHeader(&m);
232 	return 0;
233 }
234 
readMovie(FILE * f)235 static void readMovie(FILE *f)
236 {
237 	int block, type, blockstart, blockoffset, length, nextFrame=0;
238 	SWF_Parserstruct *blockp;
239 	for (;;)
240 	{
241 		blockoffset = fileOffset;
242 
243 		// printf ("Block offset: %d %d\n", fileOffset, m.size);
244 
245 		if(filelen_check_fails(2))
246 			break;
247 		block = readUInt16 (f);
248 		type = block >> 6;
249 
250 		length = block & ((1 << 6) - 1);
251 
252 		if (length == 63)		/* it's a long block. */
253 		{
254 			if(filelen_check_fails(4))
255 				break;
256 			length = readUInt32 (f);
257 		}
258 
259 		//      printf ("Found Block: %s (%i), %i bytes\n", blockName (type), type, length);
260 		blockstart = fileOffset;
261 		nextFrame = fileOffset+length;
262 
263 		if(filelen_check_fails(length))
264 			break;
265 		blockp= blockParse(f, length, type);
266 
267 		if( ftell(f) != nextFrame )
268 		{
269 			// will SEEK_SET later, so this is not a critical error
270 		        SWF_warn(" Stream out of sync after parse of blocktype %d (%s)."
271 				" %ld but expecting %d.\n", type, blockName(type),
272 				ftell(f),nextFrame);
273 		}
274 
275 		if( blockp )
276 		{
277 			outputBlock( type, blockp, f);
278 			free(blockp);
279 		} else {
280 			SWF_warn("Error parsing block (unknown block type: %d, length %d)\n",
281 				type, length);
282 		}
283 
284 		if (type == 0 || fileOffset >= m.size)
285 			break;
286 
287 		fseek(f, nextFrame, SEEK_SET);
288 		fileOffset = ftell(f);
289 	}
290 	putchar ('\n');
291 
292 	if (fileOffset < m.size)
293 	{
294 		SWF_warn("extra garbage (i.e., we messed up in main): \n");
295 		dumpBytes (f, m.size - fileOffset);
296 		printf ("\n\n");
297 	}
298 	outputTrailer(&m);
299 }
300 
301 
302 int
main(int argc,char * argv[])303 main (int argc, char *argv[])
304 {
305 	FILE *f;
306 	int compressed = 0;
307 
308 	setbuf(stdout, NULL);
309 	switch( argc )
310 	{
311 	case 2:
312 		filename = argv[1];
313 		break;
314 	case 3:
315 		if (strcmp (argv[1], "-v") == 0) {
316 			verbose = 1;
317 			filename = argv[2];
318 		} else {
319 			filename = argv[1];
320 			swftargetfile = argv[2];
321 		}
322 		break;
323 	case 4:
324 		if (strcmp (argv[1], "-v") != 0) {
325 			usage(argv[0]);
326 			exit(1);
327 		}
328 		verbose = 1;
329 		filename = argv[2];
330 		swftargetfile = argv[3];
331 		break;
332 	case 0:
333 	case 1:
334 	default:
335 		usage(argv[0]);
336 		exit(1);
337 	}
338 
339 	if (!(f = fopen (filename, "rb")))
340 	{
341 		fprintf(stderr,"Sorry, can't seem to read the file '%s'\n",filename);
342 		usage(argv[0]);
343 		exit(1);
344 	}
345 
346 	if(readMovieHeader(f, &compressed))
347 		SWF_error("reading movie header failed\n");
348 	if(compressed)
349 		f = tempfile;
350 	readMovie(f);
351 	fclose (f);
352 	if (compressed)
353 	{
354 		unlink (tmp_name);
355 	}
356 	exit (0);
357 }
358