automatically generated from opcodes in swfabc.c
[swftools.git] / lib / modules / swfabc.c
1 /* swfabc.c
2
3    Routines for handling Flash2 AVM2 ABC Actionscript
4
5    Extension module for the rfxswf library.
6    Part of the swftools package.
7
8    Copyright (c) 2007 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 int swf_GetS30(TAG*tag)
377 {
378     U32 shift = 0;
379     U32 s = 0;
380     while(1) {
381         U8 b = swf_GetU8(tag);
382         s|=(b&127)<<shift;
383         shift+=7;
384         if(!(b&128)) {
385             if(b&64) {
386                 s|=0xffffffff<<shift;
387             }
388             break;
389         }
390     }
391     return s;
392 }
393
394 double swf_GetD64(TAG*tag)
395 {
396     U32 b[2];
397
398     b[0] = swf_GetU32(tag);
399     b[1] = swf_GetU32(tag);
400
401     return 0.0;
402 }
403
404 typedef struct _abc_method {
405     /* from method signature: */
406     const char*name;
407     char*paramstr;
408     int return_type_index;//index into multiname
409     int param_count;
410     int params[16]; // indexes into multiname
411     U8 flags;
412
413     int index;
414     int method_body_index;
415 } abc_method_t;
416
417 typedef struct _abc_multiname {
418     int namespace_index;
419     int name_index;
420 } abc_multiname_t;
421
422 typedef struct _dict_entry {
423     const char*name;
424     void*data;
425 } dict_entry_t;
426
427 typedef struct _dict {
428     int num;
429     int size;
430     dict_entry_t*d;
431 } dict_t;
432
433
434 dict_t* dict_new() {
435     dict_t*d = malloc(sizeof(dict_t));
436     memset(d, 0, sizeof(dict_t));
437     return d;
438 }
439 const char*dict_getstr(dict_t*dict, int nr) {
440     if(nr > dict->num || nr<0) {
441         printf("error: reference to string %d in dict\n");
442         return 0;
443     }
444     return dict->d[nr].name;
445 }
446 char*dict_getdata(dict_t*dict, int nr) {
447     if(nr > dict->num || nr<0) {
448         printf("error: reference to string %d in dict\n");
449         return 0;
450     }
451     return dict->d[nr].data;
452 }
453 int dict_append(dict_t*dict, const char*name, void*data) {
454     while(dict->size <= dict->num) {
455         dict->size += 64;
456         if(!dict->d) {
457             dict->d = malloc(sizeof(dict_entry_t)*dict->size);
458         } else {
459             dict->d = realloc(dict->d, sizeof(dict_entry_t)*dict->size);
460         }
461     }
462     if(name) {
463         dict->d[dict->num].name = strdup(name);
464     } else {
465         dict->d[dict->num].name = 0;
466     }
467     dict->d[dict->num].data = data;
468     return dict->num++;
469 }
470 int dict_find(dict_t*dict, const char*name)
471 {
472     if(!name)
473         name = "";
474     int t;
475     for(t=0;t<dict->num;t++) {
476         if(dict->d[t].name && !strcmp(dict->d[t].name,name))
477             return t;
478     }
479     return -1;
480 }
481 int dict_update(dict_t*dict, char*name, void*data) {
482     int pos = dict_find(dict, name);
483     if(pos>=0) {
484         dict->d[pos].data = data;
485         return pos;
486     }
487     return dict_append(dict, name, data);
488 }
489 int dict_append_if_new(dict_t*dict, char*name, void*data) {
490     int pos = dict_find(dict, name);
491     if(pos>=0)
492         return pos;
493     return dict_append(dict, name, data);
494 }
495
496 typedef struct _abc_file_t {
497
498     // contant_pool
499
500     dict_t*ints;
501     dict_t*uints;
502     dict_t*floats;
503     dict_t*strings;
504     dict_t*namespaces;
505     dict_t*namespace_sets;
506     dict_t*sets;
507     dict_t*multinames;
508
509     // abc_file
510
511     dict_t*methods;
512     dict_t*classes;
513     dict_t*scripts;
514     dict_t*method_bodies;
515 } abc_file_t;
516
517 typedef struct _abc_trait {
518     unsigned char type;
519     int name_index;
520     U32 data1;
521     U32 data2;
522     int vindex;
523     int vkind;
524 } abc_trait_t;
525
526 typedef struct _abc_class {
527     int index;
528     abc_file_t*abc;
529     const char*name;
530     int classname_index;
531     int superclass_index;
532     int ns_index;
533     int iinit;
534     int cinit;
535     dict_t*traits;
536 } abc_class_t;
537
538 typedef struct _abc_code {
539     int index;
540     abc_file_t*abc;
541     //abc_class_t*cls;
542     abc_method_t*method;
543     TAG*tag;
544     int max_stack;
545     int local_count;
546     int init_scope_depth;
547     int max_scope_depth;
548     int exception_count;
549     dict_t*traits;
550 } abc_code_t;
551
552 typedef struct _opcode
553 {
554     unsigned char opcode;
555     char*name;
556     char*params;
557 } opcode_t;
558
559 /* 2 = multiname
560    m = method
561    n = number of params
562    i = method info
563    b = byte
564    s = short
565    c = class
566    s = string
567    S = switch
568 */
569
570 int abc_RegisterNameSpace(abc_file_t*file, char*name);
571 int abc_RegisterPackageNameSpace(abc_file_t*file, char*name);
572 int abc_RegisterPackageInternalNameSpace(abc_file_t*file, char*name);
573 int abc_RegisterProtectedNameSpace(abc_file_t*file, char*name);
574 int abc_RegisterExplicitNameSpace(abc_file_t*file, char*name);
575 int abc_RegisterStaticProtectedNameSpace(abc_file_t*file, char*name);
576 int abc_RegisterPrivateNameSpace(abc_file_t*file, char*name);
577
578
579 opcode_t opcodes[]={
580 {0xa0, "add", ""},
581 {0xc5, "add_i", ""},
582 {0x86, "atype", "2"},
583 {0x87, "astypelate", ""},
584 {0xA8, "bitand", ""},
585 {0x97, "bitnot", ""},
586 {0xa9, "bitor", ""},
587 {0xaa, "bitxor", ""},
588 {0x41, "call", "n"},
589 {0x43, "callmethod", "mn"},
590 {0x4c, "callproplex", "2n"},
591 {0x46, "callproperty", "2n"},
592 {0x4f, "callpropvoid", "2n"},
593 {0x44, "callstatic", "in"},
594 {0x45, "callsuper", "2n"},
595 {0x4e, "callsupervoid", "2n"},
596 {0x78, "checkfilter", ""},
597 {0x80, "coerce", "m"},
598 {0x82, "coerce_a", ""},
599 {0x85, "coerce_s", ""},
600 {0x42, "construct", "n"},
601 {0x4a, "constructprop", "2n"},
602 {0x49, "constructsuper", "n"},
603 {0x76, "convert_b", ""},
604 {0x73, "convert_i", ""},
605 {0x75, "convert_d", ""},
606 {0x77, "convert_o", ""},
607 {0x74, "convert_u", ""},
608 {0x70, "convert_s", ""},
609 {0xef, "debug", "bsbu"},
610 {0xf1, "debugfile", "s"},
611 {0xf0, "debugline", "u"},
612 {0x94, "declocal", "u"},
613 {0xc3, "declocal_i", "u"},
614 {0x93, "decrement", ""},
615 {0xc1, "decrement_i", ""},
616 {0x6a, "deleteproperty", "2"},
617 {0xa3, "divide", ""},
618 {0x2a, "dup", ""},
619 {0x06, "dxns", "s"},
620 {0x07, "dxnslate", ""},
621 {0xab, "equals", ""},
622 {0x72, "esc_xattr", ""},
623 {0x71, "esc_xelem", ""},
624 {0x5e, "findproperty", "2"},
625 {0x5d, "findpropstrict", "2"},
626 {0x59, "getdescendants", "2"},
627 {0x64, "getglobalscope", ""},
628 {0x6e, "getglobalslot", "u"},
629 {0x60, "getlex", "2"},
630 {0x62, "getlocal", "u"},
631 {0xd0, "getlocal_0", ""},
632 {0xd1, "getlocal_1", ""},
633 {0xd2, "getlocal_2", ""},
634 {0xd3, "getlocal_3", ""},
635 {0x66, "getproperty", "2"},
636 {0x65, "getscopeobject", "u"},
637 {0x6c, "getslot", "u"},
638 {0x04, "getsuper", "2"},
639 {0xaf, "greaterequals", ""},
640 {0x1f, "hasnext", ""},
641 {0x32, "hasnext2", "uu"},
642 {0x13, "ifeq", "j"},
643 {0x12, "iffalse", "j"},
644 {0x18, "ifge", "j"},
645 {0x17, "ifgt", "j"},
646 {0x16, "ifle", "j"},
647 {0x15, "iflt", "j"},
648 {0x0f, "ifnge", "j"},
649 {0x0e, "ifngt", "j"},
650 {0x0d, "ifnle", "j"},
651 {0x0c, "ifnlt", "j"},
652 {0x14, "ifne", "j"},
653 {0x14, "ifne", "j"},
654 {0x19, "ifstricteq", "j"},
655 {0x1a, "ifstrictne", "j"},
656 {0x11, "iftrue", "j"},
657 {0xb4, "in", ""},
658 {0x92, "inclocal", "u"},
659 {0xc2, "inclocal_i", "u"},
660 {0x91, "increment", ""},
661 {0xc0, "increment_i", ""},
662 {0x68, "initproperty", "2"},
663 {0xb1, "instanceof", ""},
664 {0xb2, "istype", "2"},
665 {0xb3, "istypelate", ""},
666 {0x10, "jump", "j"},
667 {0x08, "kill", "u"},
668 {0x09, "label", ""},
669 {0xae, "lessequals", ""},
670 {0xad, "lessthan", ""},
671 {0x1b, "lookupswitch", "S"},
672 {0xa5, "lshift", ""},
673 {0xa4, "modulo", ""},
674 {0xa2, "multiply", ""},
675 {0xc7, "multiply_i", ""},
676 {0x90, "negate", ""},
677 {0xc4, "negate_i", ""},
678 {0x57, "newactivation", ""},
679 {0x56, "newarray", "u"},
680 {0x5a, "newcatch", "u"}, //index into exception_info
681 {0x58, "newclass", "c"}, //index into class_info
682 {0x40, "newfunction", "u"}, //index into method_info
683 {0x55, "newobject", "u"},
684 {0x1e, "nextname", ""},
685 {0x23, "nextvalue", ""},
686 {0x02, "nop", ""},
687 {0x96, "not", ""},
688 {0x29, "pop", ""},
689 {0x1d, "popscope", ""},
690 {0x24, "pushbyte", "b"},
691 {0x2f, "pushdouble", "u"}, //index into floats
692 {0x27, "pushtrue", ""},
693 {0x2d, "pushint", "u"}, //index into ints
694 {0x31, "pushnamespace", "u"}, //index into namespace
695 {0x28, "pushnan", ""},
696 {0x20, "pushnull", ""},
697 {0x30, "pushscope", ""},
698 {0x25, "pushshort", "u"},
699 {0x2c, "pushstring", "s"},
700 {0x26, "pushtrue", ""},
701 {0x2e, "pushuint", "u"}, //index into uints
702 {0x21, "pushundefined", ""},
703 {0x1c, "pushwith", ""},
704 {0x48, "returnvalue", ""},
705 {0x47, "returnvoid", ""},
706 {0xa6, "rshift", ""},
707 {0x63, "setlocal", "u"},
708 {0xd4, "setlocal_0", ""},
709 {0xd5, "setlocal_1", ""},
710 {0xd6, "setlocal_2", ""},
711 {0xd7, "setlocal_3", ""},
712 {0x6f, "setglobalshot", "u"},
713 {0x61, "setproperty", "2"},
714 {0x6d, "setslot", "u"},
715 {0x05, "setsuper", "2"},
716 {0xac, "strictequals", ""},
717 {0xa1, "subtract", ""},
718 {0xc6, "subtract_i", ""},
719 {0x2b, "swap", ""},
720 {0x03, "throw", ""},
721 {0x95, "typeof", ""},
722 {0xa7, "urshift", ""},
723 {0xb0, "xxx", ""},
724 };
725
726 int swf_GetU24(TAG*tag)
727 {
728     int b1 = swf_GetU8(tag);
729     int b2 = swf_GetU8(tag);
730     int b3 = swf_GetU8(tag);
731     return b3<<16|b2<<8|b1;
732 }
733 static int parse_code(TAG*tag, int len, abc_file_t*pool, char*prefix)
734 {
735     int end=tag->pos+len;
736     while(tag->pos<end) {
737         U8 opcode = swf_GetU8(tag);
738         int t;
739         char found = 0;
740         for(t=0;t<sizeof(opcodes)/sizeof(opcodes[0]);t++) {
741             if(opcodes[t].opcode == opcode) {
742                 printf("%s%s ", prefix, opcodes[t].name);
743                 char*p = opcodes[t].params;
744                 char first = 1;
745                 while(*p) {
746                     if(!first)
747                         printf(", ");
748                     if(*p == 'n') {
749                         int n = swf_GetU30(tag);
750                         printf("%d params", n);
751                     } else if(*p == '2') {
752                         const char* m = dict_getstr(pool->multinames, swf_GetU30(tag));
753                         printf("%s", m);
754                     } else if(*p == 'm') {
755                         int n = swf_GetU30(tag);
756                         printf("[method%d]", n);
757                     } else if(*p == 'c') {
758                         int n = swf_GetU30(tag);
759                         printf("[classinfo%d]", n);
760                     } else if(*p == 'i') {
761                         int n = swf_GetU30(tag);
762                         printf("[methodbody%d]", n);
763                     } else if(*p == 'u') {
764                         int n = swf_GetU30(tag);
765                         printf("%d", n);
766                     } else if(*p == 'b') {
767                         int b = swf_GetU8(tag);
768                         printf("%02x", b);
769                     } else if(*p == 'j') {
770                         printf("%d", swf_GetU24(tag));
771                     } else if(*p == 's') {
772                         const char*s = dict_getstr(pool->strings, swf_GetU30(tag));
773                         printf("\"%s\"", s);
774                     } else if(*p == 'S') {
775                         swf_GetU24(tag); //default
776                         int num = swf_GetU30(tag)+1;
777                         int t;
778                         for(t=0;t<num;t++) 
779                             swf_GetU24(tag);
780                     } else {
781                         printf("Can't parse opcode param type \"%c\"\n", *p);
782                         return 0;
783                     }
784                     p++;
785                     first = 0;
786                 }
787                 found = 1;
788                 break;
789             }
790         }
791         if(!found) {
792             printf("Can't parse opcode %02x\n", opcode);
793             return 0;
794         }
795         printf("\n");
796     }
797     if(tag->pos!=end) {
798         printf("Read beyond end of ABC Bytecode\n");
799         return 0;
800     }
801     return 1;
802 }
803
804 static void dump_method(const char*prefix, const char*type, const char*name, int nr, abc_file_t*pool)
805 {
806     if(nr >= pool->methods->num) {
807         printf("Invalid method number: %d\n", nr);
808         return;
809     }
810     abc_method_t*m = (abc_method_t*)dict_getdata(pool->methods, nr);
811     printf("%s%s %s %s%s\n", prefix, type, dict_getstr(pool->multinames,m->return_type_index), name, m->paramstr);
812
813     abc_code_t*c = (abc_code_t*)dict_getdata(pool->method_bodies, m->method_body_index);
814     
815     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);
816
817     swf_SetTagPos(c->tag, 0);
818     char prefix2[80];
819     sprintf(prefix2, "%s    ", prefix);
820     printf("%s{\n", prefix);
821     parse_code(c->tag, c->tag->len, pool,prefix2);
822     printf("%s}\n", prefix);
823 }
824
825 //#define DEBUG
826 #define DEBUG if(0)
827
828 static void parse_metadata(TAG*tag, abc_file_t*pool)
829 {
830     int t;
831     int num_metadata = swf_GetU30(tag);
832     DEBUG printf("%d metadata\n");
833     for(t=0;t<num_metadata;t++) {
834         const char*name = dict_getstr(pool->strings, swf_GetU30(tag));
835         int num = swf_GetU30(tag);
836         int s;
837         DEBUG printf("  %s\n", name);
838         for(s=0;s<num;s++) {
839             const char*key = dict_getstr(pool->strings, swf_GetU30(tag));
840             const char*value = dict_getstr(pool->strings, swf_GetU30(tag));
841             DEBUG printf("    %s=%s\n", key, value);
842         }
843     }
844 }
845
846 #define TRAIT_SLOT 0
847 #define TRAIT_METHOD 1
848 #define TRAIT_GETTER 2
849 #define TRAIT_SETTER 3
850 #define TRAIT_CLASS 4
851 #define TRAIT_FUNCTION 5
852 static dict_t* parse_traits(char*prefix, TAG*tag, abc_file_t*pool, char print)
853 {
854     int num_traits = swf_GetU30(tag);
855     dict_t*traits = dict_new();
856     int t;
857     if(num_traits) {
858         DEBUG printf("%d traits\n", num_traits);
859     }
860     for(t=0;t<num_traits;t++) {
861         abc_trait_t*trait = malloc(sizeof(abc_trait_t));
862         memset(trait, 0, sizeof(abc_trait_t));
863         dict_append(traits, 0, trait);
864         int name_index = swf_GetU30(tag);
865         const char*name = dict_getstr(pool->multinames, name_index);
866         U8 kind = swf_GetU8(tag);
867         U8 attributes = kind&0xf0;
868         kind&=0x0f;
869         DEBUG printf("  trait %d) %s type=%02x\n", t, name, kind);
870         if(kind == 1 || kind == 2 || kind == 3) { // method / getter / setter
871             int disp_id = swf_GetU30(tag);
872             int nr = swf_GetU30(tag);
873             DEBUG printf("  %smethod %d %d %s\n", prefix, nr, disp_id, ((abc_method_t*)dict_getdata(pool->methods, nr))->paramstr);
874             if(print) dump_method(prefix, kind==1?"method":(kind==2?"getter":"setter"), name, nr, pool);
875         } else if(kind == 5) { // function
876             int slot_id = swf_GetU30(tag);
877             int nr = swf_GetU30(tag);
878             if(print) dump_method(prefix, "function", name, nr, pool);
879         } else if(kind == 4) { // class
880             int slot_id = swf_GetU30(tag);
881             int cls = swf_GetU30(tag);
882             if(print) printf("  %sclass %s %d %d\n", prefix, name, slot_id, cls);
883         } else if(kind == 0 || kind == 6) { // slot, const
884             int slot_id = swf_GetU30(tag);
885             const char*type_name = dict_getstr(pool->multinames, swf_GetU30(tag));
886             int vindex = swf_GetU30(tag);
887             if(vindex) {
888                 U8 vkind = swf_GetU8(tag);
889             }
890             if(print) printf("  %sslot %s %d %s (vindex=%d)\n", prefix, name, slot_id, type_name, vindex);
891         } else {
892             printf("    can't parse trait type %d\n", kind);
893             return 0;
894         }
895         if(attributes&0x40) {
896             int num = swf_GetU30(tag);
897             int s;
898             for(s=0;s<num;s++) {
899                 swf_GetU30(tag); //index into metadata array
900             }
901         }
902     }
903     return traits;
904 }
905
906 void swf_CopyData(TAG*to, TAG*from, int len)
907 {
908     unsigned char*data = malloc(len);
909     swf_GetBlock(from, data, len);
910     swf_SetBlock(to, data, len);
911     free(data);
912 }
913
914 abc_file_t*abc_file_new()
915 {
916     abc_file_t*f = malloc(sizeof(abc_file_t));
917     memset(f, 0, sizeof(abc_file_t));
918
919     f->ints = dict_new();
920     dict_append(f->ints, 0, (void*)0);
921     f->uints = dict_new();
922     dict_append(f->uints, 0, (void*)0);
923     f->floats = dict_new();
924     dict_append(f->floats, 0, 0);
925     f->strings = dict_new();
926     dict_append(f->strings, "--<UNDEFINED>--", 0);
927     f->namespaces = dict_new();
928     dict_append(f->namespaces, "--<UNDEFINED>--", 0);
929     f->namespace_sets = dict_new();
930     dict_append(f->namespace_sets, "--<UNDEFINED>--", 0);
931     f->sets = dict_new();
932     dict_append(f->sets, "--<UNDEFINED>--", 0);
933     f->multinames = dict_new();
934     dict_append(f->multinames, "--<UNDEFINED>--", 0);
935
936     // abc_file
937
938     f->methods = dict_new();
939     f->classes = dict_new();
940     f->scripts = dict_new();
941     f->method_bodies = dict_new();
942
943     return f;
944 }
945
946 static char* access2str(int type)
947 {
948     if(type==0x08) return "";
949     else if(type==0x16) return "package";
950     else if(type==0x17) return "packageinternal";
951     else if(type==0x18) return "protected";
952     else if(type==0x19) return "explicit";
953     else if(type==0x1A) return "staticprotected";
954     else if(type==0x05) return "private";
955     else return "undefined";
956 }
957
958 void swf_DissassembleABC(TAG*tag)
959 {
960     abc_file_t* pool = abc_file_new();
961
962     swf_SetTagPos(tag, 0);
963     U32 flags = swf_GetU32(tag);
964     int t;
965     DEBUG printf("flags=%08x\n", flags);
966     char*classname = swf_GetString(tag);
967     U32 version = swf_GetU32(tag);
968     if(version!=0x002e0010) {
969         fprintf(stderr, "Warning: unknown AVM2 version %08x\n", version);
970     }
971
972     int num_ints = swf_GetU30(tag);
973     DEBUG printf("%d ints\n", num_ints);
974     for(t=1;t<num_ints;t++) {
975         S32 v = swf_GetU30(tag);
976         DEBUG printf("int %d) %d\n", t, v);
977         dict_append(pool->ints, 0, (void*)v);
978     }
979
980     int num_uints = swf_GetU30(tag);
981     DEBUG printf("%d uints\n", num_uints);
982     for(t=1;t<num_uints;t++) {
983         U32 v = swf_GetS30(tag);
984         DEBUG printf("uint %d) %d\n", t, v);
985         dict_append(pool->uints, 0, (void*)v);
986     }
987     
988     int num_floats = swf_GetU30(tag);
989     DEBUG printf("%d floats\n", num_floats);
990     for(t=1;t<num_floats;t++) {
991         double d = swf_GetD64(tag);
992         DEBUG printf("float %d) %f\n", t, d);
993         dict_append(pool->floats, 0, 0);
994     }
995     
996     int num_strings = swf_GetU30(tag);
997     DEBUG printf("%d strings\n", num_strings);
998     for(t=1;t<num_strings;t++) {
999         int len = swf_GetU30(tag);
1000         char*s = malloc(len+1);
1001         swf_GetBlock(tag, s, len);
1002         s[len] = 0;
1003         dict_append(pool->strings, s, 0);
1004         DEBUG printf("%d) \"%s\"\n", t, pool->strings->d[t].name);
1005     }
1006     int num_namespaces = swf_GetU30(tag);
1007     DEBUG printf("%d namespaces\n", num_namespaces);
1008     for(t=1;t<num_namespaces;t++) {
1009         U8 type = swf_GetU8(tag);
1010         int namenr = swf_GetU30(tag);
1011         const char*name = dict_getstr(pool->strings, namenr);
1012         dict_append(pool->namespaces, name, (void*)(int)type);
1013         int w = 0;
1014         DEBUG w=1;
1015         if(w) {
1016             if(type==0x08) printf("Namespace %s\n", name);
1017             else if(type==0x16) printf("PackageNamespace %s\n", name);
1018             else if(type==0x17) printf("PackageInternalNs %s\n", name);
1019             else if(type==0x18) printf("ProtectedNamespace %s\n", name);
1020             else if(type==0x19) printf("ExplicitNamespace %s\n", name);
1021             else if(type==0x1A) printf("StaticProtectedNs %s\n", name);
1022             else if(type==0x05) printf("PrivateNs %s\n", name);
1023             else {
1024                 printf("Undefined namespace type\n");
1025                 return;
1026             }
1027         }
1028     }
1029     int num_sets = swf_GetU30(tag);
1030     DEBUG printf("%d namespace sets\n", num_namespaces);
1031     for(t=1;t<num_sets;t++) {
1032         int count = swf_GetU30(tag);
1033         int s;
1034         const char**name = malloc(sizeof(const char*)*count);
1035         int l = 0;
1036         for(s=0;s<count;s++) {
1037             int nsnr = swf_GetU30(tag);
1038             name[s] = dict_getstr(pool->namespaces, nsnr);
1039             l += strlen(name[s])+1;
1040         }
1041         char*desc = malloc(l+16);
1042         strcpy(desc, "{");
1043         for(s=0;s<count;s++) {
1044             strcat(desc, name[s]);
1045             strcat(desc, ",");
1046         }
1047         strcat(desc, "}");
1048         dict_append(pool->namespace_sets, desc, 0);
1049         DEBUG printf("set %d) %s\n", t, desc);
1050     }
1051
1052     int num_multinames = swf_GetU30(tag);
1053     DEBUG printf("%d multinames\n", num_multinames);
1054     for(t=1;t<num_multinames;t++) {
1055         U8 type = swf_GetU8(tag);
1056         char*mname = 0;
1057         if(type==0x07 || type==0x0d) {
1058             int nr1 = swf_GetU30(tag);
1059             const char*namespace = dict_getstr(pool->namespaces, nr1);
1060             U8 access = (U8)(int)dict_getdata(pool->namespaces, nr1);
1061             const char*methodname = dict_getstr(pool->strings, swf_GetU30(tag));
1062             DEBUG printf("multiname %d) <%s> %s:%s\n", t, access2str(access), namespace, methodname);
1063             mname = malloc(strlen(namespace)+strlen(methodname)+300);
1064             sprintf(mname, "[%s]\0", access2str(access));
1065             strcat(mname, namespace);
1066             strcat(mname, ":");
1067             strcat(mname, methodname);
1068         } else if(type==0x0f || type==0x10) {
1069             const char*methodname = dict_getstr(pool->strings, swf_GetU30(tag));
1070             mname = strdup(methodname);
1071         } else if(type==0x11 || type==0x12) {
1072             mname = strdup("");
1073         } else if(type==0x09 || type==0x0e) {
1074             const char*methodname = dict_getstr(pool->strings, swf_GetU30(tag));
1075             const char*namespace = dict_getstr(pool->namespace_sets, swf_GetU30(tag));
1076             DEBUG printf("multiname %d) %s:%s\n", t, namespace, methodname);
1077             mname = malloc(strlen(namespace)+strlen(methodname)+16);
1078             strcpy(mname, namespace);
1079             strcat(mname, ":");
1080             strcat(mname, methodname);
1081         } else if(type==0x1b || type==0x1c) {
1082             const char*nsset = dict_getstr(pool->namespace_sets, swf_GetU30(tag));
1083             mname = strdup(nsset);
1084         } else {
1085             printf("can't parse type %d multinames yet\n", type);
1086             return;
1087         }
1088         dict_append(pool->multinames, mname, 0);
1089         free(mname);
1090     }
1091     
1092     int num_methods = swf_GetU30(tag);
1093     DEBUG printf("%d methods\n", num_methods);
1094     for(t=0;t<num_methods;t++) {
1095         abc_method_t*m = malloc(sizeof(abc_method_t));
1096         memset(m, 0, sizeof(*m));
1097         m->param_count = swf_GetU30(tag);
1098         m->return_type_index = swf_GetU30(tag);
1099         m->index = t;
1100         int s;
1101         int params_len = 256;
1102         char* params = malloc(params_len);
1103         params[0]='(';
1104         params[1]=0;
1105         for(s=0;s<m->param_count;s++) {
1106             int typenr = swf_GetU30(tag);
1107             if(s < sizeof(m->params)/sizeof(m->params[0]))
1108                 m->params[s] = typenr;
1109             const char*type = dict_getstr(pool->multinames, typenr);
1110             while(strlen(type)+strlen(params)>params_len-4) {
1111                 params_len+=256;
1112                 params = realloc(params, params_len);
1113             }
1114             if(s)
1115                 strcat(params, ", ");
1116             strcat(params, type);
1117         }
1118         strcat(params, ")");
1119         int namenr = swf_GetU30(tag);
1120         m->name = "";
1121         if(namenr)
1122             m->name = dict_getstr(pool->strings, namenr);
1123         m->paramstr=strdup(params);
1124         free(params);params = 0;
1125
1126         m->flags = swf_GetU8(tag);
1127         
1128         DEBUG printf("method %d) %s flags=%02x\n", t, m->paramstr, m->flags);
1129
1130         if(m->flags&0x08) {
1131             /* optional parameters */
1132             int num = swf_GetU30(tag);
1133             int s;
1134             for(s=0;s<num;s++) {
1135                 int val = swf_GetU30(tag);
1136                 U8 kind = swf_GetU8(tag); // specifies index type for "val"
1137             }
1138         }
1139         if(m->flags&0x80) {
1140             printf("can't parse param names yet\n");
1141             return;
1142         }
1143         dict_append(pool->methods, m->name, m);
1144     }
1145             
1146     parse_metadata(tag, pool);
1147         
1148     /* skip classes, and scripts for now, and do the real parsing later */
1149     int num_classes = swf_GetU30(tag);
1150     int classes_pos = tag->pos;
1151     DEBUG printf("%d classes\n", num_classes);
1152     for(t=0;t<num_classes;t++) {
1153         DEBUG printf("class %d\n", t);
1154         swf_GetU30(tag); //classname
1155         swf_GetU30(tag); //supername
1156         U8 flags = swf_GetU8(tag);
1157         if(flags&8) 
1158             swf_GetU30(tag); //protectedNS
1159         int inum = swf_GetU30(tag); //interface count
1160         int s;
1161         for(s=0;s<inum;s++) {
1162             const char*interface = dict_getstr(pool->multinames, swf_GetU30(tag));
1163             DEBUG printf("  class %d interface: %s\n", t, interface);
1164         }
1165         swf_GetU30(tag); //iinit
1166         if(!parse_traits("", tag, pool, 0))
1167             return;
1168     }
1169     for(t=0;t<num_classes;t++) {
1170         swf_GetU30(tag); //cinit
1171         if(!parse_traits("", tag, pool, 0))
1172             return;
1173     }
1174     int num_scripts = swf_GetU30(tag);
1175     DEBUG printf("%d scripts\n", num_scripts);
1176     for(t=0;t<num_scripts;t++) {
1177         int init = swf_GetU30(tag);
1178         if(!parse_traits("", tag, pool, 0))
1179             return;
1180     }
1181
1182     int num_method_bodies = swf_GetU30(tag);
1183     DEBUG printf("%d method bodies\n", num_method_bodies);
1184     for(t=0;t<num_method_bodies;t++) {
1185         int methodnr = swf_GetU30(tag);
1186         if(methodnr >= pool->methods->num) {
1187             printf("Invalid method number: %d\n", methodnr);
1188             return;
1189         }
1190         abc_method_t*m = (abc_method_t*)dict_getdata(pool->methods, methodnr);
1191         abc_code_t*c = malloc(sizeof(abc_code_t));
1192         memset(c, 0, sizeof(abc_code_t));
1193         c->max_stack = swf_GetU30(tag);
1194         c->local_count = swf_GetU30(tag);
1195         c->init_scope_depth = swf_GetU30(tag);
1196         c->max_scope_depth = swf_GetU30(tag);
1197         int code_length = swf_GetU30(tag);
1198         c->method = m;
1199         m->method_body_index = t;
1200
1201         c->tag = swf_InsertTag(0,0);
1202
1203         swf_CopyData(c->tag, tag, code_length);
1204
1205         int exception_count = swf_GetU30(tag);
1206         int s;
1207         for(s=0;s<exception_count;s++) {
1208             swf_GetU30(tag); //from
1209             swf_GetU30(tag); //to
1210             swf_GetU30(tag); //target
1211             swf_GetU30(tag); //exc_type
1212             swf_GetU30(tag); //var_name
1213         }
1214         c->traits = parse_traits("<method body trait>", tag, pool, 1);
1215         if(!c->traits) {
1216             return;
1217         }
1218         DEBUG printf("method_body %d) (method %d), %d bytes of code", t, methodnr, code_length);
1219         int r,l = code_length>32?32:code_length;
1220         for(r=0;r<l;r++) {
1221             DEBUG printf("%02x ", c->tag->data[r]);
1222         }
1223         DEBUG printf("\n");
1224
1225         dict_append(pool->method_bodies, 0, c);
1226     }
1227     if(tag->len - tag->pos) {
1228         printf("%d unparsed bytes remaining in ABC block\n", tag->len - tag->pos);
1229         return;
1230     }
1231
1232     swf_SetTagPos(tag, classes_pos);
1233     for(t=0;t<num_classes;t++) {
1234         abc_class_t*cls = malloc(sizeof(abc_class_t));
1235         memset(cls, 0, sizeof(abc_class_t));
1236         const char* classname = dict_getstr(pool->multinames, swf_GetU30(tag));
1237         const char* supername = dict_getstr(pool->multinames, swf_GetU30(tag));
1238         cls->name = classname;
1239         U8 flags = swf_GetU8(tag);
1240         const char*ns = "";
1241         if(flags&8) {
1242             cls->ns_index = swf_GetU30(tag);
1243             ns = dict_getstr(pool->namespaces, cls->ns_index);
1244         }
1245         printf("class %s extends %s, %s, flags=%02x\n", classname, supername, ns, flags);
1246         printf("{\n");
1247         
1248         int num_interfaces = swf_GetU30(tag); //interface count
1249         int s;
1250         for(s=0;s<num_interfaces;s++) {
1251             swf_GetU30(tag); // multiname index TODO
1252         }
1253         cls->iinit = swf_GetU30(tag);
1254         dump_method("    ","constructor", classname, cls->iinit, pool);
1255         cls->traits = parse_traits("    ",tag, pool, 1);
1256         if(!cls->traits) {
1257             return;
1258         }
1259         printf("}\n");
1260         dict_append(pool->classes, 0, cls);
1261     }
1262     for(t=0;t<num_classes;t++) {
1263         int cinit = swf_GetU30(tag);
1264         dump_method("    ","staticconstructor", "", cinit, pool);
1265         if(!parse_traits("    ",tag, pool, 1))
1266             return;
1267     }
1268     int num_scripts2 = swf_GetU30(tag);
1269     printf("\n");
1270     for(t=0;t<num_scripts2;t++) {
1271         int init = swf_GetU30(tag);
1272         dump_method("","initmethod", "init", init, pool);
1273         if(!parse_traits("", tag, pool, 1))
1274             return;
1275     }
1276 }
1277
1278 static int registerNameSpace(abc_file_t*file, U8 access, char*name) {
1279     if(access==0) { // autodetect access
1280         char*n = strdup(name);
1281         if(n[0] == '[') {
1282             char*bracket = strchr(n, ']');
1283             if(bracket) {
1284                 *bracket = 0;
1285                 char*a = n+1;
1286                 name += (bracket-n)+1;
1287                 if(!strcmp(a, "")) access=0x16;
1288                 else if(!strcmp(a, "package")) access=0x16;
1289                 else if(!strcmp(a, "packageinternal")) access=0x17;
1290                 else if(!strcmp(a, "protected")) access=0x18;
1291                 else if(!strcmp(a, "explicit")) access=0x19;
1292                 else if(!strcmp(a, "staticprotected")) access=0x1a;
1293                 else if(!strcmp(a, "private")) access=0x05;
1294                 else {
1295                     fprintf(stderr, "Undefined access level: [%s]\n", a);
1296                     return -1;
1297                 }
1298             }
1299         } else {
1300             access = 0x16;
1301         }
1302         free(n);
1303     }
1304     int t;
1305     for(t=0;t<file->namespaces->num;t++) {
1306         const char*name2 = dict_getstr(file->namespaces, t);
1307         U8 access2 = (U8)(int)dict_getdata(file->namespaces, t);
1308         if(access == access2 && !strcmp(name, name2)) {
1309             return t;
1310         }
1311     }
1312     dict_update(file->strings, name, 0);
1313     return dict_append(file->namespaces, name, (void*)(int)access);
1314 }
1315 int abc_RegisterNameSpace(abc_file_t*file, char*name) {
1316     return registerNameSpace(file, 0x08, name);
1317 }
1318 int abc_RegisterPackageNameSpace(abc_file_t*file, char*name) {
1319     return registerNameSpace(file, 0x16 , name);
1320 }
1321 int abc_RegisterPackageInternalNameSpace(abc_file_t*file, char*name) {
1322     return registerNameSpace(file, 0x17, name);
1323 }
1324 int abc_RegisterProtectedNameSpace(abc_file_t*file, char*name) {
1325     return registerNameSpace(file, 0x18, name);
1326 }
1327 int abc_RegisterExplicitNameSpace(abc_file_t*file, char*name) {
1328     return registerNameSpace(file, 0x19, name);
1329 }
1330 int abc_RegisterStaticProtectedNameSpace(abc_file_t*file, char*name) {
1331     return registerNameSpace(file, 0x1a, name);
1332 }
1333 int abc_RegisterPrivateNameSpace(abc_file_t*file, char*name) {
1334     return registerNameSpace(file, 0x05, name);
1335 }
1336 static int multiname_index(abc_file_t*abc, const char*name2) 
1337 {
1338     if(!name2)
1339         name2 = ":";
1340     int pos = dict_find(abc->multinames, name2);
1341     if(pos>=0)
1342         return pos;
1343
1344     int access = 0x16;
1345     char*n = strdup(name2);
1346     char*p = strchr(n, ':');
1347     char*namespace=0,*name=0;
1348     if(!p) {
1349         namespace = "";
1350         name = n;
1351     } else {
1352         *p = 0;
1353         namespace = n;
1354         name = p+1;
1355     }
1356     abc_multiname_t*m = malloc(sizeof(abc_multiname_t));
1357     m->namespace_index = registerNameSpace(abc, 0, namespace);
1358     m->name_index = dict_append_if_new(abc->strings, name, 0);
1359     return dict_append(abc->multinames, name2, m);
1360 }
1361
1362 abc_class_t* abc_NewClass(abc_file_t*abc, char*classname, char*superclass) {
1363     abc_class_t* c = malloc(sizeof(abc_class_t));
1364     memset(c, 0, sizeof(abc_class_t));
1365     c->index = dict_append(abc->classes, 0, c);
1366     c->abc = abc;
1367     c->name = strdup(classname);
1368     c->classname_index = multiname_index(abc, classname);
1369     c->superclass_index = multiname_index(abc, superclass);
1370     c->ns_index = abc_RegisterProtectedNameSpace(abc, classname);
1371     c->iinit = -1;
1372     c->cinit = -1;
1373
1374     c->traits = dict_new();
1375     return c;
1376 }
1377
1378 abc_code_t* add_method(abc_file_t*abc, abc_class_t*cls, char*returntype, char*name, int num_params, va_list va)
1379 {
1380     /* construct code (method body) object */
1381     abc_code_t* c = malloc(sizeof(abc_code_t));
1382     memset(c, 0, sizeof(abc_code_t));
1383     c->index = dict_append(abc->method_bodies, 0, c);
1384     c->tag = swf_InsertTag(0,0);
1385     c->abc = abc;
1386     c->traits = dict_new();
1387
1388     /* construct method object */
1389     abc_method_t* m = malloc(sizeof(abc_method_t));
1390     memset(m, 0, sizeof(abc_method_t));
1391     m->param_count = num_params;
1392     m->index = dict_append(abc->methods, 0, m);
1393     if(returntype) 
1394         m->return_type_index = multiname_index(abc, returntype);
1395     else
1396         m->return_type_index = 0;
1397     if(num_params>sizeof(m->params)/sizeof(m->params[0])) {
1398         fprintf(stderr, "abc: Too many parameters\n");
1399         return 0;
1400     }
1401     int t;
1402     for(t=0;t<num_params;t++) {
1403         const char*param = va_arg(va, const char*);
1404         m->params[t] = multiname_index(abc, param);
1405     }
1406
1407     /* crosslink the two objects */
1408     m->method_body_index = c->index;
1409     c->method = m;
1410
1411     return c;
1412 }
1413
1414 abc_code_t* abc_AddConstructor(abc_class_t*cls, char*returntype, int num_params, ...) 
1415 {
1416     va_list va;
1417     va_start(va, num_params);
1418     abc_code_t* c = add_method(cls->abc, cls, returntype, 0, num_params, va);
1419     va_end(va);
1420     cls->iinit = c->index;
1421     return c;
1422 }
1423
1424 abc_code_t* abc_AddStaticConstructor(abc_class_t*cls, char*returntype, int num_params, ...) 
1425 {
1426     va_list va;
1427     va_start(va, num_params);
1428     abc_code_t* c = add_method(cls->abc, cls, returntype, 0, num_params, va);
1429     va_end(va);
1430     cls->cinit = c->index;
1431     return c;
1432 }
1433
1434 abc_trait_t*trait_new(int type, int name_index, int data1, int data2, int vindex, int vkind)
1435 {
1436     abc_trait_t*trait = malloc(sizeof(abc_trait_t));
1437     memset(trait, 0, sizeof(abc_trait_t));
1438     trait->type = type;
1439     trait->name_index = name_index;
1440     trait->data1 = data1;
1441     trait->data2 = data2;
1442     trait->vindex = vindex;
1443     trait->vkind = vkind;
1444     return trait;
1445 }
1446
1447 abc_code_t* abc_AddMethod(abc_class_t*cls, char*returntype, char*name, int num_params, ...) 
1448 {
1449     abc_file_t*abc = cls->abc;
1450     va_list va;
1451     va_start(va, num_params);
1452     abc_code_t* c = add_method(cls->abc, cls, returntype, name, num_params, va);
1453     va_end(va);
1454     dict_append(cls->traits, 0, trait_new(TRAIT_METHOD, multiname_index(abc, name), 0, c->method->index, 0, 0));
1455     return c;
1456 }
1457
1458 void abc_AddSlot(abc_class_t*cls, char*name, int slot, char*multiname)
1459 {
1460     abc_file_t*abc = cls->abc;
1461     int i = multiname_index(abc, name);
1462     dict_append(cls->traits, 0, trait_new(TRAIT_SLOT, i, slot, multiname_index(abc, multiname), 0, 0));
1463 }
1464
1465 void abc_code_addClassTrait(abc_code_t*code, char*multiname, int slotid, abc_class_t*cls)
1466 {
1467     abc_file_t*abc = code->abc;
1468     int i = multiname_index(abc, multiname);
1469     abc_trait_t*trait = trait_new(TRAIT_CLASS, i, slotid, cls->index, 0, 0);
1470     dict_append(code->traits, 0, trait);
1471 }
1472
1473 abc_code_t* abc_AddInitScript(abc_file_t*abc, char*returntype, int num_params, ...) 
1474 {
1475     va_list va;
1476     va_start(va, num_params);
1477     abc_code_t* c = add_method(abc, 0, returntype, 0, num_params, va);
1478     dict_append(abc->scripts, 0, c);
1479     va_end(va);
1480     return c;
1481 }
1482
1483 void swf_SetU30(TAG*tag, U32 u)
1484 {
1485     do {
1486         swf_SetU8(tag, (u&~0x7f?0x80:0) | (u&0x7F));
1487         u>>=7;
1488     } while(u);
1489 }
1490 void swf_SetU30String(TAG*tag, const char*str)
1491 {
1492     int l = strlen(str);
1493     swf_SetU30(tag, l);
1494     swf_SetBlock(tag, (void*)str, l);
1495 }
1496
1497 static void write_traits(abc_file_t*abc, TAG*tag, dict_t*traits)
1498 {
1499     swf_SetU30(tag, traits->num);
1500     int s;
1501
1502     for(s=0;s<traits->num;s++) {
1503         abc_trait_t*trait = (abc_trait_t*)dict_getdata(traits, s);
1504         swf_SetU30(tag, trait->name_index);
1505         swf_SetU8(tag, trait->type);
1506         swf_SetU30(tag, trait->data1);
1507         swf_SetU30(tag, trait->data2);
1508         if(trait->type == 0) { //slot
1509             swf_SetU30(tag, trait->vindex);
1510             if(trait->vindex) {
1511                 swf_SetU8(tag, trait->vkind);
1512             }
1513         }
1514     }
1515 }
1516
1517 void swf_WriteABC(TAG*tag, abc_file_t*abc)
1518 {
1519     swf_SetU32(tag, 1);
1520     swf_SetU8(tag, 0);
1521     swf_SetU16(tag, 0x10);
1522     swf_SetU16(tag, 0x2e);
1523     swf_SetU30(tag, abc->ints->num>1?abc->ints->num:0);
1524     // ...
1525     swf_SetU30(tag, abc->uints->num>1?abc->uints->num:0);
1526     // ...
1527     swf_SetU30(tag, abc->floats->num>1?abc->floats->num:0);
1528     // ...
1529     swf_SetU30(tag, abc->strings->num>1?abc->strings->num:0);
1530     int t;
1531     for(t=1;t<abc->strings->num;t++) {
1532         swf_SetU30String(tag, dict_getstr(abc->strings, t));
1533     }
1534     swf_SetU30(tag, abc->namespaces->num>1?abc->namespaces->num:0);
1535     for(t=1;t<abc->namespaces->num;t++) {
1536         U8 type = (U8)(int)dict_getdata(abc->namespaces, t);
1537         const char*name = dict_getstr(abc->namespaces, t);
1538         int i = dict_find(abc->strings, name);
1539         if(i<0) {
1540             fprintf(stderr, "Couldn't find namespace \"%s\" in constant pool\n", name);
1541             return;
1542         }
1543         swf_SetU8(tag, type);
1544         swf_SetU30(tag, i);
1545     }
1546     swf_SetU30(tag, abc->sets->num>1?abc->sets->num:0);
1547     // ...
1548
1549     swf_SetU30(tag, abc->multinames->num>1?abc->multinames->num:0);
1550     // ...
1551     for(t=1;t<abc->multinames->num;t++) {
1552         abc_multiname_t*m = (abc_multiname_t*)dict_getdata(abc->multinames, t);
1553         swf_SetU8(tag, 0x07);
1554         swf_SetU30(tag, m->namespace_index);
1555         swf_SetU30(tag, m->name_index);
1556     }
1557     
1558     swf_SetU30(tag, abc->methods->num);
1559     for(t=0;t<abc->methods->num;t++) {
1560         abc_method_t*m = (abc_method_t*)dict_getdata(abc->methods, t);
1561         swf_SetU30(tag, m->param_count);
1562         swf_SetU30(tag, m->return_type_index);
1563         int s;
1564         for(s=0;s<m->param_count;s++) {
1565             swf_SetU30(tag, m->params[s]);
1566         }
1567         swf_SetU30(tag, 0); // name
1568         swf_SetU8(tag, 0); //flags
1569     }
1570
1571     swf_SetU30(tag, 0);//metadata
1572
1573     swf_SetU30(tag, abc->classes->num);
1574
1575     for(t=0;t<abc->classes->num;t++) {
1576         abc_class_t*c = (abc_class_t*)dict_getdata(abc->classes, t);
1577         swf_SetU30(tag, c->classname_index);
1578         swf_SetU30(tag, c->superclass_index);
1579
1580         swf_SetU8(tag, 8); // flags
1581         swf_SetU30(tag, c->ns_index);
1582
1583         swf_SetU30(tag, 0); // no interfaces
1584         if(c->iinit<0) {
1585             fprintf(stderr, "Error: Class %s has no constructor\n", c->name);
1586             return;
1587         }
1588         swf_SetU30(tag, c->iinit);
1589         write_traits(abc, tag, c->traits);
1590     }
1591     for(t=0;t<abc->classes->num;t++) {
1592         abc_class_t*c = (abc_class_t*)dict_getdata(abc->classes, t);
1593         if(c->cinit<0) {
1594             fprintf(stderr, "Error: Class %s has no constructor\n", c->name);
1595             return;
1596         }
1597         swf_SetU30(tag, c->cinit);
1598         swf_SetU30(tag, 0); // no traits
1599     }
1600
1601     swf_SetU30(tag, abc->scripts->num);
1602     for(t=0;t<abc->scripts->num;t++) {
1603         abc_code_t*c = (abc_code_t*)dict_getdata(abc->scripts, t);
1604         swf_SetU30(tag, c->index); //!=t!
1605         write_traits(abc, tag, c->traits);
1606     }
1607
1608     swf_SetU30(tag, abc->method_bodies->num);
1609     for(t=0;t<abc->method_bodies->num;t++) {
1610         abc_code_t*c = (abc_code_t*)dict_getdata(abc->method_bodies, t);
1611         abc_method_t*m = c->method;
1612         swf_SetU30(tag, m->index);
1613         swf_SetU30(tag, c->max_stack);
1614         swf_SetU30(tag, c->local_count);
1615         swf_SetU30(tag, c->init_scope_depth);
1616         swf_SetU30(tag, c->max_scope_depth);
1617         swf_SetU30(tag, c->tag->len);
1618         swf_SetBlock(tag, c->tag->data, c->tag->len);
1619         swf_SetU30(tag, c->exception_count);
1620         swf_SetU8(tag, 0); // no traits
1621     }
1622 }
1623
1624 #include "swfabc_ops.c"
1625
1626 void swf_AddButtonLinks(TAG*tag)
1627 {
1628     abc_file_t*abc = abc_file_new();
1629     abc_code_t*c = 0;
1630     
1631     abc_class_t*maintimeline = abc_NewClass(abc, "buttonmitlink_fla:MainTimeline", "flash.display:MovieClip");
1632     
1633     c = abc_AddStaticConstructor(maintimeline, 0, 0);
1634     c->max_stack = 1;
1635     c->local_count = 1;
1636     c->init_scope_depth = 9;
1637     c->max_scope_depth = 10;
1638     abc_getlocal_0(c);
1639     abc_pushscope(c);
1640     abc_returnvoid(c);
1641     
1642     c = abc_AddMethod(maintimeline, 0, "[packageinternal]buttonmitlink_fla:frame1", 0);
1643     c->max_stack = 3;
1644     c->local_count = 1;
1645     c->init_scope_depth = 10;
1646     c->max_scope_depth = 11;
1647     abc_getlocal_0(c);
1648     abc_pushscope(c);
1649     abc_returnvoid(c);
1650     
1651     abc_AddSlot(maintimeline, ":MyButton1", 0, "flash.display:SimpleButton");
1652     abc_AddSlot(maintimeline, ":MyButton2", 0, "flash.display:SimpleButton");
1653
1654     c = abc_AddMethod(maintimeline, ":void", ":gotoPage2", 1, "flash.events:MouseEvent");
1655     c->max_stack = 3;
1656     c->local_count = 2;
1657     c->init_scope_depth = 10;
1658     c->max_scope_depth = 11;
1659     abc_getlocal_0(c);
1660     abc_pushscope(c);
1661     abc_findpropstrict(c, "flash.net:navigateToURL");
1662     abc_findpropstrict(c, "flash.net:URLRequest");
1663     abc_pushstring(c, "http://www.quiss.org");
1664     abc_constructprop(c, "flash.net:URLRequest", 1);
1665     abc_callpropvoid(c, "flash.net:navigateToURL", 1);
1666     abc_returnvoid(c);
1667     
1668     c = abc_AddMethod(maintimeline, ":void", ":gotoPage1", 1, "flash.events:MouseEvent");
1669     c->max_stack = 3;
1670     c->local_count = 2;
1671     c->init_scope_depth = 10;
1672     c->max_scope_depth = 11;
1673     abc_getlocal_0(c);
1674     abc_pushscope(c);
1675     abc_findpropstrict(c,"flash.net:navigateToURL");
1676     abc_findpropstrict(c,"flash.net:URLRequest");
1677     abc_pushstring(c,"http://www.google.com/");
1678     abc_constructprop(c,"flash.net:URLRequest", 1);
1679     abc_callpropvoid(c,"flash.net:navigateToURL", 1);
1680     abc_returnvoid(c);
1681     
1682     c = abc_AddConstructor(maintimeline, 0, 0);
1683     c->max_stack = 3;
1684     c->local_count = 1;
1685     c->init_scope_depth = 10;
1686     c->max_scope_depth = 11;
1687
1688     abc_getlocal_0(c);
1689     abc_pushscope(c);
1690
1691     abc_getlocal_0(c);
1692     abc_constructsuper(c,0);
1693     abc_findpropstrict(c,":addFrameScript");
1694     abc_pushbyte(c,0x00);
1695     abc_getlex(c,"[packageinternal]buttonmitlink_fla:frame1");
1696     abc_callpropvoid(c,":addFrameScript",2);
1697
1698     abc_getlex(c,":MyButton1");
1699     abc_getlex(c,"flash.events:MouseEvent");
1700     abc_getproperty(c, ":CLICK");
1701     abc_getlex(c, ":gotoPage1");
1702     abc_callpropvoid(c, ":addEventListener" ,2);
1703
1704     abc_getlex(c,":MyButton2");
1705     abc_getlex(c,"flash.events:MouseEvent");
1706     abc_getproperty(c, ":CLICK");
1707     abc_getlex(c,":gotoPage2");
1708     abc_callpropvoid(c,":addEventListener",2);
1709
1710     abc_returnvoid(c);
1711     
1712     c = abc_AddInitScript(abc, 0, 0);
1713     c->max_stack = 2;
1714     c->local_count = 1;
1715     c->init_scope_depth = 1;
1716     c->max_scope_depth = 9;
1717     abc_getlocal_0(c);
1718     abc_pushscope(c);
1719     abc_getscopeobject(c, 0);
1720     abc_getlex(c,":Object");
1721     abc_pushscope(c);
1722     abc_getlex(c,"flash.events:EventDispatcher");
1723     abc_pushscope(c);
1724     abc_getlex(c,"flash.display:DisplayObject");
1725     abc_pushscope(c);
1726     abc_getlex(c,"flash.display:InteractiveObject");
1727     abc_pushscope(c);
1728     abc_getlex(c,"flash.display:DisplayObjectContainer");
1729     abc_pushscope(c);
1730     abc_getlex(c,"flash.display:Sprite");
1731     abc_pushscope(c);
1732     abc_getlex(c,"flash.display:MovieClip");
1733     abc_pushscope(c);
1734     abc_getlex(c,"flash.display:MovieClip");
1735     abc_newclass(c,maintimeline);
1736     abc_popscope(c);
1737     abc_popscope(c);
1738     abc_popscope(c);
1739     abc_popscope(c);
1740     abc_popscope(c);
1741     abc_popscope(c);
1742     abc_popscope(c);
1743     abc_initproperty(c,"buttonmitlink_fla:MainTimeline");
1744     abc_returnvoid(c);
1745
1746     abc_code_addClassTrait(c, "buttonmitlink_fla:MainTimeline", 1, maintimeline);
1747
1748     swf_WriteABC(tag, abc);
1749 }