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"
15 #include "../lib/rfxswf.h"
18 #include "./settings.h"
20 static char* slavename = 0;
21 static int slaveid = -1;
22 static int slaveframe = -1;
24 static char* tag_placeobject2_name (struct swf_tag* tag)
26 struct PlaceObject2 plo2;
27 placeobject2_init (&plo2, tag);
31 static u16 tag_placeobject2_character (struct swf_tag* tag)
33 struct PlaceObject2 plo2;
34 placeobject2_init (&plo2, tag);
38 static struct swffile master;
39 static struct swffile slave;
41 static int masterids[65536];
43 static int get_free_id()
48 if(masterids[t] == -1)
57 void changedepth(struct swf_tag*tag, int add)
59 /* fucking big endian byte order */
60 if(tag->id == TAGID_PLACEOBJECT)
61 (*(u16*)&tag->data[2]) =
62 SWAP16(SWAP16(*(u16*)&tag->data[2]) + add);
63 if(tag->id == TAGID_PLACEOBJECT2)
64 (*(u16*)&tag->data[1]) =
65 SWAP16(SWAP16(*(u16*)&tag->data[1]) + add);
66 if(tag->id == TAGID_REMOVEOBJECT)
67 (*(u16*)&tag->data[2]) =
68 SWAP16(SWAP16(*(u16*)&tag->data[2]) + add);
69 if(tag->id == TAGID_REMOVEOBJECT2)
70 (*(u16*)&tag->data[0]) =
71 SWAP16(SWAP16(*(u16*)&tag->data[0]) + add);
76 /* TODO: if there's a jpegtable found, store it
77 and handle it together with the flash file
79 /* check that master and slave don't have both
80 jpegtables (which would be fatal) */
84 while(master.tags[pos].id != 0)
86 if(master.tags[pos].id == TAGID_JPEGTABLES)
91 while(master.tags[pos].id != 0)
93 if(slave.tags[pos].id == TAGID_JPEGTABLES)
97 if(spos>=0 && mpos>=0)
99 if(slave.tags[pos].length ==
100 master.tags[pos].length &&
101 !memcmp(slave.tags[pos].data, master.tags[pos].data,
102 master.tags[pos].length))
104 // ok, both have jpegtables, but they're identical.
105 // delete one and don't make an error
106 for(;spos<slave.tagnum-1;spos++)
112 if(spos>=0 && mpos>=0) {
113 logf("<error> Master and slave have incompatible JPEGTABLES.");
117 /* applies the config move and scale parameters to
118 * a matrix. (If settings would provide a rotation,
119 * this would be a matrix concatenation/multiplication
120 * routine. In this case, it's just element-wise multiplication.
122 void matrix_adjust(struct MATRIX*m)
124 if(config.scalex != 1 || config.scaley != 1)
128 m->a[0][0] = config.scalex;
129 m->a[1][1] = config.scaley;
131 m->a[0][0] *= config.scalex;
132 m->a[1][1] *= config.scaley;
135 m->a[0][1] *= config.scalex;
136 m->a[1][0] *= config.scaley;
138 m->b[0] *= config.scalex;
139 m->b[1] *= config.scaley;
141 /* printf("hasscale: %d\n",m->hasscale);
142 printf("hasrotate: %d\n", m->hasrotate);
143 printf("move: %d %d\n", m->b[0],m->b[1]);
144 printf("rot: %f %f\n",m->a[0][0],m->a[0][1]);
145 printf(" %f %f\n",m->a[1][0],m->a[1][1]);*/
146 m->b[0] += config.movex;
147 m->b[1] += config.movey;
150 void write_changepos(struct swf_tag*tag, struct writer_t*w)
152 if(config.movex || config.movey || config.scalex != 1 || config.scaley != 1)
156 case TAGID_PLACEOBJECT: {
157 struct PlaceObject p;
158 placeobject_init(&p, tag);
159 matrix_adjust(&p.matrix);
160 placeobject_write(&p, w);
163 case TAGID_PLACEOBJECT2: {
164 struct PlaceObject2 p;
165 placeobject2_init(&p, tag);
168 MATRIX_init(&p.matrix);
170 matrix_adjust(&p.matrix);
171 placeobject2_write(&p, w);
175 writer_write(w, tag->fulldata, tag->fulllength);
180 writer_write(w, tag->fulldata, tag->fulllength);
184 void write_sprite_defines(struct writer_t*w)
187 while(slave.tags[pos].id != 0) {
188 struct swf_tag * tag = &slave.tags[pos];
189 if(!is_sprite_tag(tag->id)) {
190 logf("<debug> processing sprite tag %02x", slave.tags[pos].id);
191 if(is_defining_tag(tag->id))
193 logf("<debug> [sprite defs] write tag %02x (%d bytes in body)",
194 tag->id, tag->length);
195 writer_write(w, tag->fulldata, tag->fulllength);
200 {case TAGID_DEFINEFONTINFO:
202 /* define font info is not a defining tag, in that
203 * it doesn't define a new id, but rather extends
204 * an existing one. It also isn't a sprite tag.
205 * Anyway we can't throw it out, so we just pass it
208 writer_write(w, tag->fulldata, tag->fulllength);
211 case TAGID_JPEGTABLES:
212 /* if we get here, jpeg_assert has already run,
213 ensuring this is the only one of it's kind,
214 so we may safely write it out */
215 writer_write(w, tag->fulldata, tag->fulllength);
217 case TAGID_EXPORTASSETS:
218 logf("<debug> deliberately ignoring EXPORTASSETS tag");
220 case TAGID_ENABLEDEBUGGER:
221 logf("<debug> deliberately ignoring ENABLEDEBUGGER tag");
223 case TAGID_BACKGROUNDCOLOR:
224 logf("<debug> deliberately ignoring BACKGROUNDCOLOR tag");
229 logf("<notice> found tag %d. This is a Generator template, isn't it?", slave.tags[pos].id);
232 logf("<notice> funny tag: %d is neither defining nor sprite", slave.tags[pos].id);
240 void write_sprite(struct writer_t*w, int spriteid, int replaceddefine)
247 // write slave(2) (header)
248 tmp = SWAP16(0x3f + (TAGID_DEFINESPRITE << 6));
249 writer_write(w, &tmp, 2);
250 tagidpos = (u32*)writer_getpos(w);
251 writer_write(w, &tmp32, 4);
253 startpos = (u8*)writer_getpos(w);
255 logf ("<notice> sprite id is %d", spriteid);
257 writer_write(w, &tmp, 2);
258 tmp = slave.header.count;
259 writer_write(w, &tmp, 2);
262 // write slave(2) (body)
263 tmp = slave.header.count;
264 logf("<debug> %d frames to go",tmp);
267 tmp = SWAP16(7 + (TAGID_PLACEOBJECT2 << 6));
268 writer_write(w, &tmp, 2);
269 tmp = SWAP16(2+64); //flags: character + clipaction
270 writer_write(w, &tmp, 1);
271 tmp = SWAP16(0); //depth
272 writer_write(w, &tmp,2);
273 tmp = SWAP16(replaceddefine); //id
274 writer_write(w, &tmp,2);
275 tmp = SWAP16(65535); //clipdepth
276 writer_write(w, &tmp,2);
279 if(config.overlay && !config.isframe) {
280 tmp = SWAP16(5 + (TAGID_PLACEOBJECT2 << 6));
281 writer_write(w, &tmp, 2);
282 tmp = SWAP16(2); //flags: character
283 writer_write(w, &tmp, 1);
284 tmp = SWAP16(0); //depth
285 writer_write(w, &tmp,2);
286 tmp = SWAP16(replaceddefine); //id
287 writer_write(w, &tmp,2);
291 struct swf_tag * tag = &slave.tags[pos];
292 if (is_sprite_tag(tag->id)) {
294 changedepth(tag, +1);
295 logf("<debug> [sprite main] write tag %02x (%d bytes in body)",
296 slave.tags[pos].id, slave.tags[pos].length);
297 write_changepos(tag, w);
299 if(tag->id == TAGID_SHOWFRAME)
302 logf("<debug> %d frames to go",tmp);
306 while(slave.tags[pos++].id != TAGID_END);
308 *tagidpos = SWAP32((u8*)writer_getpos(w) - startpos); // set length of sprite (in header)
309 logf("<verbose> sprite length is %d",SWAP32(*tagidpos));
312 static char tag_ok_for_slave(int id)
314 if(id == TAGID_BACKGROUNDCOLOR)
319 #define FLAGS_WRITEDEFINES 1
320 #define FLAGS_WRITENONDEFINES 2
321 #define FLAGS_WRITESPRITE 4
322 #define FLAGS_WRITESLAVE 8
323 void write_master(struct writer_t*w, int spriteid, int replaceddefine, int flags)
330 int slavewritten = 0;
331 while(master.tags[pos].id != 0)
333 if(master.tags[pos].id == TAGID_SHOWFRAME && outputslave)
335 while(slave.tags[spos].id) {
336 if(slave.tags[spos].id == TAGID_SHOWFRAME) {
341 if(tag_ok_for_slave(slave.tags[spos].id))
342 writer_write(w, slave.tags[spos].fulldata, slave.tags[spos].fulllength);
348 if(is_defining_tag(master.tags[pos].id) && (flags&FLAGS_WRITEDEFINES))
350 logf("<debug> [master] write tag %02x (%d bytes in body)",
351 master.tags[pos].id, master.tags[pos].length);
352 if(getidfromtag(&master.tags[pos]) == spriteid && !config.isframe)
356 *(u16*)master.tags[pos].data = SWAP16(replaceddefine);
357 writer_write(w, master.tags[pos].fulldata, master.tags[pos].fulllength);
359 /* don't write this tag */
360 logf("<verbose> replacing tag %d id %d with sprite", master.tags[pos].id
364 if(flags&FLAGS_WRITESPRITE)
366 write_sprite_defines(w);
367 write_sprite(w, spriteid, replaceddefine);
369 if(flags&FLAGS_WRITESLAVE)
374 writer_write(w, master.tags[pos].fulldata, master.tags[pos].fulllength);
377 if(frame == slaveframe)
379 if(flags&FLAGS_WRITESLAVE) {
383 if((flags&FLAGS_WRITESPRITE) && !slavewritten)
385 int id = get_free_id();
389 logf("<fatal> Can't combine --clip and --frame");
391 *(u16*)&data[0] = SWAP16((u16)(TAGID_PLACEOBJECT2<<6) + 5);
392 *(u8*)&data[2]= SWAP16(2); //flags: id
393 *(u16*)&data[3]= SWAP16(depth); // depth
394 *(u16*)&data[5]= SWAP16(id);
395 write_sprite_defines(w);
396 write_sprite(w, id, -1);
397 writer_write(w,data,7);
401 if(!is_defining_tag(master.tags[pos].id) && (flags&FLAGS_WRITENONDEFINES))
404 switch(master.tags[pos].id) {
405 case TAGID_PLACEOBJECT:
406 case TAGID_PLACEOBJECT2:
407 if(frame == slaveframe && !config.overlay)
409 case TAGID_REMOVEOBJECT:
410 // case TAGID_REMOVEOBJECT2:
411 /* place/removetags for the object we replaced
412 should be discarded, too, as the object to insert
415 if(spriteid>=0 && getidfromtag(&master.tags[pos]) == spriteid &&
416 !config.isframe && config.merge)
421 logf("<debug> [master] write tag %02x (%d bytes in body)",
422 master.tags[pos].id, master.tags[pos].length);
423 writer_write(w, master.tags[pos].fulldata, master.tags[pos].fulllength);
430 while(slave.tags[spos].id)
432 if(tag_ok_for_slave(slave.tags[spos].id))
433 writer_write(w, slave.tags[spos].fulldata, slave.tags[spos].fulllength);
436 if(!slavewritten && config.isframe && (flags&(FLAGS_WRITESLAVE|FLAGS_WRITESPRITE)))
438 logf("<warning> Frame %d doesn't exist in file. No substitution will occur",
442 writer_write(w, master.tags[pos].fulldata, master.tags[pos].fulllength);
445 void writeheader(struct writer_t*w, u8*data, int length)
447 if(config.hassizex || config.hassizey || config.framerate)
449 struct flash_header head;
450 struct reader_t reader;
451 swf_init(&reader, data-3, length+3);
452 head = swf_read_header(&reader);
455 head.boundingBox.x2 = head.boundingBox.x1 + config.sizex;
459 head.boundingBox.y2 = head.boundingBox.y1 + config.sizey;
463 head.rate = config.framerate;
465 swf_write_header(w, &head);
468 writer_write(w, data, length);
471 uchar * catcombine(uchar*masterdata, int masterlength, char*_slavename, uchar*slavedata, int slavelength, int*newlength)
476 int length = masterlength*2 + slavelength;
480 uchar*newdata = malloc(length);
482 logf("<fatal> Couldn't allocate %d bytes of memory", length);
486 logf("<fatal> Can't combine --cat and --frame");
489 writer_init(&w, newdata, length);
492 int tag = master.tags[pos].id;
493 if(is_defining_tag(tag)) {
494 int defineid = getidfromtag(&master.tags[pos]);
495 logf("<debug> tagid %02x defines object %d", tag, defineid);
496 masterids[defineid] = 1;
499 while(master.tags[pos++].id != 0);
501 swf_relocate (slavedata, slavelength, masterids);
502 read_swf(&slave, slavedata, slavelength);
505 writer_write(&w, "FWS",3);
506 headlength = (u32*)(writer_getpos(&w) + 1);
507 writeheader(&w, master.header.headerdata, master.header.headerlength);
509 depths = malloc(65536);
511 logf("<fatal> Couldn't allocate %d bytes of memory", 65536);
514 memset(depths, 0, 65536);
519 logf("<debug> [master] write tag %02x (%d bytes in body)",
520 master.tags[pos].id, master.tags[pos].length);
521 switch(master.tags[pos].id) {
522 case TAGID_PLACEOBJECT2:
524 case TAGID_PLACEOBJECT: {
526 reader_init (&r, master.tags[pos].data, master.tags[pos].length);
529 depth = reader_readu16(&r);
533 case TAGID_REMOVEOBJECT: {
535 reader_init (&r, master.tags[pos].data, master.tags[pos].length);
537 depths[reader_readu16(&r)] = 0;
540 case TAGID_REMOVEOBJECT2: {
542 reader_init (&r, master.tags[pos].data, master.tags[pos].length);
543 depths[reader_readu16(&r)] = 0;
547 if(master.tags[pos].id != 0)
548 writer_write(&w, master.tags[pos].fulldata, master.tags[pos].fulllength);
550 while(master.tags[pos++].id != 0);
557 *(u16*)(&data[0]) = SWAP16((TAGID_REMOVEOBJECT2<<6) + 2);
558 *(u16*)(&data[2]) = SWAP16(t);
559 writer_write(&w, data, 4);
565 logf("<debug> [slave] write tag %02x (%d bytes in body)",
566 slave.tags[pos].id, slave.tags[pos].length);
567 writer_write(&w, slave.tags[pos].fulldata, slave.tags[pos].fulllength);
569 while(slave.tags[pos++].id != 0);
571 tmp32 = (u8*)writer_getpos(&w) - (u8*)newdata; //length
573 *headlength = SWAP32(tmp32); // set the header to the correct length
575 return newdata; //length
578 uchar * normalcombine(uchar*masterdata, int masterlength, char*_slavename, uchar*slavedata, int slavelength, int*newlength)
586 int replaceddefine = -1;
591 length = masterlength + slavelength*2 + 128; // this is a guess, but a good guess.
592 newdata = malloc(length);
593 writer_init(&w, newdata, length);
596 logf("<fatal> Couldn't allocate %d bytes of memory", length);
603 int tag = master.tags[pos].id;
604 if(is_defining_tag(tag)) {
605 int defineid = getidfromtag(&master.tags[pos]);
606 logf("<debug> tagid %02x defines object %d", tag, defineid);
607 masterids[defineid] = 1;
608 } else if(tag == TAGID_PLACEOBJECT2) {
609 char * name = tag_placeobject2_name(&master.tags[pos]);
610 int id = tag_placeobject2_character(&master.tags[pos]);
613 logf("<verbose> tagid %02x places object %d named \"%s\"", tag, id, name);
615 logf("<verbose> tagid %02x places object %d (no name)", tag, id);
617 if ((name && slavename && !strcmp(name,slavename)) ||
618 (!slavename && id==slaveid)) {
621 logf("<notice> Slave file attached to object %d.", id);
624 } else if(tag == TAGID_SHOWFRAME) {
625 if(slaveframe>=0 && frame==slaveframe) {
626 logf("<notice> Slave file attached to frame %d.", frame);
629 } else if(tag == TAGID_FRAMELABEL) {
630 char * name = master.tags[pos].data;
631 if(name && slavename && config.isframe && !strcmp(name, slavename)) {
633 logf("<notice> Slave file attached to frame %d (%s).", frame, name);
637 while(master.tags[pos++].id != 0);
639 if (spriteid<0 && !config.isframe) {
641 if(strcmp(slavename,"!!dummy!!"))
642 logf("<warning> Didn't find anything named %s in file. No substitutions will occur.", slavename);
645 logf("<warning> Didn't find id %d in file. No substitutions will occur.", slaveid);
646 spriteid = get_free_id();
649 swf_relocate (slavedata, slavelength, masterids);
650 read_swf(&slave, slavedata, slavelength);
654 replaceddefine = get_free_id();
658 writer_write(&w, "FWS",3);
659 headlength = (u32*)(writer_getpos(&w) + 1);
660 writeheader(&w, master.header.headerdata, master.header.headerlength);
662 if (config.antistream) {
664 logf("<fatal> Can't combine --antistream and --merge");
666 write_sprite_defines(&w);
667 write_sprite(&w, spriteid, replaceddefine);
668 write_master(&w, spriteid, replaceddefine, FLAGS_WRITEDEFINES);
669 write_master(&w, spriteid, replaceddefine, FLAGS_WRITENONDEFINES);
672 write_master(&w, spriteid, replaceddefine,
673 FLAGS_WRITEDEFINES|FLAGS_WRITENONDEFINES|FLAGS_WRITESLAVE);
675 write_master(&w, spriteid, replaceddefine,
676 FLAGS_WRITEDEFINES|FLAGS_WRITENONDEFINES|FLAGS_WRITESPRITE);
679 tmp32 = (u8*)writer_getpos(&w) - (u8*)newdata; //length
681 *headlength = SWAP32(tmp32); // set the header to the correct length
683 return newdata; //length
686 uchar * combine(uchar*masterdata, int masterlength, char*_slavename, uchar*slavedata, int slavelength, int*newlength)
688 char master_flash = 0;
689 char slave_flash = 0;
690 slavename = _slavename;
695 if(slavename[0] == '#')
697 slaveid = atoi(&slavename[1]);
702 slaveframe = slaveid;
706 logf("<debug> move x (%d)", config.movex);
707 logf("<debug> move y (%d)", config.movey);
708 logf("<debug> scale x (%d)", config.scalex);
709 logf("<debug> scale y (%d)", config.scaley);
710 logf("<debug> is frame (%d)", config.isframe);
712 memset(masterids, -1, sizeof(masterids));
716 logf("<fatal> the master file is too small (%d bytes)", masterlength);
721 logf("<fatal> the slave file is too small (%d bytes)", slavelength);
724 if(masterdata[2] == 'S' &&
725 masterdata[1] == 'W' &&
726 masterdata[0] == 'F')
728 logf("<notice> the master file is flash (swf) format\n");
732 logf("<notice> the master file is not flash (swf) format!\n");
734 if(slavedata[2] == 'S' &&
735 slavedata[1] == 'W' &&
738 logf("<notice> the slave file is flash (swf) format\n");
742 logf("<notice> the slave file is not flash (swf) format!\n");
744 if(master_flash && slave_flash) {
745 read_swf(&master, masterdata, masterlength);
747 return catcombine(masterdata, masterlength, _slavename, slavedata, slavelength, newlength);
749 return normalcombine(masterdata, masterlength, _slavename, slavedata, slavelength, newlength);