X-Git-Url: http://git.asbjorn.biz/?p=swftools.git;a=blobdiff_plain;f=lib%2Frfxswf.c;h=ad3ad217d5db1aabad06bc267f39b4bab0a7082f;hp=5fdc4c7c171d69501c3e0920ff8614702b41efe7;hb=f3784f411338b99aa3b04c5e881c995227c8a053;hpb=827c7eb6f76dcdac5644c605c53cbacf7d1073af diff --git a/lib/rfxswf.c b/lib/rfxswf.c index 5fdc4c7..ad3ad21 100644 --- a/lib/rfxswf.c +++ b/lib/rfxswf.c @@ -1,5 +1,4 @@ /* vi: set sts=2 sw=2 :*/ - /* rfxswf.c Library for creating and reading SWF files or parts of it. @@ -8,30 +7,47 @@ Part of the swftools package. - Copyright (c) 2000, 2001 Rainer Böhme - - This file is distributed under the GPL, see file COPYING for details + Copyright (c) 2000-2003 Rainer Böhme + Copyright (c) 2003 Matthias Kramm + + 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 "mem.h" #include "rfxswf.h" -#ifdef HAVE_LIBJPEG -#ifdef HAVE_JPEGLIB_H +#ifdef HAVE_JPEGLIB #define HAVE_BOOLEAN #include -#define _JPEGLIB_INCLUDED_ -#endif // HAVE_JPEGLIB_H -#endif // HAVE_LIBJPEG +#endif // HAVE_JPEGLIB -#ifdef HAVE_LIBZ -#ifdef HAVE_ZLIB_H +#ifdef HAVE_ZLIB #include -#define _ZLIB_INCLUDED_ -#endif // HAVE_ZLIB_H -#endif // HAVE_LIBZ +#endif // HAVE_ZLIB + +#ifndef RFXSWF_DISABLESOUND +#ifdef HAVE_LAME +#include "lame/lame.h" +#endif +#endif + +#ifdef HAVE_TIME_H +#include +#endif #include "./bitio.h" +#include "./MD5.h" // internal constants @@ -40,22 +56,15 @@ #define MEMSIZE(l) (((l/MALLOC_SIZE)+1)*MALLOC_SIZE) - // inline wrapper functions TAG * swf_NextTag(TAG * t) { return t->next; } TAG * swf_PrevTag(TAG * t) { return t->prev; } -int swf_GetFrameNo(TAG * t) { return t->frame; } U16 swf_GetTagID(TAG * t) { return t->id; } U32 swf_GetTagLen(TAG * t) { return t->len; } U8* swf_GetTagLenPtr(TAG * t) { return &(t->data[t->len]); } U32 swf_GetTagPos(TAG * t) { return t->pos; } -// Basic Data Access Functions - -#define swf_ResetReadBits(tag) if (tag->readBit) { tag->pos++; tag->readBit = 0; } -#define swf_ResetWriteBits(tag) if (tag->writeBit) { tag->writeBit = 0; } - // for future purpose: avoid high level lib functions to change tagpos/bitpos #define swf_SaveTagPos(tag) @@ -64,9 +73,27 @@ U32 swf_GetTagPos(TAG * t) { return t->pos; } void swf_SetTagPos(TAG * t,U32 pos) { swf_ResetReadBits(t); if (pos<=t->len) t->pos = pos; - #ifdef DEBUG_RFXSWF - else fprintf(stderr,"SetTagPos() out of bounds: TagID = %i\n",t->id); - #endif + else { +#ifdef DEBUG_RFXSWF + fprintf(stderr,"SetTagPos(%d) out of bounds: TagID = %i\n",pos, t->id); +#endif + } +} + +char* swf_GetString(TAG*t) +{ + char* str = ((char*)(&(t)->data[(t)->pos])); + while(t->pos < t->len && swf_GetU8(t)); + /* make sure we always have a trailing zero byte */ + if(t->pos == t->len) { + if(t->len == t->memsize) { + swf_ResetWriteBits(t); + swf_SetU8(t, 0); + t->len = t->pos; + } + t->data[t->len] = 0; + } + return str; } U8 swf_GetU8(TAG * t) @@ -125,15 +152,7 @@ int swf_SetBlock(TAG * t,U8 * b,int l) swf_ResetWriteBits(t); if (newlen>t->memsize) { U32 newmem = MEMSIZE(newlen); - U8 * newdata = (U8*)((t->data)?realloc(t->data,newmem):malloc(newmem)); - if (!newdata) - { - #ifdef DEBUG_RFXSWF - fprintf(stderr,"Fatal Error: malloc()/realloc() failed (1). (%d bytes)\n", newmem); - *(int*)0=0; - #endif - return 0; - } + U8 * newdata = (U8*)(rfx_realloc(t->data,newmem)); t->memsize = newmem; t->data = newdata; } @@ -161,6 +180,13 @@ int swf_SetU16(TAG * t,U16 v) t->data[t->len++] = a[1]; return 0; } +void swf_SetS16(TAG * t,int v) +{ + if(v>32767 || v<-32768) { + fprintf(stderr, "Warning: S16 overflow: %d\n", v); + } + swf_SetU16(t, (S16)v); +} int swf_SetU32(TAG * t,U32 v) { U8 a[4]; @@ -207,10 +233,10 @@ S32 swf_GetSBits(TAG * t,int nbits) return (S32)res; } -U32 reader_GetBits(struct reader_t*reader, int nbits) +U32 reader_GetBits(reader_t*reader, int nbits) { return reader_readbits(reader, nbits); } -S32 reader_GetSBits(struct reader_t*reader, int nbits) +S32 reader_GetSBits(reader_t*reader, int nbits) { U32 res = reader_readbits(reader, nbits); if (res&(1<<(nbits-1))) res|=(0xffffffff<r = swf_GetU8(t); col->g = swf_GetU8(t); @@ -267,7 +293,7 @@ int swf_SetRGBA(TAG * t,RGBA * col) void swf_GetRGBA(TAG * t, RGBA * col) { RGBA dummy; - if(!col); + if(!col) col = &dummy; col->r = swf_GetU8(t); col->g = swf_GetU8(t); @@ -279,6 +305,10 @@ void swf_GetGradient(TAG * tag, GRADIENT * gradient, char alpha) { GRADIENT dummy; int t; + if(!tag) { + memset(gradient, 0, sizeof(GRADIENT)); + return; + } if(!gradient) gradient = &dummy; gradient->num = swf_GetU8(tag); @@ -295,22 +325,53 @@ void swf_GetGradient(TAG * tag, GRADIENT * gradient, char alpha) } } +void swf_SetGradient(TAG * tag, GRADIENT * gradient, char alpha) +{ + int t; + if(!tag) { + memset(gradient, 0, sizeof(GRADIENT)); + return; + } + swf_SetU8(tag, gradient->num); + for(t=0; t<8 && tnum; t++) + { + swf_SetU8(tag, gradient->ratios[t]); + if(!alpha) + swf_SetRGB(tag, &gradient->rgba[t]); + else + swf_SetRGBA(tag, &gradient->rgba[t]); + } +} + +int swf_CountUBits(U32 v,int nbits) +{ int n = 32; + U32 m = 0x80000000; + if(v == 0x00000000) n = 0; + else + while (!(v&m)) + { n--; + m>>=1; + } + return (n>nbits)?n:nbits; +} + int swf_CountBits(U32 v,int nbits) { int n = 33; U32 m = 0x80000000; - if (!v) n = 0; else if (v&m) - { while (v&m) + { if(v == 0xffffffff) n = 1; + else + while (v&m) { n--; m>>=1; - if (!m) break; } } else - { while (!(v&m)) + { if(v == 0x00000000) n = 0; + else + while (!(v&m)) { n--; m>>=1; - if (!m) break; } } return (n>nbits)?n:nbits; @@ -319,6 +380,7 @@ int swf_CountBits(U32 v,int nbits) int swf_GetRect(TAG * t,SRECT * r) { int nbits; SRECT dummy; + if(!t) {r->xmin=r->xmax=r->ymin=r->ymax=0;return 0;} if (!r) r = &dummy; nbits = (int) swf_GetBits(t,5); r->xmin = swf_GetSBits(t,nbits); @@ -328,7 +390,7 @@ int swf_GetRect(TAG * t,SRECT * r) return 0; } -int reader_GetRect(struct reader_t*reader,SRECT * r) +int reader_GetRect(reader_t*reader,SRECT * r) { int nbits; SRECT dummy; if (!r) r = &dummy; @@ -347,6 +409,10 @@ int swf_SetRect(TAG * t,SRECT * r) nbits = swf_CountBits(r->xmax,nbits); nbits = swf_CountBits(r->ymin,nbits); nbits = swf_CountBits(r->ymax,nbits); + if(nbits>=32) { + fprintf(stderr, "rfxswf: Warning: num_bits overflow in swf_SetRect\n"); + nbits=31; + } swf_SetBits(t,nbits,5); swf_SetBits(t,r->xmin,nbits); @@ -357,6 +423,89 @@ int swf_SetRect(TAG * t,SRECT * r) return 0; } +void swf_ExpandRect(SRECT*src, SPOINT add) +{ + if((src->xmin | src->ymin | src->xmax | src->ymax)==0) { + src->xmin = add.x; + src->ymin = add.y; + src->xmax = add.x; + src->ymax = add.y; + if((add.x|add.y) == 0) src->xmax++; //make sure the bbox is not NULL anymore + return; + } + if(add.x < src->xmin) + src->xmin = add.x; + if(add.x > src->xmax) + src->xmax = add.x; + if(add.y < src->ymin) + src->ymin = add.y; + if(add.y > src->ymax) + src->ymax = add.y; +} +void swf_ExpandRect2(SRECT*src, SRECT*add) +{ + if((add->xmin | add->ymin | add->xmax | add->ymax)==0) + return; + if((src->xmin | src->ymin | src->xmax | src->ymax)==0) + *src = *add; + if(add->xmin < src->xmin) + src->xmin = add->xmin; + if(add->ymin < src->ymin) + src->ymin = add->ymin; + if(add->xmax > src->xmax) + src->xmax = add->xmax; + if(add->ymax > src->ymax) + src->ymax = add->ymax; +} +void swf_ExpandRect3(SRECT*src, SPOINT center, int radius) +{ + if((src->xmin | src->ymin | src->xmax | src->ymax)==0) { + src->xmin = center.x-radius; + src->ymin = center.y-radius; + src->xmax = center.x+radius; + src->ymax = center.y+radius; + if((center.x|center.y|radius) == 0) src->xmax++; //make sure the bbox is not NULL anymore + return; + } + if(center.x - radius < src->xmin) + src->xmin = center.x - radius; + if(center.x + radius > src->xmax) + src->xmax = center.x + radius; + if(center.y - radius < src->ymin) + src->ymin = center.y - radius; + if(center.y + radius > src->ymax) + src->ymax = center.y + radius; +} +SPOINT swf_TurnPoint(SPOINT p, MATRIX* m) +{ + SPOINT r; + r.x = (int)(m->sx*(1/65536.0)*p.x + m->r1*(1/65536.0)*p.y + 0.5) + m->tx; + r.y = (int)(m->r0*(1/65536.0)*p.x + m->sy*(1/65536.0)*p.y + 0.5) + m->ty; + return r; +} +SRECT swf_TurnRect(SRECT r, MATRIX* m) +{ + SRECT g; + SPOINT p1,p2,p3,p4,pp1,pp2,pp3,pp4; + if(!m) + return r; + p1.x = r.xmin;p1.y = r.ymin; + p2.x = r.xmax;p2.y = r.ymin; + p3.x = r.xmin;p3.y = r.ymax; + p4.x = r.xmax;p4.y = r.ymax; + pp1 = swf_TurnPoint(p1, m); + pp2 = swf_TurnPoint(p2, m); + pp3 = swf_TurnPoint(p3, m); + pp4 = swf_TurnPoint(p4, m); + g.xmin = g.xmax = pp1.x; + g.ymin = g.ymax = pp1.y; + swf_ExpandRect(&g, pp2); + swf_ExpandRect(&g, pp3); + swf_ExpandRect(&g, pp4); + return g; +} + + int swf_GetMatrix(TAG * t,MATRIX * m) { MATRIX dummy; int nbits; @@ -412,6 +561,7 @@ int swf_SetMatrix(TAG * t,MATRIX * m) nbits = swf_CountBits(m->sx,0); nbits = swf_CountBits(m->sy,nbits); if(nbits>=32) { + /* TODO: happens on AMD64 systems for normal values? */ fprintf(stderr,"rfxswf: Error: matrix values too large\n"); nbits = 31; } @@ -447,7 +597,7 @@ int swf_SetMatrix(TAG * t,MATRIX * m) return 0; } -int swf_GetCXForm(TAG * t,CXFORM * cx,U8 alpha) //FIXME: alpha should be type bool +int swf_GetCXForm(TAG * t,CXFORM * cx,U8 alpha) { CXFORM cxf; int hasadd; int hasmul; @@ -542,57 +692,144 @@ int swf_SetCXForm(TAG * t,CXFORM * cx,U8 alpha) return 0; } -int swf_GetPoint(TAG * t,SPOINT * p) { return 0; } -int swf_SetPoint(TAG * t,SPOINT * p) { return 0; } +//int swf_GetPoint(TAG * t,SPOINT * p) { return 0; } +//int swf_SetPoint(TAG * t,SPOINT * p) { return 0; } + +void swf_SetPassword(TAG * t, const char * password) +{ + /* WARNING: crypt_md5 is not reentrant */ + char salt[3]; + char* md5string; + +#if defined(HAVE_LRAND48) && defined(HAVE_SRAND48) && defined(HAVE_TIME_H) && defined(HAVE_TIME) + srand48(time(0)); + salt[0] = "abcdefghijklmnopqrstuvwxyz0123456789"[lrand48()%36]; + salt[1] = "abcdefghijklmnopqrstuvwxyz0123456789"[lrand48()%36]; +#else + salt[0] = 'l'; + salt[1] = '8'; + fprintf(stderr, "rfxswf: Warning- no usable random generator found\n"); + fprintf(stderr, "Your password will be vulnerable to dictionary attacks\n"); +#endif + salt[2] = 0; + + md5string = crypt_md5(password, salt); + + swf_SetU16(t,0); + swf_SetString(t, md5string); +} + +int swf_VerifyPassword(TAG * t, const char * password) +{ + char*md5string1, *md5string2; + char*x; + char*md5, *salt; + int n; + + if(t->len >= 5 && t->pos==0 && + t->data[0] == 0 && + t->data[1] == 0) { + swf_GetU16(t); + } else { + printf("%d %d %d %d\n", t->len, t->pos, t->data[0], t->data[1]); + } + + md5string1 = swf_GetString(t); + + if(strncmp(md5string1, "$1$",3 )) { + fprintf(stderr, "rfxswf: no salt in pw string\n"); + return 0; + } + x = strchr(md5string1+3, '$'); + if(!x) { + fprintf(stderr, "rfxswf: invalid salt format in pw string\n"); + return 0; + } + n = x-(md5string1+3); + salt = (char*)rfx_alloc(n+1); + memcpy(salt, md5string1+3, n); + salt[n] = 0; + + md5string2 = crypt_md5(password, salt); + rfx_free(salt); + if(strcmp(md5string1, md5string2) != 0) + return 0; + return 1; +} // Tag List Manipulating Functions -int swf_UpdateFrame(TAG * t,S8 delta) -// returns number of frames -{ int res = -1; - while (t) - { t->frame+=delta; - res = t->frame; - t = t->next; +TAG * swf_InsertTag(TAG * after,U16 id) +{ TAG * t; + + t = (TAG *)rfx_calloc(sizeof(TAG)); + t->id = id; + + if (after) + { + t->prev = after; + t->next = after->next; + after->next = t; + if (t->next) t->next->prev = t; } - return res; + return t; } -TAG * swf_InsertTag(TAG * after,U16 id) // updates frames, if nescessary +TAG * swf_InsertTagBefore(SWF* swf, TAG * before,U16 id) { TAG * t; - t = (TAG *)malloc(sizeof(TAG)); - if (t) - { memset(t,0x00,sizeof(TAG)); - t->id = id; - - if (after) - { t->frame = after->frame; - t->prev = after; - t->next = after->next; - after->next = t; - if (t->next) t->next->prev = t; - - if (id==ST_SHOWFRAME) swf_UpdateFrame(t->next,+1); - } + t = (TAG *)rfx_calloc(sizeof(TAG)); + t->id = id; + + if (before) + { + t->next = before; + t->prev = before->prev; + before->prev = t; + if (t->prev) t->prev->next = t; + } + if(swf && swf->firstTag == before) { + swf->firstTag = t; } return t; } +void swf_ClearTag(TAG * t) +{ + if (t->data) rfx_free(t->data); + t->data = 0; + t->pos = 0; + t->len = 0; + t->readBit = 0; + t->writeBit = 0; + t->memsize = 0; +} + +void swf_ResetTag(TAG*tag, U16 id) +{ + tag->len = tag->pos = tag->readBit = tag->writeBit = 0; + tag->id = id; +} + +TAG* swf_CopyTag(TAG*tag, TAG*to_copy) +{ + tag = swf_InsertTag(tag, to_copy->id); + swf_SetBlock(tag, to_copy->data, to_copy->len); + return tag; +} + int swf_DeleteTag(TAG * t) { if (!t) return -1; - if (t->id==ST_SHOWFRAME) swf_UpdateFrame(t->next,-1); - if (t->prev) t->prev->next = t->next; if (t->next) t->next->prev = t->prev; - if (t->data) free(t->data); - free(t); + if (t->data) rfx_free(t->data); + rfx_free(t); return 0; } -TAG * swf_ReadTag(struct reader_t*reader, TAG * prev) +TAG * swf_ReadTag(reader_t*reader, TAG * prev) { TAG * t; U16 raw; U32 len; @@ -611,38 +848,26 @@ TAG * swf_ReadTag(struct reader_t*reader, TAG * prev) } if (id==ST_DEFINESPRITE) len = 2*sizeof(U16); - // Sprite handling fix: Flaten sprite tree + // Sprite handling fix: Flatten sprite tree - t = (TAG *)malloc(sizeof(TAG)); - - if (!t) - { - #ifdef DEBUG_RFXSWF - fprintf(stderr,"Fatal Error: malloc()/realloc() failed (2). (%d bytes)\n", sizeof(TAG)); - #endif - return NULL; - } - - memset(t,0x00,sizeof(TAG)); + t = (TAG *)rfx_calloc(sizeof(TAG)); t->len = len; t->id = id; if (t->len) - { t->data = (U8*)malloc(t->len); - if (!t->data) - { - #ifdef DEBUG_RFXSWF - fprintf(stderr,"Fatal Error: malloc()/realloc() failed (3). (%d bytes)\n", t->len); - #endif + { t->data = (U8*)rfx_alloc(t->len); + t->memsize = t->len; + if (reader->read(reader, t->data, t->len) != t->len) { + fprintf(stderr, "rfxswf: Warning: Short read (tagid %d). File truncated?\n", t->id); + free(t->data);t->data=0; + free(t); return NULL; } - t->memsize = t->len; - if (reader->read(reader, t->data, t->len) != t->len) return NULL; } if (prev) - { t->frame = prev->frame+((prev->id==ST_SHOWFRAME)?1:0); + { t->prev = prev; prev->next = t; } @@ -652,7 +877,7 @@ TAG * swf_ReadTag(struct reader_t*reader, TAG * prev) int swf_DefineSprite_GetRealSize(TAG * t); -int swf_WriteTag2(struct writer_t*writer, TAG * t) +int swf_WriteTag2(writer_t*writer, TAG * t) // returns tag length in bytes (incl. Header), -1 = Error // writer = 0 -> no output { U16 raw[3]; @@ -663,7 +888,9 @@ int swf_WriteTag2(struct writer_t*writer, TAG * t) len = (t->id==ST_DEFINESPRITE)?swf_DefineSprite_GetRealSize(t):t->len; - short_tag = len<0x3f; + short_tag = len<0x3f&& + (t->id!=ST_DEFINEBITSLOSSLESS&&t->id!=ST_DEFINEBITSLOSSLESS2&&t->id!=ST_SOUNDSTREAMBLOCK&& + t->id!=ST_DEFINEBITSJPEG&&t->id!=ST_DEFINEBITSJPEG2&&t->id!=ST_DEFINEBITSJPEG3); if (writer) { if (short_tag) @@ -716,11 +943,14 @@ int swf_WriteTag2(struct writer_t*writer, TAG * t) int swf_WriteTag(int handle, TAG * t) { - struct writer_t writer; + writer_t writer; + int len = 0; if(handle<0) return swf_WriteTag2(0, t); writer_init_filewriter(&writer, handle); - return swf_WriteTag2(&writer, t); + len = swf_WriteTag2(&writer, t); + writer.finish(&writer); + return len; } int swf_DefineSprite_GetRealSize(TAG * t) @@ -731,46 +961,116 @@ int swf_DefineSprite_GetRealSize(TAG * t) } do { t = swf_NextTag(t); - if (t->id!=ST_DEFINESPRITE) len += swf_WriteTag(-1, t); + if (t && t->id!=ST_DEFINESPRITE) len += swf_WriteTag(-1, t); else t = NULL; } while (t&&(t->id!=ST_END)); return len; } +void swf_UnFoldSprite(TAG * t) +{ + U16 id,tmp; + U32 len; + TAG*next = t; + U16 spriteid,spriteframes; + int level; + if(t->id!=ST_DEFINESPRITE) + return; + if(t->len<=4) // not folded + return; + + swf_SetTagPos(t,0); + + spriteid = swf_GetU16(t); //id + spriteframes = swf_GetU16(t); //frames + + level = 1; + + while(1) + { + TAG*it = 0; + tmp = swf_GetU16(t); + len = tmp&0x3f; + id = tmp>>6; + if(id == ST_END) + level--; + if(id == ST_DEFINESPRITE && len<=4) + level++; + + if (len==0x3f) + len = swf_GetU32(t); + it = swf_InsertTag(next, id); + next = it; + it->len = len; + it->id = id; + if (it->len) + { it->data = (U8*)rfx_alloc(it->len); + it->memsize = it->len; + swf_GetBlock(t, it->data, it->len); + } + + if(!level) + break; + } + + rfx_free(t->data); t->data = 0; + t->memsize = t->len = t->pos = 0; + + swf_SetU16(t, spriteid); + swf_SetU16(t, spriteframes); +} + void swf_FoldSprite(TAG * t) { TAG*sprtag=t,*tmp; U16 id,frames,tmpid; + int level; if(t->id!=ST_DEFINESPRITE) return; if(!t->len) { fprintf(stderr, "Error: Sprite has no ID!"); return; } + if(t->len>4) { + /* sprite is already folded */ + return; + } t->pos = 0; id = swf_GetU16(t); - //frames = swf_GetU16(t); - free(t->data); + rfx_free(t->data); t->len = t->pos = t->memsize = 0; t->data = 0; frames = 0; + t = swf_NextTag(sprtag); + level = 1; + do { if(t->id==ST_SHOWFRAME) frames++; + if(t->id == ST_DEFINESPRITE && t->len<=4) + level++; + if(t->id == ST_END) + level--; t = swf_NextTag(t); - } while(t&&t!=ST_END); + } while(t && level); + if(level) + fprintf(stderr, "rfxswf error: sprite doesn't end(1)\n"); - t = swf_NextTag(sprtag); swf_SetU16(sprtag, id); swf_SetU16(sprtag, frames); + t = swf_NextTag(sprtag); + level = 1; + do { - tmpid= t->id; - if(t->len<0x3f) { + if(t->len<0x3f&& + (t->id!=ST_DEFINEBITSLOSSLESS&&t->id!=ST_DEFINEBITSLOSSLESS2&&t->id!=ST_SOUNDSTREAMBLOCK&& + t->id!=ST_DEFINEBITSJPEG&&t->id!=ST_DEFINEBITSJPEG2&&t->id!=ST_DEFINEBITSJPEG3) + ) { swf_SetU16(sprtag,t->len|(t->id<<6)); } else { swf_SetU16(sprtag,0x3f|(t->id<<6)); @@ -779,28 +1079,110 @@ void swf_FoldSprite(TAG * t) if(t->len) swf_SetBlock(sprtag,t->data, t->len); tmp = t; + if(t->id == ST_DEFINESPRITE && t->len<=4) + level++; + if(t->id == ST_END) + level--; t = swf_NextTag(t); swf_DeleteTag(tmp); } - while (t&&(tmpid!=ST_END)); + while (t && level); + if(level) + fprintf(stderr, "rfxswf error: sprite doesn't end(2)\n"); // sprtag->next = t; // t->prev = sprtag; } +int swf_IsFolded(TAG * t) +{ + return (t->id == ST_DEFINESPRITE && t->len>4); +} + void swf_FoldAll(SWF*swf) { TAG*tag = swf->firstTag; + //swf_DumpSWF(stdout, swf); while(tag) { - if(tag->id == ST_DEFINESPRITE) + if(tag->id == ST_DEFINESPRITE) { swf_FoldSprite(tag); + //swf_DumpSWF(stdout, swf); + } tag = swf_NextTag(tag); } } +void swf_UnFoldAll(SWF*swf) +{ + TAG*tag = swf->firstTag; + while(tag) { + if(tag->id == ST_DEFINESPRITE) + swf_UnFoldSprite(tag); + tag = tag->next; + } +} + +void swf_OptimizeTagOrder(SWF*swf) +{ + TAG*tag,*next; + TAG*level0; + int level; + int changes; + swf_UnFoldAll(swf); + /* at the moment, we don't actually do optimizing, + only fixing of non-spec-conformant things like + sprite tags */ + + do { + changes = 0; + level = 0; + level0 = 0; + tag = swf->firstTag; + while(tag) { + next = tag->next; + if(tag->id == ST_DEFINESPRITE) { + if(tag->len>4) { + /* ??? all sprites are supposed to be unfolded */ + fprintf(stderr, "librfxswf error - internal error in OptimizeTagOrder/UnfoldAll\n"); + } + level++; + if(level==1) { + level0 = tag; + tag = next; + continue; + } + } + if(level>=1) { + /* move non-sprite tags out of sprite */ + if(!swf_isAllowedSpriteTag(tag) || level>=2) { + /* remove tag from current position */ + tag->prev->next = tag->next; + if(tag->next) + tag->next->prev = tag->prev; + + /* insert before tag level0 */ + tag->next = level0; + tag->prev = level0->prev; + level0->prev = tag; + if(tag->prev) + tag->prev->next = tag; + else + swf->firstTag = tag; + changes = 1; + } + } + if(tag->id == ST_END) { + level--; + } + + tag = next; + } + } while(changes); +} + // Movie Functions -int swf_ReadSWF2(struct reader_t*reader, SWF * swf) // Reads SWF to memory (malloc'ed), returns length or <0 if fails +int swf_ReadSWF2(reader_t*reader, SWF * swf) // Reads SWF to memory (malloc'ed), returns length or <0 if fails { if (!swf) return -1; memset(swf,0x00,sizeof(SWF)); @@ -809,7 +1191,7 @@ int swf_ReadSWF2(struct reader_t*reader, SWF * swf) // Reads SWF to memory (ma int len; TAG * t; TAG t1; - struct reader_t zreader; + reader_t zreader; if ((len = reader->read(reader ,b,8))<8) return -1; @@ -843,26 +1225,44 @@ int swf_ReadSWF2(struct reader_t*reader, SWF * swf) // Reads SWF to memory (ma int swf_ReadSWF(int handle, SWF * swf) { - struct reader_t reader; + reader_t reader; reader_init_filereader(&reader, handle); return swf_ReadSWF2(&reader, swf); } -int swf_WriteSWF2(struct writer_t*writer, SWF * swf) // Writes SWF to file, returns length or <0 if fails +int swf_WriteSWF2(writer_t*writer, SWF * swf) // Writes SWF to file, returns length or <0 if fails { U32 len; TAG * t; int frameCount=0; - struct writer_t zwriter; + writer_t zwriter; + int fileSize = 0; + int inSprite = 0; + int writer_lastpos = 0; + int ret; if (!swf) return -1; + if (!writer) return -1; // the caller should provide a nullwriter, not 0, for querying SWF size + + if(writer) writer_lastpos = writer->pos; + + if(swf->fileVersion >= 8) { + if ((swf->firstTag && swf->firstTag->id != ST_FILEATTRIBUTES) && + (!swf->firstTag->next || swf->firstTag->next->id != ST_FILEATTRIBUTES)) + { + U32 flags = 0; // | 128 = usenetwork, | 8 = hasmetadata + swf_SetU32(swf_InsertTagBefore(swf, swf->firstTag,ST_FILEATTRIBUTES),flags); + } + } // Insert REFLEX Tag #ifdef INSERT_RFX_TAG - if (swf->firstTag && swf_NextTag(swf->firstTag)) - if (swf_GetTagID(swf_NextTag(swf->firstTag))!=ST_REFLEX) - swf_SetBlock(swf_InsertTag(swf->firstTag,ST_REFLEX),"rfx",3); + if ((swf->firstTag && swf->firstTag->id != ST_REFLEX) && + (!swf->firstTag->next || swf->firstTag->next->id != ST_REFLEX)) + { + swf_SetBlock(swf_InsertTagBefore(swf, swf->firstTag,ST_REFLEX),"rfx",3); + } #endif // INSERT_RFX_TAG @@ -872,10 +1272,16 @@ int swf_WriteSWF2(struct writer_t*writer, SWF * swf) // Writes SWF to file, t = swf->firstTag; frameCount = 0; - while(t) - { len += swf_WriteTag(-1, t); - if (t->id==ST_SHOWFRAME) frameCount++; - t = swf_NextTag(t); + while(t) { + len += swf_WriteTag(-1,t); + if(t->id == ST_DEFINESPRITE && !swf_IsFolded(t)) inSprite++; + else if(t->id == ST_END && inSprite) inSprite--; + else if(t->id == ST_END && !inSprite) { + if(t->prev && t->prev->id!=ST_SHOWFRAME) + frameCount++; + } + else if(t->id == ST_SHOWFRAME && !inSprite) frameCount++; + t = swf_NextTag(t); } { TAG t1; @@ -897,79 +1303,108 @@ int swf_WriteSWF2(struct writer_t*writer, SWF * swf) // Writes SWF to file, swf_SetU16(&t2, swf->frameCount); l = swf_GetTagLen(&t2)+8; } + if(swf->compressed == 8) { + l -= 8; + } + fileSize = l+len; if(len) {// don't touch headers without tags - swf->fileSize = l+len; + swf->fileSize = fileSize; swf->frameCount = frameCount; } - - if(swf->compressed) { - char*id = "CWS"; - writer->write(writer, id, 3); - } - else { - char*id = "FWS"; - writer->write(writer, id, 3); - } - writer->write(writer, &swf->fileVersion, 1); - PUT32(b4, swf->fileSize); - writer->write(writer, b4, 4); + if(swf->compressed != 8) { + /* compressed flag set to 8 means "skip first 8 + header bytes". This is necessary if the caller wants to + create compressed SWFs himself . + It also means that we don't initialize our own zlib + writer, but assume the caller provided one. + */ + if(swf->compressed) { + char*id = "CWS"; + writer->write(writer, id, 3); + } + else { + char*id = "FWS"; + writer->write(writer, id, 3); + } - if(swf->compressed) { - writer_init_zlibdeflate(&zwriter, writer); - writer = &zwriter; + writer->write(writer, &swf->fileVersion, 1); + PUT32(b4, swf->fileSize); + writer->write(writer, b4, 4); + + if(swf->compressed) { + writer_init_zlibdeflate(&zwriter, writer); + writer = &zwriter; + } } swf_SetRect(&t1,&swf->movieSize); swf_SetU16(&t1,swf->frameRate); swf_SetU16(&t1,swf->frameCount); - if (writer) - { - int ret = writer->write(writer,b,swf_GetTagLen(&t1)); - if (ret!=swf_GetTagLen(&t1)) - { - #ifdef DEBUG_RFXSWF - printf("ret:%d\n",ret); - perror("write:"); - fprintf(stderr,"WriteSWF() failed: Header.\n"); - #endif - return -1; - } + ret = writer->write(writer,b,swf_GetTagLen(&t1)); + if (ret!=swf_GetTagLen(&t1)) + { + #ifdef DEBUG_RFXSWF + fprintf(stderr, "ret:%d\n",ret); + perror("write:"); + fprintf(stderr,"WriteSWF() failed: Header.\n"); + #endif + return -1; + } - t = swf->firstTag; - while (t) - { if (swf_WriteTag2(writer, t)<0) return -1; - t = swf_NextTag(t); + t = swf->firstTag; + while (t) + { if (swf_WriteTag2(writer, t)<0) return -1; + t = swf_NextTag(t); + } + if(swf->compressed) { + if(swf->compressed != 8) { + zwriter.finish(&zwriter); + return writer->pos - writer_lastpos; } - writer->finish(writer); //e.g. flush zlib buffers + return (int)fileSize; + } else { + return (int)fileSize; } } - return (int)swf->fileSize; } int swf_WriteSWF(int handle, SWF * swf) // Writes SWF to file, returns length or <0 if fails { - struct writer_t writer; + writer_t writer; + int len = 0; swf->compressed = 0; - if(handle<0) - return swf_WriteSWF2(&writer, swf); + + if(handle<0) { + writer_init_nullwriter(&writer); + len = swf_WriteSWF2(&writer, swf); + return len; + } writer_init_filewriter(&writer, handle); - return swf_WriteSWF2(&writer, swf); + len = swf_WriteSWF2(&writer, swf); + writer.finish(&writer); + return len; } int swf_WriteSWC(int handle, SWF * swf) // Writes SWF to file, returns length or <0 if fails { - struct writer_t writer; + writer_t writer; + int len = 0; swf->compressed = 1; - if(handle<0) - return swf_WriteSWF2(&writer, swf); + + if(handle<0) { + writer_init_nullwriter(&writer); + len = swf_WriteSWF2(&writer, swf); + } writer_init_filewriter(&writer, handle); - return swf_WriteSWF2(&writer, swf); + len = swf_WriteSWF2(&writer, swf); + writer.finish(&writer); + return len; } -int swf_WriteHeader2(struct writer_t*writer,SWF * swf) +int swf_WriteHeader2(writer_t*writer,SWF * swf) { SWF myswf; memcpy(&myswf,swf,sizeof(SWF)); @@ -1003,15 +1438,33 @@ int swf_WriteCGI(SWF * swf) return swf_WriteSWF(fileno(stdout),swf); } +SWF* swf_CopySWF(SWF*swf) +{ + SWF*nswf = rfx_alloc(sizeof(SWF)); + TAG*tag, *ntag; + memcpy(nswf, swf, sizeof(SWF)); + nswf->firstTag = 0; + tag = swf->firstTag; + ntag = 0; + while(tag) { + ntag = swf_CopyTag(ntag, tag); + if(!nswf->firstTag) + nswf->firstTag = ntag; + tag = tag->next; + } + return nswf; +} + void swf_FreeTags(SWF * swf) // Frees all malloc'ed memory for tags { TAG * t = swf->firstTag; while (t) { TAG * tnew = t->next; - if (t->data) free(t->data); - free(t); + if (t->data) rfx_free(t->data); + rfx_free(t); t = tnew; } + swf->firstTag = 0; } // include advanced functions @@ -1019,6 +1472,7 @@ void swf_FreeTags(SWF * swf) // Frees all malloc'ed memory for t #include "modules/swfdump.c" #include "modules/swfshape.c" #include "modules/swftext.c" +#include "modules/swffont.c" #include "modules/swfobject.c" #include "modules/swfbutton.c" #include "modules/swftools.c" @@ -1026,4 +1480,5 @@ void swf_FreeTags(SWF * swf) // Frees all malloc'ed memory for t #include "modules/swfbits.c" #include "modules/swfaction.c" #include "modules/swfsound.c" - +#include "modules/swfdraw.c" +#include "modules/swfrender.c"