moved from ../modules/
[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 "abc.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         U32 abcflags = swf_GetU32(tag);
1044         DEBUG printf("flags=%08x\n", abcflags);
1045         char*name= swf_GetString(tag);
1046         if(*name)
1047             printf("#name: %s\n", name);
1048     }
1049     U32 version = swf_GetU32(tag);
1050     if(version!=0x002e0010) {
1051         fprintf(stderr, "Warning: unknown AVM2 version %08x\n", version);
1052     }
1053
1054     int num_ints = swf_GetU30(tag);
1055     DEBUG printf("%d ints\n", num_ints);
1056     for(t=1;t<num_ints;t++) {
1057         S32 v = swf_GetU30(tag);
1058         DEBUG printf("int %d) %d\n", t, v);
1059         dict_append(pool->ints, 0, (void*)(ptroff_t)v);
1060     }
1061
1062     int num_uints = swf_GetU30(tag);
1063     DEBUG printf("%d uints\n", num_uints);
1064     for(t=1;t<num_uints;t++) {
1065         U32 v = swf_GetS30(tag);
1066         DEBUG printf("uint %d) %d\n", t, v);
1067         dict_append(pool->uints, 0, (void*)(ptroff_t)v);
1068     }
1069     
1070     int num_floats = swf_GetU30(tag);
1071     DEBUG printf("%d floats\n", num_floats);
1072     for(t=1;t<num_floats;t++) {
1073         double d = swf_GetD64(tag);
1074         DEBUG printf("float %d) %f\n", t, d);
1075         dict_append(pool->floats, 0, 0);
1076     }
1077     
1078     int num_strings = swf_GetU30(tag);
1079     DEBUG printf("%d strings\n", num_strings);
1080     for(t=1;t<num_strings;t++) {
1081         int len = swf_GetU30(tag);
1082         char*s = malloc(len+1);
1083         swf_GetBlock(tag, s, len);
1084         s[len] = 0;
1085         dict_append(pool->strings, s, 0);
1086         DEBUG printf("%d) \"%s\"\n", t, pool->strings->d[t].name);
1087     }
1088     int num_namespaces = swf_GetU30(tag);
1089     DEBUG printf("%d namespaces\n", num_namespaces);
1090     for(t=1;t<num_namespaces;t++) {
1091         U8 type = swf_GetU8(tag);
1092         int namenr = swf_GetU30(tag);
1093         const char*name = dict_getstr(pool->strings, namenr);
1094         abc_namespace_t*ns = malloc(sizeof(abc_namespace_t));
1095         memset(ns, 0, sizeof(abc_namespace_t));
1096         ns->access = type;
1097         ns->name = strdup(name);
1098         dict_append(pool->namespaces, name, ns);
1099         int w = 0;
1100         DEBUG w=1;
1101         if(w) {
1102             if(type==0x08) printf("Namespace %s\n", name);
1103             else if(type==0x16) printf("PackageNamespace %s\n", name);
1104             else if(type==0x17) printf("PackageInternalNs %s\n", name);
1105             else if(type==0x18) printf("ProtectedNamespace %s\n", name);
1106             else if(type==0x19) printf("ExplicitNamespace %s\n", name);
1107             else if(type==0x1A) printf("StaticProtectedNs %s\n", name);
1108             else if(type==0x05) printf("PrivateNs %s\n", name);
1109             else {
1110                 printf("Undefined namespace type\n");
1111                 return 0;
1112             }
1113         }
1114     }
1115     int num_sets = swf_GetU30(tag);
1116     DEBUG printf("%d namespace sets\n", num_sets);
1117     for(t=1;t<num_sets;t++) {
1118         int count = swf_GetU30(tag);
1119         int s;
1120         const char**name = malloc(sizeof(const char*)*count);
1121         int l = 0;
1122         for(s=0;s<count;s++) {
1123             int nsnr = swf_GetU30(tag);
1124             name[s] = dict_getstr(pool->namespaces, nsnr);
1125             l += strlen(name[s])+1;
1126         }
1127         char*desc = malloc(l+16);
1128         strcpy(desc, "{");
1129         for(s=0;s<count;s++) {
1130             strcat(desc, name[s]);
1131             strcat(desc, ",");
1132         }
1133         strcat(desc, "}");
1134         dict_append(pool->namespace_sets, desc, 0);
1135         DEBUG printf("set %d) %s\n", t, desc);
1136     }
1137
1138     int num_multinames = swf_GetU30(tag);
1139     DEBUG printf("%d multinames\n", num_multinames);
1140     for(t=1;t<num_multinames;t++) {
1141         abc_multiname_t*m = malloc(sizeof(abc_multiname_t));
1142         memset(m, 0, sizeof(abc_multiname_t));
1143
1144         m->type = swf_GetU8(tag);
1145
1146         if(m->type==0x07 || m->type==0x0d) {
1147             int nr1 = swf_GetU30(tag);
1148             m->ns = (abc_namespace_t*)dict_getdata(pool->namespaces, nr1);
1149             int name_index = swf_GetU30(tag);
1150             m->name = dict_getstr(pool->strings, name_index);
1151         } else if(m->type==0x0f || m->type==0x10) {
1152             int name_index = swf_GetU30(tag);
1153             m->name = dict_getstr(pool->strings, name_index);
1154         } else if(m->type==0x11 || m->type==0x12) {
1155         } else if(m->type==0x09 || m->type==0x0e) {
1156             int name_index = swf_GetU30(tag);
1157             int namespace_set_index = swf_GetU30(tag);
1158             m->name = dict_getstr(pool->strings, name_index);
1159             m->namespace_set_name = dict_getstr(pool->namespace_sets, namespace_set_index);
1160         } else if(m->type==0x1b || m->type==0x1c) {
1161             int namespace_set_index = swf_GetU30(tag);
1162             m->namespace_set_name = dict_getstr(pool->namespace_sets, namespace_set_index);
1163         } else {
1164             printf("can't parse type %d multinames yet\n", m->type);
1165             return 0;
1166         }
1167         char*mname = multiname_to_string(m);
1168         DEBUG printf("multiname %d) %s\n", t, mname);
1169         dict_append(pool->multinames, mname, m);
1170         free(mname);
1171     }
1172     
1173     int num_methods = swf_GetU30(tag);
1174     DEBUG printf("%d methods\n", num_methods);
1175     for(t=0;t<num_methods;t++) {
1176         abc_method_t*m = malloc(sizeof(abc_method_t));
1177         memset(m, 0, sizeof(*m));
1178         int param_count = swf_GetU30(tag);
1179         int return_type_index = swf_GetU30(tag);
1180         m->return_type = multiname_lookup(pool, return_type_index);
1181         m->index = t;
1182
1183         int s;
1184         for(s=0;s<param_count;s++) {
1185             int type_index = swf_GetU30(tag);
1186             list_append(&m->parameters, multiname_lookup(pool, type_index));
1187         }
1188
1189         int namenr = swf_GetU30(tag);
1190         m->name = "";
1191         if(namenr)
1192             m->name = dict_getstr(pool->strings, namenr);
1193
1194         m->flags = swf_GetU8(tag);
1195         
1196         DEBUG printf("method %d) %s flags=%02x\n", t, params_to_string(m->parameters), m->flags);
1197
1198         if(m->flags&0x08) {
1199             /* optional parameters */
1200             int num = swf_GetU30(tag);
1201             int s;
1202             for(s=0;s<num;s++) {
1203                 int val = swf_GetU30(tag);
1204                 U8 kind = swf_GetU8(tag); // specifies index type for "val"
1205             }
1206         }
1207         if(m->flags&0x80) {
1208             /* debug information- not used by avm2 */
1209             abc_multiname_list_t*l = m->parameters;
1210             while(l) {
1211                 m->name = dict_getstr(pool->strings, swf_GetU30(tag));
1212                 l = l->next;
1213             }
1214         }
1215         dict_append(pool->methods, m->name, m);
1216     }
1217             
1218     parse_metadata(tag, pool);
1219         
1220     /* skip classes, and scripts for now, and do the real parsing later */
1221     int num_classes = swf_GetU30(tag);
1222     int classes_pos = tag->pos;
1223     DEBUG printf("%d classes\n", num_classes);
1224     for(t=0;t<num_classes;t++) {
1225         abc_class_t*cls = malloc(sizeof(abc_class_t));
1226         memset(cls, 0, sizeof(abc_class_t));
1227         dict_append(pool->classes, 0, cls);
1228         
1229         DEBUG printf("class %d\n", t);
1230         swf_GetU30(tag); //classname
1231         swf_GetU30(tag); //supername
1232         cls->flags = swf_GetU8(tag);
1233         if(cls->flags&8) 
1234             swf_GetU30(tag); //protectedNS
1235         int s;
1236         int inum = swf_GetU30(tag); //interface count
1237         abc_multiname_list_t*list = 0;
1238         for(s=0;s<inum;s++) {
1239             int interface_index = swf_GetU30(tag);
1240             const char*interface = dict_getstr(pool->multinames, interface_index);
1241             abc_multiname_t* m = (abc_multiname_t*)dict_getdata(pool->multinames, interface_index);
1242             list_append(&list, m);
1243             DEBUG printf("  class %d interface: %s\n", t, interface);
1244         }
1245
1246         cls->iinit = swf_GetU30(tag);
1247         cls->traits = traits_parse(tag, pool);
1248     }
1249     for(t=0;t<num_classes;t++) {
1250         abc_class_t*cls = (abc_class_t*)dict_getdata(pool->classes, t);
1251         cls->static_constructor_index = swf_GetU30(tag); // cinit
1252         cls->static_constructor_traits = traits_parse(tag, pool);
1253     }
1254     int num_scripts = swf_GetU30(tag);
1255     DEBUG printf("%d scripts\n", num_scripts);
1256     for(t=0;t<num_scripts;t++) {
1257         int init = swf_GetU30(tag);
1258         dict_t*traits = traits_parse(tag, pool); //TODO: store
1259     }
1260
1261     int num_method_bodies = swf_GetU30(tag);
1262     DEBUG printf("%d method bodies\n", num_method_bodies);
1263     for(t=0;t<num_method_bodies;t++) {
1264         int methodnr = swf_GetU30(tag);
1265         if(methodnr >= pool->methods->num) {
1266             printf("Invalid method number: %d\n", methodnr);
1267             return 0;
1268         }
1269         abc_method_t*m = (abc_method_t*)dict_getdata(pool->methods, methodnr);
1270         abc_method_body_t*c = malloc(sizeof(abc_method_body_t));
1271         memset(c, 0, sizeof(abc_method_body_t));
1272         c->max_stack = swf_GetU30(tag);
1273         c->local_count = swf_GetU30(tag);
1274         c->init_scope_depth = swf_GetU30(tag);
1275         c->max_scope_depth = swf_GetU30(tag);
1276         int code_length = swf_GetU30(tag);
1277         c->method = m;
1278         m->method_body_index = t;
1279
1280         c->tag = swf_InsertTag(0,0);
1281
1282         swf_CopyData(c->tag, tag, code_length);
1283
1284         int exception_count = swf_GetU30(tag);
1285         int s;
1286         for(s=0;s<exception_count;s++) {
1287             swf_GetU30(tag); //from
1288             swf_GetU30(tag); //to
1289             swf_GetU30(tag); //target
1290             swf_GetU30(tag); //exc_type
1291             swf_GetU30(tag); //var_name
1292         }
1293         c->traits = traits_parse(tag, pool);
1294         if(!c->traits) {
1295             fprintf(stderr, "Can't parse code traits\n");
1296             return 0;
1297         }
1298         DEBUG printf("method_body %d) (method %d), %d bytes of code", t, methodnr, code_length);
1299         int r,l = code_length>32?32:code_length;
1300         for(r=0;r<l;r++) {
1301             DEBUG printf("%02x ", c->tag->data[r]);
1302         }
1303         DEBUG printf("\n");
1304
1305         dict_append(pool->method_bodies, 0, c);
1306     }
1307     if(tag->len - tag->pos) {
1308         fprintf(stderr, "%d unparsed bytes remaining in ABC block\n", tag->len - tag->pos);
1309         return 0;
1310     }
1311
1312     swf_SetTagPos(tag, classes_pos);
1313     for(t=0;t<num_classes;t++) {
1314         abc_class_t*cls = (abc_class_t*)dict_getdata(pool->classes, t);
1315
1316         int classname_index = swf_GetU30(tag);
1317         int superclass_index = swf_GetU30(tag);
1318         cls->classname = dict_getstr(pool->multinames, classname_index);
1319         cls->superclass = dict_getstr(pool->multinames, superclass_index);
1320         cls->flags = swf_GetU8(tag);
1321         const char*ns = "";
1322         if(cls->flags&8) {
1323             int ns_index = swf_GetU30(tag);
1324             cls->protectedNS = dict_getstr(pool->namespaces, ns_index);
1325         }
1326         
1327         if(cls->flags&1) printf("sealed ");
1328         if(cls->flags&2) printf("final ");
1329         if(cls->flags&4) printf("interface ");
1330         if(cls->flags&8) {
1331             printf("protectedNS<%s> ", cls->protectedNS);
1332         }
1333
1334         printf("class %s", cls->classname);
1335         if(cls->superclass && cls->superclass[0]) {
1336             printf(" extends %s", cls->superclass);
1337             abc_multiname_list_t*ilist = cls->interfaces;
1338             if(ilist)
1339                 printf(" implements");
1340             while(ilist) {
1341                 char*s = multiname_to_string(ilist->abc_multiname);
1342                 printf(" %d", s);
1343                 free(s);
1344                 ilist = ilist->next;
1345             }
1346             ilist->next;
1347             
1348         }
1349         if(cls->flags&0xf0) 
1350             printf("extra flags=%02x\n", cls->flags&0xf0);
1351         printf("{\n");
1352         
1353         dump_method("    ","staticconstructor", "", cls->static_constructor_index, pool);
1354         dump_traits("    ", cls->static_constructor_traits, pool);
1355         
1356         int num_interfaces = swf_GetU30(tag); //interface count
1357         int s;
1358         for(s=0;s<num_interfaces;s++) {
1359             swf_GetU30(tag); // multiname index TODO
1360         }
1361         cls->iinit = swf_GetU30(tag);
1362         dump_method("    ","constructor", cls->classname, cls->iinit, pool);
1363         cls->traits = traits_parse(tag, pool);
1364         if(!cls->traits) {
1365             fprintf(stderr, "Can't parse class traits\n");
1366             return 0;
1367         }
1368         dump_traits("    ",cls->traits, pool);
1369         
1370         printf("}\n");
1371     }
1372     for(t=0;t<num_classes;t++) {
1373         /* SKIP */
1374         swf_GetU30(tag); // cindex
1375         traits_parse(tag, pool); // TODO: free
1376     }
1377     int num_scripts2 = swf_GetU30(tag);
1378     printf("\n");
1379     for(t=0;t<num_scripts2;t++) {
1380         int init = swf_GetU30(tag);
1381         abc_method_t*m = (abc_method_t*)dict_getdata(pool->methods, init);
1382         
1383         abc_script_t*s = malloc(sizeof(abc_script_t));
1384         memset(s, 0, sizeof(abc_script_t));
1385         s->method = m;
1386         s->traits = traits_parse(tag, pool);
1387         dict_append(pool->scripts, 0, s);
1388         if(!s->traits) {
1389             fprintf(stderr, "Can't parse script traits\n");
1390             return 0;
1391         }
1392         dump_method("","initmethod", "init", init, pool);
1393         dump_traits("", s->traits, pool);
1394     }
1395     return pool;
1396 }
1397
1398 void swf_WriteABC(TAG*abctag, void*code)
1399 {
1400     abc_file_t*pool = (abc_file_t*)code;
1401
1402     TAG*tmp = swf_InsertTag(0,0);
1403     TAG*tag = tmp;
1404     int t;
1405
1406     swf_SetU30(tag, pool->methods->num);
1407     for(t=0;t<pool->methods->num;t++) {
1408         abc_method_t*m = (abc_method_t*)dict_getdata(pool->methods, t);
1409         int n = 0;
1410         abc_multiname_list_t*l = m->parameters;
1411         swf_SetU30(tag, list_length(m->parameters));
1412         swf_SetU30(tag, register_multiname(pool, m->return_type));
1413         int s;
1414         while(l) {
1415             swf_SetU30(tag, register_multiname(pool, l->abc_multiname));
1416             l = l->next;
1417         }
1418         swf_SetU30(tag, 0); // name
1419         swf_SetU8(tag, 0); //flags
1420     }
1421     
1422     swf_SetU30(tag, 0);//metadata
1423
1424     swf_SetU30(tag, pool->classes->num);
1425
1426     for(t=0;t<pool->classes->num;t++) {
1427         abc_class_t*c = (abc_class_t*)dict_getdata(pool->classes, t);
1428    
1429         int classname_index = multiname_index(pool, c->classname);
1430         int superclass_index = multiname_index(pool, c->superclass);
1431
1432         swf_SetU30(tag, classname_index);
1433         swf_SetU30(tag, superclass_index);
1434
1435         swf_SetU8(tag, c->flags); // flags
1436         if(c->flags&0x08) {
1437             abc_namespace_t*ns = abc_protectednamespace(pool, c->protectedNS);
1438             int ns_index = register_namespace(pool, ns);
1439             swf_SetU30(tag, ns_index);
1440         }
1441
1442         swf_SetU30(tag, 0); // no interfaces
1443         if(c->iinit<0) {
1444             fprintf(stderr, "Error: Class %s has no constructor\n", c->classname);
1445             return;
1446         }
1447         swf_SetU30(tag, c->iinit);
1448         write_traits(pool, tag, c->traits);
1449     }
1450     for(t=0;t<pool->classes->num;t++) {
1451         abc_class_t*c = (abc_class_t*)dict_getdata(pool->classes, t);
1452         if(c->static_constructor_index<0) {
1453             fprintf(stderr, "Error: Class %s has no static constructor\n", c->classname);
1454             return;
1455         }
1456         swf_SetU30(tag, c->static_constructor_index);
1457         write_traits(pool, tag, c->static_constructor_traits);
1458     }
1459
1460     swf_SetU30(tag, pool->scripts->num);
1461     for(t=0;t<pool->scripts->num;t++) {
1462         abc_script_t*s = (abc_script_t*)dict_getdata(pool->scripts, t);
1463         swf_SetU30(tag, s->method->index); //!=t!
1464         write_traits(pool, tag, s->traits);
1465     }
1466
1467     swf_SetU30(tag, pool->method_bodies->num);
1468     for(t=0;t<pool->method_bodies->num;t++) {
1469         abc_method_body_t*c = (abc_method_body_t*)dict_getdata(pool->method_bodies, t);
1470         abc_method_t*m = c->method;
1471         swf_SetU30(tag, m->index);
1472         swf_SetU30(tag, c->max_stack);
1473         swf_SetU30(tag, c->local_count);
1474         swf_SetU30(tag, c->init_scope_depth);
1475         swf_SetU30(tag, c->max_scope_depth);
1476         swf_SetU30(tag, c->tag->len);
1477         swf_SetBlock(tag, c->tag->data, c->tag->len);
1478         swf_SetU30(tag, c->exception_count);
1479         write_traits(pool, tag, c->traits);
1480     }
1481
1482     // --- start to write real tag --
1483     
1484     tag = abctag;
1485
1486     for(t=1;t<pool->multinames->num;t++) {
1487         abc_multiname_t*m = (abc_multiname_t*)dict_getdata(pool->multinames, t);
1488         if(m->ns) {
1489             register_namespace(pool, m->ns);
1490         }
1491         if(m->namespace_set_name) {
1492             // FIXME
1493         }
1494         if(m->name)
1495             dict_append_if_new(pool->strings, m->name, 0);
1496     }
1497     for(t=1;t<pool->namespaces->num;t++) {
1498         char*namespace_name = (char*)dict_getstr(pool->namespaces, t);
1499         dict_append_if_new(pool->strings, namespace_name, 0);
1500     }
1501
1502     swf_SetU32(tag, 1); // flags
1503     swf_SetU8(tag, 0); //classname
1504
1505     swf_SetU16(tag, 0x10); //version
1506     swf_SetU16(tag, 0x2e);
1507
1508     swf_SetU30(tag, pool->ints->num>1?pool->ints->num:0);
1509     // ...
1510     swf_SetU30(tag, pool->uints->num>1?pool->uints->num:0);
1511     // ...
1512     swf_SetU30(tag, pool->floats->num>1?pool->floats->num:0);
1513     // ...
1514     swf_SetU30(tag, pool->strings->num>1?pool->strings->num:0);
1515     for(t=1;t<pool->strings->num;t++) {
1516         swf_SetU30String(tag, dict_getstr(pool->strings, t));
1517     }
1518     swf_SetU30(tag, pool->namespaces->num>1?pool->namespaces->num:0);
1519     for(t=1;t<pool->namespaces->num;t++) {
1520         abc_namespace_t*ns= (abc_namespace_t*)dict_getdata(pool->namespaces, t);
1521         const char*name = ns->name;
1522         int i = dict_find(pool->strings, name);
1523         if(i<0) {
1524             fprintf(stderr, "Couldn't find namespace \"%s\" in constant pool\n", name);
1525             return;
1526         }
1527         swf_SetU8(tag, ns->access);
1528         swf_SetU30(tag, i);
1529     }
1530     swf_SetU30(tag, pool->sets->num>1?pool->sets->num:0);
1531     // ...
1532
1533     swf_SetU30(tag, pool->multinames->num>1?pool->multinames->num:0);
1534     // ...
1535     for(t=1;t<pool->multinames->num;t++) {
1536         abc_multiname_t*m = (abc_multiname_t*)dict_getdata(pool->multinames, t);
1537         swf_SetU8(tag, m->type);
1538
1539         if(m->ns) {
1540             assert(m->type==0x07 || m->type==0x0d);
1541             /* fixme: might find wrong version */
1542             int i = dict_find2(pool->namespaces, m->ns->name, (void*)(ptroff_t)m->ns);
1543             if(i<0) fprintf(stderr, "internal error: unregistered namespace %02x %s %s\n", m->ns->access, access2str(m->ns->access), m->ns->name);
1544             swf_SetU30(tag, i);
1545         }
1546         if(m->namespace_set_name) {
1547             assert(m->type==0x09 || m->type==0x0e || m->type==0x1c || m->type==0x1b);
1548             int i = dict_find(pool->namespace_sets, m->namespace_set_name);
1549             if(i<0) fprintf(stderr, "internal error: unregistered namespace set\n");
1550             swf_SetU30(tag, i);
1551         }
1552         if(m->name) {
1553             assert(m->type==0x09 || m->type==0x0e || m->type==0x07 || m->type==0x0d || m->type==0x0f || m->type==0x10);
1554             int i = dict_find(pool->strings, m->name);
1555             if(i<0) fprintf(stderr, "internal error: unregistered name\n");
1556             swf_SetU30(tag, i);
1557         }
1558     }
1559
1560     swf_SetBlock(tag, tmp->data, tmp->len);
1561
1562     swf_DeleteTag(0, tmp);
1563 }
1564
1565 #include "swfabc_ops.c"
1566
1567 void swf_AddButtonLinks(SWF*swf, char stop_each_frame, char events)
1568 {
1569     int num_frames = 0;
1570     int has_buttons = 0;
1571     TAG*tag=swf->firstTag;
1572     while(tag) {
1573         if(tag->id == ST_SHOWFRAME)
1574             num_frames++;
1575         if(tag->id == ST_DEFINEBUTTON || tag->id == ST_DEFINEBUTTON2)
1576             has_buttons = 1;
1577         tag = tag->next;
1578     }
1579
1580     abc_file_t*file = abc_file_new();
1581     abc_method_body_t*c = 0;
1582    
1583     abc_class_t*cls = abc_class_new(file, "rfx::MainTimeline", "flash.display::MovieClip");
1584     abc_class_protectedNS(cls, "rfx:MainTimeline");
1585   
1586     TAG*abctag = swf_InsertTagBefore(swf, swf->firstTag, ST_DOABC);
1587     
1588     tag = swf_InsertTag(abctag, ST_SYMBOLCLASS);
1589     swf_SetU16(tag, 1);
1590     swf_SetU16(tag, 0);
1591     swf_SetString(tag, "rfx.MainTimeline");
1592
1593     c = abc_class_staticconstructor(cls, 0, 0);
1594     c->max_stack = 1;
1595     c->local_count = 1;
1596     c->init_scope_depth = 9;
1597     c->max_scope_depth = 10;
1598
1599     abc_getlocal_0(c);
1600     abc_pushscope(c);
1601     abc_returnvoid(c);
1602
1603     c = abc_class_constructor(cls, 0, 0);
1604     c->max_stack = 3;
1605     c->local_count = 1;
1606     c->init_scope_depth = 10;
1607     c->max_scope_depth = 11;
1608     
1609     abc_debugfile(c, "constructor.as");
1610
1611     abc_getlocal_0(c);
1612     abc_pushscope(c);
1613
1614     abc_getlocal_0(c);
1615     abc_constructsuper(c,0);
1616
1617     abc_getlex(c, "[package]flash.system::Security");
1618     abc_pushstring(c, "*");
1619     abc_callpropvoid(c, "[package]::allowDomain", 1);
1620     
1621     if(stop_each_frame || has_buttons) {
1622         int frame = 0;
1623         tag = swf->firstTag;
1624         abc_method_body_t*f = 0; //frame script
1625         while(tag && tag->id!=ST_END) {
1626             char framename[80];
1627             char needs_framescript=0;
1628             char buttonname[80];
1629             char functionname[80];
1630             sprintf(framename, "[packageinternal]rfx::frame%d", frame);
1631             
1632             if(!f && (tag->id == ST_DEFINEBUTTON || tag->id == ST_DEFINEBUTTON2 || stop_each_frame)) {
1633                 /* make the contructor add a frame script */
1634                 abc_findpropstrict(c,"[package]::addFrameScript");
1635                 abc_pushbyte(c,frame);
1636                 abc_getlex(c,framename);
1637                 abc_callpropvoid(c,"[package]::addFrameScript",2);
1638
1639                 f = abc_class_method(cls, 0, framename, 0);
1640                 f->max_stack = 3;
1641                 f->local_count = 1;
1642                 f->init_scope_depth = 10;
1643                 f->max_scope_depth = 11;
1644                 abc_debugfile(f, "framescript.as");
1645                 abc_debugline(f, 1);
1646                 abc_getlocal_0(f);
1647                 abc_pushscope(f);
1648             }
1649
1650             if(tag->id == ST_DEFINEBUTTON || tag->id == ST_DEFINEBUTTON2) {
1651                 U16 id = swf_GetDefineID(tag);
1652                 sprintf(buttonname, "::button%d", swf_GetDefineID(tag));
1653                 abc_getlex(f,buttonname);
1654                 abc_getlex(f,"flash.events::MouseEvent");
1655                 abc_getproperty(f, "::CLICK");
1656                 sprintf(functionname, "::clickbutton%d", swf_GetDefineID(tag));
1657                 abc_getlex(f,functionname);
1658                 abc_callpropvoid(f, "::addEventListener" ,2);
1659
1660                 if(stop_each_frame) {
1661                     abc_findpropstrict(f, "[package]::stop");
1662                     abc_callpropvoid(f, "[package]::stop", 0);
1663                 }
1664                 needs_framescript = 1;
1665
1666                 abc_method_body_t*h =
1667                     abc_class_method(cls, "::void", functionname, 1, "flash.events::MouseEvent");
1668                 h->max_stack = 6;
1669                 h->local_count = 2;
1670                 h->init_scope_depth = 10;
1671                 h->max_scope_depth = 11;
1672                 abc_getlocal_0(h);
1673                 abc_pushscope(h);
1674
1675                 ActionTAG*oldaction = swf_ButtonGetAction(tag);
1676                 if(oldaction && oldaction->op == ACTION__GOTOFRAME) {
1677                     int framenr = GET16(oldaction->data);
1678                     if(framenr>254) {
1679                         fprintf(stderr, "Warning: Couldn't translate jump to frame %d to flash 9 actionscript\n", framenr);
1680                     }
1681                     if(!events) {
1682                         abc_findpropstrict(h,"[package]::gotoAndStop");
1683                         abc_pushbyte(h,framenr+1);
1684                         abc_callpropvoid(h,"[package]::gotoAndStop", 1);
1685                     } else {
1686                         char framename[80];
1687                         sprintf(framename, "frame%d", framenr);
1688                         abc_getlocal_0(h); //this
1689                         abc_findpropstrict(h, "[package]flash.events::TextEvent");
1690                         abc_pushstring(h, "link");
1691                         abc_pushtrue(h);
1692                         abc_pushtrue(h);
1693                         abc_pushstring(h, framename);
1694                         abc_constructprop(h,"[package]flash.events::TextEvent", 4);
1695                         abc_callpropvoid(h,"[package]::dispatchEvent", 1);
1696                     }
1697                 } else if(oldaction && oldaction->op == ACTION__GETURL) {
1698                     if(!events) {
1699                         abc_findpropstrict(h,"flash.net::navigateToURL");
1700                         abc_findpropstrict(h,"flash.net::URLRequest");
1701                         abc_pushstring(h,oldaction->data); //url
1702                         abc_constructprop(h,"flash.net::URLRequest", 1);
1703                         abc_callpropvoid(h,"flash.net::navigateToURL", 1);
1704                     } else {
1705                         abc_getlocal_0(h); //this
1706                         abc_findpropstrict(h, "[package]flash.events::TextEvent");
1707                         abc_pushstring(h, "link");
1708                         abc_pushtrue(h);
1709                         abc_pushtrue(h);
1710                         abc_pushstring(h,oldaction->data); //url
1711                         abc_constructprop(h,"[package]flash.events::TextEvent", 4);
1712                         abc_callpropvoid(h,"[package]::dispatchEvent", 1);
1713                     }
1714                 } else if(oldaction) {
1715                     fprintf(stderr, "Warning: Couldn't translate button code of button %d to flash 9 abc action\n", id);
1716                 }
1717                 abc_returnvoid(h);
1718                 swf_ActionFree(oldaction);
1719             }
1720             if(tag->id == ST_SHOWFRAME) {
1721                 if(f) {
1722                     abc_returnvoid(f);
1723                     f = 0;
1724                 }
1725                 frame++;
1726             }
1727             tag = tag->next;
1728         }
1729         if(f) {
1730             abc_returnvoid(f);
1731         }
1732     }
1733     abc_returnvoid(c);
1734
1735     tag = swf->firstTag;
1736     while(tag) {
1737         if(tag->id == ST_DEFINEBUTTON || tag->id == ST_DEFINEBUTTON2) {
1738             char buttonname[80];
1739             sprintf(buttonname, "::button%d", swf_GetDefineID(tag));
1740             abc_AddSlot(cls, buttonname, 0, "flash.display::SimpleButton");
1741         }
1742         tag = tag->next;
1743     }
1744
1745
1746     abc_script_t*s = abc_initscript(file, 0, 0);
1747     c = (abc_method_body_t*)dict_getdata(file->method_bodies, s->method->method_body_index);
1748     c->max_stack = 2;
1749     c->local_count = 1;
1750     c->init_scope_depth = 1;
1751     c->max_scope_depth = 9;
1752     abc_getlocal_0(c);
1753     abc_pushscope(c);
1754     abc_getscopeobject(c, 0);
1755     abc_getlex(c,"::Object");
1756     abc_pushscope(c);
1757     abc_getlex(c,"flash.events::EventDispatcher");
1758     abc_pushscope(c);
1759     abc_getlex(c,"flash.display::DisplayObject");
1760     abc_pushscope(c);
1761     abc_getlex(c,"flash.display::InteractiveObject");
1762     abc_pushscope(c);
1763     abc_getlex(c,"flash.display::DisplayObjectContainer");
1764     abc_pushscope(c);
1765     abc_getlex(c,"flash.display::Sprite");
1766     abc_pushscope(c);
1767     abc_getlex(c,"flash.display::MovieClip");
1768     abc_pushscope(c);
1769     abc_getlex(c,"flash.display::MovieClip");
1770     abc_newclass(c,cls);
1771     abc_popscope(c);
1772     abc_popscope(c);
1773     abc_popscope(c);
1774     abc_popscope(c);
1775     abc_popscope(c);
1776     abc_popscope(c);
1777     abc_popscope(c);
1778     abc_initproperty(c,"rfx::MainTimeline");
1779     abc_returnvoid(c);
1780
1781     //abc_method_body_addClassTrait(c, "rfx:MainTimeline", 1, cls);
1782     abc_initscript_addClassTrait(s, "rfx::MainTimeline", 1, cls);
1783
1784     swf_WriteABC(abctag, file);
1785 }
1786