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