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;
25 static char* tag_placeobject2_name (struct swf_tag* tag)
27 struct PlaceObject2 plo2;
28 placeobject2_init (&plo2, tag);
32 static u16 tag_placeobject2_character (struct swf_tag* tag)
34 struct PlaceObject2 plo2;
35 placeobject2_init (&plo2, tag);
39 static struct swffile master;
40 static struct swffile slave;
42 static int masterids[65536];
44 static int get_free_id()
49 if(masterids[t] == -1)
58 void changedepth(struct swf_tag*tag, int add)
60 if(tag->id == TAGID_PLACEOBJECT)
61 (*(u16*)&tag->data[2]) += add;
62 if(tag->id == TAGID_PLACEOBJECT2)
63 (*(u16*)&tag->data[1]) += add;
64 if(tag->id == TAGID_REMOVEOBJECT)
65 (*(u16*)&tag->data[2]) += add;
66 if(tag->id == TAGID_REMOVEOBJECT2)
67 (*(u16*)&tag->data[0]) += add;
70 /* applies the config move and scale parameters to
71 * a matrix. (If settings would provide a rotation,
72 * this would be a matrix concatenation/multiplication
73 * routine. In this case, it's just element-wise multiplication.
75 void matrix_adjust(struct MATRIX*m)
77 if(config.scalex != 1 || config.scaley != 1)
81 m->a[0][0] = config.scalex;
82 m->a[1][1] = config.scaley;
84 m->a[0][0] *= config.scalex;
85 m->a[1][1] *= config.scaley;
88 m->a[0][1] *= config.scalex;
89 m->a[1][0] *= config.scaley;
91 m->b[0] *= config.scalex;
92 m->b[1] *= config.scaley;
94 /* printf("hasscale: %d\n",m->hasscale);
95 printf("hasrotate: %d\n", m->hasrotate);
96 printf("move: %d %d\n", m->b[0],m->b[1]);
97 printf("rot: %f %f\n",m->a[0][0],m->a[0][1]);
98 printf(" %f %f\n",m->a[1][0],m->a[1][1]);*/
99 m->b[0] += config.movex;
100 m->b[1] += config.movey;
103 void write_changepos(struct swf_tag*tag, struct writer_t*w)
105 if(config.movex || config.movey || config.scalex != 1 || config.scaley != 1)
109 case TAGID_PLACEOBJECT: {
110 struct PlaceObject p;
111 placeobject_init(&p, tag);
112 matrix_adjust(&p.matrix);
113 placeobject_write(&p, w);
116 case TAGID_PLACEOBJECT2: {
117 struct PlaceObject2 p;
118 placeobject2_init(&p, tag);
121 MATRIX_init(&p.matrix);
123 matrix_adjust(&p.matrix);
124 placeobject2_write(&p, w);
128 writer_write(w, tag->fulldata, tag->fulllength);
133 writer_write(w, tag->fulldata, tag->fulllength);
137 void write_sprite_defines(struct writer_t*w)
140 while(slave.tags[pos].id != 0) {
141 struct swf_tag * tag = &slave.tags[pos];
142 if(!is_sprite_tag(tag->id)) {
143 logf("<debug> processing sprite tag %02x", slave.tags[pos].id);
144 if(is_defining_tag(tag->id))
146 logf("<debug> [sprite defs] write tag %02x (%d bytes in body)",
147 tag->id, tag->length);
148 writer_write(w, tag->fulldata, tag->fulllength);
153 {case TAGID_DEFINEFONTINFO:
155 /* define font info is not a defining tag, in that
156 * it doesn't define a new id, but rather extends
157 * an existing one. It also isn't a sprite tag.
158 * Anyway we can't throw it out, so we just pass it
161 writer_write(w, tag->fulldata, tag->fulllength);
164 case TAGID_JPEGTABLES:
165 /* according to the flash specs, there may only
166 be one JPEGTABLES tag per swf. This is maybe
168 writer_write(w, tag->fulldata, tag->fulllength);
170 case TAGID_EXPORTASSETS:
171 logf("<debug> deliberately ignoring EXPORTASSETS tag");
173 case TAGID_ENABLEDEBUGGER:
174 logf("<debug> deliberately ignoring ENABLEDEBUGGER tag");
176 case TAGID_BACKGROUNDCOLOR:
177 logf("<debug> deliberately ignoring BACKGROUNDCOLOR tag");
182 logf("<notice> found tag %d. This is a Generator template, isn't it?", slave.tags[pos].id);
185 logf("<notice> funny tag: %d is neither defining nor sprite", slave.tags[pos].id);
194 void write_sprite(struct writer_t*w, int spriteid, int replaceddefine)
201 // write slave(2) (header)
202 tmp = 0x3f + (TAGID_DEFINESPRITE << 6);
203 writer_write(w, &tmp, 2);
204 tagidpos = (u32*)writer_getpos(w);
205 writer_write(w, &tmp32, 4);
207 startpos = (u8*)writer_getpos(w);
209 logf ("<notice> sprite id is %d", spriteid);
211 writer_write(w, &tmp, 2);
212 tmp = slave.header.count;
213 writer_write(w, &tmp, 2);
216 // write slave(2) (body)
217 tmp = slave.header.count;
218 logf("<debug> %d frames to go",tmp);
221 tmp = 7 + (TAGID_PLACEOBJECT2 << 6);
222 writer_write(w, &tmp, 2);
223 tmp = 2+64; //flags: character + clipaction
224 writer_write(w, &tmp, 1);
226 writer_write(w, &tmp,2);
227 tmp = replaceddefine; //id
228 writer_write(w, &tmp,2);
229 tmp = 65535; //clipdepth
230 writer_write(w, &tmp,2);
234 tmp = 5 + (TAGID_PLACEOBJECT2 << 6);
235 writer_write(w, &tmp, 2);
236 tmp = 2; //flags: character
237 writer_write(w, &tmp, 1);
239 writer_write(w, &tmp,2);
240 tmp = replaceddefine; //id
241 writer_write(w, &tmp,2);
245 struct swf_tag * tag = &slave.tags[pos];
246 if (is_sprite_tag(tag->id)) {
248 changedepth(tag, +1);
249 logf("<debug> [sprite main] write tag %02x (%d bytes in body)",
250 slave.tags[pos].id, slave.tags[pos].length);
251 write_changepos(tag, w);
253 if(tag->id == TAGID_SHOWFRAME)
256 logf("<debug> %d frames to go",tmp);
260 while(slave.tags[pos++].id != TAGID_END);
262 *tagidpos = (u8*)writer_getpos(w) - startpos; // set length of sprite (in header)
263 logf("<verbose> sprite length is %d",*tagidpos);
266 #define FLAGS_WRITEDEFINES 1
267 #define FLAGS_WRITENONDEFINES 2
268 #define FLAGS_WRITESPRITE 4
269 void write_master(struct writer_t*w, int spriteid, int replaceddefine, int flags)
273 if(is_defining_tag(master.tags[pos].id) && (flags&1))
275 logf("<debug> [master] write tag %02x (%d bytes in body)",
276 master.tags[pos].id, master.tags[pos].length);
277 if( getidfromtag(&master.tags[pos]) == spriteid)
281 *(u16*)master.tags[pos].data = replaceddefine;
282 writer_write(w, master.tags[pos].fulldata, master.tags[pos].fulllength);
284 /* don't write this tag */
285 logf("<verbose> replacing tag %d id %d with sprite", master.tags[pos].id
291 write_sprite_defines(w);
292 write_sprite(w, spriteid, replaceddefine);
295 writer_write(w, master.tags[pos].fulldata, master.tags[pos].fulllength);
298 if(!is_defining_tag(master.tags[pos].id) && (flags&2))
300 logf("<debug> [master] write tag %02x (%d bytes in body)",
301 master.tags[pos].id, master.tags[pos].length);
302 writer_write(w, master.tags[pos].fulldata, master.tags[pos].fulllength);
305 while(master.tags[pos++].id != 0);
308 void writeheader(struct writer_t*w, u8*data, int length)
310 if(config.hassizex || config.hassizey || config.framerate)
312 struct flash_header head;
313 swf_init(data-3, length+3);
314 head = swf_read_header();
317 head.boundingBox.x2 = head.boundingBox.x1 + config.sizex;
321 head.boundingBox.y2 = head.boundingBox.y1 + config.sizey;
325 head.rate = config.framerate;
327 swf_write_header(w, &head);
330 writer_write(w, data, length);
333 uchar * catcombine(uchar*masterdata, int masterlength, char*_slavename, uchar*slavedata, int slavelength, int*newlength)
338 int length = masterlength + slavelength;
340 uchar*newdata = malloc(length);
342 logf("<fatal> Couldn't allocate %d bytes of memory", length);
345 writer_init(&w, newdata, length);
348 int tag = master.tags[pos].id;
349 if(is_defining_tag(tag)) {
350 int defineid = getidfromtag(&master.tags[pos]);
351 logf("<debug> tagid %02x defines object %d", tag, defineid);
352 masterids[defineid] = 1;
355 while(master.tags[pos++].id != 0);
357 swf_relocate (slavedata, slavelength, masterids);
358 read_swf(&slave, slavedata, slavelength);
360 writer_write(&w, "FWS",3);
361 headlength = (u32*)(writer_getpos(&w) + 1);
362 writeheader(&w, master.header.headerdata, master.header.headerlength);
366 logf("<debug> [master] write tag %02x (%d bytes in body)",
367 master.tags[pos].id, master.tags[pos].length);
368 if(master.tags[pos].id != 0)
369 writer_write(&w, master.tags[pos].fulldata, master.tags[pos].fulllength);
371 while(master.tags[pos++].id != 0);
375 logf("<debug> [slave] write tag %02x (%d bytes in body)",
376 slave.tags[pos].id, slave.tags[pos].length);
377 writer_write(&w, slave.tags[pos].fulldata, slave.tags[pos].fulllength);
379 while(slave.tags[pos++].id != 0);
381 tmp32 = (u8*)writer_getpos(&w) - (u8*)newdata; //length
383 *headlength = tmp32; // set the header to the correct length
385 return newdata; //length
388 uchar * normalcombine(uchar*masterdata, int masterlength, char*_slavename, uchar*slavedata, int slavelength, int*newlength)
396 int replaceddefine = -1;
399 length = masterlength + slavelength*2 + 128; // this is a guess, but a good guess.
400 newdata = malloc(length);
401 writer_init(&w, newdata, length);
404 logf("<fatal> Couldn't allocate %d bytes of memory", length);
411 int tag = master.tags[pos].id;
412 if(is_defining_tag(tag)) {
413 int defineid = getidfromtag(&master.tags[pos]);
414 logf("<debug> tagid %02x defines object %d", tag, defineid);
415 masterids[defineid] = 1;
416 } else if(tag == TAGID_PLACEOBJECT2) {
417 char * name = tag_placeobject2_name(&master.tags[pos]);
418 int id = tag_placeobject2_character(&master.tags[pos]);
421 logf("<verbose> tagid %02x places object %d named \"%s\"", tag, id, name);
423 logf("<verbose> tagid %02x places object %d (no name)", tag, id);
425 if ((name && slavename && !strcmp(name,slavename)) ||
426 (!slavename && id==slaveid)) {
429 logf("<notice> Slave file attached to object %d.", id);
434 while(master.tags[pos++].id != 0);
439 if(strcmp(slavename,"!!dummy!!"))
440 logf("<warning> Didn't find anything named %s in file. No substitutions will occur.", slavename);
443 logf("<warning> Didn't find id %d in file. No substitutions will occur.", slaveid);
444 spriteid = get_free_id();
447 swf_relocate (slavedata, slavelength, masterids);
449 read_swf(&slave, slavedata, slavelength);
452 replaceddefine = get_free_id();
456 writer_write(&w, "FWS",3);
457 headlength = (u32*)(writer_getpos(&w) + 1);
458 writeheader(&w, master.header.headerdata, master.header.headerlength);
460 if(config.antistream) {
461 write_sprite_defines(&w);
462 write_sprite(&w, spriteid, replaceddefine);
463 write_master(&w, spriteid, replaceddefine, FLAGS_WRITEDEFINES);
464 write_master(&w, spriteid, replaceddefine, FLAGS_WRITENONDEFINES);
466 write_master(&w, spriteid, replaceddefine,
467 FLAGS_WRITEDEFINES|FLAGS_WRITENONDEFINES|FLAGS_WRITESPRITE);
470 tmp32 = (u8*)writer_getpos(&w) - (u8*)newdata; //length
472 *headlength = tmp32; // set the header to the correct length
474 return newdata; //length
477 uchar * combine(uchar*masterdata, int masterlength, char*_slavename, uchar*slavedata, int slavelength, int*newlength)
479 char master_flash = 0;
480 char slave_flash = 0;
481 slavename = _slavename;
482 if(slavename[0] == '#')
484 slaveid = atoi(&slavename[1]);
488 logf("<debug> move x (%d)", config.movex);
489 logf("<debug> move y (%d)", config.movey);
490 logf("<debug> scale x (%d)", config.scalex);
491 logf("<debug> scale y (%d)", config.scaley);
493 memset(masterids, -1, sizeof(masterids));
497 logf("<fatal> the master file is too small (%d bytes)", masterlength);
502 logf("<fatal> the slave file is too small (%d bytes)", slavelength);
505 if(masterdata[2] == 'S' &&
506 masterdata[1] == 'W' &&
507 masterdata[0] == 'F')
509 logf("<notice> the master file is flash (swf) format\n");
513 logf("<notice> the master file is not flash (swf) format!\n");
515 if(slavedata[2] == 'S' &&
516 slavedata[1] == 'W' &&
519 logf("<notice> the slave file is flash (swf) format\n");
523 logf("<notice> the slave file is not flash (swf) format!\n");
525 if(master_flash && slave_flash) {
526 read_swf(&master, masterdata, masterlength);
528 return catcombine(masterdata, masterlength, _slavename, slavedata, slavelength, newlength);
530 return normalcombine(masterdata, masterlength, _slavename, slavedata, slavelength, newlength);