18be42be3693b3384ba42de19fbe41ffbe457ae2
[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, 2);
724     printf("pool is %d bytes\n", tag->pos);
725
726     int num_methods = swf_GetU30(tag);
727     DEBUG printf("%d methods\n", num_methods);
728     for(t=0;t<num_methods;t++) {
729         NEW(abc_method_t,m);
730         int param_count = swf_GetU30(tag);
731         int return_type_index = swf_GetU30(tag);
732         if(return_type_index)
733             m->return_type = multiname_clone(pool_lookup_multiname(pool, return_type_index));
734         else
735             m->return_type = 0;
736
737         int s;
738         for(s=0;s<param_count;s++) {
739             int type_index = swf_GetU30(tag);
740             
741             /* type_index might be 0 ("*") */
742             multiname_t*param = type_index?multiname_clone(pool_lookup_multiname(pool, type_index)):0;
743             list_append(m->parameters, param);
744         }
745
746         int namenr = swf_GetU30(tag);
747         if(namenr)
748             m->name = strdup(pool_lookup_string(pool, namenr));
749         else
750             m->name = strdup("");
751
752         m->flags = swf_GetU8(tag);
753         
754         DEBUG printf("method %d) %s ", m->name);
755         DEBUG params_dump(stdout, m->parameters, m->optional_parameters);
756         DEBUG printf("flags=%02x\n", t, m->flags);
757
758         if(m->flags&0x08) {
759             m->optional_parameters = list_new();
760             int num = swf_GetU30(tag);
761             int s;
762             for(s=0;s<num;s++) {
763                 int vindex = swf_GetU30(tag);
764                 U8 vkind = swf_GetU8(tag); // specifies index type for "val"
765                 constant_t*c = constant_fromindex(pool, vindex, vkind);
766                 list_append(m->optional_parameters, c);
767
768             }
769         }
770         if(m->flags&0x80) {
771             /* debug information- not used by avm2 */
772             multiname_list_t*l = m->parameters;
773             while(l) {
774                 const char*name = pool_lookup_string(pool, swf_GetU30(tag));
775                 l = l->next;
776             }
777         }
778         m->index = array_length(file->methods);
779         array_append(file->methods, NO_KEY, m);
780     }
781             
782     parse_metadata(tag, file, pool);
783         
784     /* skip classes, and scripts for now, and do the real parsing later */
785     int num_classes = swf_GetU30(tag);
786     int classes_pos = tag->pos;
787     DEBUG printf("%d classes\n", num_classes);
788     for(t=0;t<num_classes;t++) {
789         abc_class_t*cls = malloc(sizeof(abc_class_t));
790         memset(cls, 0, sizeof(abc_class_t));
791         
792         swf_GetU30(tag); //classname
793         swf_GetU30(tag); //supername
794
795         array_append(file->classes, NO_KEY, cls);
796
797         cls->flags = swf_GetU8(tag);
798         DEBUG printf("class %d %02x\n", t, cls->flags);
799         if(cls->flags&8) 
800             swf_GetU30(tag); //protectedNS
801         int s;
802         int inum = swf_GetU30(tag); //interface count
803         cls->interfaces = 0;
804         for(s=0;s<inum;s++) {
805             int interface_index = swf_GetU30(tag);
806             multiname_t* m = multiname_clone(pool_lookup_multiname(pool, interface_index));
807             list_append(cls->interfaces, m);
808             DEBUG printf("  class %d interface: %s\n", t, m->name);
809         }
810
811         int iinit = swf_GetU30(tag); //iinit
812         DEBUG printf("--iinit-->%d\n", iinit);
813         traits_skip(tag);
814     }
815     for(t=0;t<num_classes;t++) {
816         abc_class_t*cls = (abc_class_t*)array_getvalue(file->classes, t);
817         int cinit = swf_GetU30(tag);
818         DEBUG printf("--cinit(%d)-->%d\n", t, cinit);
819         cls->static_constructor = (abc_method_t*)array_getvalue(file->methods, cinit);
820         traits_skip(tag);
821     }
822     int num_scripts = swf_GetU30(tag);
823     DEBUG printf("%d scripts\n", num_scripts);
824     for(t=0;t<num_scripts;t++) {
825         int init = swf_GetU30(tag);
826         traits_skip(tag);
827     }
828
829     int num_method_bodies = swf_GetU30(tag);
830     DEBUG printf("%d method bodies\n", num_method_bodies);
831     for(t=0;t<num_method_bodies;t++) {
832         int methodnr = swf_GetU30(tag);
833         if(methodnr >= file->methods->num) {
834             printf("Invalid method number: %d\n", methodnr);
835             return 0;
836         }
837         abc_method_t*m = (abc_method_t*)array_getvalue(file->methods, methodnr);
838         abc_method_body_t*c = malloc(sizeof(abc_method_body_t));
839         memset(c, 0, sizeof(abc_method_body_t));
840         c->old.max_stack = swf_GetU30(tag);
841         c->old.local_count = swf_GetU30(tag);
842         c->old.init_scope_depth = swf_GetU30(tag);
843         c->old.max_scope_depth = swf_GetU30(tag);
844
845         c->init_scope_depth = c->old.init_scope_depth;
846         int code_length = swf_GetU30(tag);
847
848         c->method = m;
849         m->body = c;
850
851         int pos = tag->pos + code_length;
852         codelookup_t*codelookup = 0;
853         c->code = code_parse(tag, code_length, file, pool, &codelookup);
854         tag->pos = pos;
855
856         int exception_count = swf_GetU30(tag);
857         int s;
858         c->exceptions = list_new();
859         for(s=0;s<exception_count;s++) {
860             abc_exception_t*e = malloc(sizeof(abc_exception_t));
861
862             e->from = code_atposition(codelookup, swf_GetU30(tag));
863             e->to = code_atposition(codelookup, swf_GetU30(tag));
864             e->target = code_atposition(codelookup, swf_GetU30(tag));
865
866             e->exc_type = multiname_clone(pool_lookup_multiname(pool, swf_GetU30(tag)));
867             e->var_name = multiname_clone(pool_lookup_multiname(pool, swf_GetU30(tag)));
868             //e->var_name = pool_lookup_string(pool, swf_GetU30(tag));
869             //if(e->var_name) e->var_name = strdup(e->var_name);
870             list_append(c->exceptions, e);
871         }
872         codelookup_free(codelookup);
873         c->traits = traits_parse(tag, pool, file);
874
875         DEBUG printf("method_body %d) (method %d), %d bytes of code\n", t, methodnr, code_length);
876
877         array_append(file->method_bodies, NO_KEY, c);
878     }
879     if(tag->len - tag->pos) {
880         fprintf(stderr, "ERROR: %d unparsed bytes remaining in ABC block\n", tag->len - tag->pos);
881         return 0;
882     }
883
884     swf_SetTagPos(tag, classes_pos);
885     for(t=0;t<num_classes;t++) {
886         abc_class_t*cls = (abc_class_t*)array_getvalue(file->classes, t);
887
888         int classname_index = swf_GetU30(tag);
889         int superclass_index = swf_GetU30(tag);
890         cls->classname = multiname_clone(pool_lookup_multiname(pool, classname_index));
891         cls->superclass = multiname_clone(pool_lookup_multiname(pool, superclass_index));
892         cls->flags = swf_GetU8(tag);
893         const char*ns = "";
894         if(cls->flags&8) {
895             int ns_index = swf_GetU30(tag);
896             cls->protectedNS = namespace_clone(pool_lookup_namespace(pool, ns_index));
897         }
898         
899         int num_interfaces = swf_GetU30(tag); //interface count
900         int s;
901         for(s=0;s<num_interfaces;s++) {
902             swf_GetU30(tag);
903         }
904         int iinit = swf_GetU30(tag);
905         cls->constructor = (abc_method_t*)array_getvalue(file->methods, iinit);
906         cls->traits = traits_parse(tag, pool, file);
907     }
908     for(t=0;t<num_classes;t++) {
909         abc_class_t*cls = (abc_class_t*)array_getvalue(file->classes, t);
910         /* SKIP */
911         swf_GetU30(tag); // cindex
912         cls->static_traits = traits_parse(tag, pool, file);
913     }
914     int num_scripts2 = swf_GetU30(tag);
915     for(t=0;t<num_scripts2;t++) {
916         int init = swf_GetU30(tag);
917         abc_method_t*m = (abc_method_t*)array_getvalue(file->methods, init);
918         
919         abc_script_t*s = malloc(sizeof(abc_script_t));
920         memset(s, 0, sizeof(abc_script_t));
921         s->method = m;
922         s->traits = traits_parse(tag, pool, file);
923         array_append(file->scripts, NO_KEY, s);
924     }
925
926     pool_destroy(pool);
927     return file;
928 }
929
930 static pool_t*writeABC(TAG*abctag, void*code, pool_t*pool)
931 {
932     abc_file_t*file = (abc_file_t*)code;
933     if(!pool) 
934         pool = pool_new();
935
936     TAG*tmp = swf_InsertTag(0,0);
937     TAG*tag = tmp;
938     int t;
939   
940     /* add method bodies where needed */
941     for(t=0;t<file->classes->num;t++) {
942         abc_class_t*c = (abc_class_t*)array_getvalue(file->classes, t);
943         if(!c->constructor) {
944             if(!(c->flags&CLASS_INTERFACE)) {
945                 NEW(abc_method_t,m);array_append(file->methods, NO_KEY, m);
946                 NEW(abc_method_body_t,body);array_append(file->method_bodies, NO_KEY, body);
947                 // don't bother to set m->index
948                 body->method = m; m->body = body;
949                 __ returnvoid(body);
950                 c->constructor = m;
951             } else {
952                 NEW(abc_method_t,m);array_append(file->methods, NO_KEY, m);
953                 c->constructor = m;
954             }
955         }
956         if(!c->static_constructor) {
957             NEW(abc_method_t,m);array_append(file->methods, NO_KEY, m);
958             NEW(abc_method_body_t,body);array_append(file->method_bodies, NO_KEY, body);
959             body->method = m; m->body = body;
960             __ returnvoid(body);
961             c->static_constructor = m;
962         }
963     }
964
965
966     swf_SetU30(tag, file->methods->num);
967     /* enumerate classes, methods and method bodies */
968     for(t=0;t<file->methods->num;t++) {
969         abc_method_t*m = (abc_method_t*)array_getvalue(file->methods, t);
970         m->index = t;
971     }
972     for(t=0;t<file->classes->num;t++) {
973         abc_class_t*c = (abc_class_t*)array_getvalue(file->classes, t);
974         c->index = t;
975     }
976     for(t=0;t<file->method_bodies->num;t++) {
977         abc_method_body_t*m = (abc_method_body_t*)array_getvalue(file->method_bodies, t);
978         m->index = t;
979     }
980     
981     /* generate code statistics */
982     for(t=0;t<file->method_bodies->num;t++) {
983         abc_method_body_t*m = (abc_method_body_t*)array_getvalue(file->method_bodies, t);
984         m->stats = code_get_statistics(m->code, m->exceptions);
985     }
986     
987     /* level init scope depths: The init scope depth of a method is
988        always as least as high as the init scope depth of it's surrounding
989        class.
990        A method has it's own init_scope_depth if it's an init method 
991        (then its init scope depth is zero), or if it's used as a closure.
992
993        Not sure yet what to do with methods which are used at different
994        locations- e.g. the nullmethod is used all over the place.
995        EDIT: flashplayer doesn't allow this anyway- a method can only
996              be used once
997
998        Also, I have the strong suspicion that flash player uses only
999        the difference between max_scope_stack and init_scope_stack, anyway.
1000      */
1001     for(t=0;t<file->classes->num;t++) {
1002         abc_class_t*c = (abc_class_t*)array_getvalue(file->classes, t);
1003         trait_list_t*traits = c->traits;
1004         if(c->constructor && c->constructor->body &&
1005            c->constructor->body->init_scope_depth < c->init_scope_depth) {
1006            c->constructor->body->init_scope_depth = c->init_scope_depth;
1007         }
1008         if(c->static_constructor && c->static_constructor->body &&
1009            c->static_constructor->body->init_scope_depth < c->init_scope_depth) {
1010            c->static_constructor->body->init_scope_depth = c->init_scope_depth;
1011         }
1012         while(traits) {
1013             trait_t*trait = traits->trait;
1014             if(trait_is_method(trait) && trait->method->body) {
1015                 abc_method_body_t*body = trait->method->body;
1016                 if(body->init_scope_depth < c->init_scope_depth) {
1017                    body->init_scope_depth = c->init_scope_depth;
1018                 }
1019             }
1020             traits = traits->next;
1021         }
1022     }
1023     
1024     for(t=0;t<file->methods->num;t++) {
1025         abc_method_t*m = (abc_method_t*)array_getvalue(file->methods, t);
1026         int n = 0;
1027         multiname_list_t*l = m->parameters;
1028         int num_params = list_length(m->parameters);
1029         swf_SetU30(tag, num_params);
1030         if(m->return_type) 
1031             swf_SetU30(tag, pool_register_multiname(pool, m->return_type));
1032         else
1033             swf_SetU30(tag, 0);
1034         int s;
1035         while(l) {
1036             swf_SetU30(tag, pool_register_multiname(pool, l->multiname));
1037             l = l->next;
1038         }
1039         if(m->name) {
1040             swf_SetU30(tag, pool_register_string(pool, m->name));
1041         } else {
1042             swf_SetU30(tag, 0);
1043         }
1044
1045         U8 flags = m->flags&(METHOD_NEED_REST|METHOD_NEED_ARGUMENTS);
1046         if(m->optional_parameters)
1047             flags |= METHOD_HAS_OPTIONAL;
1048         if(m->body) {
1049             flags |= m->body->stats->flags;
1050         }
1051
1052         swf_SetU8(tag, flags);
1053         if(flags&METHOD_HAS_OPTIONAL) {
1054             swf_SetU30(tag, list_length(m->optional_parameters));
1055             constant_list_t*l = m->optional_parameters;
1056             while(l) {
1057                 int i = constant_get_index(pool, l->constant);
1058                 swf_SetU30(tag, i);
1059                 if(!i) {
1060                     swf_SetU8(tag, CONSTANT_NULL);
1061                 } else {
1062                     swf_SetU8(tag, l->constant->type);
1063                 }
1064                 l = l->next;
1065             }
1066         }
1067     }
1068    
1069     /* write metadata */
1070     swf_SetU30(tag, file->metadata->num);
1071     for(t=0;t<file->metadata->num;t++) {
1072         const char*entry_name = array_getkey(file->metadata, t);
1073         swf_SetU30(tag, pool_register_string(pool, entry_name));
1074         array_t*items = (array_t*)array_getvalue(file->metadata, t);
1075         swf_SetU30(tag, items->num);
1076         int s;
1077         for(s=0;s<items->num;s++) {
1078             int i1 = pool_register_string(pool, array_getkey(items, s));
1079             int i2 = pool_register_string(pool, array_getvalue(items, s));
1080             swf_SetU30(tag, i1);
1081             swf_SetU30(tag, i2);
1082         }
1083     }
1084
1085     swf_SetU30(tag, file->classes->num);
1086     for(t=0;t<file->classes->num;t++) {
1087         abc_class_t*c = (abc_class_t*)array_getvalue(file->classes, t);
1088    
1089         int classname_index = pool_register_multiname(pool, c->classname);
1090         int superclass_index = pool_register_multiname(pool, c->superclass);
1091
1092         swf_SetU30(tag, classname_index);
1093         swf_SetU30(tag, superclass_index);
1094
1095         swf_SetU8(tag, c->flags); // flags
1096         if(c->flags&0x08) {
1097             int ns_index = pool_register_namespace(pool, c->protectedNS);
1098             swf_SetU30(tag, ns_index);
1099         }
1100
1101         swf_SetU30(tag, list_length(c->interfaces));
1102         multiname_list_t*interface= c->interfaces;
1103         while(interface) {
1104             swf_SetU30(tag, pool_register_multiname(pool, interface->multiname));
1105             interface = interface->next;
1106         }
1107
1108         assert(c->constructor);
1109         swf_SetU30(tag, c->constructor->index);
1110
1111         traits_write(pool, tag, c->traits);
1112     }
1113     for(t=0;t<file->classes->num;t++) {
1114         abc_class_t*c = (abc_class_t*)array_getvalue(file->classes, t);
1115         assert(c->static_constructor);
1116         swf_SetU30(tag, c->static_constructor->index);
1117         
1118         traits_write(pool, tag, c->static_traits);
1119     }
1120
1121     swf_SetU30(tag, file->scripts->num);
1122     for(t=0;t<file->scripts->num;t++) {
1123         abc_script_t*s = (abc_script_t*)array_getvalue(file->scripts, t);
1124         swf_SetU30(tag, s->method->index); //!=t!
1125         traits_write(pool, tag, s->traits);
1126     }
1127
1128     swf_SetU30(tag, file->method_bodies->num);
1129     for(t=0;t<file->method_bodies->num;t++) {
1130         abc_method_body_t*c = (abc_method_body_t*)array_getvalue(file->method_bodies, t);
1131         abc_method_t*m = c->method;
1132         swf_SetU30(tag, m->index);
1133
1134         //swf_SetU30(tag, c->old.max_stack);
1135         //swf_SetU30(tag, c->old.local_count);
1136         //swf_SetU30(tag, c->old.init_scope_depth);
1137         //swf_SetU30(tag, c->old.max_scope_depth);
1138
1139         swf_SetU30(tag, c->stats->max_stack);
1140         int param_num = list_length(c->method->parameters)+1;
1141         if(c->method->flags&METHOD_NEED_REST)
1142             param_num++;
1143         if(param_num <= c->stats->local_count)
1144             swf_SetU30(tag, c->stats->local_count);
1145         else
1146             swf_SetU30(tag, param_num);
1147
1148         swf_SetU30(tag, c->init_scope_depth);
1149         swf_SetU30(tag, c->stats->max_scope_depth+
1150                         c->init_scope_depth);
1151
1152         code_write(tag, c->code, pool, file);
1153
1154         swf_SetU30(tag, list_length(c->exceptions));
1155         abc_exception_list_t*l = c->exceptions;
1156         while(l) {
1157             // warning: assumes "pos" in each code_t is up-to-date
1158             swf_SetU30(tag, l->abc_exception->from->pos);
1159             swf_SetU30(tag, l->abc_exception->to->pos);
1160             swf_SetU30(tag, l->abc_exception->target->pos);
1161             swf_SetU30(tag, pool_register_multiname(pool, l->abc_exception->exc_type));
1162             swf_SetU30(tag, pool_register_multiname(pool, l->abc_exception->var_name));
1163             l = l->next;
1164         }
1165
1166         traits_write(pool, tag, c->traits);
1167     }
1168    
1169     /* free temporary codestat data again. Notice: If we were to write this
1170        file multiple times, this can also be shifted to abc_file_free() */
1171     for(t=0;t<file->method_bodies->num;t++) {
1172         abc_method_body_t*m = (abc_method_body_t*)array_getvalue(file->method_bodies, t);
1173         codestats_free(m->stats);m->stats=0;
1174     }
1175
1176     // --- start to write real tag --
1177     
1178     tag = abctag;
1179
1180     if(tag->id == ST_DOABC) {
1181         swf_SetU32(tag, file->flags); // flags
1182         swf_SetString(tag, file->name);
1183     }
1184
1185     swf_SetU16(tag, 0x10); //version
1186     swf_SetU16(tag, 0x2e);
1187     
1188     pool_write(pool, tag);
1189     
1190     swf_SetBlock(tag, tmp->data, tmp->len);
1191
1192     swf_DeleteTag(0, tmp);
1193     return pool;
1194 }
1195
1196 void swf_WriteABC(TAG*abctag, void*code)
1197 {
1198     pool_t*pool = writeABC(abctag, code, 0);
1199     pool_optimize(pool);
1200     swf_ResetTag(abctag, abctag->id);
1201     writeABC(abctag, code, pool);
1202     pool_destroy(pool);
1203 }
1204
1205 void abc_file_free(abc_file_t*file)
1206 {
1207     if(!file)
1208         return;
1209     int t;
1210     if(file->metadata) {
1211         for(t=0;t<file->metadata->num;t++) {
1212             array_t*items = (array_t*)array_getvalue(file->metadata, t);
1213             int s;
1214             for(s=0;s<items->num;s++) {
1215                 free(array_getvalue(items, s));
1216             }
1217             array_free(items);
1218         }
1219         array_free(file->metadata);file->metadata=0;
1220     }
1221
1222     for(t=0;t<file->methods->num;t++) {
1223         abc_method_t*m = (abc_method_t*)array_getvalue(file->methods, t);
1224
1225         multiname_list_t*param = m->parameters;
1226         while(param) {
1227             multiname_destroy(param->multiname);param->multiname=0;
1228             param = param->next;
1229         }
1230         list_free(m->parameters);m->parameters=0;
1231        
1232         constant_list_t*opt = m->optional_parameters;
1233         while(opt) {
1234             constant_free(opt->constant);opt->constant=0;
1235             opt = opt->next;
1236         }
1237         list_free(m->optional_parameters);m->optional_parameters=0;
1238
1239         if(m->name) {
1240             free((void*)m->name);m->name=0;
1241         }
1242         if(m->return_type) {
1243             multiname_destroy(m->return_type);
1244         }
1245         free(m);
1246     }
1247     array_free(file->methods);file->methods=0;
1248
1249     for(t=0;t<file->classes->num;t++) {
1250         abc_class_t*cls = (abc_class_t*)array_getvalue(file->classes, t);
1251         traits_free(cls->traits);cls->traits=0;
1252         traits_free(cls->static_traits);cls->static_traits=0;
1253
1254         if(cls->classname) {
1255             multiname_destroy(cls->classname);
1256         }
1257         if(cls->superclass) {
1258             multiname_destroy(cls->superclass);
1259         }
1260
1261         multiname_list_t*i = cls->interfaces;
1262         while(i) {
1263             multiname_destroy(i->multiname);i->multiname=0;
1264             i = i->next;
1265         }
1266         list_free(cls->interfaces);cls->interfaces=0;
1267
1268         if(cls->protectedNS) {
1269             namespace_destroy(cls->protectedNS);
1270         }
1271         free(cls);
1272     }
1273     array_free(file->classes);file->classes=0;
1274
1275     for(t=0;t<file->scripts->num;t++) {
1276         abc_script_t*s = (abc_script_t*)array_getvalue(file->scripts, t);
1277         traits_free(s->traits);s->traits=0;
1278         free(s);
1279     }
1280     array_free(file->scripts);file->scripts=0;
1281
1282     for(t=0;t<file->method_bodies->num;t++) {
1283         abc_method_body_t*body = (abc_method_body_t*)array_getvalue(file->method_bodies, t);
1284         code_free(body->code);body->code=0;
1285         traits_free(body->traits);body->traits=0;
1286
1287         abc_exception_list_t*ee = body->exceptions;
1288         while(ee) {
1289             abc_exception_t*e=ee->abc_exception;ee->abc_exception=0;
1290             e->from = e->to = e->target = 0;
1291             multiname_destroy(e->exc_type);e->exc_type=0;
1292             multiname_destroy(e->var_name);e->var_name=0;
1293             free(e);
1294             ee=ee->next;
1295         }
1296         list_free(body->exceptions);body->exceptions=0;
1297         
1298         free(body);
1299     }
1300     array_free(file->method_bodies);file->method_bodies=0;
1301
1302     if(file->name) {
1303         free((void*)file->name);file->name=0;
1304     }
1305
1306     free(file);
1307 }
1308
1309 void swf_FreeABC(void*code)
1310 {
1311     abc_file_t*file= (abc_file_t*)code;
1312     abc_file_free(file);
1313 }
1314
1315 void swf_AddButtonLinks(SWF*swf, char stop_each_frame, char events)
1316 {
1317     int num_frames = 0;
1318     int has_buttons = 0;
1319     TAG*tag=swf->firstTag;
1320     while(tag) {
1321         if(tag->id == ST_SHOWFRAME)
1322             num_frames++;
1323         if(tag->id == ST_DEFINEBUTTON || tag->id == ST_DEFINEBUTTON2)
1324             has_buttons = 1;
1325         tag = tag->next;
1326     }
1327
1328     abc_file_t*file = abc_file_new();
1329     abc_method_body_t*c = 0;
1330    
1331     abc_class_t*cls = abc_class_new2(file, "rfx::MainTimeline", "flash.display::MovieClip");
1332     abc_class_protectedNS(cls, "rfx:MainTimeline");
1333   
1334     TAG*abctag = swf_InsertTagBefore(swf, swf->firstTag, ST_DOABC);
1335     
1336     tag = swf_InsertTag(abctag, ST_SYMBOLCLASS);
1337     swf_SetU16(tag, 1);
1338     swf_SetU16(tag, 0);
1339     swf_SetString(tag, "rfx.MainTimeline");
1340
1341     c = abc_class_getstaticconstructor(cls, 0)->body;
1342     c->old.max_stack = 1;
1343     c->old.local_count = 1;
1344     c->old.init_scope_depth = 9;
1345     c->old.max_scope_depth = 10;
1346
1347     __ getlocal_0(c);
1348     __ pushscope(c);
1349     __ returnvoid(c);
1350
1351     c = abc_class_getconstructor(cls, 0)->body;
1352     c->old.max_stack = 3;
1353     c->old.local_count = 1;
1354     c->old.init_scope_depth = 10;
1355     c->old.max_scope_depth = 11;
1356     
1357     debugfile(c, "constructor.as");
1358
1359     __ getlocal_0(c);
1360     __ pushscope(c);
1361
1362     __ getlocal_0(c);
1363     __ constructsuper(c,0);
1364
1365     __ getlex(c, "[package]flash.system::Security");
1366     __ pushstring(c, "*");
1367     __ callpropvoid(c, "[package]::allowDomain", 1);
1368     
1369     if(stop_each_frame || has_buttons) {
1370         int frame = 0;
1371         tag = swf->firstTag;
1372         abc_method_body_t*f = 0; //frame script
1373         while(tag && tag->id!=ST_END) {
1374             char framename[80];
1375             char needs_framescript=0;
1376             char buttonname[80];
1377             char functionname[80];
1378             sprintf(framename, "[packageinternal]rfx::frame%d", frame);
1379             
1380             if(!f && (tag->id == ST_DEFINEBUTTON || tag->id == ST_DEFINEBUTTON2 || stop_each_frame)) {
1381                 /* make the contructor add a frame script */
1382                 __ findpropstrict(c,"[package]::addFrameScript");
1383                 __ pushbyte(c,frame);
1384                 __ getlex(c,framename);
1385                 __ callpropvoid(c,"[package]::addFrameScript",2);
1386
1387                 f = abc_class_method(cls, 0, multiname_fromstring(framename))->body;
1388                 f->old.max_stack = 3;
1389                 f->old.local_count = 1;
1390                 f->old.init_scope_depth = 10;
1391                 f->old.max_scope_depth = 11;
1392                 __ debugfile(f, "framescript.as");
1393                 __ debugline(f, 1);
1394                 __ getlocal_0(f);
1395                 __ pushscope(f);
1396                 if(stop_each_frame) {
1397                     __ findpropstrict(f, "[package]::stop");
1398                     __ callpropvoid(f, "[package]::stop", 0);
1399                 }
1400             }
1401
1402             if(tag->id == ST_DEFINEBUTTON || tag->id == ST_DEFINEBUTTON2) {
1403                 U16 id = swf_GetDefineID(tag);
1404                 sprintf(buttonname, "::button%d", swf_GetDefineID(tag));
1405                 __ getlex(f,buttonname);
1406                 __ getlex(f,"flash.events::MouseEvent");
1407                 __ getproperty(f, "::CLICK");
1408                 sprintf(functionname, "::clickbutton%d", swf_GetDefineID(tag));
1409                 __ getlex(f,functionname);
1410                 __ callpropvoid(f, "::addEventListener" ,2);
1411
1412                 needs_framescript = 1;
1413
1414                 abc_method_body_t*h =
1415                     abc_class_method(cls, 0, multiname_fromstring(functionname))->body;
1416                 list_append(h->method->parameters, multiname_fromstring("flash.events::MouseEvent"));
1417
1418                 h->old.max_stack = 6;
1419                 h->old.local_count = 2;
1420                 h->old.init_scope_depth = 10;
1421                 h->old.max_scope_depth = 11;
1422                 __ getlocal_0(h);
1423                 __ pushscope(h);
1424
1425                 ActionTAG*oldaction = swf_ButtonGetAction(tag);
1426                 if(oldaction && oldaction->op == ACTION__GOTOFRAME) {
1427                     int framenr = GET16(oldaction->data);
1428                     if(framenr>254) {
1429                         fprintf(stderr, "Warning: Couldn't translate jump to frame %d to flash 9 actionscript\n", framenr);
1430                     }
1431                     if(!events) {
1432                         __ findpropstrict(h,"[package]::gotoAndStop");
1433                         __ pushbyte(h,framenr+1);
1434                         __ callpropvoid(h,"[package]::gotoAndStop", 1);
1435                     } else {
1436                         char framename[80];
1437                         sprintf(framename, "frame%d", framenr);
1438                         __ getlocal_0(h); //this
1439                         __ findpropstrict(h, "[package]flash.events::TextEvent");
1440                         __ pushstring(h, "link");
1441                         __ pushtrue(h);
1442                         __ pushtrue(h);
1443                         __ pushstring(h, framename);
1444                         __ constructprop(h,"[package]flash.events::TextEvent", 4);
1445                         __ callpropvoid(h,"[package]::dispatchEvent", 1);
1446                     }
1447                 } else if(oldaction && oldaction->op == ACTION__GETURL) {
1448                     if(!events) {
1449                         __ findpropstrict(h,"flash.net::navigateToURL");
1450                         __ findpropstrict(h,"flash.net::URLRequest");
1451                         // TODO: target _blank
1452                         __ pushstring(h,oldaction->data); //url
1453                         __ constructprop(h,"flash.net::URLRequest", 1);
1454                         __ callpropvoid(h,"flash.net::navigateToURL", 1);
1455                     } else {
1456                         __ getlocal_0(h); //this
1457                         __ findpropstrict(h, "[package]flash.events::TextEvent");
1458                         __ pushstring(h, "link");
1459                         __ pushtrue(h);
1460                         __ pushtrue(h);
1461                         __ pushstring(h,oldaction->data); //url
1462                         __ constructprop(h,"[package]flash.events::TextEvent", 4);
1463                         __ callpropvoid(h,"[package]::dispatchEvent", 1);
1464                     }
1465                 } else if(oldaction) {
1466                     fprintf(stderr, "Warning: Couldn't translate button code of button %d to flash 9 abc action\n", id);
1467                 }
1468                 __ returnvoid(h);
1469                 swf_ActionFree(oldaction);
1470             }
1471             if(tag->id == ST_SHOWFRAME) {
1472                 if(f) {
1473                     __ returnvoid(f);
1474                     f = 0;
1475                 }
1476                 frame++;
1477             }
1478             tag = tag->next;
1479         }
1480         if(f) {
1481             __ returnvoid(f);
1482         }
1483     }
1484     __ returnvoid(c);
1485
1486     tag = swf->firstTag;
1487     while(tag) {
1488         if(tag->id == ST_DEFINEBUTTON || tag->id == ST_DEFINEBUTTON2) {
1489             char buttonname[80];
1490             sprintf(buttonname, "::button%d", swf_GetDefineID(tag));
1491             multiname_t*s = multiname_fromstring(buttonname);
1492             //abc_class_slot(cls, multiname_fromstring(buttonname), s);
1493             abc_class_slot(cls, multiname_fromstring(buttonname), 
1494                                 multiname_fromstring("flash.display::SimpleButton"));
1495         }
1496         tag = tag->next;
1497     }
1498
1499
1500     abc_script_t*s = abc_initscript(file);
1501     c = s->method->body;
1502     c->old.max_stack = 2;
1503     c->old.local_count = 1;
1504     c->old.init_scope_depth = 1;
1505     c->old.max_scope_depth = 9;
1506
1507     __ getlocal_0(c);
1508     __ pushscope(c);
1509     __ getscopeobject(c, 0);
1510     __ getlex(c,"::Object");
1511     __ pushscope(c);
1512     __ getlex(c,"flash.events::EventDispatcher");
1513     __ pushscope(c);
1514     __ getlex(c,"flash.display::DisplayObject");
1515     __ pushscope(c);
1516     __ getlex(c,"flash.display::InteractiveObject");
1517     __ pushscope(c);
1518     __ getlex(c,"flash.display::DisplayObjectContainer");
1519     __ pushscope(c);
1520     __ getlex(c,"flash.display::Sprite");
1521     __ pushscope(c);
1522     __ getlex(c,"flash.display::MovieClip");
1523     __ pushscope(c);
1524     __ getlex(c,"flash.display::MovieClip");
1525     __ newclass(c,cls);
1526     __ popscope(c);
1527     __ popscope(c);
1528     __ popscope(c);
1529     __ popscope(c);
1530     __ popscope(c);
1531     __ popscope(c);
1532     __ popscope(c);
1533     __ initproperty(c,"rfx::MainTimeline");
1534     __ returnvoid(c);
1535
1536     //abc_method_body_addClassTrait(c, "rfx:MainTimeline", 1, cls);
1537     multiname_t*classname = multiname_fromstring("rfx::MainTimeline");
1538     abc_initscript_addClassTrait(s, classname, cls);
1539     multiname_destroy(classname);
1540
1541     swf_WriteABC(abctag, file);
1542 }
1543
1544 TAG*swf_AddAS3FontDefine(TAG*tag, U16 id, char*fontname)
1545 {
1546     tag = swf_InsertTag(tag, ST_DOABC);
1547     abc_file_t*file = abc_file_new();
1548
1549     //abc_class_t*cls = abc_class_new2(file, fontname, "flash.display::MovieClip");
1550     //abc_class_slot(cls, multiname_fromstring(fontname), multiname_fromstring("flash.text::Font"));
1551
1552     abc_class_t*cls = abc_class_new2(file, fontname, "flash.text::Font");
1553
1554     abc_script_t*s = abc_initscript(file);
1555     code_t*c = s->method->body->code;
1556     c = abc_getlocal_0(c);
1557     c = abc_pushscope(c);
1558     c = abc_getscopeobject(c, 0);
1559     c = abc_getlex(c,"flash.text::Font");
1560     c = abc_pushscope(c);
1561     c = abc_getlex(c,"flash.text::Font");
1562     c = abc_newclass(c,cls);
1563     c = abc_popscope(c);
1564     c = abc_initproperty(c, fontname);
1565     c = abc_returnvoid(c);
1566     s->method->body->code = c;
1567
1568     abc_initscript_addClassTrait(s, multiname_fromstring(fontname), cls);
1569     swf_WriteABC(tag, file);
1570         
1571     tag = swf_InsertTag(tag, ST_SYMBOLCLASS);
1572     swf_SetU16(tag, 1);
1573     swf_SetU16(tag, id);
1574     swf_SetString(tag, fontname);
1575
1576     return tag;
1577 }
1578
1579