free multiname more thoroughly
[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         m->type=0;
615         free(m);
616     }
617 }
618
619 type_t multiname_type = {
620     dup: (dup_func)multiname_clone,
621     hash: (hash_func)multiname_hash,
622     free: (free_func)multiname_destroy,
623     equals: (equals_func)multiname_equals
624 };
625
626
627 // ------------------------------- constants -------------------------------------
628
629 #define NS_TYPE(x) ((x) == 0x08 || (x) == 0x16 || (x) == 0x17 || (x) == 0x18 ||  \
630                                    (x) == 0x19 || (x) == 0x1a || (x) == 0x05)
631
632 #define UNIQUE_CONSTANT(x) ((x) == CONSTANT_TRUE || (x) == CONSTANT_FALSE || (x) == CONSTANT_NULL || (x) == CONSTANT_UNDEFINED)
633
634 constant_t* constant_new_int(int i) 
635 {
636     NEW(constant_t,c);
637     c->i = i;
638     c->type = CONSTANT_INT;
639     return c;
640 }
641 constant_t* constant_new_uint(unsigned int u)
642 {
643     NEW(constant_t,c);
644     c->u = u;
645     c->type = CONSTANT_UINT;
646     return c;
647 }
648 constant_t* constant_new_float(double f)
649 {
650     NEW(constant_t,c);
651     c->f = f;
652     c->type = CONSTANT_FLOAT;
653     return c;
654 }
655 constant_t* constant_new_string(char*s)
656 {
657     NEW(constant_t,c);
658     c->s = strdup(s);
659     c->type = CONSTANT_STRING;
660     return c;
661 }
662 constant_t* constant_new_namespace(namespace_t*ns)
663 {
664     NEW(constant_t,c);
665     c->ns = namespace_clone(ns);
666     c->type = ns->access;
667     assert(NS_TYPE(c->type));
668     return c;
669 }
670 constant_t* constant_new_true()
671 {
672     NEW(constant_t,c);
673     c->type = CONSTANT_TRUE;
674     return c;
675 }
676 constant_t* constant_new_false()
677 {
678     NEW(constant_t,c);
679     c->type = CONSTANT_FALSE;
680     return c;
681 }
682 constant_t* constant_new_null()
683 {
684     NEW(constant_t,c);
685     c->type = CONSTANT_NULL;
686     return c;
687 }
688 constant_t* constant_new_undefined()
689 {
690     NEW(constant_t,c);
691     c->type = CONSTANT_UNDEFINED;
692     return c;
693 }
694 constant_t* constant_fromindex(pool_t*pool, int index, int type)
695 {
696     if(!index) {
697         /* even for nonvalued constants (like TRUE/FALSE etc.), a nonzero
698            index is present to indicate that a type is coming */
699         return 0;
700     } 
701     NEW(constant_t,c);
702     c->type = type;
703     if(NS_TYPE(c->type)) {
704         c->ns = namespace_clone(pool_lookup_namespace(pool, index));
705     } else if(c->type == CONSTANT_INT) {
706         c->i = pool_lookup_int(pool, index);
707     } else if(c->type == CONSTANT_UINT) {
708         c->u = pool_lookup_uint(pool, index);
709     } else if(c->type == CONSTANT_FLOAT) {
710         c->f = pool_lookup_float(pool, index);
711     } else if(c->type == CONSTANT_STRING) {
712         c->s = strdup(pool_lookup_string(pool, index));
713     } else if(UNIQUE_CONSTANT(c->type)) {
714         // ok
715     } else {
716         fprintf(stderr, "invalid constant type %02x\n", c->type);
717     }
718     return c;
719 }
720 char* constant_tostring(constant_t*c)
721 {
722     if(!c)
723         return 0;
724     char buf[32];
725     if(NS_TYPE(c->type)) {
726         return namespace_tostring(c->ns);
727     } else if(c->type == CONSTANT_INT) {
728         sprintf(buf, "%d", c->i);
729         return strdup(buf);
730     } else if(c->type == CONSTANT_UINT) {
731         sprintf(buf, "%u", c->u);
732         return strdup(buf);
733     } else if(c->type == CONSTANT_FLOAT) {
734         char buf[1024];
735         sprintf(buf, "%f", c->f);
736         return strdup(buf);
737     } else if(c->type == CONSTANT_STRING) {
738         return strdup(c->s);
739     } else if(c->type == CONSTANT_TRUE) {
740         return strdup("true");
741     } else if(c->type == CONSTANT_FALSE) {
742         return strdup("false");
743     } else if(c->type == CONSTANT_NULL) {
744         return strdup("null");
745     } else if(c->type == CONSTANT_UNDEFINED) {
746         return strdup("undefined");
747     } else {
748         fprintf(stderr, "invalid constant type %02x\n", c->type);
749         return 0;
750     }
751 }
752 char constant_has_index(constant_t*c) 
753 {
754     if(!c)
755         return 0;
756     return !UNIQUE_CONSTANT(c->type);
757 }
758 int constant_get_index(pool_t*pool, constant_t*c)
759 {
760     if(!c)
761         return 0;
762     if(NS_TYPE(c->type)) {
763         assert(c->ns);
764         /*if(c->type!=c->ns->access) {
765             printf("%02x<->%02x\n", c->type, c->ns->access);
766         }*/
767         assert(c->type == c->ns->access);
768         return pool_register_namespace(pool, c->ns);
769     } else if(c->type == CONSTANT_INT) {
770         return pool_register_int(pool, c->i);
771     } else if(c->type == CONSTANT_UINT) {
772         return pool_register_uint(pool, c->u);
773     } else if(c->type == CONSTANT_FLOAT) {
774         return pool_register_float(pool, c->f);
775     } else if(c->type == CONSTANT_STRING) {
776         return pool_register_string(pool, c->s);
777     } else if(!constant_has_index(c)) {
778         return 1;
779     } else {
780         fprintf(stderr, "invalid constant type %02x\n", c->type);
781         return 0;
782     }
783 }
784 void constant_free(constant_t*c)
785 {
786     if(!c)
787         return;
788     if(c->type == CONSTANT_STRING) {
789         free(c->s);c->s=0;
790     } else if (NS_TYPE(c->type)) {
791         namespace_destroy(c->ns);c->ns=0;
792     }
793     free(c);
794 }
795 // ------------------------------- pool -------------------------------------
796
797 int pool_register_uint(pool_t*p, unsigned int i)
798 {
799     int pos = array_append_if_new(p->x_uints, &i, 0);
800     assert(pos!=0);
801     return pos;
802 }
803 int pool_register_int(pool_t*p, int i)
804 {
805     int pos = array_append_if_new(p->x_ints, &i, 0);
806     assert(pos!=0);
807     return pos;
808 }
809 int pool_register_float(pool_t*p, double d)
810 {
811     int pos = array_append_if_new(p->x_floats, &d, 0);
812     assert(pos!=0);
813     return pos;
814 }
815 int pool_register_string(pool_t*pool, const char*s)
816 {
817     if(!s) return 0;
818     ptroff_t l = strlen(s);
819     int pos = array_append_if_new(pool->x_strings, s, (void*)l);
820     assert(pos!=0);
821     return pos;
822 }
823 int pool_register_namespace(pool_t*pool, namespace_t*ns)
824 {
825     if(!ns) return 0;
826     int pos = array_append_if_new(pool->x_namespaces, ns, 0);
827     assert(pos!=0);
828     return pos;
829 }
830 int pool_register_namespace_set(pool_t*pool, namespace_set_t*set)
831 {
832     if(!set) return 0;
833     int pos = array_append_if_new(pool->x_namespace_sets, set, 0);
834     assert(pos!=0);
835     return pos;
836 }
837 int pool_register_multiname(pool_t*pool, multiname_t*n)
838 {
839     if(!n) return 0;
840     int pos = array_append_if_new(pool->x_multinames, n, 0);
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 string_t pool_lookup_string2(pool_t*pool, int i)
953 {
954     char*s = (char*)array_getkey(pool->x_strings, i);
955     int len = (int)(ptroff_t)array_getvalue(pool->x_strings, i);
956     return string_new(s,len);
957 }
958 namespace_t*pool_lookup_namespace(pool_t*pool, int i)
959 {
960     return (namespace_t*)array_getkey(pool->x_namespaces, i);
961 }
962 namespace_set_t*pool_lookup_namespace_set(pool_t*pool, int i)
963 {
964     return (namespace_set_t*)array_getkey(pool->x_namespace_sets, i);
965 }
966 multiname_t*pool_lookup_multiname(pool_t*pool, int i)
967 {
968     return (multiname_t*)array_getkey(pool->x_multinames, i);
969 }
970
971 pool_t*pool_new()
972 {
973     NEW(pool_t, p);
974
975     p->x_ints = array_new2(&uint_type);
976     p->x_uints = array_new2(&uint_type);
977     p->x_floats = array_new2(&float_type);
978     p->x_strings = array_new2(&charptr_type);
979     p->x_namespaces = array_new2(&namespace_type);
980     p->x_namespace_sets = array_new2(&namespace_set_type);
981     p->x_multinames = array_new2(&multiname_type);
982
983     /* add a zero-index entry in each list */
984   
985     array_append(p->x_ints, 0, 0);
986     array_append(p->x_uints, 0, 0);
987     array_append(p->x_floats, 0, 0);
988     array_append(p->x_strings, 0, 0);
989     array_append(p->x_namespaces, 0, 0);
990     array_append(p->x_namespace_sets, 0, 0);
991     array_append(p->x_multinames, 0, 0);
992     return p;
993 }
994
995 #define DEBUG if(0)
996 //#define DEBUG
997
998 void pool_read(pool_t*pool, TAG*tag)
999 {
1000     int num_ints = swf_GetU30(tag);
1001     DEBUG printf("%d ints\n", num_ints);
1002     int t;
1003     for(t=1;t<num_ints;t++) {
1004         S32 v = swf_GetABCS32(tag);
1005         DEBUG printf("int %d) %d\n", t, v);
1006         array_append(pool->x_ints, &v, 0);
1007     }
1008
1009     int num_uints = swf_GetU30(tag);
1010     DEBUG printf("%d uints\n", num_uints);
1011     for(t=1;t<num_uints;t++) {
1012         U32 v = swf_GetABCU32(tag);
1013         DEBUG printf("uint %d) %d\n", t, v);
1014         array_append(pool->x_uints, &v, 0);
1015     }
1016     
1017     int num_floats = swf_GetU30(tag);
1018     DEBUG printf("%d floats\n", num_floats);
1019     for(t=1;t<num_floats;t++) {
1020         double d = swf_GetD64(tag);
1021         DEBUG printf("float %d) %f\n", t, d);
1022         array_append(pool->x_floats, &d, 0);
1023     }
1024     
1025     int num_strings = swf_GetU30(tag);
1026     DEBUG printf("%d strings\n", num_strings);
1027     for(t=1;t<num_strings;t++) {
1028         int len = swf_GetU30(tag);
1029         char*s = malloc(len+1);
1030         swf_GetBlock(tag, s, len);
1031         s[len] = 0;
1032         array_append(pool->x_strings, s, (void*)(ptroff_t)len);
1033         free(s);
1034         DEBUG printf("%d) \"%s\"\n", t, pool->x_strings->d[t].name);
1035     }
1036     int num_namespaces = swf_GetU30(tag);
1037     DEBUG printf("%d namespaces\n", num_namespaces);
1038     for(t=1;t<num_namespaces;t++) {
1039         U8 type = swf_GetU8(tag);
1040         int namenr = swf_GetU30(tag);
1041         const char*name = 0; 
1042         if(namenr)
1043             name = array_getkey(pool->x_strings, namenr);
1044         namespace_t*ns = namespace_new(type, name);
1045         array_append(pool->x_namespaces, ns, 0);
1046         DEBUG printf("%d) %02x \"%s\"\n", t, type, namespace_tostring(ns));
1047         namespace_destroy(ns);
1048     }
1049     int num_sets = swf_GetU30(tag);
1050     DEBUG printf("%d namespace sets\n", num_sets);
1051     for(t=1;t<num_sets;t++) {
1052         int count = swf_GetU30(tag);
1053         int s;
1054         
1055         NEW(namespace_set_t, nsset);
1056         for(s=0;s<count;s++) {
1057             int nsnr = swf_GetU30(tag);
1058             if(!nsnr)
1059                 fprintf(stderr, "Zero entry in namespace set\n");
1060             namespace_t*ns = (namespace_t*)array_getkey(pool->x_namespaces, nsnr);
1061             list_append(nsset->namespaces, namespace_clone(ns));
1062         }
1063         array_append(pool->x_namespace_sets, nsset, 0);
1064         DEBUG printf("set %d) %s\n", t, namespace_set_tostring(nsset));
1065         namespace_set_destroy(nsset);
1066     }
1067
1068     int num_multinames = swf_GetU30(tag);
1069     DEBUG printf("%d multinames\n", num_multinames);
1070     for(t=1;t<num_multinames;t++) {
1071         multiname_t m;
1072         memset(&m, 0, sizeof(multiname_t));
1073         m.type = swf_GetU8(tag);
1074         if(m.type==0x07 || m.type==0x0d) {
1075             int namespace_index = swf_GetU30(tag);
1076             m.ns = (namespace_t*)array_getkey(pool->x_namespaces, namespace_index);
1077             int name_index = swf_GetU30(tag);
1078             if(name_index) // 0 = '*' (any)
1079                 m.name = array_getkey(pool->x_strings, name_index);
1080         } else if(m.type==0x0f || m.type==0x10) {
1081             int name_index = swf_GetU30(tag);
1082             if(name_index) // 0 = '*' (any name)
1083                 m.name = array_getkey(pool->x_strings, name_index);
1084         } else if(m.type==0x11 || m.type==0x12) {
1085         } else if(m.type==0x09 || m.type==0x0e) {
1086             int name_index = swf_GetU30(tag);
1087             int namespace_set_index = swf_GetU30(tag);
1088             if(name_index)
1089                 m.name = array_getkey(pool->x_strings, name_index);
1090             m.namespace_set = (namespace_set_t*)array_getkey(pool->x_namespace_sets, namespace_set_index);
1091         } else if(m.type==0x1b || m.type==0x1c) {
1092             int namespace_set_index = swf_GetU30(tag);
1093             m.namespace_set = (namespace_set_t*)array_getkey(pool->x_namespace_sets, namespace_set_index);
1094         } else {
1095             printf("can't parse type %d multinames yet\n", m.type);
1096         }
1097         DEBUG printf("multiname %d) %s\n", t, multiname_tostring(&m));
1098         array_append(pool->x_multinames, &m, 0);
1099     }
1100
1101
1102 void pool_write(pool_t*pool, TAG*tag)
1103 {
1104     int t;
1105     
1106     /* make sure that all namespaces used by multinames / namespace sets
1107        and all strings used by namespaces exist */
1108
1109     for(t=1;t<pool->x_multinames->num;t++) {
1110         multiname_t*m = (multiname_t*)array_getkey(pool->x_multinames, t);
1111         if(m->ns) {
1112             pool_register_namespace(pool, m->ns);
1113         }
1114         if(m->namespace_set) {
1115             pool_register_namespace_set(pool, m->namespace_set);
1116         }
1117         if(m->name) {
1118             pool_register_string(pool, m->name);
1119         }
1120     }
1121     for(t=1;t<pool->x_namespace_sets->num;t++) {
1122         namespace_set_t*set = (namespace_set_t*)array_getkey(pool->x_namespace_sets, t);
1123         namespace_list_t*i = set->namespaces;
1124         while(i) {
1125             pool_register_namespace(pool, i->namespace);
1126             i = i->next;
1127         }
1128     }
1129     for(t=1;t<pool->x_namespaces->num;t++) {
1130         namespace_t*ns= (namespace_t*)array_getkey(pool->x_namespaces, t);
1131         /*  The spec says (page 22): "a value of zero denotes an empty string".
1132             However when actually using zero strings as empty namespaces, the
1133             flash player breaks.*/
1134         //if(ns->name && ns->name[0])
1135         pool_register_string(pool, ns->name);
1136     }
1137
1138     //pool_register_int(pool, 15);
1139     //pool_register_int(pool, 1);
1140     //pool_register_int(pool, 0);
1141     
1142     /* write data */
1143     swf_SetU30(tag, pool->x_ints->num>1?pool->x_ints->num:0);
1144     for(t=1;t<pool->x_ints->num;t++) {
1145         S32 val = *(int*)array_getkey(pool->x_ints, t);
1146         swf_SetABCS32(tag, val);
1147     }
1148     swf_SetU30(tag, pool->x_uints->num>1?pool->x_uints->num:0);
1149     for(t=1;t<pool->x_uints->num;t++) {
1150         swf_SetABCU32(tag, *(unsigned int*)array_getkey(pool->x_uints, t));
1151     }
1152     swf_SetU30(tag, pool->x_floats->num>1?pool->x_floats->num:0);
1153     for(t=1;t<pool->x_floats->num;t++) {
1154         double d = pool_lookup_float(pool, t);
1155         swf_SetD64(tag, d);
1156     }
1157     swf_SetU30(tag, pool->x_strings->num>1?pool->x_strings->num:0);
1158     for(t=1;t<pool->x_strings->num;t++) {
1159         string_t str = pool_lookup_string2(pool, t);
1160         swf_SetU30String(tag, str.str, str.len);
1161     }
1162     swf_SetU30(tag, pool->x_namespaces->num>1?pool->x_namespaces->num:0);
1163     for(t=1;t<pool->x_namespaces->num;t++) {
1164         namespace_t*ns= (namespace_t*)array_getkey(pool->x_namespaces, t);
1165         swf_SetU8(tag, ns->access);
1166         const char*name = ns->name;
1167         int i = 0;
1168         
1169         //if(name && name[0])
1170         i = pool_find_string(pool, name);
1171
1172         swf_SetU30(tag, i);
1173     }
1174     swf_SetU30(tag, pool->x_namespace_sets->num>1?pool->x_namespace_sets->num:0);
1175     for(t=1;t<pool->x_namespace_sets->num;t++) {
1176         namespace_set_t*set = (namespace_set_t*)array_getkey(pool->x_namespace_sets, t);
1177         namespace_list_t*i = set->namespaces; 
1178         int len = list_length(i);
1179         swf_SetU30(tag, len);
1180         while(i) {
1181             int index = pool_find_namespace(pool, i->namespace);
1182             swf_SetU30(tag, index);
1183             i = i->next;
1184         }
1185     }
1186
1187     swf_SetU30(tag, pool->x_multinames->num>1?pool->x_multinames->num:0);
1188     for(t=1;t<pool->x_multinames->num;t++) {
1189         multiname_t*m = (multiname_t*)array_getkey(pool->x_multinames, t);
1190         swf_SetU8(tag, m->type);
1191
1192         if(m->ns) {
1193             assert(m->type==0x07 || m->type==0x0d);
1194             int i = pool_find_namespace(pool, m->ns);
1195             if(i<0) fprintf(stderr, "internal error: unregistered namespace %02x %s %s\n", m->ns->access, access2str(m->ns->access), m->ns->name);
1196             swf_SetU30(tag, i);
1197         } else {
1198             assert(m->type!=0x07 && m->type!=0x0d);
1199         }
1200         if(m->name) {
1201             assert(m->type==0x09 || m->type==0x0e || m->type==0x07 || m->type==0x0d || m->type==0x0f || m->type==0x10);
1202             int i = pool_find_string(pool, m->name);
1203             if(i<0) fprintf(stderr, "internal error: unregistered name\n");
1204             swf_SetU30(tag, i);
1205         } else {
1206             assert(m->type!=0x09 && m->type!=0x0e && m->type!=0x07 && m->type!=0x0d && m->type!=0x0f && m->type!=0x10);
1207         }
1208         if(m->namespace_set) {
1209             assert(m->type==0x09 || m->type==0x0e || m->type==0x1c || m->type==0x1b);
1210             int i = pool_find_namespace_set(pool, m->namespace_set);
1211             if(i<0) fprintf(stderr, "internal error: unregistered namespace set\n");
1212             swf_SetU30(tag, i);
1213         } else {
1214             assert(m->type!=0x09 && m->type!=0x0e && m->type!=0x1c && m->type!=0x1b);
1215         }
1216     }
1217 }
1218
1219
1220 void pool_destroy(pool_t*pool)
1221 {
1222     int t;
1223     array_free(pool->x_ints);
1224     array_free(pool->x_uints);
1225     array_free(pool->x_floats);
1226     array_free(pool->x_strings);
1227     array_free(pool->x_namespaces);
1228     array_free(pool->x_namespace_sets);
1229     array_free(pool->x_multinames);
1230     free(pool);
1231 }