2 main routine for swfcombine(1), a tool for merging .swf-files.
4 Part of the swftools package.
6 Copyright (c) 2001 Matthias Kramm <kramm@quiss.org>
8 This file is distributed under the GPL, see file COPYING for details */
13 #include "../lib/rfxswf.h"
14 #include "../lib/args.h"
19 #include "../config.h"
21 char * master_filename = 0;
22 char * master_name = 0;
23 char * slave_filename[128];
24 char * slave_name[128];
27 float slave_scalex[128];
28 float slave_scaley[128];
29 char slave_isframe[128];
32 char * outputname = "output.swf";
34 int args_callback_option(char*name,char*val) {
40 else if(!strcmp(name,"l"))
45 else if (!strcmp(name, "o"))
50 else if (!strcmp(name, "v"))
55 else if (!strcmp(name, "a"))
60 else if (!strcmp(name, "A"))
65 else if (!strcmp(name, "x"))
67 config.movex = atoi(val);
70 else if (!strcmp(name, "y"))
72 config.movey = atoi(val);
75 else if (!strcmp(name, "m"))
80 else if (!strcmp(name, "f"))
85 else if (!strcmp(name, "d"))
90 else if (!strcmp(name, "r"))
92 config.framerate = atoi(val)*256/100;
95 else if (!strcmp(name, "X"))
97 config.sizex = atoi(val)*20;
101 else if (!strcmp(name, "Y"))
103 config.sizey = atoi(val)*20;
107 else if (!strcmp(name, "s"))
109 config.scalex = config.scaley = atoi(val)/100.0;
112 else if (!strcmp(name, "t") || !strcmp(name, "T"))
114 if(master_filename) {
115 fprintf(stderr, "error with arguments. Try --help.\n");
119 if(!strcmp(name,"T"))
121 master_filename = "__none__";
124 else if (!strcmp(name, "V"))
126 printf("swfcombine - part of %s %s\n", PACKAGE, VERSION);
131 fprintf(stderr, "Unknown option: -%s\n", name);
136 struct options_t options[] =
157 int args_callback_longoption(char*name,char*val) {
158 return args_long2shortoption(options, name, val);
161 int args_callback_command(char*name, char*val) {
162 char*myname = strdup(name);
164 filename = strchr(myname, '=');
169 // argument has no explicit name field. guess one from the file name
170 char*path = strrchr(myname, '/');
171 char*ext = strrchr(myname, '.');
172 if(!path) path = myname;
179 if(!master_filename) {
180 master_filename = filename;
181 master_name = myname;
183 logf("<verbose> slave entity %s (named \"%s\")\n", filename, myname);
185 slave_filename[numslaves] = filename;
186 slave_name[numslaves] = myname;
187 slave_movex[numslaves] = config.movex;
188 slave_movey[numslaves] = config.movey;
189 slave_scalex[numslaves] = config.scalex;
190 slave_scaley[numslaves] = config.scaley;
191 slave_isframe[numslaves] = config.isframe;
193 config.movex = config.movey = 0;
194 config.scalex = config.scaley = 1.0;
200 void args_callback_usage(char*name)
202 printf("Usage: %s [-rXYomlcv] [-f] masterfile] [-xysf] [(name1|#id1)=]slavefile1 .. [-xysf] [(nameN|#idN)=]slavefileN\n", name);
203 printf("OR: %s [-rXYomv] --stack[1] [-xysf] [(name1|#id1)=]slavefile1 .. [-xysf] [(nameN|#idN)=]slavefileN\n", name);
204 printf("OR: %s [-rXYov] --cat [-xysf] [(name1|#id1)=]slavefile1 .. [-xysf] [(nameN|#idN)=]slavefileN\n", name);
205 printf("OR: %s [-rXYomlcv] --dummy [-xys] [file]\n", name);
207 printf("-o outputfile --output explicitly specify output file. (otherwise, output.swf will be used\n");
208 printf("-t --stack place each slave in a seperate frame (no master movie\n");
209 printf("-T --stack1 place each slave in the first frame (no master movie\n");
210 printf("-m --merge Don't store the slaves in Sprites/MovieClips\n");
211 printf("-a --cat concatenate all slave files (no master movie\n");
212 printf("-l --overlay Don't remove any master objects, only overlay new objects\n");
213 printf("-c --clip Clip the slave objects by the corresponding master objects\n");
214 printf("-v --verbose Use more than one -v for greater effect \n");
215 printf("-d --dummy Don't require slave objects \n");
216 printf("-f --frame The following identifier is a frame or framelabel, not an id or objectname\n");
217 printf("-x xpos --movex x Adjust position of slave by xpos twips (1/20 pixel\n");
218 printf("-y ypos --movey y Adjust position of slave by ypos twips (1/20 pixel\n");
219 printf("-s scale --scale Adjust size of slave by scale%\n");
220 printf("-r framerate --rate Set movie framerate (100 frames/sec\n");
221 printf("-X width --width Force movie width to scale (default: use master width (not with -t\n");
222 printf("-Y height --height Force movie height to scale (default: use master height (not with -t\n");
225 /* read a whole file in memory */
226 char* fi_slurp(FILE*fi, unsigned int * setlength)
229 long long int length; //;)
230 long long int pos = 0;
231 fseek(fi,0,SEEK_END);
233 fseek(fi,0,SEEK_SET);
236 mem = malloc(length);
241 pos += fread(&mem[pos], 1, 65536, fi);
248 void fi_dump(FILE*fi, void*_mem, int length)
250 char*mem = (char*)_mem;
255 if (size > (length - pos))
256 size = (length - pos);
257 pos += fwrite(&mem[pos], 1, size, fi);
261 /* todo: use rfxswf */
262 void makestackmaster(u8**masterdata, int*masterlength)
264 u8 head[] = {'F','W','S'};
272 /* scan all slaves for bounding box */
273 for(t=0;t<numslaves;t++)
275 FILE*fi=fopen(slave_filename[t],"rb");
278 struct flash_header head;
280 strlength += strlen(slave_name[t]) + 9;
282 logf("<fatal> Couldn't open %s.", slave_filename[t]);
285 ret = fread(data,1,256,fi);
287 logf("<fatal> File %s is to small (%d bytes)", slave_filename[t], ret);
290 swf_init(&r, data,256);
291 head = swf_read_header(&r);
292 logf("<verbose> File %s has bounding box %d:%d:%d:%d\n",
294 head.boundingBox.x1, head.boundingBox.y1,
295 head.boundingBox.x2, head.boundingBox.y2);
296 if(head.version > fileversion)
297 fileversion = head.version;
299 box = head.boundingBox;
301 if(head.boundingBox.x1 < box.x1)
302 box.x1 = head.boundingBox.x1;
303 if(head.boundingBox.y1 < box.y1)
304 box.y1 = head.boundingBox.y1;
305 if(head.boundingBox.x2 > box.x2)
306 box.x2 = head.boundingBox.x2;
307 if(head.boundingBox.y2 > box.y2)
308 box.y2 = head.boundingBox.y2;
310 logf("<verbose> New master bounding box is %d:%d:%d:%d\n",
316 /* we don't have a master, so we create one ourselves. */
317 *masterlength = (numslaves + 1) * 32 + strlength;
318 *masterdata = (u8*)malloc(*masterlength);
320 memcpy(pos, head, sizeof(head));
322 *pos++ = fileversion;
324 *(u32*)pos = SWAP32(0x12345678); // to be overwritten
326 writeRECT(&pos, &box);
327 *(u16*)pos = SWAP16(0x2000); // framerate
329 *(u16*)pos = SWAP16(numslaves);
331 for(t=0;t<numslaves;t++)
337 sprintf(buf, "Frame%02d", t);
338 slave_name[t] = strdup(buf);
340 namelen = strlen(slave_name[t]);
342 *(u16*)&pos[0] = SWAP16((u16)(TAGID_DEFINESPRITE<<6) + 6);
343 *(u16*)&pos[2] = SWAP16(t+1); //ID
344 *(u16*)&pos[4] = 0; // Frames
345 *(u16*)&pos[6] = 0; // TAG1
346 *(u16*)&pos[8] = SWAP16((u16)(TAGID_PLACEOBJECT2<<6) + 6 + namelen);
347 *(u16*)&pos[10]= SWAP16(34); //flags: id+name
348 *(u16*)&pos[11]= SWAP16(1+t); // depth
349 *(u16*)&pos[13]= SWAP16(t+1); // id
350 sprintf(&pos[15],slave_name[t]);
351 pos += 15 + namelen + 1;
352 if(!config.stack1 || t == numslaves-1) {
353 *(u16*)&pos[0]= SWAP16((u16)(TAGID_SHOWFRAME<<6) + 0);
359 *(u16*)&pos[0]= SWAP16((u16)(TAGID_REMOVEOBJECT2<<6) + 2);
360 *(u16*)&pos[2]= SWAP16(1+t); // depth;
364 *(u16*)pos = SWAP16(TAGID_END<<6 + 0);
365 *masterlength = pos - *masterdata;
366 *fixpos = SWAP32(*masterlength);
369 struct config_t config;
370 int main(int argn, char *argv[])
374 unsigned int masterlength;
376 unsigned int slavelength;
378 unsigned int newlength;
382 config.antistream = 0;
383 config.alloctest = 0;
396 config.framerate = 0;
401 processargs(argn, argv);
402 initLog(0,-1,0,0,-1,config.loglevel);
404 if(config.merge && config.cat) {
405 logf("<error> Can't combine --cat and --merge");
412 logf("<error> Can't combine -l and -t");
416 logf("<error> Can't combine -c and -t");
419 logf("<verbose> (stacking) %d files found\n", numslaves);
421 makestackmaster(&masterdata,&masterlength);
423 logf("<verbose> Generated %d bytes of master data", masterlength);
426 logf("<verbose> master entity %s (named \"%s\")\n", master_filename, master_name);
427 fi = fopen(master_filename, "rb");
429 fprintf(stderr, "Failed to open %s\n", master_filename);
432 masterdata = fi_slurp(fi, &masterlength);
434 fprintf(stderr, "Failed to read from %s\n", master_filename);
437 logf("<debug> Read %d bytes from masterfile\n", masterlength);
441 for(t=0;t<numslaves;t++) {
442 logf("<verbose> slave entity(%d) %s (%s \"%s\")\n", t+1, slave_filename[t],
443 slave_isframe[t]?"frame":"object", slave_name[t]);
450 logf("<error> --dummy (-d) implies there are zero slave objects. You supplied %d.", numslaves);
454 slave_filename[0] = "!!dummy!!";
455 slave_name[0] = "!!dummy!!";
456 slave_isframe[0] = 0;
459 if (config.alloctest)
461 int*bitmap = malloc(sizeof(int)*65536);
462 memset(bitmap, -1, 65536*sizeof(int));
463 memset(bitmap, 1, 101*sizeof(int));
464 swf_relocate(masterdata, masterlength, bitmap);
465 newdata = masterdata;
466 newlength = masterlength;
473 logf("<error> You must have at least one slave entity.");
476 for(t = 0; t < numslaves; t++)
478 config.movex = slave_movex[t];
479 config.movey = slave_movey[t];
480 config.scalex = slave_scalex[t];
481 config.scaley = slave_scaley[t];
482 config.isframe = slave_isframe[t];
484 logf("<notice> Combine [%s]%s and [%s]%s", master_name, master_filename,
485 slave_name[t], slave_filename[t]);
488 fi = fopen(slave_filename[t], "rb");
490 fprintf(stderr, "Failed to open %s\n", slave_filename[t]);
493 slavedata = fi_slurp(fi, &slavelength);
495 fprintf(stderr, "Failed to read from %s\n", slave_filename[t]);
498 logf("<debug> Read %d bytes from slavefile\n", slavelength);
503 slavedata = (u8*)malloc(16);
507 slavedata[3] = 4; //version
508 *(u32*)&slavedata[4] = SWAP32(14); // length
509 slavedata[8] = 0; // boundingbox
510 *(u16*)&slavedata[9] = SWAP16(0); // rate
511 *(u16*)&slavedata[11] = SWAP16(0); // count
512 *(u16*)&slavedata[13] = SWAP16(0); // end tag
516 newdata = combine(masterdata, masterlength, slave_name[t], slavedata, slavelength, &newlength);
518 logf("<fatal> Aborting.");
523 masterdata = newdata;
524 masterlength = newlength;
528 logf("<debug> New File is %d bytes \n", newlength);
529 if(newdata && newlength) {
530 FILE*fi = fopen(outputname, "wb");
531 fi_dump(fi, newdata, newlength);