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