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=(unsigned const char*)str;
152 char*newstr = malloc(len+1);
154 s=(unsigned const char*)str;
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 = m->ns?escape_string(m->ns->name):strdup("NULL");
526 mname = malloc(strlen(nsname)+namelen+32);
528 if(m->type == QNAMEA)
529 strcat(mname, ",attr");
533 strcat(mname,access2str(m->ns->access));
536 strcat(mname, nsname);
540 } else if(m->type==RTQNAME || m->type==RTQNAMEA) {
541 mname = malloc(namelen+32);
542 strcpy(mname, "<rt");
543 if(m->type == RTQNAMEA)
544 strcat(mname, ",attr");
547 } else if(m->type==RTQNAMEL) {
548 mname = strdup("<rt,l>");
549 } else if(m->type==RTQNAMELA) {
550 mname = strdup("<rt,l,attr>");
551 } else if(m->type==MULTINAME || m->type==MULTINAMEA) {
552 char*s = namespace_set_tostring(m->namespace_set);
553 mname = malloc(strlen(s)+namelen+16);
554 if(m->type == MULTINAME)
555 strcpy(mname,"<multi>");
557 strcpy(mname,"<multi,attr>");
562 } else if(m->type==MULTINAMEL || m->type==MULTINAMELA) {
563 char*s = namespace_set_tostring(m->namespace_set);
564 mname = malloc(strlen(s)+16);
565 if(m->type == MULTINAMEL)
566 strcpy(mname,"<l,multi>");
568 strcpy(mname,"<l,multi,attr>");
572 return strdup("<invalid>");
578 multiname_t* multiname_fromstring(const char*name2)
582 char*n = strdup(name2);
583 char*p = strstr(n, "::");
584 char*namespace=0,*name=0;
587 fprintf(stderr, "Error: single ':' in name\n");
595 if(strchr(namespace, ':')) {
596 fprintf(stderr, "Error: single ':' in namespace\n");
598 if(strchr(name, ':')) {
599 fprintf(stderr, "Error: single ':' in qualified name\n");
603 multiname_t*m = malloc(sizeof(multiname_t));
604 memset(m, 0, sizeof(multiname_t));
606 m->namespace_set = 0;
607 m->ns = namespace_fromstring(namespace);
608 m->name = name?strdup(name):0;
613 void multiname_destroy(multiname_t*m)
617 free((void*)m->name);m->name = 0;
620 namespace_destroy(m->ns);m->ns = 0;
622 if(m->namespace_set) {
623 namespace_set_destroy(m->namespace_set);m->namespace_set = 0;
630 type_t multiname_type = {
631 dup: (dup_func)multiname_clone,
632 hash: (hash_func)multiname_hash,
633 free: (free_func)multiname_destroy,
634 equals: (equals_func)multiname_equals
638 // ------------------------------- constants -------------------------------------
640 #define UNIQUE_CONSTANT(x) ((x) == CONSTANT_TRUE || (x) == CONSTANT_FALSE || (x) == CONSTANT_NULL || (x) == CONSTANT_UNDEFINED)
642 constant_t* constant_new_int(int i)
646 c->type = CONSTANT_INT;
649 constant_t* constant_new_uint(unsigned int u)
653 c->type = CONSTANT_UINT;
656 constant_t* constant_new_float(double f)
660 c->type = CONSTANT_FLOAT;
663 constant_t* constant_new_string(const char*s)
666 c->s = string_new4(s);
667 c->type = CONSTANT_STRING;
670 constant_t* constant_new_string2(const char*s, int len)
673 c->s = string_new3(s, len);
674 c->type = CONSTANT_STRING;
677 constant_t* constant_new_namespace(namespace_t*ns)
680 c->ns = namespace_clone(ns);
681 c->type = ns->access;
682 assert(NS_TYPE(c->type));
685 constant_t* constant_new_true()
688 c->type = CONSTANT_TRUE;
691 constant_t* constant_new_false()
694 c->type = CONSTANT_FALSE;
697 constant_t* constant_new_null()
700 c->type = CONSTANT_NULL;
703 constant_t* constant_new_undefined()
706 c->type = CONSTANT_UNDEFINED;
709 constant_t* constant_clone(constant_t*other)
712 constant_t*c = malloc(sizeof(constant_t));
713 memcpy(c, other, sizeof(constant_t));
714 if(NS_TYPE(c->type)) {
715 c->ns = namespace_clone(other->ns);
716 } else if(c->type == CONSTANT_STRING) {
717 c->s = string_dup3(other->s);
721 constant_t* constant_fromindex(pool_t*pool, int index, int type)
724 /* even for nonvalued constants (like TRUE/FALSE etc.), a nonzero
725 index is present to indicate that a type is coming */
730 if(NS_TYPE(c->type)) {
731 c->ns = namespace_clone(pool_lookup_namespace(pool, index));
732 } else if(c->type == CONSTANT_INT) {
733 c->i = pool_lookup_int(pool, index);
734 } else if(c->type == CONSTANT_UINT) {
735 c->u = pool_lookup_uint(pool, index);
736 } else if(c->type == CONSTANT_FLOAT) {
737 c->f = pool_lookup_float(pool, index);
738 } else if(c->type == CONSTANT_STRING) {
739 string_t s = pool_lookup_string2(pool, index);
740 c->s = string_dup3(&s);
741 } else if(UNIQUE_CONSTANT(c->type)) {
744 fprintf(stderr, "invalid constant type %02x\n", c->type);
748 char* constant_tostring(constant_t*c)
751 return strdup("NULL");
753 if(NS_TYPE(c->type)) {
754 return namespace_tostring(c->ns);
755 } else if(c->type == CONSTANT_INT) {
756 sprintf(buf, "%d", c->i);
758 } else if(c->type == CONSTANT_UINT) {
759 sprintf(buf, "%u", c->u);
761 } else if(c->type == CONSTANT_FLOAT) {
763 sprintf(buf, "%f", c->f);
765 } else if(c->type == CONSTANT_STRING) {
766 /* should we escape the string? \0 bytes won't be printed */
767 return strdup_n(c->s->str,c->s->len);
768 } else if(c->type == CONSTANT_TRUE) {
769 return strdup("true");
770 } else if(c->type == CONSTANT_FALSE) {
771 return strdup("false");
772 } else if(c->type == CONSTANT_NULL) {
773 return strdup("null");
774 } else if(c->type == CONSTANT_UNDEFINED) {
775 return strdup("undefined");
777 fprintf(stderr, "invalid constant type %02x\n", c->type);
781 char constant_has_index(constant_t*c)
785 return !UNIQUE_CONSTANT(c->type);
787 int constant_get_index(pool_t*pool, constant_t*c)
791 if(NS_TYPE(c->type)) {
793 /*if(c->type!=c->ns->access) {
794 printf("%02x<->%02x\n", c->type, c->ns->access);
796 assert(c->type == c->ns->access);
797 return pool_register_namespace(pool, c->ns);
798 } else if(c->type == CONSTANT_INT) {
799 return pool_register_int(pool, c->i);
800 } else if(c->type == CONSTANT_UINT) {
801 return pool_register_uint(pool, c->u);
802 } else if(c->type == CONSTANT_FLOAT) {
803 return pool_register_float(pool, c->f);
804 } else if(c->type == CONSTANT_STRING) {
805 return pool_register_string2(pool, c->s);
806 } else if(c->type == CONSTANT_UNDEFINED) {
807 /* write undefined with index 0 (and no type). Otherwise, the FlashPlayer
808 seems to throw an "attempt to read out of bounds" exception */
810 } else if(!constant_has_index(c)) {
813 fprintf(stderr, "invalid constant type %02x\n", c->type);
817 void constant_free(constant_t*c)
821 if(c->type == CONSTANT_STRING) {
823 } else if (NS_TYPE(c->type)) {
824 namespace_destroy(c->ns);c->ns=0;
828 // --------------------------- optimizing -----------------------------------
830 static int array_append_or_increase(array_t*array, void*key)
832 int pos = array_find(array, key);
834 array->d[pos].data++;
837 return array_append(array, key, 0);
840 static int compare_arrayentry(const void*_c1, const void*_c2)
842 const array_entry_t*c1 = _c1;
843 const array_entry_t*c2 = _c2;
844 return c2->data - c1->data;
847 static void* nodup(const void*o) {return (void*)o;}
849 static void reshuffle_array(array_t*array)
851 qsort(array->d+1, array->num-1, sizeof(array->d[0]), compare_arrayentry);
852 type_t* old_type = array->entry2pos->key_type;
853 type_t old_type_nodup = *old_type;
854 old_type_nodup.dup = nodup;
855 dict_t*d = dict_new2(&old_type_nodup);
856 dict_destroy_shallow(array->entry2pos);
857 array->entry2pos = d;
859 for(t=0;t<array->num;t++) {
860 dict_put(array->entry2pos, array->d[t].name, (void*)(ptroff_t)(t+1));
862 d->key_type = old_type;
866 // ------------------------------- pool -------------------------------------
868 int pool_register_uint(pool_t*p, unsigned int i)
870 int pos = array_append_or_increase(p->x_uints, &i);
874 int pool_register_int(pool_t*p, int i)
876 int pos = array_append_or_increase(p->x_ints, &i);
880 int pool_register_float(pool_t*p, double d)
882 int pos = array_append_or_increase(p->x_floats, &d);
886 int pool_register_string(pool_t*pool, const char*str)
889 string_t s = string_new2(str);
890 int pos = array_append_or_increase(pool->x_strings, &s);
894 int pool_register_string2(pool_t*pool, string_t*s)
896 if(!s || !s->str) return 0;
897 int pos = array_append_or_increase(pool->x_strings, s);
901 int pool_register_namespace(pool_t*pool, namespace_t*ns)
904 int pos = array_append_or_increase(pool->x_namespaces, ns);
908 int pool_register_namespace_set(pool_t*pool, namespace_set_t*set)
911 int pos = array_append_or_increase(pool->x_namespace_sets, set);
915 int pool_register_multiname(pool_t*pool, multiname_t*n)
918 int pos = array_append_or_increase(pool->x_multinames, n);
922 int pool_register_multiname2(pool_t*pool, char*name)
925 multiname_t*n = multiname_fromstring(name);
926 int pos = array_append_or_increase(pool->x_multinames, n);
927 multiname_destroy(n);
933 int pool_find_uint(pool_t*pool, unsigned int x)
935 int i = array_find(pool->x_uints, &x);
937 fprintf(stderr, "Couldn't find uint \"%d\" in constant pool\n", x);
942 int pool_find_int(pool_t*pool, int x)
944 int i = array_find(pool->x_ints, &x);
946 fprintf(stderr, "Couldn't find int \"%d\" in constant pool\n", x);
951 int pool_find_float(pool_t*pool, double x)
953 int i = array_find(pool->x_ints, &x);
955 fprintf(stderr, "Couldn't find int \"%d\" in constant pool\n", x);
960 int pool_find_namespace(pool_t*pool, namespace_t*ns)
964 int i = array_find(pool->x_namespaces, ns);
966 char*s = namespace_tostring(ns);
967 fprintf(stderr, "Couldn't find namespace \"%s\" %08x in constant pool\n", s, ns);
973 int pool_find_namespace_set(pool_t*pool, namespace_set_t*set)
977 int i = array_find(pool->x_namespace_sets, set);
979 char*s = namespace_set_tostring(set);
980 fprintf(stderr, "Couldn't find namespace_set \"%s\" in constant pool\n", s);
986 int pool_find_string(pool_t*pool, const char*str)
990 string_t s = string_new2(str);
991 int i = array_find(pool->x_strings, &s);
993 fprintf(stderr, "Couldn't find string \"%s\" in constant pool\n", s);
998 int pool_find_multiname(pool_t*pool, multiname_t*name)
1002 int i = array_find(pool->x_multinames, name);
1004 char*s = multiname_tostring(name);
1005 fprintf(stderr, "Couldn't find multiname \"%s\" in constant pool\n", s);
1012 int pool_lookup_int(pool_t*pool, int i)
1015 return *(int*)array_getkey(pool->x_ints, i);
1017 unsigned int pool_lookup_uint(pool_t*pool, int i)
1020 return *(unsigned int*)array_getkey(pool->x_uints, i);
1022 double pool_lookup_float(pool_t*pool, int i)
1024 if(!i) return __builtin_nan("");
1025 return *(double*)array_getkey(pool->x_floats, i);
1027 const char*pool_lookup_string(pool_t*pool, int i)
1029 string_t*s = array_getkey(pool->x_strings, i);
1033 string_t pool_lookup_string2(pool_t*pool, int i)
1035 string_t*s = array_getkey(pool->x_strings, i);
1038 namespace_t*pool_lookup_namespace(pool_t*pool, int i)
1040 return (namespace_t*)array_getkey(pool->x_namespaces, i);
1042 namespace_set_t*pool_lookup_namespace_set(pool_t*pool, int i)
1044 return (namespace_set_t*)array_getkey(pool->x_namespace_sets, i);
1046 multiname_t*pool_lookup_multiname(pool_t*pool, int i)
1048 return (multiname_t*)array_getkey(pool->x_multinames, i);
1055 p->x_ints = array_new2(&uint_type);
1056 p->x_uints = array_new2(&uint_type);
1057 p->x_floats = array_new2(&float_type);
1058 p->x_strings = array_new2(&stringstruct_type);
1059 p->x_namespaces = array_new2(&namespace_type);
1060 p->x_namespace_sets = array_new2(&namespace_set_type);
1061 p->x_multinames = array_new2(&multiname_type);
1063 /* add a zero-index entry in each list */
1065 array_append(p->x_ints, 0, 0);
1066 array_append(p->x_uints, 0, 0);
1067 array_append(p->x_floats, 0, 0);
1068 array_append(p->x_strings, 0, 0);
1069 array_append(p->x_namespaces, 0, 0);
1070 array_append(p->x_namespace_sets, 0, 0);
1071 array_append(p->x_multinames, 0, 0);
1075 void pool_optimize(pool_t*p)
1077 reshuffle_array(p->x_ints);
1078 reshuffle_array(p->x_uints);
1079 reshuffle_array(p->x_floats);
1080 reshuffle_array(p->x_strings);
1081 reshuffle_array(p->x_namespaces);
1082 reshuffle_array(p->x_namespace_sets);
1083 reshuffle_array(p->x_multinames);
1089 void pool_read(pool_t*pool, TAG*tag)
1091 int num_ints = swf_GetU30(tag);
1092 DEBUG printf("%d ints\n", num_ints);
1094 for(t=1;t<num_ints;t++) {
1095 S32 v = swf_GetABCS32(tag);
1096 DEBUG printf("int %d) %d\n", t, v);
1097 array_append(pool->x_ints, &v, 0);
1100 int num_uints = swf_GetU30(tag);
1101 DEBUG printf("%d uints\n", num_uints);
1102 for(t=1;t<num_uints;t++) {
1103 U32 v = swf_GetABCU32(tag);
1104 DEBUG printf("uint %d) %d\n", t, v);
1105 array_append(pool->x_uints, &v, 0);
1108 int num_floats = swf_GetU30(tag);
1109 DEBUG printf("%d floats\n", num_floats);
1110 for(t=1;t<num_floats;t++) {
1111 double d = swf_GetD64(tag);
1112 DEBUG printf("float %d) %f\n", t, d);
1113 array_append(pool->x_floats, &d, 0);
1116 int num_strings = swf_GetU30(tag);
1117 DEBUG printf("%d strings\n", num_strings);
1118 for(t=1;t<num_strings;t++) {
1119 int len = swf_GetU30(tag);
1120 string_t s = string_new((char*)&tag->data[tag->pos], len);
1121 swf_GetBlock(tag, 0, len);
1122 array_append(pool->x_strings, &s, 0);
1123 DEBUG printf("%d) \"%s\"\n", t, ((string_t*)array_getkey(pool->x_strings, t))->str);
1125 int num_namespaces = swf_GetU30(tag);
1126 DEBUG printf("%d namespaces\n", num_namespaces);
1127 for(t=1;t<num_namespaces;t++) {
1128 U8 type = swf_GetU8(tag);
1129 int namenr = swf_GetU30(tag);
1130 const char*name = 0;
1132 name = pool_lookup_string(pool, namenr);
1133 namespace_t*ns = namespace_new(type, name);
1134 array_append(pool->x_namespaces, ns, 0);
1135 DEBUG printf("%d) %02x \"%s\"\n", t, type, namespace_tostring(ns));
1136 namespace_destroy(ns);
1138 int num_sets = swf_GetU30(tag);
1139 DEBUG printf("%d namespace sets\n", num_sets);
1140 for(t=1;t<num_sets;t++) {
1141 int count = swf_GetU30(tag);
1144 NEW(namespace_set_t, nsset);
1145 for(s=0;s<count;s++) {
1146 int nsnr = swf_GetU30(tag);
1148 fprintf(stderr, "Zero entry in namespace set\n");
1149 namespace_t*ns = (namespace_t*)array_getkey(pool->x_namespaces, nsnr);
1150 list_append(nsset->namespaces, namespace_clone(ns));
1152 array_append(pool->x_namespace_sets, nsset, 0);
1153 DEBUG printf("set %d) %s\n", t, namespace_set_tostring(nsset));
1154 namespace_set_destroy(nsset);
1157 int num_multinames = swf_GetU30(tag);
1158 DEBUG printf("%d multinames\n", num_multinames);
1159 for(t=1;t<num_multinames;t++) {
1161 memset(&m, 0, sizeof(multiname_t));
1165 printf("0x%02x ", tag->data[tag->pos+s]);
1168 m.type = swf_GetU8(tag);
1169 if(m.type==0x07 || m.type==0x0d) {
1170 int namespace_index = swf_GetU30(tag);
1171 m.ns = (namespace_t*)array_getkey(pool->x_namespaces, namespace_index);
1173 fprintf(stderr, "Error: Illegal reference to namespace #%d in constant pool.\n", namespace_index);
1175 int name_index = swf_GetU30(tag);
1176 if(name_index) // 0 = '*' (any)
1177 m.name = pool_lookup_string(pool, name_index);
1178 } else if(m.type==0x0f || m.type==0x10) {
1179 int name_index = swf_GetU30(tag);
1180 if(name_index) // 0 = '*' (any name)
1181 m.name = pool_lookup_string(pool, name_index);
1182 } else if(m.type==0x11 || m.type==0x12) {
1183 } else if(m.type==0x09 || m.type==0x0e) {
1184 int name_index = swf_GetU30(tag);
1185 int namespace_set_index = swf_GetU30(tag);
1187 m.name = pool_lookup_string(pool, name_index);
1188 m.namespace_set = (namespace_set_t*)array_getkey(pool->x_namespace_sets, namespace_set_index);
1189 } else if(m.type==0x1b || m.type==0x1c) {
1190 int namespace_set_index = swf_GetU30(tag);
1191 m.namespace_set = (namespace_set_t*)array_getkey(pool->x_namespace_sets, namespace_set_index);
1192 } else if(m.type==0x1d) {
1193 int v1 = swf_GetU30(tag); //multiname
1194 int v2 = swf_GetU30(tag); //counter?
1195 int v3 = swf_GetU30(tag); //multiname
1196 // e.g. Vector<int> ... we only store the parent object
1197 m = *(multiname_t*)array_getkey(pool->x_multinames, v1);
1199 printf("can't parse type %d multinames yet\n", m.type);
1201 DEBUG printf("multiname %d) %s\n", t, multiname_tostring(&m));
1202 array_append(pool->x_multinames, &m, 0);
1206 void pool_dump(pool_t*pool, FILE*fo, char flags)
1209 fprintf(fo, "%d integers\n", pool->x_ints->num);
1210 for(t=1;t<pool->x_ints->num;t++) {
1211 S32 val = *(int*)array_getkey(pool->x_ints, t);
1212 int freq = (int)(ptroff_t)array_getvalue(pool->x_ints, t);
1213 if(flags&1) fprintf(fo, "%5d %d) %d\n", freq, t, val);
1215 fprintf(fo, "%d unsigned integers\n", pool->x_uints->num);
1216 for(t=1;t<pool->x_uints->num;t++) {
1217 U32 val = *(unsigned int*)array_getkey(pool->x_uints, t);
1218 int freq = (int)(ptroff_t)array_getvalue(pool->x_uints, t);
1219 if(flags&1) fprintf(fo, "%5d %d) %d\n", freq, t, val);
1221 fprintf(fo, "%d floats\n", pool->x_floats->num);
1222 for(t=1;t<pool->x_floats->num;t++) {
1223 double d = pool_lookup_float(pool, t);
1224 int freq = (int)(ptroff_t)array_getvalue(pool->x_floats, t);
1225 if(flags&2) fprintf(fo, "%5d %d) %f\n", freq, t, d);
1227 fprintf(fo, "%d strings\n", pool->x_strings->num);
1228 for(t=1;t<pool->x_strings->num;t++) {
1229 string_t str = pool_lookup_string2(pool, t);
1230 int freq = (int)(ptroff_t)array_getvalue(pool->x_strings, t);
1231 if(flags&1) fprintf(fo, "%5d %d) ", freq, t);
1232 if(flags&1) fwrite(str.str, str.len, 1, fo);
1233 if(flags&1) fprintf(fo, "\n", t);
1235 fprintf(fo, "%d namespaces\n", pool->x_namespaces->num);
1236 for(t=1;t<pool->x_namespaces->num;t++) {
1237 namespace_t*ns= (namespace_t*)array_getkey(pool->x_namespaces, t);
1238 char*s = namespace_tostring(ns);
1239 int freq = (int)(ptroff_t)array_getvalue(pool->x_namespaces, t);
1240 if(flags&1) fprintf(fo, "%5d %d) %s\n", freq, t, s);
1243 fprintf(fo, "%d namespace sets\n", pool->x_namespace_sets->num);
1244 for(t=1;t<pool->x_namespace_sets->num;t++) {
1245 namespace_set_t*set = (namespace_set_t*)array_getkey(pool->x_namespace_sets, t);
1246 char*s = namespace_set_tostring(set);
1247 int freq = (int)(ptroff_t)array_getvalue(pool->x_namespace_sets, t);
1248 if(flags&1) fprintf(fo, "%5d %d) %s\n", freq, t, s);
1252 fprintf(fo, "%d multinames\n", pool->x_multinames->num);
1253 for(t=1;t<pool->x_multinames->num;t++) {
1254 multiname_t*m = (multiname_t*)array_getkey(pool->x_multinames, t);
1255 char*s = multiname_tostring(m);
1256 int freq = (int)(ptroff_t)array_getvalue(pool->x_multinames, t);
1257 if(flags&1) fprintf(fo, "%5d %d) %s\n", freq, t, s);
1262 void pool_write(pool_t*pool, TAG*tag)
1266 /* make sure that all namespaces used by multinames / namespace sets
1267 and all strings used by namespaces exist */
1269 for(t=1;t<pool->x_multinames->num;t++) {
1270 multiname_t*m = (multiname_t*)array_getkey(pool->x_multinames, t);
1272 pool_register_namespace(pool, m->ns);
1274 if(m->namespace_set) {
1275 pool_register_namespace_set(pool, m->namespace_set);
1278 pool_register_string(pool, m->name);
1281 for(t=1;t<pool->x_namespace_sets->num;t++) {
1282 namespace_set_t*set = (namespace_set_t*)array_getkey(pool->x_namespace_sets, t);
1283 namespace_list_t*i = set->namespaces;
1285 pool_register_namespace(pool, i->namespace);
1289 for(t=1;t<pool->x_namespaces->num;t++) {
1290 namespace_t*ns= (namespace_t*)array_getkey(pool->x_namespaces, t);
1291 /* The spec says (page 22): "a value of zero denotes an empty string".
1292 However when actually using zero strings as empty namespaces, the
1293 flash player breaks.*/
1294 //if(ns->name && ns->name[0])
1295 pool_register_string(pool, ns->name);
1298 //pool_register_int(pool, 15);
1299 //pool_register_int(pool, 1);
1300 //pool_register_int(pool, 0);
1303 swf_SetU30(tag, pool->x_ints->num>1?pool->x_ints->num:0);
1304 for(t=1;t<pool->x_ints->num;t++) {
1305 S32 val = *(int*)array_getkey(pool->x_ints, t);
1306 swf_SetABCS32(tag, val);
1308 swf_SetU30(tag, pool->x_uints->num>1?pool->x_uints->num:0);
1309 for(t=1;t<pool->x_uints->num;t++) {
1310 swf_SetABCU32(tag, *(unsigned int*)array_getkey(pool->x_uints, t));
1312 swf_SetU30(tag, pool->x_floats->num>1?pool->x_floats->num:0);
1313 for(t=1;t<pool->x_floats->num;t++) {
1314 double d = pool_lookup_float(pool, t);
1317 swf_SetU30(tag, pool->x_strings->num>1?pool->x_strings->num:0);
1318 for(t=1;t<pool->x_strings->num;t++) {
1319 string_t str = pool_lookup_string2(pool, t);
1320 swf_SetU30String(tag, str.str, str.len);
1322 swf_SetU30(tag, pool->x_namespaces->num>1?pool->x_namespaces->num:0);
1323 for(t=1;t<pool->x_namespaces->num;t++) {
1324 namespace_t*ns= (namespace_t*)array_getkey(pool->x_namespaces, t);
1325 swf_SetU8(tag, ns->access);
1326 const char*name = ns->name;
1329 //if(name && name[0])
1330 i = pool_find_string(pool, name);
1334 swf_SetU30(tag, pool->x_namespace_sets->num>1?pool->x_namespace_sets->num:0);
1335 for(t=1;t<pool->x_namespace_sets->num;t++) {
1336 namespace_set_t*set = (namespace_set_t*)array_getkey(pool->x_namespace_sets, t);
1337 namespace_list_t*i = set->namespaces;
1338 int len = list_length(i);
1339 swf_SetU30(tag, len);
1341 int index = pool_find_namespace(pool, i->namespace);
1342 swf_SetU30(tag, index);
1347 swf_SetU30(tag, pool->x_multinames->num>1?pool->x_multinames->num:0);
1348 for(t=1;t<pool->x_multinames->num;t++) {
1349 multiname_t*m = (multiname_t*)array_getkey(pool->x_multinames, t);
1350 swf_SetU8(tag, m->type);
1353 assert(m->type==0x07 || m->type==0x0d);
1354 int i = pool_find_namespace(pool, m->ns);
1355 if(i<0) fprintf(stderr, "internal error: unregistered namespace %02x %s %s\n", m->ns->access, access2str(m->ns->access), m->ns->name);
1358 assert(m->type!=0x07 && m->type!=0x0d);
1361 assert(m->type==0x09 || m->type==0x0e || m->type==0x07 || m->type==0x0d || m->type==0x0f || m->type==0x10);
1362 int i = pool_find_string(pool, m->name);
1363 if(i<0) fprintf(stderr, "internal error: unregistered name\n");
1366 assert(m->type!=0x09 && m->type!=0x0e && m->type!=0x07 && m->type!=0x0d && m->type!=0x0f && m->type!=0x10);
1368 if(m->namespace_set) {
1369 assert(m->type==0x09 || m->type==0x0e || m->type==0x1c || m->type==0x1b);
1370 int i = pool_find_namespace_set(pool, m->namespace_set);
1371 if(i<0) fprintf(stderr, "internal error: unregistered namespace set\n");
1374 assert(m->type!=0x09 && m->type!=0x0e && m->type!=0x1c && m->type!=0x1b);
1380 void pool_destroy(pool_t*pool)
1383 array_free(pool->x_ints);
1384 array_free(pool->x_uints);
1385 array_free(pool->x_floats);
1386 array_free(pool->x_strings);
1387 array_free(pool->x_namespaces);
1388 array_free(pool->x_namespace_sets);
1389 array_free(pool->x_multinames);