$Id$ changes
[swftools.git] / lib / as3 / abc.c
1 /* abc.c
2
3    Routines for handling Flash2 AVM2 ABC Actionscript
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 <stdarg.h>
25 #include <assert.h>
26 #include "../rfxswf.h"
27 #include "../q.h"
28 #include "abc.h"
29
30 char stringbuffer[2048];
31
32 int abc_RegisterNameSpace(abc_file_t*file, const char*name);
33 int abc_RegisterPackageNameSpace(abc_file_t*file, const char*name);
34 int abc_RegisterPackageInternalNameSpace(abc_file_t*file, const char*name);
35 int abc_RegisterProtectedNameSpace(abc_file_t*file, const char*name);
36 int abc_RegisterExplicitNameSpace(abc_file_t*file, const char*name);
37 int abc_RegisterStaticProtectedNameSpace(abc_file_t*file, const char*name);
38 int abc_RegisterPrivateNameSpace(abc_file_t*file, const char*name);
39
40 /* TODO: switch to a datastructure with just values */
41 #define NO_KEY ""
42
43 static void params_dump(FILE*fo, multiname_list_t*l, constant_list_t*o)
44 {
45     int n = list_length(l);
46     int no = list_length(o);
47     int i = 0;
48
49     fprintf(fo, "(");
50     while(l) {
51         char*s = multiname_tostring(l->multiname);
52         fprintf(fo, s);
53         free(s);
54         if(i>=n-no) {
55             s = constant_tostring(o->constant);
56             fprintf(fo, " = ");
57             fprintf(fo, s);
58             free(s);
59             o = o->next;
60         }
61
62         if(l->next)
63             fprintf(fo, ", ");
64         l = l->next;i++;
65     }
66     fprintf(fo, ")");
67 }
68
69 //#define DEBUG
70 #define DEBUG if(0)
71
72 static void parse_metadata(TAG*tag, abc_file_t*file, pool_t*pool)
73 {
74     int t;
75     int num_metadata = swf_GetU30(tag);
76
77     DEBUG printf("%d metadata\n");
78     for(t=0;t<num_metadata;t++) {
79         const char*entry_name = pool_lookup_string(pool, swf_GetU30(tag));
80         int num = swf_GetU30(tag);
81         int s;
82         DEBUG printf("  %s\n", entry_name);
83         array_t*items = array_new();
84         for(s=0;s<num;s++) {
85             int i1 = swf_GetU30(tag);
86             int i2 = swf_GetU30(tag);
87             const char*key = i1?pool_lookup_string(pool, i1):"";
88             const char*value = i2?pool_lookup_string(pool, i2):"";
89             DEBUG printf("    %s=%s\n", key, value);
90             array_append(items, key, strdup(value));
91         }
92         array_append(file->metadata, entry_name, items);
93     }
94 }
95
96 void swf_CopyData(TAG*to, TAG*from, int len)
97 {
98     unsigned char*data = malloc(len);
99     swf_GetBlock(from, data, len);
100     swf_SetBlock(to, data, len);
101     free(data);
102 }
103
104 abc_file_t*abc_file_new()
105 {
106     abc_file_t*f = malloc(sizeof(abc_file_t));
107     memset(f, 0, sizeof(abc_file_t));
108     f->metadata = array_new();
109
110     f->methods = array_new();
111     f->classes = array_new();
112     f->scripts = array_new();
113     f->method_bodies = array_new();
114     f->flags = ABCFILE_LAZY;
115
116     return f;
117 }
118
119 abc_class_t* abc_class_new(abc_file_t*file, multiname_t*classname, multiname_t*superclass) {
120     
121     NEW(abc_class_t,c);
122     array_append(file->classes, NO_KEY, c);
123
124     c->file = file;
125     c->classname = multiname_clone(classname);
126     c->superclass = multiname_clone(superclass);
127     c->flags = 0;
128     c->constructor = 0;
129     c->static_constructor = 0;
130     c->traits = list_new();
131     return c;
132 }
133 abc_class_t* abc_class_new2(abc_file_t*pool, char*classname, char*superclass) 
134 {
135     return abc_class_new(pool, multiname_fromstring(classname), multiname_fromstring(superclass));
136 }
137
138 void abc_class_sealed(abc_class_t*c)
139 {
140     c->flags |= CLASS_SEALED;
141 }
142 void abc_class_final(abc_class_t*c)
143 {
144     c->flags |= CLASS_FINAL;
145 }
146 void abc_class_interface(abc_class_t*c)
147 {
148     c->flags |= CLASS_INTERFACE;
149 }
150 void abc_class_protectedNS(abc_class_t*c, char*namespace)
151 {
152     c->protectedNS = namespace_new_protected(namespace);
153     c->flags |= CLASS_PROTECTED_NS;
154 }
155 void abc_class_add_interface(abc_class_t*c, multiname_t*interface)
156 {
157     list_append(c->interfaces, multiname_clone(interface));
158 }
159
160 abc_method_t* abc_method_new(abc_file_t*file, multiname_t*returntype, char body)
161 {
162     /* construct method object */
163     NEW(abc_method_t,m);
164     m->index = array_length(file->methods);
165     array_append(file->methods, NO_KEY, m);
166     m->return_type = returntype;
167
168     if(body) {
169         /* construct code (method body) object */
170         NEW(abc_method_body_t,c);
171         array_append(file->method_bodies, NO_KEY, c);
172         c->index = array_length(file->method_bodies);
173         c->file = file;
174         c->traits = list_new();
175         c->code = 0;
176
177         /* crosslink the two objects */
178         m->body = c;
179         c->method = m;
180     }
181
182     return m;
183 }
184
185 abc_method_t* abc_class_getconstructor(abc_class_t*cls, multiname_t*returntype)
186 {
187     if(cls->constructor) {
188         return cls->constructor;
189     }
190     abc_method_t* m = abc_method_new(cls->file, returntype, 1);
191     cls->constructor = m;
192     return m;
193 }
194
195 abc_method_t* abc_class_getstaticconstructor(abc_class_t*cls, multiname_t*returntype)
196 {
197     if(cls->static_constructor) {
198         return cls->static_constructor;
199     }
200     abc_method_t* m = abc_method_new(cls->file, returntype, 1);
201     cls->static_constructor = m;
202     return m;
203 }
204
205 trait_t*trait_new(int type, multiname_t*name, int data1, int data2, constant_t*v)
206 {
207     trait_t*trait = malloc(sizeof(trait_t));
208     memset(trait, 0, sizeof(trait_t));
209     trait->kind = type&0x0f;
210     trait->attributes = type&0xf0;
211     trait->name = name;
212     trait->data1 = data1;
213     trait->data2 = data2;
214     trait->value = v;
215     return trait;
216 }
217
218 trait_t*trait_new_member(trait_list_t**traits, multiname_t*type, multiname_t*name,constant_t*v)
219 {
220     int kind = TRAIT_SLOT;
221     trait_t*trait = malloc(sizeof(trait_t));
222     memset(trait, 0, sizeof(trait_t));
223     trait->kind = kind&0x0f;
224     trait->attributes = kind&0xf0;
225     trait->name = name;
226     trait->type_name = type;
227    
228     trait->slot_id = list_length(*traits)+1;
229     trait_list_t*l = *traits;
230     list_append_(traits, trait);
231     return trait;
232 }
233 trait_t*trait_new_method(trait_list_t**traits, multiname_t*name, abc_method_t*m)
234 {
235     int type = TRAIT_METHOD;
236     trait_t*trait = malloc(sizeof(trait_t));
237     memset(trait, 0, sizeof(trait_t));
238     trait->kind = type&0x0f;
239     trait->attributes = type&0xf0;
240     trait->name = name;
241     trait->method = m;
242     
243     /* start assigning traits at position #1.
244        Weird things happen when assigning slot 0- slot 0 and 1 seem
245        to be identical */
246     trait->slot_id = list_length(*traits)+1;
247     list_append_(traits, trait);
248     return trait;
249 }
250
251 abc_method_t* abc_class_method(abc_class_t*cls, multiname_t*returntype, multiname_t*name)
252 {
253     abc_file_t*file = cls->file;
254     abc_method_t* m = abc_method_new(cls->file, returntype, !(cls->flags&CLASS_INTERFACE));
255     m->trait = trait_new_method(&cls->traits, multiname_clone(name), m);
256     return m;
257 }
258 abc_method_t* abc_class_staticmethod(abc_class_t*cls, multiname_t*returntype, multiname_t*name)
259 {
260     abc_file_t*file = cls->file;
261     abc_method_t* m = abc_method_new(cls->file, returntype, !(cls->flags&CLASS_INTERFACE));
262     m->trait = trait_new_method(&cls->static_traits, multiname_clone(name), m);
263     return m;
264 }
265
266 trait_t* abc_class_slot(abc_class_t*cls, multiname_t*name, multiname_t*type)
267 {
268     abc_file_t*file = cls->file;
269     multiname_t*m_name = multiname_clone(name);
270     multiname_t*m_type = multiname_clone(type);
271     trait_t*t = trait_new_member(&cls->traits, m_type, m_name, 0);
272     return t;
273 }
274 trait_t* abc_class_staticslot(abc_class_t*cls, multiname_t*name, multiname_t*type)
275 {
276     abc_file_t*file = cls->file;
277     multiname_t*m_name = multiname_clone(name);
278     multiname_t*m_type = multiname_clone(type);
279     trait_t*t = trait_new_member(&cls->static_traits, m_type, m_name, 0);
280     return t;
281 }
282
283
284 trait_t* abc_class_find_slotid(abc_class_t*cls, int slotid)
285 {
286     trait_list_t*l;
287     trait_t*t=0;
288     for(l=cls->traits;l;l=l->next) {
289         if(l->trait->slot_id==slotid) {
290             t=l->trait; 
291             break;
292         }
293     }
294     return t;
295 }
296
297 void abc_method_body_addClassTrait(abc_method_body_t*code, char*multiname, int slotid, abc_class_t*cls)
298 {
299     abc_file_t*file = code->file;
300     multiname_t*m = multiname_fromstring(multiname);
301     trait_t*trait = trait_new(TRAIT_CLASS, m, slotid, 0, 0);
302     trait->cls = cls;
303     list_append(code->traits, trait);
304 }
305
306 /* notice: traits of a method (body) belonging to an init script
307    and traits of the init script are *not* the same thing */
308 int abc_initscript_addClassTrait(abc_script_t*script, multiname_t*multiname, abc_class_t*cls)
309 {
310     abc_file_t*file = script->file;
311     multiname_t*m = multiname_clone(multiname);
312     int slotid = list_length(script->traits)+1;
313     trait_t*trait = trait_new(TRAIT_CLASS, m, slotid, 0, 0);
314     trait->cls = cls;
315     list_append(script->traits, trait);
316     return slotid;
317 }
318
319 abc_script_t* abc_initscript(abc_file_t*file)
320 {
321     abc_method_t*m = abc_method_new(file, 0, 1);
322     abc_script_t* s = malloc(sizeof(abc_script_t));
323     s->method = m;
324     s->traits = list_new();
325     s->file = file;
326     array_append(file->scripts, NO_KEY, s);
327     return s;
328 }
329
330 static void traits_dump(FILE*fo, const char*prefix, trait_list_t*traits, abc_file_t*file, dict_t*methods_seen);
331
332 static void dump_method(FILE*fo, const char*prefix, 
333                                  const char*attr, 
334                                  const char*type, 
335                                  const char*name, 
336                                  abc_method_t*m, abc_file_t*file, dict_t*methods_seen)
337 {
338     if(methods_seen)
339         dict_put(methods_seen, m, 0);
340
341     char*return_type = 0;
342     if(m->return_type)
343         return_type = multiname_tostring(m->return_type);
344     else
345         return_type = strdup("void");
346
347     fprintf(fo, "%s", prefix);
348     fprintf(fo, "%s %s", attr, type);
349     fprintf(fo, "%s %s=%s", return_type, name, m->name);
350     params_dump(fo, m->parameters, m->optional_parameters);
351     fprintf(fo, "(%d params, %d optional)\n", list_length(m->parameters), list_length(m->optional_parameters));
352
353     free(return_type);return_type=0;
354
355     abc_method_body_t*c = m->body;
356     if(!c) {
357         return;
358     }
359     
360     fprintf(fo, "%s[stack:%d locals:%d scope:%d-%d flags:", 
361             prefix, c->old.max_stack, c->old.local_count, c->old.init_scope_depth, 
362             c->old.max_scope_depth);
363
364
365     int flags = c->method->flags;
366     if(flags&METHOD_NEED_ARGUMENTS) {fprintf(fo, " need_arguments");flags&=~METHOD_NEED_ARGUMENTS;}
367     if(flags&METHOD_NEED_ACTIVATION) {fprintf(fo, " need_activation");flags&=~METHOD_NEED_ACTIVATION;}
368     if(flags&METHOD_NEED_REST) {fprintf(fo, " need_rest");flags&=~METHOD_NEED_REST;}
369     if(flags&METHOD_HAS_OPTIONAL) {fprintf(fo, " has_optional");flags&=~METHOD_HAS_OPTIONAL;}
370     if(flags&METHOD_SET_DXNS) {fprintf(fo, " set_dxns");flags&=~METHOD_SET_DXNS;}
371     if(flags&METHOD_HAS_PARAM_NAMES) {fprintf(fo, " has_param_names");flags&=~METHOD_HAS_PARAM_NAMES;}
372     if(flags) fprintf(fo, " %02x", flags);
373     fprintf(fo, "]");
374
375     if(m->trait) {
376         fprintf(fo, " slot:%d", m->trait->slot_id);
377     }
378     fprintf(fo, "\n");
379
380
381     char prefix2[80];
382     sprintf(prefix2, "%s    ", prefix);
383     if(c->traits)
384         traits_dump(fo, prefix, c->traits, file, methods_seen);
385     fprintf(fo, "%s{\n", prefix);
386     code_dump2(c->code, c->exceptions, file, prefix2, fo);
387     fprintf(fo, "%s}\n\n", prefix);
388 }
389
390 static void traits_free(trait_list_t*traits) 
391 {
392     trait_list_t*t = traits;
393     while(t) {
394         if(t->trait->name) {
395             multiname_destroy(t->trait->name);t->trait->name = 0;
396         }
397         if(t->trait->kind == TRAIT_SLOT || t->trait->kind == TRAIT_CONST) {
398             multiname_destroy(t->trait->type_name);
399         }
400         if(t->trait->value) {
401             constant_free(t->trait->value);t->trait->value = 0;
402         }
403         free(t->trait);t->trait = 0;
404         t = t->next;
405     }
406     list_free(traits);
407 }
408             
409 static char trait_is_method(trait_t*trait)
410 {
411     return (trait->kind == TRAIT_METHOD || trait->kind == TRAIT_GETTER || 
412             trait->kind == TRAIT_SETTER || trait->kind == TRAIT_FUNCTION);
413 }
414
415 static trait_list_t* traits_parse(TAG*tag, pool_t*pool, abc_file_t*file)
416 {
417     int num_traits = swf_GetU30(tag);
418     trait_list_t*traits = list_new();
419     int t;
420     if(num_traits) {
421         DEBUG printf("%d traits\n", num_traits);
422     }
423     
424     for(t=0;t<num_traits;t++) {
425         NEW(trait_t,trait);
426         list_append(traits, trait);
427
428         trait->name = multiname_clone(pool_lookup_multiname(pool, swf_GetU30(tag))); // always a QName (ns,name)
429
430         const char*name = 0;
431         DEBUG name = multiname_tostring(trait->name);
432         U8 kind = swf_GetU8(tag);
433         U8 attributes = kind&0xf0;
434         kind&=0x0f;
435         trait->kind = kind;
436         trait->attributes = attributes;
437         DEBUG printf("  trait %d) %s type=%02x\n", t, name, kind);
438         if(kind == TRAIT_METHOD || kind == TRAIT_GETTER || kind == TRAIT_SETTER) { // method / getter / setter
439             trait->disp_id = swf_GetU30(tag);
440             trait->method = (abc_method_t*)array_getvalue(file->methods, swf_GetU30(tag));
441             trait->method->trait = trait;
442             DEBUG printf("  method/getter/setter\n");
443         } else if(kind == TRAIT_FUNCTION) { // function
444             trait->slot_id =  swf_GetU30(tag);
445             trait->method = (abc_method_t*)array_getvalue(file->methods, swf_GetU30(tag));
446             trait->method->trait = trait;
447         } else if(kind == TRAIT_CLASS) { // class
448             trait->slot_id = swf_GetU30(tag);
449             trait->cls = (abc_class_t*)array_getvalue(file->classes, swf_GetU30(tag));
450             DEBUG printf("  class %s %d %d\n", name, trait->slot_id, trait->cls);
451         } else if(kind == TRAIT_SLOT || kind == TRAIT_CONST) { // slot, const
452             trait->slot_id = swf_GetU30(tag);
453             trait->type_name = multiname_clone(pool_lookup_multiname(pool, swf_GetU30(tag)));
454             int vindex = swf_GetU30(tag);
455             if(vindex) {
456                 int vkind = swf_GetU8(tag);
457                 trait->value = constant_fromindex(pool, vindex, vkind);
458             }
459             DEBUG printf("  slot %s %d %s (%s)\n", name, trait->slot_id, trait->type_name->name, constant_tostring(trait->value));
460         } else {
461             fprintf(stderr, "Can't parse trait type %d\n", kind);
462         }
463         if(attributes&0x40) {
464             int num = swf_GetU30(tag);
465             int s;
466             for(s=0;s<num;s++) {
467                 swf_GetU30(tag); //index into metadata array
468             }
469         }
470     }
471     return traits;
472 }
473
474 void traits_skip(TAG*tag)
475 {
476     int num_traits = swf_GetU30(tag);
477     int t;
478     for(t=0;t<num_traits;t++) {
479         swf_GetU30(tag);
480         U8 kind = swf_GetU8(tag);
481         U8 attributes = kind&0xf0;
482         kind&=0x0f;
483         swf_GetU30(tag);
484         swf_GetU30(tag);
485         if(kind == TRAIT_SLOT || kind == TRAIT_CONST) {
486             if(swf_GetU30(tag)) swf_GetU8(tag);
487         } else if(kind>TRAIT_CONST) {
488             fprintf(stderr, "Can't parse trait type %d\n", kind);
489         }
490         if(attributes&0x40) {
491             int s, num = swf_GetU30(tag);
492             for(s=0;s<num;s++) swf_GetU30(tag);
493         }
494     }
495 }
496
497
498 static void traits_write(pool_t*pool, TAG*tag, trait_list_t*traits)
499 {
500     if(!traits) {
501         swf_SetU30(tag, 0);
502         return;
503     }
504     swf_SetU30(tag, list_length(traits));
505     int s;
506
507     while(traits) {
508         trait_t*trait = traits->trait;
509
510         swf_SetU30(tag, pool_register_multiname(pool, trait->name));
511         swf_SetU8(tag, trait->kind|trait->attributes);
512
513         swf_SetU30(tag, trait->data1);
514
515         if(trait->kind == TRAIT_CLASS) {
516             swf_SetU30(tag, trait->cls->index);
517         } else if(trait->kind == TRAIT_GETTER ||
518                   trait->kind == TRAIT_SETTER ||
519                   trait->kind == TRAIT_METHOD) {
520             swf_SetU30(tag, trait->method->index);
521         } else if(trait->kind == TRAIT_SLOT ||
522                   trait->kind == TRAIT_CONST) {
523             int index = pool_register_multiname(pool, trait->type_name);
524             swf_SetU30(tag, index);
525         } else  {
526             swf_SetU30(tag, trait->data2);
527         }
528
529         if(trait->kind == TRAIT_SLOT || trait->kind == TRAIT_CONST) {
530             int vindex = constant_get_index(pool, trait->value);
531             swf_SetU30(tag, vindex);
532             if(vindex) {
533                 swf_SetU8(tag, trait->value->type);
534             }
535         }
536         if(trait->attributes&0x40) {
537             // metadata
538             swf_SetU30(tag, 0);
539         }
540         traits = traits->next;
541     }
542 }
543
544
545 static void traits_dump(FILE*fo, const char*prefix, trait_list_t*traits, abc_file_t*file, dict_t*methods_seen)
546 {
547     int t;
548     while(traits) {
549         trait_t*trait = traits->trait;
550         char*name = multiname_tostring(trait->name);
551         U8 kind = trait->kind;
552         U8 attributes = trait->attributes;
553
554         char a = attributes & (TRAIT_ATTR_OVERRIDE|TRAIT_ATTR_FINAL);
555         char* type = "";
556         if(a==TRAIT_ATTR_FINAL)
557             type = "final ";
558         else if(a==TRAIT_ATTR_OVERRIDE)
559             type = "override ";
560         else if(a==(TRAIT_ATTR_OVERRIDE|TRAIT_ATTR_FINAL))
561             type = "final override ";
562         
563         if(attributes&TRAIT_ATTR_METADATA)
564             fprintf(fo, "<metadata>");
565
566         if(kind == TRAIT_METHOD) {
567             abc_method_t*m = trait->method;
568             dump_method(fo, prefix, type, "method", name, m, file, methods_seen);
569         } else if(kind == TRAIT_GETTER) {
570             abc_method_t*m = trait->method;
571             dump_method(fo, prefix, type, "getter", name, m, file, methods_seen);
572         } else if(kind == TRAIT_SETTER) {
573             abc_method_t*m = trait->method;
574             dump_method(fo, prefix, type, "setter", name, m, file, methods_seen);
575         } else if(kind == TRAIT_FUNCTION) { // function
576             abc_method_t*m = trait->method;
577             dump_method(fo, prefix, type, "function", name, m, file, methods_seen);
578         } else if(kind == TRAIT_CLASS) { // class
579             abc_class_t*cls = trait->cls;
580             if(!cls) {
581                 fprintf(fo, "%sslot %d: class %s=00000000\n", prefix, trait->slot_id, name);
582             } else {
583                 fprintf(fo, "%sslot %d: class %s=%s\n", prefix, trait->slot_id, name, cls->classname->name);
584             }
585         } else if(kind == TRAIT_SLOT || kind == TRAIT_CONST) { // slot, const
586             int slot_id = trait->slot_id;
587             char*type_name = multiname_tostring(trait->type_name);
588             char*value = constant_tostring(trait->value);
589             fprintf(fo, "%sslot %d: %s %s:%s %s %s\n", prefix, trait->slot_id, 
590                     kind==TRAIT_CONST?"const":"var", name, type_name, 
591                     value?"=":"", value?value:"");
592             if(value) free(value);
593             free(type_name);
594         } else {
595             fprintf(fo, "%s    can't dump trait type %d\n", prefix, kind);
596         }
597         free(name);
598         traits=traits->next;
599     }
600 }
601
602 void* swf_DumpABC(FILE*fo, void*code, char*prefix)
603 {
604     abc_file_t* file = (abc_file_t*)code;
605
606     if(file->name) {
607         fprintf(fo, "%s#\n", prefix);
608         fprintf(fo, "%s#name: %s\n", prefix, file->name);
609         fprintf(fo, "%s#\n", prefix);
610     }
611
612     int t;
613     for(t=0;t<file->metadata->num;t++) {
614         const char*entry_name = array_getkey(file->metadata, t);
615         fprintf(fo, "%s#Metadata \"%s\":\n", prefix, entry_name);
616         int s;
617         array_t*items = (array_t*)array_getvalue(file->metadata, t);
618         for(s=0;s<items->num;s++) {
619             fprintf(fo, "%s#  %s=%s\n", prefix, array_getkey(items, s), array_getvalue(items,s));
620         }
621         fprintf(fo, "%s#\n", prefix);
622     }
623
624     dict_t*methods_seen = dict_new2(&ptr_type);
625     for(t=0;t<file->classes->num;t++) {
626         abc_class_t*cls = (abc_class_t*)array_getvalue(file->classes, t);
627         char prefix2[80];
628         sprintf(prefix2, "%s    ", prefix);
629
630         fprintf(fo, "%s", prefix);
631         if(cls->flags&1) fprintf(fo, "sealed ");
632         if(cls->flags&2) fprintf(fo, "final ");
633         if(cls->flags&4) fprintf(fo, "interface ");
634         if(cls->flags&8) {
635             char*s = namespace_tostring(cls->protectedNS);
636             fprintf(fo, "protectedNS(%s) ", s);
637             free(s);
638         }
639
640         char*classname = multiname_tostring(cls->classname);
641         fprintf(fo, "class %s", classname);
642         free(classname);
643         if(cls->superclass) {
644             char*supername = multiname_tostring(cls->superclass);
645             fprintf(fo, " extends %s", supername);
646             free(supername);
647             multiname_list_t*ilist = cls->interfaces;
648             if(ilist)
649                 fprintf(fo, " implements");
650             while(ilist) {
651                 char*s = multiname_tostring(ilist->multiname);
652                 fprintf(fo, " %s", s);
653                 free(s);
654                 ilist = ilist->next;
655             }
656             ilist->next;
657         }
658         if(cls->flags&0xf0) 
659             fprintf(fo, "extra flags=%02x\n", cls->flags&0xf0);
660         fprintf(fo, "%s{\n", prefix);
661
662         dict_put(methods_seen, cls->static_constructor, 0);
663         dict_put(methods_seen, cls->constructor, 0);
664
665         if(cls->static_constructor) {
666             dump_method(fo, prefix2, "", "staticconstructor", "", cls->static_constructor, file, methods_seen);
667         }
668         traits_dump(fo, prefix2, cls->static_traits, file, methods_seen);
669         
670         char*n = multiname_tostring(cls->classname);
671         if(cls->constructor)
672             dump_method(fo, prefix2, "", "constructor", n, cls->constructor, file, methods_seen);
673         free(n);
674         traits_dump(fo, prefix2,cls->traits, file, methods_seen);
675         fprintf(fo, "%s}\n", prefix);
676     }
677     fprintf(fo, "%s\n", prefix);
678
679     for(t=0;t<file->scripts->num;t++) {
680         abc_script_t*s = (abc_script_t*)array_getvalue(file->scripts, t);
681         dump_method(fo, prefix, "", "initmethod", "init", s->method, file, methods_seen);
682         traits_dump(fo, prefix, s->traits, file, methods_seen);
683     }
684     
685     char extra=0;
686     for(t=0;t<file->methods->num;t++) {
687         abc_method_t*m = (abc_method_t*)array_getvalue(file->methods, t);
688         if(!dict_contains(methods_seen, m)) {
689             if(!extra) {
690                 extra=1;
691                 fprintf(fo, "\n");
692                 fprintf(fo, "%s//internal (non-class non-script) methods:\n", prefix);
693             }
694             char name[18];
695             sprintf(name, "%08x ", m->index);
696             dump_method(fo, prefix, "", "internalmethod", name, m, file, methods_seen);
697         }
698     }
699     dict_destroy(methods_seen);
700
701     return file;
702 }
703
704 void* swf_ReadABC(TAG*tag)
705 {
706     abc_file_t* file = abc_file_new();
707     pool_t*pool = pool_new();
708
709     swf_SetTagPos(tag, 0);
710     int t;
711     if(tag->id == ST_DOABC) {
712         U32 abcflags = swf_GetU32(tag);
713         DEBUG printf("flags=%08x\n", abcflags);
714         char*name= swf_GetString(tag);
715         file->name = (name&&name[0])?strdup(name):0;
716     }
717     U32 version = swf_GetU32(tag);
718     if(version!=0x002e0010) {
719         fprintf(stderr, "Warning: unknown AVM2 version %08x\n", version);
720     }
721
722     pool_read(pool, tag);
723     //pool_dump(pool, stdout);
724
725     int num_methods = swf_GetU30(tag);
726     DEBUG printf("%d methods\n", num_methods);
727     for(t=0;t<num_methods;t++) {
728         NEW(abc_method_t,m);
729         int param_count = swf_GetU30(tag);
730         int return_type_index = swf_GetU30(tag);
731         if(return_type_index)
732             m->return_type = multiname_clone(pool_lookup_multiname(pool, return_type_index));
733         else
734             m->return_type = 0;
735
736         int s;
737         for(s=0;s<param_count;s++) {
738             int type_index = swf_GetU30(tag);
739             
740             /* type_index might be 0, which probably means "..." (varargs) */
741             multiname_t*param = type_index?multiname_clone(pool_lookup_multiname(pool, type_index)):0;
742             list_append(m->parameters, param);
743         }
744
745         int namenr = swf_GetU30(tag);
746         if(namenr)
747             m->name = strdup(pool_lookup_string(pool, namenr));
748         else
749             m->name = strdup("");
750
751         m->flags = swf_GetU8(tag);
752         
753         DEBUG printf("method %d) %s ", m->name);
754         DEBUG params_dump(stdout, m->parameters, m->optional_parameters);
755         DEBUG printf("flags=%02x\n", t, m->flags);
756
757         if(m->flags&0x08) {
758             m->optional_parameters = list_new();
759             int num = swf_GetU30(tag);
760             int s;
761             for(s=0;s<num;s++) {
762                 int vindex = swf_GetU30(tag);
763                 U8 vkind = swf_GetU8(tag); // specifies index type for "val"
764                 constant_t*c = constant_fromindex(pool, vindex, vkind);
765                 list_append(m->optional_parameters, c);
766
767             }
768         }
769         if(m->flags&0x80) {
770             /* debug information- not used by avm2 */
771             multiname_list_t*l = m->parameters;
772             while(l) {
773                 const char*name = pool_lookup_string(pool, swf_GetU30(tag));
774                 l = l->next;
775             }
776         }
777         m->index = array_length(file->methods);
778         array_append(file->methods, NO_KEY, m);
779     }
780             
781     parse_metadata(tag, file, pool);
782         
783     /* skip classes, and scripts for now, and do the real parsing later */
784     int num_classes = swf_GetU30(tag);
785     int classes_pos = tag->pos;
786     DEBUG printf("%d classes\n", num_classes);
787     for(t=0;t<num_classes;t++) {
788         abc_class_t*cls = malloc(sizeof(abc_class_t));
789         memset(cls, 0, sizeof(abc_class_t));
790         
791         swf_GetU30(tag); //classname
792         swf_GetU30(tag); //supername
793
794         array_append(file->classes, NO_KEY, cls);
795
796         cls->flags = swf_GetU8(tag);
797         DEBUG printf("class %d %02x\n", t, cls->flags);
798         if(cls->flags&8) 
799             swf_GetU30(tag); //protectedNS
800         int s;
801         int inum = swf_GetU30(tag); //interface count
802         cls->interfaces = 0;
803         for(s=0;s<inum;s++) {
804             int interface_index = swf_GetU30(tag);
805             multiname_t* m = multiname_clone(pool_lookup_multiname(pool, interface_index));
806             list_append(cls->interfaces, m);
807             DEBUG printf("  class %d interface: %s\n", t, m->name);
808         }
809
810         int iinit = swf_GetU30(tag); //iinit
811         DEBUG printf("--iinit-->%d\n", iinit);
812         traits_skip(tag);
813     }
814     for(t=0;t<num_classes;t++) {
815         abc_class_t*cls = (abc_class_t*)array_getvalue(file->classes, t);
816         int cinit = swf_GetU30(tag);
817         DEBUG printf("--cinit(%d)-->%d\n", t, cinit);
818         cls->static_constructor = (abc_method_t*)array_getvalue(file->methods, cinit);
819         traits_skip(tag);
820     }
821     int num_scripts = swf_GetU30(tag);
822     DEBUG printf("%d scripts\n", num_scripts);
823     for(t=0;t<num_scripts;t++) {
824         int init = swf_GetU30(tag);
825         traits_skip(tag);
826     }
827
828     int num_method_bodies = swf_GetU30(tag);
829     DEBUG printf("%d method bodies\n", num_method_bodies);
830     for(t=0;t<num_method_bodies;t++) {
831         int methodnr = swf_GetU30(tag);
832         if(methodnr >= file->methods->num) {
833             printf("Invalid method number: %d\n", methodnr);
834             return 0;
835         }
836         abc_method_t*m = (abc_method_t*)array_getvalue(file->methods, methodnr);
837         abc_method_body_t*c = malloc(sizeof(abc_method_body_t));
838         memset(c, 0, sizeof(abc_method_body_t));
839         c->old.max_stack = swf_GetU30(tag);
840         c->old.local_count = swf_GetU30(tag);
841         c->old.init_scope_depth = swf_GetU30(tag);
842         c->old.max_scope_depth = swf_GetU30(tag);
843
844         c->init_scope_depth = c->old.init_scope_depth;
845         int code_length = swf_GetU30(tag);
846
847         c->method = m;
848         m->body = c;
849
850         int pos = tag->pos + code_length;
851         codelookup_t*codelookup = 0;
852         c->code = code_parse(tag, code_length, file, pool, &codelookup);
853         tag->pos = pos;
854
855         int exception_count = swf_GetU30(tag);
856         int s;
857         c->exceptions = list_new();
858         for(s=0;s<exception_count;s++) {
859             abc_exception_t*e = malloc(sizeof(abc_exception_t));
860
861             e->from = code_atposition(codelookup, swf_GetU30(tag));
862             e->to = code_atposition(codelookup, swf_GetU30(tag));
863             e->target = code_atposition(codelookup, swf_GetU30(tag));
864
865             e->exc_type = multiname_clone(pool_lookup_multiname(pool, swf_GetU30(tag)));
866             e->var_name = multiname_clone(pool_lookup_multiname(pool, swf_GetU30(tag)));
867             //e->var_name = pool_lookup_string(pool, swf_GetU30(tag));
868             //if(e->var_name) e->var_name = strdup(e->var_name);
869             list_append(c->exceptions, e);
870         }
871         codelookup_free(codelookup);
872         c->traits = traits_parse(tag, pool, file);
873
874         DEBUG printf("method_body %d) (method %d), %d bytes of code\n", t, methodnr, code_length);
875
876         array_append(file->method_bodies, NO_KEY, c);
877     }
878     if(tag->len - tag->pos) {
879         fprintf(stderr, "%d unparsed bytes remaining in ABC block\n", tag->len - tag->pos);
880         return 0;
881     }
882
883     swf_SetTagPos(tag, classes_pos);
884     for(t=0;t<num_classes;t++) {
885         abc_class_t*cls = (abc_class_t*)array_getvalue(file->classes, t);
886
887         int classname_index = swf_GetU30(tag);
888         int superclass_index = swf_GetU30(tag);
889         cls->classname = multiname_clone(pool_lookup_multiname(pool, classname_index));
890         cls->superclass = multiname_clone(pool_lookup_multiname(pool, superclass_index));
891         cls->flags = swf_GetU8(tag);
892         const char*ns = "";
893         if(cls->flags&8) {
894             int ns_index = swf_GetU30(tag);
895             cls->protectedNS = namespace_clone(pool_lookup_namespace(pool, ns_index));
896         }
897         
898         int num_interfaces = swf_GetU30(tag); //interface count
899         int s;
900         for(s=0;s<num_interfaces;s++) {
901             swf_GetU30(tag);
902         }
903         int iinit = swf_GetU30(tag);
904         cls->constructor = (abc_method_t*)array_getvalue(file->methods, iinit);
905         cls->traits = traits_parse(tag, pool, file);
906     }
907     for(t=0;t<num_classes;t++) {
908         abc_class_t*cls = (abc_class_t*)array_getvalue(file->classes, t);
909         /* SKIP */
910         swf_GetU30(tag); // cindex
911         cls->static_traits = traits_parse(tag, pool, file);
912     }
913     int num_scripts2 = swf_GetU30(tag);
914     for(t=0;t<num_scripts2;t++) {
915         int init = swf_GetU30(tag);
916         abc_method_t*m = (abc_method_t*)array_getvalue(file->methods, init);
917         
918         abc_script_t*s = malloc(sizeof(abc_script_t));
919         memset(s, 0, sizeof(abc_script_t));
920         s->method = m;
921         s->traits = traits_parse(tag, pool, file);
922         array_append(file->scripts, NO_KEY, s);
923     }
924
925     pool_destroy(pool);
926     return file;
927 }
928
929 void swf_WriteABC(TAG*abctag, void*code)
930 {
931     abc_file_t*file = (abc_file_t*)code;
932     pool_t*pool = pool_new();
933
934     TAG*tmp = swf_InsertTag(0,0);
935     TAG*tag = tmp;
936     int t;
937   
938     /* add method bodies where needed */
939     for(t=0;t<file->classes->num;t++) {
940         abc_class_t*c = (abc_class_t*)array_getvalue(file->classes, t);
941         if(!c->constructor) {
942             if(!(c->flags&CLASS_INTERFACE)) {
943                 NEW(abc_method_t,m);array_append(file->methods, NO_KEY, m);
944                 NEW(abc_method_body_t,body);array_append(file->method_bodies, NO_KEY, body);
945                 // don't bother to set m->index
946                 body->method = m; m->body = body;
947                 __ returnvoid(body);
948                 c->constructor = m;
949             } else {
950                 NEW(abc_method_t,m);array_append(file->methods, NO_KEY, m);
951                 c->constructor = m;
952             }
953         }
954         if(!c->static_constructor) {
955             NEW(abc_method_t,m);array_append(file->methods, NO_KEY, m);
956             NEW(abc_method_body_t,body);array_append(file->method_bodies, NO_KEY, body);
957             body->method = m; m->body = body;
958             __ returnvoid(body);
959             c->static_constructor = m;
960         }
961     }
962
963
964     swf_SetU30(tag, file->methods->num);
965     /* enumerate classes, methods and method bodies */
966     for(t=0;t<file->methods->num;t++) {
967         abc_method_t*m = (abc_method_t*)array_getvalue(file->methods, t);
968         m->index = t;
969     }
970     for(t=0;t<file->classes->num;t++) {
971         abc_class_t*c = (abc_class_t*)array_getvalue(file->classes, t);
972         c->index = t;
973     }
974     for(t=0;t<file->method_bodies->num;t++) {
975         abc_method_body_t*m = (abc_method_body_t*)array_getvalue(file->method_bodies, t);
976         m->index = t;
977     }
978     
979     /* generate code statistics */
980     for(t=0;t<file->method_bodies->num;t++) {
981         abc_method_body_t*m = (abc_method_body_t*)array_getvalue(file->method_bodies, t);
982         m->stats = code_get_statistics(m->code, m->exceptions);
983     }
984     
985     /* level init scope depths: The init scope depth of a method is
986        always as least as high as the init scope depth of it's surrounding
987        class.
988        A method has it's own init_scope_depth if it's an init method 
989        (then its init scope depth is zero), or if it's used as a closure.
990
991        Not sure yet what to do with methods which are used at different
992        locations- e.g. the nullmethod is used all over the place.
993        EDIT: flashplayer doesn't allow this anyway- a method can only
994              be used once
995
996        Also, I have the strong suspicion that flash player uses only
997        the difference between max_scope_stack and init_scope_stack, anyway.
998      */
999     for(t=0;t<file->classes->num;t++) {
1000         abc_class_t*c = (abc_class_t*)array_getvalue(file->classes, t);
1001         trait_list_t*traits = c->traits;
1002         if(c->constructor && c->constructor->body &&
1003            c->constructor->body->init_scope_depth < c->init_scope_depth) {
1004            c->constructor->body->init_scope_depth = c->init_scope_depth;
1005         }
1006         if(c->static_constructor && c->static_constructor->body &&
1007            c->static_constructor->body->init_scope_depth < c->init_scope_depth) {
1008            c->static_constructor->body->init_scope_depth = c->init_scope_depth;
1009         }
1010         while(traits) {
1011             trait_t*trait = traits->trait;
1012             if(trait_is_method(trait) && trait->method->body) {
1013                 abc_method_body_t*body = trait->method->body;
1014                 if(body->init_scope_depth < c->init_scope_depth) {
1015                    body->init_scope_depth = c->init_scope_depth;
1016                 }
1017             }
1018             traits = traits->next;
1019         }
1020     }
1021     
1022     for(t=0;t<file->methods->num;t++) {
1023         abc_method_t*m = (abc_method_t*)array_getvalue(file->methods, t);
1024         int n = 0;
1025         multiname_list_t*l = m->parameters;
1026         int num_params = list_length(m->parameters);
1027         swf_SetU30(tag, num_params);
1028         if(m->return_type) 
1029             swf_SetU30(tag, pool_register_multiname(pool, m->return_type));
1030         else
1031             swf_SetU30(tag, 0);
1032         int s;
1033         while(l) {
1034             swf_SetU30(tag, pool_register_multiname(pool, l->multiname));
1035             l = l->next;
1036         }
1037         if(m->name) {
1038             swf_SetU30(tag, pool_register_string(pool, m->name));
1039         } else {
1040             swf_SetU30(tag, 0);
1041         }
1042
1043         U8 flags = m->flags&(METHOD_NEED_REST|METHOD_NEED_ARGUMENTS);
1044         if(m->optional_parameters)
1045             flags |= METHOD_HAS_OPTIONAL;
1046         if(m->body) {
1047             flags |= m->body->stats->flags;
1048         }
1049
1050         swf_SetU8(tag, flags);
1051         if(flags&METHOD_HAS_OPTIONAL) {
1052             swf_SetU30(tag, list_length(m->optional_parameters));
1053             constant_list_t*l = m->optional_parameters;
1054             while(l) {
1055                 int i = constant_get_index(pool, l->constant);
1056                 swf_SetU30(tag, i);
1057                 if(!i) {
1058                     swf_SetU8(tag, CONSTANT_NULL);
1059                 } else {
1060                     swf_SetU8(tag, l->constant->type);
1061                 }
1062                 l = l->next;
1063             }
1064         }
1065     }
1066    
1067     /* write metadata */
1068     swf_SetU30(tag, file->metadata->num);
1069     for(t=0;t<file->metadata->num;t++) {
1070         const char*entry_name = array_getkey(file->metadata, t);
1071         swf_SetU30(tag, pool_register_string(pool, entry_name));
1072         array_t*items = (array_t*)array_getvalue(file->metadata, t);
1073         swf_SetU30(tag, items->num);
1074         int s;
1075         for(s=0;s<items->num;s++) {
1076             int i1 = pool_register_string(pool, array_getkey(items, s));
1077             int i2 = pool_register_string(pool, array_getvalue(items, s));
1078             swf_SetU30(tag, i1);
1079             swf_SetU30(tag, i2);
1080         }
1081     }
1082
1083     swf_SetU30(tag, file->classes->num);
1084     for(t=0;t<file->classes->num;t++) {
1085         abc_class_t*c = (abc_class_t*)array_getvalue(file->classes, t);
1086    
1087         int classname_index = pool_register_multiname(pool, c->classname);
1088         int superclass_index = pool_register_multiname(pool, c->superclass);
1089
1090         swf_SetU30(tag, classname_index);
1091         swf_SetU30(tag, superclass_index);
1092
1093         swf_SetU8(tag, c->flags); // flags
1094         if(c->flags&0x08) {
1095             int ns_index = pool_register_namespace(pool, c->protectedNS);
1096             swf_SetU30(tag, ns_index);
1097         }
1098
1099         swf_SetU30(tag, list_length(c->interfaces));
1100         multiname_list_t*interface= c->interfaces;
1101         while(interface) {
1102             swf_SetU30(tag, pool_register_multiname(pool, interface->multiname));
1103             interface = interface->next;
1104         }
1105
1106         assert(c->constructor);
1107         swf_SetU30(tag, c->constructor->index);
1108
1109         traits_write(pool, tag, c->traits);
1110     }
1111     for(t=0;t<file->classes->num;t++) {
1112         abc_class_t*c = (abc_class_t*)array_getvalue(file->classes, t);
1113         assert(c->static_constructor);
1114         swf_SetU30(tag, c->static_constructor->index);
1115         
1116         traits_write(pool, tag, c->static_traits);
1117     }
1118
1119     swf_SetU30(tag, file->scripts->num);
1120     for(t=0;t<file->scripts->num;t++) {
1121         abc_script_t*s = (abc_script_t*)array_getvalue(file->scripts, t);
1122         swf_SetU30(tag, s->method->index); //!=t!
1123         traits_write(pool, tag, s->traits);
1124     }
1125
1126     swf_SetU30(tag, file->method_bodies->num);
1127     for(t=0;t<file->method_bodies->num;t++) {
1128         abc_method_body_t*c = (abc_method_body_t*)array_getvalue(file->method_bodies, t);
1129         abc_method_t*m = c->method;
1130         swf_SetU30(tag, m->index);
1131
1132         //swf_SetU30(tag, c->old.max_stack);
1133         //swf_SetU30(tag, c->old.local_count);
1134         //swf_SetU30(tag, c->old.init_scope_depth);
1135         //swf_SetU30(tag, c->old.max_scope_depth);
1136
1137         swf_SetU30(tag, c->stats->max_stack);
1138         int param_num = list_length(c->method->parameters)+1;
1139         if(c->method->flags&METHOD_NEED_REST)
1140             param_num++;
1141         if(param_num <= c->stats->local_count)
1142             swf_SetU30(tag, c->stats->local_count);
1143         else
1144             swf_SetU30(tag, param_num);
1145
1146         swf_SetU30(tag, c->init_scope_depth);
1147         swf_SetU30(tag, c->stats->max_scope_depth+
1148                         c->init_scope_depth);
1149
1150         code_write(tag, c->code, pool, file);
1151
1152         swf_SetU30(tag, list_length(c->exceptions));
1153         abc_exception_list_t*l = c->exceptions;
1154         while(l) {
1155             // warning: assumes "pos" in each code_t is up-to-date
1156             swf_SetU30(tag, l->abc_exception->from->pos);
1157             swf_SetU30(tag, l->abc_exception->to->pos);
1158             swf_SetU30(tag, l->abc_exception->target->pos);
1159             swf_SetU30(tag, pool_register_multiname(pool, l->abc_exception->exc_type));
1160             swf_SetU30(tag, pool_register_multiname(pool, l->abc_exception->var_name));
1161             l = l->next;
1162         }
1163
1164         traits_write(pool, tag, c->traits);
1165     }
1166    
1167     /* free temporary codestat data again. Notice: If we were to write this
1168        file multiple times, this can also be shifted to abc_file_free() */
1169     for(t=0;t<file->method_bodies->num;t++) {
1170         abc_method_body_t*m = (abc_method_body_t*)array_getvalue(file->method_bodies, t);
1171         codestats_free(m->stats);m->stats=0;
1172     }
1173
1174     // --- start to write real tag --
1175     
1176     tag = abctag;
1177
1178     if(tag->id == ST_DOABC) {
1179         swf_SetU32(tag, file->flags); // flags
1180         swf_SetString(tag, file->name);
1181     }
1182
1183     swf_SetU16(tag, 0x10); //version
1184     swf_SetU16(tag, 0x2e);
1185     
1186     pool_write(pool, tag);
1187     
1188     swf_SetBlock(tag, tmp->data, tmp->len);
1189
1190     swf_DeleteTag(0, tmp);
1191     pool_destroy(pool);
1192 }
1193
1194 void abc_file_free(abc_file_t*file)
1195 {
1196     int t;
1197     if(file->metadata) {
1198         for(t=0;t<file->metadata->num;t++) {
1199             array_t*items = (array_t*)array_getvalue(file->metadata, t);
1200             int s;
1201             for(s=0;s<items->num;s++) {
1202                 free(array_getvalue(items, s));
1203             }
1204             array_free(items);
1205         }
1206         array_free(file->metadata);file->metadata=0;
1207     }
1208
1209     for(t=0;t<file->methods->num;t++) {
1210         abc_method_t*m = (abc_method_t*)array_getvalue(file->methods, t);
1211
1212         multiname_list_t*param = m->parameters;
1213         while(param) {
1214             multiname_destroy(param->multiname);param->multiname=0;
1215             param = param->next;
1216         }
1217         list_free(m->parameters);m->parameters=0;
1218        
1219         constant_list_t*opt = m->optional_parameters;
1220         while(opt) {
1221             constant_free(opt->constant);opt->constant=0;
1222             opt = opt->next;
1223         }
1224         list_free(m->optional_parameters);m->optional_parameters=0;
1225
1226         if(m->name) {
1227             free((void*)m->name);m->name=0;
1228         }
1229         if(m->return_type) {
1230             multiname_destroy(m->return_type);
1231         }
1232         free(m);
1233     }
1234     array_free(file->methods);file->methods=0;
1235
1236     for(t=0;t<file->classes->num;t++) {
1237         abc_class_t*cls = (abc_class_t*)array_getvalue(file->classes, t);
1238         traits_free(cls->traits);cls->traits=0;
1239         traits_free(cls->static_traits);cls->static_traits=0;
1240
1241         if(cls->classname) {
1242             multiname_destroy(cls->classname);
1243         }
1244         if(cls->superclass) {
1245             multiname_destroy(cls->superclass);
1246         }
1247
1248         multiname_list_t*i = cls->interfaces;
1249         while(i) {
1250             multiname_destroy(i->multiname);i->multiname=0;
1251             i = i->next;
1252         }
1253         list_free(cls->interfaces);cls->interfaces=0;
1254
1255         if(cls->protectedNS) {
1256             namespace_destroy(cls->protectedNS);
1257         }
1258         free(cls);
1259     }
1260     array_free(file->classes);file->classes=0;
1261
1262     for(t=0;t<file->scripts->num;t++) {
1263         abc_script_t*s = (abc_script_t*)array_getvalue(file->scripts, t);
1264         traits_free(s->traits);s->traits=0;
1265         free(s);
1266     }
1267     array_free(file->scripts);file->scripts=0;
1268
1269     for(t=0;t<file->method_bodies->num;t++) {
1270         abc_method_body_t*body = (abc_method_body_t*)array_getvalue(file->method_bodies, t);
1271         code_free(body->code);body->code=0;
1272         traits_free(body->traits);body->traits=0;
1273
1274         abc_exception_list_t*ee = body->exceptions;
1275         while(ee) {
1276             abc_exception_t*e=ee->abc_exception;ee->abc_exception=0;
1277             e->from = e->to = e->target = 0;
1278             multiname_destroy(e->exc_type);e->exc_type=0;
1279             multiname_destroy(e->var_name);e->var_name=0;
1280             free(e);
1281             ee=ee->next;
1282         }
1283         list_free(body->exceptions);body->exceptions=0;
1284         
1285         free(body);
1286     }
1287     array_free(file->method_bodies);file->method_bodies=0;
1288
1289     if(file->name) {
1290         free((void*)file->name);file->name=0;
1291     }
1292
1293     free(file);
1294 }
1295
1296 void swf_FreeABC(void*code)
1297 {
1298     abc_file_t*file= (abc_file_t*)code;
1299     abc_file_free(file);
1300 }
1301
1302 void swf_AddButtonLinks(SWF*swf, char stop_each_frame, char events)
1303 {
1304     int num_frames = 0;
1305     int has_buttons = 0;
1306     TAG*tag=swf->firstTag;
1307     while(tag) {
1308         if(tag->id == ST_SHOWFRAME)
1309             num_frames++;
1310         if(tag->id == ST_DEFINEBUTTON || tag->id == ST_DEFINEBUTTON2)
1311             has_buttons = 1;
1312         tag = tag->next;
1313     }
1314
1315     abc_file_t*file = abc_file_new();
1316     abc_method_body_t*c = 0;
1317    
1318     abc_class_t*cls = abc_class_new2(file, "rfx::MainTimeline", "flash.display::MovieClip");
1319     abc_class_protectedNS(cls, "rfx:MainTimeline");
1320   
1321     TAG*abctag = swf_InsertTagBefore(swf, swf->firstTag, ST_DOABC);
1322     
1323     tag = swf_InsertTag(abctag, ST_SYMBOLCLASS);
1324     swf_SetU16(tag, 1);
1325     swf_SetU16(tag, 0);
1326     swf_SetString(tag, "rfx.MainTimeline");
1327
1328     c = abc_class_getstaticconstructor(cls, 0)->body;
1329     c->old.max_stack = 1;
1330     c->old.local_count = 1;
1331     c->old.init_scope_depth = 9;
1332     c->old.max_scope_depth = 10;
1333
1334     __ getlocal_0(c);
1335     __ pushscope(c);
1336     __ returnvoid(c);
1337
1338     c = abc_class_getconstructor(cls, 0)->body;
1339     c->old.max_stack = 3;
1340     c->old.local_count = 1;
1341     c->old.init_scope_depth = 10;
1342     c->old.max_scope_depth = 11;
1343     
1344     debugfile(c, "constructor.as");
1345
1346     __ getlocal_0(c);
1347     __ pushscope(c);
1348
1349     __ getlocal_0(c);
1350     __ constructsuper(c,0);
1351
1352     __ getlex(c, "[package]flash.system::Security");
1353     __ pushstring(c, "*");
1354     __ callpropvoid(c, "[package]::allowDomain", 1);
1355     
1356     if(stop_each_frame || has_buttons) {
1357         int frame = 0;
1358         tag = swf->firstTag;
1359         abc_method_body_t*f = 0; //frame script
1360         while(tag && tag->id!=ST_END) {
1361             char framename[80];
1362             char needs_framescript=0;
1363             char buttonname[80];
1364             char functionname[80];
1365             sprintf(framename, "[packageinternal]rfx::frame%d", frame);
1366             
1367             if(!f && (tag->id == ST_DEFINEBUTTON || tag->id == ST_DEFINEBUTTON2 || stop_each_frame)) {
1368                 /* make the contructor add a frame script */
1369                 __ findpropstrict(c,"[package]::addFrameScript");
1370                 __ pushbyte(c,frame);
1371                 __ getlex(c,framename);
1372                 __ callpropvoid(c,"[package]::addFrameScript",2);
1373
1374                 f = abc_class_method(cls, 0, multiname_fromstring(framename))->body;
1375                 f->old.max_stack = 3;
1376                 f->old.local_count = 1;
1377                 f->old.init_scope_depth = 10;
1378                 f->old.max_scope_depth = 11;
1379                 __ debugfile(f, "framescript.as");
1380                 __ debugline(f, 1);
1381                 __ getlocal_0(f);
1382                 __ pushscope(f);
1383                 if(stop_each_frame) {
1384                     __ findpropstrict(f, "[package]::stop");
1385                     __ callpropvoid(f, "[package]::stop", 0);
1386                 }
1387             }
1388
1389             if(tag->id == ST_DEFINEBUTTON || tag->id == ST_DEFINEBUTTON2) {
1390                 U16 id = swf_GetDefineID(tag);
1391                 sprintf(buttonname, "::button%d", swf_GetDefineID(tag));
1392                 __ getlex(f,buttonname);
1393                 __ getlex(f,"flash.events::MouseEvent");
1394                 __ getproperty(f, "::CLICK");
1395                 sprintf(functionname, "::clickbutton%d", swf_GetDefineID(tag));
1396                 __ getlex(f,functionname);
1397                 __ callpropvoid(f, "::addEventListener" ,2);
1398
1399                 needs_framescript = 1;
1400
1401                 abc_method_body_t*h =
1402                     abc_class_method(cls, 0, multiname_fromstring(functionname))->body;
1403                 list_append(h->method->parameters, multiname_fromstring("flash.events::MouseEvent"));
1404
1405                 h->old.max_stack = 6;
1406                 h->old.local_count = 2;
1407                 h->old.init_scope_depth = 10;
1408                 h->old.max_scope_depth = 11;
1409                 __ getlocal_0(h);
1410                 __ pushscope(h);
1411
1412                 ActionTAG*oldaction = swf_ButtonGetAction(tag);
1413                 if(oldaction && oldaction->op == ACTION__GOTOFRAME) {
1414                     int framenr = GET16(oldaction->data);
1415                     if(framenr>254) {
1416                         fprintf(stderr, "Warning: Couldn't translate jump to frame %d to flash 9 actionscript\n", framenr);
1417                     }
1418                     if(!events) {
1419                         __ findpropstrict(h,"[package]::gotoAndStop");
1420                         __ pushbyte(h,framenr+1);
1421                         __ callpropvoid(h,"[package]::gotoAndStop", 1);
1422                     } else {
1423                         char framename[80];
1424                         sprintf(framename, "frame%d", framenr);
1425                         __ getlocal_0(h); //this
1426                         __ findpropstrict(h, "[package]flash.events::TextEvent");
1427                         __ pushstring(h, "link");
1428                         __ pushtrue(h);
1429                         __ pushtrue(h);
1430                         __ pushstring(h, framename);
1431                         __ constructprop(h,"[package]flash.events::TextEvent", 4);
1432                         __ callpropvoid(h,"[package]::dispatchEvent", 1);
1433                     }
1434                 } else if(oldaction && oldaction->op == ACTION__GETURL) {
1435                     if(!events) {
1436                         __ findpropstrict(h,"flash.net::navigateToURL");
1437                         __ findpropstrict(h,"flash.net::URLRequest");
1438                         // TODO: target _blank
1439                         __ pushstring(h,oldaction->data); //url
1440                         __ constructprop(h,"flash.net::URLRequest", 1);
1441                         __ callpropvoid(h,"flash.net::navigateToURL", 1);
1442                     } else {
1443                         __ getlocal_0(h); //this
1444                         __ findpropstrict(h, "[package]flash.events::TextEvent");
1445                         __ pushstring(h, "link");
1446                         __ pushtrue(h);
1447                         __ pushtrue(h);
1448                         __ pushstring(h,oldaction->data); //url
1449                         __ constructprop(h,"[package]flash.events::TextEvent", 4);
1450                         __ callpropvoid(h,"[package]::dispatchEvent", 1);
1451                     }
1452                 } else if(oldaction) {
1453                     fprintf(stderr, "Warning: Couldn't translate button code of button %d to flash 9 abc action\n", id);
1454                 }
1455                 __ returnvoid(h);
1456                 swf_ActionFree(oldaction);
1457             }
1458             if(tag->id == ST_SHOWFRAME) {
1459                 if(f) {
1460                     __ returnvoid(f);
1461                     f = 0;
1462                 }
1463                 frame++;
1464             }
1465             tag = tag->next;
1466         }
1467         if(f) {
1468             __ returnvoid(f);
1469         }
1470     }
1471     __ returnvoid(c);
1472
1473     tag = swf->firstTag;
1474     while(tag) {
1475         if(tag->id == ST_DEFINEBUTTON || tag->id == ST_DEFINEBUTTON2) {
1476             char buttonname[80];
1477             sprintf(buttonname, "::button%d", swf_GetDefineID(tag));
1478             multiname_t*s = multiname_fromstring(buttonname);
1479             //abc_class_slot(cls, multiname_fromstring(buttonname), s);
1480             abc_class_slot(cls, multiname_fromstring(buttonname), 
1481                                 multiname_fromstring("flash.display::SimpleButton"));
1482         }
1483         tag = tag->next;
1484     }
1485
1486
1487     abc_script_t*s = abc_initscript(file);
1488     c = s->method->body;
1489     c->old.max_stack = 2;
1490     c->old.local_count = 1;
1491     c->old.init_scope_depth = 1;
1492     c->old.max_scope_depth = 9;
1493
1494     __ getlocal_0(c);
1495     __ pushscope(c);
1496     __ getscopeobject(c, 0);
1497     __ getlex(c,"::Object");
1498     __ pushscope(c);
1499     __ getlex(c,"flash.events::EventDispatcher");
1500     __ pushscope(c);
1501     __ getlex(c,"flash.display::DisplayObject");
1502     __ pushscope(c);
1503     __ getlex(c,"flash.display::InteractiveObject");
1504     __ pushscope(c);
1505     __ getlex(c,"flash.display::DisplayObjectContainer");
1506     __ pushscope(c);
1507     __ getlex(c,"flash.display::Sprite");
1508     __ pushscope(c);
1509     __ getlex(c,"flash.display::MovieClip");
1510     __ pushscope(c);
1511     __ getlex(c,"flash.display::MovieClip");
1512     __ newclass(c,cls);
1513     __ popscope(c);
1514     __ popscope(c);
1515     __ popscope(c);
1516     __ popscope(c);
1517     __ popscope(c);
1518     __ popscope(c);
1519     __ popscope(c);
1520     __ initproperty(c,"rfx::MainTimeline");
1521     __ returnvoid(c);
1522
1523     //abc_method_body_addClassTrait(c, "rfx:MainTimeline", 1, cls);
1524     multiname_t*classname = multiname_fromstring("rfx::MainTimeline");
1525     abc_initscript_addClassTrait(s, classname, cls);
1526     multiname_destroy(classname);
1527
1528     swf_WriteABC(abctag, file);
1529 }
1530
1531 TAG*swf_AddAS3FontDefine(TAG*tag, U16 id, char*fontname)
1532 {
1533     tag = swf_InsertTag(tag, ST_DOABC);
1534     abc_file_t*file = abc_file_new();
1535
1536     //abc_class_t*cls = abc_class_new2(file, fontname, "flash.display::MovieClip");
1537     //abc_class_slot(cls, multiname_fromstring(fontname), multiname_fromstring("flash.text::Font"));
1538
1539     abc_class_t*cls = abc_class_new2(file, fontname, "flash.text::Font");
1540
1541     abc_script_t*s = abc_initscript(file);
1542     code_t*c = s->method->body->code;
1543     c = abc_getlocal_0(c);
1544     c = abc_pushscope(c);
1545     c = abc_getscopeobject(c, 0);
1546     c = abc_getlex(c,"flash.text::Font");
1547     c = abc_pushscope(c);
1548     c = abc_getlex(c,"flash.text::Font");
1549     c = abc_newclass(c,cls);
1550     c = abc_popscope(c);
1551     c = abc_initproperty(c, fontname);
1552     c = abc_returnvoid(c);
1553     s->method->body->code = c;
1554
1555     abc_initscript_addClassTrait(s, multiname_fromstring(fontname), cls);
1556     swf_WriteABC(tag, file);
1557         
1558     tag = swf_InsertTag(tag, ST_SYMBOLCLASS);
1559     swf_SetU16(tag, 1);
1560     swf_SetU16(tag, id);
1561     swf_SetString(tag, fontname);
1562
1563     return tag;
1564 }
1565
1566