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