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