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