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