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
162 case TAGID_EXPORTASSETS:
163 logf("<debug> deliberately ignoring EXPORTASSETS tag");
165 case TAGID_ENABLEDEBUGGER:
166 logf("<debug> deliberately ignoring ENABLEDEBUGGER tag");
168 case TAGID_BACKGROUNDCOLOR:
169 logf("<debug> deliberately ignoring BACKGROUNDCOLOR tag");
174 logf("<notice> found tag %d. This is a Generator template, isn't it?", slave.tags[pos].id);
177 logf("<notice> funny tag: %d is neither defining nor sprite", slave.tags[pos].id);
186 void write_sprite(struct writer_t*w, int spriteid, int replaceddefine)
193 // write slave(2) (header)
194 tmp = 0x3f + (TAGID_DEFINESPRITE << 6);
195 writer_write(w, &tmp, 2);
196 tagidpos = (u32*)writer_getpos(w);
197 writer_write(w, &tmp32, 4);
199 startpos = (u8*)writer_getpos(w);
203 logf("<warning> Didn't find anything named %s in file. No substitutions will occur.", slavename);
204 spriteid = get_free_id();
207 logf ("<notice> sprite id is %d", spriteid);
209 writer_write(w, &tmp, 2);
210 tmp = slave.header.count;
211 writer_write(w, &tmp, 2);
214 // write slave(2) (body)
215 tmp = slave.header.count;
216 logf("<debug> %d frames to go",tmp);
219 tmp = 7 + (TAGID_PLACEOBJECT2 << 6);
220 writer_write(w, &tmp, 2);
221 tmp = 2+64; //flags: character + clipaction
222 writer_write(w, &tmp, 1);
224 writer_write(w, &tmp,2);
225 tmp = replaceddefine; //id
226 writer_write(w, &tmp,2);
227 tmp = 65535; //clipdepth
228 writer_write(w, &tmp,2);
232 tmp = 5 + (TAGID_PLACEOBJECT2 << 6);
233 writer_write(w, &tmp, 2);
234 tmp = 2; //flags: character
235 writer_write(w, &tmp, 1);
237 writer_write(w, &tmp,2);
238 tmp = replaceddefine; //id
239 writer_write(w, &tmp,2);
243 struct swf_tag * tag = &slave.tags[pos];
244 if (is_sprite_tag(tag->id)) {
246 changedepth(tag, +1);
247 logf("<debug> [sprite main] write tag %02x (%d bytes in body)",
248 slave.tags[pos].id, slave.tags[pos].length);
249 write_changepos(tag, w);
251 if(tag->id == TAGID_SHOWFRAME)
254 logf("<debug> %d frames to go",tmp);
258 while(slave.tags[pos++].id != TAGID_END);
260 *tagidpos = (u8*)writer_getpos(w) - startpos; // set length of sprite (in header)
261 logf("<verbose> sprite length is %d",*tagidpos);
264 #define FLAGS_WRITEDEFINES 1
265 #define FLAGS_WRITENONDEFINES 2
266 #define FLAGS_WRITESPRITE 4
267 void write_master(struct writer_t*w, int spriteid, int replaceddefine, int flags)
271 if(is_defining_tag(master.tags[pos].id) && (flags&1))
273 logf("<debug> [master] write tag %02x (%d bytes in body)",
274 master.tags[pos].id, master.tags[pos].length);
275 if( getidfromtag(&master.tags[pos]) == spriteid)
279 *(u16*)master.tags[pos].data = replaceddefine;
280 writer_write(w, master.tags[pos].fulldata, master.tags[pos].fulllength);
282 /* don't write this tag */
283 logf("<verbose> replacing tag %d id %d with sprite", master.tags[pos].id
289 write_sprite_defines(w);
290 write_sprite(w, spriteid, replaceddefine);
293 writer_write(w, master.tags[pos].fulldata, master.tags[pos].fulllength);
296 if(!is_defining_tag(master.tags[pos].id) && (flags&2))
298 logf("<debug> [master] write tag %02x (%d bytes in body)",
299 master.tags[pos].id, master.tags[pos].length);
300 writer_write(w, master.tags[pos].fulldata, master.tags[pos].fulllength);
303 while(master.tags[pos++].id != 0);
306 void writeheader(struct writer_t*w, u8*data, int length)
308 if(config.hassizex || config.hassizey || config.framerate)
310 struct flash_header head;
311 swf_init(data-3, length+3);
312 head = swf_read_header();
315 head.boundingBox.x2 = head.boundingBox.x1 + config.sizex;
319 head.boundingBox.y2 = head.boundingBox.y1 + config.sizey;
323 head.rate = config.framerate;
325 swf_write_header(w, &head);
328 writer_write(w, data, length);
331 uchar * combine(uchar*masterdata, int masterlength, char*_slavename, uchar*slavedata, int slavelength, int*newlength)
333 char master_flash = 0;
334 char slave_flash = 0;
335 slavename = _slavename;
337 logf("<debug> move x (%d)", config.movex);
338 logf("<debug> move y (%d)", config.movey);
339 logf("<debug> scale x (%d)", config.scalex);
340 logf("<debug> scale y (%d)", config.scaley);
342 memset(masterids, -1, sizeof(masterids));
346 logf("<fatal> the master file is too small (%d bytes)", masterlength);
351 logf("<fatal> the slave file is too small (%d bytes)", slavelength);
354 if(masterdata[2] == 'S' &&
355 masterdata[1] == 'W' &&
356 masterdata[0] == 'F')
358 logf("<notice> the master file is flash (swf) format\n");
362 logf("<notice> the master file is not flash (swf) format!\n");
364 if(slavedata[2] == 'S' &&
365 slavedata[1] == 'W' &&
368 logf("<notice> the slave file is flash (swf) format\n");
372 logf("<notice> the slave file is not flash (swf) format!\n");
374 if(master_flash && slave_flash)
382 int replaceddefine = -1;
385 read_swf(&master, masterdata, masterlength);
387 length = masterlength + slavelength*2 + 128; // this is a guess, but a good guess.
388 newdata = malloc(length);
389 writer_init(&w, newdata, length);
392 logf("<fatal> Couldn't allocate %d bytes of memory", length);
399 int tag = master.tags[pos].id;
400 if(is_defining_tag(tag)) {
401 int defineid = getidfromtag(&master.tags[pos]);
402 logf("<debug> tagid %02x defines object %d", tag, defineid);
403 masterids[defineid] = 1;
404 } else if(tag == TAGID_PLACEOBJECT2) {
405 char * name = tag_placeobject2_name(&master.tags[pos]);
406 int id = tag_placeobject2_character(&master.tags[pos]);
409 logf("<verbose> tagid %02x places object %d named \"%s\"", tag, id, name);
411 logf("<verbose> tagid %02x places object %d (no name)", tag, id);
413 if (name && !strcmp(name,slavename)) {
416 logf("<notice> Slave file attached to object %d.", id);
421 while(master.tags[pos++].id != 0);
423 swf_relocate (slavedata, slavelength, masterids);
425 read_swf(&slave, slavedata, slavelength);
428 replaceddefine = get_free_id();
432 writer_write(&w, "FWS",3);
433 headlength = (u32*)(writer_getpos(&w) + 1);
434 writeheader(&w, master.header.headerdata, master.header.headerlength);
436 if(config.antistream) {
437 write_sprite_defines(&w);
438 write_sprite(&w, spriteid, replaceddefine);
439 write_master(&w, spriteid, replaceddefine, FLAGS_WRITEDEFINES);
440 write_master(&w, spriteid, replaceddefine, FLAGS_WRITENONDEFINES);
442 write_master(&w, spriteid, replaceddefine,
443 FLAGS_WRITEDEFINES|FLAGS_WRITENONDEFINES|FLAGS_WRITESPRITE);
446 tmp32 = (u8*)writer_getpos(&w) - (u8*)newdata; //length
448 *headlength = tmp32; // set the header to the correct length
450 return newdata; //length