fixed tests ok/namespaces1.as, ok/packagestr.as
[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 UNIQUE_CONSTANT(x) ((x) == CONSTANT_TRUE || (x) == CONSTANT_FALSE || (x) == CONSTANT_NULL || (x) == CONSTANT_UNDEFINED)
638
639 constant_t* constant_new_int(int i) 
640 {
641     NEW(constant_t,c);
642     c->i = i;
643     c->type = CONSTANT_INT;
644     return c;
645 }
646 constant_t* constant_new_uint(unsigned int u)
647 {
648     NEW(constant_t,c);
649     c->u = u;
650     c->type = CONSTANT_UINT;
651     return c;
652 }
653 constant_t* constant_new_float(double f)
654 {
655     NEW(constant_t,c);
656     c->f = f;
657     c->type = CONSTANT_FLOAT;
658     return c;
659 }
660 constant_t* constant_new_string(char*s)
661 {
662     NEW(constant_t,c);
663     c->s = string_new4(s);
664     c->type = CONSTANT_STRING;
665     return c;
666 }
667 constant_t* constant_new_string2(const char*s, int len)
668 {
669     NEW(constant_t,c);
670     c->s = string_new3(s, len);
671     c->type = CONSTANT_STRING;
672     return c;
673 }
674 constant_t* constant_new_namespace(namespace_t*ns)
675 {
676     NEW(constant_t,c);
677     c->ns = namespace_clone(ns);
678     c->type = ns->access;
679     assert(NS_TYPE(c->type));
680     return c;
681 }
682 constant_t* constant_new_true()
683 {
684     NEW(constant_t,c);
685     c->type = CONSTANT_TRUE;
686     return c;
687 }
688 constant_t* constant_new_false()
689 {
690     NEW(constant_t,c);
691     c->type = CONSTANT_FALSE;
692     return c;
693 }
694 constant_t* constant_new_null()
695 {
696     NEW(constant_t,c);
697     c->type = CONSTANT_NULL;
698     return c;
699 }
700 constant_t* constant_new_undefined()
701 {
702     NEW(constant_t,c);
703     c->type = CONSTANT_UNDEFINED;
704     return c;
705 }
706 constant_t* constant_clone(constant_t*other)
707 {
708     if(!other) return 0;
709     constant_t*c = malloc(sizeof(constant_t));
710     memcpy(c, other, sizeof(constant_t));
711     if(NS_TYPE(c->type)) {
712         c->ns = namespace_clone(other->ns);
713     } else if(c->type == CONSTANT_STRING) {
714         c->s = string_dup3(other->s);
715     }
716     return c;
717 }
718 constant_t* constant_fromindex(pool_t*pool, int index, int type)
719 {
720     if(!index) {
721         /* even for nonvalued constants (like TRUE/FALSE etc.), a nonzero
722            index is present to indicate that a type is coming */
723         return 0;
724     } 
725     NEW(constant_t,c);
726     c->type = type;
727     if(NS_TYPE(c->type)) {
728         c->ns = namespace_clone(pool_lookup_namespace(pool, index));
729     } else if(c->type == CONSTANT_INT) {
730         c->i = pool_lookup_int(pool, index);
731     } else if(c->type == CONSTANT_UINT) {
732         c->u = pool_lookup_uint(pool, index);
733     } else if(c->type == CONSTANT_FLOAT) {
734         c->f = pool_lookup_float(pool, index);
735     } else if(c->type == CONSTANT_STRING) {
736         string_t s = pool_lookup_string2(pool, index);
737         c->s = string_dup3(&s);
738     } else if(UNIQUE_CONSTANT(c->type)) {
739         // ok
740     } else {
741         fprintf(stderr, "invalid constant type %02x\n", c->type);
742     }
743     return c;
744 }
745 char* constant_tostring(constant_t*c)
746 {
747     if(!c)
748         return strdup("NULL");
749     char buf[32];
750     if(NS_TYPE(c->type)) {
751         return namespace_tostring(c->ns);
752     } else if(c->type == CONSTANT_INT) {
753         sprintf(buf, "%d", c->i);
754         return strdup(buf);
755     } else if(c->type == CONSTANT_UINT) {
756         sprintf(buf, "%u", c->u);
757         return strdup(buf);
758     } else if(c->type == CONSTANT_FLOAT) {
759         char buf[1024];
760         sprintf(buf, "%f", c->f);
761         return strdup(buf);
762     } else if(c->type == CONSTANT_STRING) {
763         /* should we escape the string? \0 bytes won't be printed */
764         return strdup_n(c->s->str,c->s->len);
765     } else if(c->type == CONSTANT_TRUE) {
766         return strdup("true");
767     } else if(c->type == CONSTANT_FALSE) {
768         return strdup("false");
769     } else if(c->type == CONSTANT_NULL) {
770         return strdup("null");
771     } else if(c->type == CONSTANT_UNDEFINED) {
772         return strdup("undefined");
773     } else {
774         fprintf(stderr, "invalid constant type %02x\n", c->type);
775         return 0;
776     }
777 }
778 char constant_has_index(constant_t*c) 
779 {
780     if(!c)
781         return 0;
782     return !UNIQUE_CONSTANT(c->type);
783 }
784 int constant_get_index(pool_t*pool, constant_t*c)
785 {
786     if(!c)
787         return 0;
788     if(NS_TYPE(c->type)) {
789         assert(c->ns);
790         /*if(c->type!=c->ns->access) {
791             printf("%02x<->%02x\n", c->type, c->ns->access);
792         }*/
793         assert(c->type == c->ns->access);
794         return pool_register_namespace(pool, c->ns);
795     } else if(c->type == CONSTANT_INT) {
796         return pool_register_int(pool, c->i);
797     } else if(c->type == CONSTANT_UINT) {
798         return pool_register_uint(pool, c->u);
799     } else if(c->type == CONSTANT_FLOAT) {
800         return pool_register_float(pool, c->f);
801     } else if(c->type == CONSTANT_STRING) {
802         return pool_register_string2(pool, c->s);
803     } else if(!constant_has_index(c)) {
804         return 1;
805     } else {
806         fprintf(stderr, "invalid constant type %02x\n", c->type);
807         return 0;
808     }
809 }
810 void constant_free(constant_t*c)
811 {
812     if(!c)
813         return;
814     if(c->type == CONSTANT_STRING) {
815         string_free(c->s);
816     } else if (NS_TYPE(c->type)) {
817         namespace_destroy(c->ns);c->ns=0;
818     }
819     free(c);
820 }
821 // --------------------------- optimizing -----------------------------------
822
823 static int array_append_or_increase(array_t*array, void*key)
824 {
825     int pos = array_find(array, key);
826     if(pos>=0) {
827         array->d[pos].data++;
828         return pos;
829     } else {
830         return array_append(array, key, 0);
831     }
832 }
833 static int compare_arrayentry(const void*_c1, const void*_c2)
834 {
835     const array_entry_t*c1 = _c1;
836     const array_entry_t*c2 = _c2;
837     return c2->data - c1->data;
838 }
839
840 static void* nodup(const void*o) {return (void*)o;}
841
842 static void reshuffle_array(array_t*array)
843 {
844     qsort(array->d+1, array->num-1, sizeof(array->d[0]), compare_arrayentry);
845     type_t* old_type = array->entry2pos->key_type;
846     type_t old_type_nodup = *old_type;
847     old_type_nodup.dup = nodup;
848     dict_t*d = dict_new2(&old_type_nodup);
849     dict_destroy_shallow(array->entry2pos);
850     array->entry2pos = d;
851     int t;
852     for(t=0;t<array->num;t++) {
853         dict_put(array->entry2pos, array->d[t].name, (void*)(ptroff_t)(t+1));
854     }
855     d->key_type = old_type;
856
857 }
858
859 // ------------------------------- pool -------------------------------------
860
861 int pool_register_uint(pool_t*p, unsigned int i)
862 {
863     int pos = array_append_or_increase(p->x_uints, &i);
864     assert(pos!=0);
865     return pos;
866 }
867 int pool_register_int(pool_t*p, int i)
868 {
869     int pos = array_append_or_increase(p->x_ints, &i);
870     assert(pos!=0);
871     return pos;
872 }
873 int pool_register_float(pool_t*p, double d)
874 {
875     int pos = array_append_or_increase(p->x_floats, &d);
876     assert(pos!=0);
877     return pos;
878 }
879 int pool_register_string(pool_t*pool, const char*str)
880 {
881     if(!str) return 0;
882     string_t s = string_new2(str);
883     int pos = array_append_or_increase(pool->x_strings, &s);
884     assert(pos!=0);
885     return pos;
886 }
887 int pool_register_string2(pool_t*pool, string_t*s)
888 {
889     if(!s || !s->str) return 0;
890     int pos = array_append_or_increase(pool->x_strings, s);
891     assert(pos!=0);
892     return pos;
893 }
894 int pool_register_namespace(pool_t*pool, namespace_t*ns)
895 {
896     if(!ns) return 0;
897     int pos = array_append_or_increase(pool->x_namespaces, ns);
898     assert(pos!=0);
899     return pos;
900 }
901 int pool_register_namespace_set(pool_t*pool, namespace_set_t*set)
902 {
903     if(!set) return 0;
904     int pos = array_append_or_increase(pool->x_namespace_sets, set);
905     assert(pos!=0);
906     return pos;
907 }
908 int pool_register_multiname(pool_t*pool, multiname_t*n)
909 {
910     if(!n) return 0;
911     int pos = array_append_or_increase(pool->x_multinames, n);
912     assert(pos!=0);
913     return pos;
914 }
915 int pool_register_multiname2(pool_t*pool, char*name)
916 {
917     if(!name) return 0;
918     multiname_t*n = multiname_fromstring(name);
919     int pos = array_append_or_increase(pool->x_multinames, n);
920     multiname_destroy(n);
921     assert(pos!=0);
922     return pos;
923 }
924
925
926 int pool_find_uint(pool_t*pool, unsigned int x)
927 {
928     int i = array_find(pool->x_uints, &x);
929     if(i<=0) {
930         fprintf(stderr, "Couldn't find uint \"%d\" in constant pool\n", x);
931         return 0;
932     }
933     return i;
934 }
935 int pool_find_int(pool_t*pool, int 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_float(pool_t*pool, double x)
945 {
946     int i = array_find(pool->x_ints, &x);
947     if(i<=0) {
948         fprintf(stderr, "Couldn't find int \"%d\" in constant pool\n", x);
949         return 0;
950     }
951     return i;
952 }
953 int pool_find_namespace(pool_t*pool, namespace_t*ns)
954 {
955     if(!ns)
956         return 0;
957     int i = array_find(pool->x_namespaces, ns);
958     if(i<=0) {
959         char*s = namespace_tostring(ns);
960         fprintf(stderr, "Couldn't find namespace \"%s\" %08x in constant pool\n", s, ns);
961         free(s);
962         return 0;
963     }
964     return i;
965 }
966 int pool_find_namespace_set(pool_t*pool, namespace_set_t*set)
967 {
968     if(!set)
969         return 0;
970     int i = array_find(pool->x_namespace_sets, set);
971     if(i<=0) {
972         char*s = namespace_set_tostring(set);
973         fprintf(stderr, "Couldn't find namespace_set \"%s\" in constant pool\n", s);
974         free(s);
975         return 0;
976     }
977     return i;
978 }
979 int pool_find_string(pool_t*pool, const char*str)
980 {
981     if(!str)
982         return 0;
983     string_t s = string_new2(str);
984     int i = array_find(pool->x_strings, &s);
985     if(i<=0) {
986         fprintf(stderr, "Couldn't find string \"%s\" in constant pool\n", s);
987         return 0;
988     }
989     return i;
990 }
991 int pool_find_multiname(pool_t*pool, multiname_t*name)
992 {
993     if(!name)
994         return 0;
995     int i = array_find(pool->x_multinames, name);
996     if(i<=0) {
997         char*s = multiname_tostring(name);
998         fprintf(stderr, "Couldn't find multiname \"%s\" in constant pool\n", s);
999         free(s);
1000         return 0;
1001     }
1002     return i;
1003 }
1004
1005 int pool_lookup_int(pool_t*pool, int i)
1006 {
1007     if(!i) return 0;
1008     return *(int*)array_getkey(pool->x_ints, i);
1009 }
1010 unsigned int pool_lookup_uint(pool_t*pool, int i)
1011 {
1012     if(!i) return 0;
1013     return *(unsigned int*)array_getkey(pool->x_uints, i);
1014 }
1015 double pool_lookup_float(pool_t*pool, int i)
1016 {
1017     if(!i) return __builtin_nan("");
1018     return *(double*)array_getkey(pool->x_floats, i);
1019 }
1020 const char*pool_lookup_string(pool_t*pool, int i)
1021 {
1022     string_t*s = array_getkey(pool->x_strings, i);
1023     if(!s) return 0;
1024     return s->str;
1025 }
1026 string_t pool_lookup_string2(pool_t*pool, int i)
1027 {
1028     string_t*s = array_getkey(pool->x_strings, i);
1029     return *s;
1030 }
1031 namespace_t*pool_lookup_namespace(pool_t*pool, int i)
1032 {
1033     return (namespace_t*)array_getkey(pool->x_namespaces, i);
1034 }
1035 namespace_set_t*pool_lookup_namespace_set(pool_t*pool, int i)
1036 {
1037     return (namespace_set_t*)array_getkey(pool->x_namespace_sets, i);
1038 }
1039 multiname_t*pool_lookup_multiname(pool_t*pool, int i)
1040 {
1041     return (multiname_t*)array_getkey(pool->x_multinames, i);
1042 }
1043
1044 pool_t*pool_new()
1045 {
1046     NEW(pool_t, p);
1047
1048     p->x_ints = array_new2(&uint_type);
1049     p->x_uints = array_new2(&uint_type);
1050     p->x_floats = array_new2(&float_type);
1051     p->x_strings = array_new2(&stringstruct_type);
1052     p->x_namespaces = array_new2(&namespace_type);
1053     p->x_namespace_sets = array_new2(&namespace_set_type);
1054     p->x_multinames = array_new2(&multiname_type);
1055
1056     /* add a zero-index entry in each list */
1057   
1058     array_append(p->x_ints, 0, 0);
1059     array_append(p->x_uints, 0, 0);
1060     array_append(p->x_floats, 0, 0);
1061     array_append(p->x_strings, 0, 0);
1062     array_append(p->x_namespaces, 0, 0);
1063     array_append(p->x_namespace_sets, 0, 0);
1064     array_append(p->x_multinames, 0, 0);
1065     return p;
1066 }
1067
1068 void pool_optimize(pool_t*p)
1069 {
1070     reshuffle_array(p->x_ints);
1071     reshuffle_array(p->x_uints);
1072     reshuffle_array(p->x_floats);
1073     reshuffle_array(p->x_strings);
1074     reshuffle_array(p->x_namespaces);
1075     reshuffle_array(p->x_namespace_sets);
1076     reshuffle_array(p->x_multinames);
1077 }
1078
1079 #define DEBUG if(0)
1080 //#define DEBUG
1081
1082 void pool_read(pool_t*pool, TAG*tag)
1083 {
1084     int num_ints = swf_GetU30(tag);
1085     DEBUG printf("%d ints\n", num_ints);
1086     int t;
1087     for(t=1;t<num_ints;t++) {
1088         S32 v = swf_GetABCS32(tag);
1089         DEBUG printf("int %d) %d\n", t, v);
1090         array_append(pool->x_ints, &v, 0);
1091     }
1092
1093     int num_uints = swf_GetU30(tag);
1094     DEBUG printf("%d uints\n", num_uints);
1095     for(t=1;t<num_uints;t++) {
1096         U32 v = swf_GetABCU32(tag);
1097         DEBUG printf("uint %d) %d\n", t, v);
1098         array_append(pool->x_uints, &v, 0);
1099     }
1100     
1101     int num_floats = swf_GetU30(tag);
1102     DEBUG printf("%d floats\n", num_floats);
1103     for(t=1;t<num_floats;t++) {
1104         double d = swf_GetD64(tag);
1105         DEBUG printf("float %d) %f\n", t, d);
1106         array_append(pool->x_floats, &d, 0);
1107     }
1108     
1109     int num_strings = swf_GetU30(tag);
1110     DEBUG printf("%d strings\n", num_strings);
1111     for(t=1;t<num_strings;t++) {
1112         int len = swf_GetU30(tag);
1113         string_t s = string_new(&tag->data[tag->pos], len);
1114         swf_GetBlock(tag, 0, len);
1115         array_append(pool->x_strings, &s, 0);
1116         DEBUG printf("%d) \"%s\"\n", t, ((string_t*)array_getkey(pool->x_strings, t))->str);
1117     }
1118     int num_namespaces = swf_GetU30(tag);
1119     DEBUG printf("%d namespaces\n", num_namespaces);
1120     for(t=1;t<num_namespaces;t++) {
1121         U8 type = swf_GetU8(tag);
1122         int namenr = swf_GetU30(tag);
1123         const char*name = 0; 
1124         if(namenr)
1125             name = pool_lookup_string(pool, namenr);
1126         namespace_t*ns = namespace_new(type, name);
1127         array_append(pool->x_namespaces, ns, 0);
1128         DEBUG printf("%d) %02x \"%s\"\n", t, type, namespace_tostring(ns));
1129         namespace_destroy(ns);
1130     }
1131     int num_sets = swf_GetU30(tag);
1132     DEBUG printf("%d namespace sets\n", num_sets);
1133     for(t=1;t<num_sets;t++) {
1134         int count = swf_GetU30(tag);
1135         int s;
1136         
1137         NEW(namespace_set_t, nsset);
1138         for(s=0;s<count;s++) {
1139             int nsnr = swf_GetU30(tag);
1140             if(!nsnr)
1141                 fprintf(stderr, "Zero entry in namespace set\n");
1142             namespace_t*ns = (namespace_t*)array_getkey(pool->x_namespaces, nsnr);
1143             list_append(nsset->namespaces, namespace_clone(ns));
1144         }
1145         array_append(pool->x_namespace_sets, nsset, 0);
1146         DEBUG printf("set %d) %s\n", t, namespace_set_tostring(nsset));
1147         namespace_set_destroy(nsset);
1148     }
1149
1150     int num_multinames = swf_GetU30(tag);
1151     DEBUG printf("%d multinames\n", num_multinames);
1152     for(t=1;t<num_multinames;t++) {
1153         multiname_t m;
1154         memset(&m, 0, sizeof(multiname_t));
1155         
1156         /*int s;
1157         for(s=0;s<8;s++)
1158             printf("0x%02x ", tag->data[tag->pos+s]);
1159         printf("\n");*/
1160
1161         m.type = swf_GetU8(tag);
1162         if(m.type==0x07 || m.type==0x0d) {
1163             int namespace_index = swf_GetU30(tag);
1164             m.ns = (namespace_t*)array_getkey(pool->x_namespaces, namespace_index);
1165             int name_index = swf_GetU30(tag);
1166             if(name_index) // 0 = '*' (any)
1167                 m.name = pool_lookup_string(pool, name_index);
1168         } else if(m.type==0x0f || m.type==0x10) {
1169             int name_index = swf_GetU30(tag);
1170             if(name_index) // 0 = '*' (any name)
1171                 m.name = pool_lookup_string(pool, name_index);
1172         } else if(m.type==0x11 || m.type==0x12) {
1173         } else if(m.type==0x09 || m.type==0x0e) {
1174             int name_index = swf_GetU30(tag);
1175             int namespace_set_index = swf_GetU30(tag);
1176             if(name_index)
1177                 m.name = pool_lookup_string(pool, name_index);
1178             m.namespace_set = (namespace_set_t*)array_getkey(pool->x_namespace_sets, namespace_set_index);
1179         } else if(m.type==0x1b || m.type==0x1c) {
1180             int namespace_set_index = swf_GetU30(tag);
1181             m.namespace_set = (namespace_set_t*)array_getkey(pool->x_namespace_sets, namespace_set_index);
1182         } else if(m.type==0x1d) {
1183             int v1 = swf_GetU30(tag); //multiname
1184             int v2 = swf_GetU30(tag); //counter?
1185             int v3 = swf_GetU30(tag); //multiname
1186             // e.g. Vector<int> ... we only store the parent object
1187             m = *(multiname_t*)array_getkey(pool->x_multinames, v1);
1188         } else {
1189             printf("can't parse type %d multinames yet\n", m.type);
1190         }
1191         DEBUG printf("multiname %d) %s\n", t, multiname_tostring(&m));
1192         array_append(pool->x_multinames, &m, 0);
1193     }
1194
1195
1196 void pool_dump(pool_t*pool, FILE*fo, char flags)
1197 {
1198     int t;
1199     fprintf(fo, "%d integers\n", pool->x_ints->num);
1200     for(t=1;t<pool->x_ints->num;t++) {
1201         S32 val = *(int*)array_getkey(pool->x_ints, t);
1202         int freq = (int)(ptroff_t)array_getvalue(pool->x_ints, t);
1203         if(flags&1) fprintf(fo, "%5d %d) %d\n", freq, t, val);
1204     }
1205     fprintf(fo, "%d unsigned integers\n", pool->x_uints->num);
1206     for(t=1;t<pool->x_uints->num;t++) {
1207         U32 val = *(unsigned int*)array_getkey(pool->x_uints, t);
1208         int freq = (int)(ptroff_t)array_getvalue(pool->x_uints, t);
1209         if(flags&1) fprintf(fo, "%5d %d) %d\n", freq, t, val);
1210     }
1211     fprintf(fo, "%d floats\n", pool->x_floats->num);
1212     for(t=1;t<pool->x_floats->num;t++) {
1213         double d = pool_lookup_float(pool, t);
1214         int freq = (int)(ptroff_t)array_getvalue(pool->x_floats, t);
1215         if(flags&2) fprintf(fo, "%5d %d) %f\n", freq, t, d);
1216     }
1217     fprintf(fo, "%d strings\n", pool->x_strings->num);
1218     for(t=1;t<pool->x_strings->num;t++) {
1219         string_t str = pool_lookup_string2(pool, t);
1220         int freq = (int)(ptroff_t)array_getvalue(pool->x_strings, t);
1221         if(flags&1) fprintf(fo, "%5d %d) ", freq, t);
1222         if(flags&1) fwrite(str.str, str.len, 1, fo);
1223         if(flags&1) fprintf(fo, "\n", t);
1224     }
1225     fprintf(fo, "%d namespaces\n", pool->x_namespaces->num);
1226     for(t=1;t<pool->x_namespaces->num;t++) {
1227         namespace_t*ns= (namespace_t*)array_getkey(pool->x_namespaces, t);
1228         char*s = namespace_tostring(ns);
1229         int freq = (int)(ptroff_t)array_getvalue(pool->x_namespaces, t);
1230         if(flags&1) fprintf(fo, "%5d %d) %s\n", freq, t, s);
1231         free(s);
1232     }
1233     fprintf(fo, "%d namespace sets\n", pool->x_namespace_sets->num);
1234     for(t=1;t<pool->x_namespace_sets->num;t++) {
1235         namespace_set_t*set = (namespace_set_t*)array_getkey(pool->x_namespace_sets, t);
1236         char*s = namespace_set_tostring(set);
1237         int freq = (int)(ptroff_t)array_getvalue(pool->x_namespace_sets, t);
1238         if(flags&1) fprintf(fo, "%5d %d) %s\n", freq, t, s);
1239         free(s);
1240     }
1241
1242     fprintf(fo, "%d multinames\n", pool->x_multinames->num);
1243     for(t=1;t<pool->x_multinames->num;t++) {
1244         multiname_t*m = (multiname_t*)array_getkey(pool->x_multinames, t);
1245         char*s = multiname_tostring(m);
1246         int freq = (int)(ptroff_t)array_getvalue(pool->x_multinames, t);
1247         if(flags&1) fprintf(fo, "%5d %d) %s\n", freq, t, s);
1248         free(s);
1249     }
1250
1251
1252 void pool_write(pool_t*pool, TAG*tag)
1253 {
1254     int t;
1255     
1256     /* make sure that all namespaces used by multinames / namespace sets
1257        and all strings used by namespaces exist */
1258
1259     for(t=1;t<pool->x_multinames->num;t++) {
1260         multiname_t*m = (multiname_t*)array_getkey(pool->x_multinames, t);
1261         if(m->ns) {
1262             pool_register_namespace(pool, m->ns);
1263         }
1264         if(m->namespace_set) {
1265             pool_register_namespace_set(pool, m->namespace_set);
1266         }
1267         if(m->name) {
1268             pool_register_string(pool, m->name);
1269         }
1270     }
1271     for(t=1;t<pool->x_namespace_sets->num;t++) {
1272         namespace_set_t*set = (namespace_set_t*)array_getkey(pool->x_namespace_sets, t);
1273         namespace_list_t*i = set->namespaces;
1274         while(i) {
1275             pool_register_namespace(pool, i->namespace);
1276             i = i->next;
1277         }
1278     }
1279     for(t=1;t<pool->x_namespaces->num;t++) {
1280         namespace_t*ns= (namespace_t*)array_getkey(pool->x_namespaces, t);
1281         /*  The spec says (page 22): "a value of zero denotes an empty string".
1282             However when actually using zero strings as empty namespaces, the
1283             flash player breaks.*/
1284         //if(ns->name && ns->name[0])
1285         pool_register_string(pool, ns->name);
1286     }
1287
1288     //pool_register_int(pool, 15);
1289     //pool_register_int(pool, 1);
1290     //pool_register_int(pool, 0);
1291     
1292     /* write data */
1293     swf_SetU30(tag, pool->x_ints->num>1?pool->x_ints->num:0);
1294     for(t=1;t<pool->x_ints->num;t++) {
1295         S32 val = *(int*)array_getkey(pool->x_ints, t);
1296         swf_SetABCS32(tag, val);
1297     }
1298     swf_SetU30(tag, pool->x_uints->num>1?pool->x_uints->num:0);
1299     for(t=1;t<pool->x_uints->num;t++) {
1300         swf_SetABCU32(tag, *(unsigned int*)array_getkey(pool->x_uints, t));
1301     }
1302     swf_SetU30(tag, pool->x_floats->num>1?pool->x_floats->num:0);
1303     for(t=1;t<pool->x_floats->num;t++) {
1304         double d = pool_lookup_float(pool, t);
1305         swf_SetD64(tag, d);
1306     }
1307     swf_SetU30(tag, pool->x_strings->num>1?pool->x_strings->num:0);
1308     for(t=1;t<pool->x_strings->num;t++) {
1309         string_t str = pool_lookup_string2(pool, t);
1310         swf_SetU30String(tag, str.str, str.len);
1311     }
1312     swf_SetU30(tag, pool->x_namespaces->num>1?pool->x_namespaces->num:0);
1313     for(t=1;t<pool->x_namespaces->num;t++) {
1314         namespace_t*ns= (namespace_t*)array_getkey(pool->x_namespaces, t);
1315         swf_SetU8(tag, ns->access);
1316         const char*name = ns->name;
1317         int i = 0;
1318         
1319         //if(name && name[0])
1320         i = pool_find_string(pool, name);
1321
1322         swf_SetU30(tag, i);
1323     }
1324     swf_SetU30(tag, pool->x_namespace_sets->num>1?pool->x_namespace_sets->num:0);
1325     for(t=1;t<pool->x_namespace_sets->num;t++) {
1326         namespace_set_t*set = (namespace_set_t*)array_getkey(pool->x_namespace_sets, t);
1327         namespace_list_t*i = set->namespaces; 
1328         int len = list_length(i);
1329         swf_SetU30(tag, len);
1330         while(i) {
1331             int index = pool_find_namespace(pool, i->namespace);
1332             swf_SetU30(tag, index);
1333             i = i->next;
1334         }
1335     }
1336
1337     swf_SetU30(tag, pool->x_multinames->num>1?pool->x_multinames->num:0);
1338     for(t=1;t<pool->x_multinames->num;t++) {
1339         multiname_t*m = (multiname_t*)array_getkey(pool->x_multinames, t);
1340         swf_SetU8(tag, m->type);
1341
1342         if(m->ns) {
1343             assert(m->type==0x07 || m->type==0x0d);
1344             int i = pool_find_namespace(pool, m->ns);
1345             if(i<0) fprintf(stderr, "internal error: unregistered namespace %02x %s %s\n", m->ns->access, access2str(m->ns->access), m->ns->name);
1346             swf_SetU30(tag, i);
1347         } else {
1348             assert(m->type!=0x07 && m->type!=0x0d);
1349         }
1350         if(m->name) {
1351             assert(m->type==0x09 || m->type==0x0e || m->type==0x07 || m->type==0x0d || m->type==0x0f || m->type==0x10);
1352             int i = pool_find_string(pool, m->name);
1353             if(i<0) fprintf(stderr, "internal error: unregistered name\n");
1354             swf_SetU30(tag, i);
1355         } else {
1356             assert(m->type!=0x09 && m->type!=0x0e && m->type!=0x07 && m->type!=0x0d && m->type!=0x0f && m->type!=0x10);
1357         }
1358         if(m->namespace_set) {
1359             assert(m->type==0x09 || m->type==0x0e || m->type==0x1c || m->type==0x1b);
1360             int i = pool_find_namespace_set(pool, m->namespace_set);
1361             if(i<0) fprintf(stderr, "internal error: unregistered namespace set\n");
1362             swf_SetU30(tag, i);
1363         } else {
1364             assert(m->type!=0x09 && m->type!=0x0e && m->type!=0x1c && m->type!=0x1b);
1365         }
1366     }
1367 }
1368
1369
1370 void pool_destroy(pool_t*pool)
1371 {
1372     int t;
1373     array_free(pool->x_ints);
1374     array_free(pool->x_uints);
1375     array_free(pool->x_floats);
1376     array_free(pool->x_strings);
1377     array_free(pool->x_namespaces);
1378     array_free(pool->x_namespace_sets);
1379     array_free(pool->x_multinames);
1380     free(pool);
1381 }