1 /*
2 Ming, an SWF output library
3 Copyright (C) 2002 Opaque Industries - http://www.opaque.net/
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19
20 /* $Id$ */
21
22 #ifndef __C2MAN__
23 #include <stdlib.h>
24 #include <string.h>
25 #endif
26
27 #include "action.h"
28 #include "output.h"
29 #include "block.h"
30 #include "input.h"
31 #include "method.h"
32 #include "libming.h"
33 #include "character.h"
34 #include "movieclip.h"
35 #include "actioncompiler/compile.h"
36 #include "actiontypes.h"
37
38 typedef enum {
39 INPUT_EMPTY,
40 INPUT_FILE,
41 INPUT_SCRIPT
42 } ActionInputType;
43
44 struct SWFAction_s
45 {
46 struct SWFBlock_s block;
47 ActionInputType inputType;
48 SWFOutput out;
49 union
50 {
51 FILE *file;
52 char *script;
53 } input;
54 int debug;
55 };
56
57 struct SWFInitAction_s
58 {
59 struct SWFBlock_s block;
60 int spriteId;
61 SWFAction action;
62 SWFMovieClip clip;
63 };
64
readActionFile(FILE * file)65 static char *readActionFile(FILE *file)
66 {
67 int len;
68 char *script;
69 SWFInput input = newSWFInput_file(file);
70 len = SWFInput_length(input);
71 script = (char *)malloc(len + 1);
72 if(SWFInput_read(input, (unsigned char *)script, len) != len)
73 {
74 SWF_warn("readActionFile failed\n");
75 free(script);
76 return NULL;
77 }
78 destroySWFInput(input);
79 script[len] = '\0';
80 return script;
81 }
82
SWFOutput_writeAction(SWFOutput out,SWFAction action)83 void SWFOutput_writeAction(SWFOutput out, SWFAction action)
84 {
85 int len;
86 byte *data;
87
88 if(action->out == NULL)
89 {
90 SWF_warn("SWFAction: compile action first\n");
91 return;
92 }
93
94 len = SWFOutput_getLength(action->out);
95 data = SWFOutput_getBuffer(action->out);
96 SWFOutput_writeBuffer(out, data, len);
97 }
98
99 /*
100 * Compiles the current script stored in this SWFAction instance.
101 * returns 0 on success, -1 otherwise.
102 * the length of the compiled bytecode is storen in the length pointer (if not NULL).
103 */
SWFAction_compile(SWFAction action,int swfVersion,int * length)104 int SWFAction_compile(SWFAction action,
105 int swfVersion /* target SWF version */,
106 int *length /* output length */)
107 {
108 char *script = NULL;
109 Buffer b;
110 int parserError;
111
112 if(action->out != NULL)
113 {
114 if(length != NULL)
115 *length = SWFOutput_getLength(action->out);
116 return 0;
117 }
118
119 switch(action->inputType)
120 {
121 case INPUT_SCRIPT:
122 script = action->input.script;
123 break;
124 case INPUT_FILE:
125 script = readActionFile(action->input.file);
126 break;
127 default: break;
128 }
129
130 if(script != NULL && swfVersion == 4)
131 {
132 swf4ParseInit(script, action->debug, swfVersion);
133 parserError = swf4parse((void *)&b);
134 }
135 else if (script != NULL)
136 {
137 swf5ParseInit(script, action->debug, swfVersion);
138 parserError = swf5parse((void *)&b);
139 }
140 else
141 parserError = 1;
142
143 // if INPUT_FILE script was allocated by readActionFile()
144 if(action->inputType == INPUT_FILE)
145 free(script);
146
147 action->out = newSWFOutput();
148
149 if(!parserError)
150 {
151 SWFOutput_writeBuffer(action->out, b->buffer, bufferLength(b));
152 destroyBuffer(b);
153 }
154 else
155 SWF_warn("Parser error: writing empty block\n");
156
157 SWFOutput_writeUInt8(action->out, SWFACTION_END);
158 if(length != NULL)
159 *length = SWFOutput_getLength(action->out);
160
161 if(parserError)
162 return -1;
163
164 return 0;
165 }
166
167 /*
168 * Returns the compiled bytecode.
169 * If not already compiled the script will compiled for SWF V7.
170 *
171 * Returns NULL in case of an error. Length pointer stores the length of
172 * the compiled bytecode.
173 */
SWFAction_getByteCode(SWFAction action,int * length)174 byte *SWFAction_getByteCode(SWFAction action, int *length)
175 {
176 int ret = 0;
177 if(action == NULL)
178 return NULL;
179
180 if(action->out == NULL)
181 {
182 SWF_warn("SWFAction_getByteCode: please use SWFAction_compile first\n");
183 SWF_warn("auto-compiling as SWF 7 code now...\n");
184 ret = SWFAction_compile(action, 7, (int *)length);
185 }
186
187 if(ret < 0)
188 {
189 *length = -1;
190 return NULL;
191 }
192 return SWFOutput_getBuffer(action->out);
193 }
194
195 static int
completeSWFAction(SWFBlock block)196 completeSWFAction(SWFBlock block)
197 {
198 int length;
199 SWFAction action = (SWFAction)block;
200 SWFAction_compile(action, block->swfVersion, &length);
201 return length;
202 }
203
204 static int
completeSWFInitAction(SWFBlock block)205 completeSWFInitAction(SWFBlock block)
206 {
207 SWFInitAction init = (SWFInitAction)block;
208 int len;
209
210 SWFAction_compile(init->action, block->swfVersion, &len);
211 return len + 2;
212 }
213
214
215 static void
writeSWFActionToMethod(SWFBlock block,SWFByteOutputMethod method,void * data)216 writeSWFActionToMethod(SWFBlock block, SWFByteOutputMethod method, void* data)
217 {
218 SWFOutput out = ((SWFAction)block)->out;
219 SWFOutput_writeToMethod(out, method, data);
220 }
221
222 static void
writeSWFInitActionToMethod(SWFBlock block,SWFByteOutputMethod method,void * data)223 writeSWFInitActionToMethod(SWFBlock block, SWFByteOutputMethod method, void* data)
224 {
225 SWFInitAction init = (SWFInitAction)block;
226 methodWriteUInt16(init->spriteId, method, data);
227 SWFOutput_writeToMethod(init->action->out, method, data);
228 }
229
230 /*
231 * Destroys a SWFAction instance
232 */
destroySWFAction(SWFAction action)233 void destroySWFAction(SWFAction action)
234 {
235 if(!action)
236 return;
237
238 switch(action->inputType)
239 {
240 case INPUT_FILE:
241 fclose(action->input.file);
242 break;
243 case INPUT_SCRIPT:
244 free(action->input.script);
245 break;
246 default:
247 break;
248 }
249
250 if(action->out)
251 destroySWFOutput(action->out);
252
253 free(action);
254 }
255
destroySWFInitAction(SWFInitAction init)256 void destroySWFInitAction(SWFInitAction init)
257 {
258 if(!init)
259 return;
260
261 if(init->clip)
262 destroySWFMovieClip(init->clip);
263 destroySWFAction(init->action);
264 free(init);
265 }
266
267
createEmptyAction()268 static SWFAction createEmptyAction()
269 {
270 SWFAction action = (SWFAction)malloc(sizeof(struct SWFAction_s));
271
272 SWFBlockInit(BLOCK(action));
273 BLOCK(action)->type = SWF_DOACTION;
274 BLOCK(action)->writeBlock = writeSWFActionToMethod;
275 BLOCK(action)->complete = completeSWFAction;
276 BLOCK(action)->dtor = (destroySWFBlockMethod) destroySWFAction;
277 action->inputType = INPUT_EMPTY;
278 action->out = NULL;
279 action->debug = 0;
280 return action;
281 }
282
283 /**
284 * enable verbose compiler output
285 *
286 * Set debug value to 1 get very! verbose compile messages.
287 * @return old value
288 */
SWFAction_setDebug(SWFAction a,int debug)289 int SWFAction_setDebug(SWFAction a, int debug /*debug switch*/)
290 {
291 int oldval;
292 if(!a)
293 return -1;
294 oldval = a->debug;
295 a->debug = debug;
296 return oldval;
297 }
298
299 /*
300 * Creates a new SWFAction object.
301 * Takes a String containing AS[2] source code.
302 *
303 * returns a SWFAction instance.
304 */
newSWFAction(const char * script)305 SWFAction newSWFAction(const char *script)
306 {
307 SWFAction action = createEmptyAction();
308 action->inputType = INPUT_SCRIPT;
309 action->input.script = strdup(script);
310
311 return action;
312 }
313
314 /*
315 * Creates a new SWFAction object.
316 * Takes a filename pointing to a file containing AS[2] source code.
317 *
318 * return a SWFAction instance.
319 */
newSWFAction_fromFile(const char * filename)320 SWFAction newSWFAction_fromFile(const char *filename)
321 {
322 SWFAction action = createEmptyAction();
323 action->inputType = INPUT_FILE;
324 action->input.file = fopen(filename, "r");
325 if(action->input.file == NULL)
326 {
327 destroySWFAction(action);
328 return NULL;
329 }
330 return action;
331 }
332
SWFInitAction_getMovieClip(SWFInitAction action)333 SWFMovieClip SWFInitAction_getMovieClip(SWFInitAction action)
334 {
335 return action->clip;
336 }
337
338 /*
339 * create a InitAction block with a given sprite's character id
340 *
341 * This function creates a InitAction block with a given sprite's character id.
342 * Use with care!
343 */
newSWFInitAction_withId(SWFAction action,int id)344 SWFInitAction newSWFInitAction_withId(SWFAction action, int id /* mc character id */)
345 {
346 SWFInitAction init = (SWFInitAction)malloc(sizeof(struct SWFInitAction_s));
347 SWFBlockInit(BLOCK(init));
348 BLOCK(init)->writeBlock = writeSWFInitActionToMethod;
349 BLOCK(init)->complete = completeSWFInitAction;
350 BLOCK(init)->dtor = (destroySWFBlockMethod) destroySWFInitAction;
351 BLOCK(init)->type = SWF_INITACTION;
352 init->clip = NULL; // use external clip
353 init->spriteId = id;
354 init->action = action;
355 return init;
356 }
357
358 /*
359 * create a InitAction block
360 *
361 * This function creates a InitAction block and defines an empty sprite/mc
362 * which is not placed. This functions is usefull for defining classes.
363 */
newSWFInitAction(SWFAction action)364 SWFInitAction newSWFInitAction(SWFAction action)
365 {
366 SWFInitAction init = (SWFInitAction)malloc(sizeof(struct SWFInitAction_s));
367 SWFBlockInit(BLOCK(init));
368 BLOCK(init)->writeBlock = writeSWFInitActionToMethod;
369 BLOCK(init)->complete = completeSWFInitAction;
370 BLOCK(init)->dtor = (destroySWFBlockMethod) destroySWFInitAction;
371 BLOCK(init)->type = SWF_INITACTION;
372 init->clip = newSWFMovieClip();
373 init->spriteId = CHARACTERID(init->clip);
374 init->action = action;
375 return init;
376 }
377
newSWFInitAction_MovieClip(SWFMovieClip clip,SWFAction action)378 SWFInitAction newSWFInitAction_MovieClip(SWFMovieClip clip, SWFAction action)
379 {
380 SWFInitAction init = (SWFInitAction)malloc(sizeof(struct SWFInitAction_s));
381 SWFBlockInit(BLOCK(init));
382 BLOCK(init)->writeBlock = writeSWFInitActionToMethod;
383 BLOCK(init)->complete = completeSWFInitAction;
384 BLOCK(init)->dtor = (destroySWFBlockMethod) destroySWFInitAction;
385 BLOCK(init)->type = SWF_INITACTION;
386 init->spriteId = CHARACTERID(clip);
387 init->clip = NULL; // use external clip
388 init->action = action;
389 return init;
390 }
391
392 /*
393 * Local variables:
394 * tab-width: 2
395 * c-basic-offset: 2
396 * End:
397 */
398