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);
190 sprintf(string, "[%s]\"\"", access);
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";
490 else if(type==0x00) return "any";
492 fprintf(stderr, "Undefined access type %02x\n", type);
498 char multiname_late_namespace(multiname_t*m)
502 return (m->type==RTQNAME || m->type==RTQNAMEA ||
503 m->type==RTQNAMEL || m->type==RTQNAMELA);
506 char multiname_late_name(multiname_t*m)
510 return m->type==RTQNAMEL || m->type==RTQNAMELA ||
511 m->type==MULTINAMEL || m->type==MULTINAMELA;
514 char* multiname_tostring(multiname_t*m)
518 return strdup("NULL");
520 return strdup("--<MULTINAME 0xff>--");
522 char*name = m->name?escape_string(m->name):strdup("*");
523 int namelen = strlen(name);
525 if(m->type==QNAME || m->type==QNAMEA || m->type==POSTFIXTYPE) {
526 char*nsname = m->ns?escape_string(m->ns->name):strdup("NULL");
527 mname = malloc(strlen(nsname)+namelen+32);
529 if(m->type == QNAMEA)
530 strcat(mname, ",attr");
534 strcat(mname,access2str(m->ns->access));
537 strcat(mname, nsname);
541 } else if(m->type==RTQNAME || m->type==RTQNAMEA) {
542 mname = malloc(namelen+32);
543 strcpy(mname, "<rt");
544 if(m->type == RTQNAMEA)
545 strcat(mname, ",attr");
548 } else if(m->type==RTQNAMEL) {
549 mname = strdup("<rt,l>");
550 } else if(m->type==RTQNAMELA) {
551 mname = strdup("<rt,l,attr>");
552 } else if(m->type==MULTINAME || m->type==MULTINAMEA) {
553 char*s = namespace_set_tostring(m->namespace_set);
554 mname = malloc(strlen(s)+namelen+16);
555 if(m->type == MULTINAME)
556 strcpy(mname,"<multi>");
558 strcpy(mname,"<multi,attr>");
563 } else if(m->type==MULTINAMEL || m->type==MULTINAMELA) {
564 char*s = namespace_set_tostring(m->namespace_set);
565 mname = malloc(strlen(s)+16);
566 if(m->type == MULTINAMEL)
567 strcpy(mname,"<l,multi>");
569 strcpy(mname,"<l,multi,attr>");
573 return strdup("<invalid>");
579 multiname_t* multiname_fromstring(const char*name2)
583 char*n = strdup(name2);
584 char*p = strstr(n, "::");
585 char*namespace=0,*name=0;
588 fprintf(stderr, "Error: single ':' in name\n");
596 if(strchr(namespace, ':')) {
597 fprintf(stderr, "Error: single ':' in namespace\n");
599 if(strchr(name, ':')) {
600 fprintf(stderr, "Error: single ':' in qualified name\n");
604 multiname_t*m = malloc(sizeof(multiname_t));
605 memset(m, 0, sizeof(multiname_t));
607 m->namespace_set = 0;
608 m->ns = namespace_fromstring(namespace);
609 m->name = name?strdup(name):0;
614 void multiname_destroy(multiname_t*m)
618 free((void*)m->name);m->name = 0;
621 namespace_destroy(m->ns);m->ns = 0;
623 if(m->namespace_set) {
624 namespace_set_destroy(m->namespace_set);m->namespace_set = 0;
631 type_t multiname_type = {
632 dup: (dup_func)multiname_clone,
633 hash: (hash_func)multiname_hash,
634 free: (free_func)multiname_destroy,
635 equals: (equals_func)multiname_equals
639 // ------------------------------- constants -------------------------------------
641 #define UNIQUE_CONSTANT(x) ((x) == CONSTANT_TRUE || (x) == CONSTANT_FALSE || (x) == CONSTANT_NULL || (x) == CONSTANT_UNDEFINED)
643 constant_t* constant_new_int(int i)
647 c->type = CONSTANT_INT;
650 constant_t* constant_new_uint(unsigned int u)
654 c->type = CONSTANT_UINT;
657 constant_t* constant_new_float(double f)
661 c->type = CONSTANT_FLOAT;
664 constant_t* constant_new_string(const char*s)
667 c->s = string_new4(s);
668 c->type = CONSTANT_STRING;
671 constant_t* constant_new_string2(const char*s, int len)
674 c->s = string_new3(s, len);
675 c->type = CONSTANT_STRING;
678 constant_t* constant_new_namespace(namespace_t*ns)
681 c->ns = namespace_clone(ns);
682 c->type = ns->access;
683 assert(NS_TYPE(c->type));
686 constant_t* constant_new_true()
689 c->type = CONSTANT_TRUE;
692 constant_t* constant_new_false()
695 c->type = CONSTANT_FALSE;
698 constant_t* constant_new_null()
701 c->type = CONSTANT_NULL;
704 constant_t* constant_new_undefined()
707 c->type = CONSTANT_UNDEFINED;
710 constant_t* constant_clone(constant_t*other)
713 constant_t*c = malloc(sizeof(constant_t));
714 memcpy(c, other, sizeof(constant_t));
715 if(NS_TYPE(c->type)) {
716 c->ns = namespace_clone(other->ns);
717 } else if(c->type == CONSTANT_STRING) {
718 c->s = string_dup3(other->s);
722 constant_t* constant_fromindex(pool_t*pool, int index, int type)
725 /* even for nonvalued constants (like TRUE/FALSE etc.), a nonzero
726 index is present to indicate that a type is coming */
731 if(NS_TYPE(c->type)) {
732 c->ns = namespace_clone(pool_lookup_namespace(pool, index));
733 } else if(c->type == CONSTANT_INT) {
734 c->i = pool_lookup_int(pool, index);
735 } else if(c->type == CONSTANT_UINT) {
736 c->u = pool_lookup_uint(pool, index);
737 } else if(c->type == CONSTANT_FLOAT) {
738 c->f = pool_lookup_float(pool, index);
739 } else if(c->type == CONSTANT_STRING) {
740 string_t s = pool_lookup_string2(pool, index);
741 c->s = string_dup3(&s);
742 } else if(UNIQUE_CONSTANT(c->type)) {
745 fprintf(stderr, "invalid constant type %02x\n", c->type);
749 char* constant_tostring(constant_t*c)
752 return strdup("NULL");
754 if(NS_TYPE(c->type)) {
755 return namespace_tostring(c->ns);
756 } else if(c->type == CONSTANT_INT) {
757 sprintf(buf, "%d", c->i);
759 } else if(c->type == CONSTANT_UINT) {
760 sprintf(buf, "%u", c->u);
762 } else if(c->type == CONSTANT_FLOAT) {
764 sprintf(buf, "%f", c->f);
766 } else if(c->type == CONSTANT_STRING) {
767 /* should we escape the string? \0 bytes won't be printed */
768 return strdup_n(c->s->str,c->s->len);
769 } else if(c->type == CONSTANT_TRUE) {
770 return strdup("true");
771 } else if(c->type == CONSTANT_FALSE) {
772 return strdup("false");
773 } else if(c->type == CONSTANT_NULL) {
774 return strdup("null");
775 } else if(c->type == CONSTANT_UNDEFINED) {
776 return strdup("undefined");
778 fprintf(stderr, "invalid constant type %02x\n", c->type);
782 char constant_has_index(constant_t*c)
786 return !UNIQUE_CONSTANT(c->type);
788 int constant_get_index(pool_t*pool, constant_t*c)
792 if(NS_TYPE(c->type)) {
794 /*if(c->type!=c->ns->access) {
795 printf("%02x<->%02x\n", c->type, c->ns->access);
797 assert(c->type == c->ns->access);
798 return pool_register_namespace(pool, c->ns);
799 } else if(c->type == CONSTANT_INT) {
800 return pool_register_int(pool, c->i);
801 } else if(c->type == CONSTANT_UINT) {
802 return pool_register_uint(pool, c->u);
803 } else if(c->type == CONSTANT_FLOAT) {
804 return pool_register_float(pool, c->f);
805 } else if(c->type == CONSTANT_STRING) {
806 return pool_register_string2(pool, c->s);
807 } else if(c->type == CONSTANT_UNDEFINED) {
808 /* write undefined with index 0 (and no type). Otherwise, the FlashPlayer
809 seems to throw an "attempt to read out of bounds" exception */
811 } else if(!constant_has_index(c)) {
814 fprintf(stderr, "invalid constant type %02x\n", c->type);
818 void constant_free(constant_t*c)
822 if(c->type == CONSTANT_STRING) {
824 } else if (NS_TYPE(c->type)) {
825 namespace_destroy(c->ns);c->ns=0;
829 // --------------------------- optimizing -----------------------------------
831 static int array_append_or_increase(array_t*array, void*key)
833 int pos = array_find(array, key);
835 array->d[pos].data++;
838 return array_append(array, key, 0);
841 static int compare_arrayentry(const void*_c1, const void*_c2)
843 const array_entry_t*c1 = _c1;
844 const array_entry_t*c2 = _c2;
845 return c2->data - c1->data;
848 static void* nodup(const void*o) {return (void*)o;}
850 static void reshuffle_array(array_t*array)
852 qsort(array->d+1, array->num-1, sizeof(array->d[0]), compare_arrayentry);
853 type_t* old_type = array->entry2pos->key_type;
854 type_t old_type_nodup = *old_type;
855 old_type_nodup.dup = nodup;
856 dict_t*d = dict_new2(&old_type_nodup);
857 dict_destroy_shallow(array->entry2pos);
858 array->entry2pos = d;
860 for(t=0;t<array->num;t++) {
861 dict_put(array->entry2pos, array->d[t].name, (void*)(ptroff_t)(t+1));
863 d->key_type = old_type;
867 // ------------------------------- pool -------------------------------------
869 int pool_register_uint(pool_t*p, unsigned int i)
871 int pos = array_append_or_increase(p->x_uints, &i);
875 int pool_register_int(pool_t*p, int i)
877 int pos = array_append_or_increase(p->x_ints, &i);
881 int pool_register_float(pool_t*p, double d)
883 int pos = array_append_or_increase(p->x_floats, &d);
887 int pool_register_string(pool_t*pool, const char*str)
890 string_t s = string_new2(str);
891 int pos = array_append_or_increase(pool->x_strings, &s);
895 int pool_register_string2(pool_t*pool, string_t*s)
897 if(!s || !s->str) return 0;
898 int pos = array_append_or_increase(pool->x_strings, s);
902 int pool_register_namespace(pool_t*pool, namespace_t*ns)
905 int pos = array_append_or_increase(pool->x_namespaces, ns);
906 assert(pos!=0 || ns->access==ZERONAMESPACE);
909 int pool_register_namespace_set(pool_t*pool, namespace_set_t*set)
912 int pos = array_append_or_increase(pool->x_namespace_sets, set);
916 int pool_register_multiname(pool_t*pool, multiname_t*n)
919 int pos = array_append_or_increase(pool->x_multinames, n);
923 int pool_register_multiname2(pool_t*pool, char*name)
926 multiname_t*n = multiname_fromstring(name);
927 int pos = array_append_or_increase(pool->x_multinames, n);
928 multiname_destroy(n);
934 int pool_find_uint(pool_t*pool, unsigned int x)
936 int i = array_find(pool->x_uints, &x);
938 fprintf(stderr, "Couldn't find uint \"%d\" in constant pool\n", x);
943 int pool_find_int(pool_t*pool, int x)
945 int i = array_find(pool->x_ints, &x);
947 fprintf(stderr, "Couldn't find int \"%d\" in constant pool\n", x);
952 int pool_find_float(pool_t*pool, double x)
954 int i = array_find(pool->x_ints, &x);
956 fprintf(stderr, "Couldn't find int \"%f\" in constant pool\n", x);
961 int pool_find_namespace(pool_t*pool, namespace_t*ns)
965 int i = array_find(pool->x_namespaces, ns);
967 char*s = namespace_tostring(ns);
968 fprintf(stderr, "Couldn't find namespace \"%s\" %08x in constant pool\n", s, (int)ns);
974 int pool_find_namespace_set(pool_t*pool, namespace_set_t*set)
978 int i = array_find(pool->x_namespace_sets, set);
980 char*s = namespace_set_tostring(set);
981 fprintf(stderr, "Couldn't find namespace_set \"%s\" in constant pool\n", s);
987 int pool_find_string(pool_t*pool, const char*str)
991 string_t s = string_new2(str);
992 int i = array_find(pool->x_strings, &s);
994 fprintf(stderr, "Couldn't find string \"%s\" in constant pool\n", str);
999 int pool_find_multiname(pool_t*pool, multiname_t*name)
1003 int i = array_find(pool->x_multinames, name);
1005 char*s = multiname_tostring(name);
1006 fprintf(stderr, "Couldn't find multiname \"%s\" in constant pool\n", s);
1013 int pool_lookup_int(pool_t*pool, int i)
1016 return *(int*)array_getkey(pool->x_ints, i);
1018 unsigned int pool_lookup_uint(pool_t*pool, int i)
1021 return *(unsigned int*)array_getkey(pool->x_uints, i);
1023 double pool_lookup_float(pool_t*pool, int i)
1025 if(!i) return __builtin_nan("");
1026 return *(double*)array_getkey(pool->x_floats, i);
1028 const char*pool_lookup_string(pool_t*pool, int i)
1030 string_t*s = array_getkey(pool->x_strings, i);
1034 string_t pool_lookup_string2(pool_t*pool, int i)
1036 string_t*s = array_getkey(pool->x_strings, i);
1039 namespace_t*pool_lookup_namespace(pool_t*pool, int i)
1041 return (namespace_t*)array_getkey(pool->x_namespaces, i);
1043 namespace_set_t*pool_lookup_namespace_set(pool_t*pool, int i)
1045 return (namespace_set_t*)array_getkey(pool->x_namespace_sets, i);
1047 multiname_t*pool_lookup_multiname(pool_t*pool, int i)
1049 return (multiname_t*)array_getkey(pool->x_multinames, i);
1052 static namespace_t zeronamespace={ZERONAMESPACE,"*"};
1057 p->x_ints = array_new2(&uint_type);
1058 p->x_uints = array_new2(&uint_type);
1059 p->x_floats = array_new2(&float_type);
1060 p->x_strings = array_new2(&stringstruct_type);
1061 p->x_namespaces = array_new2(&namespace_type);
1062 p->x_namespace_sets = array_new2(&namespace_set_type);
1063 p->x_multinames = array_new2(&multiname_type);
1065 /* add a zero-index entry in each list */
1067 array_append(p->x_ints, 0, 0);
1068 array_append(p->x_uints, 0, 0);
1069 array_append(p->x_floats, 0, 0);
1070 array_append(p->x_strings, 0, 0);
1071 array_append(p->x_namespaces, &zeronamespace, 0);
1072 array_append(p->x_namespace_sets, 0, 0);
1073 array_append(p->x_multinames, 0, 0);
1077 void pool_optimize(pool_t*p)
1079 reshuffle_array(p->x_ints);
1080 reshuffle_array(p->x_uints);
1081 reshuffle_array(p->x_floats);
1082 reshuffle_array(p->x_strings);
1083 reshuffle_array(p->x_namespaces);
1084 reshuffle_array(p->x_namespace_sets);
1085 reshuffle_array(p->x_multinames);
1091 void pool_read(pool_t*pool, TAG*tag)
1093 int num_ints = swf_GetU30(tag);
1094 DEBUG printf("%d ints\n", num_ints);
1096 for(t=1;t<num_ints;t++) {
1097 S32 v = swf_GetABCS32(tag);
1098 DEBUG printf("int %d) %d\n", t, v);
1099 array_append(pool->x_ints, &v, 0);
1102 int num_uints = swf_GetU30(tag);
1103 DEBUG printf("%d uints\n", num_uints);
1104 for(t=1;t<num_uints;t++) {
1105 U32 v = swf_GetABCU32(tag);
1106 DEBUG printf("uint %d) %d\n", t, v);
1107 array_append(pool->x_uints, &v, 0);
1110 int num_floats = swf_GetU30(tag);
1111 DEBUG printf("%d floats\n", num_floats);
1112 for(t=1;t<num_floats;t++) {
1113 double d = swf_GetD64(tag);
1114 DEBUG printf("float %d) %f\n", t, d);
1115 array_append(pool->x_floats, &d, 0);
1118 int num_strings = swf_GetU30(tag);
1119 DEBUG printf("%d strings\n", num_strings);
1120 for(t=1;t<num_strings;t++) {
1121 int len = swf_GetU30(tag);
1122 string_t s = string_new((char*)&tag->data[tag->pos], len);
1123 swf_GetBlock(tag, 0, len);
1124 array_append(pool->x_strings, &s, 0);
1125 DEBUG printf("%d) \"%s\"\n", t, ((string_t*)array_getkey(pool->x_strings, t))->str);
1127 int num_namespaces = swf_GetU30(tag);
1128 DEBUG printf("%d namespaces\n", num_namespaces);
1129 for(t=1;t<num_namespaces;t++) {
1130 U8 type = swf_GetU8(tag);
1131 int namenr = swf_GetU30(tag);
1132 const char*name = 0;
1134 name = pool_lookup_string(pool, namenr);
1135 namespace_t*ns = namespace_new(type, name);
1136 array_append(pool->x_namespaces, ns, 0);
1137 DEBUG printf("%d) %02x \"%s\"\n", t, type, namespace_tostring(ns));
1138 namespace_destroy(ns);
1140 int num_sets = swf_GetU30(tag);
1141 DEBUG printf("%d namespace sets\n", num_sets);
1142 for(t=1;t<num_sets;t++) {
1143 int count = swf_GetU30(tag);
1146 NEW(namespace_set_t, nsset);
1147 for(s=0;s<count;s++) {
1148 int nsnr = swf_GetU30(tag);
1150 fprintf(stderr, "Zero entry in namespace set\n");
1151 namespace_t*ns = (namespace_t*)array_getkey(pool->x_namespaces, nsnr);
1152 list_append(nsset->namespaces, namespace_clone(ns));
1154 array_append(pool->x_namespace_sets, nsset, 0);
1155 DEBUG printf("set %d) %s\n", t, namespace_set_tostring(nsset));
1156 namespace_set_destroy(nsset);
1159 int num_multinames = swf_GetU30(tag);
1160 DEBUG printf("%d multinames\n", num_multinames);
1161 for(t=1;t<num_multinames;t++) {
1163 memset(&m, 0, sizeof(multiname_t));
1167 printf("0x%02x ", tag->data[tag->pos+s]);
1170 m.type = swf_GetU8(tag);
1171 if(m.type==0x07 || m.type==0x0d) {
1172 int namespace_index = swf_GetU30(tag);
1173 m.ns = (namespace_t*)array_getkey(pool->x_namespaces, namespace_index);
1175 fprintf(stderr, "Error: Illegal reference to namespace #%d in constant pool.\n", namespace_index);
1177 int name_index = swf_GetU30(tag);
1178 if(name_index) // 0 = '*' (any)
1179 m.name = pool_lookup_string(pool, name_index);
1180 } else if(m.type==0x0f || m.type==0x10) {
1181 int name_index = swf_GetU30(tag);
1182 if(name_index) // 0 = '*' (any name)
1183 m.name = pool_lookup_string(pool, name_index);
1184 } else if(m.type==0x11 || m.type==0x12) {
1185 } else if(m.type==0x09 || m.type==0x0e) {
1186 int name_index = swf_GetU30(tag);
1187 int namespace_set_index = swf_GetU30(tag);
1189 m.name = pool_lookup_string(pool, name_index);
1190 m.namespace_set = (namespace_set_t*)array_getkey(pool->x_namespace_sets, namespace_set_index);
1191 } else if(m.type==0x1b || m.type==0x1c) {
1192 int namespace_set_index = swf_GetU30(tag);
1193 m.namespace_set = (namespace_set_t*)array_getkey(pool->x_namespace_sets, namespace_set_index);
1194 } else if(m.type==0x1d) {
1195 int v1 = swf_GetU30(tag); //multiname
1196 int v2 = swf_GetU30(tag); //counter?
1197 int v3 = swf_GetU30(tag); //multiname
1198 // e.g. Vector<int> ... we only store the parent object
1199 m = *(multiname_t*)array_getkey(pool->x_multinames, v1);
1201 printf("can't parse type %d multinames yet\n", m.type);
1203 DEBUG printf("multiname %d) %s\n", t, multiname_tostring(&m));
1204 array_append(pool->x_multinames, &m, 0);
1208 void pool_dump(pool_t*pool, FILE*fo, char flags)
1211 fprintf(fo, "%d integers\n", pool->x_ints->num);
1212 for(t=1;t<pool->x_ints->num;t++) {
1213 S32 val = *(int*)array_getkey(pool->x_ints, t);
1214 int freq = (int)(ptroff_t)array_getvalue(pool->x_ints, t);
1215 if(flags&1) fprintf(fo, "%5d %d) %d\n", freq, t, val);
1217 fprintf(fo, "%d unsigned integers\n", pool->x_uints->num);
1218 for(t=1;t<pool->x_uints->num;t++) {
1219 U32 val = *(unsigned int*)array_getkey(pool->x_uints, t);
1220 int freq = (int)(ptroff_t)array_getvalue(pool->x_uints, t);
1221 if(flags&1) fprintf(fo, "%5d %d) %d\n", freq, t, val);
1223 fprintf(fo, "%d floats\n", pool->x_floats->num);
1224 for(t=1;t<pool->x_floats->num;t++) {
1225 double d = pool_lookup_float(pool, t);
1226 int freq = (int)(ptroff_t)array_getvalue(pool->x_floats, t);
1227 if(flags&2) fprintf(fo, "%5d %d) %f\n", freq, t, d);
1229 fprintf(fo, "%d strings\n", pool->x_strings->num);
1230 for(t=1;t<pool->x_strings->num;t++) {
1231 string_t str = pool_lookup_string2(pool, t);
1232 int freq = (int)(ptroff_t)array_getvalue(pool->x_strings, t);
1233 if(flags&1) fprintf(fo, "%5d %d) ", freq, t);
1234 if(flags&1) fwrite(str.str, str.len, 1, fo);
1235 if(flags&1) fprintf(fo, "\n");
1237 fprintf(fo, "%d namespaces\n", pool->x_namespaces->num);
1238 for(t=1;t<pool->x_namespaces->num;t++) {
1239 namespace_t*ns= (namespace_t*)array_getkey(pool->x_namespaces, t);
1240 char*s = namespace_tostring(ns);
1241 int freq = (int)(ptroff_t)array_getvalue(pool->x_namespaces, t);
1242 if(flags&1) fprintf(fo, "%5d %d) %s\n", freq, t, s);
1245 fprintf(fo, "%d namespace sets\n", pool->x_namespace_sets->num);
1246 for(t=1;t<pool->x_namespace_sets->num;t++) {
1247 namespace_set_t*set = (namespace_set_t*)array_getkey(pool->x_namespace_sets, t);
1248 char*s = namespace_set_tostring(set);
1249 int freq = (int)(ptroff_t)array_getvalue(pool->x_namespace_sets, t);
1250 if(flags&1) fprintf(fo, "%5d %d) %s\n", freq, t, s);
1254 fprintf(fo, "%d multinames\n", pool->x_multinames->num);
1255 for(t=1;t<pool->x_multinames->num;t++) {
1256 multiname_t*m = (multiname_t*)array_getkey(pool->x_multinames, t);
1257 char*s = multiname_tostring(m);
1258 int freq = (int)(ptroff_t)array_getvalue(pool->x_multinames, t);
1259 if(flags&1) fprintf(fo, "%5d %d) %s\n", freq, t, s);
1264 void pool_write(pool_t*pool, TAG*tag)
1268 /* make sure that all namespaces used by multinames / namespace sets
1269 and all strings used by namespaces exist */
1271 for(t=1;t<pool->x_multinames->num;t++) {
1272 multiname_t*m = (multiname_t*)array_getkey(pool->x_multinames, t);
1274 pool_register_namespace(pool, m->ns);
1276 if(m->namespace_set) {
1277 pool_register_namespace_set(pool, m->namespace_set);
1280 pool_register_string(pool, m->name);
1283 for(t=1;t<pool->x_namespace_sets->num;t++) {
1284 namespace_set_t*set = (namespace_set_t*)array_getkey(pool->x_namespace_sets, t);
1285 namespace_list_t*i = set->namespaces;
1287 pool_register_namespace(pool, i->namespace);
1291 for(t=1;t<pool->x_namespaces->num;t++) {
1292 namespace_t*ns= (namespace_t*)array_getkey(pool->x_namespaces, t);
1293 /* The spec says (page 22): "a value of zero denotes an empty string".
1294 However when actually using zero strings as empty namespaces, the
1295 flash player breaks.*/
1296 //if(ns->name && ns->name[0])
1297 pool_register_string(pool, ns->name);
1300 //pool_register_int(pool, 15);
1301 //pool_register_int(pool, 1);
1302 //pool_register_int(pool, 0);
1305 swf_SetU30(tag, pool->x_ints->num>1?pool->x_ints->num:0);
1306 for(t=1;t<pool->x_ints->num;t++) {
1307 S32 val = *(int*)array_getkey(pool->x_ints, t);
1308 swf_SetABCS32(tag, val);
1310 swf_SetU30(tag, pool->x_uints->num>1?pool->x_uints->num:0);
1311 for(t=1;t<pool->x_uints->num;t++) {
1312 swf_SetABCU32(tag, *(unsigned int*)array_getkey(pool->x_uints, t));
1314 swf_SetU30(tag, pool->x_floats->num>1?pool->x_floats->num:0);
1315 for(t=1;t<pool->x_floats->num;t++) {
1316 double d = pool_lookup_float(pool, t);
1319 swf_SetU30(tag, pool->x_strings->num>1?pool->x_strings->num:0);
1320 for(t=1;t<pool->x_strings->num;t++) {
1321 string_t str = pool_lookup_string2(pool, t);
1322 swf_SetU30String(tag, str.str, str.len);
1324 swf_SetU30(tag, pool->x_namespaces->num>1?pool->x_namespaces->num:0);
1325 for(t=1;t<pool->x_namespaces->num;t++) {
1326 namespace_t*ns= (namespace_t*)array_getkey(pool->x_namespaces, t);
1327 swf_SetU8(tag, ns->access);
1328 const char*name = ns->name;
1331 //if(name && name[0])
1332 i = pool_find_string(pool, name);
1336 swf_SetU30(tag, pool->x_namespace_sets->num>1?pool->x_namespace_sets->num:0);
1337 for(t=1;t<pool->x_namespace_sets->num;t++) {
1338 namespace_set_t*set = (namespace_set_t*)array_getkey(pool->x_namespace_sets, t);
1339 namespace_list_t*i = set->namespaces;
1340 int len = list_length(i);
1341 swf_SetU30(tag, len);
1343 int index = pool_find_namespace(pool, i->namespace);
1344 swf_SetU30(tag, index);
1349 swf_SetU30(tag, pool->x_multinames->num>1?pool->x_multinames->num:0);
1350 for(t=1;t<pool->x_multinames->num;t++) {
1351 multiname_t*m = (multiname_t*)array_getkey(pool->x_multinames, t);
1352 swf_SetU8(tag, m->type);
1355 assert(m->type==0x07 || m->type==0x0d);
1356 int i = pool_find_namespace(pool, m->ns);
1357 if(i<0) fprintf(stderr, "internal error: unregistered namespace %02x %s %s\n", m->ns->access, access2str(m->ns->access), m->ns->name);
1360 assert(m->type!=0x07 && m->type!=0x0d);
1364 assert(m->type==0x09 || m->type==0x0e || m->type==0x07 || m->type==0x0d || m->type==0x0f || m->type==0x10);
1365 int i = pool_find_string(pool, m->name);
1366 if(i<0) fprintf(stderr, "internal error: unregistered name\n");
1369 if(m->type == 0x09) {
1372 assert(m->type!=0x0e && m->type!=0x07 && m->type!=0x0d && m->type!=0x0f && m->type!=0x10);
1374 if(m->namespace_set) {
1375 assert(m->type==0x09 || m->type==0x0e || m->type==0x1c || m->type==0x1b);
1376 int i = pool_find_namespace_set(pool, m->namespace_set);
1377 if(i<0) fprintf(stderr, "internal error: unregistered namespace set\n");
1380 assert(m->type!=0x09 && m->type!=0x0e && m->type!=0x1c && m->type!=0x1b);
1386 void pool_destroy(pool_t*pool)
1389 array_free(pool->x_ints);
1390 array_free(pool->x_uints);
1391 array_free(pool->x_floats);
1392 array_free(pool->x_strings);
1393 array_free(pool->x_namespaces);
1394 array_free(pool->x_namespace_sets);
1395 array_free(pool->x_multinames);