added disassembler and assembler
[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 Alessandro Molina
9    Copyright (c) 2007,2008 Matthias Kramm <kramm@quiss.org>
10  
11    This program is free software; you can redistribute it and/or modify
12    it under the terms of the GNU General Public License as published by
13    the Free Software Foundation; either version 2 of the License, or
14    (at your option) any later version.
15
16    This program is distributed in the hope that it will be useful,
17    but WITHOUT ANY WARRANTY; without even the implied warranty of
18    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19    GNU General Public License for more details.
20
21    You should have received a copy of the GNU General Public License
22    along with this program; if not, write to the Free Software
23    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
24
25 #include <stdarg.h>
26 #include "../rfxswf.h"
27
28 static unsigned AVM2_uint32toU30(unsigned val, char * out)
29 {
30     unsigned len = 0;
31
32     while(val) {
33           out[len++] = (val&~0x7f?0x80:0) | (val & 0x7F);
34           val >>= 7;
35     }
36
37     return len;
38 }
39
40 void AVM2_InsertStops(SWF*swf)
41 {
42     TAG * t;
43
44     //MAIN AS3 CLASS INIT
45     unsigned frame_nums = 0;
46
47     /* Count number of pages to set up stop callback for every frame */
48     t = swf->firstTag;
49     while(t) {
50         if (t->id == ST_SHOWFRAME) ++frame_nums;
51         t = t->next;
52     }
53
54     TAG * classCall = swf_InsertTagBefore(swf, swf->firstTag, ST_SYMBOLCLASS);
55     swf_SetU16(classCall, 1); // number of symbols
56     swf_SetU16(classCall, 0); // object id
57     swf_SetString(classCall, "stop_fla:MainTimeline"); // class to associate with the symbol
58                       
59     //0x52 is the Flash9 equivalent to DoAction
60     char init_pool[322] = { 
61       0x01,0x00,0x00,0x00, /* Flag Parameter to ST_DOABC (1 = lazy load)*/
62       0x00,                /* 0 terminated class name */
63       0x10,0x00,0x2e,0x00, /* ABC file magic number (minor version, major version) */
64       0x00, /* zero integers */
65       0x00, /* zero unsigned integers */
66       0x00, /* zero doubles */
67                 
68       0x11, /* 16 strings (+1) */
69         0x08, 's','t','o','p','_','f','l','a', 
70         0x0c, 'M','a','i','n','T','i','m','e','l','i','n','e',
71         0x0d, 'f','l','a','s','h','.','d','i','s','p','l','a','y', 
72         0x09, 'M','o','v','i','e','C','l','i','p',
73         0x15, 's','t','o','p','_','f','l','a',':','M','a','i','n','T','i','m','e','l','i','n','e',
74         0x06, 'd','o','s','t','o','p',
75         0x00, // Empty string: ref. to the global namespace
76         0x04, 's','t','o','p',
77         0x0e, 'a','d','d','F','r','a','m','e','S','c','r','i','p','t',
78         0x06, 'O','b','j','e','c','t',
79         0x0c, 'f','l','a','s','h','.','e','v','e','n','t','s',
80         0x0f, 'E','v','e','n','t','D','i','s','p','a','t','c','h','e','r',
81         0x0d, 'D','i','s','p','l','a','y','O','b','j','e','c','t',
82         0x11, 'I','n','t','e','r','a','c','t','i','v','e','O','b','j','e','c','t',
83         0x16, 'D','i','s','p','l','a','y','O','b','j','e','c','t','C','o','n','t','a','i','n','e','r',
84         0x06, 'S','p','r','i','t','e',
85
86       0x07, /* 6 namespaces (+1) */
87         0x16,0x01, /* kind: CONSTANT_PackageNamespace, ref. to: stop_fla */
88         0x16,0x03, /* kind: CONSTANT_PackageNamespace, ref. to: flash.display */
89         0x18,0x05, /* kind: CONSTANT_ProtectedNamespace, ref. to: stop_fla:MainTimeline */
90         0x17,0x01, /* kind: CONSTANT_PackageInternalNs, ref. to: MainTimeline */
91         0x16,0x07, /* kind: CONSTANT_PackageNamespace, ref. to the global namespace */
92         0x16,0x0b, /* kind: CONSTANT_PackageNamespace, ref. to: flash.events */
93                               
94       0x00, /* zero namespace sets */
95                               
96       0x0c, /* 11 MultiNames (+1) */
97         /*  1st value: Multiname kind (0x07 = Qualified Name, a multiname with 1 namespace, refers to a method)
98             2nd value: refers to namespace name index in the namespace table
99             3rd value: refers to method name index in the string table */
100         0x07,0x01,0x02, /* stop_fla:MainTimeLine */
101         0x07,0x02,0x04, /* flash.display:MovieClip */
102         0x07,0x04,0x06, /* <4th namespace>:dostop */
103         0x07,0x05,0x08, /* <global>:stop */
104         0x07,0x05,0x09, /* <global>:addFrameScript */
105         0x07,0x05,0x0a, /* <global>:Object */
106         0x07,0x06,0x0c, /* flash.events:EventDispatcher */
107         0x07,0x02,0x0d, /* flash.display:DisplayObject */
108         0x07,0x02,0x0e, /* flash.display:InteractiveObject */
109         0x07,0x02,0x0f, /* flash.display:DisplayObjectContainer */
110         0x07,0x02,0x10, /* flash.display:Sprite */
111                               
112       0x04, /* 4 Methods */
113         /* METHOD 1 */
114         0x00,0x00,0x00,0x00, /* No params (nor params types), no return type, no method name, flags */
115         0x00,0x00,0x00,0x00, /* No params (nor params types), no return type, no method name, flags */
116         0x00,0x00,0x00,0x00, /* No params (nor params types), no return type, no method name, flags */
117         0x00,0x00,0x00,0x00, /* No params (nor params types), no return type, no method name, flags */
118
119       0x00, /* Zero Metadata */
120
121       0x01, /* 1 Class */
122         0x01, /* Name: ref. to multiname no. 1 (MainTimeline) */
123         0x02, /* Super_name (base class): ref. to multiname no. 2 (flash.display) */
124         0x08, /* Flags: 0x08 value indicates that it uses its protected namespace (and make next field exists) */
125         0x03, /* Ref. to namespace no. 3 (MainTimeline, protected namespace for this class) */
126         0x00, /* No. of interfaces: there are no interfaces (nor interface definition) */
127         0x02, /* Initializer index: ref. to method no. 2 */
128         0x01, /* No. of traits */
129         /* Trait section */     
130                 0x03, /* Name: ref. to multiname no. 3 (stop) */
131                 0x01, /* 0000: no attributes (nor metadata in the next subsection);
132                                  then 1: type is Trait_Method */
133                 /* Trait_method section */
134                         0x00, /* NO optimization for virtual calls */
135                         0x01, /* Ref. to method no. 1 */
136         /* HERE FOLLOW THE CLASS DATA */
137         0x00, /* Ref. to method no. 0 as static initializer for this class */
138         0x00, /* No. of traits for this class (no ones) */
139
140       0x01, /* 1 Script */
141         0x03, /* Ref. to method no. 3, invoked prior to any other code in the script  */
142         0x01, /* No. of traits */
143         /* Trait section */
144         0x01, /* Name: ref. to multiname no. 1 (flash.display:MovieClip) */
145         0x04,  /* 0000: no attributes (nor metadata in the next subsection);
146                                   then 4: type is Trait_Class*/
147                         /* Trait_class section */
148                         0x01, /* Slot ID where the trait resides */
149                         0x00, /* Class index (there is only one class)*/
150
151       0x04, /* Method body count: there are 4 method bodies */
152         /* HERE FOLLOW THE METHOD BODY DATA */
153         0x00, /* Method index, ref. to method no. 0 */
154         0x01, /* Max stack slots the method can use */
155         0x01, /* No. of registers +1 the method can use: this one cannot use registers */
156         0x09,0x0a, /* Min and max scope depth the method can access*/
157         0x03, /* Code length (in bytes) */
158         /* The actual method code:
159                         this is the function stop_fla::MainTimeline$cinit()*/
160                         0xd0,0x30,0x47,
161         0x00, /* No. of exceptions (no exceptions) */
162         0x00, /* No. of traits (no traits) */
163
164         0x01, /* Method index, ref. to method no. 1 */
165         0x01, /* Max stack slots the method can use */
166         0x01, /* No. of registers +1 the method can use: this one cannot use registers */
167         0x0a,0x0b, /* Min and max scope depth the method can access*/
168         0x08, /* Code length (in bytes) */
169         /* The actual method code:
170            this is the function stop_fla::dostop(), 
171            the one that actually executes the stop() */
172         0xd0,0x30,0x5d,0x04,0x4f,0x04,0x00,0x47,
173         0x00, /* No. of exceptions (no exceptions) */
174         0x00, /* No. of traits (no traits) */
175     };
176
177     /* Header of stop_fla::MainTimeline() method */
178     char constructor_header[5] = {
179       0x02, /* Method index, ref. to method no. 2 */
180       0x03, /* Max stack slots the method can use */
181       0x01, /* No. of registers +1 the method can use: this one cannot use registers */
182       0x0a,0x0b /* Min and max scope depth the method can access*/
183     };
184
185     char constructor_first[5] = {
186       /* The actual method code:
187     This is the function stop_fla::MainTimeline()
188     Does: calls the super constructor for class #0 (MainTimeline),
189             then puts on the stack the object, namespace and name of the arguments
190             needed by the addFrameScripts, then calls the addFrameScripts
191              */
192       0xd0,   /* getlocal0 */
193       0x30,   /* pushscope */
194       0xd0,   /* getlocal0 */
195       0x49,   /* constructsuper */
196       0x00   /*              0 */
197     };
198
199     char constructor_frame_register[10] = {
200       0x5d,   /* findpropstrict */
201       0x05,   /*              'addFrameScript' */
202       0x25,   /* pushshort */
203       0x00,   /*              frame number for pushshort */
204   0x02,   /* NOP (hack to write u30 value of frame number when > 127) */
205       0x60,   /* getlex */
206       0x03,   /*              'stop_fla::dostop' */
207       0x4f,   /* callpropvoid */
208       0x05,   /*              'addFrameScript' */
209       0x02   /*              2*/
210     };
211
212     char constructor_return[3] = { 
213       0x47, /* returnvoid */
214       0x00, /* No. of exceptions (no exceptions) */
215       0x00, /* No. of traits (no traits) */
216     };
217
218     char script_init_pool[47] = {
219       0x03, /* Method index, ref. to method no. 3 */
220       0x02, /* Max stack slots the method can use */
221       0x01, /* No. of registers +1 the method can use: this one cannot use registers */
222       0x01,0x09, /* Min and max scope depth the method can access*/
223       0x27, /* Code length (in bytes) */
224       /* The actual method code:
225                       this is the function script0$init() */
226       0xd0,0x30,0x65,0x00,0x60,0x06,0x30,0x60,0x07,0x30,0x60,0x08,0x30,0x60,0x09,0x30,0x60,0x0a,0x30,0x60,
227       0x0b,0x30,0x60,0x02,0x30,0x60,0x02,0x58,0x00,0x1d,0x1d,0x1d,0x1d,0x1d,0x1d,0x1d,0x68,0x01,0x47,
228       0x00, /* No. of exceptions (no exceptions) */
229       0x00  /* No. of traits (no traits) */
230     };
231     /* END OF THE ABCFILE (Actionscript Byte Code) */
232
233     char code_len[5] = {0, };
234     unsigned clen_len = AVM2_uint32toU30((6 + sizeof(constructor_frame_register) * frame_nums), code_len);
235     unsigned i, offset = 0;
236
237     TAG *classInit = swf_InsertTagBefore(swf, swf->firstTag, ST_DOABC);
238
239     /* Copy the environment Initialization code */
240     swf_SetBlock(classInit, (U8*)init_pool,sizeof(init_pool));
241     /* Copy Constructor Method header */
242     swf_SetBlock(classInit, (U8*)constructor_header, sizeof(constructor_header));
243     /* Add Code block size (u30) to the method header */
244     swf_SetBlock(classInit, (U8*)code_len, clen_len);
245
246     /* Copy Constructor Method body first part */
247     swf_SetBlock(classInit, (U8*)constructor_first, sizeof(constructor_first));
248
249     /* Register the callback for every frame */
250     for (i = 0; i < frame_nums; ++i) {
251         AVM2_uint32toU30(i,constructor_frame_register + 3); // Write current frame number
252         swf_SetBlock(classInit, (U8*)constructor_frame_register, sizeof(constructor_frame_register));
253     }
254
255     /* Copy Constructor method body ending, just a return */
256     swf_SetBlock(classInit, (U8*)constructor_return, sizeof(constructor_return));
257
258     /* Copy the script init code */
259     swf_SetBlock(classInit, (U8*)script_init_pool, sizeof(script_init_pool));
260 }
261
262 void AVM2_InsertButtonLink(SWF*swf)
263 {               
264     unsigned char displayEventCode[] = {
265     // button.dispatchEvent(new Event("pdflinkdown"),true,true)
266
267     0x01, 0x00, 0x00, 0x00, //flags
268     0x00, 
269     0x10, 0x00, 0x2e, 0x00, //version
270     0x00, //no ints
271     0x00, //no uints
272     0x00, //no floats
273     0x14, //19 strings
274     0x17, 'e','v','e','n','t','_','o','h','n','e','_','l','i','s','t','e','n','e','r','_','f','l','a',
275     0x0c, 'M','a','i','n','t','i','m','e','l','i','n','e',
276     0x0d, 'f','l','a','s','h','.','d','i','s','p','l','a','y',
277     0x09, 'M','o','v','i','e','c','l','i','p',
278     0x24, 'e','v','e','n','t','_','o','h','n','e','_','l','i','s','t','e','n','e','r','_','f','l','a',':','M','a','i','n','t','i','m','e','l','i','n','e',
279     0x00,
280     0x06, 'b','u','t','t','o','n', 
281     0x06, 'f','r','a','m','e','1', 
282     0x0c, 'f','l','a','s','h','.','e','v','e','n','t','s', 
283     0x05, 'E','v','e','n','t', 
284     0x0b, 'p','d','f','l','i','n','k','d','o','w','n', 
285     0x0d, 'd','i','s','p','a','t','c','h','E','v','e','n','t', 
286     0x0e, 'a','d','d','F','r','a','m','e','S','c','r','i','p','t',
287     0x06, 'O','b','j','e','c','t', 
288     0x0f, 'E','v','e','n','t','d','i','s','p','a','t','c','h','e','r',
289     0x0d, 'D','i','s','p','l','a','y','O','b','j','e','c','t', 
290     0x11, 'I','n','t','e','r','a','c','t','i','v','e','O','b','j','e','c','t',
291     0x16, 'D','i','s','p','l','a','y','O','b','j','e','c','t','C','o','n','t','a','i','n','e','r',
292     0x06, 'S','p','r','i','t','e',
293
294     0x07,  // 6 namespaces
295     0x16, 0x01, 
296     0x16, 0x03, 
297     0x18, 0x05, 
298     0x16, 0x06, 
299     0x17, 0x01, 
300     0x16, 0x09,
301
302     0x00, //zero namespace sets
303
304     0x0e, //13 multinames
305     0x07, 0x01, 0x02, 
306     0x07, 0x02, 0x04, 
307     0x07, 0x04, 0x07, 
308     0x07, 0x05, 0x08, 
309     0x07, 0x06, 0x0a, 
310     0x07, 0x04, 0x0c, 
311     0x07, 0x04, 0x0d, 
312     0x07, 0x04, 0x0e, 
313     0x07, 0x06, 0x0f, 
314     0x07, 0x02, 0x10, 
315     0x07, 0x02, 0x11, 
316     0x07, 0x02, 0x12, 
317     0x07, 0x02, 0x13,
318
319     0x04, // 4 methods
320     0x00, 0x00, 0x00, 0x00, 
321     0x00, 0x00, 0x00, 0x00, 
322     0x00, 0x00, 0x00, 0x00, 
323     0x00, 0x00, 0x00, 0x00, 
324     
325     0x00, // zero metadata
326
327     0x01, // 1 class
328       0x01, 0x02, 0x08, 0x03, 0x00, 0x02, 
329       0x02, // 2 traits
330         0x03, 0x00, // name, slot
331           0x00, 0x02, 0x00, 
332         0x04, 0x01, // name, method,
333           0x00, 0x01,
334       0x00, // ref to method 0 (initializer)
335       0x00, // no traits
336
337     0x01, // 1 script
338       0x03, 0x01, 0x01, 0x04, 0x01, 0x00, 
339
340     0x04, // 4 method bodies
341        // method 1
342        0x00, 0x01, 0x01, 0x09, 0x0a, 
343        0x03, 0xd0, 0x30, 0x47, // code
344        0x00, 0x00, 
345        // method 2
346        0x01, 0x05, 0x01, 0x0a, 0x0b, 
347        0x11, 0xd0, 0x30, 0x60, 0x03, 0x5d, 0x05, 0x2c, 0x0b, 0x26, 0x26, 0x4a, 0x05, 0x03, 0x4f, 0x06, 0x01, 0x47, // code
348        0x00, 0x00, 
349        // method 3
350        0x02, 0x03, 0x01, 0x0a, 0x0b, 
351        0x0f, 0xd0, 0x30, 0xd0, 0x49, 0x00, 0x5d, 0x07, 0x24, 0x00, 0x60, 0x04, 0x4f, 0x07, 0x02, 0x47, // code
352        0x00, 0x00, 
353        // method 4
354        0x03, 0x02, 0x01, 0x01, 0x09, 
355        0x27, 0xd0, 0x30, 0x65, 0x00, 0x60, 0x08, 0x30, 0x60, 0x09, 0x30, 0x60, 0x0a, 0x30, 0x60, 0x0b, //code
356        0x30, 0x60, 0x0c, 0x30, 0x60, 0x0d, 0x30, 0x60, 0x02, 0x30, 0x60, 0x02, 0x58, 0x00, 0x1d, 0x1d, 
357        0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x68, 0x01, 0x47, 
358        0x00, 0x00,
359     };
360 }
361
362 int swf_GetU30(TAG*tag)
363 {
364     U32 shift = 0;
365     U32 s = 0;
366     while(1) {
367         U8 b = swf_GetU8(tag);
368         s|=(b&127)<<shift;
369         shift+=7;
370         if(!(b&128))
371             break;
372     }
373     return s;
374 }
375
376 typedef struct _abc_method {
377     /* from method signature: */
378     const char*name;
379     char*paramstr;
380     int return_type_index;//index into multiname
381     int param_count;
382     int params[16]; // indexes into multiname
383     U8 flags;
384
385     int index;
386     int method_body_index;
387 } abc_method_t;
388
389 typedef struct _abc_multiname {
390     int namespace_index;
391     int name_index;
392 } abc_multiname_t;
393
394 typedef struct _dict_entry {
395     const char*name;
396     void*data;
397 } dict_entry_t;
398
399 typedef struct _dict {
400     int num;
401     int size;
402     dict_entry_t*d;
403 } dict_t;
404
405
406 dict_t* dict_new() {
407     dict_t*d = malloc(sizeof(dict_t));
408     memset(d, 0, sizeof(dict_t));
409     return d;
410 }
411 const char*dict_getstr(dict_t*dict, int nr) {
412     if(nr > dict->num || nr<0) {
413         printf("error: reference to string %d in dict\n");
414         return 0;
415     }
416     return dict->d[nr].name;
417 }
418 char*dict_getdata(dict_t*dict, int nr) {
419     if(nr > dict->num || nr<0) {
420         printf("error: reference to string %d in dict\n");
421         return 0;
422     }
423     return dict->d[nr].data;
424 }
425 int dict_append(dict_t*dict, const char*name, void*data) {
426     while(dict->size <= dict->num) {
427         dict->size += 64;
428         if(!dict->d) {
429             dict->d = malloc(sizeof(dict_entry_t)*dict->size);
430         } else {
431             dict->d = realloc(dict->d, sizeof(dict_entry_t)*dict->size);
432         }
433     }
434     if(name) {
435         dict->d[dict->num].name = strdup(name);
436     } else {
437         dict->d[dict->num].name = 0;
438     }
439     dict->d[dict->num].data = data;
440     return dict->num++;
441 }
442 int dict_find(dict_t*dict, const char*name)
443 {
444     if(!name)
445         name = "";
446     int t;
447     for(t=0;t<dict->num;t++) {
448         if(dict->d[t].name && !strcmp(dict->d[t].name,name))
449             return t;
450     }
451     return -1;
452 }
453 int dict_update(dict_t*dict, char*name, void*data) {
454     int pos = dict_find(dict, name);
455     if(pos>=0) {
456         dict->d[pos].data = data;
457         return pos;
458     }
459     return dict_append(dict, name, data);
460 }
461 int dict_append_if_new(dict_t*dict, char*name, void*data) {
462     int pos = dict_find(dict, name);
463     if(pos>=0)
464         return pos;
465     return dict_append(dict, name, data);
466 }
467
468 typedef struct _abc_file_t {
469
470     // contant_pool
471
472     dict_t*ints;
473     dict_t*uints;
474     dict_t*floats;
475     dict_t*strings;
476     dict_t*namespaces;
477     dict_t*sets;
478     dict_t*multinames;
479
480     // abc_file
481
482     dict_t*methods;
483     dict_t*classes;
484     dict_t*scripts;
485     dict_t*method_bodies;
486 } abc_file_t;
487
488 typedef struct _abc_trait {
489     unsigned char type;
490     int name_index;
491     U32 data1;
492     U32 data2;
493     int vindex;
494     int vkind;
495 } abc_trait_t;
496
497 typedef struct _abc_class {
498     int index;
499     abc_file_t*abc;
500     int classname_index;
501     int superclass_index;
502     int ns_index;
503     int iinit;
504     int cinit;
505     dict_t*traits;
506 } abc_class_t;
507
508 typedef struct _abc_code {
509     int index;
510     abc_file_t*abc;
511     //abc_class_t*cls;
512     abc_method_t*method;
513     TAG*tag;
514     int max_stack;
515     int local_count;
516     int init_scope_depth;
517     int max_scope_depth;
518     int exception_count;
519     dict_t*traits;
520 } abc_code_t;
521
522 typedef struct _opcode
523 {
524     unsigned char opcode;
525     char*name;
526     char*params;
527 } opcode_t;
528
529 /* 2 = multiname
530    m = method
531    n = number of params
532    i = method info
533    b = byte
534    s = short
535    c = class
536    s = string
537 */
538
539 int abc_RegisterNameSpace(abc_file_t*file, char*name);
540 int abc_RegisterPackageNameSpace(abc_file_t*file, char*name);
541 int abc_RegisterPackageInternalNameSpace(abc_file_t*file, char*name);
542 int abc_RegisterProtectedNameSpace(abc_file_t*file, char*name);
543 int abc_RegisterExplicitNameSpace(abc_file_t*file, char*name);
544 int abc_RegisterStaticProtectedNameSpace(abc_file_t*file, char*name);
545 int abc_RegisterPrivateNameSpace(abc_file_t*file, char*name);
546
547
548 opcode_t opcodes[]={
549 {0xa0, "add", ""},
550 {0xc5, "add_i", ""},
551 {0x86, "atype", "2"},
552 {0x87, "astypelate", ""},
553 {0xA8, "bitand", ""},
554 {0x97, "bitnot", ""},
555 {0xa9, "bitor", ""},
556 {0xaa, "bitxor", ""},
557 {0x41, "call", "n"},
558 {0x43, "callmethod", "mn"},
559 {0x4c, "callproplex", "2n"},
560 {0x4f, "callpropvoid", "2n"},
561 {0x44, "callstatic", "in"},
562 {0x45, "callsuper", "2n"},
563 {0x4e, "callsupervoid", "2n"},
564 {0x78, "checkfilter", ""},
565 {0x80, "coerce", "m"},
566 {0x82, "coerce_a", ""},
567 {0x85, "coerce_s", ""},
568 {0x42, "construct", "n"},
569 {0x4a, "constructprop", "2n"},
570 {0x49, "constructsuper", "n"},
571 {0x76, "convert_b", ""},
572 {0x73, "convert_i", ""},
573 {0x75, "convert_d", ""},
574 {0x77, "convert_o", ""},
575 {0x74, "convert_u", ""},
576 {0x70, "convert_s", ""},
577 {0xd0, "getlocal_0", ""},
578 {0xd1, "getlocal_1", ""},
579 {0xd2, "getlocal_2", ""},
580 {0xd3, "getlocal_3", ""},
581 {0x30, "pushscope", ""},
582 {0x47, "returnvoid", ""},
583 {0x5d, "findpropstrict", "2"},
584 {0x60, "getlex", "2"},
585 {0x65, "getscopeobject", "u"},
586 {0x2c, "pushstring", "s"},
587 {0x66, "getproperty", "2"},
588 {0x24, "pushbyte", "b"},
589 {0x58, "newclass", "c"},
590 {0x1d, "popscope", ""},
591 {0x68, "initproperty", "2"},
592 {0x26, "pushtrue", ""},
593 {0x25, "pushshort", "u"},
594 {0x02, "nop", ""},
595 };
596
597 static int parse_code(TAG*tag, int len, abc_file_t*pool, char*prefix)
598 {
599     int end=tag->pos+len;
600     while(tag->pos<end) {
601         U8 opcode = swf_GetU8(tag);
602         int t;
603         char found = 0;
604         for(t=0;t<sizeof(opcodes)/sizeof(opcodes[0]);t++) {
605             if(opcodes[t].opcode == opcode) {
606                 printf("%s%s ", prefix, opcodes[t].name);
607                 char*p = opcodes[t].params;
608                 char first = 1;
609                 while(*p) {
610                     if(!first)
611                         printf(", ");
612                     if(*p == 'n') {
613                         int n = swf_GetU30(tag);
614                         printf("%d params", n);
615                     } else if(*p == '2') {
616                         const char* m = dict_getstr(pool->multinames, swf_GetU30(tag));
617                         printf("%s", m);
618                     } else if(*p == 'm') {
619                         int n = swf_GetU30(tag);
620                         printf("[method%d]", n);
621                     } else if(*p == 'c') {
622                         int n = swf_GetU30(tag);
623                         printf("[classinfo%d]", n);
624                     } else if(*p == 'i') {
625                         int n = swf_GetU30(tag);
626                         printf("[methodbody%d]", n);
627                     } else if(*p == 'u') {
628                         int n = swf_GetU30(tag);
629                         printf("%d", n);
630                     } else if(*p == 'b') {
631                         int b = swf_GetU8(tag);
632                         printf("%02x", b);
633                     } else if(*p == 's') {
634                         const char*s = dict_getstr(pool->strings, swf_GetU30(tag));
635                         printf("\"%s\"", s);
636                     }
637                     p++;
638                     first = 0;
639                 }
640                 found = 1;
641                 break;
642             }
643         }
644         if(!found) {
645             printf("Can't parse opcode %02x\n", opcode);
646             return 0;
647         }
648         printf("\n");
649     }
650     if(tag->pos!=end) {
651         printf("Read beyond end of ABC Bytecode\n");
652         return 0;
653     }
654     return 1;
655 }
656
657 static void dump_method(const char*prefix, const char*type, const char*name, int nr, abc_file_t*pool)
658 {
659     if(nr >= pool->methods->num) {
660         printf("Invalid method number: %d\n", nr);
661         return;
662     }
663     abc_method_t*m = (abc_method_t*)dict_getdata(pool->methods, nr);
664     printf("%s%s %s %s%s\n", prefix, type, dict_getstr(pool->multinames,m->return_type_index), name, m->paramstr);
665
666     abc_code_t*c = (abc_code_t*)dict_getdata(pool->method_bodies, m->method_body_index);
667     
668     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);
669
670     swf_SetTagPos(c->tag, 0);
671     char prefix2[80];
672     sprintf(prefix2, "%s    ", prefix);
673     printf("%s{\n", prefix);
674     parse_code(c->tag, c->tag->len, pool,prefix2);
675     printf("%s}\n", prefix);
676 }
677
678 //#define DEBUG
679 #define DEBUG if(0)
680
681 #define TRAIT_SLOT 0
682 #define TRAIT_METHOD 1
683 #define TRAIT_GETTER 2
684 #define TRAIT_SETTER 3
685 #define TRAIT_CLASS 4
686 #define TRAIT_FUNCTION 5
687 static dict_t* parse_traits(char*prefix, TAG*tag, abc_file_t*pool, char print)
688 {
689     int num_traits = swf_GetU30(tag);
690     dict_t*traits = dict_new();
691     int t;
692     for(t=0;t<num_traits;t++) {
693         abc_trait_t*trait = malloc(sizeof(abc_trait_t));
694         memset(trait, 0, sizeof(abc_trait_t));
695         dict_append(traits, 0, trait);
696         int name_index = swf_GetU30(tag);
697         const char*name = dict_getstr(pool->multinames, name_index);
698         U8 kind = swf_GetU8(tag);
699         DEBUG printf("trait %d) %s type=%02x\n", t, name, kind);
700         if(kind == 1 || kind == 2 || kind == 3) { // method / getter / setter
701             int disp_id = swf_GetU30(tag);
702             int nr = swf_GetU30(tag);
703             DEBUG printf("%smethod %d %d %s\n", prefix, nr, disp_id, ((abc_method_t*)dict_getdata(pool->methods, nr))->paramstr);
704             if(print) dump_method(prefix, kind==1?"method":(kind==2?"getter":"setter"), name, nr, pool);
705         } else if(kind == 5) { // function
706             int slot_id = swf_GetU30(tag);
707             int nr = swf_GetU30(tag);
708             if(print) dump_method(prefix, "function", name, nr, pool);
709         } else if(kind == 4) { // class
710             int slot_id = swf_GetU30(tag);
711             int cls = swf_GetU30(tag);
712             if(print) printf("%sclass %s %d %d\n", prefix, name, slot_id, cls);
713         } else if(kind == 0) { // slot
714             int slot_id = swf_GetU30(tag);
715             const char*type_name = dict_getstr(pool->multinames, swf_GetU30(tag));
716             int vindex = swf_GetU30(tag);
717             if(vindex) {
718                 U8 vkind = swf_GetU8(tag);
719             }
720             if(print) printf("%sslot %s %d %s (vindex=%d)\n", prefix, name, slot_id, type_name, vindex);
721         } else {
722             printf("    can't parse trait type %d\n", kind);
723             return 0;
724         }
725     }
726     return traits;
727 }
728
729 void swf_CopyData(TAG*to, TAG*from, int len)
730 {
731     unsigned char*data = malloc(len);
732     swf_GetBlock(from, data, len);
733     swf_SetBlock(to, data, len);
734     free(data);
735 }
736
737 abc_file_t*abc_file_new()
738 {
739     abc_file_t*f = malloc(sizeof(abc_file_t));
740     memset(f, 0, sizeof(abc_file_t));
741
742     f->ints = dict_new();
743     f->ints = dict_new();
744     f->uints = dict_new();
745     f->floats = dict_new();
746     f->strings = dict_new();
747     dict_append(f->strings, "--<UNDEFINED>--", 0);
748     f->namespaces = dict_new();
749     dict_append(f->namespaces, "--<UNDEFINED>--", 0);
750     f->sets = dict_new();
751     dict_append(f->sets, "--<UNDEFINED>--", 0);
752     f->multinames = dict_new();
753     dict_append(f->multinames, "--<UNDEFINED>--", 0);
754
755     // abc_file
756
757     f->methods = dict_new();
758     f->classes = dict_new();
759     f->scripts = dict_new();
760     f->method_bodies = dict_new();
761
762     return f;
763 }
764
765 static char* access2str(int type)
766 {
767     if(type==0x08) return "";
768     else if(type==0x16) return "package";
769     else if(type==0x17) return "packageinternal";
770     else if(type==0x18) return "protected";
771     else if(type==0x19) return "explicit";
772     else if(type==0x1A) return "staticprotected";
773     else if(type==0x05) return "private";
774     else return "undefined";
775 }
776
777 void swf_DissassembleABC(TAG*tag)
778 {
779     abc_file_t* pool = abc_file_new();
780
781     swf_SetTagPos(tag, 0);
782     U32 flags = swf_GetU32(tag);
783     DEBUG printf("flags=%08x\n", flags);
784     char*classname = swf_GetString(tag);
785     U32 version = swf_GetU32(tag);
786
787     pool->ints->num = swf_GetU30(tag)-1;
788     if(pool->ints->num>0) {
789         printf("can't parse ints yet\n");
790         return;
791     }
792     pool->uints->num = swf_GetU30(tag)-1;
793     if(pool->uints->num>0) {
794         printf("can't parse uints yet\n");
795         return;
796     }
797     pool->floats->num = swf_GetU30(tag)-1;
798     if(pool->floats->num>0) {
799         printf("can't parse floats yet\n");
800         return;
801     }
802     int num_strings = swf_GetU30(tag);
803     int t;
804     DEBUG printf("%d strings\n", num_strings);
805     for(t=1;t<num_strings;t++) {
806         int len = swf_GetU30(tag);
807         char*s = malloc(len+1);
808         swf_GetBlock(tag, s, len);
809         s[len] = 0;
810         dict_append(pool->strings, s, 0);
811         DEBUG printf("%d) \"%s\"\n", t, pool->strings->d[t].name);
812     }
813     int num_namespaces = swf_GetU30(tag);
814     DEBUG printf("%d namespaces\n", num_namespaces);
815     for(t=1;t<num_namespaces;t++) {
816         U8 type = swf_GetU8(tag);
817         int namenr = swf_GetU30(tag);
818         const char*name = dict_getstr(pool->strings, namenr);
819         dict_append(pool->namespaces, name, (void*)(int)type);
820         int w = 0;
821         DEBUG w=1;
822         if(w) {
823             if(type==0x08) printf("Namespace %s\n", name);
824             else if(type==0x16) printf("PackageNamespace %s\n", name);
825             else if(type==0x17) printf("PackageInternalNs %s\n", name);
826             else if(type==0x18) printf("ProtectedNamespace %s\n", name);
827             else if(type==0x19) printf("ExplicitNamespace %s\n", name);
828             else if(type==0x1A) printf("StaticProtectedNs %s\n", name);
829             else if(type==0x05) printf("PrivateNs %s\n", name);
830             else {
831                 printf("Undefined namespace type\n");
832                 return;
833             }
834         }
835     }
836     int num_sets = swf_GetU30(tag);
837     if(num_sets>0) {
838         printf("can't parse namespace sets yet\n");
839         return;
840     }
841     int num_multinames = swf_GetU30(tag);
842     for(t=1;t<num_multinames;t++) {
843         U8 type = swf_GetU8(tag);
844         char*mname = 0;
845         if(type==0x07 || type==0x0d) {
846             int nr1 = swf_GetU30(tag);
847             const char*namespace = dict_getstr(pool->namespaces, nr1);
848             U8 access = (U8)(int)dict_getdata(pool->namespaces, nr1);
849             const char*methodname = dict_getstr(pool->strings, swf_GetU30(tag));
850             DEBUG printf("multiname %d) <%s> %s:%s\n", t, access2str(access), namespace, methodname);
851             mname = malloc(strlen(namespace)+strlen(methodname)+300);
852             sprintf(mname, "[%s]\0", access2str(access));
853             strcat(mname, namespace);
854             strcat(mname, ":");
855             strcat(mname, methodname);
856         } else if(type==0x0f || type==0x10) {
857             const char*methodname = dict_getstr(pool->strings, swf_GetU30(tag));
858             mname = strdup(methodname);
859         } else if(type==0x11 || type==0x12) {
860             mname = strdup("");
861         } else if(type==0x09 || type==0x0e || type==0x1b || type==0x1c) {
862             printf("no support for namespace sets yet\n", type);
863             return;
864         } else {
865             printf("can't parse type %d multinames yet\n", type);
866             return;
867         }
868         dict_append(pool->multinames, mname, 0);
869         free(mname);
870     }
871     
872     int num_methods = swf_GetU30(tag);
873     for(t=0;t<num_methods;t++) {
874         abc_method_t*m = malloc(sizeof(abc_method_t));
875         memset(m, 0, sizeof(*m));
876         m->param_count = swf_GetU30(tag);
877         m->return_type_index = swf_GetU30(tag);
878         m->index = t;
879         int s;
880         char params[256];
881         params[0]='(';
882         params[1]=0;
883         for(s=0;s<m->param_count;s++) {
884             if(s)
885                 strcat(params, ", ");
886             int typenr = swf_GetU30(tag);
887             if(s < sizeof(m->params)/sizeof(m->params[0]))
888                 m->params[s] = typenr;
889             const char*type = dict_getstr(pool->multinames, typenr);
890             strcat(params, type);
891         }
892         strcat(params, ")");
893         int namenr = swf_GetU30(tag);
894         m->name = "";
895         if(namenr)
896             m->name = dict_getstr(pool->strings, namenr);
897         m->paramstr=strdup(params);
898         DEBUG printf("method %d) %s\n", t, m->paramstr);
899
900         m->flags = swf_GetU8(tag);
901         if(m->flags&0x88) {
902             printf("can't parse optional or params names yet\n");
903             return;
904         }
905         dict_append(pool->methods, m->name, m);
906     }
907     int num_metadata = swf_GetU30(tag);
908     for(t=0;t<num_metadata;t++) {
909         printf("can't parse metadata yet\n");
910         return;
911     }
912         
913     /* skip classes, and scripts for now, and do the real parsing later */
914     int num_classes = swf_GetU30(tag);
915     int classes_pos = tag->pos;
916     DEBUG printf("%d classes\n", num_classes);
917     for(t=0;t<num_classes;t++) {
918         swf_GetU30(tag);
919         swf_GetU30(tag);
920         U8 flags = swf_GetU8(tag);
921         if(flags&8) 
922             swf_GetU30(tag);
923         swf_GetU30(tag);
924         swf_GetU30(tag);
925         if(!parse_traits("", tag, pool, 0))
926             return;
927     }
928     for(t=0;t<num_classes;t++) {
929         swf_GetU30(tag);
930         if(!parse_traits("", tag, pool, 0))
931             return;
932     }
933     int num_scripts = swf_GetU30(tag);
934     DEBUG printf("%d scripts\n", num_scripts);
935     for(t=0;t<num_scripts;t++) {
936         int init = swf_GetU30(tag);
937         if(!parse_traits("", tag, pool, 0))
938             return;
939     }
940
941     int num_method_bodies = swf_GetU30(tag);
942     DEBUG printf("%d method bodies\n", num_method_bodies);
943     for(t=0;t<num_method_bodies;t++) {
944         int methodnr = swf_GetU30(tag);
945         if(methodnr >= pool->methods->num) {
946             printf("Invalid method number: %d\n", methodnr);
947             return;
948         }
949         abc_method_t*m = (abc_method_t*)dict_getdata(pool->methods, methodnr);
950         abc_code_t*c = malloc(sizeof(abc_code_t));
951         memset(c, 0, sizeof(abc_code_t));
952         c->max_stack = swf_GetU30(tag);
953         c->local_count = swf_GetU30(tag);
954         c->init_scope_depth = swf_GetU30(tag);
955         c->max_scope_depth = swf_GetU30(tag);
956         int code_length = swf_GetU30(tag);
957         c->method = m;
958         m->method_body_index = t;
959
960         c->tag = swf_InsertTag(0,0);
961
962         swf_CopyData(c->tag, tag, code_length);
963
964         int exception_count = swf_GetU30(tag);
965         c->traits = parse_traits("<method body trait>", tag, pool, 1);
966         if(!c->traits) {
967             return;
968         }
969         DEBUG printf("method_body %d) (method %d), %d bytes of code", t, methodnr, code_length);
970         int r,l = code_length>32?32:code_length;
971         for(r=0;r<l;r++) {
972             DEBUG printf("%02x ", c->tag->data[r]);
973         }
974         DEBUG printf("\n");
975
976         dict_append(pool->method_bodies, 0, c);
977     }
978     if(tag->len - tag->pos) {
979         printf("%d unparsed bytes remaining in ABC block\n", tag->len - tag->pos);
980         return;
981     }
982
983     swf_SetTagPos(tag, classes_pos);
984     for(t=0;t<num_classes;t++) {
985         abc_class_t*cls = malloc(sizeof(abc_class_t));
986         memset(cls, 0, sizeof(abc_class_t));
987         const char* classname = dict_getstr(pool->multinames, swf_GetU30(tag));
988         const char* supername = dict_getstr(pool->multinames, swf_GetU30(tag));
989         U8 flags = swf_GetU8(tag);
990         const char*ns = "";
991         if(flags&8) {
992             cls->ns_index = swf_GetU30(tag);
993             ns = dict_getstr(pool->namespaces, cls->ns_index);
994         }
995         printf("class %s extends %s, %s, flags=%02x\n", classname, supername, ns, flags);
996         printf("{\n");
997         int num_interfaces = swf_GetU30(tag);
998         if(num_interfaces>0) {
999             printf("can't parse interfaces yet\n");
1000             return;
1001         }
1002         cls->iinit = swf_GetU30(tag);
1003         dump_method("    ","constructor", classname, cls->iinit, pool);
1004         cls->traits = parse_traits("    ",tag, pool, 1);
1005         if(!cls->traits) {
1006             return;
1007         }
1008         printf("}\n");
1009         dict_append(pool->classes, 0, cls);
1010     }
1011     for(t=0;t<num_classes;t++) {
1012         int cinit = swf_GetU30(tag);
1013         dump_method("    ","staticconstructor", "", cinit, pool);
1014         if(!parse_traits("    ",tag, pool, 1))
1015             return;
1016     }
1017     int num_scripts2 = swf_GetU30(tag);
1018     printf("\n");
1019     for(t=0;t<num_scripts2;t++) {
1020         int init = swf_GetU30(tag);
1021         dump_method("","initmethod", "init", init, pool);
1022         if(!parse_traits("", tag, pool, 1))
1023             return;
1024     }
1025 }
1026
1027 static int registerNameSpace(abc_file_t*file, U8 access, char*name) {
1028     if(access==0) { // autodetect access
1029         char*n = strdup(name);
1030         if(n[0] == '[') {
1031             char*bracket = strchr(n, ']');
1032             if(bracket) {
1033                 *bracket = 0;
1034                 char*a = n+1;
1035                 name += (bracket-n)+1;
1036                 if(!strcmp(a, "")) access=0x16;
1037                 else if(!strcmp(a, "package")) access=0x16;
1038                 else if(!strcmp(a, "packageinternal")) access=0x17;
1039                 else if(!strcmp(a, "protected")) access=0x18;
1040                 else if(!strcmp(a, "explicit")) access=0x19;
1041                 else if(!strcmp(a, "staticprotected")) access=0x1a;
1042                 else if(!strcmp(a, "private")) access=0x05;
1043                 else {
1044                     fprintf(stderr, "Undefined access level: [%s]\n", a);
1045                     return -1;
1046                 }
1047             }
1048         } else {
1049             access = 0x16;
1050         }
1051         free(n);
1052     }
1053     int t;
1054     for(t=0;t<file->namespaces->num;t++) {
1055         const char*name2 = dict_getstr(file->namespaces, t);
1056         U8 access2 = (U8)(int)dict_getdata(file->namespaces, t);
1057         if(access == access2 && !strcmp(name, name2)) {
1058             return t;
1059         }
1060     }
1061     dict_update(file->strings, name, 0);
1062     return dict_append(file->namespaces, name, (void*)(int)access);
1063 }
1064 int abc_RegisterNameSpace(abc_file_t*file, char*name) {
1065     return registerNameSpace(file, 0x08, name);
1066 }
1067 int abc_RegisterPackageNameSpace(abc_file_t*file, char*name) {
1068     return registerNameSpace(file, 0x16 , name);
1069 }
1070 int abc_RegisterPackageInternalNameSpace(abc_file_t*file, char*name) {
1071     return registerNameSpace(file, 0x17, name);
1072 }
1073 int abc_RegisterProtectedNameSpace(abc_file_t*file, char*name) {
1074     return registerNameSpace(file, 0x18, name);
1075 }
1076 int abc_RegisterExplicitNameSpace(abc_file_t*file, char*name) {
1077     return registerNameSpace(file, 0x19, name);
1078 }
1079 int abc_RegisterStaticProtectedNameSpace(abc_file_t*file, char*name) {
1080     return registerNameSpace(file, 0x1a, name);
1081 }
1082 int abc_RegisterPrivateNameSpace(abc_file_t*file, char*name) {
1083     return registerNameSpace(file, 0x05, name);
1084 }
1085 static int multiname_index(abc_file_t*abc, const char*name2) 
1086 {
1087     if(!name2)
1088         name2 = ":";
1089     int pos = dict_find(abc->multinames, name2);
1090     if(pos>=0)
1091         return pos;
1092
1093     int access = 0x16;
1094     char*n = strdup(name2);
1095     char*p = strchr(n, ':');
1096     char*namespace=0,*name=0;
1097     if(!p) {
1098         namespace = "";
1099         name = n;
1100     } else {
1101         *p = 0;
1102         namespace = n;
1103         name = p+1;
1104     }
1105     abc_multiname_t*m = malloc(sizeof(abc_multiname_t));
1106     m->namespace_index = registerNameSpace(abc, 0, namespace);
1107     m->name_index = dict_append_if_new(abc->strings, name, 0);
1108     return dict_append(abc->multinames, name2, m);
1109 }
1110
1111 abc_class_t* abc_NewClass(abc_file_t*abc, char*classname, char*superclass) {
1112     abc_class_t* c = malloc(sizeof(abc_class_t));
1113     memset(c, 0, sizeof(abc_class_t));
1114     c->index = dict_append(abc->classes, 0, c);
1115     c->abc = abc;
1116     c->classname_index = multiname_index(abc, classname);
1117     c->superclass_index = multiname_index(abc, superclass);
1118     c->ns_index = abc_RegisterProtectedNameSpace(abc, classname);
1119
1120     c->traits = dict_new();
1121     return c;
1122 }
1123
1124 abc_code_t* add_method(abc_file_t*abc, abc_class_t*cls, char*returntype, char*name, int num_params, va_list va)
1125 {
1126     /* construct code (method body) object */
1127     abc_code_t* c = malloc(sizeof(abc_code_t));
1128     memset(c, 0, sizeof(abc_code_t));
1129     c->index = dict_append(abc->method_bodies, 0, c);
1130     c->tag = swf_InsertTag(0,0);
1131     c->abc = abc;
1132     c->traits = dict_new();
1133
1134     /* construct method object */
1135     abc_method_t* m = malloc(sizeof(abc_method_t));
1136     memset(m, 0, sizeof(abc_method_t));
1137     m->param_count = num_params;
1138     m->index = dict_append(abc->methods, 0, m);
1139     if(returntype) 
1140         m->return_type_index = multiname_index(abc, returntype);
1141     else
1142         m->return_type_index = 0;
1143     if(num_params>sizeof(m->params)/sizeof(m->params[0])) {
1144         fprintf(stderr, "abc: Too many parameters\n");
1145         return 0;
1146     }
1147     int t;
1148     for(t=0;t<num_params;t++) {
1149         const char*param = va_arg(va, const char*);
1150         m->params[t] = multiname_index(abc, param);
1151     }
1152
1153     /* crosslink the two objects */
1154     m->method_body_index = c->index;
1155     c->method = m;
1156
1157     return c;
1158 }
1159
1160 abc_code_t* abc_AddConstructor(abc_class_t*cls, char*returntype, int num_params, ...) 
1161 {
1162     va_list va;
1163     va_start(va, num_params);
1164     abc_code_t* c = add_method(cls->abc, cls, returntype, 0, num_params, va);
1165     va_end(va);
1166     cls->iinit = c->index;
1167     return c;
1168 }
1169
1170 abc_code_t* abc_AddStaticConstructor(abc_class_t*cls, char*returntype, int num_params, ...) 
1171 {
1172     va_list va;
1173     va_start(va, num_params);
1174     abc_code_t* c = add_method(cls->abc, cls, returntype, 0, num_params, va);
1175     va_end(va);
1176     cls->cinit = c->index;
1177     return c;
1178 }
1179
1180 abc_trait_t*trait_new(int type, int name_index, int data1, int data2, int vindex, int vkind)
1181 {
1182     abc_trait_t*trait = malloc(sizeof(abc_trait_t));
1183     memset(trait, 0, sizeof(abc_trait_t));
1184     trait->type = type;
1185     trait->name_index = name_index;
1186     trait->data1 = data1;
1187     trait->data2 = data2;
1188     trait->vindex = vindex;
1189     trait->vkind = vkind;
1190     return trait;
1191 }
1192
1193 abc_code_t* abc_AddMethod(abc_class_t*cls, char*returntype, char*name, int num_params, ...) 
1194 {
1195     abc_file_t*abc = cls->abc;
1196     va_list va;
1197     va_start(va, num_params);
1198     abc_code_t* c = add_method(cls->abc, cls, returntype, name, num_params, va);
1199     va_end(va);
1200     dict_append(cls->traits, 0, trait_new(TRAIT_METHOD, multiname_index(abc, name), 0, c->method->index, 0, 0));
1201     return c;
1202 }
1203
1204 void abc_AddSlot(abc_class_t*cls, char*name, int slot, char*multiname)
1205 {
1206     abc_file_t*abc = cls->abc;
1207     int i = multiname_index(abc, name);
1208     dict_append(cls->traits, 0, trait_new(TRAIT_SLOT, i, slot, multiname_index(abc, multiname), 0, 0));
1209 }
1210
1211 void abc_code_addClassTrait(abc_code_t*code, char*multiname, int slotid, abc_class_t*cls)
1212 {
1213     abc_file_t*abc = code->abc;
1214     int i = multiname_index(abc, multiname);
1215     abc_trait_t*trait = trait_new(TRAIT_CLASS, i, slotid, cls->index, 0, 0);
1216     dict_append(code->traits, 0, trait);
1217 }
1218
1219 abc_code_t* abc_AddInitScript(abc_file_t*abc, char*returntype, int num_params, ...) 
1220 {
1221     va_list va;
1222     va_start(va, num_params);
1223     abc_code_t* c = add_method(abc, 0, returntype, 0, num_params, va);
1224     dict_append(abc->scripts, 0, c);
1225     va_end(va);
1226     return c;
1227 }
1228
1229 void swf_SetU30(TAG*tag, U32 u)
1230 {
1231     do {
1232         swf_SetU8(tag, (u&~0x7f?0x80:0) | (u&0x7F));
1233         u>>=7;
1234     } while(u);
1235 }
1236 void swf_SetU30String(TAG*tag, const char*str)
1237 {
1238     int l = strlen(str);
1239     swf_SetU30(tag, l);
1240     swf_SetBlock(tag, (void*)str, l);
1241 }
1242
1243 static void write_traits(abc_file_t*abc, TAG*tag, dict_t*traits)
1244 {
1245     swf_SetU30(tag, traits->num);
1246     int s;
1247
1248     for(s=0;s<traits->num;s++) {
1249         abc_trait_t*trait = (abc_trait_t*)dict_getdata(traits, s);
1250         swf_SetU30(tag, trait->name_index);
1251         swf_SetU8(tag, trait->type);
1252         swf_SetU30(tag, trait->data1);
1253         swf_SetU30(tag, trait->data2);
1254         if(trait->type == 0) { //slot
1255             swf_SetU30(tag, trait->vindex);
1256             if(trait->vindex) {
1257                 swf_SetU8(tag, trait->vkind);
1258             }
1259         }
1260     }
1261 }
1262
1263 void swf_WriteABC(TAG*tag, abc_file_t*abc)
1264 {
1265     swf_SetU32(tag, 1);
1266     swf_SetU8(tag, 0);
1267     swf_SetU16(tag, 0x10);
1268     swf_SetU16(tag, 0x2e);
1269     swf_SetU30(tag, abc->ints->num>1?abc->ints->num:0);
1270     // ...
1271     swf_SetU30(tag, abc->uints->num>1?abc->uints->num:0);
1272     // ...
1273     swf_SetU30(tag, abc->floats->num>1?abc->floats->num:0);
1274     // ...
1275     swf_SetU30(tag, abc->strings->num>1?abc->strings->num:0);
1276     int t;
1277     for(t=1;t<abc->strings->num;t++) {
1278         swf_SetU30String(tag, dict_getstr(abc->strings, t));
1279     }
1280     swf_SetU30(tag, abc->namespaces->num>1?abc->namespaces->num:0);
1281     for(t=1;t<abc->namespaces->num;t++) {
1282         U8 type = (U8)(int)dict_getdata(abc->namespaces, t);
1283         const char*name = dict_getstr(abc->namespaces, t);
1284         int i = dict_find(abc->strings, name);
1285         if(i<0) {
1286             fprintf(stderr, "Couldn't find namespace \"%s\" in constant pool\n", name);
1287             return;
1288         }
1289         swf_SetU8(tag, type);
1290         swf_SetU30(tag, i);
1291     }
1292     swf_SetU30(tag, abc->sets->num>1?abc->sets->num:0);
1293     // ...
1294
1295     swf_SetU30(tag, abc->multinames->num>1?abc->multinames->num:0);
1296     // ...
1297     for(t=1;t<abc->multinames->num;t++) {
1298         abc_multiname_t*m = (abc_multiname_t*)dict_getdata(abc->multinames, t);
1299         swf_SetU8(tag, 0x07);
1300         swf_SetU30(tag, m->namespace_index);
1301         swf_SetU30(tag, m->name_index);
1302     }
1303     
1304     swf_SetU30(tag, abc->methods->num);
1305     for(t=0;t<abc->methods->num;t++) {
1306         abc_method_t*m = (abc_method_t*)dict_getdata(abc->methods, t);
1307         swf_SetU30(tag, m->param_count);
1308         swf_SetU30(tag, m->return_type_index);
1309         int s;
1310         for(s=0;s<m->param_count;s++) {
1311             swf_SetU30(tag, m->params[s]);
1312         }
1313         swf_SetU30(tag, 0); // name
1314         swf_SetU8(tag, 0); //flags
1315     }
1316
1317     swf_SetU30(tag, 0);//metadata
1318
1319     swf_SetU30(tag, abc->classes->num);
1320
1321     for(t=0;t<abc->classes->num;t++) {
1322         abc_class_t*c = (abc_class_t*)dict_getdata(abc->classes, t);
1323         swf_SetU30(tag, c->classname_index);
1324         swf_SetU30(tag, c->superclass_index);
1325
1326         swf_SetU8(tag, 8); // flags
1327         swf_SetU30(tag, c->ns_index);
1328
1329         swf_SetU30(tag, 0); // no interfaces
1330         swf_SetU30(tag, c->iinit);
1331         write_traits(abc, tag, c->traits);
1332     }
1333     for(t=0;t<abc->classes->num;t++) {
1334         abc_class_t*c = (abc_class_t*)dict_getdata(abc->classes, t);
1335         swf_SetU30(tag, c->cinit);
1336         swf_SetU30(tag, 0); // no traits
1337     }
1338
1339     swf_SetU30(tag, abc->scripts->num);
1340     for(t=0;t<abc->scripts->num;t++) {
1341         abc_code_t*c = (abc_code_t*)dict_getdata(abc->scripts, t);
1342         swf_SetU30(tag, c->index); //!=t!
1343         write_traits(abc, tag, c->traits);
1344     }
1345
1346     swf_SetU30(tag, abc->method_bodies->num);
1347     for(t=0;t<abc->method_bodies->num;t++) {
1348         abc_code_t*c = (abc_code_t*)dict_getdata(abc->method_bodies, t);
1349         abc_method_t*m = c->method;
1350         swf_SetU30(tag, m->index);
1351         swf_SetU30(tag, c->max_stack);
1352         swf_SetU30(tag, c->local_count);
1353         swf_SetU30(tag, c->init_scope_depth);
1354         swf_SetU30(tag, c->max_scope_depth);
1355         swf_SetU30(tag, c->tag->len);
1356         swf_SetBlock(tag, c->tag->data, c->tag->len);
1357         swf_SetU30(tag, c->exception_count);
1358         swf_SetU8(tag, 0); // no traits
1359     }
1360 }
1361
1362 #include "swfabc_ops.c"
1363
1364 void swf_AddButtonLinks(TAG*tag)
1365 {
1366     abc_file_t*abc = abc_file_new();
1367     abc_code_t*c = 0;
1368     
1369     abc_class_t*maintimeline = abc_NewClass(abc, "buttonmitlink_fla:MainTimeline", "flash.display:MovieClip");
1370     
1371     c = abc_AddStaticConstructor(maintimeline, 0, 0);
1372     c->max_stack = 1;
1373     c->local_count = 1;
1374     c->init_scope_depth = 9;
1375     c->max_scope_depth = 10;
1376     abc_getlocal_0(c);
1377     abc_pushscope(c);
1378     abc_returnvoid(c);
1379     
1380     c = abc_AddMethod(maintimeline, 0, "[packageinternal]buttonmitlink_fla:frame1", 0);
1381     c->max_stack = 3;
1382     c->local_count = 1;
1383     c->init_scope_depth = 10;
1384     c->max_scope_depth = 11;
1385     abc_getlocal_0(c);
1386     abc_pushscope(c);
1387
1388     abc_getlex(c,":MyButton1");
1389     abc_getlex(c,"flash.events:MouseEvent");
1390     abc_getproperty(c, ":CLICK");
1391     abc_getlex(c, ":gotoPage1");
1392     abc_callpropvoid(c, ":addEventListener" ,2);
1393
1394     abc_getlex(c,":MyButton2");
1395     abc_getlex(c,"flash.events:MouseEvent");
1396     abc_getproperty(c, ":CLICK");
1397     abc_getlex(c,":gotoPage2");
1398     abc_callpropvoid(c,":addEventListener",2);
1399
1400     abc_returnvoid(c);
1401     
1402     abc_AddSlot(maintimeline, ":MyButton1", 0, "flash.display:SimpleButton");
1403     abc_AddSlot(maintimeline, ":MyButton2", 0, "flash.display:SimpleButton");
1404
1405     c = abc_AddMethod(maintimeline, ":void", ":gotoPage2", 1, "flash.events:MouseEvent");
1406     c->max_stack = 3;
1407     c->local_count = 2;
1408     c->init_scope_depth = 10;
1409     c->max_scope_depth = 11;
1410     abc_getlocal_0(c);
1411     abc_pushscope(c);
1412     abc_findpropstrict(c, "flash.net:navigateToURL");
1413     abc_findpropstrict(c, "flash.net:URLRequest");
1414     abc_pushstring(c, "http://www.quiss.org");
1415     abc_constructprop(c, "flash.net:URLRequest", 1);
1416     abc_callpropvoid(c, "flash.net:navigateToURL", 1);
1417     abc_returnvoid(c);
1418     
1419     c = abc_AddMethod(maintimeline, ":void", ":gotoPage1", 1, "flash.events:MouseEvent");
1420     c->max_stack = 3;
1421     c->local_count = 2;
1422     c->init_scope_depth = 10;
1423     c->max_scope_depth = 11;
1424     abc_getlocal_0(c);
1425     abc_pushscope(c);
1426     abc_findpropstrict(c,"flash.net:navigateToURL");
1427     abc_findpropstrict(c,"flash.net:URLRequest");
1428     abc_pushstring(c,"http://www.google.com/");
1429     abc_constructprop(c,"flash.net:URLRequest", 1);
1430     abc_callpropvoid(c,"flash.net:navigateToURL", 1);
1431     abc_returnvoid(c);
1432     
1433     c = abc_AddConstructor(maintimeline, 0, 0);
1434     c->max_stack = 3;
1435     c->local_count = 1;
1436     c->init_scope_depth = 10;
1437     c->max_scope_depth = 11;
1438     abc_getlocal_0(c);
1439     abc_pushscope(c);
1440     abc_getlocal_0(c);
1441     abc_constructsuper(c,0);
1442     abc_findpropstrict(c,":addFrameScript");
1443     abc_pushbyte(c,0x00);
1444     abc_getlex(c,"[packageinternal]buttonmitlink_fla:frame1");
1445     abc_callpropvoid(c,":addFrameScript",2);
1446     abc_returnvoid(c);
1447     
1448     c = abc_AddInitScript(abc, 0, 0);
1449     c->max_stack = 2;
1450     c->local_count = 1;
1451     c->init_scope_depth = 1;
1452     c->max_scope_depth = 9;
1453     abc_getlocal_0(c);
1454     abc_pushscope(c);
1455     abc_getscopeobject(c, 0);
1456     abc_getlex(c,":Object");
1457     abc_pushscope(c);
1458     abc_getlex(c,"flash.events:EventDispatcher");
1459     abc_pushscope(c);
1460     abc_getlex(c,"flash.display:DisplayObject");
1461     abc_pushscope(c);
1462     abc_getlex(c,"flash.display:InteractiveObject");
1463     abc_pushscope(c);
1464     abc_getlex(c,"flash.display:DisplayObjectContainer");
1465     abc_pushscope(c);
1466     abc_getlex(c,"flash.display:Sprite");
1467     abc_pushscope(c);
1468     abc_getlex(c,"flash.display:MovieClip");
1469     abc_pushscope(c);
1470     abc_getlex(c,"flash.display:MovieClip");
1471     abc_newclass(c,maintimeline);
1472     abc_popscope(c);
1473     abc_popscope(c);
1474     abc_popscope(c);
1475     abc_popscope(c);
1476     abc_popscope(c);
1477     abc_popscope(c);
1478     abc_popscope(c);
1479     abc_initproperty(c,"buttonmitlink_fla:MainTimeline");
1480     abc_returnvoid(c);
1481
1482     abc_code_addClassTrait(c, "buttonmitlink_fla:MainTimeline", 1, maintimeline);
1483
1484     swf_WriteABC(tag, abc);
1485 }