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