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 PUT16(&tag->data[2],GET16(&tag->data[2])+add);
62 if(tag->id == TAGID_PLACEOBJECT2)
63 PUT16(&tag->data[1],GET16(&tag->data[1])+add);
64 if(tag->id == TAGID_REMOVEOBJECT)
65 PUT16(&tag->data[2],GET16(&tag->data[2])+add);
66 if(tag->id == TAGID_REMOVEOBJECT2)
67 PUT16(&tag->data[0],GET16(&tag->data[0])+add);
72 /* TODO: if there's a jpegtable found, store it
73 and handle it together with the flash file
75 /* check that master and slave don't have both
76 jpegtables (which would be fatal) */
80 while(master.tags[pos].id != 0)
82 if(master.tags[pos].id == TAGID_JPEGTABLES)
87 while(slave.tags[pos].id != 0)
89 if(slave.tags[pos].id == TAGID_JPEGTABLES)
93 if(spos>=0 && mpos>=0)
95 if(slave.tags[pos].length ==
96 master.tags[pos].length &&
97 !memcmp(slave.tags[pos].data, master.tags[pos].data,
98 master.tags[pos].length))
100 // ok, both have jpegtables, but they're identical.
101 // delete one and don't make an error
102 for(;spos<slave.tagnum-1;spos++)
108 if(spos>=0 && mpos>=0) {
109 logf("<error> Master and slave have incompatible JPEGTABLES.");
113 /* applies the config move and scale parameters to
114 * a matrix. (If settings would provide a rotation,
115 * this would be a matrix concatenation/multiplication
116 * routine. In this case, it's just element-wise multiplication.
118 void matrix_adjust(struct MATRIX*m)
120 if(config.scalex != 1 || config.scaley != 1)
124 m->a[0][0] = config.scalex;
125 m->a[1][1] = config.scaley;
127 m->a[0][0] *= config.scalex;
128 m->a[1][1] *= config.scaley;
131 m->a[0][1] *= config.scalex;
132 m->a[1][0] *= config.scaley;
134 m->b[0] *= config.scalex;
135 m->b[1] *= config.scaley;
137 /* printf("hasscale: %d\n",m->hasscale);
138 printf("hasrotate: %d\n", m->hasrotate);
139 printf("move: %d %d\n", m->b[0],m->b[1]);
140 printf("rot: %f %f\n",m->a[0][0],m->a[0][1]);
141 printf(" %f %f\n",m->a[1][0],m->a[1][1]);*/
142 m->b[0] += config.movex;
143 m->b[1] += config.movey;
146 void write_changepos(struct swf_tag*tag, struct writer_t*w)
148 if(config.movex || config.movey || config.scalex != 1 || config.scaley != 1)
152 case TAGID_PLACEOBJECT: {
153 struct PlaceObject p;
154 placeobject_init(&p, tag);
155 matrix_adjust(&p.matrix);
156 placeobject_write(&p, w);
159 case TAGID_PLACEOBJECT2: {
160 struct PlaceObject2 p;
161 placeobject2_init(&p, tag);
164 MATRIX_init(&p.matrix);
166 matrix_adjust(&p.matrix);
167 placeobject2_write(&p, w);
171 writer_write(w, tag->fulldata, tag->fulllength);
176 writer_write(w, tag->fulldata, tag->fulllength);
180 void write_sprite_defines(struct writer_t*w)
183 while(slave.tags[pos].id != 0) {
184 struct swf_tag * tag = &slave.tags[pos];
185 if(!is_sprite_tag(tag->id)) {
186 logf("<debug> processing sprite tag %02x", slave.tags[pos].id);
187 if(is_defining_tag(tag->id))
189 logf("<debug> [sprite defs] write tag %02x (%d bytes in body)",
190 tag->id, tag->length);
191 writer_write(w, tag->fulldata, tag->fulllength);
196 {case TAGID_DEFINEFONTINFO:
198 /* define font info is not a defining tag, in that
199 * it doesn't define a new id, but rather extends
200 * an existing one. It also isn't a sprite tag.
201 * Anyway we can't throw it out, so we just pass it
204 writer_write(w, tag->fulldata, tag->fulllength);
207 case TAGID_JPEGTABLES:
208 /* if we get here, jpeg_assert has already run,
209 ensuring this is the only one of it's kind,
210 so we may safely write it out */
211 writer_write(w, tag->fulldata, tag->fulllength);
213 case TAGID_EXPORTASSETS:
214 logf("<debug> deliberately ignoring EXPORTASSETS tag");
216 case TAGID_ENABLEDEBUGGER:
217 logf("<debug> deliberately ignoring ENABLEDEBUGGER tag");
219 case TAGID_BACKGROUNDCOLOR:
220 logf("<debug> deliberately ignoring BACKGROUNDCOLOR tag");
225 logf("<notice> found tag %d. This is a Generator template, isn't it?", slave.tags[pos].id);
228 logf("<notice> funny tag: %d is neither defining nor sprite", slave.tags[pos].id);
236 void write_sprite(struct writer_t*w, int spriteid, int replaceddefine)
243 // write slave(2) (header)
244 tmp = SWAP16(0x3f + (TAGID_DEFINESPRITE << 6));
245 writer_write(w, &tmp, 2);
246 tagidpos = (u32*)writer_getpos(w);
247 writer_write(w, &tmp32, 4);
249 startpos = (u8*)writer_getpos(w);
251 logf ("<notice> sprite id is %d", spriteid);
252 tmp = SWAP16(spriteid);
253 writer_write(w, &tmp, 2);
254 tmp = SWAP16(slave.header.count);
255 writer_write(w, &tmp, 2);
258 // write slave(2) (body)
259 tmp = slave.header.count;
260 logf("<debug> %d frames to go",tmp);
263 tmp = SWAP16(7 + (TAGID_PLACEOBJECT2 << 6));
264 writer_write(w, &tmp, 2);
265 tmp = SWAP16(2+64); //flags: character + clipaction
266 writer_write(w, &tmp, 1);
267 tmp = SWAP16(0); //depth
268 writer_write(w, &tmp,2);
269 tmp = SWAP16(replaceddefine); //id
270 writer_write(w, &tmp,2);
271 tmp = SWAP16(65535); //clipdepth
272 writer_write(w, &tmp,2);
275 if(config.overlay && !config.isframe) {
276 tmp = SWAP16(5 + (TAGID_PLACEOBJECT2 << 6));
277 writer_write(w, &tmp, 2);
278 tmp = SWAP16(2); //flags: character
279 writer_write(w, &tmp, 1);
280 tmp = SWAP16(0); //depth
281 writer_write(w, &tmp,2);
282 tmp = SWAP16(replaceddefine); //id
283 writer_write(w, &tmp,2);
287 struct swf_tag * tag = &slave.tags[pos];
288 if (is_sprite_tag(tag->id)) {
290 changedepth(tag, +1);
291 logf("<debug> [sprite main] write tag %02x (%d bytes in body)",
292 slave.tags[pos].id, slave.tags[pos].length);
293 write_changepos(tag, w);
295 if(tag->id == TAGID_SHOWFRAME)
298 logf("<debug> %d frames to go",tmp);
302 while(slave.tags[pos++].id != TAGID_END);
304 PUT32(tagidpos, (u8*)writer_getpos(w) - startpos); // set length of sprite (in header)
305 logf("<verbose> sprite length is %d",GET32(tagidpos));
308 static char tag_ok_for_slave(int id)
310 if(id == TAGID_BACKGROUNDCOLOR)
315 #define FLAGS_WRITEDEFINES 1
316 #define FLAGS_WRITENONDEFINES 2
317 #define FLAGS_WRITESPRITE 4
318 #define FLAGS_WRITESLAVE 8
319 void write_master(struct writer_t*w, int spriteid, int replaceddefine, int flags)
326 int slavewritten = 0;
327 while(master.tags[pos].id != 0)
329 if(master.tags[pos].id == TAGID_SHOWFRAME && outputslave)
331 while(slave.tags[spos].id) {
332 if(slave.tags[spos].id == TAGID_SHOWFRAME) {
337 if(tag_ok_for_slave(slave.tags[spos].id))
338 writer_write(w, slave.tags[spos].fulldata, slave.tags[spos].fulllength);
344 if(is_defining_tag(master.tags[pos].id) && (flags&FLAGS_WRITEDEFINES))
346 logf("<debug> [master] write tag %02x (%d bytes in body)",
347 master.tags[pos].id, master.tags[pos].length);
348 if(getidfromtag(&master.tags[pos]) == spriteid && !config.isframe)
352 PUT16(master.tags[pos].data, replaceddefine);
353 writer_write(w, master.tags[pos].fulldata, master.tags[pos].fulllength);
355 /* don't write this tag */
356 logf("<verbose> replacing tag %d id %d with sprite", master.tags[pos].id
360 if(flags&FLAGS_WRITESPRITE)
362 write_sprite_defines(w);
363 write_sprite(w, spriteid, replaceddefine);
365 if(flags&FLAGS_WRITESLAVE)
370 writer_write(w, master.tags[pos].fulldata, master.tags[pos].fulllength);
373 if(frame == slaveframe)
375 if(flags&FLAGS_WRITESLAVE) {
379 if((flags&FLAGS_WRITESPRITE) && !slavewritten)
381 int id = get_free_id();
385 logf("<fatal> Can't combine --clip and --frame");
387 PUT16(&data[0], (u16)(TAGID_PLACEOBJECT2<<6) + 5);
388 *(u8*)&data[2]= 2; //flags: id
389 PUT16(&data[3], depth);
391 write_sprite_defines(w);
392 write_sprite(w, id, -1);
393 writer_write(w,data,7);
397 if(!is_defining_tag(master.tags[pos].id) && (flags&FLAGS_WRITENONDEFINES))
400 switch(master.tags[pos].id) {
401 case TAGID_PLACEOBJECT:
402 case TAGID_PLACEOBJECT2:
403 if(frame == slaveframe && !config.overlay)
405 case TAGID_REMOVEOBJECT:
406 // case TAGID_REMOVEOBJECT2:
407 /* place/removetags for the object we replaced
408 should be discarded, too, as the object to insert
411 if(spriteid>=0 && getidfromtag(&master.tags[pos]) == spriteid &&
412 !config.isframe && config.merge)
417 logf("<debug> [master] write tag %02x (%d bytes in body)",
418 master.tags[pos].id, master.tags[pos].length);
419 writer_write(w, master.tags[pos].fulldata, master.tags[pos].fulllength);
426 while(slave.tags[spos].id)
428 if(tag_ok_for_slave(slave.tags[spos].id))
429 writer_write(w, slave.tags[spos].fulldata, slave.tags[spos].fulllength);
432 if(!slavewritten && config.isframe && (flags&(FLAGS_WRITESLAVE|FLAGS_WRITESPRITE)))
434 logf("<warning> Frame %d doesn't exist in file. No substitution will occur",
438 writer_write(w, master.tags[pos].fulldata, master.tags[pos].fulllength);
441 void writeheader(struct writer_t*w, u8*data, int length)
443 if(config.hassizex || config.hassizey || config.framerate)
445 struct flash_header head;
446 struct reader_t reader;
447 swf_init(&reader, data-3, length+3);
448 head = swf_read_header(&reader);
451 head.boundingBox.x2 = head.boundingBox.x1 + config.sizex;
455 head.boundingBox.y2 = head.boundingBox.y1 + config.sizey;
459 head.rate = config.framerate;
461 swf_write_header(w, &head);
464 writer_write(w, data, length);
467 uchar * catcombine(uchar*masterdata, int masterlength, char*_slavename, uchar*slavedata, int slavelength, int*newlength)
472 int length = masterlength*2 + slavelength;
476 uchar*newdata = malloc(length);
478 logf("<fatal> Couldn't allocate %d bytes of memory", length);
482 logf("<fatal> Can't combine --cat and --frame");
485 writer_init(&w, newdata, length);
488 int tag = master.tags[pos].id;
489 if(is_defining_tag(tag)) {
490 int defineid = getidfromtag(&master.tags[pos]);
491 logf("<debug> tagid %02x defines object %d", tag, defineid);
492 masterids[defineid] = 1;
495 while(master.tags[pos++].id != 0);
497 swf_relocate (slavedata, slavelength, masterids);
498 read_swf(&slave, slavedata, slavelength);
501 writer_write(&w, "FWS",3);
502 headlength = (u32*)(writer_getpos(&w) + 1);
503 writeheader(&w, master.header.headerdata, master.header.headerlength);
505 depths = malloc(65536);
507 logf("<fatal> Couldn't allocate %d bytes of memory", 65536);
510 memset(depths, 0, 65536);
515 logf("<debug> [master] write tag %02x (%d bytes in body)",
516 master.tags[pos].id, master.tags[pos].length);
517 switch(master.tags[pos].id) {
518 case TAGID_PLACEOBJECT2:
520 case TAGID_PLACEOBJECT: {
522 reader_init (&r, master.tags[pos].data, master.tags[pos].length);
525 depth = reader_readu16(&r);
529 case TAGID_REMOVEOBJECT: {
531 reader_init (&r, master.tags[pos].data, master.tags[pos].length);
533 depths[reader_readu16(&r)] = 0;
536 case TAGID_REMOVEOBJECT2: {
538 reader_init (&r, master.tags[pos].data, master.tags[pos].length);
539 depths[reader_readu16(&r)] = 0;
543 if(master.tags[pos].id != 0)
544 writer_write(&w, master.tags[pos].fulldata, master.tags[pos].fulllength);
546 while(master.tags[pos++].id != 0);
553 PUT16(&data[0], (TAGID_REMOVEOBJECT2<<6) + 2);
555 writer_write(&w, data, 4);
561 logf("<debug> [slave] write tag %02x (%d bytes in body)",
562 slave.tags[pos].id, slave.tags[pos].length);
563 writer_write(&w, slave.tags[pos].fulldata, slave.tags[pos].fulllength);
565 while(slave.tags[pos++].id != 0);
567 tmp32 = (u8*)writer_getpos(&w) - (u8*)newdata; //length
569 PUT32(headlength, tmp32); // set the header to the correct length
571 return newdata; //length
574 uchar * normalcombine(uchar*masterdata, int masterlength, char*_slavename, uchar*slavedata, int slavelength, int*newlength)
582 int replaceddefine = -1;
587 length = masterlength + slavelength*2 + 128; // this is a guess, but a good guess.
588 newdata = malloc(length);
589 writer_init(&w, newdata, length);
592 logf("<fatal> Couldn't allocate %d bytes of memory", length);
599 int tag = master.tags[pos].id;
600 if(is_defining_tag(tag)) {
601 int defineid = getidfromtag(&master.tags[pos]);
602 logf("<debug> tagid %02x defines object %d", tag, defineid);
603 masterids[defineid] = 1;
604 } else if(tag == TAGID_PLACEOBJECT2) {
605 char * name = tag_placeobject2_name(&master.tags[pos]);
606 int id = tag_placeobject2_character(&master.tags[pos]);
609 logf("<verbose> tagid %02x places object %d named \"%s\"", tag, id, name);
611 logf("<verbose> tagid %02x places object %d (no name)", tag, id);
613 if ((name && slavename && !strcmp(name,slavename)) ||
614 (!slavename && id==slaveid)) {
617 logf("<notice> Slave file attached to object %d.", id);
620 } else if(tag == TAGID_SHOWFRAME) {
621 if(slaveframe>=0 && frame==slaveframe) {
622 logf("<notice> Slave file attached to frame %d.", frame);
625 } else if(tag == TAGID_FRAMELABEL) {
626 char * name = master.tags[pos].data;
627 if(name && slavename && config.isframe && !strcmp(name, slavename)) {
629 logf("<notice> Slave file attached to frame %d (%s).", frame, name);
633 while(master.tags[pos++].id != 0);
635 if (spriteid<0 && !config.isframe) {
637 if(strcmp(slavename,"!!dummy!!"))
638 logf("<warning> Didn't find anything named %s in file. No substitutions will occur.", slavename);
641 logf("<warning> Didn't find id %d in file. No substitutions will occur.", slaveid);
642 spriteid = get_free_id();
645 swf_relocate (slavedata, slavelength, masterids);
646 read_swf(&slave, slavedata, slavelength);
650 replaceddefine = get_free_id();
654 writer_write(&w, "FWS",3);
655 headlength = (u32*)(writer_getpos(&w) + 1);
656 writeheader(&w, master.header.headerdata, master.header.headerlength);
658 if (config.antistream) {
660 logf("<fatal> Can't combine --antistream and --merge");
662 write_sprite_defines(&w);
663 write_sprite(&w, spriteid, replaceddefine);
664 write_master(&w, spriteid, replaceddefine, FLAGS_WRITEDEFINES);
665 write_master(&w, spriteid, replaceddefine, FLAGS_WRITENONDEFINES);
668 write_master(&w, spriteid, replaceddefine,
669 FLAGS_WRITEDEFINES|FLAGS_WRITENONDEFINES|FLAGS_WRITESLAVE);
671 write_master(&w, spriteid, replaceddefine,
672 FLAGS_WRITEDEFINES|FLAGS_WRITENONDEFINES|FLAGS_WRITESPRITE);
675 tmp32 = (u8*)writer_getpos(&w) - (u8*)newdata; //length
677 PUT32(headlength, tmp32);
679 return newdata; //length
682 uchar * combine(uchar*masterdata, int masterlength, char*_slavename, uchar*slavedata, int slavelength, int*newlength)
684 char master_flash = 0;
685 char slave_flash = 0;
686 slavename = _slavename;
691 if(slavename[0] == '#')
693 slaveid = atoi(&slavename[1]);
698 slaveframe = slaveid;
702 logf("<debug> move x (%d)", config.movex);
703 logf("<debug> move y (%d)", config.movey);
704 logf("<debug> scale x (%f)", config.scalex);
705 logf("<debug> scale y (%f)", config.scaley);
706 logf("<debug> is frame (%d)", config.isframe);
708 memset(masterids, -1, sizeof(masterids));
712 logf("<fatal> the master file is too small (%d bytes)", masterlength);
717 logf("<fatal> the slave file is too small (%d bytes)", slavelength);
720 if(masterdata[2] == 'S' &&
721 masterdata[1] == 'W' &&
722 masterdata[0] == 'F')
724 logf("<notice> the master file is flash (swf) format\n");
728 logf("<notice> the master file is not flash (swf) format!\n");
730 if(slavedata[2] == 'S' &&
731 slavedata[1] == 'W' &&
734 logf("<notice> the slave file is flash (swf) format\n");
738 logf("<notice> the slave file is not flash (swf) format!\n");
740 if(master_flash && slave_flash) {
741 read_swf(&master, masterdata, masterlength);
743 return catcombine(masterdata, masterlength, _slavename, slavedata, slavelength, newlength);
745 return normalcombine(masterdata, masterlength, _slavename, slavedata, slavelength, newlength);