7aa34acae828cf9e5574c4168bee7052447fedfc
[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_to_string(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_to_string(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_to_string(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_to_string(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     m->ns = namespace_clone(ns);
448     m->name = strdup(name);
449     return m;
450 }
451
452 multiname_t* multiname_clone(multiname_t*other)
453 {
454     if(!other)
455         return 0;
456     NEW(multiname_t,m);
457     m->type = other->type;
458     if(other->ns)
459         m->ns = namespace_clone(other->ns);
460     if(other->namespace_set)
461         m->namespace_set = namespace_set_clone(other->namespace_set);
462     if(other->name)
463         m->name = strdup(other->name);
464     return m;
465 }
466
467
468 char* access2str(int type)
469 {
470     if(type==0x08) return "access08";
471     else if(type==0x16) return "package";
472     else if(type==0x17) return "packageinternal";
473     else if(type==0x18) return "protected";
474     else if(type==0x19) return "explicit";
475     else if(type==0x1A) return "staticprotected";
476     else if(type==0x05) return "private";
477     else {
478         fprintf(stderr, "Undefined access type %02x\n", type);
479         return "undefined";
480     }
481 }
482
483
484 char multiname_late_namespace(multiname_t*m)
485 {
486     if(!m)
487         return 0;
488     return (m->type==RTQNAME || m->type==RTQNAMEA ||
489             m->type==RTQNAMEL || m->type==RTQNAMELA);
490 }
491
492 char multiname_late_name(multiname_t*m)
493 {
494     if(!m)
495         return 0;
496     return m->type==RTQNAMEL || m->type==RTQNAMELA ||
497            m->type==MULTINAMEL || m->type==MULTINAMELA;
498 }
499
500 char* multiname_to_string(multiname_t*m)
501 {
502     char*mname = 0;
503     if(!m)
504         return strdup("NULL");
505     if(m->type==0xff)
506         return strdup("--<MULTINAME 0xff>--");
507
508     char*name = m->name?escape_string(m->name):strdup("*");
509     int namelen = strlen(name);
510
511     if(m->type==QNAME || m->type==QNAMEA) {
512         char*nsname = escape_string(m->ns->name);
513         mname = malloc(strlen(nsname)+namelen+32);
514         strcpy(mname, "<q");
515         if(m->type == QNAMEA)
516             strcat(mname, ",attr");
517         strcat(mname, ">[");
518         strcat(mname,access2str(m->ns->access));
519         strcat(mname, "]");
520         strcat(mname, nsname);
521         free(nsname);
522         strcat(mname, "::");
523         strcat(mname, name);
524     } else if(m->type==RTQNAME || m->type==RTQNAMEA) {
525         mname = malloc(namelen+32);
526         strcpy(mname, "<rt");
527         if(m->type == RTQNAMEA) 
528             strcat(mname, ",attr");
529         strcat(mname, ">");
530         strcat(mname, name);
531     } else if(m->type==RTQNAMEL) {
532         mname = strdup("<rt,l>");
533     } else if(m->type==RTQNAMELA) {
534         mname = strdup("<rt,l,attr>");
535     } else if(m->type==MULTINAME || m->type==MULTINAMEA) {
536         char*s = namespace_set_to_string(m->namespace_set);
537         mname = malloc(strlen(s)+namelen+16);
538         if(m->type == MULTINAME)
539             strcpy(mname,"<multi>");
540         else //MULTINAMEA
541             strcpy(mname,"<multi,attr>");
542         strcat(mname, s);
543         strcat(mname, "::");
544         strcat(mname, name);
545         free(s);
546     } else if(m->type==MULTINAMEL || m->type==MULTINAMELA) {
547         char*s = namespace_set_to_string(m->namespace_set);
548         mname = malloc(strlen(s)+16);
549         if(m->type == MULTINAMEL)
550             strcpy(mname,"<l,multi>");
551         else //MULTINAMELA
552             strcpy(mname,"<l,multi,attr>");
553         strcat(mname,s);
554         free(s);
555     } else {
556         fprintf(stderr, "Invalid multiname type: %02x\n", m->type);
557     }
558     free(name);
559     return mname;
560 }
561
562 multiname_t* multiname_fromstring(const char*name2)
563 {
564     if(!name2)
565         return 0;
566     char*n = strdup(name2);
567     char*p = strstr(n, "::");
568     char*namespace=0,*name=0;
569     if(!p) {
570         if(strchr(n, ':')) {
571             fprintf(stderr, "Error: single ':' in name\n");
572         }
573         namespace = "";
574         name = n;
575     } else {
576         *p = 0;
577         namespace = n;
578         name = p+2;
579         if(strchr(namespace, ':')) {
580             fprintf(stderr, "Error: single ':' in namespace\n");
581         }
582         if(strchr(name, ':')) {
583             fprintf(stderr, "Error: single ':' in qualified name\n");
584         }
585     }
586
587     multiname_t*m = malloc(sizeof(multiname_t));
588     memset(m, 0, sizeof(multiname_t));
589     m->type = QNAME;
590     m->namespace_set = 0;
591     m->ns = namespace_fromstring(namespace);
592     m->name = name?strdup(name):0;
593     free(n);
594     return m;
595 }
596
597 void multiname_destroy(multiname_t*m)
598 {
599     if(m) {
600         if(m->name) {
601             free((void*)m->name);m->name = 0;
602         }
603         if(m->ns) {
604             namespace_destroy(m->ns);m->ns = 0;
605         }
606         if(m->namespace_set) {
607             namespace_set_destroy(m->namespace_set);m->namespace_set = 0;
608         }
609         free(m);
610     }
611 }
612
613 type_t multiname_type = {
614     dup: (dup_func)multiname_clone,
615     hash: (hash_func)multiname_hash,
616     free: (free_func)multiname_destroy,
617     equals: (equals_func)multiname_equals
618 };
619
620
621 // ------------------------------- constants -------------------------------------
622
623 #define NS_TYPE(x) ((x) == 0x08 || (x) == 0x16 || (x) == 0x17 || (x) == 0x18 ||  \
624                                    (x) == 0x19 || (x) == 0x1a || (x) == 0x05)
625
626 #define UNIQUE_CONSTANT(x) ((x) == CONSTANT_TRUE || (x) == CONSTANT_FALSE || (x) == CONSTANT_NULL || (x) == CONSTANT_UNDEFINED)
627
628 constant_t* constant_new_int(int i) 
629 {
630     NEW(constant_t,c);
631     c->i = i;
632     c->type = CONSTANT_INT;
633     return c;
634 }
635 constant_t* constant_new_uint(unsigned int u)
636 {
637     NEW(constant_t,c);
638     c->u = u;
639     c->type = CONSTANT_UINT;
640     return c;
641 }
642 constant_t* constant_new_float(double f)
643 {
644     NEW(constant_t,c);
645     c->f = f;
646     c->type = CONSTANT_FLOAT;
647     return c;
648 }
649 constant_t* constant_new_string(char*s)
650 {
651     NEW(constant_t,c);
652     c->s = strdup(s);
653     c->type = CONSTANT_STRING;
654     return c;
655 }
656 constant_t* constant_new_namespace(namespace_t*ns)
657 {
658     NEW(constant_t,c);
659     c->ns = namespace_clone(ns);
660     c->type = ns->access;
661     assert(NS_TYPE(c->type));
662     return c;
663 }
664 constant_t* constant_new_true()
665 {
666     NEW(constant_t,c);
667     c->type = CONSTANT_TRUE;
668     return c;
669 }
670 constant_t* constant_new_false()
671 {
672     NEW(constant_t,c);
673     c->type = CONSTANT_FALSE;
674     return c;
675 }
676 constant_t* constant_new_null()
677 {
678     NEW(constant_t,c);
679     c->type = CONSTANT_NULL;
680     return c;
681 }
682 constant_t* constant_new_undefined()
683 {
684     NEW(constant_t,c);
685     c->type = CONSTANT_UNDEFINED;
686     return c;
687 }
688 constant_t* constant_fromindex(pool_t*pool, int index, int type)
689 {
690     if(!index) {
691         /* even for nonvalued constants (like TRUE/FALSE etc.), a nonzero
692            index is present to indicate that a type is coming */
693         return 0;
694     } 
695     NEW(constant_t,c);
696     c->type = type;
697     if(NS_TYPE(c->type)) {
698         c->ns =  pool_lookup_namespace(pool, index);
699     } else if(c->type == CONSTANT_INT) {
700         c->i =  pool_lookup_int(pool, index);
701     } else if(c->type == CONSTANT_UINT) {
702         c->u =  pool_lookup_uint(pool, index);
703     } else if(c->type == CONSTANT_FLOAT) {
704         c->f =  pool_lookup_float(pool, index);
705     } else if(c->type == CONSTANT_STRING) {
706         c->s =  pool_lookup_string(pool, index);
707     } else if(UNIQUE_CONSTANT(c->type)) {
708         // ok
709     } else {
710         fprintf(stderr, "invalid constant type %02x\n", c->type);
711     }
712     return c;
713 }
714 char* constant_to_string(constant_t*c)
715 {
716     if(!c)
717         return 0;
718     char buf[30];
719     if(NS_TYPE(c->type)) {
720         return namespace_to_string(c->ns);
721     } else if(c->type == CONSTANT_INT) {
722         sprintf(buf, "%d", c->i);
723         return strdup(buf);
724     } else if(c->type == CONSTANT_UINT) {
725         sprintf(buf, "%u", c->u);
726         return strdup(buf);
727     } else if(c->type == CONSTANT_FLOAT) {
728         sprintf(buf, "%f", c->f);
729         return strdup(buf);
730     } else if(c->type == CONSTANT_STRING) {
731         return strdup(c->s);
732     } else if(c->type == CONSTANT_TRUE) {
733         return strdup("true");
734     } else if(c->type == CONSTANT_FALSE) {
735         return strdup("false");
736     } else if(c->type == CONSTANT_NULL) {
737         return strdup("null");
738     } else if(c->type == CONSTANT_UNDEFINED) {
739         return strdup("undefined");
740     } else {
741         fprintf(stderr, "invalid constant type %02x\n", c->type);
742         return 0;
743     }
744 }
745 char constant_has_index(constant_t*c) 
746 {
747     if(!c)
748         return 0;
749     return !UNIQUE_CONSTANT(c->type);
750 }
751 int constant_get_index(pool_t*pool, constant_t*c)
752 {
753     if(!c)
754         return 0;
755     if(NS_TYPE(c->type)) {
756         assert(c->ns);
757         assert(c->type == c->ns->access);
758         return pool_register_namespace(pool, c->ns);
759     } else if(c->type == CONSTANT_INT) {
760         return pool_register_int(pool, c->i);
761     } else if(c->type == CONSTANT_UINT) {
762         return pool_register_uint(pool, c->u);
763     } else if(c->type == CONSTANT_FLOAT) {
764         return pool_register_float(pool, c->f);
765     } else if(c->type == CONSTANT_STRING) {
766         return pool_register_string(pool, c->s);
767     } else if(!constant_has_index(c)) {
768         return 1;
769     } else {
770         fprintf(stderr, "invalid constant type %02x\n", c->type);
771         return 0;
772     }
773 }
774 void constant_free(constant_t*c)
775 {
776     if(!c)
777         return;
778     if(c->type == CONSTANT_STRING) {
779         free(c->s);c->s=0;
780     } else if (NS_TYPE(c->type)) {
781         namespace_destroy(c->ns);c->ns=0;
782     }
783     free(c);
784 }
785 // ------------------------------- pool -------------------------------------
786
787 int pool_register_uint(pool_t*p, unsigned int i)
788 {
789     int pos = array_append_if_new(p->x_uints, &i, 0);
790     assert(pos!=0);
791     return pos;
792 }
793 int pool_register_int(pool_t*p, int i)
794 {
795     int pos = array_append_if_new(p->x_ints, &i, 0);
796     assert(pos!=0);
797     return pos;
798 }
799 int pool_register_float(pool_t*p, double d)
800 {
801     int pos = array_append_if_new(p->x_floats, &d, 0);
802     assert(pos!=0);
803     return pos;
804 }
805 int pool_register_string(pool_t*pool, const char*s)
806 {
807     if(!s) return 0;
808     int pos = array_append_if_new(pool->x_strings, s, 0);
809     assert(pos!=0);
810     return pos;
811 }
812 int pool_register_namespace(pool_t*pool, namespace_t*ns)
813 {
814     if(!ns) return 0;
815     int pos = array_append_if_new(pool->x_namespaces, ns, 0);
816     assert(pos!=0);
817     return pos;
818 }
819 int pool_register_namespace_set(pool_t*pool, namespace_set_t*set)
820 {
821     if(!set) return 0;
822     int pos = array_append_if_new(pool->x_namespace_sets, set, 0);
823     assert(pos!=0);
824     return pos;
825 }
826 int pool_register_multiname(pool_t*pool, multiname_t*n)
827 {
828     if(!n) return 0;
829     int pos = array_append_if_new(pool->x_multinames, n, 0);
830     if(pos==0) {
831         *(int*)0=0xdead;
832     }
833     assert(pos!=0);
834     return pos;
835 }
836 int pool_register_multiname2(pool_t*pool, char*name)
837 {
838     if(!name) return 0;
839     multiname_t*n = multiname_fromstring(name);
840     int pos = array_append_if_new(pool->x_multinames, n, 0);
841     multiname_destroy(n);
842     assert(pos!=0);
843     return pos;
844 }
845
846
847 int pool_find_uint(pool_t*pool, unsigned int x)
848 {
849     int i = array_find(pool->x_uints, &x);
850     if(i<=0) {
851         fprintf(stderr, "Couldn't find uint \"%d\" in constant pool\n", x);
852         return 0;
853     }
854     return i;
855 }
856 int pool_find_int(pool_t*pool, int x)
857 {
858     int i = array_find(pool->x_ints, &x);
859     if(i<=0) {
860         fprintf(stderr, "Couldn't find int \"%d\" in constant pool\n", x);
861         return 0;
862     }
863     return i;
864 }
865 int pool_find_float(pool_t*pool, double x)
866 {
867     int i = array_find(pool->x_ints, &x);
868     if(i<=0) {
869         fprintf(stderr, "Couldn't find int \"%d\" in constant pool\n", x);
870         return 0;
871     }
872     return i;
873 }
874 int pool_find_namespace(pool_t*pool, namespace_t*ns)
875 {
876     if(!ns)
877         return 0;
878     int i = array_find(pool->x_namespaces, ns);
879     if(i<=0) {
880         char*s = namespace_to_string(ns);
881         fprintf(stderr, "Couldn't find namespace \"%s\" %08x in constant pool\n", s, ns);
882         free(s);
883         return 0;
884     }
885     return i;
886 }
887 int pool_find_namespace_set(pool_t*pool, namespace_set_t*set)
888 {
889     if(!set)
890         return 0;
891     int i = array_find(pool->x_namespace_sets, set);
892     if(i<=0) {
893         char*s = namespace_set_to_string(set);
894         fprintf(stderr, "Couldn't find namespace_set \"%s\" in constant pool\n", s);
895         free(s);
896         return 0;
897     }
898     return i;
899 }
900 int pool_find_string(pool_t*pool, const char*s)
901 {
902     if(!s)
903         return 0;
904     int i = array_find(pool->x_strings, s);
905     if(i<=0) {
906         fprintf(stderr, "Couldn't find string \"%s\" in constant pool\n", s);
907         return 0;
908     }
909     return i;
910 }
911 int pool_find_multiname(pool_t*pool, multiname_t*name)
912 {
913     if(!name)
914         return 0;
915     int i = array_find(pool->x_multinames, name);
916     if(i<=0) {
917         char*s = multiname_to_string(name);
918         fprintf(stderr, "Couldn't find multiname \"%s\" in constant pool\n", s);
919         free(s);
920         return 0;
921     }
922     return i;
923 }
924
925 int pool_lookup_int(pool_t*pool, int i)
926 {
927     if(!i) return 0;
928     return *(int*)array_getkey(pool->x_ints, i);
929 }
930 unsigned int pool_lookup_uint(pool_t*pool, int i)
931 {
932     if(!i) return 0;
933     return *(unsigned int*)array_getkey(pool->x_uints, i);
934 }
935 double pool_lookup_float(pool_t*pool, int i)
936 {
937     if(!i) return __builtin_nan("");
938     return *(double*)array_getkey(pool->x_floats, i);
939 }
940 char*pool_lookup_string(pool_t*pool, int i)
941 {
942     return (char*)array_getkey(pool->x_strings, i);
943 }
944 namespace_t*pool_lookup_namespace(pool_t*pool, int i)
945 {
946     return (namespace_t*)array_getkey(pool->x_namespaces, i);
947 }
948 namespace_set_t*pool_lookup_namespace_set(pool_t*pool, int i)
949 {
950     return (namespace_set_t*)array_getkey(pool->x_namespace_sets, i);
951 }
952 multiname_t*pool_lookup_multiname(pool_t*pool, int i)
953 {
954     return (multiname_t*)array_getkey(pool->x_multinames, i);
955 }
956
957 pool_t*pool_new()
958 {
959     NEW(pool_t, p);
960
961     p->x_ints = array_new2(&uint_type);
962     p->x_uints = array_new2(&uint_type);
963     p->x_floats = array_new2(&float_type);
964     p->x_strings = array_new2(&charptr_type);
965     p->x_namespaces = array_new2(&namespace_type);
966     p->x_namespace_sets = array_new2(&namespace_set_type);
967     p->x_multinames = array_new2(&multiname_type);
968
969     /* add a zero-index entry in each list */
970   
971     array_append(p->x_ints, 0, 0);
972     array_append(p->x_uints, 0, 0);
973     array_append(p->x_floats, 0, 0);
974     array_append(p->x_strings, 0, 0);
975     array_append(p->x_namespaces, 0, 0);
976     array_append(p->x_namespace_sets, 0, 0);
977     array_append(p->x_multinames, 0, 0);
978     return p;
979 }
980
981 #define DEBUG if(0)
982 //#define DEBUG
983
984 void pool_read(pool_t*pool, TAG*tag)
985 {
986     int num_ints = swf_GetU30(tag);
987     DEBUG printf("%d ints\n", num_ints);
988     int t;
989     for(t=1;t<num_ints;t++) {
990         S32 v = swf_GetS30(tag);
991         DEBUG printf("int %d) %d\n", t, v);
992         array_append(pool->x_ints, &v, 0);
993     }
994
995     int num_uints = swf_GetU30(tag);
996     DEBUG printf("%d uints\n", num_uints);
997     for(t=1;t<num_uints;t++) {
998         U32 v = swf_GetU30(tag);
999         DEBUG printf("uint %d) %d\n", t, v);
1000         array_append(pool->x_uints, &v, 0);
1001     }
1002     
1003     int num_floats = swf_GetU30(tag);
1004     DEBUG printf("%d floats\n", num_floats);
1005     for(t=1;t<num_floats;t++) {
1006         double d = swf_GetD64(tag);
1007         DEBUG printf("float %d) %f\n", t, d);
1008         array_append(pool->x_floats, &d, 0);
1009     }
1010     
1011     int num_strings = swf_GetU30(tag);
1012     DEBUG printf("%d strings\n", num_strings);
1013     for(t=1;t<num_strings;t++) {
1014         int len = swf_GetU30(tag);
1015         char*s = malloc(len+1);
1016         swf_GetBlock(tag, s, len);
1017         s[len] = 0;
1018         array_append(pool->x_strings, s, 0);
1019         free(s);
1020         DEBUG printf("%d) \"%s\"\n", t, pool->x_strings->d[t].name);
1021     }
1022     int num_namespaces = swf_GetU30(tag);
1023     DEBUG printf("%d namespaces\n", num_namespaces);
1024     for(t=1;t<num_namespaces;t++) {
1025         U8 type = swf_GetU8(tag);
1026         int namenr = swf_GetU30(tag);
1027         const char*name = 0; 
1028         if(namenr)
1029             name = array_getkey(pool->x_strings, namenr);
1030         namespace_t*ns = namespace_new(type, name);
1031         array_append(pool->x_namespaces, ns, 0);
1032         DEBUG printf("%d) %02x \"%s\"\n", t, type, namespace_to_string(ns));
1033         namespace_destroy(ns);
1034     }
1035     int num_sets = swf_GetU30(tag);
1036     DEBUG printf("%d namespace sets\n", num_sets);
1037     for(t=1;t<num_sets;t++) {
1038         int count = swf_GetU30(tag);
1039         int s;
1040         
1041         NEW(namespace_set_t, nsset);
1042         for(s=0;s<count;s++) {
1043             int nsnr = swf_GetU30(tag);
1044             if(!nsnr)
1045                 fprintf(stderr, "Zero entry in namespace set\n");
1046             namespace_t*ns = (namespace_t*)array_getkey(pool->x_namespaces, nsnr);
1047             list_append(nsset->namespaces, namespace_clone(ns));
1048         }
1049         array_append(pool->x_namespace_sets, nsset, 0);
1050         DEBUG printf("set %d) %s\n", t, namespace_set_to_string(nsset));
1051         namespace_set_destroy(nsset);
1052     }
1053
1054     int num_multinames = swf_GetU30(tag);
1055     DEBUG printf("%d multinames\n", num_multinames);
1056     for(t=1;t<num_multinames;t++) {
1057         multiname_t m;
1058         memset(&m, 0, sizeof(multiname_t));
1059         m.type = swf_GetU8(tag);
1060         if(m.type==0x07 || m.type==0x0d) {
1061             int namespace_index = swf_GetU30(tag);
1062             m.ns = (namespace_t*)array_getkey(pool->x_namespaces, namespace_index);
1063             int name_index = swf_GetU30(tag);
1064             if(name_index) // 0 = '*' (any)
1065                 m.name = array_getkey(pool->x_strings, name_index);
1066         } else if(m.type==0x0f || m.type==0x10) {
1067             int name_index = swf_GetU30(tag);
1068             if(name_index) // 0 = '*' (any name)
1069                 m.name = array_getkey(pool->x_strings, name_index);
1070         } else if(m.type==0x11 || m.type==0x12) {
1071         } else if(m.type==0x09 || m.type==0x0e) {
1072             int name_index = swf_GetU30(tag);
1073             int namespace_set_index = swf_GetU30(tag);
1074             if(name_index)
1075                 m.name = array_getkey(pool->x_strings, name_index);
1076             m.namespace_set = (namespace_set_t*)array_getkey(pool->x_namespace_sets, namespace_set_index);
1077         } else if(m.type==0x1b || m.type==0x1c) {
1078             int namespace_set_index = swf_GetU30(tag);
1079             m.namespace_set = (namespace_set_t*)array_getkey(pool->x_namespace_sets, namespace_set_index);
1080         } else {
1081             printf("can't parse type %d multinames yet\n", m.type);
1082         }
1083         DEBUG printf("multiname %d) %s\n", t, multiname_to_string(&m));
1084         array_append(pool->x_multinames, &m, 0);
1085     }
1086
1087
1088 void pool_write(pool_t*pool, TAG*tag)
1089 {
1090     int t;
1091     
1092     /* make sure that all namespaces used by multinames / namespace sets
1093        and all strings used by namespaces exist */
1094
1095     for(t=1;t<pool->x_multinames->num;t++) {
1096         multiname_t*m = (multiname_t*)array_getkey(pool->x_multinames, t);
1097         if(m->ns) {
1098             pool_register_namespace(pool, m->ns);
1099         }
1100         if(m->namespace_set) {
1101             pool_register_namespace_set(pool, m->namespace_set);
1102         }
1103         if(m->name) {
1104             pool_register_string(pool, m->name);
1105         }
1106     }
1107     for(t=1;t<pool->x_namespace_sets->num;t++) {
1108         namespace_set_t*set = (namespace_set_t*)array_getkey(pool->x_namespace_sets, t);
1109         namespace_list_t*i = set->namespaces;
1110         while(i) {
1111             pool_register_namespace(pool, i->namespace);
1112             i = i->next;
1113         }
1114     }
1115     for(t=1;t<pool->x_namespaces->num;t++) {
1116         namespace_t*ns= (namespace_t*)array_getkey(pool->x_namespaces, t);
1117         /*  The spec says (page 22): "a value of zero denotes an empty string".
1118             However when actually using zero strings as empty namespaces, the
1119             flash player breaks.*/
1120         //if(ns->name && ns->name[0])
1121         array_append_if_new(pool->x_strings, ns->name, 0);
1122     }
1123
1124     //pool_register_int(pool, 15);
1125     //pool_register_int(pool, 1);
1126     //pool_register_int(pool, 0);
1127     
1128     /* write data */
1129     swf_SetU30(tag, pool->x_ints->num>1?pool->x_ints->num:0);
1130     for(t=1;t<pool->x_ints->num;t++) {
1131         S32 val = *(int*)array_getkey(pool->x_ints, t);
1132         swf_SetS30(tag, val);
1133     }
1134     swf_SetU30(tag, pool->x_uints->num>1?pool->x_uints->num:0);
1135     for(t=1;t<pool->x_uints->num;t++) {
1136         swf_SetU30(tag, *(unsigned int*)array_getkey(pool->x_uints, t));
1137     }
1138     swf_SetU30(tag, pool->x_floats->num>1?pool->x_floats->num:0);
1139     for(t=1;t<pool->x_floats->num;t++) {
1140         double d = pool_lookup_float(pool, t);
1141         swf_SetD64(tag, d);
1142     }
1143     swf_SetU30(tag, pool->x_strings->num>1?pool->x_strings->num:0);
1144     for(t=1;t<pool->x_strings->num;t++) {
1145         swf_SetU30String(tag, array_getkey(pool->x_strings, t));
1146     }
1147     swf_SetU30(tag, pool->x_namespaces->num>1?pool->x_namespaces->num:0);
1148     for(t=1;t<pool->x_namespaces->num;t++) {
1149         namespace_t*ns= (namespace_t*)array_getkey(pool->x_namespaces, t);
1150         swf_SetU8(tag, ns->access);
1151         const char*name = ns->name;
1152         int i = 0;
1153         
1154         //if(name && name[0])
1155         i = pool_find_string(pool, name);
1156
1157         swf_SetU30(tag, i);
1158     }
1159     swf_SetU30(tag, pool->x_namespace_sets->num>1?pool->x_namespace_sets->num:0);
1160     for(t=1;t<pool->x_namespace_sets->num;t++) {
1161         namespace_set_t*set = (namespace_set_t*)array_getkey(pool->x_namespace_sets, t);
1162         namespace_list_t*i = set->namespaces; 
1163         int len = list_length(i);
1164         swf_SetU30(tag, len);
1165         while(i) {
1166             int index = pool_find_namespace(pool, i->namespace);
1167             swf_SetU30(tag, index);
1168             i = i->next;
1169         }
1170     }
1171
1172     swf_SetU30(tag, pool->x_multinames->num>1?pool->x_multinames->num:0);
1173     for(t=1;t<pool->x_multinames->num;t++) {
1174         multiname_t*m = (multiname_t*)array_getkey(pool->x_multinames, t);
1175         swf_SetU8(tag, m->type);
1176
1177         if(m->ns) {
1178             assert(m->type==0x07 || m->type==0x0d);
1179             int i = pool_find_namespace(pool, m->ns);
1180             if(i<0) fprintf(stderr, "internal error: unregistered namespace %02x %s %s\n", m->ns->access, access2str(m->ns->access), m->ns->name);
1181             swf_SetU30(tag, i);
1182         } else {
1183             assert(m->type!=0x07 && m->type!=0x0d);
1184         }
1185         if(m->name) {
1186             assert(m->type==0x09 || m->type==0x0e || m->type==0x07 || m->type==0x0d || m->type==0x0f || m->type==0x10);
1187             int i = pool_find_string(pool, m->name);
1188             if(i<0) fprintf(stderr, "internal error: unregistered name\n");
1189             swf_SetU30(tag, i);
1190         } else {
1191             assert(m->type!=0x09 && m->type!=0x0e && m->type!=0x07 && m->type!=0x0d && m->type!=0x0f && m->type!=0x10);
1192         }
1193         if(m->namespace_set) {
1194             assert(m->type==0x09 || m->type==0x0e || m->type==0x1c || m->type==0x1b);
1195             int i = pool_find_namespace_set(pool, m->namespace_set);
1196             if(i<0) fprintf(stderr, "internal error: unregistered namespace set\n");
1197             swf_SetU30(tag, i);
1198         } else {
1199             assert(m->type!=0x09 && m->type!=0x0e && m->type!=0x1c && m->type!=0x1b);
1200         }
1201     }
1202 }
1203
1204
1205 void pool_destroy(pool_t*pool)
1206 {
1207     int t;
1208     array_free(pool->x_ints);
1209     array_free(pool->x_uints);
1210     array_free(pool->x_floats);
1211     array_free(pool->x_strings);
1212     array_free(pool->x_namespaces);
1213     array_free(pool->x_namespace_sets);
1214     array_free(pool->x_multinames);
1215     free(pool);
1216 }