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