X-Git-Url: http://git.asbjorn.biz/?a=blobdiff_plain;f=src%2Fcombine.c;h=4847a583e5c3046c55df2b3bbc9d3f09b51cacce;hb=22a49dfc00af6fc1b43057b44790f2087a09b6f2;hp=727f858d3bfb600d5c906b27e8719167eec38851;hpb=efe9cc12012cb4711840cbb7aa053dd28bd2ebff;p=swftools.git diff --git a/src/combine.c b/src/combine.c index 727f858..4847a58 100644 --- a/src/combine.c +++ b/src/combine.c @@ -12,14 +12,14 @@ #include #include #include "../lib/log.h" +#include "../lib/rfxswf.h" #include "./flash.h" #include "./reloc.h" #include "./settings.h" -// TODO: -// * readers should be object-oriented - -static char* slavename; +static char* slavename = 0; +static int slaveid = -1; +static int slaveframe = -1; static char* tag_placeobject2_name (struct swf_tag* tag) { @@ -56,14 +56,58 @@ static int get_free_id() void changedepth(struct swf_tag*tag, int add) { + /* fucking big endian byte order */ if(tag->id == TAGID_PLACEOBJECT) - (*(u16*)&tag->data[2]) += add; + PUT16(&tag->data[2],GET16(&tag->data[2])+add); if(tag->id == TAGID_PLACEOBJECT2) - (*(u16*)&tag->data[1]) += add; + PUT16(&tag->data[1],GET16(&tag->data[1])+add); if(tag->id == TAGID_REMOVEOBJECT) - (*(u16*)&tag->data[2]) += add; + PUT16(&tag->data[2],GET16(&tag->data[2])+add); if(tag->id == TAGID_REMOVEOBJECT2) - (*(u16*)&tag->data[0]) += add; + PUT16(&tag->data[0],GET16(&tag->data[0])+add); +} + +void jpeg_assert() +{ + /* TODO: if there's a jpegtable found, store it + and handle it together with the flash file + headers */ + /* check that master and slave don't have both + jpegtables (which would be fatal) */ + int pos; + int mpos=-1, spos=-1; + pos = 0; + while(master.tags[pos].id != 0) + { + if(master.tags[pos].id == TAGID_JPEGTABLES) + mpos = pos; + pos++; + } + pos = 0; + while(master.tags[pos].id != 0) + { + if(slave.tags[pos].id == TAGID_JPEGTABLES) + spos = pos; + pos++; + } + if(spos>=0 && mpos>=0) + { + if(slave.tags[pos].length == + master.tags[pos].length && + !memcmp(slave.tags[pos].data, master.tags[pos].data, + master.tags[pos].length)) + { + // ok, both have jpegtables, but they're identical. + // delete one and don't make an error + for(;spos=0 && mpos>=0) { + logf(" Master and slave have incompatible JPEGTABLES."); + } } /* applies the config move and scale parameters to @@ -157,8 +201,15 @@ void write_sprite_defines(struct writer_t*w) * Anyway we can't throw it out, so we just pass it * through. */ + writer_write(w, tag->fulldata, tag->fulllength); break; } + case TAGID_JPEGTABLES: + /* if we get here, jpeg_assert has already run, + ensuring this is the only one of it's kind, + so we may safely write it out */ + writer_write(w, tag->fulldata, tag->fulllength); + break; case TAGID_EXPORTASSETS: logf(" deliberately ignoring EXPORTASSETS tag"); break; @@ -182,7 +233,6 @@ void write_sprite_defines(struct writer_t*w) } } - void write_sprite(struct writer_t*w, int spriteid, int replaceddefine) { u16 tmp; @@ -191,23 +241,17 @@ void write_sprite(struct writer_t*w, int spriteid, int replaceddefine) u8*startpos; int pos = 0; // write slave(2) (header) - tmp = 0x3f + (TAGID_DEFINESPRITE << 6); + tmp = SWAP16(0x3f + (TAGID_DEFINESPRITE << 6)); writer_write(w, &tmp, 2); tagidpos = (u32*)writer_getpos(w); writer_write(w, &tmp32, 4); startpos = (u8*)writer_getpos(w); - if (spriteid<0) - { - logf(" Didn't find anything named %s in file. No substitutions will occur.", slavename); - spriteid = get_free_id(); - } - logf (" sprite id is %d", spriteid); - tmp = spriteid; + tmp = SWAP16(spriteid); writer_write(w, &tmp, 2); - tmp = slave.header.count; + tmp = SWAP16(slave.header.count); writer_write(w, &tmp, 2); @@ -216,26 +260,26 @@ void write_sprite(struct writer_t*w, int spriteid, int replaceddefine) logf(" %d frames to go",tmp); if(config.clip) { - tmp = 7 + (TAGID_PLACEOBJECT2 << 6); + tmp = SWAP16(7 + (TAGID_PLACEOBJECT2 << 6)); writer_write(w, &tmp, 2); - tmp = 2+64; //flags: character + clipaction + tmp = SWAP16(2+64); //flags: character + clipaction writer_write(w, &tmp, 1); - tmp = 0; //depth + tmp = SWAP16(0); //depth writer_write(w, &tmp,2); - tmp = replaceddefine; //id + tmp = SWAP16(replaceddefine); //id writer_write(w, &tmp,2); - tmp = 65535; //clipdepth + tmp = SWAP16(65535); //clipdepth writer_write(w, &tmp,2); } - if(config.overlay) { - tmp = 5 + (TAGID_PLACEOBJECT2 << 6); + if(config.overlay && !config.isframe) { + tmp = SWAP16(5 + (TAGID_PLACEOBJECT2 << 6)); writer_write(w, &tmp, 2); - tmp = 2; //flags: character + tmp = SWAP16(2); //flags: character writer_write(w, &tmp, 1); - tmp = 0; //depth + tmp = SWAP16(0); //depth writer_write(w, &tmp,2); - tmp = replaceddefine; //id + tmp = SWAP16(replaceddefine); //id writer_write(w, &tmp,2); } @@ -257,26 +301,55 @@ void write_sprite(struct writer_t*w, int spriteid, int replaceddefine) } while(slave.tags[pos++].id != TAGID_END); - *tagidpos = (u8*)writer_getpos(w) - startpos; // set length of sprite (in header) - logf(" sprite length is %d",*tagidpos); + PUT32(tagidpos, (u8*)writer_getpos(w) - startpos); // set length of sprite (in header) + logf(" sprite length is %d",GET32(tagidpos)); +} + +static char tag_ok_for_slave(int id) +{ + if(id == TAGID_BACKGROUNDCOLOR) + return 0; + return 1; } #define FLAGS_WRITEDEFINES 1 #define FLAGS_WRITENONDEFINES 2 #define FLAGS_WRITESPRITE 4 +#define FLAGS_WRITESLAVE 8 void write_master(struct writer_t*w, int spriteid, int replaceddefine, int flags) { int pos = 0; - do { - if(is_defining_tag(master.tags[pos].id) && (flags&1)) + int spos = 0; + int outputslave = 0; + int frame = 0; + int sframe = 0; + int slavewritten = 0; + while(master.tags[pos].id != 0) + { + if(master.tags[pos].id == TAGID_SHOWFRAME && outputslave) + { + while(slave.tags[spos].id) { + if(slave.tags[spos].id == TAGID_SHOWFRAME) { + spos++; + sframe++; + break; + } + if(tag_ok_for_slave(slave.tags[spos].id)) + writer_write(w, slave.tags[spos].fulldata, slave.tags[spos].fulllength); + spos++; + } + frame ++; + } + + if(is_defining_tag(master.tags[pos].id) && (flags&FLAGS_WRITEDEFINES)) { logf(" [master] write tag %02x (%d bytes in body)", master.tags[pos].id, master.tags[pos].length); - if( getidfromtag(&master.tags[pos]) == spriteid) + if(getidfromtag(&master.tags[pos]) == spriteid && !config.isframe) { if(config.overlay) { - *(u16*)master.tags[pos].data = replaceddefine; + PUT16(master.tags[pos].data, replaceddefine); writer_write(w, master.tags[pos].fulldata, master.tags[pos].fulllength); } else { /* don't write this tag */ @@ -284,23 +357,85 @@ void write_master(struct writer_t*w, int spriteid, int replaceddefine, int flags ,spriteid); } - if(flags&4) + if(flags&FLAGS_WRITESPRITE) { write_sprite_defines(w); write_sprite(w, spriteid, replaceddefine); } + if(flags&FLAGS_WRITESLAVE) + { + outputslave = 1; + } } else { writer_write(w, master.tags[pos].fulldata, master.tags[pos].fulllength); } } - if(!is_defining_tag(master.tags[pos].id) && (flags&2)) + if(frame == slaveframe) { - logf(" [master] write tag %02x (%d bytes in body)", - master.tags[pos].id, master.tags[pos].length); - writer_write(w, master.tags[pos].fulldata, master.tags[pos].fulllength); + if(flags&FLAGS_WRITESLAVE) { + outputslave = 1; + slavewritten = 1; + } + if((flags&FLAGS_WRITESPRITE) && !slavewritten) + { + int id = get_free_id(); + int depth = 0; + char data[7]; + if(config.clip) { + logf(" Can't combine --clip and --frame"); + } + PUT16(&data[0], (u16)(TAGID_PLACEOBJECT2<<6) + 5); + *(u8*)&data[2]= 2; //flags: id + PUT16(&data[3], depth); + PUT16(&data[5], id); + write_sprite_defines(w); + write_sprite(w, id, -1); + writer_write(w,data,7); + slavewritten = 1; + } + } + if(!is_defining_tag(master.tags[pos].id) && (flags&FLAGS_WRITENONDEFINES)) + { + int dontwrite = 0; + switch(master.tags[pos].id) { + case TAGID_PLACEOBJECT: + case TAGID_PLACEOBJECT2: + if(frame == slaveframe && !config.overlay) + dontwrite = 1; + case TAGID_REMOVEOBJECT: +// case TAGID_REMOVEOBJECT2: + /* place/removetags for the object we replaced + should be discarded, too, as the object to insert + isn't a sprite + */ + if(spriteid>=0 && getidfromtag(&master.tags[pos]) == spriteid && + !config.isframe && config.merge) + dontwrite = 1; + break; + } + if(!dontwrite) { + logf(" [master] write tag %02x (%d bytes in body)", + master.tags[pos].id, master.tags[pos].length); + writer_write(w, master.tags[pos].fulldata, master.tags[pos].fulllength); + } } + pos++; + } + + if(outputslave) + while(slave.tags[spos].id) + { + if(tag_ok_for_slave(slave.tags[spos].id)) + writer_write(w, slave.tags[spos].fulldata, slave.tags[spos].fulllength); + spos++; } - while(master.tags[pos++].id != 0); + if(!slavewritten && config.isframe && (flags&(FLAGS_WRITESLAVE|FLAGS_WRITESPRITE))) + { + logf(" Frame %d doesn't exist in file. No substitution will occur", + slaveframe); + } + //write END tag: + writer_write(w, master.tags[pos].fulldata, master.tags[pos].fulllength); } void writeheader(struct writer_t*w, u8*data, int length) @@ -308,8 +443,9 @@ void writeheader(struct writer_t*w, u8*data, int length) if(config.hassizex || config.hassizey || config.framerate) { struct flash_header head; - swf_init(data-3, length+3); - head = swf_read_header(); + struct reader_t reader; + swf_init(&reader, data-3, length+3); + head = swf_read_header(&reader); if(config.hassizex) { head.boundingBox.x2 = head.boundingBox.x1 + config.sizex; @@ -328,51 +464,115 @@ void writeheader(struct writer_t*w, u8*data, int length) writer_write(w, data, length); } -uchar * combine(uchar*masterdata, int masterlength, char*_slavename, uchar*slavedata, int slavelength, int*newlength) +uchar * catcombine(uchar*masterdata, int masterlength, char*_slavename, uchar*slavedata, int slavelength, int*newlength) { - char master_flash = 0; - char slave_flash = 0; - slavename = _slavename; + struct writer_t w; + u32*headlength; + u32 tmp32; + int length = masterlength*2 + slavelength; + int pos = 0; + int t; + char* depths; + uchar*newdata = malloc(length); + if(!newdata) { + logf(" Couldn't allocate %d bytes of memory", length); + return 0; + } + if(config.isframe) { + logf(" Can't combine --cat and --frame"); + exit(1); + } + writer_init(&w, newdata, length); + + do { + int tag = master.tags[pos].id; + if(is_defining_tag(tag)) { + int defineid = getidfromtag(&master.tags[pos]); + logf(" tagid %02x defines object %d", tag, defineid); + masterids[defineid] = 1; + } + } + while(master.tags[pos++].id != 0); + + swf_relocate (slavedata, slavelength, masterids); + read_swf(&slave, slavedata, slavelength); + jpeg_assert(); + + writer_write(&w, "FWS",3); + headlength = (u32*)(writer_getpos(&w) + 1); + writeheader(&w, master.header.headerdata, master.header.headerlength); - logf(" move x (%d)", config.movex); - logf(" move y (%d)", config.movey); - logf(" scale x (%d)", config.scalex); - logf(" scale y (%d)", config.scaley); - - memset(masterids, -1, sizeof(masterids)); + depths = malloc(65536); + if(!depths) { + logf(" Couldn't allocate %d bytes of memory", 65536); + return 0; + } + memset(depths, 0, 65536); + pos = 0; + do { + int num=1; + u16 depth; + logf(" [master] write tag %02x (%d bytes in body)", + master.tags[pos].id, master.tags[pos].length); + switch(master.tags[pos].id) { + case TAGID_PLACEOBJECT2: + num++; + case TAGID_PLACEOBJECT: { + struct reader_t r; + reader_init (&r, master.tags[pos].data, master.tags[pos].length); + if(num>=2) + reader_readu8(&r); + depth = reader_readu16(&r); + depths[depth] = 1; + } + break; + case TAGID_REMOVEOBJECT: { + struct reader_t r; + reader_init (&r, master.tags[pos].data, master.tags[pos].length); + reader_readu16(&r); + depths[reader_readu16(&r)] = 0; + } + break; + case TAGID_REMOVEOBJECT2: { + struct reader_t r; + reader_init (&r, master.tags[pos].data, master.tags[pos].length); + depths[reader_readu16(&r)] = 0; + } + break; + } + if(master.tags[pos].id != 0) + writer_write(&w, master.tags[pos].fulldata, master.tags[pos].fulllength); + } + while(master.tags[pos++].id != 0); - if(masterlength < 3) - { - logf(" the master file is too small (%d bytes)", masterlength); - return 0; - } - if(slavelength < 3) - { - logf(" the slave file is too small (%d bytes)", slavelength); - return 0; - } - if(masterdata[2] == 'S' && - masterdata[1] == 'W' && - masterdata[0] == 'F') - { - logf(" the master file is flash (swf) format\n"); - master_flash = 1; - } - else - logf(" the master file is not flash (swf) format!\n"); + for(t=0;t<65536;t++) + if(depths[t]) + { + char data[16]; + int len; + PUT16(&data[0], (TAGID_REMOVEOBJECT2<<6) + 2); + PUT16(&data[2], t); + writer_write(&w, data, 4); + } + free(depths); - if(slavedata[2] == 'S' && - slavedata[1] == 'W' && - slavedata[0] == 'F') - { - logf(" the slave file is flash (swf) format\n"); - slave_flash = 1; - } - else - logf(" the slave file is not flash (swf) format!\n"); + pos = 0; + do { + logf(" [slave] write tag %02x (%d bytes in body)", + slave.tags[pos].id, slave.tags[pos].length); + writer_write(&w, slave.tags[pos].fulldata, slave.tags[pos].fulllength); + } + while(slave.tags[pos++].id != 0); - if(master_flash && slave_flash) - { + tmp32 = (u8*)writer_getpos(&w) - (u8*)newdata; //length + *newlength = tmp32; + PUT32(headlength, tmp32); // set the header to the correct length + + return newdata; //length +} + +uchar * normalcombine(uchar*masterdata, int masterlength, char*_slavename, uchar*slavedata, int slavelength, int*newlength) +{ int length; int pos=0; u32 tmp32; @@ -381,9 +581,9 @@ uchar * combine(uchar*masterdata, int masterlength, char*_slavename, uchar*slave int spriteid = -1; int replaceddefine = -1; struct writer_t w; + int frame; + char*framelabel; - read_swf(&master, masterdata, masterlength); - length = masterlength + slavelength*2 + 128; // this is a guess, but a good guess. newdata = malloc(length); writer_init(&w, newdata, length); @@ -410,21 +610,43 @@ uchar * combine(uchar*masterdata, int masterlength, char*_slavename, uchar*slave else logf(" tagid %02x places object %d (no name)", tag, id); - if (name && !strcmp(name,slavename)) { + if ((name && slavename && !strcmp(name,slavename)) || + (!slavename && id==slaveid)) { if(id>=0) { spriteid = id; logf(" Slave file attached to object %d.", id); } } + } else if(tag == TAGID_SHOWFRAME) { + if(slaveframe>=0 && frame==slaveframe) { + logf(" Slave file attached to frame %d.", frame); + } + frame++; + } else if(tag == TAGID_FRAMELABEL) { + char * name = master.tags[pos].data; + if(name && slavename && config.isframe && !strcmp(name, slavename)) { + slaveframe = frame; + logf(" Slave file attached to frame %d (%s).", frame, name); + } } } while(master.tags[pos++].id != 0); - swf_relocate (slavedata, slavelength, masterids); + if (spriteid<0 && !config.isframe) { + if(slavename) { + if(strcmp(slavename,"!!dummy!!")) + logf(" Didn't find anything named %s in file. No substitutions will occur.", slavename); + } + else + logf(" Didn't find id %d in file. No substitutions will occur.", slaveid); + spriteid = get_free_id(); + } + swf_relocate (slavedata, slavelength, masterids); read_swf(&slave, slavedata, slavelength); + jpeg_assert(); - if(config.overlay) + if (config.overlay) replaceddefine = get_free_id(); // write file @@ -433,21 +655,94 @@ uchar * combine(uchar*masterdata, int masterlength, char*_slavename, uchar*slave headlength = (u32*)(writer_getpos(&w) + 1); writeheader(&w, master.header.headerdata, master.header.headerlength); - if(config.antistream) { + if (config.antistream) { + if (config.merge) { + logf(" Can't combine --antistream and --merge"); + } write_sprite_defines(&w); write_sprite(&w, spriteid, replaceddefine); write_master(&w, spriteid, replaceddefine, FLAGS_WRITEDEFINES); write_master(&w, spriteid, replaceddefine, FLAGS_WRITENONDEFINES); } else { - write_master(&w, spriteid, replaceddefine, + if (config.merge) + write_master(&w, spriteid, replaceddefine, + FLAGS_WRITEDEFINES|FLAGS_WRITENONDEFINES|FLAGS_WRITESLAVE); + else + write_master(&w, spriteid, replaceddefine, FLAGS_WRITEDEFINES|FLAGS_WRITENONDEFINES|FLAGS_WRITESPRITE); } tmp32 = (u8*)writer_getpos(&w) - (u8*)newdata; //length *newlength = tmp32; - *headlength = tmp32; // set the header to the correct length + PUT32(headlength, tmp32); return newdata; //length +} + +uchar * combine(uchar*masterdata, int masterlength, char*_slavename, uchar*slavedata, int slavelength, int*newlength) +{ + char master_flash = 0; + char slave_flash = 0; + slavename = _slavename; + + slaveid = -1; + slaveframe = -1; + + if(slavename[0] == '#') + { + slaveid = atoi(&slavename[1]); + slavename = 0; + } + if(config.isframe) + { + slaveframe = slaveid; + slaveid = -1; + } + + logf(" move x (%d)", config.movex); + logf(" move y (%d)", config.movey); + logf(" scale x (%f)", config.scalex); + logf(" scale y (%f)", config.scaley); + logf(" is frame (%d)", config.isframe); + + memset(masterids, -1, sizeof(masterids)); + + if(masterlength < 3) + { + logf(" the master file is too small (%d bytes)", masterlength); + return 0; + } + if(slavelength < 3) + { + logf(" the slave file is too small (%d bytes)", slavelength); + return 0; + } + if(masterdata[2] == 'S' && + masterdata[1] == 'W' && + masterdata[0] == 'F') + { + logf(" the master file is flash (swf) format\n"); + master_flash = 1; + } + else + logf(" the master file is not flash (swf) format!\n"); + + if(slavedata[2] == 'S' && + slavedata[1] == 'W' && + slavedata[0] == 'F') + { + logf(" the slave file is flash (swf) format\n"); + slave_flash = 1; + } + else + logf(" the slave file is not flash (swf) format!\n"); + + if(master_flash && slave_flash) { + read_swf(&master, masterdata, masterlength); + if(config.cat) + return catcombine(masterdata, masterlength, _slavename, slavedata, slavelength, newlength); + else + return normalcombine(masterdata, masterlength, _slavename, slavedata, slavelength, newlength); } *newlength = 0;