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* tag_placeobject2_name (struct swf_tag* tag)
24 struct PlaceObject2 plo2;
25 placeobject2_init (&plo2, tag);
29 static u16 tag_placeobject2_character (struct swf_tag* tag)
31 struct PlaceObject2 plo2;
32 placeobject2_init (&plo2, tag);
36 static struct swffile master;
37 static struct swffile slave;
39 static int masterids[65536];
41 static int get_free_id()
46 if(masterids[t] == -1)
55 void changedepth(struct swf_tag*tag, int add)
57 if(tag->id == TAGID_PLACEOBJECT)
58 (*(u16*)&tag->data[2]) += add;
59 if(tag->id == TAGID_PLACEOBJECT2)
60 (*(u16*)&tag->data[1]) += add;
61 if(tag->id == TAGID_REMOVEOBJECT)
62 (*(u16*)&tag->data[2]) += add;
63 if(tag->id == TAGID_REMOVEOBJECT2)
64 (*(u16*)&tag->data[0]) += add;
67 /* applies the config move and scale parameters to
68 * a matrix. (If settings would provide a rotation,
69 * this would be a matrix concatenation/multiplication
70 * routine. In this case, it's just element-wise multiplication.
72 void matrix_adjust(struct MATRIX*m)
74 if(config.scalex != 1 || config.scaley != 1)
78 m->a[0][0] = config.scalex;
79 m->a[1][1] = config.scaley;
81 m->a[0][0] *= config.scalex;
82 m->a[1][1] *= config.scaley;
85 m->a[0][1] *= config.scalex;
86 m->a[1][0] *= config.scaley;
88 m->b[0] *= config.scalex;
89 m->b[1] *= config.scaley;
91 /* printf("hasscale: %d\n",m->hasscale);
92 printf("hasrotate: %d\n", m->hasrotate);
93 printf("move: %d %d\n", m->b[0],m->b[1]);
94 printf("rot: %f %f\n",m->a[0][0],m->a[0][1]);
95 printf(" %f %f\n",m->a[1][0],m->a[1][1]);*/
96 m->b[0] += config.movex;
97 m->b[1] += config.movey;
100 void write_changepos(struct swf_tag*tag, struct writer_t*w)
102 if(config.movex || config.movey || config.scalex != 1 || config.scaley != 1)
106 case TAGID_PLACEOBJECT: {
107 struct PlaceObject p;
108 placeobject_init(&p, tag);
109 matrix_adjust(&p.matrix);
110 placeobject_write(&p, w);
113 case TAGID_PLACEOBJECT2: {
114 struct PlaceObject2 p;
115 placeobject2_init(&p, tag);
118 MATRIX_init(&p.matrix);
120 matrix_adjust(&p.matrix);
121 placeobject2_write(&p, w);
125 writer_write(w, tag->fulldata, tag->fulllength);
130 writer_write(w, tag->fulldata, tag->fulllength);
134 uchar * combine(uchar*masterdata, int masterlength, char*slavename, uchar*slavedata, int slavelength, int*newlength)
136 char master_flash = 0;
137 char slave_flash = 0;
139 logf("<debug> move x (%d)", config.movex);
140 logf("<debug> move y (%d)", config.movey);
141 logf("<debug> scale x (%d)", config.scalex);
142 logf("<debug> scale y (%d)", config.scaley);
144 memset(masterids, -1, sizeof(masterids));
148 logf("<fatal> the master file is too small (%d bytes)", masterlength);
153 logf("<fatal> the slave file is too small (%d bytes)", slavelength);
156 if(masterdata[2] == 'S' &&
157 masterdata[1] == 'W' &&
158 masterdata[0] == 'F')
160 logf("<notice> the master file is flash (swf) format\n");
163 if(slavedata[2] == 'S' &&
164 slavedata[1] == 'W' &&
167 logf("<notice> the slave file is flash (swf) format\n");
171 if(master_flash && slave_flash)
182 int replaceddefine = -1;
185 read_swf(&master, masterdata, masterlength);
187 length = masterlength + slavelength*2 + 128; // this is a guess, but a good guess.
188 newdata = malloc(length);
189 writer_init(&w, newdata, length);
192 logf("<fatal> Couldn't allocate %d bytes of memory", length);
199 int tag = master.tags[pos].id;
200 if(is_defining_tag(tag)) {
201 int defineid = getidfromtag(&master.tags[pos]);
202 logf("<debug> tagid %02x defines object %d", tag, defineid);
203 masterids[defineid] = 1;
204 } else if(tag == TAGID_PLACEOBJECT2) {
205 char * name = tag_placeobject2_name(&master.tags[pos]);
206 int id = tag_placeobject2_character(&master.tags[pos]);
209 logf("<verbose> tagid %02x places object %d named \"%s\"", tag, id, name);
211 logf("<verbose> tagid %02x places object %d (no name)", tag, id);
213 if (name && !strcmp(name,slavename)) {
216 logf("<notice> Slave file attached to object %d.", id);
221 while(master.tags[pos++].id != 0);
223 swf_relocate (slavedata, slavelength, masterids);
225 read_swf(&slave, slavedata, slavelength);
229 writer_write(&w, "FWS",3);
230 headlength = (u32*)(writer_getpos(&w) + 1);
231 writer_write(&w, master.header.headerdata, master.header.headerlength);
236 while(slave.tags[pos].id != 0) {
237 struct swf_tag * tag = &slave.tags[pos];
238 if(!is_sprite_tag(tag->id)) {
239 logf("<debug> processing sprite tag %02x", slave.tags[pos].id);
240 if(is_defining_tag(tag->id))
242 logf("<debug> [sprite defs] write tag %02x (%d bytes in body)",
243 tag->id, tag->length);
244 writer_write(&w, tag->fulldata, tag->fulllength);
249 {case TAGID_DEFINEFONTINFO:
251 /* define font info is not a defining tag, in that
252 * it doesn't define a new id, but rather extends
253 * an existing one. It also isn't a sprite tag.
254 * Anyway we can't throw it out, so we just pass it
259 case TAGID_EXPORTASSETS:
260 logf("<debug> deliberately ignoring EXPORTASSETS tag");
262 case TAGID_ENABLEDEBUGGER:
263 logf("<debug> deliberately ignoring ENABLEDEBUGGER tag");
265 case TAGID_BACKGROUNDCOLOR:
266 logf("<debug> deliberately ignoring BACKGROUNDCOLOR tag");
271 logf("<notice> found tag %d. This is a Generator template, isn't it?", slave.tags[pos].id);
274 logf("<notice> funny tag: %d is neither defining nor sprite", slave.tags[pos].id);
284 if(is_defining_tag(master.tags[pos].id))
286 logf("<debug> [master] write tag %02x (%d bytes in body)",
287 master.tags[pos].id, master.tags[pos].length);
288 if( getidfromtag(&master.tags[pos]) == spriteid)
292 *(u16*)master.tags[pos].data = replaceddefine = get_free_id();
293 writer_write(&w, master.tags[pos].fulldata, master.tags[pos].fulllength);
295 /* don't write this tag */
296 logf("<verbose> replacing tag %d id %d with sprite", master.tags[pos].id
300 writer_write(&w, master.tags[pos].fulldata, master.tags[pos].fulllength);
304 while(master.tags[pos++].id != 0);
306 // write slave(2) (header)
307 tmp = 0x3f + (TAGID_DEFINESPRITE << 6);
308 writer_write(&w, &tmp, 2);
309 tagidpos = (u32*)writer_getpos(&w);
310 writer_write(&w, &tmp32, 4);
312 startpos = (u8*)writer_getpos(&w);
316 logf("<warning> Didn't find anything named %s in file. No substitutions will occur.", slavename);
317 spriteid = get_free_id();
320 logf ("<notice> sprite id is %d", spriteid);
322 writer_write(&w, &tmp, 2);
323 tmp = slave.header.count;
324 writer_write(&w, &tmp, 2);
327 // write slave(2) (body)
329 tmp = slave.header.count;
330 logf("<debug> %d frames to go",tmp);
333 tmp = 7 + (TAGID_PLACEOBJECT2 << 6);
334 writer_write(&w, &tmp, 2);
335 tmp = 2+64; //flags: character + clipaction
336 writer_write(&w, &tmp, 1);
338 writer_write(&w, &tmp,2);
339 tmp = replaceddefine; //id
340 writer_write(&w, &tmp,2);
341 tmp = 65535; //clipdepth
342 writer_write(&w, &tmp,2);
346 tmp = 5 + (TAGID_PLACEOBJECT2 << 6);
347 writer_write(&w, &tmp, 2);
348 tmp = 2; //flags: character
349 writer_write(&w, &tmp, 1);
351 writer_write(&w, &tmp,2);
352 tmp = replaceddefine; //id
353 writer_write(&w, &tmp,2);
357 struct swf_tag * tag = &slave.tags[pos];
358 if (is_sprite_tag(tag->id)) {
360 changedepth(tag, +1);
361 logf("<debug> [sprite main] write tag %02x (%d bytes in body)",
362 slave.tags[pos].id, slave.tags[pos].length);
363 write_changepos(tag, &w);
365 if(tag->id == TAGID_SHOWFRAME)
368 logf("<debug> %d frames to go",tmp);
372 while(slave.tags[pos++].id != TAGID_END);
374 *tagidpos = (u8*)writer_getpos(&w) - startpos; // set length of sprite (in header)
375 logf("<verbose> sprite length is %d",*tagidpos);
380 if(!is_defining_tag(master.tags[pos].id))
382 logf("<debug> [master] write tag %02x (%d bytes in body)",
383 master.tags[pos].id, master.tags[pos].length);
384 writer_write(&w, master.tags[pos].fulldata, master.tags[pos].fulllength);
387 while(master.tags[pos++].id != 0);
389 tmp32 = (u8*)writer_getpos(&w) - (u8*)newdata; //length
391 *headlength = tmp32; // set the header to the correct length
393 return newdata; //length