+void multiname_destroy(multiname_t*m)
+{
+ if(m) {
+ if(m->name) {
+ free((void*)m->name);m->name = 0;
+ }
+ if(m->ns) {
+ namespace_destroy(m->ns);m->ns = 0;
+ }
+ if(m->namespace_set) {
+ namespace_set_destroy(m->namespace_set);m->namespace_set = 0;
+ }
+ m->type=0;
+ free(m);
+ }
+}
+
+type_t multiname_type = {
+ dup: (dup_func)multiname_clone,
+ hash: (hash_func)multiname_hash,
+ free: (free_func)multiname_destroy,
+ equals: (equals_func)multiname_equals
+};
+
+
+// ------------------------------- constants -------------------------------------
+
+#define UNIQUE_CONSTANT(x) ((x) == CONSTANT_TRUE || (x) == CONSTANT_FALSE || (x) == CONSTANT_NULL || (x) == CONSTANT_UNDEFINED)
+
+constant_t* constant_new_int(int i)
+{
+ NEW(constant_t,c);
+ c->i = i;
+ c->type = CONSTANT_INT;
+ return c;
+}
+constant_t* constant_new_uint(unsigned int u)
+{
+ NEW(constant_t,c);
+ c->u = u;
+ c->type = CONSTANT_UINT;
+ return c;
+}
+constant_t* constant_new_float(double f)
+{
+ NEW(constant_t,c);
+ c->f = f;
+ c->type = CONSTANT_FLOAT;
+ return c;
+}
+constant_t* constant_new_string(const char*s)
+{
+ NEW(constant_t,c);
+ c->s = string_new4(s);
+ c->type = CONSTANT_STRING;
+ return c;
+}
+constant_t* constant_new_string2(const char*s, int len)
+{
+ NEW(constant_t,c);
+ c->s = string_new3(s, len);
+ c->type = CONSTANT_STRING;
+ return c;
+}
+constant_t* constant_new_namespace(namespace_t*ns)
+{
+ NEW(constant_t,c);
+ c->ns = namespace_clone(ns);
+ c->type = ns->access;
+ assert(NS_TYPE(c->type));
+ return c;
+}
+constant_t* constant_new_true()
+{
+ NEW(constant_t,c);
+ c->type = CONSTANT_TRUE;
+ return c;
+}
+constant_t* constant_new_false()
+{
+ NEW(constant_t,c);
+ c->type = CONSTANT_FALSE;
+ return c;
+}
+constant_t* constant_new_null()
+{
+ NEW(constant_t,c);
+ c->type = CONSTANT_NULL;
+ return c;
+}
+constant_t* constant_new_undefined()
+{
+ NEW(constant_t,c);
+ c->type = CONSTANT_UNDEFINED;
+ return c;
+}
+constant_t* constant_clone(constant_t*other)
+{
+ if(!other) return 0;
+ constant_t*c = malloc(sizeof(constant_t));
+ memcpy(c, other, sizeof(constant_t));
+ if(NS_TYPE(c->type)) {
+ c->ns = namespace_clone(other->ns);
+ } else if(c->type == CONSTANT_STRING) {
+ c->s = string_dup3(other->s);
+ }
+ return c;
+}
+constant_t* constant_fromindex(pool_t*pool, int index, int type)
+{
+ if(!index) {
+ /* even for nonvalued constants (like TRUE/FALSE etc.), a nonzero
+ index is present to indicate that a type is coming */
+ return 0;
+ }
+ NEW(constant_t,c);
+ c->type = type;
+ if(NS_TYPE(c->type)) {
+ c->ns = namespace_clone(pool_lookup_namespace(pool, index));
+ } else if(c->type == CONSTANT_INT) {
+ c->i = pool_lookup_int(pool, index);
+ } else if(c->type == CONSTANT_UINT) {
+ c->u = pool_lookup_uint(pool, index);
+ } else if(c->type == CONSTANT_FLOAT) {
+ c->f = pool_lookup_float(pool, index);
+ } else if(c->type == CONSTANT_STRING) {
+ string_t s = pool_lookup_string2(pool, index);
+ c->s = string_dup3(&s);
+ } else if(UNIQUE_CONSTANT(c->type)) {
+ // ok
+ } else {
+ fprintf(stderr, "invalid constant type %02x\n", c->type);
+ }
+ return c;
+}
+char* constant_tostring(constant_t*c)
+{
+ if(!c)
+ return strdup("NULL");
+ char buf[32];
+ if(NS_TYPE(c->type)) {
+ return namespace_tostring(c->ns);
+ } else if(c->type == CONSTANT_INT) {
+ sprintf(buf, "%d", c->i);
+ return strdup(buf);
+ } else if(c->type == CONSTANT_UINT) {
+ sprintf(buf, "%u", c->u);
+ return strdup(buf);
+ } else if(c->type == CONSTANT_FLOAT) {
+ char buf[1024];
+ sprintf(buf, "%f", c->f);
+ return strdup(buf);
+ } else if(c->type == CONSTANT_STRING) {
+ /* should we escape the string? \0 bytes won't be printed */
+ return strdup_n(c->s->str,c->s->len);
+ } else if(c->type == CONSTANT_TRUE) {
+ return strdup("true");
+ } else if(c->type == CONSTANT_FALSE) {
+ return strdup("false");
+ } else if(c->type == CONSTANT_NULL) {
+ return strdup("null");
+ } else if(c->type == CONSTANT_UNDEFINED) {
+ return strdup("undefined");
+ } else {
+ fprintf(stderr, "invalid constant type %02x\n", c->type);
+ return 0;
+ }
+}
+char constant_has_index(constant_t*c)
+{
+ if(!c)
+ return 0;
+ return !UNIQUE_CONSTANT(c->type);
+}
+int constant_get_index(pool_t*pool, constant_t*c)
+{
+ if(!c)
+ return 0;
+ if(NS_TYPE(c->type)) {
+ assert(c->ns);
+ /*if(c->type!=c->ns->access) {
+ printf("%02x<->%02x\n", c->type, c->ns->access);
+ }*/
+ assert(c->type == c->ns->access);
+ return pool_register_namespace(pool, c->ns);
+ } else if(c->type == CONSTANT_INT) {
+ return pool_register_int(pool, c->i);
+ } else if(c->type == CONSTANT_UINT) {
+ return pool_register_uint(pool, c->u);
+ } else if(c->type == CONSTANT_FLOAT) {
+ return pool_register_float(pool, c->f);
+ } else if(c->type == CONSTANT_STRING) {
+ return pool_register_string2(pool, c->s);
+ } else if(c->type == CONSTANT_UNDEFINED) {
+ /* write undefined with index 0 (and no type). Otherwise, the FlashPlayer
+ seems to throw an "attempt to read out of bounds" exception */
+ return 0;
+ } else if(!constant_has_index(c)) {
+ return 1;
+ } else {
+ fprintf(stderr, "invalid constant type %02x\n", c->type);
+ return 0;
+ }
+}
+void constant_free(constant_t*c)
+{
+ if(!c)
+ return;
+ if(c->type == CONSTANT_STRING) {
+ string_free(c->s);
+ } else if (NS_TYPE(c->type)) {
+ namespace_destroy(c->ns);c->ns=0;
+ }
+ free(c);
+}
+// --------------------------- optimizing -----------------------------------
+
+static int array_append_or_increase(array_t*array, void*key)
+{
+ int pos = array_find(array, key);
+ if(pos>=0) {
+ array->d[pos].data++;
+ return pos;
+ } else {
+ return array_append(array, key, 0);
+ }
+}
+static int compare_arrayentry(const void*_c1, const void*_c2)
+{
+ const array_entry_t*c1 = _c1;
+ const array_entry_t*c2 = _c2;
+ return c2->data - c1->data;
+}
+
+static void* nodup(const void*o) {return (void*)o;}
+
+static void reshuffle_array(array_t*array)
+{
+ qsort(array->d+1, array->num-1, sizeof(array->d[0]), compare_arrayentry);
+ type_t* old_type = array->entry2pos->key_type;
+ type_t old_type_nodup = *old_type;
+ old_type_nodup.dup = nodup;
+ dict_t*d = dict_new2(&old_type_nodup);
+ dict_destroy_shallow(array->entry2pos);
+ array->entry2pos = d;
+ int t;
+ for(t=0;t<array->num;t++) {
+ dict_put(array->entry2pos, array->d[t].name, (void*)(ptroff_t)(t+1));
+ }
+ d->key_type = old_type;
+
+}
+
+// ------------------------------- pool -------------------------------------
+
+int pool_register_uint(pool_t*p, unsigned int i)
+{
+ int pos = array_append_or_increase(p->x_uints, &i);
+ assert(pos!=0);
+ return pos;
+}
+int pool_register_int(pool_t*p, int i)
+{
+ int pos = array_append_or_increase(p->x_ints, &i);
+ assert(pos!=0);
+ return pos;
+}
+int pool_register_float(pool_t*p, double d)
+{
+ int pos = array_append_or_increase(p->x_floats, &d);
+ assert(pos!=0);
+ return pos;
+}
+int pool_register_string(pool_t*pool, const char*str)
+{
+ if(!str) return 0;
+ string_t s = string_new2(str);
+ int pos = array_append_or_increase(pool->x_strings, &s);
+ assert(pos!=0);
+ return pos;
+}
+int pool_register_string2(pool_t*pool, string_t*s)
+{
+ if(!s || !s->str) return 0;
+ int pos = array_append_or_increase(pool->x_strings, s);
+ assert(pos!=0);
+ return pos;
+}
+int pool_register_namespace(pool_t*pool, namespace_t*ns)
+{
+ if(!ns) return 0;
+ int pos = array_append_or_increase(pool->x_namespaces, ns);
+ assert(pos!=0 || ns->access==ZERONAMESPACE);
+ return pos;
+}
+int pool_register_namespace_set(pool_t*pool, namespace_set_t*set)
+{
+ if(!set) return 0;
+ int pos = array_append_or_increase(pool->x_namespace_sets, set);
+ assert(pos!=0);
+ return pos;
+}
+int pool_register_multiname(pool_t*pool, multiname_t*n)
+{
+ if(!n) return 0;
+ int pos = array_append_or_increase(pool->x_multinames, n);
+ assert(pos!=0);
+ return pos;
+}
+int pool_register_multiname2(pool_t*pool, char*name)
+{
+ if(!name) return 0;
+ multiname_t*n = multiname_fromstring(name);
+ int pos = array_append_or_increase(pool->x_multinames, n);
+ multiname_destroy(n);
+ assert(pos!=0);
+ return pos;
+}
+
+
+int pool_find_uint(pool_t*pool, unsigned int x)
+{
+ int i = array_find(pool->x_uints, &x);
+ if(i<=0) {
+ fprintf(stderr, "Couldn't find uint \"%d\" in constant pool\n", x);
+ return 0;
+ }
+ return i;
+}
+int pool_find_int(pool_t*pool, int x)
+{
+ int i = array_find(pool->x_ints, &x);
+ if(i<=0) {
+ fprintf(stderr, "Couldn't find int \"%d\" in constant pool\n", x);
+ return 0;
+ }
+ return i;
+}
+int pool_find_float(pool_t*pool, double x)
+{
+ int i = array_find(pool->x_ints, &x);
+ if(i<=0) {
+ fprintf(stderr, "Couldn't find int \"%f\" in constant pool\n", x);
+ return 0;
+ }
+ return i;
+}
+int pool_find_namespace(pool_t*pool, namespace_t*ns)
+{
+ if(!ns)
+ return 0;
+ int i = array_find(pool->x_namespaces, ns);
+ if(i<0) {
+ char*s = namespace_tostring(ns);
+ fprintf(stderr, "Couldn't find namespace \"%s\" %08x in constant pool\n", s, (int)ns);
+ free(s);
+ return 0;
+ }
+ return i;
+}
+int pool_find_namespace_set(pool_t*pool, namespace_set_t*set)
+{
+ if(!set)
+ return 0;
+ int i = array_find(pool->x_namespace_sets, set);
+ if(i<=0) {
+ char*s = namespace_set_tostring(set);
+ fprintf(stderr, "Couldn't find namespace_set \"%s\" in constant pool\n", s);
+ free(s);
+ return 0;
+ }
+ return i;
+}
+int pool_find_string(pool_t*pool, const char*str)
+{
+ if(!str)
+ return 0;
+ string_t s = string_new2(str);
+ int i = array_find(pool->x_strings, &s);
+ if(i<=0) {
+ fprintf(stderr, "Couldn't find string \"%s\" in constant pool\n", str);
+ return 0;
+ }
+ return i;
+}
+int pool_find_multiname(pool_t*pool, multiname_t*name)
+{
+ if(!name)
+ return 0;
+ int i = array_find(pool->x_multinames, name);
+ if(i<=0) {
+ char*s = multiname_tostring(name);
+ fprintf(stderr, "Couldn't find multiname \"%s\" in constant pool\n", s);
+ free(s);
+ return 0;
+ }
+ return i;
+}
+
+int pool_lookup_int(pool_t*pool, int i)
+{
+ if(!i) return 0;
+ return *(int*)array_getkey(pool->x_ints, i);
+}
+unsigned int pool_lookup_uint(pool_t*pool, int i)
+{
+ if(!i) return 0;
+ return *(unsigned int*)array_getkey(pool->x_uints, i);
+}
+double pool_lookup_float(pool_t*pool, int i)
+{
+ if(!i) return __builtin_nan("");
+ return *(double*)array_getkey(pool->x_floats, i);
+}
+const char*pool_lookup_string(pool_t*pool, int i)
+{
+ string_t*s = array_getkey(pool->x_strings, i);
+ if(!s) return 0;
+ return s->str;
+}
+string_t pool_lookup_string2(pool_t*pool, int i)
+{
+ string_t*s = array_getkey(pool->x_strings, i);
+ return *s;
+}
+namespace_t*pool_lookup_namespace(pool_t*pool, int i)
+{
+ return (namespace_t*)array_getkey(pool->x_namespaces, i);
+}
+namespace_set_t*pool_lookup_namespace_set(pool_t*pool, int i)
+{
+ return (namespace_set_t*)array_getkey(pool->x_namespace_sets, i);
+}
+multiname_t*pool_lookup_multiname(pool_t*pool, int i)
+{
+ return (multiname_t*)array_getkey(pool->x_multinames, i);
+}
+
+static namespace_t zeronamespace={ZERONAMESPACE,"*"};