1 /* sswf.c++ -- written by Alexis WILKE for Made to Order Software Corp. (c) 2002-2009 */
2 
3 /*
4 
5 Copyright (c) 2002-2009 Made to Order Software Corp.
6 
7 Permission is hereby granted, free of charge, to any
8 person obtaining a copy of this software and
9 associated documentation files (the "Software"), to
10 deal in the Software without restriction, including
11 without limitation the rights to use, copy, modify,
12 merge, publish, distribute, sublicense, and/or sell
13 copies of the Software, and to permit persons to whom
14 the Software is furnished to do so, subject to the
15 following conditions:
16 
17 The above copyright notice and this permission notice
18 shall be included in all copies or substantial
19 portions of the Software.
20 
21 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
22 ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
23 LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
24 FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
25 EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
27 WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
28 ARISING FROM, OUT OF OR IN CONNECTION WITH THE
29 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30 SOFTWARE.
31 
32 */
33 
34 #define	SSWF_NEED_ASSERT
35 #include	"sswf.h"
36 
37 extern "C" {
38 #include	"sswf_grammar.h"
39 };
40 
41 
42 #include	"sswf/libsswf.h"	 /* get the version and the sswf_version() function */
43 
44 
45 
46 extern	YYLTYPE		yylloc;
47 
48 #ifdef _MSVC
49 YYLTYPE			yylloc;
50 #endif
51 
52 
53 
54 
55 
56 
57 /***************************************************** DOC
58  * NAME
59  *	sswf - create an SWF file from a script
60  *
61  * SYNOPSIS
62  *	sswf [-<opt>] file ...
63  *
64  * DESCRIPTION
65  *	The sswf tool will be used to read a script and transform
66  *	it in a list of tags in an SWF file.
67  *
68  *	The script will be written as a set of unordered objects
69  *	and a set of display lists. The display lists can be
70  *	referenced in the playback sequence or sprites.
71  *
72  *	Because the SWF format is mainly a sequence of events which
73  *	loop, it is important to include a very specific order for
74  *	object definitions and the sequence of events. However, in
75  *	most cases, the computer can take care of that sorting.
76  *
77  *	This tool only uses names for all the objects, lists,
78  *	sequences, etc. making it easy to reference anything
79  *	anywhere.
80  *
81  * OPTIONS
82  *
83  * SEE ALSO
84  *	sswf(1) manual pages
85  *	libsswf.a and libsswf.so
86  *	ScriptSWF.html
87  */
88 
89 
90 struct global_t	global;				/* stuff we want to transmit to sub-functions outside this file */
91 int		errcnt;				/* number of errors found */
92 int		warning_off;			/* if true, don't emit warnings */
93 struct node_t *	top_object;			/* the root object from which we can find all the other objects */
94 const char	no_file[] = "no file";		/* to set the lex_filename when no file is being parsed */
95 const char *	lex_filename = no_file;		/* the filename currently being read by lex */
96 int		show_input_filenames;		/* when true, print out the name of all the input files (useful when it is be searched in the -I directories) */
97 int		show_input_search;		/* if true, show as we search for a file */
98 int		show_output;			/* if true, print out the resulting data buffer */
99 int		show_bounds;			/* if true, insert an additional shape + line to draw a rectangle showing the shape boundaries */
100 int		show_origin;			/* if true, draw two lines to show the origin of the symbol (rotation center if you wish) */
101 #if DEBUG
102 int		debug_memory;			/* if true, print out the unfreed memory before to exit */
103 #endif
104 
105 
106 
107 
108 
109 #if DEBUG
110 #define	TYPE_NAME(type)		{ type, #type },
111 #else
112 #define	TYPE_NAME(type)		{ #type },
113 #endif
114 const struct node_type_names_t	node_type_names[NODE_TYPE_max] =
115 {
116 	TYPE_NAME(NODE_TYPE_UNKNOWN)
117 	TYPE_NAME(NODE_SUBTYPE_UNKNOWN)
118 	TYPE_NAME(NODE_TYPE_IDENTIFIER)
119 	TYPE_NAME(NODE_TYPE_INTEGER)
120 	TYPE_NAME(NODE_TYPE_FLOAT)
121 	TYPE_NAME(NODE_TYPE_RANGE_INTEGER)
122 	TYPE_NAME(NODE_TYPE_RANGE_FLOAT)
123 	TYPE_NAME(NODE_TYPE_STRING)
124 	TYPE_NAME(NODE_TYPE_DATA)
125 	TYPE_NAME(NODE_SUBTYPE_DEFINITION)
126 	TYPE_NAME(NODE_TYPE_DEFINITION)
127 	TYPE_NAME(NODE_TYPE_OPERATOR)
128 	TYPE_NAME(NODE_SUBTYPE_ADD)
129 	TYPE_NAME(NODE_SUBTYPE_AND)
130 	TYPE_NAME(NODE_SUBTYPE_DIVIDE)
131 	TYPE_NAME(NODE_SUBTYPE_EQUAL)
132 	TYPE_NAME(NODE_SUBTYPE_EXPAND)
133 	TYPE_NAME(NODE_SUBTYPE_FIELD)
134 	TYPE_NAME(NODE_SUBTYPE_FUNCTION)
135 	TYPE_NAME(NODE_SUBTYPE_GREATER)
136 	TYPE_NAME(NODE_SUBTYPE_GREATER_EQUAL)
137 	TYPE_NAME(NODE_SUBTYPE_GROUP)
138 	TYPE_NAME(NODE_SUBTYPE_IDENTITY)
139 	TYPE_NAME(NODE_SUBTYPE_LESS)
140 	TYPE_NAME(NODE_SUBTYPE_LESS_EQUAL)
141 	TYPE_NAME(NODE_SUBTYPE_LET)
142 	TYPE_NAME(NODE_SUBTYPE_LOGICAL_AND)
143 	TYPE_NAME(NODE_SUBTYPE_LOGICAL_NOT)
144 	TYPE_NAME(NODE_SUBTYPE_LOGICAL_OR)
145 	TYPE_NAME(NODE_SUBTYPE_LOGICAL_XOR)
146 	TYPE_NAME(NODE_SUBTYPE_MAXIMUM)
147 	TYPE_NAME(NODE_SUBTYPE_MINIMUM)
148 	TYPE_NAME(NODE_SUBTYPE_MODULO)
149 	TYPE_NAME(NODE_SUBTYPE_MULTIPLY)
150 	TYPE_NAME(NODE_SUBTYPE_NEGATE)
151 	TYPE_NAME(NODE_SUBTYPE_NOT)
152 	TYPE_NAME(NODE_SUBTYPE_NOT_EQUAL)
153 	TYPE_NAME(NODE_SUBTYPE_OR)
154 	TYPE_NAME(NODE_SUBTYPE_POWER)
155 	TYPE_NAME(NODE_SUBTYPE_RANGE)
156 	TYPE_NAME(NODE_SUBTYPE_ROTATE_LEFT)
157 	TYPE_NAME(NODE_SUBTYPE_ROTATE_RIGHT)
158 	TYPE_NAME(NODE_SUBTYPE_SELECT)
159 	TYPE_NAME(NODE_SUBTYPE_SHIFT_LEFT)
160 	TYPE_NAME(NODE_SUBTYPE_SHIFT_RIGHT)
161 	TYPE_NAME(NODE_SUBTYPE_SHIFT_RIGHT_UNSIGNED)
162 	TYPE_NAME(NODE_SUBTYPE_SUBSCRIPT)
163 	TYPE_NAME(NODE_SUBTYPE_SUBTRACT)
164 	TYPE_NAME(NODE_SUBTYPE_XOR)
165 	TYPE_NAME(NODE_TYPE_UNIT)
166 	TYPE_NAME(NODE_SUBTYPE_BC)
167 	TYPE_NAME(NODE_SUBTYPE_CM)
168 	TYPE_NAME(NODE_SUBTYPE_DEG)
169 	TYPE_NAME(NODE_SUBTYPE_FC)
170 	TYPE_NAME(NODE_SUBTYPE_FPF)
171 	TYPE_NAME(NODE_SUBTYPE_FPS)
172 	TYPE_NAME(NODE_SUBTYPE_FRM)
173 	TYPE_NAME(NODE_SUBTYPE_GRAD)
174 	TYPE_NAME(NODE_SUBTYPE_IN)
175 	TYPE_NAME(NODE_SUBTYPE_MIN)
176 	TYPE_NAME(NODE_SUBTYPE_PR)
177 	TYPE_NAME(NODE_SUBTYPE_PX)
178 	TYPE_NAME(NODE_SUBTYPE_RAD)
179 	TYPE_NAME(NODE_SUBTYPE_RT)
180 	TYPE_NAME(NODE_SUBTYPE_SEC)
181 	TYPE_NAME(NODE_SUBTYPE_TW)
182 	TYPE_NAME(NODE_SUBTYPE_OTHER)
183 	TYPE_NAME(NODE_TYPE_OBJECT)
184 	TYPE_NAME(NODE_SUBTYPE_ACTION)
185 	TYPE_NAME(NODE_SUBTYPE_ACTION_SCRIPT)
186 	TYPE_NAME(NODE_SUBTYPE_BLOCK)
187 	TYPE_NAME(NODE_SUBTYPE_BUTTON)
188 	TYPE_NAME(NODE_SUBTYPE_CATCH)
189 	TYPE_NAME(NODE_SUBTYPE_COLOR)
190 	TYPE_NAME(NODE_SUBTYPE_COLOR_TRANSFORM)
191 	TYPE_NAME(NODE_SUBTYPE_DO_ACTION)
192 	TYPE_NAME(NODE_SUBTYPE_EDGES)
193 	TYPE_NAME(NODE_SUBTYPE_EDIT_TEXT)
194 	TYPE_NAME(NODE_SUBTYPE_END)
195 	TYPE_NAME(NODE_SUBTYPE_ENVELOPE)
196 	TYPE_NAME(NODE_SUBTYPE_EXPORT)
197 	TYPE_NAME(NODE_SUBTYPE_FILL_STYLE)
198 	TYPE_NAME(NODE_SUBTYPE_FINALLY)
199 	TYPE_NAME(NODE_SUBTYPE_FONT)
200 	TYPE_NAME(NODE_SUBTYPE_FOR)
201 	TYPE_NAME(NODE_SUBTYPE_FRAME_LABEL)
202 	TYPE_NAME(NODE_SUBTYPE_GLYPH)
203 	TYPE_NAME(NODE_SUBTYPE_GRADIENT)
204 	TYPE_NAME(NODE_SUBTYPE_IF)
205 	TYPE_NAME(NODE_SUBTYPE_IMAGE)
206 	TYPE_NAME(NODE_SUBTYPE_IMPORT)
207 	TYPE_NAME(NODE_SUBTYPE_LABEL)
208 	TYPE_NAME(NODE_SUBTYPE_LINE_STYLE)
209 	TYPE_NAME(NODE_SUBTYPE_LIST)
210 	TYPE_NAME(NODE_SUBTYPE_MATRIX)
211 	TYPE_NAME(NODE_SUBTYPE_METADATA)
212 	TYPE_NAME(NODE_SUBTYPE_ON_EVENT)
213 	TYPE_NAME(NODE_SUBTYPE_PLACE_OBJECT)
214 	TYPE_NAME(NODE_SUBTYPE_POINTS)
215 	TYPE_NAME(NODE_SUBTYPE_RECT)
216 	TYPE_NAME(NODE_SUBTYPE_REFERENCE)
217 	TYPE_NAME(NODE_SUBTYPE_REMOVE)
218 	TYPE_NAME(NODE_SUBTYPE_REMOVE_ALL)
219 	TYPE_NAME(NODE_SUBTYPE_REPLACE_OBJECT)
220 	TYPE_NAME(NODE_SUBTYPE_SCENE_FRAME_DATA)
221 	TYPE_NAME(NODE_SUBTYPE_SCRIPT_LIMITS)
222 	TYPE_NAME(NODE_SUBTYPE_SEQUENCE)
223 	TYPE_NAME(NODE_SUBTYPE_SET_BACKGROUND_COLOR)
224 	TYPE_NAME(NODE_SUBTYPE_SET_TAB_INDEX)
225 	TYPE_NAME(NODE_SUBTYPE_SHAPE)
226 	TYPE_NAME(NODE_SUBTYPE_SHOW_FRAME)
227 	TYPE_NAME(NODE_SUBTYPE_SOUND)
228 	TYPE_NAME(NODE_SUBTYPE_SOUND_INFO)
229 	TYPE_NAME(NODE_SUBTYPE_SPRITE)
230 	TYPE_NAME(NODE_SUBTYPE_STATE)
231 	TYPE_NAME(NODE_SUBTYPE_TEXT)
232 	TYPE_NAME(NODE_SUBTYPE_TEXT_SETUP)
233 	TYPE_NAME(NODE_SUBTYPE_TRY)
234 	TYPE_NAME(NODE_SUBTYPE_VARIABLE)
235 	TYPE_NAME(NODE_SUBTYPE_WITH)
236 };
237 
238 
239 
240 #if DEBUG
241 extern "C" {
assert(int cond,const char * format,...)242 void assert(int cond, const char *format, ...)
243 {
244 	va_list		ap;
245 
246 	if(cond) return;	/* no prob. */
247 
248 	va_start(ap, format);
249 	vfprintf(stderr, format, ap);
250 	va_end(ap);
251 	fprintf(stderr, ".\n");
252 
253 	abort();
254 }
255 };
256 //#else
257 //#ifdef _MSVC
258 //extern "C" {
259 //void assert(int cond, const char *format, ...)
260 //{
261 //}
262 //};
263 //#endif
264 #endif
265 
266 
267 
268 
269 
270 
271 #if DEBUG
check_type_names(void)272 void check_type_names(void)
273 {
274 	int		idx;
275 
276 	assert(sizeof(node_type_names) / sizeof(struct node_type_names_t) == NODE_TYPE_max, "the size of the node_type_names table doesn't match the NODE_TYPE_max enumeration counter");
277 	for(idx = 0; idx < NODE_TYPE_max; idx++) {
278 		assert(node_type_names[idx].type == idx, "the type at offset %d doesn't correspond to the expected type (%d)", idx, node_type_names[idx].type);
279 	}
280 }
281 #endif
282 
283 
284 
285 
init_top_object(void)286 void init_top_object(void)
287 {
288 	lex_filename = "*root object*";
289 	top_object = node_alloc(NODE_TYPE_OBJECT, NODE_SUBTYPE_BLOCK, 0);
290 	top_object->left = node_alloc(NODE_TYPE_STRING, NODE_SUBTYPE_UNKNOWN, 0);
291 	top_object->left->string = sswf_strdup("root");
292 	top_object->left->parent = top_object;
293 }
294 
295 
296 
297 
298 #if DEBUG
clean_top_objects(void)299 void clean_top_objects(void)
300 {
301 	//node_print(top_object);		// print out the entire tree of nodes
302 	node_free(top_object);		// remove all the user objects
303 	top_object = NULL;
304 	node_done_object();		// remove the all_objects too
305 }
306 #endif
307 
308 
309 
310 
init_internal_variables(void)311 void init_internal_variables(void)
312 {
313 	set_var("pi", TO_STR(M_PI));
314 	set_var("e", TO_STR(M_E));
315 }
316 
317 
318 
parse(void)319 int parse(void)
320 {
321 	struct node_t	*result;
322 	int		ec;
323 
324 	yylloc.first_line = 1;		/* start from the beginning each time */
325 	ec = yyparse(&result);
326 	if(ec != 0) {
327 		return 1;
328 	}
329 
330 	/* ensure that the top-most nodes have a proper parent field */
331 	node_link_parent(top_object, result);
332 
333 	if(top_object->left == NULL) {
334 		top_object->left = result;
335 	}
336 	else {
337 		node_link_tail(top_object->left, result);
338 	}
339 
340 	return 0;
341 }
342 
343 
344 
345 
346 
check_flag(struct node_t * seq,const char * name,unsigned long flag,int def_value)347 static void check_flag(struct node_t *seq, const char *name, unsigned long flag, int def_value)
348 {
349 	struct node_t			result, *var;
350 	struct node_exec_status_t	status;
351 	int				ec, v;
352 
353 	memset(&status, 0, sizeof(status));
354 	status.unit = NODE_UNIT_UNKNOWN;
355 	status.obj = seq;
356 
357 	var = node_search_list(seq, name);
358 	if(var == NULL) {
359 		return;
360 	}
361 
362 	node_init(&result, NODE_TYPE_UNKNOWN, NODE_TYPE_UNKNOWN);
363 	ec = node_eval(var->right, &result, &status);
364 	if(ec == 0) {
365 		v = def_value;
366 		switch(result.type) {
367 		case NODE_TYPE_INTEGER:
368 			v = result.integer != 0;
369 			break;
370 
371 		case NODE_TYPE_FLOAT:
372 			v = result.floating_point != 0;
373 			break;
374 
375 		case NODE_TYPE_STRING:
376 			v = !(result.string == NULL || result.string[0] == '\0');
377 			break;
378 
379 		default:
380 fprintf(stderr, "ERROR: the protect variable needs to be set to a boolean value.");
381 			errcnt++;
382 			break;
383 
384 		}
385 		if(v) {
386 			global.f_flags |= flag;
387 		}
388 		else {
389 			global.f_flags &= ~flag;
390 		}
391 	}
392 
393 	node_clean(&result, 0);
394 }
395 
396 
evaluate(void)397 int evaluate(void)
398 {
399 	struct node_t			result, fr_result, mv_result, *seq, **l;
400 	struct node_t			*frame_rate_var, *minimum_version, *maximum_version, *version;
401 	struct node_exec_status_t	status;
402 	int				ec, cnt;
403 
404 	if(global.f_show_steps > 0) {
405 		printf("+ Evaluating the scripts.\n");
406 	}
407 
408 	/* put objects in their respective parent object list */
409 	ec = node_setup_objects();
410 	if(ec != 0) {
411 		fprintf(stderr, "ERROR: error #%d occured while setting up the objects.\n", ec);
412 		errcnt++;
413 		return ec;
414 	}
415 
416 	/* search for the main sequence */
417 	seq = node_search_list(top_object, "main");
418 	if(seq == NULL) {
419 		/* search the first sequence object instead */
420 		l = top_object->list;
421 		cnt = top_object->cnt;
422 		while(cnt > 0) {
423 			seq = *l++;
424 			if(seq->type == NODE_TYPE_OBJECT && seq->sub_type == NODE_SUBTYPE_SEQUENCE) {
425 				break;
426 			}
427 			cnt--;
428 		}
429 		if(cnt == 0) {
430 			/* didn't find any sequence! */
431 			fprintf(stderr, "ERROR: can't find a sequence to evaluate as an SWF binary file.\n");
432 			errcnt++;
433 			return 1;
434 		}
435 		if(!warning_off && seq->left != NULL) {
436 fprintf(stderr, "WARNING: using sequence \"%s\" as the main sequence.\n", seq->left->string);
437 		}
438 	}
439 	else if(seq->type != NODE_TYPE_OBJECT || seq->sub_type != NODE_SUBTYPE_SEQUENCE) {
440 		fprintf(stderr, "ERROR: the object named \"main\" is not a sequence. (%d/%d)\n", seq->type, seq->sub_type);
441 		errcnt++;
442 		return 1;
443 	}
444 
445 	/* ready to evaluate, let's go! */
446 	memset(&status, 0, sizeof(status));
447 	status.unit = NODE_UNIT_UNKNOWN;
448 	status.obj = seq;
449 #if 0
450 printf("%%%%%% node_execute()\n");
451 sswf_info_serial();
452 #endif
453 	node_init(&result, NODE_TYPE_UNKNOWN, NODE_TYPE_UNKNOWN);
454 	ec = node_execute(seq, &result, &status);
455 	if(ec != 0) {
456 		fprintf(stderr, "ERROR: error #%d occured while executing the nodes; the process will stop.\n", abs(ec));
457 		errcnt++;
458 		node_clean(&result, 0);
459 		return ec;
460 	}
461 	if(result.type != NODE_TYPE_DATA) {
462 		fprintf(stderr, "ERROR: unexpected result for a sequence object (Type: %d).\n", result.type);
463 		errcnt++;
464 		node_clean(&result, 0);
465 		return 1;
466 	}
467 
468 	if(global.f_show_steps > 0) {
469 		printf("+ The evaluation is finished.\n");
470 	}
471 
472 	/* everything worked now we can nearly save the result in a .swf file! */
473 #if 0
474 printf("%%%%%% define frame rate, protect, compress...\n");
475 sswf_info_serial();
476 #endif
477 	global.f_frame_rate = 30.0;
478 	frame_rate_var = node_search_list(seq, "frame_rate");
479 	if(frame_rate_var == NULL) {
480 		frame_rate_var = node_search_list(seq, "framerate");
481 	}
482 	if(frame_rate_var != NULL) {
483 		status.unit = NODE_UNIT_SPEED;		/* by default we want FPS here */
484 		node_init(&fr_result, NODE_TYPE_UNKNOWN, NODE_TYPE_UNKNOWN);
485 		ec = node_eval(frame_rate_var->right, &fr_result, &status);
486 		if(ec != 0) {
487 			node_clean(&result, 0);
488 			return ec;
489 		}
490 		if(fr_result.type == NODE_TYPE_INTEGER) {
491 			global.f_frame_rate = (double) fr_result.integer;
492 		}
493 		else if(fr_result.type == NODE_TYPE_FLOAT) {
494 			global.f_frame_rate = fr_result.floating_point;
495 		}
496 		else if(fr_result.type == NODE_TYPE_STRING) {
497 			if(strcasecmp(fr_result.string, "PAL") == 0) {
498 				global.f_frame_rate = 25.0;
499 			}
500 			else if(strcasecmp(fr_result.string, "NTSC") == 0) {
501 				global.f_frame_rate = 30.0;
502 			}
503 			else {
504 fprintf(stderr, "ERROR: unknown frame rate (%s).", fr_result.string);
505 				errcnt++;
506 			}
507 		}
508 		else {
509 fprintf(stderr, "ERROR: invalid frame rate value; an integer, a floating point or a string was expected.");
510 			errcnt++;
511 		}
512 		node_clean(&fr_result, 0);
513 	}
514 
515 	global.f_version = 0;
516 	version = node_search_list(seq, "version");
517 	if(version != NULL) {
518 		status.unit = NODE_UNIT_SIZE;		/* there isn't really any unit for this one */
519 		node_init(&mv_result, NODE_TYPE_UNKNOWN, NODE_TYPE_UNKNOWN);
520 		ec = node_eval(version->right, &mv_result, &status);
521 		if(ec != 0) {
522 			node_clean(&result, 0);
523 			return ec;
524 		}
525 		if(mv_result.type == NODE_TYPE_INTEGER) {
526 			global.f_version = mv_result.integer;
527 		}
528 		else if(mv_result.type == NODE_TYPE_FLOAT) {
529 			global.f_version = (int) rint(mv_result.floating_point);
530 		}
531 		else {
532 fprintf(stderr, "ERROR: invalid version value; an integer or a a floating point was expected.");
533 			errcnt++;
534 		}
535 		node_clean(&mv_result, 0);
536 		if(global.f_version < 0) {
537 fprintf(stderr, "ERROR: invalid version; it has to be 1 or more.\n");
538 			errcnt++;
539 		}
540 	}
541 
542 
543 	global.f_minimum_version = 0;
544 	minimum_version = node_search_list(seq, "minimum_version");
545 	if(minimum_version == NULL) {
546 		minimum_version = node_search_list(seq, "minimumversion");
547 	}
548 	if(minimum_version != NULL) {
549 		status.unit = NODE_UNIT_SIZE;		/* there isn't really any unit for this one */
550 		node_init(&mv_result, NODE_TYPE_UNKNOWN, NODE_TYPE_UNKNOWN);
551 		ec = node_eval(minimum_version->right, &mv_result, &status);
552 		if(ec != 0) {
553 			node_clean(&result, 0);
554 			return ec;
555 		}
556 		if(mv_result.type == NODE_TYPE_INTEGER) {
557 			global.f_minimum_version = mv_result.integer;
558 		}
559 		else if(mv_result.type == NODE_TYPE_FLOAT) {
560 			global.f_minimum_version = (int) rint(mv_result.floating_point);
561 		}
562 		else {
563 fprintf(stderr, "ERROR: invalid minimum version value; an integer or a a floating point was expected.");
564 			errcnt++;
565 		}
566 		node_clean(&mv_result, 0);
567 		if(global.f_minimum_version < 0) {
568 fprintf(stderr, "ERROR: invalid minimum version; it has to be 1 or more.\n");
569 			errcnt++;
570 		}
571 	}
572 
573 	global.f_maximum_version = 0;
574 	maximum_version = node_search_list(seq, "maximum_version");
575 	if(maximum_version == NULL) {
576 		maximum_version = node_search_list(seq, "maximumversion");
577 	}
578 	if(maximum_version != NULL) {
579 		status.unit = NODE_UNIT_SIZE;		/* there isn't really any unit for this one */
580 		node_init(&mv_result, NODE_TYPE_UNKNOWN, NODE_TYPE_UNKNOWN);
581 		ec = node_eval(maximum_version->right, &mv_result, &status);
582 		if(ec != 0) {
583 			node_clean(&result, 0);
584 			return ec;
585 		}
586 		if(mv_result.type == NODE_TYPE_INTEGER) {
587 			global.f_maximum_version = mv_result.integer;
588 		}
589 		else if(mv_result.type == NODE_TYPE_FLOAT) {
590 			global.f_maximum_version = (int) rint(mv_result.floating_point);
591 		}
592 		else {
593 fprintf(stderr, "ERROR: invalid maximum version value; an integer or a a floating point was expected.");
594 			errcnt++;
595 		}
596 		node_clean(&mv_result, 0);
597 		if(global.f_maximum_version < 0) {
598 fprintf(stderr, "ERROR: invalid maximum version; it has to be 1 or more.\n");
599 			errcnt++;
600 		}
601 	}
602 
603 
604 	if(global.f_minimum_version != 0 && global.f_maximum_version != 0
605 	&& global.f_minimum_version > global.f_maximum_version) {
606 fprintf(stderr, "ERROR: the minimum version cannot be larger than the maximum version.\n");
607 		errcnt++;
608 	}
609 	if(global.f_version != 0) {
610 		if((global.f_minimum_version != 0 && global.f_version < global.f_minimum_version)
611 		     || (global.f_maximum_version != 0 && global.f_version > global.f_maximum_version)) {
612 fprintf(stderr, "ERROR: version must be defined between the minimum and maximum versions.\n");
613 			errcnt++;
614 		}
615 	}
616 
617 
618 
619 	check_flag(seq, "protect",  GLOBAL_FLAG_PROTECT,  true);
620 
621 	/*
622 	 * Try with and without the '_'; we expect the users to have
623 	 * only one such flag anyway.
624 	 * For security reasons, this flag is assumed to be false
625 	 * by default. It anyway has no effect on older movies
626 	 * (version 7 or less).
627 	 */
628 	check_flag(seq, "usenetwork",  GLOBAL_FLAG_USE_NETWORK,  false);
629 	check_flag(seq, "use_network",  GLOBAL_FLAG_USE_NETWORK,  false);
630 
631 	/*
632 	 * The default for the compression flag should be true if the
633 	 * movie is to be saved in a V6 Flash movie binary file
634 	 */
635 	check_flag(seq, "compress", GLOBAL_FLAG_COMPRESS, false);
636 
637 	if(show_output) {
638 		node_print_data(result.data);
639 	}
640 
641 	if(global.f_show_steps) {
642 		printf("+ Save the resulting SWF file.\n");
643 	}
644 
645 	/* we don't want to save if any error occured */
646 	if(errcnt > 0) {
647 		ec = 1;
648 	}
649 	else {
650 #if 0
651 printf("%%%%%% save_data()\n");
652 sswf_info_serial();
653 #endif
654 		ec = save_data(result.data, &global);
655 	}
656 
657 	node_clean(&result, 0);
658 
659 #if 0
660 printf("%%%%%% done evaluation...\n");
661 sswf_info_serial();
662 #endif
663 
664 	return ec;
665 }
666 
667 
668 
set_var(const char * name,const char * value)669 void set_var(const char *name, const char *value)
670 {
671 	const char	*str;
672 	char		*end;
673 	struct node_t	*n, *var;
674 	double		v;
675 
676 /* skip leading spaces so we know if the value is only composed of spaces */
677 	str = value;
678 	while(isspace(*value)) {
679 		value++;
680 	}
681 
682 	lex_filename = "*command line variable*";
683 
684 /* create a variable */
685 	var = node_alloc(NODE_TYPE_OBJECT, NODE_SUBTYPE_VARIABLE, 0);
686 
687 /* set the variable name */
688 	n = node_alloc(NODE_TYPE_IDENTIFIER, NODE_SUBTYPE_UNKNOWN, 0);
689 	n->string = sswf_strdup(name);
690 	node_link_left(var, n);
691 
692 /* create a node for the variable value */
693 	n = node_alloc(NODE_TYPE_INTEGER, NODE_SUBTYPE_UNKNOWN, 0);
694 	if(*value == '\0') {
695 		/* by default we assume 1 */
696 		n->integer = 1;
697 	}
698 	else {
699 		v = strtod(value, &end);
700 		if(v == 0.0 && value == end) {
701 			end = 0;
702 		}
703 		else {
704 			while(isspace(*end)) {
705 				end++;
706 			}
707 			if(*end != '\0') {
708 				end = 0;
709 			}
710 		}
711 		if(end == 0) {	// failed
712 			n->type = NODE_TYPE_STRING;
713 			n->string = sswf_strdup(str);
714 		}
715 		else {
716 			if(v == floor(v)) {
717 				n->integer = (long) v;
718 			}
719 			else {
720 				n->type = NODE_TYPE_FLOAT;
721 				n->floating_point = v;
722 			}
723 		}
724 	}
725 	node_link_right(var, n);
726 	node_link_object(var);
727 
728 	/* make the variable public */
729 	node_link_parent(top_object, var);
730 	if(top_object->left == NULL) {
731 		top_object->left = var;
732 	}
733 	else {
734 		node_link_tail(top_object->left, var);
735 	}
736 }
737 
738 
739 
740 
741 
usage(void)742 void usage(void)
743 {
744 fprintf(stderr, "sswf v" TO_STR(SSWF_VERSION) " -- Copyright (c) 2002-2009 Made to Order Software Corp.\n");
745 fprintf(stderr, "\n");
746 fprintf(stderr, "Usage: sswf [-opt] [input-file ...]\n");
747 fprintf(stderr, "  where the available options are:\n");
748 fprintf(stderr, "\n");
749 fprintf(stderr, "     -c or --compress\n");
750 fprintf(stderr, "                 creates a compressed movie (v6 only)\n");
751 fprintf(stderr, "\n");
752 fprintf(stderr, "     -D<varname>=<value>\n");
753 fprintf(stderr, "                 defines a named variable\n");
754 fprintf(stderr, "\n");
755 fprintf(stderr, "     -e <name> or --encoding=<name>\n");
756 fprintf(stderr, "                 define the character encoding to use in the output\n");
757 fprintf(stderr, "\n");
758 fprintf(stderr, "     -h or --help\n");
759 fprintf(stderr, "                 print out this help screen\n");
760 fprintf(stderr, "\n");
761 fprintf(stderr, "     -I <path>\n");
762 fprintf(stderr, "                 specify one or more paths to search for input files\n");
763 fprintf(stderr, "\n");
764 fprintf(stderr, "     --lib-version\n");
765 fprintf(stderr, "                 output the version of the library and exit\n");
766 fprintf(stderr, "\n");
767 fprintf(stderr, "     -o <filename> or --output=<filename>\n");
768 fprintf(stderr, "                 defines the name of the output filename (default: \"a.swf\")\n");
769 fprintf(stderr, "\n");
770 fprintf(stderr, "     --no-network\n");
771 fprintf(stderr, "                 forbid local movies from using the network (since version 8)\n");
772 fprintf(stderr, "\n");
773 fprintf(stderr, "     --protect\n");
774 fprintf(stderr, "                 creates a protected movie (this is the default)\n");
775 fprintf(stderr, "\n");
776 fprintf(stderr, "     --show-bounds\n");
777 fprintf(stderr, "                 draw each shape boundaries with a red rectangle\n");
778 fprintf(stderr, "\n");
779 fprintf(stderr, "     --show-input-filenames\n");
780 fprintf(stderr, "                 show files which are read as input\n");
781 fprintf(stderr, "\n");
782 fprintf(stderr, "     --show-input-search\n");
783 fprintf(stderr, "                 show where each file is being searched\n");
784 fprintf(stderr, "\n");
785 fprintf(stderr, "     --show-origin\n");
786 fprintf(stderr, "                 draw a veritcal and horizontal set of lines to show the origin of all shapes\n");
787 fprintf(stderr, "\n");
788 fprintf(stderr, "     --show-output\n");
789 fprintf(stderr, "                 print the parsed data before to generate the output file\n");
790 fprintf(stderr, "\n");
791 fprintf(stderr, "     --show-step[=<level>]\n");
792 fprintf(stderr, "                 print out the current working step\n");
793 fprintf(stderr, "\n");
794 fprintf(stderr, "     --uncompress\n");
795 fprintf(stderr, "                 creates an uncompressed movie (default)\n");
796 fprintf(stderr, "\n");
797 fprintf(stderr, "     --unprotect\n");
798 fprintf(stderr, "                 creates an unprotected movie\n");
799 fprintf(stderr, "\n");
800 fprintf(stderr, "     -n or --use-network\n");
801 fprintf(stderr, "                 allow local movies to use network connections\n");
802 fprintf(stderr, "\n");
803 fprintf(stderr, "     --version\n");
804 fprintf(stderr, "                 output the version and exit\n");
805 #if DEBUG
806 fprintf(stderr, "\n");
807 fprintf(stderr, "     --debug-memory[=<level>]\n");
808 fprintf(stderr, "                 test memory extensively to ensure proper behavior\n");
809 #endif
810 }
811 
812 
813 
814 
commandline(int argc,char * argv[])815 int commandline(int argc, char *argv[])
816 {
817 	int		i, j, len, files_only, parsed;
818 	char		*file, *name, *value, *end, c;
819 
820 	parsed = 0;
821 	files_only = 0;
822 	i = 1;
823 	while(i < argc) {
824 		// if we have an option, check it
825 		// note that "-" is not an option but a filename (i.e. stdin)
826 		if(argv[i][0] == '-' && argv[i][1] != '\0' && !files_only) {
827 			file = NULL;
828 			if(argv[i][1] == '-') {
829 				if(argv[i][2] == '\0') {
830 					files_only = 1;
831 				}
832 				else if(strcmp(argv[i] + 2, "compress") == 0) {
833 					global.f_flags |= GLOBAL_FLAG_COMPRESS;
834 				}
835 #if DEBUG
836 				else if(strncmp(argv[i] + 2, "debug-memory", 12) == 0) {
837 					j = 2 + 12;
838 					if(argv[i][j] == '=') {
839 						j++;
840 					}
841 					debug_memory = atol(argv[i] + j);
842 					if(debug_memory <= 0) {
843 						debug_memory = 1;
844 					}
845 				}
846 #endif
847 				else if(strncmp(argv[i] + 2, "encoding", 8) == 0) {
848 					if(argv[i][10] == '=') {
849 						global.f_output_encoding = argv[i] + 11;
850 					}
851 					else if(argv[i][10] != '\0') {
852 						fprintf(stderr, "ERROR: invalid flag '%s'\n", argv[i]);
853 						return -1;
854 					}
855 					else {
856 						i++;
857 						if(i >= argc) {
858 							fprintf(stderr, "ERROR: invalid use of the --encoding flag; a filename was expected.\n");
859 							return -1;
860 						}
861 						global.f_output_encoding = argv[i];
862 					}
863 				}
864 				else if(strcmp(argv[i] + 2, "help") == 0) {
865 					return -1;
866 				}
867 				else if(strcmp(argv[i] + 2, "lib-version") == 0) {
868 					printf("%s\n", sswf::sswf_version());
869 					exit(0);
870 				}
871 				else if(strcmp(argv[i] + 2, "no-network") == 0) {
872 					global.f_flags &= ~GLOBAL_FLAG_USE_NETWORK;
873 				}
874 				else if(strncmp(argv[i] + 2, "output", 6) == 0) {
875 					if(argv[i][8] == '=') {
876 						file = argv[i] + 9;
877 					}
878 					else if(argv[i][8] != '\0') {
879 						fprintf(stderr, "ERROR: invalid flag '%s'\n", argv[i]);
880 						return -1;
881 					}
882 					else {
883 						i++;
884 						if(i >= argc) {
885 							fprintf(stderr, "ERROR: invalid use of the --output flag; a filename was expected.\n");
886 							return -1;
887 						}
888 						file = argv[i];
889 					}
890 				}
891 				else if(strcmp(argv[i] + 2, "protect") == 0) {
892 					global.f_flags |= GLOBAL_FLAG_PROTECT;
893 				}
894 				else if(strcmp(argv[i] + 2, "show-input-filenames") == 0) {
895 					show_input_filenames = 1;
896 				}
897 				else if(strcmp(argv[i] + 2, "show-input-search") == 0) {
898 					show_input_search = 1;
899 				}
900 				else if(strcmp(argv[i] + 2, "show-output") == 0) {
901 					show_output = 1;
902 				}
903 				else if(strcmp(argv[i] + 2, "show-bounds") == 0) {
904 					show_bounds = 1;
905 				}
906 				else if(strcmp(argv[i] + 2, "show-origin") == 0) {
907 					show_origin = 1;
908 				}
909 				else if(strncmp(argv[i] + 2, "show-step", 9) == 0) {
910 					if(argv[i][11] == '=') {
911 						global.f_show_steps = atol(argv[i] + 12);
912 					}
913 					else if(argv[i][11] == '\0') {
914 						global.f_show_steps = 1;
915 					}
916 					else {
917 						fprintf(stderr, "ERROR: invalid flag '%s'\n", argv[i]);
918 						return -1;
919 					}
920 				}
921 				else if(strcmp(argv[i] + 2, "uncompress") == 0) {
922 					global.f_flags &= ~GLOBAL_FLAG_COMPRESS;
923 				}
924 				else if(strcmp(argv[i] + 2, "unprotect") == 0) {
925 					global.f_flags &= ~GLOBAL_FLAG_PROTECT;
926 				}
927 				else if(strcmp(argv[i] + 2, "use-network") == 0) {
928 					global.f_flags |= GLOBAL_FLAG_USE_NETWORK;
929 				}
930 				else if(strcmp(argv[i] + 2, "version") == 0) {
931 					printf(TO_STR(SSWF_VERSION) "\n");
932 					exit(0);
933 				}
934 				else {
935 					fprintf(stderr, "ERROR: flag '%s' not recognized.\n", argv[i]);
936 					return -1;
937 				}
938 			}
939 			else {
940 				len = strlen(argv[i]);
941 				j = 1;
942 				while(j < len) {
943 					switch(argv[i][j]) {
944 					case 'c':
945 						global.f_flags |= GLOBAL_FLAG_COMPRESS;
946 						break;
947 
948 					case 'e':
949 						j++;
950 						if(argv[i][j] == '\0') {
951 							j = 0;
952 							i++;
953 							if(i >= argc) {
954 								fprintf(stderr, "ERROR: expected the name of an encoding.\n");
955 								return -1;
956 							}
957 							if(argv[i][0] == '\0') {
958 								fprintf(stderr, "ERROR: -e doesn't like empty encoding names.\n");
959 								return -1;
960 							}
961 						}
962 						global.f_output_encoding = argv[i] + j;
963 						j = len;
964 						break;
965 
966 					case 'h':
967 						return -1;
968 
969 					case 'n':
970 						global.f_flags |= GLOBAL_FLAG_USE_NETWORK;
971 						break;
972 
973 					case 'o':
974 						j++;
975 						if(argv[i][j] == '\0') {
976 							j = 0;
977 							i++;
978 							if(i >= argc) {
979 								fprintf(stderr, "ERROR: invalid use of the -o flag; a filename was expected.\n");
980 								return -1;
981 							}
982 							if(argv[i][0] == '\0') {
983 								fprintf(stderr, "ERROR: -o doesn't like empty filenames.\n");
984 								return -1;
985 							}
986 						}
987 						global.f_output_filename = argv[i] + j;
988 						j = len;
989 						break;
990 
991 					case 'D':
992 						j++;
993 						if(argv[i][j] == '\0') {
994 							j = 0;
995 							i++;
996 							if(i >= argc) {
997 								fprintf(stderr, "ERROR: invalid use of the -D flag; a variable was expected.\n");
998 								return -1;
999 							}
1000 							if(argv[i][0] == '\0') {
1001 								fprintf(stderr, "ERROR: -D doesn't like empty variable names.\n");
1002 								return -1;
1003 							}
1004 						}
1005 
1006 						value = name = argv[i] + j;
1007 						while(*value != '\0' && *value != '=') {
1008 							value++;
1009 						}
1010 						end = value;
1011 						if(*value == '=') {
1012 							value++;
1013 						}
1014 						c = *end;
1015 						*end = '\0';
1016 						set_var(name, value);
1017 						*end = c;
1018 						j = len;
1019 
1020 						break;
1021 
1022 					case 'I':
1023 						j++;
1024 						if(argv[i][j] == '\0') {
1025 							i++;
1026 							if(i >= argc) {
1027 								// NOTE: most certainly useless...
1028 								sswf_set_default_include(1);
1029 								break;
1030 							}
1031 							else if(argv[i][0] == '-') {
1032 								sswf_set_default_include(1);
1033 								i--;
1034 								break;
1035 							}
1036 							/* use that as a path */
1037 							j = 0;
1038 						}
1039 						else if(argv[i][j] == '-' && argv[i][j + 1] == '\0') {
1040 							sswf_set_default_include(1);
1041 							j = len;
1042 							break;
1043 						}
1044 						sswf_add_include(argv[i] + j);
1045 						j = len;
1046 						break;
1047 
1048 					default:
1049 						fprintf(stderr, "ERROR: flag '-%c' not recognized.\n", argv[i][j]);
1050 						return -1;
1051 
1052 					}
1053 					j++;
1054 				}
1055 			}
1056 		}
1057 		else {
1058 			file = argv[i];
1059 		}
1060 		if(file != NULL) {
1061 			/* parse this file */
1062 			parsed = 1;		/* mark that some files were parsed otherwise read stdin */
1063 			if(sswf_open_script(file) == 0) {
1064 				if(global.f_show_steps > 0) {
1065 					printf("+ Parsing file \"%s\".\n", lex_filename);
1066 				}
1067 				j = parse();
1068 				sswf_close_script();		/* we're done with this one! */
1069 				if(j != 0) {
1070 					return j;
1071 				}
1072 			}
1073 		}
1074 		i++;
1075 	}
1076 
1077 	if(!parsed) {
1078 		if(sswf_open_script("-") == 0) {
1079 			if(global.f_show_steps > 0) {
1080 				printf("+ Parsing standard input.\n");
1081 			}
1082 			j = parse();
1083 			sswf_close_script();		/* we're done with this one! */
1084 			return j;
1085 		}
1086 		return 1;
1087 	}
1088 
1089 	return 0;
1090 }
1091 
1092 
1093 #include <time.h>
main(int argc,char * argv[])1094 int main(int argc, char *argv[])
1095 {
1096 	int		ec;
1097 
1098 	/* avoid core dumps because they tend to be hyper large! */
1099 	/* I think this won't work under MS-Windows... */
1100 #ifndef __MINGW32__
1101 #ifndef _MSVC
1102 {
1103 	struct rlimit	l;
1104 	l.rlim_cur = 0;
1105 	l.rlim_max = 0;
1106 	setrlimit(RLIMIT_CORE, &l);
1107 }
1108 #endif
1109 #endif
1110 
1111 	global.f_flags = GLOBAL_FLAG_PROTECT;
1112 	global.f_output_filename = "a.swf";	/* name of the destination file */
1113 
1114 #if DEBUG
1115 	check_type_names();
1116 #endif
1117 	assert(sizeof(struct data_common_t) == SSWF_MEM_ALIGN(sizeof(struct data_common_t)), "the size of the data_common_t structure needs to be a multiple of sizeof(double)");
1118 
1119 #define	REPEAT_TEST	0
1120 #if REPEAT_TEST
1121 	int repeat = 2;
1122 	while(repeat > 0) {
1123 	repeat--;
1124 	printf("INFO: REPEAT TEST ON (%d)\n", repeat);
1125 #endif
1126 	init_top_object();
1127 	init_internal_variables();
1128 
1129 	ec = commandline(argc, argv);
1130 	if(ec == -1) {
1131 		usage();
1132 		ec = 1;
1133 	}
1134 	else if(ec == 0) {
1135 		/* now we can evaluate this sswf script! */
1136 		ec = evaluate();
1137 	}
1138 
1139 #if DEBUG
1140 	if(debug_memory) {
1141 		clean_top_objects();
1142 		printf("Any more buffers allocated?\n");
1143 		sswf_info();
1144 	}
1145 #endif
1146 #if REPEAT_TEST
1147 	}
1148 #endif
1149 
1150 	if(ec == 0 && errcnt != 0) {
1151 		ec = 1;
1152 	}
1153 
1154 	exit(ec);
1155 	/*NOTREACHED*/
1156 	return ec;		/* avoid warnings with some compilers */
1157 }
1158 
1159