implemented --framerate.
[swftools.git] / lib / rfxswf.c
index 70b2dbc..7824dee 100644 (file)
@@ -1,4 +1,4 @@
-/* vi:sts=2 sw=2 */
+/* vi: set sts=2 sw=2 :*/
 
 /* rfxswf.c 
 
 #endif // HAVE_ZLIB_H
 #endif // HAVE_LIBZ
 
+#define LAME
+#include "lame/lame.h"
+
+#include "./bitio.h"
+
 // internal constants
 
 #define MALLOC_SIZE     128
@@ -128,6 +133,7 @@ int swf_SetBlock(TAG * t,U8 * b,int l)
     {
       #ifdef DEBUG_RFXSWF
         fprintf(stderr,"Fatal Error: malloc()/realloc() failed (1). (%d bytes)\n", newmem);
+       *(int*)0=0;
       #endif
       return 0;
     }
@@ -198,9 +204,6 @@ U32 swf_GetBits(TAG * t,int nbits)
   return res;
 }
 
-/* reader/writer stuff - from ../src/bitio.c */
-#include "./bitio.c"
-
 S32 swf_GetSBits(TAG * t,int nbits)
 { U32 res = swf_GetBits(t,nbits);
   if (res&(1<<(nbits-1))) res|=(0xffffffff<<nbits);  
@@ -347,6 +350,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);
@@ -737,6 +744,51 @@ int swf_DefineSprite_GetRealSize(TAG * t)
   return len;
 }
 
+void swf_UnFoldSprite(TAG * t)
+{
+  U16 id,tmp;
+  U32 len;
+  TAG*next = t;
+  U16 spriteid,spriteframes;
+  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
+
+  tmp = swf_GetU16(t);
+  len = tmp&0x3f;
+  id  = tmp>>6;
+  while(id)
+  {
+    TAG*it = 0;
+    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(t->len);
+      it->memsize = it->len;
+      swf_GetBlock(t, it->data, it->len);
+    }
+    tmp = swf_GetU16(t);
+    len = tmp&0x3f;
+    id  = tmp>>6;
+  }
+  
+  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;
@@ -747,6 +799,10 @@ void swf_FoldSprite(TAG * t)
       fprintf(stderr, "Error: Sprite has no ID!");
       return;
   }
+  if(t->len>4) {
+    /* sprite is already folded */
+      return;
+  }
 
   t->pos = 0;
   id = swf_GetU16(t);
@@ -798,9 +854,20 @@ void swf_FoldAll(SWF*swf)
     }
 }
 
+void swf_UnFoldAll(SWF*swf)
+{
+    TAG*tag = swf->firstTag;
+    while(tag) {
+        TAG*next = swf_NextTag(tag);
+       if(tag->id == ST_DEFINESPRITE)
+           swf_UnFoldSprite(tag);
+       tag = next;
+    }
+}
+
 // Movie Functions
 
-int swf_ReadSWF2(struct reader_t*reader2, 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));
@@ -810,7 +877,6 @@ int swf_ReadSWF2(struct reader_t*reader2, SWF * swf)   // Reads SWF to memory (m
     TAG * t;
     TAG t1;
     struct reader_t zreader;
-    struct reader_t* reader;
     
     if ((len = reader->read(reader ,b,8))<8) return -1;
 
@@ -821,12 +887,9 @@ int swf_ReadSWF2(struct reader_t*reader2, SWF * swf)   // Reads SWF to memory (m
     swf->compressed  = (b[0]=='C')?1:0;
     swf->fileSize    = GET32(&b[4]);
     
-    /* TODO: start decompression here */
     if(swf->compressed) {
-       reader_init_zlibinflate(&zreader, reader2);
+       reader_init_zlibinflate(&zreader, reader);
        reader = &zreader;
-    } else {
-       reader = reader2;
     }
 
     reader_GetRect(reader, &swf->movieSize);
@@ -842,7 +905,7 @@ int swf_ReadSWF2(struct reader_t*reader2, SWF * swf)   // Reads SWF to memory (m
     t1.next->prev = NULL;
   }
   
-  return 0;
+  return reader->pos;
 }
 
 int swf_ReadSWF(int handle, SWF * swf)
@@ -855,6 +918,9 @@ int swf_ReadSWF(int handle, SWF * 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;
 
@@ -872,43 +938,66 @@ int  swf_WriteSWF2(struct writer_t*writer, SWF * swf)     // Writes SWF to file,
 
   len = 0;
   t = swf->firstTag;
-  swf->frameCount = 0;
+  frameCount = 0;
 
   while(t)
   { len += swf_WriteTag(-1, t);
-    if (t->id==ST_SHOWFRAME) swf->frameCount++;
+    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,swf->fileSize);         // 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;
+    }
+
+    fileSize = l+len;
+    if(len) {// don't touch headers without tags
+       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) {
+      writer_init_zlibdeflate(&zwriter, writer);
+      writer = &zwriter;
+    }
+
     swf_SetRect(&t1,&swf->movieSize);
     swf_SetU16(&t1,swf->frameRate);
     swf_SetU16(&t1,swf->frameCount);
 
-    l = swf_GetTagLen(&t1);
-    swf->fileSize = l+len;
-    if(swf->firstTag) {
-       t1.len = 4;                         // bad & ugly trick !
-       swf_SetU32(&t1,swf->fileSize);
-    }
-
     if (writer)
     { 
-      int ret = writer->write(writer,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\n",ret);
@@ -923,27 +1012,46 @@ int  swf_WriteSWF2(struct writer_t*writer, SWF * swf)     // Writes SWF to file,
       { if (swf_WriteTag2(writer, t)<0) return -1;
         t = swf_NextTag(t);
       }
+      writer->finish(writer); //e.g. flush zlib buffers
     }
   }
-  return (int)swf->fileSize;
+  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)
     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;
-  swf_WriteSWF(handle, &myswf);
-  return 0;
+  return swf_WriteSWF(handle, &myswf);
 }
 
 int swf_WriteCGI(SWF * swf)