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