finished inner function implementation
[swftools.git] / lib / as3 / abc.c
index 7f6d0bf..2962331 100644 (file)
@@ -40,43 +40,30 @@ int abc_RegisterPrivateNameSpace(abc_file_t*file, const char*name);
 /* TODO: switch to a datastructure with just values */
 #define NO_KEY ""
 
-static char* params_tostring(multiname_list_t*list)
+static void params_dump(FILE*fo, multiname_list_t*l, constant_list_t*o)
 {
-    multiname_list_t*l;
-    int n = list_length(list);
-    char**names = (char**)malloc(sizeof(char*)*n);
-    
-    l = list;
-    n = 0;
-    int size = 0;
-    while(l) {
-        names[n] = multiname_tostring(l->multiname);
-        size += strlen(names[n]) + 2;
-        n++;l=l->next;
-    }
+    int n = list_length(l);
+    int no = list_length(o);
+    int i = 0;
 
-    char* params = malloc(size+15);
-    params[0]='(';
-    params[1]=0;
-    l = list;
-    int s=0;
-    n = 0;
+    fprintf(fo, "(");
     while(l) {
-        if(s)
-            strcat(params, ", ");
-        strcat(params, names[n]);
-        free(names[n]);
-        l = l->next;
-        n++;
-        s=1;
+        char*s = multiname_tostring(l->multiname);
+        fprintf(fo, s);
+        free(s);
+        if(i>=n-no) {
+            s = constant_tostring(o->constant);
+            fprintf(fo, " = ");
+            fprintf(fo, s);
+            free(s);
+            o = o->next;
+        }
+
+        if(l->next)
+            fprintf(fo, ", ");
+        l = l->next;i++;
     }
-    free(names);
-    /*char num[20];
-    sprintf(num, "[%d params]", n);
-    strcat(params, num);*/
-    strcat(params, ")");
-    int t;
-    return params;
+    fprintf(fo, ")");
 }
 
 //#define DEBUG
@@ -170,10 +157,9 @@ void abc_class_add_interface(abc_class_t*c, multiname_t*interface)
     list_append(c->interfaces, multiname_clone(interface));
 }
 
-abc_method_t* abc_method_new(abc_file_t*file, multiname_t*returntype, char body)
+void abc_method_init(abc_method_t*m, abc_file_t*file, multiname_t*returntype, char body)
 {
     /* construct method object */
-    NEW(abc_method_t,m);
     m->index = array_length(file->methods);
     array_append(file->methods, NO_KEY, m);
     m->return_type = returntype;
@@ -191,7 +177,11 @@ abc_method_t* abc_method_new(abc_file_t*file, multiname_t*returntype, char body)
         m->body = c;
         c->method = m;
     }
-
+}
+abc_method_t* abc_method_new(abc_file_t*file, multiname_t*returntype, char body)
+{
+    NEW(abc_method_t,m);
+    abc_method_init(m, file, returntype, body);
     return m;
 }
 
@@ -289,16 +279,16 @@ trait_t* abc_class_staticslot(abc_class_t*cls, multiname_t*name, multiname_t*typ
     abc_file_t*file = cls->file;
     multiname_t*m_name = multiname_clone(name);
     multiname_t*m_type = multiname_clone(type);
-    trait_t*t = trait_new_member(&cls->traits, m_type, m_name, 0);
+    trait_t*t = trait_new_member(&cls->static_traits, m_type, m_name, 0);
     return t;
 }
 
 
-trait_t* abc_class_find_slotid(abc_class_t*cls, int slotid)
+trait_t* traits_find_slotid(trait_list_t*traits, int slotid)
 {
     trait_list_t*l;
     trait_t*t=0;
-    for(l=cls->traits;l;l=l->next) {
+    for(l=traits;l;l=l->next) {
         if(l->trait->slot_id==slotid) {
             t=l->trait; 
             break;
@@ -329,9 +319,9 @@ int abc_initscript_addClassTrait(abc_script_t*script, multiname_t*multiname, abc
     return slotid;
 }
 
-abc_script_t* abc_initscript(abc_file_t*file, multiname_t*returntype)
+abc_script_t* abc_initscript(abc_file_t*file)
 {
-    abc_method_t*m = abc_method_new(file, returntype, 1);
+    abc_method_t*m = abc_method_new(file, 0, 1);
     abc_script_t* s = malloc(sizeof(abc_script_t));
     s->method = m;
     s->traits = list_new();
@@ -356,12 +346,13 @@ static void dump_method(FILE*fo, const char*prefix,
         return_type = multiname_tostring(m->return_type);
     else
         return_type = strdup("void");
-    char*paramstr = params_tostring(m->parameters);
-    fprintf(fo, "%s%s%s %s %s=%s %s (%d params, %d optional)\n", prefix, attr, type, return_type, name, m->name, paramstr, 
-            list_length(m->parameters),
-            list_length(m->optional_parameters)
-            );
-    free(paramstr);paramstr=0;
+
+    fprintf(fo, "%s", prefix);
+    fprintf(fo, "%s %s ", attr, type);
+    fprintf(fo, "%s %s=%s", return_type, name, m->name);
+    params_dump(fo, m->parameters, m->optional_parameters);
+    fprintf(fo, "(%d params, %d optional)\n", list_length(m->parameters), list_length(m->optional_parameters));
+
     free(return_type);return_type=0;
 
     abc_method_body_t*c = m->body;
@@ -395,7 +386,7 @@ static void dump_method(FILE*fo, const char*prefix,
     if(c->traits)
         traits_dump(fo, prefix, c->traits, file, methods_seen);
     fprintf(fo, "%s{\n", prefix);
-    code_dump(c->code, c->exceptions, file, prefix2, fo);
+    code_dump2(c->code, c->exceptions, file, prefix2, fo);
     fprintf(fo, "%s}\n\n", prefix);
 }
 
@@ -461,10 +452,6 @@ static trait_list_t* traits_parse(TAG*tag, pool_t*pool, abc_file_t*file)
            trait->cls = (abc_class_t*)array_getvalue(file->classes, swf_GetU30(tag));
            DEBUG printf("  class %s %d %d\n", name, trait->slot_id, trait->cls);
        } else if(kind == TRAIT_SLOT || kind == TRAIT_CONST) { // slot, const
-            /* a slot is a variable in a class that is shared amonst all instances
-               of the same type, but which has a unique location in each object 
-               (in other words, slots are non-static, traits are static)
-             */
            trait->slot_id = swf_GetU30(tag);
             trait->type_name = multiname_clone(pool_lookup_multiname(pool, swf_GetU30(tag)));
            int vindex = swf_GetU30(tag);
@@ -602,9 +589,9 @@ static void traits_dump(FILE*fo, const char*prefix, trait_list_t*traits, abc_fil
            int slot_id = trait->slot_id;
            char*type_name = multiname_tostring(trait->type_name);
             char*value = constant_tostring(trait->value);
-           fprintf(fo, "%sslot %d: %s%s %s %s %s\n", prefix, trait->slot_id, 
-                    kind==TRAIT_CONST?"const ":"", type_name, name, 
-                    value?"=":"", value);
+           fprintf(fo, "%sslot %d: %s %s:%s %s %s\n", prefix, trait->slot_id, 
+                    kind==TRAIT_CONST?"const":"var", name, type_name, 
+                    value?"=":"", value?value:"");
             if(value) free(value);
             free(type_name);
        } else {
@@ -618,7 +605,7 @@ static void traits_dump(FILE*fo, const char*prefix, trait_list_t*traits, abc_fil
 void* swf_DumpABC(FILE*fo, void*code, char*prefix)
 {
     abc_file_t* file = (abc_file_t*)code;
-        
+
     if(file->name) {
         fprintf(fo, "%s#\n", prefix);
         fprintf(fo, "%s#name: %s\n", prefix, file->name);
@@ -708,7 +695,7 @@ void* swf_DumpABC(FILE*fo, void*code, char*prefix)
                 fprintf(fo, "%s//internal (non-class non-script) methods:\n", prefix);
             }
             char name[18];
-            sprintf(name, "%08x ", m);
+            sprintf(name, "%08x ", m->index);
             dump_method(fo, prefix, "", "internalmethod", name, m, file, methods_seen);
         }
     }
@@ -752,7 +739,7 @@ void* swf_ReadABC(TAG*tag)
        for(s=0;s<param_count;s++) {
            int type_index = swf_GetU30(tag);
             
-            /* type_index might be 0, which probably means "..." (varargs) */
+            /* type_index might be 0 ("*") */
             multiname_t*param = type_index?multiname_clone(pool_lookup_multiname(pool, type_index)):0;
             list_append(m->parameters, param);
         }
@@ -765,7 +752,9 @@ void* swf_ReadABC(TAG*tag)
 
        m->flags = swf_GetU8(tag);
        
-        DEBUG printf("method %d) %s %s flags=%02x\n", t, m->name, params_tostring(m->parameters), m->flags);
+        DEBUG printf("method %d) %s ", m->name);
+        DEBUG params_dump(stdout, m->parameters, m->optional_parameters);
+        DEBUG printf("flags=%02x\n", t, m->flags);
 
         if(m->flags&0x08) {
             m->optional_parameters = list_new();
@@ -776,6 +765,7 @@ void* swf_ReadABC(TAG*tag)
                 U8 vkind = swf_GetU8(tag); // specifies index type for "val"
                 constant_t*c = constant_fromindex(pool, vindex, vkind);
                 list_append(m->optional_parameters, c);
+
             }
         }
        if(m->flags&0x80) {
@@ -888,7 +878,7 @@ void* swf_ReadABC(TAG*tag)
        array_append(file->method_bodies, NO_KEY, c);
     }
     if(tag->len - tag->pos) {
-       fprintf(stderr, "%d unparsed bytes remaining in ABC block\n", tag->len - tag->pos);
+       fprintf(stderr, "ERROR: %d unparsed bytes remaining in ABC block\n", tag->len - tag->pos);
        return 0;
     }
 
@@ -938,10 +928,13 @@ void* swf_ReadABC(TAG*tag)
     return file;
 }
 
-void swf_WriteABC(TAG*abctag, void*code)
+static pool_t*writeABC(TAG*abctag, void*code, pool_t*pool)
 {
     abc_file_t*file = (abc_file_t*)code;
-    pool_t*pool = pool_new();
+    if(!pool) 
+        pool = pool_new();
+    if(!file)
+        file = abc_file_new();
 
     TAG*tmp = swf_InsertTag(0,0);
     TAG*tag = tmp;
@@ -1064,8 +1057,13 @@ void swf_WriteABC(TAG*abctag, void*code)
             swf_SetU30(tag, list_length(m->optional_parameters));
             constant_list_t*l = m->optional_parameters;
             while(l) {
-                swf_SetU30(tag, constant_get_index(pool, l->constant));
-                swf_SetU8(tag, l->constant->type);
+                int i = constant_get_index(pool, l->constant);
+                swf_SetU30(tag, i);
+                if(!i) {
+                    swf_SetU8(tag, CONSTANT_NULL);
+                } else {
+                    swf_SetU8(tag, l->constant->type);
+                }
                 l = l->next;
             }
         }
@@ -1142,7 +1140,6 @@ void swf_WriteABC(TAG*abctag, void*code)
        //swf_SetU30(tag, c->old.max_scope_depth);
 
        swf_SetU30(tag, c->stats->max_stack);
-
         int param_num = list_length(c->method->parameters)+1;
         if(c->method->flags&METHOD_NEED_REST)
             param_num++;
@@ -1196,11 +1193,22 @@ void swf_WriteABC(TAG*abctag, void*code)
     swf_SetBlock(tag, tmp->data, tmp->len);
 
     swf_DeleteTag(0, tmp);
+    return pool;
+}
+
+void swf_WriteABC(TAG*abctag, void*code)
+{
+    pool_t*pool = writeABC(abctag, code, 0);
+    pool_optimize(pool);
+    swf_ResetTag(abctag, abctag->id);
+    writeABC(abctag, code, pool);
     pool_destroy(pool);
 }
 
 void abc_file_free(abc_file_t*file)
 {
+    if(!file)
+        return;
     int t;
     if(file->metadata) {
         for(t=0;t<file->metadata->num;t++) {
@@ -1307,230 +1315,3 @@ void swf_FreeABC(void*code)
     abc_file_free(file);
 }
 
-void swf_AddButtonLinks(SWF*swf, char stop_each_frame, char events)
-{
-    int num_frames = 0;
-    int has_buttons = 0;
-    TAG*tag=swf->firstTag;
-    while(tag) {
-        if(tag->id == ST_SHOWFRAME)
-            num_frames++;
-        if(tag->id == ST_DEFINEBUTTON || tag->id == ST_DEFINEBUTTON2)
-            has_buttons = 1;
-        tag = tag->next;
-    }
-
-    abc_file_t*file = abc_file_new();
-    abc_method_body_t*c = 0;
-   
-    abc_class_t*cls = abc_class_new2(file, "rfx::MainTimeline", "flash.display::MovieClip");
-    abc_class_protectedNS(cls, "rfx:MainTimeline");
-  
-    TAG*abctag = swf_InsertTagBefore(swf, swf->firstTag, ST_DOABC);
-    
-    tag = swf_InsertTag(abctag, ST_SYMBOLCLASS);
-    swf_SetU16(tag, 1);
-    swf_SetU16(tag, 0);
-    swf_SetString(tag, "rfx.MainTimeline");
-
-    c = abc_class_getstaticconstructor(cls, 0)->body;
-    c->old.max_stack = 1;
-    c->old.local_count = 1;
-    c->old.init_scope_depth = 9;
-    c->old.max_scope_depth = 10;
-
-    __ getlocal_0(c);
-    __ pushscope(c);
-    __ returnvoid(c);
-
-    c = abc_class_getconstructor(cls, 0)->body;
-    c->old.max_stack = 3;
-    c->old.local_count = 1;
-    c->old.init_scope_depth = 10;
-    c->old.max_scope_depth = 11;
-    
-    debugfile(c, "constructor.as");
-
-    __ getlocal_0(c);
-    __ pushscope(c);
-
-    __ getlocal_0(c);
-    __ constructsuper(c,0);
-
-    __ getlex(c, "[package]flash.system::Security");
-    __ pushstring(c, "*");
-    __ callpropvoid(c, "[package]::allowDomain", 1);
-    
-    if(stop_each_frame || has_buttons) {
-        int frame = 0;
-        tag = swf->firstTag;
-        abc_method_body_t*f = 0; //frame script
-        while(tag && tag->id!=ST_END) {
-            char framename[80];
-            char needs_framescript=0;
-            char buttonname[80];
-            char functionname[80];
-            sprintf(framename, "[packageinternal]rfx::frame%d", frame);
-            
-            if(!f && (tag->id == ST_DEFINEBUTTON || tag->id == ST_DEFINEBUTTON2 || stop_each_frame)) {
-                /* make the contructor add a frame script */
-                __ findpropstrict(c,"[package]::addFrameScript");
-                __ pushbyte(c,frame);
-                __ getlex(c,framename);
-                __ callpropvoid(c,"[package]::addFrameScript",2);
-
-                f = abc_class_method(cls, 0, multiname_fromstring(framename))->body;
-                f->old.max_stack = 3;
-                f->old.local_count = 1;
-                f->old.init_scope_depth = 10;
-                f->old.max_scope_depth = 11;
-                __ debugfile(f, "framescript.as");
-                __ debugline(f, 1);
-                __ getlocal_0(f);
-                __ pushscope(f);
-                if(stop_each_frame) {
-                    __ findpropstrict(f, "[package]::stop");
-                    __ callpropvoid(f, "[package]::stop", 0);
-                }
-            }
-
-            if(tag->id == ST_DEFINEBUTTON || tag->id == ST_DEFINEBUTTON2) {
-                U16 id = swf_GetDefineID(tag);
-                sprintf(buttonname, "::button%d", swf_GetDefineID(tag));
-                __ getlex(f,buttonname);
-                __ getlex(f,"flash.events::MouseEvent");
-                __ getproperty(f, "::CLICK");
-                sprintf(functionname, "::clickbutton%d", swf_GetDefineID(tag));
-                __ getlex(f,functionname);
-                __ callpropvoid(f, "::addEventListener" ,2);
-
-                needs_framescript = 1;
-
-                abc_method_body_t*h =
-                    abc_class_method(cls, 0, multiname_fromstring(functionname))->body;
-                list_append(h->method->parameters, multiname_fromstring("flash.events::MouseEvent"));
-
-                h->old.max_stack = 6;
-                h->old.local_count = 2;
-                h->old.init_scope_depth = 10;
-                h->old.max_scope_depth = 11;
-                __ getlocal_0(h);
-                __ pushscope(h);
-
-                ActionTAG*oldaction = swf_ButtonGetAction(tag);
-                if(oldaction && oldaction->op == ACTION__GOTOFRAME) {
-                    int framenr = GET16(oldaction->data);
-                    if(framenr>254) {
-                        fprintf(stderr, "Warning: Couldn't translate jump to frame %d to flash 9 actionscript\n", framenr);
-                    }
-                    if(!events) {
-                        __ findpropstrict(h,"[package]::gotoAndStop");
-                        __ pushbyte(h,framenr+1);
-                        __ callpropvoid(h,"[package]::gotoAndStop", 1);
-                    } else {
-                        char framename[80];
-                        sprintf(framename, "frame%d", framenr);
-                        __ getlocal_0(h); //this
-                        __ findpropstrict(h, "[package]flash.events::TextEvent");
-                        __ pushstring(h, "link");
-                        __ pushtrue(h);
-                        __ pushtrue(h);
-                        __ pushstring(h, framename);
-                        __ constructprop(h,"[package]flash.events::TextEvent", 4);
-                        __ callpropvoid(h,"[package]::dispatchEvent", 1);
-                    }
-                } else if(oldaction && oldaction->op == ACTION__GETURL) {
-                    if(!events) {
-                        __ findpropstrict(h,"flash.net::navigateToURL");
-                        __ findpropstrict(h,"flash.net::URLRequest");
-                        // TODO: target _blank
-                        __ pushstring(h,oldaction->data); //url
-                        __ constructprop(h,"flash.net::URLRequest", 1);
-                        __ callpropvoid(h,"flash.net::navigateToURL", 1);
-                    } else {
-                        __ getlocal_0(h); //this
-                        __ findpropstrict(h, "[package]flash.events::TextEvent");
-                        __ pushstring(h, "link");
-                        __ pushtrue(h);
-                        __ pushtrue(h);
-                        __ pushstring(h,oldaction->data); //url
-                        __ constructprop(h,"[package]flash.events::TextEvent", 4);
-                        __ callpropvoid(h,"[package]::dispatchEvent", 1);
-                    }
-                } else if(oldaction) {
-                    fprintf(stderr, "Warning: Couldn't translate button code of button %d to flash 9 abc action\n", id);
-                }
-                __ returnvoid(h);
-                swf_ActionFree(oldaction);
-            }
-            if(tag->id == ST_SHOWFRAME) {
-                if(f) {
-                    __ returnvoid(f);
-                    f = 0;
-                }
-                frame++;
-            }
-            tag = tag->next;
-        }
-        if(f) {
-            __ returnvoid(f);
-        }
-    }
-    __ returnvoid(c);
-
-    tag = swf->firstTag;
-    while(tag) {
-        if(tag->id == ST_DEFINEBUTTON || tag->id == ST_DEFINEBUTTON2) {
-            char buttonname[80];
-            sprintf(buttonname, "::button%d", swf_GetDefineID(tag));
-            multiname_t*s = multiname_fromstring(buttonname);
-            abc_class_slot(cls, multiname_fromstring(buttonname), s);
-        }
-        tag = tag->next;
-    }
-
-
-    abc_script_t*s = abc_initscript(file, 0);
-    c = s->method->body;
-    c->old.max_stack = 2;
-    c->old.local_count = 1;
-    c->old.init_scope_depth = 1;
-    c->old.max_scope_depth = 9;
-
-    __ getlocal_0(c);
-    __ pushscope(c);
-    __ getscopeobject(c, 0);
-    __ getlex(c,"::Object");
-    __ pushscope(c);
-    __ getlex(c,"flash.events::EventDispatcher");
-    __ pushscope(c);
-    __ getlex(c,"flash.display::DisplayObject");
-    __ pushscope(c);
-    __ getlex(c,"flash.display::InteractiveObject");
-    __ pushscope(c);
-    __ getlex(c,"flash.display::DisplayObjectContainer");
-    __ pushscope(c);
-    __ getlex(c,"flash.display::Sprite");
-    __ pushscope(c);
-    __ getlex(c,"flash.display::MovieClip");
-    __ pushscope(c);
-    __ getlex(c,"flash.display::MovieClip");
-    __ newclass(c,cls);
-    __ popscope(c);
-    __ popscope(c);
-    __ popscope(c);
-    __ popscope(c);
-    __ popscope(c);
-    __ popscope(c);
-    __ popscope(c);
-    __ initproperty(c,"rfx::MainTimeline");
-    __ returnvoid(c);
-
-    //abc_method_body_addClassTrait(c, "rfx:MainTimeline", 1, cls);
-    multiname_t*classname = multiname_fromstring("rfx::MainTimeline");
-    abc_initscript_addClassTrait(s, classname, cls);
-    multiname_destroy(classname);
-
-    swf_WriteABC(abctag, file);
-}
-