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