X-Git-Url: http://git.asbjorn.biz/?a=blobdiff_plain;f=lib%2Fmodules%2Fswftools.c;h=1ed9e17083e96dc7191d8c9af21a39f710e9244b;hb=6f9968fe9231b75ffc067c8b27a05aaefca5bfb2;hp=29b363103144c1f1233affd218efc979e2fcefee;hpb=9158b8afa0cd28413091347213a69349d0b8a593;p=swftools.git diff --git a/lib/modules/swftools.c b/lib/modules/swftools.c index 29b3631..1ed9e17 100644 --- a/lib/modules/swftools.c +++ b/lib/modules/swftools.c @@ -25,9 +25,11 @@ #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"); + return result; } SFIXED RFXSWF_QFIX(int zaehler,int nenner) // bildet Quotient von zwei INTs in SFIXED { S64 z = zaehler<<16; @@ -42,13 +44,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,6 +98,7 @@ U16 swf_GetDefineID(TAG * t) { case ST_DEFINESHAPE: case ST_DEFINESHAPE2: case ST_DEFINESHAPE3: + case ST_DEFINESHAPE4: case ST_DEFINEMORPHSHAPE: case ST_DEFINEEDITTEXT: case ST_DEFINEBITS: @@ -102,14 +106,18 @@ U16 swf_GetDefineID(TAG * t) 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_DEFINETEXT: case ST_DEFINETEXT2: case ST_DEFINESOUND: @@ -136,6 +144,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); @@ -194,6 +203,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; } @@ -206,9 +221,11 @@ static int swf_definingtagids[] = {ST_DEFINESHAPE, ST_DEFINESHAPE2, ST_DEFINESHAPE3, + ST_DEFINESHAPE4, ST_DEFINEMORPHSHAPE, ST_DEFINEFONT, ST_DEFINEFONT2, + ST_DEFINEFONT3, ST_DEFINETEXT, ST_DEFINETEXT2, ST_DEFINEEDITTEXT, @@ -231,8 +248,9 @@ static int swf_spritetagids[] = {ST_SHOWFRAME, ST_PLACEOBJECT, ST_PLACEOBJECT2, + ST_PLACEOBJECT3, ST_REMOVEOBJECT, - ST_REMOVEOBJECT2, //? + ST_REMOVEOBJECT2, ST_DOACTION, ST_STARTSOUND, ST_FRAMELABEL, @@ -243,12 +261,16 @@ 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_DEFINEBUTTONCXFORM, ST_DEFINEBUTTONSOUND, + ST_DEFINESCALINGGRID, + ST_CSMTEXTSETTINGS, ST_NAMECHARACTER, ST_DOINITACTION, ST_VIDEOFRAME, @@ -315,6 +337,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); @@ -358,8 +385,11 @@ char* swf_GetName(TAG * t) case ST_FRAMELABEL: name = &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 @@ -369,7 +399,7 @@ 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); @@ -397,50 +427,55 @@ void swf_GetMorphGradient(TAG * tag, GRADIENT * gradient1, GRADIENT * gradient2) for(t=0;tnum;t++) { int s=t; - if(s>=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]); + if(s>=16) //FIXME + s=15; + gradient1->ratios[s] = swf_GetU8(tag); + swf_GetRGBA(tag, &gradient1->rgba[s]); + gradient2->ratios[s] = swf_GetU8(tag); + swf_GetRGBA(tag, &gradient2->rgba[s]); } } #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_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 only + 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); 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);} } - else if(type == 0x10 || type == 0x12) + else if(type == 0x10 || type == 0x12 || type == 0x13) { swf_ResetReadBits(tag); - swf_GetMatrix(tag, NULL); + MATRIX m; + swf_GetMatrix(tag, &m); + DEBUG_ENUMERATE swf_DumpMatrix(stdout, &m); if(morph) swf_GetMatrix(tag, NULL); swf_ResetReadBits(tag); if(morph) swf_GetMorphGradient(tag, NULL, NULL); - else + else { swf_GetGradient(tag, NULL, /*alpha*/ num>=3?1:0); + } } - else if(type == 0x40 || type == 0x41) + else if(type == 0x40 || type == 0x41 || type == 0x42 || type == 0x43) { swf_ResetReadBits(tag); // we made it. @@ -455,22 +490,26 @@ static void enumerateUsedIDs_styles(TAG * tag, void (*callback)(TAG*, int, void* swf_GetMatrix(tag, NULL); } else { - fprintf(stderr, "rfxswf:swftools.c Unknown fillstyle:0x%02x\n",type); + fprintf(stderr, "rfxswf:swftools.c Unknown fillstyle:0x%02x in tag %02x\n",type, tag->id); } } swf_ResetReadBits(tag); count = swf_GetU8(tag); // line style array if(count == 0xff) count = swf_GetU16(tag); + DEBUG_ENUMERATE printf("%d line 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++) { @@ -508,7 +547,7 @@ 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; @@ -522,6 +561,20 @@ 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_FREECHARACTER: /* unusual tags, which all start with an ID */ case ST_NAMECHARACTER: case ST_GENERATORTEXT: @@ -536,6 +589,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; @@ -624,44 +683,47 @@ void enumerateUsedIDs(TAG * tag, int base, void (*callback)(TAG*, int, void*), v advancebits = swf_GetU8(tag); //advancebits while(1) { U16 flags; + int t; swf_ResetReadBits(tag); flags = swf_GetBits(tag, 8); if(!flags) break; - if(flags & 128) // text style record - { + + 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); - 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 @@ -685,21 +750,32 @@ 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; + 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_GetRect(tag, NULL); // edge bounds1 + } + if(num>=4) { + swf_GetRect(tag, NULL); // edge bounds + swf_GetU8(tag); // flags, &1: contains scaling stroke, &2: contains non-scaling stroke + } + 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("style tag pos: %d\n", tag->pos); enumerateUsedIDs_styles(tag, callback, callback_data, num, morph); DEBUG_ENUMERATE printf("-------\n"); while(--numshapes>=0) /* morph shapes define two shapes */ @@ -707,7 +783,7 @@ void enumerateUsedIDs(TAG * tag, int base, void (*callback)(TAG*, int, void*), v 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); while(1) { int flags; @@ -851,7 +927,8 @@ void swf_Relocate (SWF*swf, char*bitmap) for(t=0;tdata[ptr[t]]); if(slaveids[id]<0) { - fprintf(stderr, "swf_Relocate: Mapping id never encountered before: %d\n", id); + fprintf(stderr, "swf_Relocate: Mapping id (%d) never encountered before in %s\n", id, + swf_TagGetName(tag)); return ; } id = slaveids[id]; @@ -862,6 +939,36 @@ void swf_Relocate (SWF*swf, char*bitmap) } } +/* 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 = 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); + } + } + } + } +} + void swf_RelocateDepth(SWF*swf, char*bitmap) { TAG*tag; @@ -877,10 +984,27 @@ void swf_RelocateDepth(SWF*swf, char*bitmap) while(tag) { + int depth; /* TODO * clip depths * sprites */ - int depth = swf_GetDepth(tag); + 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) { @@ -897,7 +1021,33 @@ U8 swf_isShapeTag(TAG*tag) { if(tag->id == ST_DEFINESHAPE || tag->id == ST_DEFINESHAPE2 || - tag->id == ST_DEFINESHAPE3) + 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_DEFINEFONTINFO) return 1; return 0; } @@ -999,8 +1149,6 @@ void swf_Optimize(SWF*swf) } tag = swf->firstTag; while(tag) { - int doremap=1; - TAG*next = tag->next; /* remap the tag */ @@ -1014,7 +1162,6 @@ void swf_Optimize(SWF*swf) PUT16(&tag->data[positions[t]], id); } rfx_free(positions); - tag = tag->next; /* now look for previous tags with the same content */ @@ -1025,22 +1172,11 @@ void swf_Optimize(SWF*swf) int match=0; if(!dontremap[id]) while((tag2 = hashmap[hash%hash_size])) { - if(tag2 != (TAG*)(-1) && tag->len == tag2->len) { - int t; - /* start at pos 2, as 0 and 1 are the id */ - for(t=2;tlen;t++) { - if(tag->data[t] != tag2->data[t]) - break; - } - if(t == tag->len) { - match=1; - } - } - if(match) { - /* we found two identical tags- remap one - of them */ - remap[id] = swf_GetDefineID(tag2); - break; + if(tag2 != (TAG*)0 && tag->len == tag2->len) { + if(memcmp(&tag->data[2],&tag2->data[2],tag->len-2) == 0) { + match = 1; + break; + } } hash++; } @@ -1048,10 +1184,12 @@ void swf_Optimize(SWF*swf) 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(tag); if(tag == swf->firstTag) swf->firstTag = next; - doremap = 0; } } else if(swf_isPseudoDefiningTag(tag)) { int id = swf_GetDefineID(tag); @@ -1062,14 +1200,71 @@ void swf_Optimize(SWF*swf) swf_DeleteTag(tag); if(tag == swf->firstTag) swf->firstTag = next; - doremap = 0; } } 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 = 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; +} +