moved insertion of event handlers into constructor
[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     const char*name;
501     int classname_index;
502     int superclass_index;
503     int ns_index;
504     int iinit;
505     int cinit;
506     dict_t*traits;
507 } abc_class_t;
508
509 typedef struct _abc_code {
510     int index;
511     abc_file_t*abc;
512     //abc_class_t*cls;
513     abc_method_t*method;
514     TAG*tag;
515     int max_stack;
516     int local_count;
517     int init_scope_depth;
518     int max_scope_depth;
519     int exception_count;
520     dict_t*traits;
521 } abc_code_t;
522
523 typedef struct _opcode
524 {
525     unsigned char opcode;
526     char*name;
527     char*params;
528 } opcode_t;
529
530 /* 2 = multiname
531    m = method
532    n = number of params
533    i = method info
534    b = byte
535    s = short
536    c = class
537    s = string
538 */
539
540 int abc_RegisterNameSpace(abc_file_t*file, char*name);
541 int abc_RegisterPackageNameSpace(abc_file_t*file, char*name);
542 int abc_RegisterPackageInternalNameSpace(abc_file_t*file, char*name);
543 int abc_RegisterProtectedNameSpace(abc_file_t*file, char*name);
544 int abc_RegisterExplicitNameSpace(abc_file_t*file, char*name);
545 int abc_RegisterStaticProtectedNameSpace(abc_file_t*file, char*name);
546 int abc_RegisterPrivateNameSpace(abc_file_t*file, char*name);
547
548
549 opcode_t opcodes[]={
550 {0xa0, "add", ""},
551 {0xc5, "add_i", ""},
552 {0x86, "atype", "2"},
553 {0x87, "astypelate", ""},
554 {0xA8, "bitand", ""},
555 {0x97, "bitnot", ""},
556 {0xa9, "bitor", ""},
557 {0xaa, "bitxor", ""},
558 {0x41, "call", "n"},
559 {0x43, "callmethod", "mn"},
560 {0x4c, "callproplex", "2n"},
561 {0x4f, "callpropvoid", "2n"},
562 {0x44, "callstatic", "in"},
563 {0x45, "callsuper", "2n"},
564 {0x4e, "callsupervoid", "2n"},
565 {0x78, "checkfilter", ""},
566 {0x80, "coerce", "m"},
567 {0x82, "coerce_a", ""},
568 {0x85, "coerce_s", ""},
569 {0x42, "construct", "n"},
570 {0x4a, "constructprop", "2n"},
571 {0x49, "constructsuper", "n"},
572 {0x76, "convert_b", ""},
573 {0x73, "convert_i", ""},
574 {0x75, "convert_d", ""},
575 {0x77, "convert_o", ""},
576 {0x74, "convert_u", ""},
577 {0x70, "convert_s", ""},
578 {0xd0, "getlocal_0", ""},
579 {0xd1, "getlocal_1", ""},
580 {0xd2, "getlocal_2", ""},
581 {0xd3, "getlocal_3", ""},
582 {0x30, "pushscope", ""},
583 {0x47, "returnvoid", ""},
584 {0x5d, "findpropstrict", "2"},
585 {0x60, "getlex", "2"},
586 {0x65, "getscopeobject", "u"},
587 {0x2c, "pushstring", "s"},
588 {0x66, "getproperty", "2"},
589 {0x24, "pushbyte", "b"},
590 {0x58, "newclass", "c"},
591 {0x1d, "popscope", ""},
592 {0x68, "initproperty", "2"},
593 {0x26, "pushtrue", ""},
594 {0x25, "pushshort", "u"},
595 {0x02, "nop", ""},
596 };
597
598 static int parse_code(TAG*tag, int len, abc_file_t*pool, char*prefix)
599 {
600     int end=tag->pos+len;
601     while(tag->pos<end) {
602         U8 opcode = swf_GetU8(tag);
603         int t;
604         char found = 0;
605         for(t=0;t<sizeof(opcodes)/sizeof(opcodes[0]);t++) {
606             if(opcodes[t].opcode == opcode) {
607                 printf("%s%s ", prefix, opcodes[t].name);
608                 char*p = opcodes[t].params;
609                 char first = 1;
610                 while(*p) {
611                     if(!first)
612                         printf(", ");
613                     if(*p == 'n') {
614                         int n = swf_GetU30(tag);
615                         printf("%d params", n);
616                     } else if(*p == '2') {
617                         const char* m = dict_getstr(pool->multinames, swf_GetU30(tag));
618                         printf("%s", m);
619                     } else if(*p == 'm') {
620                         int n = swf_GetU30(tag);
621                         printf("[method%d]", n);
622                     } else if(*p == 'c') {
623                         int n = swf_GetU30(tag);
624                         printf("[classinfo%d]", n);
625                     } else if(*p == 'i') {
626                         int n = swf_GetU30(tag);
627                         printf("[methodbody%d]", n);
628                     } else if(*p == 'u') {
629                         int n = swf_GetU30(tag);
630                         printf("%d", n);
631                     } else if(*p == 'b') {
632                         int b = swf_GetU8(tag);
633                         printf("%02x", b);
634                     } else if(*p == 's') {
635                         const char*s = dict_getstr(pool->strings, swf_GetU30(tag));
636                         printf("\"%s\"", s);
637                     }
638                     p++;
639                     first = 0;
640                 }
641                 found = 1;
642                 break;
643             }
644         }
645         if(!found) {
646             printf("Can't parse opcode %02x\n", opcode);
647             return 0;
648         }
649         printf("\n");
650     }
651     if(tag->pos!=end) {
652         printf("Read beyond end of ABC Bytecode\n");
653         return 0;
654     }
655     return 1;
656 }
657
658 static void dump_method(const char*prefix, const char*type, const char*name, int nr, abc_file_t*pool)
659 {
660     if(nr >= pool->methods->num) {
661         printf("Invalid method number: %d\n", nr);
662         return;
663     }
664     abc_method_t*m = (abc_method_t*)dict_getdata(pool->methods, nr);
665     printf("%s%s %s %s%s\n", prefix, type, dict_getstr(pool->multinames,m->return_type_index), name, m->paramstr);
666
667     abc_code_t*c = (abc_code_t*)dict_getdata(pool->method_bodies, m->method_body_index);
668     
669     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);
670
671     swf_SetTagPos(c->tag, 0);
672     char prefix2[80];
673     sprintf(prefix2, "%s    ", prefix);
674     printf("%s{\n", prefix);
675     parse_code(c->tag, c->tag->len, pool,prefix2);
676     printf("%s}\n", prefix);
677 }
678
679 //#define DEBUG
680 #define DEBUG if(0)
681
682 #define TRAIT_SLOT 0
683 #define TRAIT_METHOD 1
684 #define TRAIT_GETTER 2
685 #define TRAIT_SETTER 3
686 #define TRAIT_CLASS 4
687 #define TRAIT_FUNCTION 5
688 static dict_t* parse_traits(char*prefix, TAG*tag, abc_file_t*pool, char print)
689 {
690     int num_traits = swf_GetU30(tag);
691     dict_t*traits = dict_new();
692     int t;
693     for(t=0;t<num_traits;t++) {
694         abc_trait_t*trait = malloc(sizeof(abc_trait_t));
695         memset(trait, 0, sizeof(abc_trait_t));
696         dict_append(traits, 0, trait);
697         int name_index = swf_GetU30(tag);
698         const char*name = dict_getstr(pool->multinames, name_index);
699         U8 kind = swf_GetU8(tag);
700         DEBUG printf("trait %d) %s type=%02x\n", t, name, kind);
701         if(kind == 1 || kind == 2 || kind == 3) { // method / getter / setter
702             int disp_id = swf_GetU30(tag);
703             int nr = swf_GetU30(tag);
704             DEBUG printf("%smethod %d %d %s\n", prefix, nr, disp_id, ((abc_method_t*)dict_getdata(pool->methods, nr))->paramstr);
705             if(print) dump_method(prefix, kind==1?"method":(kind==2?"getter":"setter"), name, nr, pool);
706         } else if(kind == 5) { // function
707             int slot_id = swf_GetU30(tag);
708             int nr = swf_GetU30(tag);
709             if(print) dump_method(prefix, "function", name, nr, pool);
710         } else if(kind == 4) { // class
711             int slot_id = swf_GetU30(tag);
712             int cls = swf_GetU30(tag);
713             if(print) printf("%sclass %s %d %d\n", prefix, name, slot_id, cls);
714         } else if(kind == 0) { // slot
715             int slot_id = swf_GetU30(tag);
716             const char*type_name = dict_getstr(pool->multinames, swf_GetU30(tag));
717             int vindex = swf_GetU30(tag);
718             if(vindex) {
719                 U8 vkind = swf_GetU8(tag);
720             }
721             if(print) printf("%sslot %s %d %s (vindex=%d)\n", prefix, name, slot_id, type_name, vindex);
722         } else {
723             printf("    can't parse trait type %d\n", kind);
724             return 0;
725         }
726     }
727     return traits;
728 }
729
730 void swf_CopyData(TAG*to, TAG*from, int len)
731 {
732     unsigned char*data = malloc(len);
733     swf_GetBlock(from, data, len);
734     swf_SetBlock(to, data, len);
735     free(data);
736 }
737
738 abc_file_t*abc_file_new()
739 {
740     abc_file_t*f = malloc(sizeof(abc_file_t));
741     memset(f, 0, sizeof(abc_file_t));
742
743     f->ints = dict_new();
744     f->ints = dict_new();
745     f->uints = dict_new();
746     f->floats = dict_new();
747     f->strings = dict_new();
748     dict_append(f->strings, "--<UNDEFINED>--", 0);
749     f->namespaces = dict_new();
750     dict_append(f->namespaces, "--<UNDEFINED>--", 0);
751     f->sets = dict_new();
752     dict_append(f->sets, "--<UNDEFINED>--", 0);
753     f->multinames = dict_new();
754     dict_append(f->multinames, "--<UNDEFINED>--", 0);
755
756     // abc_file
757
758     f->methods = dict_new();
759     f->classes = dict_new();
760     f->scripts = dict_new();
761     f->method_bodies = dict_new();
762
763     return f;
764 }
765
766 static char* access2str(int type)
767 {
768     if(type==0x08) return "";
769     else if(type==0x16) return "package";
770     else if(type==0x17) return "packageinternal";
771     else if(type==0x18) return "protected";
772     else if(type==0x19) return "explicit";
773     else if(type==0x1A) return "staticprotected";
774     else if(type==0x05) return "private";
775     else return "undefined";
776 }
777
778 void swf_DissassembleABC(TAG*tag)
779 {
780     abc_file_t* pool = abc_file_new();
781
782     swf_SetTagPos(tag, 0);
783     U32 flags = swf_GetU32(tag);
784     DEBUG printf("flags=%08x\n", flags);
785     char*classname = swf_GetString(tag);
786     U32 version = swf_GetU32(tag);
787
788     pool->ints->num = swf_GetU30(tag)-1;
789     if(pool->ints->num>0) {
790         printf("can't parse ints yet\n");
791         return;
792     }
793     pool->uints->num = swf_GetU30(tag)-1;
794     if(pool->uints->num>0) {
795         printf("can't parse uints yet\n");
796         return;
797     }
798     pool->floats->num = swf_GetU30(tag)-1;
799     if(pool->floats->num>0) {
800         printf("can't parse floats yet\n");
801         return;
802     }
803     int num_strings = swf_GetU30(tag);
804     int t;
805     DEBUG printf("%d strings\n", num_strings);
806     for(t=1;t<num_strings;t++) {
807         int len = swf_GetU30(tag);
808         char*s = malloc(len+1);
809         swf_GetBlock(tag, s, len);
810         s[len] = 0;
811         dict_append(pool->strings, s, 0);
812         DEBUG printf("%d) \"%s\"\n", t, pool->strings->d[t].name);
813     }
814     int num_namespaces = swf_GetU30(tag);
815     DEBUG printf("%d namespaces\n", num_namespaces);
816     for(t=1;t<num_namespaces;t++) {
817         U8 type = swf_GetU8(tag);
818         int namenr = swf_GetU30(tag);
819         const char*name = dict_getstr(pool->strings, namenr);
820         dict_append(pool->namespaces, name, (void*)(int)type);
821         int w = 0;
822         DEBUG w=1;
823         if(w) {
824             if(type==0x08) printf("Namespace %s\n", name);
825             else if(type==0x16) printf("PackageNamespace %s\n", name);
826             else if(type==0x17) printf("PackageInternalNs %s\n", name);
827             else if(type==0x18) printf("ProtectedNamespace %s\n", name);
828             else if(type==0x19) printf("ExplicitNamespace %s\n", name);
829             else if(type==0x1A) printf("StaticProtectedNs %s\n", name);
830             else if(type==0x05) printf("PrivateNs %s\n", name);
831             else {
832                 printf("Undefined namespace type\n");
833                 return;
834             }
835         }
836     }
837     int num_sets = swf_GetU30(tag);
838     if(num_sets>0) {
839         printf("can't parse namespace sets yet\n");
840         return;
841     }
842     int num_multinames = swf_GetU30(tag);
843     for(t=1;t<num_multinames;t++) {
844         U8 type = swf_GetU8(tag);
845         char*mname = 0;
846         if(type==0x07 || type==0x0d) {
847             int nr1 = swf_GetU30(tag);
848             const char*namespace = dict_getstr(pool->namespaces, nr1);
849             U8 access = (U8)(int)dict_getdata(pool->namespaces, nr1);
850             const char*methodname = dict_getstr(pool->strings, swf_GetU30(tag));
851             DEBUG printf("multiname %d) <%s> %s:%s\n", t, access2str(access), namespace, methodname);
852             mname = malloc(strlen(namespace)+strlen(methodname)+300);
853             sprintf(mname, "[%s]\0", access2str(access));
854             strcat(mname, namespace);
855             strcat(mname, ":");
856             strcat(mname, methodname);
857         } else if(type==0x0f || type==0x10) {
858             const char*methodname = dict_getstr(pool->strings, swf_GetU30(tag));
859             mname = strdup(methodname);
860         } else if(type==0x11 || type==0x12) {
861             mname = strdup("");
862         } else if(type==0x09 || type==0x0e || type==0x1b || type==0x1c) {
863             printf("no support for namespace sets yet\n", type);
864             return;
865         } else {
866             printf("can't parse type %d multinames yet\n", type);
867             return;
868         }
869         dict_append(pool->multinames, mname, 0);
870         free(mname);
871     }
872     
873     int num_methods = swf_GetU30(tag);
874     for(t=0;t<num_methods;t++) {
875         abc_method_t*m = malloc(sizeof(abc_method_t));
876         memset(m, 0, sizeof(*m));
877         m->param_count = swf_GetU30(tag);
878         m->return_type_index = swf_GetU30(tag);
879         m->index = t;
880         int s;
881         char params[256];
882         params[0]='(';
883         params[1]=0;
884         for(s=0;s<m->param_count;s++) {
885             if(s)
886                 strcat(params, ", ");
887             int typenr = swf_GetU30(tag);
888             if(s < sizeof(m->params)/sizeof(m->params[0]))
889                 m->params[s] = typenr;
890             const char*type = dict_getstr(pool->multinames, typenr);
891             strcat(params, type);
892         }
893         strcat(params, ")");
894         int namenr = swf_GetU30(tag);
895         m->name = "";
896         if(namenr)
897             m->name = dict_getstr(pool->strings, namenr);
898         m->paramstr=strdup(params);
899         DEBUG printf("method %d) %s\n", t, m->paramstr);
900
901         m->flags = swf_GetU8(tag);
902         if(m->flags&0x88) {
903             printf("can't parse optional or params names yet\n");
904             return;
905         }
906         dict_append(pool->methods, m->name, m);
907     }
908     int num_metadata = swf_GetU30(tag);
909     for(t=0;t<num_metadata;t++) {
910         printf("can't parse metadata yet\n");
911         return;
912     }
913         
914     /* skip classes, and scripts for now, and do the real parsing later */
915     int num_classes = swf_GetU30(tag);
916     int classes_pos = tag->pos;
917     DEBUG printf("%d classes\n", num_classes);
918     for(t=0;t<num_classes;t++) {
919         swf_GetU30(tag);
920         swf_GetU30(tag);
921         U8 flags = swf_GetU8(tag);
922         if(flags&8) 
923             swf_GetU30(tag);
924         swf_GetU30(tag);
925         swf_GetU30(tag);
926         if(!parse_traits("", tag, pool, 0))
927             return;
928     }
929     for(t=0;t<num_classes;t++) {
930         swf_GetU30(tag);
931         if(!parse_traits("", tag, pool, 0))
932             return;
933     }
934     int num_scripts = swf_GetU30(tag);
935     DEBUG printf("%d scripts\n", num_scripts);
936     for(t=0;t<num_scripts;t++) {
937         int init = swf_GetU30(tag);
938         if(!parse_traits("", tag, pool, 0))
939             return;
940     }
941
942     int num_method_bodies = swf_GetU30(tag);
943     DEBUG printf("%d method bodies\n", num_method_bodies);
944     for(t=0;t<num_method_bodies;t++) {
945         int methodnr = swf_GetU30(tag);
946         if(methodnr >= pool->methods->num) {
947             printf("Invalid method number: %d\n", methodnr);
948             return;
949         }
950         abc_method_t*m = (abc_method_t*)dict_getdata(pool->methods, methodnr);
951         abc_code_t*c = malloc(sizeof(abc_code_t));
952         memset(c, 0, sizeof(abc_code_t));
953         c->max_stack = swf_GetU30(tag);
954         c->local_count = swf_GetU30(tag);
955         c->init_scope_depth = swf_GetU30(tag);
956         c->max_scope_depth = swf_GetU30(tag);
957         int code_length = swf_GetU30(tag);
958         c->method = m;
959         m->method_body_index = t;
960
961         c->tag = swf_InsertTag(0,0);
962
963         swf_CopyData(c->tag, tag, code_length);
964
965         int exception_count = swf_GetU30(tag);
966         c->traits = parse_traits("<method body trait>", tag, pool, 1);
967         if(!c->traits) {
968             return;
969         }
970         DEBUG printf("method_body %d) (method %d), %d bytes of code", t, methodnr, code_length);
971         int r,l = code_length>32?32:code_length;
972         for(r=0;r<l;r++) {
973             DEBUG printf("%02x ", c->tag->data[r]);
974         }
975         DEBUG printf("\n");
976
977         dict_append(pool->method_bodies, 0, c);
978     }
979     if(tag->len - tag->pos) {
980         printf("%d unparsed bytes remaining in ABC block\n", tag->len - tag->pos);
981         return;
982     }
983
984     swf_SetTagPos(tag, classes_pos);
985     for(t=0;t<num_classes;t++) {
986         abc_class_t*cls = malloc(sizeof(abc_class_t));
987         memset(cls, 0, sizeof(abc_class_t));
988         const char* classname = dict_getstr(pool->multinames, swf_GetU30(tag));
989         const char* supername = dict_getstr(pool->multinames, swf_GetU30(tag));
990         cls->name = classname;
991         U8 flags = swf_GetU8(tag);
992         const char*ns = "";
993         if(flags&8) {
994             cls->ns_index = swf_GetU30(tag);
995             ns = dict_getstr(pool->namespaces, cls->ns_index);
996         }
997         printf("class %s extends %s, %s, flags=%02x\n", classname, supername, ns, flags);
998         printf("{\n");
999         int num_interfaces = swf_GetU30(tag);
1000         if(num_interfaces>0) {
1001             printf("can't parse interfaces yet\n");
1002             return;
1003         }
1004         cls->iinit = swf_GetU30(tag);
1005         dump_method("    ","constructor", classname, cls->iinit, pool);
1006         cls->traits = parse_traits("    ",tag, pool, 1);
1007         if(!cls->traits) {
1008             return;
1009         }
1010         printf("}\n");
1011         dict_append(pool->classes, 0, cls);
1012     }
1013     for(t=0;t<num_classes;t++) {
1014         int cinit = swf_GetU30(tag);
1015         dump_method("    ","staticconstructor", "", cinit, pool);
1016         if(!parse_traits("    ",tag, pool, 1))
1017             return;
1018     }
1019     int num_scripts2 = swf_GetU30(tag);
1020     printf("\n");
1021     for(t=0;t<num_scripts2;t++) {
1022         int init = swf_GetU30(tag);
1023         dump_method("","initmethod", "init", init, pool);
1024         if(!parse_traits("", tag, pool, 1))
1025             return;
1026     }
1027 }
1028
1029 static int registerNameSpace(abc_file_t*file, U8 access, char*name) {
1030     if(access==0) { // autodetect access
1031         char*n = strdup(name);
1032         if(n[0] == '[') {
1033             char*bracket = strchr(n, ']');
1034             if(bracket) {
1035                 *bracket = 0;
1036                 char*a = n+1;
1037                 name += (bracket-n)+1;
1038                 if(!strcmp(a, "")) access=0x16;
1039                 else if(!strcmp(a, "package")) access=0x16;
1040                 else if(!strcmp(a, "packageinternal")) access=0x17;
1041                 else if(!strcmp(a, "protected")) access=0x18;
1042                 else if(!strcmp(a, "explicit")) access=0x19;
1043                 else if(!strcmp(a, "staticprotected")) access=0x1a;
1044                 else if(!strcmp(a, "private")) access=0x05;
1045                 else {
1046                     fprintf(stderr, "Undefined access level: [%s]\n", a);
1047                     return -1;
1048                 }
1049             }
1050         } else {
1051             access = 0x16;
1052         }
1053         free(n);
1054     }
1055     int t;
1056     for(t=0;t<file->namespaces->num;t++) {
1057         const char*name2 = dict_getstr(file->namespaces, t);
1058         U8 access2 = (U8)(int)dict_getdata(file->namespaces, t);
1059         if(access == access2 && !strcmp(name, name2)) {
1060             return t;
1061         }
1062     }
1063     dict_update(file->strings, name, 0);
1064     return dict_append(file->namespaces, name, (void*)(int)access);
1065 }
1066 int abc_RegisterNameSpace(abc_file_t*file, char*name) {
1067     return registerNameSpace(file, 0x08, name);
1068 }
1069 int abc_RegisterPackageNameSpace(abc_file_t*file, char*name) {
1070     return registerNameSpace(file, 0x16 , name);
1071 }
1072 int abc_RegisterPackageInternalNameSpace(abc_file_t*file, char*name) {
1073     return registerNameSpace(file, 0x17, name);
1074 }
1075 int abc_RegisterProtectedNameSpace(abc_file_t*file, char*name) {
1076     return registerNameSpace(file, 0x18, name);
1077 }
1078 int abc_RegisterExplicitNameSpace(abc_file_t*file, char*name) {
1079     return registerNameSpace(file, 0x19, name);
1080 }
1081 int abc_RegisterStaticProtectedNameSpace(abc_file_t*file, char*name) {
1082     return registerNameSpace(file, 0x1a, name);
1083 }
1084 int abc_RegisterPrivateNameSpace(abc_file_t*file, char*name) {
1085     return registerNameSpace(file, 0x05, name);
1086 }
1087 static int multiname_index(abc_file_t*abc, const char*name2) 
1088 {
1089     if(!name2)
1090         name2 = ":";
1091     int pos = dict_find(abc->multinames, name2);
1092     if(pos>=0)
1093         return pos;
1094
1095     int access = 0x16;
1096     char*n = strdup(name2);
1097     char*p = strchr(n, ':');
1098     char*namespace=0,*name=0;
1099     if(!p) {
1100         namespace = "";
1101         name = n;
1102     } else {
1103         *p = 0;
1104         namespace = n;
1105         name = p+1;
1106     }
1107     abc_multiname_t*m = malloc(sizeof(abc_multiname_t));
1108     m->namespace_index = registerNameSpace(abc, 0, namespace);
1109     m->name_index = dict_append_if_new(abc->strings, name, 0);
1110     return dict_append(abc->multinames, name2, m);
1111 }
1112
1113 abc_class_t* abc_NewClass(abc_file_t*abc, char*classname, char*superclass) {
1114     abc_class_t* c = malloc(sizeof(abc_class_t));
1115     memset(c, 0, sizeof(abc_class_t));
1116     c->index = dict_append(abc->classes, 0, c);
1117     c->abc = abc;
1118     c->name = strdup(classname);
1119     c->classname_index = multiname_index(abc, classname);
1120     c->superclass_index = multiname_index(abc, superclass);
1121     c->ns_index = abc_RegisterProtectedNameSpace(abc, classname);
1122     c->iinit = -1;
1123     c->cinit = -1;
1124
1125     c->traits = dict_new();
1126     return c;
1127 }
1128
1129 abc_code_t* add_method(abc_file_t*abc, abc_class_t*cls, char*returntype, char*name, int num_params, va_list va)
1130 {
1131     /* construct code (method body) object */
1132     abc_code_t* c = malloc(sizeof(abc_code_t));
1133     memset(c, 0, sizeof(abc_code_t));
1134     c->index = dict_append(abc->method_bodies, 0, c);
1135     c->tag = swf_InsertTag(0,0);
1136     c->abc = abc;
1137     c->traits = dict_new();
1138
1139     /* construct method object */
1140     abc_method_t* m = malloc(sizeof(abc_method_t));
1141     memset(m, 0, sizeof(abc_method_t));
1142     m->param_count = num_params;
1143     m->index = dict_append(abc->methods, 0, m);
1144     if(returntype) 
1145         m->return_type_index = multiname_index(abc, returntype);
1146     else
1147         m->return_type_index = 0;
1148     if(num_params>sizeof(m->params)/sizeof(m->params[0])) {
1149         fprintf(stderr, "abc: Too many parameters\n");
1150         return 0;
1151     }
1152     int t;
1153     for(t=0;t<num_params;t++) {
1154         const char*param = va_arg(va, const char*);
1155         m->params[t] = multiname_index(abc, param);
1156     }
1157
1158     /* crosslink the two objects */
1159     m->method_body_index = c->index;
1160     c->method = m;
1161
1162     return c;
1163 }
1164
1165 abc_code_t* abc_AddConstructor(abc_class_t*cls, char*returntype, int num_params, ...) 
1166 {
1167     va_list va;
1168     va_start(va, num_params);
1169     abc_code_t* c = add_method(cls->abc, cls, returntype, 0, num_params, va);
1170     va_end(va);
1171     cls->iinit = c->index;
1172     return c;
1173 }
1174
1175 abc_code_t* abc_AddStaticConstructor(abc_class_t*cls, char*returntype, int num_params, ...) 
1176 {
1177     va_list va;
1178     va_start(va, num_params);
1179     abc_code_t* c = add_method(cls->abc, cls, returntype, 0, num_params, va);
1180     va_end(va);
1181     cls->cinit = c->index;
1182     return c;
1183 }
1184
1185 abc_trait_t*trait_new(int type, int name_index, int data1, int data2, int vindex, int vkind)
1186 {
1187     abc_trait_t*trait = malloc(sizeof(abc_trait_t));
1188     memset(trait, 0, sizeof(abc_trait_t));
1189     trait->type = type;
1190     trait->name_index = name_index;
1191     trait->data1 = data1;
1192     trait->data2 = data2;
1193     trait->vindex = vindex;
1194     trait->vkind = vkind;
1195     return trait;
1196 }
1197
1198 abc_code_t* abc_AddMethod(abc_class_t*cls, char*returntype, char*name, int num_params, ...) 
1199 {
1200     abc_file_t*abc = cls->abc;
1201     va_list va;
1202     va_start(va, num_params);
1203     abc_code_t* c = add_method(cls->abc, cls, returntype, name, num_params, va);
1204     va_end(va);
1205     dict_append(cls->traits, 0, trait_new(TRAIT_METHOD, multiname_index(abc, name), 0, c->method->index, 0, 0));
1206     return c;
1207 }
1208
1209 void abc_AddSlot(abc_class_t*cls, char*name, int slot, char*multiname)
1210 {
1211     abc_file_t*abc = cls->abc;
1212     int i = multiname_index(abc, name);
1213     dict_append(cls->traits, 0, trait_new(TRAIT_SLOT, i, slot, multiname_index(abc, multiname), 0, 0));
1214 }
1215
1216 void abc_code_addClassTrait(abc_code_t*code, char*multiname, int slotid, abc_class_t*cls)
1217 {
1218     abc_file_t*abc = code->abc;
1219     int i = multiname_index(abc, multiname);
1220     abc_trait_t*trait = trait_new(TRAIT_CLASS, i, slotid, cls->index, 0, 0);
1221     dict_append(code->traits, 0, trait);
1222 }
1223
1224 abc_code_t* abc_AddInitScript(abc_file_t*abc, char*returntype, int num_params, ...) 
1225 {
1226     va_list va;
1227     va_start(va, num_params);
1228     abc_code_t* c = add_method(abc, 0, returntype, 0, num_params, va);
1229     dict_append(abc->scripts, 0, c);
1230     va_end(va);
1231     return c;
1232 }
1233
1234 void swf_SetU30(TAG*tag, U32 u)
1235 {
1236     do {
1237         swf_SetU8(tag, (u&~0x7f?0x80:0) | (u&0x7F));
1238         u>>=7;
1239     } while(u);
1240 }
1241 void swf_SetU30String(TAG*tag, const char*str)
1242 {
1243     int l = strlen(str);
1244     swf_SetU30(tag, l);
1245     swf_SetBlock(tag, (void*)str, l);
1246 }
1247
1248 static void write_traits(abc_file_t*abc, TAG*tag, dict_t*traits)
1249 {
1250     swf_SetU30(tag, traits->num);
1251     int s;
1252
1253     for(s=0;s<traits->num;s++) {
1254         abc_trait_t*trait = (abc_trait_t*)dict_getdata(traits, s);
1255         swf_SetU30(tag, trait->name_index);
1256         swf_SetU8(tag, trait->type);
1257         swf_SetU30(tag, trait->data1);
1258         swf_SetU30(tag, trait->data2);
1259         if(trait->type == 0) { //slot
1260             swf_SetU30(tag, trait->vindex);
1261             if(trait->vindex) {
1262                 swf_SetU8(tag, trait->vkind);
1263             }
1264         }
1265     }
1266 }
1267
1268 void swf_WriteABC(TAG*tag, abc_file_t*abc)
1269 {
1270     swf_SetU32(tag, 1);
1271     swf_SetU8(tag, 0);
1272     swf_SetU16(tag, 0x10);
1273     swf_SetU16(tag, 0x2e);
1274     swf_SetU30(tag, abc->ints->num>1?abc->ints->num:0);
1275     // ...
1276     swf_SetU30(tag, abc->uints->num>1?abc->uints->num:0);
1277     // ...
1278     swf_SetU30(tag, abc->floats->num>1?abc->floats->num:0);
1279     // ...
1280     swf_SetU30(tag, abc->strings->num>1?abc->strings->num:0);
1281     int t;
1282     for(t=1;t<abc->strings->num;t++) {
1283         swf_SetU30String(tag, dict_getstr(abc->strings, t));
1284     }
1285     swf_SetU30(tag, abc->namespaces->num>1?abc->namespaces->num:0);
1286     for(t=1;t<abc->namespaces->num;t++) {
1287         U8 type = (U8)(int)dict_getdata(abc->namespaces, t);
1288         const char*name = dict_getstr(abc->namespaces, t);
1289         int i = dict_find(abc->strings, name);
1290         if(i<0) {
1291             fprintf(stderr, "Couldn't find namespace \"%s\" in constant pool\n", name);
1292             return;
1293         }
1294         swf_SetU8(tag, type);
1295         swf_SetU30(tag, i);
1296     }
1297     swf_SetU30(tag, abc->sets->num>1?abc->sets->num:0);
1298     // ...
1299
1300     swf_SetU30(tag, abc->multinames->num>1?abc->multinames->num:0);
1301     // ...
1302     for(t=1;t<abc->multinames->num;t++) {
1303         abc_multiname_t*m = (abc_multiname_t*)dict_getdata(abc->multinames, t);
1304         swf_SetU8(tag, 0x07);
1305         swf_SetU30(tag, m->namespace_index);
1306         swf_SetU30(tag, m->name_index);
1307     }
1308     
1309     swf_SetU30(tag, abc->methods->num);
1310     for(t=0;t<abc->methods->num;t++) {
1311         abc_method_t*m = (abc_method_t*)dict_getdata(abc->methods, t);
1312         swf_SetU30(tag, m->param_count);
1313         swf_SetU30(tag, m->return_type_index);
1314         int s;
1315         for(s=0;s<m->param_count;s++) {
1316             swf_SetU30(tag, m->params[s]);
1317         }
1318         swf_SetU30(tag, 0); // name
1319         swf_SetU8(tag, 0); //flags
1320     }
1321
1322     swf_SetU30(tag, 0);//metadata
1323
1324     swf_SetU30(tag, abc->classes->num);
1325
1326     for(t=0;t<abc->classes->num;t++) {
1327         abc_class_t*c = (abc_class_t*)dict_getdata(abc->classes, t);
1328         swf_SetU30(tag, c->classname_index);
1329         swf_SetU30(tag, c->superclass_index);
1330
1331         swf_SetU8(tag, 8); // flags
1332         swf_SetU30(tag, c->ns_index);
1333
1334         swf_SetU30(tag, 0); // no interfaces
1335         if(c->iinit<0) {
1336             fprintf(stderr, "Error: Class %s has no constructor\n", c->name);
1337             return;
1338         }
1339         swf_SetU30(tag, c->iinit);
1340         write_traits(abc, tag, c->traits);
1341     }
1342     for(t=0;t<abc->classes->num;t++) {
1343         abc_class_t*c = (abc_class_t*)dict_getdata(abc->classes, t);
1344         if(c->cinit<0) {
1345             fprintf(stderr, "Error: Class %s has no constructor\n", c->name);
1346             return;
1347         }
1348         swf_SetU30(tag, c->cinit);
1349         swf_SetU30(tag, 0); // no traits
1350     }
1351
1352     swf_SetU30(tag, abc->scripts->num);
1353     for(t=0;t<abc->scripts->num;t++) {
1354         abc_code_t*c = (abc_code_t*)dict_getdata(abc->scripts, t);
1355         swf_SetU30(tag, c->index); //!=t!
1356         write_traits(abc, tag, c->traits);
1357     }
1358
1359     swf_SetU30(tag, abc->method_bodies->num);
1360     for(t=0;t<abc->method_bodies->num;t++) {
1361         abc_code_t*c = (abc_code_t*)dict_getdata(abc->method_bodies, t);
1362         abc_method_t*m = c->method;
1363         swf_SetU30(tag, m->index);
1364         swf_SetU30(tag, c->max_stack);
1365         swf_SetU30(tag, c->local_count);
1366         swf_SetU30(tag, c->init_scope_depth);
1367         swf_SetU30(tag, c->max_scope_depth);
1368         swf_SetU30(tag, c->tag->len);
1369         swf_SetBlock(tag, c->tag->data, c->tag->len);
1370         swf_SetU30(tag, c->exception_count);
1371         swf_SetU8(tag, 0); // no traits
1372     }
1373 }
1374
1375 #include "swfabc_ops.c"
1376
1377 void swf_AddButtonLinks(TAG*tag)
1378 {
1379     abc_file_t*abc = abc_file_new();
1380     abc_code_t*c = 0;
1381     
1382     abc_class_t*maintimeline = abc_NewClass(abc, "buttonmitlink_fla:MainTimeline", "flash.display:MovieClip");
1383     
1384     c = abc_AddStaticConstructor(maintimeline, 0, 0);
1385     c->max_stack = 1;
1386     c->local_count = 1;
1387     c->init_scope_depth = 9;
1388     c->max_scope_depth = 10;
1389     abc_getlocal_0(c);
1390     abc_pushscope(c);
1391     abc_returnvoid(c);
1392     
1393     c = abc_AddMethod(maintimeline, 0, "[packageinternal]buttonmitlink_fla:frame1", 0);
1394     c->max_stack = 3;
1395     c->local_count = 1;
1396     c->init_scope_depth = 10;
1397     c->max_scope_depth = 11;
1398     abc_getlocal_0(c);
1399     abc_pushscope(c);
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
1439     abc_getlocal_0(c);
1440     abc_pushscope(c);
1441
1442     abc_getlocal_0(c);
1443     abc_constructsuper(c,0);
1444     abc_findpropstrict(c,":addFrameScript");
1445     abc_pushbyte(c,0x00);
1446     abc_getlex(c,"[packageinternal]buttonmitlink_fla:frame1");
1447     abc_callpropvoid(c,":addFrameScript",2);
1448
1449     abc_getlex(c,":MyButton1");
1450     abc_getlex(c,"flash.events:MouseEvent");
1451     abc_getproperty(c, ":CLICK");
1452     abc_getlex(c, ":gotoPage1");
1453     abc_callpropvoid(c, ":addEventListener" ,2);
1454
1455     abc_getlex(c,":MyButton2");
1456     abc_getlex(c,"flash.events:MouseEvent");
1457     abc_getproperty(c, ":CLICK");
1458     abc_getlex(c,":gotoPage2");
1459     abc_callpropvoid(c,":addEventListener",2);
1460
1461     abc_returnvoid(c);
1462     
1463     c = abc_AddInitScript(abc, 0, 0);
1464     c->max_stack = 2;
1465     c->local_count = 1;
1466     c->init_scope_depth = 1;
1467     c->max_scope_depth = 9;
1468     abc_getlocal_0(c);
1469     abc_pushscope(c);
1470     abc_getscopeobject(c, 0);
1471     abc_getlex(c,":Object");
1472     abc_pushscope(c);
1473     abc_getlex(c,"flash.events:EventDispatcher");
1474     abc_pushscope(c);
1475     abc_getlex(c,"flash.display:DisplayObject");
1476     abc_pushscope(c);
1477     abc_getlex(c,"flash.display:InteractiveObject");
1478     abc_pushscope(c);
1479     abc_getlex(c,"flash.display:DisplayObjectContainer");
1480     abc_pushscope(c);
1481     abc_getlex(c,"flash.display:Sprite");
1482     abc_pushscope(c);
1483     abc_getlex(c,"flash.display:MovieClip");
1484     abc_pushscope(c);
1485     abc_getlex(c,"flash.display:MovieClip");
1486     abc_newclass(c,maintimeline);
1487     abc_popscope(c);
1488     abc_popscope(c);
1489     abc_popscope(c);
1490     abc_popscope(c);
1491     abc_popscope(c);
1492     abc_popscope(c);
1493     abc_popscope(c);
1494     abc_initproperty(c,"buttonmitlink_fla:MainTimeline");
1495     abc_returnvoid(c);
1496
1497     abc_code_addClassTrait(c, "buttonmitlink_fla:MainTimeline", 1, maintimeline);
1498
1499     swf_WriteABC(tag, abc);
1500 }