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 */
14 #include "../lib/rfxswf.h"
15 #include "../lib/args.h"
16 #include "../lib/log.h"
22 #include "../config.h"
24 char * master_filename = 0;
25 char * master_name = 0;
26 char * slave_filename[128];
27 char * slave_name[128];
30 float slave_scalex[128];
31 float slave_scaley[128];
32 char slave_isframe[128];
35 char * outputname = "output.swf";
37 int args_callback_option(char*name,char*val) {
43 else if(!strcmp(name,"l"))
48 else if (!strcmp(name, "o"))
53 else if (!strcmp(name, "v"))
58 else if (!strcmp(name, "a"))
63 else if (!strcmp(name, "A"))
68 else if (!strcmp(name, "x"))
70 config.movex = atoi(val);
73 else if (!strcmp(name, "y"))
75 config.movey = atoi(val);
78 else if (!strcmp(name, "m"))
83 else if (!strcmp(name, "f"))
88 else if (!strcmp(name, "d"))
93 else if (!strcmp(name, "z"))
98 else if (!strcmp(name, "r"))
100 config.framerate = atoi(val)*256/100;
103 else if (!strcmp(name, "X"))
105 config.sizex = atoi(val)*20;
109 else if (!strcmp(name, "Y"))
111 config.sizey = atoi(val)*20;
115 else if (!strcmp(name, "s"))
117 config.scalex = config.scaley = atoi(val)/100.0;
120 else if (!strcmp(name, "t") || !strcmp(name, "T"))
122 if(master_filename) {
123 fprintf(stderr, "error with arguments. Try --help.\n");
127 if(!strcmp(name,"T"))
129 master_filename = "__none__";
132 else if (!strcmp(name, "V"))
134 printf("swfcombine - part of %s %s\n", PACKAGE, VERSION);
139 fprintf(stderr, "Unknown option: -%s\n", name);
144 struct options_t options[] =
166 int args_callback_longoption(char*name,char*val) {
167 return args_long2shortoption(options, name, val);
170 int args_callback_command(char*name, char*val) {
171 char*myname = strdup(name);
173 filename = strchr(myname, '=');
178 // argument has no explicit name field. guess one from the file name
179 char*path = strrchr(myname, '/');
180 char*ext = strrchr(myname, '.');
181 if(!path) path = myname;
188 if(!master_filename) {
189 master_filename = filename;
190 master_name = myname;
192 logf("<verbose> slave entity %s (named \"%s\")\n", filename, myname);
194 slave_filename[numslaves] = filename;
195 slave_name[numslaves] = myname;
196 slave_movex[numslaves] = config.movex;
197 slave_movey[numslaves] = config.movey;
198 slave_scalex[numslaves] = config.scalex;
199 slave_scaley[numslaves] = config.scaley;
200 slave_isframe[numslaves] = config.isframe;
202 config.movex = config.movey = 0;
203 config.scalex = config.scaley = 1.0;
209 void args_callback_usage(char*name)
211 printf("Usage: %s [-rXYomlcv] [-f] masterfile] [-xysf] [(name1|#id1)=]slavefile1 .. [-xysf] [(nameN|#idN)=]slavefileN\n", name);
212 printf("OR: %s [-rXYomv] --stack[1] [-xysf] [(name1|#id1)=]slavefile1 .. [-xysf] [(nameN|#idN)=]slavefileN\n", name);
213 printf("OR: %s [-rXYov] --cat [-xysf] [(name1|#id1)=]slavefile1 .. [-xysf] [(nameN|#idN)=]slavefileN\n", name);
214 printf("OR: %s [-rXYomlcv] --dummy [-xys] [file]\n", name);
216 printf("-o outputfile --output explicitly specify output file. (otherwise, output.swf will be used\n");
217 printf("-t --stack place each slave in a seperate frame (no master movie\n");
218 printf("-T --stack1 place each slave in the first frame (no master movie\n");
219 printf("-m --merge Don't store the slaves in Sprites/MovieClips\n");
220 printf("-a --cat concatenate all slave files (no master movie\n");
221 printf("-l --overlay Don't remove any master objects, only overlay new objects\n");
222 printf("-c --clip Clip the slave objects by the corresponding master objects\n");
223 printf("-v --verbose Use more than one -v for greater effect \n");
224 printf("-d --dummy Don't require slave objects \n");
225 printf("-f --frame The following identifier is a frame or framelabel, not an id or objectname\n");
226 printf("-x xpos --movex x Adjust position of slave by xpos twips (1/20 pixel\n");
227 printf("-y ypos --movey y Adjust position of slave by ypos twips (1/20 pixel\n");
228 printf("-s scale --scale Adjust size of slave by scale%\n");
229 printf("-r framerate --rate Set movie framerate (100 frames/sec\n");
230 printf("-X width --width Force movie width to scale (default: use master width (not with -t\n");
231 printf("-Y height --height Force movie height to scale (default: use master height (not with -t\n");
232 printf("-z zlib --zlib Enable Flash 6 (MX) Zlib Compression\n");
235 static void zlib_error(int ret, char* msg, z_stream*zs)
237 fprintf(stderr, "%s: zlib error (%d): last zlib error: %s\n",
240 zs->msg?zs->msg:"unknown");
245 static char* fi_depack(FILE* fi, unsigned int * setlength) {
249 char buffer1[8192], *buffer2;
252 memset(&zs,0,sizeof(z_stream));
256 buffer2 = malloc(8192);
258 ret = inflateInit(&zs);
259 if (ret != Z_OK) zlib_error(ret, "inflate_init", &zs);
261 fread(buffer2, 8, 1, fi);
264 zs.next_out = &buffer2[8];
265 zs.avail_out = 8192-8;
271 zs.avail_in = fread(buffer1, 1, 8192, fi);
272 zs.next_in = buffer1;
275 ret = inflate(&zs, Z_NO_FLUSH);
277 ret = inflate(&zs, Z_FINISH);
279 if (ret == Z_STREAM_END)
281 if (ret != Z_OK) zlib_error(ret, "inflate_init", &zs);
283 if (zs.avail_out == 0)
285 buffer2 = realloc(buffer2, memsize + 8192);
287 zs.next_out = &buffer2[memsize];
291 *setlength = (zs.next_out - (Bytef*)buffer2);
292 ret = inflateEnd(&zs);
293 if(ret != Z_OK) zlib_error(ret, "inflate_init", &zs);
297 /* read a whole file in memory */
298 static char* fi_slurp(FILE*fi, unsigned int * setlength)
301 long long int length; //;)
302 long long int pos = 0;
304 fseek(fi,0,SEEK_END);
306 fseek(fi,0,SEEK_SET);
310 fseek(fi, 0, SEEK_SET);
311 if(!strncmp(id, "CWS", 3)) {
312 return fi_depack(fi, setlength);
315 mem = malloc(length);
320 pos += fread(&mem[pos], 1, 65536, fi);
327 static void fi_pack(FILE*fi, void*_mem, int length)
331 char*mem = (char*)_mem;
333 memset(&zs,0,sizeof(z_stream));
338 ret = deflateInit(&zs, 9);
339 if (ret != Z_OK) zlib_error(ret, "deflate_init", &zs);
342 fwrite(mem, 8, 1, fi);
344 zs.avail_in = length-8;
347 zs.next_out = buffer;
352 ret = deflate(&zs, Z_NO_FLUSH);
354 ret = deflate(&zs, Z_FINISH);
356 if (ret == Z_STREAM_END)
359 if (ret != Z_OK) zlib_error(ret, "deflate_sync", &zs);
361 if (zs.avail_out == 0)
363 fwrite(buffer, 8192, 1, fi);
364 zs.next_out = buffer;
368 fwrite(buffer, zs.next_out - (Bytef*)buffer, 1, fi);
370 ret = deflateEnd(&zs);
371 if (ret != Z_OK) zlib_error(ret, "deflate_end", &zs);
374 static void fi_dump(FILE*fi, void*_mem, int length)
376 char*mem = (char*)_mem;
381 if (size > (length - pos))
382 size = (length - pos);
383 pos += fwrite(&mem[pos], 1, size, fi);
387 /* todo: use rfxswf */
388 static void makestackmaster(u8**masterdata, int*masterlength)
390 u8 head[] = {'F','W','S'};
398 /* scan all slaves for bounding box */
399 for(t=0;t<numslaves;t++)
401 FILE*fi=fopen(slave_filename[t],"rb");
404 struct flash_header head;
406 strlength += strlen(slave_name[t]) + 9;
408 logf("<fatal> Couldn't open %s.", slave_filename[t]);
411 ret = fread(data,1,256,fi);
413 logf("<fatal> File %s is to small (%d bytes)", slave_filename[t], ret);
416 swf_init(&r, data,256);
417 head = swf_read_header(&r);
418 logf("<verbose> File %s has bounding box %d:%d:%d:%d\n",
420 head.boundingBox.x1, head.boundingBox.y1,
421 head.boundingBox.x2, head.boundingBox.y2);
422 if(head.version > fileversion)
423 fileversion = head.version;
425 box = head.boundingBox;
427 if(head.boundingBox.x1 < box.x1)
428 box.x1 = head.boundingBox.x1;
429 if(head.boundingBox.y1 < box.y1)
430 box.y1 = head.boundingBox.y1;
431 if(head.boundingBox.x2 > box.x2)
432 box.x2 = head.boundingBox.x2;
433 if(head.boundingBox.y2 > box.y2)
434 box.y2 = head.boundingBox.y2;
436 logf("<verbose> New master bounding box is %d:%d:%d:%d\n",
442 /* we don't have a master, so we create one ourselves. */
443 *masterlength = (numslaves + 1) * 32 + strlength;
444 *masterdata = (u8*)malloc(*masterlength);
446 memcpy(pos, head, sizeof(head));
448 *pos++ = fileversion;
450 PUT32(pos, 0x12345678); // to be overwritten
452 writeRECT(&pos, &box);
453 PUT16(pos, 0x2000) // framerate
455 PUT16(pos, numslaves) // framerate
457 for(t=0;t<numslaves;t++)
463 sprintf(buf, "Frame%02d", t);
464 slave_name[t] = strdup(buf);
466 namelen = strlen(slave_name[t]);
468 PUT16(&pos[0] , ((u16)(TAGID_DEFINESPRITE<<6) + 6));
469 PUT16(&pos[2] , (t+1)); //ID
470 PUT16(&pos[4] , 0); // Frames
471 PUT16(&pos[6] , 0); // TAG1
472 PUT16(&pos[8] , ((u16)(TAGID_PLACEOBJECT2<<6) + 6 + namelen));
473 PUT16(&pos[10], (34)); //flags: id+name
474 PUT16(&pos[11], (1+t)); // depth
475 PUT16(&pos[13], (t+1)); // id
476 sprintf(&pos[15],slave_name[t]);
477 pos += 15 + namelen + 1;
478 if(!config.stack1 || t == numslaves-1) {
479 PUT16(&pos[0],((u16)(TAGID_SHOWFRAME<<6) + 0));
485 PUT16(&pos[0], ((u16)(TAGID_REMOVEOBJECT2<<6) + 2));
486 PUT16(&pos[2], (1+t)); // depth;
490 PUT16(pos, ((TAGID_END<<6) + 0));
491 *masterlength = pos - *masterdata;
492 PUT32(fixpos, *masterlength);
495 struct config_t config;
496 int main(int argn, char *argv[])
500 unsigned int masterlength;
502 unsigned int slavelength;
504 unsigned int newlength;
508 config.antistream = 0;
509 config.alloctest = 0;
522 config.framerate = 0;
528 processargs(argn, argv);
529 initLog(0,-1,0,0,-1,config.loglevel);
531 if(config.merge && config.cat) {
532 logf("<error> Can't combine --cat and --merge");
539 logf("<error> Can't combine -l and -t");
543 logf("<error> Can't combine -c and -t");
546 logf("<verbose> (stacking) %d files found\n", numslaves);
548 makestackmaster(&masterdata,&masterlength);
550 logf("<verbose> Generated %d bytes of master data", masterlength);
553 logf("<verbose> master entity %s (named \"%s\")\n", master_filename, master_name);
554 fi = fopen(master_filename, "rb");
556 logf("<fatal> Failed to open %s\n", master_filename);
559 masterdata = fi_slurp(fi, &masterlength);
561 logf("<fatal> Failed to read from %s\n", master_filename);
564 logf("<debug> Read %d bytes from masterfile\n", masterlength);
568 for(t=0;t<numslaves;t++) {
569 logf("<verbose> slave entity(%d) %s (%s \"%s\")\n", t+1, slave_filename[t],
570 slave_isframe[t]?"frame":"object", slave_name[t]);
577 logf("<error> --dummy (-d) implies there are zero slave objects. You supplied %d.", numslaves);
581 slave_filename[0] = "!!dummy!!";
582 slave_name[0] = "!!dummy!!";
583 slave_isframe[0] = 0;
586 if (config.alloctest)
588 int*bitmap = malloc(sizeof(int)*65536);
589 memset(bitmap, -1, 65536*sizeof(int));
590 memset(bitmap, 1, 101*sizeof(int));
591 swf_relocate(masterdata, masterlength, bitmap);
592 newdata = masterdata;
593 newlength = masterlength;
600 logf("<error> You must have at least one slave entity.");
603 for(t = 0; t < numslaves; t++)
605 config.movex = slave_movex[t];
606 config.movey = slave_movey[t];
607 config.scalex = slave_scalex[t];
608 config.scaley = slave_scaley[t];
609 config.isframe = slave_isframe[t];
611 logf("<notice> Combine [%s]%s and [%s]%s", master_name, master_filename,
612 slave_name[t], slave_filename[t]);
615 fi = fopen(slave_filename[t], "rb");
617 logf("<fatal> Failed to open %s\n", slave_filename[t]);
620 slavedata = fi_slurp(fi, &slavelength);
622 logf("<fatal> Failed to read from %s\n", slave_filename[t]);
625 logf("<debug> Read %d bytes from slavefile\n", slavelength);
630 slavedata = (u8*)malloc(16);
634 slavedata[3] = 4; //version
635 PUT32(&slavedata[4], 14); ; // length
636 slavedata[8] = 0; // boundingbox
637 PUT16(&slavedata[9] , (0)); // rate
638 PUT16(&slavedata[11] , (0)); // count
639 PUT16(&slavedata[13] , (0)); // end tag
643 newdata = combine(masterdata, masterlength, slave_name[t], slavedata, slavelength, &newlength);
645 logf("<fatal> Aborting.");
650 masterdata = newdata;
651 masterlength = newlength;
655 logf("<debug> New File is %d bytes \n", newlength);
656 if(newdata && newlength) {
657 FILE*fi = fopen(outputname, "wb");
659 fi_pack(fi, newdata, newlength);
661 fi_dump(fi, newdata, newlength);