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"
19 static char* slavename = 0;
20 static int slaveid = -1;
21 static int slaveframe = -1;
23 static char* tag_placeobject2_name (struct swf_tag* tag)
25 struct PlaceObject2 plo2;
26 placeobject2_init (&plo2, tag);
30 static u16 tag_placeobject2_character (struct swf_tag* tag)
32 struct PlaceObject2 plo2;
33 placeobject2_init (&plo2, tag);
37 static struct swffile master;
38 static struct swffile slave;
40 static int masterids[65536];
42 static int get_free_id()
47 if(masterids[t] == -1)
56 void changedepth(struct swf_tag*tag, int add)
58 /* fucking big endian byte order */
59 if(tag->id == TAGID_PLACEOBJECT)
60 (*(u16*)&tag->data[2]) =
61 SWAP16(SWAP16(*(u16*)&tag->data[2]) + add);
62 if(tag->id == TAGID_PLACEOBJECT2)
63 (*(u16*)&tag->data[1]) =
64 SWAP16(SWAP16(*(u16*)&tag->data[1]) + add);
65 if(tag->id == TAGID_REMOVEOBJECT)
66 (*(u16*)&tag->data[2]) =
67 SWAP16(SWAP16(*(u16*)&tag->data[2]) + add);
68 if(tag->id == TAGID_REMOVEOBJECT2)
69 (*(u16*)&tag->data[0]) =
70 SWAP16(SWAP16(*(u16*)&tag->data[0]) + add);
73 /* applies the config move and scale parameters to
74 * a matrix. (If settings would provide a rotation,
75 * this would be a matrix concatenation/multiplication
76 * routine. In this case, it's just element-wise multiplication.
78 void matrix_adjust(struct MATRIX*m)
80 if(config.scalex != 1 || config.scaley != 1)
84 m->a[0][0] = config.scalex;
85 m->a[1][1] = config.scaley;
87 m->a[0][0] *= config.scalex;
88 m->a[1][1] *= config.scaley;
91 m->a[0][1] *= config.scalex;
92 m->a[1][0] *= config.scaley;
94 m->b[0] *= config.scalex;
95 m->b[1] *= config.scaley;
97 /* printf("hasscale: %d\n",m->hasscale);
98 printf("hasrotate: %d\n", m->hasrotate);
99 printf("move: %d %d\n", m->b[0],m->b[1]);
100 printf("rot: %f %f\n",m->a[0][0],m->a[0][1]);
101 printf(" %f %f\n",m->a[1][0],m->a[1][1]);*/
102 m->b[0] += config.movex;
103 m->b[1] += config.movey;
106 void write_changepos(struct swf_tag*tag, struct writer_t*w)
108 if(config.movex || config.movey || config.scalex != 1 || config.scaley != 1)
112 case TAGID_PLACEOBJECT: {
113 struct PlaceObject p;
114 placeobject_init(&p, tag);
115 matrix_adjust(&p.matrix);
116 placeobject_write(&p, w);
119 case TAGID_PLACEOBJECT2: {
120 struct PlaceObject2 p;
121 placeobject2_init(&p, tag);
124 MATRIX_init(&p.matrix);
126 matrix_adjust(&p.matrix);
127 placeobject2_write(&p, w);
131 writer_write(w, tag->fulldata, tag->fulllength);
136 writer_write(w, tag->fulldata, tag->fulllength);
140 void write_sprite_defines(struct writer_t*w)
143 while(slave.tags[pos].id != 0) {
144 struct swf_tag * tag = &slave.tags[pos];
145 if(!is_sprite_tag(tag->id)) {
146 logf("<debug> processing sprite tag %02x", slave.tags[pos].id);
147 if(is_defining_tag(tag->id))
149 logf("<debug> [sprite defs] write tag %02x (%d bytes in body)",
150 tag->id, tag->length);
151 writer_write(w, tag->fulldata, tag->fulllength);
156 {case TAGID_DEFINEFONTINFO:
158 /* define font info is not a defining tag, in that
159 * it doesn't define a new id, but rather extends
160 * an existing one. It also isn't a sprite tag.
161 * Anyway we can't throw it out, so we just pass it
164 writer_write(w, tag->fulldata, tag->fulllength);
167 case TAGID_JPEGTABLES:
168 /* according to the flash specs, there may only
169 be one JPEGTABLES tag per swf. This is maybe
171 writer_write(w, tag->fulldata, tag->fulllength);
173 case TAGID_EXPORTASSETS:
174 logf("<debug> deliberately ignoring EXPORTASSETS tag");
176 case TAGID_ENABLEDEBUGGER:
177 logf("<debug> deliberately ignoring ENABLEDEBUGGER tag");
179 case TAGID_BACKGROUNDCOLOR:
180 logf("<debug> deliberately ignoring BACKGROUNDCOLOR tag");
185 logf("<notice> found tag %d. This is a Generator template, isn't it?", slave.tags[pos].id);
188 logf("<notice> funny tag: %d is neither defining nor sprite", slave.tags[pos].id);
196 void write_sprite(struct writer_t*w, int spriteid, int replaceddefine)
203 // write slave(2) (header)
204 tmp = SWAP16(0x3f + (TAGID_DEFINESPRITE << 6));
205 writer_write(w, &tmp, 2);
206 tagidpos = (u32*)writer_getpos(w);
207 writer_write(w, &tmp32, 4);
209 startpos = (u8*)writer_getpos(w);
211 logf ("<notice> sprite id is %d", spriteid);
213 writer_write(w, &tmp, 2);
214 tmp = slave.header.count;
215 writer_write(w, &tmp, 2);
218 // write slave(2) (body)
219 tmp = slave.header.count;
220 logf("<debug> %d frames to go",tmp);
223 tmp = SWAP16(7 + (TAGID_PLACEOBJECT2 << 6));
224 writer_write(w, &tmp, 2);
225 tmp = SWAP16(2+64); //flags: character + clipaction
226 writer_write(w, &tmp, 1);
227 tmp = SWAP16(0); //depth
228 writer_write(w, &tmp,2);
229 tmp = SWAP16(replaceddefine); //id
230 writer_write(w, &tmp,2);
231 tmp = SWAP16(65535); //clipdepth
232 writer_write(w, &tmp,2);
235 if(config.overlay && !config.isframe) {
236 tmp = SWAP16(5 + (TAGID_PLACEOBJECT2 << 6));
237 writer_write(w, &tmp, 2);
238 tmp = SWAP16(2); //flags: character
239 writer_write(w, &tmp, 1);
240 tmp = SWAP16(0); //depth
241 writer_write(w, &tmp,2);
242 tmp = SWAP16(replaceddefine); //id
243 writer_write(w, &tmp,2);
247 struct swf_tag * tag = &slave.tags[pos];
248 if (is_sprite_tag(tag->id)) {
250 changedepth(tag, +1);
251 logf("<debug> [sprite main] write tag %02x (%d bytes in body)",
252 slave.tags[pos].id, slave.tags[pos].length);
253 write_changepos(tag, w);
255 if(tag->id == TAGID_SHOWFRAME)
258 logf("<debug> %d frames to go",tmp);
262 while(slave.tags[pos++].id != TAGID_END);
264 *tagidpos = SWAP32((u8*)writer_getpos(w) - startpos); // set length of sprite (in header)
265 logf("<verbose> sprite length is %d",SWAP32(*tagidpos));
268 static char tag_ok_for_slave(int id)
270 if(id == TAGID_BACKGROUNDCOLOR)
275 #define FLAGS_WRITEDEFINES 1
276 #define FLAGS_WRITENONDEFINES 2
277 #define FLAGS_WRITESPRITE 4
278 #define FLAGS_WRITESLAVE 8
279 void write_master(struct writer_t*w, int spriteid, int replaceddefine, int flags)
286 int slavewritten = 0;
287 while(master.tags[pos].id != 0)
289 if(master.tags[pos].id == TAGID_SHOWFRAME && outputslave)
291 while(slave.tags[spos].id) {
292 if(slave.tags[spos].id == TAGID_SHOWFRAME) {
297 if(tag_ok_for_slave(slave.tags[spos].id))
298 writer_write(w, slave.tags[spos].fulldata, slave.tags[spos].fulllength);
304 if(is_defining_tag(master.tags[pos].id) && (flags&FLAGS_WRITEDEFINES))
306 logf("<debug> [master] write tag %02x (%d bytes in body)",
307 master.tags[pos].id, master.tags[pos].length);
308 if(getidfromtag(&master.tags[pos]) == spriteid && !config.isframe)
312 *(u16*)master.tags[pos].data = SWAP16(replaceddefine);
313 writer_write(w, master.tags[pos].fulldata, master.tags[pos].fulllength);
315 /* don't write this tag */
316 logf("<verbose> replacing tag %d id %d with sprite", master.tags[pos].id
320 if(flags&FLAGS_WRITESPRITE)
322 write_sprite_defines(w);
323 write_sprite(w, spriteid, replaceddefine);
325 if(flags&FLAGS_WRITESLAVE)
330 writer_write(w, master.tags[pos].fulldata, master.tags[pos].fulllength);
333 if(frame == slaveframe)
335 if(flags&FLAGS_WRITESLAVE) {
339 if((flags&FLAGS_WRITESPRITE) && !slavewritten)
341 int id = get_free_id();
345 logf("<fatal> Can't combine --clip and --frame");
347 *(u16*)&data[0] = SWAP16((u16)(TAGID_PLACEOBJECT2<<6) + 5);
348 *(u8*)&data[2]= SWAP16(2); //flags: id
349 *(u16*)&data[3]= SWAP16(depth); // depth
350 *(u16*)&data[5]= SWAP16(id);
351 write_sprite_defines(w);
352 write_sprite(w, id, -1);
353 writer_write(w,data,7);
357 if(!is_defining_tag(master.tags[pos].id) && (flags&FLAGS_WRITENONDEFINES))
360 switch(master.tags[pos].id) {
361 case TAGID_PLACEOBJECT:
362 case TAGID_PLACEOBJECT2:
363 if(frame == slaveframe && !config.overlay)
365 case TAGID_REMOVEOBJECT:
366 // case TAGID_REMOVEOBJECT2:
367 /* place/removetags for the object we replaced
368 should be discarded, too, as the object to insert
371 if(spriteid>=0 && getidfromtag(&master.tags[pos]) == spriteid &&
372 !config.isframe && config.merge)
377 logf("<debug> [master] write tag %02x (%d bytes in body)",
378 master.tags[pos].id, master.tags[pos].length);
379 writer_write(w, master.tags[pos].fulldata, master.tags[pos].fulllength);
386 while(slave.tags[spos].id)
388 if(tag_ok_for_slave(slave.tags[spos].id))
389 writer_write(w, slave.tags[spos].fulldata, slave.tags[spos].fulllength);
392 if(!slavewritten && config.isframe && (flags&(FLAGS_WRITESLAVE|FLAGS_WRITESPRITE)))
394 logf("<warning> Frame %d doesn't exist in file. No substitution will occur",
398 writer_write(w, master.tags[pos].fulldata, master.tags[pos].fulllength);
401 void writeheader(struct writer_t*w, u8*data, int length)
403 if(config.hassizex || config.hassizey || config.framerate)
405 struct flash_header head;
406 struct reader_t reader;
407 swf_init(&reader, data-3, length+3);
408 head = swf_read_header(&reader);
411 head.boundingBox.x2 = head.boundingBox.x1 + config.sizex;
415 head.boundingBox.y2 = head.boundingBox.y1 + config.sizey;
419 head.rate = config.framerate;
421 swf_write_header(w, &head);
424 writer_write(w, data, length);
427 uchar * catcombine(uchar*masterdata, int masterlength, char*_slavename, uchar*slavedata, int slavelength, int*newlength)
432 int length = masterlength*2 + slavelength;
436 uchar*newdata = malloc(length);
438 logf("<fatal> Couldn't allocate %d bytes of memory", length);
442 logf("<fatal> Can't combine --cat and --frame");
445 writer_init(&w, newdata, length);
448 int tag = master.tags[pos].id;
449 if(is_defining_tag(tag)) {
450 int defineid = getidfromtag(&master.tags[pos]);
451 logf("<debug> tagid %02x defines object %d", tag, defineid);
452 masterids[defineid] = 1;
455 while(master.tags[pos++].id != 0);
457 swf_relocate (slavedata, slavelength, masterids);
458 read_swf(&slave, slavedata, slavelength);
460 writer_write(&w, "FWS",3);
461 headlength = (u32*)(writer_getpos(&w) + 1);
462 writeheader(&w, master.header.headerdata, master.header.headerlength);
464 depths = malloc(65536);
466 logf("<fatal> Couldn't allocate %d bytes of memory", 65536);
469 memset(depths, 0, 65536);
474 logf("<debug> [master] write tag %02x (%d bytes in body)",
475 master.tags[pos].id, master.tags[pos].length);
476 switch(master.tags[pos].id) {
477 case TAGID_PLACEOBJECT2:
479 case TAGID_PLACEOBJECT: {
481 reader_init (&r, master.tags[pos].data, master.tags[pos].length);
484 depth = reader_readu16(&r);
488 case TAGID_REMOVEOBJECT: {
490 reader_init (&r, master.tags[pos].data, master.tags[pos].length);
492 depths[reader_readu16(&r)] = 0;
495 case TAGID_REMOVEOBJECT2: {
497 reader_init (&r, master.tags[pos].data, master.tags[pos].length);
498 depths[reader_readu16(&r)] = 0;
502 if(master.tags[pos].id != 0)
503 writer_write(&w, master.tags[pos].fulldata, master.tags[pos].fulllength);
505 while(master.tags[pos++].id != 0);
512 *(u16*)(&data[0]) = SWAP16((TAGID_REMOVEOBJECT2<<6) + 2);
513 *(u16*)(&data[2]) = SWAP16(t);
514 writer_write(&w, data, 4);
520 logf("<debug> [slave] write tag %02x (%d bytes in body)",
521 slave.tags[pos].id, slave.tags[pos].length);
522 writer_write(&w, slave.tags[pos].fulldata, slave.tags[pos].fulllength);
524 while(slave.tags[pos++].id != 0);
526 tmp32 = (u8*)writer_getpos(&w) - (u8*)newdata; //length
528 *headlength = SWAP32(tmp32); // set the header to the correct length
530 return newdata; //length
533 uchar * normalcombine(uchar*masterdata, int masterlength, char*_slavename, uchar*slavedata, int slavelength, int*newlength)
541 int replaceddefine = -1;
546 length = masterlength + slavelength*2 + 128; // this is a guess, but a good guess.
547 newdata = malloc(length);
548 writer_init(&w, newdata, length);
551 logf("<fatal> Couldn't allocate %d bytes of memory", length);
558 int tag = master.tags[pos].id;
559 if(is_defining_tag(tag)) {
560 int defineid = getidfromtag(&master.tags[pos]);
561 logf("<debug> tagid %02x defines object %d", tag, defineid);
562 masterids[defineid] = 1;
563 } else if(tag == TAGID_PLACEOBJECT2) {
564 char * name = tag_placeobject2_name(&master.tags[pos]);
565 int id = tag_placeobject2_character(&master.tags[pos]);
568 logf("<verbose> tagid %02x places object %d named \"%s\"", tag, id, name);
570 logf("<verbose> tagid %02x places object %d (no name)", tag, id);
572 if ((name && slavename && !strcmp(name,slavename)) ||
573 (!slavename && id==slaveid)) {
576 logf("<notice> Slave file attached to object %d.", id);
579 } else if(tag == TAGID_SHOWFRAME) {
580 if(slaveframe>=0 && frame==slaveframe) {
581 logf("<notice> Slave file attached to frame %d.", frame);
584 } else if(tag == TAGID_FRAMELABEL) {
585 char * name = master.tags[pos].data;
586 if(name && slavename && config.isframe && !strcmp(name, slavename)) {
588 logf("<notice> Slave file attached to frame %d (%s).", frame, name);
592 while(master.tags[pos++].id != 0);
594 if (spriteid<0 && !config.isframe) {
596 if(strcmp(slavename,"!!dummy!!"))
597 logf("<warning> Didn't find anything named %s in file. No substitutions will occur.", slavename);
600 logf("<warning> Didn't find id %d in file. No substitutions will occur.", slaveid);
601 spriteid = get_free_id();
604 swf_relocate (slavedata, slavelength, masterids);
606 read_swf(&slave, slavedata, slavelength);
609 replaceddefine = get_free_id();
613 writer_write(&w, "FWS",3);
614 headlength = (u32*)(writer_getpos(&w) + 1);
615 writeheader(&w, master.header.headerdata, master.header.headerlength);
617 if (config.antistream) {
619 logf("<fatal> Can't combine --antistream and --merge");
621 write_sprite_defines(&w);
622 write_sprite(&w, spriteid, replaceddefine);
623 write_master(&w, spriteid, replaceddefine, FLAGS_WRITEDEFINES);
624 write_master(&w, spriteid, replaceddefine, FLAGS_WRITENONDEFINES);
627 write_master(&w, spriteid, replaceddefine,
628 FLAGS_WRITEDEFINES|FLAGS_WRITENONDEFINES|FLAGS_WRITESLAVE);
630 write_master(&w, spriteid, replaceddefine,
631 FLAGS_WRITEDEFINES|FLAGS_WRITENONDEFINES|FLAGS_WRITESPRITE);
634 tmp32 = (u8*)writer_getpos(&w) - (u8*)newdata; //length
636 *headlength = SWAP32(tmp32); // set the header to the correct length
638 return newdata; //length
641 uchar * combine(uchar*masterdata, int masterlength, char*_slavename, uchar*slavedata, int slavelength, int*newlength)
643 char master_flash = 0;
644 char slave_flash = 0;
645 slavename = _slavename;
650 if(slavename[0] == '#')
652 slaveid = atoi(&slavename[1]);
657 slaveframe = slaveid;
661 logf("<debug> move x (%d)", config.movex);
662 logf("<debug> move y (%d)", config.movey);
663 logf("<debug> scale x (%d)", config.scalex);
664 logf("<debug> scale y (%d)", config.scaley);
665 logf("<debug> is frame (%d)", config.isframe);
667 memset(masterids, -1, sizeof(masterids));
671 logf("<fatal> the master file is too small (%d bytes)", masterlength);
676 logf("<fatal> the slave file is too small (%d bytes)", slavelength);
679 if(masterdata[2] == 'S' &&
680 masterdata[1] == 'W' &&
681 masterdata[0] == 'F')
683 logf("<notice> the master file is flash (swf) format\n");
687 logf("<notice> the master file is not flash (swf) format!\n");
689 if(slavedata[2] == 'S' &&
690 slavedata[1] == 'W' &&
693 logf("<notice> the slave file is flash (swf) format\n");
697 logf("<notice> the slave file is not flash (swf) format!\n");
699 if(master_flash && slave_flash) {
700 read_swf(&master, masterdata, masterlength);
702 return catcombine(masterdata, masterlength, _slavename, slavedata, slavelength, newlength);
704 return normalcombine(masterdata, masterlength, _slavename, slavedata, slavelength, newlength);