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;
831 static void reshuffle_array(array_t*array)
833 qsort(array->d+1, array->num-1, sizeof(array->d[0]), compare_arrayentry);
834 dict_t*d = dict_new2(array->entry2pos->key_type);
835 dict_destroy_shallow(array->entry2pos);
836 array->entry2pos = d;
838 for(t=0;t<array->num;t++) {
839 dict_put(array->entry2pos, array->d[t].name, (void*)(ptroff_t)(t+1));
843 // ------------------------------- pool -------------------------------------
845 int pool_register_uint(pool_t*p, unsigned int i)
847 int pos = array_append_or_increase(p->x_uints, &i);
851 int pool_register_int(pool_t*p, int i)
853 int pos = array_append_or_increase(p->x_ints, &i);
857 int pool_register_float(pool_t*p, double d)
859 int pos = array_append_or_increase(p->x_floats, &d);
863 int pool_register_string(pool_t*pool, const char*str)
866 string_t s = string_new2(str);
867 int pos = array_append_or_increase(pool->x_strings, &s);
871 int pool_register_string2(pool_t*pool, string_t*s)
873 if(!s || !s->str) return 0;
874 int pos = array_append_or_increase(pool->x_strings, s);
878 int pool_register_namespace(pool_t*pool, namespace_t*ns)
881 int pos = array_append_or_increase(pool->x_namespaces, ns);
885 int pool_register_namespace_set(pool_t*pool, namespace_set_t*set)
888 int pos = array_append_or_increase(pool->x_namespace_sets, set);
892 int pool_register_multiname(pool_t*pool, multiname_t*n)
895 int pos = array_append_or_increase(pool->x_multinames, n);
899 int pool_register_multiname2(pool_t*pool, char*name)
902 multiname_t*n = multiname_fromstring(name);
903 int pos = array_append_or_increase(pool->x_multinames, n);
904 multiname_destroy(n);
910 int pool_find_uint(pool_t*pool, unsigned int x)
912 int i = array_find(pool->x_uints, &x);
914 fprintf(stderr, "Couldn't find uint \"%d\" in constant pool\n", x);
919 int pool_find_int(pool_t*pool, int x)
921 int i = array_find(pool->x_ints, &x);
923 fprintf(stderr, "Couldn't find int \"%d\" in constant pool\n", x);
928 int pool_find_float(pool_t*pool, double x)
930 int i = array_find(pool->x_ints, &x);
932 fprintf(stderr, "Couldn't find int \"%d\" in constant pool\n", x);
937 int pool_find_namespace(pool_t*pool, namespace_t*ns)
941 int i = array_find(pool->x_namespaces, ns);
943 char*s = namespace_tostring(ns);
944 fprintf(stderr, "Couldn't find namespace \"%s\" %08x in constant pool\n", s, ns);
950 int pool_find_namespace_set(pool_t*pool, namespace_set_t*set)
954 int i = array_find(pool->x_namespace_sets, set);
956 char*s = namespace_set_tostring(set);
957 fprintf(stderr, "Couldn't find namespace_set \"%s\" in constant pool\n", s);
963 int pool_find_string(pool_t*pool, const char*str)
967 string_t s = string_new2(str);
968 int i = array_find(pool->x_strings, &s);
970 fprintf(stderr, "Couldn't find string \"%s\" in constant pool\n", s);
975 int pool_find_multiname(pool_t*pool, multiname_t*name)
979 int i = array_find(pool->x_multinames, name);
981 char*s = multiname_tostring(name);
982 fprintf(stderr, "Couldn't find multiname \"%s\" in constant pool\n", s);
989 int pool_lookup_int(pool_t*pool, int i)
992 return *(int*)array_getkey(pool->x_ints, i);
994 unsigned int pool_lookup_uint(pool_t*pool, int i)
997 return *(unsigned int*)array_getkey(pool->x_uints, i);
999 double pool_lookup_float(pool_t*pool, int i)
1001 if(!i) return __builtin_nan("");
1002 return *(double*)array_getkey(pool->x_floats, i);
1004 const char*pool_lookup_string(pool_t*pool, int i)
1006 string_t*s = array_getkey(pool->x_strings, i);
1010 string_t pool_lookup_string2(pool_t*pool, int i)
1012 string_t*s = array_getkey(pool->x_strings, i);
1015 namespace_t*pool_lookup_namespace(pool_t*pool, int i)
1017 return (namespace_t*)array_getkey(pool->x_namespaces, i);
1019 namespace_set_t*pool_lookup_namespace_set(pool_t*pool, int i)
1021 return (namespace_set_t*)array_getkey(pool->x_namespace_sets, i);
1023 multiname_t*pool_lookup_multiname(pool_t*pool, int i)
1025 return (multiname_t*)array_getkey(pool->x_multinames, i);
1032 p->x_ints = array_new2(&uint_type);
1033 p->x_uints = array_new2(&uint_type);
1034 p->x_floats = array_new2(&float_type);
1035 p->x_strings = array_new2(&stringstruct_type);
1036 p->x_namespaces = array_new2(&namespace_type);
1037 p->x_namespace_sets = array_new2(&namespace_set_type);
1038 p->x_multinames = array_new2(&multiname_type);
1040 /* add a zero-index entry in each list */
1042 array_append(p->x_ints, 0, 0);
1043 array_append(p->x_uints, 0, 0);
1044 array_append(p->x_floats, 0, 0);
1045 array_append(p->x_strings, 0, 0);
1046 array_append(p->x_namespaces, 0, 0);
1047 array_append(p->x_namespace_sets, 0, 0);
1048 array_append(p->x_multinames, 0, 0);
1052 void pool_optimize(pool_t*p)
1054 reshuffle_array(p->x_ints);
1055 reshuffle_array(p->x_uints);
1056 reshuffle_array(p->x_floats);
1057 reshuffle_array(p->x_strings);
1058 reshuffle_array(p->x_namespaces);
1059 reshuffle_array(p->x_namespace_sets);
1060 reshuffle_array(p->x_multinames);
1066 void pool_read(pool_t*pool, TAG*tag)
1068 int num_ints = swf_GetU30(tag);
1069 DEBUG printf("%d ints\n", num_ints);
1071 for(t=1;t<num_ints;t++) {
1072 S32 v = swf_GetABCS32(tag);
1073 DEBUG printf("int %d) %d\n", t, v);
1074 array_append(pool->x_ints, &v, 0);
1077 int num_uints = swf_GetU30(tag);
1078 DEBUG printf("%d uints\n", num_uints);
1079 for(t=1;t<num_uints;t++) {
1080 U32 v = swf_GetABCU32(tag);
1081 DEBUG printf("uint %d) %d\n", t, v);
1082 array_append(pool->x_uints, &v, 0);
1085 int num_floats = swf_GetU30(tag);
1086 DEBUG printf("%d floats\n", num_floats);
1087 for(t=1;t<num_floats;t++) {
1088 double d = swf_GetD64(tag);
1089 DEBUG printf("float %d) %f\n", t, d);
1090 array_append(pool->x_floats, &d, 0);
1093 int num_strings = swf_GetU30(tag);
1094 DEBUG printf("%d strings\n", num_strings);
1095 for(t=1;t<num_strings;t++) {
1096 int len = swf_GetU30(tag);
1097 string_t s = string_new(&tag->data[tag->pos], len);
1098 swf_GetBlock(tag, 0, len);
1099 array_append(pool->x_strings, &s, 0);
1100 DEBUG printf("%d) \"%s\"\n", t, ((string_t*)array_getkey(pool->x_strings, t))->str);
1102 int num_namespaces = swf_GetU30(tag);
1103 DEBUG printf("%d namespaces\n", num_namespaces);
1104 for(t=1;t<num_namespaces;t++) {
1105 U8 type = swf_GetU8(tag);
1106 int namenr = swf_GetU30(tag);
1107 const char*name = 0;
1109 name = pool_lookup_string(pool, namenr);
1110 namespace_t*ns = namespace_new(type, name);
1111 array_append(pool->x_namespaces, ns, 0);
1112 DEBUG printf("%d) %02x \"%s\"\n", t, type, namespace_tostring(ns));
1113 namespace_destroy(ns);
1115 int num_sets = swf_GetU30(tag);
1116 DEBUG printf("%d namespace sets\n", num_sets);
1117 for(t=1;t<num_sets;t++) {
1118 int count = swf_GetU30(tag);
1121 NEW(namespace_set_t, nsset);
1122 for(s=0;s<count;s++) {
1123 int nsnr = swf_GetU30(tag);
1125 fprintf(stderr, "Zero entry in namespace set\n");
1126 namespace_t*ns = (namespace_t*)array_getkey(pool->x_namespaces, nsnr);
1127 list_append(nsset->namespaces, namespace_clone(ns));
1129 array_append(pool->x_namespace_sets, nsset, 0);
1130 DEBUG printf("set %d) %s\n", t, namespace_set_tostring(nsset));
1131 namespace_set_destroy(nsset);
1134 int num_multinames = swf_GetU30(tag);
1135 DEBUG printf("%d multinames\n", num_multinames);
1136 for(t=1;t<num_multinames;t++) {
1138 memset(&m, 0, sizeof(multiname_t));
1139 m.type = swf_GetU8(tag);
1140 if(m.type==0x07 || m.type==0x0d) {
1141 int namespace_index = swf_GetU30(tag);
1142 m.ns = (namespace_t*)array_getkey(pool->x_namespaces, namespace_index);
1143 int name_index = swf_GetU30(tag);
1144 if(name_index) // 0 = '*' (any)
1145 m.name = pool_lookup_string(pool, name_index);
1146 } else if(m.type==0x0f || m.type==0x10) {
1147 int name_index = swf_GetU30(tag);
1148 if(name_index) // 0 = '*' (any name)
1149 m.name = pool_lookup_string(pool, name_index);
1150 } else if(m.type==0x11 || m.type==0x12) {
1151 } else if(m.type==0x09 || m.type==0x0e) {
1152 int name_index = swf_GetU30(tag);
1153 int namespace_set_index = swf_GetU30(tag);
1155 m.name = pool_lookup_string(pool, name_index);
1156 m.namespace_set = (namespace_set_t*)array_getkey(pool->x_namespace_sets, namespace_set_index);
1157 } else if(m.type==0x1b || m.type==0x1c) {
1158 int namespace_set_index = swf_GetU30(tag);
1159 m.namespace_set = (namespace_set_t*)array_getkey(pool->x_namespace_sets, namespace_set_index);
1161 printf("can't parse type %d multinames yet\n", m.type);
1163 DEBUG printf("multiname %d) %s\n", t, multiname_tostring(&m));
1164 array_append(pool->x_multinames, &m, 0);
1168 void pool_dump(pool_t*pool, FILE*fo, char flags)
1171 fprintf(fo, "%d integers:\n", pool->x_ints->num);
1172 for(t=1;t<pool->x_ints->num;t++) {
1173 S32 val = *(int*)array_getkey(pool->x_ints, t);
1174 int freq = (int)(ptroff_t)array_getvalue(pool->x_ints, t);
1175 if(flags&1) fprintf(fo, "%5d %d) %d\n", freq, t, val);
1177 fprintf(fo, "%d unsigned integers:\n", pool->x_uints->num);
1178 for(t=1;t<pool->x_uints->num;t++) {
1179 U32 val = *(unsigned int*)array_getkey(pool->x_uints, t);
1180 int freq = (int)(ptroff_t)array_getvalue(pool->x_uints, t);
1181 if(flags&1) fprintf(fo, "%5d %d) %d\n", freq, t, val);
1183 fprintf(fo, "%d floats:\n", pool->x_floats->num);
1184 for(t=1;t<pool->x_floats->num;t++) {
1185 double d = pool_lookup_float(pool, t);
1186 int freq = (int)(ptroff_t)array_getvalue(pool->x_floats, t);
1187 if(flags&2) fprintf(fo, "%5d %d) %f\n", freq, t, d);
1189 fprintf(fo, "%d strings:\n", pool->x_strings->num);
1190 for(t=1;t<pool->x_strings->num;t++) {
1191 string_t str = pool_lookup_string2(pool, t);
1192 int freq = (int)(ptroff_t)array_getvalue(pool->x_strings, t);
1193 if(flags&1) fprintf(fo, "%5d %d) ", freq, t);
1194 if(flags&1) fwrite(str.str, str.len, 1, fo);
1195 if(flags&1) fprintf(fo, "\n", t);
1197 fprintf(fo, "%d namespaces:\n", pool->x_namespaces->num);
1198 for(t=1;t<pool->x_namespaces->num;t++) {
1199 namespace_t*ns= (namespace_t*)array_getkey(pool->x_namespaces, t);
1200 char*s = namespace_tostring(ns);
1201 int freq = (int)(ptroff_t)array_getvalue(pool->x_namespaces, t);
1202 if(flags&1) fprintf(fo, "%5d %d) %s\n", freq, t, s);
1205 fprintf(fo, "%d namespace sets:\n", pool->x_namespace_sets->num);
1206 for(t=1;t<pool->x_namespace_sets->num;t++) {
1207 namespace_set_t*set = (namespace_set_t*)array_getkey(pool->x_namespace_sets, t);
1208 char*s = namespace_set_tostring(set);
1209 int freq = (int)(ptroff_t)array_getvalue(pool->x_namespace_sets, t);
1210 if(flags&1) fprintf(fo, "%5d %d) %s\n", freq, t, s);
1214 fprintf(fo, "%d multinames:\n", pool->x_multinames->num);
1215 for(t=1;t<pool->x_multinames->num;t++) {
1216 multiname_t*m = (multiname_t*)array_getkey(pool->x_multinames, t);
1217 char*s = multiname_tostring(m);
1218 int freq = (int)(ptroff_t)array_getvalue(pool->x_multinames, t);
1219 if(flags&1) fprintf(fo, "%5d %d) %s\n", freq, t, s);
1224 void pool_write(pool_t*pool, TAG*tag)
1228 /* make sure that all namespaces used by multinames / namespace sets
1229 and all strings used by namespaces exist */
1231 for(t=1;t<pool->x_multinames->num;t++) {
1232 multiname_t*m = (multiname_t*)array_getkey(pool->x_multinames, t);
1234 pool_register_namespace(pool, m->ns);
1236 if(m->namespace_set) {
1237 pool_register_namespace_set(pool, m->namespace_set);
1240 pool_register_string(pool, m->name);
1243 for(t=1;t<pool->x_namespace_sets->num;t++) {
1244 namespace_set_t*set = (namespace_set_t*)array_getkey(pool->x_namespace_sets, t);
1245 namespace_list_t*i = set->namespaces;
1247 pool_register_namespace(pool, i->namespace);
1251 for(t=1;t<pool->x_namespaces->num;t++) {
1252 namespace_t*ns= (namespace_t*)array_getkey(pool->x_namespaces, t);
1253 /* The spec says (page 22): "a value of zero denotes an empty string".
1254 However when actually using zero strings as empty namespaces, the
1255 flash player breaks.*/
1256 //if(ns->name && ns->name[0])
1257 pool_register_string(pool, ns->name);
1260 //pool_register_int(pool, 15);
1261 //pool_register_int(pool, 1);
1262 //pool_register_int(pool, 0);
1265 swf_SetU30(tag, pool->x_ints->num>1?pool->x_ints->num:0);
1266 for(t=1;t<pool->x_ints->num;t++) {
1267 S32 val = *(int*)array_getkey(pool->x_ints, t);
1268 swf_SetABCS32(tag, val);
1270 swf_SetU30(tag, pool->x_uints->num>1?pool->x_uints->num:0);
1271 for(t=1;t<pool->x_uints->num;t++) {
1272 swf_SetABCU32(tag, *(unsigned int*)array_getkey(pool->x_uints, t));
1274 swf_SetU30(tag, pool->x_floats->num>1?pool->x_floats->num:0);
1275 for(t=1;t<pool->x_floats->num;t++) {
1276 double d = pool_lookup_float(pool, t);
1279 swf_SetU30(tag, pool->x_strings->num>1?pool->x_strings->num:0);
1280 for(t=1;t<pool->x_strings->num;t++) {
1281 string_t str = pool_lookup_string2(pool, t);
1282 swf_SetU30String(tag, str.str, str.len);
1284 swf_SetU30(tag, pool->x_namespaces->num>1?pool->x_namespaces->num:0);
1285 for(t=1;t<pool->x_namespaces->num;t++) {
1286 namespace_t*ns= (namespace_t*)array_getkey(pool->x_namespaces, t);
1287 swf_SetU8(tag, ns->access);
1288 const char*name = ns->name;
1291 //if(name && name[0])
1292 i = pool_find_string(pool, name);
1296 swf_SetU30(tag, pool->x_namespace_sets->num>1?pool->x_namespace_sets->num:0);
1297 for(t=1;t<pool->x_namespace_sets->num;t++) {
1298 namespace_set_t*set = (namespace_set_t*)array_getkey(pool->x_namespace_sets, t);
1299 namespace_list_t*i = set->namespaces;
1300 int len = list_length(i);
1301 swf_SetU30(tag, len);
1303 int index = pool_find_namespace(pool, i->namespace);
1304 swf_SetU30(tag, index);
1309 swf_SetU30(tag, pool->x_multinames->num>1?pool->x_multinames->num:0);
1310 for(t=1;t<pool->x_multinames->num;t++) {
1311 multiname_t*m = (multiname_t*)array_getkey(pool->x_multinames, t);
1312 swf_SetU8(tag, m->type);
1315 assert(m->type==0x07 || m->type==0x0d);
1316 int i = pool_find_namespace(pool, m->ns);
1317 if(i<0) fprintf(stderr, "internal error: unregistered namespace %02x %s %s\n", m->ns->access, access2str(m->ns->access), m->ns->name);
1320 assert(m->type!=0x07 && m->type!=0x0d);
1323 assert(m->type==0x09 || m->type==0x0e || m->type==0x07 || m->type==0x0d || m->type==0x0f || m->type==0x10);
1324 int i = pool_find_string(pool, m->name);
1325 if(i<0) fprintf(stderr, "internal error: unregistered name\n");
1328 assert(m->type!=0x09 && m->type!=0x0e && m->type!=0x07 && m->type!=0x0d && m->type!=0x0f && m->type!=0x10);
1330 if(m->namespace_set) {
1331 assert(m->type==0x09 || m->type==0x0e || m->type==0x1c || m->type==0x1b);
1332 int i = pool_find_namespace_set(pool, m->namespace_set);
1333 if(i<0) fprintf(stderr, "internal error: unregistered namespace set\n");
1336 assert(m->type!=0x09 && m->type!=0x0e && m->type!=0x1c && m->type!=0x1b);
1342 void pool_destroy(pool_t*pool)
1345 array_free(pool->x_ints);
1346 array_free(pool->x_uints);
1347 array_free(pool->x_floats);
1348 array_free(pool->x_strings);
1349 array_free(pool->x_namespaces);
1350 array_free(pool->x_namespace_sets);
1351 array_free(pool->x_multinames);