new function swf_GetMorphGradient
[swftools.git] / lib / rfxswf.c
index 801171f..4a7035c 100644 (file)
@@ -1,4 +1,6 @@
-/* rfxswf.c
+/* 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.
@@ -16,6 +18,7 @@
 
 #ifdef HAVE_LIBJPEG
 #ifdef HAVE_JPEGLIB_H
+#define HAVE_BOOLEAN
 #include <jpeglib.h>
 #define _JPEGLIB_INCLUDED_
 #endif // HAVE_JPEGLIB_H
 #endif // HAVE_ZLIB_H
 #endif // HAVE_LIBZ
 
-// Win32 support may be broken since it was only tested in an older version for Watcom C
-#ifdef __NT__
-#  include <io.h>
-#  include <malloc.h>
-#  include <string.h>
-#  ifdef DEBUG_RFXSWF
-#    include <stdio.h>
-#  endif
-#else
-#endif
+#define LAME
+#include "lame/lame.h"
+
+#include "./bitio.h"
 
 // internal constants
 
 
 #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_GetDataSize(TAG * t) { return t->len; }
-U8*   swf_GetDataSizePtr(TAG * t) { return &(t->data[t->len]); }
+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_ResetBitmask(tag)   if (tag->bitmask)  { tag->pos++; tag->bitmask = 0; }
-#define swf_ResetBitcount(tag)  if (tag->bitcount) { tag->bitcount = 0; }
+#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/bitcount
+// 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_ResetBitmask(t);
+{ 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);
@@ -75,7 +73,7 @@ void swf_SetTagPos(TAG * t,U32 pos)
 }
 
 U8 swf_GetU8(TAG * t)
-{ swf_ResetBitmask(t);
+{ swf_ResetReadBits(t);
   #ifdef DEBUG_RFXSWF
     if (t->pos>=t->len) 
     { fprintf(stderr,"GetU8() out of bounds: TagID = %i\n",t->id);
@@ -87,7 +85,7 @@ U8 swf_GetU8(TAG * t)
 
 U16 swf_GetU16(TAG * t)
 { U16 res;
-  swf_ResetBitmask(t);
+  swf_ResetReadBits(t);
   #ifdef DEBUG_RFXSWF
     if (t->pos>(t->len-2)) 
     { fprintf(stderr,"GetU16() out of bounds: TagID = %i\n",t->id);
@@ -101,7 +99,7 @@ U16 swf_GetU16(TAG * t)
 
 U32 swf_GetU32(TAG * t)
 { U32 res;
-  swf_ResetBitmask(t);
+  swf_ResetReadBits(t);
   #ifdef DEBUG_RFXSWF
     if (t->pos>(t->len-4)) 
     { fprintf(stderr,"GetU32() out of bounds: TagID = %i\n",t->id);
@@ -117,7 +115,7 @@ U32 swf_GetU32(TAG * t)
 int swf_GetBlock(TAG * t,U8 * b,int l)
 // returns number of bytes written (<=l)
 // b = NULL -> skip data
-{ swf_ResetBitmask(t);
+{ swf_ResetReadBits(t);
   if ((t->len-t->pos)<l) l=t->len-t->pos;
   if (b && l) memcpy(b,&t->data[t->pos],l);
   t->pos+=l;
@@ -127,14 +125,15 @@ int swf_GetBlock(TAG * t,U8 * b,int 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_ResetBitcount(t);
+  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.\n");
+        fprintf(stderr,"Fatal Error: malloc()/realloc() failed (1). (%d bytes)\n", newmem);
+       *(int*)0=0;
       #endif
       return 0;
     }
@@ -148,7 +147,7 @@ int swf_SetBlock(TAG * t,U8 * b,int l)
 }
 
 int swf_SetU8(TAG * t,U8 v)
-{ swf_ResetBitcount(t);
+{ 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;
@@ -159,7 +158,7 @@ int swf_SetU16(TAG * t,U16 v)
   a[0] = v&0xff;
   a[1] = v>>8;
   
-  swf_ResetBitcount(t);
+  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];
@@ -173,7 +172,7 @@ int swf_SetU32(TAG * t,U32 v)
   a[2] = (v>>16)&0xff;
   a[3] = (v>>24)&0xff;
   
-  swf_ResetBitcount(t);
+  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];
@@ -185,14 +184,14 @@ int swf_SetU32(TAG * t,U32 v)
 U32 swf_GetBits(TAG * t,int nbits)
 { U32 res = 0;
   if (!nbits) return 0;
-  if (!t->bitmask) t->bitmask = 0x80;
+  if (!t->readBit) t->readBit = 0x80;
   while (nbits)
   { res<<=1;
-    if (t->data[t->pos]&t->bitmask) res|=1;
-    t->bitmask>>=1;
+    if (t->data[t->pos]&t->readBit) res|=1;
+    t->readBit>>=1;
     nbits--;
-    if (!t->bitmask)
-    { if (nbits) t->bitmask = 0x80;
+    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);
@@ -211,17 +210,26 @@ S32 swf_GetSBits(TAG * t,int nbits)
   return (S32)res;
 }
 
+U32 reader_GetBits(struct reader_t*reader, int nbits)
+{ return reader_readbits(reader, nbits);
+}
+S32 reader_GetSBits(struct reader_t*reader, int nbits)
+{ U32 res = reader_readbits(reader, nbits);
+  if (res&(1<<(nbits-1))) res|=(0xffffffff<<nbits);  
+  return (S32)res;
+}
+
 int swf_SetBits(TAG * t,U32 v,int nbits)
 { U32 bm = 1<<(nbits-1);
 
   while (nbits)
-  { if (!t->bitcount)
+  { if (!t->writeBit)
     { if (FAILED(swf_SetU8(t,0))) return -1;
-      t->bitcount = 0x80;
+      t->writeBit = 0x80;
     }
-    if (v&bm) t->data[t->len-1] |= t->bitcount;
+    if (v&bm) t->data[t->len-1] |= t->writeBit;
     bm>>=1;
-    t->bitcount>>=1;
+    t->writeBit>>=1;
     nbits--;
   }
   return 0;
@@ -238,6 +246,16 @@ int swf_SetRGB(TAG * t,RGBA * col)
   } 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;
@@ -249,6 +267,59 @@ int swf_SetRGBA(TAG * t,RGBA * col)
   } 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(!gradient)
+       gradient = &dummy;
+    gradient->num = swf_GetU8(tag);
+    for(t=0;t<gradient->num;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_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;t<gradient1->num;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]);
+    }
+}
 
 int swf_CountBits(U32 v,int nbits)
 { int n = 33;
@@ -283,6 +354,18 @@ int swf_GetRect(TAG * t,SRECT * r)
   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;
     
@@ -313,7 +396,7 @@ int swf_GetMatrix(TAG * t,MATRIX * m)
     return -1;
   }
 
-  swf_ResetBitmask(t);
+  swf_ResetReadBits(t);
   
   if (swf_GetBits(t,1))
   { nbits = swf_GetBits(t,5);
@@ -347,13 +430,17 @@ int swf_SetMatrix(TAG * t,MATRIX * m)
     ma.tx = ma.ty = 0;
   }
 
-  swf_ResetBitcount(t);
+  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);
@@ -364,6 +451,10 @@ int swf_SetMatrix(TAG * t,MATRIX * m)
   { 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);
@@ -371,6 +462,10 @@ int swf_SetMatrix(TAG * t,MATRIX * m)
 
   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);
@@ -391,7 +486,7 @@ int swf_GetCXForm(TAG * t,CXFORM * cx,U8 alpha) //FIXME: alpha should be type bo
 
   if (!t) return 0;
   
-  swf_ResetBitmask(t);
+  swf_ResetReadBits(t);
   hasadd = swf_GetBits(t,1);
   hasmul = swf_GetBits(t,1);
   nbits  = swf_GetBits(t,4);
@@ -451,7 +546,7 @@ int swf_SetCXForm(TAG * t,CXFORM * cx,U8 alpha)
     nbits = swf_CountBits((S32)cx->b1,nbits);
   }
   
-  swf_ResetBitcount(t);
+  swf_ResetWriteBits(t);
   swf_SetBits(t,hasadd?1:0,1);
   swf_SetBits(t,hasmul?1:0,1);
   swf_SetBits(t,nbits,4);
@@ -478,7 +573,7 @@ int swf_SetPoint(TAG * t,SPOINT * p) { return 0; }
 
 // Tag List Manipulating Functions
 
-int RFXSWF_UpdateFrame(TAG * t,S8 delta)
+int swf_UpdateFrame(TAG * t,S8 delta)
 // returns number of frames
 { int res = -1;
   while (t)
@@ -489,8 +584,6 @@ int RFXSWF_UpdateFrame(TAG * t,S8 delta)
   return res;
 }
 
-#define swf_UpdateFrame(a,b) RFXSWF_UpdateFrame(a,b)
-
 TAG * swf_InsertTag(TAG * after,U16 id)     // updates frames, if nescessary
 { TAG * t;
 
@@ -498,7 +591,6 @@ TAG * swf_InsertTag(TAG * after,U16 id)     // updates frames, if nescessary
   if (t)
   { memset(t,0x00,sizeof(TAG));
     t->id = id;
-    t->bitcount = 0x80;
     
     if (after)
     { t->frame = after->frame;
@@ -526,19 +618,22 @@ int swf_DeleteTag(TAG * t)
   return 0;
 }
 
-TAG * RFXSWF_ReadTag(int handle,TAG * prev)
+TAG * swf_ReadTag(struct reader_t*reader, TAG * prev)
 { TAG * t;
   U16 raw;
   U32 len;
   int id;
 
-  if (read(handle,&raw,2)!=2) return NULL;
+  if (reader->read(reader, &raw, 2) !=2 ) return NULL;
+  raw = SWAP16(raw);
 
   len = raw&0x3f;
   id  = raw>>6;
 
   if (len==0x3f)
-  { if (read(handle,&len,4)!=4) return NULL;
+  {
+      if (reader->read(reader, &len, 4) != 4) return NULL;
+      len = SWAP32(len);
   }
 
   if (id==ST_DEFINESPRITE) len = 2*sizeof(U16);
@@ -549,7 +644,7 @@ TAG * RFXSWF_ReadTag(int handle,TAG * prev)
   if (!t)
   {
     #ifdef DEBUG_RFXSWF
-      fprintf(stderr,"Fatal Error: malloc()/realloc() failed.\n");
+      fprintf(stderr,"Fatal Error: malloc()/realloc() failed (2). (%d bytes)\n", sizeof(TAG));
     #endif
     return NULL;
   }
@@ -564,12 +659,12 @@ TAG * RFXSWF_ReadTag(int handle,TAG * prev)
     if (!t->data)
     {
       #ifdef DEBUG_RFXSWF
-        fprintf(stderr,"Fatal Error: malloc()/realloc() failed.\n");
+        fprintf(stderr,"Fatal Error: malloc()/realloc() failed (3). (%d bytes)\n", t->len);
       #endif
       return NULL;
     }
     t->memsize = t->len;
-    if (read(handle,t->data,t->len)!=t->len) return NULL;
+    if (reader->read(reader, t->data, t->len) != t->len) return NULL;
   }
 
   if (prev)
@@ -581,25 +676,25 @@ TAG * RFXSWF_ReadTag(int handle,TAG * prev)
   return t;
 }
 
-int RFXSWF_DefineSprite_GetRealSize(TAG * t);
+int swf_DefineSprite_GetRealSize(TAG * t);
 
-int RFXSWF_WriteTag(int handle,TAG * t)
+int swf_WriteTag2(struct writer_t*writer, TAG * t)
 // returns tag length in bytes (incl. Header), -1 = Error
-// handle = -1 -> no output
+// writer = 0 -> no output
 { U16 raw[3];
   U32 len;
   int short_tag;
 
   if (!t) return -1;
 
-  len = (t->id==ST_DEFINESPRITE)?RFXSWF_DefineSprite_GetRealSize(t):t->len;
+  len = (t->id==ST_DEFINESPRITE)?swf_DefineSprite_GetRealSize(t):t->len;
 
   short_tag = len<0x3f;
 
-  if (handle>=0)
+  if (writer)
   { if (short_tag)
-    { raw[0] = len|((t->id&0x3ff)<<6);
-      if (write(handle,raw,2)!=2)
+    { 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");
@@ -608,20 +703,28 @@ int RFXSWF_WriteTag(int handle,TAG * t)
       }
     }
     else
-    { raw[0] = (t->id<<6)|0x3f;
-      raw[1] = (U16)(len&0xffff);
-      raw[2] = (U16)(len>>16);
-      if (write(handle,raw,6)!=6)
+    {
+      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.\n");
+          fprintf(stderr,"WriteTag() failed: Long Header (2).\n");
         #endif
         return -1;
       }
     }
     
     if (t->data)
-    { if (write(handle,t->data,t->len)!=t->len)
+    { if (writer->write(writer,t->data,t->len)!=t->len)
       {
         #ifdef DEBUG_RFXSWF
           fprintf(stderr,"WriteTag() failed: Data.\n");
@@ -637,61 +740,149 @@ int RFXSWF_WriteTag(int handle,TAG * t)
   return t->len+(short_tag?2:6);
 }
 
-int RFXSWF_DefineSprite_GetRealSize(TAG * t)
+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->id!=ST_DEFINESPRITE) len += RFXSWF_WriteTag(-1,t);
+    if (t->id!=ST_DEFINESPRITE) len += swf_WriteTag(-1, t);
     else t = NULL;
   } while (t&&(t->id!=ST_END));
   return len;
 }
 
-#define swf_ReadTag(a,b)  RFXSWF_ReadTag(a,b)
-#define swf_WriteTag(a,b) RFXSWF_WriteTag(a,b)
+void swf_FoldSprite(TAG * t)
+{
+  TAG*sprtag=t,*tmp;
+  U16 id,frames,tmpid;
+  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);
+  t->len = t->pos = t->memsize = 0;
+  t->data = 0;
+
+  frames = 0;
+
+  do 
+  { 
+    if(t->id==ST_SHOWFRAME) frames++;
+    t = swf_NextTag(t);
+  } while(t&&t!=ST_END);
+
+  t = swf_NextTag(sprtag);
+  swf_SetU16(sprtag, id);
+  swf_SetU16(sprtag, frames);
+
+  do
+  { 
+    tmpid= t->id;
+    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;
+    t = swf_NextTag(t);
+    swf_DeleteTag(tmp);
+  } 
+  while (t&&(tmpid!=ST_END));
+
+//  sprtag->next = t;
+//  t->prev = sprtag;
+}
+
+void swf_FoldAll(SWF*swf)
+{
+    TAG*tag = swf->firstTag;
+    while(tag) {
+       if(tag->id == ST_DEFINESPRITE)
+           swf_FoldSprite(tag);
+       tag = swf_NextTag(tag);
+    }
+}
 
 // Movie Functions
 
-int swf_ReadSWF(int handle,SWF * swf)   // Reads SWF to memory (malloc'ed), returns length or <0 if fails
+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
-    TAG t1;
+    int len;
     TAG * t;
+    TAG t1;
+    struct reader_t zreader;
     
-    memset(&t1,0x00,sizeof(TAG));
+    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 ((t1.len=read(handle,b,32))<21) return -1;
-    t1.data = (U8*)b;
-
-    if (swf_GetU8(&t1)!=(U8)'F') return -1;
-    if (swf_GetU8(&t1)!=(U8)'W') return -1;
-    if (swf_GetU8(&t1)!=(U8)'S') return -1;
+    if(swf->compressed) {
+       reader_init_zlibinflate(&zreader, reader);
+       reader = &zreader;
+    }
 
-    swf->fileVersion = swf_GetU8(&t1);
-    swf->fileSize    = swf_GetU32(&t1);
-    swf_GetRect(&t1,&swf->movieSize);
-    swf->frameRate   = swf_GetU16(&t1);
-    swf->frameCount  = swf_GetU16(&t1);
+    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);
 
-    swf_GetU8(&t1);
-    lseek(handle,swf_GetTagPos(&t1)-1,SEEK_SET);
-  
-                                        // reda tags and connect to list
+    /* read tags and connect to list */
     t = &t1;
-    while (t) t = swf_ReadTag(handle,t);
+    while (t) t = swf_ReadTag(reader,t);
     swf->firstTag = t1.next;
     t1.next->prev = NULL;
   }
   
-  return 0;
+  return reader->pos;
 }
-int  swf_WriteSWF(int handle,SWF * swf)     // Writes SWF to file, returns length or <0 if fails
+
+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;
     
   if (!swf) return -1;
 
@@ -699,7 +890,7 @@ int  swf_WriteSWF(int handle,SWF * swf)     // Writes SWF to file, returns lengt
 
 #ifdef INSERT_RFX_TAG
 
-  if (swf_NextTag(swf->firstTag))
+  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);
 
@@ -709,44 +900,68 @@ int  swf_WriteSWF(int handle,SWF * swf)     // Writes SWF to file, returns lengt
 
   len = 0;
   t = swf->firstTag;
-  swf->frameCount = 0;
+  frameCount = 0;
 
   while(t)
-  { len += swf_WriteTag(-1,t);
-    if (t->id==ST_SHOWFRAME) swf->frameCount++;
+  { len += swf_WriteTag(-1, t);
+    if (t->id==ST_SHOWFRAME) frameCount++;
     t = swf_NextTag(t);
   }
   
   { TAG t1;
-    char b[64];
+    char b[64],b4[4];
     U32 l;
 
     memset(&t1,0x00,sizeof(TAG));
     t1.data    = (U8*)b;
     t1.memsize = 64;
     
-    swf_SetU8(&t1,'F');      
-    swf_SetU8(&t1,'W');      
-    swf_SetU8(&t1,'S');
-    swf_SetU8(&t1,swf->fileVersion);
-    
-    swf_SetU32(&t1,0);                      // Keep space for filesize
+    { // 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(len) {// don't touch headers without tags
+       swf->fileSize = l+len;
+       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) {
+      writer_init_zlibdeflate(&zwriter, writer);
+      writer = &zwriter;
+    }
+
     swf_SetRect(&t1,&swf->movieSize);
     swf_SetU16(&t1,swf->frameRate);
     swf_SetU16(&t1,swf->frameCount);
 
-    l = swf_GetDataSize(&t1);
-    swf->fileSize = l+len;
-    t1.len = 4;                         // bad & ugly trick !
-    swf_SetU32(&t1,swf->fileSize);
-
-    if (handle>=0)
+    if (writer)
     { 
-      int ret = write(handle,b,l);
-      if (ret!=l)
+      int ret = writer->write(writer,b,swf_GetTagLen(&t1));
+      if (ret!=swf_GetTagLen(&t1))
       {
         #ifdef DEBUG_RFXSWF
-          printf("ret:%d (fd:%d)\n",ret, handle);
+          printf("ret:%d\n",ret);
           perror("write:");
           fprintf(stderr,"WriteSWF() failed: Header.\n");
         #endif
@@ -755,15 +970,52 @@ int  swf_WriteSWF(int handle,SWF * swf)     // Writes SWF to file, returns lengt
 
       t = swf->firstTag;
       while (t)
-      { if (swf_WriteTag(handle,t)<0) return -1;
+      { if (swf_WriteTag2(writer, t)<0) return -1;
         t = swf_NextTag(t);
       }
+      writer->finish(writer); //e.g. flush zlib buffers
     }
   }
   return (int)swf->fileSize;
 }
 
-int WriteCGI(SWF * swf)
+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)
+    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)
+    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];
     
@@ -794,20 +1046,6 @@ void swf_FreeTags(SWF * swf)                 // Frees all malloc'ed memory for t
 
 // 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"
-#include "modules\swfaction.c"
-
-#else
-
 #include "modules/swfdump.c"
 #include "modules/swfshape.c"
 #include "modules/swftext.c"
@@ -817,7 +1055,5 @@ void swf_FreeTags(SWF * swf)                 // Frees all malloc'ed memory for t
 #include "modules/swfcgi.c"
 #include "modules/swfbits.c"
 #include "modules/swfaction.c"
-
-#endif
-
+#include "modules/swfsound.c"