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 NS_TYPE(x) ((x) == 0x08 || (x) == 0x16 || (x) == 0x17 || (x) == 0x18 || \
638 (x) == 0x19 || (x) == 0x1a || (x) == 0x05)
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(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_fromindex(pool_t*pool, int index, int type)
712 /* even for nonvalued constants (like TRUE/FALSE etc.), a nonzero
713 index is present to indicate that a type is coming */
718 if(NS_TYPE(c->type)) {
719 c->ns = namespace_clone(pool_lookup_namespace(pool, index));
720 } else if(c->type == CONSTANT_INT) {
721 c->i = pool_lookup_int(pool, index);
722 } else if(c->type == CONSTANT_UINT) {
723 c->u = pool_lookup_uint(pool, index);
724 } else if(c->type == CONSTANT_FLOAT) {
725 c->f = pool_lookup_float(pool, index);
726 } else if(c->type == CONSTANT_STRING) {
727 string_t s = pool_lookup_string2(pool, index);
728 c->s = string_dup3(&s);
729 } else if(UNIQUE_CONSTANT(c->type)) {
732 fprintf(stderr, "invalid constant type %02x\n", c->type);
736 char* constant_tostring(constant_t*c)
739 return strdup("NULL");
741 if(NS_TYPE(c->type)) {
742 return namespace_tostring(c->ns);
743 } else if(c->type == CONSTANT_INT) {
744 sprintf(buf, "%d", c->i);
746 } else if(c->type == CONSTANT_UINT) {
747 sprintf(buf, "%u", c->u);
749 } else if(c->type == CONSTANT_FLOAT) {
751 sprintf(buf, "%f", c->f);
753 } else if(c->type == CONSTANT_STRING) {
754 /* should we escape the string? \0 bytes won't be printed */
755 return strdup_n(c->s->str,c->s->len);
756 } else if(c->type == CONSTANT_TRUE) {
757 return strdup("true");
758 } else if(c->type == CONSTANT_FALSE) {
759 return strdup("false");
760 } else if(c->type == CONSTANT_NULL) {
761 return strdup("null");
762 } else if(c->type == CONSTANT_UNDEFINED) {
763 return strdup("undefined");
765 fprintf(stderr, "invalid constant type %02x\n", c->type);
769 char constant_has_index(constant_t*c)
773 return !UNIQUE_CONSTANT(c->type);
775 int constant_get_index(pool_t*pool, constant_t*c)
779 if(NS_TYPE(c->type)) {
781 /*if(c->type!=c->ns->access) {
782 printf("%02x<->%02x\n", c->type, c->ns->access);
784 assert(c->type == c->ns->access);
785 return pool_register_namespace(pool, c->ns);
786 } else if(c->type == CONSTANT_INT) {
787 return pool_register_int(pool, c->i);
788 } else if(c->type == CONSTANT_UINT) {
789 return pool_register_uint(pool, c->u);
790 } else if(c->type == CONSTANT_FLOAT) {
791 return pool_register_float(pool, c->f);
792 } else if(c->type == CONSTANT_STRING) {
793 return pool_register_string2(pool, c->s);
794 } else if(!constant_has_index(c)) {
797 fprintf(stderr, "invalid constant type %02x\n", c->type);
801 void constant_free(constant_t*c)
805 if(c->type == CONSTANT_STRING) {
807 } else if (NS_TYPE(c->type)) {
808 namespace_destroy(c->ns);c->ns=0;
812 // --------------------------- optimizing -----------------------------------
814 static int array_append_or_increase(array_t*array, void*key)
816 int pos = array_find(array, key);
818 array->d[pos].data++;
821 return array_append(array, key, 0);
824 static int compare_arrayentry(const void*_c1, const void*_c2)
826 const array_entry_t*c1 = _c1;
827 const array_entry_t*c2 = _c2;
828 return c2->data - c1->data;
831 static void* nodup(const void*o) {return (void*)o;}
833 static void reshuffle_array(array_t*array)
835 qsort(array->d+1, array->num-1, sizeof(array->d[0]), compare_arrayentry);
836 type_t* old_type = array->entry2pos->key_type;
837 type_t old_type_nodup = *old_type;
838 old_type_nodup.dup = nodup;
839 dict_t*d = dict_new2(&old_type_nodup);
840 dict_destroy_shallow(array->entry2pos);
841 array->entry2pos = d;
843 for(t=0;t<array->num;t++) {
844 dict_put(array->entry2pos, array->d[t].name, (void*)(ptroff_t)(t+1));
846 d->key_type = old_type;
850 // ------------------------------- pool -------------------------------------
852 int pool_register_uint(pool_t*p, unsigned int i)
854 int pos = array_append_or_increase(p->x_uints, &i);
858 int pool_register_int(pool_t*p, int i)
860 int pos = array_append_or_increase(p->x_ints, &i);
864 int pool_register_float(pool_t*p, double d)
866 int pos = array_append_or_increase(p->x_floats, &d);
870 int pool_register_string(pool_t*pool, const char*str)
873 string_t s = string_new2(str);
874 int pos = array_append_or_increase(pool->x_strings, &s);
878 int pool_register_string2(pool_t*pool, string_t*s)
880 if(!s || !s->str) return 0;
881 int pos = array_append_or_increase(pool->x_strings, s);
885 int pool_register_namespace(pool_t*pool, namespace_t*ns)
888 int pos = array_append_or_increase(pool->x_namespaces, ns);
892 int pool_register_namespace_set(pool_t*pool, namespace_set_t*set)
895 int pos = array_append_or_increase(pool->x_namespace_sets, set);
899 int pool_register_multiname(pool_t*pool, multiname_t*n)
902 int pos = array_append_or_increase(pool->x_multinames, n);
906 int pool_register_multiname2(pool_t*pool, char*name)
909 multiname_t*n = multiname_fromstring(name);
910 int pos = array_append_or_increase(pool->x_multinames, n);
911 multiname_destroy(n);
917 int pool_find_uint(pool_t*pool, unsigned int x)
919 int i = array_find(pool->x_uints, &x);
921 fprintf(stderr, "Couldn't find uint \"%d\" in constant pool\n", x);
926 int pool_find_int(pool_t*pool, int x)
928 int i = array_find(pool->x_ints, &x);
930 fprintf(stderr, "Couldn't find int \"%d\" in constant pool\n", x);
935 int pool_find_float(pool_t*pool, double 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_namespace(pool_t*pool, namespace_t*ns)
948 int i = array_find(pool->x_namespaces, ns);
950 char*s = namespace_tostring(ns);
951 fprintf(stderr, "Couldn't find namespace \"%s\" %08x in constant pool\n", s, ns);
957 int pool_find_namespace_set(pool_t*pool, namespace_set_t*set)
961 int i = array_find(pool->x_namespace_sets, set);
963 char*s = namespace_set_tostring(set);
964 fprintf(stderr, "Couldn't find namespace_set \"%s\" in constant pool\n", s);
970 int pool_find_string(pool_t*pool, const char*str)
974 string_t s = string_new2(str);
975 int i = array_find(pool->x_strings, &s);
977 fprintf(stderr, "Couldn't find string \"%s\" in constant pool\n", s);
982 int pool_find_multiname(pool_t*pool, multiname_t*name)
986 int i = array_find(pool->x_multinames, name);
988 char*s = multiname_tostring(name);
989 fprintf(stderr, "Couldn't find multiname \"%s\" in constant pool\n", s);
996 int pool_lookup_int(pool_t*pool, int i)
999 return *(int*)array_getkey(pool->x_ints, i);
1001 unsigned int pool_lookup_uint(pool_t*pool, int i)
1004 return *(unsigned int*)array_getkey(pool->x_uints, i);
1006 double pool_lookup_float(pool_t*pool, int i)
1008 if(!i) return __builtin_nan("");
1009 return *(double*)array_getkey(pool->x_floats, i);
1011 const char*pool_lookup_string(pool_t*pool, int i)
1013 string_t*s = array_getkey(pool->x_strings, i);
1017 string_t pool_lookup_string2(pool_t*pool, int i)
1019 string_t*s = array_getkey(pool->x_strings, i);
1022 namespace_t*pool_lookup_namespace(pool_t*pool, int i)
1024 return (namespace_t*)array_getkey(pool->x_namespaces, i);
1026 namespace_set_t*pool_lookup_namespace_set(pool_t*pool, int i)
1028 return (namespace_set_t*)array_getkey(pool->x_namespace_sets, i);
1030 multiname_t*pool_lookup_multiname(pool_t*pool, int i)
1032 return (multiname_t*)array_getkey(pool->x_multinames, i);
1039 p->x_ints = array_new2(&uint_type);
1040 p->x_uints = array_new2(&uint_type);
1041 p->x_floats = array_new2(&float_type);
1042 p->x_strings = array_new2(&stringstruct_type);
1043 p->x_namespaces = array_new2(&namespace_type);
1044 p->x_namespace_sets = array_new2(&namespace_set_type);
1045 p->x_multinames = array_new2(&multiname_type);
1047 /* add a zero-index entry in each list */
1049 array_append(p->x_ints, 0, 0);
1050 array_append(p->x_uints, 0, 0);
1051 array_append(p->x_floats, 0, 0);
1052 array_append(p->x_strings, 0, 0);
1053 array_append(p->x_namespaces, 0, 0);
1054 array_append(p->x_namespace_sets, 0, 0);
1055 array_append(p->x_multinames, 0, 0);
1059 void pool_optimize(pool_t*p)
1061 reshuffle_array(p->x_ints);
1062 reshuffle_array(p->x_uints);
1063 reshuffle_array(p->x_floats);
1064 reshuffle_array(p->x_strings);
1065 reshuffle_array(p->x_namespaces);
1066 reshuffle_array(p->x_namespace_sets);
1067 reshuffle_array(p->x_multinames);
1073 void pool_read(pool_t*pool, TAG*tag)
1075 int num_ints = swf_GetU30(tag);
1076 DEBUG printf("%d ints\n", num_ints);
1078 for(t=1;t<num_ints;t++) {
1079 S32 v = swf_GetABCS32(tag);
1080 DEBUG printf("int %d) %d\n", t, v);
1081 array_append(pool->x_ints, &v, 0);
1084 int num_uints = swf_GetU30(tag);
1085 DEBUG printf("%d uints\n", num_uints);
1086 for(t=1;t<num_uints;t++) {
1087 U32 v = swf_GetABCU32(tag);
1088 DEBUG printf("uint %d) %d\n", t, v);
1089 array_append(pool->x_uints, &v, 0);
1092 int num_floats = swf_GetU30(tag);
1093 DEBUG printf("%d floats\n", num_floats);
1094 for(t=1;t<num_floats;t++) {
1095 double d = swf_GetD64(tag);
1096 DEBUG printf("float %d) %f\n", t, d);
1097 array_append(pool->x_floats, &d, 0);
1100 int num_strings = swf_GetU30(tag);
1101 DEBUG printf("%d strings\n", num_strings);
1102 for(t=1;t<num_strings;t++) {
1103 int len = swf_GetU30(tag);
1104 string_t s = string_new(&tag->data[tag->pos], len);
1105 swf_GetBlock(tag, 0, len);
1106 array_append(pool->x_strings, &s, 0);
1107 DEBUG printf("%d) \"%s\"\n", t, ((string_t*)array_getkey(pool->x_strings, t))->str);
1109 int num_namespaces = swf_GetU30(tag);
1110 DEBUG printf("%d namespaces\n", num_namespaces);
1111 for(t=1;t<num_namespaces;t++) {
1112 U8 type = swf_GetU8(tag);
1113 int namenr = swf_GetU30(tag);
1114 const char*name = 0;
1116 name = pool_lookup_string(pool, namenr);
1117 namespace_t*ns = namespace_new(type, name);
1118 array_append(pool->x_namespaces, ns, 0);
1119 DEBUG printf("%d) %02x \"%s\"\n", t, type, namespace_tostring(ns));
1120 namespace_destroy(ns);
1122 int num_sets = swf_GetU30(tag);
1123 DEBUG printf("%d namespace sets\n", num_sets);
1124 for(t=1;t<num_sets;t++) {
1125 int count = swf_GetU30(tag);
1128 NEW(namespace_set_t, nsset);
1129 for(s=0;s<count;s++) {
1130 int nsnr = swf_GetU30(tag);
1132 fprintf(stderr, "Zero entry in namespace set\n");
1133 namespace_t*ns = (namespace_t*)array_getkey(pool->x_namespaces, nsnr);
1134 list_append(nsset->namespaces, namespace_clone(ns));
1136 array_append(pool->x_namespace_sets, nsset, 0);
1137 DEBUG printf("set %d) %s\n", t, namespace_set_tostring(nsset));
1138 namespace_set_destroy(nsset);
1141 int num_multinames = swf_GetU30(tag);
1142 DEBUG printf("%d multinames\n", num_multinames);
1143 for(t=1;t<num_multinames;t++) {
1145 memset(&m, 0, sizeof(multiname_t));
1149 printf("0x%02x ", tag->data[tag->pos+s]);
1152 m.type = swf_GetU8(tag);
1153 if(m.type==0x07 || m.type==0x0d) {
1154 int namespace_index = swf_GetU30(tag);
1155 m.ns = (namespace_t*)array_getkey(pool->x_namespaces, namespace_index);
1156 int name_index = swf_GetU30(tag);
1157 if(name_index) // 0 = '*' (any)
1158 m.name = pool_lookup_string(pool, name_index);
1159 } else if(m.type==0x0f || m.type==0x10) {
1160 int name_index = swf_GetU30(tag);
1161 if(name_index) // 0 = '*' (any name)
1162 m.name = pool_lookup_string(pool, name_index);
1163 } else if(m.type==0x11 || m.type==0x12) {
1164 } else if(m.type==0x09 || m.type==0x0e) {
1165 int name_index = swf_GetU30(tag);
1166 int namespace_set_index = swf_GetU30(tag);
1168 m.name = pool_lookup_string(pool, name_index);
1169 m.namespace_set = (namespace_set_t*)array_getkey(pool->x_namespace_sets, namespace_set_index);
1170 } else if(m.type==0x1b || m.type==0x1c) {
1171 int namespace_set_index = swf_GetU30(tag);
1172 m.namespace_set = (namespace_set_t*)array_getkey(pool->x_namespace_sets, namespace_set_index);
1173 } else if(m.type==0x1d) {
1174 int v1 = swf_GetU30(tag); //multiname
1175 int v2 = swf_GetU30(tag); //counter?
1176 int v3 = swf_GetU30(tag); //multiname
1177 // e.g. Vector<int> ... we only store the parent object
1178 m = *(multiname_t*)array_getkey(pool->x_multinames, v1);
1180 printf("can't parse type %d multinames yet\n", m.type);
1182 DEBUG printf("multiname %d) %s\n", t, multiname_tostring(&m));
1183 array_append(pool->x_multinames, &m, 0);
1187 void pool_dump(pool_t*pool, FILE*fo, char flags)
1190 fprintf(fo, "%d integers\n", pool->x_ints->num);
1191 for(t=1;t<pool->x_ints->num;t++) {
1192 S32 val = *(int*)array_getkey(pool->x_ints, t);
1193 int freq = (int)(ptroff_t)array_getvalue(pool->x_ints, t);
1194 if(flags&1) fprintf(fo, "%5d %d) %d\n", freq, t, val);
1196 fprintf(fo, "%d unsigned integers\n", pool->x_uints->num);
1197 for(t=1;t<pool->x_uints->num;t++) {
1198 U32 val = *(unsigned int*)array_getkey(pool->x_uints, t);
1199 int freq = (int)(ptroff_t)array_getvalue(pool->x_uints, t);
1200 if(flags&1) fprintf(fo, "%5d %d) %d\n", freq, t, val);
1202 fprintf(fo, "%d floats\n", pool->x_floats->num);
1203 for(t=1;t<pool->x_floats->num;t++) {
1204 double d = pool_lookup_float(pool, t);
1205 int freq = (int)(ptroff_t)array_getvalue(pool->x_floats, t);
1206 if(flags&2) fprintf(fo, "%5d %d) %f\n", freq, t, d);
1208 fprintf(fo, "%d strings\n", pool->x_strings->num);
1209 for(t=1;t<pool->x_strings->num;t++) {
1210 string_t str = pool_lookup_string2(pool, t);
1211 int freq = (int)(ptroff_t)array_getvalue(pool->x_strings, t);
1212 if(flags&1) fprintf(fo, "%5d %d) ", freq, t);
1213 if(flags&1) fwrite(str.str, str.len, 1, fo);
1214 if(flags&1) fprintf(fo, "\n", t);
1216 fprintf(fo, "%d namespaces\n", pool->x_namespaces->num);
1217 for(t=1;t<pool->x_namespaces->num;t++) {
1218 namespace_t*ns= (namespace_t*)array_getkey(pool->x_namespaces, t);
1219 char*s = namespace_tostring(ns);
1220 int freq = (int)(ptroff_t)array_getvalue(pool->x_namespaces, t);
1221 if(flags&1) fprintf(fo, "%5d %d) %s\n", freq, t, s);
1224 fprintf(fo, "%d namespace sets\n", pool->x_namespace_sets->num);
1225 for(t=1;t<pool->x_namespace_sets->num;t++) {
1226 namespace_set_t*set = (namespace_set_t*)array_getkey(pool->x_namespace_sets, t);
1227 char*s = namespace_set_tostring(set);
1228 int freq = (int)(ptroff_t)array_getvalue(pool->x_namespace_sets, t);
1229 if(flags&1) fprintf(fo, "%5d %d) %s\n", freq, t, s);
1233 fprintf(fo, "%d multinames\n", pool->x_multinames->num);
1234 for(t=1;t<pool->x_multinames->num;t++) {
1235 multiname_t*m = (multiname_t*)array_getkey(pool->x_multinames, t);
1236 char*s = multiname_tostring(m);
1237 int freq = (int)(ptroff_t)array_getvalue(pool->x_multinames, t);
1238 if(flags&1) fprintf(fo, "%5d %d) %s\n", freq, t, s);
1243 void pool_write(pool_t*pool, TAG*tag)
1247 /* make sure that all namespaces used by multinames / namespace sets
1248 and all strings used by namespaces exist */
1250 for(t=1;t<pool->x_multinames->num;t++) {
1251 multiname_t*m = (multiname_t*)array_getkey(pool->x_multinames, t);
1253 pool_register_namespace(pool, m->ns);
1255 if(m->namespace_set) {
1256 pool_register_namespace_set(pool, m->namespace_set);
1259 pool_register_string(pool, m->name);
1262 for(t=1;t<pool->x_namespace_sets->num;t++) {
1263 namespace_set_t*set = (namespace_set_t*)array_getkey(pool->x_namespace_sets, t);
1264 namespace_list_t*i = set->namespaces;
1266 pool_register_namespace(pool, i->namespace);
1270 for(t=1;t<pool->x_namespaces->num;t++) {
1271 namespace_t*ns= (namespace_t*)array_getkey(pool->x_namespaces, t);
1272 /* The spec says (page 22): "a value of zero denotes an empty string".
1273 However when actually using zero strings as empty namespaces, the
1274 flash player breaks.*/
1275 //if(ns->name && ns->name[0])
1276 pool_register_string(pool, ns->name);
1279 //pool_register_int(pool, 15);
1280 //pool_register_int(pool, 1);
1281 //pool_register_int(pool, 0);
1284 swf_SetU30(tag, pool->x_ints->num>1?pool->x_ints->num:0);
1285 for(t=1;t<pool->x_ints->num;t++) {
1286 S32 val = *(int*)array_getkey(pool->x_ints, t);
1287 swf_SetABCS32(tag, val);
1289 swf_SetU30(tag, pool->x_uints->num>1?pool->x_uints->num:0);
1290 for(t=1;t<pool->x_uints->num;t++) {
1291 swf_SetABCU32(tag, *(unsigned int*)array_getkey(pool->x_uints, t));
1293 swf_SetU30(tag, pool->x_floats->num>1?pool->x_floats->num:0);
1294 for(t=1;t<pool->x_floats->num;t++) {
1295 double d = pool_lookup_float(pool, t);
1298 swf_SetU30(tag, pool->x_strings->num>1?pool->x_strings->num:0);
1299 for(t=1;t<pool->x_strings->num;t++) {
1300 string_t str = pool_lookup_string2(pool, t);
1301 swf_SetU30String(tag, str.str, str.len);
1303 swf_SetU30(tag, pool->x_namespaces->num>1?pool->x_namespaces->num:0);
1304 for(t=1;t<pool->x_namespaces->num;t++) {
1305 namespace_t*ns= (namespace_t*)array_getkey(pool->x_namespaces, t);
1306 swf_SetU8(tag, ns->access);
1307 const char*name = ns->name;
1310 //if(name && name[0])
1311 i = pool_find_string(pool, name);
1315 swf_SetU30(tag, pool->x_namespace_sets->num>1?pool->x_namespace_sets->num:0);
1316 for(t=1;t<pool->x_namespace_sets->num;t++) {
1317 namespace_set_t*set = (namespace_set_t*)array_getkey(pool->x_namespace_sets, t);
1318 namespace_list_t*i = set->namespaces;
1319 int len = list_length(i);
1320 swf_SetU30(tag, len);
1322 int index = pool_find_namespace(pool, i->namespace);
1323 swf_SetU30(tag, index);
1328 swf_SetU30(tag, pool->x_multinames->num>1?pool->x_multinames->num:0);
1329 for(t=1;t<pool->x_multinames->num;t++) {
1330 multiname_t*m = (multiname_t*)array_getkey(pool->x_multinames, t);
1331 swf_SetU8(tag, m->type);
1334 assert(m->type==0x07 || m->type==0x0d);
1335 int i = pool_find_namespace(pool, m->ns);
1336 if(i<0) fprintf(stderr, "internal error: unregistered namespace %02x %s %s\n", m->ns->access, access2str(m->ns->access), m->ns->name);
1339 assert(m->type!=0x07 && m->type!=0x0d);
1342 assert(m->type==0x09 || m->type==0x0e || m->type==0x07 || m->type==0x0d || m->type==0x0f || m->type==0x10);
1343 int i = pool_find_string(pool, m->name);
1344 if(i<0) fprintf(stderr, "internal error: unregistered name\n");
1347 assert(m->type!=0x09 && m->type!=0x0e && m->type!=0x07 && m->type!=0x0d && m->type!=0x0f && m->type!=0x10);
1349 if(m->namespace_set) {
1350 assert(m->type==0x09 || m->type==0x0e || m->type==0x1c || m->type==0x1b);
1351 int i = pool_find_namespace_set(pool, m->namespace_set);
1352 if(i<0) fprintf(stderr, "internal error: unregistered namespace set\n");
1355 assert(m->type!=0x09 && m->type!=0x0e && m->type!=0x1c && m->type!=0x1b);
1361 void pool_destroy(pool_t*pool)
1364 array_free(pool->x_ints);
1365 array_free(pool->x_uints);
1366 array_free(pool->x_floats);
1367 array_free(pool->x_strings);
1368 array_free(pool->x_namespaces);
1369 array_free(pool->x_namespace_sets);
1370 array_free(pool->x_multinames);