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 * combine(uchar*masterdata, int masterlength, char*_slavename, uchar*slavedata, int slavelength, int*newlength)
335 char master_flash = 0;
336 char slave_flash = 0;
337 slavename = _slavename;
338 if(slavename[0] == '#')
340 slaveid = atoi(&slavename[1]);
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 && slavename && !strcmp(name,slavename)) ||
421 (!slavename && id==slaveid)) {
424 logf("<notice> Slave file attached to object %d.", id);
429 while(master.tags[pos++].id != 0);
434 if(strcmp(slavename,"!!dummy!!"))
435 logf("<warning> Didn't find anything named %s in file. No substitutions will occur.", slavename);
438 logf("<warning> Didn't find id %d in file. No substitutions will occur.", slaveid);
439 spriteid = get_free_id();
442 swf_relocate (slavedata, slavelength, masterids);
444 read_swf(&slave, slavedata, slavelength);
447 replaceddefine = get_free_id();
451 writer_write(&w, "FWS",3);
452 headlength = (u32*)(writer_getpos(&w) + 1);
453 writeheader(&w, master.header.headerdata, master.header.headerlength);
455 if(config.antistream) {
456 write_sprite_defines(&w);
457 write_sprite(&w, spriteid, replaceddefine);
458 write_master(&w, spriteid, replaceddefine, FLAGS_WRITEDEFINES);
459 write_master(&w, spriteid, replaceddefine, FLAGS_WRITENONDEFINES);
461 write_master(&w, spriteid, replaceddefine,
462 FLAGS_WRITEDEFINES|FLAGS_WRITENONDEFINES|FLAGS_WRITESPRITE);
465 tmp32 = (u8*)writer_getpos(&w) - (u8*)newdata; //length
467 *headlength = tmp32; // set the header to the correct length
469 return newdata; //length