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