3 Routines for handling Flash2 AVM2 ABC contantpool entries.
5 Extension module for the rfxswf library.
6 Part of the swftools package.
8 Copyright (c) 2008 Matthias Kramm <kramm@quiss.org>
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
28 // ----------------------------- float ----------------------------------
30 void* float_clone(const void*_v) {
34 double*v2 = malloc(sizeof(double));
38 unsigned int float_hash(const void*_v) {
41 const unsigned char*b=_v;
45 h = crc32_add_byte(h, b[t]);
48 void float_destroy(void*_v) {
49 double*v = (double*)_v;
53 char float_equals(const void*_v1, const void*_v2) {
59 if(*v1==*v2) return 1;
60 if(*v1!=*v1 && *v2!=*v2) return 1; //both values are NaN
71 // ----------------------------- uint ----------------------------------
73 unsigned int undefined_uint = 0;
75 void*uint_clone(const void*_v) {
78 const unsigned int*v1=_v;
79 unsigned int*v2 = malloc(sizeof(unsigned int));
83 unsigned int uint_hash(const void*_v) {
86 const unsigned int*v=_v;
89 void uint_destroy(void*_v) {
90 unsigned int*v = (unsigned int*)_v;
94 char uint_equals(const void*_v1, const void*_v2) {
95 const unsigned int*v1=_v1;
96 const unsigned int*v2=_v2;
103 dup: (dup_func)uint_clone,
104 hash: (hash_func)uint_hash,
105 free: (free_func)uint_destroy,
106 equals: (equals_func)uint_equals
109 // ----------------------------- namespace ----------------------------------
111 unsigned int namespace_hash(namespace_t*n)
115 unsigned int hash = 0;
116 hash = crc32_add_byte(hash, n->access);
117 hash = crc32_add_string(hash, n->name);
121 unsigned char namespace_equals(const namespace_t*n1, const namespace_t*n2)
125 if(n1->access != n2->access)
127 if(!(n1->name) != !(n2->name))
129 if(n1->name && n2->name && strcmp(n1->name, n2->name))
134 char*escape_string(const char*str)
137 return strdup("NULL");
139 unsigned const char*s=str;
152 char*newstr = malloc(len+1);
157 dest+=sprintf(dest, "\\%d", *s);
160 dest+=sprintf(dest, "\\r");
162 dest+=sprintf(dest, "\\n");
164 dest+=sprintf(dest, "\\t");
166 dest+=sprintf(dest, "\\%2o", *s);
170 dest+=sprintf(dest, "\\x%02x", *s);
178 char* namespace_tostring(namespace_t*ns)
181 return strdup("NULL");
183 U8 type = ns->access;
184 access = access2str(type);
185 char*s = escape_string(ns->name);
186 char*string = (char*)malloc(strlen(access)+strlen(s)+7);
188 sprintf(string, "[%s]NULL", access, s);
190 sprintf(string, "[%s]\"\"", access, s);
192 sprintf(string, "[%s]%s", access, s);
197 namespace_t* namespace_clone(namespace_t*other)
202 n->access = other->access;
203 n->name = other->name?strdup(other->name):0;
207 namespace_t* namespace_fromstring(const char*name)
209 namespace_t*ns = malloc(sizeof(namespace_t));
210 memset(ns, 0, sizeof(namespace_t));
213 char*n = strdup(name);
214 char*bracket = strchr(n, ']');
218 name += (bracket-n)+1;
219 if(!strcmp(a, "")) access=0x16;
220 else if(!strcmp(a, "undefined")) access=0x08; // public??
221 else if(!strcmp(a, "package")) access=0x16;
222 else if(!strcmp(a, "public")) access=0x16;
223 else if(!strcmp(a, "packageinternal")) access=0x17;
224 else if(!strcmp(a, "protected")) access=0x18;
225 else if(!strcmp(a, "explicit")) access=0x19;
226 else if(!strcmp(a, "staticprotected")) access=0x1a;
227 else if(!strcmp(a, "private")) access=0x05;
229 fprintf(stderr, "Undefined access level: [%s]\n", a);
235 ns->name = strdup(name);
240 ns->name = strdup(name);
245 namespace_t* namespace_new(U8 access, const char*name)
247 namespace_t*ns = malloc(sizeof(namespace_t));
249 /* not sure what namespaces with empty strings are good for, but they *do* exist */
250 ns->name = name?strdup(name):0;
253 namespace_t* namespace_new_namespace(const char*name) {
254 return namespace_new(0x08, name); // public?
256 namespace_t* namespace_new_package(const char*name) {
257 return namespace_new(0x16 , name);
259 namespace_t* namespace_new_packageinternal(const char*name) {
260 return namespace_new(0x17, name);
262 namespace_t* namespace_new_protected(const char*name) {
263 return namespace_new(0x18, name);
265 namespace_t* namespace_new_explicit(const char*name) {
266 return namespace_new(0x19, name);
268 namespace_t* namespace_new_staticprotected(const char*name) {
269 return namespace_new(0x1a, name);
271 namespace_t* namespace_new_private(const char*name) {
272 return namespace_new(0x05, name);
275 void namespace_destroy(namespace_t*n)
278 free((char*)n->name);n->name=0;
284 type_t namespace_type = {
285 dup: (dup_func)namespace_clone,
286 hash: (hash_func)namespace_hash,
287 free: (free_func)namespace_destroy,
288 equals: (equals_func)namespace_equals
291 // ---------------------------namespace sets --------------------------------
293 unsigned int namespace_set_hash(namespace_set_t*set)
297 namespace_list_t*l = set->namespaces;
298 unsigned int hash = 0;
300 hash = crc32_add_byte(hash, l->namespace->access);
301 hash = crc32_add_string(hash, l->namespace->name);
307 int namespace_set_equals(namespace_set_t*m1, namespace_set_t*m2)
311 namespace_list_t*l1 = m1->namespaces;
312 namespace_list_t*l2 = m2->namespaces;
314 if(l1->namespace->access != l2->namespace->access)
316 if(!(l1->namespace->name) != !(l2->namespace->name))
318 if(l1->namespace->name && l2->namespace->name && strcmp(l1->namespace->name, l2->namespace->name))
328 namespace_set_t* namespace_set_clone(namespace_set_t*other)
332 NEW(namespace_set_t,set);
333 set->namespaces = list_new();
334 namespace_list_t*l = other->namespaces;
336 list_append(set->namespaces, namespace_clone(l->namespace));
341 namespace_set_t* namespace_set_new()
343 NEW(namespace_set_t,set);
344 set->namespaces = list_new();
347 char* namespace_set_tostring(namespace_set_t*set)
350 return strdup("NULL");
351 /* TODO: is the order of the namespaces important (does it
352 change the lookup order?). E.g. flex freely shuffles namespaces
354 If the order is not important, we can optimize constant pools by sorting
358 namespace_list_t*lns = set->namespaces;
360 char*s = namespace_tostring(lns->namespace);
365 char*desc = malloc(l+16);
367 lns = set->namespaces;
369 char*s = namespace_tostring(lns->namespace);
380 void namespace_set_destroy(namespace_set_t*set)
383 namespace_list_t*l = set->namespaces;
385 namespace_destroy(l->namespace);l->namespace=0;
388 list_free(set->namespaces);
393 type_t namespace_set_type = {
394 dup: (dup_func)namespace_set_clone,
395 hash: (hash_func)namespace_set_hash,
396 free: (free_func)namespace_set_destroy,
397 equals: (equals_func)namespace_set_equals
400 // ----------------------------- multiname ----------------------------------
402 unsigned int multiname_hash(multiname_t*m)
406 unsigned int hash = crc32_add_byte(0, m->type);
408 hash = crc32_add_string(hash, m->name);
411 hash = crc32_add_byte(hash, m->ns->access);
412 hash = crc32_add_string(hash, m->ns->name);
414 if(m->namespace_set) {
415 namespace_list_t*l = m->namespace_set->namespaces;
417 hash = crc32_add_byte(hash, l->namespace->access);
418 hash = crc32_add_string(hash, l->namespace->name);
425 int multiname_equals(multiname_t*m1, multiname_t*m2)
429 if(m1->type!=m2->type)
432 if((!m1->name) != (!m2->name))
434 if((!m1->ns) != (!m2->ns))
436 if((!m1->namespace_set) != (!m2->namespace_set))
439 if(m1->name && m2->name && strcmp(m1->name,m2->name))
441 if(m1->ns && m2->ns) {
442 if(!namespace_equals(m1->ns, m2->ns))
445 if(m1->namespace_set && m2->namespace_set) {
446 if(!namespace_set_equals(m1->namespace_set, m2->namespace_set))
452 multiname_t* multiname_new(namespace_t*ns, const char*name)
457 m->ns = namespace_new_packageinternal("");
459 m->ns = namespace_clone(ns);
461 m->name = strdup(name);
465 multiname_t* multiname_clone(multiname_t*other)
470 m->type = other->type;
472 m->ns = namespace_clone(other->ns);
473 if(other->namespace_set)
474 m->namespace_set = namespace_set_clone(other->namespace_set);
476 m->name = strdup(other->name);
481 char* access2str(int type)
483 if(type==0x08) return "namespace";
484 else if(type==0x16) return "public";
485 else if(type==0x17) return "packageinternal";
486 else if(type==0x18) return "protected";
487 else if(type==0x19) return "explicit";
488 else if(type==0x1A) return "staticprotected";
489 else if(type==0x05) return "private";
491 fprintf(stderr, "Undefined access type %02x\n", type);
497 char multiname_late_namespace(multiname_t*m)
501 return (m->type==RTQNAME || m->type==RTQNAMEA ||
502 m->type==RTQNAMEL || m->type==RTQNAMELA);
505 char multiname_late_name(multiname_t*m)
509 return m->type==RTQNAMEL || m->type==RTQNAMELA ||
510 m->type==MULTINAMEL || m->type==MULTINAMELA;
513 char* multiname_tostring(multiname_t*m)
517 return strdup("NULL");
519 return strdup("--<MULTINAME 0xff>--");
521 char*name = m->name?escape_string(m->name):strdup("*");
522 int namelen = strlen(name);
524 if(m->type==QNAME || m->type==QNAMEA || m->type==POSTFIXTYPE) {
525 char*nsname = escape_string(m->ns->name);
526 mname = malloc(strlen(nsname)+namelen+32);
528 if(m->type == QNAMEA)
529 strcat(mname, ",attr");
531 strcat(mname,access2str(m->ns->access));
533 strcat(mname, nsname);
537 } else if(m->type==RTQNAME || m->type==RTQNAMEA) {
538 mname = malloc(namelen+32);
539 strcpy(mname, "<rt");
540 if(m->type == RTQNAMEA)
541 strcat(mname, ",attr");
544 } else if(m->type==RTQNAMEL) {
545 mname = strdup("<rt,l>");
546 } else if(m->type==RTQNAMELA) {
547 mname = strdup("<rt,l,attr>");
548 } else if(m->type==MULTINAME || m->type==MULTINAMEA) {
549 char*s = namespace_set_tostring(m->namespace_set);
550 mname = malloc(strlen(s)+namelen+16);
551 if(m->type == MULTINAME)
552 strcpy(mname,"<multi>");
554 strcpy(mname,"<multi,attr>");
559 } else if(m->type==MULTINAMEL || m->type==MULTINAMELA) {
560 char*s = namespace_set_tostring(m->namespace_set);
561 mname = malloc(strlen(s)+16);
562 if(m->type == MULTINAMEL)
563 strcpy(mname,"<l,multi>");
565 strcpy(mname,"<l,multi,attr>");
569 return strdup("<invalid>");
575 multiname_t* multiname_fromstring(const char*name2)
579 char*n = strdup(name2);
580 char*p = strstr(n, "::");
581 char*namespace=0,*name=0;
584 fprintf(stderr, "Error: single ':' in name\n");
592 if(strchr(namespace, ':')) {
593 fprintf(stderr, "Error: single ':' in namespace\n");
595 if(strchr(name, ':')) {
596 fprintf(stderr, "Error: single ':' in qualified name\n");
600 multiname_t*m = malloc(sizeof(multiname_t));
601 memset(m, 0, sizeof(multiname_t));
603 m->namespace_set = 0;
604 m->ns = namespace_fromstring(namespace);
605 m->name = name?strdup(name):0;
610 void multiname_destroy(multiname_t*m)
614 free((void*)m->name);m->name = 0;
617 namespace_destroy(m->ns);m->ns = 0;
619 if(m->namespace_set) {
620 namespace_set_destroy(m->namespace_set);m->namespace_set = 0;
627 type_t multiname_type = {
628 dup: (dup_func)multiname_clone,
629 hash: (hash_func)multiname_hash,
630 free: (free_func)multiname_destroy,
631 equals: (equals_func)multiname_equals
635 // ------------------------------- constants -------------------------------------
637 #define UNIQUE_CONSTANT(x) ((x) == CONSTANT_TRUE || (x) == CONSTANT_FALSE || (x) == CONSTANT_NULL || (x) == CONSTANT_UNDEFINED)
639 constant_t* constant_new_int(int i)
643 c->type = CONSTANT_INT;
646 constant_t* constant_new_uint(unsigned int u)
650 c->type = CONSTANT_UINT;
653 constant_t* constant_new_float(double f)
657 c->type = CONSTANT_FLOAT;
660 constant_t* constant_new_string(char*s)
663 c->s = string_new4(s);
664 c->type = CONSTANT_STRING;
667 constant_t* constant_new_string2(const char*s, int len)
670 c->s = string_new3(s, len);
671 c->type = CONSTANT_STRING;
674 constant_t* constant_new_namespace(namespace_t*ns)
677 c->ns = namespace_clone(ns);
678 c->type = ns->access;
679 assert(NS_TYPE(c->type));
682 constant_t* constant_new_true()
685 c->type = CONSTANT_TRUE;
688 constant_t* constant_new_false()
691 c->type = CONSTANT_FALSE;
694 constant_t* constant_new_null()
697 c->type = CONSTANT_NULL;
700 constant_t* constant_new_undefined()
703 c->type = CONSTANT_UNDEFINED;
706 constant_t* constant_clone(constant_t*other)
709 constant_t*c = malloc(sizeof(constant_t));
710 memcpy(c, other, sizeof(constant_t));
711 if(NS_TYPE(c->type)) {
712 c->ns = namespace_clone(other->ns);
713 } else if(c->type == CONSTANT_STRING) {
714 c->s = string_dup3(other->s);
718 constant_t* constant_fromindex(pool_t*pool, int index, int type)
721 /* even for nonvalued constants (like TRUE/FALSE etc.), a nonzero
722 index is present to indicate that a type is coming */
727 if(NS_TYPE(c->type)) {
728 c->ns = namespace_clone(pool_lookup_namespace(pool, index));
729 } else if(c->type == CONSTANT_INT) {
730 c->i = pool_lookup_int(pool, index);
731 } else if(c->type == CONSTANT_UINT) {
732 c->u = pool_lookup_uint(pool, index);
733 } else if(c->type == CONSTANT_FLOAT) {
734 c->f = pool_lookup_float(pool, index);
735 } else if(c->type == CONSTANT_STRING) {
736 string_t s = pool_lookup_string2(pool, index);
737 c->s = string_dup3(&s);
738 } else if(UNIQUE_CONSTANT(c->type)) {
741 fprintf(stderr, "invalid constant type %02x\n", c->type);
745 char* constant_tostring(constant_t*c)
748 return strdup("NULL");
750 if(NS_TYPE(c->type)) {
751 return namespace_tostring(c->ns);
752 } else if(c->type == CONSTANT_INT) {
753 sprintf(buf, "%d", c->i);
755 } else if(c->type == CONSTANT_UINT) {
756 sprintf(buf, "%u", c->u);
758 } else if(c->type == CONSTANT_FLOAT) {
760 sprintf(buf, "%f", c->f);
762 } else if(c->type == CONSTANT_STRING) {
763 /* should we escape the string? \0 bytes won't be printed */
764 return strdup_n(c->s->str,c->s->len);
765 } else if(c->type == CONSTANT_TRUE) {
766 return strdup("true");
767 } else if(c->type == CONSTANT_FALSE) {
768 return strdup("false");
769 } else if(c->type == CONSTANT_NULL) {
770 return strdup("null");
771 } else if(c->type == CONSTANT_UNDEFINED) {
772 return strdup("undefined");
774 fprintf(stderr, "invalid constant type %02x\n", c->type);
778 char constant_has_index(constant_t*c)
782 return !UNIQUE_CONSTANT(c->type);
784 int constant_get_index(pool_t*pool, constant_t*c)
788 if(NS_TYPE(c->type)) {
790 /*if(c->type!=c->ns->access) {
791 printf("%02x<->%02x\n", c->type, c->ns->access);
793 assert(c->type == c->ns->access);
794 return pool_register_namespace(pool, c->ns);
795 } else if(c->type == CONSTANT_INT) {
796 return pool_register_int(pool, c->i);
797 } else if(c->type == CONSTANT_UINT) {
798 return pool_register_uint(pool, c->u);
799 } else if(c->type == CONSTANT_FLOAT) {
800 return pool_register_float(pool, c->f);
801 } else if(c->type == CONSTANT_STRING) {
802 return pool_register_string2(pool, c->s);
803 } else if(!constant_has_index(c)) {
806 fprintf(stderr, "invalid constant type %02x\n", c->type);
810 void constant_free(constant_t*c)
814 if(c->type == CONSTANT_STRING) {
816 } else if (NS_TYPE(c->type)) {
817 namespace_destroy(c->ns);c->ns=0;
821 // --------------------------- optimizing -----------------------------------
823 static int array_append_or_increase(array_t*array, void*key)
825 int pos = array_find(array, key);
827 array->d[pos].data++;
830 return array_append(array, key, 0);
833 static int compare_arrayentry(const void*_c1, const void*_c2)
835 const array_entry_t*c1 = _c1;
836 const array_entry_t*c2 = _c2;
837 return c2->data - c1->data;
840 static void* nodup(const void*o) {return (void*)o;}
842 static void reshuffle_array(array_t*array)
844 qsort(array->d+1, array->num-1, sizeof(array->d[0]), compare_arrayentry);
845 type_t* old_type = array->entry2pos->key_type;
846 type_t old_type_nodup = *old_type;
847 old_type_nodup.dup = nodup;
848 dict_t*d = dict_new2(&old_type_nodup);
849 dict_destroy_shallow(array->entry2pos);
850 array->entry2pos = d;
852 for(t=0;t<array->num;t++) {
853 dict_put(array->entry2pos, array->d[t].name, (void*)(ptroff_t)(t+1));
855 d->key_type = old_type;
859 // ------------------------------- pool -------------------------------------
861 int pool_register_uint(pool_t*p, unsigned int i)
863 int pos = array_append_or_increase(p->x_uints, &i);
867 int pool_register_int(pool_t*p, int i)
869 int pos = array_append_or_increase(p->x_ints, &i);
873 int pool_register_float(pool_t*p, double d)
875 int pos = array_append_or_increase(p->x_floats, &d);
879 int pool_register_string(pool_t*pool, const char*str)
882 string_t s = string_new2(str);
883 int pos = array_append_or_increase(pool->x_strings, &s);
887 int pool_register_string2(pool_t*pool, string_t*s)
889 if(!s || !s->str) return 0;
890 int pos = array_append_or_increase(pool->x_strings, s);
894 int pool_register_namespace(pool_t*pool, namespace_t*ns)
897 int pos = array_append_or_increase(pool->x_namespaces, ns);
901 int pool_register_namespace_set(pool_t*pool, namespace_set_t*set)
904 int pos = array_append_or_increase(pool->x_namespace_sets, set);
908 int pool_register_multiname(pool_t*pool, multiname_t*n)
911 int pos = array_append_or_increase(pool->x_multinames, n);
915 int pool_register_multiname2(pool_t*pool, char*name)
918 multiname_t*n = multiname_fromstring(name);
919 int pos = array_append_or_increase(pool->x_multinames, n);
920 multiname_destroy(n);
926 int pool_find_uint(pool_t*pool, unsigned int x)
928 int i = array_find(pool->x_uints, &x);
930 fprintf(stderr, "Couldn't find uint \"%d\" in constant pool\n", x);
935 int pool_find_int(pool_t*pool, int x)
937 int i = array_find(pool->x_ints, &x);
939 fprintf(stderr, "Couldn't find int \"%d\" in constant pool\n", x);
944 int pool_find_float(pool_t*pool, double x)
946 int i = array_find(pool->x_ints, &x);
948 fprintf(stderr, "Couldn't find int \"%d\" in constant pool\n", x);
953 int pool_find_namespace(pool_t*pool, namespace_t*ns)
957 int i = array_find(pool->x_namespaces, ns);
959 char*s = namespace_tostring(ns);
960 fprintf(stderr, "Couldn't find namespace \"%s\" %08x in constant pool\n", s, ns);
966 int pool_find_namespace_set(pool_t*pool, namespace_set_t*set)
970 int i = array_find(pool->x_namespace_sets, set);
972 char*s = namespace_set_tostring(set);
973 fprintf(stderr, "Couldn't find namespace_set \"%s\" in constant pool\n", s);
979 int pool_find_string(pool_t*pool, const char*str)
983 string_t s = string_new2(str);
984 int i = array_find(pool->x_strings, &s);
986 fprintf(stderr, "Couldn't find string \"%s\" in constant pool\n", s);
991 int pool_find_multiname(pool_t*pool, multiname_t*name)
995 int i = array_find(pool->x_multinames, name);
997 char*s = multiname_tostring(name);
998 fprintf(stderr, "Couldn't find multiname \"%s\" in constant pool\n", s);
1005 int pool_lookup_int(pool_t*pool, int i)
1008 return *(int*)array_getkey(pool->x_ints, i);
1010 unsigned int pool_lookup_uint(pool_t*pool, int i)
1013 return *(unsigned int*)array_getkey(pool->x_uints, i);
1015 double pool_lookup_float(pool_t*pool, int i)
1017 if(!i) return __builtin_nan("");
1018 return *(double*)array_getkey(pool->x_floats, i);
1020 const char*pool_lookup_string(pool_t*pool, int i)
1022 string_t*s = array_getkey(pool->x_strings, i);
1026 string_t pool_lookup_string2(pool_t*pool, int i)
1028 string_t*s = array_getkey(pool->x_strings, i);
1031 namespace_t*pool_lookup_namespace(pool_t*pool, int i)
1033 return (namespace_t*)array_getkey(pool->x_namespaces, i);
1035 namespace_set_t*pool_lookup_namespace_set(pool_t*pool, int i)
1037 return (namespace_set_t*)array_getkey(pool->x_namespace_sets, i);
1039 multiname_t*pool_lookup_multiname(pool_t*pool, int i)
1041 return (multiname_t*)array_getkey(pool->x_multinames, i);
1048 p->x_ints = array_new2(&uint_type);
1049 p->x_uints = array_new2(&uint_type);
1050 p->x_floats = array_new2(&float_type);
1051 p->x_strings = array_new2(&stringstruct_type);
1052 p->x_namespaces = array_new2(&namespace_type);
1053 p->x_namespace_sets = array_new2(&namespace_set_type);
1054 p->x_multinames = array_new2(&multiname_type);
1056 /* add a zero-index entry in each list */
1058 array_append(p->x_ints, 0, 0);
1059 array_append(p->x_uints, 0, 0);
1060 array_append(p->x_floats, 0, 0);
1061 array_append(p->x_strings, 0, 0);
1062 array_append(p->x_namespaces, 0, 0);
1063 array_append(p->x_namespace_sets, 0, 0);
1064 array_append(p->x_multinames, 0, 0);
1068 void pool_optimize(pool_t*p)
1070 reshuffle_array(p->x_ints);
1071 reshuffle_array(p->x_uints);
1072 reshuffle_array(p->x_floats);
1073 reshuffle_array(p->x_strings);
1074 reshuffle_array(p->x_namespaces);
1075 reshuffle_array(p->x_namespace_sets);
1076 reshuffle_array(p->x_multinames);
1082 void pool_read(pool_t*pool, TAG*tag)
1084 int num_ints = swf_GetU30(tag);
1085 DEBUG printf("%d ints\n", num_ints);
1087 for(t=1;t<num_ints;t++) {
1088 S32 v = swf_GetABCS32(tag);
1089 DEBUG printf("int %d) %d\n", t, v);
1090 array_append(pool->x_ints, &v, 0);
1093 int num_uints = swf_GetU30(tag);
1094 DEBUG printf("%d uints\n", num_uints);
1095 for(t=1;t<num_uints;t++) {
1096 U32 v = swf_GetABCU32(tag);
1097 DEBUG printf("uint %d) %d\n", t, v);
1098 array_append(pool->x_uints, &v, 0);
1101 int num_floats = swf_GetU30(tag);
1102 DEBUG printf("%d floats\n", num_floats);
1103 for(t=1;t<num_floats;t++) {
1104 double d = swf_GetD64(tag);
1105 DEBUG printf("float %d) %f\n", t, d);
1106 array_append(pool->x_floats, &d, 0);
1109 int num_strings = swf_GetU30(tag);
1110 DEBUG printf("%d strings\n", num_strings);
1111 for(t=1;t<num_strings;t++) {
1112 int len = swf_GetU30(tag);
1113 string_t s = string_new(&tag->data[tag->pos], len);
1114 swf_GetBlock(tag, 0, len);
1115 array_append(pool->x_strings, &s, 0);
1116 DEBUG printf("%d) \"%s\"\n", t, ((string_t*)array_getkey(pool->x_strings, t))->str);
1118 int num_namespaces = swf_GetU30(tag);
1119 DEBUG printf("%d namespaces\n", num_namespaces);
1120 for(t=1;t<num_namespaces;t++) {
1121 U8 type = swf_GetU8(tag);
1122 int namenr = swf_GetU30(tag);
1123 const char*name = 0;
1125 name = pool_lookup_string(pool, namenr);
1126 namespace_t*ns = namespace_new(type, name);
1127 array_append(pool->x_namespaces, ns, 0);
1128 DEBUG printf("%d) %02x \"%s\"\n", t, type, namespace_tostring(ns));
1129 namespace_destroy(ns);
1131 int num_sets = swf_GetU30(tag);
1132 DEBUG printf("%d namespace sets\n", num_sets);
1133 for(t=1;t<num_sets;t++) {
1134 int count = swf_GetU30(tag);
1137 NEW(namespace_set_t, nsset);
1138 for(s=0;s<count;s++) {
1139 int nsnr = swf_GetU30(tag);
1141 fprintf(stderr, "Zero entry in namespace set\n");
1142 namespace_t*ns = (namespace_t*)array_getkey(pool->x_namespaces, nsnr);
1143 list_append(nsset->namespaces, namespace_clone(ns));
1145 array_append(pool->x_namespace_sets, nsset, 0);
1146 DEBUG printf("set %d) %s\n", t, namespace_set_tostring(nsset));
1147 namespace_set_destroy(nsset);
1150 int num_multinames = swf_GetU30(tag);
1151 DEBUG printf("%d multinames\n", num_multinames);
1152 for(t=1;t<num_multinames;t++) {
1154 memset(&m, 0, sizeof(multiname_t));
1158 printf("0x%02x ", tag->data[tag->pos+s]);
1161 m.type = swf_GetU8(tag);
1162 if(m.type==0x07 || m.type==0x0d) {
1163 int namespace_index = swf_GetU30(tag);
1164 m.ns = (namespace_t*)array_getkey(pool->x_namespaces, namespace_index);
1165 int name_index = swf_GetU30(tag);
1166 if(name_index) // 0 = '*' (any)
1167 m.name = pool_lookup_string(pool, name_index);
1168 } else if(m.type==0x0f || m.type==0x10) {
1169 int name_index = swf_GetU30(tag);
1170 if(name_index) // 0 = '*' (any name)
1171 m.name = pool_lookup_string(pool, name_index);
1172 } else if(m.type==0x11 || m.type==0x12) {
1173 } else if(m.type==0x09 || m.type==0x0e) {
1174 int name_index = swf_GetU30(tag);
1175 int namespace_set_index = swf_GetU30(tag);
1177 m.name = pool_lookup_string(pool, name_index);
1178 m.namespace_set = (namespace_set_t*)array_getkey(pool->x_namespace_sets, namespace_set_index);
1179 } else if(m.type==0x1b || m.type==0x1c) {
1180 int namespace_set_index = swf_GetU30(tag);
1181 m.namespace_set = (namespace_set_t*)array_getkey(pool->x_namespace_sets, namespace_set_index);
1182 } else if(m.type==0x1d) {
1183 int v1 = swf_GetU30(tag); //multiname
1184 int v2 = swf_GetU30(tag); //counter?
1185 int v3 = swf_GetU30(tag); //multiname
1186 // e.g. Vector<int> ... we only store the parent object
1187 m = *(multiname_t*)array_getkey(pool->x_multinames, v1);
1189 printf("can't parse type %d multinames yet\n", m.type);
1191 DEBUG printf("multiname %d) %s\n", t, multiname_tostring(&m));
1192 array_append(pool->x_multinames, &m, 0);
1196 void pool_dump(pool_t*pool, FILE*fo, char flags)
1199 fprintf(fo, "%d integers\n", pool->x_ints->num);
1200 for(t=1;t<pool->x_ints->num;t++) {
1201 S32 val = *(int*)array_getkey(pool->x_ints, t);
1202 int freq = (int)(ptroff_t)array_getvalue(pool->x_ints, t);
1203 if(flags&1) fprintf(fo, "%5d %d) %d\n", freq, t, val);
1205 fprintf(fo, "%d unsigned integers\n", pool->x_uints->num);
1206 for(t=1;t<pool->x_uints->num;t++) {
1207 U32 val = *(unsigned int*)array_getkey(pool->x_uints, t);
1208 int freq = (int)(ptroff_t)array_getvalue(pool->x_uints, t);
1209 if(flags&1) fprintf(fo, "%5d %d) %d\n", freq, t, val);
1211 fprintf(fo, "%d floats\n", pool->x_floats->num);
1212 for(t=1;t<pool->x_floats->num;t++) {
1213 double d = pool_lookup_float(pool, t);
1214 int freq = (int)(ptroff_t)array_getvalue(pool->x_floats, t);
1215 if(flags&2) fprintf(fo, "%5d %d) %f\n", freq, t, d);
1217 fprintf(fo, "%d strings\n", pool->x_strings->num);
1218 for(t=1;t<pool->x_strings->num;t++) {
1219 string_t str = pool_lookup_string2(pool, t);
1220 int freq = (int)(ptroff_t)array_getvalue(pool->x_strings, t);
1221 if(flags&1) fprintf(fo, "%5d %d) ", freq, t);
1222 if(flags&1) fwrite(str.str, str.len, 1, fo);
1223 if(flags&1) fprintf(fo, "\n", t);
1225 fprintf(fo, "%d namespaces\n", pool->x_namespaces->num);
1226 for(t=1;t<pool->x_namespaces->num;t++) {
1227 namespace_t*ns= (namespace_t*)array_getkey(pool->x_namespaces, t);
1228 char*s = namespace_tostring(ns);
1229 int freq = (int)(ptroff_t)array_getvalue(pool->x_namespaces, t);
1230 if(flags&1) fprintf(fo, "%5d %d) %s\n", freq, t, s);
1233 fprintf(fo, "%d namespace sets\n", pool->x_namespace_sets->num);
1234 for(t=1;t<pool->x_namespace_sets->num;t++) {
1235 namespace_set_t*set = (namespace_set_t*)array_getkey(pool->x_namespace_sets, t);
1236 char*s = namespace_set_tostring(set);
1237 int freq = (int)(ptroff_t)array_getvalue(pool->x_namespace_sets, t);
1238 if(flags&1) fprintf(fo, "%5d %d) %s\n", freq, t, s);
1242 fprintf(fo, "%d multinames\n", pool->x_multinames->num);
1243 for(t=1;t<pool->x_multinames->num;t++) {
1244 multiname_t*m = (multiname_t*)array_getkey(pool->x_multinames, t);
1245 char*s = multiname_tostring(m);
1246 int freq = (int)(ptroff_t)array_getvalue(pool->x_multinames, t);
1247 if(flags&1) fprintf(fo, "%5d %d) %s\n", freq, t, s);
1252 void pool_write(pool_t*pool, TAG*tag)
1256 /* make sure that all namespaces used by multinames / namespace sets
1257 and all strings used by namespaces exist */
1259 for(t=1;t<pool->x_multinames->num;t++) {
1260 multiname_t*m = (multiname_t*)array_getkey(pool->x_multinames, t);
1262 pool_register_namespace(pool, m->ns);
1264 if(m->namespace_set) {
1265 pool_register_namespace_set(pool, m->namespace_set);
1268 pool_register_string(pool, m->name);
1271 for(t=1;t<pool->x_namespace_sets->num;t++) {
1272 namespace_set_t*set = (namespace_set_t*)array_getkey(pool->x_namespace_sets, t);
1273 namespace_list_t*i = set->namespaces;
1275 pool_register_namespace(pool, i->namespace);
1279 for(t=1;t<pool->x_namespaces->num;t++) {
1280 namespace_t*ns= (namespace_t*)array_getkey(pool->x_namespaces, t);
1281 /* The spec says (page 22): "a value of zero denotes an empty string".
1282 However when actually using zero strings as empty namespaces, the
1283 flash player breaks.*/
1284 //if(ns->name && ns->name[0])
1285 pool_register_string(pool, ns->name);
1288 //pool_register_int(pool, 15);
1289 //pool_register_int(pool, 1);
1290 //pool_register_int(pool, 0);
1293 swf_SetU30(tag, pool->x_ints->num>1?pool->x_ints->num:0);
1294 for(t=1;t<pool->x_ints->num;t++) {
1295 S32 val = *(int*)array_getkey(pool->x_ints, t);
1296 swf_SetABCS32(tag, val);
1298 swf_SetU30(tag, pool->x_uints->num>1?pool->x_uints->num:0);
1299 for(t=1;t<pool->x_uints->num;t++) {
1300 swf_SetABCU32(tag, *(unsigned int*)array_getkey(pool->x_uints, t));
1302 swf_SetU30(tag, pool->x_floats->num>1?pool->x_floats->num:0);
1303 for(t=1;t<pool->x_floats->num;t++) {
1304 double d = pool_lookup_float(pool, t);
1307 swf_SetU30(tag, pool->x_strings->num>1?pool->x_strings->num:0);
1308 for(t=1;t<pool->x_strings->num;t++) {
1309 string_t str = pool_lookup_string2(pool, t);
1310 swf_SetU30String(tag, str.str, str.len);
1312 swf_SetU30(tag, pool->x_namespaces->num>1?pool->x_namespaces->num:0);
1313 for(t=1;t<pool->x_namespaces->num;t++) {
1314 namespace_t*ns= (namespace_t*)array_getkey(pool->x_namespaces, t);
1315 swf_SetU8(tag, ns->access);
1316 const char*name = ns->name;
1319 //if(name && name[0])
1320 i = pool_find_string(pool, name);
1324 swf_SetU30(tag, pool->x_namespace_sets->num>1?pool->x_namespace_sets->num:0);
1325 for(t=1;t<pool->x_namespace_sets->num;t++) {
1326 namespace_set_t*set = (namespace_set_t*)array_getkey(pool->x_namespace_sets, t);
1327 namespace_list_t*i = set->namespaces;
1328 int len = list_length(i);
1329 swf_SetU30(tag, len);
1331 int index = pool_find_namespace(pool, i->namespace);
1332 swf_SetU30(tag, index);
1337 swf_SetU30(tag, pool->x_multinames->num>1?pool->x_multinames->num:0);
1338 for(t=1;t<pool->x_multinames->num;t++) {
1339 multiname_t*m = (multiname_t*)array_getkey(pool->x_multinames, t);
1340 swf_SetU8(tag, m->type);
1343 assert(m->type==0x07 || m->type==0x0d);
1344 int i = pool_find_namespace(pool, m->ns);
1345 if(i<0) fprintf(stderr, "internal error: unregistered namespace %02x %s %s\n", m->ns->access, access2str(m->ns->access), m->ns->name);
1348 assert(m->type!=0x07 && m->type!=0x0d);
1351 assert(m->type==0x09 || m->type==0x0e || m->type==0x07 || m->type==0x0d || m->type==0x0f || m->type==0x10);
1352 int i = pool_find_string(pool, m->name);
1353 if(i<0) fprintf(stderr, "internal error: unregistered name\n");
1356 assert(m->type!=0x09 && m->type!=0x0e && m->type!=0x07 && m->type!=0x0d && m->type!=0x0f && m->type!=0x10);
1358 if(m->namespace_set) {
1359 assert(m->type==0x09 || m->type==0x0e || m->type==0x1c || m->type==0x1b);
1360 int i = pool_find_namespace_set(pool, m->namespace_set);
1361 if(i<0) fprintf(stderr, "internal error: unregistered namespace set\n");
1364 assert(m->type!=0x09 && m->type!=0x0e && m->type!=0x1c && m->type!=0x1b);
1370 void pool_destroy(pool_t*pool)
1373 array_free(pool->x_ints);
1374 array_free(pool->x_uints);
1375 array_free(pool->x_floats);
1376 array_free(pool->x_strings);
1377 array_free(pool->x_namespaces);
1378 array_free(pool->x_namespace_sets);
1379 array_free(pool->x_multinames);