added DEFINEMOVIE to define tags
[swftools.git] / lib / rfxswf.c
index 7824dee..3a84d11 100644 (file)
 
 #include "rfxswf.h"
 
-#ifdef HAVE_LIBJPEG
-#ifdef HAVE_JPEGLIB_H
+#ifdef HAVE_JPEGLIB
 #define HAVE_BOOLEAN
 #include <jpeglib.h>
-#define _JPEGLIB_INCLUDED_
-#endif // HAVE_JPEGLIB_H
-#endif // HAVE_LIBJPEG
+#endif // HAVE_JPEGLIB
 
-#ifdef HAVE_LIBZ
-#ifdef HAVE_ZLIB_H
+#ifdef HAVE_ZLIB
 #include <zlib.h>
-#define _ZLIB_INCLUDED_
-#endif // HAVE_ZLIB_H
-#endif // HAVE_LIBZ
+#endif // HAVE_ZLIB
 
 #define LAME
 #include "lame/lame.h"
@@ -72,6 +66,13 @@ void swf_SetTagPos(TAG * t,U32 pos)
   #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
@@ -322,6 +323,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);
@@ -364,6 +366,58 @@ int swf_SetRect(TAG * t,SRECT * r)
   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;
@@ -586,6 +640,47 @@ TAG * swf_InsertTag(TAG * after,U16 id)     // updates frames, if nescessary
   return t;
 }
 
+TAG * swf_InsertTagBefore(SWF* swf, TAG * before,U16 id)     // updates frames, if nescessary
+{ TAG * t;
+
+  t = (TAG *)malloc(sizeof(TAG));
+  if (t)
+  { memset(t,0x00,sizeof(TAG));
+    t->id = id;
+    
+    if (before)
+    { t->frame = before->frame;
+      t->next  = before;
+      t->prev  = before->prev;
+      before->prev = t;
+      if (t->prev) t->prev->next = t;
+      
+      if (id==ST_SHOWFRAME) swf_UpdateFrame(t->next,+1);
+    }
+  }
+  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;
 
@@ -738,7 +833,7 @@ 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;
@@ -750,6 +845,7 @@ void swf_UnFoldSprite(TAG * t)
   U32 len;
   TAG*next = t;
   U16 spriteid,spriteframes;
+  int level;
   if(t->id!=ST_DEFINESPRITE)
     return;
   if(t->len<=4) // not folded
@@ -760,12 +856,19 @@ void swf_UnFoldSprite(TAG * t)
   spriteid = swf_GetU16(t); //id
   spriteframes = swf_GetU16(t); //frames
 
-  tmp = swf_GetU16(t);
-  len = tmp&0x3f;
-  id  = tmp>>6;
-  while(id)
+  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);
@@ -773,13 +876,13 @@ void swf_UnFoldSprite(TAG * t)
     it->len = len;
     it->id  = id;
     if (it->len)
-    { it->data = (U8*)malloc(t->len);
+    { it->data = (U8*)malloc(it->len);
       it->memsize = it->len;
       swf_GetBlock(t, it->data, it->len);
     }
-    tmp = swf_GetU16(t);
-    len = tmp&0x3f;
-    id  = tmp>>6;
+
+    if(!level)
+       break;
   }
   
   free(t->data); t->data = 0;
@@ -793,6 +896,7 @@ void swf_FoldSprite(TAG * t)
 {
   TAG*sprtag=t,*tmp;
   U16 id,frames,tmpid;
+  int level;
   if(t->id!=ST_DEFINESPRITE)
       return;
   if(!t->len) {
@@ -806,26 +910,35 @@ void swf_FoldSprite(TAG * t)
 
   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;
 
+  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) {
        swf_SetU16(sprtag,t->len|(t->id<<6));
     } else {
@@ -835,15 +948,26 @@ 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;
@@ -858,11 +982,65 @@ 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;
+       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
@@ -965,29 +1143,37 @@ 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 = 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 */
+      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);
@@ -1000,7 +1186,7 @@ int  swf_WriteSWF2(struct writer_t*writer, SWF * swf)     // Writes SWF to file,
       if (ret!=swf_GetTagLen(&t1))
       {
         #ifdef DEBUG_RFXSWF
-          printf("ret:%d\n",ret);
+          fprintf(stderr, "ret:%d\n",ret);
           perror("write:");
           fprintf(stderr,"WriteSWF() failed: Header.\n");
         #endif
@@ -1012,7 +1198,8 @@ 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
+      if(swf->compressed != 8)
+       writer->finish(writer); // flush zlib buffers - only if _we_ initialized that writer.
     }
   }
   return (int)fileSize;
@@ -1095,4 +1282,3 @@ void swf_FreeTags(SWF * swf)                 // Frees all malloc'ed memory for t
 #include "modules/swfbits.c"
 #include "modules/swfaction.c"
 #include "modules/swfsound.c"
-