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;
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 if(tag->id == TAGID_PLACEOBJECT)
60 (*(u16*)&tag->data[2]) += add;
61 if(tag->id == TAGID_PLACEOBJECT2)
62 (*(u16*)&tag->data[1]) += add;
63 if(tag->id == TAGID_REMOVEOBJECT)
64 (*(u16*)&tag->data[2]) += add;
65 if(tag->id == TAGID_REMOVEOBJECT2)
66 (*(u16*)&tag->data[0]) += add;
69 /* applies the config move and scale parameters to
70 * a matrix. (If settings would provide a rotation,
71 * this would be a matrix concatenation/multiplication
72 * routine. In this case, it's just element-wise multiplication.
74 void matrix_adjust(struct MATRIX*m)
76 if(config.scalex != 1 || config.scaley != 1)
80 m->a[0][0] = config.scalex;
81 m->a[1][1] = config.scaley;
83 m->a[0][0] *= config.scalex;
84 m->a[1][1] *= config.scaley;
87 m->a[0][1] *= config.scalex;
88 m->a[1][0] *= config.scaley;
90 m->b[0] *= config.scalex;
91 m->b[1] *= config.scaley;
93 /* printf("hasscale: %d\n",m->hasscale);
94 printf("hasrotate: %d\n", m->hasrotate);
95 printf("move: %d %d\n", m->b[0],m->b[1]);
96 printf("rot: %f %f\n",m->a[0][0],m->a[0][1]);
97 printf(" %f %f\n",m->a[1][0],m->a[1][1]);*/
98 m->b[0] += config.movex;
99 m->b[1] += config.movey;
102 void write_changepos(struct swf_tag*tag, struct writer_t*w)
104 if(config.movex || config.movey || config.scalex != 1 || config.scaley != 1)
108 case TAGID_PLACEOBJECT: {
109 struct PlaceObject p;
110 placeobject_init(&p, tag);
111 matrix_adjust(&p.matrix);
112 placeobject_write(&p, w);
115 case TAGID_PLACEOBJECT2: {
116 struct PlaceObject2 p;
117 placeobject2_init(&p, tag);
120 MATRIX_init(&p.matrix);
122 matrix_adjust(&p.matrix);
123 placeobject2_write(&p, w);
127 writer_write(w, tag->fulldata, tag->fulllength);
132 writer_write(w, tag->fulldata, tag->fulllength);
136 void write_sprite_defines(struct writer_t*w)
139 while(slave.tags[pos].id != 0) {
140 struct swf_tag * tag = &slave.tags[pos];
141 if(!is_sprite_tag(tag->id)) {
142 logf("<debug> processing sprite tag %02x", slave.tags[pos].id);
143 if(is_defining_tag(tag->id))
145 logf("<debug> [sprite defs] write tag %02x (%d bytes in body)",
146 tag->id, tag->length);
147 writer_write(w, tag->fulldata, tag->fulllength);
152 {case TAGID_DEFINEFONTINFO:
154 /* define font info is not a defining tag, in that
155 * it doesn't define a new id, but rather extends
156 * an existing one. It also isn't a sprite tag.
157 * Anyway we can't throw it out, so we just pass it
160 writer_write(w, tag->fulldata, tag->fulllength);
163 case TAGID_JPEGTABLES:
164 /* according to the flash specs, there may only
165 be one JPEGTABLES tag per swf. This is maybe
167 writer_write(w, tag->fulldata, tag->fulllength);
169 case TAGID_EXPORTASSETS:
170 logf("<debug> deliberately ignoring EXPORTASSETS tag");
172 case TAGID_ENABLEDEBUGGER:
173 logf("<debug> deliberately ignoring ENABLEDEBUGGER tag");
175 case TAGID_BACKGROUNDCOLOR:
176 logf("<debug> deliberately ignoring BACKGROUNDCOLOR tag");
181 logf("<notice> found tag %d. This is a Generator template, isn't it?", slave.tags[pos].id);
184 logf("<notice> funny tag: %d is neither defining nor sprite", slave.tags[pos].id);
193 void write_sprite(struct writer_t*w, int spriteid, int replaceddefine)
200 // write slave(2) (header)
201 tmp = 0x3f + (TAGID_DEFINESPRITE << 6);
202 writer_write(w, &tmp, 2);
203 tagidpos = (u32*)writer_getpos(w);
204 writer_write(w, &tmp32, 4);
206 startpos = (u8*)writer_getpos(w);
210 logf("<warning> Didn't find anything named %s in file. No substitutions will occur.", slavename);
211 spriteid = get_free_id();
214 logf ("<notice> sprite id is %d", spriteid);
216 writer_write(w, &tmp, 2);
217 tmp = slave.header.count;
218 writer_write(w, &tmp, 2);
221 // write slave(2) (body)
222 tmp = slave.header.count;
223 logf("<debug> %d frames to go",tmp);
226 tmp = 7 + (TAGID_PLACEOBJECT2 << 6);
227 writer_write(w, &tmp, 2);
228 tmp = 2+64; //flags: character + clipaction
229 writer_write(w, &tmp, 1);
231 writer_write(w, &tmp,2);
232 tmp = replaceddefine; //id
233 writer_write(w, &tmp,2);
234 tmp = 65535; //clipdepth
235 writer_write(w, &tmp,2);
239 tmp = 5 + (TAGID_PLACEOBJECT2 << 6);
240 writer_write(w, &tmp, 2);
241 tmp = 2; //flags: character
242 writer_write(w, &tmp, 1);
244 writer_write(w, &tmp,2);
245 tmp = replaceddefine; //id
246 writer_write(w, &tmp,2);
250 struct swf_tag * tag = &slave.tags[pos];
251 if (is_sprite_tag(tag->id)) {
253 changedepth(tag, +1);
254 logf("<debug> [sprite main] write tag %02x (%d bytes in body)",
255 slave.tags[pos].id, slave.tags[pos].length);
256 write_changepos(tag, w);
258 if(tag->id == TAGID_SHOWFRAME)
261 logf("<debug> %d frames to go",tmp);
265 while(slave.tags[pos++].id != TAGID_END);
267 *tagidpos = (u8*)writer_getpos(w) - startpos; // set length of sprite (in header)
268 logf("<verbose> sprite length is %d",*tagidpos);
271 #define FLAGS_WRITEDEFINES 1
272 #define FLAGS_WRITENONDEFINES 2
273 #define FLAGS_WRITESPRITE 4
274 void write_master(struct writer_t*w, int spriteid, int replaceddefine, int flags)
278 if(is_defining_tag(master.tags[pos].id) && (flags&1))
280 logf("<debug> [master] write tag %02x (%d bytes in body)",
281 master.tags[pos].id, master.tags[pos].length);
282 if( getidfromtag(&master.tags[pos]) == spriteid)
286 *(u16*)master.tags[pos].data = replaceddefine;
287 writer_write(w, master.tags[pos].fulldata, master.tags[pos].fulllength);
289 /* don't write this tag */
290 logf("<verbose> replacing tag %d id %d with sprite", master.tags[pos].id
296 write_sprite_defines(w);
297 write_sprite(w, spriteid, replaceddefine);
300 writer_write(w, master.tags[pos].fulldata, master.tags[pos].fulllength);
303 if(!is_defining_tag(master.tags[pos].id) && (flags&2))
305 logf("<debug> [master] write tag %02x (%d bytes in body)",
306 master.tags[pos].id, master.tags[pos].length);
307 writer_write(w, master.tags[pos].fulldata, master.tags[pos].fulllength);
310 while(master.tags[pos++].id != 0);
313 void writeheader(struct writer_t*w, u8*data, int length)
315 if(config.hassizex || config.hassizey || config.framerate)
317 struct flash_header head;
318 swf_init(data-3, length+3);
319 head = swf_read_header();
322 head.boundingBox.x2 = head.boundingBox.x1 + config.sizex;
326 head.boundingBox.y2 = head.boundingBox.y1 + config.sizey;
330 head.rate = config.framerate;
332 swf_write_header(w, &head);
335 writer_write(w, data, length);
338 uchar * combine(uchar*masterdata, int masterlength, char*_slavename, uchar*slavedata, int slavelength, int*newlength)
340 char master_flash = 0;
341 char slave_flash = 0;
342 slavename = _slavename;
344 logf("<debug> move x (%d)", config.movex);
345 logf("<debug> move y (%d)", config.movey);
346 logf("<debug> scale x (%d)", config.scalex);
347 logf("<debug> scale y (%d)", config.scaley);
349 memset(masterids, -1, sizeof(masterids));
353 logf("<fatal> the master file is too small (%d bytes)", masterlength);
358 logf("<fatal> the slave file is too small (%d bytes)", slavelength);
361 if(masterdata[2] == 'S' &&
362 masterdata[1] == 'W' &&
363 masterdata[0] == 'F')
365 logf("<notice> the master file is flash (swf) format\n");
369 logf("<notice> the master file is not flash (swf) format!\n");
371 if(slavedata[2] == 'S' &&
372 slavedata[1] == 'W' &&
375 logf("<notice> the slave file is flash (swf) format\n");
379 logf("<notice> the slave file is not flash (swf) format!\n");
381 if(master_flash && slave_flash)
389 int replaceddefine = -1;
392 read_swf(&master, masterdata, masterlength);
394 length = masterlength + slavelength*2 + 128; // this is a guess, but a good guess.
395 newdata = malloc(length);
396 writer_init(&w, newdata, length);
399 logf("<fatal> Couldn't allocate %d bytes of memory", length);
406 int tag = master.tags[pos].id;
407 if(is_defining_tag(tag)) {
408 int defineid = getidfromtag(&master.tags[pos]);
409 logf("<debug> tagid %02x defines object %d", tag, defineid);
410 masterids[defineid] = 1;
411 } else if(tag == TAGID_PLACEOBJECT2) {
412 char * name = tag_placeobject2_name(&master.tags[pos]);
413 int id = tag_placeobject2_character(&master.tags[pos]);
416 logf("<verbose> tagid %02x places object %d named \"%s\"", tag, id, name);
418 logf("<verbose> tagid %02x places object %d (no name)", tag, id);
420 if (name && !strcmp(name,slavename)) {
423 logf("<notice> Slave file attached to object %d.", id);
428 while(master.tags[pos++].id != 0);
430 swf_relocate (slavedata, slavelength, masterids);
432 read_swf(&slave, slavedata, slavelength);
435 replaceddefine = get_free_id();
439 writer_write(&w, "FWS",3);
440 headlength = (u32*)(writer_getpos(&w) + 1);
441 writeheader(&w, master.header.headerdata, master.header.headerlength);
443 if(config.antistream) {
444 write_sprite_defines(&w);
445 write_sprite(&w, spriteid, replaceddefine);
446 write_master(&w, spriteid, replaceddefine, FLAGS_WRITEDEFINES);
447 write_master(&w, spriteid, replaceddefine, FLAGS_WRITENONDEFINES);
449 write_master(&w, spriteid, replaceddefine,
450 FLAGS_WRITEDEFINES|FLAGS_WRITENONDEFINES|FLAGS_WRITESPRITE);
453 tmp32 = (u8*)writer_getpos(&w) - (u8*)newdata; //length
455 *headlength = tmp32; // set the header to the correct length
457 return newdata; //length