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]", access, s);
198 namespace_t* namespace_clone(namespace_t*other)
203 n->access = other->access;
204 n->name = other->name?strdup(other->name):0;
208 namespace_t* namespace_fromstring(const char*name)
210 namespace_t*ns = malloc(sizeof(namespace_t));
211 memset(ns, 0, sizeof(namespace_t));
214 char*n = strdup(name);
215 char*bracket = strchr(n, ']');
219 name += (bracket-n)+1;
220 if(!strcmp(a, "")) access=0x16;
221 else if(!strcmp(a, "undefined")) access=0x08; // public??
222 else if(!strcmp(a, "package")) access=0x16;
223 else if(!strcmp(a, "public")) access=0x16;
224 else if(!strcmp(a, "packageinternal")) access=0x17;
225 else if(!strcmp(a, "protected")) access=0x18;
226 else if(!strcmp(a, "explicit")) access=0x19;
227 else if(!strcmp(a, "staticprotected")) access=0x1a;
228 else if(!strcmp(a, "private")) access=0x05;
230 fprintf(stderr, "Undefined access level: [%s]\n", a);
236 ns->name = strdup(name);
241 ns->name = strdup(name);
246 namespace_t* namespace_new(U8 access, const char*name)
248 namespace_t*ns = malloc(sizeof(namespace_t));
250 /* not sure what namespaces with empty strings are good for, but they *do* exist */
251 ns->name = name?strdup(name):0;
254 namespace_t* namespace_new_undefined(const char*name) {
255 return namespace_new(0x08, name); // public?
257 namespace_t* namespace_new_package(const char*name) {
258 return namespace_new(0x16 , name);
260 namespace_t* namespace_new_packageinternal(const char*name) {
261 return namespace_new(0x17, name);
263 namespace_t* namespace_new_protected(const char*name) {
264 return namespace_new(0x18, name);
266 namespace_t* namespace_new_explicit(const char*name) {
267 return namespace_new(0x19, name);
269 namespace_t* namespace_new_staticprotected(const char*name) {
270 return namespace_new(0x1a, name);
272 namespace_t* namespace_new_private(const char*name) {
273 return namespace_new(0x05, name);
276 void namespace_destroy(namespace_t*n)
279 free(n->name);n->name=0;
285 type_t namespace_type = {
286 dup: (dup_func)namespace_clone,
287 hash: (hash_func)namespace_hash,
288 free: (free_func)namespace_destroy,
289 equals: (equals_func)namespace_equals
292 // ---------------------------namespace sets --------------------------------
294 unsigned int namespace_set_hash(namespace_set_t*set)
298 namespace_list_t*l = set->namespaces;
299 unsigned int hash = 0;
301 hash = crc32_add_byte(hash, l->namespace->access);
302 hash = crc32_add_string(hash, l->namespace->name);
308 int namespace_set_equals(namespace_set_t*m1, namespace_set_t*m2)
312 namespace_list_t*l1 = m1->namespaces;
313 namespace_list_t*l2 = m2->namespaces;
315 if(l1->namespace->access != l2->namespace->access)
317 if(!(l1->namespace->name) != !(l2->namespace->name))
319 if(l1->namespace->name && l2->namespace->name && strcmp(l1->namespace->name, l2->namespace->name))
329 namespace_set_t* namespace_set_clone(namespace_set_t*other)
333 NEW(namespace_set_t,set);
334 set->namespaces = list_new();
335 namespace_list_t*l = other->namespaces;
337 list_append(set->namespaces, namespace_clone(l->namespace));
342 namespace_set_t* namespace_set_new()
344 NEW(namespace_set_t,set);
345 set->namespaces = list_new();
348 char* namespace_set_tostring(namespace_set_t*set)
351 return strdup("NULL");
352 /* TODO: is the order of the namespaces important (does it
353 change the lookup order?). E.g. flex freely shuffles namespaces
355 If the order is not important, we can optimize constant pools by sorting
359 namespace_list_t*lns = set->namespaces;
361 char*s = namespace_tostring(lns->namespace);
366 char*desc = malloc(l+16);
368 lns = set->namespaces;
370 char*s = namespace_tostring(lns->namespace);
381 void namespace_set_destroy(namespace_set_t*set)
384 namespace_list_t*l = set->namespaces;
386 namespace_destroy(l->namespace);l->namespace=0;
389 list_free(set->namespaces);
394 type_t namespace_set_type = {
395 dup: (dup_func)namespace_set_clone,
396 hash: (hash_func)namespace_set_hash,
397 free: (free_func)namespace_set_destroy,
398 equals: (equals_func)namespace_set_equals
401 // ----------------------------- multiname ----------------------------------
403 unsigned int multiname_hash(multiname_t*m)
407 unsigned int hash = crc32_add_byte(0, m->type);
409 hash = crc32_add_string(hash, m->name);
412 hash = crc32_add_byte(hash, m->ns->access);
413 hash = crc32_add_string(hash, m->ns->name);
415 if(m->namespace_set) {
416 namespace_list_t*l = m->namespace_set->namespaces;
418 hash = crc32_add_byte(hash, l->namespace->access);
419 hash = crc32_add_string(hash, l->namespace->name);
426 int multiname_equals(multiname_t*m1, multiname_t*m2)
430 if(m1->type!=m2->type)
433 if((!m1->name) != (!m2->name))
435 if((!m1->ns) != (!m2->ns))
437 if((!m1->namespace_set) != (!m2->namespace_set))
440 if(m1->name && m2->name && strcmp(m1->name,m2->name))
442 if(m1->ns && m2->ns) {
443 if(!namespace_equals(m1->ns, m2->ns))
446 if(m1->namespace_set && m2->namespace_set) {
447 if(!namespace_set_equals(m1->namespace_set, m2->namespace_set))
453 multiname_t* multiname_new(namespace_t*ns, const char*name)
458 m->ns = namespace_new_packageinternal("");
460 m->ns = namespace_clone(ns);
462 m->name = strdup(name);
466 multiname_t* multiname_clone(multiname_t*other)
471 m->type = other->type;
473 m->ns = namespace_clone(other->ns);
474 if(other->namespace_set)
475 m->namespace_set = namespace_set_clone(other->namespace_set);
477 m->name = strdup(other->name);
482 char* access2str(int type)
484 if(type==0x08) return "namespace";
485 else if(type==0x16) return "public";
486 else if(type==0x17) return "packageinternal";
487 else if(type==0x18) return "protected";
488 else if(type==0x19) return "explicit";
489 else if(type==0x1A) return "staticprotected";
490 else if(type==0x05) return "private";
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) {
526 char*nsname = escape_string(m->ns->name);
527 mname = malloc(strlen(nsname)+namelen+32);
529 if(m->type == QNAMEA)
530 strcat(mname, ",attr");
532 strcat(mname,access2str(m->ns->access));
534 strcat(mname, nsname);
538 } else if(m->type==RTQNAME || m->type==RTQNAMEA) {
539 mname = malloc(namelen+32);
540 strcpy(mname, "<rt");
541 if(m->type == RTQNAMEA)
542 strcat(mname, ",attr");
545 } else if(m->type==RTQNAMEL) {
546 mname = strdup("<rt,l>");
547 } else if(m->type==RTQNAMELA) {
548 mname = strdup("<rt,l,attr>");
549 } else if(m->type==MULTINAME || m->type==MULTINAMEA) {
550 char*s = namespace_set_tostring(m->namespace_set);
551 mname = malloc(strlen(s)+namelen+16);
552 if(m->type == MULTINAME)
553 strcpy(mname,"<multi>");
555 strcpy(mname,"<multi,attr>");
560 } else if(m->type==MULTINAMEL || m->type==MULTINAMELA) {
561 char*s = namespace_set_tostring(m->namespace_set);
562 mname = malloc(strlen(s)+16);
563 if(m->type == MULTINAMEL)
564 strcpy(mname,"<l,multi>");
566 strcpy(mname,"<l,multi,attr>");
570 fprintf(stderr, "Invalid multiname type: %02x\n", m->type);
576 multiname_t* multiname_fromstring(const char*name2)
580 char*n = strdup(name2);
581 char*p = strstr(n, "::");
582 char*namespace=0,*name=0;
585 fprintf(stderr, "Error: single ':' in name\n");
593 if(strchr(namespace, ':')) {
594 fprintf(stderr, "Error: single ':' in namespace\n");
596 if(strchr(name, ':')) {
597 fprintf(stderr, "Error: single ':' in qualified name\n");
601 multiname_t*m = malloc(sizeof(multiname_t));
602 memset(m, 0, sizeof(multiname_t));
604 m->namespace_set = 0;
605 m->ns = namespace_fromstring(namespace);
606 m->name = name?strdup(name):0;
611 void multiname_destroy(multiname_t*m)
615 free((void*)m->name);m->name = 0;
618 namespace_destroy(m->ns);m->ns = 0;
620 if(m->namespace_set) {
621 namespace_set_destroy(m->namespace_set);m->namespace_set = 0;
628 type_t multiname_type = {
629 dup: (dup_func)multiname_clone,
630 hash: (hash_func)multiname_hash,
631 free: (free_func)multiname_destroy,
632 equals: (equals_func)multiname_equals
636 // ------------------------------- constants -------------------------------------
638 #define NS_TYPE(x) ((x) == 0x08 || (x) == 0x16 || (x) == 0x17 || (x) == 0x18 || \
639 (x) == 0x19 || (x) == 0x1a || (x) == 0x05)
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(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_fromindex(pool_t*pool, int index, int type)
713 /* even for nonvalued constants (like TRUE/FALSE etc.), a nonzero
714 index is present to indicate that a type is coming */
719 if(NS_TYPE(c->type)) {
720 c->ns = namespace_clone(pool_lookup_namespace(pool, index));
721 } else if(c->type == CONSTANT_INT) {
722 c->i = pool_lookup_int(pool, index);
723 } else if(c->type == CONSTANT_UINT) {
724 c->u = pool_lookup_uint(pool, index);
725 } else if(c->type == CONSTANT_FLOAT) {
726 c->f = pool_lookup_float(pool, index);
727 } else if(c->type == CONSTANT_STRING) {
728 string_t s = pool_lookup_string2(pool, index);
729 c->s = string_dup3(&s);
730 } else if(UNIQUE_CONSTANT(c->type)) {
733 fprintf(stderr, "invalid constant type %02x\n", c->type);
737 char* constant_tostring(constant_t*c)
740 return strdup("NULL");
742 if(NS_TYPE(c->type)) {
743 return namespace_tostring(c->ns);
744 } else if(c->type == CONSTANT_INT) {
745 sprintf(buf, "%d", c->i);
747 } else if(c->type == CONSTANT_UINT) {
748 sprintf(buf, "%u", c->u);
750 } else if(c->type == CONSTANT_FLOAT) {
752 sprintf(buf, "%f", c->f);
754 } else if(c->type == CONSTANT_STRING) {
755 /* should we escape the string? \0 bytes won't be printed */
756 return strdup_n(c->s->str,c->s->len);
757 } else if(c->type == CONSTANT_TRUE) {
758 return strdup("true");
759 } else if(c->type == CONSTANT_FALSE) {
760 return strdup("false");
761 } else if(c->type == CONSTANT_NULL) {
762 return strdup("null");
763 } else if(c->type == CONSTANT_UNDEFINED) {
764 return strdup("undefined");
766 fprintf(stderr, "invalid constant type %02x\n", c->type);
770 char constant_has_index(constant_t*c)
774 return !UNIQUE_CONSTANT(c->type);
776 int constant_get_index(pool_t*pool, constant_t*c)
780 if(NS_TYPE(c->type)) {
782 /*if(c->type!=c->ns->access) {
783 printf("%02x<->%02x\n", c->type, c->ns->access);
785 assert(c->type == c->ns->access);
786 return pool_register_namespace(pool, c->ns);
787 } else if(c->type == CONSTANT_INT) {
788 return pool_register_int(pool, c->i);
789 } else if(c->type == CONSTANT_UINT) {
790 return pool_register_uint(pool, c->u);
791 } else if(c->type == CONSTANT_FLOAT) {
792 return pool_register_float(pool, c->f);
793 } else if(c->type == CONSTANT_STRING) {
794 return pool_register_string2(pool, c->s);
795 } else if(!constant_has_index(c)) {
798 fprintf(stderr, "invalid constant type %02x\n", c->type);
802 void constant_free(constant_t*c)
806 if(c->type == CONSTANT_STRING) {
808 } else if (NS_TYPE(c->type)) {
809 namespace_destroy(c->ns);c->ns=0;
813 // --------------------------- optimizing -----------------------------------
815 static int array_append_or_increase(array_t*array, void*key)
817 int pos = array_find(array, key);
819 array->d[pos].data++;
822 return array_append(array, key, 0);
825 static int compare_arrayentry(const void*_c1, const void*_c2)
827 const array_entry_t*c1 = _c1;
828 const array_entry_t*c2 = _c2;
829 return c2->data - c1->data;
832 static void* nodup(const void*o) {return (void*)o;}
834 static void reshuffle_array(array_t*array)
836 qsort(array->d+1, array->num-1, sizeof(array->d[0]), compare_arrayentry);
837 type_t* old_type = array->entry2pos->key_type;
838 type_t old_type_nodup = *old_type;
839 old_type_nodup.dup = nodup;
840 dict_t*d = dict_new2(&old_type_nodup);
841 dict_destroy_shallow(array->entry2pos);
842 array->entry2pos = d;
844 for(t=0;t<array->num;t++) {
845 dict_put(array->entry2pos, array->d[t].name, (void*)(ptroff_t)(t+1));
847 d->key_type = old_type;
851 // ------------------------------- pool -------------------------------------
853 int pool_register_uint(pool_t*p, unsigned int i)
855 int pos = array_append_or_increase(p->x_uints, &i);
859 int pool_register_int(pool_t*p, int i)
861 int pos = array_append_or_increase(p->x_ints, &i);
865 int pool_register_float(pool_t*p, double d)
867 int pos = array_append_or_increase(p->x_floats, &d);
871 int pool_register_string(pool_t*pool, const char*str)
874 string_t s = string_new2(str);
875 int pos = array_append_or_increase(pool->x_strings, &s);
879 int pool_register_string2(pool_t*pool, string_t*s)
881 if(!s || !s->str) return 0;
882 int pos = array_append_or_increase(pool->x_strings, s);
886 int pool_register_namespace(pool_t*pool, namespace_t*ns)
889 int pos = array_append_or_increase(pool->x_namespaces, ns);
893 int pool_register_namespace_set(pool_t*pool, namespace_set_t*set)
896 int pos = array_append_or_increase(pool->x_namespace_sets, set);
900 int pool_register_multiname(pool_t*pool, multiname_t*n)
903 int pos = array_append_or_increase(pool->x_multinames, n);
907 int pool_register_multiname2(pool_t*pool, char*name)
910 multiname_t*n = multiname_fromstring(name);
911 int pos = array_append_or_increase(pool->x_multinames, n);
912 multiname_destroy(n);
918 int pool_find_uint(pool_t*pool, unsigned int x)
920 int i = array_find(pool->x_uints, &x);
922 fprintf(stderr, "Couldn't find uint \"%d\" in constant pool\n", x);
927 int pool_find_int(pool_t*pool, int x)
929 int i = array_find(pool->x_ints, &x);
931 fprintf(stderr, "Couldn't find int \"%d\" in constant pool\n", x);
936 int pool_find_float(pool_t*pool, double x)
938 int i = array_find(pool->x_ints, &x);
940 fprintf(stderr, "Couldn't find int \"%d\" in constant pool\n", x);
945 int pool_find_namespace(pool_t*pool, namespace_t*ns)
949 int i = array_find(pool->x_namespaces, ns);
951 char*s = namespace_tostring(ns);
952 fprintf(stderr, "Couldn't find namespace \"%s\" %08x in constant pool\n", s, ns);
958 int pool_find_namespace_set(pool_t*pool, namespace_set_t*set)
962 int i = array_find(pool->x_namespace_sets, set);
964 char*s = namespace_set_tostring(set);
965 fprintf(stderr, "Couldn't find namespace_set \"%s\" in constant pool\n", s);
971 int pool_find_string(pool_t*pool, const char*str)
975 string_t s = string_new2(str);
976 int i = array_find(pool->x_strings, &s);
978 fprintf(stderr, "Couldn't find string \"%s\" in constant pool\n", s);
983 int pool_find_multiname(pool_t*pool, multiname_t*name)
987 int i = array_find(pool->x_multinames, name);
989 char*s = multiname_tostring(name);
990 fprintf(stderr, "Couldn't find multiname \"%s\" in constant pool\n", s);
997 int pool_lookup_int(pool_t*pool, int i)
1000 return *(int*)array_getkey(pool->x_ints, i);
1002 unsigned int pool_lookup_uint(pool_t*pool, int i)
1005 return *(unsigned int*)array_getkey(pool->x_uints, i);
1007 double pool_lookup_float(pool_t*pool, int i)
1009 if(!i) return __builtin_nan("");
1010 return *(double*)array_getkey(pool->x_floats, i);
1012 const char*pool_lookup_string(pool_t*pool, int i)
1014 string_t*s = array_getkey(pool->x_strings, i);
1018 string_t pool_lookup_string2(pool_t*pool, int i)
1020 string_t*s = array_getkey(pool->x_strings, i);
1023 namespace_t*pool_lookup_namespace(pool_t*pool, int i)
1025 return (namespace_t*)array_getkey(pool->x_namespaces, i);
1027 namespace_set_t*pool_lookup_namespace_set(pool_t*pool, int i)
1029 return (namespace_set_t*)array_getkey(pool->x_namespace_sets, i);
1031 multiname_t*pool_lookup_multiname(pool_t*pool, int i)
1033 return (multiname_t*)array_getkey(pool->x_multinames, i);
1040 p->x_ints = array_new2(&uint_type);
1041 p->x_uints = array_new2(&uint_type);
1042 p->x_floats = array_new2(&float_type);
1043 p->x_strings = array_new2(&stringstruct_type);
1044 p->x_namespaces = array_new2(&namespace_type);
1045 p->x_namespace_sets = array_new2(&namespace_set_type);
1046 p->x_multinames = array_new2(&multiname_type);
1048 /* add a zero-index entry in each list */
1050 array_append(p->x_ints, 0, 0);
1051 array_append(p->x_uints, 0, 0);
1052 array_append(p->x_floats, 0, 0);
1053 array_append(p->x_strings, 0, 0);
1054 array_append(p->x_namespaces, 0, 0);
1055 array_append(p->x_namespace_sets, 0, 0);
1056 array_append(p->x_multinames, 0, 0);
1060 void pool_optimize(pool_t*p)
1062 reshuffle_array(p->x_ints);
1063 reshuffle_array(p->x_uints);
1064 reshuffle_array(p->x_floats);
1065 reshuffle_array(p->x_strings);
1066 reshuffle_array(p->x_namespaces);
1067 reshuffle_array(p->x_namespace_sets);
1068 reshuffle_array(p->x_multinames);
1074 void pool_read(pool_t*pool, TAG*tag)
1076 int num_ints = swf_GetU30(tag);
1077 DEBUG printf("%d ints\n", num_ints);
1079 for(t=1;t<num_ints;t++) {
1080 S32 v = swf_GetABCS32(tag);
1081 DEBUG printf("int %d) %d\n", t, v);
1082 array_append(pool->x_ints, &v, 0);
1085 int num_uints = swf_GetU30(tag);
1086 DEBUG printf("%d uints\n", num_uints);
1087 for(t=1;t<num_uints;t++) {
1088 U32 v = swf_GetABCU32(tag);
1089 DEBUG printf("uint %d) %d\n", t, v);
1090 array_append(pool->x_uints, &v, 0);
1093 int num_floats = swf_GetU30(tag);
1094 DEBUG printf("%d floats\n", num_floats);
1095 for(t=1;t<num_floats;t++) {
1096 double d = swf_GetD64(tag);
1097 DEBUG printf("float %d) %f\n", t, d);
1098 array_append(pool->x_floats, &d, 0);
1101 int num_strings = swf_GetU30(tag);
1102 DEBUG printf("%d strings\n", num_strings);
1103 for(t=1;t<num_strings;t++) {
1104 int len = swf_GetU30(tag);
1105 string_t s = string_new(&tag->data[tag->pos], len);
1106 swf_GetBlock(tag, 0, len);
1107 array_append(pool->x_strings, &s, 0);
1108 DEBUG printf("%d) \"%s\"\n", t, ((string_t*)array_getkey(pool->x_strings, t))->str);
1110 int num_namespaces = swf_GetU30(tag);
1111 DEBUG printf("%d namespaces\n", num_namespaces);
1112 for(t=1;t<num_namespaces;t++) {
1113 U8 type = swf_GetU8(tag);
1114 int namenr = swf_GetU30(tag);
1115 const char*name = 0;
1117 name = pool_lookup_string(pool, namenr);
1118 namespace_t*ns = namespace_new(type, name);
1119 array_append(pool->x_namespaces, ns, 0);
1120 DEBUG printf("%d) %02x \"%s\"\n", t, type, namespace_tostring(ns));
1121 namespace_destroy(ns);
1123 int num_sets = swf_GetU30(tag);
1124 DEBUG printf("%d namespace sets\n", num_sets);
1125 for(t=1;t<num_sets;t++) {
1126 int count = swf_GetU30(tag);
1129 NEW(namespace_set_t, nsset);
1130 for(s=0;s<count;s++) {
1131 int nsnr = swf_GetU30(tag);
1133 fprintf(stderr, "Zero entry in namespace set\n");
1134 namespace_t*ns = (namespace_t*)array_getkey(pool->x_namespaces, nsnr);
1135 list_append(nsset->namespaces, namespace_clone(ns));
1137 array_append(pool->x_namespace_sets, nsset, 0);
1138 DEBUG printf("set %d) %s\n", t, namespace_set_tostring(nsset));
1139 namespace_set_destroy(nsset);
1142 int num_multinames = swf_GetU30(tag);
1143 DEBUG printf("%d multinames\n", num_multinames);
1144 for(t=1;t<num_multinames;t++) {
1146 memset(&m, 0, sizeof(multiname_t));
1147 m.type = swf_GetU8(tag);
1148 if(m.type==0x07 || m.type==0x0d) {
1149 int namespace_index = swf_GetU30(tag);
1150 m.ns = (namespace_t*)array_getkey(pool->x_namespaces, namespace_index);
1151 int name_index = swf_GetU30(tag);
1152 if(name_index) // 0 = '*' (any)
1153 m.name = pool_lookup_string(pool, name_index);
1154 } else if(m.type==0x0f || m.type==0x10) {
1155 int name_index = swf_GetU30(tag);
1156 if(name_index) // 0 = '*' (any name)
1157 m.name = pool_lookup_string(pool, name_index);
1158 } else if(m.type==0x11 || m.type==0x12) {
1159 } else if(m.type==0x09 || m.type==0x0e) {
1160 int name_index = swf_GetU30(tag);
1161 int namespace_set_index = swf_GetU30(tag);
1163 m.name = pool_lookup_string(pool, name_index);
1164 m.namespace_set = (namespace_set_t*)array_getkey(pool->x_namespace_sets, namespace_set_index);
1165 } else if(m.type==0x1b || m.type==0x1c) {
1166 int namespace_set_index = swf_GetU30(tag);
1167 m.namespace_set = (namespace_set_t*)array_getkey(pool->x_namespace_sets, namespace_set_index);
1169 printf("can't parse type %d multinames yet\n", m.type);
1171 DEBUG printf("multiname %d) %s\n", t, multiname_tostring(&m));
1172 array_append(pool->x_multinames, &m, 0);
1176 void pool_dump(pool_t*pool, FILE*fo, char flags)
1179 fprintf(fo, "%d integers\n", pool->x_ints->num);
1180 for(t=1;t<pool->x_ints->num;t++) {
1181 S32 val = *(int*)array_getkey(pool->x_ints, t);
1182 int freq = (int)(ptroff_t)array_getvalue(pool->x_ints, t);
1183 if(flags&1) fprintf(fo, "%5d %d) %d\n", freq, t, val);
1185 fprintf(fo, "%d unsigned integers\n", pool->x_uints->num);
1186 for(t=1;t<pool->x_uints->num;t++) {
1187 U32 val = *(unsigned int*)array_getkey(pool->x_uints, t);
1188 int freq = (int)(ptroff_t)array_getvalue(pool->x_uints, t);
1189 if(flags&1) fprintf(fo, "%5d %d) %d\n", freq, t, val);
1191 fprintf(fo, "%d floats\n", pool->x_floats->num);
1192 for(t=1;t<pool->x_floats->num;t++) {
1193 double d = pool_lookup_float(pool, t);
1194 int freq = (int)(ptroff_t)array_getvalue(pool->x_floats, t);
1195 if(flags&2) fprintf(fo, "%5d %d) %f\n", freq, t, d);
1197 fprintf(fo, "%d strings\n", pool->x_strings->num);
1198 for(t=1;t<pool->x_strings->num;t++) {
1199 string_t str = pool_lookup_string2(pool, t);
1200 int freq = (int)(ptroff_t)array_getvalue(pool->x_strings, t);
1201 if(flags&1) fprintf(fo, "%5d %d) ", freq, t);
1202 if(flags&1) fwrite(str.str, str.len, 1, fo);
1203 if(flags&1) fprintf(fo, "\n", t);
1205 fprintf(fo, "%d namespaces\n", pool->x_namespaces->num);
1206 for(t=1;t<pool->x_namespaces->num;t++) {
1207 namespace_t*ns= (namespace_t*)array_getkey(pool->x_namespaces, t);
1208 char*s = namespace_tostring(ns);
1209 int freq = (int)(ptroff_t)array_getvalue(pool->x_namespaces, t);
1210 if(flags&1) fprintf(fo, "%5d %d) %s\n", freq, t, s);
1213 fprintf(fo, "%d namespace sets\n", pool->x_namespace_sets->num);
1214 for(t=1;t<pool->x_namespace_sets->num;t++) {
1215 namespace_set_t*set = (namespace_set_t*)array_getkey(pool->x_namespace_sets, t);
1216 char*s = namespace_set_tostring(set);
1217 int freq = (int)(ptroff_t)array_getvalue(pool->x_namespace_sets, t);
1218 if(flags&1) fprintf(fo, "%5d %d) %s\n", freq, t, s);
1222 fprintf(fo, "%d multinames\n", pool->x_multinames->num);
1223 for(t=1;t<pool->x_multinames->num;t++) {
1224 multiname_t*m = (multiname_t*)array_getkey(pool->x_multinames, t);
1225 char*s = multiname_tostring(m);
1226 int freq = (int)(ptroff_t)array_getvalue(pool->x_multinames, t);
1227 if(flags&1) fprintf(fo, "%5d %d) %s\n", freq, t, s);
1232 void pool_write(pool_t*pool, TAG*tag)
1236 /* make sure that all namespaces used by multinames / namespace sets
1237 and all strings used by namespaces exist */
1239 for(t=1;t<pool->x_multinames->num;t++) {
1240 multiname_t*m = (multiname_t*)array_getkey(pool->x_multinames, t);
1242 pool_register_namespace(pool, m->ns);
1244 if(m->namespace_set) {
1245 pool_register_namespace_set(pool, m->namespace_set);
1248 pool_register_string(pool, m->name);
1251 for(t=1;t<pool->x_namespace_sets->num;t++) {
1252 namespace_set_t*set = (namespace_set_t*)array_getkey(pool->x_namespace_sets, t);
1253 namespace_list_t*i = set->namespaces;
1255 pool_register_namespace(pool, i->namespace);
1259 for(t=1;t<pool->x_namespaces->num;t++) {
1260 namespace_t*ns= (namespace_t*)array_getkey(pool->x_namespaces, t);
1261 /* The spec says (page 22): "a value of zero denotes an empty string".
1262 However when actually using zero strings as empty namespaces, the
1263 flash player breaks.*/
1264 //if(ns->name && ns->name[0])
1265 pool_register_string(pool, ns->name);
1268 //pool_register_int(pool, 15);
1269 //pool_register_int(pool, 1);
1270 //pool_register_int(pool, 0);
1273 swf_SetU30(tag, pool->x_ints->num>1?pool->x_ints->num:0);
1274 for(t=1;t<pool->x_ints->num;t++) {
1275 S32 val = *(int*)array_getkey(pool->x_ints, t);
1276 swf_SetABCS32(tag, val);
1278 swf_SetU30(tag, pool->x_uints->num>1?pool->x_uints->num:0);
1279 for(t=1;t<pool->x_uints->num;t++) {
1280 swf_SetABCU32(tag, *(unsigned int*)array_getkey(pool->x_uints, t));
1282 swf_SetU30(tag, pool->x_floats->num>1?pool->x_floats->num:0);
1283 for(t=1;t<pool->x_floats->num;t++) {
1284 double d = pool_lookup_float(pool, t);
1287 swf_SetU30(tag, pool->x_strings->num>1?pool->x_strings->num:0);
1288 for(t=1;t<pool->x_strings->num;t++) {
1289 string_t str = pool_lookup_string2(pool, t);
1290 swf_SetU30String(tag, str.str, str.len);
1292 swf_SetU30(tag, pool->x_namespaces->num>1?pool->x_namespaces->num:0);
1293 for(t=1;t<pool->x_namespaces->num;t++) {
1294 namespace_t*ns= (namespace_t*)array_getkey(pool->x_namespaces, t);
1295 swf_SetU8(tag, ns->access);
1296 const char*name = ns->name;
1299 //if(name && name[0])
1300 i = pool_find_string(pool, name);
1304 swf_SetU30(tag, pool->x_namespace_sets->num>1?pool->x_namespace_sets->num:0);
1305 for(t=1;t<pool->x_namespace_sets->num;t++) {
1306 namespace_set_t*set = (namespace_set_t*)array_getkey(pool->x_namespace_sets, t);
1307 namespace_list_t*i = set->namespaces;
1308 int len = list_length(i);
1309 swf_SetU30(tag, len);
1311 int index = pool_find_namespace(pool, i->namespace);
1312 swf_SetU30(tag, index);
1317 swf_SetU30(tag, pool->x_multinames->num>1?pool->x_multinames->num:0);
1318 for(t=1;t<pool->x_multinames->num;t++) {
1319 multiname_t*m = (multiname_t*)array_getkey(pool->x_multinames, t);
1320 swf_SetU8(tag, m->type);
1323 assert(m->type==0x07 || m->type==0x0d);
1324 int i = pool_find_namespace(pool, m->ns);
1325 if(i<0) fprintf(stderr, "internal error: unregistered namespace %02x %s %s\n", m->ns->access, access2str(m->ns->access), m->ns->name);
1328 assert(m->type!=0x07 && m->type!=0x0d);
1331 assert(m->type==0x09 || m->type==0x0e || m->type==0x07 || m->type==0x0d || m->type==0x0f || m->type==0x10);
1332 int i = pool_find_string(pool, m->name);
1333 if(i<0) fprintf(stderr, "internal error: unregistered name\n");
1336 assert(m->type!=0x09 && m->type!=0x0e && m->type!=0x07 && m->type!=0x0d && m->type!=0x0f && m->type!=0x10);
1338 if(m->namespace_set) {
1339 assert(m->type==0x09 || m->type==0x0e || m->type==0x1c || m->type==0x1b);
1340 int i = pool_find_namespace_set(pool, m->namespace_set);
1341 if(i<0) fprintf(stderr, "internal error: unregistered namespace set\n");
1344 assert(m->type!=0x09 && m->type!=0x0e && m->type!=0x1c && m->type!=0x1b);
1350 void pool_destroy(pool_t*pool)
1353 array_free(pool->x_ints);
1354 array_free(pool->x_uints);
1355 array_free(pool->x_floats);
1356 array_free(pool->x_strings);
1357 array_free(pool->x_namespaces);
1358 array_free(pool->x_namespace_sets);
1359 array_free(pool->x_multinames);