new parameter -s textonly
[swftools.git] / src / swfcombine.c
1 /* swfcombine.c
2    main routine for swfcombine(1), a tool for merging .swf-files.
3
4    Part of the swftools package.
5    
6    Copyright (c) 2001,2002,2003 Matthias Kramm <kramm@quiss.org> 
7  
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
21
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include "../lib/rfxswf.h"
26 #include "../lib/args.h"
27 #include "../lib/log.h"
28 #include "../config.h"
29
30 struct config_t
31 {
32    char overlay;
33    char alloctest;
34    char clip;
35    char stack;
36    char stack1;
37    char antistream;
38    char dummy;
39    char zlib;
40    char cat;
41    char merge;
42    char isframe;
43    char local_with_networking;
44    char local_with_filesystem;
45    char accelerated_blit;
46    char hardware_gpu;
47    int loglevel;
48    int sizex;
49    char hassizex;
50    int sizey;
51    char hassizey;
52    int flashversion;
53    int framerate;
54    int movex;
55    int movey;
56    float scalex;
57    float scaley;
58    int mastermovex;
59    int mastermovey;
60    float masterscalex;
61    float masterscaley;
62 };
63 struct config_t config;
64
65 char * master_filename = 0;
66 char * master_name = 0;
67 char * slave_filename[128];
68 char * slave_name[128];
69 int slave_movex[128];
70 int slave_movey[128];
71 float slave_scalex[128];
72 float slave_scaley[128];
73 char slave_isframe[128];
74 int numslaves = 0;
75
76 char * outputname = "output.swf";
77
78 int args_callback_option(char*name,char*val) {
79     if(!strcmp(name,"c"))
80     {
81         config.clip = 1;
82         return 0;
83     }
84     else if(!strcmp(name,"l"))
85     {
86         config.overlay = 1;
87         return 0;
88     }
89     else if (!strcmp(name, "o"))
90     {
91         outputname = val;
92         return 1;
93     }
94     else if (!strcmp(name, "v"))
95     {
96         config.loglevel ++;
97         return 0;
98     }
99     else if (!strcmp(name, "a"))
100     {
101         config.cat = 1;
102         return 0;
103     }
104     else if (!strcmp(name, "A"))
105     {
106         config.alloctest = 1;
107         return 0;
108     }
109     else if (!strcmp(name, "x"))
110     {
111         float x = atof(val);
112         config.movex = (int)(x*20+0.5);
113         return 1;
114     }
115     else if (!strcmp(name, "y"))
116     {
117         float y = atof(val);
118         config.movey = (int)(y*20+0.5);
119         return 1;
120     }
121     else if (!strcmp(name, "m"))
122     {
123         config.merge = 1;
124         return 0;
125     }
126     else if (!strcmp(name, "f"))
127     {
128         config.isframe = 1;
129         return 0;
130     }
131     else if (!strcmp(name, "F"))
132     {
133         config.flashversion = atoi(val);
134         return 1;
135     }
136     else if (!strcmp(name, "d"))
137     {
138         config.dummy = 1;
139         return 0;
140     }
141     else if (!strcmp(name, "z"))
142     {
143         config.zlib = 1;
144         return 0;
145     }
146     else if (!strcmp(name, "r"))
147     {
148
149         float rate = atof(val);
150         if ((rate < 0) ||(rate >= 256.0)) {
151             fprintf(stderr, "Error: You must specify a valid framerate between 1/256 and 255.\n");
152             exit(1);
153         }
154         config.framerate = (int)(rate*256);
155         return 1;
156     }
157     else if (!strcmp(name, "X"))
158     {
159         config.sizex = atoi(val)*20;
160         config.hassizex = 1;
161         return 1;
162     }
163     else if (!strcmp(name, "Y"))
164     {
165         config.sizey = atoi(val)*20;
166         config.hassizey = 1;
167         return 1;
168     }
169     else if (!strcmp(name, "s"))
170     {
171         config.scalex = config.scaley = atoi(val)/100.0;
172         return 1;
173     }
174     else if (!strcmp(name, "w"))
175     {
176         config.scalex = atoi(val)/100.0;
177         return 1;
178     }
179     else if (!strcmp(name, "h"))
180     {
181         config.scaley = atoi(val)/100.0;
182         return 1;
183     }
184     else if (!strcmp(name, "N"))
185     {
186         config.local_with_networking = 1;
187         return 0;
188     }
189     else if (!strcmp(name, "L"))
190     {
191         config.local_with_filesystem = 1;
192         return 0;
193     }
194     else if (!strcmp(name, "B"))
195     {
196         config.accelerated_blit = 1;
197         return 0;
198     }
199     else if (!strcmp(name, "G"))
200     {
201         config.hardware_gpu = 1;
202         return 0;
203     }
204     else if (!strcmp(name, "t") || !strcmp(name, "T"))
205     {
206         if(master_filename) {
207             fprintf(stderr, "error with arguments. Try --help.\n");
208             exit(1);
209         }
210         config.stack = 1;
211         if(!strcmp(name,"T"))
212             config.stack1 = 1;
213         master_filename = "__none__";
214         return 0;
215     }
216     else if (!strcmp(name, "V"))
217     {   
218         printf("swfcombine - part of %s %s\n", PACKAGE, VERSION);
219         exit(0);
220     }
221     else 
222     {
223         fprintf(stderr, "Unknown option: -%s\n", name);
224         exit(1);
225     }
226 }
227
228 static struct options_t options[] = {
229 {"o", "output"},
230 {"t", "stack"},
231 {"T", "stack1"},
232 {"m", "merge"},
233 {"a", "cat"},
234 {"l", "overlay"},
235 {"c", "clip"},
236 {"v", "verbose"},
237 {"F", "flashversion"},
238 {"d", "dummy"},
239 {"f", "frame"},
240 {"x", "movex"},
241 {"y", "movey"},
242 {"s", "scale"},
243 {"r", "rate"},
244 {"X", "width"},
245 {"Y", "height"},
246 {"N", "local-with-networking"},
247 {"G", "hardware-gpu"},
248 {"B", "accelerated-blit"},
249 {"L", "local-with-filesystem"},
250 {"z", "zlib"},
251 {0,0}
252 };
253
254 int args_callback_longoption(char*name,char*val) {
255     return args_long2shortoption(options, name, val);
256 }
257
258 int args_callback_command(char*name, char*val) {
259     char*myname = strdup(name);
260     char*filename;
261     filename = strchr(myname, '=');
262     if(filename) {
263         *filename = 0;
264         filename++;
265     } else {
266         // argument has no explicit name field. guess one from the file name
267         char*path = strrchr(myname, '/');
268         char*ext = strrchr(myname, '.');
269         if(!path) path = myname;
270         else path ++;
271         if(ext) *ext = 0;
272         myname = path;
273         filename = name;
274     }
275
276     if(!master_filename) {
277         master_filename = filename;
278         master_name = myname;
279         config.mastermovex = config.movex;
280         config.mastermovey = config.movey;
281         config.masterscalex = config.scalex;
282         config.masterscaley = config.scaley;
283         config.movex = config.movey = 0;
284         config.scalex = config.scaley = 1.0;
285     } else {             
286         msg("<verbose> slave entity %s (named \"%s\")\n", filename, myname);
287
288         slave_filename[numslaves] = filename;
289         slave_name[numslaves] = myname;
290         slave_movex[numslaves] = config.movex;
291         slave_movey[numslaves] = config.movey;
292         slave_scalex[numslaves] = config.scalex;
293         slave_scaley[numslaves] = config.scaley;
294         slave_isframe[numslaves] = config.isframe; 
295         config.isframe = 0;
296         config.movex = config.movey = 0;
297         config.scalex = config.scaley = 1.0;
298         numslaves ++;
299     }
300     return 0;
301 }
302
303 void args_callback_usage(char *name)
304 {
305     printf("\n");
306     printf("Usage: %s [-rXYomlcv] [-f] masterfile [-xysf] [(name1|#id1)=]slavefile1 .. [-xysf] [(nameN|#idN)=]slavefileN\n", name);
307     printf("OR:    %s [-rXYomv] --stack[1] [-xysf] [(name1|#id1)=]slavefile1 .. [-xysf] [(nameN|#idN)=]slavefileN\n", name);
308     printf("OR:    %s [-rXYov] --cat [-xysf] [(name1|#id1)=]slavefile1 .. [-xysf] [(nameN|#idN)=]slavefileN\n", name);
309     printf("OR:    %s [-rXYomlcv] --dummy [-xys] [file]\n", name);
310     printf("\n");
311     printf("-o , --output <outputfile>      explicitly specify output file. (otherwise, output.swf will be used)\n");
312     printf("-t , --stack                   place each slave in a seperate frame (no master movie)\n");
313     printf("-T , --stack1                  place each slave in the first frame (no master movie)\n");
314     printf("-m , --merge                   Don't store the slaves in Sprites/MovieClips\n");
315     printf("-a , --cat                     concatenate all slave files (no master movie)\n");
316     printf("-l , --overlay                 Don't remove any master objects, only overlay new objects\n");
317     printf("-c , --clip                    Clip the slave objects by the corresponding master objects\n");
318     printf("-v , --verbose                 Be verbose. Use more than one -v for greater effect \n");
319     printf("-F , --flashversion            Set the flash version of the output file.\n");
320     printf("-d , --dummy                   Don't require slave objects (for changing movie attributes)\n");
321     printf("-f , --frame                   The following identifier is a frame or framelabel, not an id or objectname\n");
322     printf("-x , --movex <xpos>            x Adjust position of slave by <xpos> pixels\n");
323     printf("-y , --movey <ypos>            y Adjust position of slave by <ypos> pixels\n");
324     printf("-s , --scale <scale>           Adjust size of slave by <scale> percent (e.g. 100%% = original size)\n");
325     printf("-r , --rate <fps>              Set movie framerate to <fps> (frames/sec)\n");
326     printf("-X , --width <width>           Force movie bbox width to <width> (default: use master width (not with -t))\n");
327     printf("-Y , --height <height>          Force movie bbox height to <height> (default: use master height (not with -t))\n");
328     printf("-N , --local-with-networking     Make output file \"local-with-networking\"\n");
329     printf("-G , --hardware-gpu            Set the \"use hardware gpu\" bit in the output file\n");
330     printf("-B , --accelerated-blit        Set the \"use accelerated blit\" bit in the output file\n");
331     printf("-L , --local-with-filesystem     Make output file \"local-with-filesystem\"\n");
332     printf("-z , --zlib <zlib>             Enable Flash 6 (MX) Zlib Compression\n");
333     printf("\n");
334 }
335
336 void removeCommonTags(SWF * swf)
337 {
338     TAG*tag = swf->firstTag;
339     while(tag) {
340         if(tag->id == ST_SCENEDESCRIPTION ||
341            tag->id == ST_FILEATTRIBUTES ||
342            tag->id == ST_REFLEX) {
343             tag = swf_DeleteTag(swf, tag);
344         } else {
345             tag = tag->next;
346         }
347     }
348 }
349
350 static void makestackmaster(SWF*swf)
351 {
352     TAG*tag;
353     int t;
354     SRECT box;
355     int fileversion = config.zlib?6:3;
356     int frameRate = 256;
357     U32 fileAttributes = 0;
358     RGBA rgb;
359     rgb.r=rgb.b=rgb.g=0;
360     memset(&box, 0, sizeof(box));
361
362     /* scan all slaves for bounding box */
363     for(t=numslaves-1;t>=0;t--)
364     {
365         SWF head;
366         int ret;
367         int fi=open(slave_filename[t],O_RDONLY|O_BINARY);
368         TAG*tag;
369         if(fi<0 || swf_ReadSWF(fi, &head)<0) {
370             msg("<fatal> Couldn't open/read %s.", slave_filename[t]);
371             exit(1);
372         }
373         close(fi);
374         swf_RemoveJPEGTables(&head);
375         fileAttributes |= head.fileAttributes;
376         removeCommonTags(&head);
377
378         msg("<verbose> File %s has bounding box %d:%d:%d:%d\n",
379                 slave_filename[t], 
380                 head.movieSize.xmin, head.movieSize.ymin,
381                 head.movieSize.xmax, head.movieSize.ymax);
382
383         tag = head.firstTag;
384         while(tag) {
385             if(tag->id == ST_SETBACKGROUNDCOLOR && tag->len>=3) {
386                 rgb.r = tag->data[0];
387                 rgb.g = tag->data[1];
388                 rgb.b = tag->data[2];
389             }
390             tag=tag->next;
391         }
392         frameRate = head.frameRate;
393         if(head.fileVersion > fileversion)
394             fileversion = head.fileVersion;
395         if(!t)
396             box = head.movieSize;
397         else {
398             if(head.movieSize.xmin < box.xmin)
399                 box.xmin = head.movieSize.xmin;
400             if(head.movieSize.ymin < box.ymin)
401                 box.ymin = head.movieSize.ymin;
402             if(head.movieSize.xmax > box.xmax)
403                 box.xmax = head.movieSize.xmax;
404             if(head.movieSize.ymax > box.ymax)
405                 box.ymax = head.movieSize.ymax;
406         }
407         msg("<verbose> New master bounding box is %d:%d:%d:%d\n",
408                 box.xmin, box.ymin,
409                 box.xmax, box.ymax);
410         swf_FreeTags(&head);
411     }
412
413     memset(swf, 0, sizeof(SWF));
414     swf->fileVersion = fileversion;
415     swf->movieSize = box;
416     swf->frameRate = frameRate;
417     swf->fileAttributes = fileAttributes;
418
419     swf->firstTag = swf_InsertTag(0, ST_SETBACKGROUNDCOLOR);
420     tag = swf->firstTag;
421     swf_SetRGB(tag, &rgb);
422     
423     for(t=0;t<numslaves;t++)
424     {
425         char buf[128];
426         sprintf(buf, "Frame%02d", t);
427         slave_name[t] = strdup(buf);
428
429         tag = swf_InsertTag(tag, ST_DEFINESPRITE);
430         swf_SetU16(tag, t+1);
431         swf_SetU16(tag, 0);
432         tag = swf_InsertTag(tag, ST_END);
433         tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
434         swf_ObjectPlace(tag, t+1, 1+t,0,0, slave_name[t]);
435
436         if(!config.stack1 || t == numslaves-1) {
437             tag = swf_InsertTag(tag, ST_SHOWFRAME);
438         }
439         if(!config.stack)
440         if(t!=numslaves-1)
441         {
442             tag = swf_InsertTag(tag, ST_REMOVEOBJECT2);
443             swf_SetU16(tag, 1+t);
444         }
445     }
446     tag = swf_InsertTag(tag, ST_END);
447     msg("<verbose> temporary SWF created");
448 }
449
450 static char* slavename = 0;
451 static int slaveid = -1;
452 static int slaveframe = -1;
453 static char masterbitmap[65536];
454 static char depthbitmap[65536];
455
456 #define FLAGS_WRITEDEFINES 1
457 #define FLAGS_WRITENONDEFINES 2
458 #define FLAGS_WRITESPRITE 4
459 #define FLAGS_WRITESLAVE 8
460
461 int get_free_id(char*bitmap)
462 {
463     int t;
464     for(t=1;t<65536;t++)
465         if(!bitmap[t]) {
466             bitmap[t] = 1;
467             return t;
468         }
469     return -1;
470 }
471
472 void jpeg_assert(SWF*master, SWF*slave)
473 {
474     /* TODO: if there's a jpegtable found, store it
475        and handle it together with the flash file
476        headers */
477
478     /* check that master and slave don't have both
479        jpegtables (which would be fatal) */
480     int pos;
481     TAG *mpos=0, *spos=0;
482     TAG *mtag,*stag;
483     pos = 0;
484     mtag = master->firstTag;
485     stag = slave->firstTag;
486     while(mtag)
487     {
488         if(mtag->id  == ST_JPEGTABLES)
489             mpos = mtag;
490         mtag = mtag->next;
491     }
492     while(stag)
493     {
494         if(stag->id == ST_JPEGTABLES)
495             spos = stag;
496         stag = stag->next;
497     }
498     if(mpos && spos)
499     {
500         if(spos->len == mpos->len &&
501         !memcmp(spos->data, mpos->data, mpos->len))
502         {
503             // ok, both have jpegtables, but they're identical.
504             // delete one and don't throw an error
505             swf_DeleteTag(slave, spos);
506             spos = 0;
507         }
508     }
509     if(spos && mpos) {
510         msg("<error> Master and slave have incompatible JPEGTABLES.");
511     }
512 }
513
514 TAG* write_sprite_defines(TAG*tag, SWF*sprite)
515 {
516     TAG*rtag = sprite->firstTag;
517     while(rtag && rtag->id!=ST_END) {
518         if(!swf_isAllowedSpriteTag(rtag)) {
519             msg("<debug> processing sprite tag %02x", tag->id);
520             if(swf_isDefiningTag(rtag))
521             {
522                 msg("<debug> [sprite defs] write tag %02x (%d bytes in body)", 
523                         tag->id, tag->len);
524                 tag = swf_InsertTag(tag, rtag->id);
525                 swf_SetBlock(tag, rtag->data, rtag->len);
526             }
527             else if(swf_isPseudoDefiningTag(rtag))
528             {
529                 msg("<debug> [sprite defs] write tag %02x (%d bytes in body)", 
530                         tag->id, tag->len);
531                 tag = swf_InsertTag(tag, rtag->id);
532                 swf_SetBlock(tag, rtag->data, rtag->len);
533             }
534             else {
535                 switch(rtag->id)
536                 {
537                     case ST_JPEGTABLES:
538                            /* if we get here, jpeg_assert has already run,
539                               ensuring this is the only one of it's kind,
540                               so we may safely write it out */
541                            tag = swf_InsertTag(tag, rtag->id);
542                            swf_SetBlock(tag, rtag->data, rtag->len);
543                        break;
544                     case ST_EXPORTASSETS:
545                        msg("<debug> deliberately ignoring EXPORTASSETS tag");
546                        break;
547                     case ST_ENABLEDEBUGGER:
548                        msg("<debug> deliberately ignoring ENABLEDEBUGGER tag");
549                        break;
550                     case ST_SETBACKGROUNDCOLOR:
551                        msg("<debug> deliberately ignoring BACKGROUNDCOLOR tag");
552                        break;
553                     case ST_SHOWFRAME:
554                        msg("<debug> deliberately ignoring SHOWFRAME tag");
555                        break;
556                     case ST_REFLEX:
557                        msg("<debug> deliberately ignoring REFLEX tag");
558                        break;
559                     case 40:
560                     case 49:
561                     case 51:
562                        msg("<notice> found tag %d. This is a Generator template, isn't it?", rtag->id);
563                        break;
564                     default:
565                        msg("<notice> funny tag: %d is neither defining nor sprite", rtag->id);
566                 }
567             }
568         }
569         rtag = rtag->next;
570     }
571     return tag;
572 }
573
574 void changedepth(TAG*tag, int add)
575 {
576     if(tag->id == ST_PLACEOBJECT)
577         PUT16(&tag->data[2],GET16(&tag->data[2])+add);
578     if(tag->id == ST_PLACEOBJECT2)
579         PUT16(&tag->data[1],GET16(&tag->data[1])+add);
580     if(tag->id == ST_REMOVEOBJECT)
581         PUT16(&tag->data[2],GET16(&tag->data[2])+add);
582     if(tag->id == ST_REMOVEOBJECT2)
583         PUT16(&tag->data[0],GET16(&tag->data[0])+add);
584     if(tag->id == ST_PLACEOBJECT2) {
585         SWFPLACEOBJECT obj;
586         U8 flags;
587         swf_SetTagPos(tag, 0);
588         flags = swf_GetU8(tag);
589         if(flags&2) swf_GetU16(tag); //id
590         if(flags&4) swf_GetMatrix(tag, 0);
591         if(flags&8) swf_GetCXForm(tag, 0,1);
592         if(flags&16) swf_GetU16(tag); //ratio
593         if(flags&64) {
594             swf_ResetReadBits(tag);
595             printf("%d->%d\n", GET16(&tag->data[tag->pos]),
596                                GET16(&tag->data[tag->pos])+add);
597             PUT16(&tag->data[tag->pos],GET16(&tag->data[tag->pos])+add);
598         }
599         msg("<warning> Depth relocation not fully working yet with clipdepths", tag->id);
600     }
601 }
602
603 void matrix_adjust(MATRIX*m, int movex, int movey, float scalex, float scaley, int scalepos)
604 {
605     m->sx = (int)(m->sx*scalex);
606     m->sy = (int)(m->sy*scaley);
607     m->r1 = (int)(m->r1*scalex);
608     m->r0 = (int)(m->r0*scaley);
609     if(scalepos) {
610         m->tx *= scalex;
611         m->ty *= scaley;
612     }
613     m->tx += movex;
614     m->ty += movey;
615 }
616
617 void write_changepos(TAG*output, TAG*tag, int movex, int movey, float scalex, float scaley, int scalepos)
618 {
619     if(movex || movey || scalex != 1.0 || scaley != 1.0)
620     {
621         switch(tag->id)
622         {
623             case ST_PLACEOBJECT2: {
624                 MATRIX m;
625                 U8 flags;
626                 swf_GetMatrix(0, &m);
627                 tag->pos = 0;
628                 tag->readBit = 0;
629
630                 flags = swf_GetU8(tag);
631                 swf_SetU8(output, flags|4);
632                 swf_SetU16(output, swf_GetU16(tag)); //depth
633                 //flags&1: move
634                 if(flags&2) {
635                     swf_SetU16(output, swf_GetU16(tag)); //id
636                 }
637                 // flags & 4
638                 if(flags&4) {
639                     swf_GetMatrix(tag, &m);
640                 } else {
641                     swf_GetMatrix(0, &m);
642                 }
643                 matrix_adjust(&m, movex, movey, scalex, scaley, scalepos);
644                 swf_SetMatrix(output, &m);
645
646                 if (tag->readBit)  { tag->pos++; tag->readBit = 0; } //swf_ResetReadBits(tag);
647
648                 swf_SetBlock(output, &tag->data[tag->pos], tag->len - tag->pos);
649                 break;
650             }
651             case ST_PLACEOBJECT: {
652                 MATRIX m;
653                 swf_SetU16(output, swf_GetU16(tag)); //id
654                 swf_SetU16(output, swf_GetU16(tag)); //depth
655                 
656                 swf_GetMatrix(tag, &m);
657                 matrix_adjust(&m, movex, movey, scalex, scaley, scalepos);
658                 swf_SetMatrix(output, &m);
659                 
660                 if (tag->readBit)  { tag->pos++; tag->readBit = 0; } //swf_ResetReadBits(tag);
661
662                 swf_SetBlock(output, &tag->data[tag->pos], tag->len - tag->pos);
663                 break;
664             }
665             default:
666             swf_SetBlock(output, tag->data, tag->len);
667         }
668     } 
669     else 
670     {
671             swf_SetBlock(output, tag->data, tag->len);
672     }
673 }
674
675 TAG* write_sprite(TAG*tag, SWF*sprite, int spriteid, int replaceddefine)
676 {
677     TAG* definespritetag;
678     TAG* rtag;
679     int tmp;
680
681     definespritetag = tag = swf_InsertTag(tag, ST_DEFINESPRITE);
682     swf_SetU16(tag, spriteid);
683     swf_SetU16(tag, sprite->frameCount);
684     msg ("<notice> sprite id is %d", spriteid);
685
686     tmp = sprite->frameCount;
687     msg("<debug> %d frames to go",tmp);
688
689     if(config.clip) {
690         tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
691         swf_SetU8(tag, 2+64); //flags: character+clipdepth
692         swf_SetU16(tag, 0); //depth
693         swf_SetU16(tag, replaceddefine); //id
694         swf_SetU16(tag, 65535); //clipdepth
695     }
696
697     if(config.overlay && !config.isframe) {
698         tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
699         swf_SetU8(tag, 2); //flags: character
700         swf_SetU16(tag, 1); //depth
701         swf_SetU16(tag, replaceddefine); //id
702     }
703
704     rtag = sprite->firstTag;
705     while(rtag && rtag->id!=ST_END)
706     {
707         if (swf_isAllowedSpriteTag(rtag)) {
708
709             msg("<debug> [sprite main] write tag %02x (%d bytes in body)", 
710                     rtag->id, rtag->len);
711             tag = swf_InsertTag(tag, rtag->id);
712             write_changepos(tag, rtag, config.movex, config.movey, config.scalex, config.scaley, 0);
713
714             if(config.clip || (config.overlay && !config.isframe))
715                 changedepth(tag, +2);
716
717             if(tag->id == ST_SHOWFRAME)
718             {
719                 tmp--;
720                 msg("<debug> %d frames to go",tmp);
721             }
722         }
723         rtag = rtag->next;
724     }
725     tag = swf_InsertTag(tag, ST_END);
726     return tag;
727 }
728
729 static char tag_ok_for_slave(int id)
730 {
731     if(id == ST_SETBACKGROUNDCOLOR)
732         return 0;
733     return 1;
734 }
735
736 TAG* write_master(TAG*tag, SWF*master, SWF*slave, int spriteid, int replaceddefine, int flags)
737 {
738     int outputslave = 0;
739     int frame = 1;
740     int sframe = 0;
741     int slavewritten = 0;
742     int deletedepth = -1;
743
744     TAG* rtag = master->firstTag;
745     TAG* stag = slave->firstTag;
746
747     while(rtag && rtag->id!=ST_END)
748     {
749         if(rtag->id == ST_SHOWFRAME && outputslave)
750         {
751             while(stag && stag->id!=ST_END) {
752                 if(stag->id == ST_SHOWFRAME) {
753                     stag = stag->next;
754                     sframe++;
755                     break;
756                 }
757                 if(tag_ok_for_slave(stag->id)) {
758                     tag = swf_InsertTag(tag, stag->id);
759                     write_changepos(tag, stag, config.movex, config.movey, config.scalex, config.scaley, 0);
760                 }
761                 stag = stag->next;
762             }
763         }
764         if(rtag->id == ST_SHOWFRAME)
765         {
766             frame ++;
767             tag = swf_InsertTag(tag, ST_SHOWFRAME);
768             if(deletedepth>=0) {
769                 tag = swf_InsertTag(tag, ST_REMOVEOBJECT2);
770                 swf_SetU16(tag, deletedepth);
771                 deletedepth=-1;
772             }
773             rtag = rtag->next;
774             continue;
775         }
776
777         if(swf_isDefiningTag(rtag) && (flags&FLAGS_WRITEDEFINES))
778         {
779             msg("<debug> [master] write tag %02x (%d bytes in body)", 
780                     rtag->id, rtag->len);
781             if(swf_GetDefineID(rtag) == spriteid && !config.isframe)
782             {
783                 if(config.overlay)
784                 {
785                     tag = swf_InsertTag(tag, rtag->id);
786                     swf_SetBlock(tag, rtag->data, rtag->len);
787                     swf_SetDefineID(tag, replaceddefine);
788                 } else {
789                     /* don't write this tag */
790                     msg("<verbose> replacing tag %d ID %d with sprite", rtag->id ,spriteid);
791                 }
792
793                 if(flags&FLAGS_WRITESPRITE)
794                 {
795                     msg("<debug> writing sprite defines");
796                     tag = write_sprite_defines(tag, slave);
797                     msg("<debug> writing sprite");
798                     tag = write_sprite(tag, slave, spriteid, replaceddefine);
799                 }
800                 if(flags&FLAGS_WRITESLAVE)
801                 {
802                     msg("<debug> writing slave");
803                     outputslave = 1;
804                 }
805             } else { 
806                 tag = swf_InsertTag(tag, rtag->id);
807                 swf_SetBlock(tag, rtag->data, rtag->len);
808             }
809         }
810         if(frame == slaveframe) /* only happens with config.isframe: put slave at specific frame */
811         {
812             if(flags&FLAGS_WRITESLAVE) {
813                 outputslave = 1;
814                 slavewritten = 1;
815             }
816             if((flags&FLAGS_WRITESPRITE) && !slavewritten)
817             {
818                 int id = get_free_id(masterbitmap);
819                 int depth = 65535;
820                 deletedepth = 65535;
821                 if(config.clip) {
822                     msg("<fatal> Can't combine --clip and --frame");
823                 }
824                 
825                 tag = write_sprite_defines(tag, slave);
826                 tag = write_sprite(tag, slave, id, -1);
827
828                 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
829                     swf_SetU8(tag, 2); //flags: id
830                     swf_SetU16(tag, depth);
831                     swf_SetU16(tag, id);
832
833                 slavewritten = 1;
834             }
835         }
836         if(!swf_isDefiningTag(rtag) && (flags&FLAGS_WRITENONDEFINES))
837         {
838             int dontwrite = 0;
839             switch(rtag->id) {
840                 case ST_PLACEOBJECT:
841                 case ST_PLACEOBJECT2:
842                     if(frame == slaveframe && !config.overlay)
843                         dontwrite = 1;
844                 case ST_REMOVEOBJECT:
845                     /* place/removetags for the object we replaced
846                        should be discarded, too, as the object to insert 
847                        isn't a sprite 
848                      */
849                     if(spriteid>=0 && swf_GetPlaceID(rtag) == spriteid && 
850                             !config.isframe && config.merge)
851                         dontwrite = 1;
852                 break;
853                 case ST_REMOVEOBJECT2:
854                 break;
855             }
856             if(!dontwrite) {
857                 msg("<debug> [master] write tag %02x (%d bytes in body)", 
858                         rtag->id, rtag->len);
859                 tag = swf_InsertTag(tag, rtag->id);
860                 write_changepos(tag, rtag, config.mastermovex, config.mastermovey, config.masterscalex, config.masterscaley, 1);
861                 
862             }
863         }
864         rtag = rtag->next;
865     }
866    
867     if(outputslave) 
868     while(stag && stag->id!=ST_END)
869     {
870             if(tag_ok_for_slave(stag->id)) {
871                 msg("<debug> [slave] write tag %02x (%d bytes in body), %.2f %.2f", rtag->id, rtag->len, config.movex /20.0, config.movey /20.0);
872                 tag = swf_InsertTag(tag, stag->id);
873                 write_changepos(tag, stag, config.movex, config.movey, config.scalex, config.scaley, 0);
874             }
875             stag = stag->next;
876     }
877     if(!slavewritten && config.isframe && (flags&(FLAGS_WRITESLAVE|FLAGS_WRITESPRITE)))
878     {
879         if(slaveframe>=0)
880             msg("<warning> Frame %d doesn't exist in file. No substitution will occur",
881                     slaveframe);
882         else
883             msg("<warning> Frame \"%s\" doesn't exist in file. No substitution will occur",
884                     slavename);
885     }
886     tag = swf_InsertTag(tag, ST_END);
887     return tag;
888 }
889
890 void adjustheader(SWF*swf)
891 {
892     if(config.framerate)
893         swf->frameRate = config.framerate;
894     if(config.hassizex) {
895         swf->movieSize.xmax = 
896         swf->movieSize.xmin + config.sizex;
897     }
898     if(config.hassizey) {
899         swf->movieSize.ymax = 
900         swf->movieSize.ymin + config.sizey;
901     }
902     if(config.flashversion)
903         swf->fileVersion = config.flashversion;
904 }
905
906 void catcombine(SWF*master, char*slave_name, SWF*slave, SWF*newswf)
907 {
908     char* depths;
909     int t;
910     TAG*tag;
911     TAG*mtag,*stag;
912     if(config.isframe) {
913         msg("<fatal> Can't combine --cat and --frame");
914         exit(1);
915     }
916     if(config.flashversion)
917         master->fileVersion = config.flashversion;
918    
919     tag = master->firstTag;
920     while(tag)
921     {
922         if(swf_isDefiningTag(tag)) {
923             int defineid = swf_GetDefineID(tag);
924             msg("<debug> tagid %02x defines object %d", tag->id, defineid);
925             masterbitmap[defineid] = 1;
926         }
927         tag = tag->next;
928     }
929     
930     swf_Relocate(slave, masterbitmap);
931     jpeg_assert(master, slave);
932     
933     memcpy(newswf, master, sizeof(SWF));
934     adjustheader(newswf);
935
936     tag = newswf->firstTag = swf_InsertTag(0, ST_REFLEX); // to be removed later
937
938     depths = malloc(65536);
939     if(!depths) {
940         msg("<fatal> Couldn't allocate %d bytes of memory", 65536);
941         return;
942     }
943     memset(depths, 0, 65536);
944     mtag = master->firstTag;
945     while(mtag && mtag->id!=ST_END)
946     {
947         int num=1;
948         U16 depth;
949         msg("<debug> [master] write tag %02x (%d bytes in body)", 
950                 mtag->id, mtag->len);
951         switch(mtag->id) {
952             case ST_PLACEOBJECT2:
953                 num++;
954             case ST_PLACEOBJECT: {
955                depth = swf_GetDepth(mtag);
956                depths[depth] = 1;
957             }
958             break;
959             case ST_REMOVEOBJECT: {
960                depth = swf_GetDepth(mtag);
961                depths[depth] = 0;
962             }
963             break;
964             case ST_REMOVEOBJECT2: {
965                depth = swf_GetDepth(mtag);
966                depths[depth] = 0;
967             }
968             break;
969         }
970         tag = swf_InsertTag(tag, mtag->id);
971         swf_SetBlock(tag, mtag->data, mtag->len);
972
973         mtag = mtag->next;
974     }
975
976     for(t=0;t<65536;t++) 
977     if(depths[t])
978     {
979         char data[16];
980         int len;
981         tag = swf_InsertTag(tag, ST_REMOVEOBJECT2);
982         swf_SetU16(tag, t);
983     }
984     free(depths);
985
986     stag = slave->firstTag;
987     while(stag && stag->id!=ST_END)
988     {
989         msg("<debug> [slave] write tag %02x (%d bytes in body)", 
990                 stag->id, stag->len);
991         tag = swf_InsertTag(tag, stag->id);
992         swf_SetBlock(tag, stag->data, stag->len);
993         stag = stag->next;
994     }
995     tag = swf_InsertTag(tag, ST_END);
996
997     swf_DeleteTag(newswf, tag);
998 }
999
1000 void normalcombine(SWF*master, char*slave_name, SWF*slave, SWF*newswf)
1001 {
1002     int spriteid = -1;
1003     int replaceddefine = -1;
1004     int frame = 0;
1005     char*framelabel;
1006     TAG * tag = master->firstTag;
1007
1008     memset(depthbitmap, 0, sizeof(depthbitmap));
1009     
1010     // set the idtab
1011     while(tag)
1012     {
1013         int depth = swf_GetDepth(tag);
1014         if(depth>=0) {
1015             depthbitmap[depth] = 1;
1016         }
1017         if(swf_isDefiningTag(tag)) {
1018             int defineid = swf_GetDefineID(tag);
1019             msg("<debug> tagid %02x defines object %d", tag->id, defineid);
1020             masterbitmap[defineid] = 1;
1021
1022             if (!slavename && defineid==slaveid) {
1023                 if(defineid>=0) {
1024                   spriteid = defineid;
1025                   msg("<notice> Slave file attached to object %d.", defineid);
1026                 }
1027             }
1028         } else if(tag->id == ST_EXPORTASSETS) {
1029             int t;
1030             int num = swf_GetU16(tag);
1031             for(t=0;t<num;t++)
1032             {
1033                 U16 id = swf_GetU16(tag);
1034                 char*name = swf_GetString(tag);
1035                 if(spriteid<0 && slavename && !strcmp(name,slavename)) {
1036                     spriteid = id;
1037                     msg("<notice> Slave file attached to object %d exported as %s.", id, name);
1038                 }
1039             }
1040         } else if(tag->id == ST_SYMBOLCLASS) {
1041             /* a symbolclass tag is like a define tag: it defines id 0000 */
1042             int num = swf_GetU16(tag);
1043             int t;
1044             for(t=0;t<num;t++) {
1045                 U16 id = swf_GetU16(tag);
1046                 if(!id) {
1047                     masterbitmap[id] = 1;
1048                 }
1049                 swf_GetString(tag);
1050             }
1051         } else if(tag->id == ST_PLACEOBJECT2) {
1052             char * name = swf_GetName(tag);
1053             int id = swf_GetPlaceID(tag);
1054
1055             {
1056                 SWFPLACEOBJECT obj;
1057                 swf_GetPlaceObject(tag, &obj);
1058                 swf_PlaceObjectFree(&obj);
1059                 if(obj.clipdepth) {
1060                     depthbitmap[obj.clipdepth] = 1;
1061                 }
1062             }
1063
1064             if(name)
1065               msg("<verbose> tagid %02x places object %d named \"%s\"", tag->id, id, name);
1066             else
1067               msg("<verbose> tagid %02x places object %d (no name)", tag->id, id);
1068
1069             if (name && slavename && !strcmp(name,slavename)) {
1070                 if(id>=0) {
1071                   spriteid = id;
1072                   msg("<notice> Slave file attached to named object %s (%d).", name, id);
1073                 }
1074             }
1075         } else if(tag->id == ST_SHOWFRAME) {
1076             if(slaveframe>=0 && frame==slaveframe) {
1077                 msg("<notice> Slave file attached to frame %d.", frame);
1078             }
1079             frame++;
1080         } else if(tag->id == ST_FRAMELABEL) {
1081             char * name = tag->data;
1082             if(name && slavename && config.isframe && !strcmp(name, slavename)) {
1083                 slaveframe = frame;
1084                 msg("<notice> Slave file attached to frame %d (%s).", frame, name);
1085             }
1086         }
1087         tag = tag->next;
1088     };
1089
1090     if (spriteid<0 && !config.isframe) {
1091         if(slavename) {
1092             if(strcmp(slavename,"!!dummy!!")) {
1093                 msg("<warning> Didn't find anything named %s in file. No substitutions will occur.", slavename);
1094                 if(!strcmp(slavename, "swf")) {
1095                     msg("<warning> (If you were trying to combine rfxview with a document, try replacing 'swf' with 'viewport'.");
1096                 }
1097             }
1098         }
1099         else
1100             msg("<warning> Didn't find id %d in file. No substitutions will occur.", slaveid);
1101         spriteid = get_free_id(masterbitmap);
1102     }
1103
1104     swf_Relocate (slave, masterbitmap);
1105     
1106     if(config.merge)
1107         swf_RelocateDepth (slave, depthbitmap);
1108     jpeg_assert(slave, master);
1109     
1110     if (config.overlay)
1111         replaceddefine = get_free_id(masterbitmap);
1112     
1113     // write file 
1114
1115     memcpy(newswf, master, sizeof(SWF));
1116     adjustheader(newswf);
1117
1118     newswf->firstTag = tag = swf_InsertTag(0, ST_REFLEX); // to be removed later
1119
1120     if (config.antistream) {
1121         if (config.merge) {
1122             msg("<fatal> Can't combine --antistream and --merge");
1123         }
1124         tag = write_sprite_defines(tag, slave);
1125         tag = write_sprite(tag, slave, spriteid, replaceddefine);
1126         tag = write_master(tag, master, slave, spriteid, replaceddefine, FLAGS_WRITEDEFINES);
1127         tag = write_master(tag, master, slave, spriteid, replaceddefine, FLAGS_WRITENONDEFINES);
1128     } else {
1129         if (config.merge)
1130             tag = write_master(tag, master, slave, spriteid, replaceddefine, 
1131                 FLAGS_WRITEDEFINES|FLAGS_WRITENONDEFINES|   FLAGS_WRITESLAVE    );
1132         else
1133             tag = write_master(tag, master, slave, spriteid, replaceddefine, 
1134                 FLAGS_WRITEDEFINES|FLAGS_WRITENONDEFINES|   FLAGS_WRITESPRITE   );
1135     }
1136
1137     swf_DeleteTag(newswf, newswf->firstTag);
1138 }
1139
1140 void combine(SWF*master, char*slave_name, SWF*slave, SWF*newswf)
1141 {
1142     slavename = slave_name;
1143     slaveid = -1;
1144     slaveframe = -1;
1145
1146     if(!master->fileVersion && slave)
1147         master->fileVersion = slave->fileVersion;
1148         
1149     master->fileAttributes |= slave->fileAttributes;
1150
1151     swf_FoldAll(master);
1152     swf_FoldAll(slave);
1153
1154     if(slavename[0] == '#')
1155     {
1156         slaveid = atoi(&slavename[1]);
1157         slavename = 0;
1158     }
1159
1160     if(config.isframe)
1161     {
1162         if(slavename && slavename[0]!='#') {
1163             int tmp;
1164             int len;
1165             sscanf(slavename, "%d%n", &tmp, &len);
1166             if(len == strlen(slavename)) {
1167             /* if the name the slave should replace 
1168                consists only of digits and the -f
1169                option is given, it probably is not
1170                a frame name but a frame number.
1171              */
1172                 slaveid = tmp;
1173                 slavename = 0;
1174             }
1175         }
1176
1177         if(slaveid>=0) {
1178             slaveframe = slaveid;
1179             slaveid = -1;
1180         } else {
1181         /* if id wasn't given as either #number or number,
1182            the name is a frame label. BTW: The user wouldn't necessarily have
1183            needed to supply the -f option in this case */
1184         }
1185     }
1186
1187     msg("<debug> move x (%d)", config.movex);
1188     msg("<debug> move y (%d)", config.movey);
1189     msg("<debug> scale x (%f)", config.scalex);
1190     msg("<debug> scale y (%f)", config.scaley);
1191     msg("<debug> master move x (%d)", config.mastermovex);
1192     msg("<debug> master move y (%d)", config.mastermovey);
1193     msg("<debug> master scale x (%f)", config.masterscalex);
1194     msg("<debug> master scale y (%f)", config.masterscaley);
1195     msg("<debug> is frame (%d)", config.isframe);
1196     
1197     memset(masterbitmap, 0, sizeof(masterbitmap));
1198
1199     if(config.cat) 
1200         return catcombine(master, slave_name, slave, newswf);
1201     else
1202         return normalcombine(master, slave_name, slave, newswf);
1203 }
1204
1205 int main(int argn, char *argv[])
1206 {
1207     int fi;
1208     SWF master;
1209     SWF slave;
1210     SWF newswf;
1211     int t;
1212
1213     config.overlay = 0; 
1214     config.antistream = 0; 
1215     config.alloctest = 0;
1216     config.cat = 0;
1217     config.merge = 0;
1218     config.clip = 0;
1219     config.loglevel = 2; 
1220     config.movex = 0;
1221     config.movey = 0;
1222     config.scalex = 1.0;
1223     config.scaley = 1.0;
1224     config.sizex = 0;
1225     config.sizey = 0;
1226     config.masterscalex = 1.0;
1227     config.masterscaley = 1.0;
1228     config.mastermovex = 0;
1229     config.mastermovey = 0;
1230     config.hassizex = 0;
1231     config.hassizey = 0;
1232     config.framerate = 0;
1233     config.stack = 0;
1234     config.stack1 = 0;
1235     config.dummy = 0;
1236     config.zlib = 0;
1237
1238     processargs(argn, argv);
1239     initLog(0,-1,0,0,-1,config.loglevel);
1240
1241     if(config.merge && config.cat) {
1242         msg("<error> Can't combine --cat and --merge");
1243         exit(1);
1244     }
1245     
1246     if(config.stack && config.cat) {
1247         msg("<error> Can't combine --cat and --stack");
1248         exit(1);
1249     }
1250
1251     if(config.stack) {
1252         if(config.overlay) {
1253             msg("<error> Can't combine -l and -t");
1254             exit(1);
1255         }
1256         if(config.clip) {
1257             msg("<error> Can't combine -c and -t");
1258             exit(1);
1259         }
1260         msg("<verbose> (stacking) %d files found\n", numslaves);
1261
1262         makestackmaster(&master);
1263     }
1264     else {
1265         int ret;
1266         msg("<verbose> master entity %s (named \"%s\")\n", master_filename, master_name);
1267         fi = open(master_filename, O_RDONLY|O_BINARY);
1268         if(fi<0) {
1269             msg("<fatal> Failed to open %s\n", master_filename);
1270             exit(1);
1271         }
1272         ret = swf_ReadSWF(fi, &master);
1273         if(ret<0) {
1274             msg("<fatal> Failed to read from %s\n", master_filename);
1275             exit(1);
1276         }
1277         swf_RemoveJPEGTables(&master);
1278         removeCommonTags(&master);
1279         msg("<debug> Read %d bytes from masterfile\n", ret);
1280         close(fi);
1281     }
1282
1283     for(t=0;t<numslaves;t++) {
1284             msg("<verbose> slave entity(%d) %s (%s \"%s\")\n", t+1, slave_filename[t], 
1285                     slave_isframe[t]?"frame":"object", slave_name[t]);
1286     }
1287
1288     if(config.dummy)
1289     {
1290         if(numslaves)
1291         {
1292             msg("<error> --dummy (-d) implies there are zero slave objects. You supplied %d.", numslaves);
1293             exit(1);
1294         }
1295         numslaves = 1;
1296         slave_filename[0] = "!!dummy!!";
1297         slave_name[0] = "!!dummy!!";
1298         slave_isframe[0] = 0;
1299     }
1300
1301     if (config.alloctest)
1302     {
1303         char*bitmap = malloc(sizeof(char)*65536);
1304         memset(bitmap, 0, 65536*sizeof(char));
1305         memset(bitmap, 1, 101*sizeof(char));
1306         swf_Relocate(&master, bitmap);
1307         newswf = master;
1308         free(bitmap);
1309 //      makestackmaster(&newswf);
1310     }
1311     else
1312     {
1313         if (!numslaves)
1314         {
1315             if(config.cat)
1316                 msg("<error> You must have at least two objects.");
1317             else
1318                 msg("<error> You must have at least one slave entity.");
1319             return 0;
1320         }
1321         for(t = 0; t < numslaves; t++)
1322         {
1323             config.movex = slave_movex[t];
1324             config.movey = slave_movey[t];
1325             config.scalex = slave_scalex[t];
1326             config.scaley = slave_scaley[t];
1327             config.isframe = slave_isframe[t];
1328
1329             msg("<notice> Combine [%s]%s and [%s]%s", master_name, master_filename,
1330                     slave_name[t], slave_filename[t]);
1331             if(!config.dummy)
1332             {
1333                 int ret;
1334                 fi = open(slave_filename[t], O_RDONLY|O_BINARY);
1335                 if(!fi) {
1336                     msg("<fatal> Failed to open %s\n", slave_filename[t]);
1337                     exit(1);
1338                 }
1339                 ret = swf_ReadSWF(fi, &slave);
1340                 if(ret<0) {
1341                     msg("<fatal> Failed to read from %s\n", slave_filename[t]);
1342                     exit(1);
1343                 }
1344                 msg("<debug> Read %d bytes from slavefile\n", ret);
1345                 close(fi);
1346                 swf_RemoveJPEGTables(&slave);
1347                 removeCommonTags(&slave);
1348             }
1349             else
1350             {
1351                 memset(&slave, 0, sizeof(slave));
1352                 slave.firstTag = swf_InsertTag(0, ST_END);
1353                 slave.frameRate = 0;
1354                 slave.fileVersion = 0;
1355                 slave.frameCount = 0;
1356             }
1357
1358             combine(&master, slave_name[t], &slave, &newswf);
1359             master = newswf;
1360         }
1361         if(config.dummy && !config.hassizex && !config.hassizey && !config.mastermovex && !config.mastermovey) {
1362             newswf.movieSize.xmin = newswf.movieSize.xmin*config.masterscalex;
1363             newswf.movieSize.ymin = newswf.movieSize.ymin*config.masterscaley;
1364             newswf.movieSize.xmax = newswf.movieSize.xmax*config.masterscalex;
1365             newswf.movieSize.ymax = newswf.movieSize.ymax*config.masterscaley;
1366         }
1367     }
1368
1369     if(!newswf.fileVersion)
1370         newswf.fileVersion = 4;
1371
1372     if(config.local_with_filesystem)
1373         newswf.fileAttributes &= ~FILEATTRIBUTE_USENETWORK;
1374     if(config.local_with_networking)
1375         newswf.fileAttributes |= FILEATTRIBUTE_USENETWORK;
1376     if(config.accelerated_blit)
1377         newswf.fileAttributes |= FILEATTRIBUTE_USEACCELERATEDBLIT;
1378     if(config.hardware_gpu)
1379         newswf.fileAttributes |= FILEATTRIBUTE_USEHARDWAREGPU;
1380
1381     fi = open(outputname, O_BINARY|O_RDWR|O_TRUNC|O_CREAT, 0777);
1382
1383     if(config.zlib) {
1384         if(newswf.fileVersion < 6)
1385             newswf.fileVersion = 6;
1386         newswf.compressed = 1;
1387         swf_WriteSWF(fi, &newswf);
1388     } else {
1389         newswf.compressed = -1; // don't compress
1390         swf_WriteSWF(fi, &newswf);
1391     }
1392     close(fi);
1393
1394     return 0; //ok
1395 }
1396