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(const 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(c->type == CONSTANT_UNDEFINED) {
804 /* write undefined with index 0 (and no type). Otherwise, the FlashPlayer
805 seems to throw an "attempt to read out of bounds" exception */
807 } else if(!constant_has_index(c)) {
810 fprintf(stderr, "invalid constant type %02x\n", c->type);
814 void constant_free(constant_t*c)
818 if(c->type == CONSTANT_STRING) {
820 } else if (NS_TYPE(c->type)) {
821 namespace_destroy(c->ns);c->ns=0;
825 // --------------------------- optimizing -----------------------------------
827 static int array_append_or_increase(array_t*array, void*key)
829 int pos = array_find(array, key);
831 array->d[pos].data++;
834 return array_append(array, key, 0);
837 static int compare_arrayentry(const void*_c1, const void*_c2)
839 const array_entry_t*c1 = _c1;
840 const array_entry_t*c2 = _c2;
841 return c2->data - c1->data;
844 static void* nodup(const void*o) {return (void*)o;}
846 static void reshuffle_array(array_t*array)
848 qsort(array->d+1, array->num-1, sizeof(array->d[0]), compare_arrayentry);
849 type_t* old_type = array->entry2pos->key_type;
850 type_t old_type_nodup = *old_type;
851 old_type_nodup.dup = nodup;
852 dict_t*d = dict_new2(&old_type_nodup);
853 dict_destroy_shallow(array->entry2pos);
854 array->entry2pos = d;
856 for(t=0;t<array->num;t++) {
857 dict_put(array->entry2pos, array->d[t].name, (void*)(ptroff_t)(t+1));
859 d->key_type = old_type;
863 // ------------------------------- pool -------------------------------------
865 int pool_register_uint(pool_t*p, unsigned int i)
867 int pos = array_append_or_increase(p->x_uints, &i);
871 int pool_register_int(pool_t*p, int i)
873 int pos = array_append_or_increase(p->x_ints, &i);
877 int pool_register_float(pool_t*p, double d)
879 int pos = array_append_or_increase(p->x_floats, &d);
883 int pool_register_string(pool_t*pool, const char*str)
886 string_t s = string_new2(str);
887 int pos = array_append_or_increase(pool->x_strings, &s);
891 int pool_register_string2(pool_t*pool, string_t*s)
893 if(!s || !s->str) return 0;
894 int pos = array_append_or_increase(pool->x_strings, s);
898 int pool_register_namespace(pool_t*pool, namespace_t*ns)
901 int pos = array_append_or_increase(pool->x_namespaces, ns);
905 int pool_register_namespace_set(pool_t*pool, namespace_set_t*set)
908 int pos = array_append_or_increase(pool->x_namespace_sets, set);
912 int pool_register_multiname(pool_t*pool, multiname_t*n)
915 int pos = array_append_or_increase(pool->x_multinames, n);
919 int pool_register_multiname2(pool_t*pool, char*name)
922 multiname_t*n = multiname_fromstring(name);
923 int pos = array_append_or_increase(pool->x_multinames, n);
924 multiname_destroy(n);
930 int pool_find_uint(pool_t*pool, unsigned int x)
932 int i = array_find(pool->x_uints, &x);
934 fprintf(stderr, "Couldn't find uint \"%d\" in constant pool\n", x);
939 int pool_find_int(pool_t*pool, int x)
941 int i = array_find(pool->x_ints, &x);
943 fprintf(stderr, "Couldn't find int \"%d\" in constant pool\n", x);
948 int pool_find_float(pool_t*pool, double x)
950 int i = array_find(pool->x_ints, &x);
952 fprintf(stderr, "Couldn't find int \"%d\" in constant pool\n", x);
957 int pool_find_namespace(pool_t*pool, namespace_t*ns)
961 int i = array_find(pool->x_namespaces, ns);
963 char*s = namespace_tostring(ns);
964 fprintf(stderr, "Couldn't find namespace \"%s\" %08x in constant pool\n", s, ns);
970 int pool_find_namespace_set(pool_t*pool, namespace_set_t*set)
974 int i = array_find(pool->x_namespace_sets, set);
976 char*s = namespace_set_tostring(set);
977 fprintf(stderr, "Couldn't find namespace_set \"%s\" in constant pool\n", s);
983 int pool_find_string(pool_t*pool, const char*str)
987 string_t s = string_new2(str);
988 int i = array_find(pool->x_strings, &s);
990 fprintf(stderr, "Couldn't find string \"%s\" in constant pool\n", s);
995 int pool_find_multiname(pool_t*pool, multiname_t*name)
999 int i = array_find(pool->x_multinames, name);
1001 char*s = multiname_tostring(name);
1002 fprintf(stderr, "Couldn't find multiname \"%s\" in constant pool\n", s);
1009 int pool_lookup_int(pool_t*pool, int i)
1012 return *(int*)array_getkey(pool->x_ints, i);
1014 unsigned int pool_lookup_uint(pool_t*pool, int i)
1017 return *(unsigned int*)array_getkey(pool->x_uints, i);
1019 double pool_lookup_float(pool_t*pool, int i)
1021 if(!i) return __builtin_nan("");
1022 return *(double*)array_getkey(pool->x_floats, i);
1024 const char*pool_lookup_string(pool_t*pool, int i)
1026 string_t*s = array_getkey(pool->x_strings, i);
1030 string_t pool_lookup_string2(pool_t*pool, int i)
1032 string_t*s = array_getkey(pool->x_strings, i);
1035 namespace_t*pool_lookup_namespace(pool_t*pool, int i)
1037 return (namespace_t*)array_getkey(pool->x_namespaces, i);
1039 namespace_set_t*pool_lookup_namespace_set(pool_t*pool, int i)
1041 return (namespace_set_t*)array_getkey(pool->x_namespace_sets, i);
1043 multiname_t*pool_lookup_multiname(pool_t*pool, int i)
1045 return (multiname_t*)array_getkey(pool->x_multinames, i);
1052 p->x_ints = array_new2(&uint_type);
1053 p->x_uints = array_new2(&uint_type);
1054 p->x_floats = array_new2(&float_type);
1055 p->x_strings = array_new2(&stringstruct_type);
1056 p->x_namespaces = array_new2(&namespace_type);
1057 p->x_namespace_sets = array_new2(&namespace_set_type);
1058 p->x_multinames = array_new2(&multiname_type);
1060 /* add a zero-index entry in each list */
1062 array_append(p->x_ints, 0, 0);
1063 array_append(p->x_uints, 0, 0);
1064 array_append(p->x_floats, 0, 0);
1065 array_append(p->x_strings, 0, 0);
1066 array_append(p->x_namespaces, 0, 0);
1067 array_append(p->x_namespace_sets, 0, 0);
1068 array_append(p->x_multinames, 0, 0);
1072 void pool_optimize(pool_t*p)
1074 reshuffle_array(p->x_ints);
1075 reshuffle_array(p->x_uints);
1076 reshuffle_array(p->x_floats);
1077 reshuffle_array(p->x_strings);
1078 reshuffle_array(p->x_namespaces);
1079 reshuffle_array(p->x_namespace_sets);
1080 reshuffle_array(p->x_multinames);
1086 void pool_read(pool_t*pool, TAG*tag)
1088 int num_ints = swf_GetU30(tag);
1089 DEBUG printf("%d ints\n", num_ints);
1091 for(t=1;t<num_ints;t++) {
1092 S32 v = swf_GetABCS32(tag);
1093 DEBUG printf("int %d) %d\n", t, v);
1094 array_append(pool->x_ints, &v, 0);
1097 int num_uints = swf_GetU30(tag);
1098 DEBUG printf("%d uints\n", num_uints);
1099 for(t=1;t<num_uints;t++) {
1100 U32 v = swf_GetABCU32(tag);
1101 DEBUG printf("uint %d) %d\n", t, v);
1102 array_append(pool->x_uints, &v, 0);
1105 int num_floats = swf_GetU30(tag);
1106 DEBUG printf("%d floats\n", num_floats);
1107 for(t=1;t<num_floats;t++) {
1108 double d = swf_GetD64(tag);
1109 DEBUG printf("float %d) %f\n", t, d);
1110 array_append(pool->x_floats, &d, 0);
1113 int num_strings = swf_GetU30(tag);
1114 DEBUG printf("%d strings\n", num_strings);
1115 for(t=1;t<num_strings;t++) {
1116 int len = swf_GetU30(tag);
1117 string_t s = string_new(&tag->data[tag->pos], len);
1118 swf_GetBlock(tag, 0, len);
1119 array_append(pool->x_strings, &s, 0);
1120 DEBUG printf("%d) \"%s\"\n", t, ((string_t*)array_getkey(pool->x_strings, t))->str);
1122 int num_namespaces = swf_GetU30(tag);
1123 DEBUG printf("%d namespaces\n", num_namespaces);
1124 for(t=1;t<num_namespaces;t++) {
1125 U8 type = swf_GetU8(tag);
1126 int namenr = swf_GetU30(tag);
1127 const char*name = 0;
1129 name = pool_lookup_string(pool, namenr);
1130 namespace_t*ns = namespace_new(type, name);
1131 array_append(pool->x_namespaces, ns, 0);
1132 DEBUG printf("%d) %02x \"%s\"\n", t, type, namespace_tostring(ns));
1133 namespace_destroy(ns);
1135 int num_sets = swf_GetU30(tag);
1136 DEBUG printf("%d namespace sets\n", num_sets);
1137 for(t=1;t<num_sets;t++) {
1138 int count = swf_GetU30(tag);
1141 NEW(namespace_set_t, nsset);
1142 for(s=0;s<count;s++) {
1143 int nsnr = swf_GetU30(tag);
1145 fprintf(stderr, "Zero entry in namespace set\n");
1146 namespace_t*ns = (namespace_t*)array_getkey(pool->x_namespaces, nsnr);
1147 list_append(nsset->namespaces, namespace_clone(ns));
1149 array_append(pool->x_namespace_sets, nsset, 0);
1150 DEBUG printf("set %d) %s\n", t, namespace_set_tostring(nsset));
1151 namespace_set_destroy(nsset);
1154 int num_multinames = swf_GetU30(tag);
1155 DEBUG printf("%d multinames\n", num_multinames);
1156 for(t=1;t<num_multinames;t++) {
1158 memset(&m, 0, sizeof(multiname_t));
1162 printf("0x%02x ", tag->data[tag->pos+s]);
1165 m.type = swf_GetU8(tag);
1166 if(m.type==0x07 || m.type==0x0d) {
1167 int namespace_index = swf_GetU30(tag);
1168 m.ns = (namespace_t*)array_getkey(pool->x_namespaces, namespace_index);
1169 int name_index = swf_GetU30(tag);
1170 if(name_index) // 0 = '*' (any)
1171 m.name = pool_lookup_string(pool, name_index);
1172 } else if(m.type==0x0f || m.type==0x10) {
1173 int name_index = swf_GetU30(tag);
1174 if(name_index) // 0 = '*' (any name)
1175 m.name = pool_lookup_string(pool, name_index);
1176 } else if(m.type==0x11 || m.type==0x12) {
1177 } else if(m.type==0x09 || m.type==0x0e) {
1178 int name_index = swf_GetU30(tag);
1179 int namespace_set_index = swf_GetU30(tag);
1181 m.name = pool_lookup_string(pool, name_index);
1182 m.namespace_set = (namespace_set_t*)array_getkey(pool->x_namespace_sets, namespace_set_index);
1183 } else if(m.type==0x1b || m.type==0x1c) {
1184 int namespace_set_index = swf_GetU30(tag);
1185 m.namespace_set = (namespace_set_t*)array_getkey(pool->x_namespace_sets, namespace_set_index);
1186 } else if(m.type==0x1d) {
1187 int v1 = swf_GetU30(tag); //multiname
1188 int v2 = swf_GetU30(tag); //counter?
1189 int v3 = swf_GetU30(tag); //multiname
1190 // e.g. Vector<int> ... we only store the parent object
1191 m = *(multiname_t*)array_getkey(pool->x_multinames, v1);
1193 printf("can't parse type %d multinames yet\n", m.type);
1195 DEBUG printf("multiname %d) %s\n", t, multiname_tostring(&m));
1196 array_append(pool->x_multinames, &m, 0);
1200 void pool_dump(pool_t*pool, FILE*fo, char flags)
1203 fprintf(fo, "%d integers\n", pool->x_ints->num);
1204 for(t=1;t<pool->x_ints->num;t++) {
1205 S32 val = *(int*)array_getkey(pool->x_ints, t);
1206 int freq = (int)(ptroff_t)array_getvalue(pool->x_ints, t);
1207 if(flags&1) fprintf(fo, "%5d %d) %d\n", freq, t, val);
1209 fprintf(fo, "%d unsigned integers\n", pool->x_uints->num);
1210 for(t=1;t<pool->x_uints->num;t++) {
1211 U32 val = *(unsigned int*)array_getkey(pool->x_uints, t);
1212 int freq = (int)(ptroff_t)array_getvalue(pool->x_uints, t);
1213 if(flags&1) fprintf(fo, "%5d %d) %d\n", freq, t, val);
1215 fprintf(fo, "%d floats\n", pool->x_floats->num);
1216 for(t=1;t<pool->x_floats->num;t++) {
1217 double d = pool_lookup_float(pool, t);
1218 int freq = (int)(ptroff_t)array_getvalue(pool->x_floats, t);
1219 if(flags&2) fprintf(fo, "%5d %d) %f\n", freq, t, d);
1221 fprintf(fo, "%d strings\n", pool->x_strings->num);
1222 for(t=1;t<pool->x_strings->num;t++) {
1223 string_t str = pool_lookup_string2(pool, t);
1224 int freq = (int)(ptroff_t)array_getvalue(pool->x_strings, t);
1225 if(flags&1) fprintf(fo, "%5d %d) ", freq, t);
1226 if(flags&1) fwrite(str.str, str.len, 1, fo);
1227 if(flags&1) fprintf(fo, "\n", t);
1229 fprintf(fo, "%d namespaces\n", pool->x_namespaces->num);
1230 for(t=1;t<pool->x_namespaces->num;t++) {
1231 namespace_t*ns= (namespace_t*)array_getkey(pool->x_namespaces, t);
1232 char*s = namespace_tostring(ns);
1233 int freq = (int)(ptroff_t)array_getvalue(pool->x_namespaces, t);
1234 if(flags&1) fprintf(fo, "%5d %d) %s\n", freq, t, s);
1237 fprintf(fo, "%d namespace sets\n", pool->x_namespace_sets->num);
1238 for(t=1;t<pool->x_namespace_sets->num;t++) {
1239 namespace_set_t*set = (namespace_set_t*)array_getkey(pool->x_namespace_sets, t);
1240 char*s = namespace_set_tostring(set);
1241 int freq = (int)(ptroff_t)array_getvalue(pool->x_namespace_sets, t);
1242 if(flags&1) fprintf(fo, "%5d %d) %s\n", freq, t, s);
1246 fprintf(fo, "%d multinames\n", pool->x_multinames->num);
1247 for(t=1;t<pool->x_multinames->num;t++) {
1248 multiname_t*m = (multiname_t*)array_getkey(pool->x_multinames, t);
1249 char*s = multiname_tostring(m);
1250 int freq = (int)(ptroff_t)array_getvalue(pool->x_multinames, t);
1251 if(flags&1) fprintf(fo, "%5d %d) %s\n", freq, t, s);
1256 void pool_write(pool_t*pool, TAG*tag)
1260 /* make sure that all namespaces used by multinames / namespace sets
1261 and all strings used by namespaces exist */
1263 for(t=1;t<pool->x_multinames->num;t++) {
1264 multiname_t*m = (multiname_t*)array_getkey(pool->x_multinames, t);
1266 pool_register_namespace(pool, m->ns);
1268 if(m->namespace_set) {
1269 pool_register_namespace_set(pool, m->namespace_set);
1272 pool_register_string(pool, m->name);
1275 for(t=1;t<pool->x_namespace_sets->num;t++) {
1276 namespace_set_t*set = (namespace_set_t*)array_getkey(pool->x_namespace_sets, t);
1277 namespace_list_t*i = set->namespaces;
1279 pool_register_namespace(pool, i->namespace);
1283 for(t=1;t<pool->x_namespaces->num;t++) {
1284 namespace_t*ns= (namespace_t*)array_getkey(pool->x_namespaces, t);
1285 /* The spec says (page 22): "a value of zero denotes an empty string".
1286 However when actually using zero strings as empty namespaces, the
1287 flash player breaks.*/
1288 //if(ns->name && ns->name[0])
1289 pool_register_string(pool, ns->name);
1292 //pool_register_int(pool, 15);
1293 //pool_register_int(pool, 1);
1294 //pool_register_int(pool, 0);
1297 swf_SetU30(tag, pool->x_ints->num>1?pool->x_ints->num:0);
1298 for(t=1;t<pool->x_ints->num;t++) {
1299 S32 val = *(int*)array_getkey(pool->x_ints, t);
1300 swf_SetABCS32(tag, val);
1302 swf_SetU30(tag, pool->x_uints->num>1?pool->x_uints->num:0);
1303 for(t=1;t<pool->x_uints->num;t++) {
1304 swf_SetABCU32(tag, *(unsigned int*)array_getkey(pool->x_uints, t));
1306 swf_SetU30(tag, pool->x_floats->num>1?pool->x_floats->num:0);
1307 for(t=1;t<pool->x_floats->num;t++) {
1308 double d = pool_lookup_float(pool, t);
1311 swf_SetU30(tag, pool->x_strings->num>1?pool->x_strings->num:0);
1312 for(t=1;t<pool->x_strings->num;t++) {
1313 string_t str = pool_lookup_string2(pool, t);
1314 swf_SetU30String(tag, str.str, str.len);
1316 swf_SetU30(tag, pool->x_namespaces->num>1?pool->x_namespaces->num:0);
1317 for(t=1;t<pool->x_namespaces->num;t++) {
1318 namespace_t*ns= (namespace_t*)array_getkey(pool->x_namespaces, t);
1319 swf_SetU8(tag, ns->access);
1320 const char*name = ns->name;
1323 //if(name && name[0])
1324 i = pool_find_string(pool, name);
1328 swf_SetU30(tag, pool->x_namespace_sets->num>1?pool->x_namespace_sets->num:0);
1329 for(t=1;t<pool->x_namespace_sets->num;t++) {
1330 namespace_set_t*set = (namespace_set_t*)array_getkey(pool->x_namespace_sets, t);
1331 namespace_list_t*i = set->namespaces;
1332 int len = list_length(i);
1333 swf_SetU30(tag, len);
1335 int index = pool_find_namespace(pool, i->namespace);
1336 swf_SetU30(tag, index);
1341 swf_SetU30(tag, pool->x_multinames->num>1?pool->x_multinames->num:0);
1342 for(t=1;t<pool->x_multinames->num;t++) {
1343 multiname_t*m = (multiname_t*)array_getkey(pool->x_multinames, t);
1344 swf_SetU8(tag, m->type);
1347 assert(m->type==0x07 || m->type==0x0d);
1348 int i = pool_find_namespace(pool, m->ns);
1349 if(i<0) fprintf(stderr, "internal error: unregistered namespace %02x %s %s\n", m->ns->access, access2str(m->ns->access), m->ns->name);
1352 assert(m->type!=0x07 && m->type!=0x0d);
1355 assert(m->type==0x09 || m->type==0x0e || m->type==0x07 || m->type==0x0d || m->type==0x0f || m->type==0x10);
1356 int i = pool_find_string(pool, m->name);
1357 if(i<0) fprintf(stderr, "internal error: unregistered name\n");
1360 assert(m->type!=0x09 && m->type!=0x0e && m->type!=0x07 && m->type!=0x0d && m->type!=0x0f && m->type!=0x10);
1362 if(m->namespace_set) {
1363 assert(m->type==0x09 || m->type==0x0e || m->type==0x1c || m->type==0x1b);
1364 int i = pool_find_namespace_set(pool, m->namespace_set);
1365 if(i<0) fprintf(stderr, "internal error: unregistered namespace set\n");
1368 assert(m->type!=0x09 && m->type!=0x0e && m->type!=0x1c && m->type!=0x1b);
1374 void pool_destroy(pool_t*pool)
1377 array_free(pool->x_ints);
1378 array_free(pool->x_uints);
1379 array_free(pool->x_floats);
1380 array_free(pool->x_strings);
1381 array_free(pool->x_namespaces);
1382 array_free(pool->x_namespace_sets);
1383 array_free(pool->x_multinames);