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