added -I option
[swftools.git] / lib / as3 / mklib.c
1 /* code.c
2
3    File to generate builtin.c
4
5    Copyright (c) 2008 Matthias Kramm <kramm@quiss.org>
6  
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
20
21 #include <stdlib.h>
22 #include <stdio.h>
23 #include <unistd.h>
24 #include <memory.h>
25 #include "../rfxswf.h"
26 #include "../os.h"
27 #include "pool.h"
28 #include "files.h"
29 #include "tokenizer.h"
30 #include "parser.tab.h"
31 #include "parser.h"
32
33 void fixstring(char*s)
34 {
35     char first=1;
36     for(;*s;s++) {
37         if(!((*s>='a' && *s<='z') || (*s>='A' && *s<='Z') || 
38                     (*s>='0' && *s<='9' && !first))) {
39             *s = '_';
40         }
41         first = 0;
42     }
43 }
44
45 char* mkpid(const char*package)
46 {
47     char*id = malloc(strlen(package)+20);
48     strcpy(id, "package_");
49     if(!*package) 
50         strcat(id, "global");
51     else
52         strcat(id, package);
53     fixstring(id);
54     return id;
55 }
56 char* mkid(const char*package, const char*name)
57 {
58     char*id = malloc(strlen(package)+strlen(name)+10);
59     strcpy(id, package);
60     strcat(id, "_");
61     strcat(id, name);
62     fixstring(id);
63     return id;
64 }
65
66 char*mkid2(multiname_t*m)
67 {
68     if(m->type == QNAME)
69         return mkid(m->ns->name, m->name);
70     else if(m->type == MULTINAME) {
71         namespace_list_t*l = m->namespace_set->namespaces;
72         while(l) {
73             if(l->namespace->name &&
74                l->namespace->name[0])
75                 break;
76             l = l->next;
77         }
78         return mkid(l->namespace->name, m->name);
79     }
80     else {
81         fprintf(stderr, "can't convert multiname type %d\n", m->type);
82     }
83 }
84
85 static array_t*tosort=0;
86 static int compare_classes(const void*v1, const void*v2)
87 {
88     int x1 = *(int*)v1;
89     int x2 = *(int*)v2;
90     abc_class_t*c1 = array_getvalue(tosort, x1);
91     abc_class_t*c2 = array_getvalue(tosort, x2);
92     int i = strcmp(c1->classname->ns->name, c2->classname->ns->name);
93     if(i)
94         return i;
95     return strcmp(c1->classname->name, c2->classname->name);
96 }
97
98 static int compare_traits(const void*v1, const void*v2)
99 {
100     trait_t* x1 = *(trait_t**)v1;
101     trait_t* x2 = *(trait_t**)v2;
102     int i = strcmp(x1->name->ns->name, x2->name->ns->name);
103     if(i)
104         return i;
105     return strcmp(x1->name->name, x2->name->name);
106 }
107
108 char* kind2string(int kind)
109 {
110 }
111
112 void write_member_info(FILE*fi, char*parent, char*id2, const char*name, int flags, trait_t*trait)
113 {
114     char*retvalue = 0;
115     char*type="0";
116     switch(trait->kind) {
117         case TRAIT_METHOD: {
118             multiname_t*ret = trait->method->return_type;
119
120             if(!ret)
121                 retvalue = 0;
122             else
123                 retvalue = mkid(ret->ns->name, ret->name);
124             if(ret && !strcmp(ret->name, "void"))
125                 retvalue = 0;
126         } //fallthrough
127         case TRAIT_FUNCTION:
128             type = "MEMBER_METHOD";
129             break;
130         case TRAIT_CONST:
131         case TRAIT_GETTER:
132         case TRAIT_SETTER:
133         case TRAIT_SLOT:
134             type = "MEMBER_SLOT";
135             break;
136         default:
137             fprintf(stderr, "Unknown trait type %d\n", trait->kind);
138     }
139     fprintf(fi, "static memberinfo_t %s = {%s, 0x%02x, \"%s\"", id2, type, flags, name);
140     if(!retvalue)
141         fprintf(fi, ", 0");
142     else
143         fprintf(fi, ", &%s", retvalue);
144   
145     if(!parent) 
146         fprintf(fi, ", 0");
147     else
148         fprintf(fi, ", &%s", parent); // parent
149
150     fprintf(fi, ", 0,0,0};\n");
151 }
152
153 int access2flags(multiname_t*m)
154 {
155     int access = m->ns->access;
156     int flags=0;
157     if(access == ACCESS_PACKAGE) flags|=FLAG_PUBLIC;
158     if(access == ACCESS_PRIVATE) flags|=FLAG_PRIVATE;
159     if(access == ACCESS_PROTECTED) flags|=FLAG_PROTECTED;
160     if(access == ACCESS_PACKAGEINTERNAL) flags|=FLAG_PACKAGEINTERNAL;
161     if(access == ACCESS_NAMESPACE) {
162         if(!strcmp(m->ns->name, "http://adobe.com/AS3/2006/builtin")) {
163             flags|=FLAG_NAMESPACE_ADOBE;
164         }
165     }
166     return flags;
167 }
168
169 void load_libraries(char*filename, int pass, FILE*fi)
170 {
171     SWF swf;
172     memset(&swf, 0, sizeof(SWF));
173     TAG*tag = swf_InsertTag(0, ST_RAWABC);
174     memfile_t*file = memfile_open(filename);
175     tag->data = file->data;
176     tag->len = file->len;
177     abc_file_t*abc = swf_ReadABC(tag);
178     //swf_DumpABC(stdout, abc, "");
179
180     if(pass<=2) {
181         int*index = malloc(abc->classes->num*sizeof(int));
182         int t;
183         tosort=abc->classes;
184         for(t=0;t<abc->classes->num;t++) {index[t]=t;}
185         qsort(index, abc->classes->num, sizeof(int), compare_classes);
186
187         if(pass==-1) {
188             const char*last_package = "-*-";
189             for(t=0;t<abc->classes->num;t++) {
190                 abc_class_t*cls = array_getvalue(abc->classes, index[t]);
191                 const char*package = cls->classname->ns->name;
192                 char*pid = mkpid(package);
193                 if(strcmp(last_package, package)) {
194                     last_package = package;
195                     fprintf(fi, "static packageinfo_t %s = {\"%s\"};\n", pid, package);
196                 }
197             }
198         }
199
200         if(pass>=0)
201         for(t=0;t<abc->classes->num;t++) {
202             abc_class_t*cls = array_getvalue(abc->classes, index[t]);
203             int access = cls->classname->ns->access;
204             if(access==ACCESS_PRIVATE ||
205                access==ACCESS_PACKAGEINTERNAL)
206                 continue;
207             if(!strncmp(cls->classname->ns->name, "__AS3", 5))
208                 continue;
209
210             const char*package = cls->classname->ns->name;
211             const char*name = cls->classname->name;
212             const char*superpackage = 0;
213             const char*supername = 0;
214             char*superid = 0;
215             if(cls->superclass) {
216                 superpackage = cls->superclass->ns->name;
217                 supername = cls->superclass->name;
218                 superid = mkid(superpackage, supername);
219             }
220             char*id = mkid(package, name);
221             U8 flags = cls->flags;
222             
223             if(pass==0)  {
224                 fprintf(fi, "static classinfo_t %s;\n", id);
225             } else if(pass==1) {
226                 fprintf(fi, "static classinfo_t %s = {0x%02x, 0x%02x, \"%s\", \"%s\"", id, access, flags, package, name);
227                 fprintf(fi, ", (void*)0"); //slot
228                 if(superid)
229                     fprintf(fi, ", &%s, interfaces:{", superid);
230                 else
231                     fprintf(fi, ", (void*)0, interfaces:{");
232                 if(cls->interfaces) {
233                     multiname_list_t*i=cls->interfaces;
234                     while(i) {
235                         char*iid = mkid2(i->multiname);
236                         fprintf(fi, "&%s, ", iid);
237                         i = i->next;
238                     }
239                 }
240                 fprintf(fi, "(void*)0}};\n");
241             } else if(pass==2) {
242                 trait_list_t*l=cls->traits;
243                 fprintf(fi, "    dict_put(d, &%s, &%s);\n", id, id);
244                 fprintf(fi, "    dict_init(&%s.members, %d);\n", id, list_length(l)+1);
245             }
246
247           
248             trait_list_t*l=0;
249             char is_static = 0;
250             dict_t*d = dict_new();
251             l = cls->traits;
252             while(l) {
253                 trait_t*trait = l->trait;
254                 if(trait->name->ns->access==ACCESS_PRIVATE)
255                     goto cont;
256                 const char*name = trait->name->name;
257                 char id2[1024];
258                 sprintf(id2, "%s_%s", id, name);
259                 
260                 if(dict_lookup(d, name)) {
261                     goto cont;
262                 } else {
263                     dict_put(d, (char*)name, (char*)name);
264                 }
265                 int flags = is_static?FLAG_STATIC:0;
266                 //flags |= access2flags(access);
267                 flags |= access2flags(trait->name);
268
269                 if(pass==0) {
270                     fprintf(fi, "static memberinfo_t %s;\n", id2);
271                 } if(pass==1) {
272                     write_member_info(fi, id, id2, name, flags, trait);
273                 } else if(pass==2) {
274                     fprintf(fi, "    dict_put(&%s.members, \"%s\", &%s);\n", id, name, id2);
275                 }
276     cont:
277                 l = l->next;
278                 if(!l && !is_static) {
279                     l = cls->static_traits;
280                     is_static = 1;
281                 }
282             }
283             
284             dict_destroy(d);
285
286             if(id) free(id);
287             if(superid) free(superid);
288         }
289         free(index);
290     }
291
292     if(pass==0 || pass==1 || pass==3) {
293         int t;
294
295 #define IS_PUBLIC_MEMBER(trait) ((trait)->kind != TRAIT_CLASS)
296   
297         /* count public functions */
298         int num_methods=0;
299         for(t=0;t<abc->scripts->num;t++) {
300             trait_list_t*l = ((abc_script_t*)array_getvalue(abc->scripts, t))->traits;
301             for(;l;l=l->next) {
302                 num_methods += IS_PUBLIC_MEMBER(l->trait);
303             }
304         }
305         trait_t**traits = (trait_t**)malloc(num_methods*sizeof(trait_t*));
306         num_methods=0;
307         for(t=0;t<abc->scripts->num;t++) {
308             trait_list_t*l = ((abc_script_t*)array_getvalue(abc->scripts, t))->traits;
309             for(;l;l=l->next) {
310                 if(IS_PUBLIC_MEMBER(l->trait)) {
311                     traits[num_methods++] = l->trait;
312                 }
313             }
314         }
315         qsort(traits, num_methods, sizeof(trait_t*), compare_traits);
316         const char*last_package = "-xxx-";
317         for(t=0;t<num_methods;t++) {
318             trait_t*trait = traits[t];
319             if(IS_PUBLIC_MEMBER(trait)) {
320                 const char*package = trait->name->ns->name;
321                 const char*name = trait->name->name;
322                 char*pid = mkpid(package);
323                 char*id2 = mkid2(trait->name);
324                 int flags = FLAG_STATIC|access2flags(trait->name);
325                 NEW(memberinfo_t,m);
326                 char np = 0;
327                 int clsflags = FLAG_STATIC | FLAG_METHOD;
328                 if(pass==0) {
329                     fprintf(fi, "static memberinfo_t %s;\n", id2);
330                     fprintf(fi, "static classinfo_t %s_class;\n", id2);
331                 } else if(pass==1) {
332                     write_member_info(fi, 0, id2, name, flags, trait);
333                     fprintf(fi, "static classinfo_t %s_class = {0x%02x, 0x%02x, \"%s\", \"%s\", &%s, (void*)0, members:{(void*)0}};\n", 
334                             id2,
335                             trait->name->ns->access, clsflags,
336                             package, name, 
337                             id2);
338                 } else if(pass==3) {
339                     /*if(np) {
340                         fprintf(fi, "    dict_init(%s.classes, 1); //not used yet\n", pid);
341                         fprintf(fi, "    dict_init(%s.functions, 1);\n", pid);
342                     }
343                     fprintf(fi, "    dict_put(&%s.functions, \"%s\", &%s);\n", pid, name, id2);*/
344                     fprintf(fi, "    dict_put(d, &%s_class, &%s_class);\n", id2, id2);
345                 }
346             } else if(trait->kind == TRAIT_CLASS) {
347                 // ignore classes, these are treated above
348             } else {
349                 printf("%02x %s\n", trait->kind, multiname_tostring(trait->name));
350             }
351         }
352     }
353
354     swf_FreeABC(abc);
355     memfile_close(file);tag->data=0;
356     swf_DeleteTag(0, tag);
357 }
358
359 int main()
360 {
361     FILE*fi = fopen("builtin.c", "wb");
362     fprintf(fi, "#include \"builtin.h\"\n");
363
364     //load_libraries("builtin.abc", -1, fi);
365     //load_libraries("playerglobal.abc", -1, fi);
366     //fprintf(fi, "static packageinfo_t package_flash_debugger = {\"flash.debugger\"};\n");
367     //fprintf(fi, "static packageinfo_t package_flash_profiler = {\"flash.profiler\"};\n");
368
369     load_libraries("builtin.abc", 0, fi);
370     load_libraries("playerglobal.abc", 0, fi);
371     
372     load_libraries("builtin.abc", 1, fi);
373     load_libraries("playerglobal.abc", 1, fi);
374    
375     fprintf(fi, "dict_t* builtin_getclasses()\n");
376     fprintf(fi, "{\n");
377     fprintf(fi, "    dict_t*d = dict_new2(&classinfo_type);\n");
378     load_libraries("builtin.abc", 2, fi);
379     load_libraries("playerglobal.abc", 2, fi);
380     load_libraries("builtin.abc", 3, fi);
381     load_libraries("playerglobal.abc", 3, fi);
382     fprintf(fi, "    return d;\n");
383     fprintf(fi, "}\n");
384     fprintf(fi, "\n");
385     
386     //fprintf(fi, "dict_t* builtin_getglobalfunctions()\n");
387     //fprintf(fi, "{\n");
388     //fprintf(fi, "    dict_t*d = dict_new();\n");
389     //load_libraries("builtin.abc", 3, fi);
390     //load_libraries("playerglobal.abc", 3, fi);
391     //fprintf(fi, "    return d;\n");
392     //fprintf(fi, "}\n");
393
394     fclose(fi);
395 }