f694bcc1d3f3b853e7c12633a9a686c7c4ba78e3
[swftools.git] / src / combine.c
1 /* combine.c 
2    Implements combine(), which merges two swfs in memory.
3
4    Part of the swftools package.
5    
6    Copyright (c) 2001 Matthias Kramm <kramm@quiss.org> 
7
8    This file is distributed under the GPL, see file COPYING for details */
9
10 #include <stdlib.h>
11 #include <stdio.h>
12 #include <string.h>
13 #include <memory.h>
14 #include "../lib/log.h"
15 #include "../lib/rfxswf.h"
16 #include "./flash.h"
17 #include "./reloc.h"
18 #include "./settings.h"
19
20 static char* slavename = 0;
21 static int slaveid = -1;
22 static int slaveframe = -1;
23
24 static char* tag_placeobject2_name (struct swf_tag* tag)
25 {
26     struct PlaceObject2 plo2;
27     placeobject2_init (&plo2, tag);
28     return plo2.name;
29 }
30
31 static u16 tag_placeobject2_character (struct swf_tag* tag)
32 {
33     struct PlaceObject2 plo2;
34     placeobject2_init (&plo2, tag);
35     return plo2.id;
36 }
37
38 static struct swffile master;
39 static struct swffile slave;
40
41 static int masterids[65536];
42
43 static int get_free_id()
44 {
45     int t;
46     for (t=1;t<65536;t++)
47     {
48         if(masterids[t] == -1)
49         {
50             masterids[t] = 1;
51             return t;
52         }
53     }
54     return -1;
55 }
56
57 void changedepth(struct swf_tag*tag, int add)
58 {
59     /* fucking big endian byte order */
60     if(tag->id == TAGID_PLACEOBJECT)
61         (*(u16*)&tag->data[2]) =
62         SWAP16(SWAP16(*(u16*)&tag->data[2]) + add);
63     if(tag->id == TAGID_PLACEOBJECT2)
64         (*(u16*)&tag->data[1]) =
65         SWAP16(SWAP16(*(u16*)&tag->data[1]) + add);
66     if(tag->id == TAGID_REMOVEOBJECT)
67         (*(u16*)&tag->data[2]) =
68         SWAP16(SWAP16(*(u16*)&tag->data[2]) + add);
69     if(tag->id == TAGID_REMOVEOBJECT2)
70         (*(u16*)&tag->data[0]) =
71         SWAP16(SWAP16(*(u16*)&tag->data[0]) + add);
72 }
73
74 void jpeg_assert()
75 {
76     /* TODO: if there's a jpegtable found, store it
77        and handle it together with the flash file
78        headers */
79     /* check that master and slave don't have both
80        jpegtables (which would be fatal) */
81     int pos;
82     int mpos=-1, spos=-1;
83     pos = 0;
84     while(master.tags[pos].id != 0)
85     {
86         if(master.tags[pos].id == TAGID_JPEGTABLES)
87             mpos = pos;
88         pos++;
89     }
90     pos = 0;
91     while(master.tags[pos].id != 0)
92     {
93         if(slave.tags[pos].id == TAGID_JPEGTABLES)
94             spos = pos;
95         pos++;
96     }
97     if(spos>=0 && mpos>=0)
98     {
99         if(slave.tags[pos].length ==
100            master.tags[pos].length &&
101         !memcmp(slave.tags[pos].data, master.tags[pos].data,
102             master.tags[pos].length))
103         {
104             // ok, both have jpegtables, but they're identical.
105             // delete one and don't make an error
106             for(;spos<slave.tagnum-1;spos++)
107                 slave.tags[spos] =
108                     slave.tags[spos+1];
109             spos = -1;
110         }
111     }
112     if(spos>=0 && mpos>=0) {
113         logf("<error> Master and slave have incompatible JPEGTABLES.");
114     }
115 }
116
117 /* applies the config move and scale parameters to
118  * a matrix. (If settings would provide a rotation,
119  * this would be a matrix concatenation/multiplication
120  * routine. In this case, it's just element-wise multiplication.
121  */
122 void matrix_adjust(struct MATRIX*m)
123 {
124     if(config.scalex != 1 || config.scaley != 1)
125     {
126         if(!m->hasscale) {
127             m->hasscale = 1;
128             m->a[0][0] = config.scalex;
129             m->a[1][1] = config.scaley;
130         } else {
131             m->a[0][0] *= config.scalex;
132             m->a[1][1] *= config.scaley;
133         }
134         if(m->hasrotate) {
135             m->a[0][1] *= config.scalex;
136             m->a[1][0] *= config.scaley;
137         }
138         m->b[0] *= config.scalex;
139         m->b[1] *= config.scaley;
140     }
141 /*    printf("hasscale: %d\n",m->hasscale);
142     printf("hasrotate: %d\n", m->hasrotate);
143     printf("move: %d %d\n", m->b[0],m->b[1]);
144     printf("rot: %f %f\n",m->a[0][0],m->a[0][1]);
145     printf("     %f %f\n",m->a[1][0],m->a[1][1]);*/
146     m->b[0] += config.movex;
147     m->b[1] += config.movey;
148 }
149
150 void write_changepos(struct swf_tag*tag, struct writer_t*w)
151 {
152     if(config.movex || config.movey || config.scalex != 1 || config.scaley != 1)
153     {
154         switch(tag->id)
155         {
156             case TAGID_PLACEOBJECT: {
157                 struct PlaceObject p;
158                 placeobject_init(&p, tag);
159                 matrix_adjust(&p.matrix);
160                 placeobject_write(&p, w);
161                 break;
162             }
163             case TAGID_PLACEOBJECT2: {
164                 struct PlaceObject2 p;
165                 placeobject2_init(&p, tag);
166                 if(!p.hasmatrix) {
167                     p.hasmatrix = 1;
168                     MATRIX_init(&p.matrix);
169                 }
170                 matrix_adjust(&p.matrix);
171                 placeobject2_write(&p, w);
172                 break;
173             }
174             default:
175             writer_write(w, tag->fulldata, tag->fulllength);
176         }
177     } 
178     else 
179     {
180             writer_write(w, tag->fulldata, tag->fulllength);
181     }
182 }
183
184 void write_sprite_defines(struct writer_t*w)
185 {
186     int pos = 0;
187     while(slave.tags[pos].id != 0) {
188         struct swf_tag * tag = &slave.tags[pos];
189         if(!is_sprite_tag(tag->id)) {
190             logf("<debug> processing sprite tag %02x", slave.tags[pos].id);
191             if(is_defining_tag(tag->id))
192             {
193                 logf("<debug> [sprite defs] write tag %02x (%d bytes in body)", 
194                         tag->id, tag->length);
195                 writer_write(w, tag->fulldata, tag->fulllength);
196             }
197             else
198             {
199                 switch(tag->id)
200                 {case TAGID_DEFINEFONTINFO:
201                     {
202                         /* define font info is not a defining tag, in that
203                          * it doesn't define a new id, but rather extends
204                          * an existing one. It also isn't a sprite tag. 
205                          * Anyway we can't throw it out, so we just pass it
206                          * through.
207                          */
208                         writer_write(w, tag->fulldata, tag->fulllength);
209                         break;
210                     }
211                  case TAGID_JPEGTABLES:
212                         /* if we get here, jpeg_assert has already run,
213                            ensuring this is the only one of it's kind,
214                            so we may safely write it out */
215                         writer_write(w, tag->fulldata, tag->fulllength);
216                     break;
217                  case TAGID_EXPORTASSETS:
218                     logf("<debug> deliberately ignoring EXPORTASSETS tag");
219                     break;
220                  case TAGID_ENABLEDEBUGGER:
221                     logf("<debug> deliberately ignoring ENABLEDEBUGGER tag");
222                     break;
223                  case TAGID_BACKGROUNDCOLOR:
224                     logf("<debug> deliberately ignoring BACKGROUNDCOLOR tag");
225                     break;
226                  case 40:
227                  case 49:
228                  case 51:
229                     logf("<notice> found tag %d. This is a Generator template, isn't it?", slave.tags[pos].id);
230                     break;
231                  default:
232                     logf("<notice> funny tag: %d is neither defining nor sprite", slave.tags[pos].id);
233                 }
234             }
235         }
236         pos++;
237     }
238 }
239
240 void write_sprite(struct writer_t*w, int spriteid, int replaceddefine)
241 {
242     u16 tmp;
243     u32 tmp32;
244     u32*tagidpos;
245     u8*startpos;
246     int pos = 0;
247     // write slave(2) (header)
248     tmp = SWAP16(0x3f + (TAGID_DEFINESPRITE << 6));
249     writer_write(w, &tmp, 2);
250     tagidpos = (u32*)writer_getpos(w);
251     writer_write(w, &tmp32, 4);
252     
253     startpos = (u8*)writer_getpos(w);
254
255     logf ("<notice> sprite id is %d", spriteid);
256     tmp = spriteid;
257     writer_write(w, &tmp, 2);
258     tmp = slave.header.count;
259     writer_write(w, &tmp, 2);
260
261
262     // write slave(2) (body)
263     tmp = slave.header.count;
264     logf("<debug> %d frames to go",tmp);
265
266     if(config.clip) {
267         tmp = SWAP16(7 + (TAGID_PLACEOBJECT2 << 6));
268         writer_write(w, &tmp, 2);
269         tmp = SWAP16(2+64); //flags: character + clipaction
270         writer_write(w, &tmp, 1);
271         tmp = SWAP16(0); //depth
272         writer_write(w, &tmp,2);
273         tmp = SWAP16(replaceddefine); //id
274         writer_write(w, &tmp,2);
275         tmp = SWAP16(65535); //clipdepth
276         writer_write(w, &tmp,2);
277     }
278
279     if(config.overlay && !config.isframe) {
280         tmp = SWAP16(5 + (TAGID_PLACEOBJECT2 << 6));
281         writer_write(w, &tmp, 2);
282         tmp = SWAP16(2); //flags: character
283         writer_write(w, &tmp, 1);
284         tmp = SWAP16(0); //depth
285         writer_write(w, &tmp,2);
286         tmp = SWAP16(replaceddefine); //id
287         writer_write(w, &tmp,2);
288     }
289
290     do {
291         struct swf_tag * tag = &slave.tags[pos];
292         if (is_sprite_tag(tag->id)) {
293
294             changedepth(tag, +1);
295             logf("<debug> [sprite main] write tag %02x (%d bytes in body)", 
296                     slave.tags[pos].id, slave.tags[pos].length);
297             write_changepos(tag, w);
298
299             if(tag->id == TAGID_SHOWFRAME)
300             {
301                 tmp--;
302                 logf("<debug> %d frames to go",tmp);
303             }
304         }
305     }
306     while(slave.tags[pos++].id != TAGID_END);
307
308     *tagidpos = SWAP32((u8*)writer_getpos(w) - startpos); // set length of sprite (in header)
309     logf("<verbose> sprite length is %d",SWAP32(*tagidpos));
310 }
311
312 static char tag_ok_for_slave(int id)
313 {
314     if(id == TAGID_BACKGROUNDCOLOR)
315         return 0;
316     return 1;
317 }
318
319 #define FLAGS_WRITEDEFINES 1
320 #define FLAGS_WRITENONDEFINES 2
321 #define FLAGS_WRITESPRITE 4
322 #define FLAGS_WRITESLAVE 8
323 void write_master(struct writer_t*w, int spriteid, int replaceddefine, int flags)
324 {
325     int pos = 0;
326     int spos = 0;
327     int outputslave = 0;
328     int frame = 0;
329     int sframe = 0;
330     int slavewritten = 0;
331     while(master.tags[pos].id != 0)
332     {
333         if(master.tags[pos].id == TAGID_SHOWFRAME && outputslave)
334         {
335             while(slave.tags[spos].id) {
336                 if(slave.tags[spos].id == TAGID_SHOWFRAME) {
337                     spos++;
338                     sframe++;
339                     break;
340                 }
341                 if(tag_ok_for_slave(slave.tags[spos].id))
342                     writer_write(w, slave.tags[spos].fulldata, slave.tags[spos].fulllength);
343                 spos++;
344             }
345             frame ++;
346         }
347
348         if(is_defining_tag(master.tags[pos].id) && (flags&FLAGS_WRITEDEFINES))
349         {
350             logf("<debug> [master] write tag %02x (%d bytes in body)", 
351                     master.tags[pos].id, master.tags[pos].length);
352             if(getidfromtag(&master.tags[pos]) == spriteid && !config.isframe)
353             {
354                 if(config.overlay)
355                 {
356                     *(u16*)master.tags[pos].data = SWAP16(replaceddefine);
357                     writer_write(w, master.tags[pos].fulldata, master.tags[pos].fulllength);
358                 } else {
359                     /* don't write this tag */
360                     logf("<verbose> replacing tag %d id %d with sprite", master.tags[pos].id
361                             ,spriteid);
362                 }
363
364                 if(flags&FLAGS_WRITESPRITE)
365                 {
366                     write_sprite_defines(w);
367                     write_sprite(w, spriteid, replaceddefine);
368                 }
369                 if(flags&FLAGS_WRITESLAVE)
370                 {
371                     outputslave = 1;
372                 }
373             } else { 
374                 writer_write(w, master.tags[pos].fulldata, master.tags[pos].fulllength);
375             }
376         }
377         if(frame == slaveframe)
378         {
379             if(flags&FLAGS_WRITESLAVE) {
380                 outputslave = 1;
381                 slavewritten = 1;
382             }
383             if((flags&FLAGS_WRITESPRITE) && !slavewritten)
384             {
385                 int id = get_free_id();
386                 int depth = 0;
387                 char data[7];
388                 if(config.clip) {
389                     logf("<fatal> Can't combine --clip and --frame");
390                 }
391                 *(u16*)&data[0] = SWAP16((u16)(TAGID_PLACEOBJECT2<<6) + 5);
392                 *(u8*)&data[2]= SWAP16(2); //flags: id
393                 *(u16*)&data[3]= SWAP16(depth); // depth
394                 *(u16*)&data[5]= SWAP16(id);
395                 write_sprite_defines(w);
396                 write_sprite(w, id, -1);
397                 writer_write(w,data,7);
398                 slavewritten = 1;
399             }
400         }
401         if(!is_defining_tag(master.tags[pos].id) && (flags&FLAGS_WRITENONDEFINES))
402         {
403             int dontwrite = 0;
404             switch(master.tags[pos].id) {
405                 case TAGID_PLACEOBJECT:
406                 case TAGID_PLACEOBJECT2:
407                     if(frame == slaveframe && !config.overlay)
408                         dontwrite = 1;
409                 case TAGID_REMOVEOBJECT:
410 //              case TAGID_REMOVEOBJECT2:
411                     /* place/removetags for the object we replaced
412                        should be discarded, too, as the object to insert 
413                        isn't a sprite 
414                      */
415                     if(spriteid>=0 && getidfromtag(&master.tags[pos]) == spriteid && 
416                             !config.isframe && config.merge)
417                         dontwrite = 1;
418                 break;
419             }
420             if(!dontwrite) {
421                 logf("<debug> [master] write tag %02x (%d bytes in body)", 
422                         master.tags[pos].id, master.tags[pos].length);
423                 writer_write(w, master.tags[pos].fulldata, master.tags[pos].fulllength);
424             }
425         }
426         pos++;
427     }
428    
429     if(outputslave) 
430     while(slave.tags[spos].id)
431     {
432             if(tag_ok_for_slave(slave.tags[spos].id))
433                 writer_write(w, slave.tags[spos].fulldata, slave.tags[spos].fulllength);
434             spos++;
435     }
436     if(!slavewritten && config.isframe && (flags&(FLAGS_WRITESLAVE|FLAGS_WRITESPRITE)))
437     {
438         logf("<warning> Frame %d doesn't exist in file. No substitution will occur",
439                 slaveframe);
440     }
441     //write END tag: 
442     writer_write(w, master.tags[pos].fulldata, master.tags[pos].fulllength);
443 }
444
445 void writeheader(struct writer_t*w, u8*data, int length)
446 {
447     if(config.hassizex || config.hassizey || config.framerate)
448     {
449         struct flash_header head;
450         struct reader_t reader;
451         swf_init(&reader, data-3, length+3);
452         head = swf_read_header(&reader);
453         if(config.hassizex)
454         {
455             head.boundingBox.x2 = head.boundingBox.x1 + config.sizex;
456         }
457         if(config.hassizey)
458         {
459             head.boundingBox.y2 = head.boundingBox.y1 + config.sizey;
460         }
461         if(config.framerate)
462         {
463             head.rate = config.framerate;
464         }
465         swf_write_header(w, &head);
466     }
467     else
468     writer_write(w, data, length);
469 }
470
471 uchar * catcombine(uchar*masterdata, int masterlength, char*_slavename, uchar*slavedata, int slavelength, int*newlength)
472 {
473         struct writer_t w;
474         u32*headlength;
475         u32 tmp32;
476         int length = masterlength*2 + slavelength;
477         int pos = 0;
478         int t;
479         char* depths;
480         uchar*newdata = malloc(length);
481         if(!newdata) {
482             logf("<fatal> Couldn't allocate %d bytes of memory", length);
483             return 0;
484         }
485         if(config.isframe) {
486             logf("<fatal> Can't combine --cat and --frame");
487             exit(1);
488         }
489         writer_init(&w, newdata, length);
490         
491         do {
492             int tag = master.tags[pos].id;
493             if(is_defining_tag(tag)) {
494                 int defineid = getidfromtag(&master.tags[pos]);
495                 logf("<debug> tagid %02x defines object %d", tag, defineid);
496                 masterids[defineid] = 1;
497             }
498         }
499         while(master.tags[pos++].id != 0);
500         
501         swf_relocate (slavedata, slavelength, masterids);
502         read_swf(&slave, slavedata, slavelength);
503         jpeg_assert();
504         
505         writer_write(&w, "FWS",3);
506         headlength = (u32*)(writer_getpos(&w) + 1);
507         writeheader(&w, master.header.headerdata, master.header.headerlength);
508
509         depths = malloc(65536);
510         if(!depths) {
511             logf("<fatal> Couldn't allocate %d bytes of memory", 65536);
512             return 0;
513         }
514         memset(depths, 0, 65536);
515         pos = 0;
516         do {
517             int num=1;
518             u16 depth;
519             logf("<debug> [master] write tag %02x (%d bytes in body)", 
520                     master.tags[pos].id, master.tags[pos].length);
521             switch(master.tags[pos].id) {
522                 case TAGID_PLACEOBJECT2:
523                     num++;
524                 case TAGID_PLACEOBJECT: {
525                    struct reader_t r;
526                    reader_init (&r, master.tags[pos].data, master.tags[pos].length);
527                    if(num>=2)
528                         reader_readu8(&r);
529                    depth = reader_readu16(&r);
530                    depths[depth] = 1;
531                 }
532                 break;
533                 case TAGID_REMOVEOBJECT: {
534                    struct reader_t r;
535                    reader_init (&r, master.tags[pos].data, master.tags[pos].length);
536                    reader_readu16(&r);
537                    depths[reader_readu16(&r)] = 0;
538                 }
539                 break;
540                 case TAGID_REMOVEOBJECT2: {
541                    struct reader_t r;
542                    reader_init (&r, master.tags[pos].data, master.tags[pos].length);
543                    depths[reader_readu16(&r)] = 0;
544                 }
545                 break;
546             }
547             if(master.tags[pos].id != 0)
548                 writer_write(&w, master.tags[pos].fulldata, master.tags[pos].fulllength);
549         }
550         while(master.tags[pos++].id != 0);
551
552         for(t=0;t<65536;t++) 
553         if(depths[t])
554         {
555             char data[16];
556             int len;
557             *(u16*)(&data[0]) = SWAP16((TAGID_REMOVEOBJECT2<<6) + 2);
558             *(u16*)(&data[2]) = SWAP16(t);
559             writer_write(&w, data, 4);
560         }
561         free(depths);
562
563         pos = 0;
564         do {
565             logf("<debug> [slave] write tag %02x (%d bytes in body)", 
566                     slave.tags[pos].id, slave.tags[pos].length);
567             writer_write(&w, slave.tags[pos].fulldata, slave.tags[pos].fulllength);
568         }
569         while(slave.tags[pos++].id != 0);
570
571         tmp32 = (u8*)writer_getpos(&w) - (u8*)newdata; //length
572         *newlength = tmp32;
573         *headlength = SWAP32(tmp32); // set the header to the correct length
574
575         return newdata; //length
576 }
577
578 uchar * normalcombine(uchar*masterdata, int masterlength, char*_slavename, uchar*slavedata, int slavelength, int*newlength)
579 {
580         int length;
581         int pos=0;
582         u32 tmp32;
583         u32*headlength;
584         uchar*newdata;
585         int spriteid = -1;
586         int replaceddefine = -1;
587         struct writer_t w;
588         int frame;
589         char*framelabel;
590         
591         length = masterlength + slavelength*2 + 128; // this is a guess, but a good guess.
592         newdata = malloc(length);
593         writer_init(&w, newdata, length);
594
595         if(!newdata) {
596             logf("<fatal> Couldn't allocate %d bytes of memory", length);
597             return 0;
598         }
599
600         // set the idtab
601         pos = 0;
602         do {
603             int tag = master.tags[pos].id;
604             if(is_defining_tag(tag)) {
605                 int defineid = getidfromtag(&master.tags[pos]);
606                 logf("<debug> tagid %02x defines object %d", tag, defineid);
607                 masterids[defineid] = 1;
608             } else if(tag == TAGID_PLACEOBJECT2) {
609                 char * name = tag_placeobject2_name(&master.tags[pos]);
610                 int id = tag_placeobject2_character(&master.tags[pos]);
611
612                 if(name)
613                   logf("<verbose> tagid %02x places object %d named \"%s\"", tag, id, name);
614                 else
615                   logf("<verbose> tagid %02x places object %d (no name)", tag, id);
616
617                 if ((name && slavename && !strcmp(name,slavename)) || 
618                     (!slavename && id==slaveid)) {
619                     if(id>=0) {
620                       spriteid = id;
621                       logf("<notice> Slave file attached to object %d.", id);
622                     }
623                 }
624             } else if(tag == TAGID_SHOWFRAME) {
625                 if(slaveframe>=0 && frame==slaveframe) {
626                     logf("<notice> Slave file attached to frame %d.", frame);
627                 }
628                 frame++;
629             } else if(tag == TAGID_FRAMELABEL) {
630                 char * name = master.tags[pos].data;
631                 if(name && slavename && config.isframe && !strcmp(name, slavename)) {
632                     slaveframe = frame;
633                     logf("<notice> Slave file attached to frame %d (%s).", frame, name);
634                 }
635             }
636         }
637         while(master.tags[pos++].id != 0);
638
639         if (spriteid<0 && !config.isframe) {
640             if(slavename) {
641                 if(strcmp(slavename,"!!dummy!!"))
642                     logf("<warning> Didn't find anything named %s in file. No substitutions will occur.", slavename);
643             }
644             else
645                 logf("<warning> Didn't find id %d in file. No substitutions will occur.", slaveid);
646             spriteid = get_free_id();
647         }
648
649         swf_relocate (slavedata, slavelength, masterids);
650         read_swf(&slave, slavedata, slavelength);
651         jpeg_assert();
652         
653         if (config.overlay)
654             replaceddefine = get_free_id();
655         
656         // write file 
657
658         writer_write(&w, "FWS",3);
659         headlength = (u32*)(writer_getpos(&w) + 1);
660         writeheader(&w, master.header.headerdata, master.header.headerlength);
661
662         if (config.antistream) {
663             if (config.merge) {
664                 logf("<fatal> Can't combine --antistream and --merge");
665             }
666             write_sprite_defines(&w);
667             write_sprite(&w, spriteid, replaceddefine);
668             write_master(&w, spriteid, replaceddefine, FLAGS_WRITEDEFINES);
669             write_master(&w, spriteid, replaceddefine, FLAGS_WRITENONDEFINES);
670         } else {
671             if (config.merge)
672                 write_master(&w, spriteid, replaceddefine, 
673                     FLAGS_WRITEDEFINES|FLAGS_WRITENONDEFINES|FLAGS_WRITESLAVE);
674             else
675                 write_master(&w, spriteid, replaceddefine, 
676                     FLAGS_WRITEDEFINES|FLAGS_WRITENONDEFINES|FLAGS_WRITESPRITE);
677         }
678
679         tmp32 = (u8*)writer_getpos(&w) - (u8*)newdata; //length
680         *newlength = tmp32;
681         *headlength = SWAP32(tmp32); // set the header to the correct length
682
683         return newdata; //length
684 }
685
686 uchar * combine(uchar*masterdata, int masterlength, char*_slavename, uchar*slavedata, int slavelength, int*newlength)
687 {
688     char master_flash = 0;
689     char slave_flash = 0;
690     slavename = _slavename;
691
692     slaveid = -1;
693     slaveframe = -1;
694
695     if(slavename[0] == '#')
696     {
697         slaveid = atoi(&slavename[1]);
698         slavename = 0;
699     }
700     if(config.isframe)
701     {
702         slaveframe = slaveid;
703         slaveid = -1;
704     }
705
706     logf("<debug> move x (%d)", config.movex);
707     logf("<debug> move y (%d)", config.movey);
708     logf("<debug> scale x (%d)", config.scalex);
709     logf("<debug> scale y (%d)", config.scaley);
710     logf("<debug> is frame (%d)", config.isframe);
711     
712     memset(masterids, -1, sizeof(masterids));
713
714     if(masterlength < 3)
715     {
716         logf("<fatal> the master file is too small (%d bytes)", masterlength);
717         return 0;
718     }
719     if(slavelength < 3)
720     {
721         logf("<fatal> the slave file is too small (%d bytes)", slavelength);
722         return 0;
723     }
724     if(masterdata[2] == 'S' &&
725        masterdata[1] == 'W' &&
726        masterdata[0] == 'F')
727     {
728         logf("<notice> the master file is flash (swf) format\n");
729         master_flash = 1;
730     }
731     else
732         logf("<notice> the master file is not flash (swf) format!\n");
733
734     if(slavedata[2] == 'S' &&
735        slavedata[1] == 'W' &&
736        slavedata[0] == 'F')
737     {
738         logf("<notice> the slave file is flash (swf) format\n");
739         slave_flash = 1;
740     }
741     else
742         logf("<notice> the slave file is not flash (swf) format!\n");
743
744     if(master_flash && slave_flash) {
745         read_swf(&master, masterdata, masterlength);
746         if(config.cat) 
747             return catcombine(masterdata, masterlength, _slavename, slavedata, slavelength, newlength);
748         else
749             return normalcombine(masterdata, masterlength, _slavename, slavedata, slavelength, newlength);
750     }
751     
752     *newlength = 0;
753     return 0;
754 }