abc constant pool implementation
[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 "pool.h"
25
26 char* access2str(int type)
27 {
28     if(type==0x08) return "";
29     else if(type==0x16) return "package";
30     else if(type==0x17) return "packageinternal";
31     else if(type==0x18) return "protected";
32     else if(type==0x19) return "explicit";
33     else if(type==0x1A) return "staticprotected";
34     else if(type==0x05) return "private";
35     else return "undefined";
36 }
37
38 char* multiname_to_string(multiname_t*m)
39 {
40     char*mname = 0;
41     if(m->type==0x07 || m->type==0x0d) {
42         mname = malloc(strlen(m->ns->name)+strlen(m->name)+32);
43         sprintf(mname, "<%s>\0", access2str(m->ns->access));
44         strcat(mname, m->ns->name);
45         strcat(mname, "::");
46         strcat(mname, m->name);
47     } else if(m->type==0x0f || m->type==0x10) {
48         mname = strdup(m->name);
49     } else if(m->type==0x11 || m->type==0x12) {
50         mname = strdup("");
51     } else if(m->type==0x09 || m->type==0x0e) {
52         char*s = namespace_set_to_string(m->namespace_set);
53         mname = malloc(strlen(s)+strlen(m->name)+16);
54         strcpy(mname, s);
55         free(s);
56         strcat(mname, "::");
57         strcat(mname, m->name);
58     } else if(m->type==0x1b || m->type==0x1c) {
59         mname = namespace_set_to_string(m->namespace_set);
60     }
61     return mname;
62 }
63
64 char* namespace_to_string(namespace_t*ns)
65 {
66     char*access = 0;
67     U8 type = ns->access;
68     if(type==0x08) access = "";
69     else if(type==0x16) access = "Package";
70     else if(type==0x17) access = "PackageInternal";
71     else if(type==0x18) access = "Protected";
72     else if(type==0x19) access = "Explicit";
73     else if(type==0x1A) access = "StaticProtected";
74     else if(type==0x05) access = "Private";
75     else {
76         fprintf(stderr, "Undefined namespace type %02x\n", type);
77         access = "UnknownNS";
78     }
79     char*string = malloc(strlen(access)+strlen(ns->name)+3);
80     sprintf(string, "<%s>%s", access, ns->name);
81     return string;
82 }
83
84 char* namespace_set_to_string(namespace_set_t*set)
85 {
86     /* TODO: is the order of the namespaces important (does it
87        change the lookup order?). E.g. flex freely shuffles namespaces
88        around.
89        If the order is not important, we can optimize constant pools by sorting
90        the namespaces.
91     */
92     int l = 0;
93     namespace_list_t*lns = set->namespaces;
94     while(lns) {
95         char*s = namespace_to_string(lns->namespace);
96         l += strlen(s)+1;
97         free(s);
98         lns = lns->next;
99     }
100     char*desc = malloc(l+16);
101     strcpy(desc, "{");
102     lns = set->namespaces;
103     while(lns) {
104         char*s = namespace_to_string(lns->namespace);
105         strcat(desc, s);
106         free(s);
107         strcat(desc, ",");
108         lns = lns->next;
109     }
110     strcat(desc, "}");
111     return desc;
112 }
113
114
115 int pool_register_string(pool_t*pool, const char*s)
116 {
117     return array_append_if_new(pool->strings, s, 0);
118 }
119
120 int pool_register_namespace(pool_t*pool, namespace_t*ns)
121 {
122     if(!ns)
123         return 0;
124     char*name = namespace_to_string(ns);
125     int i = array_append_if_new(pool->namespaces, name, ns);
126     free(name);
127     return i;
128 }
129 int pool_register_namespace_set(pool_t*pool, namespace_set_t*set)
130 {
131     char*name = namespace_set_to_string(set);
132     int i = array_append_if_new(pool->namespace_sets, name, set);
133     free(name);
134     return i;
135 }
136 int pool_register_multiname(pool_t*pool, multiname_t*n)
137 {
138     if(!n)
139         return 0;
140     char*name = multiname_to_string(n);
141     int i =array_append_if_new(pool->multinames, name, n);
142     free(name);
143     return i;
144 }
145 int pool_register_multiname2(pool_t*pool, char*name)
146 {
147     multiname_t*n = multiname_fromstring(name);
148     int i =array_append_if_new(pool->multinames, name, n);
149     return i;
150 }
151 int pool_find_namespace(pool_t*pool, namespace_t*ns)
152 {
153     if(!ns)
154         return 0;
155     char*name = namespace_to_string(ns);
156     int i = array_find(pool->namespaces, name);
157     if(i<0) {
158         fprintf(stderr, "Couldn't find namespace \"%s\" %08x in constant pool\n", name, ns);
159         return 0;
160     }
161     free(name);
162     return i;
163 }
164 int pool_find_namespace_set(pool_t*pool, namespace_set_t*set)
165 {
166     char*name = namespace_set_to_string(set);
167     int i = array_find(pool->namespace_sets, name);
168     free(name);
169     if(i<0) {
170         fprintf(stderr, "Couldn't find namespace_set \"%s\" in constant pool\n", name);
171         return 0;
172     }
173     return i;
174 }
175 int pool_find_string(pool_t*pool, const char*s)
176 {
177     int i = array_find(pool->strings, s);
178     if(i<0) {
179         fprintf(stderr, "Couldn't find string \"%s\" in constant pool\n", s);
180         *(int*)0=0;
181         return 0;
182     }
183     return i;
184 }
185 int pool_find_multiname(pool_t*pool, multiname_t*name)
186 {
187     char*n = multiname_to_string(name);
188     int i = array_find(pool->multinames, n);
189     if(i<0) {
190         fprintf(stderr, "Couldn't find multiname \"%s\" in constant pool\n", n);
191         return 0;
192     }
193     return i;
194 }
195
196 multiname_t*pool_lookup_multiname(pool_t*pool, int i)
197 {
198     multiname_t*m = (multiname_t*)array_getvalue(pool->multinames, i);
199     return m;
200 }
201
202 multiname_t* multiname_fromstring(const char*name2)
203 {
204     if(!name2)
205         name2 = "::";
206     char*n = strdup(name2);
207     char*p = strstr(n, "::");
208     char*namespace=0,*name=0;
209     if(!p) {
210         if(strchr(n, ':')) {
211             fprintf(stderr, "Error: single ':' in name\n");
212         }
213         namespace = "";
214         name = n;
215     } else {
216         *p = 0;
217         namespace = n;
218         name = p+2;
219         if(strchr(namespace, ':')) {
220             fprintf(stderr, "Error: single ':' in namespace\n");
221         }
222         if(strchr(name, ':')) {
223             fprintf(stderr, "Error: single ':' in qualified name\n");
224         }
225     }
226
227     multiname_t*m = malloc(sizeof(multiname_t));
228     memset(m, 0, sizeof(multiname_t));
229     m->type = QNAME;
230     m->namespace_set = 0;
231     NEW(namespace_t,ns);
232     ns->name= namespace;
233     m->ns = ns;
234     m->name = name;
235     return m;
236 }
237
238 pool_t*pool_new()
239 {
240     NEW(pool_t, p);
241
242     p->ints = array_new();
243     array_append(p->ints, 0, (void*)(ptroff_t)0);
244     p->uints = array_new();
245     array_append(p->uints, 0, (void*)(ptroff_t)0);
246     p->floats = array_new();
247     array_append(p->floats, 0, 0);
248     p->strings = array_new();
249     array_append(p->strings, "--<UNDEFINED_STRING>--", 0);
250     p->namespaces = array_new();
251     array_append(p->namespaces, "--<UNDEFINED_NAMESPACE>--", 0);
252     p->namespace_sets = array_new();
253     array_append(p->namespace_sets, "--<UNDEFINED_NSSET>--", 0);
254     p->multinames = array_new();
255     array_append(p->multinames, "--<UNDEFINED_MULTINAME>--", 0);
256
257     return p;
258 }
259
260 #define DEBUG if(0)
261
262 void pool_read(pool_t*pool, TAG*tag)
263 {
264     int num_ints = swf_GetU30(tag);
265     DEBUG printf("%d ints\n", num_ints);
266     int t;
267     for(t=1;t<num_ints;t++) {
268         S32 v = swf_GetS30(tag);
269         DEBUG printf("int %d) %d\n", t, v);
270         array_append(pool->ints, 0, (void*)(ptroff_t)v);
271     }
272
273     int num_uints = swf_GetU30(tag);
274     DEBUG printf("%d uints\n", num_uints);
275     for(t=1;t<num_uints;t++) {
276         U32 v = swf_GetU30(tag);
277         DEBUG printf("uint %d) %d\n", t, v);
278         array_append(pool->uints, 0, (void*)(ptroff_t)v);
279     }
280     
281     int num_floats = swf_GetU30(tag);
282     DEBUG printf("%d floats\n", num_floats);
283     for(t=1;t<num_floats;t++) {
284         double d = swf_GetD64(tag);
285         DEBUG printf("float %d) %f\n", t, d);
286         array_append(pool->floats, 0, 0);
287     }
288     
289     int num_strings = swf_GetU30(tag);
290     DEBUG printf("%d strings\n", num_strings);
291     for(t=1;t<num_strings;t++) {
292         int len = swf_GetU30(tag);
293         char*s = malloc(len+1);
294         swf_GetBlock(tag, s, len);
295         s[len] = 0;
296         array_append(pool->strings, s, 0);
297         DEBUG printf("%d) \"%s\"\n", t, pool->strings->d[t].name);
298     }
299     int num_namespaces = swf_GetU30(tag);
300     DEBUG printf("%d namespaces\n", num_namespaces);
301     for(t=1;t<num_namespaces;t++) {
302         U8 type = swf_GetU8(tag);
303         int namenr = swf_GetU30(tag);
304         const char*name = array_getkey(pool->strings, namenr);
305         NEW(namespace_t, ns);
306         memset(ns, 0, sizeof(namespace_t));
307         ns->access = type;
308         ns->name = strdup(name);
309         array_append(pool->namespaces, name, ns);
310     }
311     int num_sets = swf_GetU30(tag);
312     DEBUG printf("%d namespace sets\n", num_sets);
313     for(t=1;t<num_sets;t++) {
314         int count = swf_GetU30(tag);
315         int s;
316         
317         NEW(namespace_set_t, nsset);
318         for(s=0;s<count;s++) {
319             int nsnr = swf_GetU30(tag);
320             namespace_t*ns = (namespace_t*)array_getvalue(pool->namespaces, nsnr);
321             list_append(nsset->namespaces, ns);
322         }
323         char*desc = namespace_set_to_string(nsset);
324
325         array_append(pool->namespace_sets, desc, nsset);
326         DEBUG printf("set %d) %s\n", t, desc);
327     }
328
329     int num_multinames = swf_GetU30(tag);
330     DEBUG printf("%d multinames\n", num_multinames);
331     for(t=1;t<num_multinames;t++) {
332         
333         NEW(multiname_t,m);
334         m->type = swf_GetU8(tag);
335         if(m->type==0x07 || m->type==0x0d) {
336             int namespace_index = swf_GetU30(tag);
337             m->ns = (namespace_t*)array_getvalue(pool->namespaces, namespace_index);
338             int name_index = swf_GetU30(tag);
339             m->name = array_getkey(pool->strings, name_index);
340         } else if(m->type==0x0f || m->type==0x10) {
341             int name_index = swf_GetU30(tag);
342             m->name = array_getkey(pool->strings, name_index);
343         } else if(m->type==0x11 || m->type==0x12) {
344         } else if(m->type==0x09 || m->type==0x0e) {
345             int name_index = swf_GetU30(tag);
346             int namespace_set_index = swf_GetU30(tag);
347             m->name = array_getkey(pool->strings, name_index);
348             m->namespace_set = (namespace_set_t*)array_getvalue(pool->namespace_sets, namespace_set_index);
349         } else if(m->type==0x1b || m->type==0x1c) {
350             int namespace_set_index = swf_GetU30(tag);
351             m->namespace_set = (namespace_set_t*)array_getvalue(pool->namespace_sets, namespace_set_index);
352         } else {
353             printf("can't parse type %d multinames yet\n", m->type);
354         }
355         char*mname = multiname_to_string(m);
356         DEBUG printf("multiname %d) %s\n", t, mname);
357         array_append(pool->multinames, mname, m);
358         free(mname);
359     }
360
361
362 void pool_destroy(pool_t*pool)
363 {
364     int t;
365     array_free(pool->ints);
366     array_free(pool->uints);
367     array_free(pool->floats);
368
369     for(t=1;t<pool->strings->num;t++) {
370         free((void*)array_getkey(pool->strings, t));
371     }
372     array_free(pool->strings);
373
374     for(t=1;t<pool->namespaces->num;t++) {
375         free(array_getvalue(pool->namespaces, t));
376     }
377     array_free(pool->namespaces);
378    
379     for(t=1;t<pool->namespace_sets->num;t++) {
380         namespace_set_t*set = (namespace_set_t*)array_getvalue(pool->namespace_sets, t);
381         list_free(set->namespaces);
382         free(set);
383     }
384     array_free(pool->namespace_sets);
385
386     for(t=1;t<pool->multinames->num;t++) {
387         free(array_getvalue(pool->multinames, t));
388     }
389     array_free(pool->multinames);
390 }