small print refinement
[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)+3);
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 "access08";
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 = strdup(s);
665     c->type = CONSTANT_STRING;
666     return c;
667 }
668 constant_t* constant_new_namespace(namespace_t*ns)
669 {
670     NEW(constant_t,c);
671     c->ns = namespace_clone(ns);
672     c->type = ns->access;
673     assert(NS_TYPE(c->type));
674     return c;
675 }
676 constant_t* constant_new_true()
677 {
678     NEW(constant_t,c);
679     c->type = CONSTANT_TRUE;
680     return c;
681 }
682 constant_t* constant_new_false()
683 {
684     NEW(constant_t,c);
685     c->type = CONSTANT_FALSE;
686     return c;
687 }
688 constant_t* constant_new_null()
689 {
690     NEW(constant_t,c);
691     c->type = CONSTANT_NULL;
692     return c;
693 }
694 constant_t* constant_new_undefined()
695 {
696     NEW(constant_t,c);
697     c->type = CONSTANT_UNDEFINED;
698     return c;
699 }
700 constant_t* constant_fromindex(pool_t*pool, int index, int type)
701 {
702     if(!index) {
703         /* even for nonvalued constants (like TRUE/FALSE etc.), a nonzero
704            index is present to indicate that a type is coming */
705         return 0;
706     } 
707     NEW(constant_t,c);
708     c->type = type;
709     if(NS_TYPE(c->type)) {
710         c->ns = namespace_clone(pool_lookup_namespace(pool, index));
711     } else if(c->type == CONSTANT_INT) {
712         c->i = pool_lookup_int(pool, index);
713     } else if(c->type == CONSTANT_UINT) {
714         c->u = pool_lookup_uint(pool, index);
715     } else if(c->type == CONSTANT_FLOAT) {
716         c->f = pool_lookup_float(pool, index);
717     } else if(c->type == CONSTANT_STRING) {
718         c->s = strdup(pool_lookup_string(pool, index));
719     } else if(UNIQUE_CONSTANT(c->type)) {
720         // ok
721     } else {
722         fprintf(stderr, "invalid constant type %02x\n", c->type);
723     }
724     return c;
725 }
726 char* constant_tostring(constant_t*c)
727 {
728     if(!c)
729         return 0;
730     char buf[32];
731     if(NS_TYPE(c->type)) {
732         return namespace_tostring(c->ns);
733     } else if(c->type == CONSTANT_INT) {
734         sprintf(buf, "%d", c->i);
735         return strdup(buf);
736     } else if(c->type == CONSTANT_UINT) {
737         sprintf(buf, "%u", c->u);
738         return strdup(buf);
739     } else if(c->type == CONSTANT_FLOAT) {
740         char buf[1024];
741         sprintf(buf, "%f", c->f);
742         return strdup(buf);
743     } else if(c->type == CONSTANT_STRING) {
744         return strdup(c->s);
745     } else if(c->type == CONSTANT_TRUE) {
746         return strdup("true");
747     } else if(c->type == CONSTANT_FALSE) {
748         return strdup("false");
749     } else if(c->type == CONSTANT_NULL) {
750         return strdup("null");
751     } else if(c->type == CONSTANT_UNDEFINED) {
752         return strdup("undefined");
753     } else {
754         fprintf(stderr, "invalid constant type %02x\n", c->type);
755         return 0;
756     }
757 }
758 char constant_has_index(constant_t*c) 
759 {
760     if(!c)
761         return 0;
762     return !UNIQUE_CONSTANT(c->type);
763 }
764 int constant_get_index(pool_t*pool, constant_t*c)
765 {
766     if(!c)
767         return 0;
768     if(NS_TYPE(c->type)) {
769         assert(c->ns);
770         /*if(c->type!=c->ns->access) {
771             printf("%02x<->%02x\n", c->type, c->ns->access);
772         }*/
773         assert(c->type == c->ns->access);
774         return pool_register_namespace(pool, c->ns);
775     } else if(c->type == CONSTANT_INT) {
776         return pool_register_int(pool, c->i);
777     } else if(c->type == CONSTANT_UINT) {
778         return pool_register_uint(pool, c->u);
779     } else if(c->type == CONSTANT_FLOAT) {
780         return pool_register_float(pool, c->f);
781     } else if(c->type == CONSTANT_STRING) {
782         return pool_register_string(pool, c->s);
783     } else if(!constant_has_index(c)) {
784         return 1;
785     } else {
786         fprintf(stderr, "invalid constant type %02x\n", c->type);
787         return 0;
788     }
789 }
790 void constant_free(constant_t*c)
791 {
792     if(!c)
793         return;
794     if(c->type == CONSTANT_STRING) {
795         free(c->s);c->s=0;
796     } else if (NS_TYPE(c->type)) {
797         namespace_destroy(c->ns);c->ns=0;
798     }
799     free(c);
800 }
801 // ------------------------------- pool -------------------------------------
802
803 int pool_register_uint(pool_t*p, unsigned int i)
804 {
805     int pos = array_append_if_new(p->x_uints, &i, 0);
806     assert(pos!=0);
807     return pos;
808 }
809 int pool_register_int(pool_t*p, int i)
810 {
811     int pos = array_append_if_new(p->x_ints, &i, 0);
812     assert(pos!=0);
813     return pos;
814 }
815 int pool_register_float(pool_t*p, double d)
816 {
817     int pos = array_append_if_new(p->x_floats, &d, 0);
818     assert(pos!=0);
819     return pos;
820 }
821 int pool_register_string(pool_t*pool, const char*s)
822 {
823     if(!s) return 0;
824     ptroff_t l = strlen(s);
825     int pos = array_append_if_new(pool->x_strings, s, (void*)l);
826     assert(pos!=0);
827     return pos;
828 }
829 int pool_register_namespace(pool_t*pool, namespace_t*ns)
830 {
831     if(!ns) return 0;
832     int pos = array_append_if_new(pool->x_namespaces, ns, 0);
833     assert(pos!=0);
834     return pos;
835 }
836 int pool_register_namespace_set(pool_t*pool, namespace_set_t*set)
837 {
838     if(!set) return 0;
839     int pos = array_append_if_new(pool->x_namespace_sets, set, 0);
840     assert(pos!=0);
841     return pos;
842 }
843 int pool_register_multiname(pool_t*pool, multiname_t*n)
844 {
845     if(!n) return 0;
846     int pos = array_append_if_new(pool->x_multinames, n, 0);
847     assert(pos!=0);
848     return pos;
849 }
850 int pool_register_multiname2(pool_t*pool, char*name)
851 {
852     if(!name) return 0;
853     multiname_t*n = multiname_fromstring(name);
854     int pos = array_append_if_new(pool->x_multinames, n, 0);
855     multiname_destroy(n);
856     assert(pos!=0);
857     return pos;
858 }
859
860
861 int pool_find_uint(pool_t*pool, unsigned int x)
862 {
863     int i = array_find(pool->x_uints, &x);
864     if(i<=0) {
865         fprintf(stderr, "Couldn't find uint \"%d\" in constant pool\n", x);
866         return 0;
867     }
868     return i;
869 }
870 int pool_find_int(pool_t*pool, int x)
871 {
872     int i = array_find(pool->x_ints, &x);
873     if(i<=0) {
874         fprintf(stderr, "Couldn't find int \"%d\" in constant pool\n", x);
875         return 0;
876     }
877     return i;
878 }
879 int pool_find_float(pool_t*pool, double x)
880 {
881     int i = array_find(pool->x_ints, &x);
882     if(i<=0) {
883         fprintf(stderr, "Couldn't find int \"%d\" in constant pool\n", x);
884         return 0;
885     }
886     return i;
887 }
888 int pool_find_namespace(pool_t*pool, namespace_t*ns)
889 {
890     if(!ns)
891         return 0;
892     int i = array_find(pool->x_namespaces, ns);
893     if(i<=0) {
894         char*s = namespace_tostring(ns);
895         fprintf(stderr, "Couldn't find namespace \"%s\" %08x in constant pool\n", s, ns);
896         free(s);
897         return 0;
898     }
899     return i;
900 }
901 int pool_find_namespace_set(pool_t*pool, namespace_set_t*set)
902 {
903     if(!set)
904         return 0;
905     int i = array_find(pool->x_namespace_sets, set);
906     if(i<=0) {
907         char*s = namespace_set_tostring(set);
908         fprintf(stderr, "Couldn't find namespace_set \"%s\" in constant pool\n", s);
909         free(s);
910         return 0;
911     }
912     return i;
913 }
914 int pool_find_string(pool_t*pool, const char*s)
915 {
916     if(!s)
917         return 0;
918     int i = array_find(pool->x_strings, s);
919     if(i<=0) {
920         fprintf(stderr, "Couldn't find string \"%s\" in constant pool\n", s);
921         return 0;
922     }
923     return i;
924 }
925 int pool_find_multiname(pool_t*pool, multiname_t*name)
926 {
927     if(!name)
928         return 0;
929     int i = array_find(pool->x_multinames, name);
930     if(i<=0) {
931         char*s = multiname_tostring(name);
932         fprintf(stderr, "Couldn't find multiname \"%s\" in constant pool\n", s);
933         free(s);
934         return 0;
935     }
936     return i;
937 }
938
939 int pool_lookup_int(pool_t*pool, int i)
940 {
941     if(!i) return 0;
942     return *(int*)array_getkey(pool->x_ints, i);
943 }
944 unsigned int pool_lookup_uint(pool_t*pool, int i)
945 {
946     if(!i) return 0;
947     return *(unsigned int*)array_getkey(pool->x_uints, i);
948 }
949 double pool_lookup_float(pool_t*pool, int i)
950 {
951     if(!i) return __builtin_nan("");
952     return *(double*)array_getkey(pool->x_floats, i);
953 }
954 char*pool_lookup_string(pool_t*pool, int i)
955 {
956     return (char*)array_getkey(pool->x_strings, i);
957 }
958 string_t pool_lookup_string2(pool_t*pool, int i)
959 {
960     char*s = (char*)array_getkey(pool->x_strings, i);
961     int len = (int)(ptroff_t)array_getvalue(pool->x_strings, i);
962     return string_new(s,len);
963 }
964 namespace_t*pool_lookup_namespace(pool_t*pool, int i)
965 {
966     return (namespace_t*)array_getkey(pool->x_namespaces, i);
967 }
968 namespace_set_t*pool_lookup_namespace_set(pool_t*pool, int i)
969 {
970     return (namespace_set_t*)array_getkey(pool->x_namespace_sets, i);
971 }
972 multiname_t*pool_lookup_multiname(pool_t*pool, int i)
973 {
974     return (multiname_t*)array_getkey(pool->x_multinames, i);
975 }
976
977 pool_t*pool_new()
978 {
979     NEW(pool_t, p);
980
981     p->x_ints = array_new2(&uint_type);
982     p->x_uints = array_new2(&uint_type);
983     p->x_floats = array_new2(&float_type);
984     p->x_strings = array_new2(&charptr_type);
985     p->x_namespaces = array_new2(&namespace_type);
986     p->x_namespace_sets = array_new2(&namespace_set_type);
987     p->x_multinames = array_new2(&multiname_type);
988
989     /* add a zero-index entry in each list */
990   
991     array_append(p->x_ints, 0, 0);
992     array_append(p->x_uints, 0, 0);
993     array_append(p->x_floats, 0, 0);
994     array_append(p->x_strings, 0, 0);
995     array_append(p->x_namespaces, 0, 0);
996     array_append(p->x_namespace_sets, 0, 0);
997     array_append(p->x_multinames, 0, 0);
998     return p;
999 }
1000
1001 #define DEBUG if(0)
1002 //#define DEBUG
1003
1004 void pool_read(pool_t*pool, TAG*tag)
1005 {
1006     int num_ints = swf_GetU30(tag);
1007     DEBUG printf("%d ints\n", num_ints);
1008     int t;
1009     for(t=1;t<num_ints;t++) {
1010         S32 v = swf_GetABCS32(tag);
1011         DEBUG printf("int %d) %d\n", t, v);
1012         array_append(pool->x_ints, &v, 0);
1013     }
1014
1015     int num_uints = swf_GetU30(tag);
1016     DEBUG printf("%d uints\n", num_uints);
1017     for(t=1;t<num_uints;t++) {
1018         U32 v = swf_GetABCU32(tag);
1019         DEBUG printf("uint %d) %d\n", t, v);
1020         array_append(pool->x_uints, &v, 0);
1021     }
1022     
1023     int num_floats = swf_GetU30(tag);
1024     DEBUG printf("%d floats\n", num_floats);
1025     for(t=1;t<num_floats;t++) {
1026         double d = swf_GetD64(tag);
1027         DEBUG printf("float %d) %f\n", t, d);
1028         array_append(pool->x_floats, &d, 0);
1029     }
1030     
1031     int num_strings = swf_GetU30(tag);
1032     DEBUG printf("%d strings\n", num_strings);
1033     for(t=1;t<num_strings;t++) {
1034         int len = swf_GetU30(tag);
1035         char*s = malloc(len+1);
1036         swf_GetBlock(tag, s, len);
1037         s[len] = 0;
1038         array_append(pool->x_strings, s, (void*)(ptroff_t)len);
1039         free(s);
1040         DEBUG printf("%d) \"%s\"\n", t, pool->x_strings->d[t].name);
1041     }
1042     int num_namespaces = swf_GetU30(tag);
1043     DEBUG printf("%d namespaces\n", num_namespaces);
1044     for(t=1;t<num_namespaces;t++) {
1045         U8 type = swf_GetU8(tag);
1046         int namenr = swf_GetU30(tag);
1047         const char*name = 0; 
1048         if(namenr)
1049             name = array_getkey(pool->x_strings, namenr);
1050         namespace_t*ns = namespace_new(type, name);
1051         array_append(pool->x_namespaces, ns, 0);
1052         DEBUG printf("%d) %02x \"%s\"\n", t, type, namespace_tostring(ns));
1053         namespace_destroy(ns);
1054     }
1055     int num_sets = swf_GetU30(tag);
1056     DEBUG printf("%d namespace sets\n", num_sets);
1057     for(t=1;t<num_sets;t++) {
1058         int count = swf_GetU30(tag);
1059         int s;
1060         
1061         NEW(namespace_set_t, nsset);
1062         for(s=0;s<count;s++) {
1063             int nsnr = swf_GetU30(tag);
1064             if(!nsnr)
1065                 fprintf(stderr, "Zero entry in namespace set\n");
1066             namespace_t*ns = (namespace_t*)array_getkey(pool->x_namespaces, nsnr);
1067             list_append(nsset->namespaces, namespace_clone(ns));
1068         }
1069         array_append(pool->x_namespace_sets, nsset, 0);
1070         DEBUG printf("set %d) %s\n", t, namespace_set_tostring(nsset));
1071         namespace_set_destroy(nsset);
1072     }
1073
1074     int num_multinames = swf_GetU30(tag);
1075     DEBUG printf("%d multinames\n", num_multinames);
1076     for(t=1;t<num_multinames;t++) {
1077         multiname_t m;
1078         memset(&m, 0, sizeof(multiname_t));
1079         m.type = swf_GetU8(tag);
1080         if(m.type==0x07 || m.type==0x0d) {
1081             int namespace_index = swf_GetU30(tag);
1082             m.ns = (namespace_t*)array_getkey(pool->x_namespaces, namespace_index);
1083             int name_index = swf_GetU30(tag);
1084             if(name_index) // 0 = '*' (any)
1085                 m.name = array_getkey(pool->x_strings, name_index);
1086         } else if(m.type==0x0f || m.type==0x10) {
1087             int name_index = swf_GetU30(tag);
1088             if(name_index) // 0 = '*' (any name)
1089                 m.name = array_getkey(pool->x_strings, name_index);
1090         } else if(m.type==0x11 || m.type==0x12) {
1091         } else if(m.type==0x09 || m.type==0x0e) {
1092             int name_index = swf_GetU30(tag);
1093             int namespace_set_index = swf_GetU30(tag);
1094             if(name_index)
1095                 m.name = array_getkey(pool->x_strings, name_index);
1096             m.namespace_set = (namespace_set_t*)array_getkey(pool->x_namespace_sets, namespace_set_index);
1097         } else if(m.type==0x1b || m.type==0x1c) {
1098             int namespace_set_index = swf_GetU30(tag);
1099             m.namespace_set = (namespace_set_t*)array_getkey(pool->x_namespace_sets, namespace_set_index);
1100         } else {
1101             printf("can't parse type %d multinames yet\n", m.type);
1102         }
1103         DEBUG printf("multiname %d) %s\n", t, multiname_tostring(&m));
1104         array_append(pool->x_multinames, &m, 0);
1105     }
1106
1107
1108 void pool_write(pool_t*pool, TAG*tag)
1109 {
1110     int t;
1111     
1112     /* make sure that all namespaces used by multinames / namespace sets
1113        and all strings used by namespaces exist */
1114
1115     for(t=1;t<pool->x_multinames->num;t++) {
1116         multiname_t*m = (multiname_t*)array_getkey(pool->x_multinames, t);
1117         if(m->ns) {
1118             pool_register_namespace(pool, m->ns);
1119         }
1120         if(m->namespace_set) {
1121             pool_register_namespace_set(pool, m->namespace_set);
1122         }
1123         if(m->name) {
1124             pool_register_string(pool, m->name);
1125         }
1126     }
1127     for(t=1;t<pool->x_namespace_sets->num;t++) {
1128         namespace_set_t*set = (namespace_set_t*)array_getkey(pool->x_namespace_sets, t);
1129         namespace_list_t*i = set->namespaces;
1130         while(i) {
1131             pool_register_namespace(pool, i->namespace);
1132             i = i->next;
1133         }
1134     }
1135     for(t=1;t<pool->x_namespaces->num;t++) {
1136         namespace_t*ns= (namespace_t*)array_getkey(pool->x_namespaces, t);
1137         /*  The spec says (page 22): "a value of zero denotes an empty string".
1138             However when actually using zero strings as empty namespaces, the
1139             flash player breaks.*/
1140         //if(ns->name && ns->name[0])
1141         pool_register_string(pool, ns->name);
1142     }
1143
1144     //pool_register_int(pool, 15);
1145     //pool_register_int(pool, 1);
1146     //pool_register_int(pool, 0);
1147     
1148     /* write data */
1149     swf_SetU30(tag, pool->x_ints->num>1?pool->x_ints->num:0);
1150     for(t=1;t<pool->x_ints->num;t++) {
1151         S32 val = *(int*)array_getkey(pool->x_ints, t);
1152         swf_SetABCS32(tag, val);
1153     }
1154     swf_SetU30(tag, pool->x_uints->num>1?pool->x_uints->num:0);
1155     for(t=1;t<pool->x_uints->num;t++) {
1156         swf_SetABCU32(tag, *(unsigned int*)array_getkey(pool->x_uints, t));
1157     }
1158     swf_SetU30(tag, pool->x_floats->num>1?pool->x_floats->num:0);
1159     for(t=1;t<pool->x_floats->num;t++) {
1160         double d = pool_lookup_float(pool, t);
1161         swf_SetD64(tag, d);
1162     }
1163     swf_SetU30(tag, pool->x_strings->num>1?pool->x_strings->num:0);
1164     for(t=1;t<pool->x_strings->num;t++) {
1165         string_t str = pool_lookup_string2(pool, t);
1166         swf_SetU30String(tag, str.str, str.len);
1167     }
1168     swf_SetU30(tag, pool->x_namespaces->num>1?pool->x_namespaces->num:0);
1169     for(t=1;t<pool->x_namespaces->num;t++) {
1170         namespace_t*ns= (namespace_t*)array_getkey(pool->x_namespaces, t);
1171         swf_SetU8(tag, ns->access);
1172         const char*name = ns->name;
1173         int i = 0;
1174         
1175         //if(name && name[0])
1176         i = pool_find_string(pool, name);
1177
1178         swf_SetU30(tag, i);
1179     }
1180     swf_SetU30(tag, pool->x_namespace_sets->num>1?pool->x_namespace_sets->num:0);
1181     for(t=1;t<pool->x_namespace_sets->num;t++) {
1182         namespace_set_t*set = (namespace_set_t*)array_getkey(pool->x_namespace_sets, t);
1183         namespace_list_t*i = set->namespaces; 
1184         int len = list_length(i);
1185         swf_SetU30(tag, len);
1186         while(i) {
1187             int index = pool_find_namespace(pool, i->namespace);
1188             swf_SetU30(tag, index);
1189             i = i->next;
1190         }
1191     }
1192
1193     swf_SetU30(tag, pool->x_multinames->num>1?pool->x_multinames->num:0);
1194     for(t=1;t<pool->x_multinames->num;t++) {
1195         multiname_t*m = (multiname_t*)array_getkey(pool->x_multinames, t);
1196         swf_SetU8(tag, m->type);
1197
1198         if(m->ns) {
1199             assert(m->type==0x07 || m->type==0x0d);
1200             int i = pool_find_namespace(pool, m->ns);
1201             if(i<0) fprintf(stderr, "internal error: unregistered namespace %02x %s %s\n", m->ns->access, access2str(m->ns->access), m->ns->name);
1202             swf_SetU30(tag, i);
1203         } else {
1204             assert(m->type!=0x07 && m->type!=0x0d);
1205         }
1206         if(m->name) {
1207             assert(m->type==0x09 || m->type==0x0e || m->type==0x07 || m->type==0x0d || m->type==0x0f || m->type==0x10);
1208             int i = pool_find_string(pool, m->name);
1209             if(i<0) fprintf(stderr, "internal error: unregistered name\n");
1210             swf_SetU30(tag, i);
1211         } else {
1212             assert(m->type!=0x09 && m->type!=0x0e && m->type!=0x07 && m->type!=0x0d && m->type!=0x0f && m->type!=0x10);
1213         }
1214         if(m->namespace_set) {
1215             assert(m->type==0x09 || m->type==0x0e || m->type==0x1c || m->type==0x1b);
1216             int i = pool_find_namespace_set(pool, m->namespace_set);
1217             if(i<0) fprintf(stderr, "internal error: unregistered namespace set\n");
1218             swf_SetU30(tag, i);
1219         } else {
1220             assert(m->type!=0x09 && m->type!=0x0e && m->type!=0x1c && m->type!=0x1b);
1221         }
1222     }
1223 }
1224
1225
1226 void pool_destroy(pool_t*pool)
1227 {
1228     int t;
1229     array_free(pool->x_ints);
1230     array_free(pool->x_uints);
1231     array_free(pool->x_floats);
1232     array_free(pool->x_strings);
1233     array_free(pool->x_namespaces);
1234     array_free(pool->x_namespace_sets);
1235     array_free(pool->x_multinames);
1236     free(pool);
1237 }