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