renamed 'package' to 'public'
[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_tostring(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, "public")) access=0x16;
215             else if(!strcmp(a, "packageinternal")) access=0x17;
216             else if(!strcmp(a, "protected")) access=0x18;
217             else if(!strcmp(a, "explicit")) access=0x19;
218             else if(!strcmp(a, "staticprotected")) access=0x1a;
219             else if(!strcmp(a, "private")) access=0x05;
220             else {
221                 fprintf(stderr, "Undefined access level: [%s]\n", a);
222                 free(n);
223                 return 0;
224             }
225         }
226         ns->access = access;
227         ns->name = strdup(name);
228         free(n);
229         return ns;
230     } else {
231         ns->access = 0x16;
232         ns->name = strdup(name);
233         return ns;
234     }
235 }
236
237 namespace_t* namespace_new(U8 access, const char*name)
238 {
239     namespace_t*ns = malloc(sizeof(namespace_t));
240     ns->access = access;
241     /* not sure what namespaces with empty strings are good for, but they *do* exist */
242     ns->name = name?strdup(name):0;
243     return ns;
244 }
245 namespace_t* namespace_new_undefined(const char*name) {
246     return namespace_new(0x08, name); // public?
247 }
248 namespace_t* namespace_new_package(const char*name) {
249     return namespace_new(0x16 , name);
250 }
251 namespace_t* namespace_new_packageinternal(const char*name) {
252     return namespace_new(0x17, name);
253 }
254 namespace_t* namespace_new_protected(const char*name) {
255     return namespace_new(0x18, name);
256 }
257 namespace_t* namespace_new_explicit(const char*name) {
258     return namespace_new(0x19, name);
259 }
260 namespace_t* namespace_new_staticprotected(const char*name) {
261     return namespace_new(0x1a, name);
262 }
263 namespace_t* namespace_new_private(const char*name) {
264     return namespace_new(0x05, name);
265 }
266
267 void namespace_destroy(namespace_t*n)
268 {
269     if(n) {
270         free(n->name);n->name=0;
271         n->access=0x00;
272         free(n);
273     }
274 }
275
276 type_t namespace_type = {
277     dup: (dup_func)namespace_clone,
278     hash: (hash_func)namespace_hash,
279     free: (free_func)namespace_destroy,
280     equals: (equals_func)namespace_equals
281 };
282
283 // ---------------------------namespace sets --------------------------------
284
285 unsigned int namespace_set_hash(namespace_set_t*set)
286 {
287     if(!set)
288         return 0;
289     namespace_list_t*l = set->namespaces;
290     unsigned int hash = 0;
291     while(l) {
292         hash = crc32_add_byte(hash, l->namespace->access);
293         hash = crc32_add_string(hash, l->namespace->name);
294         l = l->next;
295     }
296     return hash;
297 }
298
299 int namespace_set_equals(namespace_set_t*m1, namespace_set_t*m2)
300 {
301     if(!m1 || !m2)
302         return m1==m2;
303     namespace_list_t*l1 = m1->namespaces;
304     namespace_list_t*l2 = m2->namespaces;
305     while(l1 && l2) {
306         if(l1->namespace->access != l2->namespace->access)
307             return 0;
308         if(!(l1->namespace->name) != !(l2->namespace->name))
309             return 0;
310         if(l1->namespace->name && l2->namespace->name && strcmp(l1->namespace->name, l2->namespace->name))
311             return 0;
312         l1 = l1->next;
313         l2 = l2->next;
314     }
315     if(l1||l2)
316         return 0;
317     return 1;
318 }
319
320 namespace_set_t* namespace_set_clone(namespace_set_t*other)
321 {
322     if(!other)
323         return 0;
324     NEW(namespace_set_t,set);
325     set->namespaces = list_new();
326     namespace_list_t*l = other->namespaces;
327     while(l) {
328         list_append(set->namespaces, namespace_clone(l->namespace));
329         l = l->next;
330     }
331     return set;
332 }
333 namespace_set_t* namespace_set_new()
334 {
335     NEW(namespace_set_t,set);
336     set->namespaces = list_new();
337     return set;
338 }
339 char* namespace_set_tostring(namespace_set_t*set)
340 {
341     if(!set)
342         return strdup("NULL");
343     /* TODO: is the order of the namespaces important (does it
344        change the lookup order?). E.g. flex freely shuffles namespaces
345        around.
346        If the order is not important, we can optimize constant pools by sorting
347        the namespaces.
348     */
349     int l = 0;
350     namespace_list_t*lns = set->namespaces;
351     while(lns) {
352         char*s = namespace_tostring(lns->namespace);
353         l += strlen(s)+1;
354         free(s);
355         lns = lns->next;
356     }
357     char*desc = malloc(l+16);
358     strcpy(desc, "{");
359     lns = set->namespaces;
360     while(lns) {
361         char*s = namespace_tostring(lns->namespace);
362         strcat(desc, s);
363         free(s);
364         lns = lns->next;
365         if(lns)
366             strcat(desc, ",");
367     }
368     strcat(desc, "}");
369     return desc;
370 }
371
372 void namespace_set_destroy(namespace_set_t*set)
373 {
374     if(set) {
375         namespace_list_t*l = set->namespaces;
376         while(l) {
377             namespace_destroy(l->namespace);l->namespace=0;
378             l = l->next;
379         }
380         list_free(set->namespaces);
381         free(set);
382     }
383 }
384
385 type_t namespace_set_type = {
386     dup: (dup_func)namespace_set_clone,
387     hash: (hash_func)namespace_set_hash,
388     free: (free_func)namespace_set_destroy,
389     equals: (equals_func)namespace_set_equals
390 };
391
392 // ----------------------------- multiname ----------------------------------
393
394 unsigned int multiname_hash(multiname_t*m)
395 {
396     if(!m)
397         return 0;
398     unsigned int hash = crc32_add_byte(0, m->type);
399     if(m->name) {
400         hash = crc32_add_string(hash, m->name);
401     }
402     if(m->ns) {
403         hash = crc32_add_byte(hash, m->ns->access);
404         hash = crc32_add_string(hash, m->ns->name);
405     }
406     if(m->namespace_set) {
407         namespace_list_t*l = m->namespace_set->namespaces;
408         while(l) {
409             hash = crc32_add_byte(hash, l->namespace->access);
410             hash = crc32_add_string(hash, l->namespace->name);
411             l = l->next;
412         }
413     }
414     return hash;
415 }
416
417 int multiname_equals(multiname_t*m1, multiname_t*m2)
418 {
419     if(!m1 || !m2)
420         return m1==m2;
421     if(m1->type!=m2->type)
422         return 0;
423
424     if((!m1->name) != (!m2->name))
425         return 0;
426     if((!m1->ns) != (!m2->ns))
427         return 0;
428     if((!m1->namespace_set) != (!m2->namespace_set))
429         return 0;
430
431     if(m1->name && m2->name && strcmp(m1->name,m2->name))
432         return 0;
433     if(m1->ns && m2->ns) {
434         if(!namespace_equals(m1->ns, m2->ns))
435             return 0;
436     }
437     if(m1->namespace_set && m2->namespace_set) {
438         if(!namespace_set_equals(m1->namespace_set, m2->namespace_set))
439             return 0;
440     }
441     return 1;
442 }
443
444 multiname_t* multiname_new(namespace_t*ns, const char*name)
445 {
446     NEW(multiname_t,m);
447     m->type = QNAME;
448     if(!ns) {
449         m->ns = namespace_new_packageinternal("");
450     } else {
451         m->ns = namespace_clone(ns);
452     }
453     m->name = strdup(name);
454     return m;
455 }
456
457 multiname_t* multiname_clone(multiname_t*other)
458 {
459     if(!other)
460         return 0;
461     NEW(multiname_t,m);
462     m->type = other->type;
463     if(other->ns)
464         m->ns = namespace_clone(other->ns);
465     if(other->namespace_set)
466         m->namespace_set = namespace_set_clone(other->namespace_set);
467     if(other->name)
468         m->name = strdup(other->name);
469     return m;
470 }
471
472
473 char* access2str(int type)
474 {
475     if(type==0x08) return "access08";
476     else if(type==0x16) return "public";
477     else if(type==0x17) return "packageinternal";
478     else if(type==0x18) return "protected";
479     else if(type==0x19) return "explicit";
480     else if(type==0x1A) return "staticprotected";
481     else if(type==0x05) return "private";
482     else {
483         fprintf(stderr, "Undefined access type %02x\n", type);
484         return "undefined";
485     }
486 }
487
488
489 char multiname_late_namespace(multiname_t*m)
490 {
491     if(!m)
492         return 0;
493     return (m->type==RTQNAME || m->type==RTQNAMEA ||
494             m->type==RTQNAMEL || m->type==RTQNAMELA);
495 }
496
497 char multiname_late_name(multiname_t*m)
498 {
499     if(!m)
500         return 0;
501     return m->type==RTQNAMEL || m->type==RTQNAMELA ||
502            m->type==MULTINAMEL || m->type==MULTINAMELA;
503 }
504
505 char* multiname_tostring(multiname_t*m)
506 {
507     char*mname = 0;
508     if(!m)
509         return strdup("NULL");
510     if(m->type==0xff)
511         return strdup("--<MULTINAME 0xff>--");
512
513     char*name = m->name?escape_string(m->name):strdup("*");
514     int namelen = strlen(name);
515
516     if(m->type==QNAME || m->type==QNAMEA) {
517         char*nsname = escape_string(m->ns->name);
518         mname = malloc(strlen(nsname)+namelen+32);
519         strcpy(mname, "<q");
520         if(m->type == QNAMEA)
521             strcat(mname, ",attr");
522         strcat(mname, ">[");
523         strcat(mname,access2str(m->ns->access));
524         strcat(mname, "]");
525         strcat(mname, nsname);
526         free(nsname);
527         strcat(mname, "::");
528         strcat(mname, name);
529     } else if(m->type==RTQNAME || m->type==RTQNAMEA) {
530         mname = malloc(namelen+32);
531         strcpy(mname, "<rt");
532         if(m->type == RTQNAMEA) 
533             strcat(mname, ",attr");
534         strcat(mname, ">");
535         strcat(mname, name);
536     } else if(m->type==RTQNAMEL) {
537         mname = strdup("<rt,l>");
538     } else if(m->type==RTQNAMELA) {
539         mname = strdup("<rt,l,attr>");
540     } else if(m->type==MULTINAME || m->type==MULTINAMEA) {
541         char*s = namespace_set_tostring(m->namespace_set);
542         mname = malloc(strlen(s)+namelen+16);
543         if(m->type == MULTINAME)
544             strcpy(mname,"<multi>");
545         else //MULTINAMEA
546             strcpy(mname,"<multi,attr>");
547         strcat(mname, s);
548         strcat(mname, "::");
549         strcat(mname, name);
550         free(s);
551     } else if(m->type==MULTINAMEL || m->type==MULTINAMELA) {
552         char*s = namespace_set_tostring(m->namespace_set);
553         mname = malloc(strlen(s)+16);
554         if(m->type == MULTINAMEL)
555             strcpy(mname,"<l,multi>");
556         else //MULTINAMELA
557             strcpy(mname,"<l,multi,attr>");
558         strcat(mname,s);
559         free(s);
560     } else {
561         fprintf(stderr, "Invalid multiname type: %02x\n", m->type);
562     }
563     free(name);
564     return mname;
565 }
566
567 multiname_t* multiname_fromstring(const char*name2)
568 {
569     if(!name2)
570         return 0;
571     char*n = strdup(name2);
572     char*p = strstr(n, "::");
573     char*namespace=0,*name=0;
574     if(!p) {
575         if(strchr(n, ':')) {
576             fprintf(stderr, "Error: single ':' in name\n");
577         }
578         namespace = "";
579         name = n;
580     } else {
581         *p = 0;
582         namespace = n;
583         name = p+2;
584         if(strchr(namespace, ':')) {
585             fprintf(stderr, "Error: single ':' in namespace\n");
586         }
587         if(strchr(name, ':')) {
588             fprintf(stderr, "Error: single ':' in qualified name\n");
589         }
590     }
591
592     multiname_t*m = malloc(sizeof(multiname_t));
593     memset(m, 0, sizeof(multiname_t));
594     m->type = QNAME;
595     m->namespace_set = 0;
596     m->ns = namespace_fromstring(namespace);
597     m->name = name?strdup(name):0;
598     free(n);
599     return m;
600 }
601
602 void multiname_destroy(multiname_t*m)
603 {
604     if(m) {
605         if(m->name) {
606             free((void*)m->name);m->name = 0;
607         }
608         if(m->ns) {
609             namespace_destroy(m->ns);m->ns = 0;
610         }
611         if(m->namespace_set) {
612             namespace_set_destroy(m->namespace_set);m->namespace_set = 0;
613         }
614         free(m);
615     }
616 }
617
618 type_t multiname_type = {
619     dup: (dup_func)multiname_clone,
620     hash: (hash_func)multiname_hash,
621     free: (free_func)multiname_destroy,
622     equals: (equals_func)multiname_equals
623 };
624
625
626 // ------------------------------- constants -------------------------------------
627
628 #define NS_TYPE(x) ((x) == 0x08 || (x) == 0x16 || (x) == 0x17 || (x) == 0x18 ||  \
629                                    (x) == 0x19 || (x) == 0x1a || (x) == 0x05)
630
631 #define UNIQUE_CONSTANT(x) ((x) == CONSTANT_TRUE || (x) == CONSTANT_FALSE || (x) == CONSTANT_NULL || (x) == CONSTANT_UNDEFINED)
632
633 constant_t* constant_new_int(int i) 
634 {
635     NEW(constant_t,c);
636     c->i = i;
637     c->type = CONSTANT_INT;
638     return c;
639 }
640 constant_t* constant_new_uint(unsigned int u)
641 {
642     NEW(constant_t,c);
643     c->u = u;
644     c->type = CONSTANT_UINT;
645     return c;
646 }
647 constant_t* constant_new_float(double f)
648 {
649     NEW(constant_t,c);
650     c->f = f;
651     c->type = CONSTANT_FLOAT;
652     return c;
653 }
654 constant_t* constant_new_string(char*s)
655 {
656     NEW(constant_t,c);
657     c->s = strdup(s);
658     c->type = CONSTANT_STRING;
659     return c;
660 }
661 constant_t* constant_new_namespace(namespace_t*ns)
662 {
663     NEW(constant_t,c);
664     c->ns = namespace_clone(ns);
665     c->type = ns->access;
666     assert(NS_TYPE(c->type));
667     return c;
668 }
669 constant_t* constant_new_true()
670 {
671     NEW(constant_t,c);
672     c->type = CONSTANT_TRUE;
673     return c;
674 }
675 constant_t* constant_new_false()
676 {
677     NEW(constant_t,c);
678     c->type = CONSTANT_FALSE;
679     return c;
680 }
681 constant_t* constant_new_null()
682 {
683     NEW(constant_t,c);
684     c->type = CONSTANT_NULL;
685     return c;
686 }
687 constant_t* constant_new_undefined()
688 {
689     NEW(constant_t,c);
690     c->type = CONSTANT_UNDEFINED;
691     return c;
692 }
693 constant_t* constant_fromindex(pool_t*pool, int index, int type)
694 {
695     if(!index) {
696         /* even for nonvalued constants (like TRUE/FALSE etc.), a nonzero
697            index is present to indicate that a type is coming */
698         return 0;
699     } 
700     NEW(constant_t,c);
701     c->type = type;
702     if(NS_TYPE(c->type)) {
703         c->ns = namespace_clone(pool_lookup_namespace(pool, index));
704     } else if(c->type == CONSTANT_INT) {
705         c->i = pool_lookup_int(pool, index);
706     } else if(c->type == CONSTANT_UINT) {
707         c->u = pool_lookup_uint(pool, index);
708     } else if(c->type == CONSTANT_FLOAT) {
709         c->f = pool_lookup_float(pool, index);
710     } else if(c->type == CONSTANT_STRING) {
711         c->s = strdup(pool_lookup_string(pool, index));
712     } else if(UNIQUE_CONSTANT(c->type)) {
713         // ok
714     } else {
715         fprintf(stderr, "invalid constant type %02x\n", c->type);
716     }
717     return c;
718 }
719 char* constant_tostring(constant_t*c)
720 {
721     if(!c)
722         return 0;
723     char buf[30];
724     if(NS_TYPE(c->type)) {
725         return namespace_tostring(c->ns);
726     } else if(c->type == CONSTANT_INT) {
727         sprintf(buf, "%d", c->i);
728         return strdup(buf);
729     } else if(c->type == CONSTANT_UINT) {
730         sprintf(buf, "%u", c->u);
731         return strdup(buf);
732     } else if(c->type == CONSTANT_FLOAT) {
733         sprintf(buf, "%f", c->f);
734         return strdup(buf);
735     } else if(c->type == CONSTANT_STRING) {
736         return strdup(c->s);
737     } else if(c->type == CONSTANT_TRUE) {
738         return strdup("true");
739     } else if(c->type == CONSTANT_FALSE) {
740         return strdup("false");
741     } else if(c->type == CONSTANT_NULL) {
742         return strdup("null");
743     } else if(c->type == CONSTANT_UNDEFINED) {
744         return strdup("undefined");
745     } else {
746         fprintf(stderr, "invalid constant type %02x\n", c->type);
747         return 0;
748     }
749 }
750 char constant_has_index(constant_t*c) 
751 {
752     if(!c)
753         return 0;
754     return !UNIQUE_CONSTANT(c->type);
755 }
756 int constant_get_index(pool_t*pool, constant_t*c)
757 {
758     if(!c)
759         return 0;
760     if(NS_TYPE(c->type)) {
761         assert(c->ns);
762         /*if(c->type!=c->ns->access) {
763             printf("%02x<->%02x\n", c->type, c->ns->access);
764         }*/
765         assert(c->type == c->ns->access);
766         return pool_register_namespace(pool, c->ns);
767     } else if(c->type == CONSTANT_INT) {
768         return pool_register_int(pool, c->i);
769     } else if(c->type == CONSTANT_UINT) {
770         return pool_register_uint(pool, c->u);
771     } else if(c->type == CONSTANT_FLOAT) {
772         return pool_register_float(pool, c->f);
773     } else if(c->type == CONSTANT_STRING) {
774         return pool_register_string(pool, c->s);
775     } else if(!constant_has_index(c)) {
776         return 1;
777     } else {
778         fprintf(stderr, "invalid constant type %02x\n", c->type);
779         return 0;
780     }
781 }
782 void constant_free(constant_t*c)
783 {
784     if(!c)
785         return;
786     if(c->type == CONSTANT_STRING) {
787         free(c->s);c->s=0;
788     } else if (NS_TYPE(c->type)) {
789         namespace_destroy(c->ns);c->ns=0;
790     }
791     free(c);
792 }
793 // ------------------------------- pool -------------------------------------
794
795 int pool_register_uint(pool_t*p, unsigned int i)
796 {
797     int pos = array_append_if_new(p->x_uints, &i, 0);
798     assert(pos!=0);
799     return pos;
800 }
801 int pool_register_int(pool_t*p, int i)
802 {
803     int pos = array_append_if_new(p->x_ints, &i, 0);
804     assert(pos!=0);
805     return pos;
806 }
807 int pool_register_float(pool_t*p, double d)
808 {
809     int pos = array_append_if_new(p->x_floats, &d, 0);
810     assert(pos!=0);
811     return pos;
812 }
813 int pool_register_string(pool_t*pool, const char*s)
814 {
815     if(!s) return 0;
816     int pos = array_append_if_new(pool->x_strings, s, 0);
817     assert(pos!=0);
818     return pos;
819 }
820 int pool_register_namespace(pool_t*pool, namespace_t*ns)
821 {
822     if(!ns) return 0;
823     int pos = array_append_if_new(pool->x_namespaces, ns, 0);
824     assert(pos!=0);
825     return pos;
826 }
827 int pool_register_namespace_set(pool_t*pool, namespace_set_t*set)
828 {
829     if(!set) return 0;
830     int pos = array_append_if_new(pool->x_namespace_sets, set, 0);
831     assert(pos!=0);
832     return pos;
833 }
834 int pool_register_multiname(pool_t*pool, multiname_t*n)
835 {
836     if(!n) return 0;
837     int pos = array_append_if_new(pool->x_multinames, n, 0);
838     if(pos==0) {
839         *(int*)0=0xdead;
840     }
841     assert(pos!=0);
842     return pos;
843 }
844 int pool_register_multiname2(pool_t*pool, char*name)
845 {
846     if(!name) return 0;
847     multiname_t*n = multiname_fromstring(name);
848     int pos = array_append_if_new(pool->x_multinames, n, 0);
849     multiname_destroy(n);
850     assert(pos!=0);
851     return pos;
852 }
853
854
855 int pool_find_uint(pool_t*pool, unsigned int x)
856 {
857     int i = array_find(pool->x_uints, &x);
858     if(i<=0) {
859         fprintf(stderr, "Couldn't find uint \"%d\" in constant pool\n", x);
860         return 0;
861     }
862     return i;
863 }
864 int pool_find_int(pool_t*pool, int x)
865 {
866     int i = array_find(pool->x_ints, &x);
867     if(i<=0) {
868         fprintf(stderr, "Couldn't find int \"%d\" in constant pool\n", x);
869         return 0;
870     }
871     return i;
872 }
873 int pool_find_float(pool_t*pool, double x)
874 {
875     int i = array_find(pool->x_ints, &x);
876     if(i<=0) {
877         fprintf(stderr, "Couldn't find int \"%d\" in constant pool\n", x);
878         return 0;
879     }
880     return i;
881 }
882 int pool_find_namespace(pool_t*pool, namespace_t*ns)
883 {
884     if(!ns)
885         return 0;
886     int i = array_find(pool->x_namespaces, ns);
887     if(i<=0) {
888         char*s = namespace_tostring(ns);
889         fprintf(stderr, "Couldn't find namespace \"%s\" %08x in constant pool\n", s, ns);
890         free(s);
891         return 0;
892     }
893     return i;
894 }
895 int pool_find_namespace_set(pool_t*pool, namespace_set_t*set)
896 {
897     if(!set)
898         return 0;
899     int i = array_find(pool->x_namespace_sets, set);
900     if(i<=0) {
901         char*s = namespace_set_tostring(set);
902         fprintf(stderr, "Couldn't find namespace_set \"%s\" in constant pool\n", s);
903         free(s);
904         return 0;
905     }
906     return i;
907 }
908 int pool_find_string(pool_t*pool, const char*s)
909 {
910     if(!s)
911         return 0;
912     int i = array_find(pool->x_strings, s);
913     if(i<=0) {
914         fprintf(stderr, "Couldn't find string \"%s\" in constant pool\n", s);
915         return 0;
916     }
917     return i;
918 }
919 int pool_find_multiname(pool_t*pool, multiname_t*name)
920 {
921     if(!name)
922         return 0;
923     int i = array_find(pool->x_multinames, name);
924     if(i<=0) {
925         char*s = multiname_tostring(name);
926         fprintf(stderr, "Couldn't find multiname \"%s\" in constant pool\n", s);
927         free(s);
928         return 0;
929     }
930     return i;
931 }
932
933 int pool_lookup_int(pool_t*pool, int i)
934 {
935     if(!i) return 0;
936     return *(int*)array_getkey(pool->x_ints, i);
937 }
938 unsigned int pool_lookup_uint(pool_t*pool, int i)
939 {
940     if(!i) return 0;
941     return *(unsigned int*)array_getkey(pool->x_uints, i);
942 }
943 double pool_lookup_float(pool_t*pool, int i)
944 {
945     if(!i) return __builtin_nan("");
946     return *(double*)array_getkey(pool->x_floats, i);
947 }
948 char*pool_lookup_string(pool_t*pool, int i)
949 {
950     return (char*)array_getkey(pool->x_strings, i);
951 }
952 namespace_t*pool_lookup_namespace(pool_t*pool, int i)
953 {
954     return (namespace_t*)array_getkey(pool->x_namespaces, i);
955 }
956 namespace_set_t*pool_lookup_namespace_set(pool_t*pool, int i)
957 {
958     return (namespace_set_t*)array_getkey(pool->x_namespace_sets, i);
959 }
960 multiname_t*pool_lookup_multiname(pool_t*pool, int i)
961 {
962     return (multiname_t*)array_getkey(pool->x_multinames, i);
963 }
964
965 pool_t*pool_new()
966 {
967     NEW(pool_t, p);
968
969     p->x_ints = array_new2(&uint_type);
970     p->x_uints = array_new2(&uint_type);
971     p->x_floats = array_new2(&float_type);
972     p->x_strings = array_new2(&charptr_type);
973     p->x_namespaces = array_new2(&namespace_type);
974     p->x_namespace_sets = array_new2(&namespace_set_type);
975     p->x_multinames = array_new2(&multiname_type);
976
977     /* add a zero-index entry in each list */
978   
979     array_append(p->x_ints, 0, 0);
980     array_append(p->x_uints, 0, 0);
981     array_append(p->x_floats, 0, 0);
982     array_append(p->x_strings, 0, 0);
983     array_append(p->x_namespaces, 0, 0);
984     array_append(p->x_namespace_sets, 0, 0);
985     array_append(p->x_multinames, 0, 0);
986     return p;
987 }
988
989 #define DEBUG if(0)
990 //#define DEBUG
991
992 void pool_read(pool_t*pool, TAG*tag)
993 {
994     int num_ints = swf_GetU30(tag);
995     DEBUG printf("%d ints\n", num_ints);
996     int t;
997     for(t=1;t<num_ints;t++) {
998         S32 v = swf_GetS30(tag);
999         DEBUG printf("int %d) %d\n", t, v);
1000         array_append(pool->x_ints, &v, 0);
1001     }
1002
1003     int num_uints = swf_GetU30(tag);
1004     DEBUG printf("%d uints\n", num_uints);
1005     for(t=1;t<num_uints;t++) {
1006         U32 v = swf_GetU30(tag);
1007         DEBUG printf("uint %d) %d\n", t, v);
1008         array_append(pool->x_uints, &v, 0);
1009     }
1010     
1011     int num_floats = swf_GetU30(tag);
1012     DEBUG printf("%d floats\n", num_floats);
1013     for(t=1;t<num_floats;t++) {
1014         double d = swf_GetD64(tag);
1015         DEBUG printf("float %d) %f\n", t, d);
1016         array_append(pool->x_floats, &d, 0);
1017     }
1018     
1019     int num_strings = swf_GetU30(tag);
1020     DEBUG printf("%d strings\n", num_strings);
1021     for(t=1;t<num_strings;t++) {
1022         int len = swf_GetU30(tag);
1023         char*s = malloc(len+1);
1024         swf_GetBlock(tag, s, len);
1025         s[len] = 0;
1026         array_append(pool->x_strings, s, 0);
1027         free(s);
1028         DEBUG printf("%d) \"%s\"\n", t, pool->x_strings->d[t].name);
1029     }
1030     int num_namespaces = swf_GetU30(tag);
1031     DEBUG printf("%d namespaces\n", num_namespaces);
1032     for(t=1;t<num_namespaces;t++) {
1033         U8 type = swf_GetU8(tag);
1034         int namenr = swf_GetU30(tag);
1035         const char*name = 0; 
1036         if(namenr)
1037             name = array_getkey(pool->x_strings, namenr);
1038         namespace_t*ns = namespace_new(type, name);
1039         array_append(pool->x_namespaces, ns, 0);
1040         DEBUG printf("%d) %02x \"%s\"\n", t, type, namespace_tostring(ns));
1041         namespace_destroy(ns);
1042     }
1043     int num_sets = swf_GetU30(tag);
1044     DEBUG printf("%d namespace sets\n", num_sets);
1045     for(t=1;t<num_sets;t++) {
1046         int count = swf_GetU30(tag);
1047         int s;
1048         
1049         NEW(namespace_set_t, nsset);
1050         for(s=0;s<count;s++) {
1051             int nsnr = swf_GetU30(tag);
1052             if(!nsnr)
1053                 fprintf(stderr, "Zero entry in namespace set\n");
1054             namespace_t*ns = (namespace_t*)array_getkey(pool->x_namespaces, nsnr);
1055             list_append(nsset->namespaces, namespace_clone(ns));
1056         }
1057         array_append(pool->x_namespace_sets, nsset, 0);
1058         DEBUG printf("set %d) %s\n", t, namespace_set_tostring(nsset));
1059         namespace_set_destroy(nsset);
1060     }
1061
1062     int num_multinames = swf_GetU30(tag);
1063     DEBUG printf("%d multinames\n", num_multinames);
1064     for(t=1;t<num_multinames;t++) {
1065         multiname_t m;
1066         memset(&m, 0, sizeof(multiname_t));
1067         m.type = swf_GetU8(tag);
1068         if(m.type==0x07 || m.type==0x0d) {
1069             int namespace_index = swf_GetU30(tag);
1070             m.ns = (namespace_t*)array_getkey(pool->x_namespaces, namespace_index);
1071             int name_index = swf_GetU30(tag);
1072             if(name_index) // 0 = '*' (any)
1073                 m.name = array_getkey(pool->x_strings, name_index);
1074         } else if(m.type==0x0f || m.type==0x10) {
1075             int name_index = swf_GetU30(tag);
1076             if(name_index) // 0 = '*' (any name)
1077                 m.name = array_getkey(pool->x_strings, name_index);
1078         } else if(m.type==0x11 || m.type==0x12) {
1079         } else if(m.type==0x09 || m.type==0x0e) {
1080             int name_index = swf_GetU30(tag);
1081             int namespace_set_index = swf_GetU30(tag);
1082             if(name_index)
1083                 m.name = array_getkey(pool->x_strings, name_index);
1084             m.namespace_set = (namespace_set_t*)array_getkey(pool->x_namespace_sets, namespace_set_index);
1085         } else if(m.type==0x1b || m.type==0x1c) {
1086             int namespace_set_index = swf_GetU30(tag);
1087             m.namespace_set = (namespace_set_t*)array_getkey(pool->x_namespace_sets, namespace_set_index);
1088         } else {
1089             printf("can't parse type %d multinames yet\n", m.type);
1090         }
1091         DEBUG printf("multiname %d) %s\n", t, multiname_tostring(&m));
1092         array_append(pool->x_multinames, &m, 0);
1093     }
1094
1095
1096 void pool_write(pool_t*pool, TAG*tag)
1097 {
1098     int t;
1099     
1100     /* make sure that all namespaces used by multinames / namespace sets
1101        and all strings used by namespaces exist */
1102
1103     for(t=1;t<pool->x_multinames->num;t++) {
1104         multiname_t*m = (multiname_t*)array_getkey(pool->x_multinames, t);
1105         if(m->ns) {
1106             pool_register_namespace(pool, m->ns);
1107         }
1108         if(m->namespace_set) {
1109             pool_register_namespace_set(pool, m->namespace_set);
1110         }
1111         if(m->name) {
1112             pool_register_string(pool, m->name);
1113         }
1114     }
1115     for(t=1;t<pool->x_namespace_sets->num;t++) {
1116         namespace_set_t*set = (namespace_set_t*)array_getkey(pool->x_namespace_sets, t);
1117         namespace_list_t*i = set->namespaces;
1118         while(i) {
1119             pool_register_namespace(pool, i->namespace);
1120             i = i->next;
1121         }
1122     }
1123     for(t=1;t<pool->x_namespaces->num;t++) {
1124         namespace_t*ns= (namespace_t*)array_getkey(pool->x_namespaces, t);
1125         /*  The spec says (page 22): "a value of zero denotes an empty string".
1126             However when actually using zero strings as empty namespaces, the
1127             flash player breaks.*/
1128         //if(ns->name && ns->name[0])
1129         array_append_if_new(pool->x_strings, ns->name, 0);
1130     }
1131
1132     //pool_register_int(pool, 15);
1133     //pool_register_int(pool, 1);
1134     //pool_register_int(pool, 0);
1135     
1136     /* write data */
1137     swf_SetU30(tag, pool->x_ints->num>1?pool->x_ints->num:0);
1138     for(t=1;t<pool->x_ints->num;t++) {
1139         S32 val = *(int*)array_getkey(pool->x_ints, t);
1140         swf_SetS30(tag, val);
1141     }
1142     swf_SetU30(tag, pool->x_uints->num>1?pool->x_uints->num:0);
1143     for(t=1;t<pool->x_uints->num;t++) {
1144         swf_SetU30(tag, *(unsigned int*)array_getkey(pool->x_uints, t));
1145     }
1146     swf_SetU30(tag, pool->x_floats->num>1?pool->x_floats->num:0);
1147     for(t=1;t<pool->x_floats->num;t++) {
1148         double d = pool_lookup_float(pool, t);
1149         swf_SetD64(tag, d);
1150     }
1151     swf_SetU30(tag, pool->x_strings->num>1?pool->x_strings->num:0);
1152     for(t=1;t<pool->x_strings->num;t++) {
1153         swf_SetU30String(tag, array_getkey(pool->x_strings, t));
1154     }
1155     swf_SetU30(tag, pool->x_namespaces->num>1?pool->x_namespaces->num:0);
1156     for(t=1;t<pool->x_namespaces->num;t++) {
1157         namespace_t*ns= (namespace_t*)array_getkey(pool->x_namespaces, t);
1158         swf_SetU8(tag, ns->access);
1159         const char*name = ns->name;
1160         int i = 0;
1161         
1162         //if(name && name[0])
1163         i = pool_find_string(pool, name);
1164
1165         swf_SetU30(tag, i);
1166     }
1167     swf_SetU30(tag, pool->x_namespace_sets->num>1?pool->x_namespace_sets->num:0);
1168     for(t=1;t<pool->x_namespace_sets->num;t++) {
1169         namespace_set_t*set = (namespace_set_t*)array_getkey(pool->x_namespace_sets, t);
1170         namespace_list_t*i = set->namespaces; 
1171         int len = list_length(i);
1172         swf_SetU30(tag, len);
1173         while(i) {
1174             int index = pool_find_namespace(pool, i->namespace);
1175             swf_SetU30(tag, index);
1176             i = i->next;
1177         }
1178     }
1179
1180     swf_SetU30(tag, pool->x_multinames->num>1?pool->x_multinames->num:0);
1181     for(t=1;t<pool->x_multinames->num;t++) {
1182         multiname_t*m = (multiname_t*)array_getkey(pool->x_multinames, t);
1183         swf_SetU8(tag, m->type);
1184
1185         if(m->ns) {
1186             assert(m->type==0x07 || m->type==0x0d);
1187             int i = pool_find_namespace(pool, m->ns);
1188             if(i<0) fprintf(stderr, "internal error: unregistered namespace %02x %s %s\n", m->ns->access, access2str(m->ns->access), m->ns->name);
1189             swf_SetU30(tag, i);
1190         } else {
1191             assert(m->type!=0x07 && m->type!=0x0d);
1192         }
1193         if(m->name) {
1194             assert(m->type==0x09 || m->type==0x0e || m->type==0x07 || m->type==0x0d || m->type==0x0f || m->type==0x10);
1195             int i = pool_find_string(pool, m->name);
1196             if(i<0) fprintf(stderr, "internal error: unregistered name\n");
1197             swf_SetU30(tag, i);
1198         } else {
1199             assert(m->type!=0x09 && m->type!=0x0e && m->type!=0x07 && m->type!=0x0d && m->type!=0x0f && m->type!=0x10);
1200         }
1201         if(m->namespace_set) {
1202             assert(m->type==0x09 || m->type==0x0e || m->type==0x1c || m->type==0x1b);
1203             int i = pool_find_namespace_set(pool, m->namespace_set);
1204             if(i<0) fprintf(stderr, "internal error: unregistered namespace set\n");
1205             swf_SetU30(tag, i);
1206         } else {
1207             assert(m->type!=0x09 && m->type!=0x0e && m->type!=0x1c && m->type!=0x1b);
1208         }
1209     }
1210 }
1211
1212
1213 void pool_destroy(pool_t*pool)
1214 {
1215     int t;
1216     array_free(pool->x_ints);
1217     array_free(pool->x_uints);
1218     array_free(pool->x_floats);
1219     array_free(pool->x_strings);
1220     array_free(pool->x_namespaces);
1221     array_free(pool->x_namespace_sets);
1222     array_free(pool->x_multinames);
1223     free(pool);
1224 }