fixed a security bug in logging, added basic xml support to as3 compiler
[swftools.git] / lib / as3 / initcode.c
index 59d2efc..20e483a 100644 (file)
@@ -3,16 +3,91 @@
 #include "registry.h"
 #include "initcode.h"
 
-void initcode_add_classlist(abc_script_t*init, parsedclass_list_t*classes)
+int compare_lists(const void *_v1, const void *_v2)
+{
+    classinfo_t**v1 = *(classinfo_t***)_v1;
+    classinfo_t**v2 = *(classinfo_t***)_v2;
+    parsedclass_t*p1 = **(parsedclass_t***)_v1;
+    parsedclass_t*p2 = **(parsedclass_t***)_v2;
+    if((p1->cls->flags^p2->cls->flags)&FLAG_INTERFACE) {
+        return (int)(p2->cls->flags&FLAG_INTERFACE) - (int)(p1->cls->flags&FLAG_INTERFACE);
+    }
+    do {
+        v1++;v2++;
+        if(*v1<*v2) return -1;
+        else if(*v1>*v2) return 1;
+    } while(*v1 && *v2);
+    return 0;
+}
+
+/* sort classes so that 
+   (a) interfaces appear before classes
+   (b) base classes always appear before their subclasses
+   (c) neighboring elements have similar scope stacks 
+
+   Notice: we don't yet handle multiple inheritance (in interfaces) correctly.
+*/
+parsedclass_t** initcode_sort_classlist(parsedclass_list_t*classes)
+{
+    /* count classes */
+    int count = 0;
+    parsedclass_list_t*l;
+    for(l=classes;l;l=l->next) {
+        count++;
+    }
+    void***list = malloc(sizeof(void**)*count);
+
+    /* build an array for each class */
+    int i = 0;
+    for(l=classes;l;l=l->next) {
+        classinfo_t*cls = l->parsedclass->cls;
+        int len=0;
+        classinfo_t*c=cls;
+        while(c) {
+            len ++;
+            c = c->flags&FLAG_INTERFACE?c->interfaces[0]:c->superclass;
+        }
+        void**a = (void**)malloc(sizeof(void*)*(len+2));
+        a[0] = l->parsedclass;
+        a[len+1] = 0;
+        int t=len;
+        c = cls;
+        while(c) {
+            len ++;
+            a[t--] = c;
+            c = c->flags&FLAG_INTERFACE?c->interfaces[0]:c->superclass;
+        }
+        list[i++] = a;
+    }
+    
+    /* sort and flatten */
+    qsort(list, count, sizeof(void**), compare_lists);
+
+    parsedclass_t**list2 = malloc(sizeof(parsedclass_t*)*(count+1));
+    for(i=0;i<count;i++) {
+        list2[i] = (parsedclass_t*)list[i][0];
+        free(list[i]);
+    }
+    list2[count]=0;
+    free(list);
+    return list2;
+}
+
+void initcode_add_classlist(abc_script_t*init, parsedclass_list_t*_classes)
 {
     code_t*c = 0;
 
     c = abc_getlocal_0(c);
     c = abc_pushscope(c);
+  
+    parsedclass_t**classes = initcode_sort_classlist(_classes);
 
-    for(;classes;classes=classes->next) {
-        abc_class_t*abc = classes->parsedclass->abc;
-        classinfo_t*cls = classes->parsedclass->cls;
+    int t;
+    for(t=0;classes[t];t++) {
+        abc_class_t*abc = classes[t]->abc;
+        classinfo_t*cls = classes[t]->cls;
+        
+        array_append(init->file->classes, "", abc);
 
         /* write the construction code for this class to the global init
            function */
@@ -67,6 +142,8 @@ void initcode_add_classlist(abc_script_t*init, parsedclass_list_t*classes)
     }
     c = abc_returnvoid(c);
 
+    free(classes);
+
     init->method->body->code = c;
 }