2 Implements combine(), which merges two swfs in memory.
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/log.h"
17 #include "./settings.h"
20 // * readers should be object-oriented
22 static char* slavename = 0;
23 static int slaveid = -1;
24 static int slaveframe = -1;
26 static char* tag_placeobject2_name (struct swf_tag* tag)
28 struct PlaceObject2 plo2;
29 placeobject2_init (&plo2, tag);
33 static u16 tag_placeobject2_character (struct swf_tag* tag)
35 struct PlaceObject2 plo2;
36 placeobject2_init (&plo2, tag);
40 static struct swffile master;
41 static struct swffile slave;
43 static int masterids[65536];
45 static int get_free_id()
50 if(masterids[t] == -1)
59 void changedepth(struct swf_tag*tag, int add)
61 if(tag->id == TAGID_PLACEOBJECT)
62 (*(u16*)&tag->data[2]) += add;
63 if(tag->id == TAGID_PLACEOBJECT2)
64 (*(u16*)&tag->data[1]) += add;
65 if(tag->id == TAGID_REMOVEOBJECT)
66 (*(u16*)&tag->data[2]) += add;
67 if(tag->id == TAGID_REMOVEOBJECT2)
68 (*(u16*)&tag->data[0]) += add;
71 /* applies the config move and scale parameters to
72 * a matrix. (If settings would provide a rotation,
73 * this would be a matrix concatenation/multiplication
74 * routine. In this case, it's just element-wise multiplication.
76 void matrix_adjust(struct MATRIX*m)
78 if(config.scalex != 1 || config.scaley != 1)
82 m->a[0][0] = config.scalex;
83 m->a[1][1] = config.scaley;
85 m->a[0][0] *= config.scalex;
86 m->a[1][1] *= config.scaley;
89 m->a[0][1] *= config.scalex;
90 m->a[1][0] *= config.scaley;
92 m->b[0] *= config.scalex;
93 m->b[1] *= config.scaley;
95 /* printf("hasscale: %d\n",m->hasscale);
96 printf("hasrotate: %d\n", m->hasrotate);
97 printf("move: %d %d\n", m->b[0],m->b[1]);
98 printf("rot: %f %f\n",m->a[0][0],m->a[0][1]);
99 printf(" %f %f\n",m->a[1][0],m->a[1][1]);*/
100 m->b[0] += config.movex;
101 m->b[1] += config.movey;
104 void write_changepos(struct swf_tag*tag, struct writer_t*w)
106 if(config.movex || config.movey || config.scalex != 1 || config.scaley != 1)
110 case TAGID_PLACEOBJECT: {
111 struct PlaceObject p;
112 placeobject_init(&p, tag);
113 matrix_adjust(&p.matrix);
114 placeobject_write(&p, w);
117 case TAGID_PLACEOBJECT2: {
118 struct PlaceObject2 p;
119 placeobject2_init(&p, tag);
122 MATRIX_init(&p.matrix);
124 matrix_adjust(&p.matrix);
125 placeobject2_write(&p, w);
129 writer_write(w, tag->fulldata, tag->fulllength);
134 writer_write(w, tag->fulldata, tag->fulllength);
138 void write_sprite_defines(struct writer_t*w)
141 while(slave.tags[pos].id != 0) {
142 struct swf_tag * tag = &slave.tags[pos];
143 if(!is_sprite_tag(tag->id)) {
144 logf("<debug> processing sprite tag %02x", slave.tags[pos].id);
145 if(is_defining_tag(tag->id))
147 logf("<debug> [sprite defs] write tag %02x (%d bytes in body)",
148 tag->id, tag->length);
149 writer_write(w, tag->fulldata, tag->fulllength);
154 {case TAGID_DEFINEFONTINFO:
156 /* define font info is not a defining tag, in that
157 * it doesn't define a new id, but rather extends
158 * an existing one. It also isn't a sprite tag.
159 * Anyway we can't throw it out, so we just pass it
162 writer_write(w, tag->fulldata, tag->fulllength);
165 case TAGID_JPEGTABLES:
166 /* according to the flash specs, there may only
167 be one JPEGTABLES tag per swf. This is maybe
169 writer_write(w, tag->fulldata, tag->fulllength);
171 case TAGID_EXPORTASSETS:
172 logf("<debug> deliberately ignoring EXPORTASSETS tag");
174 case TAGID_ENABLEDEBUGGER:
175 logf("<debug> deliberately ignoring ENABLEDEBUGGER tag");
177 case TAGID_BACKGROUNDCOLOR:
178 logf("<debug> deliberately ignoring BACKGROUNDCOLOR tag");
183 logf("<notice> found tag %d. This is a Generator template, isn't it?", slave.tags[pos].id);
186 logf("<notice> funny tag: %d is neither defining nor sprite", slave.tags[pos].id);
195 void write_sprite(struct writer_t*w, int spriteid, int replaceddefine)
202 // write slave(2) (header)
203 tmp = 0x3f + (TAGID_DEFINESPRITE << 6);
204 writer_write(w, &tmp, 2);
205 tagidpos = (u32*)writer_getpos(w);
206 writer_write(w, &tmp32, 4);
208 startpos = (u8*)writer_getpos(w);
210 logf ("<notice> sprite id is %d", spriteid);
212 writer_write(w, &tmp, 2);
213 tmp = slave.header.count;
214 writer_write(w, &tmp, 2);
217 // write slave(2) (body)
218 tmp = slave.header.count;
219 logf("<debug> %d frames to go",tmp);
222 tmp = 7 + (TAGID_PLACEOBJECT2 << 6);
223 writer_write(w, &tmp, 2);
224 tmp = 2+64; //flags: character + clipaction
225 writer_write(w, &tmp, 1);
227 writer_write(w, &tmp,2);
228 tmp = replaceddefine; //id
229 writer_write(w, &tmp,2);
230 tmp = 65535; //clipdepth
231 writer_write(w, &tmp,2);
234 if(config.overlay && !config.isframe) {
235 tmp = 5 + (TAGID_PLACEOBJECT2 << 6);
236 writer_write(w, &tmp, 2);
237 tmp = 2; //flags: character
238 writer_write(w, &tmp, 1);
240 writer_write(w, &tmp,2);
241 tmp = replaceddefine; //id
242 writer_write(w, &tmp,2);
246 struct swf_tag * tag = &slave.tags[pos];
247 if (is_sprite_tag(tag->id)) {
249 changedepth(tag, +1);
250 logf("<debug> [sprite main] write tag %02x (%d bytes in body)",
251 slave.tags[pos].id, slave.tags[pos].length);
252 write_changepos(tag, w);
254 if(tag->id == TAGID_SHOWFRAME)
257 logf("<debug> %d frames to go",tmp);
261 while(slave.tags[pos++].id != TAGID_END);
263 *tagidpos = (u8*)writer_getpos(w) - startpos; // set length of sprite (in header)
264 logf("<verbose> sprite length is %d",*tagidpos);
267 static char tag_ok_for_slave(int id)
269 if(id == TAGID_BACKGROUNDCOLOR)
274 #define FLAGS_WRITEDEFINES 1
275 #define FLAGS_WRITENONDEFINES 2
276 #define FLAGS_WRITESPRITE 4
277 #define FLAGS_WRITESLAVE 8
278 void write_master(struct writer_t*w, int spriteid, int replaceddefine, int flags)
285 int slavewritten = 0;
286 while(master.tags[pos].id != 0)
288 if(master.tags[pos].id == TAGID_SHOWFRAME && outputslave)
290 while(slave.tags[spos].id) {
291 if(slave.tags[spos].id == TAGID_SHOWFRAME) {
296 if(tag_ok_for_slave(slave.tags[spos].id))
297 writer_write(w, slave.tags[spos].fulldata, slave.tags[spos].fulllength);
303 if(is_defining_tag(master.tags[pos].id) && (flags&FLAGS_WRITEDEFINES))
305 logf("<debug> [master] write tag %02x (%d bytes in body)",
306 master.tags[pos].id, master.tags[pos].length);
307 if(getidfromtag(&master.tags[pos]) == spriteid && !config.isframe)
311 *(u16*)master.tags[pos].data = replaceddefine;
312 writer_write(w, master.tags[pos].fulldata, master.tags[pos].fulllength);
314 /* don't write this tag */
315 logf("<verbose> replacing tag %d id %d with sprite", master.tags[pos].id
319 if(flags&FLAGS_WRITESPRITE)
321 write_sprite_defines(w);
322 write_sprite(w, spriteid, replaceddefine);
324 if(flags&FLAGS_WRITESLAVE)
329 writer_write(w, master.tags[pos].fulldata, master.tags[pos].fulllength);
332 if(frame == slaveframe)
334 if(flags&FLAGS_WRITESLAVE) {
338 if((flags&FLAGS_WRITESPRITE) && !slavewritten)
340 int id = get_free_id();
344 logf("<fatal> Can't combine --clip and --frame");
346 *(u16*)&data[0] = (u16)(TAGID_PLACEOBJECT2<<6) + 5 ;
347 *(u8*)&data[2]= 2; //flags: id
348 *(u16*)&data[3]= depth; // depth
350 write_sprite_defines(w);
351 write_sprite(w, id, -1);
352 writer_write(w,data,7);
356 if(!is_defining_tag(master.tags[pos].id) && (flags&FLAGS_WRITENONDEFINES))
359 switch(master.tags[pos].id) {
360 case TAGID_PLACEOBJECT:
361 case TAGID_PLACEOBJECT2:
362 if(frame == slaveframe && !config.overlay)
364 case TAGID_REMOVEOBJECT:
365 // case TAGID_REMOVEOBJECT2:
366 /* place/removetags for the object we replaced
367 should be discarded, too, as the object to insert
370 if(spriteid>=0 && getidfromtag(&master.tags[pos]) == spriteid &&
371 !config.isframe && config.merge)
376 logf("<debug> [master] write tag %02x (%d bytes in body)",
377 master.tags[pos].id, master.tags[pos].length);
378 writer_write(w, master.tags[pos].fulldata, master.tags[pos].fulllength);
385 while(slave.tags[spos].id)
387 if(tag_ok_for_slave(slave.tags[spos].id))
388 writer_write(w, slave.tags[spos].fulldata, slave.tags[spos].fulllength);
391 if(!slavewritten && config.isframe && (flags&(FLAGS_WRITESLAVE|FLAGS_WRITESPRITE)))
393 logf("<warning> Frame %d doesn't exist in file. No substitution will occur",
397 writer_write(w, master.tags[pos].fulldata, master.tags[pos].fulllength);
400 void writeheader(struct writer_t*w, u8*data, int length)
402 if(config.hassizex || config.hassizey || config.framerate)
404 struct flash_header head;
405 swf_init(data-3, length+3);
406 head = swf_read_header();
409 head.boundingBox.x2 = head.boundingBox.x1 + config.sizex;
413 head.boundingBox.y2 = head.boundingBox.y1 + config.sizey;
417 head.rate = config.framerate;
419 swf_write_header(w, &head);
422 writer_write(w, data, length);
425 uchar * catcombine(uchar*masterdata, int masterlength, char*_slavename, uchar*slavedata, int slavelength, int*newlength)
430 int length = masterlength*2 + slavelength;
434 uchar*newdata = malloc(length);
436 logf("<fatal> Couldn't allocate %d bytes of memory", length);
440 logf("<fatal> Can't combine --cat and --frame");
443 writer_init(&w, newdata, length);
446 int tag = master.tags[pos].id;
447 if(is_defining_tag(tag)) {
448 int defineid = getidfromtag(&master.tags[pos]);
449 logf("<debug> tagid %02x defines object %d", tag, defineid);
450 masterids[defineid] = 1;
453 while(master.tags[pos++].id != 0);
455 swf_relocate (slavedata, slavelength, masterids);
456 read_swf(&slave, slavedata, slavelength);
458 writer_write(&w, "FWS",3);
459 headlength = (u32*)(writer_getpos(&w) + 1);
460 writeheader(&w, master.header.headerdata, master.header.headerlength);
462 depths = malloc(65536);
464 logf("<fatal> Couldn't allocate %d bytes of memory", 65536);
467 memset(depths, 0, 65536);
472 logf("<debug> [master] write tag %02x (%d bytes in body)",
473 master.tags[pos].id, master.tags[pos].length);
474 switch(master.tags[pos].id) {
475 case TAGID_PLACEOBJECT2:
477 case TAGID_PLACEOBJECT:
478 reader_init (master.tags[pos].data, master.tags[pos].length);
484 case TAGID_REMOVEOBJECT:
485 reader_init (master.tags[pos].data, master.tags[pos].length);
487 depths[readu16()] = 0;
489 case TAGID_REMOVEOBJECT2:
490 reader_init (master.tags[pos].data, master.tags[pos].length);
491 depths[readu16()] = 0;
494 if(master.tags[pos].id != 0)
495 writer_write(&w, master.tags[pos].fulldata, master.tags[pos].fulllength);
497 while(master.tags[pos++].id != 0);
504 *(u16*)(&data[0]) = (TAGID_REMOVEOBJECT2<<6) + 2;
505 *(u16*)(&data[2]) = t;
506 writer_write(&w, data, 4);
512 logf("<debug> [slave] write tag %02x (%d bytes in body)",
513 slave.tags[pos].id, slave.tags[pos].length);
514 writer_write(&w, slave.tags[pos].fulldata, slave.tags[pos].fulllength);
516 while(slave.tags[pos++].id != 0);
518 tmp32 = (u8*)writer_getpos(&w) - (u8*)newdata; //length
520 *headlength = tmp32; // set the header to the correct length
522 return newdata; //length
525 uchar * normalcombine(uchar*masterdata, int masterlength, char*_slavename, uchar*slavedata, int slavelength, int*newlength)
533 int replaceddefine = -1;
538 length = masterlength + slavelength*2 + 128; // this is a guess, but a good guess.
539 newdata = malloc(length);
540 writer_init(&w, newdata, length);
543 logf("<fatal> Couldn't allocate %d bytes of memory", length);
550 int tag = master.tags[pos].id;
551 if(is_defining_tag(tag)) {
552 int defineid = getidfromtag(&master.tags[pos]);
553 logf("<debug> tagid %02x defines object %d", tag, defineid);
554 masterids[defineid] = 1;
555 } else if(tag == TAGID_PLACEOBJECT2) {
556 char * name = tag_placeobject2_name(&master.tags[pos]);
557 int id = tag_placeobject2_character(&master.tags[pos]);
560 logf("<verbose> tagid %02x places object %d named \"%s\"", tag, id, name);
562 logf("<verbose> tagid %02x places object %d (no name)", tag, id);
564 if ((name && slavename && !strcmp(name,slavename)) ||
565 (!slavename && id==slaveid)) {
568 logf("<notice> Slave file attached to object %d.", id);
571 } else if(tag == TAGID_SHOWFRAME) {
572 if(slaveframe>=0 && frame==slaveframe) {
573 logf("<notice> Slave file attached to frame %d.", frame);
576 } else if(tag == TAGID_FRAMELABEL) {
577 char * name = master.tags[pos].data;
578 if(name && slavename && config.isframe && !strcmp(name, slavename)) {
580 logf("<notice> Slave file attached to frame %d (%s).", frame, name);
584 while(master.tags[pos++].id != 0);
586 if (spriteid<0 && !config.isframe) {
588 if(strcmp(slavename,"!!dummy!!"))
589 logf("<warning> Didn't find anything named %s in file. No substitutions will occur.", slavename);
592 logf("<warning> Didn't find id %d in file. No substitutions will occur.", slaveid);
593 spriteid = get_free_id();
596 swf_relocate (slavedata, slavelength, masterids);
598 read_swf(&slave, slavedata, slavelength);
601 replaceddefine = get_free_id();
605 writer_write(&w, "FWS",3);
606 headlength = (u32*)(writer_getpos(&w) + 1);
607 writeheader(&w, master.header.headerdata, master.header.headerlength);
609 if (config.antistream) {
611 logf("<fatal> Can't combine --antistream and --merge");
613 write_sprite_defines(&w);
614 write_sprite(&w, spriteid, replaceddefine);
615 write_master(&w, spriteid, replaceddefine, FLAGS_WRITEDEFINES);
616 write_master(&w, spriteid, replaceddefine, FLAGS_WRITENONDEFINES);
619 write_master(&w, spriteid, replaceddefine,
620 FLAGS_WRITEDEFINES|FLAGS_WRITENONDEFINES|FLAGS_WRITESLAVE);
622 write_master(&w, spriteid, replaceddefine,
623 FLAGS_WRITEDEFINES|FLAGS_WRITENONDEFINES|FLAGS_WRITESPRITE);
626 tmp32 = (u8*)writer_getpos(&w) - (u8*)newdata; //length
628 *headlength = tmp32; // set the header to the correct length
630 return newdata; //length
633 uchar * combine(uchar*masterdata, int masterlength, char*_slavename, uchar*slavedata, int slavelength, int*newlength)
635 char master_flash = 0;
636 char slave_flash = 0;
637 slavename = _slavename;
642 if(slavename[0] == '#')
644 slaveid = atoi(&slavename[1]);
649 slaveframe = slaveid;
653 logf("<debug> move x (%d)", config.movex);
654 logf("<debug> move y (%d)", config.movey);
655 logf("<debug> scale x (%d)", config.scalex);
656 logf("<debug> scale y (%d)", config.scaley);
657 logf("<debug> is frame (%d)", config.isframe);
659 memset(masterids, -1, sizeof(masterids));
663 logf("<fatal> the master file is too small (%d bytes)", masterlength);
668 logf("<fatal> the slave file is too small (%d bytes)", slavelength);
671 if(masterdata[2] == 'S' &&
672 masterdata[1] == 'W' &&
673 masterdata[0] == 'F')
675 logf("<notice> the master file is flash (swf) format\n");
679 logf("<notice> the master file is not flash (swf) format!\n");
681 if(slavedata[2] == 'S' &&
682 slavedata[1] == 'W' &&
685 logf("<notice> the slave file is flash (swf) format\n");
689 logf("<notice> the slave file is not flash (swf) format!\n");
691 if(master_flash && slave_flash) {
692 read_swf(&master, masterdata, masterlength);
694 return catcombine(masterdata, masterlength, _slavename, slavedata, slavelength, newlength);
696 return normalcombine(masterdata, masterlength, _slavename, slavedata, slavelength, newlength);