merged final cvs changes to git
[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 c1->data - c2->data;
830 }
831 static void reshuffle_array(array_t*array)
832 {
833     qsort(array->d, array->num, sizeof(array->d[0]), compare_arrayentry);
834     dict_destroy(array->entry2pos);
835     array->entry2pos = dict_new();
836     int t;
837     for(t=0;t<array->num;t++) {
838         dict_put(array->entry2pos, array->d[t].name, (void*)(ptroff_t)(t+1));
839     }
840 }
841
842 // ------------------------------- pool -------------------------------------
843
844 int pool_register_uint(pool_t*p, unsigned int i)
845 {
846     int pos = array_append_or_increase(p->x_uints, &i);
847     assert(pos!=0);
848     return pos;
849 }
850 int pool_register_int(pool_t*p, int i)
851 {
852     int pos = array_append_or_increase(p->x_ints, &i);
853     assert(pos!=0);
854     return pos;
855 }
856 int pool_register_float(pool_t*p, double d)
857 {
858     int pos = array_append_or_increase(p->x_floats, &d);
859     assert(pos!=0);
860     return pos;
861 }
862 int pool_register_string(pool_t*pool, const char*str)
863 {
864     if(!str) return 0;
865     string_t s = string_new2(str);
866     int pos = array_append_or_increase(pool->x_strings, &s);
867     assert(pos!=0);
868     return pos;
869 }
870 int pool_register_string2(pool_t*pool, string_t*s)
871 {
872     if(!s || !s->str) return 0;
873     int pos = array_append_or_increase(pool->x_strings, s);
874     assert(pos!=0);
875     return pos;
876 }
877 int pool_register_namespace(pool_t*pool, namespace_t*ns)
878 {
879     if(!ns) return 0;
880     int pos = array_append_or_increase(pool->x_namespaces, ns);
881     assert(pos!=0);
882     return pos;
883 }
884 int pool_register_namespace_set(pool_t*pool, namespace_set_t*set)
885 {
886     if(!set) return 0;
887     int pos = array_append_or_increase(pool->x_namespace_sets, set);
888     assert(pos!=0);
889     return pos;
890 }
891 int pool_register_multiname(pool_t*pool, multiname_t*n)
892 {
893     if(!n) return 0;
894     int pos = array_append_or_increase(pool->x_multinames, n);
895     assert(pos!=0);
896     return pos;
897 }
898 int pool_register_multiname2(pool_t*pool, char*name)
899 {
900     if(!name) return 0;
901     multiname_t*n = multiname_fromstring(name);
902     int pos = array_append_or_increase(pool->x_multinames, n);
903     multiname_destroy(n);
904     assert(pos!=0);
905     return pos;
906 }
907
908
909 int pool_find_uint(pool_t*pool, unsigned int x)
910 {
911     int i = array_find(pool->x_uints, &x);
912     if(i<=0) {
913         fprintf(stderr, "Couldn't find uint \"%d\" in constant pool\n", x);
914         return 0;
915     }
916     return i;
917 }
918 int pool_find_int(pool_t*pool, int x)
919 {
920     int i = array_find(pool->x_ints, &x);
921     if(i<=0) {
922         fprintf(stderr, "Couldn't find int \"%d\" in constant pool\n", x);
923         return 0;
924     }
925     return i;
926 }
927 int pool_find_float(pool_t*pool, double 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_namespace(pool_t*pool, namespace_t*ns)
937 {
938     if(!ns)
939         return 0;
940     int i = array_find(pool->x_namespaces, ns);
941     if(i<=0) {
942         char*s = namespace_tostring(ns);
943         fprintf(stderr, "Couldn't find namespace \"%s\" %08x in constant pool\n", s, ns);
944         free(s);
945         return 0;
946     }
947     return i;
948 }
949 int pool_find_namespace_set(pool_t*pool, namespace_set_t*set)
950 {
951     if(!set)
952         return 0;
953     int i = array_find(pool->x_namespace_sets, set);
954     if(i<=0) {
955         char*s = namespace_set_tostring(set);
956         fprintf(stderr, "Couldn't find namespace_set \"%s\" in constant pool\n", s);
957         free(s);
958         return 0;
959     }
960     return i;
961 }
962 int pool_find_string(pool_t*pool, const char*str)
963 {
964     if(!str)
965         return 0;
966     string_t s = string_new2(str);
967     int i = array_find(pool->x_strings, &s);
968     if(i<=0) {
969         fprintf(stderr, "Couldn't find string \"%s\" in constant pool\n", s);
970         return 0;
971     }
972     return i;
973 }
974 int pool_find_multiname(pool_t*pool, multiname_t*name)
975 {
976     if(!name)
977         return 0;
978     int i = array_find(pool->x_multinames, name);
979     if(i<=0) {
980         char*s = multiname_tostring(name);
981         fprintf(stderr, "Couldn't find multiname \"%s\" in constant pool\n", s);
982         free(s);
983         return 0;
984     }
985     return i;
986 }
987
988 int pool_lookup_int(pool_t*pool, int i)
989 {
990     if(!i) return 0;
991     return *(int*)array_getkey(pool->x_ints, i);
992 }
993 unsigned int pool_lookup_uint(pool_t*pool, int i)
994 {
995     if(!i) return 0;
996     return *(unsigned int*)array_getkey(pool->x_uints, i);
997 }
998 double pool_lookup_float(pool_t*pool, int i)
999 {
1000     if(!i) return __builtin_nan("");
1001     return *(double*)array_getkey(pool->x_floats, i);
1002 }
1003 const char*pool_lookup_string(pool_t*pool, int i)
1004 {
1005     string_t*s = array_getkey(pool->x_strings, i);
1006     if(!s) return 0;
1007     return s->str;
1008 }
1009 string_t pool_lookup_string2(pool_t*pool, int i)
1010 {
1011     string_t*s = array_getkey(pool->x_strings, i);
1012     return *s;
1013 }
1014 namespace_t*pool_lookup_namespace(pool_t*pool, int i)
1015 {
1016     return (namespace_t*)array_getkey(pool->x_namespaces, i);
1017 }
1018 namespace_set_t*pool_lookup_namespace_set(pool_t*pool, int i)
1019 {
1020     return (namespace_set_t*)array_getkey(pool->x_namespace_sets, i);
1021 }
1022 multiname_t*pool_lookup_multiname(pool_t*pool, int i)
1023 {
1024     return (multiname_t*)array_getkey(pool->x_multinames, i);
1025 }
1026
1027 pool_t*pool_new()
1028 {
1029     NEW(pool_t, p);
1030
1031     p->x_ints = array_new2(&uint_type);
1032     p->x_uints = array_new2(&uint_type);
1033     p->x_floats = array_new2(&float_type);
1034     p->x_strings = array_new2(&stringstruct_type);
1035     p->x_namespaces = array_new2(&namespace_type);
1036     p->x_namespace_sets = array_new2(&namespace_set_type);
1037     p->x_multinames = array_new2(&multiname_type);
1038
1039     /* add a zero-index entry in each list */
1040   
1041     array_append(p->x_ints, 0, 0);
1042     array_append(p->x_uints, 0, 0);
1043     array_append(p->x_floats, 0, 0);
1044     array_append(p->x_strings, 0, 0);
1045     array_append(p->x_namespaces, 0, 0);
1046     array_append(p->x_namespace_sets, 0, 0);
1047     array_append(p->x_multinames, 0, 0);
1048     return p;
1049 }
1050
1051 void pool_optimize(pool_t*p)
1052 {
1053     reshuffle_array(p->x_ints);
1054     reshuffle_array(p->x_uints);
1055     reshuffle_array(p->x_floats);
1056     reshuffle_array(p->x_strings);
1057     reshuffle_array(p->x_namespaces);
1058     reshuffle_array(p->x_namespace_sets);
1059     reshuffle_array(p->x_multinames);
1060 }
1061
1062 #define DEBUG if(0)
1063 //#define DEBUG
1064
1065 void pool_read(pool_t*pool, TAG*tag)
1066 {
1067     int num_ints = swf_GetU30(tag);
1068     DEBUG printf("%d ints\n", num_ints);
1069     int t;
1070     for(t=1;t<num_ints;t++) {
1071         S32 v = swf_GetABCS32(tag);
1072         DEBUG printf("int %d) %d\n", t, v);
1073         array_append(pool->x_ints, &v, 0);
1074     }
1075
1076     int num_uints = swf_GetU30(tag);
1077     DEBUG printf("%d uints\n", num_uints);
1078     for(t=1;t<num_uints;t++) {
1079         U32 v = swf_GetABCU32(tag);
1080         DEBUG printf("uint %d) %d\n", t, v);
1081         array_append(pool->x_uints, &v, 0);
1082     }
1083     
1084     int num_floats = swf_GetU30(tag);
1085     DEBUG printf("%d floats\n", num_floats);
1086     for(t=1;t<num_floats;t++) {
1087         double d = swf_GetD64(tag);
1088         DEBUG printf("float %d) %f\n", t, d);
1089         array_append(pool->x_floats, &d, 0);
1090     }
1091     
1092     int num_strings = swf_GetU30(tag);
1093     DEBUG printf("%d strings\n", num_strings);
1094     for(t=1;t<num_strings;t++) {
1095         int len = swf_GetU30(tag);
1096         string_t s = string_new(&tag->data[tag->pos], len);
1097         swf_GetBlock(tag, 0, len);
1098         array_append(pool->x_strings, &s, 0);
1099         DEBUG printf("%d) \"%s\"\n", t, ((string_t*)array_getkey(pool->x_strings, t))->str);
1100     }
1101     int num_namespaces = swf_GetU30(tag);
1102     DEBUG printf("%d namespaces\n", num_namespaces);
1103     for(t=1;t<num_namespaces;t++) {
1104         U8 type = swf_GetU8(tag);
1105         int namenr = swf_GetU30(tag);
1106         const char*name = 0; 
1107         if(namenr)
1108             name = pool_lookup_string(pool, namenr);
1109         namespace_t*ns = namespace_new(type, name);
1110         array_append(pool->x_namespaces, ns, 0);
1111         DEBUG printf("%d) %02x \"%s\"\n", t, type, namespace_tostring(ns));
1112         namespace_destroy(ns);
1113     }
1114     int num_sets = swf_GetU30(tag);
1115     DEBUG printf("%d namespace sets\n", num_sets);
1116     for(t=1;t<num_sets;t++) {
1117         int count = swf_GetU30(tag);
1118         int s;
1119         
1120         NEW(namespace_set_t, nsset);
1121         for(s=0;s<count;s++) {
1122             int nsnr = swf_GetU30(tag);
1123             if(!nsnr)
1124                 fprintf(stderr, "Zero entry in namespace set\n");
1125             namespace_t*ns = (namespace_t*)array_getkey(pool->x_namespaces, nsnr);
1126             list_append(nsset->namespaces, namespace_clone(ns));
1127         }
1128         array_append(pool->x_namespace_sets, nsset, 0);
1129         DEBUG printf("set %d) %s\n", t, namespace_set_tostring(nsset));
1130         namespace_set_destroy(nsset);
1131     }
1132
1133     int num_multinames = swf_GetU30(tag);
1134     DEBUG printf("%d multinames\n", num_multinames);
1135     for(t=1;t<num_multinames;t++) {
1136         multiname_t m;
1137         memset(&m, 0, sizeof(multiname_t));
1138         m.type = swf_GetU8(tag);
1139         if(m.type==0x07 || m.type==0x0d) {
1140             int namespace_index = swf_GetU30(tag);
1141             m.ns = (namespace_t*)array_getkey(pool->x_namespaces, namespace_index);
1142             int name_index = swf_GetU30(tag);
1143             if(name_index) // 0 = '*' (any)
1144                 m.name = pool_lookup_string(pool, name_index);
1145         } else if(m.type==0x0f || m.type==0x10) {
1146             int name_index = swf_GetU30(tag);
1147             if(name_index) // 0 = '*' (any name)
1148                 m.name = pool_lookup_string(pool, name_index);
1149         } else if(m.type==0x11 || m.type==0x12) {
1150         } else if(m.type==0x09 || m.type==0x0e) {
1151             int name_index = swf_GetU30(tag);
1152             int namespace_set_index = swf_GetU30(tag);
1153             if(name_index)
1154                 m.name = pool_lookup_string(pool, name_index);
1155             m.namespace_set = (namespace_set_t*)array_getkey(pool->x_namespace_sets, namespace_set_index);
1156         } else if(m.type==0x1b || m.type==0x1c) {
1157             int namespace_set_index = swf_GetU30(tag);
1158             m.namespace_set = (namespace_set_t*)array_getkey(pool->x_namespace_sets, namespace_set_index);
1159         } else {
1160             printf("can't parse type %d multinames yet\n", m.type);
1161         }
1162         DEBUG printf("multiname %d) %s\n", t, multiname_tostring(&m));
1163         array_append(pool->x_multinames, &m, 0);
1164     }
1165
1166
1167 void pool_dump(pool_t*pool, FILE*fo, char flags)
1168 {
1169     int t;
1170     fprintf(fo, "%d integers:\n", pool->x_ints->num);
1171     for(t=1;t<pool->x_ints->num;t++) {
1172         S32 val = *(int*)array_getkey(pool->x_ints, t);
1173         if(flags&1) fprintf(fo, "%d) %d\n", t, val);
1174     }
1175     fprintf(fo, "%d unsigned integers:\n", pool->x_uints->num);
1176     for(t=1;t<pool->x_uints->num;t++) {
1177         U32 val = *(unsigned int*)array_getkey(pool->x_uints, t);
1178         if(flags&1) fprintf(fo, "%d) %d\n", t, val);
1179     }
1180     fprintf(fo, "%d floats:\n", pool->x_floats->num);
1181     for(t=1;t<pool->x_floats->num;t++) {
1182         double d = pool_lookup_float(pool, t);
1183         if(flags&2) fprintf(fo, "%d) %f\n", t, d);
1184     }
1185     fprintf(fo, "%d strings:\n", pool->x_strings->num);
1186     for(t=1;t<pool->x_strings->num;t++) {
1187         string_t str = pool_lookup_string2(pool, t);
1188         if(flags&1) fprintf(fo, "%d) ", t);
1189         if(flags&1) fwrite(str.str, str.len, 1, fo);
1190         if(flags&1) fprintf(fo, "\n", t);
1191     }
1192     fprintf(fo, "%d namespaces:\n", pool->x_namespaces->num);
1193     for(t=1;t<pool->x_namespaces->num;t++) {
1194         namespace_t*ns= (namespace_t*)array_getkey(pool->x_namespaces, t);
1195         char*s = namespace_tostring(ns);
1196         if(flags&1) fprintf(fo, "%d) %s\n", t, s);
1197         free(s);
1198     }
1199     fprintf(fo, "%d namespace sets:\n", pool->x_namespace_sets->num);
1200     for(t=1;t<pool->x_namespace_sets->num;t++) {
1201         namespace_set_t*set = (namespace_set_t*)array_getkey(pool->x_namespace_sets, t);
1202         char*s = namespace_set_tostring(set);
1203         if(flags&1) fprintf(fo, "%d) %s\n", t, s);
1204         free(s);
1205     }
1206
1207     fprintf(fo, "%d multinames:\n", pool->x_multinames->num);
1208     for(t=1;t<pool->x_multinames->num;t++) {
1209         multiname_t*m = (multiname_t*)array_getkey(pool->x_multinames, t);
1210         char*s = multiname_tostring(m);
1211         if(flags&1) fprintf(fo, "%d) %s\n", t, s);
1212         free(s);
1213     }
1214
1215
1216 void pool_write(pool_t*pool, TAG*tag)
1217 {
1218     int t;
1219     
1220     /* make sure that all namespaces used by multinames / namespace sets
1221        and all strings used by namespaces exist */
1222
1223     for(t=1;t<pool->x_multinames->num;t++) {
1224         multiname_t*m = (multiname_t*)array_getkey(pool->x_multinames, t);
1225         if(m->ns) {
1226             pool_register_namespace(pool, m->ns);
1227         }
1228         if(m->namespace_set) {
1229             pool_register_namespace_set(pool, m->namespace_set);
1230         }
1231         if(m->name) {
1232             pool_register_string(pool, m->name);
1233         }
1234     }
1235     for(t=1;t<pool->x_namespace_sets->num;t++) {
1236         namespace_set_t*set = (namespace_set_t*)array_getkey(pool->x_namespace_sets, t);
1237         namespace_list_t*i = set->namespaces;
1238         while(i) {
1239             pool_register_namespace(pool, i->namespace);
1240             i = i->next;
1241         }
1242     }
1243     for(t=1;t<pool->x_namespaces->num;t++) {
1244         namespace_t*ns= (namespace_t*)array_getkey(pool->x_namespaces, t);
1245         /*  The spec says (page 22): "a value of zero denotes an empty string".
1246             However when actually using zero strings as empty namespaces, the
1247             flash player breaks.*/
1248         //if(ns->name && ns->name[0])
1249         pool_register_string(pool, ns->name);
1250     }
1251
1252     //pool_register_int(pool, 15);
1253     //pool_register_int(pool, 1);
1254     //pool_register_int(pool, 0);
1255     
1256     /* write data */
1257     swf_SetU30(tag, pool->x_ints->num>1?pool->x_ints->num:0);
1258     for(t=1;t<pool->x_ints->num;t++) {
1259         S32 val = *(int*)array_getkey(pool->x_ints, t);
1260         swf_SetABCS32(tag, val);
1261     }
1262     swf_SetU30(tag, pool->x_uints->num>1?pool->x_uints->num:0);
1263     for(t=1;t<pool->x_uints->num;t++) {
1264         swf_SetABCU32(tag, *(unsigned int*)array_getkey(pool->x_uints, t));
1265     }
1266     swf_SetU30(tag, pool->x_floats->num>1?pool->x_floats->num:0);
1267     for(t=1;t<pool->x_floats->num;t++) {
1268         double d = pool_lookup_float(pool, t);
1269         swf_SetD64(tag, d);
1270     }
1271     swf_SetU30(tag, pool->x_strings->num>1?pool->x_strings->num:0);
1272     for(t=1;t<pool->x_strings->num;t++) {
1273         string_t str = pool_lookup_string2(pool, t);
1274         swf_SetU30String(tag, str.str, str.len);
1275     }
1276     swf_SetU30(tag, pool->x_namespaces->num>1?pool->x_namespaces->num:0);
1277     for(t=1;t<pool->x_namespaces->num;t++) {
1278         namespace_t*ns= (namespace_t*)array_getkey(pool->x_namespaces, t);
1279         swf_SetU8(tag, ns->access);
1280         const char*name = ns->name;
1281         int i = 0;
1282         
1283         //if(name && name[0])
1284         i = pool_find_string(pool, name);
1285
1286         swf_SetU30(tag, i);
1287     }
1288     swf_SetU30(tag, pool->x_namespace_sets->num>1?pool->x_namespace_sets->num:0);
1289     for(t=1;t<pool->x_namespace_sets->num;t++) {
1290         namespace_set_t*set = (namespace_set_t*)array_getkey(pool->x_namespace_sets, t);
1291         namespace_list_t*i = set->namespaces; 
1292         int len = list_length(i);
1293         swf_SetU30(tag, len);
1294         while(i) {
1295             int index = pool_find_namespace(pool, i->namespace);
1296             swf_SetU30(tag, index);
1297             i = i->next;
1298         }
1299     }
1300
1301     swf_SetU30(tag, pool->x_multinames->num>1?pool->x_multinames->num:0);
1302     for(t=1;t<pool->x_multinames->num;t++) {
1303         multiname_t*m = (multiname_t*)array_getkey(pool->x_multinames, t);
1304         swf_SetU8(tag, m->type);
1305
1306         if(m->ns) {
1307             assert(m->type==0x07 || m->type==0x0d);
1308             int i = pool_find_namespace(pool, m->ns);
1309             if(i<0) fprintf(stderr, "internal error: unregistered namespace %02x %s %s\n", m->ns->access, access2str(m->ns->access), m->ns->name);
1310             swf_SetU30(tag, i);
1311         } else {
1312             assert(m->type!=0x07 && m->type!=0x0d);
1313         }
1314         if(m->name) {
1315             assert(m->type==0x09 || m->type==0x0e || m->type==0x07 || m->type==0x0d || m->type==0x0f || m->type==0x10);
1316             int i = pool_find_string(pool, m->name);
1317             if(i<0) fprintf(stderr, "internal error: unregistered name\n");
1318             swf_SetU30(tag, i);
1319         } else {
1320             assert(m->type!=0x09 && m->type!=0x0e && m->type!=0x07 && m->type!=0x0d && m->type!=0x0f && m->type!=0x10);
1321         }
1322         if(m->namespace_set) {
1323             assert(m->type==0x09 || m->type==0x0e || m->type==0x1c || m->type==0x1b);
1324             int i = pool_find_namespace_set(pool, m->namespace_set);
1325             if(i<0) fprintf(stderr, "internal error: unregistered namespace set\n");
1326             swf_SetU30(tag, i);
1327         } else {
1328             assert(m->type!=0x09 && m->type!=0x0e && m->type!=0x1c && m->type!=0x1b);
1329         }
1330     }
1331 }
1332
1333
1334 void pool_destroy(pool_t*pool)
1335 {
1336     int t;
1337     array_free(pool->x_ints);
1338     array_free(pool->x_uints);
1339     array_free(pool->x_floats);
1340     array_free(pool->x_strings);
1341     array_free(pool->x_namespaces);
1342     array_free(pool->x_namespace_sets);
1343     array_free(pool->x_multinames);
1344     free(pool);
1345 }