implemented asset resolving
[swftools.git] / lib / as3 / import.c
index c38f02e..b2255e3 100644 (file)
 #include "import.h"
 #include "abc.h"
 #include "registry.h"
+#include "common.h"
 #include "tokenizer.h"
+#include "assets.h"
 #include "../os.h"
 
+static void import_code(void*_abc, char*filename, int pass, asset_bundle_t*a);
+
 void as3_import_abc(char*filename)
 {
     TAG*tag = swf_InsertTag(0, ST_RAWABC);
@@ -32,7 +36,8 @@ void as3_import_abc(char*filename)
     tag->data = file->data;
     tag->len = file->len;
     abc_file_t*abc = swf_ReadABC(tag);
-    as3_import_code(abc);
+    import_code(abc, filename, 0, 0);
+    import_code(abc, filename, 1, 0);
     swf_FreeABC(abc);
     memfile_close(file);
     free(tag);
@@ -43,17 +48,39 @@ void as3_import_swf(char*filename)
     SWF* swf = swf_OpenSWF(filename);
     if(!swf)
         return;
+    swf_FoldAll(swf);
+
     TAG*tag = swf->firstTag;
+
+    asset_resolver_t* assets =  swf_ParseAssets(swf);
+
+    /* pass 1 */
     while(tag) {
         if(tag->id == ST_DOABC || tag->id == ST_RAWABC) {
             abc_file_t*abc = swf_ReadABC(tag);
-            as3_import_code(abc);
+            import_code(abc, filename, 0, 0);
             swf_FreeABC(abc);
         }
         tag = tag->next;
     }
-    swf_FreeTags(swf);
+
+    tag = swf->firstTag;
+    /* pass 2 */
+    while(tag) {
+        if(tag->id == ST_DOABC || tag->id == ST_RAWABC) {
+            abc_file_t*abc = swf_ReadABC(tag); //FIXME: mem leak
+           swf_ResolveAssets(assets, abc);
+           NEW(asset_bundle_t, a);
+           a->file = abc;
+           registry_add_asset(a);
+            import_code(abc, filename, 1, a);
+        }
+        tag = tag->next;
+    }
+
+    //swf_FreeTags(swf); // FIXME: mem leak
     free(swf);
+
 }
 
 void as3_import_file(char*filename)
@@ -81,10 +108,12 @@ static int compare_traits(const void*v1, const void*v2)
     return strcmp(x1->name->name, x2->name->name);
 }
 
-static classinfo_t*resolve_class(char*what, multiname_t*n)
+static classinfo_t*resolve_class(char*filename, char*what, multiname_t*n)
 {
     if(!n) return 0;
-    if(!n->name[0] || !strcmp(n->name, "void")) return 0;
+    if(!n->name[0]) return 0;
+    if(!strcmp(n->name, "void")) 
+        return &voidclass;
 
     classinfo_t*c = 0;
     if(n->ns && n->ns->name) {
@@ -100,39 +129,43 @@ static classinfo_t*resolve_class(char*what, multiname_t*n)
     }
 
     if(!c) {
-        as3_warning("import: couldn't resolve %s %s", what, n->name);
+        as3_warning("import %s: couldn't resolve %s %s.%s", filename, what, n->ns->name, n->name);
         return 0;
     }
     if(c->kind != INFOTYPE_CLASS)
-        as3_warning("import: %s %s resolves to something that's not a class", what, n->name);
+        as3_warning("import %s: %s %s resolves to something that's not a class", filename, what, n->name);
     return c;
 }
 
-void as3_import_code(abc_file_t*abc)
+static void import_code(void*_abc, char*filename, int pass, asset_bundle_t*asset_bundle)
 {
+    abc_file_t*abc = _abc;
     int t;
-    for(t=0;t<abc->classes->num;t++) {
-        abc_class_t*cls = array_getvalue(abc->classes, t);
-        U8 access = cls->classname->ns->access;
-        if(access==ACCESS_PRIVATE ||
-           access==ACCESS_PACKAGEINTERNAL)
-            continue;
-        //if(!strncmp(cls->classname->ns->name, "__AS3", 5))
-        //    continue;
+    if(pass==0) {
+        for(t=0;t<abc->classes->num;t++) {
+            abc_class_t*cls = array_getvalue(abc->classes, t);
+            U8 access = cls->classname->ns->access;
+            if(access==ACCESS_PRIVATE ||
+               access==ACCESS_PACKAGEINTERNAL)
+                continue;
+            //if(!strncmp(cls->classname->ns->name, "__AS3", 5))
+            //    continue;
 
-        const char*package = strdup(cls->classname->ns->name);
-        const char*name = strdup(cls->classname->name);
-                
-        multiname_list_t*i=cls->interfaces;
-        classinfo_t*c = classinfo_register(access, package, name, list_length(i));
-        c->flags|=FLAG_BUILTIN;
-
-        if(cls->flags & CLASS_FINAL)
-            c->flags |= FLAG_FINAL;
-        if(cls->flags & CLASS_INTERFACE)
-            c->flags |= FLAG_INTERFACE;
-        if(!(cls->flags & CLASS_SEALED))
-            c->flags |= FLAG_DYNAMIC;
+            const char*package = strdup(cls->classname->ns->name);
+            const char*name = strdup(cls->classname->name);
+
+            multiname_list_t*i=cls->interfaces;
+            classinfo_t*c = classinfo_register(access, package, name, list_length(i));
+            c->flags|=FLAG_ASSET;
+
+            if(cls->flags & CLASS_FINAL)
+                c->flags |= FLAG_FINAL;
+            if(cls->flags & CLASS_INTERFACE)
+                c->flags |= FLAG_INTERFACE;
+            if(!(cls->flags & CLASS_SEALED))
+                c->flags |= FLAG_DYNAMIC;
+        }
+        return;
     }
     
     for(t=0;t<abc->classes->num;t++) {
@@ -142,36 +175,67 @@ void as3_import_code(abc_file_t*abc)
         classinfo_t*c = (classinfo_t*)registry_find(package, name);
         if(!c) continue;
 
+       if(cls->asset) {
+           c->assets = asset_bundle;
+       }
+
         int nr = 0;
         multiname_list_t*i = cls->interfaces;
         while(i) {
-            c->interfaces[nr++] = resolve_class("interface", i->multiname);
+            c->interfaces[nr++] = resolve_class(filename, "interface", i->multiname);
             i = i->next;
         }
-        c->superclass = resolve_class("superclass", cls->superclass);
+        c->superclass = resolve_class(filename, "superclass", cls->superclass);
       
         trait_list_t*l=0;
         char is_static = 0;
         l = cls->traits;
+        if(!l) {
+            l = cls->static_traits;
+            is_static = 1;
+        }
+        dict_t*names = dict_new();
         while(l) {
             trait_t*trait = l->trait;
             U8 access = trait->name->ns->access;
+
             if(access==ACCESS_PRIVATE)
                 goto cont;
             const char*name = trait->name->name;
-            char* ns= ACCESS_NAMESPACE?strdup(trait->name->ns->name):"";
-            if(registry_findmember(c, ns, name, 0))
+            char* ns = access==ACCESS_NAMESPACE?strdup(trait->name->ns->name):"";
+        
+           if(registry_findmember(c, ns, name, 0, is_static))
                 goto cont;
+
             name = strdup(name);
 
             memberinfo_t*s = 0;
             if(trait->kind == TRAIT_METHOD) {
-                s = (memberinfo_t*)methodinfo_register_onclass(c, access, ns, name);
-                s->return_type = resolve_class("return type", trait->method->return_type);
-            } else if(trait->kind == TRAIT_SLOT ||
-                      trait->kind == TRAIT_GETTER) {
-                s = (memberinfo_t*)varinfo_register_onclass(c, access, ns, name);
-                s->type = resolve_class("type", trait->type_name);
+                s = (memberinfo_t*)methodinfo_register_onclass(c, access, ns, name, is_static);
+                s->return_type = resolve_class(filename, "return type", trait->method->return_type);
+                dict_put(names, name, 0);
+            } else if(trait->kind == TRAIT_SLOT) {
+                s = (memberinfo_t*)varinfo_register_onclass(c, access, ns, name, is_static);
+                s->type = resolve_class(filename, "type", trait->type_name);
+                dict_put(names, name, 0);
+            } else if(trait->kind == TRAIT_GETTER) {
+                s = (memberinfo_t*)varinfo_register_onclass(c, access, ns, name, is_static);
+                s->type = resolve_class(filename, "type", trait->method->return_type);
+                dict_put(names, name, 0);
+            } else if(trait->kind == TRAIT_CONST) {
+                /* some variables (e.g. XML.length) are apparently both a method and a slot.
+                   needs split of static/non-static first */
+                if(!dict_contains(names, name)) {
+                    varinfo_t*v = (varinfo_t*)varinfo_register_onclass(c, access, ns, name, is_static);
+                    v->type = resolve_class(filename, "type", trait->type_name);
+                    v->flags |= FLAG_CONST;
+                    /* leave this alone for now- it blows up the file too much 
+                    v->value = constant_clone(trait->value);*/
+                    s = (memberinfo_t*)v;
+                    dict_put(names, name, 0);
+                } else 
+                    goto cont;
+
             } else {
                 goto cont;
             }
@@ -187,6 +251,7 @@ void as3_import_code(abc_file_t*abc)
                 is_static = 1;
             }
         }
+        dict_destroy(names);
     }
 
 #   define IS_PUBLIC_MEMBER(trait) ((trait)->kind != TRAIT_CLASS && (trait)->name->ns->access != ACCESS_PRIVATE)
@@ -220,13 +285,22 @@ void as3_import_code(abc_file_t*abc)
             memberinfo_t*m = 0;
             if(trait->kind == TRAIT_METHOD) {
                 m = (memberinfo_t*)methodinfo_register_global(access, package, name);
-                m->return_type = resolve_class("return type", trait->method->return_type);
+                m->return_type = resolve_class(filename, "return type", trait->method->return_type);
             } else {
-                m = (memberinfo_t*)varinfo_register_global(access, package, name);
-                m->type = resolve_class("type", trait->type_name);
+                varinfo_t*v = varinfo_register_global(access, package, name);
+                v->type = resolve_class(filename, "type", trait->type_name);
+                v->value = constant_clone(trait->value);
+                v->flags |= trait->kind==TRAIT_CONST?FLAG_CONST:0;
+                m = (memberinfo_t*)v;
             }
-            m->flags |= FLAG_BUILTIN;
+            m->flags |= FLAG_ASSET;
             m->parent = 0;
         }
     }
 }
+
+void as3_import_code(void*_abc)
+{
+    import_code(_abc, "", 0, 0);
+    import_code(_abc, "", 1, 0);
+}