added swf_Optimize() method.
[swftools.git] / lib / modules / swftools.c
index e46bd77..d195817 100644 (file)
@@ -116,8 +116,10 @@ U16 swf_GetDefineID(TAG * t)
     case ST_DEFINESPRITE:
     case ST_DEFINEMOVIE:
     case ST_DEFINEVIDEOSTREAM:
+    case ST_GLYPHNAMES: //pseudodefine
     case ST_VIDEOFRAME: //pseudodefine
     case ST_NAMECHARACTER: //pseudodefine
+    case ST_DOINITACTION: //pseudodefine
       id = swf_GetU16(t);
       break;
   }
@@ -143,8 +145,6 @@ SRECT swf_GetDefineBBox(TAG * t)
     case ST_DEFINESHAPE2:
     case ST_DEFINESHAPE3:
     case ST_DEFINEEDITTEXT:
-    case ST_DEFINEBUTTON:
-    case ST_DEFINEBUTTON2:
     case ST_DEFINETEXT:
     case ST_DEFINETEXT2:
     case ST_DEFINEVIDEOSTREAM:
@@ -250,6 +250,7 @@ static int swf_pseudodefiningtagids[] =
  ST_NAMECHARACTER,
  ST_DOINITACTION,
  ST_VIDEOFRAME,
+ ST_GLYPHNAMES,
  -1
 };
 
@@ -658,6 +659,7 @@ void enumerateUsedIDs(TAG * tag, int base, void (*callback)(TAG*, int, void*), v
            }
            break;
        }
+       case ST_GLYPHNAMES:
        case ST_DEFINEFONTINFO:
        case ST_DEFINEFONTINFO2:
        case ST_VIDEOFRAME:
@@ -871,6 +873,9 @@ void swf_RelocateDepth(SWF*swf, char*bitmap)
 
     while(tag)
     {
+       /* TODO * clip depths 
+               * sprites
+        */
        int depth = swf_GetDepth(tag);
        if(depth>=0) {
            int newdepth = depth+nr;
@@ -889,9 +894,9 @@ TAG* swf_Concatenate (TAG*list1,TAG*list2)
     TAG*tag=0,*lasttag=0;
     char bitmap[65536];
     char depthmap[65536];
+    SWF swf1,swf2;
     memset(bitmap, 0, sizeof(bitmap));
     memset(depthmap, 0, sizeof(depthmap));
-    SWF swf1,swf2;
     memset(&swf1, 0, sizeof(swf1));
     memset(&swf2, 0, sizeof(swf2));
 
@@ -926,3 +931,75 @@ TAG* swf_Concatenate (TAG*list1,TAG*list2)
 
     return swf1.firstTag;
 }
+
+static int tagHash(TAG*tag)
+{
+    int t, h=0;
+    unsigned int a = 0x6b973e5a;
+    for(t=0;t<tag->len;t++) {
+        unsigned int b = a;
+        a >>= 8;
+        a += tag->data[t]*0xefbc35a5*b*(t+1);
+    }
+    return a;
+}
+
+void swf_Optimize(SWF*swf)
+{
+    TAG* tag = swf->firstTag;
+    int hash_size = 131072;
+    U16* remap = malloc(sizeof(U16)*65536);
+    TAG** hashmap = malloc(sizeof(TAG*)*hash_size);
+    memset(hashmap, 0, sizeof(TAG*)*hash_size);
+    int t;
+    for(t=0;t<65536;t++) {
+        remap[t] = t;
+    }
+    while(tag) {
+        TAG*next = tag->next;
+        if(!swf_isDefiningTag(tag)) {
+            int num = swf_GetNumUsedIDs(tag);
+            int*positions = malloc(sizeof(int)*num);
+            int t;
+            swf_GetUsedIDs(tag, positions);
+            for(t=0;t<num;t++) {
+                int id = GET16(&tag->data[positions[t]]);
+                id = remap[id];
+                PUT16(&tag->data[positions[t]], id);
+            }
+            tag = tag->next;
+        } else {
+            TAG*tag2;
+            int hash = tagHash(tag);
+            int match=0;
+            while((tag2 = hashmap[hash%hash_size])) {
+                if(tag->len == tag2->len) {
+                    int t;
+                    for(t=0;t<tag->len;t++) {
+                        if(tag->data[t] != tag2->data[t])
+                            break;
+                    }
+                    if(t == tag->len) {
+                        match=1;
+                    }
+                }
+                if(match) {
+                    /* we found two identical tags- remap one
+                       of them */
+                    remap[swf_GetDefineID(tag2)] = swf_GetDefineID(tag);
+                    break;
+                }
+                hash++;
+            }
+            if(!match) {
+                while(hashmap[hash%hash_size]) hash++;
+                hashmap[hash%hash_size] = tag;
+            } else {
+                swf_DeleteTag(tag);
+                if(tag == swf->firstTag)
+                    swf->firstTag = next;
+            }
+        }
+        tag = next;
+    }
+}