implemented asset resolving
[swftools.git] / lib / as3 / compiler.c
1 /* compiler.h
2
3    Compiler for parsing Flash2 AVM2 ABC Actionscript
4
5    Extension module for the rfxswf library.
6    Part of the swftools package.
7
8    Copyright (c) 2008/2009 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 "common.h"
25 #include "tokenizer.h"
26 #include "files.h"
27 #include "parser.h"
28 #include "parser.tab.h"
29 #include "compiler.h"
30 #include "registry.h"
31 #include "assets.h"
32 #include "../os.h"
33 #ifdef HAVE_SYS_STAT_H
34 #include <sys/stat.h>
35 #endif
36 #ifdef HAVE_DIRENT_H
37 #include <dirent.h>
38 #endif
39
40 /* flex/bison definitions */
41 extern int a3_parse();
42 extern int as3_lex();
43 extern int as3_lex_destroy();
44
45 static char config_recurse = 0;
46
47 void as3_setverbosity(int level)
48 {
49     as3_verbosity=level;
50 }
51 void as3_add_include_dir(char*dir)
52 {
53     add_include_dir(dir);
54 }
55 void as3_set_option(const char*key, const char*value)
56 {
57     if(!strcmp(key, "recurse")) {
58         config_recurse=atoi(value);
59     }
60 }
61
62 static char registry_initialized = 0;
63 static char parser_initialized = 0;
64
65 //#define STORE_TOKENS
66
67 //#define DEBUG
68 #define DEBUG if(0)
69
70 int a3_lex()
71 {
72     as3_tokencount++;
73     return as3_lex();
74 }
75
76 typedef struct _compile_list {
77     const char*name;
78     const char*filename;
79     struct _compile_list*next;
80 } compile_list_t;
81 static compile_list_t*compile_list=0;
82
83 static void as3_parse_file_or_array(const char*name, const char*filename, const void*mem, int length)
84 {
85     if(!registry_initialized) {
86         registry_initialized = 1;
87         registry_init();
88     }
89     if(!parser_initialized) {
90         parser_initialized = 1;
91         initialize_parser();
92     }
93
94     FILE*fi = 0;
95     if(filename) {
96         if(as3_pass==1 && !mem) {
97             // record the fact that we compiled this file
98             compile_list_t*c = rfx_calloc(sizeof(compile_list_t));
99             c->next = compile_list;
100             c->name = strdup(name);
101             c->filename = strdup(filename);
102             compile_list = c;
103         }
104         DEBUG printf("[pass %d] parse file %s %s\n", as3_pass, name, filename);
105         fi = enter_file2(name, filename, 0);
106         as3_file_input(fi);
107     } else {
108         DEBUG printf("[pass %d] parse bytearray %s (%d bytes)\n", as3_pass, name, length);
109         enter_file(name, name, 0);
110         as3_buffer_input((void*)mem, length);
111     }
112
113     as3_tokencount=0;
114     initialize_file(name, filename);
115     a3_parse();
116     as3_lex_destroy();
117     finish_file();
118     if(fi) fclose(fi);
119 }
120
121 typedef struct _scheduled_file {
122     char*name;
123     char*filename;
124     struct _scheduled_file*next;
125 } scheduled_file_t;
126
127 static scheduled_file_t*scheduled=0;
128 dict_t*scheduled_dict=0;
129
130 void as3_parse_scheduled()
131 {
132     DEBUG printf("[pass %d] parse scheduled\n", as3_pass);
133
134     while(scheduled) {
135         scheduled_file_t*s = scheduled;
136         scheduled = 0;
137         while(s) {
138             scheduled_file_t*old = s;
139             as3_parse_file_or_array(s->name, s->filename, 0,0);
140             s = s->next;
141
142             free(old->filename);
143             free(old->name);
144             old->filename = old->name = 0;
145             free(old);
146         }
147     }
148     if(scheduled_dict) {
149         dict_destroy(scheduled_dict);
150         scheduled_dict=0;
151     }
152 }
153
154 void as3_schedule_file(const char*name, const char*filename) 
155 {
156     if(!scheduled_dict) {
157         scheduled_dict = dict_new();
158     }
159
160     filename = normalize_path(filename);
161
162     if(dict_contains(scheduled_dict, filename)) {
163         return; //already processed
164     } else {
165         dict_put(scheduled_dict, filename, 0);
166     }
167     DEBUG printf("[pass %d] schedule %s %s\n", as3_pass, name, filename);
168
169     NEW(scheduled_file_t, f);
170     f->name = strdup(name);
171     f->filename = strdup(filename);
172     f->next = scheduled; // dfs
173     scheduled = f;
174 }
175
176 void as3_parse_list()
177 {
178     while(compile_list) {
179         as3_parse_file_or_array(compile_list->name, compile_list->filename, 0,0);
180         compile_list = compile_list->next;
181     }
182 }
183
184 void as3_parse_bytearray(const char*name, const void*mem, int length)
185 {
186     as3_pass = 1;
187     as3_parse_file_or_array(name, 0, mem, length);
188     as3_parse_scheduled();
189     
190     registry_resolve_all();
191     
192     as3_pass = 2;
193     as3_parse_file_or_array(name, 0, mem, length);
194     as3_parse_list();
195 }
196
197 void as3_parse_file(const char*filename) 
198 {
199     char*fullfilename = find_file(filename, 1);
200     if(!fullfilename)
201         return; // not found
202
203     compile_list = 0;
204     as3_pass = 1;
205     as3_schedule_file(filename, fullfilename);
206     as3_parse_scheduled();
207     
208     registry_resolve_all();
209
210     as3_pass = 2;
211     as3_parse_list();
212
213     free(fullfilename);
214 }
215
216 void as3_parse_directory(const char*dir)
217 {
218     compile_list = 0;
219
220     as3_pass = 1;
221     as3_schedule_directory(dir);
222     if(!scheduled)
223         as3_warning("Directory %s doesn't contain any ActionScript files", dir);
224     as3_parse_scheduled();
225
226     registry_resolve_all();
227
228     as3_pass = 2;
229     as3_parse_list();
230 }
231
232 char as3_schedule_directory(const char*dirname)
233 {
234     DEBUG printf("[pass %d] schedule directory %s\n", as3_pass, dirname);
235     char ok=0;
236 #ifdef HAVE_DIRENT_H
237     include_dir_t*i = current_include_dirs;
238     while(i) {
239         char*fulldirname = concat_paths(i->path, dirname);
240         DEBUG printf("[pass %d] ... %s\n", as3_pass, fulldirname);
241         DIR*dir = opendir(fulldirname);
242         if(dir) {
243             ok = 1;
244             struct dirent*ent;
245             while(1) {
246                 ent = readdir(dir);
247                 if (!ent) 
248                     break;
249                 char*name = ent->d_name;
250                 char type = 0;
251                 if(!name) continue;
252                 int l=strlen(name);
253                 if(l<4)
254                     continue;
255                 if(strncasecmp(&name[l-3], ".as", 3)) 
256                     continue;
257                 char*fullfilename = concatPaths(fulldirname, name);
258                 as3_schedule_file(name, fullfilename);
259                 free(fullfilename);
260             }
261         }
262         free(fulldirname);
263         i = i->next;
264     }
265 #endif
266     return ok;
267 }
268
269 void as3_schedule_package(const char*package)
270 {
271     DEBUG printf("[pass %d] schedule package %s\n", as3_pass, package);
272     char*dirname = strdup(package);
273     int s=0;
274     while(dirname[s]) {
275         if(dirname[s]=='.') 
276             dirname[s] = path_seperator;
277         s++;
278     };
279     if(!as3_schedule_directory(dirname))
280         as3_softwarning("Could not find package %s in file system", package);
281 }
282
283 static void schedule_class(const char*package, const char*cls, char error)
284 {
285     if(error) {
286         DEBUG printf("[pass %d] schedule class %s.%s\n",  as3_pass, package, cls);
287     }
288     if(!cls) {
289         as3_schedule_package(package);
290         return;
291     }
292     int l1 = package?strlen(package):0;
293     int l2 = cls?strlen(cls):0;
294     char*filename = malloc(l1+l2+5);
295     int s=0,t=0;
296     while(package[s]) {
297         if(package[s]=='.')
298             filename[t++]='/';
299         else
300             filename[t++] = package[s];
301         s++;
302     }
303     if(t)
304         filename[t++] = '/';
305
306     strcpy(filename+t, cls);
307     strcpy(filename+t+l2, ".as");
308     char*f=find_file(filename, error);
309     if(!f) {
310         int i;
311         filename = filename_to_lowercase(filename);
312         f=find_file(filename, error);
313     }
314     if(!f) {
315         if(error) {
316             strcpy(filename+t, cls);
317             strcpy(filename+t+l2, ".as");
318             as3_warning("Could not open file %s", filename);
319         }
320         return;
321     }
322     as3_schedule_file(filename, f);
323 }
324
325 void as3_schedule_class(const char*package, const char*cls)
326 {
327     schedule_class(package, cls, 1);
328 }
329
330 void as3_schedule_class_noerror(const char*package, const char*cls)
331 {
332     if(config_recurse) {
333         schedule_class(package, cls, 0);
334     }
335 }
336
337
338 static void*as3code = 0;
339 void* as3_getcode()
340 {
341     if(parser_initialized) {
342         parser_initialized = 0;
343         as3code = finish_parser();
344     }
345     return as3code;
346 }
347 void* as3_getassets(void*t)
348 {
349     return swf_AssetsToTags((TAG*)t, registry_getassets());
350 }
351 char* as3_getglobalclass()
352 {
353     return as3_globalclass;
354 }
355
356 void as3_destroy() 
357 {
358     if(parser_initialized) {
359         parser_initialized = 0;
360         swf_FreeABC(finish_parser());
361 #ifdef STORE_TOKENS
362         mem_clear(&tokens);
363 #endif
364     }
365     if(as3_globalclass) {
366         free(as3_globalclass);as3_globalclass=0;
367     }
368 }
369