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