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