as3: introduced compile-time constants
[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     
59     if(*v1==*v2) return 1;
60     if(*v1!=*v1 && *v2!=*v2) return 1; //both values are NaN
61     return 0;
62 }
63
64 type_t float_type = {
65     dup: float_clone,
66     hash: float_hash,
67     free: float_destroy,
68     equals: float_equals
69 };
70
71 // ----------------------------- uint ----------------------------------
72
73 unsigned int undefined_uint = 0;
74
75 void*uint_clone(const void*_v) {
76     if(!_v)
77         return 0;
78     const unsigned int*v1=_v;
79     unsigned int*v2 = malloc(sizeof(unsigned int));
80     *v2 = *v1;
81     return v2;
82 }
83 unsigned int uint_hash(const void*_v) {
84     if(!_v)
85         return 0;
86     const unsigned int*v=_v;
87     return *v;
88 }
89 void uint_destroy(void*_v) {
90     unsigned int*v = (unsigned int*)_v;
91     if(v)
92         free(v);
93 }
94 char uint_equals(const void*_v1, const void*_v2) {
95     const unsigned int*v1=_v1;
96     const unsigned int*v2=_v2;
97     if(!v1 || !v2)
98         return v1==v2;
99     return *v1==*v2;
100 }
101
102 type_t uint_type = {
103     dup: (dup_func)uint_clone,
104     hash: (hash_func)uint_hash,
105     free: (free_func)uint_destroy,
106     equals: (equals_func)uint_equals
107 };
108
109 // ----------------------------- namespace ----------------------------------
110
111 unsigned int namespace_hash(namespace_t*n)
112 {
113     if(!n)
114         return 0;
115     unsigned int hash = 0;
116     hash = crc32_add_byte(hash, n->access);
117     hash = crc32_add_string(hash, n->name);
118     return hash;
119 }
120
121 unsigned char namespace_equals(const namespace_t*n1, const namespace_t*n2)
122 {
123     if(!n1 || !n2)
124         return n1==n2;
125     if(n1->access != n2->access)
126         return 0;
127     if(!(n1->name) != !(n2->name))
128         return 0;
129     if(n1->name && n2->name && strcmp(n1->name, n2->name))
130         return 0;
131     return 1;
132 }
133
134 char*escape_string(const char*str)
135 {
136     if(!str)
137         return strdup("NULL");
138     int len=0;
139     unsigned const char*s=str;
140     while(*s) {
141         if(*s<10) {
142             len+=2; // \d
143         } else if(*s<32) {
144             len+=3; // \dd
145         } else if(*s<127) {
146             len++;
147         } else {
148             len+=4; // \xhh
149         }
150         s++;
151     }
152     char*newstr = malloc(len+1);
153     char*dest = newstr;
154     s=str;
155     while(*s) {
156         if(*s<9) {
157             dest+=sprintf(dest, "\\%d", *s);
158         } else if(*s<32) {
159             if(*s==13)
160                 dest+=sprintf(dest, "\\r");
161             else if(*s==10) 
162                 dest+=sprintf(dest, "\\n");
163             else if(*s==9) 
164                 dest+=sprintf(dest, "\\t");
165             else 
166                 dest+=sprintf(dest, "\\%2o", *s);
167         } else if(*s<127) {
168             *dest++=*s;
169         } else {
170             dest+=sprintf(dest, "\\x%02x", *s);
171         }
172         s++;
173     }
174     *dest = 0;
175     return newstr;
176 }
177
178 char* namespace_tostring(namespace_t*ns)
179 {
180     if(!ns)
181         return strdup("NULL");
182     char*access = 0;
183     U8 type = ns->access;
184     access = access2str(type);
185     char*s = escape_string(ns->name);
186     char*string = (char*)malloc(strlen(access)+strlen(s)+7);
187     if(!s)
188         sprintf(string, "[%s]NULL", access, s);
189     else if(!*s)
190         sprintf(string, "[%s]\"\"", access, s);
191     else 
192         sprintf(string, "[%s]%s", access, s);
193     free(s);
194     return string;
195 }
196
197 namespace_t* namespace_clone(namespace_t*other)
198 {
199     if(!other)
200         return 0;
201     NEW(namespace_t,n);
202     n->access = other->access;
203     n->name = other->name?strdup(other->name):0;
204     return n;
205 }
206
207 namespace_t* namespace_fromstring(const char*name)
208 {
209     namespace_t*ns = malloc(sizeof(namespace_t));
210     memset(ns, 0, sizeof(namespace_t));
211     if(name[0] == '[') {
212         U8 access;
213         char*n = strdup(name);
214         char*bracket = strchr(n, ']');
215         if(bracket) {
216             *bracket = 0;
217             char*a = n+1;
218             name += (bracket-n)+1;
219             if(!strcmp(a, "")) access=0x16;
220             else if(!strcmp(a, "undefined")) access=0x08; // public??
221             else if(!strcmp(a, "package")) access=0x16;
222             else if(!strcmp(a, "public")) access=0x16;
223             else if(!strcmp(a, "packageinternal")) access=0x17;
224             else if(!strcmp(a, "protected")) access=0x18;
225             else if(!strcmp(a, "explicit")) access=0x19;
226             else if(!strcmp(a, "staticprotected")) access=0x1a;
227             else if(!strcmp(a, "private")) access=0x05;
228             else {
229                 fprintf(stderr, "Undefined access level: [%s]\n", a);
230                 free(n);
231                 return 0;
232             }
233         }
234         ns->access = access;
235         ns->name = strdup(name);
236         free(n);
237         return ns;
238     } else {
239         ns->access = 0x16;
240         ns->name = strdup(name);
241         return ns;
242     }
243 }
244
245 namespace_t* namespace_new(U8 access, const char*name)
246 {
247     namespace_t*ns = malloc(sizeof(namespace_t));
248     ns->access = access;
249     /* not sure what namespaces with empty strings are good for, but they *do* exist */
250     ns->name = name?strdup(name):0;
251     return ns;
252 }
253 namespace_t* namespace_new_namespace(const char*name) {
254     return namespace_new(0x08, name); // public?
255 }
256 namespace_t* namespace_new_package(const char*name) {
257     return namespace_new(0x16 , name);
258 }
259 namespace_t* namespace_new_packageinternal(const char*name) {
260     return namespace_new(0x17, name);
261 }
262 namespace_t* namespace_new_protected(const char*name) {
263     return namespace_new(0x18, name);
264 }
265 namespace_t* namespace_new_explicit(const char*name) {
266     return namespace_new(0x19, name);
267 }
268 namespace_t* namespace_new_staticprotected(const char*name) {
269     return namespace_new(0x1a, name);
270 }
271 namespace_t* namespace_new_private(const char*name) {
272     return namespace_new(0x05, name);
273 }
274
275 void namespace_destroy(namespace_t*n)
276 {
277     if(n) {
278         free((char*)n->name);n->name=0;
279         n->access=0x00;
280         free(n);
281     }
282 }
283
284 type_t namespace_type = {
285     dup: (dup_func)namespace_clone,
286     hash: (hash_func)namespace_hash,
287     free: (free_func)namespace_destroy,
288     equals: (equals_func)namespace_equals
289 };
290
291 // ---------------------------namespace sets --------------------------------
292
293 unsigned int namespace_set_hash(namespace_set_t*set)
294 {
295     if(!set)
296         return 0;
297     namespace_list_t*l = set->namespaces;
298     unsigned int hash = 0;
299     while(l) {
300         hash = crc32_add_byte(hash, l->namespace->access);
301         hash = crc32_add_string(hash, l->namespace->name);
302         l = l->next;
303     }
304     return hash;
305 }
306
307 int namespace_set_equals(namespace_set_t*m1, namespace_set_t*m2)
308 {
309     if(!m1 || !m2)
310         return m1==m2;
311     namespace_list_t*l1 = m1->namespaces;
312     namespace_list_t*l2 = m2->namespaces;
313     while(l1 && l2) {
314         if(l1->namespace->access != l2->namespace->access)
315             return 0;
316         if(!(l1->namespace->name) != !(l2->namespace->name))
317             return 0;
318         if(l1->namespace->name && l2->namespace->name && strcmp(l1->namespace->name, l2->namespace->name))
319             return 0;
320         l1 = l1->next;
321         l2 = l2->next;
322     }
323     if(l1||l2)
324         return 0;
325     return 1;
326 }
327
328 namespace_set_t* namespace_set_clone(namespace_set_t*other)
329 {
330     if(!other)
331         return 0;
332     NEW(namespace_set_t,set);
333     set->namespaces = list_new();
334     namespace_list_t*l = other->namespaces;
335     while(l) {
336         list_append(set->namespaces, namespace_clone(l->namespace));
337         l = l->next;
338     }
339     return set;
340 }
341 namespace_set_t* namespace_set_new()
342 {
343     NEW(namespace_set_t,set);
344     set->namespaces = list_new();
345     return set;
346 }
347 char* namespace_set_tostring(namespace_set_t*set)
348 {
349     if(!set)
350         return strdup("NULL");
351     /* TODO: is the order of the namespaces important (does it
352        change the lookup order?). E.g. flex freely shuffles namespaces
353        around.
354        If the order is not important, we can optimize constant pools by sorting
355        the namespaces.
356     */
357     int l = 0;
358     namespace_list_t*lns = set->namespaces;
359     while(lns) {
360         char*s = namespace_tostring(lns->namespace);
361         l += strlen(s)+1;
362         free(s);
363         lns = lns->next;
364     }
365     char*desc = malloc(l+16);
366     strcpy(desc, "{");
367     lns = set->namespaces;
368     while(lns) {
369         char*s = namespace_tostring(lns->namespace);
370         strcat(desc, s);
371         free(s);
372         lns = lns->next;
373         if(lns)
374             strcat(desc, ",");
375     }
376     strcat(desc, "}");
377     return desc;
378 }
379
380 void namespace_set_destroy(namespace_set_t*set)
381 {
382     if(set) {
383         namespace_list_t*l = set->namespaces;
384         while(l) {
385             namespace_destroy(l->namespace);l->namespace=0;
386             l = l->next;
387         }
388         list_free(set->namespaces);
389         free(set);
390     }
391 }
392
393 type_t namespace_set_type = {
394     dup: (dup_func)namespace_set_clone,
395     hash: (hash_func)namespace_set_hash,
396     free: (free_func)namespace_set_destroy,
397     equals: (equals_func)namespace_set_equals
398 };
399
400 // ----------------------------- multiname ----------------------------------
401
402 unsigned int multiname_hash(multiname_t*m)
403 {
404     if(!m)
405         return 0;
406     unsigned int hash = crc32_add_byte(0, m->type);
407     if(m->name) {
408         hash = crc32_add_string(hash, m->name);
409     }
410     if(m->ns) {
411         hash = crc32_add_byte(hash, m->ns->access);
412         hash = crc32_add_string(hash, m->ns->name);
413     }
414     if(m->namespace_set) {
415         namespace_list_t*l = m->namespace_set->namespaces;
416         while(l) {
417             hash = crc32_add_byte(hash, l->namespace->access);
418             hash = crc32_add_string(hash, l->namespace->name);
419             l = l->next;
420         }
421     }
422     return hash;
423 }
424
425 int multiname_equals(multiname_t*m1, multiname_t*m2)
426 {
427     if(!m1 || !m2)
428         return m1==m2;
429     if(m1->type!=m2->type)
430         return 0;
431
432     if((!m1->name) != (!m2->name))
433         return 0;
434     if((!m1->ns) != (!m2->ns))
435         return 0;
436     if((!m1->namespace_set) != (!m2->namespace_set))
437         return 0;
438
439     if(m1->name && m2->name && strcmp(m1->name,m2->name))
440         return 0;
441     if(m1->ns && m2->ns) {
442         if(!namespace_equals(m1->ns, m2->ns))
443             return 0;
444     }
445     if(m1->namespace_set && m2->namespace_set) {
446         if(!namespace_set_equals(m1->namespace_set, m2->namespace_set))
447             return 0;
448     }
449     return 1;
450 }
451
452 multiname_t* multiname_new(namespace_t*ns, const char*name)
453 {
454     NEW(multiname_t,m);
455     m->type = QNAME;
456     if(!ns) {
457         m->ns = namespace_new_packageinternal("");
458     } else {
459         m->ns = namespace_clone(ns);
460     }
461     m->name = strdup(name);
462     return m;
463 }
464
465 multiname_t* multiname_clone(multiname_t*other)
466 {
467     if(!other)
468         return 0;
469     NEW(multiname_t,m);
470     m->type = other->type;
471     if(other->ns)
472         m->ns = namespace_clone(other->ns);
473     if(other->namespace_set)
474         m->namespace_set = namespace_set_clone(other->namespace_set);
475     if(other->name)
476         m->name = strdup(other->name);
477     return m;
478 }
479
480
481 char* access2str(int type)
482 {
483     if(type==0x08) return "namespace";
484     else if(type==0x16) return "public";
485     else if(type==0x17) return "packageinternal";
486     else if(type==0x18) return "protected";
487     else if(type==0x19) return "explicit";
488     else if(type==0x1A) return "staticprotected";
489     else if(type==0x05) return "private";
490     else {
491         fprintf(stderr, "Undefined access type %02x\n", type);
492         return "undefined";
493     }
494 }
495
496
497 char multiname_late_namespace(multiname_t*m)
498 {
499     if(!m)
500         return 0;
501     return (m->type==RTQNAME || m->type==RTQNAMEA ||
502             m->type==RTQNAMEL || m->type==RTQNAMELA);
503 }
504
505 char multiname_late_name(multiname_t*m)
506 {
507     if(!m)
508         return 0;
509     return m->type==RTQNAMEL || m->type==RTQNAMELA ||
510            m->type==MULTINAMEL || m->type==MULTINAMELA;
511 }
512
513 char* multiname_tostring(multiname_t*m)
514 {
515     char*mname = 0;
516     if(!m)
517         return strdup("NULL");
518     if(m->type==0xff)
519         return strdup("--<MULTINAME 0xff>--");
520
521     char*name = m->name?escape_string(m->name):strdup("*");
522     int namelen = strlen(name);
523
524     if(m->type==QNAME || m->type==QNAMEA || m->type==POSTFIXTYPE) {
525         char*nsname = escape_string(m->ns->name);
526         mname = malloc(strlen(nsname)+namelen+32);
527         strcpy(mname, "<q");
528         if(m->type == QNAMEA)
529             strcat(mname, ",attr");
530         strcat(mname, ">[");
531         strcat(mname,access2str(m->ns->access));
532         strcat(mname, "]");
533         strcat(mname, nsname);
534         free(nsname);
535         strcat(mname, "::");
536         strcat(mname, name);
537     } else if(m->type==RTQNAME || m->type==RTQNAMEA) {
538         mname = malloc(namelen+32);
539         strcpy(mname, "<rt");
540         if(m->type == RTQNAMEA) 
541             strcat(mname, ",attr");
542         strcat(mname, ">");
543         strcat(mname, name);
544     } else if(m->type==RTQNAMEL) {
545         mname = strdup("<rt,l>");
546     } else if(m->type==RTQNAMELA) {
547         mname = strdup("<rt,l,attr>");
548     } else if(m->type==MULTINAME || m->type==MULTINAMEA) {
549         char*s = namespace_set_tostring(m->namespace_set);
550         mname = malloc(strlen(s)+namelen+16);
551         if(m->type == MULTINAME)
552             strcpy(mname,"<multi>");
553         else //MULTINAMEA
554             strcpy(mname,"<multi,attr>");
555         strcat(mname, s);
556         strcat(mname, "::");
557         strcat(mname, name);
558         free(s);
559     } else if(m->type==MULTINAMEL || m->type==MULTINAMELA) {
560         char*s = namespace_set_tostring(m->namespace_set);
561         mname = malloc(strlen(s)+16);
562         if(m->type == MULTINAMEL)
563             strcpy(mname,"<l,multi>");
564         else //MULTINAMELA
565             strcpy(mname,"<l,multi,attr>");
566         strcat(mname,s);
567         free(s);
568     } else {
569         return strdup("<invalid>");
570     }
571     free(name);
572     return mname;
573 }
574
575 multiname_t* multiname_fromstring(const char*name2)
576 {
577     if(!name2)
578         return 0;
579     char*n = strdup(name2);
580     char*p = strstr(n, "::");
581     char*namespace=0,*name=0;
582     if(!p) {
583         if(strchr(n, ':')) {
584             fprintf(stderr, "Error: single ':' in name\n");
585         }
586         namespace = "";
587         name = n;
588     } else {
589         *p = 0;
590         namespace = n;
591         name = p+2;
592         if(strchr(namespace, ':')) {
593             fprintf(stderr, "Error: single ':' in namespace\n");
594         }
595         if(strchr(name, ':')) {
596             fprintf(stderr, "Error: single ':' in qualified name\n");
597         }
598     }
599
600     multiname_t*m = malloc(sizeof(multiname_t));
601     memset(m, 0, sizeof(multiname_t));
602     m->type = QNAME;
603     m->namespace_set = 0;
604     m->ns = namespace_fromstring(namespace);
605     m->name = name?strdup(name):0;
606     free(n);
607     return m;
608 }
609
610 void multiname_destroy(multiname_t*m)
611 {
612     if(m) {
613         if(m->name) {
614             free((void*)m->name);m->name = 0;
615         }
616         if(m->ns) {
617             namespace_destroy(m->ns);m->ns = 0;
618         }
619         if(m->namespace_set) {
620             namespace_set_destroy(m->namespace_set);m->namespace_set = 0;
621         }
622         m->type=0;
623         free(m);
624     }
625 }
626
627 type_t multiname_type = {
628     dup: (dup_func)multiname_clone,
629     hash: (hash_func)multiname_hash,
630     free: (free_func)multiname_destroy,
631     equals: (equals_func)multiname_equals
632 };
633
634
635 // ------------------------------- constants -------------------------------------
636
637 #define UNIQUE_CONSTANT(x) ((x) == CONSTANT_TRUE || (x) == CONSTANT_FALSE || (x) == CONSTANT_NULL || (x) == CONSTANT_UNDEFINED)
638
639 constant_t* constant_new_int(int i) 
640 {
641     NEW(constant_t,c);
642     c->i = i;
643     c->type = CONSTANT_INT;
644     return c;
645 }
646 constant_t* constant_new_uint(unsigned int u)
647 {
648     NEW(constant_t,c);
649     c->u = u;
650     c->type = CONSTANT_UINT;
651     return c;
652 }
653 constant_t* constant_new_float(double f)
654 {
655     NEW(constant_t,c);
656     c->f = f;
657     c->type = CONSTANT_FLOAT;
658     return c;
659 }
660 constant_t* constant_new_string(char*s)
661 {
662     NEW(constant_t,c);
663     c->s = string_new4(s);
664     c->type = CONSTANT_STRING;
665     return c;
666 }
667 constant_t* constant_new_string2(const char*s, int len)
668 {
669     NEW(constant_t,c);
670     c->s = string_new3(s, len);
671     c->type = CONSTANT_STRING;
672     return c;
673 }
674 constant_t* constant_new_namespace(namespace_t*ns)
675 {
676     NEW(constant_t,c);
677     c->ns = namespace_clone(ns);
678     c->type = ns->access;
679     assert(NS_TYPE(c->type));
680     return c;
681 }
682 constant_t* constant_new_true()
683 {
684     NEW(constant_t,c);
685     c->type = CONSTANT_TRUE;
686     return c;
687 }
688 constant_t* constant_new_false()
689 {
690     NEW(constant_t,c);
691     c->type = CONSTANT_FALSE;
692     return c;
693 }
694 constant_t* constant_new_null()
695 {
696     NEW(constant_t,c);
697     c->type = CONSTANT_NULL;
698     return c;
699 }
700 constant_t* constant_new_undefined()
701 {
702     NEW(constant_t,c);
703     c->type = CONSTANT_UNDEFINED;
704     return c;
705 }
706 constant_t* constant_clone(constant_t*other)
707 {
708     if(!other) return 0;
709     constant_t*c = malloc(sizeof(constant_t));
710     memcpy(c, other, sizeof(constant_t));
711     if(NS_TYPE(c->type)) {
712         c->ns = namespace_clone(other->ns);
713     } else if(c->type == CONSTANT_STRING) {
714         c->s = string_dup3(other->s);
715     }
716     return c;
717 }
718 constant_t* constant_fromindex(pool_t*pool, int index, int type)
719 {
720     if(!index) {
721         /* even for nonvalued constants (like TRUE/FALSE etc.), a nonzero
722            index is present to indicate that a type is coming */
723         return 0;
724     } 
725     NEW(constant_t,c);
726     c->type = type;
727     if(NS_TYPE(c->type)) {
728         c->ns = namespace_clone(pool_lookup_namespace(pool, index));
729     } else if(c->type == CONSTANT_INT) {
730         c->i = pool_lookup_int(pool, index);
731     } else if(c->type == CONSTANT_UINT) {
732         c->u = pool_lookup_uint(pool, index);
733     } else if(c->type == CONSTANT_FLOAT) {
734         c->f = pool_lookup_float(pool, index);
735     } else if(c->type == CONSTANT_STRING) {
736         string_t s = pool_lookup_string2(pool, index);
737         c->s = string_dup3(&s);
738     } else if(UNIQUE_CONSTANT(c->type)) {
739         // ok
740     } else {
741         fprintf(stderr, "invalid constant type %02x\n", c->type);
742     }
743     return c;
744 }
745 char* constant_tostring(constant_t*c)
746 {
747     if(!c)
748         return strdup("NULL");
749     char buf[32];
750     if(NS_TYPE(c->type)) {
751         return namespace_tostring(c->ns);
752     } else if(c->type == CONSTANT_INT) {
753         sprintf(buf, "%d", c->i);
754         return strdup(buf);
755     } else if(c->type == CONSTANT_UINT) {
756         sprintf(buf, "%u", c->u);
757         return strdup(buf);
758     } else if(c->type == CONSTANT_FLOAT) {
759         char buf[1024];
760         sprintf(buf, "%f", c->f);
761         return strdup(buf);
762     } else if(c->type == CONSTANT_STRING) {
763         /* should we escape the string? \0 bytes won't be printed */
764         return strdup_n(c->s->str,c->s->len);
765     } else if(c->type == CONSTANT_TRUE) {
766         return strdup("true");
767     } else if(c->type == CONSTANT_FALSE) {
768         return strdup("false");
769     } else if(c->type == CONSTANT_NULL) {
770         return strdup("null");
771     } else if(c->type == CONSTANT_UNDEFINED) {
772         return strdup("undefined");
773     } else {
774         fprintf(stderr, "invalid constant type %02x\n", c->type);
775         return 0;
776     }
777 }
778 char constant_has_index(constant_t*c) 
779 {
780     if(!c)
781         return 0;
782     return !UNIQUE_CONSTANT(c->type);
783 }
784 int constant_get_index(pool_t*pool, constant_t*c)
785 {
786     if(!c)
787         return 0;
788     if(NS_TYPE(c->type)) {
789         assert(c->ns);
790         /*if(c->type!=c->ns->access) {
791             printf("%02x<->%02x\n", c->type, c->ns->access);
792         }*/
793         assert(c->type == c->ns->access);
794         return pool_register_namespace(pool, c->ns);
795     } else if(c->type == CONSTANT_INT) {
796         return pool_register_int(pool, c->i);
797     } else if(c->type == CONSTANT_UINT) {
798         return pool_register_uint(pool, c->u);
799     } else if(c->type == CONSTANT_FLOAT) {
800         return pool_register_float(pool, c->f);
801     } else if(c->type == CONSTANT_STRING) {
802         return pool_register_string2(pool, c->s);
803     } else if(c->type == CONSTANT_UNDEFINED) {
804         /* write undefined with index 0 (and no type). Otherwise, the FlashPlayer 
805            seems to throw an "attempt to read out of bounds" exception */
806         return 0;
807     } else if(!constant_has_index(c)) {
808         return 1;
809     } else {
810         fprintf(stderr, "invalid constant type %02x\n", c->type);
811         return 0;
812     }
813 }
814 void constant_free(constant_t*c)
815 {
816     if(!c)
817         return;
818     if(c->type == CONSTANT_STRING) {
819         string_free(c->s);
820     } else if (NS_TYPE(c->type)) {
821         namespace_destroy(c->ns);c->ns=0;
822     }
823     free(c);
824 }
825 // --------------------------- optimizing -----------------------------------
826
827 static int array_append_or_increase(array_t*array, void*key)
828 {
829     int pos = array_find(array, key);
830     if(pos>=0) {
831         array->d[pos].data++;
832         return pos;
833     } else {
834         return array_append(array, key, 0);
835     }
836 }
837 static int compare_arrayentry(const void*_c1, const void*_c2)
838 {
839     const array_entry_t*c1 = _c1;
840     const array_entry_t*c2 = _c2;
841     return c2->data - c1->data;
842 }
843
844 static void* nodup(const void*o) {return (void*)o;}
845
846 static void reshuffle_array(array_t*array)
847 {
848     qsort(array->d+1, array->num-1, sizeof(array->d[0]), compare_arrayentry);
849     type_t* old_type = array->entry2pos->key_type;
850     type_t old_type_nodup = *old_type;
851     old_type_nodup.dup = nodup;
852     dict_t*d = dict_new2(&old_type_nodup);
853     dict_destroy_shallow(array->entry2pos);
854     array->entry2pos = d;
855     int t;
856     for(t=0;t<array->num;t++) {
857         dict_put(array->entry2pos, array->d[t].name, (void*)(ptroff_t)(t+1));
858     }
859     d->key_type = old_type;
860
861 }
862
863 // ------------------------------- pool -------------------------------------
864
865 int pool_register_uint(pool_t*p, unsigned int i)
866 {
867     int pos = array_append_or_increase(p->x_uints, &i);
868     assert(pos!=0);
869     return pos;
870 }
871 int pool_register_int(pool_t*p, int i)
872 {
873     int pos = array_append_or_increase(p->x_ints, &i);
874     assert(pos!=0);
875     return pos;
876 }
877 int pool_register_float(pool_t*p, double d)
878 {
879     int pos = array_append_or_increase(p->x_floats, &d);
880     assert(pos!=0);
881     return pos;
882 }
883 int pool_register_string(pool_t*pool, const char*str)
884 {
885     if(!str) return 0;
886     string_t s = string_new2(str);
887     int pos = array_append_or_increase(pool->x_strings, &s);
888     assert(pos!=0);
889     return pos;
890 }
891 int pool_register_string2(pool_t*pool, string_t*s)
892 {
893     if(!s || !s->str) return 0;
894     int pos = array_append_or_increase(pool->x_strings, s);
895     assert(pos!=0);
896     return pos;
897 }
898 int pool_register_namespace(pool_t*pool, namespace_t*ns)
899 {
900     if(!ns) return 0;
901     int pos = array_append_or_increase(pool->x_namespaces, ns);
902     assert(pos!=0);
903     return pos;
904 }
905 int pool_register_namespace_set(pool_t*pool, namespace_set_t*set)
906 {
907     if(!set) return 0;
908     int pos = array_append_or_increase(pool->x_namespace_sets, set);
909     assert(pos!=0);
910     return pos;
911 }
912 int pool_register_multiname(pool_t*pool, multiname_t*n)
913 {
914     if(!n) return 0;
915     int pos = array_append_or_increase(pool->x_multinames, n);
916     assert(pos!=0);
917     return pos;
918 }
919 int pool_register_multiname2(pool_t*pool, char*name)
920 {
921     if(!name) return 0;
922     multiname_t*n = multiname_fromstring(name);
923     int pos = array_append_or_increase(pool->x_multinames, n);
924     multiname_destroy(n);
925     assert(pos!=0);
926     return pos;
927 }
928
929
930 int pool_find_uint(pool_t*pool, unsigned int x)
931 {
932     int i = array_find(pool->x_uints, &x);
933     if(i<=0) {
934         fprintf(stderr, "Couldn't find uint \"%d\" in constant pool\n", x);
935         return 0;
936     }
937     return i;
938 }
939 int pool_find_int(pool_t*pool, int x)
940 {
941     int i = array_find(pool->x_ints, &x);
942     if(i<=0) {
943         fprintf(stderr, "Couldn't find int \"%d\" in constant pool\n", x);
944         return 0;
945     }
946     return i;
947 }
948 int pool_find_float(pool_t*pool, double x)
949 {
950     int i = array_find(pool->x_ints, &x);
951     if(i<=0) {
952         fprintf(stderr, "Couldn't find int \"%d\" in constant pool\n", x);
953         return 0;
954     }
955     return i;
956 }
957 int pool_find_namespace(pool_t*pool, namespace_t*ns)
958 {
959     if(!ns)
960         return 0;
961     int i = array_find(pool->x_namespaces, ns);
962     if(i<=0) {
963         char*s = namespace_tostring(ns);
964         fprintf(stderr, "Couldn't find namespace \"%s\" %08x in constant pool\n", s, ns);
965         free(s);
966         return 0;
967     }
968     return i;
969 }
970 int pool_find_namespace_set(pool_t*pool, namespace_set_t*set)
971 {
972     if(!set)
973         return 0;
974     int i = array_find(pool->x_namespace_sets, set);
975     if(i<=0) {
976         char*s = namespace_set_tostring(set);
977         fprintf(stderr, "Couldn't find namespace_set \"%s\" in constant pool\n", s);
978         free(s);
979         return 0;
980     }
981     return i;
982 }
983 int pool_find_string(pool_t*pool, const char*str)
984 {
985     if(!str)
986         return 0;
987     string_t s = string_new2(str);
988     int i = array_find(pool->x_strings, &s);
989     if(i<=0) {
990         fprintf(stderr, "Couldn't find string \"%s\" in constant pool\n", s);
991         return 0;
992     }
993     return i;
994 }
995 int pool_find_multiname(pool_t*pool, multiname_t*name)
996 {
997     if(!name)
998         return 0;
999     int i = array_find(pool->x_multinames, name);
1000     if(i<=0) {
1001         char*s = multiname_tostring(name);
1002         fprintf(stderr, "Couldn't find multiname \"%s\" in constant pool\n", s);
1003         free(s);
1004         return 0;
1005     }
1006     return i;
1007 }
1008
1009 int pool_lookup_int(pool_t*pool, int i)
1010 {
1011     if(!i) return 0;
1012     return *(int*)array_getkey(pool->x_ints, i);
1013 }
1014 unsigned int pool_lookup_uint(pool_t*pool, int i)
1015 {
1016     if(!i) return 0;
1017     return *(unsigned int*)array_getkey(pool->x_uints, i);
1018 }
1019 double pool_lookup_float(pool_t*pool, int i)
1020 {
1021     if(!i) return __builtin_nan("");
1022     return *(double*)array_getkey(pool->x_floats, i);
1023 }
1024 const char*pool_lookup_string(pool_t*pool, int i)
1025 {
1026     string_t*s = array_getkey(pool->x_strings, i);
1027     if(!s) return 0;
1028     return s->str;
1029 }
1030 string_t pool_lookup_string2(pool_t*pool, int i)
1031 {
1032     string_t*s = array_getkey(pool->x_strings, i);
1033     return *s;
1034 }
1035 namespace_t*pool_lookup_namespace(pool_t*pool, int i)
1036 {
1037     return (namespace_t*)array_getkey(pool->x_namespaces, i);
1038 }
1039 namespace_set_t*pool_lookup_namespace_set(pool_t*pool, int i)
1040 {
1041     return (namespace_set_t*)array_getkey(pool->x_namespace_sets, i);
1042 }
1043 multiname_t*pool_lookup_multiname(pool_t*pool, int i)
1044 {
1045     return (multiname_t*)array_getkey(pool->x_multinames, i);
1046 }
1047
1048 pool_t*pool_new()
1049 {
1050     NEW(pool_t, p);
1051
1052     p->x_ints = array_new2(&uint_type);
1053     p->x_uints = array_new2(&uint_type);
1054     p->x_floats = array_new2(&float_type);
1055     p->x_strings = array_new2(&stringstruct_type);
1056     p->x_namespaces = array_new2(&namespace_type);
1057     p->x_namespace_sets = array_new2(&namespace_set_type);
1058     p->x_multinames = array_new2(&multiname_type);
1059
1060     /* add a zero-index entry in each list */
1061   
1062     array_append(p->x_ints, 0, 0);
1063     array_append(p->x_uints, 0, 0);
1064     array_append(p->x_floats, 0, 0);
1065     array_append(p->x_strings, 0, 0);
1066     array_append(p->x_namespaces, 0, 0);
1067     array_append(p->x_namespace_sets, 0, 0);
1068     array_append(p->x_multinames, 0, 0);
1069     return p;
1070 }
1071
1072 void pool_optimize(pool_t*p)
1073 {
1074     reshuffle_array(p->x_ints);
1075     reshuffle_array(p->x_uints);
1076     reshuffle_array(p->x_floats);
1077     reshuffle_array(p->x_strings);
1078     reshuffle_array(p->x_namespaces);
1079     reshuffle_array(p->x_namespace_sets);
1080     reshuffle_array(p->x_multinames);
1081 }
1082
1083 #define DEBUG if(0)
1084 //#define DEBUG
1085
1086 void pool_read(pool_t*pool, TAG*tag)
1087 {
1088     int num_ints = swf_GetU30(tag);
1089     DEBUG printf("%d ints\n", num_ints);
1090     int t;
1091     for(t=1;t<num_ints;t++) {
1092         S32 v = swf_GetABCS32(tag);
1093         DEBUG printf("int %d) %d\n", t, v);
1094         array_append(pool->x_ints, &v, 0);
1095     }
1096
1097     int num_uints = swf_GetU30(tag);
1098     DEBUG printf("%d uints\n", num_uints);
1099     for(t=1;t<num_uints;t++) {
1100         U32 v = swf_GetABCU32(tag);
1101         DEBUG printf("uint %d) %d\n", t, v);
1102         array_append(pool->x_uints, &v, 0);
1103     }
1104     
1105     int num_floats = swf_GetU30(tag);
1106     DEBUG printf("%d floats\n", num_floats);
1107     for(t=1;t<num_floats;t++) {
1108         double d = swf_GetD64(tag);
1109         DEBUG printf("float %d) %f\n", t, d);
1110         array_append(pool->x_floats, &d, 0);
1111     }
1112     
1113     int num_strings = swf_GetU30(tag);
1114     DEBUG printf("%d strings\n", num_strings);
1115     for(t=1;t<num_strings;t++) {
1116         int len = swf_GetU30(tag);
1117         string_t s = string_new(&tag->data[tag->pos], len);
1118         swf_GetBlock(tag, 0, len);
1119         array_append(pool->x_strings, &s, 0);
1120         DEBUG printf("%d) \"%s\"\n", t, ((string_t*)array_getkey(pool->x_strings, t))->str);
1121     }
1122     int num_namespaces = swf_GetU30(tag);
1123     DEBUG printf("%d namespaces\n", num_namespaces);
1124     for(t=1;t<num_namespaces;t++) {
1125         U8 type = swf_GetU8(tag);
1126         int namenr = swf_GetU30(tag);
1127         const char*name = 0; 
1128         if(namenr)
1129             name = pool_lookup_string(pool, namenr);
1130         namespace_t*ns = namespace_new(type, name);
1131         array_append(pool->x_namespaces, ns, 0);
1132         DEBUG printf("%d) %02x \"%s\"\n", t, type, namespace_tostring(ns));
1133         namespace_destroy(ns);
1134     }
1135     int num_sets = swf_GetU30(tag);
1136     DEBUG printf("%d namespace sets\n", num_sets);
1137     for(t=1;t<num_sets;t++) {
1138         int count = swf_GetU30(tag);
1139         int s;
1140         
1141         NEW(namespace_set_t, nsset);
1142         for(s=0;s<count;s++) {
1143             int nsnr = swf_GetU30(tag);
1144             if(!nsnr)
1145                 fprintf(stderr, "Zero entry in namespace set\n");
1146             namespace_t*ns = (namespace_t*)array_getkey(pool->x_namespaces, nsnr);
1147             list_append(nsset->namespaces, namespace_clone(ns));
1148         }
1149         array_append(pool->x_namespace_sets, nsset, 0);
1150         DEBUG printf("set %d) %s\n", t, namespace_set_tostring(nsset));
1151         namespace_set_destroy(nsset);
1152     }
1153
1154     int num_multinames = swf_GetU30(tag);
1155     DEBUG printf("%d multinames\n", num_multinames);
1156     for(t=1;t<num_multinames;t++) {
1157         multiname_t m;
1158         memset(&m, 0, sizeof(multiname_t));
1159         
1160         /*int s;
1161         for(s=0;s<8;s++)
1162             printf("0x%02x ", tag->data[tag->pos+s]);
1163         printf("\n");*/
1164
1165         m.type = swf_GetU8(tag);
1166         if(m.type==0x07 || m.type==0x0d) {
1167             int namespace_index = swf_GetU30(tag);
1168             m.ns = (namespace_t*)array_getkey(pool->x_namespaces, namespace_index);
1169             int name_index = swf_GetU30(tag);
1170             if(name_index) // 0 = '*' (any)
1171                 m.name = pool_lookup_string(pool, name_index);
1172         } else if(m.type==0x0f || m.type==0x10) {
1173             int name_index = swf_GetU30(tag);
1174             if(name_index) // 0 = '*' (any name)
1175                 m.name = pool_lookup_string(pool, name_index);
1176         } else if(m.type==0x11 || m.type==0x12) {
1177         } else if(m.type==0x09 || m.type==0x0e) {
1178             int name_index = swf_GetU30(tag);
1179             int namespace_set_index = swf_GetU30(tag);
1180             if(name_index)
1181                 m.name = pool_lookup_string(pool, name_index);
1182             m.namespace_set = (namespace_set_t*)array_getkey(pool->x_namespace_sets, namespace_set_index);
1183         } else if(m.type==0x1b || m.type==0x1c) {
1184             int namespace_set_index = swf_GetU30(tag);
1185             m.namespace_set = (namespace_set_t*)array_getkey(pool->x_namespace_sets, namespace_set_index);
1186         } else if(m.type==0x1d) {
1187             int v1 = swf_GetU30(tag); //multiname
1188             int v2 = swf_GetU30(tag); //counter?
1189             int v3 = swf_GetU30(tag); //multiname
1190             // e.g. Vector<int> ... we only store the parent object
1191             m = *(multiname_t*)array_getkey(pool->x_multinames, v1);
1192         } else {
1193             printf("can't parse type %d multinames yet\n", m.type);
1194         }
1195         DEBUG printf("multiname %d) %s\n", t, multiname_tostring(&m));
1196         array_append(pool->x_multinames, &m, 0);
1197     }
1198
1199
1200 void pool_dump(pool_t*pool, FILE*fo, char flags)
1201 {
1202     int t;
1203     fprintf(fo, "%d integers\n", pool->x_ints->num);
1204     for(t=1;t<pool->x_ints->num;t++) {
1205         S32 val = *(int*)array_getkey(pool->x_ints, t);
1206         int freq = (int)(ptroff_t)array_getvalue(pool->x_ints, t);
1207         if(flags&1) fprintf(fo, "%5d %d) %d\n", freq, t, val);
1208     }
1209     fprintf(fo, "%d unsigned integers\n", pool->x_uints->num);
1210     for(t=1;t<pool->x_uints->num;t++) {
1211         U32 val = *(unsigned int*)array_getkey(pool->x_uints, t);
1212         int freq = (int)(ptroff_t)array_getvalue(pool->x_uints, t);
1213         if(flags&1) fprintf(fo, "%5d %d) %d\n", freq, t, val);
1214     }
1215     fprintf(fo, "%d floats\n", pool->x_floats->num);
1216     for(t=1;t<pool->x_floats->num;t++) {
1217         double d = pool_lookup_float(pool, t);
1218         int freq = (int)(ptroff_t)array_getvalue(pool->x_floats, t);
1219         if(flags&2) fprintf(fo, "%5d %d) %f\n", freq, t, d);
1220     }
1221     fprintf(fo, "%d strings\n", pool->x_strings->num);
1222     for(t=1;t<pool->x_strings->num;t++) {
1223         string_t str = pool_lookup_string2(pool, t);
1224         int freq = (int)(ptroff_t)array_getvalue(pool->x_strings, t);
1225         if(flags&1) fprintf(fo, "%5d %d) ", freq, t);
1226         if(flags&1) fwrite(str.str, str.len, 1, fo);
1227         if(flags&1) fprintf(fo, "\n", t);
1228     }
1229     fprintf(fo, "%d namespaces\n", pool->x_namespaces->num);
1230     for(t=1;t<pool->x_namespaces->num;t++) {
1231         namespace_t*ns= (namespace_t*)array_getkey(pool->x_namespaces, t);
1232         char*s = namespace_tostring(ns);
1233         int freq = (int)(ptroff_t)array_getvalue(pool->x_namespaces, t);
1234         if(flags&1) fprintf(fo, "%5d %d) %s\n", freq, t, s);
1235         free(s);
1236     }
1237     fprintf(fo, "%d namespace sets\n", pool->x_namespace_sets->num);
1238     for(t=1;t<pool->x_namespace_sets->num;t++) {
1239         namespace_set_t*set = (namespace_set_t*)array_getkey(pool->x_namespace_sets, t);
1240         char*s = namespace_set_tostring(set);
1241         int freq = (int)(ptroff_t)array_getvalue(pool->x_namespace_sets, t);
1242         if(flags&1) fprintf(fo, "%5d %d) %s\n", freq, t, s);
1243         free(s);
1244     }
1245
1246     fprintf(fo, "%d multinames\n", pool->x_multinames->num);
1247     for(t=1;t<pool->x_multinames->num;t++) {
1248         multiname_t*m = (multiname_t*)array_getkey(pool->x_multinames, t);
1249         char*s = multiname_tostring(m);
1250         int freq = (int)(ptroff_t)array_getvalue(pool->x_multinames, t);
1251         if(flags&1) fprintf(fo, "%5d %d) %s\n", freq, t, s);
1252         free(s);
1253     }
1254
1255
1256 void pool_write(pool_t*pool, TAG*tag)
1257 {
1258     int t;
1259     
1260     /* make sure that all namespaces used by multinames / namespace sets
1261        and all strings used by namespaces exist */
1262
1263     for(t=1;t<pool->x_multinames->num;t++) {
1264         multiname_t*m = (multiname_t*)array_getkey(pool->x_multinames, t);
1265         if(m->ns) {
1266             pool_register_namespace(pool, m->ns);
1267         }
1268         if(m->namespace_set) {
1269             pool_register_namespace_set(pool, m->namespace_set);
1270         }
1271         if(m->name) {
1272             pool_register_string(pool, m->name);
1273         }
1274     }
1275     for(t=1;t<pool->x_namespace_sets->num;t++) {
1276         namespace_set_t*set = (namespace_set_t*)array_getkey(pool->x_namespace_sets, t);
1277         namespace_list_t*i = set->namespaces;
1278         while(i) {
1279             pool_register_namespace(pool, i->namespace);
1280             i = i->next;
1281         }
1282     }
1283     for(t=1;t<pool->x_namespaces->num;t++) {
1284         namespace_t*ns= (namespace_t*)array_getkey(pool->x_namespaces, t);
1285         /*  The spec says (page 22): "a value of zero denotes an empty string".
1286             However when actually using zero strings as empty namespaces, the
1287             flash player breaks.*/
1288         //if(ns->name && ns->name[0])
1289         pool_register_string(pool, ns->name);
1290     }
1291
1292     //pool_register_int(pool, 15);
1293     //pool_register_int(pool, 1);
1294     //pool_register_int(pool, 0);
1295     
1296     /* write data */
1297     swf_SetU30(tag, pool->x_ints->num>1?pool->x_ints->num:0);
1298     for(t=1;t<pool->x_ints->num;t++) {
1299         S32 val = *(int*)array_getkey(pool->x_ints, t);
1300         swf_SetABCS32(tag, val);
1301     }
1302     swf_SetU30(tag, pool->x_uints->num>1?pool->x_uints->num:0);
1303     for(t=1;t<pool->x_uints->num;t++) {
1304         swf_SetABCU32(tag, *(unsigned int*)array_getkey(pool->x_uints, t));
1305     }
1306     swf_SetU30(tag, pool->x_floats->num>1?pool->x_floats->num:0);
1307     for(t=1;t<pool->x_floats->num;t++) {
1308         double d = pool_lookup_float(pool, t);
1309         swf_SetD64(tag, d);
1310     }
1311     swf_SetU30(tag, pool->x_strings->num>1?pool->x_strings->num:0);
1312     for(t=1;t<pool->x_strings->num;t++) {
1313         string_t str = pool_lookup_string2(pool, t);
1314         swf_SetU30String(tag, str.str, str.len);
1315     }
1316     swf_SetU30(tag, pool->x_namespaces->num>1?pool->x_namespaces->num:0);
1317     for(t=1;t<pool->x_namespaces->num;t++) {
1318         namespace_t*ns= (namespace_t*)array_getkey(pool->x_namespaces, t);
1319         swf_SetU8(tag, ns->access);
1320         const char*name = ns->name;
1321         int i = 0;
1322         
1323         //if(name && name[0])
1324         i = pool_find_string(pool, name);
1325
1326         swf_SetU30(tag, i);
1327     }
1328     swf_SetU30(tag, pool->x_namespace_sets->num>1?pool->x_namespace_sets->num:0);
1329     for(t=1;t<pool->x_namespace_sets->num;t++) {
1330         namespace_set_t*set = (namespace_set_t*)array_getkey(pool->x_namespace_sets, t);
1331         namespace_list_t*i = set->namespaces; 
1332         int len = list_length(i);
1333         swf_SetU30(tag, len);
1334         while(i) {
1335             int index = pool_find_namespace(pool, i->namespace);
1336             swf_SetU30(tag, index);
1337             i = i->next;
1338         }
1339     }
1340
1341     swf_SetU30(tag, pool->x_multinames->num>1?pool->x_multinames->num:0);
1342     for(t=1;t<pool->x_multinames->num;t++) {
1343         multiname_t*m = (multiname_t*)array_getkey(pool->x_multinames, t);
1344         swf_SetU8(tag, m->type);
1345
1346         if(m->ns) {
1347             assert(m->type==0x07 || m->type==0x0d);
1348             int i = pool_find_namespace(pool, m->ns);
1349             if(i<0) fprintf(stderr, "internal error: unregistered namespace %02x %s %s\n", m->ns->access, access2str(m->ns->access), m->ns->name);
1350             swf_SetU30(tag, i);
1351         } else {
1352             assert(m->type!=0x07 && m->type!=0x0d);
1353         }
1354         if(m->name) {
1355             assert(m->type==0x09 || m->type==0x0e || m->type==0x07 || m->type==0x0d || m->type==0x0f || m->type==0x10);
1356             int i = pool_find_string(pool, m->name);
1357             if(i<0) fprintf(stderr, "internal error: unregistered name\n");
1358             swf_SetU30(tag, i);
1359         } else {
1360             assert(m->type!=0x09 && m->type!=0x0e && m->type!=0x07 && m->type!=0x0d && m->type!=0x0f && m->type!=0x10);
1361         }
1362         if(m->namespace_set) {
1363             assert(m->type==0x09 || m->type==0x0e || m->type==0x1c || m->type==0x1b);
1364             int i = pool_find_namespace_set(pool, m->namespace_set);
1365             if(i<0) fprintf(stderr, "internal error: unregistered namespace set\n");
1366             swf_SetU30(tag, i);
1367         } else {
1368             assert(m->type!=0x09 && m->type!=0x0e && m->type!=0x1c && m->type!=0x1b);
1369         }
1370     }
1371 }
1372
1373
1374 void pool_destroy(pool_t*pool)
1375 {
1376     int t;
1377     array_free(pool->x_ints);
1378     array_free(pool->x_uints);
1379     array_free(pool->x_floats);
1380     array_free(pool->x_strings);
1381     array_free(pool->x_namespaces);
1382     array_free(pool->x_namespace_sets);
1383     array_free(pool->x_multinames);
1384     free(pool);
1385 }