X-Git-Url: http://git.asbjorn.biz/?p=swftools.git;a=blobdiff_plain;f=lib%2Fmodules%2Fswftools.c;h=1dc66d89fd6e7dca20a76ca669c1f3414be0a76d;hp=35cd13c8429c9b73db335280aed3847e6d042f42;hb=faa7df4336cea6ae258ac4f83ae09e0227ca844d;hpb=70d8aa1b4a40fb5d8660566b311ad931f3976d88 diff --git a/lib/modules/swftools.c b/lib/modules/swftools.c index 35cd13c..1dc66d8 100644 --- a/lib/modules/swftools.c +++ b/lib/modules/swftools.c @@ -23,11 +23,15 @@ // Matrix & Math tools for SWF files +#include "../rfxswf.h" + #define S64 long long SFIXED RFXSWF_SP(SFIXED a1,SFIXED a2,SFIXED b1,SFIXED b2) -{ S64 a; - a = (S64)a1*(S64)b1+(S64)a2*(S64)b2; - return (SFIXED)(a>>16); +{ S64 a = ((S64)a1*(S64)b1+(S64)a2*(S64)b2)>>16; + SFIXED result = (SFIXED)(a); + if(a!=result) + fprintf(stderr, "Warning: overflow in matrix multiplication\n"); + return result; } SFIXED RFXSWF_QFIX(int zaehler,int nenner) // bildet Quotient von zwei INTs in SFIXED { S64 z = zaehler<<16; @@ -42,13 +46,14 @@ MATRIX * swf_MatrixJoin(MATRIX * d,MATRIX * s1,MATRIX * s2) if (!s1) return (s2)?(MATRIX *)memcpy(d,s2,sizeof(MATRIX)):NULL; if (!s2) return (MATRIX *)memcpy(d,s1,sizeof(MATRIX)); - d->tx = s1->tx + s2->tx; - d->ty = s1->ty + s2->ty; + d->tx = s1->tx + RFXSWF_SP(s1->sx,s1->r1,s2->tx,s2->ty); + d->ty = s1->ty + RFXSWF_SP(s1->r0,s1->sy,s2->tx,s2->ty); d->sx = RFXSWF_SP(s1->sx,s1->r1,s2->sx,s2->r0); - d->sy = RFXSWF_SP(s1->r0,s1->sy,s2->r1,s2->sy); d->r0 = RFXSWF_SP(s1->r0,s1->sy,s2->sx,s2->r0); + d->r1 = RFXSWF_SP(s1->sx,s1->r1,s2->r1,s2->sy); + d->sy = RFXSWF_SP(s1->r0,s1->sy,s2->r1,s2->sy); //DumpMatrix(NULL,d); @@ -95,32 +100,43 @@ U16 swf_GetDefineID(TAG * t) { case ST_DEFINESHAPE: case ST_DEFINESHAPE2: case ST_DEFINESHAPE3: + case ST_DEFINESHAPE4: case ST_DEFINEMORPHSHAPE: + case ST_DEFINEMORPHSHAPE2: case ST_DEFINEEDITTEXT: case ST_DEFINEBITS: case ST_DEFINEBITSJPEG2: case ST_DEFINEBITSJPEG3: case ST_DEFINEBITSLOSSLESS: case ST_DEFINEBITSLOSSLESS2: + case ST_DEFINESCALINGGRID: //pseudodefine case ST_DEFINEBUTTON: case ST_DEFINEBUTTON2: case ST_DEFINEBUTTONCXFORM: //pseudodefine case ST_DEFINEBUTTONSOUND: //pseudodefine + case ST_CSMTEXTSETTINGS: //pseudodefine case ST_DEFINEFONT: case ST_DEFINEFONT2: + case ST_DEFINEFONT3: case ST_DEFINEFONTINFO: //pseudodefine case ST_DEFINEFONTINFO2: //pseudodefine + case ST_DEFINEFONTALIGNZONES: //pseudodefine + case ST_DEFINEFONTNAME: //pseudodefine case ST_DEFINETEXT: + case ST_DEFINEBINARY: case ST_DEFINETEXT2: case ST_DEFINESOUND: case ST_DEFINESPRITE: case ST_DEFINEMOVIE: case ST_DEFINEVIDEOSTREAM: - { case ST_GLYPHNAMES: //pseudodefine + case ST_GLYPHNAMES: //pseudodefine case ST_VIDEOFRAME: //pseudodefine case ST_NAMECHARACTER: //pseudodefine + case ST_DOINITACTION: //pseudodefine id = swf_GetU16(t); break; + default: + fprintf(stderr, "rfxswf: Error: tag %d (%s) has no id\n", t->id, swf_TagGetName(t)); } swf_SetTagPos(t,oldTagPos); @@ -133,6 +149,7 @@ SRECT swf_GetDefineBBox(TAG * t) U32 oldTagPos; U16 id = 0; SRECT b1,b2; + memset(&b1, 0, sizeof(b1)); oldTagPos = swf_GetTagPos(t); swf_SetTagPos(t,0); @@ -143,6 +160,7 @@ SRECT swf_GetDefineBBox(TAG * t) { case ST_DEFINESHAPE: case ST_DEFINESHAPE2: case ST_DEFINESHAPE3: + case ST_DEFINESHAPE4: case ST_DEFINEEDITTEXT: case ST_DEFINETEXT: case ST_DEFINETEXT2: @@ -191,6 +209,12 @@ U16 swf_GetPlaceID(TAG * t) U16 d = swf_GetU16(t); id = (flags&PF_CHAR)?swf_GetU16(t):id; } break; + case ST_PLACEOBJECT3: + { U8 flags = swf_GetU8(t); + U8 flags2 = swf_GetU8(t); + U16 d = swf_GetU16(t); + id = (flags&PF_CHAR)?swf_GetU16(t):id; + } break; } @@ -203,9 +227,12 @@ static int swf_definingtagids[] = {ST_DEFINESHAPE, ST_DEFINESHAPE2, ST_DEFINESHAPE3, + ST_DEFINESHAPE4, ST_DEFINEMORPHSHAPE, + ST_DEFINEMORPHSHAPE2, ST_DEFINEFONT, ST_DEFINEFONT2, + ST_DEFINEFONT3, ST_DEFINETEXT, ST_DEFINETEXT2, ST_DEFINEEDITTEXT, @@ -220,6 +247,7 @@ static int swf_definingtagids[] = ST_DEFINEBUTTON2, ST_DEFINESOUND, ST_DEFINEVIDEOSTREAM, + ST_DEFINEBINARY, -1 }; @@ -228,9 +256,11 @@ static int swf_spritetagids[] = {ST_SHOWFRAME, ST_PLACEOBJECT, ST_PLACEOBJECT2, + ST_PLACEOBJECT3, ST_REMOVEOBJECT, - ST_REMOVEOBJECT2, //? + ST_REMOVEOBJECT2, ST_DOACTION, + ST_DOABC, ST_STARTSOUND, ST_FRAMELABEL, ST_SOUNDSTREAMHEAD, @@ -240,12 +270,17 @@ static int swf_spritetagids[] = -1 }; +/* tags which add content or information to a character with a given ID */ static int swf_pseudodefiningtagids[] = { ST_DEFINEFONTINFO, ST_DEFINEFONTINFO2, + ST_DEFINEFONTALIGNZONES, + ST_DEFINEFONTNAME, ST_DEFINEBUTTONCXFORM, ST_DEFINEBUTTONSOUND, + ST_DEFINESCALINGGRID, + ST_CSMTEXTSETTINGS, ST_NAMECHARACTER, ST_DOINITACTION, ST_VIDEOFRAME, @@ -312,6 +347,11 @@ int swf_GetDepth(TAG * t) { U8 flags = swf_GetU8(t); depth = swf_GetU16(t); } break; + case ST_PLACEOBJECT3: + { U8 flags = swf_GetU8(t); + U8 flags2 = swf_GetU8(t); + depth = swf_GetU16(t); + } break; case ST_SETTABINDEX: { depth = swf_GetU16(t); @@ -353,10 +393,13 @@ char* swf_GetName(TAG * t) switch(swf_GetTagID(t)) { case ST_FRAMELABEL: - name = &t->data[swf_GetTagPos(t)]; + name = (char*)&t->data[swf_GetTagPos(t)]; break; + case ST_PLACEOBJECT3: case ST_PLACEOBJECT2: { U8 flags = swf_GetU8(t); + if(t->id == ST_PLACEOBJECT3) + swf_GetU8(t); swf_GetU16(t); //depth; if(flags&PF_CHAR) swf_GetU16(t); //id @@ -366,11 +409,11 @@ char* swf_GetName(TAG * t) swf_GetCXForm(t, &c, 1); if(flags&PF_RATIO) swf_GetU16(t); - if(flags&PF_CLIPACTION) + if(flags&PF_CLIPDEPTH) swf_GetU16(t); if(flags&PF_NAME) { swf_ResetReadBits(t); - name = &t->data[swf_GetTagPos(t)]; + name = (char*)&t->data[swf_GetTagPos(t)]; } } break; @@ -382,92 +425,152 @@ char* swf_GetName(TAG * t) /* used in enumerateUsedIDs */ void swf_GetMorphGradient(TAG * tag, GRADIENT * gradient1, GRADIENT * gradient2) { - GRADIENT dummy1; - GRADIENT dummy2; int t; - if(!gradient1) - gradient1 = &dummy1; - if(!gradient2) - gradient2 = &dummy2; - gradient1->num = - gradient2->num = swf_GetU8(tag); - for(t=0;tnum;t++) + int num = swf_GetU8(tag) & 15; + if(gradient1) gradient1->num = num; + if(gradient2) gradient2->num = num; + + if(gradient1) { + gradient1->num = num; + gradient1->rgba = (RGBA*)rfx_calloc(sizeof(RGBA)*gradient1->num); + gradient1->ratios = (U8*)rfx_calloc(sizeof(gradient1->ratios[0])*gradient1->num); + } + if(gradient2) { + gradient2->num = num; + gradient2->rgba = (RGBA*)rfx_calloc(sizeof(RGBA)*gradient2->num); + gradient2->ratios = (U8*)rfx_calloc(sizeof(gradient2->ratios[0])*gradient2->num); + } + for(t=0;t=8) //FIXME - s=7; - gradient1->ratios[t] = swf_GetU8(tag); - swf_GetRGBA(tag, &gradient1->rgba[t]); - gradient2->ratios[t] = swf_GetU8(tag); - swf_GetRGBA(tag, &gradient2->rgba[t]); + U8 ratio; + RGBA color; + + ratio = swf_GetU8(tag); + swf_GetRGBA(tag, &color); + if(gradient1) { + gradient1->ratios[t] = ratio; + gradient1->rgba[t] = color; + } + + ratio = swf_GetU8(tag); + swf_GetRGBA(tag, &color); + if(gradient2) { + gradient2->ratios[t] = ratio; + gradient2->rgba[t] = color; + } } } #define DEBUG_ENUMERATE if(0) +//#define DEBUG_ENUMERATE -static void enumerateUsedIDs_styles(TAG * tag, void (*callback)(TAG*, int, void*), void*callback_data, int num, int morph) +void enumerateUsedIDs_fillstyle(TAG * tag, int t, void (*callback)(TAG*, int, void*), void*callback_data, int num, int morph) { - U16 count; - int t; - count = swf_GetU8(tag); - if(count == 0xff && num>1) // defineshape2,3 only - count = swf_GetU16(tag); - - for(t=0;tpos); + if(type == 0) { + RGBA color; + if(num >= 3) + {swf_GetRGBA(tag, &color);if(morph) swf_GetRGBA(tag, NULL);} + else + {swf_GetRGB(tag, &color);if(morph) swf_GetRGB(tag, NULL);} + DEBUG_ENUMERATE printf(" %02x%02x%02x%02x\n", color.r,color.g,color.b,color.a); + } + else if(type == 0x10 || type == 0x12 || type == 0x13) { - int type; - U8*pos; swf_ResetReadBits(tag); - type = swf_GetU8(tag); //type - if(type == 0) { - if(num == 3) - {swf_GetRGBA(tag, NULL);if(morph) swf_GetRGBA(tag, NULL);} - else - {swf_GetRGB(tag, NULL);if(morph) swf_GetRGB(tag, NULL);} + MATRIX m; + swf_GetMatrix(tag, &m); + DEBUG_ENUMERATE swf_DumpMatrix(stdout, &m); + if(morph) { + swf_GetMatrix(tag, &m); + DEBUG_ENUMERATE swf_DumpMatrix(stdout, &m); } - else if(type == 0x10 || type == 0x12) - { - swf_ResetReadBits(tag); - swf_GetMatrix(tag, NULL); - if(morph) - swf_GetMatrix(tag, NULL); - swf_ResetReadBits(tag); - if(morph) - swf_GetMorphGradient(tag, NULL, NULL); - else - swf_GetGradient(tag, NULL, /*alpha*/ num>=3?1:0); + swf_ResetReadBits(tag); + if(morph) { + swf_GetMorphGradient(tag, NULL, NULL); + if(type == 0x13) { + swf_GetU16(tag); + swf_GetU16(tag); + } + } else { + GRADIENT g; + swf_GetGradient(tag, &g, /*alpha*/ num>=3?1:0); + DEBUG_ENUMERATE swf_DumpGradient(stdout, &g); + if(type == 0x13) + swf_GetU16(tag); } - else if(type == 0x40 || type == 0x41) - { - swf_ResetReadBits(tag); - // we made it. - if(tag->data[tag->pos] != 0xff || - tag->data[tag->pos+1] != 0xff) - (callback)(tag, tag->pos, callback_data); + } + else if(type == 0x40 || type == 0x41 || type == 0x42 || type == 0x43) + { + swf_ResetReadBits(tag); + if(tag->data[tag->pos] != 0xff || + tag->data[tag->pos+1] != 0xff) + (callback)(tag, tag->pos, callback_data); - swf_GetU16(tag); - swf_ResetReadBits(tag); + swf_GetU16(tag); + swf_ResetReadBits(tag); + swf_GetMatrix(tag, NULL); + if(morph) swf_GetMatrix(tag, NULL); - if(morph) - swf_GetMatrix(tag, NULL); + } + else { + fprintf(stderr, "rfxswf:swftools.c Unknown fillstyle:0x%02x in tag %02d\n",type, tag->id); + } +} + +void enumerateUsedIDs_linestyle(TAG * tag, int t, void (*callback)(TAG*, int, void*), void*callback_data, int num, int morph) +{ + U16 width; + RGBA color; + width = swf_GetU16(tag); + char fill=0; + if(morph) + swf_GetU16(tag); + if(num >= 4) { + U16 flags = swf_GetU16(tag); + DEBUG_ENUMERATE printf("line style %d) flags: %08x\n", t, flags); + if((flags & 0x30) == 0x20) { + U16 miter = swf_GetU16(tag); // miter limit + DEBUG_ENUMERATE printf("line style %d) miter join: %08x\n", t, miter); } - else { - fprintf(stderr, "rfxswf:swftools.c Unknown fillstyle:0x%02x\n",type); + if(flags & 0x08) { + fill = 1; } } + if(!fill) { + if(num >= 3) + {swf_GetRGBA(tag, &color);if(morph) swf_GetRGBA(tag, NULL);} + else + {swf_GetRGB(tag, &color);if(morph) swf_GetRGB(tag, NULL);} + } else { + enumerateUsedIDs_fillstyle(tag, t, callback, callback_data, num, morph); + } + DEBUG_ENUMERATE printf("line style %d) width=%.2f color=%02x%02x%02x%02x \n", t, width/20.0, color.r,color.g,color.b,color.a); +} + +void enumerateUsedIDs_styles(TAG * tag, void (*callback)(TAG*, int, void*), void*callback_data, int num, int morph) +{ + U16 count; + int t; + count = swf_GetU8(tag); + if(count == 0xff && num>1) // defineshape2,3,4 only + count = swf_GetU16(tag); + + DEBUG_ENUMERATE printf("%d fill styles\n", count); + for(t=0;tpos = 0; switch(tag->id) { - case ST_DEFINEBUTTONCXFORM: { + case ST_DEFINEBUTTONSOUND: { int t; callback(tag, tag->pos + base, callback_data); for(t=0;t<4;t++) { @@ -505,10 +608,11 @@ void enumerateUsedIDs(TAG * tag, int base, void (*callback)(TAG*, int, void*), v } } } break; - case ST_DEFINEBUTTONSOUND: + case ST_DEFINEBUTTONCXFORM: callback(tag, tag->pos + base, callback_data); //button id break; + case ST_SYMBOLCLASS: case ST_EXPORTASSETS: { int num = swf_GetU16(tag); int t; @@ -519,8 +623,27 @@ void enumerateUsedIDs(TAG * tag, int base, void (*callback)(TAG*, int, void*), v } } break; + case ST_IMPORTASSETS: + case ST_IMPORTASSETS2: { + swf_GetString(tag); //count + swf_GetU8(tag); //reserved + swf_GetU8(tag); //reserved + int num = swf_GetU16(tag); //url + int t; + for(t=0;tpos + base, callback_data); //button id + swf_GetU16(tag); //id + while(swf_GetU8(tag)); //name + } + } break; + + case ST_DOABC: + case ST_RAWABC: + break; + case ST_FREECHARACTER: /* unusual tags, which all start with an ID */ case ST_NAMECHARACTER: + case ST_DEFINEFONTNAME: case ST_GENERATORTEXT: callback(tag, tag->pos + base, callback_data); break; @@ -533,6 +656,12 @@ void enumerateUsedIDs(TAG * tag, int base, void (*callback)(TAG*, int, void*), v break; callback(tag, 3 + base, callback_data); break; + case ST_PLACEOBJECT3: + // only if placeflaghascharacter + if(!(tag->data[0]&2)) + break; + callback(tag, 4 + base, callback_data); + break; case ST_REMOVEOBJECT: callback(tag, tag->pos + base, callback_data); break; @@ -557,12 +686,12 @@ void enumerateUsedIDs(TAG * tag, int base, void (*callback)(TAG*, int, void*), v if(id == ST_END) break; tag2->len = tag2->memsize = len; - tag2->data = malloc(len); + tag2->data = (U8*)rfx_alloc(len); memcpy(tag2->data, &tag->data[tag->pos], len); /* I never saw recursive sprites, but they are (theoretically) possible, so better add base here again */ enumerateUsedIDs(tag2, tag->pos + base, callback, callback_data); - swf_DeleteTag(tag2); + swf_DeleteTag(0, tag2); swf_GetBlock(tag, NULL, len); } } @@ -580,8 +709,8 @@ void enumerateUsedIDs(TAG * tag, int base, void (*callback)(TAG*, int, void*), v } while(1) { - U16 charid; - if(!swf_GetU8(tag)) //flags + U8 flags = swf_GetU8(tag); + if(!flags) //flags break; callback(tag, tag->pos + base, callback_data); swf_GetU16(tag); //char @@ -592,6 +721,16 @@ void enumerateUsedIDs(TAG * tag, int base, void (*callback)(TAG*, int, void*), v swf_ResetReadBits(tag); swf_GetCXForm(tag, NULL, 1); } + if(flags&0x10) { + U8 num = swf_GetU8(tag); + int t; + for(t=0;tpos + base, callback_data); + id = swf_GetU16(tag); + } + if(flags & 4) { // hascolor + if(num==1) swf_GetRGB(tag, NULL); + else swf_GetRGBA(tag, NULL); + } + if(flags & 2) { //has x offset swf_ResetReadBits(tag); - if(flags & 8) { // hasfont - callback(tag, tag->pos + base, callback_data); - id = swf_GetU16(tag); - } - if(flags & 4) { // hascolor - if(num==1) swf_GetRGB(tag, NULL); - else swf_GetRGBA(tag, NULL); - } - if(flags & 2) { //has x offset - swf_ResetReadBits(tag); - swf_GetU16(tag); - } - if(flags & 1) { //has y offset - swf_ResetReadBits(tag); - swf_GetU16(tag); - } - if(flags & 8) { //has height - swf_ResetReadBits(tag); - swf_GetU16(tag); - } - } else { // glyph record - int t; + swf_GetU16(tag); + } + if(flags & 1) { //has y offset swf_ResetReadBits(tag); - for(t=0;tpos + base, callback_data); break; + case ST_DEFINEMORPHSHAPE2: + case ST_DEFINESHAPE4: + num++; case ST_DEFINEMORPHSHAPE: case ST_DEFINESHAPE3: num++; //fallthrough @@ -682,30 +827,48 @@ void enumerateUsedIDs(TAG * tag, int base, void (*callback)(TAG*, int, void*), v int id; int numshapes = 1; int morph = 0; - if(tag->id == ST_DEFINEMORPHSHAPE) { + if(tag->id == ST_DEFINEMORPHSHAPE || tag->id==ST_DEFINEMORPHSHAPE2) { numshapes = 2; morph = 1; } id = swf_GetU16(tag); // id; - swf_GetRect(tag, NULL); // bounds + SRECT r={0,0,0,0},r2={0,0,0,0}; + swf_GetRect(tag, &r); // shape bounds if(morph) { swf_ResetReadBits(tag); - swf_GetRect(tag, NULL); // bounds2 + swf_GetRect(tag, NULL); // shape bounds2 + if(num>=4) { + swf_ResetReadBits(tag); + swf_GetRect(tag, NULL); // edge bounds1 + } + } + if(num>=4) { + swf_ResetReadBits(tag); + swf_GetRect(tag, &r2); // edge bounds + U8 flags = swf_GetU8(tag); // flags, &1: contains scaling stroke, &2: contains non-scaling stroke + DEBUG_ENUMERATE printf("flags: %02x (1=scaling strokes, 2=non-scaling strokes)\n", flags); + } + if(morph) { swf_GetU32(tag); //offset to endedges } DEBUG_ENUMERATE printf("Tag:%d Name:%s ID:%d\n", tag->id, swf_TagGetName(tag), id); + DEBUG_ENUMERATE printf("BBox %.2f %.2f %.2f %.2f\n", r.xmin/20.0,r.ymin/20.0,r.xmax/20.0,r.ymax/20.0); + DEBUG_ENUMERATE printf("BBox %.2f %.2f %.2f %.2f\n", r2.xmin/20.0,r2.ymin/20.0,r2.xmax/20.0,r2.ymax/20.0); + DEBUG_ENUMERATE printf("style tag pos: %d\n", tag->pos); enumerateUsedIDs_styles(tag, callback, callback_data, num, morph); DEBUG_ENUMERATE printf("-------\n"); + swf_ResetReadBits(tag); while(--numshapes>=0) /* morph shapes define two shapes */ { DEBUG_ENUMERATE printf("shape:%d\n", numshapes); fillbits = swf_GetBits(tag, 4); linebits = swf_GetBits(tag, 4); - DEBUG_ENUMERATE printf("%d %d\n", fillbits, linebits); + DEBUG_ENUMERATE printf("fillbits=%d linebits=%d\n", fillbits, linebits); swf_ResetReadBits(tag); + int x=0,y=0; while(1) { int flags; flags = swf_GetBits(tag, 1); @@ -715,10 +878,9 @@ void enumerateUsedIDs(TAG * tag, int base, void (*callback)(TAG*, int, void*), v break; if(flags&1) { //move int n = swf_GetBits(tag, 5); - int x,y; x = swf_GetBits(tag, n); //x y = swf_GetBits(tag, n); //y - DEBUG_ENUMERATE printf("move %f %f\n",x/20.0,y/20.0); + DEBUG_ENUMERATE printf("moveTo %.2f %.2f\n",x/20.0,y/20.0); } if(flags&2) { //fill0 int fill0; @@ -746,15 +908,18 @@ void enumerateUsedIDs(TAG * tag, int base, void (*callback)(TAG*, int, void*), v if(flags) { //straight edge int n = swf_GetBits(tag, 4) + 2; if(swf_GetBits(tag, 1)) { //line flag - int x,y; - x = swf_GetSBits(tag, n); //delta x - y = swf_GetSBits(tag, n); //delta y - DEBUG_ENUMERATE printf("line %f %f\n",x/20.0,y/20.0); + x += swf_GetSBits(tag, n); //delta x + y += swf_GetSBits(tag, n); //delta y + DEBUG_ENUMERATE printf("lineTo %.2f %.2f\n",x/20.0,y/20.0); } else { int v=swf_GetBits(tag, 1); int d; d = swf_GetSBits(tag, n); //vert/horz - DEBUG_ENUMERATE printf("%s %f\n",v?"vertical":"horizontal", d/20.0); + if(!v) + x += d; + else + y += d; + DEBUG_ENUMERATE printf("lineTo %.2f %.2f (%s)\n",x/20.0,y/20.0, v?"vertical":"horizontal"); } } else { //curved edge int n = swf_GetBits(tag, 4) + 2; @@ -763,7 +928,7 @@ void enumerateUsedIDs(TAG * tag, int base, void (*callback)(TAG*, int, void*), v y1 = swf_GetSBits(tag, n); x2 = swf_GetSBits(tag, n); y2 = swf_GetSBits(tag, n); - DEBUG_ENUMERATE printf("curve %f %f %f %f\n", x1/20.0, y1/20.0, x2/20.0, y2/20.0); + DEBUG_ENUMERATE printf("splineTo %.2f %.2f %.2f %.2f\n", x1/20.0, y1/20.0, x2/20.0, y2/20.0); } } } @@ -801,17 +966,31 @@ void swf_GetUsedIDs(TAG * t, int * positions) enumerateUsedIDs(t, 0, callbackFillin, &ptr); } -void swf_Relocate (SWF*swf, char*bitmap) +char swf_Relocate (SWF*swf, char*bitmap) { TAG*tag; int slaveids[65536]; memset(slaveids, -1, sizeof(slaveids)); tag = swf->firstTag; + char ok = 1; + + int current_id=0; +#define NEW_ID(n) \ + for(current_id++;current_id<65536;current_id++) { \ + if(!bitmap[current_id]) { \ + n = current_id; \ + break; \ + } \ + } \ + if(current_id==65536) { \ + fprintf(stderr, "swf_Relocate: Couldn't relocate: Out of IDs\n"); \ + return 0; \ + } + while(tag) { int num; int *ptr; - int t; if(swf_isDefiningTag(tag)) { @@ -822,18 +1001,12 @@ void swf_Relocate (SWF*swf, char*bitmap) if(!bitmap[id]) { //free newid = id; + } else if(slaveids[id]>0) { + newid = slaveids[id]; + } else { + NEW_ID(newid); } - else { - newid = 0; - for (t=1;t<65536;t++) - { - if(!bitmap[t]) - { - newid = t; - break; - } - } - } + bitmap[newid] = 1; slaveids[id] = newid; @@ -841,20 +1014,77 @@ void swf_Relocate (SWF*swf, char*bitmap) } num = swf_GetNumUsedIDs(tag); - ptr = malloc(sizeof(int)*num); - swf_GetUsedIDs(tag, ptr); - - for(t=0;tdata[ptr[t]]); - if(slaveids[id]<0) { - fprintf(stderr, "swf_Relocate: Mapping id never encountered before: %d\n", id); - return ; + if(num) { + ptr = (int*)rfx_alloc(sizeof(int)*num); + swf_GetUsedIDs(tag, ptr); + int t; + for(t=0;tdata[ptr[t]]); + if(slaveids[id]<0) { + if(!id && bitmap[id]) { + /* id 0 is only used in SWF versions >=9. It's the ID of + the main timeline. It's used in e.g. SYMBOLTAG tags, but + never defined, so if we're asked to reallocate it, we have + to allocate an ID for it on the fly. */ + int newid; + NEW_ID(newid); + bitmap[newid] = 1; + slaveids[id] = newid; + id = newid; + } else if(!bitmap[id]) { + /* well- we don't know this id, but it's not reserved anyway, so just + leave it alone */ + } else { + /* this actually happens with files created with Flash CS4 and never. + Apparently e.g. DefineButton tags are able to use forward declarations of objects. */ + fprintf(stderr, "warning: Mapping id (%d) never encountered before in %s\n", id, + swf_TagGetName(tag)); + int newid; + NEW_ID(newid); + id = slaveids[id] = newid; + ok = 0; + } + } else { + id = slaveids[id]; + } + PUT16(&tag->data[ptr[t]], id); } - id = slaveids[id]; - PUT16(&tag->data[ptr[t]], id); + free(ptr); } tag=tag->next; } + return ok; +} + +/* untested */ +void swf_Relocate2(SWF*swf, int*id2id) +{ + TAG*tag; + tag = swf->firstTag; + while(tag) { + if(swf_isDefiningTag(tag)) { + int id = swf_GetDefineID(tag); + id = id2id[id]; + if(id>=0) { + swf_SetDefineID(tag, id); + } + } + int num = swf_GetNumUsedIDs(tag); + if(num) { + int *ptr; + int t; + ptr = (int*)rfx_alloc(sizeof(int)*num); + swf_GetUsedIDs(tag, ptr); + for(t=0;tdata[ptr[t]]); + id = id2id[id]; + if(id>=0) { + PUT16(&tag->data[ptr[t]], id); + } + } + free(ptr); + } + } } void swf_RelocateDepth(SWF*swf, char*bitmap) @@ -872,7 +1102,27 @@ void swf_RelocateDepth(SWF*swf, char*bitmap) while(tag) { - int depth = swf_GetDepth(tag); + int depth; + /* TODO * clip depths + * sprites + */ + if(tag->id == ST_PLACEOBJECT2) { + SWFPLACEOBJECT obj; + swf_GetPlaceObject(tag, &obj); + if(obj.clipdepth) { + int newdepth = obj.clipdepth+nr; + if(newdepth>65535) { + fprintf(stderr, "Couldn't relocate depths: too large values\n"); + newdepth = 65535; + } + obj.clipdepth = newdepth; + swf_ResetTag(tag, ST_PLACEOBJECT2); + swf_SetPlaceObject(tag, &obj); + } + swf_PlaceObjectFree(&obj); + } + + depth = swf_GetDepth(tag); if(depth>=0) { int newdepth = depth+nr; if(newdepth>65535) { @@ -885,6 +1135,53 @@ void swf_RelocateDepth(SWF*swf, char*bitmap) } } +U8 swf_isShapeTag(TAG*tag) +{ + if(tag->id == ST_DEFINESHAPE || + tag->id == ST_DEFINESHAPE2 || + tag->id == ST_DEFINESHAPE3 || + tag->id == ST_DEFINESHAPE4) + return 1; + return 0; +} + +U8 swf_isPlaceTag(TAG*tag) +{ + if(tag->id == ST_PLACEOBJECT || + tag->id == ST_PLACEOBJECT2 || + tag->id == ST_PLACEOBJECT3) + return 1; + return 0; +} +U8 swf_isTextTag(TAG*tag) +{ + if(tag->id == ST_DEFINETEXT || + tag->id == ST_DEFINETEXT2) + return 1; + return 0; +} + +U8 swf_isFontTag(TAG*tag) +{ + if(tag->id == ST_DEFINEFONT || + tag->id == ST_DEFINEFONT2 || + tag->id == ST_DEFINEFONT3 || + tag->id == ST_DEFINEFONTINFO) + return 1; + return 0; +} + +U8 swf_isImageTag(TAG*tag) +{ + if(tag->id == ST_DEFINEBITSJPEG || + tag->id == ST_DEFINEBITSJPEG2 || + tag->id == ST_DEFINEBITSJPEG3 || + tag->id == ST_DEFINEBITSLOSSLESS || + tag->id == ST_DEFINEBITSLOSSLESS2) + return 1; + return 0; +} + TAG* swf_Concatenate (TAG*list1,TAG*list2) { TAG*tag=0,*lasttag=0; @@ -927,3 +1224,162 @@ TAG* swf_Concatenate (TAG*list1,TAG*list2) return swf1.firstTag; } + +static int tagHash(TAG*tag) +{ + int t, h=0; + unsigned int a = 0x6b973e5a; + /* start at pos 2, as 0 and 1 are the id */ + for(t=2;tlen;t++) { + unsigned int b = a; + a >>= 8; + a += tag->data[t]*0xefbc35a5*b*(t+1); + } + return a&0x7fffffff; //always return positive number +} + +void swf_Optimize(SWF*swf) +{ + const int hash_size = 131072; + char* dontremap = (char*)rfx_calloc(sizeof(char)*65536); + U16* remap = (U16*)rfx_alloc(sizeof(U16)*65536); + TAG* id2tag = (TAG*)rfx_calloc(sizeof(TAG*)*65536); + TAG** hashmap = (TAG**)rfx_calloc(sizeof(TAG*)*hash_size); + TAG* tag; + int t; + for(t=0;t<65536;t++) { + remap[t] = t; + } + + swf_FoldAll(swf); + + tag = swf->firstTag; + while(tag) { + /* make sure we don't remap to this tag, + as it might have different "helper tags" + FIXME: a better way would be to compare + the helper tags, too. + */ + if(swf_isPseudoDefiningTag(tag) && + tag->id != ST_NAMECHARACTER) { + dontremap[swf_GetDefineID(tag)] = 1; + } + tag=tag->next; + } + tag = swf->firstTag; + while(tag) { + TAG*next = tag->next; + + /* remap the tag */ + int num = swf_GetNumUsedIDs(tag); + int*positions = (int*)rfx_alloc(sizeof(int)*num); + int t; + swf_GetUsedIDs(tag, positions); + for(t=0;tdata[positions[t]]); + id = remap[id]; + PUT16(&tag->data[positions[t]], id); + } + rfx_free(positions); + + /* now look for previous tags with the same + content */ + if(swf_isDefiningTag(tag)) { + TAG*tag2; + int id = swf_GetDefineID(tag); + int hash = tagHash(tag); + int match=0; + if(!dontremap[id]) + while((tag2 = hashmap[hash%hash_size])) { + if(tag2 != (TAG*)0 && tag->len == tag2->len) { + if(memcmp(&tag->data[2],&tag2->data[2],tag->len-2) == 0) { + match = 1; + break; + } + } + hash++; + } + if(!match) { + while(hashmap[hash%hash_size]) hash++; + hashmap[hash%hash_size] = tag; + } else { + /* we found two identical tags- remap one + of them */ + remap[id] = swf_GetDefineID(tag2); + swf_DeleteTag(swf, tag); + } + } else if(swf_isPseudoDefiningTag(tag)) { + int id = swf_GetDefineID(tag); + if(remap[id]!=id) { + /* if this tag was remapped, we don't + need the helper tag anymore. Discard + it. */ + swf_DeleteTag(swf, tag); + } + } + + tag = next; + } + + rfx_free(dontremap); + rfx_free(remap); + rfx_free(id2tag); + rfx_free(hashmap); +} + +void swf_SetDefineBBox(TAG * tag, SRECT newbbox) +{ + U16 id = 0; + SRECT b1; + swf_SetTagPos(tag,0); + + switch (swf_GetTagID(tag)) + { + case ST_DEFINESHAPE: + case ST_DEFINESHAPE2: + case ST_DEFINESHAPE3: + case ST_DEFINEEDITTEXT: + case ST_DEFINETEXT: + case ST_DEFINETEXT2: + case ST_DEFINEVIDEOSTREAM: { + U32 after_bbox_offset = 0, len; + U8*data; + id = swf_GetU16(tag); + swf_GetRect(tag, &b1); + swf_ResetReadBits(tag); + after_bbox_offset = tag->pos; + len = tag->len - after_bbox_offset; + data = (U8*)malloc(len); + memcpy(data, &tag->data[after_bbox_offset], len); + tag->writeBit = 0; + tag->len = 2; + swf_SetRect(tag, &newbbox); + swf_SetBlock(tag, data, len); + free(data); + tag->pos = tag->readBit = 0; + + } break; + default: + fprintf(stderr, "rfxswf: Tag %d (%s) has no bbox\n", tag->id, swf_TagGetName(tag)); + } +} + +RGBA swf_GetSWFBackgroundColor(SWF*swf) +{ + TAG*t=swf->firstTag; + RGBA color; + color.r = color.b = color.g = 0; + color.a = 255; + while(t) { + if(t->id == ST_SETBACKGROUNDCOLOR) { + swf_SetTagPos(t, 0); + color.r = swf_GetU8(t); + color.g = swf_GetU8(t); + color.b = swf_GetU8(t); + break; + } + t=t->next; + } + return color; +} +