/* swfcombine.c
- main routine for swfcombine(1), which is a tool for merging .swf-files.
+ main routine for swfcombine(1), a tool for merging .swf-files.
Part of the swftools package.
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
-#include "args.h"
+#include <zlib.h>
+#include "../lib/rfxswf.h"
+#include "../lib/args.h"
+#include "../lib/log.h"
#include "combine.h"
#include "settings.h"
#include "types.h"
#include "flash.h"
+#include "reloc.h"
+#include "../config.h"
char * master_filename = 0;
char * master_name = 0;
int slave_movey[128];
float slave_scalex[128];
float slave_scaley[128];
+char slave_isframe[128];
int numslaves = 0;
char * outputname = "output.swf";
}
else if (!strcmp(name, "a"))
{
+ config.cat = 1;
+ return 0;
+ }
+ else if (!strcmp(name, "A"))
+ {
config.alloctest = 1;
return 0;
}
config.movey = atoi(val);
return 1;
}
+ else if (!strcmp(name, "m"))
+ {
+ config.merge = 1;
+ return 0;
+ }
+ else if (!strcmp(name, "f"))
+ {
+ config.isframe = 1;
+ return 0;
+ }
+ else if (!strcmp(name, "d"))
+ {
+ config.dummy = 1;
+ return 0;
+ }
+ else if (!strcmp(name, "z"))
+ {
+ config.zlib = 1;
+ return 0;
+ }
+ else if (!strcmp(name, "r"))
+ {
+ config.framerate = atoi(val)*256/100;
+ return 1;
+ }
+ else if (!strcmp(name, "X"))
+ {
+ config.sizex = atoi(val)*20;
+ config.hassizex = 1;
+ return 1;
+ }
+ else if (!strcmp(name, "Y"))
+ {
+ config.sizey = atoi(val)*20;
+ config.hassizey = 1;
+ return 1;
+ }
else if (!strcmp(name, "s"))
{
config.scalex = config.scaley = atoi(val)/100.0;
return 1;
}
- else if (!strcmp(name, "t"))
+ else if (!strcmp(name, "t") || !strcmp(name, "T"))
{
if(master_filename) {
fprintf(stderr, "error with arguments. Try --help.\n");
exit(1);
}
config.stack = 1;
+ if(!strcmp(name,"T"))
+ config.stack1 = 1;
master_filename = "__none__";
return 0;
}
else if (!strcmp(name, "V"))
{
- printf("swfcombine - part of swftools 0.0.1\n");
+ printf("swfcombine - part of %s %s\n", PACKAGE, VERSION);
exit(0);
}
else
}
}
-struct options_t
-{
- char*shortoption;
- char*longoption;
-} options[] =
+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}
};
int args_callback_longoption(char*name,char*val) {
- int t;
- for(t=0;t<sizeof(options)/sizeof(struct options_t);t++)
- if(!strcmp(options[t].longoption, name))
- return args_callback_option(options[t].shortoption,val);
- fprintf(stderr, "Unknown option: --%s\n", name);
- exit(1);
+ return args_long2shortoption(options, name, val);
}
int args_callback_command(char*name, char*val) {
}
if(!master_filename) {
-
master_filename = filename;
master_name = myname;
} else {
slave_movey[numslaves] = config.movey;
slave_scalex[numslaves] = config.scalex;
slave_scaley[numslaves] = config.scaley;
+ slave_isframe[numslaves] = config.isframe;
+ config.isframe = 0;
config.movex = config.movey = 0;
config.scalex = config.scaley = 1.0;
numslaves ++;
void args_callback_usage(char*name)
{
- printf("Usage: %s [-l] [-o outputfile] [name=]masterfile [-x xpos] [-y ypos] [-s scale] [name1=]slavefile1 .. [-x xpos] [-y ypos] [-s scale] [nameN=]slavefileN\n", name);
- printf("\n");
- printf("-o outputfile explicitly specify output file. (otherwise, output.swf will be used)\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("-x xpos (move x) Adjust position of slave by xpos twips (1/20 pixel)\n");
- printf("-y ypos (move y) Adjust position of slave by ypos twips (1/20 pixel)\n");
- printf("-s scale (scale) Adjust size of slave by scale%\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");
+}
+
+static void zlib_error(int ret, char* msg, z_stream*zs)
+{
+ fprintf(stderr, "%s: zlib error (%d): last zlib error: %s\n",
+ msg,
+ ret,
+ zs->msg?zs->msg:"unknown");
+ perror("errno:");
+ exit(1);
+}
+
+static char* fi_depack(FILE* fi, unsigned int * setlength) {
+ char * mem;
+ z_stream zs;
+ int ret;
+ char buffer1[8192], *buffer2;
+ int memsize = 8192;
+ int mempos = 0;
+ memset(&zs,0,sizeof(z_stream));
+ zs.zalloc = Z_NULL;
+ zs.zfree = Z_NULL;
+ zs.opaque = Z_NULL;
+ buffer2 = malloc(8192);
+
+ ret = inflateInit(&zs);
+ if (ret != Z_OK) zlib_error(ret, "inflate_init", &zs);
+
+ fread(buffer2, 8, 1, fi);
+ buffer2[0] = 'F';
+
+ zs.next_out = &buffer2[8];
+ zs.avail_out = 8192-8;
+ zs.avail_in = 0;
+
+ while(1)
+ {
+ if(!zs.avail_in) {
+ zs.avail_in = fread(buffer1, 1, 8192, fi);
+ zs.next_in = buffer1;
+ }
+ if(zs.avail_in)
+ ret = inflate(&zs, Z_NO_FLUSH);
+ else
+ ret = inflate(&zs, Z_FINISH);
+
+ if (ret == Z_STREAM_END)
+ break;
+ if (ret != Z_OK) zlib_error(ret, "inflate_init", &zs);
+
+ if (zs.avail_out == 0)
+ {
+ buffer2 = realloc(buffer2, memsize + 8192);
+ zs.avail_out = 8192;
+ zs.next_out = &buffer2[memsize];
+ memsize += 8192;
+ }
+ }
+ *setlength = (zs.next_out - (Bytef*)buffer2);
+ ret = inflateEnd(&zs);
+ if(ret != Z_OK) zlib_error(ret, "inflate_init", &zs);
+ return buffer2;
}
/* read a whole file in memory */
-char* fi_slurp(FILE*fi, unsigned int * setlength)
+static char* fi_slurp(FILE*fi, unsigned int * setlength)
{
char * mem;
long long int length; //;)
long long int pos = 0;
+ unsigned char id[3];
fseek(fi,0,SEEK_END);
length = ftell(fi);
fseek(fi,0,SEEK_SET);
- if(!length)
+ if(length<3)
return 0;
+ fread(id, 3, 1, fi);
+ fseek(fi, 0, SEEK_SET);
+ if(!strncmp(id, "CWS", 3)) {
+ return fi_depack(fi, setlength);
+ }
+
mem = malloc(length);
if(!mem)
return 0;
return mem;
}
-void fi_dump(FILE*fi, void*_mem, int length)
+static void fi_pack(FILE*fi, void*_mem, int length)
+{
+ z_stream zs;
+ int ret;
+ char*mem = (char*)_mem;
+ char buffer[8192];
+ memset(&zs,0,sizeof(z_stream));
+ zs.zalloc = Z_NULL;
+ zs.zfree = Z_NULL;
+ zs.opaque = Z_NULL;
+
+ ret = deflateInit(&zs, 9);
+ if (ret != Z_OK) zlib_error(ret, "deflate_init", &zs);
+
+ mem[0] = 'C';
+ fwrite(mem, 8, 1, fi);
+
+ zs.avail_in = length-8;
+ zs.next_in = mem+8;
+ zs.avail_out = 8192;
+ zs.next_out = buffer;
+
+ while(1)
+ {
+ if(zs.avail_in)
+ ret = deflate(&zs, Z_NO_FLUSH);
+ else
+ ret = deflate(&zs, Z_FINISH);
+
+ if (ret == Z_STREAM_END)
+ break;
+
+ if (ret != Z_OK) zlib_error(ret, "deflate_sync", &zs);
+
+ if (zs.avail_out == 0)
+ {
+ fwrite(buffer, 8192, 1, fi);
+ zs.next_out = buffer;
+ zs.avail_out = 8192;
+ }
+ }
+ fwrite(buffer, zs.next_out - (Bytef*)buffer, 1, fi);
+
+ ret = deflateEnd(&zs);
+ if (ret != Z_OK) zlib_error(ret, "deflate_end", &zs);
+}
+
+static void fi_dump(FILE*fi, void*_mem, int length)
{
char*mem = (char*)_mem;
int pos = 0;
}
}
-void makestackmaster(u8**masterdata, int*masterlength)
+/* todo: use rfxswf */
+static void makestackmaster(u8**masterdata, int*masterlength)
{
u8 head[] = {'F','W','S'};
u8 *pos;
int strlength = 0;
int fileversion = 1;
- logf("<error> stacking doesn't work yet. Prepare for problems.");
-
/* scan all slaves for bounding box */
for(t=0;t<numslaves;t++)
{
u8 data[256];
int ret;
struct flash_header head;
+ struct reader_t r;
strlength += strlen(slave_name[t]) + 9;
if(!fi) {
logf("<fatal> Couldn't open %s.", slave_filename[t]);
logf("<fatal> File %s is to small (%d bytes)", slave_filename[t], ret);
exit(1);
}
- swf_init(data,256);
- head = swf_read_header();
+ swf_init(&r, data,256);
+ head = swf_read_header(&r);
logf("<verbose> File %s has bounding box %d:%d:%d:%d\n",
slave_filename[t],
head.boundingBox.x1, head.boundingBox.y1,
}
/* we don't have a master, so we create one ourselves. */
- /* (please notice the philosophical content) */
*masterlength = (numslaves + 1) * 32 + strlength;
*masterdata = (u8*)malloc(*masterlength);
pos = *masterdata;
pos += sizeof(head);
*pos++ = fileversion;
fixpos = (u32*)pos;
- *(u32*)pos = 0x12345678; // to be overwritten
+ PUT32(pos, 0x12345678); // to be overwritten
pos += 4;
writeRECT(&pos, &box);
- *(u16*)pos = 0x2000; // framerate
+ PUT16(pos, 0x2000) // framerate
pos += 2;
- *(u16*)pos = numslaves;
+ PUT16(pos, numslaves) // framerate
pos += 2;
for(t=0;t<numslaves;t++)
{
}
namelen = strlen(slave_name[t]);
- *(u16*)&pos[0] = (u16)(TAGID_DEFINESPRITE<<6) + 6;
- *(u16*)&pos[2] = t+1; //ID
- *(u16*)&pos[4] = 0; // Frames
- *(u16*)&pos[6] = 0; // TAG1
- *(u16*)&pos[8] = (u16)(TAGID_PLACEOBJECT2<<6) + 6 + namelen;
- *(u16*)&pos[10]= 34; //flags: id+name
- *(u16*)&pos[11]= 1; // depth
- *(u16*)&pos[13]= t+1; // id
+ PUT16(&pos[0] , ((u16)(TAGID_DEFINESPRITE<<6) + 6));
+ PUT16(&pos[2] , (t+1)); //ID
+ PUT16(&pos[4] , 0); // Frames
+ PUT16(&pos[6] , 0); // TAG1
+ PUT16(&pos[8] , ((u16)(TAGID_PLACEOBJECT2<<6) + 6 + namelen));
+ PUT16(&pos[10], (34)); //flags: id+name
+ PUT16(&pos[11], (1+t)); // depth
+ PUT16(&pos[13], (t+1)); // id
sprintf(&pos[15],slave_name[t]);
pos += 15 + namelen + 1;
- *(u16*)&pos[0]= (u16)(TAGID_SHOWFRAME<<6) + 0;
- pos += 2;
+ if(!config.stack1 || t == numslaves-1) {
+ PUT16(&pos[0],((u16)(TAGID_SHOWFRAME<<6) + 0));
+ pos += 2;
+ }
+ if(!config.stack)
if(t!=numslaves-1)
{
- *(u16*)&pos[0]= (u16)(TAGID_REMOVEOBJECT2<<6) + 2;
- *(u16*)&pos[2]= 1; // depth;
+ PUT16(&pos[0], ((u16)(TAGID_REMOVEOBJECT2<<6) + 2));
+ PUT16(&pos[2], (1+t)); // depth;
pos += 4;
}
}
- *(u16*)pos = TAGID_END<<6 + 0;
+ PUT16(pos, ((TAGID_END<<6) + 0));
*masterlength = pos - *masterdata;
- *fixpos = *masterlength;
+ PUT32(fixpos, *masterlength);
}
struct config_t config;
int t;
config.overlay = 0;
+ config.antistream = 0;
config.alloctest = 0;
+ config.cat = 0;
+ config.merge = 0;
config.clip = 0;
config.loglevel = 2;
config.movex = 0;
config.movey = 0;
config.scalex = 1.0;
config.scaley = 1.0;
+ config.sizex = 0;
+ config.sizey = 0;
+ config.hassizex = 0;
+ config.hassizey = 0;
+ config.framerate = 0;
config.stack = 0;
+ config.stack1 = 0;
+ config.dummy = 0;
+ config.zlib = 0;
processargs(argn, argv);
initLog(0,-1,0,0,-1,config.loglevel);
+ if(config.merge && config.cat) {
+ logf("<error> Can't combine --cat and --merge");
+ exit(1);
+ }
+
if(config.stack) {
if(config.overlay) {
logf("<verbose> master entity %s (named \"%s\")\n", master_filename, master_name);
fi = fopen(master_filename, "rb");
if(!fi) {
- fprintf(stderr, "Failed to open %s\n", master_filename);
- return 1;
+ logf("<fatal> Failed to open %s\n", master_filename);
+ exit(1);
}
masterdata = fi_slurp(fi, &masterlength);
if(!masterdata) {
- fprintf(stderr, "Failed to read from %s\n", master_filename);
- return 1;
+ logf("<fatal> Failed to read from %s\n", master_filename);
+ exit(1);
}
logf("<debug> Read %d bytes from masterfile\n", masterlength);
fclose(fi);
}
-
- for(t=0;t<numslaves;t++)
- logf("<verbose> slave entity(%d) %s (named \"%s\")\n", t+1, slave_filename[t], slave_name[t]);
+
+ for(t=0;t<numslaves;t++) {
+ logf("<verbose> slave entity(%d) %s (%s \"%s\")\n", t+1, slave_filename[t],
+ slave_isframe[t]?"frame":"object", slave_name[t]);
+ }
+
+ if(config.dummy)
+ {
+ if(numslaves)
+ {
+ logf("<error> --dummy (-d) implies there are zero slave objects. You supplied %d.", numslaves);
+ exit(1);
+ }
+ numslaves = 1;
+ slave_filename[0] = "!!dummy!!";
+ slave_name[0] = "!!dummy!!";
+ slave_isframe[0] = 0;
+ }
if (config.alloctest)
{
config.movey = slave_movey[t];
config.scalex = slave_scalex[t];
config.scaley = slave_scaley[t];
+ config.isframe = slave_isframe[t];
logf("<notice> Combine [%s]%s and [%s]%s", master_name, master_filename,
slave_name[t], slave_filename[t]);
- fi = fopen(slave_filename[t], "rb");
- if(!fi) {
- fprintf(stderr, "Failed to open %s\n", slave_filename[t]);
- return 1;
+ if(!config.dummy)
+ {
+ fi = fopen(slave_filename[t], "rb");
+ if(!fi) {
+ logf("<fatal> Failed to open %s\n", slave_filename[t]);
+ exit(1);
+ }
+ slavedata = fi_slurp(fi, &slavelength);
+ if(!slavedata) {
+ logf("<fatal> Failed to read from %s\n", slave_filename[t]);
+ exit(1);
+ }
+ logf("<debug> Read %d bytes from slavefile\n", slavelength);
+ fclose(fi);
}
- slavedata = fi_slurp(fi, &slavelength);
- if(!slavedata) {
- fprintf(stderr, "Failed to read from %s\n", slave_filename[t]);
- return 1;
+ else
+ {
+ slavedata = (u8*)malloc(16);
+ slavedata[0] = 'F';
+ slavedata[1] = 'W';
+ slavedata[2] = 'S';
+ slavedata[3] = 4; //version
+ PUT32(&slavedata[4], 14); ; // length
+ slavedata[8] = 0; // boundingbox
+ PUT16(&slavedata[9] , (0)); // rate
+ PUT16(&slavedata[11] , (0)); // count
+ PUT16(&slavedata[13] , (0)); // end tag
+ slavelength = 17;
}
- logf("<debug> Read %d bytes from slavefile\n", slavelength);
- fclose(fi);
newdata = combine(masterdata, masterlength, slave_name[t], slavedata, slavelength, &newlength);
if(!newdata) {
logf("<debug> New File is %d bytes \n", newlength);
if(newdata && newlength) {
FILE*fi = fopen(outputname, "wb");
- fi_dump(fi, newdata, newlength);
+ if(config.zlib)
+ fi_pack(fi, newdata, newlength);
+ else
+ fi_dump(fi, newdata, newlength);
fclose(fi);
}
return 0;