ccb6ac76350e1f6fc67df4b9af994090b79e447d
[swftools.git] / lib / as3 / pool.c
1 /* pool.c
2
3    Routines for handling Flash2 AVM2 ABC contantpool entries.
4
5    Extension module for the rfxswf library.
6    Part of the swftools package.
7
8    Copyright (c) 2008 Matthias Kramm <kramm@quiss.org>
9  
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.
14
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.
19
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 */
23
24 #include <assert.h>
25 #include "pool.h"
26
27
28 // ----------------------------- float ----------------------------------
29
30 double undefined_float = 0.0;
31
32 void* float_clone(const void*_v) {
33     if(_v==&undefined_float)
34         return &undefined_float;
35     const double*v1=_v;
36     double*v2 = malloc(sizeof(double));
37     *v2 = *v1;
38     return v2;
39 }
40 unsigned int float_hash(const void*_v) {
41     const unsigned char*b=_v;
42     unsigned int h=0;
43     int t;
44     for(t=0;t<8;t++)
45         h = crc32_add_byte(h, b[t]);
46     return h;
47 }
48 void float_destroy(void*_v) {
49     double*v = (double*)_v;
50     if(v!=&undefined_float)
51         free(v);
52 }
53 char float_equals(const void*_v1, const void*_v2) {
54     const double*v1=_v1;
55     const double*v2=_v2;
56     if(v1==&undefined_float || v2==&undefined_float)
57         return 0;
58     return *v1==*v2;
59 }
60
61 type_t float_type = {
62     dup: float_clone,
63     hash: float_hash,
64     free: float_destroy,
65     equals: float_equals
66 };
67
68 // ----------------------------- uint ----------------------------------
69
70 int undefined_uint = 0;
71
72 ptroff_t uint_clone(const void*v) {
73     return (ptroff_t)v;
74 }
75 unsigned int uint_hash(const void*v) {return (ptroff_t)v;}
76 void uint_destroy(void*v) {}
77 char uint_equals(const void*v1, const void*v2) {return v1==v2;}
78
79 type_t uint_type = {
80     dup: (dup_func)uint_clone,
81     hash: (hash_func)uint_hash,
82     free: (free_func)uint_destroy,
83     equals: (equals_func)uint_equals
84 };
85
86 // ----------------------------- namespace ----------------------------------
87
88 unsigned int namespace_hash(namespace_t*n)
89 {
90     unsigned int hash = 0;
91     hash = crc32_add_byte(hash, n->access);
92     hash = crc32_add_string(hash, n->name);
93     return hash;
94 }
95
96 unsigned char namespace_equals(const namespace_t*n1, const namespace_t*n2)
97 {
98     if(n1->access != n2->access)
99         return 0;
100     if(!(n1->name) != !(n2->name))
101         return 0;
102     if(n1->name && n2->name && strcmp(n1->name, n2->name))
103         return 0;
104     return 1;
105 }
106
107 char* namespace_to_string(namespace_t*ns)
108 {
109     char*access = 0;
110     U8 type = ns->access;
111     access = access2str(type);
112     char*string = malloc(strlen(access)+strlen(ns->name)+3);
113     sprintf(string, "[%s]%s", access, ns->name);
114     return string;
115 }
116
117 namespace_t* namespace_clone(namespace_t*other)
118 {
119     NEW(namespace_t,n);
120     n->access = other->access;
121     n->name = strdup(other->name);
122     return n;
123 }
124
125 namespace_t* namespace_new(U8 access, const char*name)
126 {
127     namespace_t*ns = malloc(sizeof(namespace_t));
128     memset(ns, 0, sizeof(namespace_t));
129
130     if(access==0) { // autodetect access
131         char*n = strdup(name);
132         if(n[0] == '[') {
133             char*bracket = strchr(n, ']');
134             if(bracket) {
135                 *bracket = 0;
136                 char*a = n+1;
137                 name += (bracket-n)+1;
138                 if(!strcmp(a, "")) access=0x16;
139                 else if(!strcmp(a, "undefined")) access=0x08; // public??
140                 else if(!strcmp(a, "package")) access=0x16;
141                 else if(!strcmp(a, "packageinternal")) access=0x17;
142                 else if(!strcmp(a, "protected")) access=0x18;
143                 else if(!strcmp(a, "explicit")) access=0x19;
144                 else if(!strcmp(a, "staticprotected")) access=0x1a;
145                 else if(!strcmp(a, "private")) access=0x05;
146                 else {
147                     fprintf(stderr, "Undefined access level: [%s]\n", a);
148                     return 0;
149                 }
150             }
151         } else {
152             access = 0x16;
153         }
154         free(n);
155     }
156     ns->access = access;
157     ns->name = strdup(name);
158     return ns;
159 }
160
161 namespace_t* namespace_new_undefined(const char*name) {
162     return namespace_new(0x08, name); // public?
163 }
164 namespace_t* namespace_new_package(const char*name) {
165     return namespace_new(0x16 , name);
166 }
167 namespace_t* namespace_new_packageinternal(const char*name) {
168     return namespace_new(0x17, name);
169 }
170 namespace_t* namespace_new_protected(const char*name) {
171     return namespace_new(0x18, name);
172 }
173 namespace_t* namespace_new_explicit(const char*name) {
174     return namespace_new(0x19, name);
175 }
176 namespace_t* namespace_new_staticprotected(const char*name) {
177     return namespace_new(0x1a, name);
178 }
179 namespace_t* namespace_new_private(const char*name) {
180     return namespace_new(0x05, name);
181 }
182
183 void namespace_destroy(namespace_t*n)
184 {
185     free(n->name);n->name=0;
186     n->access=0x00;
187     free(n);
188 }
189
190 type_t namespace_type = {
191     dup: (dup_func)namespace_clone,
192     hash: (hash_func)namespace_hash,
193     free: (free_func)namespace_destroy,
194     equals: (equals_func)namespace_equals
195 };
196
197 // ---------------------------namespace sets --------------------------------
198
199 unsigned int namespace_set_hash(namespace_set_t*set)
200 {
201     namespace_list_t*l = set->namespaces;
202     unsigned int hash = 0;
203     while(l) {
204         hash = crc32_add_byte(hash, l->namespace->access);
205         hash = crc32_add_string(hash, l->namespace->name);
206         l = l->next;
207     }
208     return hash;
209 }
210
211 int namespace_set_equals(namespace_set_t*m1, namespace_set_t*m2)
212 {
213     namespace_list_t*l1 = m1->namespaces;
214     namespace_list_t*l2 = m2->namespaces;
215     while(l1 && l2) {
216         if(l1->namespace->access != l2->namespace->access)
217             return 0;
218         if(!(l1->namespace->name) != !(l2->namespace->name))
219             return 0;
220         if(strcmp(l1->namespace->name, l2->namespace->name))
221             return 0;
222         l1 = l1->next;
223         l2 = l2->next;
224     }
225     if(l1||l2)
226         return 0;
227     return 1;
228 }
229
230 namespace_set_t* namespace_set_clone(namespace_set_t*other)
231 {
232     NEW(namespace_set_t,set);
233     set->namespaces = list_new();
234     namespace_list_t*l = other->namespaces;
235     while(l) {
236         list_append(set->namespaces, namespace_clone(l->namespace));
237         l = l->next;
238     }
239     return set;
240 }
241 namespace_set_t* namespace_set_new()
242 {
243     NEW(namespace_set_t,set);
244     set->namespaces = list_new();
245     return set;
246 }
247 char* namespace_set_to_string(namespace_set_t*set)
248 {
249     /* TODO: is the order of the namespaces important (does it
250        change the lookup order?). E.g. flex freely shuffles namespaces
251        around.
252        If the order is not important, we can optimize constant pools by sorting
253        the namespaces.
254     */
255     int l = 0;
256     namespace_list_t*lns = set->namespaces;
257     while(lns) {
258         char*s = namespace_to_string(lns->namespace);
259         l += strlen(s)+1;
260         free(s);
261         lns = lns->next;
262     }
263     char*desc = malloc(l+16);
264     strcpy(desc, "{");
265     lns = set->namespaces;
266     while(lns) {
267         char*s = namespace_to_string(lns->namespace);
268         strcat(desc, s);
269         free(s);
270         lns = lns->next;
271         if(lns)
272             strcat(desc, ",");
273     }
274     strcat(desc, "}");
275     return desc;
276 }
277
278 void namespace_set_destroy(namespace_set_t*set)
279 {
280     namespace_list_t*l = set->namespaces;
281     while(l) {
282         namespace_destroy(l->namespace);l->namespace=0;
283         l = l->next;
284     }
285     list_free(set->namespaces);
286     free(set);
287 }
288
289 type_t namespace_set_type = {
290     dup: (dup_func)namespace_set_clone,
291     hash: (hash_func)namespace_set_hash,
292     free: (free_func)namespace_set_destroy,
293     equals: (equals_func)namespace_set_equals
294 };
295
296 // ----------------------------- multiname ----------------------------------
297
298 unsigned int multiname_hash(multiname_t*m)
299 {
300     unsigned int hash = crc32_add_byte(0, m->type);
301     if(m->name) {
302         hash = crc32_add_string(hash, m->name);
303     }
304     if(m->ns) {
305         hash = crc32_add_byte(hash, m->ns->access);
306         hash = crc32_add_string(hash, m->ns->name);
307     }
308     if(m->namespace_set) {
309         namespace_list_t*l = m->namespace_set->namespaces;
310         while(l) {
311             hash = crc32_add_byte(hash, l->namespace->access);
312             hash = crc32_add_string(hash, l->namespace->name);
313             l = l->next;
314         }
315     }
316     return hash;
317 }
318
319 int multiname_equals(multiname_t*m1, multiname_t*m2)
320 {
321     if(m1->type!=m2->type)
322         return 0;
323
324     if((!m1->name) != (!m2->name))
325         return 0;
326     if((!m1->ns) != (!m2->ns))
327         return 0;
328     if((!m1->namespace_set) != (!m2->namespace_set))
329         return 0;
330
331     if(m1->name && m2->name && strcmp(m1->name,m2->name))
332         return 0;
333     if(m1->ns && m2->ns) {
334         if(!namespace_equals(m1->ns, m2->ns))
335             return 0;
336     }
337     if(m1->namespace_set && m2->namespace_set) {
338         if(!namespace_set_equals(m1->namespace_set, m2->namespace_set))
339             return 0;
340     }
341     return 1;
342 }
343
344 multiname_t* multiname_new(namespace_t*ns, const char*name)
345 {
346     NEW(multiname_t,m);
347     m->type = QNAME;
348     m->ns = namespace_clone(ns);
349     m->name = strdup(name);
350     return m;
351 }
352
353 multiname_t* multiname_clone(multiname_t*other)
354 {
355     NEW(multiname_t,m);
356     m->type = other->type;
357     if(other->ns)
358         m->ns = namespace_clone(other->ns);
359     if(other->namespace_set)
360         m->namespace_set = namespace_set_clone(other->namespace_set);
361     if(other->name)
362         m->name = strdup(other->name);
363     return m;
364 }
365
366
367 char* access2str(int type)
368 {
369     if(type==0x08) return "access08";
370     else if(type==0x16) return "package";
371     else if(type==0x17) return "packageinternal";
372     else if(type==0x18) return "protected";
373     else if(type==0x19) return "explicit";
374     else if(type==0x1A) return "staticprotected";
375     else if(type==0x05) return "private";
376     else {
377         fprintf(stderr, "Undefined access type %02x\n", type);
378         return "undefined";
379     }
380 }
381
382 char* multiname_to_string(multiname_t*m)
383 {
384     char*mname = 0;
385     if(!m || m->type==0xff)
386         return strdup("--<UNDEFINED_MULTINAME>--");
387
388     int namelen = m->name?strlen(m->name):1;
389
390     if(m->type==QNAME || m->type==QNAMEA) {
391         mname = malloc(strlen(m->ns->name)+namelen+32);
392         strcpy(mname, "<q");
393         if(m->type == QNAMEA)
394             strcat(mname, ",attr");
395         strcat(mname, ">[");
396         strcat(mname,access2str(m->ns->access));
397         strcat(mname, "]");
398         strcat(mname, m->ns->name);
399         strcat(mname, "::");
400         if(m->name)
401             strcat(mname, m->name);
402         else
403             strcat(mname, "*");
404     } else if(m->type==RTQNAME || m->type==RTQNAMEA) {
405         mname = malloc(namelen+32);
406         strcpy(mname, "<rt");
407         if(m->type == RTQNAMEA) 
408             strcat(mname, ",attr");
409         strcat(mname, ">");
410         if(m->name)
411             strcat(mname, m->name);
412         else
413             strcat(mname, "*");
414     } else if(m->type==RTQNAMEL) {
415         mname = strdup("<l>");
416     } else if(m->type==RTQNAMELA) {
417         mname = strdup("<l,attr>");
418     } else if(m->type==MULTINAME || m->type==MULTINAMEA) {
419         char*s = namespace_set_to_string(m->namespace_set);
420         mname = malloc(strlen(s)+namelen+16);
421         if(m->type == MULTINAME)
422             strcpy(mname,"<multi>");
423         else //MULTINAMEA
424             strcpy(mname,"<multi,attr>");
425         strcat(mname, s);
426         strcat(mname, "::");
427         if(m->name)
428             strcat(mname, m->name);
429         else
430             strcat(mname, "*");
431         free(s);
432     } else if(m->type==MULTINAMEL || m->type==MULTINAMELA) {
433         char*s = namespace_set_to_string(m->namespace_set);
434         mname = malloc(strlen(s)+16);
435         if(m->type == MULTINAMEL)
436             strcpy(mname,"<l,multi>");
437         else //MULTINAMELA
438             strcpy(mname,"<l,multi,attr>");
439         strcat(mname,s);
440         free(s);
441     } else {
442         fprintf(stderr, "Invalid multiname type: %02x\n", m->type);
443     }
444     return mname;
445 }
446
447 multiname_t* multiname_fromstring(const char*name2)
448 {
449     if(!name2)
450         return 0;
451     char*n = strdup(name2);
452     char*p = strstr(n, "::");
453     char*namespace=0,*name=0;
454     if(!p) {
455         if(strchr(n, ':')) {
456             fprintf(stderr, "Error: single ':' in name\n");
457         }
458         namespace = "";
459         name = n;
460     } else {
461         *p = 0;
462         namespace = n;
463         name = p+2;
464         if(strchr(namespace, ':')) {
465             fprintf(stderr, "Error: single ':' in namespace\n");
466         }
467         if(strchr(name, ':')) {
468             fprintf(stderr, "Error: single ':' in qualified name\n");
469         }
470     }
471
472     multiname_t*m = malloc(sizeof(multiname_t));
473     memset(m, 0, sizeof(multiname_t));
474     m->type = QNAME;
475     m->namespace_set = 0;
476     NEW(namespace_t,ns);
477     ns->name= namespace;
478     m->ns = ns;
479     m->name = name;
480     return m;
481 }
482
483 void multiname_destroy(multiname_t*m)
484 {
485     if(m->name) {
486         free((void*)m->name);m->name = 0;
487     }
488     if(m->ns) {
489         namespace_destroy(m->ns);m->ns = 0;
490     }
491     if(m->namespace_set) {
492         namespace_set_destroy(m->namespace_set);m->namespace_set = 0;
493     }
494     free(m);
495 }
496
497 type_t multiname_type = {
498     dup: (dup_func)multiname_clone,
499     hash: (hash_func)multiname_hash,
500     free: (free_func)multiname_destroy,
501     equals: (equals_func)multiname_equals
502 };
503
504 // ------------------------------- pool -------------------------------------
505
506 int pool_register_uint(pool_t*p, unsigned int i)
507 {
508     return array_append_if_new(p->x_uints, (void*)(ptroff_t)i, 0);
509 }
510 int pool_register_int(pool_t*p, int i)
511 {
512     return array_append_if_new(p->x_ints, (void*)(ptroff_t)i, 0);
513 }
514 int pool_register_float(pool_t*p, double d)
515 {
516     return array_append_if_new(p->x_floats, &d, 0);
517 }
518 int pool_register_string(pool_t*pool, const char*s)
519 {
520     if(!s) return 0;
521     return array_append_if_new(pool->x_strings, s, 0);
522 }
523 int pool_register_namespace(pool_t*pool, namespace_t*ns)
524 {
525     if(!ns) return 0;
526     return array_append_if_new(pool->x_namespaces, ns, 0);
527 }
528 int pool_register_namespace_set(pool_t*pool, namespace_set_t*set)
529 {
530     if(!set) return 0;
531     return array_append_if_new(pool->x_namespace_sets, set, 0);
532 }
533 int pool_register_multiname(pool_t*pool, multiname_t*n)
534 {
535     if(!n) return 0;
536     return array_append_if_new(pool->x_multinames, n, 0);
537 }
538 int pool_register_multiname2(pool_t*pool, char*name)
539 {
540     if(!name) return 0;
541     multiname_t*n = multiname_fromstring(name);
542     return array_append_if_new(pool->x_multinames, n, 0);
543 }
544
545
546 int pool_find_uint(pool_t*pool, unsigned int x)
547 {
548     int i = array_find(pool->x_uints, (void*)(ptroff_t)x);
549     if(i<0) {
550         fprintf(stderr, "Couldn't find uint \"%d\" in constant pool\n", x);
551         return 0;
552     }
553     return i;
554 }
555 int pool_find_int(pool_t*pool, int x)
556 {
557     int i = array_find(pool->x_ints, (void*)(ptroff_t)x);
558     if(i<0) {
559         fprintf(stderr, "Couldn't find int \"%d\" in constant pool\n", x);
560         return 0;
561     }
562     return i;
563 }
564 int pool_find_float(pool_t*pool, double x)
565 {
566     int i = array_find(pool->x_ints, &x);
567     if(i<0) {
568         fprintf(stderr, "Couldn't find int \"%d\" in constant pool\n", x);
569         return 0;
570     }
571     return i;
572 }
573 int pool_find_namespace(pool_t*pool, namespace_t*ns)
574 {
575     if(!ns)
576         return 0;
577     int i = array_find(pool->x_namespaces, ns);
578     if(i<0) {
579         char*s = namespace_to_string(ns);
580         fprintf(stderr, "Couldn't find namespace \"%s\" %08x in constant pool\n", s, ns);
581         free(s);
582         return 0;
583     }
584     return i;
585 }
586 int pool_find_namespace_set(pool_t*pool, namespace_set_t*set)
587 {
588     int i = array_find(pool->x_namespace_sets, set);
589     if(i<0) {
590         char*s = namespace_set_to_string(set);
591         fprintf(stderr, "Couldn't find namespace_set \"%s\" in constant pool\n", s);
592         free(s);
593         return 0;
594     }
595     return i;
596 }
597 int pool_find_string(pool_t*pool, const char*s)
598 {
599     int i = array_find(pool->x_strings, s);
600     if(i<0) {
601         fprintf(stderr, "Couldn't find string \"%s\" in constant pool\n", s);
602         *(int*)0=0;
603         return 0;
604     }
605     return i;
606 }
607 int pool_find_multiname(pool_t*pool, multiname_t*name)
608 {
609     int i = array_find(pool->x_multinames, name);
610     if(i<0) {
611         char*s = multiname_to_string(name);
612         fprintf(stderr, "Couldn't find multiname \"%s\" in constant pool\n", s);
613         free(s);
614         return 0;
615     }
616     return i;
617 }
618
619 int pool_lookup_int(pool_t*pool, int i)
620 {
621     return *(int*)array_getkey(pool->x_ints, i);
622 }
623 unsigned int pool_lookup_uint(pool_t*pool, int i)
624 {
625     return *(unsigned int*)array_getkey(pool->x_uints, i);
626 }
627 double pool_lookup_float(pool_t*pool, int i)
628 {
629     return *(double*)array_getkey(pool->x_floats, i);
630 }
631 char*pool_lookup_string(pool_t*pool, int i)
632 {
633     return (char*)array_getkey(pool->x_strings, i);
634 }
635 namespace_t*pool_lookup_namespace(pool_t*pool, int i)
636 {
637     return (namespace_t*)array_getkey(pool->x_namespaces, i);
638 }
639 namespace_set_t*pool_lookup_namespace_set(pool_t*pool, int i)
640 {
641     return (namespace_set_t*)array_getkey(pool->x_namespace_sets, i);
642 }
643 multiname_t*pool_lookup_multiname(pool_t*pool, int i)
644 {
645     return (multiname_t*)array_getkey(pool->x_multinames, i);
646 }
647
648 pool_t*pool_new()
649 {
650     NEW(pool_t, p);
651
652     p->x_ints = array_new2(&uint_type);
653     p->x_uints = array_new2(&uint_type);
654     p->x_floats = array_new2(&float_type);
655     p->x_strings = array_new2(&charptr_type);
656     p->x_namespaces = array_new2(&namespace_type);
657     p->x_namespace_sets = array_new2(&namespace_set_type);
658     p->x_multinames = array_new2(&multiname_type);
659
660     /* add a zero-index entry in each list */
661   
662     array_append(p->x_ints, &undefined_uint, 0);
663     array_append(p->x_uints, &undefined_uint, 0);
664     array_append(p->x_floats, &undefined_float, 0);
665
666     pool_register_string(p, "--<UNDEFINED_STRING>--");
667
668     namespace_t*ns = namespace_new(0,"--<UNDEFINED NAMESPACE>--");
669     pool_register_namespace(p, ns);
670     namespace_destroy(ns);
671
672     namespace_set_t*nsset = namespace_set_new();
673     list_append(nsset->namespaces, namespace_new(0, "--<UNDEFINED NAMESPACE SET>--"));
674     pool_register_namespace_set(p, nsset);
675     namespace_set_destroy(nsset);
676
677     namespace_t*mns = namespace_new(0,"nons");
678     multiname_t*mname = multiname_new(mns,"--<UNDEFINED MULTINAME>--");
679     mname->type = 0xff;
680     pool_register_multiname(p, mname);
681     multiname_destroy(mname);
682     namespace_destroy(mns);
683
684     return p;
685 }
686
687 #define DEBUG if(0)
688 //#define DEBUG
689
690 void pool_read(pool_t*pool, TAG*tag)
691 {
692     int num_ints = swf_GetU30(tag);
693     DEBUG printf("%d ints\n", num_ints);
694     int t;
695     for(t=1;t<num_ints;t++) {
696         S32 v = swf_GetS30(tag);
697         DEBUG printf("int %d) %d\n", t, v);
698         array_append(pool->x_ints, (void*)(ptroff_t)v, 0);
699     }
700
701     int num_uints = swf_GetU30(tag);
702     DEBUG printf("%d uints\n", num_uints);
703     for(t=1;t<num_uints;t++) {
704         U32 v = swf_GetU30(tag);
705         DEBUG printf("uint %d) %d\n", t, v);
706         array_append(pool->x_uints, (void*)(ptroff_t)v, 0);
707     }
708     
709     int num_floats = swf_GetU30(tag);
710     DEBUG printf("%d floats\n", num_floats);
711     for(t=1;t<num_floats;t++) {
712         double d = swf_GetD64(tag);
713         DEBUG printf("float %d) %f\n", t, d);
714         array_append(pool->x_floats, &d, 0);
715     }
716     
717     int num_strings = swf_GetU30(tag);
718     DEBUG printf("%d strings\n", num_strings);
719     for(t=1;t<num_strings;t++) {
720         int len = swf_GetU30(tag);
721         char*s = malloc(len+1);
722         swf_GetBlock(tag, s, len);
723         s[len] = 0;
724         array_append(pool->x_strings, s, 0);
725         free(s);
726         DEBUG printf("%d) \"%s\"\n", t, pool->x_strings->d[t].name);
727     }
728     int num_namespaces = swf_GetU30(tag);
729     DEBUG printf("%d namespaces\n", num_namespaces);
730     for(t=1;t<num_namespaces;t++) {
731         U8 type = swf_GetU8(tag);
732         int namenr = swf_GetU30(tag);
733         const char*name = array_getkey(pool->x_strings, namenr);
734         namespace_t*ns = namespace_new(type, name);
735         array_append(pool->x_namespaces, ns, 0);
736         DEBUG printf("%d) \"%s\"\n", t, namespace_to_string(ns));
737         namespace_destroy(ns);
738     }
739     int num_sets = swf_GetU30(tag);
740     DEBUG printf("%d namespace sets\n", num_sets);
741     for(t=1;t<num_sets;t++) {
742         int count = swf_GetU30(tag);
743         int s;
744         
745         NEW(namespace_set_t, nsset);
746         for(s=0;s<count;s++) {
747             int nsnr = swf_GetU30(tag);
748             namespace_t*ns = (namespace_t*)array_getkey(pool->x_namespaces, nsnr);
749             list_append(nsset->namespaces, namespace_clone(ns));
750         }
751         array_append(pool->x_namespace_sets, nsset, 0);
752         DEBUG printf("set %d) %s\n", t, namespace_set_to_string(nsset));
753         namespace_set_destroy(nsset);
754     }
755
756     int num_multinames = swf_GetU30(tag);
757     DEBUG printf("%d multinames\n", num_multinames);
758     for(t=1;t<num_multinames;t++) {
759         multiname_t m;
760         memset(&m, 0, sizeof(multiname_t));
761         m.type = swf_GetU8(tag);
762         if(m.type==0x07 || m.type==0x0d) {
763             int namespace_index = swf_GetU30(tag);
764             m.ns = (namespace_t*)array_getkey(pool->x_namespaces, namespace_index);
765             int name_index = swf_GetU30(tag);
766             if(name_index) // 0 = '*' (any)
767                 m.name = array_getkey(pool->x_strings, name_index);
768         } else if(m.type==0x0f || m.type==0x10) {
769             int name_index = swf_GetU30(tag);
770             if(name_index) // 0 = '*' (any name)
771                 m.name = array_getkey(pool->x_strings, name_index);
772         } else if(m.type==0x11 || m.type==0x12) {
773         } else if(m.type==0x09 || m.type==0x0e) {
774             int name_index = swf_GetU30(tag);
775             int namespace_set_index = swf_GetU30(tag);
776             if(name_index)
777                 m.name = array_getkey(pool->x_strings, name_index);
778             m.namespace_set = (namespace_set_t*)array_getkey(pool->x_namespace_sets, namespace_set_index);
779         } else if(m.type==0x1b || m.type==0x1c) {
780             int namespace_set_index = swf_GetU30(tag);
781             m.namespace_set = (namespace_set_t*)array_getkey(pool->x_namespace_sets, namespace_set_index);
782         } else {
783             printf("can't parse type %d multinames yet\n", m.type);
784         }
785         DEBUG printf("multiname %d) %s\n", t, multiname_to_string(&m));
786         array_append(pool->x_multinames, &m, 0);
787     }
788
789
790 void pool_write(pool_t*pool, TAG*tag)
791 {
792     int t;
793     
794     /* make sure that all namespaces used by multinames / namespace sets
795        and all strings used by namespaces exist */
796
797     for(t=1;t<pool->x_multinames->num;t++) {
798         multiname_t*m = (multiname_t*)array_getkey(pool->x_multinames, t);
799         if(m->ns) {
800             pool_register_namespace(pool, m->ns);
801         }
802         if(m->namespace_set) {
803             pool_register_namespace_set(pool, m->namespace_set);
804         }
805         if(m->name) {
806             pool_register_string(pool, m->name);
807         }
808     }
809     for(t=1;t<pool->x_namespace_sets->num;t++) {
810         namespace_set_t*set = (namespace_set_t*)array_getkey(pool->x_namespace_sets, t);
811         namespace_list_t*i = set->namespaces;
812         while(i) {
813             pool_register_namespace(pool, i->namespace);
814             i = i->next;
815         }
816     }
817     for(t=1;t<pool->x_namespaces->num;t++) {
818         namespace_t*ns= (namespace_t*)array_getkey(pool->x_namespaces, t);
819         array_append_if_new(pool->x_strings, ns->name, 0);
820     }
821
822     /* write data */
823     swf_SetU30(tag, pool->x_ints->num>1?pool->x_ints->num:0);
824     for(t=1;t<pool->x_ints->num;t++) {
825         S32 val = (ptroff_t)array_getkey(pool->x_ints, t);
826         swf_SetS30(tag, val);
827     }
828     swf_SetU30(tag, pool->x_uints->num>1?pool->x_uints->num:0);
829     for(t=1;t<pool->x_uints->num;t++) {
830         swf_SetU30(tag, (ptroff_t)array_getkey(pool->x_uints, t));
831     }
832     swf_SetU30(tag, pool->x_floats->num>1?pool->x_floats->num:0);
833     for(t=1;t<pool->x_floats->num;t++) {
834         array_getvalue(pool->x_floats, t);
835         swf_SetD64(tag, 0.0); // fixme
836     }
837     swf_SetU30(tag, pool->x_strings->num>1?pool->x_strings->num:0);
838     for(t=1;t<pool->x_strings->num;t++) {
839         swf_SetU30String(tag, array_getkey(pool->x_strings, t));
840     }
841     swf_SetU30(tag, pool->x_namespaces->num>1?pool->x_namespaces->num:0);
842     for(t=1;t<pool->x_namespaces->num;t++) {
843         namespace_t*ns= (namespace_t*)array_getkey(pool->x_namespaces, t);
844         const char*name = ns->name;
845         int i = pool_find_string(pool, name);
846         swf_SetU8(tag, ns->access);
847         swf_SetU30(tag, i);
848     }
849     swf_SetU30(tag, pool->x_namespace_sets->num>1?pool->x_namespace_sets->num:0);
850     for(t=1;t<pool->x_namespace_sets->num;t++) {
851         namespace_set_t*set = (namespace_set_t*)array_getkey(pool->x_namespace_sets, t);
852         namespace_list_t*i = set->namespaces; 
853         int len = list_length(i);
854         swf_SetU30(tag, len);
855         while(i) {
856             int index = pool_find_namespace(pool, i->namespace);
857             swf_SetU30(tag, index);
858             i = i->next;
859         }
860     }
861
862     swf_SetU30(tag, pool->x_multinames->num>1?pool->x_multinames->num:0);
863     for(t=1;t<pool->x_multinames->num;t++) {
864         multiname_t*m = (multiname_t*)array_getkey(pool->x_multinames, t);
865         swf_SetU8(tag, m->type);
866
867         if(m->ns) {
868             assert(m->type==0x07 || m->type==0x0d);
869             int i = pool_find_namespace(pool, m->ns);
870             if(i<0) fprintf(stderr, "internal error: unregistered namespace %02x %s %s\n", m->ns->access, access2str(m->ns->access), m->ns->name);
871             swf_SetU30(tag, i);
872         } else {
873             assert(m->type!=0x07 && m->type!=0x0d);
874         }
875         if(m->name) {
876             assert(m->type==0x09 || m->type==0x0e || m->type==0x07 || m->type==0x0d || m->type==0x0f || m->type==0x10);
877             int i = pool_find_string(pool, m->name);
878             if(i<0) fprintf(stderr, "internal error: unregistered name\n");
879             swf_SetU30(tag, i);
880         } else {
881             assert(m->type!=0x09 && m->type!=0x0e && m->type!=0x07 && m->type!=0x0d && m->type!=0x0f && m->type!=0x10);
882         }
883         if(m->namespace_set) {
884             assert(m->type==0x09 || m->type==0x0e || m->type==0x1c || m->type==0x1b);
885             int i = pool_find_namespace_set(pool, m->namespace_set);
886             if(i<0) fprintf(stderr, "internal error: unregistered namespace set\n");
887             swf_SetU30(tag, i);
888         } else {
889             assert(m->type!=0x09 && m->type!=0x0e && m->type!=0x1c && m->type!=0x1b);
890         }
891     }
892 }
893
894
895 void pool_destroy(pool_t*pool)
896 {
897     int t;
898     array_free(pool->x_ints);
899     array_free(pool->x_uints);
900     array_free(pool->x_floats);
901     array_free(pool->x_strings);
902     array_free(pool->x_namespaces);
903     array_free(pool->x_namespace_sets);
904     array_free(pool->x_multinames);
905     free(pool);
906 }