removed duplicate opcodes
[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 {0x19, "ifstricteq", "j"},
654 {0x1a, "ifstrictne", "j"},
655 {0x11, "iftrue", "j"},
656 {0xb4, "in", ""},
657 {0x92, "inclocal", "u"},
658 {0xc2, "inclocal_i", "u"},
659 {0x91, "increment", ""},
660 {0xc0, "increment_i", ""},
661 {0x68, "initproperty", "2"},
662 {0xb1, "instanceof", ""},
663 {0xb2, "istype", "2"},
664 {0xb3, "istypelate", ""},
665 {0x10, "jump", "j"},
666 {0x08, "kill", "u"},
667 {0x09, "label", ""},
668 {0xae, "lessequals", ""},
669 {0xad, "lessthan", ""},
670 {0x1b, "lookupswitch", "S"},
671 {0xa5, "lshift", ""},
672 {0xa4, "modulo", ""},
673 {0xa2, "multiply", ""},
674 {0xc7, "multiply_i", ""},
675 {0x90, "negate", ""},
676 {0xc4, "negate_i", ""},
677 {0x57, "newactivation", ""},
678 {0x56, "newarray", "u"},
679 {0x5a, "newcatch", "u"}, //index into exception_info
680 {0x58, "newclass", "c"}, //index into class_info
681 {0x40, "newfunction", "u"}, //index into method_info
682 {0x55, "newobject", "u"},
683 {0x1e, "nextname", ""},
684 {0x23, "nextvalue", ""},
685 {0x02, "nop", ""},
686 {0x96, "not", ""},
687 {0x29, "pop", ""},
688 {0x1d, "popscope", ""},
689 {0x24, "pushbyte", "b"},
690 {0x2f, "pushdouble", "u"}, //index into floats
691 {0x27, "pushfalse", ""},
692 {0x2d, "pushint", "u"}, //index into ints
693 {0x31, "pushnamespace", "u"}, //index into namespace
694 {0x28, "pushnan", ""},
695 {0x20, "pushnull", ""},
696 {0x30, "pushscope", ""},
697 {0x25, "pushshort", "u"},
698 {0x2c, "pushstring", "s"},
699 {0x26, "pushtrue", ""},
700 {0x2e, "pushuint", "u"}, //index into uints
701 {0x21, "pushundefined", ""},
702 {0x1c, "pushwith", ""},
703 {0x48, "returnvalue", ""},
704 {0x47, "returnvoid", ""},
705 {0xa6, "rshift", ""},
706 {0x63, "setlocal", "u"},
707 {0xd4, "setlocal_0", ""},
708 {0xd5, "setlocal_1", ""},
709 {0xd6, "setlocal_2", ""},
710 {0xd7, "setlocal_3", ""},
711 {0x6f, "setglobalshot", "u"},
712 {0x61, "setproperty", "2"},
713 {0x6d, "setslot", "u"},
714 {0x05, "setsuper", "2"},
715 {0xac, "strictequals", ""},
716 {0xa1, "subtract", ""},
717 {0xc6, "subtract_i", ""},
718 {0x2b, "swap", ""},
719 {0x03, "throw", ""},
720 {0x95, "typeof", ""},
721 {0xa7, "urshift", ""},
722 {0xb0, "xxx", ""},
723 };
724
725 int swf_GetU24(TAG*tag)
726 {
727     int b1 = swf_GetU8(tag);
728     int b2 = swf_GetU8(tag);
729     int b3 = swf_GetU8(tag);
730     return b3<<16|b2<<8|b1;
731 }
732 static int parse_code(TAG*tag, int len, abc_file_t*pool, char*prefix)
733 {
734     int end=tag->pos+len;
735     while(tag->pos<end) {
736         U8 opcode = swf_GetU8(tag);
737         int t;
738         char found = 0;
739         for(t=0;t<sizeof(opcodes)/sizeof(opcodes[0]);t++) {
740             if(opcodes[t].opcode == opcode) {
741                 printf("%s%s ", prefix, opcodes[t].name);
742                 char*p = opcodes[t].params;
743                 char first = 1;
744                 while(*p) {
745                     if(!first)
746                         printf(", ");
747                     if(*p == 'n') {
748                         int n = swf_GetU30(tag);
749                         printf("%d params", n);
750                     } else if(*p == '2') {
751                         const char* m = dict_getstr(pool->multinames, swf_GetU30(tag));
752                         printf("%s", m);
753                     } else if(*p == 'm') {
754                         int n = swf_GetU30(tag);
755                         printf("[method%d]", n);
756                     } else if(*p == 'c') {
757                         int n = swf_GetU30(tag);
758                         printf("[classinfo%d]", n);
759                     } else if(*p == 'i') {
760                         int n = swf_GetU30(tag);
761                         printf("[methodbody%d]", n);
762                     } else if(*p == 'u') {
763                         int n = swf_GetU30(tag);
764                         printf("%d", n);
765                     } else if(*p == 'b') {
766                         int b = swf_GetU8(tag);
767                         printf("%02x", b);
768                     } else if(*p == 'j') {
769                         printf("%d", swf_GetU24(tag));
770                     } else if(*p == 's') {
771                         const char*s = dict_getstr(pool->strings, swf_GetU30(tag));
772                         printf("\"%s\"", s);
773                     } else if(*p == 'S') {
774                         swf_GetU24(tag); //default
775                         int num = swf_GetU30(tag)+1;
776                         int t;
777                         for(t=0;t<num;t++) 
778                             swf_GetU24(tag);
779                     } else {
780                         printf("Can't parse opcode param type \"%c\"\n", *p);
781                         return 0;
782                     }
783                     p++;
784                     first = 0;
785                 }
786                 found = 1;
787                 break;
788             }
789         }
790         if(!found) {
791             printf("Can't parse opcode %02x\n", opcode);
792             return 0;
793         }
794         printf("\n");
795     }
796     if(tag->pos!=end) {
797         printf("Read beyond end of ABC Bytecode\n");
798         return 0;
799     }
800     return 1;
801 }
802
803 static void dump_method(const char*prefix, const char*type, const char*name, int nr, abc_file_t*pool)
804 {
805     if(nr >= pool->methods->num) {
806         printf("Invalid method number: %d\n", nr);
807         return;
808     }
809     abc_method_t*m = (abc_method_t*)dict_getdata(pool->methods, nr);
810     printf("%s%s %s %s%s\n", prefix, type, dict_getstr(pool->multinames,m->return_type_index), name, m->paramstr);
811
812     abc_code_t*c = (abc_code_t*)dict_getdata(pool->method_bodies, m->method_body_index);
813     
814     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);
815
816     swf_SetTagPos(c->tag, 0);
817     char prefix2[80];
818     sprintf(prefix2, "%s    ", prefix);
819     printf("%s{\n", prefix);
820     parse_code(c->tag, c->tag->len, pool,prefix2);
821     printf("%s}\n", prefix);
822 }
823
824 //#define DEBUG
825 #define DEBUG if(0)
826
827 static void parse_metadata(TAG*tag, abc_file_t*pool)
828 {
829     int t;
830     int num_metadata = swf_GetU30(tag);
831     DEBUG printf("%d metadata\n");
832     for(t=0;t<num_metadata;t++) {
833         const char*name = dict_getstr(pool->strings, swf_GetU30(tag));
834         int num = swf_GetU30(tag);
835         int s;
836         DEBUG printf("  %s\n", name);
837         for(s=0;s<num;s++) {
838             const char*key = dict_getstr(pool->strings, swf_GetU30(tag));
839             const char*value = dict_getstr(pool->strings, swf_GetU30(tag));
840             DEBUG printf("    %s=%s\n", key, value);
841         }
842     }
843 }
844
845 #define TRAIT_SLOT 0
846 #define TRAIT_METHOD 1
847 #define TRAIT_GETTER 2
848 #define TRAIT_SETTER 3
849 #define TRAIT_CLASS 4
850 #define TRAIT_FUNCTION 5
851 static dict_t* parse_traits(char*prefix, TAG*tag, abc_file_t*pool, char print)
852 {
853     int num_traits = swf_GetU30(tag);
854     dict_t*traits = dict_new();
855     int t;
856     if(num_traits) {
857         DEBUG printf("%d traits\n", num_traits);
858     }
859     for(t=0;t<num_traits;t++) {
860         abc_trait_t*trait = malloc(sizeof(abc_trait_t));
861         memset(trait, 0, sizeof(abc_trait_t));
862         dict_append(traits, 0, trait);
863         int name_index = swf_GetU30(tag);
864         const char*name = dict_getstr(pool->multinames, name_index);
865         U8 kind = swf_GetU8(tag);
866         U8 attributes = kind&0xf0;
867         kind&=0x0f;
868         DEBUG printf("  trait %d) %s type=%02x\n", t, name, kind);
869         if(kind == 1 || kind == 2 || kind == 3) { // method / getter / setter
870             int disp_id = swf_GetU30(tag);
871             int nr = swf_GetU30(tag);
872             DEBUG printf("  %smethod %d %d %s\n", prefix, nr, disp_id, ((abc_method_t*)dict_getdata(pool->methods, nr))->paramstr);
873             if(print) dump_method(prefix, kind==1?"method":(kind==2?"getter":"setter"), name, nr, pool);
874         } else if(kind == 5) { // function
875             int slot_id = swf_GetU30(tag);
876             int nr = swf_GetU30(tag);
877             if(print) dump_method(prefix, "function", name, nr, pool);
878         } else if(kind == 4) { // class
879             int slot_id = swf_GetU30(tag);
880             int cls = swf_GetU30(tag);
881             if(print) printf("  %sclass %s %d %d\n", prefix, name, slot_id, cls);
882         } else if(kind == 0 || kind == 6) { // slot, const
883             int slot_id = swf_GetU30(tag);
884             const char*type_name = dict_getstr(pool->multinames, swf_GetU30(tag));
885             int vindex = swf_GetU30(tag);
886             if(vindex) {
887                 U8 vkind = swf_GetU8(tag);
888             }
889             if(print) printf("  %sslot %s %d %s (vindex=%d)\n", prefix, name, slot_id, type_name, vindex);
890         } else {
891             printf("    can't parse trait type %d\n", kind);
892             return 0;
893         }
894         if(attributes&0x40) {
895             int num = swf_GetU30(tag);
896             int s;
897             for(s=0;s<num;s++) {
898                 swf_GetU30(tag); //index into metadata array
899             }
900         }
901     }
902     return traits;
903 }
904
905 void swf_CopyData(TAG*to, TAG*from, int len)
906 {
907     unsigned char*data = malloc(len);
908     swf_GetBlock(from, data, len);
909     swf_SetBlock(to, data, len);
910     free(data);
911 }
912
913 abc_file_t*abc_file_new()
914 {
915     abc_file_t*f = malloc(sizeof(abc_file_t));
916     memset(f, 0, sizeof(abc_file_t));
917
918     f->ints = dict_new();
919     dict_append(f->ints, 0, (void*)0);
920     f->uints = dict_new();
921     dict_append(f->uints, 0, (void*)0);
922     f->floats = dict_new();
923     dict_append(f->floats, 0, 0);
924     f->strings = dict_new();
925     dict_append(f->strings, "--<UNDEFINED>--", 0);
926     f->namespaces = dict_new();
927     dict_append(f->namespaces, "--<UNDEFINED>--", 0);
928     f->namespace_sets = dict_new();
929     dict_append(f->namespace_sets, "--<UNDEFINED>--", 0);
930     f->sets = dict_new();
931     dict_append(f->sets, "--<UNDEFINED>--", 0);
932     f->multinames = dict_new();
933     dict_append(f->multinames, "--<UNDEFINED>--", 0);
934
935     // abc_file
936
937     f->methods = dict_new();
938     f->classes = dict_new();
939     f->scripts = dict_new();
940     f->method_bodies = dict_new();
941
942     return f;
943 }
944
945 static char* access2str(int type)
946 {
947     if(type==0x08) return "";
948     else if(type==0x16) return "package";
949     else if(type==0x17) return "packageinternal";
950     else if(type==0x18) return "protected";
951     else if(type==0x19) return "explicit";
952     else if(type==0x1A) return "staticprotected";
953     else if(type==0x05) return "private";
954     else return "undefined";
955 }
956
957 void swf_DissassembleABC(TAG*tag)
958 {
959     abc_file_t* pool = abc_file_new();
960
961     swf_SetTagPos(tag, 0);
962     U32 flags = swf_GetU32(tag);
963     int t;
964     DEBUG printf("flags=%08x\n", flags);
965     char*classname = swf_GetString(tag);
966     U32 version = swf_GetU32(tag);
967     if(version!=0x002e0010) {
968         fprintf(stderr, "Warning: unknown AVM2 version %08x\n", version);
969     }
970
971     int num_ints = swf_GetU30(tag);
972     DEBUG printf("%d ints\n", num_ints);
973     for(t=1;t<num_ints;t++) {
974         S32 v = swf_GetU30(tag);
975         DEBUG printf("int %d) %d\n", t, v);
976         dict_append(pool->ints, 0, (void*)v);
977     }
978
979     int num_uints = swf_GetU30(tag);
980     DEBUG printf("%d uints\n", num_uints);
981     for(t=1;t<num_uints;t++) {
982         U32 v = swf_GetS30(tag);
983         DEBUG printf("uint %d) %d\n", t, v);
984         dict_append(pool->uints, 0, (void*)v);
985     }
986     
987     int num_floats = swf_GetU30(tag);
988     DEBUG printf("%d floats\n", num_floats);
989     for(t=1;t<num_floats;t++) {
990         double d = swf_GetD64(tag);
991         DEBUG printf("float %d) %f\n", t, d);
992         dict_append(pool->floats, 0, 0);
993     }
994     
995     int num_strings = swf_GetU30(tag);
996     DEBUG printf("%d strings\n", num_strings);
997     for(t=1;t<num_strings;t++) {
998         int len = swf_GetU30(tag);
999         char*s = malloc(len+1);
1000         swf_GetBlock(tag, s, len);
1001         s[len] = 0;
1002         dict_append(pool->strings, s, 0);
1003         DEBUG printf("%d) \"%s\"\n", t, pool->strings->d[t].name);
1004     }
1005     int num_namespaces = swf_GetU30(tag);
1006     DEBUG printf("%d namespaces\n", num_namespaces);
1007     for(t=1;t<num_namespaces;t++) {
1008         U8 type = swf_GetU8(tag);
1009         int namenr = swf_GetU30(tag);
1010         const char*name = dict_getstr(pool->strings, namenr);
1011         dict_append(pool->namespaces, name, (void*)(int)type);
1012         int w = 0;
1013         DEBUG w=1;
1014         if(w) {
1015             if(type==0x08) printf("Namespace %s\n", name);
1016             else if(type==0x16) printf("PackageNamespace %s\n", name);
1017             else if(type==0x17) printf("PackageInternalNs %s\n", name);
1018             else if(type==0x18) printf("ProtectedNamespace %s\n", name);
1019             else if(type==0x19) printf("ExplicitNamespace %s\n", name);
1020             else if(type==0x1A) printf("StaticProtectedNs %s\n", name);
1021             else if(type==0x05) printf("PrivateNs %s\n", name);
1022             else {
1023                 printf("Undefined namespace type\n");
1024                 return;
1025             }
1026         }
1027     }
1028     int num_sets = swf_GetU30(tag);
1029     DEBUG printf("%d namespace sets\n", num_namespaces);
1030     for(t=1;t<num_sets;t++) {
1031         int count = swf_GetU30(tag);
1032         int s;
1033         const char**name = malloc(sizeof(const char*)*count);
1034         int l = 0;
1035         for(s=0;s<count;s++) {
1036             int nsnr = swf_GetU30(tag);
1037             name[s] = dict_getstr(pool->namespaces, nsnr);
1038             l += strlen(name[s])+1;
1039         }
1040         char*desc = malloc(l+16);
1041         strcpy(desc, "{");
1042         for(s=0;s<count;s++) {
1043             strcat(desc, name[s]);
1044             strcat(desc, ",");
1045         }
1046         strcat(desc, "}");
1047         dict_append(pool->namespace_sets, desc, 0);
1048         DEBUG printf("set %d) %s\n", t, desc);
1049     }
1050
1051     int num_multinames = swf_GetU30(tag);
1052     DEBUG printf("%d multinames\n", num_multinames);
1053     for(t=1;t<num_multinames;t++) {
1054         U8 type = swf_GetU8(tag);
1055         char*mname = 0;
1056         if(type==0x07 || type==0x0d) {
1057             int nr1 = swf_GetU30(tag);
1058             const char*namespace = dict_getstr(pool->namespaces, nr1);
1059             U8 access = (U8)(int)dict_getdata(pool->namespaces, nr1);
1060             const char*methodname = dict_getstr(pool->strings, swf_GetU30(tag));
1061             DEBUG printf("multiname %d) <%s> %s:%s\n", t, access2str(access), namespace, methodname);
1062             mname = malloc(strlen(namespace)+strlen(methodname)+300);
1063             sprintf(mname, "[%s]\0", access2str(access));
1064             strcat(mname, namespace);
1065             strcat(mname, ":");
1066             strcat(mname, methodname);
1067         } else if(type==0x0f || type==0x10) {
1068             const char*methodname = dict_getstr(pool->strings, swf_GetU30(tag));
1069             mname = strdup(methodname);
1070         } else if(type==0x11 || type==0x12) {
1071             mname = strdup("");
1072         } else if(type==0x09 || type==0x0e) {
1073             const char*methodname = dict_getstr(pool->strings, swf_GetU30(tag));
1074             const char*namespace = dict_getstr(pool->namespace_sets, swf_GetU30(tag));
1075             DEBUG printf("multiname %d) %s:%s\n", t, namespace, methodname);
1076             mname = malloc(strlen(namespace)+strlen(methodname)+16);
1077             strcpy(mname, namespace);
1078             strcat(mname, ":");
1079             strcat(mname, methodname);
1080         } else if(type==0x1b || type==0x1c) {
1081             const char*nsset = dict_getstr(pool->namespace_sets, swf_GetU30(tag));
1082             mname = strdup(nsset);
1083         } else {
1084             printf("can't parse type %d multinames yet\n", type);
1085             return;
1086         }
1087         dict_append(pool->multinames, mname, 0);
1088         free(mname);
1089     }
1090     
1091     int num_methods = swf_GetU30(tag);
1092     DEBUG printf("%d methods\n", num_methods);
1093     for(t=0;t<num_methods;t++) {
1094         abc_method_t*m = malloc(sizeof(abc_method_t));
1095         memset(m, 0, sizeof(*m));
1096         m->param_count = swf_GetU30(tag);
1097         m->return_type_index = swf_GetU30(tag);
1098         m->index = t;
1099         int s;
1100         int params_len = 256;
1101         char* params = malloc(params_len);
1102         params[0]='(';
1103         params[1]=0;
1104         for(s=0;s<m->param_count;s++) {
1105             int typenr = swf_GetU30(tag);
1106             if(s < sizeof(m->params)/sizeof(m->params[0]))
1107                 m->params[s] = typenr;
1108             const char*type = dict_getstr(pool->multinames, typenr);
1109             while(strlen(type)+strlen(params)>params_len-4) {
1110                 params_len+=256;
1111                 params = realloc(params, params_len);
1112             }
1113             if(s)
1114                 strcat(params, ", ");
1115             strcat(params, type);
1116         }
1117         strcat(params, ")");
1118         int namenr = swf_GetU30(tag);
1119         m->name = "";
1120         if(namenr)
1121             m->name = dict_getstr(pool->strings, namenr);
1122         m->paramstr=strdup(params);
1123         free(params);params = 0;
1124
1125         m->flags = swf_GetU8(tag);
1126         
1127         DEBUG printf("method %d) %s flags=%02x\n", t, m->paramstr, m->flags);
1128
1129         if(m->flags&0x08) {
1130             /* optional parameters */
1131             int num = swf_GetU30(tag);
1132             int s;
1133             for(s=0;s<num;s++) {
1134                 int val = swf_GetU30(tag);
1135                 U8 kind = swf_GetU8(tag); // specifies index type for "val"
1136             }
1137         }
1138         if(m->flags&0x80) {
1139             printf("can't parse param names yet\n");
1140             return;
1141         }
1142         dict_append(pool->methods, m->name, m);
1143     }
1144             
1145     parse_metadata(tag, pool);
1146         
1147     /* skip classes, and scripts for now, and do the real parsing later */
1148     int num_classes = swf_GetU30(tag);
1149     int classes_pos = tag->pos;
1150     DEBUG printf("%d classes\n", num_classes);
1151     for(t=0;t<num_classes;t++) {
1152         DEBUG printf("class %d\n", t);
1153         swf_GetU30(tag); //classname
1154         swf_GetU30(tag); //supername
1155         U8 flags = swf_GetU8(tag);
1156         if(flags&8) 
1157             swf_GetU30(tag); //protectedNS
1158         int inum = swf_GetU30(tag); //interface count
1159         int s;
1160         for(s=0;s<inum;s++) {
1161             const char*interface = dict_getstr(pool->multinames, swf_GetU30(tag));
1162             DEBUG printf("  class %d interface: %s\n", t, interface);
1163         }
1164         swf_GetU30(tag); //iinit
1165         if(!parse_traits("", tag, pool, 0))
1166             return;
1167     }
1168     for(t=0;t<num_classes;t++) {
1169         swf_GetU30(tag); //cinit
1170         if(!parse_traits("", tag, pool, 0))
1171             return;
1172     }
1173     int num_scripts = swf_GetU30(tag);
1174     DEBUG printf("%d scripts\n", num_scripts);
1175     for(t=0;t<num_scripts;t++) {
1176         int init = swf_GetU30(tag);
1177         if(!parse_traits("", tag, pool, 0))
1178             return;
1179     }
1180
1181     int num_method_bodies = swf_GetU30(tag);
1182     DEBUG printf("%d method bodies\n", num_method_bodies);
1183     for(t=0;t<num_method_bodies;t++) {
1184         int methodnr = swf_GetU30(tag);
1185         if(methodnr >= pool->methods->num) {
1186             printf("Invalid method number: %d\n", methodnr);
1187             return;
1188         }
1189         abc_method_t*m = (abc_method_t*)dict_getdata(pool->methods, methodnr);
1190         abc_code_t*c = malloc(sizeof(abc_code_t));
1191         memset(c, 0, sizeof(abc_code_t));
1192         c->max_stack = swf_GetU30(tag);
1193         c->local_count = swf_GetU30(tag);
1194         c->init_scope_depth = swf_GetU30(tag);
1195         c->max_scope_depth = swf_GetU30(tag);
1196         int code_length = swf_GetU30(tag);
1197         c->method = m;
1198         m->method_body_index = t;
1199
1200         c->tag = swf_InsertTag(0,0);
1201
1202         swf_CopyData(c->tag, tag, code_length);
1203
1204         int exception_count = swf_GetU30(tag);
1205         int s;
1206         for(s=0;s<exception_count;s++) {
1207             swf_GetU30(tag); //from
1208             swf_GetU30(tag); //to
1209             swf_GetU30(tag); //target
1210             swf_GetU30(tag); //exc_type
1211             swf_GetU30(tag); //var_name
1212         }
1213         c->traits = parse_traits("<method body trait>", tag, pool, 1);
1214         if(!c->traits) {
1215             return;
1216         }
1217         DEBUG printf("method_body %d) (method %d), %d bytes of code", t, methodnr, code_length);
1218         int r,l = code_length>32?32:code_length;
1219         for(r=0;r<l;r++) {
1220             DEBUG printf("%02x ", c->tag->data[r]);
1221         }
1222         DEBUG printf("\n");
1223
1224         dict_append(pool->method_bodies, 0, c);
1225     }
1226     if(tag->len - tag->pos) {
1227         printf("%d unparsed bytes remaining in ABC block\n", tag->len - tag->pos);
1228         return;
1229     }
1230
1231     swf_SetTagPos(tag, classes_pos);
1232     for(t=0;t<num_classes;t++) {
1233         abc_class_t*cls = malloc(sizeof(abc_class_t));
1234         memset(cls, 0, sizeof(abc_class_t));
1235         const char* classname = dict_getstr(pool->multinames, swf_GetU30(tag));
1236         const char* supername = dict_getstr(pool->multinames, swf_GetU30(tag));
1237         cls->name = classname;
1238         U8 flags = swf_GetU8(tag);
1239         const char*ns = "";
1240         if(flags&8) {
1241             cls->ns_index = swf_GetU30(tag);
1242             ns = dict_getstr(pool->namespaces, cls->ns_index);
1243         }
1244         printf("class %s extends %s, %s, flags=%02x\n", classname, supername, ns, flags);
1245         printf("{\n");
1246         
1247         int num_interfaces = swf_GetU30(tag); //interface count
1248         int s;
1249         for(s=0;s<num_interfaces;s++) {
1250             swf_GetU30(tag); // multiname index TODO
1251         }
1252         cls->iinit = swf_GetU30(tag);
1253         dump_method("    ","constructor", classname, cls->iinit, pool);
1254         cls->traits = parse_traits("    ",tag, pool, 1);
1255         if(!cls->traits) {
1256             return;
1257         }
1258         printf("}\n");
1259         dict_append(pool->classes, 0, cls);
1260     }
1261     for(t=0;t<num_classes;t++) {
1262         int cinit = swf_GetU30(tag);
1263         dump_method("    ","staticconstructor", "", cinit, pool);
1264         if(!parse_traits("    ",tag, pool, 1))
1265             return;
1266     }
1267     int num_scripts2 = swf_GetU30(tag);
1268     printf("\n");
1269     for(t=0;t<num_scripts2;t++) {
1270         int init = swf_GetU30(tag);
1271         dump_method("","initmethod", "init", init, pool);
1272         if(!parse_traits("", tag, pool, 1))
1273             return;
1274     }
1275 }
1276
1277 static int registerNameSpace(abc_file_t*file, U8 access, char*name) {
1278     if(access==0) { // autodetect access
1279         char*n = strdup(name);
1280         if(n[0] == '[') {
1281             char*bracket = strchr(n, ']');
1282             if(bracket) {
1283                 *bracket = 0;
1284                 char*a = n+1;
1285                 name += (bracket-n)+1;
1286                 if(!strcmp(a, "")) access=0x16;
1287                 else if(!strcmp(a, "package")) access=0x16;
1288                 else if(!strcmp(a, "packageinternal")) access=0x17;
1289                 else if(!strcmp(a, "protected")) access=0x18;
1290                 else if(!strcmp(a, "explicit")) access=0x19;
1291                 else if(!strcmp(a, "staticprotected")) access=0x1a;
1292                 else if(!strcmp(a, "private")) access=0x05;
1293                 else {
1294                     fprintf(stderr, "Undefined access level: [%s]\n", a);
1295                     return -1;
1296                 }
1297             }
1298         } else {
1299             access = 0x16;
1300         }
1301         free(n);
1302     }
1303     int t;
1304     for(t=0;t<file->namespaces->num;t++) {
1305         const char*name2 = dict_getstr(file->namespaces, t);
1306         U8 access2 = (U8)(int)dict_getdata(file->namespaces, t);
1307         if(access == access2 && !strcmp(name, name2)) {
1308             return t;
1309         }
1310     }
1311     dict_update(file->strings, name, 0);
1312     return dict_append(file->namespaces, name, (void*)(int)access);
1313 }
1314 int abc_RegisterNameSpace(abc_file_t*file, char*name) {
1315     return registerNameSpace(file, 0x08, name);
1316 }
1317 int abc_RegisterPackageNameSpace(abc_file_t*file, char*name) {
1318     return registerNameSpace(file, 0x16 , name);
1319 }
1320 int abc_RegisterPackageInternalNameSpace(abc_file_t*file, char*name) {
1321     return registerNameSpace(file, 0x17, name);
1322 }
1323 int abc_RegisterProtectedNameSpace(abc_file_t*file, char*name) {
1324     return registerNameSpace(file, 0x18, name);
1325 }
1326 int abc_RegisterExplicitNameSpace(abc_file_t*file, char*name) {
1327     return registerNameSpace(file, 0x19, name);
1328 }
1329 int abc_RegisterStaticProtectedNameSpace(abc_file_t*file, char*name) {
1330     return registerNameSpace(file, 0x1a, name);
1331 }
1332 int abc_RegisterPrivateNameSpace(abc_file_t*file, char*name) {
1333     return registerNameSpace(file, 0x05, name);
1334 }
1335 static int multiname_index(abc_file_t*abc, const char*name2) 
1336 {
1337     if(!name2)
1338         name2 = ":";
1339     int pos = dict_find(abc->multinames, name2);
1340     if(pos>=0)
1341         return pos;
1342
1343     int access = 0x16;
1344     char*n = strdup(name2);
1345     char*p = strchr(n, ':');
1346     char*namespace=0,*name=0;
1347     if(!p) {
1348         namespace = "";
1349         name = n;
1350     } else {
1351         *p = 0;
1352         namespace = n;
1353         name = p+1;
1354     }
1355     abc_multiname_t*m = malloc(sizeof(abc_multiname_t));
1356     m->namespace_index = registerNameSpace(abc, 0, namespace);
1357     m->name_index = dict_append_if_new(abc->strings, name, 0);
1358     return dict_append(abc->multinames, name2, m);
1359 }
1360
1361 abc_class_t* abc_NewClass(abc_file_t*abc, char*classname, char*superclass) {
1362     abc_class_t* c = malloc(sizeof(abc_class_t));
1363     memset(c, 0, sizeof(abc_class_t));
1364     c->index = dict_append(abc->classes, 0, c);
1365     c->abc = abc;
1366     c->name = strdup(classname);
1367     c->classname_index = multiname_index(abc, classname);
1368     c->superclass_index = multiname_index(abc, superclass);
1369     c->ns_index = abc_RegisterProtectedNameSpace(abc, classname);
1370     c->iinit = -1;
1371     c->cinit = -1;
1372
1373     c->traits = dict_new();
1374     return c;
1375 }
1376
1377 abc_code_t* add_method(abc_file_t*abc, abc_class_t*cls, char*returntype, char*name, int num_params, va_list va)
1378 {
1379     /* construct code (method body) object */
1380     abc_code_t* c = malloc(sizeof(abc_code_t));
1381     memset(c, 0, sizeof(abc_code_t));
1382     c->index = dict_append(abc->method_bodies, 0, c);
1383     c->tag = swf_InsertTag(0,0);
1384     c->abc = abc;
1385     c->traits = dict_new();
1386
1387     /* construct method object */
1388     abc_method_t* m = malloc(sizeof(abc_method_t));
1389     memset(m, 0, sizeof(abc_method_t));
1390     m->param_count = num_params;
1391     m->index = dict_append(abc->methods, 0, m);
1392     if(returntype) 
1393         m->return_type_index = multiname_index(abc, returntype);
1394     else
1395         m->return_type_index = 0;
1396     if(num_params>sizeof(m->params)/sizeof(m->params[0])) {
1397         fprintf(stderr, "abc: Too many parameters\n");
1398         return 0;
1399     }
1400     int t;
1401     for(t=0;t<num_params;t++) {
1402         const char*param = va_arg(va, const char*);
1403         m->params[t] = multiname_index(abc, param);
1404     }
1405
1406     /* crosslink the two objects */
1407     m->method_body_index = c->index;
1408     c->method = m;
1409
1410     return c;
1411 }
1412
1413 abc_code_t* abc_AddConstructor(abc_class_t*cls, char*returntype, int num_params, ...) 
1414 {
1415     va_list va;
1416     va_start(va, num_params);
1417     abc_code_t* c = add_method(cls->abc, cls, returntype, 0, num_params, va);
1418     va_end(va);
1419     cls->iinit = c->index;
1420     return c;
1421 }
1422
1423 abc_code_t* abc_AddStaticConstructor(abc_class_t*cls, char*returntype, int num_params, ...) 
1424 {
1425     va_list va;
1426     va_start(va, num_params);
1427     abc_code_t* c = add_method(cls->abc, cls, returntype, 0, num_params, va);
1428     va_end(va);
1429     cls->cinit = c->index;
1430     return c;
1431 }
1432
1433 abc_trait_t*trait_new(int type, int name_index, int data1, int data2, int vindex, int vkind)
1434 {
1435     abc_trait_t*trait = malloc(sizeof(abc_trait_t));
1436     memset(trait, 0, sizeof(abc_trait_t));
1437     trait->type = type;
1438     trait->name_index = name_index;
1439     trait->data1 = data1;
1440     trait->data2 = data2;
1441     trait->vindex = vindex;
1442     trait->vkind = vkind;
1443     return trait;
1444 }
1445
1446 abc_code_t* abc_AddMethod(abc_class_t*cls, char*returntype, char*name, int num_params, ...) 
1447 {
1448     abc_file_t*abc = cls->abc;
1449     va_list va;
1450     va_start(va, num_params);
1451     abc_code_t* c = add_method(cls->abc, cls, returntype, name, num_params, va);
1452     va_end(va);
1453     dict_append(cls->traits, 0, trait_new(TRAIT_METHOD, multiname_index(abc, name), 0, c->method->index, 0, 0));
1454     return c;
1455 }
1456
1457 void abc_AddSlot(abc_class_t*cls, char*name, int slot, char*multiname)
1458 {
1459     abc_file_t*abc = cls->abc;
1460     int i = multiname_index(abc, name);
1461     dict_append(cls->traits, 0, trait_new(TRAIT_SLOT, i, slot, multiname_index(abc, multiname), 0, 0));
1462 }
1463
1464 void abc_code_addClassTrait(abc_code_t*code, char*multiname, int slotid, abc_class_t*cls)
1465 {
1466     abc_file_t*abc = code->abc;
1467     int i = multiname_index(abc, multiname);
1468     abc_trait_t*trait = trait_new(TRAIT_CLASS, i, slotid, cls->index, 0, 0);
1469     dict_append(code->traits, 0, trait);
1470 }
1471
1472 abc_code_t* abc_AddInitScript(abc_file_t*abc, char*returntype, int num_params, ...) 
1473 {
1474     va_list va;
1475     va_start(va, num_params);
1476     abc_code_t* c = add_method(abc, 0, returntype, 0, num_params, va);
1477     dict_append(abc->scripts, 0, c);
1478     va_end(va);
1479     return c;
1480 }
1481
1482 void swf_SetU30(TAG*tag, U32 u)
1483 {
1484     do {
1485         swf_SetU8(tag, (u&~0x7f?0x80:0) | (u&0x7F));
1486         u>>=7;
1487     } while(u);
1488 }
1489 void swf_SetU30String(TAG*tag, const char*str)
1490 {
1491     int l = strlen(str);
1492     swf_SetU30(tag, l);
1493     swf_SetBlock(tag, (void*)str, l);
1494 }
1495
1496 static void write_traits(abc_file_t*abc, TAG*tag, dict_t*traits)
1497 {
1498     swf_SetU30(tag, traits->num);
1499     int s;
1500
1501     for(s=0;s<traits->num;s++) {
1502         abc_trait_t*trait = (abc_trait_t*)dict_getdata(traits, s);
1503         swf_SetU30(tag, trait->name_index);
1504         swf_SetU8(tag, trait->type);
1505         swf_SetU30(tag, trait->data1);
1506         swf_SetU30(tag, trait->data2);
1507         if(trait->type == 0) { //slot
1508             swf_SetU30(tag, trait->vindex);
1509             if(trait->vindex) {
1510                 swf_SetU8(tag, trait->vkind);
1511             }
1512         }
1513     }
1514 }
1515
1516 void swf_WriteABC(TAG*tag, abc_file_t*abc)
1517 {
1518     swf_SetU32(tag, 1);
1519     swf_SetU8(tag, 0);
1520     swf_SetU16(tag, 0x10);
1521     swf_SetU16(tag, 0x2e);
1522     swf_SetU30(tag, abc->ints->num>1?abc->ints->num:0);
1523     // ...
1524     swf_SetU30(tag, abc->uints->num>1?abc->uints->num:0);
1525     // ...
1526     swf_SetU30(tag, abc->floats->num>1?abc->floats->num:0);
1527     // ...
1528     swf_SetU30(tag, abc->strings->num>1?abc->strings->num:0);
1529     int t;
1530     for(t=1;t<abc->strings->num;t++) {
1531         swf_SetU30String(tag, dict_getstr(abc->strings, t));
1532     }
1533     swf_SetU30(tag, abc->namespaces->num>1?abc->namespaces->num:0);
1534     for(t=1;t<abc->namespaces->num;t++) {
1535         U8 type = (U8)(int)dict_getdata(abc->namespaces, t);
1536         const char*name = dict_getstr(abc->namespaces, t);
1537         int i = dict_find(abc->strings, name);
1538         if(i<0) {
1539             fprintf(stderr, "Couldn't find namespace \"%s\" in constant pool\n", name);
1540             return;
1541         }
1542         swf_SetU8(tag, type);
1543         swf_SetU30(tag, i);
1544     }
1545     swf_SetU30(tag, abc->sets->num>1?abc->sets->num:0);
1546     // ...
1547
1548     swf_SetU30(tag, abc->multinames->num>1?abc->multinames->num:0);
1549     // ...
1550     for(t=1;t<abc->multinames->num;t++) {
1551         abc_multiname_t*m = (abc_multiname_t*)dict_getdata(abc->multinames, t);
1552         swf_SetU8(tag, 0x07);
1553         swf_SetU30(tag, m->namespace_index);
1554         swf_SetU30(tag, m->name_index);
1555     }
1556     
1557     swf_SetU30(tag, abc->methods->num);
1558     for(t=0;t<abc->methods->num;t++) {
1559         abc_method_t*m = (abc_method_t*)dict_getdata(abc->methods, t);
1560         swf_SetU30(tag, m->param_count);
1561         swf_SetU30(tag, m->return_type_index);
1562         int s;
1563         for(s=0;s<m->param_count;s++) {
1564             swf_SetU30(tag, m->params[s]);
1565         }
1566         swf_SetU30(tag, 0); // name
1567         swf_SetU8(tag, 0); //flags
1568     }
1569
1570     swf_SetU30(tag, 0);//metadata
1571
1572     swf_SetU30(tag, abc->classes->num);
1573
1574     for(t=0;t<abc->classes->num;t++) {
1575         abc_class_t*c = (abc_class_t*)dict_getdata(abc->classes, t);
1576         swf_SetU30(tag, c->classname_index);
1577         swf_SetU30(tag, c->superclass_index);
1578
1579         swf_SetU8(tag, 8); // flags
1580         swf_SetU30(tag, c->ns_index);
1581
1582         swf_SetU30(tag, 0); // no interfaces
1583         if(c->iinit<0) {
1584             fprintf(stderr, "Error: Class %s has no constructor\n", c->name);
1585             return;
1586         }
1587         swf_SetU30(tag, c->iinit);
1588         write_traits(abc, tag, c->traits);
1589     }
1590     for(t=0;t<abc->classes->num;t++) {
1591         abc_class_t*c = (abc_class_t*)dict_getdata(abc->classes, t);
1592         if(c->cinit<0) {
1593             fprintf(stderr, "Error: Class %s has no constructor\n", c->name);
1594             return;
1595         }
1596         swf_SetU30(tag, c->cinit);
1597         swf_SetU30(tag, 0); // no traits
1598     }
1599
1600     swf_SetU30(tag, abc->scripts->num);
1601     for(t=0;t<abc->scripts->num;t++) {
1602         abc_code_t*c = (abc_code_t*)dict_getdata(abc->scripts, t);
1603         swf_SetU30(tag, c->index); //!=t!
1604         write_traits(abc, tag, c->traits);
1605     }
1606
1607     swf_SetU30(tag, abc->method_bodies->num);
1608     for(t=0;t<abc->method_bodies->num;t++) {
1609         abc_code_t*c = (abc_code_t*)dict_getdata(abc->method_bodies, t);
1610         abc_method_t*m = c->method;
1611         swf_SetU30(tag, m->index);
1612         swf_SetU30(tag, c->max_stack);
1613         swf_SetU30(tag, c->local_count);
1614         swf_SetU30(tag, c->init_scope_depth);
1615         swf_SetU30(tag, c->max_scope_depth);
1616         swf_SetU30(tag, c->tag->len);
1617         swf_SetBlock(tag, c->tag->data, c->tag->len);
1618         swf_SetU30(tag, c->exception_count);
1619         swf_SetU8(tag, 0); // no traits
1620     }
1621 }
1622
1623 #include "swfabc_ops.c"
1624
1625 void swf_AddButtonLinks(TAG*tag)
1626 {
1627     abc_file_t*abc = abc_file_new();
1628     abc_code_t*c = 0;
1629     
1630     abc_class_t*maintimeline = abc_NewClass(abc, "buttonmitlink_fla:MainTimeline", "flash.display:MovieClip");
1631     
1632     c = abc_AddStaticConstructor(maintimeline, 0, 0);
1633     c->max_stack = 1;
1634     c->local_count = 1;
1635     c->init_scope_depth = 9;
1636     c->max_scope_depth = 10;
1637     abc_getlocal_0(c);
1638     abc_pushscope(c);
1639     abc_returnvoid(c);
1640     
1641     c = abc_AddMethod(maintimeline, 0, "[packageinternal]buttonmitlink_fla:frame1", 0);
1642     c->max_stack = 3;
1643     c->local_count = 1;
1644     c->init_scope_depth = 10;
1645     c->max_scope_depth = 11;
1646     abc_getlocal_0(c);
1647     abc_pushscope(c);
1648     abc_returnvoid(c);
1649     
1650     abc_AddSlot(maintimeline, ":MyButton1", 0, "flash.display:SimpleButton");
1651     abc_AddSlot(maintimeline, ":MyButton2", 0, "flash.display:SimpleButton");
1652
1653     c = abc_AddMethod(maintimeline, ":void", ":gotoPage2", 1, "flash.events:MouseEvent");
1654     c->max_stack = 3;
1655     c->local_count = 2;
1656     c->init_scope_depth = 10;
1657     c->max_scope_depth = 11;
1658     abc_getlocal_0(c);
1659     abc_pushscope(c);
1660     abc_findpropstrict(c, "flash.net:navigateToURL");
1661     abc_findpropstrict(c, "flash.net:URLRequest");
1662     abc_pushstring(c, "http://www.quiss.org");
1663     abc_constructprop(c, "flash.net:URLRequest", 1);
1664     abc_callpropvoid(c, "flash.net:navigateToURL", 1);
1665     abc_returnvoid(c);
1666     
1667     c = abc_AddMethod(maintimeline, ":void", ":gotoPage1", 1, "flash.events:MouseEvent");
1668     c->max_stack = 3;
1669     c->local_count = 2;
1670     c->init_scope_depth = 10;
1671     c->max_scope_depth = 11;
1672     abc_getlocal_0(c);
1673     abc_pushscope(c);
1674     abc_findpropstrict(c,"flash.net:navigateToURL");
1675     abc_findpropstrict(c,"flash.net:URLRequest");
1676     abc_pushstring(c,"http://www.google.com/");
1677     abc_constructprop(c,"flash.net:URLRequest", 1);
1678     abc_callpropvoid(c,"flash.net:navigateToURL", 1);
1679     abc_returnvoid(c);
1680     
1681     c = abc_AddConstructor(maintimeline, 0, 0);
1682     c->max_stack = 3;
1683     c->local_count = 1;
1684     c->init_scope_depth = 10;
1685     c->max_scope_depth = 11;
1686
1687     abc_getlocal_0(c);
1688     abc_pushscope(c);
1689
1690     abc_getlocal_0(c);
1691     abc_constructsuper(c,0);
1692     abc_findpropstrict(c,":addFrameScript");
1693     abc_pushbyte(c,0x00);
1694     abc_getlex(c,"[packageinternal]buttonmitlink_fla:frame1");
1695     abc_callpropvoid(c,":addFrameScript",2);
1696
1697     abc_getlex(c,":MyButton1");
1698     abc_getlex(c,"flash.events:MouseEvent");
1699     abc_getproperty(c, ":CLICK");
1700     abc_getlex(c, ":gotoPage1");
1701     abc_callpropvoid(c, ":addEventListener" ,2);
1702
1703     abc_getlex(c,":MyButton2");
1704     abc_getlex(c,"flash.events:MouseEvent");
1705     abc_getproperty(c, ":CLICK");
1706     abc_getlex(c,":gotoPage2");
1707     abc_callpropvoid(c,":addEventListener",2);
1708
1709     abc_returnvoid(c);
1710     
1711     c = abc_AddInitScript(abc, 0, 0);
1712     c->max_stack = 2;
1713     c->local_count = 1;
1714     c->init_scope_depth = 1;
1715     c->max_scope_depth = 9;
1716     abc_getlocal_0(c);
1717     abc_pushscope(c);
1718     abc_getscopeobject(c, 0);
1719     abc_getlex(c,":Object");
1720     abc_pushscope(c);
1721     abc_getlex(c,"flash.events:EventDispatcher");
1722     abc_pushscope(c);
1723     abc_getlex(c,"flash.display:DisplayObject");
1724     abc_pushscope(c);
1725     abc_getlex(c,"flash.display:InteractiveObject");
1726     abc_pushscope(c);
1727     abc_getlex(c,"flash.display:DisplayObjectContainer");
1728     abc_pushscope(c);
1729     abc_getlex(c,"flash.display:Sprite");
1730     abc_pushscope(c);
1731     abc_getlex(c,"flash.display:MovieClip");
1732     abc_pushscope(c);
1733     abc_getlex(c,"flash.display:MovieClip");
1734     abc_newclass(c,maintimeline);
1735     abc_popscope(c);
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_initproperty(c,"buttonmitlink_fla:MainTimeline");
1743     abc_returnvoid(c);
1744
1745     abc_code_addClassTrait(c, "buttonmitlink_fla:MainTimeline", 1, maintimeline);
1746
1747     swf_WriteABC(tag, abc);
1748 }