abc constant pool implementation
authorkramm <kramm>
Sun, 23 Nov 2008 13:57:20 +0000 (13:57 +0000)
committerkramm <kramm>
Sun, 23 Nov 2008 13:57:20 +0000 (13:57 +0000)
lib/as3/pool.c [new file with mode: 0644]
lib/as3/pool.h [new file with mode: 0644]

diff --git a/lib/as3/pool.c b/lib/as3/pool.c
new file mode 100644 (file)
index 0000000..65e7793
--- /dev/null
@@ -0,0 +1,390 @@
+/* pool.c
+
+   Routines for handling Flash2 AVM2 ABC contantpool entries.
+
+   Extension module for the rfxswf library.
+   Part of the swftools package.
+
+   Copyright (c) 2008 Matthias Kramm <kramm@quiss.org>
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
+
+#include "pool.h"
+
+char* access2str(int type)
+{
+    if(type==0x08) return "";
+    else if(type==0x16) return "package";
+    else if(type==0x17) return "packageinternal";
+    else if(type==0x18) return "protected";
+    else if(type==0x19) return "explicit";
+    else if(type==0x1A) return "staticprotected";
+    else if(type==0x05) return "private";
+    else return "undefined";
+}
+
+char* multiname_to_string(multiname_t*m)
+{
+    char*mname = 0;
+    if(m->type==0x07 || m->type==0x0d) {
+        mname = malloc(strlen(m->ns->name)+strlen(m->name)+32);
+        sprintf(mname, "<%s>\0", access2str(m->ns->access));
+        strcat(mname, m->ns->name);
+        strcat(mname, "::");
+        strcat(mname, m->name);
+    } else if(m->type==0x0f || m->type==0x10) {
+        mname = strdup(m->name);
+    } else if(m->type==0x11 || m->type==0x12) {
+        mname = strdup("");
+    } else if(m->type==0x09 || m->type==0x0e) {
+        char*s = namespace_set_to_string(m->namespace_set);
+        mname = malloc(strlen(s)+strlen(m->name)+16);
+        strcpy(mname, s);
+        free(s);
+        strcat(mname, "::");
+        strcat(mname, m->name);
+    } else if(m->type==0x1b || m->type==0x1c) {
+        mname = namespace_set_to_string(m->namespace_set);
+    }
+    return mname;
+}
+
+char* namespace_to_string(namespace_t*ns)
+{
+    char*access = 0;
+    U8 type = ns->access;
+    if(type==0x08) access = "";
+    else if(type==0x16) access = "Package";
+    else if(type==0x17) access = "PackageInternal";
+    else if(type==0x18) access = "Protected";
+    else if(type==0x19) access = "Explicit";
+    else if(type==0x1A) access = "StaticProtected";
+    else if(type==0x05) access = "Private";
+    else {
+        fprintf(stderr, "Undefined namespace type %02x\n", type);
+        access = "UnknownNS";
+    }
+    char*string = malloc(strlen(access)+strlen(ns->name)+3);
+    sprintf(string, "<%s>%s", access, ns->name);
+    return string;
+}
+
+char* namespace_set_to_string(namespace_set_t*set)
+{
+    /* TODO: is the order of the namespaces important (does it
+       change the lookup order?). E.g. flex freely shuffles namespaces
+       around.
+       If the order is not important, we can optimize constant pools by sorting
+       the namespaces.
+    */
+    int l = 0;
+    namespace_list_t*lns = set->namespaces;
+    while(lns) {
+        char*s = namespace_to_string(lns->namespace);
+        l += strlen(s)+1;
+        free(s);
+        lns = lns->next;
+    }
+    char*desc = malloc(l+16);
+    strcpy(desc, "{");
+    lns = set->namespaces;
+    while(lns) {
+        char*s = namespace_to_string(lns->namespace);
+        strcat(desc, s);
+        free(s);
+        strcat(desc, ",");
+        lns = lns->next;
+    }
+    strcat(desc, "}");
+    return desc;
+}
+
+
+int pool_register_string(pool_t*pool, const char*s)
+{
+    return array_append_if_new(pool->strings, s, 0);
+}
+
+int pool_register_namespace(pool_t*pool, namespace_t*ns)
+{
+    if(!ns)
+        return 0;
+    char*name = namespace_to_string(ns);
+    int i = array_append_if_new(pool->namespaces, name, ns);
+    free(name);
+    return i;
+}
+int pool_register_namespace_set(pool_t*pool, namespace_set_t*set)
+{
+    char*name = namespace_set_to_string(set);
+    int i = array_append_if_new(pool->namespace_sets, name, set);
+    free(name);
+    return i;
+}
+int pool_register_multiname(pool_t*pool, multiname_t*n)
+{
+    if(!n)
+        return 0;
+    char*name = multiname_to_string(n);
+    int i =array_append_if_new(pool->multinames, name, n);
+    free(name);
+    return i;
+}
+int pool_register_multiname2(pool_t*pool, char*name)
+{
+    multiname_t*n = multiname_fromstring(name);
+    int i =array_append_if_new(pool->multinames, name, n);
+    return i;
+}
+int pool_find_namespace(pool_t*pool, namespace_t*ns)
+{
+    if(!ns)
+        return 0;
+    char*name = namespace_to_string(ns);
+    int i = array_find(pool->namespaces, name);
+    if(i<0) {
+        fprintf(stderr, "Couldn't find namespace \"%s\" %08x in constant pool\n", name, ns);
+        return 0;
+    }
+    free(name);
+    return i;
+}
+int pool_find_namespace_set(pool_t*pool, namespace_set_t*set)
+{
+    char*name = namespace_set_to_string(set);
+    int i = array_find(pool->namespace_sets, name);
+    free(name);
+    if(i<0) {
+        fprintf(stderr, "Couldn't find namespace_set \"%s\" in constant pool\n", name);
+        return 0;
+    }
+    return i;
+}
+int pool_find_string(pool_t*pool, const char*s)
+{
+    int i = array_find(pool->strings, s);
+    if(i<0) {
+        fprintf(stderr, "Couldn't find string \"%s\" in constant pool\n", s);
+        *(int*)0=0;
+        return 0;
+    }
+    return i;
+}
+int pool_find_multiname(pool_t*pool, multiname_t*name)
+{
+    char*n = multiname_to_string(name);
+    int i = array_find(pool->multinames, n);
+    if(i<0) {
+        fprintf(stderr, "Couldn't find multiname \"%s\" in constant pool\n", n);
+        return 0;
+    }
+    return i;
+}
+
+multiname_t*pool_lookup_multiname(pool_t*pool, int i)
+{
+    multiname_t*m = (multiname_t*)array_getvalue(pool->multinames, i);
+    return m;
+}
+
+multiname_t* multiname_fromstring(const char*name2)
+{
+    if(!name2)
+       name2 = "::";
+    char*n = strdup(name2);
+    char*p = strstr(n, "::");
+    char*namespace=0,*name=0;
+    if(!p) {
+        if(strchr(n, ':')) {
+            fprintf(stderr, "Error: single ':' in name\n");
+        }
+       namespace = "";
+       name = n;
+    } else {
+       *p = 0;
+       namespace = n;
+       name = p+2;
+        if(strchr(namespace, ':')) {
+            fprintf(stderr, "Error: single ':' in namespace\n");
+        }
+        if(strchr(name, ':')) {
+            fprintf(stderr, "Error: single ':' in qualified name\n");
+        }
+    }
+
+    multiname_t*m = malloc(sizeof(multiname_t));
+    memset(m, 0, sizeof(multiname_t));
+    m->type = QNAME;
+    m->namespace_set = 0;
+    NEW(namespace_t,ns);
+    ns->name= namespace;
+    m->ns = ns;
+    m->name = name;
+    return m;
+}
+
+pool_t*pool_new()
+{
+    NEW(pool_t, p);
+
+    p->ints = array_new();
+    array_append(p->ints, 0, (void*)(ptroff_t)0);
+    p->uints = array_new();
+    array_append(p->uints, 0, (void*)(ptroff_t)0);
+    p->floats = array_new();
+    array_append(p->floats, 0, 0);
+    p->strings = array_new();
+    array_append(p->strings, "--<UNDEFINED_STRING>--", 0);
+    p->namespaces = array_new();
+    array_append(p->namespaces, "--<UNDEFINED_NAMESPACE>--", 0);
+    p->namespace_sets = array_new();
+    array_append(p->namespace_sets, "--<UNDEFINED_NSSET>--", 0);
+    p->multinames = array_new();
+    array_append(p->multinames, "--<UNDEFINED_MULTINAME>--", 0);
+
+    return p;
+}
+
+#define DEBUG if(0)
+
+void pool_read(pool_t*pool, TAG*tag)
+{
+    int num_ints = swf_GetU30(tag);
+    DEBUG printf("%d ints\n", num_ints);
+    int t;
+    for(t=1;t<num_ints;t++) {
+        S32 v = swf_GetS30(tag);
+        DEBUG printf("int %d) %d\n", t, v);
+        array_append(pool->ints, 0, (void*)(ptroff_t)v);
+    }
+
+    int num_uints = swf_GetU30(tag);
+    DEBUG printf("%d uints\n", num_uints);
+    for(t=1;t<num_uints;t++) {
+        U32 v = swf_GetU30(tag);
+        DEBUG printf("uint %d) %d\n", t, v);
+        array_append(pool->uints, 0, (void*)(ptroff_t)v);
+    }
+    
+    int num_floats = swf_GetU30(tag);
+    DEBUG printf("%d floats\n", num_floats);
+    for(t=1;t<num_floats;t++) {
+        double d = swf_GetD64(tag);
+        DEBUG printf("float %d) %f\n", t, d);
+        array_append(pool->floats, 0, 0);
+    }
+    
+    int num_strings = swf_GetU30(tag);
+    DEBUG printf("%d strings\n", num_strings);
+    for(t=1;t<num_strings;t++) {
+       int len = swf_GetU30(tag);
+       char*s = malloc(len+1);
+       swf_GetBlock(tag, s, len);
+       s[len] = 0;
+       array_append(pool->strings, s, 0);
+       DEBUG printf("%d) \"%s\"\n", t, pool->strings->d[t].name);
+    }
+    int num_namespaces = swf_GetU30(tag);
+    DEBUG printf("%d namespaces\n", num_namespaces);
+    for(t=1;t<num_namespaces;t++) {
+       U8 type = swf_GetU8(tag);
+       int namenr = swf_GetU30(tag);
+       const char*name = array_getkey(pool->strings, namenr);
+        NEW(namespace_t, ns);
+        memset(ns, 0, sizeof(namespace_t));
+        ns->access = type;
+        ns->name = strdup(name);
+       array_append(pool->namespaces, name, ns);
+    }
+    int num_sets = swf_GetU30(tag);
+    DEBUG printf("%d namespace sets\n", num_sets);
+    for(t=1;t<num_sets;t++) {
+        int count = swf_GetU30(tag);
+        int s;
+        
+        NEW(namespace_set_t, nsset);
+        for(s=0;s<count;s++) {
+            int nsnr = swf_GetU30(tag);
+            namespace_t*ns = (namespace_t*)array_getvalue(pool->namespaces, nsnr);
+            list_append(nsset->namespaces, ns);
+        }
+        char*desc = namespace_set_to_string(nsset);
+
+        array_append(pool->namespace_sets, desc, nsset);
+        DEBUG printf("set %d) %s\n", t, desc);
+    }
+
+    int num_multinames = swf_GetU30(tag);
+    DEBUG printf("%d multinames\n", num_multinames);
+    for(t=1;t<num_multinames;t++) {
+        
+        NEW(multiname_t,m);
+       m->type = swf_GetU8(tag);
+       if(m->type==0x07 || m->type==0x0d) {
+           int namespace_index = swf_GetU30(tag);
+            m->ns = (namespace_t*)array_getvalue(pool->namespaces, namespace_index);
+            int name_index = swf_GetU30(tag);
+           m->name = array_getkey(pool->strings, name_index);
+       } else if(m->type==0x0f || m->type==0x10) {
+            int name_index = swf_GetU30(tag);
+           m->name = array_getkey(pool->strings, name_index);
+       } else if(m->type==0x11 || m->type==0x12) {
+       } else if(m->type==0x09 || m->type==0x0e) {
+            int name_index = swf_GetU30(tag);
+            int namespace_set_index = swf_GetU30(tag);
+           m->name = array_getkey(pool->strings, name_index);
+           m->namespace_set = (namespace_set_t*)array_getvalue(pool->namespace_sets, namespace_set_index);
+        } else if(m->type==0x1b || m->type==0x1c) {
+            int namespace_set_index = swf_GetU30(tag);
+           m->namespace_set = (namespace_set_t*)array_getvalue(pool->namespace_sets, namespace_set_index);
+       } else {
+           printf("can't parse type %d multinames yet\n", m->type);
+       }
+       char*mname = multiname_to_string(m);
+        DEBUG printf("multiname %d) %s\n", t, mname);
+       array_append(pool->multinames, mname, m);
+       free(mname);
+    }
+} 
+
+void pool_destroy(pool_t*pool)
+{
+    int t;
+    array_free(pool->ints);
+    array_free(pool->uints);
+    array_free(pool->floats);
+
+    for(t=1;t<pool->strings->num;t++) {
+        free((void*)array_getkey(pool->strings, t));
+    }
+    array_free(pool->strings);
+
+    for(t=1;t<pool->namespaces->num;t++) {
+        free(array_getvalue(pool->namespaces, t));
+    }
+    array_free(pool->namespaces);
+   
+    for(t=1;t<pool->namespace_sets->num;t++) {
+        namespace_set_t*set = (namespace_set_t*)array_getvalue(pool->namespace_sets, t);
+        list_free(set->namespaces);
+        free(set);
+    }
+    array_free(pool->namespace_sets);
+
+    for(t=1;t<pool->multinames->num;t++) {
+        free(array_getvalue(pool->multinames, t));
+    }
+    array_free(pool->multinames);
+}
diff --git a/lib/as3/pool.h b/lib/as3/pool.h
new file mode 100644 (file)
index 0000000..db91e70
--- /dev/null
@@ -0,0 +1,106 @@
+/* pool.h
+
+   Routines for handling Flash2 AVM2 ABC contantpool entries.
+
+   Extension module for the rfxswf library.
+   Part of the swftools package.
+
+   Copyright (c) 2008 Matthias Kramm <kramm@quiss.org>
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
+
+#ifndef __pool_h__
+#define __pool_h__
+
+#include "../q.h"
+#include "../rfxswf.h"
+
+DECLARE(pool);
+DECLARE(multiname);
+DECLARE(namespace);
+DECLARE(namespace_set);
+DECLARE_LIST(multiname);
+DECLARE_LIST(namespace);
+DECLARE_LIST(trait);
+
+/* abc file constant pool */
+struct _pool {
+    array_t*ints;
+    array_t*uints;
+    array_t*floats;
+    array_t*strings;
+    array_t*namespaces;
+    array_t*namespace_sets;
+    array_t*multinames;
+};
+
+typedef enum multiname_type
+{QNAME=0x07,
+ QNAMEA=0x0D,
+ RTQNAME=0x0F,
+ RTQNAMEA=0x10,
+ RTQNAMEL=0x11,
+ RTQNAMELA=0x12,
+ MULTINAME=0x09,
+ MULTINAMEA=0x0E,
+ MULTINAMEL=0x1B,
+ MULTINAMELA=0x1C
+} multiname_type_t;
+
+char* access2str(int type);
+
+struct _namespace {
+    U8 access;
+    char*name;
+};
+struct _namespace_set {
+    namespace_list_t*namespaces;
+};
+struct _multiname {
+    multiname_type_t type;
+    namespace_t*ns;
+    namespace_set_t*namespace_set;
+    const char*name;
+};
+
+/* object -> string */
+char* namespace_set_to_string(namespace_set_t*set);
+char* multiname_to_string(multiname_t*m);
+char* namespace_to_string(namespace_t*ns);
+
+/* integer -> object */
+multiname_t*pool_lookup_multiname(pool_t*pool, int i);
+
+/* object -> integer (lookup) */
+int pool_find_namespace(pool_t*pool, namespace_t*ns);
+int pool_find_namespace_set(pool_t*pool, namespace_set_t*set);
+int pool_find_string(pool_t*pool, const char*s);
+int pool_find_multiname(pool_t*pool, multiname_t*name);
+
+/* object -> integer (lookup/creation) */
+int pool_register_string(pool_t*pool, const char*s);
+int pool_register_namespace(pool_t*pool, namespace_t*ns);
+int pool_register_namespace_set(pool_t*pool, namespace_set_t*set);
+int pool_register_multiname(pool_t*pool, multiname_t*n);
+int pool_register_multiname2(pool_t*pool, char*name);
+
+/* creation */
+multiname_t* multiname_fromstring(const char*name);
+
+pool_t*pool_new();
+void pool_read(pool_t*pool, TAG*tag);
+void pool_destroy(pool_t*pool);
+
+#endif