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