added support for \0 in strings
[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     ptroff_t l = strlen(s);
817     int pos = array_append_if_new(pool->x_strings, s, (void*)l);
818     assert(pos!=0);
819     return pos;
820 }
821 int pool_register_namespace(pool_t*pool, namespace_t*ns)
822 {
823     if(!ns) return 0;
824     int pos = array_append_if_new(pool->x_namespaces, ns, 0);
825     assert(pos!=0);
826     return pos;
827 }
828 int pool_register_namespace_set(pool_t*pool, namespace_set_t*set)
829 {
830     if(!set) return 0;
831     int pos = array_append_if_new(pool->x_namespace_sets, set, 0);
832     assert(pos!=0);
833     return pos;
834 }
835 int pool_register_multiname(pool_t*pool, multiname_t*n)
836 {
837     if(!n) return 0;
838     int pos = array_append_if_new(pool->x_multinames, n, 0);
839     if(pos==0) {
840         *(int*)0=0xdead;
841     }
842     assert(pos!=0);
843     return pos;
844 }
845 int pool_register_multiname2(pool_t*pool, char*name)
846 {
847     if(!name) return 0;
848     multiname_t*n = multiname_fromstring(name);
849     int pos = array_append_if_new(pool->x_multinames, n, 0);
850     multiname_destroy(n);
851     assert(pos!=0);
852     return pos;
853 }
854
855
856 int pool_find_uint(pool_t*pool, unsigned int x)
857 {
858     int i = array_find(pool->x_uints, &x);
859     if(i<=0) {
860         fprintf(stderr, "Couldn't find uint \"%d\" in constant pool\n", x);
861         return 0;
862     }
863     return i;
864 }
865 int pool_find_int(pool_t*pool, int x)
866 {
867     int i = array_find(pool->x_ints, &x);
868     if(i<=0) {
869         fprintf(stderr, "Couldn't find int \"%d\" in constant pool\n", x);
870         return 0;
871     }
872     return i;
873 }
874 int pool_find_float(pool_t*pool, double x)
875 {
876     int i = array_find(pool->x_ints, &x);
877     if(i<=0) {
878         fprintf(stderr, "Couldn't find int \"%d\" in constant pool\n", x);
879         return 0;
880     }
881     return i;
882 }
883 int pool_find_namespace(pool_t*pool, namespace_t*ns)
884 {
885     if(!ns)
886         return 0;
887     int i = array_find(pool->x_namespaces, ns);
888     if(i<=0) {
889         char*s = namespace_tostring(ns);
890         fprintf(stderr, "Couldn't find namespace \"%s\" %08x in constant pool\n", s, ns);
891         free(s);
892         return 0;
893     }
894     return i;
895 }
896 int pool_find_namespace_set(pool_t*pool, namespace_set_t*set)
897 {
898     if(!set)
899         return 0;
900     int i = array_find(pool->x_namespace_sets, set);
901     if(i<=0) {
902         char*s = namespace_set_tostring(set);
903         fprintf(stderr, "Couldn't find namespace_set \"%s\" in constant pool\n", s);
904         free(s);
905         return 0;
906     }
907     return i;
908 }
909 int pool_find_string(pool_t*pool, const char*s)
910 {
911     if(!s)
912         return 0;
913     int i = array_find(pool->x_strings, s);
914     if(i<=0) {
915         fprintf(stderr, "Couldn't find string \"%s\" in constant pool\n", s);
916         return 0;
917     }
918     return i;
919 }
920 int pool_find_multiname(pool_t*pool, multiname_t*name)
921 {
922     if(!name)
923         return 0;
924     int i = array_find(pool->x_multinames, name);
925     if(i<=0) {
926         char*s = multiname_tostring(name);
927         fprintf(stderr, "Couldn't find multiname \"%s\" in constant pool\n", s);
928         free(s);
929         return 0;
930     }
931     return i;
932 }
933
934 int pool_lookup_int(pool_t*pool, int i)
935 {
936     if(!i) return 0;
937     return *(int*)array_getkey(pool->x_ints, i);
938 }
939 unsigned int pool_lookup_uint(pool_t*pool, int i)
940 {
941     if(!i) return 0;
942     return *(unsigned int*)array_getkey(pool->x_uints, i);
943 }
944 double pool_lookup_float(pool_t*pool, int i)
945 {
946     if(!i) return __builtin_nan("");
947     return *(double*)array_getkey(pool->x_floats, i);
948 }
949 char*pool_lookup_string(pool_t*pool, int i)
950 {
951     return (char*)array_getkey(pool->x_strings, i);
952 }
953 string_t pool_lookup_string2(pool_t*pool, int i)
954 {
955     char*s = (char*)array_getkey(pool->x_strings, i);
956     int len = (int)(ptroff_t)array_getvalue(pool->x_strings, i);
957     return string_new(s,len);
958 }
959 namespace_t*pool_lookup_namespace(pool_t*pool, int i)
960 {
961     return (namespace_t*)array_getkey(pool->x_namespaces, i);
962 }
963 namespace_set_t*pool_lookup_namespace_set(pool_t*pool, int i)
964 {
965     return (namespace_set_t*)array_getkey(pool->x_namespace_sets, i);
966 }
967 multiname_t*pool_lookup_multiname(pool_t*pool, int i)
968 {
969     return (multiname_t*)array_getkey(pool->x_multinames, i);
970 }
971
972 pool_t*pool_new()
973 {
974     NEW(pool_t, p);
975
976     p->x_ints = array_new2(&uint_type);
977     p->x_uints = array_new2(&uint_type);
978     p->x_floats = array_new2(&float_type);
979     p->x_strings = array_new2(&charptr_type);
980     p->x_namespaces = array_new2(&namespace_type);
981     p->x_namespace_sets = array_new2(&namespace_set_type);
982     p->x_multinames = array_new2(&multiname_type);
983
984     /* add a zero-index entry in each list */
985   
986     array_append(p->x_ints, 0, 0);
987     array_append(p->x_uints, 0, 0);
988     array_append(p->x_floats, 0, 0);
989     array_append(p->x_strings, 0, 0);
990     array_append(p->x_namespaces, 0, 0);
991     array_append(p->x_namespace_sets, 0, 0);
992     array_append(p->x_multinames, 0, 0);
993     return p;
994 }
995
996 #define DEBUG if(0)
997 //#define DEBUG
998
999 void pool_read(pool_t*pool, TAG*tag)
1000 {
1001     int num_ints = swf_GetU30(tag);
1002     DEBUG printf("%d ints\n", num_ints);
1003     int t;
1004     for(t=1;t<num_ints;t++) {
1005         S32 v = swf_GetABCS32(tag);
1006         DEBUG printf("int %d) %d\n", t, v);
1007         array_append(pool->x_ints, &v, 0);
1008     }
1009
1010     int num_uints = swf_GetU30(tag);
1011     DEBUG printf("%d uints\n", num_uints);
1012     for(t=1;t<num_uints;t++) {
1013         U32 v = swf_GetABCU32(tag);
1014         DEBUG printf("uint %d) %d\n", t, v);
1015         array_append(pool->x_uints, &v, 0);
1016     }
1017     
1018     int num_floats = swf_GetU30(tag);
1019     DEBUG printf("%d floats\n", num_floats);
1020     for(t=1;t<num_floats;t++) {
1021         double d = swf_GetD64(tag);
1022         DEBUG printf("float %d) %f\n", t, d);
1023         array_append(pool->x_floats, &d, 0);
1024     }
1025     
1026     int num_strings = swf_GetU30(tag);
1027     DEBUG printf("%d strings\n", num_strings);
1028     for(t=1;t<num_strings;t++) {
1029         int len = swf_GetU30(tag);
1030         char*s = malloc(len+1);
1031         swf_GetBlock(tag, s, len);
1032         s[len] = 0;
1033         array_append(pool->x_strings, s, (void*)(ptroff_t)len);
1034         free(s);
1035         DEBUG printf("%d) \"%s\"\n", t, pool->x_strings->d[t].name);
1036     }
1037     int num_namespaces = swf_GetU30(tag);
1038     DEBUG printf("%d namespaces\n", num_namespaces);
1039     for(t=1;t<num_namespaces;t++) {
1040         U8 type = swf_GetU8(tag);
1041         int namenr = swf_GetU30(tag);
1042         const char*name = 0; 
1043         if(namenr)
1044             name = array_getkey(pool->x_strings, namenr);
1045         namespace_t*ns = namespace_new(type, name);
1046         array_append(pool->x_namespaces, ns, 0);
1047         DEBUG printf("%d) %02x \"%s\"\n", t, type, namespace_tostring(ns));
1048         namespace_destroy(ns);
1049     }
1050     int num_sets = swf_GetU30(tag);
1051     DEBUG printf("%d namespace sets\n", num_sets);
1052     for(t=1;t<num_sets;t++) {
1053         int count = swf_GetU30(tag);
1054         int s;
1055         
1056         NEW(namespace_set_t, nsset);
1057         for(s=0;s<count;s++) {
1058             int nsnr = swf_GetU30(tag);
1059             if(!nsnr)
1060                 fprintf(stderr, "Zero entry in namespace set\n");
1061             namespace_t*ns = (namespace_t*)array_getkey(pool->x_namespaces, nsnr);
1062             list_append(nsset->namespaces, namespace_clone(ns));
1063         }
1064         array_append(pool->x_namespace_sets, nsset, 0);
1065         DEBUG printf("set %d) %s\n", t, namespace_set_tostring(nsset));
1066         namespace_set_destroy(nsset);
1067     }
1068
1069     int num_multinames = swf_GetU30(tag);
1070     DEBUG printf("%d multinames\n", num_multinames);
1071     for(t=1;t<num_multinames;t++) {
1072         multiname_t m;
1073         memset(&m, 0, sizeof(multiname_t));
1074         m.type = swf_GetU8(tag);
1075         if(m.type==0x07 || m.type==0x0d) {
1076             int namespace_index = swf_GetU30(tag);
1077             m.ns = (namespace_t*)array_getkey(pool->x_namespaces, namespace_index);
1078             int name_index = swf_GetU30(tag);
1079             if(name_index) // 0 = '*' (any)
1080                 m.name = array_getkey(pool->x_strings, name_index);
1081         } else if(m.type==0x0f || m.type==0x10) {
1082             int name_index = swf_GetU30(tag);
1083             if(name_index) // 0 = '*' (any name)
1084                 m.name = array_getkey(pool->x_strings, name_index);
1085         } else if(m.type==0x11 || m.type==0x12) {
1086         } else if(m.type==0x09 || m.type==0x0e) {
1087             int name_index = swf_GetU30(tag);
1088             int namespace_set_index = swf_GetU30(tag);
1089             if(name_index)
1090                 m.name = array_getkey(pool->x_strings, name_index);
1091             m.namespace_set = (namespace_set_t*)array_getkey(pool->x_namespace_sets, namespace_set_index);
1092         } else if(m.type==0x1b || m.type==0x1c) {
1093             int namespace_set_index = swf_GetU30(tag);
1094             m.namespace_set = (namespace_set_t*)array_getkey(pool->x_namespace_sets, namespace_set_index);
1095         } else {
1096             printf("can't parse type %d multinames yet\n", m.type);
1097         }
1098         DEBUG printf("multiname %d) %s\n", t, multiname_tostring(&m));
1099         array_append(pool->x_multinames, &m, 0);
1100     }
1101
1102
1103 void pool_write(pool_t*pool, TAG*tag)
1104 {
1105     int t;
1106     
1107     /* make sure that all namespaces used by multinames / namespace sets
1108        and all strings used by namespaces exist */
1109
1110     for(t=1;t<pool->x_multinames->num;t++) {
1111         multiname_t*m = (multiname_t*)array_getkey(pool->x_multinames, t);
1112         if(m->ns) {
1113             pool_register_namespace(pool, m->ns);
1114         }
1115         if(m->namespace_set) {
1116             pool_register_namespace_set(pool, m->namespace_set);
1117         }
1118         if(m->name) {
1119             pool_register_string(pool, m->name);
1120         }
1121     }
1122     for(t=1;t<pool->x_namespace_sets->num;t++) {
1123         namespace_set_t*set = (namespace_set_t*)array_getkey(pool->x_namespace_sets, t);
1124         namespace_list_t*i = set->namespaces;
1125         while(i) {
1126             pool_register_namespace(pool, i->namespace);
1127             i = i->next;
1128         }
1129     }
1130     for(t=1;t<pool->x_namespaces->num;t++) {
1131         namespace_t*ns= (namespace_t*)array_getkey(pool->x_namespaces, t);
1132         /*  The spec says (page 22): "a value of zero denotes an empty string".
1133             However when actually using zero strings as empty namespaces, the
1134             flash player breaks.*/
1135         //if(ns->name && ns->name[0])
1136         pool_register_string(pool, ns->name);
1137     }
1138
1139     //pool_register_int(pool, 15);
1140     //pool_register_int(pool, 1);
1141     //pool_register_int(pool, 0);
1142     
1143     /* write data */
1144     swf_SetU30(tag, pool->x_ints->num>1?pool->x_ints->num:0);
1145     for(t=1;t<pool->x_ints->num;t++) {
1146         S32 val = *(int*)array_getkey(pool->x_ints, t);
1147         swf_SetABCS32(tag, val);
1148     }
1149     swf_SetU30(tag, pool->x_uints->num>1?pool->x_uints->num:0);
1150     for(t=1;t<pool->x_uints->num;t++) {
1151         swf_SetABCU32(tag, *(unsigned int*)array_getkey(pool->x_uints, t));
1152     }
1153     swf_SetU30(tag, pool->x_floats->num>1?pool->x_floats->num:0);
1154     for(t=1;t<pool->x_floats->num;t++) {
1155         double d = pool_lookup_float(pool, t);
1156         swf_SetD64(tag, d);
1157     }
1158     swf_SetU30(tag, pool->x_strings->num>1?pool->x_strings->num:0);
1159     for(t=1;t<pool->x_strings->num;t++) {
1160         string_t str = pool_lookup_string2(pool, t);
1161         swf_SetU30String(tag, str.str, str.len);
1162     }
1163     swf_SetU30(tag, pool->x_namespaces->num>1?pool->x_namespaces->num:0);
1164     for(t=1;t<pool->x_namespaces->num;t++) {
1165         namespace_t*ns= (namespace_t*)array_getkey(pool->x_namespaces, t);
1166         swf_SetU8(tag, ns->access);
1167         const char*name = ns->name;
1168         int i = 0;
1169         
1170         //if(name && name[0])
1171         i = pool_find_string(pool, name);
1172
1173         swf_SetU30(tag, i);
1174     }
1175     swf_SetU30(tag, pool->x_namespace_sets->num>1?pool->x_namespace_sets->num:0);
1176     for(t=1;t<pool->x_namespace_sets->num;t++) {
1177         namespace_set_t*set = (namespace_set_t*)array_getkey(pool->x_namespace_sets, t);
1178         namespace_list_t*i = set->namespaces; 
1179         int len = list_length(i);
1180         swf_SetU30(tag, len);
1181         while(i) {
1182             int index = pool_find_namespace(pool, i->namespace);
1183             swf_SetU30(tag, index);
1184             i = i->next;
1185         }
1186     }
1187
1188     swf_SetU30(tag, pool->x_multinames->num>1?pool->x_multinames->num:0);
1189     for(t=1;t<pool->x_multinames->num;t++) {
1190         multiname_t*m = (multiname_t*)array_getkey(pool->x_multinames, t);
1191         swf_SetU8(tag, m->type);
1192
1193         if(m->ns) {
1194             assert(m->type==0x07 || m->type==0x0d);
1195             int i = pool_find_namespace(pool, m->ns);
1196             if(i<0) fprintf(stderr, "internal error: unregistered namespace %02x %s %s\n", m->ns->access, access2str(m->ns->access), m->ns->name);
1197             swf_SetU30(tag, i);
1198         } else {
1199             assert(m->type!=0x07 && m->type!=0x0d);
1200         }
1201         if(m->name) {
1202             assert(m->type==0x09 || m->type==0x0e || m->type==0x07 || m->type==0x0d || m->type==0x0f || m->type==0x10);
1203             int i = pool_find_string(pool, m->name);
1204             if(i<0) fprintf(stderr, "internal error: unregistered name\n");
1205             swf_SetU30(tag, i);
1206         } else {
1207             assert(m->type!=0x09 && m->type!=0x0e && m->type!=0x07 && m->type!=0x0d && m->type!=0x0f && m->type!=0x10);
1208         }
1209         if(m->namespace_set) {
1210             assert(m->type==0x09 || m->type==0x0e || m->type==0x1c || m->type==0x1b);
1211             int i = pool_find_namespace_set(pool, m->namespace_set);
1212             if(i<0) fprintf(stderr, "internal error: unregistered namespace set\n");
1213             swf_SetU30(tag, i);
1214         } else {
1215             assert(m->type!=0x09 && m->type!=0x0e && m->type!=0x1c && m->type!=0x1b);
1216         }
1217     }
1218 }
1219
1220
1221 void pool_destroy(pool_t*pool)
1222 {
1223     int t;
1224     array_free(pool->x_ints);
1225     array_free(pool->x_uints);
1226     array_free(pool->x_floats);
1227     array_free(pool->x_strings);
1228     array_free(pool->x_namespaces);
1229     array_free(pool->x_namespace_sets);
1230     array_free(pool->x_multinames);
1231     free(pool);
1232 }