more horizontal refactoring
[swftools.git] / lib / modules / swfscripts.c
1 /* swfscripts.c
2
3    AVM2 Utility Actionscripts
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
363
364
365
366
367
368