X-Git-Url: http://git.asbjorn.biz/?p=swftools.git;a=blobdiff_plain;f=lib%2Frfxswf.c;h=944418d6f172accd2bb53e0d65450690ec4b83c5;hp=d7cbb03ed53180570b3166c84c51fd29e89428a9;hb=6feed80959ad2c11f0427bf0e5a30aab8abd7083;hpb=1464bfc1385c44d1562b7b156683679a642d1604 diff --git a/lib/rfxswf.c b/lib/rfxswf.c index d7cbb03..944418d 100644 --- a/lib/rfxswf.c +++ b/lib/rfxswf.c @@ -1,812 +1,1358 @@ -/* rfxswf.c - - Library for creating and reading SWF files or parts of it. - There's a module directory which provides some extended functionality. - Most modules are included at the bottom of this file. - - Part of the swftools package. - - Copyright (c) 2000, 2001 Rainer Böhme - - This file is distributed under the GPL, see file COPYING for details - -*/ - -#include "rfxswf.h" - -#ifdef HAVE_JPEGLIB_H -#include -#define _JPEGLIB_INCLUDED_ -#endif - -// Win32 support may be broken since it was only tested in an older version for Watcom C -#ifdef __NT__ -# include -# include -# include -# ifdef DEBUG_RFXSWF -# include -# endif -#else -#endif - -// internal constants - -#define MALLOC_SIZE 128 -#define INSERT_RFX_TAG - -#define MEMSIZE(l) (((l/MALLOC_SIZE)+1)*MALLOC_SIZE) - -// inline wrapper functions - -LPTAG NextTag(LPTAG t) { return t->next; } -LPTAG PrevTag(LPTAG t) { return t->prev; } -int GetFrameNo(LPTAG t) { return t->frame; } -U16 GetTagID(LPTAG t) { return t->id; } -U32 GetDataSize(LPTAG t) { return t->len; } -U8* GetDataSizePtr(LPTAG t) { return &(t->data[t->len]); } -U32 GetTagPos(LPTAG t) { return t->pos; } - -// Basic Data Access Functions - -#define ResetBitmask(tag) if (tag->bitmask) { tag->pos++; tag->bitmask = 0; } -#define ResetBitcount(tag) if (tag->bitcount) { tag->bitcount = 0; } - -// for future purpose: avoid high level lib functions to change tagpos/bitcount - -#define SaveTagPos(tag) -#define RestoreTagPos(tag) - -void SetTagPos(LPTAG t,U32 pos) -{ ResetBitmask(t); - if (pos<=t->len) t->pos = pos; - #ifdef DEBUG_RFXSWF - else fprintf(stderr,"SetTagPos() out of bounds: TagID = %i\n",t->id); - #endif -} - -U8 GetU8(LPTAG t) -{ ResetBitmask(t); - #ifdef DEBUG_RFXSWF - if (t->pos>=t->len) - { fprintf(stderr,"GetU8() out of bounds: TagID = %i\n",t->id); - return 0; - } - #endif - return t->data[t->pos++]; -} - -U16 GetU16(LPTAG t) -{ U16 res; - ResetBitmask(t); - #ifdef DEBUG_RFXSWF - if (t->pos>(t->len-2)) - { fprintf(stderr,"GetU16() out of bounds: TagID = %i\n",t->id); - return 0; - } - #endif - res = t->data[t->pos] | (t->data[t->pos+1]<<8); - t->pos+=2; - return res; -} - -U32 GetU32(LPTAG t) -{ U32 res; - ResetBitmask(t); - #ifdef DEBUG_RFXSWF - if (t->pos>(t->len-4)) - { fprintf(stderr,"GetU32() out of bounds: TagID = %i\n",t->id); - return 0; - } - #endif - res = t->data[t->pos] | (t->data[t->pos+1]<<8) | - (t->data[t->pos+2]<<16) | (t->data[t->pos+3]<<24); - t->pos+=4; - return res; -} - -int GetBlock(LPTAG t,U8 * b,int l) -// returns number of bytes written (<=l) -// b = NULL -> skip data -{ ResetBitmask(t); - if ((t->len-t->pos)len-t->pos; - if (b && l) memcpy(b,&t->data[t->pos],l); - t->pos+=l; - return l; -} - -int SetBlock(LPTAG t,U8 * b,int l) -// Appends Block to the end of Tagdata, returns size -{ U32 newlen = t->len + l; - ResetBitcount(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.\n"); - #endif - return 0; - } - t->memsize = newmem; - t->data = newdata; - } - if (b) memcpy(&t->data[t->len],b,l); - else memset(&t->data[t->len],0x00,l); - t->len+=l; - return l; -} - -int SetU8(LPTAG t,U8 v) -{ ResetBitcount(t); - if ((t->len+1)>t->memsize) return (SetBlock(t,&v,1)==1)?0:-1; - t->data[t->len++] = v; - return 0; -} - -int SetU16(LPTAG t,U16 v) -{ U8 a[2]; - a[0] = v&0xff; - a[1] = v>>8; - - ResetBitcount(t); - if ((t->len+2)>t->memsize) return (SetBlock(t,a,2)==2)?0:-1; - t->data[t->len++] = a[0]; - t->data[t->len++] = a[1]; - return 0; -} - -int SetU32(LPTAG t,U32 v) -{ U8 a[4]; - a[0] = v&0xff; // to ensure correct handling of non-intel byteorder - a[1] = (v>>8)&0xff; - a[2] = (v>>16)&0xff; - a[3] = (v>>24)&0xff; - - ResetBitcount(t); - if ((t->len+4)>t->memsize) return (SetBlock(t,a,4)==4)?0:-1; - t->data[t->len++] = a[0]; - t->data[t->len++] = a[1]; - t->data[t->len++] = a[2]; - t->data[t->len++] = a[3]; - return 0; -} - -U32 GetBits(LPTAG t,int nbits) -{ U32 res = 0; - if (!nbits) return 0; - if (!t->bitmask) t->bitmask = 0x80; - while (nbits) - { res<<=1; - if (t->data[t->pos]&t->bitmask) res|=1; - t->bitmask>>=1; - nbits--; - if (!t->bitmask) - { if (nbits) t->bitmask = 0x80; - #ifdef DEBUG_RFXSWF - if (t->pos>=t->len) - { fprintf(stderr,"GetBits() out of bounds: TagID = %i\n",t->id); - return res; - } - #endif - t->pos++; - } - } - return res; -} - -S32 GetSBits(LPTAG t,int nbits) -{ U32 res = GetBits(t,nbits); - if (res&(1<<(nbits-1))) res|=(0xffffffff<bitcount) - { if (FAILED(SetU8(t,0))) return -1; - t->bitcount = 0x80; - } - if (v&bm) t->data[t->len-1] |= t->bitcount; - bm>>=1; - t->bitcount>>=1; - nbits--; - } - return 0; -} - -// Advanced Data Access Functions - -int SetRGB(LPTAG t,LPRGBA col) -{ if (!t) return -1; - if (col) - { SetU8(t,col->r); - SetU8(t,col->g); - SetU8(t,col->b); - } else SetBlock(t,NULL,3); - return 0; -} - -int SetRGBA(LPTAG t,LPRGBA col) -{ if (!t) return -1; - if (col) - { SetU8(t,col->r); - SetU8(t,col->g); - SetU8(t,col->b); - SetU8(t,col->a); - } else SetBlock(t,NULL,4); - return 0; -} - -int CountBits(U32 v,int nbits) -{ int n = 33; - U32 m = 0x80000000; - if (!v) n = 0; else - if (v&m) - { while (v&m) - { n--; - m>>=1; - if (!m) break; - } - } - else - { while (!(v&m)) - { n--; - m>>=1; - if (!m) break; - } - } - return (n>nbits)?n:nbits; -} - -int GetRect(LPTAG t,LPSRECT r) -{ int nbits; - SRECT dummy; - if (!r) r = &dummy; - nbits = (int) GetBits(t,5); - r->xmin = GetSBits(t,nbits); - r->xmax = GetSBits(t,nbits); - r->ymin = GetSBits(t,nbits); - r->ymax = GetSBits(t,nbits); - return 0; -} - -int SetRect(LPTAG t,LPSRECT r) -{ int nbits; - - nbits = CountBits(r->xmin,0); - nbits = CountBits(r->xmax,nbits); - nbits = CountBits(r->ymin,nbits); - nbits = CountBits(r->ymax,nbits); - - SetBits(t,nbits,5); - SetBits(t,r->xmin,nbits); - SetBits(t,r->xmax,nbits); - SetBits(t,r->ymin,nbits); - SetBits(t,r->ymax,nbits); - - return 0; -} - -int GetMatrix(LPTAG t,LPMATRIX m) -{ MATRIX dummy; - int nbits; - - if (!m) m = &dummy; - - if (!t) - { m->sx = m->sy = 0x10000; - m->r0 = m->r1 = 0; - m->tx = m->ty = 0; - return -1; - } - - ResetBitmask(t); - - if (GetBits(t,1)) - { nbits = GetBits(t,5); - m->sx = GetSBits(t,nbits); - m->sy = GetSBits(t,nbits); - } - else m->sx = m->sy = 0x10000; - - if (GetBits(t,1)) - { nbits = GetBits(t,5); - m->r0 = GetSBits(t,nbits); - m->r1 = GetSBits(t,nbits); - } - else m->r0 = m->r1 = 0x0; - - nbits = GetBits(t,5); - m->tx = GetSBits(t,nbits); - m->ty = GetSBits(t,nbits); - - return 0; -} - -int SetMatrix(LPTAG t,LPMATRIX m) -{ int nbits; - MATRIX ma; - - if (!m) - { m = &ma; - ma.sx = ma.sy = 0x10000; - ma.r0 = ma.r1 = 0; - ma.tx = ma.ty = 0; - } - - ResetBitcount(t); - - if ((m->sx==0x10000)&&(m->sy==0x10000)) SetBits(t,0,1); - else - { SetBits(t,1,1); - nbits = CountBits(m->sx,0); - nbits = CountBits(m->sy,nbits); - SetBits(t,nbits,5); - SetBits(t,m->sx,nbits); - SetBits(t,m->sy,nbits); - } - - if ((!m->r0)&&(!m->r1)) SetBits(t,0,1); - else - { SetBits(t,1,1); - nbits = CountBits(m->r0,0); - nbits = CountBits(m->r1,nbits); - SetBits(t,nbits,5); - SetBits(t,m->r0,nbits); - SetBits(t,m->r1,nbits); - } - - nbits = CountBits(m->tx,0); - nbits = CountBits(m->ty,nbits); - SetBits(t,nbits,5); - SetBits(t,m->tx,nbits); - SetBits(t,m->ty,nbits); - - return 0; -} - -int GetCXForm(LPTAG t,LPCXFORM cx,U8 alpha) //FIXME: alpha should be type bool -{ CXFORM cxf; - int hasadd; - int hasmul; - int nbits; - - if (!cx) cx = &cxf; - - cx->a0 = cx->r0 = cx->g0 = cx->b0 = 256; - cx->a1 = cx->r1 = cx->g1 = cx->b1 = 0; - - if (!t) return 0; - - ResetBitmask(t); - hasadd = GetBits(t,1); - hasmul = GetBits(t,1); - nbits = GetBits(t,4); - - if (hasmul) - { cx->r0 = (S16)GetSBits(t,nbits); - cx->g0 = (S16)GetSBits(t,nbits); - cx->b0 = (S16)GetSBits(t,nbits); - if (alpha) - cx->a0 = (S16)GetSBits(t,nbits); - } - - if (hasadd) - { cx->r1 = (S16)GetSBits(t,nbits); - cx->g1 = (S16)GetSBits(t,nbits); - cx->b1 = (S16)GetSBits(t,nbits); - if (alpha) - cx->a1 = (S16)GetSBits(t,nbits); - } - - return 0; -} - -int SetCXForm(LPTAG t,LPCXFORM cx,U8 alpha) -{ CXFORM cxf; - int hasadd; - int hasmul; - int nbits; - - if (!cx) - { cx = &cxf; - cx->a0 = cx->r0 = cx->g0 = cx->b0 = 256; - cx->a1 = cx->r1 = cx->g1 = cx->b1 = 0; - } - - if (!alpha) - { cx->a0 = 256; - cx->a1 = 0; - } - - nbits = 0; - - hasmul = (cx->a0!=256)||(cx->r0!=256)||(cx->g0!=256)||(cx->b0!=256); - hasadd = cx->a1|cx->r1|cx->g1|cx->b1; - - if (hasmul) - { if (alpha) nbits = CountBits((S32)cx->a0,nbits); - nbits = CountBits((S32)cx->r0,nbits); - nbits = CountBits((S32)cx->g0,nbits); - nbits = CountBits((S32)cx->b0,nbits); - } - - if (hasadd) - { if (alpha) nbits = CountBits((S32)cx->a1,nbits); - nbits = CountBits((S32)cx->r1,nbits); - nbits = CountBits((S32)cx->g1,nbits); - nbits = CountBits((S32)cx->b1,nbits); - } - - ResetBitcount(t); - SetBits(t,hasadd?1:0,1); - SetBits(t,hasmul?1:0,1); - SetBits(t,nbits,4); - - if (hasmul) - { SetBits(t,cx->r0,nbits); - SetBits(t,cx->g0,nbits); - SetBits(t,cx->b0,nbits); - if (alpha) SetBits(t,cx->a0,nbits); - } - - if (hasadd) - { SetBits(t,cx->r1,nbits); - SetBits(t,cx->g1,nbits); - SetBits(t,cx->b1,nbits); - if (alpha) SetBits(t,cx->a1,nbits); - } - - return 0; -} - -int GetPoint(LPTAG t,LPSPOINT p) { return 0; } -int SetPoint(LPTAG t,LPSPOINT p) { return 0; } - -// Tag List Manipulating Functions - -int RFXSWF_UpdateFrame(LPTAG t,S8 delta) -// returns number of frames -{ int res = -1; - while (t) - { t->frame+=delta; - res = t->frame; - t = t->next; - } - return res; -} - -#define UpdateFrame(a,b) RFXSWF_UpdateFrame(a,b) - -LPTAG InsertTag(LPTAG after,U16 id) // updates frames, if nescessary -{ LPTAG t; - - t = (LPTAG)malloc(sizeof(TAG)); - if (t) - { memset(t,0x00,sizeof(TAG)); - t->id = id; - t->bitcount = 0x80; - - 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) UpdateFrame(t->next,+1); - } - } - return t; -} - -int DeleteTag(LPTAG t) -{ if (!t) return -1; - - if (t->id==ST_SHOWFRAME) 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); - return 0; -} - -LPTAG RFXSWF_ReadTag(int handle,LPTAG prev) -{ LPTAG t; - U16 raw; - U32 len; - int id; - - if (read(handle,&raw,2)!=2) return NULL; - - len = raw&0x3f; - id = raw>>6; - - if (len==0x3f) - { if (read(handle,&len,4)!=4) return NULL; - } - - if (id==ST_DEFINESPRITE) len = 2*sizeof(U16); - // Sprite handling fix: Flaten sprite tree - - t = (LPTAG)malloc(sizeof(TAG)); - - if (!t) - { - #ifdef DEBUG_RFXSWF - fprintf(stderr,"Fatal Error: malloc()/realloc() failed.\n"); - #endif - return NULL; - } - - memset(t,0x00,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.\n"); - #endif - return NULL; - } - t->memsize = t->len; - if (read(handle,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; - } - - return t; -} - -int DefineSprite_GetRealSize(LPTAG t); - -int RFXSWF_WriteTag(int handle,LPTAG t) -// returns tag length in bytes (incl. Header), -1 = Error -// handle = -1 -> no output -{ U16 raw[3]; - U32 len; - int short_tag; - - if (!t) return -1; - - len = (t->id==ST_DEFINESPRITE)?DefineSprite_GetRealSize(t):t->len; - - short_tag = len<0x3f; - - if (handle>=0) - { if (short_tag) - { raw[0] = len|((t->id&0x3ff)<<6); - if (write(handle,raw,2)!=2) - { - #ifdef DEBUG_RFXSWF - fprintf(stderr,"WriteTag() failed: Short Header.\n"); - #endif - return -1; - } - } - else - { raw[0] = (t->id<<6)|0x3f; - raw[1] = (U16)(len&0xffff); - raw[2] = (U16)(len>>16); - if (write(handle,raw,6)!=6) - { - #ifdef DEBUG_RFXSWF - fprintf(stderr,"WriteTag() failed: Long Header.\n"); - #endif - return -1; - } - } - - if (t->data) - { if (write(handle,t->data,t->len)!=t->len) - { - #ifdef DEBUG_RFXSWF - fprintf(stderr,"WriteTag() failed: Data.\n"); - #endif - return -1; - } - } - #ifdef DEBUG_RFXSWF - else if (t->len) fprintf(stderr,"WriteTag(): Tag Data Error, id=%i\n",t->id); - #endif - } - - return t->len+(short_tag?2:6); -} - -int DefineSprite_GetRealSize(LPTAG t) -// Sprite Handling: Helper function to pack DefineSprite-Tag -{ U32 len = t->len; - do - { t = NextTag(t); - if (t->id!=ST_DEFINESPRITE) len += RFXSWF_WriteTag(-1,t); - else t = NULL; - } while (t&&(t->id!=ST_END)); - return len; -} - -#define ReadTag(a,b) RFXSWF_ReadTag(a,b) -#define WriteTag(a,b) RFXSWF_WriteTag(a,b) - -// Movie Functions - -int ReadSWF(int handle,LPSWF swf) // Reads SWF to memory (malloc'ed), returns length or <0 if fails -{ - if (!swf) return -1; - memset(swf,0x00,sizeof(SWF)); - - { char b[32]; // Header lesen - TAG t1; - LPTAG t; - - memset(&t1,0x00,sizeof(TAG)); - - if ((t1.len=read(handle,b,32))<21) return -1; - t1.data = (U8*)b; - - if (GetU8(&t1)!=(U8)'F') return -1; - if (GetU8(&t1)!=(U8)'W') return -1; - if (GetU8(&t1)!=(U8)'S') return -1; - - swf->FileVersion = GetU8(&t1); - swf->FileSize = GetU32(&t1); - GetRect(&t1,&swf->MovieSize); - swf->FrameRate = GetU16(&t1); - swf->FrameCount = GetU16(&t1); - - GetU8(&t1); - lseek(handle,GetTagPos(&t1)-1,SEEK_SET); - - // Tags lesen und verketten - t = &t1; - while (t) t = ReadTag(handle,t); - swf->FirstTag = t1.next; - t1.next->prev = NULL; - } - - return 0; -} -int WriteSWF(int handle,LPSWF swf) // Writes SWF to file, returns length or <0 if fails -{ U32 len; - LPTAG t; - - if (!swf) return -1; - - // Insert REFLEX Tag - -#ifdef INSERT_RFX_TAG - - if (NextTag(swf->FirstTag)) - if (GetTagID(NextTag(swf->FirstTag))!=ST_REFLEX) - SetBlock(InsertTag(swf->FirstTag,ST_REFLEX),"rfx",3); - -#endif // INSERT_RFX_TAG - - // Count Frames + File Size - - len = 0; - t = swf->FirstTag; - swf->FrameCount = 0; - - while(t) - { len += WriteTag(-1,t); - if (t->id==ST_SHOWFRAME) swf->FrameCount++; - t = NextTag(t); - } - - { TAG t1; - char b[64]; - U32 l; - - memset(&t1,0x00,sizeof(TAG)); - t1.data = (U8*)b; - t1.memsize = 64; - - SetU8(&t1,'F'); - SetU8(&t1,'W'); - SetU8(&t1,'S'); - SetU8(&t1,swf->FileVersion); - - SetU32(&t1,0); // Keep space for filesize - SetRect(&t1,&swf->MovieSize); - SetU16(&t1,swf->FrameRate); - SetU16(&t1,swf->FrameCount); - - l = GetDataSize(&t1); - swf->FileSize = l+len; - t1.len = 4; // bad & ugly trick ! - SetU32(&t1,swf->FileSize); - - if (handle>=0) - { - int ret = write(handle,b,l); - if (ret!=l) - { - #ifdef DEBUG_RFXSWF - printf("ret:%d (fd:%d)\n",ret, handle); - perror("write:"); - fprintf(stderr,"WriteSWF() failed: Header.\n"); - #endif - return -1; - } - - t = swf->FirstTag; - while (t) - { if (WriteTag(handle,t)<0) return -1; - t = NextTag(t); - } - } - } - return (int)swf->FileSize; -} - -int WriteCGI(LPSWF swf) -{ int len; - char s[1024]; - - len = WriteSWF(-1,swf); - - if (len<0) return -1; - - sprintf(s,"Content-type: application/x-shockwave-flash\n" - "Accept-Ranges: bytes\n" - "Content-Length: %lu\n" - "Expires: Thu, 13 Apr 2000 23:59:59 GMT\n" - "\n",len); - - write(fileno(stdout),s,strlen(s)); - return WriteSWF(fileno(stdout),swf); -} - -void FreeTags(LPSWF swf) // Frees all malloc'ed memory for tags -{ LPTAG t = swf->FirstTag; - - while (t) - { LPTAG tnew = t->next; - if (t->data) free(t->data); - free(t); - t = tnew; - } -} - -// include advanced functions - -#ifdef __NT__ - -#include "modules\swfdump.c" -#include "modules\swfshape.c" -#include "modules\swftext.c" -#include "modules\swfobject.c" -#include "modules\swfbutton.c" -#include "modules\swftools.c" -#include "modules\swfcgi.c" -#include "modules\swfbits.c" - -#else - -#include "modules/swfdump.c" -#include "modules/swfshape.c" -#include "modules/swftext.c" -#include "modules/swfobject.c" -#include "modules/swfbutton.c" -#include "modules/swftools.c" -#include "modules/swfcgi.c" -#include "modules/swfbits.c" - -#endif - - +/* vi: set sts=2 sw=2 :*/ +/* rfxswf.c + + Library for creating and reading SWF files or parts of it. + There's a module directory which provides some extended functionality. + Most modules are included at the bottom of this file. + + Part of the swftools package. + + 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 "rfxswf.h" + +#ifdef HAVE_JPEGLIB +#define HAVE_BOOLEAN +#include +#endif // HAVE_JPEGLIB + +#ifdef HAVE_ZLIB +#include +#endif // HAVE_ZLIB + +#ifndef RFXSWF_DISABLESOUND +#ifdef HAVE_LAME +#include "lame/lame.h" +#endif +#endif + +#include "./bitio.h" +#include "./MD5.h" + +// internal constants + +#define MALLOC_SIZE 128 +#define INSERT_RFX_TAG + +#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; } +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) +#define swf_RestoreTagPos(tag) + +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 +} + +char* swf_GetString(TAG*t) +{ + char* str = ((char*)(&(t)->data[(t)->pos])); + while(swf_GetU8(t)); + return str; +} + +U8 swf_GetU8(TAG * t) +{ swf_ResetReadBits(t); + #ifdef DEBUG_RFXSWF + if (t->pos>=t->len) + { fprintf(stderr,"GetU8() out of bounds: TagID = %i\n",t->id); + return 0; + } + #endif + return t->data[t->pos++]; +} + +U16 swf_GetU16(TAG * t) +{ U16 res; + swf_ResetReadBits(t); + #ifdef DEBUG_RFXSWF + if (t->pos>(t->len-2)) + { fprintf(stderr,"GetU16() out of bounds: TagID = %i\n",t->id); + return 0; + } + #endif + res = t->data[t->pos] | (t->data[t->pos+1]<<8); + t->pos+=2; + return res; +} + +U32 swf_GetU32(TAG * t) +{ U32 res; + swf_ResetReadBits(t); + #ifdef DEBUG_RFXSWF + if (t->pos>(t->len-4)) + { fprintf(stderr,"GetU32() out of bounds: TagID = %i\n",t->id); + return 0; + } + #endif + res = t->data[t->pos] | (t->data[t->pos+1]<<8) | + (t->data[t->pos+2]<<16) | (t->data[t->pos+3]<<24); + t->pos+=4; + return res; +} + +int swf_GetBlock(TAG * t,U8 * b,int l) +// returns number of bytes written (<=l) +// b = NULL -> skip data +{ swf_ResetReadBits(t); + if ((t->len-t->pos)len-t->pos; + if (b && l) memcpy(b,&t->data[t->pos],l); + t->pos+=l; + return l; +} + +int swf_SetBlock(TAG * t,U8 * b,int l) +// Appends Block to the end of Tagdata, returns size +{ U32 newlen = t->len + 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; + } + t->memsize = newmem; + t->data = newdata; + } + if (b) memcpy(&t->data[t->len],b,l); + else memset(&t->data[t->len],0x00,l); + t->len+=l; + return l; +} + +int swf_SetU8(TAG * t,U8 v) +{ swf_ResetWriteBits(t); + if ((t->len+1)>t->memsize) return (swf_SetBlock(t,&v,1)==1)?0:-1; + t->data[t->len++] = v; + return 0; +} + +int swf_SetU16(TAG * t,U16 v) +{ U8 a[2]; + a[0] = v&0xff; + a[1] = v>>8; + + swf_ResetWriteBits(t); + if ((t->len+2)>t->memsize) return (swf_SetBlock(t,a,2)==2)?0:-1; + t->data[t->len++] = a[0]; + t->data[t->len++] = a[1]; + return 0; +} + +int swf_SetU32(TAG * t,U32 v) +{ U8 a[4]; + a[0] = v&0xff; // to ensure correct handling of non-intel byteorder + a[1] = (v>>8)&0xff; + a[2] = (v>>16)&0xff; + a[3] = (v>>24)&0xff; + + swf_ResetWriteBits(t); + if ((t->len+4)>t->memsize) return (swf_SetBlock(t,a,4)==4)?0:-1; + t->data[t->len++] = a[0]; + t->data[t->len++] = a[1]; + t->data[t->len++] = a[2]; + t->data[t->len++] = a[3]; + return 0; +} + +U32 swf_GetBits(TAG * t,int nbits) +{ U32 res = 0; + if (!nbits) return 0; + if (!t->readBit) t->readBit = 0x80; + while (nbits) + { res<<=1; + if (t->data[t->pos]&t->readBit) res|=1; + t->readBit>>=1; + nbits--; + if (!t->readBit) + { if (nbits) t->readBit = 0x80; + #ifdef DEBUG_RFXSWF + if (t->pos>=t->len) + { fprintf(stderr,"GetBits() out of bounds: TagID = %i\n",t->id); + return res; + } + #endif + t->pos++; + } + } + return res; +} + +S32 swf_GetSBits(TAG * t,int nbits) +{ U32 res = swf_GetBits(t,nbits); + if (res&(1<<(nbits-1))) res|=(0xffffffff<writeBit) + { if (FAILED(swf_SetU8(t,0))) return -1; + t->writeBit = 0x80; + } + if (v&bm) t->data[t->len-1] |= t->writeBit; + bm>>=1; + t->writeBit>>=1; + nbits--; + } + return 0; +} + +// Advanced Data Access Functions + +int swf_SetRGB(TAG * t,RGBA * col) +{ if (!t) return -1; + if (col) + { swf_SetU8(t,col->r); + swf_SetU8(t,col->g); + swf_SetU8(t,col->b); + } else swf_SetBlock(t,NULL,3); + return 0; +} +void swf_GetRGB(TAG * t, RGBA * col) +{ + RGBA dummy; + if(!col) + col = &dummy; + col->r = swf_GetU8(t); + col->g = swf_GetU8(t); + col->b = swf_GetU8(t); + col->a = 255; +} + +int swf_SetRGBA(TAG * t,RGBA * col) +{ if (!t) return -1; + if (col) + { swf_SetU8(t,col->r); + swf_SetU8(t,col->g); + swf_SetU8(t,col->b); + swf_SetU8(t,col->a); + } else swf_SetBlock(t,NULL,4); + return 0; +} +void swf_GetRGBA(TAG * t, RGBA * col) +{ + RGBA dummy; + if(!col); + col = &dummy; + col->r = swf_GetU8(t); + col->g = swf_GetU8(t); + col->b = swf_GetU8(t); + col->a = swf_GetU8(t); +} + +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); + for(t=0;tnum;t++) + { + int s=t; + if(s>=8) //FIXME + s=7; + gradient->ratios[t] = swf_GetU8(tag); + if(!alpha) + swf_GetRGB(tag, &gradient->rgba[t]); + else + swf_GetRGBA(tag, &gradient->rgba[t]); + } +} + +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&m) + { if(v == 0xffffffff) n = 1; + else + while (v&m) + { n--; + m>>=1; + } + } + else + { if(v == 0x00000000) n = 0; + else + while (!(v&m)) + { n--; + m>>=1; + } + } + return (n>nbits)?n: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); + r->xmax = swf_GetSBits(t,nbits); + r->ymin = swf_GetSBits(t,nbits); + r->ymax = swf_GetSBits(t,nbits); + return 0; +} + +int reader_GetRect(struct reader_t*reader,SRECT * r) +{ int nbits; + SRECT dummy; + if (!r) r = &dummy; + nbits = (int) reader_GetBits(reader,5); + r->xmin = reader_GetSBits(reader,nbits); + r->xmax = reader_GetSBits(reader,nbits); + r->ymin = reader_GetSBits(reader,nbits); + r->ymax = reader_GetSBits(reader,nbits); + return 0; +} + +int swf_SetRect(TAG * t,SRECT * r) +{ int nbits; + + nbits = swf_CountBits(r->xmin,0); + 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); + swf_SetBits(t,r->xmax,nbits); + swf_SetBits(t,r->ymin,nbits); + swf_SetBits(t,r->ymax,nbits); + + return 0; +} + +void swf_ExpandRect(SRECT*src, SPOINT add) +{ + 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(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; +} +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; + 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; + + if (!m) m = &dummy; + + if (!t) + { m->sx = m->sy = 0x10000; + m->r0 = m->r1 = 0; + m->tx = m->ty = 0; + return -1; + } + + swf_ResetReadBits(t); + + if (swf_GetBits(t,1)) + { nbits = swf_GetBits(t,5); + m->sx = swf_GetSBits(t,nbits); + m->sy = swf_GetSBits(t,nbits); + } + else m->sx = m->sy = 0x10000; + + if (swf_GetBits(t,1)) + { nbits = swf_GetBits(t,5); + m->r0 = swf_GetSBits(t,nbits); + m->r1 = swf_GetSBits(t,nbits); + } + else m->r0 = m->r1 = 0x0; + + nbits = swf_GetBits(t,5); + m->tx = swf_GetSBits(t,nbits); + m->ty = swf_GetSBits(t,nbits); + + return 0; +} + +int swf_SetMatrix(TAG * t,MATRIX * m) +{ int nbits; + MATRIX ma; + + if (!m) + { m = &ma; + ma.sx = ma.sy = 0x10000; + ma.r0 = ma.r1 = 0; + ma.tx = ma.ty = 0; + } + + swf_ResetWriteBits(t); + + if ((m->sx==0x10000)&&(m->sy==0x10000)) swf_SetBits(t,0,1); + else + { swf_SetBits(t,1,1); + nbits = swf_CountBits(m->sx,0); + nbits = swf_CountBits(m->sy,nbits); + if(nbits>=32) { + fprintf(stderr,"rfxswf: Error: matrix values too large\n"); + nbits = 31; + } + swf_SetBits(t,nbits,5); + swf_SetBits(t,m->sx,nbits); + swf_SetBits(t,m->sy,nbits); + } + + if ((!m->r0)&&(!m->r1)) swf_SetBits(t,0,1); + else + { swf_SetBits(t,1,1); + nbits = swf_CountBits(m->r0,0); + nbits = swf_CountBits(m->r1,nbits); + if(nbits>=32) { + fprintf(stderr,"rfxswf: Error: matrix values too large\n"); + nbits = 31; + } + swf_SetBits(t,nbits,5); + swf_SetBits(t,m->r0,nbits); + swf_SetBits(t,m->r1,nbits); + } + + nbits = swf_CountBits(m->tx,0); + nbits = swf_CountBits(m->ty,nbits); + if(nbits>=32) { + fprintf(stderr,"rfxswf: Error: matrix values too large\n"); + nbits = 31; + } + swf_SetBits(t,nbits,5); + swf_SetBits(t,m->tx,nbits); + swf_SetBits(t,m->ty,nbits); + + return 0; +} + +int swf_GetCXForm(TAG * t,CXFORM * cx,U8 alpha) //FIXME: alpha should be type bool +{ CXFORM cxf; + int hasadd; + int hasmul; + int nbits; + + if (!cx) cx = &cxf; + + cx->a0 = cx->r0 = cx->g0 = cx->b0 = 256; + cx->a1 = cx->r1 = cx->g1 = cx->b1 = 0; + + if (!t) return 0; + + swf_ResetReadBits(t); + hasadd = swf_GetBits(t,1); + hasmul = swf_GetBits(t,1); + nbits = swf_GetBits(t,4); + + if (hasmul) + { cx->r0 = (S16)swf_GetSBits(t,nbits); + cx->g0 = (S16)swf_GetSBits(t,nbits); + cx->b0 = (S16)swf_GetSBits(t,nbits); + if (alpha) + cx->a0 = (S16)swf_GetSBits(t,nbits); + } + + if (hasadd) + { cx->r1 = (S16)swf_GetSBits(t,nbits); + cx->g1 = (S16)swf_GetSBits(t,nbits); + cx->b1 = (S16)swf_GetSBits(t,nbits); + if (alpha) + cx->a1 = (S16)swf_GetSBits(t,nbits); + } + + return 0; +} + +int swf_SetCXForm(TAG * t,CXFORM * cx,U8 alpha) +{ CXFORM cxf; + int hasadd; + int hasmul; + int nbits; + + if (!cx) + { cx = &cxf; + cx->a0 = cx->r0 = cx->g0 = cx->b0 = 256; + cx->a1 = cx->r1 = cx->g1 = cx->b1 = 0; + } + + if (!alpha) + { cx->a0 = 256; + cx->a1 = 0; + } + + nbits = 0; + + hasmul = (cx->a0!=256)||(cx->r0!=256)||(cx->g0!=256)||(cx->b0!=256); + hasadd = cx->a1|cx->r1|cx->g1|cx->b1; + + if (hasmul) + { if (alpha) nbits = swf_CountBits((S32)cx->a0,nbits); + nbits = swf_CountBits((S32)cx->r0,nbits); + nbits = swf_CountBits((S32)cx->g0,nbits); + nbits = swf_CountBits((S32)cx->b0,nbits); + } + + if (hasadd) + { if (alpha) nbits = swf_CountBits((S32)cx->a1,nbits); + nbits = swf_CountBits((S32)cx->r1,nbits); + nbits = swf_CountBits((S32)cx->g1,nbits); + nbits = swf_CountBits((S32)cx->b1,nbits); + } + + swf_ResetWriteBits(t); + swf_SetBits(t,hasadd?1:0,1); + swf_SetBits(t,hasmul?1:0,1); + swf_SetBits(t,nbits,4); + + if (hasmul) + { swf_SetBits(t,cx->r0,nbits); + swf_SetBits(t,cx->g0,nbits); + swf_SetBits(t,cx->b0,nbits); + if (alpha) swf_SetBits(t,cx->a0,nbits); + } + + if (hasadd) + { swf_SetBits(t,cx->r1,nbits); + swf_SetBits(t,cx->g1,nbits); + swf_SetBits(t,cx->b1,nbits); + if (alpha) swf_SetBits(t,cx->a1,nbits); + } + + 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* md5string = crypt_md5(password, "salt"); /* FIXME- get random salt */ + swf_SetString(t, md5string); +} + +int swf_VerifyPassword(TAG * t, const char * password) +{ + char*md5string1, *md5string2; + char*x; + char*md5, *salt; + int n; + + md5string1 = swf_GetString(t); + + if(!strncmp(md5string1, "$1$",3 )) { + return 0; + } + x = strchr(md5string1+3, '$'); + if(!x) + return 0; + n = x-(md5string1+3); + salt = (char*)malloc(n+1); + memcpy(salt, md5string1+3, n); + salt[n] = 0; + + md5string2 = crypt_md5(password, salt); + free(salt); + if(strcmp(md5string1, md5string2) != 0) + return 0; + return 1; +} + +// Tag List Manipulating Functions + +TAG * swf_InsertTag(TAG * after,U16 id) +{ TAG * t; + + t = (TAG *)malloc(sizeof(TAG)); + if (t) + { memset(t,0x00,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 t; +} + +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 (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) 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; +} + +int swf_DeleteTag(TAG * t) +{ if (!t) return -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); + return 0; +} + +TAG * swf_ReadTag(struct reader_t*reader, TAG * prev) +{ TAG * t; + U16 raw; + U32 len; + int id; + + if (reader->read(reader, &raw, 2) !=2 ) return NULL; + raw = SWAP16(raw); + + len = raw&0x3f; + id = raw>>6; + + if (len==0x3f) + { + if (reader->read(reader, &len, 4) != 4) return NULL; + len = SWAP32(len); + } + + if (id==ST_DEFINESPRITE) len = 2*sizeof(U16); + // 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->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 + return NULL; + } + t->memsize = t->len; + if (reader->read(reader, t->data, t->len) != t->len) return NULL; + } + + if (prev) + { + t->prev = prev; + prev->next = t; + } + + return t; +} + +int swf_DefineSprite_GetRealSize(TAG * t); + +int swf_WriteTag2(struct writer_t*writer, TAG * t) +// returns tag length in bytes (incl. Header), -1 = Error +// writer = 0 -> no output +{ U16 raw[3]; + U32 len; + int short_tag; + + if (!t) return -1; + + len = (t->id==ST_DEFINESPRITE)?swf_DefineSprite_GetRealSize(t):t->len; + + short_tag = len<0x3f; + + if (writer) + { if (short_tag) + { raw[0] = SWAP16(len|((t->id&0x3ff)<<6)); + if (writer->write(writer,raw,2)!=2) + { + #ifdef DEBUG_RFXSWF + fprintf(stderr,"WriteTag() failed: Short Header.\n"); + #endif + return -1; + } + } + else + { + raw[0] = SWAP16((t->id<<6)|0x3f); + if (writer->write(writer,raw,2)!=2) + { +#ifdef DEBUG_RFXSWF + fprintf(stderr,"WriteTag() failed: Long Header (1).\n"); +#endif + return -1; + } + + len = SWAP32(len); + if (writer->write(writer,&len,4)!=4) + { + #ifdef DEBUG_RFXSWF + fprintf(stderr,"WriteTag() failed: Long Header (2).\n"); + #endif + return -1; + } + } + + if (t->data) + { if (writer->write(writer,t->data,t->len)!=t->len) + { + #ifdef DEBUG_RFXSWF + fprintf(stderr,"WriteTag() failed: Data.\n"); + #endif + return -1; + } + } + #ifdef DEBUG_RFXSWF + else if (t->len) fprintf(stderr,"WriteTag(): Tag Data Error, id=%i\n",t->id); + #endif + } + + return t->len+(short_tag?2:6); +} + +int swf_WriteTag(int handle, TAG * t) +{ + struct writer_t writer; + if(handle<0) + return swf_WriteTag2(0, t); + writer_init_filewriter(&writer, handle); + return swf_WriteTag2(&writer, t); +} + +int swf_DefineSprite_GetRealSize(TAG * t) +// Sprite Handling: Helper function to pack DefineSprite-Tag +{ U32 len = t->len; + if(len>4) { // folded sprite + return t->len; + } + do + { t = swf_NextTag(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*)malloc(it->len); + it->memsize = it->len; + swf_GetBlock(t, it->data, it->len); + } + + if(!level) + break; + } + + 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); + 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 && level); + if(level) + fprintf(stderr, "rfxswf error: sprite doesn't end(1)\n"); + + swf_SetU16(sprtag, id); + swf_SetU16(sprtag, frames); + + t = swf_NextTag(sprtag); + level = 1; + + do + { + if(t->len<0x3f) { + swf_SetU16(sprtag,t->len|(t->id<<6)); + } else { + swf_SetU16(sprtag,0x3f|(t->id<<6)); + swf_SetU32(sprtag,t->len); + } + 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 && 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) { + 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; + tag->prev->next = 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 +{ + if (!swf) return -1; + memset(swf,0x00,sizeof(SWF)); + + { char b[32]; // read Header + int len; + TAG * t; + TAG t1; + struct reader_t zreader; + + if ((len = reader->read(reader ,b,8))<8) return -1; + + if (b[0]!='F' && b[0]!='C') return -1; + if (b[1]!='W') return -1; + if (b[2]!='S') return -1; + swf->fileVersion = b[3]; + swf->compressed = (b[0]=='C')?1:0; + swf->fileSize = GET32(&b[4]); + + if(swf->compressed) { + reader_init_zlibinflate(&zreader, reader); + reader = &zreader; + } + + reader_GetRect(reader, &swf->movieSize); + reader->read(reader, &swf->frameRate, 2); + swf->frameRate = SWAP16(swf->frameRate); + reader->read(reader, &swf->frameCount, 2); + swf->frameCount = SWAP16(swf->frameCount); + + /* read tags and connect to list */ + t = &t1; + while (t) t = swf_ReadTag(reader,t); + swf->firstTag = t1.next; + t1.next->prev = NULL; + } + + return reader->pos; +} + +int swf_ReadSWF(int handle, SWF * swf) +{ + struct 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 +{ U32 len; + TAG * t; + int frameCount=0; + struct writer_t zwriter; + int fileSize = 0; + + if (!swf) return -1; + + // 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); + +#endif // INSERT_RFX_TAG + + // Count Frames + File Size + + len = 0; + t = swf->firstTag; + frameCount = 0; + + while(t) + { len += swf_WriteTag(-1, t); + if (t->id==ST_SHOWFRAME) frameCount++; + t = swf_NextTag(t); + } + + { TAG t1; + char b[64],b4[4]; + U32 l; + + memset(&t1,0x00,sizeof(TAG)); + t1.data = (U8*)b; + t1.memsize = 64; + + { // measure header file size + TAG t2; + char b2[64]; + memset(&t2,0x00,sizeof(TAG)); + t2.data = (U8*)b2; + t2.memsize = 64; + swf_SetRect(&t2, &swf->movieSize); + swf_SetU16(&t2, swf->frameRate); + 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 = fileSize; + swf->frameCount = frameCount; + } + + 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 */ + 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) { + 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 + 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); + } + if(swf->compressed != 8) + writer->finish(writer); // flush zlib buffers - only if _we_ initialized that writer. + } + } + return (int)fileSize; +} + +int swf_WriteSWF(int handle, SWF * swf) // Writes SWF to file, returns length or <0 if fails +{ + struct writer_t writer; + swf->compressed = 0; + if(handle<0) { + writer_init_nullwriter(&writer); + return swf_WriteSWF2(&writer, swf); + } + writer_init_filewriter(&writer, handle); + return swf_WriteSWF2(&writer, swf); +} + +int swf_WriteSWC(int handle, SWF * swf) // Writes SWF to file, returns length or <0 if fails +{ + struct writer_t writer; + swf->compressed = 1; + if(handle<0) { + writer_init_nullwriter(&writer); + return swf_WriteSWF2(&writer, swf); + } + writer_init_filewriter(&writer, handle); + return swf_WriteSWF2(&writer, swf); +} + +int swf_WriteHeader2(struct writer_t*writer,SWF * swf) +{ + SWF myswf; + memcpy(&myswf,swf,sizeof(SWF)); + myswf.firstTag = 0; + return swf_WriteSWF2(writer, &myswf); +} + +int swf_WriteHeader(int handle,SWF * swf) +{ + SWF myswf; + memcpy(&myswf,swf,sizeof(SWF)); + myswf.firstTag = 0; + return swf_WriteSWF(handle, &myswf); +} + +int swf_WriteCGI(SWF * swf) +{ int len; + char s[1024]; + + len = swf_WriteSWF(-1,swf); + + if (len<0) return -1; + + sprintf(s,"Content-type: application/x-shockwave-flash\n" + "Accept-Ranges: bytes\n" + "Content-Length: %lu\n" + "Expires: Thu, 13 Apr 2000 23:59:59 GMT\n" + "\n",len); + + write(fileno(stdout),s,strlen(s)); + return swf_WriteSWF(fileno(stdout),swf); +} + +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); + t = tnew; + } +} + +// include advanced functions + +#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" +#include "modules/swfcgi.c" +#include "modules/swfbits.c" +#include "modules/swfaction.c" +#include "modules/swfsound.c" +#include "modules/swfdraw.c"