moved declarations into include file
[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         namespace = "";
795         name = n;
796     } else {
797         *p = 0;
798         namespace = n;
799         name = p+2;
800     }
801
802     abc_multiname_t*m = malloc(sizeof(abc_multiname_t));
803     memset(m, 0, sizeof(abc_multiname_t));
804
805     m->type = QNAME;
806     m->namespace_set_name = 0;
807     m->ns = namespace_new(0, namespace);
808     m->name = name;
809     return dict_append(pool->multinames, name2, m);
810 }
811 static abc_multiname_t* multiname_fromstring(abc_file_t*pool, const char*name)
812 {
813     int i = multiname_index(pool, name);
814     return (abc_multiname_t*)dict_getdata(pool->multinames, i);
815 }
816
817
818 #define CLASS_SEALED 1
819 #define CLASS_FINAL 2
820 #define CLASS_INTERFACE 4
821 #define CLASS_PROTECTED_NS 8
822
823 abc_class_t* abc_class_new(abc_file_t*pool, char*classname, char*superclass) {
824     abc_class_t* c = malloc(sizeof(abc_class_t));
825     memset(c, 0, sizeof(abc_class_t));
826     c->index = dict_append(pool->classes, 0, c);
827     c->pool = pool;
828     c->classname = strdup(classname);
829     c->superclass = superclass?strdup(superclass):0;
830     c->flags = 0;
831     c->iinit = -1;
832     c->static_constructor_index = -1;
833     c->traits = dict_new();
834     return c;
835 }
836
837 void abc_class_sealed(abc_class_t*c)
838 {
839     c->flags |= CLASS_SEALED;
840 }
841 void abc_class_final(abc_class_t*c)
842 {
843     c->flags |= CLASS_FINAL;
844 }
845 void abc_class_interface(abc_class_t*c)
846 {
847     c->flags |= CLASS_INTERFACE;
848 }
849 void abc_class_protectedNS(abc_class_t*c, char*namespace)
850 {
851     c->protectedNS = namespace;
852     c->flags |= CLASS_PROTECTED_NS;
853 }
854
855 abc_method_body_t* add_method(abc_file_t*pool, abc_class_t*cls, char*returntype, int num_params, va_list va)
856 {
857     /* construct code (method body) object */
858     abc_method_body_t* c = malloc(sizeof(abc_method_body_t));
859     memset(c, 0, sizeof(abc_method_body_t));
860     c->index = dict_append(pool->method_bodies, 0, c);
861     c->tag = swf_InsertTag(0,0);
862     c->pool = pool;
863     c->traits = dict_new();
864
865     /* construct method object */
866     abc_method_t* m = malloc(sizeof(abc_method_t));
867     memset(m, 0, sizeof(abc_method_t));
868     m->index = dict_append(pool->methods, 0, m);
869     if(returntype && strcmp(returntype, "void")) {
870         m->return_type = multiname_fromstring(pool, returntype);
871     } else {
872         m->return_type = 0;
873     }
874     int t;
875     for(t=0;t<num_params;t++) {
876         const char*param = va_arg(va, const char*);
877         list_append(&m->parameters, multiname_fromstring(pool, param));
878     }
879
880     /* crosslink the two objects */
881     m->method_body_index = c->index;
882     c->method = m;
883
884     return c;
885 }
886
887 abc_method_body_t* abc_class_constructor(abc_class_t*cls, char*returntype, int num_params, ...) 
888 {
889     va_list va;
890     va_start(va, num_params);
891     abc_method_body_t* c = add_method(cls->pool, cls, returntype, num_params, va);
892     va_end(va);
893     cls->iinit = c->index;
894     return c;
895 }
896
897 abc_method_body_t* abc_class_staticconstructor(abc_class_t*cls, char*returntype, int num_params, ...) 
898 {
899     va_list va;
900     va_start(va, num_params);
901     abc_method_body_t* c = add_method(cls->pool, cls, returntype, num_params, va);
902     va_end(va);
903     cls->static_constructor_index = c->index;
904     return c;
905 }
906
907 abc_trait_t*trait_new(int type, int name_index, int data1, int data2, int vindex, int vkind)
908 {
909     abc_trait_t*trait = malloc(sizeof(abc_trait_t));
910     memset(trait, 0, sizeof(abc_trait_t));
911     trait->type = type;
912     trait->name_index = name_index;
913     trait->data1 = data1;
914     trait->data2 = data2;
915     trait->vindex = vindex;
916     trait->vkind = vkind;
917     return trait;
918 }
919
920 abc_method_body_t* abc_class_method(abc_class_t*cls, char*returntype, char*name, int num_params, ...)
921 {
922     abc_file_t*pool = cls->pool;
923     va_list va;
924     va_start(va, num_params);
925     abc_method_body_t* c = add_method(cls->pool, cls, returntype, num_params, va);
926     va_end(va);
927     dict_append(cls->traits, 0, trait_new(TRAIT_METHOD, multiname_index(pool, name), 0, c->method->index, 0, 0));
928     return c;
929 }
930
931 void abc_AddSlot(abc_class_t*cls, char*name, int slot, char*multiname)
932 {
933     abc_file_t*pool = cls->pool;
934     int i = multiname_index(pool, name);
935     dict_append(cls->traits, 0, trait_new(TRAIT_SLOT, i, slot, multiname_index(pool, multiname), 0, 0));
936 }
937
938 void abc_method_body_addClassTrait(abc_method_body_t*code, char*multiname, int slotid, abc_class_t*cls)
939 {
940     abc_file_t*pool = code->pool;
941     int i = multiname_index(pool, multiname);
942     abc_trait_t*trait = trait_new(TRAIT_CLASS, i, slotid, cls->index, 0, 0);
943     dict_append(code->traits, 0, trait);
944 }
945
946 /* notice: traits of a method (body) belonging to an init script
947    and traits of the init script are *not* the same thing */
948 void abc_initscript_addClassTrait(abc_script_t*script, char*multiname, int slotid, abc_class_t*cls)
949 {
950     abc_file_t*pool = script->pool;
951     int i = multiname_index(pool, multiname);
952     abc_trait_t*trait = trait_new(TRAIT_CLASS, i, slotid, cls->index, 0, 0);
953     dict_append(script->traits, 0, trait);
954 }
955
956 abc_script_t* abc_initscript(abc_file_t*pool, char*returntype, int num_params, ...) 
957 {
958     va_list va;
959     va_start(va, num_params);
960     abc_method_body_t* c = add_method(pool, 0, returntype, num_params, va);
961     abc_script_t* s = malloc(sizeof(abc_script_t));
962     s->method = c->method;
963     s->traits = dict_new();
964     s->pool = pool;
965     dict_append(pool->scripts, 0, s);
966     va_end(va);
967     return s;
968 }
969
970 void swf_SetU30(TAG*tag, U32 u)
971 {
972     do {
973         swf_SetU8(tag, (u&~0x7f?0x80:0) | (u&0x7F));
974         u>>=7;
975     } while(u);
976 }
977 void swf_SetU30String(TAG*tag, const char*str)
978 {
979     int l = strlen(str);
980     swf_SetU30(tag, l);
981     swf_SetBlock(tag, (void*)str, l);
982 }
983
984 static void write_traits(abc_file_t*pool, TAG*tag, dict_t*traits)
985 {
986     if(!traits) {
987         swf_SetU30(tag, 0);
988         return;
989     }
990     swf_SetU30(tag, traits->num);
991     int s;
992
993     for(s=0;s<traits->num;s++) {
994         abc_trait_t*trait = (abc_trait_t*)dict_getdata(traits, s);
995         swf_SetU30(tag, trait->name_index);
996         swf_SetU8(tag, trait->type);
997         swf_SetU30(tag, trait->data1);
998         swf_SetU30(tag, trait->data2);
999         if(trait->type == 0) { //slot
1000             swf_SetU30(tag, trait->vindex);
1001             if(trait->vindex) {
1002                 swf_SetU8(tag, trait->vkind);
1003             }
1004         }
1005     }
1006 }
1007
1008 int register_multiname(abc_file_t*pool, abc_multiname_t*n)
1009 {
1010     if(!n)
1011         return 0;
1012     /* FIXME: might create duplicates */
1013     return dict_append_if_new2(pool->multinames, n->name, n);
1014 }
1015
1016 int register_namespace(abc_file_t*pool, abc_namespace_t*ns)
1017 {
1018     /* FIXME: might create duplicates */
1019     return dict_append_if_new2(pool->namespaces, ns->name, ns);
1020 }
1021
1022 static inline abc_multiname_t*multiname_lookup(abc_file_t*pool, int i)
1023 {
1024     return (abc_multiname_t*)dict_getdata(pool->multinames, i);
1025 }
1026
1027 void* swf_ReadABC(TAG*tag)
1028 {
1029     abc_file_t* pool = abc_file_new();
1030
1031     swf_SetTagPos(tag, 0);
1032     U32 abcflags = swf_GetU32(tag);
1033     int t;
1034     DEBUG printf("flags=%08x\n", abcflags);
1035     char*classname = swf_GetString(tag);
1036     U32 version = swf_GetU32(tag);
1037     if(version!=0x002e0010) {
1038         fprintf(stderr, "Warning: unknown AVM2 version %08x\n", version);
1039     }
1040
1041     int num_ints = swf_GetU30(tag);
1042     DEBUG printf("%d ints\n", num_ints);
1043     for(t=1;t<num_ints;t++) {
1044         S32 v = swf_GetU30(tag);
1045         DEBUG printf("int %d) %d\n", t, v);
1046         dict_append(pool->ints, 0, (void*)(ptroff_t)v);
1047     }
1048
1049     int num_uints = swf_GetU30(tag);
1050     DEBUG printf("%d uints\n", num_uints);
1051     for(t=1;t<num_uints;t++) {
1052         U32 v = swf_GetS30(tag);
1053         DEBUG printf("uint %d) %d\n", t, v);
1054         dict_append(pool->uints, 0, (void*)(ptroff_t)v);
1055     }
1056     
1057     int num_floats = swf_GetU30(tag);
1058     DEBUG printf("%d floats\n", num_floats);
1059     for(t=1;t<num_floats;t++) {
1060         double d = swf_GetD64(tag);
1061         DEBUG printf("float %d) %f\n", t, d);
1062         dict_append(pool->floats, 0, 0);
1063     }
1064     
1065     int num_strings = swf_GetU30(tag);
1066     DEBUG printf("%d strings\n", num_strings);
1067     for(t=1;t<num_strings;t++) {
1068         int len = swf_GetU30(tag);
1069         char*s = malloc(len+1);
1070         swf_GetBlock(tag, s, len);
1071         s[len] = 0;
1072         dict_append(pool->strings, s, 0);
1073         DEBUG printf("%d) \"%s\"\n", t, pool->strings->d[t].name);
1074     }
1075     int num_namespaces = swf_GetU30(tag);
1076     DEBUG printf("%d namespaces\n", num_namespaces);
1077     for(t=1;t<num_namespaces;t++) {
1078         U8 type = swf_GetU8(tag);
1079         int namenr = swf_GetU30(tag);
1080         const char*name = dict_getstr(pool->strings, namenr);
1081         abc_namespace_t*ns = malloc(sizeof(abc_namespace_t));
1082         memset(ns, 0, sizeof(abc_namespace_t));
1083         ns->access = type;
1084         ns->name = strdup(name);
1085         dict_append(pool->namespaces, name, ns);
1086         int w = 0;
1087         DEBUG w=1;
1088         if(w) {
1089             if(type==0x08) printf("Namespace %s\n", name);
1090             else if(type==0x16) printf("PackageNamespace %s\n", name);
1091             else if(type==0x17) printf("PackageInternalNs %s\n", name);
1092             else if(type==0x18) printf("ProtectedNamespace %s\n", name);
1093             else if(type==0x19) printf("ExplicitNamespace %s\n", name);
1094             else if(type==0x1A) printf("StaticProtectedNs %s\n", name);
1095             else if(type==0x05) printf("PrivateNs %s\n", name);
1096             else {
1097                 printf("Undefined namespace type\n");
1098                 return 0;
1099             }
1100         }
1101     }
1102     int num_sets = swf_GetU30(tag);
1103     DEBUG printf("%d namespace sets\n", num_sets);
1104     for(t=1;t<num_sets;t++) {
1105         int count = swf_GetU30(tag);
1106         int s;
1107         const char**name = malloc(sizeof(const char*)*count);
1108         int l = 0;
1109         for(s=0;s<count;s++) {
1110             int nsnr = swf_GetU30(tag);
1111             name[s] = dict_getstr(pool->namespaces, nsnr);
1112             l += strlen(name[s])+1;
1113         }
1114         char*desc = malloc(l+16);
1115         strcpy(desc, "{");
1116         for(s=0;s<count;s++) {
1117             strcat(desc, name[s]);
1118             strcat(desc, ",");
1119         }
1120         strcat(desc, "}");
1121         dict_append(pool->namespace_sets, desc, 0);
1122         DEBUG printf("set %d) %s\n", t, desc);
1123     }
1124
1125     int num_multinames = swf_GetU30(tag);
1126     DEBUG printf("%d multinames\n", num_multinames);
1127     for(t=1;t<num_multinames;t++) {
1128         abc_multiname_t*m = malloc(sizeof(abc_multiname_t));
1129         memset(m, 0, sizeof(abc_multiname_t));
1130
1131         m->type = swf_GetU8(tag);
1132
1133         if(m->type==0x07 || m->type==0x0d) {
1134             int nr1 = swf_GetU30(tag);
1135             m->ns = (abc_namespace_t*)dict_getdata(pool->namespaces, nr1);
1136             int name_index = swf_GetU30(tag);
1137             m->name = dict_getstr(pool->strings, name_index);
1138         } else if(m->type==0x0f || m->type==0x10) {
1139             int name_index = swf_GetU30(tag);
1140             m->name = dict_getstr(pool->strings, name_index);
1141         } else if(m->type==0x11 || m->type==0x12) {
1142         } else if(m->type==0x09 || m->type==0x0e) {
1143             int name_index = swf_GetU30(tag);
1144             int namespace_set_index = swf_GetU30(tag);
1145             m->name = dict_getstr(pool->strings, name_index);
1146             m->namespace_set_name = dict_getstr(pool->namespace_sets, namespace_set_index);
1147         } else if(m->type==0x1b || m->type==0x1c) {
1148             int namespace_set_index = swf_GetU30(tag);
1149             m->namespace_set_name = dict_getstr(pool->namespace_sets, namespace_set_index);
1150         } else {
1151             printf("can't parse type %d multinames yet\n", m->type);
1152             return 0;
1153         }
1154         char*mname = multiname_to_string(m);
1155         DEBUG printf("multiname %d) %s\n", t, mname);
1156         dict_append(pool->multinames, mname, m);
1157         free(mname);
1158     }
1159     
1160     int num_methods = swf_GetU30(tag);
1161     DEBUG printf("%d methods\n", num_methods);
1162     for(t=0;t<num_methods;t++) {
1163         abc_method_t*m = malloc(sizeof(abc_method_t));
1164         memset(m, 0, sizeof(*m));
1165         int param_count = swf_GetU30(tag);
1166         int return_type_index = swf_GetU30(tag);
1167         m->return_type = multiname_lookup(pool, return_type_index);
1168         m->index = t;
1169
1170         int s;
1171         for(s=0;s<param_count;s++) {
1172             int type_index = swf_GetU30(tag);
1173             list_append(&m->parameters, multiname_lookup(pool, type_index));
1174         }
1175
1176         int namenr = swf_GetU30(tag);
1177         m->name = "";
1178         if(namenr)
1179             m->name = dict_getstr(pool->strings, namenr);
1180
1181         m->flags = swf_GetU8(tag);
1182         
1183         DEBUG printf("method %d) %s flags=%02x\n", t, params_to_string(m->parameters), m->flags);
1184
1185         if(m->flags&0x08) {
1186             /* optional parameters */
1187             int num = swf_GetU30(tag);
1188             int s;
1189             for(s=0;s<num;s++) {
1190                 int val = swf_GetU30(tag);
1191                 U8 kind = swf_GetU8(tag); // specifies index type for "val"
1192             }
1193         }
1194         if(m->flags&0x80) {
1195             /* debug information- not used by avm2 */
1196             abc_multiname_list_t*l = m->parameters;
1197             while(l) {
1198                 m->name = dict_getstr(pool->strings, swf_GetU30(tag));
1199                 l = l->next;
1200             }
1201         }
1202         dict_append(pool->methods, m->name, m);
1203     }
1204             
1205     parse_metadata(tag, pool);
1206         
1207     /* skip classes, and scripts for now, and do the real parsing later */
1208     int num_classes = swf_GetU30(tag);
1209     int classes_pos = tag->pos;
1210     DEBUG printf("%d classes\n", num_classes);
1211     for(t=0;t<num_classes;t++) {
1212         abc_class_t*cls = malloc(sizeof(abc_class_t));
1213         memset(cls, 0, sizeof(abc_class_t));
1214         dict_append(pool->classes, 0, cls);
1215         
1216         DEBUG printf("class %d\n", t);
1217         swf_GetU30(tag); //classname
1218         swf_GetU30(tag); //supername
1219         cls->flags = swf_GetU8(tag);
1220         if(cls->flags&8) 
1221             swf_GetU30(tag); //protectedNS
1222         int s;
1223         int inum = swf_GetU30(tag); //interface count
1224         abc_multiname_list_t*list = 0;
1225         for(s=0;s<inum;s++) {
1226             int interface_index = swf_GetU30(tag);
1227             const char*interface = dict_getstr(pool->multinames, interface_index);
1228             abc_multiname_t* m = (abc_multiname_t*)dict_getdata(pool->multinames, interface_index);
1229             list_append(&list, m);
1230             DEBUG printf("  class %d interface: %s\n", t, interface);
1231         }
1232
1233         cls->iinit = swf_GetU30(tag);
1234         cls->traits = traits_parse(tag, pool);
1235     }
1236     for(t=0;t<num_classes;t++) {
1237         abc_class_t*cls = (abc_class_t*)dict_getdata(pool->classes, t);
1238         cls->static_constructor_index = swf_GetU30(tag); // cinit
1239         cls->static_constructor_traits = traits_parse(tag, pool);
1240     }
1241     int num_scripts = swf_GetU30(tag);
1242     DEBUG printf("%d scripts\n", num_scripts);
1243     for(t=0;t<num_scripts;t++) {
1244         int init = swf_GetU30(tag);
1245         dict_t*traits = traits_parse(tag, pool); //TODO: store
1246     }
1247
1248     int num_method_bodies = swf_GetU30(tag);
1249     DEBUG printf("%d method bodies\n", num_method_bodies);
1250     for(t=0;t<num_method_bodies;t++) {
1251         int methodnr = swf_GetU30(tag);
1252         if(methodnr >= pool->methods->num) {
1253             printf("Invalid method number: %d\n", methodnr);
1254             return 0;
1255         }
1256         abc_method_t*m = (abc_method_t*)dict_getdata(pool->methods, methodnr);
1257         abc_method_body_t*c = malloc(sizeof(abc_method_body_t));
1258         memset(c, 0, sizeof(abc_method_body_t));
1259         c->max_stack = swf_GetU30(tag);
1260         c->local_count = swf_GetU30(tag);
1261         c->init_scope_depth = swf_GetU30(tag);
1262         c->max_scope_depth = swf_GetU30(tag);
1263         int code_length = swf_GetU30(tag);
1264         c->method = m;
1265         m->method_body_index = t;
1266
1267         c->tag = swf_InsertTag(0,0);
1268
1269         swf_CopyData(c->tag, tag, code_length);
1270
1271         int exception_count = swf_GetU30(tag);
1272         int s;
1273         for(s=0;s<exception_count;s++) {
1274             swf_GetU30(tag); //from
1275             swf_GetU30(tag); //to
1276             swf_GetU30(tag); //target
1277             swf_GetU30(tag); //exc_type
1278             swf_GetU30(tag); //var_name
1279         }
1280         c->traits = traits_parse(tag, pool);
1281         if(!c->traits) {
1282             fprintf(stderr, "Can't parse code traits\n");
1283             return 0;
1284         }
1285         DEBUG printf("method_body %d) (method %d), %d bytes of code", t, methodnr, code_length);
1286         int r,l = code_length>32?32:code_length;
1287         for(r=0;r<l;r++) {
1288             DEBUG printf("%02x ", c->tag->data[r]);
1289         }
1290         DEBUG printf("\n");
1291
1292         dict_append(pool->method_bodies, 0, c);
1293     }
1294     if(tag->len - tag->pos) {
1295         fprintf(stderr, "%d unparsed bytes remaining in ABC block\n", tag->len - tag->pos);
1296         return 0;
1297     }
1298
1299     swf_SetTagPos(tag, classes_pos);
1300     for(t=0;t<num_classes;t++) {
1301         abc_class_t*cls = (abc_class_t*)dict_getdata(pool->classes, t);
1302
1303         int classname_index = swf_GetU30(tag);
1304         int superclass_index = swf_GetU30(tag);
1305         cls->classname = dict_getstr(pool->multinames, classname_index);
1306         cls->superclass = dict_getstr(pool->multinames, superclass_index);
1307         cls->flags = swf_GetU8(tag);
1308         const char*ns = "";
1309         if(cls->flags&8) {
1310             int ns_index = swf_GetU30(tag);
1311             cls->protectedNS = dict_getstr(pool->namespaces, ns_index);
1312         }
1313         
1314         if(cls->flags&1) printf("sealed ");
1315         if(cls->flags&2) printf("final ");
1316         if(cls->flags&4) printf("interface ");
1317         if(cls->flags&8) {
1318             printf("protectedNS<%s> ", cls->protectedNS);
1319         }
1320
1321         printf("class %s", cls->classname);
1322         if(cls->superclass && cls->superclass[0]) {
1323             printf(" extends %s", cls->superclass);
1324             abc_multiname_list_t*ilist = cls->interfaces;
1325             if(ilist)
1326                 printf(" implements");
1327             while(ilist) {
1328                 char*s = multiname_to_string(ilist->abc_multiname);
1329                 printf(" %d", s);
1330                 free(s);
1331                 ilist = ilist->next;
1332             }
1333             ilist->next;
1334             
1335         }
1336         if(cls->flags&0xf0) 
1337             printf("extra flags=%02x\n", cls->flags&0xf0);
1338         printf("{\n");
1339         
1340         dump_method("    ","staticconstructor", "", cls->static_constructor_index, pool);
1341         dump_traits("    ", cls->static_constructor_traits, pool);
1342         
1343         int num_interfaces = swf_GetU30(tag); //interface count
1344         int s;
1345         for(s=0;s<num_interfaces;s++) {
1346             swf_GetU30(tag); // multiname index TODO
1347         }
1348         cls->iinit = swf_GetU30(tag);
1349         dump_method("    ","constructor", classname, cls->iinit, pool);
1350         cls->traits = traits_parse(tag, pool);
1351         if(!cls->traits) {
1352             fprintf(stderr, "Can't parse class traits\n");
1353             return 0;
1354         }
1355         dump_traits("    ",cls->traits, pool);
1356         
1357         printf("}\n");
1358     }
1359     for(t=0;t<num_classes;t++) {
1360         /* SKIP */
1361         swf_GetU30(tag); // cindex
1362         traits_parse(tag, pool); // TODO: free
1363     }
1364     int num_scripts2 = swf_GetU30(tag);
1365     printf("\n");
1366     for(t=0;t<num_scripts2;t++) {
1367         int init = swf_GetU30(tag);
1368         abc_method_t*m = (abc_method_t*)dict_getdata(pool->methods, init);
1369         
1370         abc_script_t*s = malloc(sizeof(abc_script_t));
1371         memset(s, 0, sizeof(abc_script_t));
1372         s->method = m;
1373         s->traits = traits_parse(tag, pool);
1374         dict_append(pool->scripts, 0, s);
1375         if(!s->traits) {
1376             fprintf(stderr, "Can't parse script traits\n");
1377             return 0;
1378         }
1379         dump_method("","initmethod", "init", init, pool);
1380         dump_traits("", s->traits, pool);
1381     }
1382     return pool;
1383 }
1384
1385 void swf_WriteABC(TAG*abctag, void*code)
1386 {
1387     abc_file_t*pool = (abc_file_t*)code;
1388
1389     TAG*tmp = swf_InsertTag(0,0);
1390     TAG*tag = tmp;
1391     int t;
1392
1393     swf_SetU30(tag, pool->methods->num);
1394     for(t=0;t<pool->methods->num;t++) {
1395         abc_method_t*m = (abc_method_t*)dict_getdata(pool->methods, t);
1396         int n = 0;
1397         abc_multiname_list_t*l = m->parameters;
1398         swf_SetU30(tag, list_length(m->parameters));
1399         swf_SetU30(tag, register_multiname(pool, m->return_type));
1400         int s;
1401         while(l) {
1402             swf_SetU30(tag, register_multiname(pool, l->abc_multiname));
1403             l = l->next;
1404         }
1405         swf_SetU30(tag, 0); // name
1406         swf_SetU8(tag, 0); //flags
1407     }
1408     
1409     swf_SetU30(tag, 0);//metadata
1410
1411     swf_SetU30(tag, pool->classes->num);
1412
1413     for(t=0;t<pool->classes->num;t++) {
1414         abc_class_t*c = (abc_class_t*)dict_getdata(pool->classes, t);
1415    
1416         int classname_index = multiname_index(pool, c->classname);
1417         int superclass_index = multiname_index(pool, c->superclass);
1418
1419         swf_SetU30(tag, classname_index);
1420         swf_SetU30(tag, superclass_index);
1421
1422         swf_SetU8(tag, c->flags); // flags
1423         if(c->flags&0x08) {
1424             abc_namespace_t*ns = abc_protectednamespace(pool, c->protectedNS);
1425             int ns_index = register_namespace(pool, ns);
1426             swf_SetU30(tag, ns_index);
1427         }
1428
1429         swf_SetU30(tag, 0); // no interfaces
1430         if(c->iinit<0) {
1431             fprintf(stderr, "Error: Class %s has no constructor\n", c->classname);
1432             return;
1433         }
1434         swf_SetU30(tag, c->iinit);
1435         write_traits(pool, tag, c->traits);
1436     }
1437     for(t=0;t<pool->classes->num;t++) {
1438         abc_class_t*c = (abc_class_t*)dict_getdata(pool->classes, t);
1439         if(c->static_constructor_index<0) {
1440             fprintf(stderr, "Error: Class %s has no static constructor\n", c->classname);
1441             return;
1442         }
1443         swf_SetU30(tag, c->static_constructor_index);
1444         write_traits(pool, tag, c->static_constructor_traits);
1445     }
1446
1447     swf_SetU30(tag, pool->scripts->num);
1448     for(t=0;t<pool->scripts->num;t++) {
1449         abc_script_t*s = (abc_script_t*)dict_getdata(pool->scripts, t);
1450         swf_SetU30(tag, s->method->index); //!=t!
1451         write_traits(pool, tag, s->traits);
1452     }
1453
1454     swf_SetU30(tag, pool->method_bodies->num);
1455     for(t=0;t<pool->method_bodies->num;t++) {
1456         abc_method_body_t*c = (abc_method_body_t*)dict_getdata(pool->method_bodies, t);
1457         abc_method_t*m = c->method;
1458         swf_SetU30(tag, m->index);
1459         swf_SetU30(tag, c->max_stack);
1460         swf_SetU30(tag, c->local_count);
1461         swf_SetU30(tag, c->init_scope_depth);
1462         swf_SetU30(tag, c->max_scope_depth);
1463         swf_SetU30(tag, c->tag->len);
1464         swf_SetBlock(tag, c->tag->data, c->tag->len);
1465         swf_SetU30(tag, c->exception_count);
1466         write_traits(pool, tag, c->traits);
1467     }
1468
1469     // --- start to write real tag --
1470     
1471     tag = abctag;
1472
1473     for(t=1;t<pool->multinames->num;t++) {
1474         abc_multiname_t*m = (abc_multiname_t*)dict_getdata(pool->multinames, t);
1475         if(m->ns) {
1476             register_namespace(pool, m->ns);
1477         }
1478         if(m->namespace_set_name) {
1479             // FIXME
1480         }
1481         if(m->name)
1482             dict_append_if_new(pool->strings, m->name, 0);
1483     }
1484     for(t=1;t<pool->namespaces->num;t++) {
1485         char*namespace_name = (char*)dict_getstr(pool->namespaces, t);
1486         dict_append_if_new(pool->strings, namespace_name, 0);
1487     }
1488
1489     swf_SetU32(tag, 1);
1490     swf_SetU8(tag, 0);
1491     swf_SetU16(tag, 0x10);
1492     swf_SetU16(tag, 0x2e);
1493
1494     swf_SetU30(tag, pool->ints->num>1?pool->ints->num:0);
1495     // ...
1496     swf_SetU30(tag, pool->uints->num>1?pool->uints->num:0);
1497     // ...
1498     swf_SetU30(tag, pool->floats->num>1?pool->floats->num:0);
1499     // ...
1500     swf_SetU30(tag, pool->strings->num>1?pool->strings->num:0);
1501     for(t=1;t<pool->strings->num;t++) {
1502         swf_SetU30String(tag, dict_getstr(pool->strings, t));
1503     }
1504     swf_SetU30(tag, pool->namespaces->num>1?pool->namespaces->num:0);
1505     for(t=1;t<pool->namespaces->num;t++) {
1506         abc_namespace_t*ns= (abc_namespace_t*)dict_getdata(pool->namespaces, t);
1507         const char*name = ns->name;
1508         int i = dict_find(pool->strings, name);
1509         if(i<0) {
1510             fprintf(stderr, "Couldn't find namespace \"%s\" in constant pool\n", name);
1511             return;
1512         }
1513         swf_SetU8(tag, ns->access);
1514         swf_SetU30(tag, i);
1515     }
1516     swf_SetU30(tag, pool->sets->num>1?pool->sets->num:0);
1517     // ...
1518
1519     swf_SetU30(tag, pool->multinames->num>1?pool->multinames->num:0);
1520     // ...
1521     for(t=1;t<pool->multinames->num;t++) {
1522         abc_multiname_t*m = (abc_multiname_t*)dict_getdata(pool->multinames, t);
1523         swf_SetU8(tag, m->type);
1524
1525         if(m->ns) {
1526             assert(m->type==0x07 || m->type==0x0d);
1527             /* fixme: might find wrong version */
1528             int i = dict_find2(pool->namespaces, m->ns->name, (void*)(ptroff_t)m->ns);
1529             if(i<0) fprintf(stderr, "internal error: unregistered namespace %02x %s %s\n", m->ns->access, access2str(m->ns->access), m->ns->name);
1530             swf_SetU30(tag, i);
1531         }
1532         if(m->namespace_set_name) {
1533             assert(m->type==0x09 || m->type==0x0e || m->type==0x1c || m->type==0x1b);
1534             int i = dict_find(pool->namespace_sets, m->namespace_set_name);
1535             if(i<0) fprintf(stderr, "internal error: unregistered namespace set\n");
1536             swf_SetU30(tag, i);
1537         }
1538         if(m->name) {
1539             assert(m->type==0x09 || m->type==0x0e || m->type==0x07 || m->type==0x0d || m->type==0x0f || m->type==0x10);
1540             int i = dict_find(pool->strings, m->name);
1541             if(i<0) fprintf(stderr, "internal error: unregistered name\n");
1542             swf_SetU30(tag, i);
1543         }
1544     }
1545
1546     swf_SetBlock(tag, tmp->data, tmp->len);
1547
1548     swf_DeleteTag(0, tmp);
1549 }
1550
1551 #include "swfabc_ops.c"
1552
1553 void swf_AddButtonLinks(SWF*swf, char stop_each_frame)
1554 {
1555     int num_frames = 0;
1556     TAG*tag=swf->firstTag;
1557     while(tag) {
1558         if(tag->id == ST_SHOWFRAME)
1559             num_frames++;
1560         tag = tag->next;
1561     }
1562
1563     abc_file_t*file = abc_file_new();
1564     abc_method_body_t*c = 0;
1565    
1566     abc_class_t*cls = abc_class_new(file, "rfx::MainTimeline", "flash.display::MovieClip");
1567     abc_class_protectedNS(cls, "rfx::MainTimeline");
1568   
1569     TAG*abctag = swf_InsertTagBefore(swf, swf->firstTag, ST_DOABC);
1570     
1571     tag = swf_InsertTag(abctag, ST_SYMBOLCLASS);
1572     swf_SetU16(tag, 1);
1573     swf_SetU16(tag, 0);
1574     swf_SetString(tag, "rfx.MainTimeline");
1575
1576     c = abc_class_staticconstructor(cls, 0, 0);
1577     c->max_stack = 1;
1578     c->local_count = 1;
1579     c->init_scope_depth = 9;
1580     c->max_scope_depth = 10;
1581
1582     abc_getlocal_0(c);
1583     abc_pushscope(c);
1584     abc_returnvoid(c);
1585
1586     c = abc_class_constructor(cls, 0, 0);
1587     c->max_stack = 3;
1588     c->local_count = 1;
1589     c->init_scope_depth = 10;
1590     c->max_scope_depth = 11;
1591
1592     abc_getlocal_0(c);
1593     abc_pushscope(c);
1594
1595     abc_getlocal_0(c);
1596     abc_constructsuper(c,0);
1597
1598     abc_getlex(c, "[package]flash.system::Security");
1599     abc_pushstring(c, "*");
1600     abc_callpropvoid(c, "[package]::allowDomain", 1);
1601     
1602     if(stop_each_frame) {
1603         int i;
1604         for(i=0;i<num_frames;i++) {
1605             abc_findpropstrict(c,"[package]::addFrameScript");
1606             abc_pushbyte(c,i);
1607             abc_getlex(c,"[packageinternal]rfx::stopframe");
1608             abc_callpropvoid(c,"[package]::addFrameScript",2);
1609         }
1610     }
1611       
1612     tag = swf->firstTag;
1613     while(tag) {
1614         if(tag->id == ST_DEFINEBUTTON || tag->id == ST_DEFINEBUTTON2) {
1615             char buttonname[80];
1616             char functionname[80];
1617             sprintf(buttonname, "::button%d", swf_GetDefineID(tag));
1618             //sprintf(functionname, ":clickLink%d", swf_GetDefineID(t));
1619             sprintf(functionname, "::clickLink1");
1620             abc_getlex(c,buttonname);
1621             abc_getlex(c,"flash.events::MouseEvent");
1622             abc_getproperty(c, "::CLICK");
1623             abc_getlex(c,functionname);
1624             abc_callpropvoid(c, "::addEventListener" ,2);
1625         }
1626         tag = tag->next;
1627     }
1628
1629     abc_returnvoid(c);
1630
1631     if(stop_each_frame) {
1632         c = abc_class_method(cls, 0, "[packageinternal]rfx::stopframe", 0);
1633         c->max_stack = 3;
1634         c->local_count = 1;
1635         c->init_scope_depth = 10;
1636         c->max_scope_depth = 11;
1637
1638         abc_getlocal_0(c);
1639         abc_pushscope(c);
1640         abc_findpropstrict(c, "[package]::stop");
1641         abc_callpropvoid(c, "[package]::stop", 0);
1642         abc_returnvoid(c);
1643     }
1644     
1645     tag = swf->firstTag;
1646     while(tag) {
1647         if(tag->id == ST_DEFINEBUTTON || tag->id == ST_DEFINEBUTTON2) {
1648             char buttonname[80];
1649             sprintf(buttonname, ":button%d", swf_GetDefineID(tag));
1650             abc_AddSlot(cls, buttonname, 0, "flash.display::SimpleButton");
1651         }
1652         tag = tag->next;
1653     }
1654
1655     c = abc_class_method(cls, "::void", "::clickLink1", 1, "flash.events::MouseEvent");
1656     c->max_stack = 3;
1657     c->local_count = 2;
1658     c->init_scope_depth = 10;
1659     c->max_scope_depth = 11;
1660     abc_getlocal_0(c);
1661     abc_pushscope(c);
1662     abc_findpropstrict(c,"flash.net::navigateToURL");
1663     abc_findpropstrict(c,"flash.net::URLRequest");
1664     abc_pushstring(c,"http://www.quiss.org/");
1665     //abc_pushstring(c,"file:///home/kramm/c/swftools/lib/modules/test2.html");
1666     abc_constructprop(c,"flash.net::URLRequest", 1);
1667     abc_callpropvoid(c,"flash.net::navigateToURL", 1);
1668     abc_returnvoid(c);
1669   
1670
1671     abc_script_t*s = abc_initscript(file, 0, 0);
1672     c = (abc_method_body_t*)dict_getdata(file->method_bodies, s->method->method_body_index);
1673     c->max_stack = 2;
1674     c->local_count = 1;
1675     c->init_scope_depth = 1;
1676     c->max_scope_depth = 9;
1677     abc_getlocal_0(c);
1678     abc_pushscope(c);
1679     abc_getscopeobject(c, 0);
1680     abc_getlex(c,"::Object");
1681     abc_pushscope(c);
1682     abc_getlex(c,"flash.events::EventDispatcher");
1683     abc_pushscope(c);
1684     abc_getlex(c,"flash.display::DisplayObject");
1685     abc_pushscope(c);
1686     abc_getlex(c,"flash.display::InteractiveObject");
1687     abc_pushscope(c);
1688     abc_getlex(c,"flash.display::DisplayObjectContainer");
1689     abc_pushscope(c);
1690     abc_getlex(c,"flash.display::Sprite");
1691     abc_pushscope(c);
1692     abc_getlex(c,"flash.display::MovieClip");
1693     abc_pushscope(c);
1694     abc_getlex(c,"flash.display::MovieClip");
1695     abc_newclass(c,cls);
1696     abc_popscope(c);
1697     abc_popscope(c);
1698     abc_popscope(c);
1699     abc_popscope(c);
1700     abc_popscope(c);
1701     abc_popscope(c);
1702     abc_popscope(c);
1703     abc_initproperty(c,"rfx::MainTimeline");
1704     abc_returnvoid(c);
1705
1706     //abc_method_body_addClassTrait(c, "rfx:MainTimeline", 1, cls);
1707     abc_initscript_addClassTrait(s, "rfx::MainTimeline", 1, cls);
1708
1709     swf_WriteABC(abctag, file);
1710 }
1711