reworked tristate logic
[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     return mname;
559 }
560
561 multiname_t* multiname_fromstring(const char*name2)
562 {
563     if(!name2)
564         return 0;
565     char*n = strdup(name2);
566     char*p = strstr(n, "::");
567     char*namespace=0,*name=0;
568     if(!p) {
569         if(strchr(n, ':')) {
570             fprintf(stderr, "Error: single ':' in name\n");
571         }
572         namespace = "";
573         name = n;
574     } else {
575         *p = 0;
576         namespace = n;
577         name = p+2;
578         if(strchr(namespace, ':')) {
579             fprintf(stderr, "Error: single ':' in namespace\n");
580         }
581         if(strchr(name, ':')) {
582             fprintf(stderr, "Error: single ':' in qualified name\n");
583         }
584     }
585
586     multiname_t*m = malloc(sizeof(multiname_t));
587     memset(m, 0, sizeof(multiname_t));
588     m->type = QNAME;
589     m->namespace_set = 0;
590     m->ns = namespace_fromstring(namespace);
591     m->name = name?strdup(name):0;
592     free(n);
593     return m;
594 }
595
596 void multiname_destroy(multiname_t*m)
597 {
598     if(m) {
599         if(m->name) {
600             free((void*)m->name);m->name = 0;
601         }
602         if(m->ns) {
603             namespace_destroy(m->ns);m->ns = 0;
604         }
605         if(m->namespace_set) {
606             namespace_set_destroy(m->namespace_set);m->namespace_set = 0;
607         }
608         free(m);
609     }
610 }
611
612 type_t multiname_type = {
613     dup: (dup_func)multiname_clone,
614     hash: (hash_func)multiname_hash,
615     free: (free_func)multiname_destroy,
616     equals: (equals_func)multiname_equals
617 };
618
619 // ------------------------------- pool -------------------------------------
620
621 int pool_register_uint(pool_t*p, unsigned int i)
622 {
623     int pos = array_append_if_new(p->x_uints, &i, 0);
624     assert(pos!=0);
625     return pos;
626 }
627 int pool_register_int(pool_t*p, int i)
628 {
629     int pos = array_append_if_new(p->x_ints, &i, 0);
630     assert(pos!=0);
631     return pos;
632 }
633 int pool_register_float(pool_t*p, double d)
634 {
635     int pos = array_append_if_new(p->x_floats, &d, 0);
636     assert(pos!=0);
637     return pos;
638 }
639 int pool_register_string(pool_t*pool, const char*s)
640 {
641     if(!s) return 0;
642     int pos = array_append_if_new(pool->x_strings, s, 0);
643     assert(pos!=0);
644     return pos;
645 }
646 int pool_register_namespace(pool_t*pool, namespace_t*ns)
647 {
648     if(!ns) return 0;
649     int pos = array_append_if_new(pool->x_namespaces, ns, 0);
650     assert(pos!=0);
651     return pos;
652 }
653 int pool_register_namespace_set(pool_t*pool, namespace_set_t*set)
654 {
655     if(!set) return 0;
656     int pos = array_append_if_new(pool->x_namespace_sets, set, 0);
657     assert(pos!=0);
658     return pos;
659 }
660 int pool_register_multiname(pool_t*pool, multiname_t*n)
661 {
662     if(!n) return 0;
663     int pos = array_append_if_new(pool->x_multinames, n, 0);
664     if(pos==0) {
665         *(int*)0=0xdead;
666     }
667     assert(pos!=0);
668     return pos;
669 }
670 int pool_register_multiname2(pool_t*pool, char*name)
671 {
672     if(!name) return 0;
673     multiname_t*n = multiname_fromstring(name);
674     int pos = array_append_if_new(pool->x_multinames, n, 0);
675     multiname_destroy(n);
676     assert(pos!=0);
677     return pos;
678 }
679
680
681 int pool_find_uint(pool_t*pool, unsigned int x)
682 {
683     int i = array_find(pool->x_uints, &x);
684     if(i<=0) {
685         fprintf(stderr, "Couldn't find uint \"%d\" in constant pool\n", x);
686         return 0;
687     }
688     return i;
689 }
690 int pool_find_int(pool_t*pool, int x)
691 {
692     int i = array_find(pool->x_ints, &x);
693     if(i<=0) {
694         fprintf(stderr, "Couldn't find int \"%d\" in constant pool\n", x);
695         return 0;
696     }
697     return i;
698 }
699 int pool_find_float(pool_t*pool, double x)
700 {
701     int i = array_find(pool->x_ints, &x);
702     if(i<=0) {
703         fprintf(stderr, "Couldn't find int \"%d\" in constant pool\n", x);
704         return 0;
705     }
706     return i;
707 }
708 int pool_find_namespace(pool_t*pool, namespace_t*ns)
709 {
710     if(!ns)
711         return 0;
712     int i = array_find(pool->x_namespaces, ns);
713     if(i<=0) {
714         char*s = namespace_to_string(ns);
715         fprintf(stderr, "Couldn't find namespace \"%s\" %08x in constant pool\n", s, ns);
716         free(s);
717         return 0;
718     }
719     return i;
720 }
721 int pool_find_namespace_set(pool_t*pool, namespace_set_t*set)
722 {
723     if(!set)
724         return 0;
725     int i = array_find(pool->x_namespace_sets, set);
726     if(i<=0) {
727         char*s = namespace_set_to_string(set);
728         fprintf(stderr, "Couldn't find namespace_set \"%s\" in constant pool\n", s);
729         free(s);
730         return 0;
731     }
732     return i;
733 }
734 int pool_find_string(pool_t*pool, const char*s)
735 {
736     if(!s)
737         return 0;
738     int i = array_find(pool->x_strings, s);
739     if(i<=0) {
740         fprintf(stderr, "Couldn't find string \"%s\" in constant pool\n", s);
741         return 0;
742     }
743     return i;
744 }
745 int pool_find_multiname(pool_t*pool, multiname_t*name)
746 {
747     if(!name)
748         return 0;
749     int i = array_find(pool->x_multinames, name);
750     if(i<=0) {
751         char*s = multiname_to_string(name);
752         fprintf(stderr, "Couldn't find multiname \"%s\" in constant pool\n", s);
753         free(s);
754         return 0;
755     }
756     return i;
757 }
758
759 int pool_lookup_int(pool_t*pool, int i)
760 {
761     if(!i) return 0;
762     return *(int*)array_getkey(pool->x_ints, i);
763 }
764 unsigned int pool_lookup_uint(pool_t*pool, int i)
765 {
766     if(!i) return 0;
767     return *(unsigned int*)array_getkey(pool->x_uints, i);
768 }
769 double pool_lookup_float(pool_t*pool, int i)
770 {
771     if(!i) return __builtin_nan("");
772     return *(double*)array_getkey(pool->x_floats, i);
773 }
774 char*pool_lookup_string(pool_t*pool, int i)
775 {
776     return (char*)array_getkey(pool->x_strings, i);
777 }
778 namespace_t*pool_lookup_namespace(pool_t*pool, int i)
779 {
780     return (namespace_t*)array_getkey(pool->x_namespaces, i);
781 }
782 namespace_set_t*pool_lookup_namespace_set(pool_t*pool, int i)
783 {
784     return (namespace_set_t*)array_getkey(pool->x_namespace_sets, i);
785 }
786 multiname_t*pool_lookup_multiname(pool_t*pool, int i)
787 {
788     return (multiname_t*)array_getkey(pool->x_multinames, i);
789 }
790
791 pool_t*pool_new()
792 {
793     NEW(pool_t, p);
794
795     p->x_ints = array_new2(&uint_type);
796     p->x_uints = array_new2(&uint_type);
797     p->x_floats = array_new2(&float_type);
798     p->x_strings = array_new2(&charptr_type);
799     p->x_namespaces = array_new2(&namespace_type);
800     p->x_namespace_sets = array_new2(&namespace_set_type);
801     p->x_multinames = array_new2(&multiname_type);
802
803     /* add a zero-index entry in each list */
804   
805     array_append(p->x_ints, 0, 0);
806     array_append(p->x_uints, 0, 0);
807     array_append(p->x_floats, 0, 0);
808     array_append(p->x_strings, 0, 0);
809     array_append(p->x_namespaces, 0, 0);
810     array_append(p->x_namespace_sets, 0, 0);
811     array_append(p->x_multinames, 0, 0);
812     return p;
813 }
814
815 #define DEBUG if(0)
816 //#define DEBUG
817
818 void pool_read(pool_t*pool, TAG*tag)
819 {
820     int num_ints = swf_GetU30(tag);
821     DEBUG printf("%d ints\n", num_ints);
822     int t;
823     for(t=1;t<num_ints;t++) {
824         S32 v = swf_GetS30(tag);
825         DEBUG printf("int %d) %d\n", t, v);
826         array_append(pool->x_ints, &v, 0);
827     }
828
829     int num_uints = swf_GetU30(tag);
830     DEBUG printf("%d uints\n", num_uints);
831     for(t=1;t<num_uints;t++) {
832         U32 v = swf_GetU30(tag);
833         DEBUG printf("uint %d) %d\n", t, v);
834         array_append(pool->x_uints, &v, 0);
835     }
836     
837     int num_floats = swf_GetU30(tag);
838     DEBUG printf("%d floats\n", num_floats);
839     for(t=1;t<num_floats;t++) {
840         double d = swf_GetD64(tag);
841         DEBUG printf("float %d) %f\n", t, d);
842         array_append(pool->x_floats, &d, 0);
843     }
844     
845     int num_strings = swf_GetU30(tag);
846     DEBUG printf("%d strings\n", num_strings);
847     for(t=1;t<num_strings;t++) {
848         int len = swf_GetU30(tag);
849         char*s = malloc(len+1);
850         swf_GetBlock(tag, s, len);
851         s[len] = 0;
852         array_append(pool->x_strings, s, 0);
853         free(s);
854         DEBUG printf("%d) \"%s\"\n", t, pool->x_strings->d[t].name);
855     }
856     int num_namespaces = swf_GetU30(tag);
857     DEBUG printf("%d namespaces\n", num_namespaces);
858     for(t=1;t<num_namespaces;t++) {
859         U8 type = swf_GetU8(tag);
860         int namenr = swf_GetU30(tag);
861         const char*name = ""; 
862         if(namenr) //spec page 22: "a value of zero denotes an empty string"
863             name = array_getkey(pool->x_strings, namenr);
864         namespace_t*ns = namespace_new(type, name);
865         array_append(pool->x_namespaces, ns, 0);
866         DEBUG printf("%d) %02x \"%s\"\n", t, type, namespace_to_string(ns));
867         namespace_destroy(ns);
868     }
869     int num_sets = swf_GetU30(tag);
870     DEBUG printf("%d namespace sets\n", num_sets);
871     for(t=1;t<num_sets;t++) {
872         int count = swf_GetU30(tag);
873         int s;
874         
875         NEW(namespace_set_t, nsset);
876         for(s=0;s<count;s++) {
877             int nsnr = swf_GetU30(tag);
878             if(!nsnr)
879                 fprintf(stderr, "Zero entry in namespace set\n");
880             namespace_t*ns = (namespace_t*)array_getkey(pool->x_namespaces, nsnr);
881             list_append(nsset->namespaces, namespace_clone(ns));
882         }
883         array_append(pool->x_namespace_sets, nsset, 0);
884         DEBUG printf("set %d) %s\n", t, namespace_set_to_string(nsset));
885         namespace_set_destroy(nsset);
886     }
887
888     int num_multinames = swf_GetU30(tag);
889     DEBUG printf("%d multinames\n", num_multinames);
890     for(t=1;t<num_multinames;t++) {
891         multiname_t m;
892         memset(&m, 0, sizeof(multiname_t));
893         m.type = swf_GetU8(tag);
894         if(m.type==0x07 || m.type==0x0d) {
895             int namespace_index = swf_GetU30(tag);
896             m.ns = (namespace_t*)array_getkey(pool->x_namespaces, namespace_index);
897             int name_index = swf_GetU30(tag);
898             if(name_index) // 0 = '*' (any)
899                 m.name = array_getkey(pool->x_strings, name_index);
900         } else if(m.type==0x0f || m.type==0x10) {
901             int name_index = swf_GetU30(tag);
902             if(name_index) // 0 = '*' (any name)
903                 m.name = array_getkey(pool->x_strings, name_index);
904         } else if(m.type==0x11 || m.type==0x12) {
905         } else if(m.type==0x09 || m.type==0x0e) {
906             int name_index = swf_GetU30(tag);
907             int namespace_set_index = swf_GetU30(tag);
908             if(name_index)
909                 m.name = array_getkey(pool->x_strings, name_index);
910             m.namespace_set = (namespace_set_t*)array_getkey(pool->x_namespace_sets, namespace_set_index);
911         } else if(m.type==0x1b || m.type==0x1c) {
912             int namespace_set_index = swf_GetU30(tag);
913             m.namespace_set = (namespace_set_t*)array_getkey(pool->x_namespace_sets, namespace_set_index);
914         } else {
915             printf("can't parse type %d multinames yet\n", m.type);
916         }
917         DEBUG printf("multiname %d) %s\n", t, multiname_to_string(&m));
918         array_append(pool->x_multinames, &m, 0);
919     }
920     printf("%d ints\n", num_ints);
921     printf("%d uints\n", num_uints);
922     printf("%d strings\n", num_strings);
923     printf("%d namespaces\n", num_namespaces);
924     printf("%d namespace sets\n", num_sets);
925     printf("%d multinames\n", num_multinames);
926
927
928 void pool_write(pool_t*pool, TAG*tag)
929 {
930     int t;
931     
932     /* make sure that all namespaces used by multinames / namespace sets
933        and all strings used by namespaces exist */
934
935     for(t=1;t<pool->x_multinames->num;t++) {
936         multiname_t*m = (multiname_t*)array_getkey(pool->x_multinames, t);
937         if(m->ns) {
938             pool_register_namespace(pool, m->ns);
939         }
940         if(m->namespace_set) {
941             pool_register_namespace_set(pool, m->namespace_set);
942         }
943         if(m->name) {
944             pool_register_string(pool, m->name);
945         }
946     }
947     for(t=1;t<pool->x_namespace_sets->num;t++) {
948         namespace_set_t*set = (namespace_set_t*)array_getkey(pool->x_namespace_sets, t);
949         namespace_list_t*i = set->namespaces;
950         while(i) {
951             pool_register_namespace(pool, i->namespace);
952             i = i->next;
953         }
954     }
955     for(t=1;t<pool->x_namespaces->num;t++) {
956         namespace_t*ns= (namespace_t*)array_getkey(pool->x_namespaces, t);
957         if(ns->name && ns->name[0])
958             array_append_if_new(pool->x_strings, ns->name, 0);
959     }
960
961     /* write data */
962     swf_SetU30(tag, pool->x_ints->num>1?pool->x_ints->num:0);
963     for(t=1;t<pool->x_ints->num;t++) {
964         S32 val = *(int*)array_getkey(pool->x_ints, t);
965         swf_SetS30(tag, val);
966     }
967     swf_SetU30(tag, pool->x_uints->num>1?pool->x_uints->num:0);
968     for(t=1;t<pool->x_uints->num;t++) {
969         swf_SetU30(tag, *(unsigned int*)array_getkey(pool->x_uints, t));
970     }
971     swf_SetU30(tag, pool->x_floats->num>1?pool->x_floats->num:0);
972     for(t=1;t<pool->x_floats->num;t++) {
973         array_getvalue(pool->x_floats, t);
974         swf_SetD64(tag, 0.0); // fixme
975     }
976     swf_SetU30(tag, pool->x_strings->num>1?pool->x_strings->num:0);
977     for(t=1;t<pool->x_strings->num;t++) {
978         swf_SetU30String(tag, array_getkey(pool->x_strings, t));
979     }
980     swf_SetU30(tag, pool->x_namespaces->num>1?pool->x_namespaces->num:0);
981     for(t=1;t<pool->x_namespaces->num;t++) {
982         namespace_t*ns= (namespace_t*)array_getkey(pool->x_namespaces, t);
983         swf_SetU8(tag, ns->access);
984         const char*name = ns->name;
985         int i = 0;
986         if(name && name[0])
987             i = pool_find_string(pool, name);
988         swf_SetU30(tag, i);
989     }
990     swf_SetU30(tag, pool->x_namespace_sets->num>1?pool->x_namespace_sets->num:0);
991     for(t=1;t<pool->x_namespace_sets->num;t++) {
992         namespace_set_t*set = (namespace_set_t*)array_getkey(pool->x_namespace_sets, t);
993         namespace_list_t*i = set->namespaces; 
994         int len = list_length(i);
995         swf_SetU30(tag, len);
996         while(i) {
997             int index = pool_find_namespace(pool, i->namespace);
998             swf_SetU30(tag, index);
999             i = i->next;
1000         }
1001     }
1002
1003     swf_SetU30(tag, pool->x_multinames->num>1?pool->x_multinames->num:0);
1004     for(t=1;t<pool->x_multinames->num;t++) {
1005         multiname_t*m = (multiname_t*)array_getkey(pool->x_multinames, t);
1006         swf_SetU8(tag, m->type);
1007
1008         if(m->ns) {
1009             assert(m->type==0x07 || m->type==0x0d);
1010             int i = pool_find_namespace(pool, m->ns);
1011             if(i<0) fprintf(stderr, "internal error: unregistered namespace %02x %s %s\n", m->ns->access, access2str(m->ns->access), m->ns->name);
1012             swf_SetU30(tag, i);
1013         } else {
1014             assert(m->type!=0x07 && m->type!=0x0d);
1015         }
1016         if(m->name) {
1017             assert(m->type==0x09 || m->type==0x0e || m->type==0x07 || m->type==0x0d || m->type==0x0f || m->type==0x10);
1018             int i = pool_find_string(pool, m->name);
1019             if(i<0) fprintf(stderr, "internal error: unregistered name\n");
1020             swf_SetU30(tag, i);
1021         } else {
1022             assert(m->type!=0x09 && m->type!=0x0e && m->type!=0x07 && m->type!=0x0d && m->type!=0x0f && m->type!=0x10);
1023         }
1024         if(m->namespace_set) {
1025             assert(m->type==0x09 || m->type==0x0e || m->type==0x1c || m->type==0x1b);
1026             int i = pool_find_namespace_set(pool, m->namespace_set);
1027             if(i<0) fprintf(stderr, "internal error: unregistered namespace set\n");
1028             swf_SetU30(tag, i);
1029         } else {
1030             assert(m->type!=0x09 && m->type!=0x0e && m->type!=0x1c && m->type!=0x1b);
1031         }
1032     }
1033 }
1034
1035
1036 void pool_destroy(pool_t*pool)
1037 {
1038     int t;
1039     array_free(pool->x_ints);
1040     array_free(pool->x_uints);
1041     array_free(pool->x_floats);
1042     array_free(pool->x_strings);
1043     array_free(pool->x_namespaces);
1044     array_free(pool->x_namespace_sets);
1045     array_free(pool->x_multinames);
1046     free(pool);
1047 }