fixed format warnings
[swftools.git] / src / swfcombine.c
index 8514bda..7daec9c 100644 (file)
@@ -3,9 +3,21 @@
 
    Part of the swftools package.
    
-   Copyright (c) 2001 Matthias Kramm <kramm@quiss.org> 
-
-   This file is distributed under the GPL, see file COPYING for details */
+   Copyright (c) 2001,2002,2003 Matthias Kramm <kramm@quiss.org> 
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
 
 #include <stdlib.h>
 #include <stdio.h>
@@ -28,11 +40,16 @@ struct config_t
    char cat;
    char merge;
    char isframe;
+   char local_with_networking;
+   char local_with_filesystem;
+   char accelerated_blit;
+   char hardware_gpu;
    int loglevel;
    int sizex;
    char hassizex;
    int sizey;
    char hassizey;
+   int flashversion;
    int framerate;
    int movex;
    int movey;
@@ -91,12 +108,14 @@ int args_callback_option(char*name,char*val) {
     }
     else if (!strcmp(name, "x"))
     {
-       config.movex = atoi(val);
+       float x = atof(val);
+       config.movex = (int)(x*20+0.5);
        return 1;
     }
     else if (!strcmp(name, "y"))
     {
-       config.movey = atoi(val);
+       float y = atof(val);
+       config.movey = (int)(y*20+0.5);
        return 1;
     }
     else if (!strcmp(name, "m"))
@@ -121,7 +140,13 @@ int args_callback_option(char*name,char*val) {
     }
     else if (!strcmp(name, "r"))
     {
-       config.framerate = atoi(val)*256/100;
+
+       float rate = atof(val);
+       if ((rate < 0) ||(rate >= 256.0)) {
+           fprintf(stderr, "Error: You must specify a valid framerate between 1/256 and 255.\n");
+           exit(1);
+       }
+       config.framerate = (int)(rate*256);
        return 1;
     }
     else if (!strcmp(name, "X"))
@@ -141,6 +166,36 @@ int args_callback_option(char*name,char*val) {
        config.scalex = config.scaley = atoi(val)/100.0;
        return 1;
     }
+    else if (!strcmp(name, "w"))
+    {
+       config.scalex = atoi(val)/100.0;
+       return 1;
+    }
+    else if (!strcmp(name, "h"))
+    {
+       config.scaley = atoi(val)/100.0;
+       return 1;
+    }
+    else if (!strcmp(name, "N"))
+    {
+       config.local_with_networking = 1;
+       return 0;
+    }
+    else if (!strcmp(name, "L"))
+    {
+       config.local_with_filesystem = 1;
+       return 0;
+    }
+    else if (!strcmp(name, "B"))
+    {
+       config.accelerated_blit = 1;
+       return 0;
+    }
+    else if (!strcmp(name, "G"))
+    {
+       config.hardware_gpu = 1;
+       return 0;
+    }
     else if (!strcmp(name, "t") || !strcmp(name, "T"))
     {
        if(master_filename) {
@@ -165,26 +220,30 @@ int args_callback_option(char*name,char*val) {
     }
 }
 
-struct options_t options[] =
-{{"o","output"},
- {"s","scale"},
- {"d","dummy"},
- {"x","xpos"},
- {"y","ypos"},
- {"X","width"},
- {"Y","height"},
- {"r","rate"},
- {"f","frame"},
- {"l","overlay"},
- {"m","merge"},
- {"t","stack"},
- {"T","stack1"},
- {"v","verbose"},
- {"V","version"},
- {"c","clip"},
- {"a","cat"},
- {"z","zlib"},
- {0,0}
+static struct options_t options[] = {
+{"o", "output"},
+{"t", "stack"},
+{"T", "stack1"},
+{"m", "merge"},
+{"a", "cat"},
+{"l", "overlay"},
+{"c", "clip"},
+{"v", "verbose"},
+{"F", "flashversion"},
+{"d", "dummy"},
+{"f", "frame"},
+{"x", "movex"},
+{"y", "movey"},
+{"s", "scale"},
+{"r", "rate"},
+{"X", "width"},
+{"Y", "height"},
+{"N", "local-with-networking"},
+{"G", "hardware-gpu"},
+{"B", "accelerated-blit"},
+{"L", "local-with-filesystem"},
+{"z", "zlib"},
+{0,0}
 };
 
 int args_callback_longoption(char*name,char*val) {
@@ -219,7 +278,7 @@ int args_callback_command(char*name, char*val) {
        config.movex = config.movey = 0;
        config.scalex = config.scaley = 1.0;
     } else {            
-       logf("<verbose> slave entity %s (named \"%s\")\n", filename, myname);
+       msg("<verbose> slave entity %s (named \"%s\")\n", filename, myname);
 
        slave_filename[numslaves] = filename;
        slave_name[numslaves] = myname;
@@ -236,30 +295,51 @@ int args_callback_command(char*name, char*val) {
     return 0;
 }
 
-void args_callback_usage(char*name)
+void args_callback_usage(char *name)
 {
+    printf("\n");
     printf("Usage: %s [-rXYomlcv] [-f] masterfile [-xysf] [(name1|#id1)=]slavefile1 .. [-xysf] [(nameN|#idN)=]slavefileN\n", name);
     printf("OR:    %s [-rXYomv] --stack[1] [-xysf] [(name1|#id1)=]slavefile1 .. [-xysf] [(nameN|#idN)=]slavefileN\n", name);
     printf("OR:    %s [-rXYov] --cat [-xysf] [(name1|#id1)=]slavefile1 .. [-xysf] [(nameN|#idN)=]slavefileN\n", name);
     printf("OR:    %s [-rXYomlcv] --dummy [-xys] [file]\n", name);
     printf("\n");
-    printf("-o outputfile       --output    explicitly specify output file. (otherwise, output.swf will be used)\n");
-    printf("-t                  --stack     place each slave in a seperate frame (no master movie)\n");
-    printf("-T                  --stack1    place each slave in the first frame (no master movie)\n");
-    printf("-m                  --merge     Don't store the slaves in Sprites/MovieClips\n");
-    printf("-a                  --cat       concatenate all slave files (no master movie)\n");
-    printf("-l                  --overlay   Don't remove any master objects, only overlay new objects\n");
-    printf("-c                  --clip      Clip the slave objects by the corresponding master objects\n");
-    printf("-v                  --verbose   Use more than one -v for greater effect \n");
-    printf("-d                  --dummy     Don't require slave objects \n");
-    printf("-f                  --frame     The following identifier is a frame or framelabel, not an id or objectname\n");
-    printf("-x xpos             --movex     x Adjust position of slave by xpos twips (1/20 pixel)\n");
-    printf("-y ypos             --movey     y Adjust position of slave by ypos twips (1/20 pixel)\n");
-    printf("-s scale            --scale     Adjust size of slave by scale%\n");
-    printf("-r framerate        --rate      Set movie framerate (100 frames/sec)\n");
-    printf("-X width            --width     Force movie width to scale (default: use master width (not with -t))\n");
-    printf("-Y height           --height    Force movie height to scale (default: use master height (not with -t))\n");
-    printf("-z zlib             --zlib      Enable Flash 6 (MX) Zlib Compression\n");
+    printf("-o , --output <outputfile>      explicitly specify output file. (otherwise, output.swf will be used)\n");
+    printf("-t , --stack                   place each slave in a seperate frame (no master movie)\n");
+    printf("-T , --stack1                  place each slave in the first frame (no master movie)\n");
+    printf("-m , --merge                   Don't store the slaves in Sprites/MovieClips\n");
+    printf("-a , --cat                     concatenate all slave files (no master movie)\n");
+    printf("-l , --overlay                 Don't remove any master objects, only overlay new objects\n");
+    printf("-c , --clip                    Clip the slave objects by the corresponding master objects\n");
+    printf("-v , --verbose                 Be verbose. Use more than one -v for greater effect \n");
+    printf("-F , --flashversion            Set the flash version of the output file.\n");
+    printf("-d , --dummy                   Don't require slave objects (for changing movie attributes)\n");
+    printf("-f , --frame                   The following identifier is a frame or framelabel, not an id or objectname\n");
+    printf("-x , --movex <xpos>            x Adjust position of slave by <xpos> pixels\n");
+    printf("-y , --movey <ypos>            y Adjust position of slave by <ypos> pixels\n");
+    printf("-s , --scale <scale>           Adjust size of slave by <scale> percent (e.g. 100%% = original size)\n");
+    printf("-r , --rate <fps>              Set movie framerate to <fps> (frames/sec)\n");
+    printf("-X , --width <width>           Force movie bbox width to <width> (default: use master width (not with -t))\n");
+    printf("-Y , --height <height>          Force movie bbox height to <height> (default: use master height (not with -t))\n");
+    printf("-N , --local-with-networking     Make output file \"local-with-networking\"\n");
+    printf("-G , --hardware-gpu            Set the \"use hardware gpu\" bit in the output file\n");
+    printf("-B , --accelerated-blit        Set the \"use accelerated blit\" bit in the output file\n");
+    printf("-L , --local-with-filesystem     Make output file \"local-with-filesystem\"\n");
+    printf("-z , --zlib <zlib>             Enable Flash 6 (MX) Zlib Compression\n");
+    printf("\n");
+}
+
+void removeCommonTags(SWF * swf)
+{
+    TAG*tag = swf->firstTag;
+    while(tag) {
+       if(tag->id == ST_SCENEDESCRIPTION ||
+          tag->id == ST_FILEATTRIBUTES ||
+          tag->id == ST_REFLEX) {
+           tag = swf_DeleteTag(swf, tag);
+       } else {
+           tag = tag->next;
+       }
+    }
 }
 
 static void makestackmaster(SWF*swf)
@@ -267,8 +347,9 @@ static void makestackmaster(SWF*swf)
     TAG*tag;
     int t;
     SRECT box;
-    int fileversion = 1;
+    int fileversion = config.zlib?6:3;
     int frameRate = 256;
+    U32 fileAttributes = 0;
     RGBA rgb;
     rgb.r=rgb.b=rgb.g=0;
     memset(&box, 0, sizeof(box));
@@ -278,14 +359,18 @@ static void makestackmaster(SWF*swf)
     {
        SWF head;
        int ret;
-       int fi=open(slave_filename[t],O_RDONLY);
+       int fi=open(slave_filename[t],O_RDONLY|O_BINARY);
        TAG*tag;
        if(fi<0 || swf_ReadSWF(fi, &head)<0) {
-           logf("<fatal> Couldn't open/read %s.", slave_filename[t]);
+           msg("<fatal> Couldn't open/read %s.", slave_filename[t]);
            exit(1);
        }
        close(fi);
-       logf("<verbose> File %s has bounding box %d:%d:%d:%d\n",
+       swf_RemoveJPEGTables(&head);
+        fileAttributes |= head.fileAttributes;
+       removeCommonTags(&head);
+
+       msg("<verbose> File %s has bounding box %d:%d:%d:%d\n",
                slave_filename[t], 
                head.movieSize.xmin, head.movieSize.ymin,
                head.movieSize.xmax, head.movieSize.ymax);
@@ -314,7 +399,7 @@ static void makestackmaster(SWF*swf)
            if(head.movieSize.ymax > box.ymax)
                box.ymax = head.movieSize.ymax;
        }
-       logf("<verbose> New master bounding box is %d:%d:%d:%d\n",
+       msg("<verbose> New master bounding box is %d:%d:%d:%d\n",
                box.xmin, box.ymin,
                box.xmax, box.ymax);
        swf_FreeTags(&head);
@@ -324,6 +409,7 @@ static void makestackmaster(SWF*swf)
     swf->fileVersion = fileversion;
     swf->movieSize = box;
     swf->frameRate = frameRate;
+    swf->fileAttributes = fileAttributes;
 
     swf->firstTag = swf_InsertTag(0, ST_SETBACKGROUNDCOLOR);
     tag = swf->firstTag;
@@ -353,13 +439,14 @@ static void makestackmaster(SWF*swf)
        }
     }
     tag = swf_InsertTag(tag, ST_END);
-    logf("<verbose> temporary SWF created");
+    msg("<verbose> temporary SWF created");
 }
 
 static char* slavename = 0;
 static int slaveid = -1;
 static int slaveframe = -1;
 static char masterbitmap[65536];
+static char depthbitmap[65536];
 
 #define FLAGS_WRITEDEFINES 1
 #define FLAGS_WRITENONDEFINES 2
@@ -410,12 +497,12 @@ void jpeg_assert(SWF*master, SWF*slave)
        {
            // ok, both have jpegtables, but they're identical.
            // delete one and don't throw an error
-           swf_DeleteTag(spos);
+           swf_DeleteTag(slave, spos);
            spos = 0;
        }
     }
     if(spos && mpos) {
-       logf("<error> Master and slave have incompatible JPEGTABLES.");
+       msg("<error> Master and slave have incompatible JPEGTABLES.");
     }
 }
 
@@ -424,17 +511,17 @@ TAG* write_sprite_defines(TAG*tag, SWF*sprite)
     TAG*rtag = sprite->firstTag;
     while(rtag && rtag->id!=ST_END) {
        if(!swf_isAllowedSpriteTag(rtag)) {
-           logf("<debug> processing sprite tag %02x", tag->id);
+           msg("<debug> processing sprite tag %02x", tag->id);
            if(swf_isDefiningTag(rtag))
            {
-               logf("<debug> [sprite defs] write tag %02x (%d bytes in body)", 
+               msg("<debug> [sprite defs] write tag %02x (%d bytes in body)", 
                        tag->id, tag->len);
                tag = swf_InsertTag(tag, rtag->id);
                swf_SetBlock(tag, rtag->data, rtag->len);
            }
            else if(swf_isPseudoDefiningTag(rtag))
            {
-               logf("<debug> [sprite defs] write tag %02x (%d bytes in body)", 
+               msg("<debug> [sprite defs] write tag %02x (%d bytes in body)", 
                        tag->id, tag->len);
                tag = swf_InsertTag(tag, rtag->id);
                swf_SetBlock(tag, rtag->data, rtag->len);
@@ -450,21 +537,27 @@ TAG* write_sprite_defines(TAG*tag, SWF*sprite)
                           swf_SetBlock(tag, rtag->data, rtag->len);
                       break;
                    case ST_EXPORTASSETS:
-                      logf("<debug> deliberately ignoring EXPORTASSETS tag");
+                      msg("<debug> deliberately ignoring EXPORTASSETS tag");
                       break;
                    case ST_ENABLEDEBUGGER:
-                      logf("<debug> deliberately ignoring ENABLEDEBUGGER tag");
+                      msg("<debug> deliberately ignoring ENABLEDEBUGGER tag");
                       break;
                    case ST_SETBACKGROUNDCOLOR:
-                      logf("<debug> deliberately ignoring BACKGROUNDCOLOR tag");
+                      msg("<debug> deliberately ignoring BACKGROUNDCOLOR tag");
+                      break;
+                   case ST_SHOWFRAME:
+                      msg("<debug> deliberately ignoring SHOWFRAME tag");
+                      break;
+                   case ST_REFLEX:
+                      msg("<debug> deliberately ignoring REFLEX tag");
                       break;
                    case 40:
                    case 49:
                    case 51:
-                      logf("<notice> found tag %d. This is a Generator template, isn't it?", tag->id);
+                      msg("<notice> found tag %d. This is a Generator template, isn't it?", rtag->id);
                       break;
                    default:
-                      logf("<notice> funny tag: %d is neither defining nor sprite", tag->id);
+                      msg("<notice> funny tag: %d is neither defining nor sprite", rtag->id);
                }
            }
        }
@@ -475,7 +568,6 @@ TAG* write_sprite_defines(TAG*tag, SWF*sprite)
 
 void changedepth(TAG*tag, int add)
 {
-    /* fucking byteorders */
     if(tag->id == ST_PLACEOBJECT)
        PUT16(&tag->data[2],GET16(&tag->data[2])+add);
     if(tag->id == ST_PLACEOBJECT2)
@@ -484,6 +576,23 @@ void changedepth(TAG*tag, int add)
        PUT16(&tag->data[2],GET16(&tag->data[2])+add);
     if(tag->id == ST_REMOVEOBJECT2)
        PUT16(&tag->data[0],GET16(&tag->data[0])+add);
+    if(tag->id == ST_PLACEOBJECT2) {
+       SWFPLACEOBJECT obj;
+       U8 flags;
+       swf_SetTagPos(tag, 0);
+       flags = swf_GetU8(tag);
+       if(flags&2) swf_GetU16(tag); //id
+       if(flags&4) swf_GetMatrix(tag, 0);
+       if(flags&8) swf_GetCXForm(tag, 0,1);
+       if(flags&16) swf_GetU16(tag); //ratio
+       if(flags&64) {
+           swf_ResetReadBits(tag);
+           printf("%d->%d\n", GET16(&tag->data[tag->pos]),
+                              GET16(&tag->data[tag->pos])+add);
+           PUT16(&tag->data[tag->pos],GET16(&tag->data[tag->pos])+add);
+       }
+       msg("<warning> Depth relocation not fully working yet with clipdepths", tag->id);
+    }
 }
 
 void matrix_adjust(MATRIX*m, int movex, int movey, float scalex, float scaley, int scalepos)
@@ -502,7 +611,7 @@ void matrix_adjust(MATRIX*m, int movex, int movey, float scalex, float scaley, i
 
 void write_changepos(TAG*output, TAG*tag, int movex, int movey, float scalex, float scaley, int scalepos)
 {
-    if(movex || movey || scalex != 1 || scaley != 1)
+    if(movex || movey || scalex != 1.0 || scaley != 1.0)
     {
        switch(tag->id)
        {
@@ -529,7 +638,8 @@ void write_changepos(TAG*output, TAG*tag, int movex, int movey, float scalex, fl
                matrix_adjust(&m, movex, movey, scalex, scaley, scalepos);
                swf_SetMatrix(output, &m);
 
-               //swf_ResetReadBits(tag);
+               if (tag->readBit)  { tag->pos++; tag->readBit = 0; } //swf_ResetReadBits(tag);
+
                swf_SetBlock(output, &tag->data[tag->pos], tag->len - tag->pos);
                break;
            }
@@ -542,7 +652,8 @@ void write_changepos(TAG*output, TAG*tag, int movex, int movey, float scalex, fl
                matrix_adjust(&m, movex, movey, scalex, scaley, scalepos);
                swf_SetMatrix(output, &m);
                
-               //swf_ResetReadBits(tag);
+               if (tag->readBit)  { tag->pos++; tag->readBit = 0; } //swf_ResetReadBits(tag);
+
                swf_SetBlock(output, &tag->data[tag->pos], tag->len - tag->pos);
                break;
            }
@@ -565,10 +676,10 @@ TAG* write_sprite(TAG*tag, SWF*sprite, int spriteid, int replaceddefine)
     definespritetag = tag = swf_InsertTag(tag, ST_DEFINESPRITE);
     swf_SetU16(tag, spriteid);
     swf_SetU16(tag, sprite->frameCount);
-    logf ("<notice> sprite id is %d", spriteid);
+    msg ("<notice> sprite id is %d", spriteid);
 
     tmp = sprite->frameCount;
-    logf("<debug> %d frames to go",tmp);
+    msg("<debug> %d frames to go",tmp);
 
     if(config.clip) {
        tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
@@ -590,17 +701,18 @@ TAG* write_sprite(TAG*tag, SWF*sprite, int spriteid, int replaceddefine)
     {
        if (swf_isAllowedSpriteTag(rtag)) {
 
-           logf("<debug> [sprite main] write tag %02x (%d bytes in body)", 
+           msg("<debug> [sprite main] write tag %02x (%d bytes in body)", 
                    rtag->id, rtag->len);
            tag = swf_InsertTag(tag, rtag->id);
            write_changepos(tag, rtag, config.movex, config.movey, config.scalex, config.scaley, 0);
-       
-           changedepth(tag, +2);
+
+           if(config.clip || (config.overlay && !config.isframe))
+               changedepth(tag, +2);
 
            if(tag->id == ST_SHOWFRAME)
            {
                tmp--;
-               logf("<debug> %d frames to go",tmp);
+               msg("<debug> %d frames to go",tmp);
            }
        }
        rtag = rtag->next;
@@ -619,9 +731,10 @@ static char tag_ok_for_slave(int id)
 TAG* write_master(TAG*tag, SWF*master, SWF*slave, int spriteid, int replaceddefine, int flags)
 {
     int outputslave = 0;
-    int frame = 0;
+    int frame = 1;
     int sframe = 0;
     int slavewritten = 0;
+    int deletedepth = -1;
 
     TAG* rtag = master->firstTag;
     TAG* stag = slave->firstTag;
@@ -638,7 +751,7 @@ TAG* write_master(TAG*tag, SWF*master, SWF*slave, int spriteid, int replaceddefi
                }
                if(tag_ok_for_slave(stag->id)) {
                    tag = swf_InsertTag(tag, stag->id);
-                   swf_SetBlock(tag, stag->data, stag->len);
+                   write_changepos(tag, stag, config.movex, config.movey, config.scalex, config.scaley, 0);
                }
                stag = stag->next;
            }
@@ -646,11 +759,19 @@ TAG* write_master(TAG*tag, SWF*master, SWF*slave, int spriteid, int replaceddefi
        if(rtag->id == ST_SHOWFRAME)
        {
            frame ++;
+           tag = swf_InsertTag(tag, ST_SHOWFRAME);
+            if(deletedepth>=0) {
+                tag = swf_InsertTag(tag, ST_REMOVEOBJECT2);
+                swf_SetU16(tag, deletedepth);
+                deletedepth=-1;
+            }
+           rtag = rtag->next;
+            continue;
        }
 
        if(swf_isDefiningTag(rtag) && (flags&FLAGS_WRITEDEFINES))
        {
-           logf("<debug> [master] write tag %02x (%d bytes in body)", 
+           msg("<debug> [master] write tag %02x (%d bytes in body)", 
                    rtag->id, rtag->len);
            if(swf_GetDefineID(rtag) == spriteid && !config.isframe)
            {
@@ -661,17 +782,19 @@ TAG* write_master(TAG*tag, SWF*master, SWF*slave, int spriteid, int replaceddefi
                    swf_SetDefineID(tag, replaceddefine);
                } else {
                    /* don't write this tag */
-                   logf("<verbose> replacing tag %d id %d with sprite", rtag->id
-                           ,spriteid);
+                   msg("<verbose> replacing tag %d ID %d with sprite", rtag->id ,spriteid);
                }
 
                if(flags&FLAGS_WRITESPRITE)
                {
+                   msg("<debug> writing sprite defines");
                    tag = write_sprite_defines(tag, slave);
+                   msg("<debug> writing sprite");
                    tag = write_sprite(tag, slave, spriteid, replaceddefine);
                }
                if(flags&FLAGS_WRITESLAVE)
                {
+                   msg("<debug> writing slave");
                    outputslave = 1;
                }
            } else { 
@@ -679,7 +802,7 @@ TAG* write_master(TAG*tag, SWF*master, SWF*slave, int spriteid, int replaceddefi
                swf_SetBlock(tag, rtag->data, rtag->len);
            }
        }
-       if(frame == slaveframe)
+       if(frame == slaveframe) /* only happens with config.isframe: put slave at specific frame */
        {
            if(flags&FLAGS_WRITESLAVE) {
                outputslave = 1;
@@ -688,9 +811,10 @@ TAG* write_master(TAG*tag, SWF*master, SWF*slave, int spriteid, int replaceddefi
            if((flags&FLAGS_WRITESPRITE) && !slavewritten)
            {
                int id = get_free_id(masterbitmap);
-               int depth = 0;
+               int depth = 65535;
+               deletedepth = 65535;
                if(config.clip) {
-                   logf("<fatal> Can't combine --clip and --frame");
+                   msg("<fatal> Can't combine --clip and --frame");
                }
                
                tag = write_sprite_defines(tag, slave);
@@ -725,10 +849,11 @@ TAG* write_master(TAG*tag, SWF*master, SWF*slave, int spriteid, int replaceddefi
                break;
            }
            if(!dontwrite) {
-               logf("<debug> [master] write tag %02x (%d bytes in body)", 
+               msg("<debug> [master] write tag %02x (%d bytes in body)", 
                        rtag->id, rtag->len);
                tag = swf_InsertTag(tag, rtag->id);
                write_changepos(tag, rtag, config.mastermovex, config.mastermovey, config.masterscalex, config.masterscaley, 1);
+               
            }
        }
        rtag = rtag->next;
@@ -738,18 +863,19 @@ TAG* write_master(TAG*tag, SWF*master, SWF*slave, int spriteid, int replaceddefi
     while(stag && stag->id!=ST_END)
     {
            if(tag_ok_for_slave(stag->id)) {
+               msg("<debug> [slave] write tag %02x (%d bytes in body), %.2f %.2f", rtag->id, rtag->len, config.movex /20.0, config.movey /20.0);
                tag = swf_InsertTag(tag, stag->id);
-               swf_SetBlock(tag, stag->data, stag->len);
+               write_changepos(tag, stag, config.movex, config.movey, config.scalex, config.scaley, 0);
            }
            stag = stag->next;
     }
     if(!slavewritten && config.isframe && (flags&(FLAGS_WRITESLAVE|FLAGS_WRITESPRITE)))
     {
        if(slaveframe>=0)
-           logf("<warning> Frame %d doesn't exist in file. No substitution will occur",
+           msg("<warning> Frame %d doesn't exist in file. No substitution will occur",
                    slaveframe);
        else
-           logf("<warning> Frame \"%s\" doesn't exist in file. No substitution will occur",
+           msg("<warning> Frame \"%s\" doesn't exist in file. No substitution will occur",
                    slavename);
     }
     tag = swf_InsertTag(tag, ST_END);
@@ -768,6 +894,8 @@ void adjustheader(SWF*swf)
        swf->movieSize.ymax = 
        swf->movieSize.ymin + config.sizey;
     }
+    if(config.flashversion)
+       swf->fileVersion = config.flashversion;
 }
 
 void catcombine(SWF*master, char*slave_name, SWF*slave, SWF*newswf)
@@ -777,16 +905,18 @@ void catcombine(SWF*master, char*slave_name, SWF*slave, SWF*newswf)
     TAG*tag;
     TAG*mtag,*stag;
     if(config.isframe) {
-       logf("<fatal> Can't combine --cat and --frame");
+       msg("<fatal> Can't combine --cat and --frame");
        exit(1);
     }
+    if(config.flashversion)
+       master->fileVersion = config.flashversion;
    
     tag = master->firstTag;
     while(tag)
     {
        if(swf_isDefiningTag(tag)) {
            int defineid = swf_GetDefineID(tag);
-           logf("<debug> tagid %02x defines object %d", tag->id, defineid);
+           msg("<debug> tagid %02x defines object %d", tag->id, defineid);
            masterbitmap[defineid] = 1;
        }
        tag = tag->next;
@@ -802,7 +932,7 @@ void catcombine(SWF*master, char*slave_name, SWF*slave, SWF*newswf)
 
     depths = malloc(65536);
     if(!depths) {
-       logf("<fatal> Couldn't allocate %d bytes of memory", 65536);
+       msg("<fatal> Couldn't allocate %d bytes of memory", 65536);
        return;
     }
     memset(depths, 0, 65536);
@@ -811,7 +941,7 @@ void catcombine(SWF*master, char*slave_name, SWF*slave, SWF*newswf)
     {
        int num=1;
        U16 depth;
-       logf("<debug> [master] write tag %02x (%d bytes in body)", 
+       msg("<debug> [master] write tag %02x (%d bytes in body)", 
                mtag->id, mtag->len);
        switch(mtag->id) {
            case ST_PLACEOBJECT2:
@@ -851,7 +981,7 @@ void catcombine(SWF*master, char*slave_name, SWF*slave, SWF*newswf)
     stag = slave->firstTag;
     while(stag && stag->id!=ST_END)
     {
-       logf("<debug> [slave] write tag %02x (%d bytes in body)", 
+       msg("<debug> [slave] write tag %02x (%d bytes in body)", 
                stag->id, stag->len);
        tag = swf_InsertTag(tag, stag->id);
        swf_SetBlock(tag, stag->data, stag->len);
@@ -859,9 +989,7 @@ void catcombine(SWF*master, char*slave_name, SWF*slave, SWF*newswf)
     }
     tag = swf_InsertTag(tag, ST_END);
 
-    tag = newswf->firstTag;
-    newswf->firstTag = newswf->firstTag->next; //remove temporary tag
-    swf_DeleteTag(tag);
+    swf_DeleteTag(newswf, tag);
 }
 
 void normalcombine(SWF*master, char*slave_name, SWF*slave, SWF*newswf)
@@ -871,45 +999,84 @@ void normalcombine(SWF*master, char*slave_name, SWF*slave, SWF*newswf)
     int frame = 0;
     char*framelabel;
     TAG * tag = master->firstTag;
+
+    memset(depthbitmap, 0, sizeof(depthbitmap));
     
     // set the idtab
     while(tag)
     {
+       int depth = swf_GetDepth(tag);
+       if(depth>=0) {
+           depthbitmap[depth] = 1;
+       }
        if(swf_isDefiningTag(tag)) {
            int defineid = swf_GetDefineID(tag);
-           logf("<debug> tagid %02x defines object %d", tag->id, defineid);
+           msg("<debug> tagid %02x defines object %d", tag->id, defineid);
            masterbitmap[defineid] = 1;
+
            if (!slavename && defineid==slaveid) {
                if(defineid>=0) {
                  spriteid = defineid;
-                 logf("<notice> Slave file attached to object %d.", defineid);
+                 msg("<notice> Slave file attached to object %d.", defineid);
                }
            }
+       } else if(tag->id == ST_EXPORTASSETS) {
+           int t;
+           int num = swf_GetU16(tag);
+           for(t=0;t<num;t++)
+           {
+               U16 id = swf_GetU16(tag);
+               char*name = swf_GetString(tag);
+               if(spriteid<0 && slavename && !strcmp(name,slavename)) {
+                   spriteid = id;
+                   msg("<notice> Slave file attached to object %d exported as %s.", id, name);
+               }
+           }
+       } else if(tag->id == ST_SYMBOLCLASS) {
+           /* a symbolclass tag is like a define tag: it defines id 0000 */
+           int num = swf_GetU16(tag);
+           int t;
+           for(t=0;t<num;t++) {
+               U16 id = swf_GetU16(tag);
+               if(!id) {
+                   masterbitmap[id] = 1;
+               }
+               swf_GetString(tag);
+           }
        } else if(tag->id == ST_PLACEOBJECT2) {
            char * name = swf_GetName(tag);
            int id = swf_GetPlaceID(tag);
 
+           {
+               SWFPLACEOBJECT obj;
+               swf_GetPlaceObject(tag, &obj);
+               swf_PlaceObjectFree(&obj);
+               if(obj.clipdepth) {
+                   depthbitmap[obj.clipdepth] = 1;
+               }
+           }
+
            if(name)
-             logf("<verbose> tagid %02x places object %d named \"%s\"", tag->id, id, name);
+             msg("<verbose> tagid %02x places object %d named \"%s\"", tag->id, id, name);
            else
-             logf("<verbose> tagid %02x places object %d (no name)", tag->id, id);
+             msg("<verbose> tagid %02x places object %d (no name)", tag->id, id);
 
            if (name && slavename && !strcmp(name,slavename)) {
                if(id>=0) {
                  spriteid = id;
-                 logf("<notice> Slave file attached to named object %s (%d).", name, id);
+                 msg("<notice> Slave file attached to named object %s (%d).", name, id);
                }
            }
        } else if(tag->id == ST_SHOWFRAME) {
            if(slaveframe>=0 && frame==slaveframe) {
-               logf("<notice> Slave file attached to frame %d.", frame);
+               msg("<notice> Slave file attached to frame %d.", frame);
            }
            frame++;
        } else if(tag->id == ST_FRAMELABEL) {
            char * name = tag->data;
            if(name && slavename && config.isframe && !strcmp(name, slavename)) {
                slaveframe = frame;
-               logf("<notice> Slave file attached to frame %d (%s).", frame, name);
+               msg("<notice> Slave file attached to frame %d (%s).", frame, name);
            }
        }
        tag = tag->next;
@@ -917,15 +1084,22 @@ void normalcombine(SWF*master, char*slave_name, SWF*slave, SWF*newswf)
 
     if (spriteid<0 && !config.isframe) {
        if(slavename) {
-           if(strcmp(slavename,"!!dummy!!"))
-               logf("<warning> Didn't find anything named %s in file. No substitutions will occur.", slavename);
+           if(strcmp(slavename,"!!dummy!!")) {
+               msg("<warning> Didn't find anything named %s in file. No substitutions will occur.", slavename);
+               if(!strcmp(slavename, "swf")) {
+                   msg("<warning> (If you were trying to combine rfxview with a document, try replacing 'swf' with 'viewport'.");
+               }
+           }
        }
        else
-           logf("<warning> Didn't find id %d in file. No substitutions will occur.", slaveid);
+           msg("<warning> Didn't find id %d in file. No substitutions will occur.", slaveid);
        spriteid = get_free_id(masterbitmap);
     }
 
     swf_Relocate (slave, masterbitmap);
+    
+    if(config.merge)
+       swf_RelocateDepth (slave, depthbitmap);
     jpeg_assert(slave, master);
     
     if (config.overlay)
@@ -940,7 +1114,7 @@ void normalcombine(SWF*master, char*slave_name, SWF*slave, SWF*newswf)
 
     if (config.antistream) {
        if (config.merge) {
-           logf("<fatal> Can't combine --antistream and --merge");
+           msg("<fatal> Can't combine --antistream and --merge");
        }
        tag = write_sprite_defines(tag, slave);
        tag = write_sprite(tag, slave, spriteid, replaceddefine);
@@ -955,9 +1129,7 @@ void normalcombine(SWF*master, char*slave_name, SWF*slave, SWF*newswf)
                FLAGS_WRITEDEFINES|FLAGS_WRITENONDEFINES|   FLAGS_WRITESPRITE   );
     }
 
-    tag = newswf->firstTag;
-    newswf->firstTag = newswf->firstTag->next; //remove temporary tag
-    swf_DeleteTag(tag);
+    swf_DeleteTag(newswf, newswf->firstTag);
 }
 
 void combine(SWF*master, char*slave_name, SWF*slave, SWF*newswf)
@@ -966,6 +1138,11 @@ void combine(SWF*master, char*slave_name, SWF*slave, SWF*newswf)
     slaveid = -1;
     slaveframe = -1;
 
+    if(!master->fileVersion && slave)
+       master->fileVersion = slave->fileVersion;
+        
+    master->fileAttributes |= slave->fileAttributes;
+
     swf_FoldAll(master);
     swf_FoldAll(slave);
 
@@ -977,16 +1154,19 @@ void combine(SWF*master, char*slave_name, SWF*slave, SWF*newswf)
 
     if(config.isframe)
     {
-       int tmp;
-       if(slavename && slavename[0]!='#' && (sscanf(slavename, "%d", &tmp) ==
-               strlen(slavename))) {
-       /* if the name the slave should replace 
-          consists only of digits and the -f
-          option is given, it probably is not
-          a frame name but a frame number.
-        */
-           slaveid = tmp;
-           slavename = 0;
+       if(slavename && slavename[0]!='#') {
+           int tmp;
+           int len;
+           sscanf(slavename, "%d%n", &tmp, &len);
+           if(len == strlen(slavename)) {
+           /* if the name the slave should replace 
+              consists only of digits and the -f
+              option is given, it probably is not
+              a frame name but a frame number.
+            */
+               slaveid = tmp;
+               slavename = 0;
+           }
        }
 
        if(slaveid>=0) {
@@ -999,15 +1179,15 @@ void combine(SWF*master, char*slave_name, SWF*slave, SWF*newswf)
        }
     }
 
-    logf("<debug> move x (%d)", config.movex);
-    logf("<debug> move y (%d)", config.movey);
-    logf("<debug> scale x (%f)", config.scalex);
-    logf("<debug> scale y (%f)", config.scaley);
-    logf("<debug> master move x (%d)", config.mastermovex);
-    logf("<debug> master move y (%d)", config.mastermovey);
-    logf("<debug> master scale x (%f)", config.masterscalex);
-    logf("<debug> master scale y (%f)", config.masterscaley);
-    logf("<debug> is frame (%d)", config.isframe);
+    msg("<debug> move x (%d)", config.movex);
+    msg("<debug> move y (%d)", config.movey);
+    msg("<debug> scale x (%f)", config.scalex);
+    msg("<debug> scale y (%f)", config.scaley);
+    msg("<debug> master move x (%d)", config.mastermovex);
+    msg("<debug> master move y (%d)", config.mastermovey);
+    msg("<debug> master scale x (%f)", config.masterscalex);
+    msg("<debug> master scale y (%f)", config.masterscaley);
+    msg("<debug> is frame (%d)", config.isframe);
     
     memset(masterbitmap, 0, sizeof(masterbitmap));
 
@@ -1054,42 +1234,49 @@ int main(int argn, char *argv[])
     initLog(0,-1,0,0,-1,config.loglevel);
 
     if(config.merge && config.cat) {
-       logf("<error> Can't combine --cat and --merge");
+       msg("<error> Can't combine --cat and --merge");
+       exit(1);
+    }
+    
+    if(config.stack && config.cat) {
+       msg("<error> Can't combine --cat and --stack");
        exit(1);
     }
 
     if(config.stack) {
        if(config.overlay) {
-           logf("<error> Can't combine -l and -t");
+           msg("<error> Can't combine -l and -t");
            exit(1);
        }
        if(config.clip) {
-           logf("<error> Can't combine -c and -t");
+           msg("<error> Can't combine -c and -t");
            exit(1);
        }
-       logf("<verbose> (stacking) %d files found\n", numslaves);
+       msg("<verbose> (stacking) %d files found\n", numslaves);
 
        makestackmaster(&master);
     }
     else {
        int ret;
-       logf("<verbose> master entity %s (named \"%s\")\n", master_filename, master_name);
-       fi = open(master_filename, O_RDONLY);
+       msg("<verbose> master entity %s (named \"%s\")\n", master_filename, master_name);
+       fi = open(master_filename, O_RDONLY|O_BINARY);
        if(fi<0) {
-           logf("<fatal> Failed to open %s\n", master_filename);
+           msg("<fatal> Failed to open %s\n", master_filename);
            exit(1);
        }
        ret = swf_ReadSWF(fi, &master);
        if(ret<0) {
-           logf("<fatal> Failed to read from %s\n", master_filename);
+           msg("<fatal> Failed to read from %s\n", master_filename);
            exit(1);
        }
-       logf("<debug> Read %d bytes from masterfile\n", ret);
+       swf_RemoveJPEGTables(&master);
+       removeCommonTags(&master);
+       msg("<debug> Read %d bytes from masterfile\n", ret);
        close(fi);
     }
 
     for(t=0;t<numslaves;t++) {
-           logf("<verbose> slave entity(%d) %s (%s \"%s\")\n", t+1, slave_filename[t], 
+           msg("<verbose> slave entity(%d) %s (%s \"%s\")\n", t+1, slave_filename[t], 
                    slave_isframe[t]?"frame":"object", slave_name[t]);
     }
 
@@ -1097,7 +1284,7 @@ int main(int argn, char *argv[])
     {
        if(numslaves)
        {
-           logf("<error> --dummy (-d) implies there are zero slave objects. You supplied %d.", numslaves);
+           msg("<error> --dummy (-d) implies there are zero slave objects. You supplied %d.", numslaves);
            exit(1);
        }
        numslaves = 1;
@@ -1121,9 +1308,9 @@ int main(int argn, char *argv[])
        if (!numslaves)
        {
            if(config.cat)
-               logf("<error> You must have at least two objects.");
+               msg("<error> You must have at least two objects.");
            else
-               logf("<error> You must have at least one slave entity.");
+               msg("<error> You must have at least one slave entity.");
            return 0;
        }
        for(t = 0; t < numslaves; t++)
@@ -1134,47 +1321,71 @@ int main(int argn, char *argv[])
            config.scaley = slave_scaley[t];
            config.isframe = slave_isframe[t];
 
-           logf("<notice> Combine [%s]%s and [%s]%s", master_name, master_filename,
+           msg("<notice> Combine [%s]%s and [%s]%s", master_name, master_filename,
                    slave_name[t], slave_filename[t]);
            if(!config.dummy)
            {
                int ret;
-               fi = open(slave_filename[t], O_RDONLY);
+               fi = open(slave_filename[t], O_RDONLY|O_BINARY);
                if(!fi) {
-                   logf("<fatal> Failed to open %s\n", slave_filename[t]);
+                   msg("<fatal> Failed to open %s\n", slave_filename[t]);
                    exit(1);
                }
                ret = swf_ReadSWF(fi, &slave);
                if(ret<0) {
-                   logf("<fatal> Failed to read from %s\n", slave_filename[t]);
+                   msg("<fatal> Failed to read from %s\n", slave_filename[t]);
                    exit(1);
                }
-               logf("<debug> Read %d bytes from slavefile\n", ret);
+               msg("<debug> Read %d bytes from slavefile\n", ret);
                close(fi);
+               swf_RemoveJPEGTables(&slave);
+               removeCommonTags(&slave);
            }
            else
            {
                memset(&slave, 0, sizeof(slave));
                slave.firstTag = swf_InsertTag(0, ST_END);
                slave.frameRate = 0;
-               slave.fileVersion = 4;
+               slave.fileVersion = 0;
                slave.frameCount = 0;
            }
 
            combine(&master, slave_name[t], &slave, &newswf);
            master = newswf;
        }
+       if(config.dummy && !config.hassizex && !config.hassizey && !config.mastermovex && !config.mastermovey) {
+           newswf.movieSize.xmin = newswf.movieSize.xmin*config.masterscalex;
+           newswf.movieSize.ymin = newswf.movieSize.ymin*config.masterscaley;
+           newswf.movieSize.xmax = newswf.movieSize.xmax*config.masterscalex;
+           newswf.movieSize.ymax = newswf.movieSize.ymax*config.masterscaley;
+       }
     }
 
+    if(!newswf.fileVersion)
+       newswf.fileVersion = 4;
+
+    if(config.local_with_filesystem)
+        newswf.fileAttributes &= ~FILEATTRIBUTE_USENETWORK;
+    if(config.local_with_networking)
+        newswf.fileAttributes |= FILEATTRIBUTE_USENETWORK;
+    if(config.accelerated_blit)
+        newswf.fileAttributes |= FILEATTRIBUTE_USEACCELERATEDBLIT;
+    if(config.hardware_gpu)
+        newswf.fileAttributes |= FILEATTRIBUTE_USEHARDWAREGPU;
+
     fi = open(outputname, O_BINARY|O_RDWR|O_TRUNC|O_CREAT, 0777);
 
-    if(config.zlib)
-       swf_WriteSWC(fi, &newswf);
-    else {
-       newswf.compressed = 0;
+    if(config.zlib) {
+       if(newswf.fileVersion < 6)
+           newswf.fileVersion = 6;
+        newswf.compressed = 1;
+       swf_WriteSWF(fi, &newswf);
+    } else {
+       newswf.compressed = -1; // don't compress
        swf_WriteSWF(fi, &newswf);
     }
     close(fi);
-    return 0;
+
+    return 0; //ok
 }