added flash8->flash9 actionscript link conversion
[swftools.git] / lib / modules / swfabc.c
1 /* swfabc.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) 2007,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 "swfabc.h"
28
29 char stringbuffer[2048];
30
31 dict_t* dict_new() {
32     dict_t*d = malloc(sizeof(dict_t));
33     memset(d, 0, sizeof(dict_t));
34     return d;
35 }
36
37 void dict_free(dict_t*dict) {
38     if(dict->d)
39     free(dict->d);dict->d = 0;
40     free(dict);
41 }
42
43 const char*dict_getstr(dict_t*dict, int nr) {
44     if(nr > dict->num || nr<0) {
45         printf("error: reference to string %d in dict\n");
46         return 0;
47     }
48     return dict->d[nr].name;
49 }
50 char*dict_getdata(dict_t*dict, int nr) {
51     if(nr > dict->num || nr<0) {
52         printf("error: reference to string %d in dict\n");
53         return 0;
54     }
55     return dict->d[nr].data;
56 }
57 int dict_append(dict_t*dict, const char*name, void*data) {
58     while(dict->size <= dict->num) {
59         dict->size += 64;
60         if(!dict->d) {
61             dict->d = malloc(sizeof(dict_entry_t)*dict->size);
62         } else {
63             dict->d = realloc(dict->d, sizeof(dict_entry_t)*dict->size);
64         }
65     }
66     if(name) {
67         dict->d[dict->num].name = strdup(name);
68     } else {
69         dict->d[dict->num].name = 0;
70     }
71     dict->d[dict->num].data = data;
72     return dict->num++;
73 }
74 int dict_find(dict_t*dict, const char*name)
75 {
76     if(!name)
77         name = "";
78     int t;
79     for(t=0;t<dict->num;t++) {
80         if(dict->d[t].name && !strcmp(dict->d[t].name,name))
81             return t;
82     }
83     return -1;
84 }
85 int dict_find2(dict_t*dict, const char*name, void*data)
86 {
87     if(!name)
88         name = "";
89     int t;
90     for(t=0;t<dict->num;t++) {
91         if(dict->d[t].name && !strcmp(dict->d[t].name,name) && dict->d[t].data == data)
92             return t;
93     }
94     return -1;
95 }
96 int dict_update(dict_t*dict, const char*name, void*data) {
97     int pos = dict_find(dict, name);
98     if(pos>=0) {
99         dict->d[pos].data = data;
100         return pos;
101     }
102     return dict_append(dict, name, data);
103 }
104 int dict_append_if_new(dict_t*dict, const char*name, void*data) {
105     int pos = dict_find(dict, name);
106     if(pos>=0)
107         return pos;
108     return dict_append(dict, name, data);
109 }
110 int dict_append_if_new2(dict_t*dict, const char*name, void*data) {
111     int pos = dict_find2(dict, name, data);
112     if(pos>=0)
113         return pos;
114     return dict_append(dict, name, data);
115 }
116
117 typedef struct _commonlist {
118     void*entry;
119     struct _commonlist*next;
120     struct _commonlist*last[0];
121 } commonlist_t;
122
123 int list_length(void*_list)
124 {
125     commonlist_t*l = (commonlist_t*)_list;
126     int n=0;
127     while(l) {
128         l = l->next;
129         n++;
130     }
131     return n;
132 }
133 void list_append(void*_list, void*entry)
134 {
135     commonlist_t**list = (commonlist_t**)_list;
136     commonlist_t* n = 0;
137     if(!*list) {
138         n = malloc(sizeof(commonlist_t)+sizeof(commonlist_t*));
139         *list = n;
140     } else {
141         n = malloc(sizeof(commonlist_t));
142         (*list)->last[0]->next = n;
143     }
144     n->next = 0;
145     n->entry = entry;
146     (*list)->last[0] = n;
147 }
148
149 int swf_GetU30(TAG*tag)
150 {
151     U32 shift = 0;
152     U32 s = 0;
153     while(1) {
154         U8 b = swf_GetU8(tag);
155         s|=(b&127)<<shift;
156         shift+=7;
157         if(!(b&128))
158             break;
159     }
160     return s;
161 }
162
163 int swf_GetS30(TAG*tag)
164 {
165     U32 shift = 0;
166     U32 s = 0;
167     while(1) {
168         U8 b = swf_GetU8(tag);
169         s|=(b&127)<<shift;
170         shift+=7;
171         if(!(b&128)) {
172             if(b&64) {
173                 s|=0xffffffff<<shift;
174             }
175             break;
176         }
177     }
178     return s;
179 }
180
181 double swf_GetD64(TAG*tag)
182 {
183     double value = *(double*)&tag->data[tag->pos];
184     swf_GetU32(tag);
185     swf_GetU32(tag);
186     return value;
187 }
188
189
190 typedef struct _opcode
191 {
192     unsigned char opcode;
193     char*name;
194     char*params;
195 } opcode_t;
196
197 /* 2 = multiname
198    m = method
199    n = number of params
200    i = method info
201    b = byte
202    s = short
203    c = class
204    s = string
205    S = switch
206 */
207
208 int abc_RegisterNameSpace(abc_file_t*file, const char*name);
209 int abc_RegisterPackageNameSpace(abc_file_t*file, const char*name);
210 int abc_RegisterPackageInternalNameSpace(abc_file_t*file, const char*name);
211 int abc_RegisterProtectedNameSpace(abc_file_t*file, const char*name);
212 int abc_RegisterExplicitNameSpace(abc_file_t*file, const char*name);
213 int abc_RegisterStaticProtectedNameSpace(abc_file_t*file, const char*name);
214 int abc_RegisterPrivateNameSpace(abc_file_t*file, const char*name);
215
216
217 opcode_t opcodes[]={
218 {0xa0, "add", ""},
219 {0xc5, "add_i", ""},
220 {0x86, "atype", "2"},
221 {0x87, "astypelate", ""},
222 {0xA8, "bitand", ""},
223 {0x97, "bitnot", ""},
224 {0xa9, "bitor", ""},
225 {0xaa, "bitxor", ""},
226 {0x41, "call", "n"},
227 {0x43, "callmethod", "mn"},
228 {0x4c, "callproplex", "2n"},
229 {0x46, "callproperty", "2n"},
230 {0x4f, "callpropvoid", "2n"},
231 {0x44, "callstatic", "in"},
232 {0x45, "callsuper", "2n"},
233 {0x4e, "callsupervoid", "2n"},
234 {0x78, "checkfilter", ""},
235 {0x80, "coerce", "m"},
236 {0x82, "coerce_a", ""},
237 {0x85, "coerce_s", ""},
238 {0x42, "construct", "n"},
239 {0x4a, "constructprop", "2n"},
240 {0x49, "constructsuper", "n"},
241 {0x76, "convert_b", ""},
242 {0x73, "convert_i", ""},
243 {0x75, "convert_d", ""},
244 {0x77, "convert_o", ""},
245 {0x74, "convert_u", ""},
246 {0x70, "convert_s", ""},
247 {0xef, "debug", "bsbu"},
248 {0xf1, "debugfile", "s"},
249 {0xf0, "debugline", "u"},
250 {0x94, "declocal", "u"},
251 {0xc3, "declocal_i", "u"},
252 {0x93, "decrement", ""},
253 {0xc1, "decrement_i", ""},
254 {0x6a, "deleteproperty", "2"},
255 {0xa3, "divide", ""},
256 {0x2a, "dup", ""},
257 {0x06, "dxns", "s"},
258 {0x07, "dxnslate", ""},
259 {0xab, "equals", ""},
260 {0x72, "esc_xattr", ""},
261 {0x71, "esc_xelem", ""},
262 {0x5e, "findproperty", "2"},
263 {0x5d, "findpropstrict", "2"},
264 {0x59, "getdescendants", "2"},
265 {0x64, "getglobalscope", ""},
266 {0x6e, "getglobalslot", "u"},
267 {0x60, "getlex", "2"},
268 {0x62, "getlocal", "u"},
269 {0xd0, "getlocal_0", ""},
270 {0xd1, "getlocal_1", ""},
271 {0xd2, "getlocal_2", ""},
272 {0xd3, "getlocal_3", ""},
273 {0x66, "getproperty", "2"},
274 {0x65, "getscopeobject", "u"},
275 {0x6c, "getslot", "u"},
276 {0x04, "getsuper", "2"},
277 {0xaf, "greaterequals", ""},
278 {0x1f, "hasnext", ""},
279 {0x32, "hasnext2", "uu"},
280 {0x13, "ifeq", "j"},
281 {0x12, "iffalse", "j"},
282 {0x18, "ifge", "j"},
283 {0x17, "ifgt", "j"},
284 {0x16, "ifle", "j"},
285 {0x15, "iflt", "j"},
286 {0x0f, "ifnge", "j"},
287 {0x0e, "ifngt", "j"},
288 {0x0d, "ifnle", "j"},
289 {0x0c, "ifnlt", "j"},
290 {0x14, "ifne", "j"},
291 {0x19, "ifstricteq", "j"},
292 {0x1a, "ifstrictne", "j"},
293 {0x11, "iftrue", "j"},
294 {0xb4, "in", ""},
295 {0x92, "inclocal", "u"},
296 {0xc2, "inclocal_i", "u"},
297 {0x91, "increment", ""},
298 {0xc0, "increment_i", ""},
299 {0x68, "initproperty", "2"},
300 {0xb1, "instanceof", ""},
301 {0xb2, "istype", "2"},
302 {0xb3, "istypelate", ""},
303 {0x10, "jump", "j"},
304 {0x08, "kill", "u"},
305 {0x09, "label", ""},
306 {0xae, "lessequals", ""},
307 {0xad, "lessthan", ""},
308 {0x1b, "lookupswitch", "S"},
309 {0xa5, "lshift", ""},
310 {0xa4, "modulo", ""},
311 {0xa2, "multiply", ""},
312 {0xc7, "multiply_i", ""},
313 {0x90, "negate", ""},
314 {0xc4, "negate_i", ""},
315 {0x57, "newactivation", ""},
316 {0x56, "newarray", "u"},
317 {0x5a, "newcatch", "u"}, //index into exception_info
318 {0x58, "newclass", "c"}, //index into class_info
319 {0x40, "newfunction", "u"}, //index into method_info
320 {0x55, "newobject", "u"},
321 {0x1e, "nextname", ""},
322 {0x23, "nextvalue", ""},
323 {0x02, "nop", ""},
324 {0x96, "not", ""},
325 {0x29, "pop", ""},
326 {0x1d, "popscope", ""},
327 {0x24, "pushbyte", "b"},
328 {0x2f, "pushdouble", "u"}, //index into floats
329 {0x27, "pushfalse", ""},
330 {0x2d, "pushint", "u"}, //index into ints
331 {0x31, "pushnamespace", "u"}, //index into namespace
332 {0x28, "pushnan", ""},
333 {0x20, "pushnull", ""},
334 {0x30, "pushscope", ""},
335 {0x25, "pushshort", "u"},
336 {0x2c, "pushstring", "s"},
337 {0x26, "pushtrue", ""},
338 {0x2e, "pushuint", "u"}, //index into uints
339 {0x21, "pushundefined", ""},
340 {0x1c, "pushwith", ""},
341 {0x48, "returnvalue", ""},
342 {0x47, "returnvoid", ""},
343 {0xa6, "rshift", ""},
344 {0x63, "setlocal", "u"},
345 {0xd4, "setlocal_0", ""},
346 {0xd5, "setlocal_1", ""},
347 {0xd6, "setlocal_2", ""},
348 {0xd7, "setlocal_3", ""},
349 {0x6f, "setglobalshot", "u"},
350 {0x61, "setproperty", "2"},
351 {0x6d, "setslot", "u"},
352 {0x05, "setsuper", "2"},
353 {0xac, "strictequals", ""},
354 {0xa1, "subtract", ""},
355 {0xc6, "subtract_i", ""},
356 {0x2b, "swap", ""},
357 {0x03, "throw", ""},
358 {0x95, "typeof", ""},
359 {0xa7, "urshift", ""},
360 {0xb0, "xxx", ""},
361 };
362
363 int swf_GetU24(TAG*tag)
364 {
365     int b1 = swf_GetU8(tag);
366     int b2 = swf_GetU8(tag);
367     int b3 = swf_GetU8(tag);
368     return b3<<16|b2<<8|b1;
369 }
370 int swf_GetS24(TAG*tag)
371 {
372     int b1 = swf_GetU8(tag);
373     int b2 = swf_GetU8(tag);
374     int b3 = swf_GetU8(tag);
375     if(b3&0x80) {
376         return -1-((b3<<16|b2<<8|b1)^0xffffff);
377     } else {
378         return b3<<16|b2<<8|b1;
379     }
380 }
381 static int parse_code(TAG*tag, int len, abc_file_t*pool, char*prefix)
382 {
383     int end=tag->pos+len;
384     while(tag->pos<end) {
385         U8 opcode = swf_GetU8(tag);
386         int t;
387         char found = 0;
388         for(t=0;t<sizeof(opcodes)/sizeof(opcodes[0]);t++) {
389             if(opcodes[t].opcode == opcode) {
390                 printf("%s%s ", prefix, opcodes[t].name);
391                 char*p = opcodes[t].params;
392                 char first = 1;
393                 while(*p) {
394                     if(!first)
395                         printf(", ");
396                     if(*p == 'n') {
397                         int n = swf_GetU30(tag);
398                         printf("%d params", n);
399                     } else if(*p == '2') {
400                         const char* m = dict_getstr(pool->multinames, swf_GetU30(tag));
401                         printf("%s", m);
402                     } else if(*p == 'm') {
403                         int n = swf_GetU30(tag);
404                         printf("[method%d]", n);
405                     } else if(*p == 'c') {
406                         int n = swf_GetU30(tag);
407                         abc_class_t*cls = (abc_class_t*)dict_getdata(pool->classes, n);
408                         printf("[classinfo%d %s]", n, cls->classname);
409                     } else if(*p == 'i') {
410                         int n = swf_GetU30(tag);
411                         printf("[methodbody%d]", n);
412                     } else if(*p == 'u') {
413                         int n = swf_GetU30(tag);
414                         printf("%d", n);
415                     } else if(*p == 'b') {
416                         int b = swf_GetU8(tag);
417                         printf("%02x", b);
418                     } else if(*p == 'j') {
419                         printf("%d", swf_GetS24(tag));
420                     } else if(*p == 's') {
421                         const char*s = dict_getstr(pool->strings, swf_GetU30(tag));
422                         printf("\"%s\"", s);
423                     } else if(*p == 'S') {
424                         swf_GetU24(tag); //default
425                         int num = swf_GetU30(tag)+1;
426                         int t;
427                         for(t=0;t<num;t++) 
428                             swf_GetU24(tag);
429                     } else {
430                         printf("Can't parse opcode param type \"%c\"\n", *p);
431                         return 0;
432                     }
433                     p++;
434                     first = 0;
435                 }
436                 found = 1;
437                 break;
438             }
439         }
440         if(!found) {
441             printf("Can't parse opcode %02x\n", opcode);
442             return 0;
443         }
444         printf("\n");
445     }
446     if(tag->pos!=end) {
447         printf("Read beyond end of ABC Bytecode\n");
448         return 0;
449     }
450     return 1;
451 }
452
453 static char* access2str(int type)
454 {
455     if(type==0x08) return "";
456     else if(type==0x16) return "package";
457     else if(type==0x17) return "packageinternal";
458     else if(type==0x18) return "protected";
459     else if(type==0x19) return "explicit";
460     else if(type==0x1A) return "staticprotected";
461     else if(type==0x05) return "private";
462     else return "undefined";
463 }
464
465
466 char* multiname_to_string(abc_multiname_t*m)
467 {
468     char*mname = 0;
469     if(m->type==0x07 || m->type==0x0d) {
470         mname = malloc(strlen(m->ns->name)+strlen(m->name)+32);
471         sprintf(mname, "<%s>\0", access2str(m->ns->access));
472         strcat(mname, m->ns->name);
473         strcat(mname, "::");
474         strcat(mname, m->name);
475     } else if(m->type==0x0f || m->type==0x10) {
476         mname = strdup(m->name);
477     } else if(m->type==0x11 || m->type==0x12) {
478         mname = strdup("");
479     } else if(m->type==0x09 || m->type==0x0e) {
480         mname = malloc(strlen(m->namespace_set_name)+strlen(m->name)+16);
481         strcpy(mname, m->namespace_set_name);
482         strcat(mname, "::");
483         strcat(mname, m->name);
484     } else if(m->type==0x1b || m->type==0x1c) {
485         mname = strdup(m->namespace_set_name);
486     }
487     return mname;
488 }
489
490
491 static void dump_traits(const char*prefix, dict_t*traits, abc_file_t*pool);
492
493 static char* params_to_string(abc_multiname_list_t*list)
494 {
495     abc_multiname_list_t*l;
496     int n;
497
498     l = list;
499     n = 0;
500     while(list) {
501         n++;list=list->next;
502     }
503
504     char**names = (char**)malloc(sizeof(char*)*n);
505     
506     l = list;
507     n = 0;
508     int size = 0;
509     while(list) {
510         names[n] = multiname_to_string(list->abc_multiname);
511         size += strlen(names[n]) + 2;
512         n++;list=list->next;
513     }
514
515     char* params = malloc(size+5);
516     params[0]='(';
517     params[1]=0;
518     l = list;
519     int s=0;
520     n = 0;
521     while(list) {
522         if(s)
523             strcat(params, ", ");
524         strcat(params, names[n]);
525         free(names[n]);
526         n++;
527         s=1;
528     }
529     free(names);
530     strcat(params, ")");
531     int t;
532     return params;
533 }
534
535 static void dump_method(const char*prefix, const char*type, const char*name, int nr, abc_file_t*pool)
536 {
537     if(nr >= pool->methods->num) {
538         printf("Invalid method number: %d\n", nr);
539         return;
540     }
541     abc_method_t*m = (abc_method_t*)dict_getdata(pool->methods, nr);
542
543     const char*return_type = "";
544     if(m->return_type)
545         return_type = multiname_to_string(m->return_type);
546
547     char*paramstr = params_to_string(m->parameters);
548
549     printf("%s%s %s %s=%s %s\n", prefix, type, return_type, name, m->name, paramstr);
550
551     abc_method_body_t*c = (abc_method_body_t*)dict_getdata(pool->method_bodies, m->method_body_index);
552     
553     printf("%s[%d %d %d %d %d]\n", prefix, c->max_stack, c->local_count, c->init_scope_depth, c->max_scope_depth, c->exception_count);
554
555     swf_SetTagPos(c->tag, 0);
556     char prefix2[80];
557     sprintf(prefix2, "%s    ", prefix);
558     if(c->traits)
559         dump_traits(prefix, c->traits, pool);
560     printf("%s{\n", prefix);
561     parse_code(c->tag, c->tag->len, pool,prefix2);
562     printf("%s}\n\n", prefix);
563 }
564
565 //#define DEBUG
566 #define DEBUG if(0)
567
568 static void parse_metadata(TAG*tag, abc_file_t*pool)
569 {
570     int t;
571     int num_metadata = swf_GetU30(tag);
572     DEBUG printf("%d metadata\n");
573     for(t=0;t<num_metadata;t++) {
574         const char*name = dict_getstr(pool->strings, swf_GetU30(tag));
575         int num = swf_GetU30(tag);
576         int s;
577         DEBUG printf("  %s\n", name);
578         for(s=0;s<num;s++) {
579             const char*key = dict_getstr(pool->strings, swf_GetU30(tag));
580             const char*value = dict_getstr(pool->strings, swf_GetU30(tag));
581             DEBUG printf("    %s=%s\n", key, value);
582         }
583     }
584 }
585
586 #define TRAIT_SLOT 0
587 #define TRAIT_METHOD 1
588 #define TRAIT_GETTER 2
589 #define TRAIT_SETTER 3
590 #define TRAIT_CLASS 4
591 #define TRAIT_FUNCTION 5
592 #define TRAIT_CONST 6
593
594 static dict_t* traits_parse(TAG*tag, abc_file_t*pool)
595 {
596     int num_traits = swf_GetU30(tag);
597     dict_t*traits = dict_new();
598     int t;
599     if(num_traits) {
600         DEBUG printf("%d traits\n", num_traits);
601     }
602     
603     for(t=0;t<num_traits;t++) {
604         abc_trait_t*trait = malloc(sizeof(abc_trait_t));
605         memset(trait, 0, sizeof(abc_trait_t));
606         dict_append(traits, 0, trait);
607         trait->name_index = swf_GetU30(tag);
608         const char*name = dict_getstr(pool->multinames, trait->name_index);
609         U8 kind = trait->type = swf_GetU8(tag);
610         U8 attributes = kind&0xf0;
611         kind&=0x0f;
612         DEBUG printf("  trait %d) %s type=%02x\n", t, name, kind);
613         if(kind == 1 || kind == 2 || kind == 3) { // method / getter / setter
614             trait->disp_id = swf_GetU30(tag);
615             trait->nr = swf_GetU30(tag);
616             DEBUG printf("  method/getter/setter\n");
617         } else if(kind == 5) { // function
618             trait->slot_id =  swf_GetU30(tag);
619             trait->nr = swf_GetU30(tag);
620         } else if(kind == 4) { // class
621             trait->slot_id = swf_GetU30(tag);
622             trait->cls = swf_GetU30(tag);
623             DEBUG printf("  class %s %d %d\n", name, trait->slot_id, trait->cls);
624         } else if(kind == 0 || kind == 6) { // slot, const
625             /* a slot is a variable in a class that is shared amonst all instances
626                of the same type, but which has a unique location in each object 
627                (in other words, slots are non-static, traits are static)
628              */
629             trait->slot_id = swf_GetU30(tag);
630             const char*type_name = dict_getstr(pool->multinames, swf_GetU30(tag));
631             trait->vindex = swf_GetU30(tag);
632             if(trait->vindex) {
633                 trait->vkind = swf_GetU8(tag);
634             }
635             DEBUG printf("  slot %s %d %s (vindex=%d)\n", name, trait->slot_id, type_name, trait->vindex);
636         } else {
637             printf("    can't parse trait type %d\n", kind);
638             return 0;
639         }
640         if(attributes&0x40) {
641             int num = swf_GetU30(tag);
642             int s;
643             for(s=0;s<num;s++) {
644                 swf_GetU30(tag); //index into metadata array
645             }
646         }
647     }
648     return traits;
649 }
650
651 static void dump_traits(const char*prefix, dict_t*traits, abc_file_t*pool)
652 {
653     int num_traits = traits->num;
654     int t;
655     for(t=0;t<num_traits;t++) {
656         abc_trait_t*trait = (abc_trait_t*)dict_getdata(traits, t);
657         const char*name = dict_getstr(pool->multinames, trait->name_index);
658         U8 kind = trait->type;
659         U8 attributes = kind&0xf0;
660         kind&=0x0f;
661         if(kind == TRAIT_METHOD) {
662             dump_method(prefix, "method", name, trait->nr, pool);
663         } else if(kind == TRAIT_GETTER) {
664             dump_method(prefix, "getter", name, trait->nr, pool);
665         } else if(kind == TRAIT_SETTER) {
666             dump_method(prefix, "setter", name, trait->nr, pool);
667         } else if(kind == TRAIT_FUNCTION) { // function
668             dump_method(prefix, "function", name, trait->nr, pool);
669         } else if(kind == TRAIT_CLASS) { // class
670             abc_class_t*cls = (abc_class_t*)dict_getdata(pool->classes, trait->cls);
671             if(!cls) {
672                 printf("%sslot %d: class %s=class%d %d\n", prefix, trait->slot_id, name, trait->cls);
673             } else {
674                 printf("%sslot %d: class %s=%s\n", prefix, trait->slot_id, name, cls->classname);
675             }
676         } else if(kind == TRAIT_SLOT || kind == TRAIT_CONST) { // slot, const
677             int slot_id = trait->slot_id;
678             const char*type_name = dict_getstr(pool->multinames, trait->type_index);
679             printf("%sslot %s %d %s (vindex=%d)\n", prefix, name, trait->slot_id, type_name, trait->vindex);
680         } else {
681             printf("    can't dump trait type %d\n", kind);
682         }
683     }
684 }
685
686 void swf_CopyData(TAG*to, TAG*from, int len)
687 {
688     unsigned char*data = malloc(len);
689     swf_GetBlock(from, data, len);
690     swf_SetBlock(to, data, len);
691     free(data);
692 }
693
694 abc_file_t*abc_file_new()
695 {
696     abc_file_t*f = malloc(sizeof(abc_file_t));
697     memset(f, 0, sizeof(abc_file_t));
698
699     f->ints = dict_new();
700     dict_append(f->ints, 0, (void*)(ptroff_t)0);
701     f->uints = dict_new();
702     dict_append(f->uints, 0, (void*)(ptroff_t)0);
703     f->floats = dict_new();
704     dict_append(f->floats, 0, 0);
705     f->strings = dict_new();
706     dict_append(f->strings, "--<UNDEFINED_STRING>--", 0);
707     f->namespaces = dict_new();
708     dict_append(f->namespaces, "--<UNDEFINED_NAMESPACE>--", 0);
709     f->namespace_sets = dict_new();
710     dict_append(f->namespace_sets, "--<UNDEFINED_NSSET>--", 0);
711     f->sets = dict_new();
712     dict_append(f->sets, "--<UNDEFINED_SET>--", 0);
713     f->multinames = dict_new();
714     dict_append(f->multinames, "--<UNDEFINED_MULTINAME>--", 0);
715
716     // abc_file
717
718     f->methods = dict_new();
719     f->classes = dict_new();
720     f->scripts = dict_new();
721     f->method_bodies = dict_new();
722
723     return f;
724 }
725
726 static abc_namespace_t* namespace_new(U8 access, const char*name)
727 {
728     abc_namespace_t*ns = malloc(sizeof(abc_namespace_t));
729     memset(ns, 0, sizeof(abc_namespace_t));
730
731     if(access==0) { // autodetect access
732         char*n = strdup(name);
733         if(n[0] == '[') {
734             char*bracket = strchr(n, ']');
735             if(bracket) {
736                 *bracket = 0;
737                 char*a = n+1;
738                 name += (bracket-n)+1;
739                 if(!strcmp(a, "")) access=0x16;
740                 else if(!strcmp(a, "package")) access=0x16;
741                 else if(!strcmp(a, "packageinternal")) access=0x17;
742                 else if(!strcmp(a, "protected")) access=0x18;
743                 else if(!strcmp(a, "explicit")) access=0x19;
744                 else if(!strcmp(a, "staticprotected")) access=0x1a;
745                 else if(!strcmp(a, "private")) access=0x05;
746                 else {
747                     fprintf(stderr, "Undefined access level: [%s]\n", a);
748                     return 0;
749                 }
750             }
751         } else {
752             access = 0x16;
753         }
754         free(n);
755     }
756     ns->access = access;
757     ns->name = strdup(name);
758     return ns;
759 }
760 abc_namespace_t* abc_namespace(abc_file_t*file, const char*name) {
761     return namespace_new(0x08, name);
762 }
763 abc_namespace_t* abc_packagenamespace(abc_file_t*file, const char*name) {
764     return namespace_new(0x16 , name);
765 }
766 abc_namespace_t* abc_packageinternalnamespace(abc_file_t*file, const char*name) {
767     return namespace_new(0x17, name);
768 }
769 abc_namespace_t* abc_protectednamespace(abc_file_t*file, const char*name) {
770     return namespace_new(0x18, name);
771 }
772 abc_namespace_t* abc_explicitnamespace(abc_file_t*file, const char*name) {
773     return namespace_new(0x19, name);
774 }
775 abc_namespace_t* abc_staticprotectednamespace(abc_file_t*file, const char*name) {
776     return namespace_new(0x1a, name);
777 }
778 abc_namespace_t* abc_privatenamespace(abc_file_t*file, const char*name) {
779     return namespace_new(0x05, name);
780 }
781
782 static int multiname_index(abc_file_t*pool, const char*name2) 
783 {
784     if(!name2)
785         name2 = "::";
786     int pos = dict_find(pool->multinames, name2);
787     if(pos>=0)
788         return pos;
789
790     char*n = strdup(name2);
791     char*p = strstr(n, "::");
792     char*namespace=0,*name=0;
793     if(!p) {
794         if(strchr(n, ':')) {
795             fprintf(stderr, "Error: single ':' in name\n");
796         }
797         namespace = "";
798         name = n;
799     } else {
800         *p = 0;
801         namespace = n;
802         name = p+2;
803         if(strchr(namespace, ':')) {
804             fprintf(stderr, "Error: single ':' in namespace\n");
805         }
806         if(strchr(name, ':')) {
807             fprintf(stderr, "Error: single ':' in qualified name\n");
808         }
809     }
810
811     abc_multiname_t*m = malloc(sizeof(abc_multiname_t));
812     memset(m, 0, sizeof(abc_multiname_t));
813
814     m->type = QNAME;
815     m->namespace_set_name = 0;
816     m->ns = namespace_new(0, namespace);
817     m->name = name;
818     return dict_append(pool->multinames, name2, m);
819 }
820 static abc_multiname_t* multiname_fromstring(abc_file_t*pool, const char*name)
821 {
822     int i = multiname_index(pool, name);
823     return (abc_multiname_t*)dict_getdata(pool->multinames, i);
824 }
825
826
827 #define CLASS_SEALED 1
828 #define CLASS_FINAL 2
829 #define CLASS_INTERFACE 4
830 #define CLASS_PROTECTED_NS 8
831
832 abc_class_t* abc_class_new(abc_file_t*pool, char*classname, char*superclass) {
833     abc_class_t* c = malloc(sizeof(abc_class_t));
834     memset(c, 0, sizeof(abc_class_t));
835     c->index = dict_append(pool->classes, 0, c);
836     c->pool = pool;
837     c->classname = strdup(classname);
838     c->superclass = superclass?strdup(superclass):0;
839     c->flags = 0;
840     c->iinit = -1;
841     c->static_constructor_index = -1;
842     c->traits = dict_new();
843     return c;
844 }
845
846 void abc_class_sealed(abc_class_t*c)
847 {
848     c->flags |= CLASS_SEALED;
849 }
850 void abc_class_final(abc_class_t*c)
851 {
852     c->flags |= CLASS_FINAL;
853 }
854 void abc_class_interface(abc_class_t*c)
855 {
856     c->flags |= CLASS_INTERFACE;
857 }
858 void abc_class_protectedNS(abc_class_t*c, char*namespace)
859 {
860     c->protectedNS = namespace;
861     c->flags |= CLASS_PROTECTED_NS;
862 }
863
864 abc_method_body_t* add_method(abc_file_t*pool, abc_class_t*cls, char*returntype, int num_params, va_list va)
865 {
866     /* construct code (method body) object */
867     abc_method_body_t* c = malloc(sizeof(abc_method_body_t));
868     memset(c, 0, sizeof(abc_method_body_t));
869     c->index = dict_append(pool->method_bodies, 0, c);
870     c->tag = swf_InsertTag(0,0);
871     c->pool = pool;
872     c->traits = dict_new();
873
874     /* construct method object */
875     abc_method_t* m = malloc(sizeof(abc_method_t));
876     memset(m, 0, sizeof(abc_method_t));
877     m->index = dict_append(pool->methods, 0, m);
878     if(returntype && strcmp(returntype, "void")) {
879         m->return_type = multiname_fromstring(pool, returntype);
880     } else {
881         m->return_type = 0;
882     }
883     int t;
884     for(t=0;t<num_params;t++) {
885         const char*param = va_arg(va, const char*);
886         list_append(&m->parameters, multiname_fromstring(pool, param));
887     }
888
889     /* crosslink the two objects */
890     m->method_body_index = c->index;
891     c->method = m;
892
893     return c;
894 }
895
896 abc_method_body_t* abc_class_constructor(abc_class_t*cls, char*returntype, int num_params, ...) 
897 {
898     va_list va;
899     va_start(va, num_params);
900     abc_method_body_t* c = add_method(cls->pool, cls, returntype, num_params, va);
901     va_end(va);
902     cls->iinit = c->index;
903     return c;
904 }
905
906 abc_method_body_t* abc_class_staticconstructor(abc_class_t*cls, char*returntype, int num_params, ...) 
907 {
908     va_list va;
909     va_start(va, num_params);
910     abc_method_body_t* c = add_method(cls->pool, cls, returntype, num_params, va);
911     va_end(va);
912     cls->static_constructor_index = c->index;
913     return c;
914 }
915
916 abc_trait_t*trait_new(int type, int name_index, int data1, int data2, int vindex, int vkind)
917 {
918     abc_trait_t*trait = malloc(sizeof(abc_trait_t));
919     memset(trait, 0, sizeof(abc_trait_t));
920     trait->type = type;
921     trait->name_index = name_index;
922     trait->data1 = data1;
923     trait->data2 = data2;
924     trait->vindex = vindex;
925     trait->vkind = vkind;
926     return trait;
927 }
928
929 abc_method_body_t* abc_class_method(abc_class_t*cls, char*returntype, char*name, int num_params, ...)
930 {
931     abc_file_t*pool = cls->pool;
932     va_list va;
933     va_start(va, num_params);
934     abc_method_body_t* c = add_method(cls->pool, cls, returntype, num_params, va);
935     va_end(va);
936     dict_append(cls->traits, 0, trait_new(TRAIT_METHOD, multiname_index(pool, name), 0, c->method->index, 0, 0));
937     return c;
938 }
939
940 void abc_AddSlot(abc_class_t*cls, char*name, int slot, char*multiname)
941 {
942     abc_file_t*pool = cls->pool;
943     int i = multiname_index(pool, name);
944     dict_append(cls->traits, 0, trait_new(TRAIT_SLOT, i, slot, multiname_index(pool, multiname), 0, 0));
945 }
946
947 void abc_method_body_addClassTrait(abc_method_body_t*code, char*multiname, int slotid, abc_class_t*cls)
948 {
949     abc_file_t*pool = code->pool;
950     int i = multiname_index(pool, multiname);
951     abc_trait_t*trait = trait_new(TRAIT_CLASS, i, slotid, cls->index, 0, 0);
952     dict_append(code->traits, 0, trait);
953 }
954
955 /* notice: traits of a method (body) belonging to an init script
956    and traits of the init script are *not* the same thing */
957 void abc_initscript_addClassTrait(abc_script_t*script, char*multiname, int slotid, abc_class_t*cls)
958 {
959     abc_file_t*pool = script->pool;
960     int i = multiname_index(pool, multiname);
961     abc_trait_t*trait = trait_new(TRAIT_CLASS, i, slotid, cls->index, 0, 0);
962     dict_append(script->traits, 0, trait);
963 }
964
965 abc_script_t* abc_initscript(abc_file_t*pool, char*returntype, int num_params, ...) 
966 {
967     va_list va;
968     va_start(va, num_params);
969     abc_method_body_t* c = add_method(pool, 0, returntype, num_params, va);
970     abc_script_t* s = malloc(sizeof(abc_script_t));
971     s->method = c->method;
972     s->traits = dict_new();
973     s->pool = pool;
974     dict_append(pool->scripts, 0, s);
975     va_end(va);
976     return s;
977 }
978
979 void swf_SetU30(TAG*tag, U32 u)
980 {
981     do {
982         swf_SetU8(tag, (u&~0x7f?0x80:0) | (u&0x7F));
983         u>>=7;
984     } while(u);
985 }
986 void swf_SetU30String(TAG*tag, const char*str)
987 {
988     int l = strlen(str);
989     swf_SetU30(tag, l);
990     swf_SetBlock(tag, (void*)str, l);
991 }
992
993 static void write_traits(abc_file_t*pool, TAG*tag, dict_t*traits)
994 {
995     if(!traits) {
996         swf_SetU30(tag, 0);
997         return;
998     }
999     swf_SetU30(tag, traits->num);
1000     int s;
1001
1002     for(s=0;s<traits->num;s++) {
1003         abc_trait_t*trait = (abc_trait_t*)dict_getdata(traits, s);
1004         swf_SetU30(tag, trait->name_index);
1005         swf_SetU8(tag, trait->type);
1006         swf_SetU30(tag, trait->data1);
1007         swf_SetU30(tag, trait->data2);
1008         if(trait->type == 0) { //slot
1009             swf_SetU30(tag, trait->vindex);
1010             if(trait->vindex) {
1011                 swf_SetU8(tag, trait->vkind);
1012             }
1013         }
1014     }
1015 }
1016
1017 int register_multiname(abc_file_t*pool, abc_multiname_t*n)
1018 {
1019     if(!n)
1020         return 0;
1021     /* FIXME: might create duplicates */
1022     return dict_append_if_new2(pool->multinames, n->name, n);
1023 }
1024
1025 int register_namespace(abc_file_t*pool, abc_namespace_t*ns)
1026 {
1027     /* FIXME: might create duplicates */
1028     return dict_append_if_new2(pool->namespaces, ns->name, ns);
1029 }
1030
1031 static inline abc_multiname_t*multiname_lookup(abc_file_t*pool, int i)
1032 {
1033     return (abc_multiname_t*)dict_getdata(pool->multinames, i);
1034 }
1035
1036 void* swf_ReadABC(TAG*tag)
1037 {
1038     abc_file_t* pool = abc_file_new();
1039
1040     swf_SetTagPos(tag, 0);
1041     int t;
1042     if(tag->id == ST_DOABC) {
1043         /* the strange 72 tag from flex doesn't have abc flags */
1044         U32 abcflags = swf_GetU32(tag);
1045         DEBUG printf("flags=%08x\n", abcflags);
1046         char*classname = swf_GetString(tag);
1047     }
1048     U32 version = swf_GetU32(tag);
1049     if(version!=0x002e0010) {
1050         fprintf(stderr, "Warning: unknown AVM2 version %08x\n", version);
1051     }
1052
1053     int num_ints = swf_GetU30(tag);
1054     DEBUG printf("%d ints\n", num_ints);
1055     for(t=1;t<num_ints;t++) {
1056         S32 v = swf_GetU30(tag);
1057         DEBUG printf("int %d) %d\n", t, v);
1058         dict_append(pool->ints, 0, (void*)(ptroff_t)v);
1059     }
1060
1061     int num_uints = swf_GetU30(tag);
1062     DEBUG printf("%d uints\n", num_uints);
1063     for(t=1;t<num_uints;t++) {
1064         U32 v = swf_GetS30(tag);
1065         DEBUG printf("uint %d) %d\n", t, v);
1066         dict_append(pool->uints, 0, (void*)(ptroff_t)v);
1067     }
1068     
1069     int num_floats = swf_GetU30(tag);
1070     DEBUG printf("%d floats\n", num_floats);
1071     for(t=1;t<num_floats;t++) {
1072         double d = swf_GetD64(tag);
1073         DEBUG printf("float %d) %f\n", t, d);
1074         dict_append(pool->floats, 0, 0);
1075     }
1076     
1077     int num_strings = swf_GetU30(tag);
1078     DEBUG printf("%d strings\n", num_strings);
1079     for(t=1;t<num_strings;t++) {
1080         int len = swf_GetU30(tag);
1081         char*s = malloc(len+1);
1082         swf_GetBlock(tag, s, len);
1083         s[len] = 0;
1084         dict_append(pool->strings, s, 0);
1085         DEBUG printf("%d) \"%s\"\n", t, pool->strings->d[t].name);
1086     }
1087     int num_namespaces = swf_GetU30(tag);
1088     DEBUG printf("%d namespaces\n", num_namespaces);
1089     for(t=1;t<num_namespaces;t++) {
1090         U8 type = swf_GetU8(tag);
1091         int namenr = swf_GetU30(tag);
1092         const char*name = dict_getstr(pool->strings, namenr);
1093         abc_namespace_t*ns = malloc(sizeof(abc_namespace_t));
1094         memset(ns, 0, sizeof(abc_namespace_t));
1095         ns->access = type;
1096         ns->name = strdup(name);
1097         dict_append(pool->namespaces, name, ns);
1098         int w = 0;
1099         DEBUG w=1;
1100         if(w) {
1101             if(type==0x08) printf("Namespace %s\n", name);
1102             else if(type==0x16) printf("PackageNamespace %s\n", name);
1103             else if(type==0x17) printf("PackageInternalNs %s\n", name);
1104             else if(type==0x18) printf("ProtectedNamespace %s\n", name);
1105             else if(type==0x19) printf("ExplicitNamespace %s\n", name);
1106             else if(type==0x1A) printf("StaticProtectedNs %s\n", name);
1107             else if(type==0x05) printf("PrivateNs %s\n", name);
1108             else {
1109                 printf("Undefined namespace type\n");
1110                 return 0;
1111             }
1112         }
1113     }
1114     int num_sets = swf_GetU30(tag);
1115     DEBUG printf("%d namespace sets\n", num_sets);
1116     for(t=1;t<num_sets;t++) {
1117         int count = swf_GetU30(tag);
1118         int s;
1119         const char**name = malloc(sizeof(const char*)*count);
1120         int l = 0;
1121         for(s=0;s<count;s++) {
1122             int nsnr = swf_GetU30(tag);
1123             name[s] = dict_getstr(pool->namespaces, nsnr);
1124             l += strlen(name[s])+1;
1125         }
1126         char*desc = malloc(l+16);
1127         strcpy(desc, "{");
1128         for(s=0;s<count;s++) {
1129             strcat(desc, name[s]);
1130             strcat(desc, ",");
1131         }
1132         strcat(desc, "}");
1133         dict_append(pool->namespace_sets, desc, 0);
1134         DEBUG printf("set %d) %s\n", t, desc);
1135     }
1136
1137     int num_multinames = swf_GetU30(tag);
1138     DEBUG printf("%d multinames\n", num_multinames);
1139     for(t=1;t<num_multinames;t++) {
1140         abc_multiname_t*m = malloc(sizeof(abc_multiname_t));
1141         memset(m, 0, sizeof(abc_multiname_t));
1142
1143         m->type = swf_GetU8(tag);
1144
1145         if(m->type==0x07 || m->type==0x0d) {
1146             int nr1 = swf_GetU30(tag);
1147             m->ns = (abc_namespace_t*)dict_getdata(pool->namespaces, nr1);
1148             int name_index = swf_GetU30(tag);
1149             m->name = dict_getstr(pool->strings, name_index);
1150         } else if(m->type==0x0f || m->type==0x10) {
1151             int name_index = swf_GetU30(tag);
1152             m->name = dict_getstr(pool->strings, name_index);
1153         } else if(m->type==0x11 || m->type==0x12) {
1154         } else if(m->type==0x09 || m->type==0x0e) {
1155             int name_index = swf_GetU30(tag);
1156             int namespace_set_index = swf_GetU30(tag);
1157             m->name = dict_getstr(pool->strings, name_index);
1158             m->namespace_set_name = dict_getstr(pool->namespace_sets, namespace_set_index);
1159         } else if(m->type==0x1b || m->type==0x1c) {
1160             int namespace_set_index = swf_GetU30(tag);
1161             m->namespace_set_name = dict_getstr(pool->namespace_sets, namespace_set_index);
1162         } else {
1163             printf("can't parse type %d multinames yet\n", m->type);
1164             return 0;
1165         }
1166         char*mname = multiname_to_string(m);
1167         DEBUG printf("multiname %d) %s\n", t, mname);
1168         dict_append(pool->multinames, mname, m);
1169         free(mname);
1170     }
1171     
1172     int num_methods = swf_GetU30(tag);
1173     DEBUG printf("%d methods\n", num_methods);
1174     for(t=0;t<num_methods;t++) {
1175         abc_method_t*m = malloc(sizeof(abc_method_t));
1176         memset(m, 0, sizeof(*m));
1177         int param_count = swf_GetU30(tag);
1178         int return_type_index = swf_GetU30(tag);
1179         m->return_type = multiname_lookup(pool, return_type_index);
1180         m->index = t;
1181
1182         int s;
1183         for(s=0;s<param_count;s++) {
1184             int type_index = swf_GetU30(tag);
1185             list_append(&m->parameters, multiname_lookup(pool, type_index));
1186         }
1187
1188         int namenr = swf_GetU30(tag);
1189         m->name = "";
1190         if(namenr)
1191             m->name = dict_getstr(pool->strings, namenr);
1192
1193         m->flags = swf_GetU8(tag);
1194         
1195         DEBUG printf("method %d) %s flags=%02x\n", t, params_to_string(m->parameters), m->flags);
1196
1197         if(m->flags&0x08) {
1198             /* optional parameters */
1199             int num = swf_GetU30(tag);
1200             int s;
1201             for(s=0;s<num;s++) {
1202                 int val = swf_GetU30(tag);
1203                 U8 kind = swf_GetU8(tag); // specifies index type for "val"
1204             }
1205         }
1206         if(m->flags&0x80) {
1207             /* debug information- not used by avm2 */
1208             abc_multiname_list_t*l = m->parameters;
1209             while(l) {
1210                 m->name = dict_getstr(pool->strings, swf_GetU30(tag));
1211                 l = l->next;
1212             }
1213         }
1214         dict_append(pool->methods, m->name, m);
1215     }
1216             
1217     parse_metadata(tag, pool);
1218         
1219     /* skip classes, and scripts for now, and do the real parsing later */
1220     int num_classes = swf_GetU30(tag);
1221     int classes_pos = tag->pos;
1222     DEBUG printf("%d classes\n", num_classes);
1223     for(t=0;t<num_classes;t++) {
1224         abc_class_t*cls = malloc(sizeof(abc_class_t));
1225         memset(cls, 0, sizeof(abc_class_t));
1226         dict_append(pool->classes, 0, cls);
1227         
1228         DEBUG printf("class %d\n", t);
1229         swf_GetU30(tag); //classname
1230         swf_GetU30(tag); //supername
1231         cls->flags = swf_GetU8(tag);
1232         if(cls->flags&8) 
1233             swf_GetU30(tag); //protectedNS
1234         int s;
1235         int inum = swf_GetU30(tag); //interface count
1236         abc_multiname_list_t*list = 0;
1237         for(s=0;s<inum;s++) {
1238             int interface_index = swf_GetU30(tag);
1239             const char*interface = dict_getstr(pool->multinames, interface_index);
1240             abc_multiname_t* m = (abc_multiname_t*)dict_getdata(pool->multinames, interface_index);
1241             list_append(&list, m);
1242             DEBUG printf("  class %d interface: %s\n", t, interface);
1243         }
1244
1245         cls->iinit = swf_GetU30(tag);
1246         cls->traits = traits_parse(tag, pool);
1247     }
1248     for(t=0;t<num_classes;t++) {
1249         abc_class_t*cls = (abc_class_t*)dict_getdata(pool->classes, t);
1250         cls->static_constructor_index = swf_GetU30(tag); // cinit
1251         cls->static_constructor_traits = traits_parse(tag, pool);
1252     }
1253     int num_scripts = swf_GetU30(tag);
1254     DEBUG printf("%d scripts\n", num_scripts);
1255     for(t=0;t<num_scripts;t++) {
1256         int init = swf_GetU30(tag);
1257         dict_t*traits = traits_parse(tag, pool); //TODO: store
1258     }
1259
1260     int num_method_bodies = swf_GetU30(tag);
1261     DEBUG printf("%d method bodies\n", num_method_bodies);
1262     for(t=0;t<num_method_bodies;t++) {
1263         int methodnr = swf_GetU30(tag);
1264         if(methodnr >= pool->methods->num) {
1265             printf("Invalid method number: %d\n", methodnr);
1266             return 0;
1267         }
1268         abc_method_t*m = (abc_method_t*)dict_getdata(pool->methods, methodnr);
1269         abc_method_body_t*c = malloc(sizeof(abc_method_body_t));
1270         memset(c, 0, sizeof(abc_method_body_t));
1271         c->max_stack = swf_GetU30(tag);
1272         c->local_count = swf_GetU30(tag);
1273         c->init_scope_depth = swf_GetU30(tag);
1274         c->max_scope_depth = swf_GetU30(tag);
1275         int code_length = swf_GetU30(tag);
1276         c->method = m;
1277         m->method_body_index = t;
1278
1279         c->tag = swf_InsertTag(0,0);
1280
1281         swf_CopyData(c->tag, tag, code_length);
1282
1283         int exception_count = swf_GetU30(tag);
1284         int s;
1285         for(s=0;s<exception_count;s++) {
1286             swf_GetU30(tag); //from
1287             swf_GetU30(tag); //to
1288             swf_GetU30(tag); //target
1289             swf_GetU30(tag); //exc_type
1290             swf_GetU30(tag); //var_name
1291         }
1292         c->traits = traits_parse(tag, pool);
1293         if(!c->traits) {
1294             fprintf(stderr, "Can't parse code traits\n");
1295             return 0;
1296         }
1297         DEBUG printf("method_body %d) (method %d), %d bytes of code", t, methodnr, code_length);
1298         int r,l = code_length>32?32:code_length;
1299         for(r=0;r<l;r++) {
1300             DEBUG printf("%02x ", c->tag->data[r]);
1301         }
1302         DEBUG printf("\n");
1303
1304         dict_append(pool->method_bodies, 0, c);
1305     }
1306     if(tag->len - tag->pos) {
1307         fprintf(stderr, "%d unparsed bytes remaining in ABC block\n", tag->len - tag->pos);
1308         return 0;
1309     }
1310
1311     swf_SetTagPos(tag, classes_pos);
1312     for(t=0;t<num_classes;t++) {
1313         abc_class_t*cls = (abc_class_t*)dict_getdata(pool->classes, t);
1314
1315         int classname_index = swf_GetU30(tag);
1316         int superclass_index = swf_GetU30(tag);
1317         cls->classname = dict_getstr(pool->multinames, classname_index);
1318         cls->superclass = dict_getstr(pool->multinames, superclass_index);
1319         cls->flags = swf_GetU8(tag);
1320         const char*ns = "";
1321         if(cls->flags&8) {
1322             int ns_index = swf_GetU30(tag);
1323             cls->protectedNS = dict_getstr(pool->namespaces, ns_index);
1324         }
1325         
1326         if(cls->flags&1) printf("sealed ");
1327         if(cls->flags&2) printf("final ");
1328         if(cls->flags&4) printf("interface ");
1329         if(cls->flags&8) {
1330             printf("protectedNS<%s> ", cls->protectedNS);
1331         }
1332
1333         printf("class %s", cls->classname);
1334         if(cls->superclass && cls->superclass[0]) {
1335             printf(" extends %s", cls->superclass);
1336             abc_multiname_list_t*ilist = cls->interfaces;
1337             if(ilist)
1338                 printf(" implements");
1339             while(ilist) {
1340                 char*s = multiname_to_string(ilist->abc_multiname);
1341                 printf(" %d", s);
1342                 free(s);
1343                 ilist = ilist->next;
1344             }
1345             ilist->next;
1346             
1347         }
1348         if(cls->flags&0xf0) 
1349             printf("extra flags=%02x\n", cls->flags&0xf0);
1350         printf("{\n");
1351         
1352         dump_method("    ","staticconstructor", "", cls->static_constructor_index, pool);
1353         dump_traits("    ", cls->static_constructor_traits, pool);
1354         
1355         int num_interfaces = swf_GetU30(tag); //interface count
1356         int s;
1357         for(s=0;s<num_interfaces;s++) {
1358             swf_GetU30(tag); // multiname index TODO
1359         }
1360         cls->iinit = swf_GetU30(tag);
1361         dump_method("    ","constructor", cls->classname, cls->iinit, pool);
1362         cls->traits = traits_parse(tag, pool);
1363         if(!cls->traits) {
1364             fprintf(stderr, "Can't parse class traits\n");
1365             return 0;
1366         }
1367         dump_traits("    ",cls->traits, pool);
1368         
1369         printf("}\n");
1370     }
1371     for(t=0;t<num_classes;t++) {
1372         /* SKIP */
1373         swf_GetU30(tag); // cindex
1374         traits_parse(tag, pool); // TODO: free
1375     }
1376     int num_scripts2 = swf_GetU30(tag);
1377     printf("\n");
1378     for(t=0;t<num_scripts2;t++) {
1379         int init = swf_GetU30(tag);
1380         abc_method_t*m = (abc_method_t*)dict_getdata(pool->methods, init);
1381         
1382         abc_script_t*s = malloc(sizeof(abc_script_t));
1383         memset(s, 0, sizeof(abc_script_t));
1384         s->method = m;
1385         s->traits = traits_parse(tag, pool);
1386         dict_append(pool->scripts, 0, s);
1387         if(!s->traits) {
1388             fprintf(stderr, "Can't parse script traits\n");
1389             return 0;
1390         }
1391         dump_method("","initmethod", "init", init, pool);
1392         dump_traits("", s->traits, pool);
1393     }
1394     return pool;
1395 }
1396
1397 void swf_WriteABC(TAG*abctag, void*code)
1398 {
1399     abc_file_t*pool = (abc_file_t*)code;
1400
1401     TAG*tmp = swf_InsertTag(0,0);
1402     TAG*tag = tmp;
1403     int t;
1404
1405     swf_SetU30(tag, pool->methods->num);
1406     for(t=0;t<pool->methods->num;t++) {
1407         abc_method_t*m = (abc_method_t*)dict_getdata(pool->methods, t);
1408         int n = 0;
1409         abc_multiname_list_t*l = m->parameters;
1410         swf_SetU30(tag, list_length(m->parameters));
1411         swf_SetU30(tag, register_multiname(pool, m->return_type));
1412         int s;
1413         while(l) {
1414             swf_SetU30(tag, register_multiname(pool, l->abc_multiname));
1415             l = l->next;
1416         }
1417         swf_SetU30(tag, 0); // name
1418         swf_SetU8(tag, 0); //flags
1419     }
1420     
1421     swf_SetU30(tag, 0);//metadata
1422
1423     swf_SetU30(tag, pool->classes->num);
1424
1425     for(t=0;t<pool->classes->num;t++) {
1426         abc_class_t*c = (abc_class_t*)dict_getdata(pool->classes, t);
1427    
1428         int classname_index = multiname_index(pool, c->classname);
1429         int superclass_index = multiname_index(pool, c->superclass);
1430
1431         swf_SetU30(tag, classname_index);
1432         swf_SetU30(tag, superclass_index);
1433
1434         swf_SetU8(tag, c->flags); // flags
1435         if(c->flags&0x08) {
1436             abc_namespace_t*ns = abc_protectednamespace(pool, c->protectedNS);
1437             int ns_index = register_namespace(pool, ns);
1438             swf_SetU30(tag, ns_index);
1439         }
1440
1441         swf_SetU30(tag, 0); // no interfaces
1442         if(c->iinit<0) {
1443             fprintf(stderr, "Error: Class %s has no constructor\n", c->classname);
1444             return;
1445         }
1446         swf_SetU30(tag, c->iinit);
1447         write_traits(pool, tag, c->traits);
1448     }
1449     for(t=0;t<pool->classes->num;t++) {
1450         abc_class_t*c = (abc_class_t*)dict_getdata(pool->classes, t);
1451         if(c->static_constructor_index<0) {
1452             fprintf(stderr, "Error: Class %s has no static constructor\n", c->classname);
1453             return;
1454         }
1455         swf_SetU30(tag, c->static_constructor_index);
1456         write_traits(pool, tag, c->static_constructor_traits);
1457     }
1458
1459     swf_SetU30(tag, pool->scripts->num);
1460     for(t=0;t<pool->scripts->num;t++) {
1461         abc_script_t*s = (abc_script_t*)dict_getdata(pool->scripts, t);
1462         swf_SetU30(tag, s->method->index); //!=t!
1463         write_traits(pool, tag, s->traits);
1464     }
1465
1466     swf_SetU30(tag, pool->method_bodies->num);
1467     for(t=0;t<pool->method_bodies->num;t++) {
1468         abc_method_body_t*c = (abc_method_body_t*)dict_getdata(pool->method_bodies, t);
1469         abc_method_t*m = c->method;
1470         swf_SetU30(tag, m->index);
1471         swf_SetU30(tag, c->max_stack);
1472         swf_SetU30(tag, c->local_count);
1473         swf_SetU30(tag, c->init_scope_depth);
1474         swf_SetU30(tag, c->max_scope_depth);
1475         swf_SetU30(tag, c->tag->len);
1476         swf_SetBlock(tag, c->tag->data, c->tag->len);
1477         swf_SetU30(tag, c->exception_count);
1478         write_traits(pool, tag, c->traits);
1479     }
1480
1481     // --- start to write real tag --
1482     
1483     tag = abctag;
1484
1485     for(t=1;t<pool->multinames->num;t++) {
1486         abc_multiname_t*m = (abc_multiname_t*)dict_getdata(pool->multinames, t);
1487         if(m->ns) {
1488             register_namespace(pool, m->ns);
1489         }
1490         if(m->namespace_set_name) {
1491             // FIXME
1492         }
1493         if(m->name)
1494             dict_append_if_new(pool->strings, m->name, 0);
1495     }
1496     for(t=1;t<pool->namespaces->num;t++) {
1497         char*namespace_name = (char*)dict_getstr(pool->namespaces, t);
1498         dict_append_if_new(pool->strings, namespace_name, 0);
1499     }
1500
1501     swf_SetU32(tag, 1); // flags
1502     swf_SetU8(tag, 0); //classname
1503
1504     swf_SetU16(tag, 0x10); //version
1505     swf_SetU16(tag, 0x2e);
1506
1507     swf_SetU30(tag, pool->ints->num>1?pool->ints->num:0);
1508     // ...
1509     swf_SetU30(tag, pool->uints->num>1?pool->uints->num:0);
1510     // ...
1511     swf_SetU30(tag, pool->floats->num>1?pool->floats->num:0);
1512     // ...
1513     swf_SetU30(tag, pool->strings->num>1?pool->strings->num:0);
1514     for(t=1;t<pool->strings->num;t++) {
1515         swf_SetU30String(tag, dict_getstr(pool->strings, t));
1516     }
1517     swf_SetU30(tag, pool->namespaces->num>1?pool->namespaces->num:0);
1518     for(t=1;t<pool->namespaces->num;t++) {
1519         abc_namespace_t*ns= (abc_namespace_t*)dict_getdata(pool->namespaces, t);
1520         const char*name = ns->name;
1521         int i = dict_find(pool->strings, name);
1522         if(i<0) {
1523             fprintf(stderr, "Couldn't find namespace \"%s\" in constant pool\n", name);
1524             return;
1525         }
1526         swf_SetU8(tag, ns->access);
1527         swf_SetU30(tag, i);
1528     }
1529     swf_SetU30(tag, pool->sets->num>1?pool->sets->num:0);
1530     // ...
1531
1532     swf_SetU30(tag, pool->multinames->num>1?pool->multinames->num:0);
1533     // ...
1534     for(t=1;t<pool->multinames->num;t++) {
1535         abc_multiname_t*m = (abc_multiname_t*)dict_getdata(pool->multinames, t);
1536         swf_SetU8(tag, m->type);
1537
1538         if(m->ns) {
1539             assert(m->type==0x07 || m->type==0x0d);
1540             /* fixme: might find wrong version */
1541             int i = dict_find2(pool->namespaces, m->ns->name, (void*)(ptroff_t)m->ns);
1542             if(i<0) fprintf(stderr, "internal error: unregistered namespace %02x %s %s\n", m->ns->access, access2str(m->ns->access), m->ns->name);
1543             swf_SetU30(tag, i);
1544         }
1545         if(m->namespace_set_name) {
1546             assert(m->type==0x09 || m->type==0x0e || m->type==0x1c || m->type==0x1b);
1547             int i = dict_find(pool->namespace_sets, m->namespace_set_name);
1548             if(i<0) fprintf(stderr, "internal error: unregistered namespace set\n");
1549             swf_SetU30(tag, i);
1550         }
1551         if(m->name) {
1552             assert(m->type==0x09 || m->type==0x0e || m->type==0x07 || m->type==0x0d || m->type==0x0f || m->type==0x10);
1553             int i = dict_find(pool->strings, m->name);
1554             if(i<0) fprintf(stderr, "internal error: unregistered name\n");
1555             swf_SetU30(tag, i);
1556         }
1557     }
1558
1559     swf_SetBlock(tag, tmp->data, tmp->len);
1560
1561     swf_DeleteTag(0, tmp);
1562 }
1563
1564 #include "swfabc_ops.c"
1565
1566 void swf_AddButtonLinks(SWF*swf, char stop_each_frame)
1567 {
1568     int num_frames = 0;
1569     int has_buttons = 0;
1570     TAG*tag=swf->firstTag;
1571     while(tag) {
1572         if(tag->id == ST_SHOWFRAME)
1573             num_frames++;
1574         if(tag->id == ST_DEFINEBUTTON || tag->id == ST_DEFINEBUTTON2)
1575             has_buttons = 1;
1576         tag = tag->next;
1577     }
1578
1579     abc_file_t*file = abc_file_new();
1580     abc_method_body_t*c = 0;
1581    
1582     abc_class_t*cls = abc_class_new(file, "rfx::MainTimeline", "flash.display::MovieClip");
1583     abc_class_protectedNS(cls, "rfx:MainTimeline");
1584   
1585     TAG*abctag = swf_InsertTagBefore(swf, swf->firstTag, ST_DOABC);
1586     
1587     tag = swf_InsertTag(abctag, ST_SYMBOLCLASS);
1588     swf_SetU16(tag, 1);
1589     swf_SetU16(tag, 0);
1590     swf_SetString(tag, "rfx.MainTimeline");
1591
1592     c = abc_class_staticconstructor(cls, 0, 0);
1593     c->max_stack = 1;
1594     c->local_count = 1;
1595     c->init_scope_depth = 9;
1596     c->max_scope_depth = 10;
1597
1598     abc_getlocal_0(c);
1599     abc_pushscope(c);
1600     abc_returnvoid(c);
1601
1602     c = abc_class_constructor(cls, 0, 0);
1603     c->max_stack = 3;
1604     c->local_count = 1;
1605     c->init_scope_depth = 10;
1606     c->max_scope_depth = 11;
1607     
1608     abc_debugfile(c, "constructor.as");
1609
1610     abc_getlocal_0(c);
1611     abc_pushscope(c);
1612
1613     abc_getlocal_0(c);
1614     abc_constructsuper(c,0);
1615
1616     abc_getlex(c, "[package]flash.system::Security");
1617     abc_pushstring(c, "*");
1618     abc_callpropvoid(c, "[package]::allowDomain", 1);
1619     
1620     if(stop_each_frame || has_buttons) {
1621         int frame = 0;
1622         tag = swf->firstTag;
1623         abc_method_body_t*f = 0; //frame script
1624         while(tag && tag->id!=ST_END) {
1625             char framename[80];
1626             char needs_framescript=0;
1627             char buttonname[80];
1628             char functionname[80];
1629             sprintf(framename, "[packageinternal]rfx::frame%d", frame);
1630             
1631             if(!f && (tag->id == ST_DEFINEBUTTON || tag->id == ST_DEFINEBUTTON2 || stop_each_frame)) {
1632                 /* make the contructor add a frame script */
1633                 abc_findpropstrict(c,"[package]::addFrameScript");
1634                 abc_pushbyte(c,frame);
1635                 abc_getlex(c,framename);
1636                 abc_callpropvoid(c,"[package]::addFrameScript",2);
1637
1638                 f = abc_class_method(cls, 0, framename, 0);
1639                 f->max_stack = 3;
1640                 f->local_count = 1;
1641                 f->init_scope_depth = 10;
1642                 f->max_scope_depth = 11;
1643                 abc_debugfile(f, "framescript.as");
1644                 abc_debugline(f, 1);
1645                 abc_getlocal_0(f);
1646                 abc_pushscope(f);
1647             }
1648
1649             if(tag->id == ST_DEFINEBUTTON || tag->id == ST_DEFINEBUTTON2) {
1650                 U16 id = swf_GetDefineID(tag);
1651                 sprintf(buttonname, "::button%d", swf_GetDefineID(tag));
1652                 abc_getlex(f,buttonname);
1653                 abc_getlex(f,"flash.events::MouseEvent");
1654                 abc_getproperty(f, "::CLICK");
1655                 sprintf(functionname, "::clickbutton%d", swf_GetDefineID(tag));
1656                 abc_getlex(f,functionname);
1657                 abc_callpropvoid(f, "::addEventListener" ,2);
1658
1659                 if(stop_each_frame) {
1660                     abc_findpropstrict(f, "[package]::stop");
1661                     abc_callpropvoid(f, "[package]::stop", 0);
1662                 }
1663                 needs_framescript = 1;
1664
1665                 abc_method_body_t*h =
1666                     abc_class_method(cls, "::void", functionname, 1, "flash.events::MouseEvent");
1667                 h->max_stack = 3;
1668                 h->local_count = 2;
1669                 h->init_scope_depth = 10;
1670                 h->max_scope_depth = 11;
1671                 abc_getlocal_0(h);
1672                 abc_pushscope(h);
1673
1674                 ActionTAG*oldaction = swf_ButtonGetAction(tag);
1675                 if(oldaction && oldaction->op == ACTION__GOTOFRAME) {
1676                     abc_findpropstrict(h,"flash.net::gotoFrame");
1677                     int framenr = GET16(oldaction->data);
1678                     // FIXME: doesn't work yet
1679                     if(framenr>255) {
1680                         fprintf(stderr, "Warning: Couldn't translate jump to frame %d to flash 9 actionscript\n", framenr);
1681                     }
1682                     abc_pushbyte(h,framenr);
1683                     abc_callpropvoid(h,"flash.net::gotoFrame", 1);
1684                 } else if(oldaction && oldaction->op == ACTION__GETURL) {
1685                     abc_findpropstrict(h,"flash.net::navigateToURL");
1686                     abc_findpropstrict(h,"flash.net::URLRequest");
1687                     abc_pushstring(h,oldaction->data);
1688                     abc_constructprop(h,"flash.net::URLRequest", 1);
1689                     abc_callpropvoid(h,"flash.net::navigateToURL", 1);
1690                 } else if(oldaction) {
1691                     fprintf(stderr, "Warning: Couldn't translate button code of button %d to flash 9 abc action\n", id);
1692                 }
1693                 abc_returnvoid(h);
1694                 swf_ActionFree(oldaction);
1695             }
1696             if(tag->id == ST_SHOWFRAME) {
1697                 if(f) {
1698                     abc_returnvoid(f);
1699                     f = 0;
1700                 }
1701                 frame++;
1702             }
1703             tag = tag->next;
1704         }
1705         if(f) {
1706             abc_returnvoid(f);
1707         }
1708     }
1709     abc_returnvoid(c);
1710
1711     tag = swf->firstTag;
1712     while(tag) {
1713         if(tag->id == ST_DEFINEBUTTON || tag->id == ST_DEFINEBUTTON2) {
1714             char buttonname[80];
1715             sprintf(buttonname, "::button%d", swf_GetDefineID(tag));
1716             abc_AddSlot(cls, buttonname, 0, "flash.display::SimpleButton");
1717         }
1718         tag = tag->next;
1719     }
1720
1721
1722     abc_script_t*s = abc_initscript(file, 0, 0);
1723     c = (abc_method_body_t*)dict_getdata(file->method_bodies, s->method->method_body_index);
1724     c->max_stack = 2;
1725     c->local_count = 1;
1726     c->init_scope_depth = 1;
1727     c->max_scope_depth = 9;
1728     abc_getlocal_0(c);
1729     abc_pushscope(c);
1730     abc_getscopeobject(c, 0);
1731     abc_getlex(c,"::Object");
1732     abc_pushscope(c);
1733     abc_getlex(c,"flash.events::EventDispatcher");
1734     abc_pushscope(c);
1735     abc_getlex(c,"flash.display::DisplayObject");
1736     abc_pushscope(c);
1737     abc_getlex(c,"flash.display::InteractiveObject");
1738     abc_pushscope(c);
1739     abc_getlex(c,"flash.display::DisplayObjectContainer");
1740     abc_pushscope(c);
1741     abc_getlex(c,"flash.display::Sprite");
1742     abc_pushscope(c);
1743     abc_getlex(c,"flash.display::MovieClip");
1744     abc_pushscope(c);
1745     abc_getlex(c,"flash.display::MovieClip");
1746     abc_newclass(c,cls);
1747     abc_popscope(c);
1748     abc_popscope(c);
1749     abc_popscope(c);
1750     abc_popscope(c);
1751     abc_popscope(c);
1752     abc_popscope(c);
1753     abc_popscope(c);
1754     abc_initproperty(c,"rfx::MainTimeline");
1755     abc_returnvoid(c);
1756
1757     //abc_method_body_addClassTrait(c, "rfx:MainTimeline", 1, cls);
1758     abc_initscript_addClassTrait(s, "rfx::MainTimeline", 1, cls);
1759
1760     swf_WriteABC(abctag, file);
1761 }
1762