1 /* swfc.c
2    Compiles swf code (.sc) files into .swf files.
3 
4    Part of the swftools package.
5 
6    Copyright (c) 2001 Matthias Kramm <kramm@quiss.org>
7 
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12 
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17 
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
21 
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <stdarg.h>
25 #include <string.h>
26 #include <memory.h>
27 #include <errno.h>
28 #include <math.h>
29 #include "../config.h"
30 #include "../lib/rfxswf.h"
31 #include "../lib/drawer.h"
32 #include "../lib/log.h"
33 #include "../lib/args.h"
34 #include "../lib/q.h"
35 #include "../lib/mp3.h"
36 #include "../lib/wav.h"
37 #include "parser.h"
38 #include "../lib/png.h"
39 #include "swfc-feedback.h"
40 #include "swfc-interpolation.h"
41 #include "swfc-history.h"
42 
43 //#define DEBUG
44 static char * outputname = "output.swf";
45 static int verbose = 2;
46 static int optimize = 0;
47 static int override_outputname = 0;
48 static int do_cgi = 0;
49 static int change_sets_all = 0;
50 static int do_exports = 0;
51 static char * mainclass = "";
52 
53 static struct options_t options[] = {
54 {"h", "help"},
55 {"V", "version"},
56 {"C", "cgi"},
57 {"v", "verbose"},
58 {"o", "output"},
59 {0,0}
60 };
61 
args_callback_option(char * name,char * val)62 int args_callback_option(char*name,char*val)
63 {
64     if(!strcmp(name, "V")) {
65         printf("swfc - part of %s %s\n", PACKAGE, VERSION);
66         exit(0);
67     }
68     else if(!strcmp(name, "o")) {
69 	outputname = val;
70 	override_outputname = 1;
71 	return 1;
72     }
73     else if(!strcmp(name, "O")) {
74 	optimize = 1;
75 	return 0;
76     }
77     else if(!strcmp(name, "C")) {
78 	do_cgi = 1;
79 	return 0;
80     }
81     else if(!strcmp(name, "v")) {
82 	verbose ++;
83 	return 0;
84     }
85     else {
86         printf("Unknown option: -%s\n", name);
87 	exit(1);
88     }
89     return 0;
90 }
args_callback_longoption(char * name,char * val)91 int args_callback_longoption(char*name,char*val)
92 {
93     return args_long2shortoption(options, name, val);
94 }
args_callback_usage(char * name)95 void args_callback_usage(char *name)
96 {
97     printf("\n");
98     printf("Usage: %s [-o file.swf] file.sc\n", name);
99     printf("\n");
100     printf("-h , --help                    Print short help message and exit\n");
101     printf("-V , --version                 Print version info and exit\n");
102     printf("-C , --cgi                     Output to stdout (for use in CGI environments)\n");
103     printf("-v , --verbose                 Increase verbosity. \n");
104     printf("-o , --output <filename>       Set output file to <filename>.\n");
105     printf("\n");
106 }
args_callback_command(char * name,char * val)107 int args_callback_command(char*name,char*val)
108 {
109     if(filename) {
110         fprintf(stderr, "Only one file allowed. You supplied at least two. (%s and %s)\n",
111                  filename, name);
112     }
113     filename = name;
114     return 0;
115 }
116 
117 static struct token_t* file;
118 
119 static int pos;
120 static char*text;
121 static int textlen;
122 static int type;
123 
readToken()124 static void readToken()
125 {
126     type = file[pos].type;
127     if(type == END) {
128 	syntaxerror("unexpected end of file");
129     }
130     text = file[pos].text;
131     textlen = strlen(text);
132     line = file[pos].line;
133     column = file[pos].column;
134     pos++;
135     //printf("---> %d(%s) %s\n", type, type_names[type], text);
136 }
137 
pushBack()138 static void pushBack()
139 {
140     int p;
141     if(!pos) syntaxerror("internal error 3");
142     pos--;
143     p = pos;
144     if(p) p--;
145     text = file[p].text;
146     textlen = strlen(text);
147     type = file[p].type;
148     line = file[p].line;
149     column = file[p].column;
150 }
151 
noMoreTokens()152 static int noMoreTokens()
153 {
154     if(file[pos].type == END)
155 	return 1;
156     return 0;
157 }
158 
159 enum
160 {
161     PT_PUT = 0,
162     PT_CHANGE = 1,
163     PT_SCHANGE = 2,
164     PT_MOVE = 3,
165     PT_SMOVE = 4,
166     PT_SWEEP = 5,
167     PT_JUMP = 6,
168     PT_STARTCLIP = 7,
169     PT_BUTTON = 8
170 };
171 
172 // ------------------------------ swf routines ----------------------------
173 struct _character;
174 static struct level
175 {
176    int type; //0=swf, 1=sprite, 2=clip, 3=button
177 
178    /* for swf (0): */
179    SWF*swf;
180    char*filename;
181    char as3;
182 
183    /* for sprites (1): */
184    TAG*tag;
185    U16 id;
186    char*name;
187    char*as3name;
188    U16 olddepth;
189    int oldframe;
190    dict_t oldinstances;
191    SRECT oldrect;
192    TAG* cut;
193 
194    SRECT scalegrid;
195 
196 } stack[256];
197 static int stackpos = 0;
198 
199 static dict_t characters;
200 static dict_t images;
201 static dict_t textures;
202 static dict_t outlines;
203 static dict_t gradients;
204 static dict_t filters;
205 static dict_t interpolations;
206 static char idmap[65536];
207 static TAG*tag = 0; //current tag
208 
209 static int id; //current character id
210 static int currentframe; //current frame in current level
211 static SRECT currentrect; //current bounding box in current level
212 static U16 currentdepth;
213 static dict_t instances;
214 static dict_t fonts;
215 static dict_t sounds;
216 static dict_t fontUsage;
217 
218 typedef struct _parameters {
219     int x,y;
220     float scalex, scaley;
221     CXFORM cxform;
222     float rotate;
223     float shear;
224     SPOINT pivot;
225     SPOINT pin;
226     U8 blendmode; //not interpolated
227     FILTERLIST* filters;
228     U16 set; // bits indicating wether a parameter was set in the c_placement function
229     U16 flags; // bits to toggle anything you may care to implement as a toggle
230     int noinstancename;
231 } parameters_t;
232 
233 typedef struct _character {
234     TAG*definingTag;
235     U16 id;
236     SRECT size;
237 } character_t;
238 
239 typedef struct _instance {
240     character_t*character;
241     U16 depth;
242     parameters_t parameters;
243     history_t* history;
244 } instance_t;
245 
246 typedef struct _outline {
247     SHAPE* shape;
248     SRECT bbox;
249 } outline_t;
250 
251 typedef struct _gradient {
252     GRADIENT gradient;
253     char radial;
254     int rotate;
255 } gradient_t;
256 
257 typedef struct _filter {
258     FILTER filter;
259 } filter_t;
260 
261 typedef struct _texture {
262     FILLSTYLE fs;
263 } texture_t;
264 
265 char* interpolationFunctions[] = {"linear", \
266         "quadIn", "quadOut", "quadInOut", \
267         "cubicIn", "cubicOut", "cubicInOut", \
268         "quartIn", "quartOut", "quartInOut", \
269         "quintIn", "quintOut", "quintInOut", \
270         "circleIn", "circleOut", "circleInOut", \
271         "exponentialIn", "exponentialOut", "exponentialInOut", \
272         "sineIn", "sineOut", "sineInOut", \
273         "elasticIn", "elasticOut", "elasticInOut", \
274         "backIn", "backOut", "backInOut", \
275         "bounceIn", "bounceOut", "bounceInOut", \
276         "fastBounceIn", "fastBounceOut", "fastBounceInOut"};
277 
character_init(character_t * c)278 static void character_init(character_t*c)
279 {
280     memset(c, 0, sizeof(character_t));
281 }
282 
character_new()283 static character_t* character_new()
284 {
285     character_t*c;
286     c = (character_t*)malloc(sizeof(character_t));
287     character_init(c);
288     return c;
289 }
290 
instance_init(instance_t * i)291 static void instance_init(instance_t*i)
292 {
293     memset(i, 0, sizeof(instance_t));
294     i->history = history_new();
295 }
296 
instance_free(instance_t * i)297 static void instance_free(instance_t* i)
298 {
299     history_free(i->history);
300     free(i);
301 }
302 
instance_new()303 static instance_t* instance_new()
304 {
305     instance_t*c;
306     c = (instance_t*)malloc(sizeof(instance_t));
307     instance_init(c);
308     return c;
309 }
310 
free_instance(void * i)311 static void free_instance(void* i)
312 {
313     instance_free((instance_t*)i);
314 }
315 
free_font(void * f)316 static void free_font(void* f)
317 {
318     swf_FontFree((SWFFONT*)f);
319 }
320 
gradient_free(GRADIENT * grad)321 static void gradient_free(GRADIENT* grad)
322 {
323     free(grad->ratios);
324     free(grad->rgba);
325     free(grad);
326 }
327 
free_gradient(void * grad)328 static void free_gradient(void* grad)
329 {
330     gradient_free((GRADIENT*) grad);
331 }
332 
outline_free(outline_t * o)333 static void outline_free(outline_t* o)
334 {
335     free(o->shape->data);
336     free(o->shape);
337     free(o);
338 }
339 
free_outline(void * o)340 static void free_outline(void* o)
341 {
342     outline_free((outline_t*)o);
343 }
344 
freeDictionaries()345 static void freeDictionaries()
346 {
347     dict_free_all(&instances, 1, free_instance);
348     dict_free_all(&characters, 1, free);
349     dict_free_all(&images, 1, free);
350     dict_free_all(&textures, 1, free);
351     dict_free_all(&outlines, 1, free_outline);
352     dict_free_all(&gradients, 1, free_gradient);
353     dict_free_all(&filters, 1, free);
354     dict_free_all(&fonts, 1, free_font);
355     dict_free_all(&sounds, 1, free);
356     dict_free_all(&interpolations, 1, free);
357     cleanUp = 0;
358 }
359 
freeFontDictionary()360 static void freeFontDictionary()
361 {
362     dict_free_all(&fonts, 1, free_font);
363 }
364 
incrementid()365 static void incrementid()
366 {
367     while(id<65536 && idmap[id]) {
368         id++;
369     }
370     if(id>=65536)
371 	syntaxerror("Out of character ids.");
372     idmap[id] = 1;
373 }
374 
s_addcharacter(const char * name,U16 id,TAG * ctag,SRECT r)375 static void s_addcharacter(const char*name, U16 id, TAG*ctag, SRECT r)
376 {
377     if(dict_lookup(&characters, name))
378         syntaxerror("character %s defined twice", name);
379     character_t* c = character_new();
380 
381     c->definingTag = ctag;
382     c->id = id;
383     c->size = r;
384     dict_put(&characters, name, c);
385 
386     if(do_exports) {
387 	tag = swf_InsertTag(tag, ST_NAMECHARACTER);
388 	swf_SetU16(tag, id);
389 	swf_SetString(tag, name);
390 	tag = swf_InsertTag(tag, ST_EXPORTASSETS);
391 	swf_SetU16(tag, 1);
392 	swf_SetU16(tag, id);
393 	swf_SetString(tag, name);
394     }
395 }
s_addimage(const char * name,U16 id,TAG * ctag,SRECT r)396 static void s_addimage(const char*name, U16 id, TAG*ctag, SRECT r)
397 {
398     if(dict_lookup(&images, name))
399         syntaxerror("image %s defined twice", name);
400 
401     character_t* c = character_new();
402     c->definingTag = ctag;
403     c->id = id;
404     c->size = r;
405     dict_put(&images, name, c);
406 }
s_addinstance(const char * name,character_t * c,U16 depth)407 static instance_t* s_addinstance(const char*name, character_t*c, U16 depth)
408 {
409     if(dict_lookup(&instances, name))
410         syntaxerror("object %s defined twice", name);
411     instance_t* i = instance_new();
412     i->character = c;
413     i->depth = depth;
414     //swf_GetMatrix(0, &i->matrix);
415     dict_put(&instances, name, i);
416     return i;
417 }
418 
parameters_clear(parameters_t * p)419 static void parameters_clear(parameters_t*p)
420 {
421     p->x = 0; p->y = 0;
422     p->scalex = 1.0; p->scaley = 1.0;
423     p->pin.x = 0;  //1??
424     p->pin.y = 0;
425     p->pivot.x = 0; p->pivot.y = 0;
426     p->rotate = 0;
427     p->shear = 0;
428     p->blendmode = 0;
429     p->filters = 0;
430     p->noinstancename = 0;
431     swf_GetCXForm(0, &p->cxform, 1);
432 }
433 
makeMatrix(MATRIX * m,parameters_t * p)434 static void makeMatrix(MATRIX*m, parameters_t*p)
435 {
436     SPOINT h;
437     float sx,r1,r0,sy;
438 
439     /*	      /sx r1\ /x\
440      *	      \r0 sy/ \y/
441      */
442 
443     sx =  p->scalex*cos(p->rotate/360*2*M_PI);
444     r1 = -p->scalex*sin(p->rotate/360*2*M_PI)+sx*p->shear;
445     r0 =  p->scaley*sin(p->rotate/360*2*M_PI);
446     sy =  p->scaley*cos(p->rotate/360*2*M_PI)+r0*p->shear;
447 
448     m->sx = (int)(sx*65536+0.5);
449     m->r1 = (int)(r1*65536+0.5);
450     m->r0 = (int)(r0*65536+0.5);
451     m->sy = (int)(sy*65536+0.5);
452 
453     m->tx = m->ty = 0;
454 
455     h = swf_TurnPoint(p->pin, m);
456     m->tx = p->x - h.x;
457     m->ty = p->y - h.y;
458 }
459 
s_instancepos(SRECT rect,parameters_t * p)460 static MATRIX s_instancepos(SRECT rect, parameters_t*p)
461 {
462     MATRIX m;
463     SRECT r;
464     makeMatrix(&m, p);
465     r = swf_TurnRect(rect, &m);
466     if(currentrect.xmin == 0 && currentrect.ymin == 0 &&
467        currentrect.xmax == 0 && currentrect.ymax == 0)
468 	currentrect = r;
469     else
470 	swf_ExpandRect2(&currentrect, &r);
471     return m;
472 }
473 
initBuiltIns()474 void initBuiltIns()
475 {
476     interpolation_t* new;
477     new = (interpolation_t*)malloc(sizeof(interpolation_t));
478     new->function = IF_LINEAR;
479     dict_put(&interpolations, "linear", new);
480 
481     new = (interpolation_t*)malloc(sizeof(interpolation_t));
482     new->function = IF_QUAD_IN;
483     new->slope = 0;
484     dict_put(&interpolations, "quadIn", new);
485     new = (interpolation_t*)malloc(sizeof(interpolation_t));
486     new->function = IF_QUAD_OUT;
487     new->slope = 0;
488     dict_put(&interpolations, "quadOut", new);
489     new = (interpolation_t*)malloc(sizeof(interpolation_t));
490     new->function = IF_QUAD_IN_OUT;
491     new->slope = 0;
492     dict_put(&interpolations, "quadInOut", new);
493 
494     new = (interpolation_t*)malloc(sizeof(interpolation_t));
495     new->function = IF_CUBIC_IN;
496     new->slope = 0;
497     dict_put(&interpolations, "cubicIn", new);
498     new = (interpolation_t*)malloc(sizeof(interpolation_t));
499     new->function = IF_CUBIC_OUT;
500     new->slope = 0;
501     dict_put(&interpolations, "cubicOut", new);
502     new = (interpolation_t*)malloc(sizeof(interpolation_t));
503     new->function = IF_CUBIC_IN_OUT;
504     new->slope = 0;
505     dict_put(&interpolations, "cubicInOut", new);
506 
507     new = (interpolation_t*)malloc(sizeof(interpolation_t));
508     new->function = IF_QUART_IN;
509     new->slope = 0;
510     dict_put(&interpolations, "quartIn", new);
511     new = (interpolation_t*)malloc(sizeof(interpolation_t));
512     new->function = IF_QUART_OUT;
513     new->slope = 0;
514     dict_put(&interpolations, "quartOut", new);
515     new = (interpolation_t*)malloc(sizeof(interpolation_t));
516     new->function = IF_QUART_IN_OUT;
517     new->slope = 0;
518     dict_put(&interpolations, "quartInOut", new);
519 
520     new = (interpolation_t*)malloc(sizeof(interpolation_t));
521     new->function = IF_QUINT_IN;
522     new->slope = 0;
523     dict_put(&interpolations, "quintIn", new);
524     new = (interpolation_t*)malloc(sizeof(interpolation_t));
525     new->function = IF_QUINT_OUT;
526     new->slope = 0;
527     dict_put(&interpolations, "quintOut", new);
528     new = (interpolation_t*)malloc(sizeof(interpolation_t));
529     new->function = IF_QUINT_IN_OUT;
530     new->slope = 0;
531     dict_put(&interpolations, "quintInOut", new);
532 
533     new = (interpolation_t*)malloc(sizeof(interpolation_t));
534     new->function = IF_CIRCLE_IN;
535     dict_put(&interpolations, "circleIn", new);
536     new = (interpolation_t*)malloc(sizeof(interpolation_t));
537     new->function = IF_CIRCLE_OUT;
538     dict_put(&interpolations, "circleOut", new);
539     new = (interpolation_t*)malloc(sizeof(interpolation_t));
540     new->function = IF_CIRCLE_IN_OUT;
541     dict_put(&interpolations, "circleInOut", new);
542 
543     new = (interpolation_t*)malloc(sizeof(interpolation_t));
544     new->function = IF_EXPONENTIAL_IN;
545     dict_put(&interpolations, "exponentialIn", new);
546     new = (interpolation_t*)malloc(sizeof(interpolation_t));
547     new->function = IF_EXPONENTIAL_OUT;
548     dict_put(&interpolations, "exponentialOut", new);
549     new = (interpolation_t*)malloc(sizeof(interpolation_t));
550     new->function = IF_EXPONENTIAL_IN_OUT;
551     dict_put(&interpolations, "exponentialInOut", new);
552 
553     new = (interpolation_t*)malloc(sizeof(interpolation_t));
554     new->function = IF_SINE_IN;
555     dict_put(&interpolations, "sineIn", new);
556     new = (interpolation_t*)malloc(sizeof(interpolation_t));
557     new->function = IF_SINE_OUT;
558     dict_put(&interpolations, "sineOut", new);
559     new = (interpolation_t*)malloc(sizeof(interpolation_t));
560     new->function = IF_SINE_IN_OUT;
561     dict_put(&interpolations, "sineInOut", new);
562 
563     RGBA c;
564     memset(&c, 0, sizeof(RGBA));
565     gradient_t* noGradient = (gradient_t*)malloc(sizeof(gradient_t));
566     noGradient->gradient.ratios = (U8*)malloc(16 * sizeof(U8));
567     noGradient->gradient.rgba = (RGBA*)malloc(16 * sizeof(RGBA));
568     noGradient->gradient.num = 2;
569     noGradient->gradient.rgba[0] = c;
570     noGradient->gradient.ratios[0] = 0;
571     noGradient->gradient.rgba[1] = c;
572     noGradient->gradient.ratios[1] = 255;
573     noGradient->radial = 0;
574     noGradient->rotate = 0;
575     dict_put(&gradients, "no_gradient", noGradient);
576 
577     noFilters = 0;
578 // put a no_filters entry in the filters dictionary to provoce a message when a user tries
579 // to define a no_filters filter. The real filter=no_filters case is handled in parseFilters.
580     FILTER* dummy = (FILTER*)malloc(sizeof(FILTER));
581     dict_put(&filters, "no_filters", dummy);
582     noBlur = (FILTER_BLUR*) swf_NewFilter(FILTERTYPE_BLUR);
583     noBlur->passes = 1;
584     dict_put(&filters, "no_blur", noBlur);
585     noBevel = (FILTER_BEVEL*) swf_NewFilter(FILTERTYPE_BEVEL);
586     noBevel->passes = 1;
587     noBevel->composite = 1;
588     dict_put(&filters, "no_bevel", noBevel);
589     noDropshadow = (FILTER_DROPSHADOW*) swf_NewFilter(FILTERTYPE_DROPSHADOW);
590     noDropshadow->passes = 1;
591     noDropshadow->composite = 1;
592     dict_put(&filters, "no_dropshadow", noDropshadow);
593     noGradientGlow = (FILTER_GRADIENTGLOW*) swf_NewFilter(FILTERTYPE_GRADIENTGLOW);
594     noGradientGlow->passes = 1;
595     noGradientGlow->composite = 1;
596     noGradientGlow->gradient = &noGradient->gradient;
597     dict_put(&filters, "no_gradientglow", noGradientGlow);
598 }
599 
s_swf(const char * name,SRECT r,int version,int fps,int compress,RGBA background)600 void s_swf(const char*name, SRECT r, int version, int fps, int compress, RGBA background)
601 {
602     if(stackpos)
603         syntaxerror(".swf blocks can't be nested");
604     if(stackpos==sizeof(stack)/sizeof(stack[0]))
605         syntaxerror("too many levels of recursion");
606 
607     SWF*swf = (SWF*)malloc(sizeof(SWF));
608 
609     memset(swf, 0, sizeof(swf));
610     swf->fileVersion = version;
611     swf->movieSize = r;
612     swf->frameRate = fps;
613     swf->firstTag = tag = swf_InsertTag(0, ST_SETBACKGROUNDCOLOR);
614     swf->compressed = compress;
615     swf_SetRGB(tag,&background);
616 
617     dict_init(&characters, 16);
618     dict_init(&images, 16);
619     dict_init(&textures, 16);
620     dict_init(&outlines, 16);
621     dict_init(&gradients, 16);
622     dict_init(&filters, 16);
623     dict_init(&instances, 16);
624     dict_init(&sounds, 16);
625     dict_init(&interpolations, 16);
626     initBuiltIns();
627     cleanUp = &freeDictionaries;
628 
629     memset(&stack[stackpos], 0, sizeof(stack[0]));
630     stack[stackpos].type = 0;
631     stack[stackpos].filename = strdup(name);
632     stack[stackpos].swf = swf;
633     stack[stackpos].oldframe = -1;
634     stackpos++;
635 
636     currentframe = 0;
637     memset(&currentrect, 0, sizeof(currentrect));
638     currentdepth = 1;
639 
640     memset(idmap, 0, sizeof(idmap));
641     idmap[0]=1; //main movie has ID 0
642 
643     incrementid();
644 }
645 
s_sprite(const char * name,SRECT * scalegrid,const char * as3name)646 void s_sprite(const char*name, SRECT*scalegrid, const char*as3name)
647 {
648     tag = swf_InsertTag(tag, ST_DEFINESPRITE);
649     swf_SetU16(tag, id); //id
650     swf_SetU16(tag, 0); //frames
651 
652     memset(&stack[stackpos], 0, sizeof(stack[0]));
653     stack[stackpos].type = 1;
654     stack[stackpos].oldframe = currentframe;
655     stack[stackpos].olddepth = currentdepth;
656     stack[stackpos].oldrect = currentrect;
657     stack[stackpos].oldinstances = instances;
658     stack[stackpos].tag = tag;
659     stack[stackpos].id = id;
660     stack[stackpos].name = strdup(name);
661     stack[stackpos].as3name = strdup(as3name);
662     if(scalegrid) {
663 	stack[stackpos].scalegrid = *scalegrid;
664     } else {
665 	memset(&stack[stackpos].scalegrid, 0, sizeof(SRECT));
666     }
667 
668     /* FIXME: those four fields should be bundled together */
669     dict_init(&instances, 16);
670     currentframe = 0;
671     currentdepth = 1;
672     memset(&currentrect, 0, sizeof(currentrect));
673 
674     stackpos++;
675     incrementid();
676 }
677 
678 typedef struct _buttonrecord
679 {
680     U16 id;
681     MATRIX matrix;
682     CXFORM cxform;
683     char set;
684 } buttonrecord_t;
685 
686 typedef struct _button
687 {
688     int endofshapes;
689     int nr_actions;
690     buttonrecord_t records[4];
691 } button_t;
692 
693 static button_t mybutton;
694 
s_button(const char * name,const char * as3name)695 void s_button(const char*name, const char*as3name)
696 {
697     tag = swf_InsertTag(tag, ST_DEFINEBUTTON2);
698     swf_SetU16(tag, id); //id
699     swf_ButtonSetFlags(tag, 0); //menu=no
700 
701     memset(&mybutton, 0, sizeof(mybutton));
702 
703     memset(&stack[stackpos], 0, sizeof(stack[0]));
704     stack[stackpos].type = 3;
705     stack[stackpos].tag = tag;
706     stack[stackpos].id = id;
707     stack[stackpos].name = strdup(name);
708     stack[stackpos].as3name = strdup(as3name);
709     stack[stackpos].oldrect = currentrect;
710     memset(&currentrect, 0, sizeof(currentrect));
711 
712     stackpos++;
713     incrementid();
714 }
s_buttonput(const char * character,const char * as,parameters_t p)715 void s_buttonput(const char*character, const char*as, parameters_t p)
716 {
717     character_t* c = dict_lookup(&characters, character);
718     MATRIX m;
719     int flags = 0;
720     const char*o = as,*s = as;
721     buttonrecord_t r;
722     if(!stackpos || (stack[stackpos-1].type != 3))  {
723 	syntaxerror(".show may only appear in .button");
724     }
725     if(!c) {
726 	syntaxerror("character %s not known (in .shape %s)", character, character);
727     }
728     if(mybutton.endofshapes) {
729 	syntaxerror("a .do may not precede a .show", character, character);
730     }
731 
732     m = s_instancepos(c->size, &p);
733 
734     r.id = c->id;
735     r.matrix = m;
736     r.cxform = p.cxform;
737     r.set = 1;
738 
739     while(1) {
740 	if(*s==',' || *s==0) {
741 	    if(!strncmp(o,"idle",s-o)) {mybutton.records[0]=r;o=s+1;}
742 	    else if(!strncmp(o,"shape",s-o)) {mybutton.records[0]=r;o=s+1;}
743 	    else if(!strncmp(o,"hover",s-o)) {mybutton.records[1]=r;o=s+1;}
744 	    else if(!strncmp(o,"pressed",s-o)) {mybutton.records[2]=r;o=s+1;}
745 	    else if(!strncmp(o,"area",s-o)) {mybutton.records[3]=r;o=s+1;}
746 	    else syntaxerror("unknown \"as\" argument: \"%s\"", strdup_n(o,s-o));
747 	}
748 	if(!*s)
749 	    break;
750 	s++;
751     }
752 }
setbuttonrecords(TAG * tag)753 static void setbuttonrecords(TAG*tag)
754 {
755     int flags[] = {BS_UP,BS_OVER,BS_DOWN,BS_HIT};
756     if(!mybutton.endofshapes) {
757 	int t;
758 
759 	if(!mybutton.records[3].set) {
760 	    memcpy(&mybutton.records[3], &mybutton.records[0], sizeof(buttonrecord_t));
761 	}
762 
763 	for(t=0;t<4;t++) {
764 	    if(mybutton.records[t].set) {
765 		swf_ButtonSetRecord(tag,flags[t],mybutton.records[t].id,1,&mybutton.records[t].matrix,&mybutton.records[t].cxform);
766 	    }
767 	}
768 	swf_SetU8(tag,0); // end of button records
769 	mybutton.endofshapes = 1;
770     }
771 }
772 
s_buttonaction(int flags,const char * action)773 void s_buttonaction(int flags, const char*action)
774 {
775     ActionTAG* a = 0;
776     if(flags==0) {
777 	return;
778     }
779     if(!stackpos || !stack[stackpos-1].tag ||
780             stack[stackpos-1].tag->id != ST_DEFINEBUTTON2) {
781         syntaxerror("Need to be inside a button for .on_* commands");
782     }
783     setbuttonrecords(stack[stackpos-1].tag);
784 
785     a = swf_ActionCompile(text, stack[0].swf->fileVersion);
786     if(!a) {
787 	syntaxerror("Couldn't compile ActionScript");
788     }
789 
790     swf_ButtonSetCondition(stack[stackpos-1].tag, flags);
791     swf_ActionSet(stack[stackpos-1].tag, a);
792     mybutton.nr_actions++;
793 
794     swf_ActionFree(a);
795 }
796 
setactionend(TAG * tag)797 static void setactionend(TAG*tag)
798 {
799     if(!mybutton.nr_actions) {
800 	/* no actions means we didn't have an actionoffset,
801 	   which means we can't signal the end of the
802 	   buttonaction records, so, *sigh*, we have
803 	   to insert a dummy record */
804 	swf_SetU16(tag, 0); //offset
805 	swf_SetU16(tag, 0); //condition
806 	swf_SetU8(tag, 0); //action
807     }
808 }
809 
s_endButton()810 static void s_endButton()
811 {
812     SRECT r;
813     setbuttonrecords(stack[stackpos-1].tag);
814     setactionend(stack[stackpos-1].tag);
815     stackpos--;
816 
817     swf_ButtonPostProcess(stack[stackpos].tag, mybutton.nr_actions);
818 
819     r = currentrect;
820 
821     tag = stack[stackpos].tag;
822     currentrect = stack[stackpos].oldrect;
823 
824     s_addcharacter(stack[stackpos].name, stack[stackpos].id, stack[stackpos].tag, r);
825 
826     if(*stack[stackpos].as3name) {
827         tag = swf_InsertTag(tag, ST_SYMBOLCLASS);
828         swf_SetU16(tag, 1);
829         swf_SetU16(tag, stack[stackpos].id);
830         swf_SetString(tag, stack[stackpos].as3name);
831     }
832 
833     free(stack[stackpos].name);
834 }
835 
removeFromTo(TAG * from,TAG * to)836 TAG* removeFromTo(TAG*from, TAG*to)
837 {
838     TAG*save = from->prev;
839     while(from!=to) {
840 	TAG*next = from->next;
841 	if(swf_isAllowedSpriteTag(from))
842 	    swf_DeleteTag(0, from);
843 	from = next;
844     }
845     save->next = 0;
846     return save;
847 }
848 
parametersChange(history_t * history,int frame)849 static int parametersChange(history_t* history, int frame)
850 {
851     int willChange = 0;
852 
853     willChange = willChange || history_change(history, frame, "x");
854     willChange = willChange || history_change(history, frame, "y");
855     willChange = willChange || history_change(history, frame, "scalex");
856     willChange = willChange || history_change(history, frame, "scaley");
857     willChange = willChange || history_change(history, frame, "cxform.r0");
858     willChange = willChange || history_change(history, frame, "cxform.g0");
859     willChange = willChange || history_change(history, frame, "cxform.b0");
860     willChange = willChange || history_change(history, frame, "cxform.a0");
861     willChange = willChange || history_change(history, frame, "cxform.r1");
862     willChange = willChange || history_change(history, frame, "cxform.g1");
863     willChange = willChange || history_change(history, frame, "cxform.b1");
864     willChange = willChange || history_change(history, frame, "cxform.a1");
865     willChange = willChange || history_change(history, frame, "rotate");
866     willChange = willChange || history_change(history, frame, "shear");
867     willChange = willChange || history_change(history, frame, "pivot.x");
868     willChange = willChange || history_change(history, frame, "pivot.y");
869     willChange = willChange || history_change(history, frame, "pin.x");
870     willChange = willChange || history_change(history, frame, "pin.y");
871     willChange = willChange || history_change(history, frame, "blendmode");
872     willChange = willChange || history_changeFilter(history, frame);
873 
874     return willChange;
875 }
876 
free_filterlist(FILTERLIST * f_list)877 static void free_filterlist(FILTERLIST* f_list)
878 {
879     int i;
880     for (i = 0; i < f_list->num; i++)
881     {
882         if(f_list->filter[i]->type == FILTERTYPE_GRADIENTGLOW)
883             gradient_free(((FILTER_GRADIENTGLOW*)f_list->filter[i])->gradient);
884         free(f_list->filter[i]);
885     }
886     free(f_list);
887 }
888 
readParameters(history_t * history,parameters_t * p,int frame)889 static void readParameters(history_t* history, parameters_t* p, int frame)
890 {
891     p->x = history_value(history, frame, "x");
892     p->y = history_value(history, frame, "y");
893     p->scalex = history_value(history, frame, "scalex");
894     p->scaley = history_value(history, frame, "scaley");
895     p->cxform.r0 = history_value(history, frame, "cxform.r0");
896     p->cxform.g0 = history_value(history, frame, "cxform.g0");
897     p->cxform.b0 = history_value(history, frame, "cxform.b0");
898     p->cxform.a0 = history_value(history, frame, "cxform.a0");
899     p->cxform.r1 = history_value(history, frame, "cxform.r1");
900     p->cxform.g1 = history_value(history, frame, "cxform.g1");
901     p->cxform.b1 = history_value(history, frame, "cxform.b1");
902     p->cxform.a1 = history_value(history, frame, "cxform.a1");
903     p->rotate = history_rotateValue(history, frame);
904     p->shear = history_value(history, frame, "shear");
905     p->pivot.x = history_value(history, frame, "pivot.x");
906     p->pivot.y = history_value(history, frame, "pivot.y");
907     p->pin.x = history_value(history, frame, "pin.x");
908     p->pin.y = history_value(history, frame, "pin.y");
909     p->blendmode = history_value(history, frame, "blendmode");
910     p->filters = history_filterValue(history, frame);
911 }
912 
setPlacement(TAG * tag,U16 id,U16 depth,MATRIX m,const char * name,parameters_t * p,char move)913 void setPlacement(TAG*tag, U16 id, U16 depth, MATRIX m, const char*name, parameters_t*p, char move)
914 {
915     SWFPLACEOBJECT po;
916     FILTERLIST flist;
917     swf_GetPlaceObject(NULL, &po);
918     po.id = id;
919     po.depth = depth;
920     po.matrix = m;
921     po.cxform = p->cxform;
922     po.name = (char*)name;
923     po.move = move;
924     if(move)
925     po.id = 0;
926     if(p->blendmode) {
927     po.blendmode = p->blendmode;
928     }
929     if(p->filters)
930     	po.filters = p->filters;
931     swf_SetPlaceObject(tag, &po);
932 }
933 
writeInstance(void * _i)934 static void writeInstance(void* _i)
935 {
936     instance_t*i = (instance_t*)_i;
937     parameters_t p;
938     MATRIX m;
939     int frame = i->history->firstFrame;
940     TAG* tag = i->history->firstTag;
941     history_processFlags(i->history);
942     while (tag && frame < currentframe)
943     {
944         frame++;
945         while (tag && tag->id != ST_SHOWFRAME)
946             tag = tag->next;
947         if(parametersChange(i->history, frame))
948         {
949             readParameters(i->history, &p, frame);
950             m = s_instancepos(i->character->size, &p);
951 
952             if(p.blendmode || p.filters)
953         	tag = swf_InsertTag(tag, ST_PLACEOBJECT3);
954             else
955         	tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
956             setPlacement(tag, 0, i->depth, m, 0, &p, 1);
957             if(p.filters)
958             	free_filterlist(p.filters);
959         } else if(tag) {
960             tag = tag->next;
961         }
962     }
963 }
964 
dumpSWF(SWF * swf)965 void dumpSWF(SWF*swf)
966 {
967     TAG* tag = swf->firstTag;
968     printf("vvvvvvvvvvvvvvvvvvvvv\n");
969     while(tag) {
970     printf("%8d %s\n", tag->len, swf_TagGetName(tag));
971     tag = tag->next;
972     }
973     printf("^^^^^^^^^^^^^^^^^^^^^\n");
974 }
975 
s_endSprite()976 static void s_endSprite()
977 {
978     SRECT r = currentrect;
979 
980     stackpos--;
981     instance_t *i;
982 
983     dict_foreach_value(&instances, writeInstance);
984 
985     if(stack[stackpos].cut)
986 	tag = removeFromTo(stack[stackpos].cut, tag);
987 
988     // the writeInstance loop above may have inserted tags after what used to be the current tag,
989     // so let's make sure 'tag' point to the current tag again.
990     while (tag->next)
991 	tag = tag->next;
992 
993     tag = swf_InsertTag(tag, ST_SHOWFRAME);
994     tag = swf_InsertTag(tag, ST_END);
995 
996     tag = stack[stackpos].tag;
997     swf_FoldSprite(tag);
998 
999     if(stack[stackpos].scalegrid.xmin | stack[stackpos].scalegrid.ymin |
1000        stack[stackpos].scalegrid.xmax | stack[stackpos].scalegrid.ymax)
1001     {
1002 	tag = swf_InsertTag(tag, ST_DEFINESCALINGGRID);
1003 	swf_SetU16(tag, stack[stackpos].id);
1004 	swf_SetRect(tag, &stack[stackpos].scalegrid);
1005     }
1006 
1007     if(tag->next != 0)
1008         syntaxerror("internal error(7)");
1009     /* TODO: before clearing, prepend "<spritename>." to names and
1010              copy into old instances dict */
1011     dict_free_all(&instances, 1, free_instance);
1012 
1013     currentframe = stack[stackpos].oldframe;
1014     currentrect = stack[stackpos].oldrect;
1015     currentdepth = stack[stackpos].olddepth;
1016     instances = stack[stackpos].oldinstances;
1017 
1018     s_addcharacter(stack[stackpos].name, stack[stackpos].id, stack[stackpos].tag, r);
1019 
1020     if(*stack[stackpos].as3name) {
1021         tag = swf_InsertTag(tag, ST_SYMBOLCLASS);
1022         swf_SetU16(tag, 1);
1023         swf_SetU16(tag, stack[stackpos].id);
1024         swf_SetString(tag, stack[stackpos].as3name);
1025     }
1026 
1027 
1028     free(stack[stackpos].name);
1029 }
1030 
s_endSWF()1031 static void s_endSWF()
1032 {
1033     int fi;
1034     SWF* swf;
1035     char*filename;
1036     char*mc="";
1037 
1038     dict_foreach_value(&instances, writeInstance);
1039 
1040     if(stack[stackpos].cut)
1041 	tag = removeFromTo(stack[stackpos].cut, tag);
1042 
1043     stackpos--;
1044 
1045     swf = stack[stackpos].swf;
1046     filename = stack[stackpos].filename;
1047 
1048     // the writeInstance loop above may have inserted tags after what used yo be the current tag,
1049     // so let's make sure 'tag' point to the current tag again.
1050     while (tag->next)
1051 	tag = tag->next;
1052 
1053     //if(tag->prev && tag->prev->id != ST_SHOWFRAME)
1054     //    tag = swf_InsertTag(tag, ST_SHOWFRAME);
1055     tag = swf_InsertTag(tag, ST_SHOWFRAME);
1056 
1057     if(stack[0].as3) {
1058         TAG*tag = swf->firstTag;
1059         tag = swf_InsertTag(tag, ST_DOABC);
1060         void*code = as3_getcode();
1061         swf_WriteABC(tag, code);
1062         if(*mainclass)
1063             mc = mainclass;
1064         else if(as3_getglobalclass())
1065             mc = as3_getglobalclass();
1066         if(*mc) {
1067             tag = swf_InsertTag(tag, ST_SYMBOLCLASS);
1068             swf_SetU16(tag, 1);
1069             swf_SetU16(tag, 0);
1070             swf_SetString(tag, mc);
1071         } else {
1072             warning("no global public MovieClip subclass");
1073         }
1074         as3_destroy();
1075     }
1076 
1077     tag = swf_InsertTag(tag, ST_END);
1078 
1079     swf_OptimizeTagOrder(swf);
1080 
1081     if(optimize) {
1082 	swf_Optimize(swf);
1083     }
1084 
1085     if(!(swf->movieSize.xmax-swf->movieSize.xmin) || !(swf->movieSize.ymax-swf->movieSize.ymin)) {
1086 	swf->movieSize = currentrect; /* "autocrop" */
1087     }
1088 
1089     if(!(swf->movieSize.xmax-swf->movieSize.xmin) || !(swf->movieSize.ymax-swf->movieSize.ymin)) {
1090 	swf->movieSize.xmax += 20; /* 1 by 1 pixels */
1091 	swf->movieSize.ymax += 20;
1092 	warning("Empty bounding box for movie");
1093     }
1094 
1095     if(do_cgi || !strcmp(filename, "-"))
1096 	fi = fileno(stdout);
1097     else
1098 	fi = open(filename, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0644);
1099     if(fi<0) {
1100 	syntaxerror("couldn't create output file %s", filename);
1101     }
1102     if(do_cgi)
1103 	{if(swf_WriteCGI(swf)<0) syntaxerror("WriteCGI() failed.\n");}
1104     else
1105 	{if(swf_WriteSWF(fi, swf)<0) syntaxerror("WriteSWF() failed.\n");}
1106 
1107     close(fi);
1108 
1109     freeDictionaries();
1110 
1111     swf_FreeTags(swf);
1112     free(swf);
1113     free(filename);
1114 }
1115 
s_close()1116 void s_close()
1117 {
1118     if(stackpos) {
1119 	if(stack[stackpos-1].type == 0)
1120 	    syntaxerror("End of file encountered in .flash block");
1121 	if(stack[stackpos-1].type == 1)
1122 	    syntaxerror("End of file encountered in .sprite block");
1123 	if(stack[stackpos-1].type == 2)
1124 	    syntaxerror("End of file encountered in .clip block");
1125     }
1126 }
1127 
s_getframe()1128 int s_getframe()
1129 {
1130     return currentframe+1;
1131 }
1132 
s_frame(int nr,int cut,const char * name,char anchor)1133 void s_frame(int nr, int cut, const char*name, char anchor)
1134 {
1135     int t;
1136     TAG*now = tag;
1137 
1138     if(nr<1)
1139 	syntaxerror("Illegal frame number");
1140     nr--; // internally, frame 1 is frame 0
1141 
1142     for(t=currentframe;t<nr;t++) {
1143 	tag = swf_InsertTag(tag, ST_SHOWFRAME);
1144 	if(t==nr-1 && name && *name) {
1145 	    tag = swf_InsertTag(tag, ST_FRAMELABEL);
1146 	    swf_SetString(tag, name);
1147 	    if(anchor)
1148 		swf_SetU8(tag, 1); //make this an anchor
1149 	}
1150     }
1151     if(nr == 0 && currentframe == 0 && name && *name) {
1152         tag = swf_InsertTag(tag, ST_FRAMELABEL);
1153         swf_SetString(tag, name);
1154 	if(anchor)
1155 	    swf_SetU8(tag, 1); //make this an anchor
1156     }
1157 
1158     if(cut) {
1159 	if(now == tag) {
1160 	    syntaxerror("Can't cut, frame empty");
1161 	}
1162 	stack[stackpos].cut = tag;
1163     }
1164 
1165     currentframe = nr;
1166 }
1167 
1168 int parseColor2(const char*str, RGBA*color);
1169 
addFillStyle(SHAPE * s,SRECT * r,const char * name)1170 int addFillStyle(SHAPE*s, SRECT*r, const char*name)
1171 {
1172     RGBA color;
1173     character_t*image;
1174     gradient_t*gradient;
1175     texture_t*texture;
1176     if(name[0] == '#') {
1177 	parseColor2(name, &color);
1178 	return swf_ShapeAddSolidFillStyle(s, &color);
1179     } else if((texture = dict_lookup(&textures, name))) {
1180 	return swf_ShapeAddFillStyle2(s, &texture->fs);
1181     } else if((image = dict_lookup(&images, name))) {
1182 	MATRIX m;
1183 	swf_GetMatrix(0, &m);
1184 	m.sx = 65536.0*20.0*(r->xmax - r->xmin)/image->size.xmax;
1185 	m.sy = 65536.0*20.0*(r->ymax - r->ymin)/image->size.ymax;
1186 	m.tx = r->xmin;
1187 	m.ty = r->ymin;
1188 	return swf_ShapeAddBitmapFillStyle(s, &m, image->id, 0);
1189     }  else if((gradient = dict_lookup(&gradients, name))) {
1190 	SRECT r2;
1191 	MATRIX rot,m;
1192 	double ccos,csin;
1193 	swf_GetMatrix(0, &rot);
1194     	ccos = cos(-gradient->rotate*2*M_PI/360);
1195     	csin = sin(-gradient->rotate*2*M_PI/360);
1196 	rot.sx =  ccos*65536;
1197 	rot.r1 = -csin*65536;
1198 	rot.r0 =  csin*65536;
1199 	rot.sy =  ccos*65536;
1200 	r2 = swf_TurnRect(*r, &rot);
1201 	swf_GetMatrix(0, &m);
1202 	m.sx =  (r2.xmax - r2.xmin)*2*ccos;
1203 	m.r1 = -(r2.xmax - r2.xmin)*2*csin;
1204 	m.r0 =  (r2.ymax - r2.ymin)*2*csin;
1205 	m.sy =  (r2.ymax - r2.ymin)*2*ccos;
1206 	m.tx = r->xmin + (r->xmax - r->xmin)/2;
1207 	m.ty = r->ymin + (r->ymax - r->ymin)/2;
1208 	return swf_ShapeAddGradientFillStyle(s, &m, &gradient->gradient, gradient->radial);
1209     }  else if(parseColor2(name, &color)) {
1210 	return swf_ShapeAddSolidFillStyle(s, &color);
1211     } else {
1212 	syntaxerror("not a color/fillstyle: %s", name);
1213 	return 0;
1214     }
1215 }
1216 
1217 RGBA black={r:0,g:0,b:0,a:0};
s_box(const char * name,int width,int height,RGBA color,int linewidth,const char * texture)1218 void s_box(const char*name, int width, int height, RGBA color, int linewidth, const char*texture)
1219 {
1220     SRECT r,r2;
1221     SHAPE* s;
1222     int ls1=0,fs1=0;
1223     r2.xmin = 0;
1224     r2.ymin = 0;
1225     r2.xmax = width;
1226     r2.ymax = height;
1227     tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
1228     swf_ShapeNew(&s);
1229     if(linewidth) {
1230 	linewidth = linewidth>=20?linewidth-20:0;
1231         ls1 = swf_ShapeAddLineStyle(s,linewidth,&color);
1232     }
1233     if(texture)
1234 	fs1 = addFillStyle(s, &r2, texture);
1235 
1236     swf_SetU16(tag,id);
1237     r.xmin = r2.xmin-linewidth/2;
1238     r.ymin = r2.ymin-linewidth/2;
1239     r.xmax = r2.xmax+linewidth/2;
1240     r.ymax = r2.ymax+linewidth/2;
1241     swf_SetRect(tag,&r);
1242     swf_SetShapeHeader(tag,s);
1243     swf_ShapeSetAll(tag,s,0,0,ls1,fs1,0);
1244     swf_ShapeSetLine(tag,s,width,0);
1245     swf_ShapeSetLine(tag,s,0,height);
1246     swf_ShapeSetLine(tag,s,-width,0);
1247     swf_ShapeSetLine(tag,s,0,-height);
1248     swf_ShapeSetEnd(tag);
1249     swf_ShapeFree(s);
1250 
1251     s_addcharacter(name, id, tag, r);
1252     incrementid();
1253 }
1254 
s_filled(const char * name,const char * outlinename,RGBA color,int linewidth,const char * texture)1255 void s_filled(const char*name, const char*outlinename, RGBA color, int linewidth, const char*texture)
1256 {
1257     SRECT rect,r2;
1258     SHAPE* s;
1259     int ls1,fs1=0;
1260     outline_t* outline;
1261     outline = dict_lookup(&outlines, outlinename);
1262     if(!outline) {
1263 	syntaxerror("outline %s not defined", outlinename);
1264     }
1265     r2 = outline->bbox;
1266 
1267     tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
1268     swf_ShapeNew(&s);
1269     if(linewidth) {
1270 	linewidth = linewidth>=20?linewidth-20:0;
1271         ls1 = swf_ShapeAddLineStyle(s,linewidth,&color);
1272     }
1273     if(texture)
1274 	fs1 = addFillStyle(s, &r2, texture);
1275 
1276     swf_SetU16(tag,id);
1277     rect.xmin = r2.xmin-linewidth/2;
1278     rect.ymin = r2.ymin-linewidth/2;
1279     rect.xmax = r2.xmax+linewidth/2;
1280     rect.ymax = r2.ymax+linewidth/2;
1281 
1282     swf_SetRect(tag,&rect);
1283     swf_SetShapeStyles(tag, s);
1284     swf_ShapeCountBits(s,0,0);
1285     swf_RecodeShapeData(outline->shape->data, outline->shape->bitlen, outline->shape->bits.fill, outline->shape->bits.line,
1286                         &s->data,             &s->bitlen,             s->bits.fill,              s->bits.line);
1287     swf_SetShapeBits(tag, s);
1288     swf_SetBlock(tag, s->data, (s->bitlen+7)/8);
1289     swf_ShapeFree(s);
1290 
1291     s_addcharacter(name, id, tag, rect);
1292     incrementid();
1293 }
1294 
s_circle(const char * name,int r,RGBA color,int linewidth,const char * texture)1295 void s_circle(const char*name, int r, RGBA color, int linewidth, const char*texture)
1296 {
1297     SRECT rect,r2;
1298     SHAPE* s;
1299     int ls1=0,fs1=0;
1300     r2.xmin = r2.ymin = 0;
1301     r2.xmax = 2*r;
1302     r2.ymax = 2*r;
1303 
1304     tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
1305     swf_ShapeNew(&s);
1306     if(linewidth) {
1307 	linewidth = linewidth>=20?linewidth-20:0;
1308         ls1 = swf_ShapeAddLineStyle(s,linewidth,&color);
1309     }
1310     if(texture)
1311 	fs1 = addFillStyle(s, &r2, texture);
1312     swf_SetU16(tag,id);
1313     rect.xmin = r2.xmin-linewidth/2;
1314     rect.ymin = r2.ymin-linewidth/2;
1315     rect.xmax = r2.xmax+linewidth/2;
1316     rect.ymax = r2.ymax+linewidth/2;
1317 
1318     swf_SetRect(tag,&rect);
1319     swf_SetShapeHeader(tag,s);
1320     swf_ShapeSetAll(tag,s,0,0,ls1,fs1,0);
1321     swf_ShapeSetCircle(tag, s, r,r,r,r);
1322     swf_ShapeSetEnd(tag);
1323     swf_ShapeFree(s);
1324 
1325     s_addcharacter(name, id, tag, rect);
1326     incrementid();
1327 }
1328 
s_textshape(const char * name,const char * fontname,float size,const char * _text)1329 void s_textshape(const char*name, const char*fontname, float size, const char*_text)
1330 {
1331     int g;
1332     U8*text = (U8*)_text;
1333     outline_t* outline;
1334 
1335     SWFFONT*font;
1336     font = dict_lookup(&fonts, fontname);
1337     if(!font)
1338 	syntaxerror("font \"%s\" not known!", fontname);
1339 
1340     if(text[0] >= font->maxascii || font->ascii2glyph[text[0]]<0) {
1341 	warning("no character 0x%02x (%c) in font \"%s\"", text[0], text[0], fontname);
1342 	s_box(name, 0, 0, black, 20, 0);
1343 	return;
1344     }
1345     g = font->ascii2glyph[text[0]];
1346 
1347     outline = malloc(sizeof(outline_t));
1348     memset(outline, 0, sizeof(outline_t));
1349     outline->shape = font->glyph[g].shape;
1350     outline->bbox = font->layout->bounds[g];
1351 
1352     {
1353 	drawer_t draw;
1354 	swf_Shape11DrawerInit(&draw, 0);
1355 	swf_DrawText(&draw, font, (int)(size*100), (char*)_text);
1356 	draw.finish(&draw);
1357 	outline->shape = swf_ShapeDrawerToShape(&draw);
1358 	outline->bbox = swf_ShapeDrawerGetBBox(&draw);
1359 	draw.dealloc(&draw);
1360     }
1361 
1362     if(dict_lookup(&outlines, name))
1363 	syntaxerror("outline %s defined twice", name);
1364     dict_put(&outlines, name, outline);
1365 }
1366 
s_text(const char * name,const char * fontname,const char * text,int size,RGBA color)1367 void s_text(const char*name, const char*fontname, const char*text, int size, RGBA color)
1368 {
1369     SRECT r;
1370     MATRIX _m,*m=0;
1371     SWFFONT*font;
1372     font = dict_lookup(&fonts, fontname);
1373     if(!font)
1374 	syntaxerror("font \"%s\" not known!", fontname);
1375 
1376     tag = swf_InsertTag(tag, ST_DEFINETEXT2);
1377     swf_SetU16(tag, id);
1378     if(!font->numchars) {
1379 	s_box(name, 0, 0, black, 20, 0);
1380 	return;
1381     }
1382     r = swf_SetDefineText(tag, font, &color, (char*)text, size);
1383 
1384     if(stack[0].swf->fileVersion >= 8) {
1385 	tag = swf_InsertTag(tag, ST_CSMTEXTSETTINGS);
1386 	swf_SetU16(tag, id);
1387 	swf_SetU8(tag, /*grid*/(1<<3)|/*flashtype*/0x40);
1388 	swf_SetU32(tag, 0);//thickness
1389 	swf_SetU32(tag, 0);//sharpness
1390 	swf_SetU8(tag, 0);//reserved
1391     }
1392 
1393     s_addcharacter(name, id, tag, r);
1394     incrementid();
1395 }
1396 
s_quicktime(const char * name,const char * url)1397 void s_quicktime(const char*name, const char*url)
1398 {
1399     SRECT r;
1400     MATRIX _m,*m=0;
1401 
1402     memset(&r, 0, sizeof(r));
1403 
1404     tag = swf_InsertTag(tag, ST_DEFINEMOVIE);
1405     swf_SetU16(tag, id);
1406     swf_SetString(tag, url);
1407 
1408     s_addcharacter(name, id, tag, r);
1409     incrementid();
1410 }
1411 
s_video(const char * name,int width,int height)1412 void s_video(const char *name, int width, int height)
1413 {
1414     SRECT r;
1415 
1416     memset(&r, 0, sizeof(r));
1417 
1418     tag = swf_InsertTag(tag, ST_DEFINEVIDEOSTREAM);
1419     swf_SetU16(tag, id);
1420     swf_SetU16(tag, 0); // numframes
1421     swf_SetU16(tag, width);
1422     swf_SetU16(tag, height);
1423     swf_SetU8(tag, 0); // videoflags
1424     swf_SetU8(tag, 0); // codecid
1425 
1426     s_addcharacter(name, id, tag, r);
1427     incrementid();
1428 }
1429 
s_edittext(const char * name,const char * fontname,int size,int width,int height,const char * text,RGBA * color,int maxlength,const char * variable,int flags,int align)1430 void s_edittext(const char*name, const char*fontname, int size, int width, int height, const char*text, RGBA*color, int maxlength, const char*variable, int flags, int align)
1431 {
1432     SWFFONT*font = 0;
1433     EditTextLayout layout;
1434     SRECT r;
1435 
1436     if(fontname && *fontname) {
1437 	flags |= ET_USEOUTLINES;
1438 	font = dict_lookup(&fonts, fontname);
1439 	if(!font)
1440 	    syntaxerror("font \"%s\" not known!", fontname);
1441     }
1442     tag = swf_InsertTag(tag, ST_DEFINEEDITTEXT);
1443     swf_SetU16(tag, id);
1444     layout.align = align;
1445     layout.leftmargin = 0;
1446     layout.rightmargin = 0;
1447     layout.indent = 0;
1448     layout.leading = 0;
1449     r.xmin = 0;
1450     r.ymin = 0;
1451     r.xmax = width;
1452     r.ymax = height;
1453 
1454     swf_SetEditText(tag, flags, r, (char*)text, color, maxlength, font?font->id:0, size, &layout, (char*)variable);
1455 
1456     s_addcharacter(name, id, tag, r);
1457     incrementid();
1458 }
1459 
1460 /* type: either "jpeg" or "png"
1461  */
s_image(const char * name,const char * type,const char * filename,int quality)1462 void s_image(const char*name, const char*type, const char*filename, int quality)
1463 {
1464     /* an image is actually two folded: 1st bitmap, 2nd character.
1465        Both of them can be used separately */
1466 
1467     /* step 1: the bitmap */
1468     SRECT r;
1469     int imageID = id;
1470     unsigned width, height;
1471     if(!strcmp(type,"jpeg")) {
1472 #ifndef HAVE_JPEGLIB
1473 	warning("no jpeg support compiled in");
1474 	s_box(name, 0, 0, black, 20, 0);
1475 	return;
1476 #else
1477 	tag = swf_InsertTag(tag, ST_DEFINEBITSJPEG2);
1478 	swf_SetU16(tag, imageID);
1479 
1480 	if(swf_SetJPEGBits(tag, (char*)filename, quality) < 0) {
1481 	    syntaxerror("Image \"%s\" not found, or contains errors", filename);
1482 	}
1483 
1484 	swf_GetJPEGSize(filename, &width, &height);
1485 
1486 	r.xmin = 0;
1487 	r.ymin = 0;
1488 	r.xmax = width*20;
1489 	r.ymax = height*20;
1490 
1491 	s_addimage(name, id, tag, r);
1492 	incrementid();
1493 #endif
1494     } else if(!strcmp(type,"png")) {
1495 	RGBA*data = 0;
1496 	swf_SetU16(tag, imageID);
1497 
1498 	png_load(filename, &width, &height, (unsigned char**)&data);
1499 
1500 	if(!data) {
1501 	    syntaxerror("Image \"%s\" not found, or contains errors", filename);
1502 	}
1503 
1504 	/*tag = swf_AddImage(tag, imageID, data, width, height, quality)*/
1505 	tag = swf_InsertTag(tag, ST_DEFINEBITSLOSSLESS);
1506 	swf_SetU16(tag, imageID);
1507 	swf_SetLosslessImage(tag, data, width, height);
1508     free(data);
1509 
1510 	r.xmin = 0;
1511 	r.ymin = 0;
1512 	r.xmax = width*20;
1513 	r.ymax = height*20;
1514 	s_addimage(name, id, tag, r);
1515 	incrementid();
1516     } else {
1517 	warning("image type \"%s\" not supported yet!", type);
1518 	s_box(name, 0, 0, black, 20, 0);
1519 	return;
1520     }
1521 
1522     /* step 2: the character */
1523     tag = swf_InsertTag(tag, ST_DEFINESHAPE); // todo: should be defineshape2/3 once images can be transparent.(?)
1524     swf_SetU16(tag, id);
1525     swf_ShapeSetBitmapRect(tag, imageID, width, height);
1526 
1527     s_addcharacter(name, id, tag, r);
1528     incrementid();
1529 }
1530 
s_getBitmapSize(const char * name,int * width,int * height)1531 void s_getBitmapSize(const char*name, int*width, int*height)
1532 {
1533     character_t* image = dict_lookup(&images, name);
1534     gradient_t* gradient = dict_lookup(&gradients,name);
1535     if(image) {
1536 	*width = image->size.xmax;
1537 	*height = image->size.ymax;
1538 	return;
1539     }
1540     if(gradient) {
1541 	/* internal SWF gradient size */
1542 	if(gradient->radial) {
1543 	    *width = 16384;
1544 	    *height = 16384;
1545 	} else {
1546 	    *width = 32768;
1547 	    *height = 32768;
1548 	}
1549 	return;
1550     }
1551     syntaxerror("No such bitmap/gradient: %s", name);
1552 }
1553 
s_texture(const char * name,const char * object,int x,int y,float scalex,float scaley,float rotate,float shear)1554 void s_texture(const char*name, const char*object, int x, int y, float scalex, float scaley, float rotate, float shear)
1555 {
1556     if(dict_lookup(&textures, name))
1557         syntaxerror("texture %s defined twice", name);
1558     gradient_t* gradient = dict_lookup(&gradients, object);
1559     character_t* bitmap = dict_lookup(&images, object);
1560     texture_t* texture = (texture_t*)rfx_calloc(sizeof(texture_t));
1561     parameters_t p;
1562     FILLSTYLE*fs = &texture->fs;
1563 
1564     memset(&p, 0, sizeof(parameters_t));
1565 
1566     if(bitmap) {
1567 	fs->type = FILL_TILED;
1568 	fs->id_bitmap = bitmap->id;
1569     } else if(gradient) {
1570 	fs->type = gradient->radial?FILL_RADIAL:FILL_LINEAR;
1571 	fs->gradient = gradient->gradient;
1572     }
1573     p.x = x;p.y = y;p.scalex = scalex;p.scaley = scaley;p.rotate=rotate;p.shear=shear;
1574     makeMatrix(&fs->m, &p);
1575     if(gradient && !gradient->radial) {
1576 	MATRIX m = fs->m;
1577 	SPOINT p1,p2;
1578 	m.tx = 0;
1579 	m.ty = 0;
1580 	p1.x = 16384;
1581 	p1.y = 16384;
1582 	p2 = swf_TurnPoint(p1, &m);
1583 	fs->m.tx += p2.x;
1584 	fs->m.ty += p2.y;
1585     }
1586     if(bitmap) {
1587 	fs->m.sx *= 20;
1588 	fs->m.sy *= 20;
1589     }
1590 
1591     dict_put(&textures, name, texture);
1592 }
1593 
s_createfont(const char * name,const char * filename,const char * glyphs,char flashtype)1594 void s_createfont(const char*name, const char*filename, const char*glyphs, char flashtype)
1595 {
1596     if(dict_lookup(&fonts, name))
1597 	syntaxerror("font %s defined twice", name);
1598 
1599     SWFFONT* font = swf_LoadFont(filename, flashtype);
1600     if(font == 0) {
1601 	warning("Couldn't open font file \"%s\"", filename);
1602 	font = (SWFFONT*)malloc(sizeof(SWFFONT));
1603 	memset(font, 0, sizeof(SWFFONT));
1604 	dict_put(&fonts, name, font);
1605 	return;
1606     }
1607     swf_FontPrepareForEditText(font);
1608 
1609     if(!strcmp(glyphs, "all")) {
1610 	swf_FontUseAll(font);
1611 	font->use->glyphs_specified = 1;
1612     } else {
1613 	if(!glyphs[0]) {
1614 	    swf_FontInitUsage(font);
1615 	} else {
1616 	    swf_FontUseUTF8(font, (const U8*)glyphs, 0xffff);
1617 	    font->use->glyphs_specified = 1;
1618 	}
1619     }
1620     dict_put(&fonts, name, font);
1621 }
1622 
s_font(const char * name,const char * filename)1623 void s_font(const char*name, const char*filename)
1624 {
1625     SWFFONT* font;
1626     font = dict_lookup(&fonts, name);
1627     font->id = id;
1628     swf_FontReduce_swfc(font);
1629 
1630     if(font->version>=3 && stack[0].swf->fileVersion < 8) {
1631 	warning("flashtype not supported for flash versions 8 and below");
1632     }
1633 
1634     tag = swf_InsertTag(tag, font->version==3?ST_DEFINEFONT3:ST_DEFINEFONT2);
1635     swf_FontSetDefine2(tag, font);
1636 
1637     if(do_exports) {
1638 	tag = swf_InsertTag(tag, ST_EXPORTASSETS);
1639 	swf_SetU16(tag, 1);
1640 	swf_SetU16(tag, id);
1641 	swf_SetString(tag, name);
1642     }
1643 
1644     incrementid();
1645 }
1646 
1647 
1648 
1649 typedef struct _sound_t
1650 {
1651     U16 id;
1652     TAG*tag;
1653 } sound_t;
1654 
s_sound(const char * name,const char * filename)1655 void s_sound(const char*name, const char*filename)
1656 {
1657     struct WAV wav, wav2;
1658     struct MP3 mp3;
1659     sound_t* sound;
1660     U16*samples = NULL;
1661     unsigned numsamples = 1;
1662     unsigned blocksize = 1152;
1663     int is_mp3 = 0;
1664 
1665     if(dict_lookup(&sounds, name))
1666         syntaxerror("sound %s defined twice", name);
1667 
1668     if(wav_read(&wav, filename))
1669     {
1670         int t;
1671         wav_convert2mono(&wav, &wav2, 44100);
1672         samples = (U16*)wav2.data;
1673         numsamples = wav2.size/2;
1674         free(wav.data);
1675 #ifdef WORDS_BIGENDIAN
1676 	/* swap bytes */
1677         for(t=0;t<numsamples;t++)
1678             samples[t] = (samples[t]>>8)&0xff | (samples[t]<<8)&0xff00;
1679 #endif
1680     }
1681     else
1682         if(mp3_read(&mp3, filename))
1683         {
1684             fprintf(stderr, "\"%s\" seems to work as a MP3 file...\n", filename);
1685             blocksize = 1;
1686             is_mp3 = 1;
1687         }
1688         else
1689         {
1690             warning("Couldn't read WAV/MP3 file \"%s\"", filename);
1691             samples = 0;
1692             numsamples = 0;
1693         }
1694 
1695     if(numsamples%blocksize != 0)
1696     {
1697 	// apply padding, so that block is a multiple of blocksize
1698         int numblocks = (numsamples+blocksize-1)/blocksize;
1699         int numsamples2;
1700         U16* samples2;
1701         numsamples2 = numblocks * blocksize;
1702         samples2 = malloc(sizeof(U16)*numsamples2);
1703         memcpy(samples2, samples, numsamples*sizeof(U16));
1704         memset(&samples2[numsamples], 0, sizeof(U16)*(numsamples2 - numsamples));
1705         numsamples = numsamples2;
1706         free(samples);
1707         samples = samples2;
1708     }
1709 
1710     tag = swf_InsertTag(tag, ST_DEFINESOUND);
1711     swf_SetU16(tag, id); //id
1712     if(is_mp3)
1713     {
1714         swf_SetSoundDefineMP3(
1715                 tag, mp3.data, mp3.size,
1716                 mp3.SampRate,
1717                 mp3.Channels,
1718                 mp3.NumFrames);
1719         mp3_clear(&mp3);
1720     }
1721     else
1722         swf_SetSoundDefine(tag, samples, numsamples);
1723 
1724     if(do_exports) {
1725 	tag = swf_InsertTag(tag, ST_NAMECHARACTER);
1726 	swf_SetU16(tag, id);
1727 	swf_SetString(tag, name);
1728 	tag = swf_InsertTag(tag, ST_EXPORTASSETS);
1729 	swf_SetU16(tag, 1);
1730 	swf_SetU16(tag, id);
1731 	swf_SetString(tag, name);
1732     }
1733 
1734     sound = (sound_t*)malloc(sizeof(sound_t)); /* mem leak */
1735     sound->tag = tag;
1736     sound->id = id;
1737 
1738     dict_put(&sounds, name, sound);
1739 
1740     incrementid();
1741 
1742     if(samples)
1743         free(samples);
1744 }
1745 
gradient_getToken(const char ** p)1746 static char* gradient_getToken(const char**p)
1747 {
1748     const char*start;
1749     char*result;
1750     while(**p && strchr(" \t\n\r", **p)) {
1751 	(*p)++;
1752     }
1753     start = *p;
1754     while(**p && !strchr(" \t\n\r", **p)) {
1755 	(*p)++;
1756     }
1757     result = malloc((*p)-start+1);
1758     memcpy(result,start,(*p)-start+1);
1759     result[(*p)-start] = 0;
1760     return result;
1761 }
1762 
1763 float parsePercent(const char*str);
1764 RGBA parseColor(const char*str);
1765 
parseGradient(const char * str)1766 GRADIENT parseGradient(const char*str)
1767 {
1768     GRADIENT gradient;
1769     int lastpos = -1;
1770     const char* p = str;
1771     memset(&gradient, 0, sizeof(GRADIENT));
1772     gradient.ratios = rfx_calloc(16*sizeof(U8));
1773     gradient.rgba = rfx_calloc(16*sizeof(RGBA));
1774 
1775     while(*p)
1776     {
1777         char*posstr,*colorstr;
1778         int pos;
1779         RGBA color;
1780         posstr = gradient_getToken(&p);
1781         if(!*posstr)
1782         {
1783             free(posstr);
1784             break;
1785         }
1786         pos = (int)(parsePercent(posstr)*255.0);
1787         if(pos == lastpos)
1788             pos++;
1789         if(!*p)
1790         {
1791             rfx_free(gradient.ratios);
1792             rfx_free(gradient.rgba);
1793             free(posstr);
1794             syntaxerror("Error in shape data: Color expected after %s", posstr);
1795         }
1796         colorstr = gradient_getToken(&p);
1797         color = parseColor(colorstr);
1798         if(gradient.num == 16)
1799         {
1800             warning("gradient record too big- max size is 16, rest ignored");
1801             break;
1802         }
1803         gradient.ratios[gradient.num] = pos;
1804         gradient.rgba[gradient.num] = color;
1805         gradient.num++;
1806         free(posstr);
1807         free(colorstr);
1808         lastpos = pos;
1809 	}
1810     return gradient;
1811 }
1812 
parseFilters(char * list)1813 FILTERLIST* parseFilters(char* list)
1814 {
1815     if(!strcmp(list, "no_filters"))
1816     	return 0;
1817     FILTER* f;
1818     FILTERLIST* f_list = (FILTERLIST*)malloc(sizeof(FILTERLIST));
1819     f_list->num = 0;
1820     char* f_start = list;
1821     char* f_end;
1822     while (f_start)
1823     {
1824     	f_end = strchr(f_start, ',');
1825     	if(f_end)
1826     	    *f_end = '\0';
1827     	f = dict_lookup(&filters, f_start);
1828     	if(!f)
1829     	{
1830     	    free(f_list);
1831     	    syntaxerror("unknown filter %s", f_start);
1832     	}
1833     	if(f_list->num == 8)
1834     	{
1835     	    warning("too many filters in filterlist, no more than 8 please, rest ignored");
1836     	    break;
1837     	}
1838     	f_list->filter[f_list->num] = f;
1839     	f_list->num++;
1840     	if(f_end)
1841     	{
1842     	    *f_end = ',';
1843     	    f_start = f_end + 1;
1844     	}
1845     	else
1846     	    f_start = 0;
1847     }
1848     return f_list;
1849 }
1850 
s_gradient(const char * name,const char * text,int radial,int rotate)1851 void s_gradient(const char*name, const char*text, int radial, int rotate)
1852 {
1853     gradient_t* gradient;
1854     gradient = malloc(sizeof(gradient_t));
1855     memset(gradient, 0, sizeof(gradient_t));
1856     gradient->gradient = parseGradient(text);
1857     gradient->radial = radial;
1858     gradient->rotate = rotate;
1859 
1860     dict_put(&gradients, name, gradient);
1861 }
1862 
s_gradientglow(const char * name,const char * gradient,float blurx,float blury,float angle,float distance,float strength,char innershadow,char knockout,char composite,char ontop,int passes)1863 void s_gradientglow(const char*name, const char*gradient, float blurx, float blury,
1864 		    float angle, float distance, float strength, char innershadow,
1865 		    char knockout, char composite, char ontop, int passes)
1866 {
1867     if(dict_lookup(&filters, name))
1868         syntaxerror("filter %s defined twice", name);
1869 
1870     gradient_t* g = dict_lookup(&gradients, gradient);
1871     if(!g)
1872 	syntaxerror("unknown gradient %s", gradient);
1873 
1874     composite = 1;
1875 
1876     FILTER_GRADIENTGLOW* filter = rfx_calloc(sizeof(FILTER_GRADIENTGLOW));
1877     filter->type = FILTERTYPE_GRADIENTGLOW;
1878     filter->gradient = &g->gradient;
1879     filter->blurx = blurx;
1880     filter->blury = blury;
1881     filter->strength = strength;
1882     filter->angle = angle;
1883     filter->distance = distance;
1884     filter->innershadow = innershadow;
1885     filter->knockout = knockout;
1886     filter->composite = composite;
1887     filter->ontop = ontop;
1888     filter->passes = passes;
1889 
1890     dict_put(&filters, name, filter);
1891 }
1892 
s_dropshadow(const char * name,RGBA color,double blurx,double blury,double angle,double distance,double strength,char innershadow,char knockout,char composite,int passes)1893 void s_dropshadow(const char*name, RGBA color, double blurx, double blury, double angle, double distance, double strength, char innershadow, char knockout, char composite, int passes)
1894 {
1895     if(dict_lookup(&filters, name))
1896         syntaxerror("filter %s defined twice", name);
1897 
1898     composite = 1;
1899     FILTER_DROPSHADOW* filter = rfx_calloc(sizeof(FILTER_DROPSHADOW));
1900     filter->type = FILTERTYPE_DROPSHADOW;
1901     filter->color= color;
1902     filter->blurx = blurx;
1903     filter->blury = blury;
1904     filter->strength = strength;
1905     filter->angle = angle;
1906     filter->distance = distance;
1907     filter->innershadow = innershadow;
1908     filter->knockout = knockout;
1909     filter->composite = composite;
1910     filter->passes = passes;
1911 
1912     dict_put(&filters, name, filter);
1913 }
1914 
s_bevel(const char * name,RGBA shadow,RGBA highlight,double blurx,double blury,double angle,double distance,double strength,char innershadow,char knockout,char composite,char ontop,int passes)1915 void s_bevel(const char*name, RGBA shadow, RGBA highlight, double blurx, double blury, double angle, double distance, double strength, char innershadow, char knockout, char composite, char ontop, int passes)
1916 {
1917     if(dict_lookup(&filters, name))
1918         syntaxerror("filter %s defined twice", name);
1919 
1920     composite = 1;
1921     FILTER_BEVEL* filter = rfx_calloc(sizeof(FILTER_BEVEL));
1922     filter->type = FILTERTYPE_BEVEL;
1923     filter->shadow = shadow;
1924     filter->highlight = highlight;
1925     filter->blurx = blurx;
1926     filter->blury = blury;
1927     filter->strength = strength;
1928     filter->angle = angle;
1929     filter->distance = distance;
1930     filter->innershadow = innershadow;
1931     filter->knockout = knockout;
1932     filter->composite = composite;
1933     filter->ontop = ontop;
1934     filter->passes = passes;
1935 
1936     dict_put(&filters, name, filter);
1937 }
1938 
s_blur(const char * name,double blurx,double blury,int passes)1939 void s_blur(const char*name, double blurx, double blury, int passes)
1940 {
1941     if(dict_lookup(&filters, name))
1942         syntaxerror("filter %s defined twice", name);
1943 
1944     FILTER_BLUR* filter = rfx_calloc(sizeof(FILTER_BLUR));
1945     filter->type = FILTERTYPE_BLUR;
1946     filter->blurx = blurx;
1947     filter->blury = blury;
1948     filter->passes = passes;
1949 
1950     dict_put(&filters, name, filter);
1951 }
1952 
s_action(const char * text)1953 void s_action(const char*text)
1954 {
1955     if(stack[0].swf->fileVersion < 9) {
1956         ActionTAG* a = 0;
1957         a = swf_ActionCompile(text, stack[0].swf->fileVersion);
1958         if(!a) {
1959             swf_ActionFree(a);
1960             syntaxerror("Couldn't compile ActionScript");
1961         }
1962         tag = swf_InsertTag(tag, ST_DOACTION);
1963         swf_ActionSet(tag, a);
1964         swf_ActionFree(a);
1965     } else {
1966         as3_parse_bytearray(stack[0].filename, text, strlen(text));
1967         stack[0].as3 = 1;
1968     }
1969 }
1970 
s_initaction(const char * character,const char * text)1971 void s_initaction(const char*character, const char*text)
1972 {
1973     ActionTAG* a = 0;
1974     character_t*c = 0;
1975     a = swf_ActionCompile(text, stack[0].swf->fileVersion);
1976     if(!a)
1977     {
1978         swf_ActionFree(a);
1979         syntaxerror("Couldn't compile ActionScript");
1980     }
1981 
1982     c = (character_t*)dict_lookup(&characters, character);
1983 
1984     tag = swf_InsertTag(tag, ST_DOINITACTION);
1985     swf_SetU16(tag, c->id);
1986     swf_ActionSet(tag, a);
1987 
1988     swf_ActionFree(a);
1989 }
1990 
s_swf3action(const char * name,const char * action)1991 int s_swf3action(const char*name, const char*action)
1992 {
1993     ActionTAG* a = 0;
1994     instance_t* object = 0;
1995     if(name)
1996 	object = (instance_t*)dict_lookup(&instances, name);
1997     if(!object && name && *name) {
1998 	/* we have a name, but couldn't find it. Abort. */
1999 	return 0;
2000     }
2001     a = action_SetTarget(0, name);
2002     if(!strcmp(action, "nextframe")) a = action_NextFrame(a);
2003     else if(!strcmp(action, "previousframe")) a = action_PreviousFrame(a);
2004     else if(!strcmp(action, "stop")) a = action_Stop(a);
2005     else if(!strcmp(action, "play")) a = action_Play(a);
2006     a = action_SetTarget(a, "");
2007     a = action_End(a);
2008 
2009     tag = swf_InsertTag(tag, ST_DOACTION);
2010     swf_ActionSet(tag, a);
2011     swf_ActionFree(a);
2012     return 1;
2013 }
2014 
s_outline(const char * name,const char * format,const char * source)2015 void s_outline(const char*name, const char*format, const char*source)
2016 {
2017     if(dict_lookup(&outlines, name))
2018         syntaxerror("outline %s defined twice", name);
2019 
2020     outline_t* outline;
2021 
2022     drawer_t draw;
2023     SHAPE* shape;
2024     SHAPE2* shape2;
2025     SRECT bounds;
2026 
2027     //swf_Shape10DrawerInit(&draw, 0);
2028     swf_Shape11DrawerInit(&draw, 0);
2029 
2030     draw_string(&draw, source);
2031     draw.finish(&draw);
2032     shape = swf_ShapeDrawerToShape(&draw);
2033     bounds = swf_ShapeDrawerGetBBox(&draw);
2034     draw.dealloc(&draw);
2035 
2036     outline = (outline_t*)rfx_calloc(sizeof(outline_t));
2037     outline->shape = shape;
2038     outline->bbox = bounds;
2039 
2040     dict_put(&outlines, name, outline);
2041 }
2042 
s_playsound(const char * name,int loops,int nomultiple,int stop)2043 int s_playsound(const char*name, int loops, int nomultiple, int stop)
2044 {
2045     sound_t* sound;
2046     SOUNDINFO info;
2047     if(!name)
2048 	return 0;
2049     sound = dict_lookup(&sounds, name);
2050     if(!sound)
2051 	return 0;
2052 
2053     tag = swf_InsertTag(tag, ST_STARTSOUND);
2054     swf_SetU16(tag, sound->id); //id
2055     memset(&info, 0, sizeof(info));
2056     info.stop = stop;
2057     info.loops = loops;
2058     info.nomultiple = nomultiple;
2059     swf_SetSoundInfo(tag, &info);
2060     return 1;
2061 }
2062 
s_includeswf(const char * name,const char * filename,const char * as3name)2063 void s_includeswf(const char*name, const char*filename, const char*as3name)
2064 {
2065     int f;
2066     SWF swf;
2067     TAG* ftag;
2068     SRECT r;
2069     TAG* s;
2070     int level = 0;
2071     U16 cutout[] = {ST_SETBACKGROUNDCOLOR, ST_PROTECT, ST_FREEALL, ST_REFLEX};
2072     f = open(filename,O_RDONLY|O_BINARY);
2073     if(f<0) {
2074 	warning("Couldn't open file \"%s\": %s", filename, strerror(errno));
2075 	s_box(name, 0, 0, black, 20, 0);
2076 	return;
2077     }
2078     if(swf_ReadSWF(f,&swf)<0) {
2079 	warning("Only SWF files supported in .shape for now. File \"%s\" wasn't SWF.", filename);
2080 	s_box(name, 0, 0, black, 20, 0);
2081 	return;
2082     }
2083     close(f);
2084 
2085     /* FIXME: The following sets the bounding Box for the character.
2086               It is wrong for two reasons:
2087 	      a) It may be too small (in case objects in the movie clip at the borders)
2088 	      b) it may be too big (because the poor movie never got autocropped)
2089     */
2090     r = swf.movieSize;
2091 
2092     s = tag = swf_InsertTag(tag, ST_DEFINESPRITE);
2093     swf_SetU16(tag, id);
2094     swf_SetU16(tag, swf.frameCount);
2095 
2096     swf_Relocate(&swf, idmap);
2097 
2098     ftag = swf.firstTag;
2099     level = 1;
2100     while(ftag) {
2101 	int t;
2102 	for(t=0;t<sizeof(cutout)/sizeof(cutout[0]);t++)
2103 	    if(cutout[t] == ftag->id) {
2104 		ftag = ftag->next;
2105 		continue;
2106 	    }
2107 	if(ftag->id == ST_DEFINESPRITE && !swf_IsFolded(ftag))
2108 	    level++;
2109 	if(ftag->id == ST_END)
2110 	    level--;
2111 	if(!level)
2112 	    break;
2113 
2114 	if(ftag->id != ST_SETBACKGROUNDCOLOR) {
2115 	    /* We simply dump all tags right after the sprite
2116 	       header, relying on the fact that swf_OptimizeTagOrder() will
2117 	       sort things out for us later.
2118 	       We also rely on the fact that the imported SWF is well-formed.
2119 	     */
2120 	    tag = swf_InsertTag(tag, ftag->id);
2121 	    swf_SetBlock(tag, ftag->data, ftag->len);
2122 	}
2123 
2124 	ftag = ftag->next;
2125     }
2126     if(!ftag)
2127 	syntaxerror("Included file %s contains errors", filename);
2128     tag = swf_InsertTag(tag, ST_END);
2129 
2130     swf_FreeTags(&swf);
2131 
2132     s_addcharacter(name, id, tag, r);
2133 
2134     if(*as3name) {
2135         tag = swf_InsertTag(tag, ST_SYMBOLCLASS);
2136         swf_SetU16(tag, 1);
2137         swf_SetU16(tag, id);
2138         swf_SetString(tag, as3name);
2139     }
2140     incrementid();
2141 }
s_getCharBBox(const char * name)2142 SRECT s_getCharBBox(const char*name)
2143 {
2144     character_t* c = dict_lookup(&characters, name);
2145     if(!c) syntaxerror("character '%s' unknown(2)", name);
2146     return c->size;
2147 }
s_getInstanceBBox(const char * name)2148 SRECT s_getInstanceBBox(const char*name)
2149 {
2150     instance_t * i = dict_lookup(&instances, name);
2151     character_t * c;
2152     if(!i) syntaxerror("instance '%s' unknown(4)", name);
2153     c = i->character;
2154     if(!c) syntaxerror("internal error(5)");
2155     return c->size;
2156 }
s_getParameters(const char * name,parameters_t * p)2157 void s_getParameters(const char*name, parameters_t* p)
2158 {
2159     instance_t * i = dict_lookup(&instances, name);
2160     if(!i)
2161     	syntaxerror("instance '%s' unknown(10)", name);
2162     if(change_sets_all)
2163         readParameters(i->history, p, currentframe);
2164     else
2165     	*p = i->parameters;
2166 }
2167 
setStartparameters(instance_t * i,parameters_t * p,TAG * tag)2168 void setStartparameters(instance_t* i, parameters_t* p, TAG* tag)
2169 {
2170     history_begin(i->history, "x", currentframe, tag, p->x);
2171     history_begin(i->history, "y", currentframe, tag, p->y);
2172     history_begin(i->history, "scalex", currentframe, tag, p->scalex);
2173     history_begin(i->history, "scaley", currentframe, tag, p->scaley);
2174     history_begin(i->history, "cxform.r0", currentframe, tag, p->cxform.r0);
2175     history_begin(i->history, "cxform.g0", currentframe, tag, p->cxform.g0);
2176     history_begin(i->history, "cxform.b0", currentframe, tag, p->cxform.b0);
2177     history_begin(i->history, "cxform.a0", currentframe, tag, p->cxform.a0);
2178     history_begin(i->history, "cxform.r1", currentframe, tag, p->cxform.r1);
2179     history_begin(i->history, "cxform.g1", currentframe, tag, p->cxform.g1);
2180     history_begin(i->history, "cxform.b1", currentframe, tag, p->cxform.b1);
2181     history_begin(i->history, "cxform.a1", currentframe, tag, p->cxform.a1);
2182     history_begin(i->history, "rotate", currentframe, tag, p->rotate);
2183     history_begin(i->history, "shear", currentframe, tag, p->shear);
2184     history_begin(i->history, "pivot.x", currentframe, tag, p->pivot.x);
2185     history_begin(i->history, "pivot.y", currentframe, tag, p->pivot.y);
2186     history_begin(i->history, "pin.x", currentframe, tag, p->pin.x);
2187     history_begin(i->history, "pin.y", currentframe, tag, p->pin.y);
2188     history_begin(i->history, "blendmode", currentframe, tag, p->blendmode);
2189     history_beginFilter(i->history, currentframe, tag, p->filters);
2190     history_begin(i->history, "flags", currentframe, tag, 0);
2191 }
2192 
s_startclip(const char * instance,const char * character,parameters_t p)2193 void s_startclip(const char*instance, const char*character, parameters_t p)
2194 {
2195     character_t* c = dict_lookup(&characters, character);
2196     instance_t* i;
2197     MATRIX m;
2198     if(!c) {
2199 	syntaxerror("character %s not known", character);
2200     }
2201     i = s_addinstance(instance, c, currentdepth);
2202     i->parameters = p;
2203     m = s_instancepos(i->character->size, &p);
2204 
2205     tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
2206     /* TODO: should be ObjectPlaceClip, with clipdepth backpatched */
2207     swf_ObjectPlace(tag, c->id, currentdepth, &m, &p.cxform, instance);
2208 
2209     stack[stackpos].tag = tag;
2210     stack[stackpos].type = 2;
2211     stackpos++;
2212 
2213     setStartparameters(i, &p, tag);
2214     currentdepth++;
2215 }
s_endClip()2216 void s_endClip()
2217 {
2218     SWFPLACEOBJECT p;
2219     stackpos--;
2220     swf_SetTagPos(stack[stackpos].tag, 0);
2221     swf_GetPlaceObject(stack[stackpos].tag, &p);
2222     p.clipdepth = currentdepth;
2223     //p.name = 0;
2224     swf_ClearTag(stack[stackpos].tag);
2225     swf_SetPlaceObject(stack[stackpos].tag, &p);
2226     currentdepth++;
2227 }
2228 
s_put(const char * instance,const char * character,parameters_t p)2229 void s_put(const char*instance, const char*character, parameters_t p)
2230 {
2231     character_t* c = dict_lookup(&characters, character);
2232     instance_t* i;
2233     MATRIX m;
2234     if(!c)
2235         syntaxerror("character %s not known (in .put %s=%s)", character, instance, character);
2236 
2237     i = s_addinstance(instance, c, currentdepth);
2238     i->parameters = p;
2239     m = s_instancepos(i->character->size, &p);
2240 
2241     if(p.blendmode || p.filters)
2242     {
2243         if(stack[0].swf->fileVersion < 8)
2244         {
2245             if(p.blendmode)
2246                 warning("blendmodes only supported for flash version>=8");
2247             else
2248                 warning("filters only supported for flash version>=8");
2249         }
2250         tag = swf_InsertTag(tag, ST_PLACEOBJECT3);
2251 	}
2252     else
2253         tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
2254     setPlacement(tag, c->id, currentdepth, m, p.noinstancename ? NULL : instance, &p, 0);
2255     setStartparameters(i, &p, tag);
2256     currentdepth++;
2257 }
2258 
recordChanges(history_t * history,parameters_t p,int changeFunction,interpolation_t * inter)2259 void recordChanges(history_t* history, parameters_t p, int changeFunction, interpolation_t* inter)
2260 {
2261     if(p.set & SF_X)
2262         history_remember(history, "x", currentframe, changeFunction, p.x, inter);
2263     if(p.set & SF_Y)
2264         history_remember(history, "y", currentframe, changeFunction, p.y, inter);
2265     if(p.set & SF_SCALEX)
2266         history_remember(history, "scalex", currentframe, changeFunction, p.scalex, inter);
2267     if(p.set & SF_SCALEY)
2268         history_remember(history, "scaley", currentframe, changeFunction, p.scaley, inter);
2269     if(p.set & SF_CX_R)
2270     {
2271         history_remember(history, "cxform.r0", currentframe, changeFunction, p.cxform.r0, inter);
2272         history_remember(history, "cxform.r1", currentframe, changeFunction, p.cxform.r1, inter);
2273     }
2274     if(p.set & SF_CX_G)
2275     {
2276         history_remember(history, "cxform.g0", currentframe, changeFunction, p.cxform.g0, inter);
2277         history_remember(history, "cxform.g1", currentframe, changeFunction, p.cxform.g1, inter);
2278     }
2279     if(p.set & SF_CX_B)
2280     {
2281         history_remember(history, "cxform.b0", currentframe, changeFunction, p.cxform.b0, inter);
2282         history_remember(history, "cxform.b1", currentframe, changeFunction, p.cxform.b1, inter);
2283     }
2284     if(p.set & SF_CX_A)
2285     {
2286         history_remember(history, "cxform.a0", currentframe, changeFunction, p.cxform.a0, inter);
2287         history_remember(history, "cxform.a1", currentframe, changeFunction, p.cxform.a1, inter);
2288     }
2289     if(p.set & SF_ROTATE)
2290         history_remember(history, "rotate", currentframe, changeFunction, p.rotate, inter);
2291     if(p.set & SF_SHEAR)
2292         history_remember(history, "shear", currentframe, changeFunction, p.shear, inter);
2293     if(p.set & SF_PIVOT)
2294     {
2295         history_remember(history, "pivot.x", currentframe, changeFunction, p.pivot.x, inter);
2296         history_remember(history, "pivot.y", currentframe, changeFunction, p.pivot.y, inter);
2297     }
2298     if(p.set & SF_PIN)
2299     {
2300         history_remember(history, "pin.x", currentframe, changeFunction, p.pin.x, inter);
2301         history_remember(history, "pin.y", currentframe, changeFunction, p.pin.y, inter);
2302     }
2303     if(p.set & SF_BLEND)
2304         history_remember(history, "blendmode", currentframe, changeFunction, p.blendmode, inter);
2305     if(p.set & SF_FILTER)
2306         history_rememberFilter(history, currentframe, changeFunction, p.filters, inter);
2307 }
2308 
s_jump(const char * instance,parameters_t p)2309 void s_jump(const char* instance, parameters_t p)
2310 {
2311     instance_t* i = dict_lookup(&instances, instance);
2312     if(!i)
2313         syntaxerror("instance %s not known", instance);
2314     recordChanges(i->history, p, CF_JUMP, 0);
2315 }
2316 
s_change(const char * instance,parameters_t p,interpolation_t * inter)2317 void s_change(const char*instance, parameters_t p, interpolation_t* inter)
2318 {
2319     instance_t* i = dict_lookup(&instances, instance);
2320     if(!i)
2321         syntaxerror("instance %s not known", instance);
2322     recordChanges(i->history, p, CF_CHANGE, inter);
2323 }
2324 
s_sweep(const char * instance,parameters_t p,float radius,int clockwise,int short_arc,interpolation_t * inter)2325 void s_sweep(const char* instance, parameters_t p, float radius, int clockwise, int short_arc, interpolation_t* inter)
2326 {
2327     instance_t* i = dict_lookup(&instances, instance);
2328     if(!i)
2329         syntaxerror("instance %s not known", instance);
2330     history_rememberSweep(i->history, currentframe, p.x, p.y, radius, clockwise, short_arc, inter);
2331 }
2332 
s_toggle(const char * instance,U16 flagsOn,U16 flagsOff)2333 void s_toggle(const char* instance, U16 flagsOn, U16 flagsOff)
2334 {
2335     instance_t* i = dict_lookup(&instances, instance);
2336     if(!i)
2337         syntaxerror("instance %s not known", instance);
2338     U16 flags = (U16)history_value(i->history, currentframe, "flags");
2339     flags |= flagsOn;
2340     flags &= flagsOff;
2341     history_remember(i->history, "flags", currentframe, CF_JUMP, flags, 0);
2342 }
2343 
s_delinstance(const char * instance)2344 void s_delinstance(const char*instance)
2345 {
2346     instance_t* i = dict_lookup(&instances, instance);
2347     if(!i)
2348         syntaxerror("instance %s not known", instance);
2349     writeInstance(i);
2350     tag = swf_InsertTag(tag, ST_REMOVEOBJECT2);
2351     swf_SetU16(tag, i->depth);
2352     dict_del(&instances, instance);
2353     free(i);
2354 }
2355 
s_schange(const char * instance,parameters_t p,interpolation_t * inter)2356 void s_schange(const char*instance, parameters_t p, interpolation_t* inter)
2357 {
2358     instance_t* i = dict_lookup(&instances, instance);
2359     if(!i)
2360         syntaxerror("instance %s not known", instance);
2361     recordChanges(i->history, p, CF_SCHANGE, inter);
2362 }
2363 
s_end()2364 void s_end()
2365 {
2366     if(!stackpos)
2367 	syntaxerror(".end unexpected");
2368     switch (stack[stackpos-1].type)
2369     {
2370         case 0:
2371             s_endSWF();
2372             break;
2373         case 1:
2374             s_endSprite();
2375             break;
2376         case 2:
2377             s_endClip();
2378             break;
2379         case 3:
2380             s_endButton();
2381             break;
2382         default:
2383             syntaxerror("internal error 1");
2384     }
2385 }
2386 
2387 // ------------------------------------------------------------------------
2388 
2389 typedef int command_func_t(map_t*args);
2390 
parseBox(const char * str)2391 SRECT parseBox(const char*str)
2392 {
2393     SRECT r = {0,0,0,0};
2394     float xmin, xmax, ymin, ymax;
2395     char*x = strchr(str, 'x');
2396     char*d1=0,*d2=0;
2397     if(!strcmp(str, "autocrop")) {
2398 	r.xmin = r.ymin = r.xmax = r.ymax = 0;
2399 	return r;
2400     }
2401     if(!x) goto error;
2402     d1 = strchr(x+1, ':');
2403     if(d1)
2404 	d2 = strchr(d1+1, ':');
2405     if(!d1) {
2406 	if(sscanf(str, "%fx%f", &xmax, &ymax) < 2)
2407 	    goto error;
2408 	xmin = ymin = 0;
2409     }
2410     else if(d1 && !d2) {
2411 	if(sscanf(str, "%fx%f:%f", &xmax, &ymax, &xmin) < 3)
2412 	    goto error;
2413 	xmax += xmin;
2414 	ymin = 0;
2415     }
2416     else {
2417 	if(sscanf(str, "%fx%f:%f:%f", &xmax, &ymax, &xmin, &ymin) < 4)
2418 	    goto error;
2419 	xmax += xmin;
2420 	ymax += ymin;
2421     }
2422     r.xmin = (SCOORD)(xmin*20);
2423     r.ymin = (SCOORD)(ymin*20);
2424     r.xmax = (SCOORD)(xmax*20);
2425     r.ymax = (SCOORD)(ymax*20);
2426     return r;
2427 error:
2428     syntaxerror("expression %s is not a valid bound Box.\nE.g. 1024x768 or 1024x768:30:30 would have been valid bounding Boxes.", str);
2429     return r;
2430 }
parseFloat(const char * str)2431 float parseFloat(const char*str)
2432 {
2433     return atof(str);
2434 }
parseInt(const char * str)2435 int parseInt(const char*str)
2436 {
2437     int t;
2438     int l=strlen(str);
2439     int s=0;
2440     if(str[0]=='+' || str[0]=='-')
2441 	s++;
2442 
2443     for(t=s;t<l;t++)
2444 	if(str[t]<'0' || str[t]>'9')
2445 	    syntaxerror("Not an Integer: \"%s\"", str);
2446     return atoi(str);
2447 }
parseRawTwip(const char * str)2448 static double parseRawTwip(const char*str)
2449 {
2450     char*dot;
2451     int sign=1;
2452     if(str[0]=='+' || str[0]=='-') {
2453 	if(str[0]=='-')
2454 	    sign = -1;
2455 	str++;
2456     }
2457     dot = strchr(str, '.');
2458     if(!dot) {
2459 	int l=strlen(str);
2460 	int t;
2461 	return sign*parseInt(str);
2462     } else {
2463 	char* old = strdup(str);
2464 	int l=strlen(dot+1);
2465 	const char*s;
2466 	*dot++ = 0;
2467 	for(s=str;s<dot-1;s++) {
2468             if(*s<'0' || *s>'9')
2469             {
2470                 free(old);
2471                 syntaxerror("Not a coordinate: \"%s\"", str);
2472             }
2473         }
2474         for(s=dot;*s;s++) {
2475             if(*s<'0' || *s>'9')
2476             {
2477                 free(old);
2478                 syntaxerror("Not a coordinate: \"%s\"", str);
2479             }
2480         }
2481 	if(l>2 || (l==2 && (dot[1]!='0' && dot[1]!='5'))) {
2482 	    dot[1] = ((dot[1]-0x30)/5)*5 + 0x30;
2483 	    dot[2] = 0;
2484 	    l=2;
2485 	    warning("precision loss: %s converted to twip: %s.%s", old, str, dot);
2486 	}
2487 	free(old);
2488 	if(l==0)
2489 	    return sign*(atoi(str));
2490 	if(l==1)
2491 	    return sign*(atoi(str)+0.1*atoi(dot));
2492 	if(l==2)
2493 	    return sign*(atoi(str)+0.01*atoi(dot));
2494     }
2495     return 0;
2496 }
2497 
2498 static dict_t defines;
2499 static int defines_initialized = 0;
2500 static mem_t define_values;
2501 
parseNameOrTwip(const char * s)2502 static double parseNameOrTwip(const char*s)
2503 {
2504     int l = 0;
2505     double v;
2506     if(defines_initialized) {
2507         l = PTR_AS_INT(dict_lookup(&defines, s));
2508     }
2509     if(l) {
2510         return *(int*)&define_values.buffer[l-1];
2511     } else {
2512         return parseRawTwip(s);
2513     }
2514 }
2515 
2516 /* automatically generated by yiyiyacc, http://www.quiss.org/yiyiyacc/ */
parseExpression(char * s)2517 static double parseExpression(char*s)
2518 {
2519     int chr2index[256];
2520     memset(chr2index, -1, sizeof(chr2index));
2521     chr2index['+'] = 0;
2522     chr2index['-'] = 1;
2523     chr2index['*'] = 2;
2524     chr2index['/'] = 3;
2525     chr2index['('] = 5;
2526     chr2index[')'] = 6;
2527     chr2index['\0'] = 7;
2528 
2529     int stackpos = 1;
2530     int stack[256];
2531     double values[256];
2532     stack[0]=0;
2533     values[0]=0;
2534     int accept = 18;
2535     int left[10]={11,8,8,8,8,9,9,9,10,10}; //production left side
2536     int plen[10]={1,3,2,3,1,3,3,1,1,3}; //production size
2537     int table[18][12] = {
2538         {0, 4, 0, 0, 5, 6, 0, 0, 1, 2, 3, 0},
2539         {7, 8, 0, 0, 0, 0, 0, 18, 0, 0, 0, 0},
2540         {-4, -4, 9, 10, 0, 0, -4, -4, 0, 0, 0, 0},
2541         {-7, -7, -7, -7, 0, 0, -7, -7, 0, 0, 0, 0},
2542         {0, 0, 0, 0, 5, 6, 0, 0, 0, 11, 3, 0},
2543         {-8, -8, -8, -8, 0, 0, -8, -8, 0, 0, 0, 0},
2544         {0, 4, 0, 0, 5, 6, 0, 0, 12, 2, 3, 0},
2545         {0, 0, 0, 0, 5, 6, 0, 0, 0, 13, 3, 0},
2546         {0, 0, 0, 0, 5, 6, 0, 0, 0, 14, 3, 0},
2547         {0, 0, 0, 0, 5, 6, 0, 0, 0, 0, 15, 0},
2548         {0, 0, 0, 0, 5, 6, 0, 0, 0, 0, 16, 0},
2549         {-2, -2, 9, 10, 0, 0, -2, -2, 0, 0, 0, 0},
2550         {7, 8, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0},
2551         {-1, -1, 9, 10, 0, 0, -1, -1, 0, 0, 0, 0},
2552         {-3, -3, 9, 10, 0, 0, -3, -3, 0, 0, 0, 0},
2553         {-5, -5, -5, -5, 0, 0, -5, -5, 0, 0, 0, 0},
2554         {-6, -6, -6, -6, 0, 0, -6, -6, 0, 0, 0, 0},
2555         {-9, -9, -9, -9, 0, 0, -9, -9, 0, 0, 0, 0}};
2556 
2557     char*p = s;
2558     while(1) {
2559         char*pnext = p+1;
2560         int action;
2561         double value = 0;
2562         if(!stackpos) {
2563             fprintf(stderr, "Error in expression\n");
2564             return 0.0;
2565         }
2566 
2567         if(chr2index[*p]<0) {
2568             action = table[stack[stackpos-1]][4];
2569             if(action>0) {
2570                 while(chr2index[*pnext]<0)
2571                     pnext++;
2572                 char save = *pnext;
2573                 *pnext = 0;
2574                 value = parseNameOrTwip(p);
2575                 *pnext = save;
2576             }
2577         } else {
2578             action = table[stack[stackpos-1]][chr2index[*p]];
2579         }
2580 
2581         if(action == accept) {
2582             return values[stack[stackpos-1]];
2583         } else if(action>0) { // shift
2584             if(stackpos>254) {
2585                 fprintf(stderr, "Stack overflow while parsing expression\n");
2586                 return 0.0;
2587             }
2588             values[stackpos]=value;
2589             stack[stackpos++]=action;
2590             p=pnext;
2591         } else if(action<0) { // reduce
2592             stackpos-=plen[-action];
2593             stack[stackpos] = table[stack[stackpos-1]][left[-action]];
2594             switch(-action) {
2595               case 1:
2596                 values[stackpos] = values[stackpos+0] + values[stackpos+2];
2597               break;
2598               case 2:
2599                 values[stackpos] = 0 - values[stackpos+1];
2600               break;
2601               case 3:
2602                 values[stackpos] = values[stackpos+0] - values[stackpos+2];
2603               break;
2604               case 5:
2605                 values[stackpos] = values[stackpos+0] * values[stackpos+2];
2606               break;
2607               case 6:
2608                 values[stackpos] = values[stackpos+0] / values[stackpos+2];
2609               break;
2610               case 9:
2611                 values[stackpos] = values[stackpos+1];
2612               break;
2613             }
2614             stackpos++;
2615         } else {
2616             fprintf(stderr, "Syntax error in expression\n");
2617             return 0.0;
2618         }
2619     }
2620 }
2621 
parseTwip(const char * str)2622 int parseTwip(const char*str)
2623 {
2624     char*str2 = (char*)str;
2625     int v = (int)(parseExpression(str2)*20);
2626     return v;
2627 }
2628 
parseArc(const char * str)2629 int parseArc(const char* str)
2630 {
2631     if(!strcmp(str, "short"))
2632     	return 1;
2633     if(!strcmp(str, "long"))
2634     	return 0;
2635     syntaxerror("invalid value for the arc parameter: %s", str);
2636     return 1;
2637 }
2638 
parseDir(const char * str)2639 int parseDir(const char* str)
2640 {
2641     if(!strcmp(str, "clockwise"))
2642     	return 1;
2643     if(!strcmp(str, "counterclockwise"))
2644     	return 0;
2645     syntaxerror("invalid value for the dir parameter: %s", str);
2646     return 1;
2647 }
2648 
isPoint(const char * str)2649 int isPoint(const char*str)
2650 {
2651     if(strchr(str, '('))
2652 	return 1;
2653     else
2654 	return 0;
2655 }
2656 
parsePoint(const char * str)2657 SPOINT parsePoint(const char*str)
2658 {
2659     SPOINT p;
2660     char tmp[80];
2661     int l = strlen(str);
2662     char*comma = strchr(str, ',');
2663     if(str[0]!='(' || str[l-1]!=')' || !comma || l>70)
2664 	syntaxerror("\"%s\" is not a valid point of the form (x,y)", str);
2665     strncpy(tmp, str+1, comma-(str+1));tmp[comma-(str+1)]=0;
2666     p.x = parseTwip(tmp);
2667     strncpy(tmp, comma+1, l-1-(comma+1-str));tmp[l-1-(comma+1-str)]=0;
2668     p.y = parseTwip(tmp);
2669     return p;
2670 }
2671 
parseColor2(const char * str,RGBA * color)2672 int parseColor2(const char*str, RGBA*color)
2673 {
2674     int l = strlen(str);
2675     int r,g,b,a;
2676     int t;
2677 
2678     struct {unsigned char r,g,b;char*name;} colors[] =
2679     {{255,250,250,"snow"},{220,220,220,"gainsboro"},{250,240,230,"linen"},{255,228,196,"bisque"},
2680     {255,228,181,"moccasin"},{255,248,220,"cornsilk"},{255,255,240,"ivory"},{255,245,238,"seashell"},
2681     {240,255,240,"honeydew"},{240,255,255,"azure"},{230,230,250,"lavender"},{255,255,255,"white"},
2682     {0,0,0,"black"},{190,190,190,"gray"},{190,190,190,"grey"},{0,0,128,"navy"},{0,0,255,"blue"},
2683     {64,224,208,"turquoise"},{0,255,255,"cyan"},{127,255,212,"aquamarine"}, {0,255,0,"green"},
2684     {127,255,0,"chartreuse"},{240,230,140,"khaki"},{255,255,0,"yellow"},
2685     {255,215,0,"gold"},{218,165,32,"goldenrod"},{160,82,45,"sienna"},{205,133,63,"peru"},
2686     {222,184,135,"burlywood"},{245,245,220,"beige"},{245,222,179,"wheat"},{210,180,140,"tan"},
2687     {210,105,30,"chocolate"},{178,34,34,"firebrick"},{165,42,42,"brown"},{250,128,114,"salmon"},
2688     {255,165,0,"orange"},{255,127,80,"coral"},{255,99,71,"tomato"},{255,0,0,"red"},
2689     {255,192,203,"pink"},{176,48,96,"maroon"},{255,0,255,"magenta"},{238,130,238,"violet"},
2690     {221,160,221,"plum"},{218,112,214,"orchid"},{160,32,240,"purple"},{216,191,216,"thistle"}};
2691 
2692     a=255;r=g=b=0;
2693 
2694     if(str[0]=='#' && (l==7 || l==9)) {
2695 	if(l == 7 && !(sscanf(str, "#%02x%02x%02x", &r, &g, &b)))
2696 	    return 0;
2697 	if(l == 9 && !(sscanf(str, "#%02x%02x%02x%02x", &r, &g, &b, &a)))
2698 	    return 0;
2699 	color->r = r; color->g = g; color->b = b; color->a = a;
2700 	return 1;
2701     }
2702     int len=strlen(str);
2703     int alpha = 255;
2704     if(strchr(str, '/')) {
2705 	len = strchr(str, '/')-str;
2706 	sscanf(str+len+1,"%02x", &alpha);
2707     }
2708     for(t=0;t<sizeof(colors)/sizeof(colors[0]);t++)
2709 	if(!strncmp(str, colors[t].name, len)) {
2710 	    r = colors[t].r;
2711 	    g = colors[t].g;
2712 	    b = colors[t].b;
2713 	    a = alpha;
2714 	    color->r = r; color->g = g; color->b = b; color->a = a;
2715 	    return 1;
2716 	}
2717     return 0;
2718 
2719 }
parseColor(const char * str)2720 RGBA parseColor(const char*str)
2721 {
2722     RGBA c;
2723     if(!parseColor2(str, &c))
2724 	syntaxerror("Expression '%s' is not a color", str);
2725     return c;
2726 }
2727 
2728 typedef struct _muladd {
2729     S16 mul;
2730     S16 add;
2731 } MULADD;
2732 
parseMulAdd(const char * str)2733 MULADD parseMulAdd(const char*str)
2734 {
2735     float add, mul;
2736     char* str2 = (char*)malloc(strlen(str)+5);
2737     int i;
2738     MULADD m;
2739     strcpy(str2, str);
2740     strcat(str2, " 0");
2741     add = 0;
2742     mul = 1.0;
2743     if(sscanf(str2, "%f%f %d", &mul, &add, &i)==2+1) { add/=256.0; i=1;}
2744     else if(sscanf(str2, "%f%%%f %d", &mul, &add, &i)==2+1) { mul/=100.0; add/=256.0; i=2;}
2745     else if(sscanf(str2, "%f%f%% %d", &mul, &add, &i)==2+1) { add/=100.0; i=3;}
2746     else if(sscanf(str2, "%f%%%f%% %d", &mul, &add, &i)==2+1) { mul/=100.0; add/=100.0; i=4;}
2747     else if(sscanf(str2, "+%f%% %d", &add, &i)==1+1) { mul=1.0;add/=100.0; i=5;}
2748     else if(sscanf(str2, "+%f %d", &add, &i)==1+1) { mul=1.0;add/=256.0; i=6;}
2749     else if(sscanf(str2, "-%f%% %d", &add, &i)==1+1) { mul=1.0;add/=-100.0; i=7;}
2750     else if(sscanf(str2, "-%f %d", &add, &i)==1+1) { mul=1.0;add/=-256.0; i=8;}
2751     else if(sscanf(str2, "%f%% %d", &mul, &i)==1+1) { mul/=100.0;add=0; i=9;}
2752     else if(sscanf(str2, "%f %d", &mul, &i)==1+1) { add=0; i=10;}
2753     else {
2754 	syntaxerror("'%s' is not a valid color transform expression", str);
2755     }
2756     m.add = (int)(add*256);
2757     m.mul = (int)(mul*256);
2758     free(str2);
2759     return m;
2760 }
2761 
mergeMulAdd(MULADD m1,MULADD m2)2762 MULADD mergeMulAdd(MULADD m1, MULADD m2)
2763 {
2764     int a = (int)((double)m2.add+((double)m1.add*(double)m2.mul)/256.0);
2765     double m = ((double)m1.mul*(double)m2.mul)/256.0;
2766     MULADD r;
2767     if(a<-32768) a=-32768;
2768     if(a>32767) a=32767;
2769     if(m<-32768) m=-32768;
2770     if(m>32767) m=32767;
2771     r.add = a;
2772     r.mul = (int)m;
2773     return r;
2774 }
2775 
parsePxOrPercent(const char * fontname,const char * str)2776 float parsePxOrPercent(const char*fontname, const char*str)
2777 {
2778     int l = strlen(str);
2779     if(strchr(str, '%'))
2780 	return parsePercent(str);
2781     if(l>2 && str[l-2]=='p' && str[l-1]=='t') {
2782 	float p = atof(str);
2783 	return p/64.0; /*64 = FT_SUBPIXELS- see ../lib/modules/swffont.c */
2784     }
2785     syntaxerror("Expression '%s' is neither a point size (?pt) nor a percentage (?%)", str);
2786     return 0;
2787 }
2788 
parsePercent(const char * str)2789 float parsePercent(const char*str)
2790 {
2791     int l = strlen(str);
2792     if(!l)
2793 	return 1.0;
2794     if(str[l-1]=='%') {
2795 	return atof(str)/100.0;
2796     }
2797     syntaxerror("Expression '%s' is not a percentage", str);
2798     return 0;
2799 }
isPercent(const char * str)2800 int isPercent(const char*str)
2801 {
2802     return str[strlen(str)-1]=='%';
2803 }
parseNewSize(const char * str,int size)2804 int parseNewSize(const char*str, int size)
2805 {
2806     if(isPercent(str))
2807 	return parsePercent(str)*size;
2808     else
2809 	return (int)(atof(str)*20);
2810 }
2811 
isColor(char * str)2812 int isColor(char*str)
2813 {
2814     RGBA c;
2815     return parseColor2(str, &c);
2816 }
2817 
lu(map_t * args,char * name)2818 static const char* lu(map_t* args, char*name)
2819 {
2820     const char* value = map_lookup(args, name);
2821     if(!value) {
2822 	map_dump(args, stdout, "");
2823 	syntaxerror("internal error 2: value %s should be set", name);
2824     }
2825     return value;
2826 }
2827 
c_flash(map_t * args)2828 static int c_flash(map_t*args)
2829 {
2830     const char* filename = map_lookup(args, "filename");
2831     const char* compressstr = lu(args, "compress");
2832     const char* change_modestr = lu(args, "change-sets-all");
2833     const char* exportstr = lu(args, "export");
2834     SRECT bbox = parseBox(lu(args, "bbox"));
2835     int version = parseInt(lu(args, "version"));
2836     int fps = (int)(parseFloat(lu(args, "fps"))*256);
2837     RGBA color = parseColor(lu(args, "background"));
2838     int compress = 0;
2839 
2840     if(!filename || !*filename) {
2841 	/* for compatibility */
2842 	filename = map_lookup(args, "name");
2843 	if(!filename || !*filename) {
2844 	    filename = 0;
2845 	} else {
2846 	    //msg("<warning> line %d: .flash name=... is deprecated, use .flash filename=...", line);
2847 	    msg("<notice> line %d: .flash name=... is deprecated, use .flash filename=...", line);
2848 	}
2849     }
2850 
2851     if(!filename || override_outputname)
2852 	filename = outputname;
2853 
2854     if(!strcmp(compressstr, "default"))
2855 	compress = version>=6;
2856     else if(!strcmp(compressstr, "yes") || !strcmp(compressstr, "compress"))
2857 	compress = 1;
2858     else if(!strcmp(compressstr, "no"))
2859 	compress = 0;
2860     else syntaxerror("value \"%s\" not supported for the compress argument", compressstr);
2861 
2862     if(!strcmp(change_modestr, "yes"))
2863 	change_sets_all = 1;
2864     else
2865 	if(strcmp(change_modestr, "no"))
2866 	    syntaxerror("value \"%s\" not supported for the change-sets-all argument", change_modestr);
2867 
2868     do_exports=atoi(exportstr);
2869     mainclass=strdup(lu(args, "mainclass"));
2870 
2871     s_swf(filename, bbox, version, fps, compress, color);
2872     return 0;
2873 }
isRelative(const char * str)2874 int isRelative(const char*str)
2875 {
2876     return !strncmp(str, "<plus>", 6) ||
2877 	   !strncmp(str, "<minus>", 7);
2878 }
getOffset(const char * str)2879 const char* getOffset(const char*str)
2880 {
2881     if(!strncmp(str, "<plus>", 6))
2882 	return str+6;
2883     if(!strncmp(str, "<minus>", 7))
2884 	return str+7;
2885     syntaxerror("internal error (347)");
2886     return 0;
2887 }
getSign(const char * str)2888 int getSign(const char*str)
2889 {
2890     if(!strncmp(str, "<plus>", 6))
2891 	return 1;
2892     if(!strncmp(str, "<minus>", 7))
2893 	return -1;
2894     syntaxerror("internal error (348)");
2895     return 0;
2896 }
2897 
2898 static dict_t points;
2899 static mem_t mpoints;
2900 static int points_initialized = 0;
2901 
c_interpolation(map_t * args)2902 static int c_interpolation(map_t *args)
2903 {
2904     int i;
2905     const char* name = lu(args, "name");
2906     if(dict_lookup(&interpolations, name))
2907         syntaxerror("interpolation %s defined twice", name);
2908 
2909     interpolation_t* inter = (interpolation_t*)malloc(sizeof(interpolation_t));
2910     const char* functionstr = lu(args, "function");
2911     inter->function = 0;
2912     for (i = 0; i < sizeof(interpolationFunctions) / sizeof(interpolationFunctions[0]); i++)
2913         if(!strcmp(functionstr,interpolationFunctions[i]))
2914         {
2915             inter->function = i + 1;
2916             break;
2917         }
2918     if(!inter->function)
2919         syntaxerror("unknown interpolation function %s", functionstr);
2920     inter->speed = parseFloat(lu(args, "speed"));
2921     inter->amplitude = parseTwip(lu(args, "amplitude"));
2922     inter->growth = parseFloat(lu(args, "growth"));
2923     inter->bounces = parseInt(lu(args, "bounces"));
2924     inter->damping = parseFloat(lu(args, "damping"));
2925     inter->slope = parseFloat(lu(args, "slope"));
2926 
2927     dict_put(&interpolations, name, inter);
2928     return 0;
2929 }
2930 
getPoint(SRECT r,const char * name)2931 SPOINT getPoint(SRECT r, const char*name)
2932 {
2933     int l=0;
2934     if(!strcmp(name, "center")) {
2935         SPOINT p;
2936         p.x = (r.xmin + r.xmax)/2;
2937         p.y = (r.ymin + r.ymax)/2;
2938         return p;
2939     }
2940     if(!strcmp(name, "bottom-center")) {
2941         SPOINT p;
2942         p.x = (r.xmin + r.xmax)/2;
2943         p.y = r.ymax;
2944         return p;
2945     }
2946     if(!strcmp(name, "top-center")) {
2947         SPOINT p;
2948         p.x = (r.xmin + r.xmax)/2;
2949         p.y = r.ymin;
2950         return p;
2951     }
2952     if(!strcmp(name, "top-left")) {
2953         SPOINT p;
2954         p.x = r.xmin;
2955         p.y = r.ymin;
2956         return p;
2957     }
2958     if(!strcmp(name, "top-right")) {
2959         SPOINT p;
2960         p.x = r.xmax;
2961         p.y = r.ymin;
2962         return p;
2963     }
2964     if(!strcmp(name, "bottom-right")) {
2965         SPOINT p;
2966         p.x = r.xmax;
2967         p.y = r.ymax;
2968         return p;
2969     }
2970     if(!strcmp(name, "bottom-left")) {
2971         SPOINT p;
2972         p.x = r.xmin;
2973         p.y = r.ymax;
2974         return p;
2975     }
2976     if(!strcmp(name, "left-center")) {
2977         SPOINT p;
2978         p.x = r.xmin;
2979         p.y = (r.ymin + r.ymax)/2;
2980         return p;
2981     }
2982     if(!strcmp(name, "right-center")) {
2983         SPOINT p;
2984         p.x = r.xmax;
2985         p.y = (r.ymin + r.ymax)/2;
2986         return p;
2987     }
2988 
2989 
2990     if(points_initialized)
2991         l = PTR_AS_INT(dict_lookup(&points, name));
2992     if(l==0) {
2993         syntaxerror("Invalid point: \"%s\".", name);
2994     }
2995     return *(SPOINT*)&mpoints.buffer[l-1];
2996 }
2997 
2998 
texture2(const char * name,const char * object,map_t * args,int errors)2999 static int texture2(const char*name, const char*object, map_t*args, int errors)
3000 {
3001     SPOINT pos,size;
3002     const char*xstr = map_lookup(args, "x");
3003     const char*ystr = map_lookup(args, "y");
3004     const char*widthstr = map_lookup(args, "width");
3005     const char*heightstr = map_lookup(args, "height");
3006     const char*scalestr = map_lookup(args, "scale");
3007     const char*scalexstr = map_lookup(args, "scalex");
3008     const char*scaleystr = map_lookup(args, "scaley");
3009     const char*rotatestr = map_lookup(args, "rotate");
3010     const char* shearstr = map_lookup(args, "shear");
3011     const char* radiusstr = map_lookup(args, "r");
3012     float x=0,y=0;
3013     float scalex = 1.0, scaley = 1.0;
3014     float rotate=0, shear=0;
3015     float r = 0;
3016     if(!*xstr && !*ystr) {
3017 	if(errors)
3018 	    syntaxerror("x and y must be set");
3019 	return 0;
3020     }
3021     if(*scalestr && (*scalexstr || *scaleystr)) {
3022 	syntaxerror("scale and scalex/scaley can't both be set");
3023 	return 0;
3024     }
3025     if((*widthstr || *heightstr) && *radiusstr) {
3026 	syntaxerror("width/height and radius can't both be set");
3027     }
3028     if(*radiusstr) {
3029 	widthstr = radiusstr;
3030 	heightstr = radiusstr;
3031     }
3032     if(!*xstr) xstr="0";
3033     if(!*ystr) ystr="0";
3034     if(!*rotatestr) rotatestr="0";
3035     if(!*shearstr) shearstr="0";
3036 
3037     if(*scalestr) {
3038 	scalex = scaley = parsePercent(scalestr);
3039     } else if(*scalexstr || *scaleystr) {
3040 	if(scalexstr) scalex = parsePercent(scalexstr);
3041 	if(scaleystr) scaley = parsePercent(scaleystr);
3042     } else if(*widthstr || *heightstr) {
3043 	int width=0;
3044 	int height=0;
3045 	s_getBitmapSize(object, &width, &height);
3046 	if(*widthstr)
3047 	    scalex = (float)parseTwip(widthstr)/(float)width;
3048 	if(*heightstr)
3049 	    scaley = (float)parseTwip(heightstr)/(float)height;
3050     }
3051     x = parseTwip(xstr);
3052     y = parseTwip(ystr);
3053     rotate = parseFloat(rotatestr);
3054     shear = parseFloat(shearstr);
3055 
3056     s_texture(name, object, x,y,scalex,scaley,rotate, shear);
3057 
3058     return 0;
3059 }
3060 
c_texture(map_t * args)3061 static int c_texture(map_t*args)
3062 {
3063     const char*name = lu(args, "instance");
3064     const char*object = lu(args, "character");
3065     return texture2(name, object, args, 1);
3066 }
3067 
c_gradient(map_t * args)3068 static int c_gradient(map_t*args)
3069 {
3070     const char*name = lu(args, "name");
3071     int radial= strcmp(lu(args, "radial"), "radial")?0:1;
3072     int rotate = parseInt(lu(args, "rotate"));
3073 
3074     readToken();
3075     if(type != RAWDATA)
3076         syntaxerror("colon (:) expected");
3077 
3078     if(dict_lookup(&gradients, name))
3079         syntaxerror("gradient %s defined twice", name);
3080 
3081     s_gradient(name, text, radial, rotate);
3082 
3083     /* check whether we also have placement information,
3084        which would make this a positioned gradient.
3085        If there is placement information, texture2() will
3086        add a texture, which has priority over the gradient.
3087      */
3088     texture2(name, name, args, 0);
3089     return 0;
3090 }
3091 
checkFiltername(map_t * args)3092 static const char* checkFiltername(map_t* args)
3093 {
3094     const char* name = lu(args, "name");
3095     if(strchr(name, ','))
3096     	syntaxerror("the comma (,) is used to separate filters in filterlists. Please do not use in filternames.");
3097     return name;
3098 }
3099 
c_blur(map_t * args)3100 static int c_blur(map_t*args)
3101 {
3102     const char*name = checkFiltername(args);
3103     const char*blurstr = lu(args, "blur");
3104     const char*blurxstr = lu(args, "blurx");
3105     const char*blurystr = lu(args, "blury");
3106     float blurx=1.0, blury=1.0;
3107     if(blurstr[0]) {
3108 	blurx = parseFloat(blurstr);
3109 	blury = parseFloat(blurstr);
3110     }
3111     if(blurxstr[0])
3112 	blurx = parseFloat(blurxstr);
3113     if(blurystr[0])
3114 	blury = parseFloat(blurystr);
3115     int passes = parseInt(lu(args, "passes"));
3116     s_blur(name, blurx, blury, passes);
3117     return 0;
3118 }
3119 
c_gradientglow(map_t * args)3120 static int c_gradientglow(map_t*args)
3121 {
3122     const char*name = checkFiltername(args);
3123     const char*gradient = lu(args, "gradient");
3124     const char*blurstr = lu(args, "blur");
3125     const char*blurxstr = lu(args, "blurx");
3126     const char*blurystr = lu(args, "blury");
3127     float blurx=1.0, blury=1.0;
3128     if(blurstr[0]) {
3129 	blurx = parseFloat(blurstr);
3130 	blury = parseFloat(blurstr);
3131     }
3132     if(blurxstr[0])
3133 	blurx = parseFloat(blurxstr);
3134     if(blurystr[0])
3135 	blury = parseFloat(blurystr);
3136 
3137     float angle = parseFloat(lu(args, "angle")) / 180 * M_PI;
3138     float distance = parseFloat(lu(args, "distance"));
3139     float strength = parseFloat(lu(args, "strength"));
3140     char innershadow = strcmp(lu(args, "innershadow"),"innershadow")?0:1;
3141     char knockout = strcmp(lu(args, "knockout"),"knockout")?0:1;
3142     char composite = strcmp(lu(args, "composite"),"composite")?0:1;
3143     char ontop = strcmp(lu(args, "ontop"),"ontop")?0:1;
3144     int passes = parseInt(lu(args, "passes"));
3145 
3146     s_gradientglow(name, gradient, blurx, blury, angle, distance, strength, innershadow, knockout, composite, ontop, passes);
3147     return 0;
3148 }
3149 
c_dropshadow(map_t * args)3150 static int c_dropshadow(map_t*args)
3151 {
3152     const char*name = checkFiltername(args);
3153     RGBA color = parseColor(lu(args, "color"));
3154     const char*blurstr = lu(args, "blur");
3155     const char*blurxstr = lu(args, "blurx");
3156     const char*blurystr = lu(args, "blury");
3157     float blurx=1.0, blury=1.0;
3158     if(blurstr[0]) {
3159 	blurx = parseFloat(blurstr);
3160 	blury = parseFloat(blurstr);
3161     }
3162     if(blurxstr[0])
3163 	blurx = parseFloat(blurxstr);
3164     if(blurystr[0])
3165 	blury = parseFloat(blurystr);
3166 
3167     float angle = parseFloat(lu(args, "angle")) / 180 * M_PI;
3168     float distance = parseFloat(lu(args, "distance"));
3169     float strength = parseFloat(lu(args, "strength"));
3170     char innershadow = strcmp(lu(args, "innershadow"),"innershadow")?0:1;
3171     char knockout = strcmp(lu(args, "knockout"),"knockout")?0:1;
3172     char composite = strcmp(lu(args, "composite"),"composite")?0:1;
3173     int passes = parseInt(lu(args, "passes"));
3174 
3175     s_dropshadow(name, color, blurx, blury, angle, distance, strength, innershadow, knockout, composite, passes);
3176     return 0;
3177 }
3178 
c_bevel(map_t * args)3179 static int c_bevel(map_t*args)
3180 {
3181     const char*name = checkFiltername(args);
3182     RGBA shadow = parseColor(lu(args, "shadow"));
3183     RGBA highlight = parseColor(lu(args, "highlight"));
3184     const char*blurstr = lu(args, "blur");
3185     const char*blurxstr = lu(args, "blurx");
3186     const char*blurystr = lu(args, "blury");
3187     float blurx=1.0, blury=1.0;
3188     if(blurstr[0]) {
3189 	blurx = parseFloat(blurstr);
3190 	blury = parseFloat(blurstr);
3191     }
3192     if(blurxstr[0])
3193 	blurx = parseFloat(blurxstr);
3194     if(blurystr[0])
3195 	blury = parseFloat(blurystr);
3196 
3197     float angle = parseFloat(lu(args, "angle")) / 180 * M_PI;
3198     float distance = parseFloat(lu(args, "distance"));
3199     float strength = parseFloat(lu(args, "strength"));
3200     char innershadow = strcmp(lu(args, "innershadow"),"innershadow")?0:1;
3201     char knockout = strcmp(lu(args, "knockout"),"knockout")?0:1;
3202     char composite = strcmp(lu(args, "composite"),"composite")?0:1;
3203     char ontop = strcmp(lu(args, "ontop"),"ontop")?0:1;
3204     int passes = parseInt(lu(args, "passes"));
3205 
3206     s_bevel(name, shadow, highlight, blurx, blury, angle, distance, strength, innershadow, knockout, composite, ontop, passes);
3207     return 0;
3208 }
3209 
c_define(map_t * args)3210 static int c_define(map_t*args)
3211 {
3212     const char*name = lu(args, "name");
3213     const char*value = lu(args, "value");
3214 
3215     if(!defines_initialized) {
3216 	dict_init(&defines, 16);
3217 	mem_init(&define_values);
3218 	defines_initialized = 1;
3219     }
3220     int val = parseTwip(value);
3221     int pos = mem_put(&define_values, &val, sizeof(val));
3222     dict_put(&defines, name, INT_AS_PTR(pos + 1));
3223     return 0;
3224 }
c_point(map_t * args)3225 static int c_point(map_t*args)
3226 {
3227     const char*name = lu(args, "name");
3228     int pos;
3229     SPOINT p;
3230     if(!points_initialized) {
3231 	dict_init(&points, 16);
3232 	mem_init(&mpoints);
3233 	points_initialized = 1;
3234     }
3235     p.x = parseTwip(lu(args, "x"));
3236     p.y = parseTwip(lu(args, "y"));
3237     pos = mem_put(&mpoints, &p, sizeof(p));
3238     dict_put(&points, name, INT_AS_PTR(pos+1));
3239     return 0;
3240 }
c_play(map_t * args)3241 static int c_play(map_t*args)
3242 {
3243     const char*name = lu(args, "name");
3244     const char*loop = lu(args, "loop");
3245     const char*nomultiple = lu(args, "nomultiple");
3246     int nm = 0;
3247     if(!strcmp(nomultiple, "nomultiple"))
3248 	nm = 1;
3249     else
3250 	nm = parseInt(nomultiple);
3251 
3252     if(s_playsound(name, parseInt(loop), nm, 0)) {
3253 	return 0;
3254     } else if(s_swf3action(name, "play")) {
3255 	return 0;
3256     }
3257     return 0;
3258 }
3259 
c_stop(map_t * args)3260 static int c_stop(map_t*args)
3261 {
3262     const char*name = map_lookup(args, "name");
3263 
3264     if(s_playsound(name, 0,0,1))
3265         return 0;
3266     else if(s_swf3action(name, "stop"))
3267         return 0;
3268     syntaxerror("I don't know anything about sound/movie \"%s\"", name);
3269 	return 0;
3270 }
3271 
c_nextframe(map_t * args)3272 static int c_nextframe(map_t*args)
3273 {
3274     const char*name = lu(args, "name");
3275 
3276     if(s_swf3action(name, "nextframe")) {
3277 	return 0;
3278     }
3279     syntaxerror("I don't know anything about movie \"%s\"", name);
3280     return 0;
3281 }
3282 
c_previousframe(map_t * args)3283 static int c_previousframe(map_t*args)
3284 {
3285     const char*name = lu(args, "name");
3286 
3287     if(s_swf3action(name, "previousframe")) {
3288 	return 0;
3289     }
3290     syntaxerror("I don't know anything about movie \"%s\"", name);
3291     return 0;
3292 }
3293 
c_movement(map_t * args,int type)3294 static int c_movement(map_t*args, int type)
3295 {
3296     const char*instance = lu(args, "name");
3297 
3298     const char* xstr="";
3299     const char* ystr="";
3300     SRECT oldbbox;
3301     parameters_t p;
3302     U16 set = 0x0000;
3303 
3304     xstr = lu(args, "x");
3305     ystr = lu(args, "y");
3306 
3307     s_getParameters(instance, &p);
3308 
3309     /* x,y position */
3310     if(xstr[0])
3311     {
3312         if(isRelative(xstr))
3313         {
3314             if(type == PT_PUT || type == PT_STARTCLIP)
3315                 syntaxerror("relative x values not allowed for initial put or startclip");
3316             p.x += parseTwip(getOffset(xstr))*getSign(xstr);
3317         }
3318         else
3319         {
3320             p.x = parseTwip(xstr);
3321         }
3322         set = set | SF_X;
3323      }
3324     if(ystr[0])
3325     {
3326         if(isRelative(ystr))
3327         {
3328             if(type == PT_PUT || type == PT_STARTCLIP)
3329                 syntaxerror("relative y values not allowed for initial put or startclip");
3330             p.y += parseTwip(getOffset(ystr))*getSign(ystr);
3331         }
3332         else
3333         {
3334             p.y = parseTwip(ystr);
3335         }
3336         set = set | SF_Y;
3337     }
3338 
3339     if(change_sets_all)
3340 	set = SF_ALL;
3341     p.set = set;
3342 
3343     switch (type)
3344     {
3345         case PT_MOVE:
3346             {
3347                 const char* interstr = lu(args, "interpolation");
3348                 interpolation_t* inter = (interpolation_t*)dict_lookup(&interpolations, interstr);
3349                 if(!inter)
3350                     syntaxerror("unknown interpolation %s", interstr);
3351                 s_change(instance, p, inter);
3352             }
3353             break;
3354         case PT_SMOVE:
3355             {
3356                 const char* interstr = lu(args, "interpolation");
3357                 interpolation_t* inter = (interpolation_t*)dict_lookup(&interpolations, interstr);
3358                 if(!inter)
3359                     syntaxerror("unknown interpolation %s", interstr);
3360             	s_schange(instance, p, inter);
3361             }
3362             break;
3363         case PT_SWEEP:
3364             {
3365             	const char* rstr = lu(args, "r");
3366             	int radius = parseTwip(rstr);
3367             	if(radius <= 0)
3368             		syntaxerror("sweep not possible: radius must be greater than 0.");
3369             	const char* dirstr = lu(args, "dir");
3370             	int clockwise = parseDir(dirstr);
3371             	const char* arcstr = lu(args, "arc");
3372             	int short_arc = parseArc(arcstr);
3373                 const char* interstr = lu(args, "interpolation");
3374                 interpolation_t* inter = (interpolation_t*)dict_lookup(&interpolations, interstr);
3375                 if(!inter)
3376                     syntaxerror("unknown interpolation %s", interstr);
3377             	s_sweep(instance, p, radius, clockwise, short_arc, inter);
3378             }
3379             break;
3380 	}
3381     return 0;
3382 }
3383 
c_placement(map_t * args,int type)3384 static int c_placement(map_t*args, int type)
3385 {
3386     const char*instance = lu(args, (type==PT_PUT||type==PT_STARTCLIP)?"instance":"name");
3387     const char*character = 0;
3388 
3389     const char* luminancestr = lu(args, "luminance");
3390     const char* scalestr = lu(args, "scale");
3391     const char* scalexstr = lu(args, "scalex");
3392     const char* scaleystr = lu(args, "scaley");
3393     const char* rotatestr = lu(args, "rotate");
3394     const char* shearstr = lu(args, "shear");
3395     const char* xstr="", *pivotstr="";
3396     const char* ystr="", *anglestr="";
3397     const char*above = lu(args, "above"); /*FIXME*/
3398     const char*below = lu(args, "below");
3399     const char* rstr = lu(args, "red");
3400     const char* gstr = lu(args, "green");
3401     const char* bstr = lu(args, "blue");
3402     const char* astr = lu(args, "alpha");
3403     const char* pinstr = lu(args, "pin");
3404     const char* as = map_lookup(args, "as");
3405     const char* blendmode = lu(args, "blend");
3406     const char* filterstr = lu(args, "filter");
3407     const char* noinstancenamestr = "";
3408     U8 blend;
3409     MULADD r,g,b,a;
3410     float oldwidth;
3411     float oldheight;
3412     SRECT oldbbox;
3413     MULADD luminance;
3414     parameters_t p;
3415     U16 set = 0x0000;
3416 
3417     if(type==PT_PUT)
3418         noinstancenamestr = lu(args, "noinstancename");
3419 
3420     if(type==9)
3421     { // (?) .rotate  or .arcchange
3422         pivotstr = lu(args, "pivot");
3423         anglestr = lu(args, "angle");
3424     }
3425     else
3426     {
3427         xstr = lu(args, "x");
3428         ystr = lu(args, "y");
3429     }
3430 
3431     if(luminancestr[0])
3432         luminance = parseMulAdd(luminancestr);
3433     else
3434     {
3435         luminance.add = 0;
3436         luminance.mul = 256;
3437     }
3438 
3439     if(scalestr[0])
3440     {
3441         if(scalexstr[0]||scaleystr[0])
3442             syntaxerror("scalex/scaley and scale cannot both be set");
3443         scalexstr = scaleystr = scalestr;
3444     }
3445 
3446     if(type == PT_PUT || type == PT_STARTCLIP)  {
3447 	// put or startclip
3448 	character = lu(args, "character");
3449 	parameters_clear(&p);
3450     } else if(type == PT_BUTTON) {
3451 	character = lu(args, "name");
3452 	parameters_clear(&p);
3453 	// button's show
3454     } else {
3455 	s_getParameters(instance, &p);
3456     }
3457 
3458     /* noinstancename */
3459     p.noinstancename = !strcmp(noinstancenamestr, "noinstancename");
3460 
3461     /* x,y position */
3462     if(xstr[0])
3463     {
3464         if(isRelative(xstr))
3465         {
3466             if(type == PT_PUT || type == PT_STARTCLIP)
3467                 syntaxerror("relative x values not allowed for initial put or startclip");
3468             p.x += parseTwip(getOffset(xstr))*getSign(xstr);
3469         }
3470         else
3471         {
3472             p.x = parseTwip(xstr);
3473         }
3474         set = set | SF_X;
3475      }
3476     if(ystr[0])
3477     {
3478         if(isRelative(ystr))
3479         {
3480             if(type == PT_PUT || type == PT_STARTCLIP)
3481                 syntaxerror("relative y values not allowed for initial put or startclip");
3482             p.y += parseTwip(getOffset(ystr))*getSign(ystr);
3483         }
3484         else
3485         {
3486             p.y = parseTwip(ystr);
3487         }
3488         set = set | SF_Y;
3489 	}
3490 
3491     /* scale, scalex, scaley */
3492     if(character)
3493         oldbbox = s_getCharBBox(character);
3494     else
3495         oldbbox = s_getInstanceBBox(instance);
3496     oldwidth = oldbbox.xmax - oldbbox.xmin;
3497     oldheight = oldbbox.ymax - oldbbox.ymin;
3498     if(scalexstr[0])
3499     {
3500         if(oldwidth==0)
3501             p.scalex = 1.0;
3502         else
3503             if(scalexstr[0])
3504                 p.scalex = (float)(parseNewSize(scalexstr, oldwidth))/oldwidth;
3505         set = set | SF_SCALEX;
3506     }
3507    if(scaleystr[0])
3508    {
3509         if(oldheight==0)
3510             p.scaley = 1.0;
3511         else
3512             if(scaleystr[0])
3513                 p.scaley = (float)(parseNewSize(scaleystr, oldheight))/oldheight;
3514         set = set | SF_SCALEY;
3515    }
3516 
3517     /* rotation */
3518     if(rotatestr[0])
3519     {
3520         if(isRelative(rotatestr))
3521             p.rotate += parseFloat(getOffset(rotatestr))*getSign(rotatestr);
3522         else
3523             p.rotate = parseFloat(rotatestr);
3524         set = set | SF_ROTATE;
3525 	}
3526 
3527     /* shearing */
3528     if(shearstr[0])
3529     {
3530         if(isRelative(shearstr))
3531             p.shear += parseFloat(getOffset(shearstr))*getSign(shearstr);
3532         else
3533             p.shear = parseFloat(shearstr);
3534         set = set | SF_SHEAR;
3535     }
3536 
3537     if(pivotstr[0])
3538     {
3539         if(isPoint(pivotstr))
3540             p.pivot = parsePoint(pivotstr);
3541         else
3542             p.pivot = getPoint(oldbbox, pivotstr);
3543         set = set | SF_PIVOT;
3544     }
3545 
3546     if(pinstr[0])
3547     {
3548         if(isPoint(pinstr))
3549             p.pin = parsePoint(pinstr);
3550         else
3551             p.pin = getPoint(oldbbox, pinstr);
3552         set = set | SF_PIN;
3553     }
3554 
3555     /* color transform */
3556 
3557     if(rstr[0] || luminancestr[0])
3558     {
3559         MULADD r;
3560         if(rstr[0])
3561             r = parseMulAdd(rstr);
3562         else
3563         {
3564             r.add = p.cxform.r0;
3565             r.mul = p.cxform.r1;
3566         }
3567         r = mergeMulAdd(r, luminance);
3568         p.cxform.r0 = r.mul;
3569         p.cxform.r1 = r.add;
3570         set = set | SF_CX_R;
3571 	}
3572     if(gstr[0] || luminancestr[0])
3573     {
3574         MULADD g;
3575         if(gstr[0])
3576             g = parseMulAdd(gstr);
3577         else
3578         {
3579             g.add = p.cxform.g0;
3580             g.mul = p.cxform.g1;
3581         }
3582         g = mergeMulAdd(g, luminance);
3583         p.cxform.g0 = g.mul;
3584         p.cxform.g1 = g.add;
3585         set = set | SF_CX_G;
3586     }
3587     if(bstr[0] || luminancestr[0])
3588     {
3589         MULADD b;
3590         if(bstr[0])
3591             b = parseMulAdd(bstr);
3592         else
3593         {
3594             b.add = p.cxform.b0;
3595             b.mul = p.cxform.b1;
3596         }
3597         b = mergeMulAdd(b, luminance);
3598         p.cxform.b0 = b.mul;
3599         p.cxform.b1 = b.add;
3600         set = set | SF_CX_B;
3601     }
3602     if(astr[0])
3603     {
3604         MULADD a = parseMulAdd(astr);
3605         p.cxform.a0 = a.mul;
3606         p.cxform.a1 = a.add;
3607         set = set | SF_CX_A;
3608     }
3609 
3610     if(blendmode[0])
3611     {
3612         int t;
3613         blend = 255;
3614         for(t = 0; blendModeNames[t]; t++)
3615         {
3616             if(!strcmp(blendModeNames[t], blendmode))
3617             {
3618                 blend = t;
3619                 break;
3620             }
3621         }
3622         if(blend == 255)
3623         {
3624             syntaxerror("unknown blend mode: '%s'", blendmode);
3625         }
3626         p.blendmode = blend;
3627         set = set | SF_BLEND;
3628 	}
3629 
3630     if(filterstr[0])
3631     {
3632         p.filters = parseFilters((char*)filterstr);
3633         set = set | SF_FILTER;
3634     }
3635 
3636     if(type == PT_CHANGE && set & (SF_X | SF_Y))
3637 	warning("As of version 0.8.2 using the .change command to modify an \
3638 object's position on the stage is considered deprecated. Future \
3639 versions may consider x and y parameters for the .change command \
3640 to be illegal; please use the .move command.");
3641 
3642     if(change_sets_all)
3643 	set = SF_ALL;
3644     p.set = set;
3645 
3646     switch (type)
3647     {
3648         case PT_PUT:
3649             s_put(instance, character, p);
3650             break;
3651         case PT_CHANGE:
3652             {
3653                 const char* interstr = lu(args, "interpolation");
3654                 interpolation_t* inter = (interpolation_t*)dict_lookup(&interpolations, interstr);
3655                 if(!inter)
3656                     syntaxerror("unknown interpolation %s", interstr);
3657                 s_change(instance, p, inter);
3658             }
3659             break;
3660         case PT_SCHANGE:
3661             {
3662                 const char* interstr = lu(args, "interpolation");
3663                 interpolation_t* inter = (interpolation_t*)dict_lookup(&interpolations, interstr);
3664                 if(!inter)
3665                     syntaxerror("unknown interpolation %s", interstr);
3666             	s_schange(instance, p, inter);
3667             }
3668             break;
3669         case PT_JUMP:
3670             s_jump(instance, p);
3671             break;
3672         case PT_STARTCLIP:
3673             s_startclip(instance, character, p);
3674             break;
3675         case PT_BUTTON:
3676             if(as && as[0])
3677                 s_buttonput(character, as, p);
3678             else
3679                 s_buttonput(character, "shape", p);
3680             break;
3681 //        default:
3682 	}
3683     return 0;
3684 }
c_put(map_t * args)3685 static int c_put(map_t*args)
3686 {
3687     c_placement(args, PT_PUT);
3688     return 0;
3689 }
c_change(map_t * args)3690 static int c_change(map_t*args)
3691 {
3692     if(currentframe == 0)
3693         warning("change commands in frame 1 will be ignored, please use the put command to set object parameters");
3694     c_placement(args, PT_CHANGE);
3695     return 0;
3696 }
c_schange(map_t * args)3697 static int c_schange(map_t*args)
3698 {
3699     c_placement(args, PT_SCHANGE);
3700     return 0;
3701 }
c_move(map_t * args)3702 static int c_move(map_t* args)
3703 {
3704     c_movement(args, PT_MOVE);
3705     return 0;
3706 }
c_smove(map_t * args)3707 static int c_smove(map_t* args)
3708 {
3709     c_movement(args, PT_SMOVE);
3710     return 0;
3711 }
c_sweep(map_t * args)3712 static int c_sweep(map_t* args)
3713 {
3714     c_movement(args, PT_SWEEP);
3715     return 0;
3716 }
c_arcchange(map_t * args)3717 static int c_arcchange(map_t*args)
3718 {
3719     c_placement(args, 0);
3720     return 0;
3721 }
c_jump(map_t * args)3722 static int c_jump(map_t*args)
3723 {
3724     c_placement(args, PT_JUMP);
3725     return 0;
3726 }
c_startclip(map_t * args)3727 static int c_startclip(map_t*args)
3728 {
3729     c_placement(args, PT_STARTCLIP);
3730     return 0;
3731 }
c_show(map_t * args)3732 static int c_show(map_t*args)
3733 {
3734     c_placement(args, PT_BUTTON);
3735     return 0;
3736 }
c_toggle(map_t * args)3737 static int c_toggle(map_t* args)
3738 {
3739     const char*instance = lu(args, "name");
3740     U16 flagsOn = 0x0000, flagsOff = 0xffff;
3741     const char* alignstr = lu(args, "fixed_alignment");
3742     if(!strcmp(alignstr, "on"))
3743     	flagsOn += IF_FIXED_ALIGNMENT;
3744     else
3745     	if(!strcmp(alignstr, "off"))
3746     	    flagsOff -= IF_FIXED_ALIGNMENT;
3747     	else
3748     	    syntaxerror("values for toggle must be \"on\" or \"off\". %s is not legal.", alignstr);
3749     s_toggle(instance, flagsOn, flagsOff);
3750     return 0;
3751 }
c_del(map_t * args)3752 static int c_del(map_t*args)
3753 {
3754     const char*instance = lu(args, "name");
3755     s_delinstance(instance);
3756     return 0;
3757 }
c_end(map_t * args)3758 static int c_end(map_t*args)
3759 {
3760     s_end();
3761     return 0;
3762 }
c_sprite(map_t * args)3763 static int c_sprite(map_t*args)
3764 {
3765     const char* name = lu(args, "name");
3766     const char* scalinggrid = lu(args, "scalinggrid");
3767     const char* as3name = lu(args, "as3name");
3768 
3769     if(scalinggrid && *scalinggrid) {
3770 	SRECT r = parseBox(scalinggrid);
3771 	s_sprite(name, &r, as3name);
3772     } else {
3773 	s_sprite(name, 0, as3name);
3774     }
3775     return 0;
3776 }
c_frame(map_t * args)3777 static int c_frame(map_t*args)
3778 {
3779     const char*framestr = lu(args, "n");
3780     const char*cutstr = lu(args, "cut");
3781 
3782     const char*name = lu(args, "name");
3783     const char*anchor = lu(args, "anchor");
3784     char buf[40];
3785 
3786     if(!strcmp(anchor, "anchor") && !*name)
3787 	name = framestr;
3788 
3789     int frame;
3790     int cut = 0;
3791     if(strcmp(cutstr, "no"))
3792 	cut = 1;
3793     if(isRelative(framestr)) {
3794 	frame = s_getframe();
3795 	if(getSign(framestr)<0)
3796 	    syntaxerror("relative frame expressions must be positive");
3797 	frame += parseInt(getOffset(framestr));
3798     }
3799     else {
3800 	frame = parseInt(framestr);
3801 	if(s_getframe() >= frame
3802 		&& !(frame==1 && s_getframe()==frame)) // equality is o.k. for frame 0
3803 	    syntaxerror("frame expression must be >%d (is:%s)", s_getframe(), framestr);
3804     }
3805     s_frame(frame, cut, name, !strcmp(anchor, "anchor"));
3806     return 0;
3807 }
c_primitive(map_t * args)3808 static int c_primitive(map_t*args)
3809 {
3810     const char*name = lu(args, "name");
3811     const char*command = lu(args, "commandname");
3812     int width=0, height=0, r=0;
3813     int linewidth = parseTwip(lu(args, "line"));
3814     const char*colorstr = lu(args, "color");
3815     RGBA color = parseColor(colorstr);
3816     const char*fillstr = lu(args, "fill");
3817     int dofill = 1;
3818     int type=0;
3819     const char* font;
3820     const char* text;
3821     const char* outline=0;
3822     RGBA fill;
3823     if(!strcmp(command, "circle"))
3824 	type = 1;
3825     else if(!strcmp(command, "filled"))
3826 	type = 2;
3827 
3828     if(type==0) {
3829 	width = parseTwip(lu(args, "width"));
3830 	height = parseTwip(lu(args, "height"));
3831     } else if(type==1) {
3832 	r = parseTwip(lu(args, "r"));
3833     } else if(type==2) {
3834 	outline = lu(args, "outline");
3835     }
3836 
3837     if(!strcmp(fillstr, "fill"))
3838 	fillstr = colorstr;
3839     if(!strcmp(fillstr, "none"))
3840 	fillstr = 0;
3841     if(width<0 || height<0 || linewidth<0 || r<0)
3842 	syntaxerror("values width, height, line, r must be positive");
3843 
3844     if(type == 0) s_box(name, width, height, color, linewidth, fillstr);
3845     else if(type==1) s_circle(name, r, color, linewidth, fillstr);
3846     else if(type==2) s_filled(name, outline, color, linewidth, fillstr);
3847     return 0;
3848 }
3849 
c_textshape(map_t * args)3850 static int c_textshape(map_t*args)
3851 {
3852     const char*name = lu(args, "name");
3853     const char*text = lu(args, "text");
3854     const char*font = lu(args, "font");
3855     float size = parsePxOrPercent(font, lu(args, "size"));
3856 
3857     s_textshape(name, font, size, text);
3858     return 0;
3859 }
3860 
c_swf(map_t * args)3861 static int c_swf(map_t*args)
3862 {
3863     const char*name = lu(args, "name");
3864     const char*filename = lu(args, "filename");
3865     const char*command = lu(args, "commandname");
3866     const char*as3name = lu(args, "as3name");
3867 
3868     if(!strcmp(command, "shape"))
3869 	warning("Please use .swf instead of .shape");
3870     s_includeswf(name, filename, as3name);
3871     return 0;
3872 }
3873 
c_font(map_t * args)3874 static int c_font(map_t*args)
3875 {
3876     const char*name = lu(args, "name");
3877     const char*filename = lu(args, "filename");
3878     s_font(name, filename);
3879     return 0;
3880 }
3881 
c_sound(map_t * args)3882 static int c_sound(map_t*args)
3883 {
3884     const char*name = lu(args, "name");
3885     const char*filename = lu(args, "filename");
3886     s_sound(name, filename);
3887     return 0;
3888 }
3889 
c_text(map_t * args)3890 static int c_text(map_t*args)
3891 {
3892     const char*name = lu(args, "name");
3893     const char*text = lu(args, "text");
3894     const char*font = lu(args, "font");
3895     float size = parsePxOrPercent(font, lu(args, "size"));
3896     RGBA color = parseColor(lu(args, "color"));
3897     s_text(name, font, text, (int)(size*100), color);
3898     return 0;
3899 }
3900 
c_soundtrack(map_t * args)3901 static int c_soundtrack(map_t*args)
3902 {
3903     return 0;
3904 }
3905 
c_quicktime(map_t * args)3906 static int c_quicktime(map_t*args)
3907 {
3908     const char*name = lu(args, "name");
3909     const char*url = lu(args, "url");
3910     s_quicktime(name, url);
3911     return 0;
3912 }
3913 
c_video(map_t * args)3914 static int c_video(map_t*args)
3915 {
3916     const char*name = lu(args, "name");
3917     int width = parseInt(lu(args, "width"));
3918     int height = parseInt(lu(args, "height"));
3919     s_video(name, width, height);
3920     return 0;
3921 }
3922 
c_image(map_t * args)3923 static int c_image(map_t*args)
3924 {
3925     const char*command = lu(args, "commandname");
3926     const char*name = lu(args, "name");
3927     const char*filename = lu(args, "filename");
3928     if(!strcmp(command,"jpeg")) {
3929 	int quality = (int)(parsePercent(lu(args, "quality"))*100);
3930 	s_image(name, "jpeg", filename, quality);
3931     } else {
3932 	s_image(name, "png", filename, 0);
3933     }
3934     return 0;
3935 }
3936 
c_outline(map_t * args)3937 static int c_outline(map_t*args)
3938 {
3939     const char*name = lu(args, "name");
3940     const char*format = lu(args, "format");
3941 
3942     readToken();
3943     if(type != RAWDATA)
3944 	syntaxerror("colon (:) expected");
3945 
3946     s_outline(name, format, text);
3947     return 0;
3948 }
3949 
fakechar(map_t * args)3950 int fakechar(map_t*args)
3951 {
3952     const char*name = lu(args, "name");
3953     s_box(name, 0, 0, black, 20, 0);
3954     return 0;
3955 }
3956 
c_egon(map_t * args)3957 static int c_egon(map_t*args) {return fakechar(args);}
c_button(map_t * args)3958 static int c_button(map_t*args) {
3959     const char*name = lu(args, "name");
3960     const char*as3name = lu(args, "as3name");
3961     s_button(name, as3name);
3962     return 0;
3963 }
3964 static int current_button_flags = 0;
c_on_press(map_t * args)3965 static int c_on_press(map_t*args)
3966 {
3967     const char*position = lu(args, "position");
3968     const char*action = "";
3969     if(!strcmp(position, "inside")) {
3970 	current_button_flags |= BC_OVERUP_OVERDOWN;
3971     } else if(!strcmp(position, "outside")) {
3972 	//current_button_flags |= BC_IDLE_OUTDOWN;
3973 	syntaxerror("IDLE_OVERDOWN not supported by SWF");
3974     } else if(!strcmp(position, "anywhere")) {
3975 	current_button_flags |= /*BC_IDLE_OUTDOWN|*/BC_OVERUP_OVERDOWN|BC_IDLE_OVERDOWN;
3976     }
3977     readToken();
3978     if(type == RAWDATA) {
3979 	action = text;
3980 	s_buttonaction(current_button_flags, action);
3981 	current_button_flags = 0;
3982     }
3983     else
3984 	pushBack();
3985     return 0;
3986 }
c_on_release(map_t * args)3987 static int c_on_release(map_t*args)
3988 {
3989     const char*position = lu(args, "position");
3990     const char*action = "";
3991     if(!strcmp(position, "inside")) {
3992 	current_button_flags |= BC_OVERDOWN_OVERUP;
3993     } else if(!strcmp(position, "outside")) {
3994 	current_button_flags |= BC_OUTDOWN_IDLE;
3995     } else if(!strcmp(position, "anywhere")) {
3996 	current_button_flags |= BC_OVERDOWN_OVERUP|BC_OUTDOWN_IDLE|BC_OVERDOWN_IDLE;
3997     }
3998     readToken();
3999     if(type == RAWDATA) {
4000 	action = text;
4001 	s_buttonaction(current_button_flags, action);
4002 	current_button_flags = 0;
4003     }
4004     else
4005 	pushBack();
4006     return 0;
4007 }
c_on_move_in(map_t * args)4008 static int c_on_move_in(map_t*args)
4009 {
4010     const char*position = lu(args, "state");
4011     const char*action = "";
4012     if(!strcmp(position, "pressed")) {
4013 	current_button_flags |= BC_OUTDOWN_OVERDOWN;
4014     } else if(!strcmp(position, "not_pressed")) {
4015 	current_button_flags |= BC_IDLE_OVERUP;
4016     } else if(!strcmp(position, "any")) {
4017 	current_button_flags |= BC_OUTDOWN_OVERDOWN|BC_IDLE_OVERUP|BC_IDLE_OVERDOWN;
4018     }
4019     readToken();
4020     if(type == RAWDATA) {
4021 	action = text;
4022 	s_buttonaction(current_button_flags, action);
4023 	current_button_flags = 0;
4024     }
4025     else
4026 	pushBack();
4027     return 0;
4028 }
c_on_move_out(map_t * args)4029 static int c_on_move_out(map_t*args)
4030 {
4031     const char*position = lu(args, "state");
4032     const char*action = "";
4033     if(!strcmp(position, "pressed")) {
4034 	current_button_flags |= BC_OVERDOWN_OUTDOWN;
4035     } else if(!strcmp(position, "not_pressed")) {
4036 	current_button_flags |= BC_OVERUP_IDLE;
4037     } else if(!strcmp(position, "any")) {
4038 	current_button_flags |= BC_OVERDOWN_OUTDOWN|BC_OVERUP_IDLE|BC_OVERDOWN_IDLE;
4039     }
4040     readToken();
4041     if(type == RAWDATA) {
4042 	action = text;
4043 	s_buttonaction(current_button_flags, action);
4044 	current_button_flags = 0;
4045     }
4046     else
4047 	pushBack();
4048     return 0;
4049 }
c_on_key(map_t * args)4050 static int c_on_key(map_t*args)
4051 {
4052     const char*key = lu(args, "key");
4053     const char*action = "";
4054     if(strlen(key)==1) {
4055 	/* ascii */
4056 	if(key[0]>=32) {
4057 	    current_button_flags |= 0x4000 + (key[0]*0x200);
4058 	} else {
4059 	    syntaxerror("invalid character: %c",key[0]);
4060 	    return 1;
4061 	}
4062     } else {
4063 	/* TODO:
4064 	   <ctrl-x> = 0x200*(x-'a')
4065 	   esc = = 0x3600
4066 	   space = = 0x4000;
4067 	*/
4068 	syntaxerror("invalid key: %s",key);
4069     }
4070     readToken();
4071     if(type == RAWDATA) {
4072 	action = text;
4073 	s_buttonaction(current_button_flags, action);
4074 	current_button_flags = 0;
4075     }
4076     else
4077 	pushBack();
4078     return 0;
4079 }
4080 
c_edittext(map_t * args)4081 static int c_edittext(map_t*args)
4082 {
4083  //"name font size width height text="" color=black maxlength=0 variable="" @password=0 @wordwrap=0 @multiline=0 @html=0 @noselect=0 @readonly=0 @autosize=0"},
4084     const char*name = lu(args, "name");
4085     const char*font = lu(args, "font");
4086     int size = (int)(1024*parsePxOrPercent(font, lu(args, "size")));
4087     int width = parseTwip(lu(args, "width"));
4088     int height = parseTwip(lu(args, "height"));
4089     const char*text  = lu(args, "text");
4090     RGBA color = parseColor(lu(args, "color"));
4091     int maxlength = parseInt(lu(args, "maxlength"));
4092     const char*variable = lu(args, "variable");
4093     const char*passwordstr = lu(args, "password");
4094     const char*wordwrapstr = lu(args, "wordwrap");
4095     const char*multilinestr = lu(args, "multiline");
4096     const char*htmlstr = lu(args, "html");
4097     const char*noselectstr = lu(args, "noselect");
4098     const char*readonlystr = lu(args, "readonly");
4099     const char*borderstr = lu(args, "border");
4100     const char*autosizestr = lu(args, "autosize");
4101     const char*alignstr = lu(args, "align");
4102     int align = -1;
4103 
4104     int flags = 0;
4105     if(!strcmp(passwordstr, "password")) flags |= ET_PASSWORD;
4106     if(!strcmp(wordwrapstr, "wordwrap")) flags |= ET_WORDWRAP;
4107     if(!strcmp(multilinestr, "multiline")) flags |= ET_MULTILINE;
4108     if(!strcmp(readonlystr, "readonly")) flags |= ET_READONLY;
4109     if(!strcmp(htmlstr, "html")) flags |= ET_HTML;
4110     if(!strcmp(noselectstr, "noselect")) flags |= ET_NOSELECT;
4111     if(!strcmp(borderstr, "border")) flags |= ET_BORDER;
4112     if(!strcmp(autosizestr, "autosize")) flags |= ET_AUTOSIZE;
4113     if(!strcmp(alignstr, "left") || !*alignstr) align = ET_ALIGN_LEFT;
4114     else if(!strcmp(alignstr, "right")) align = ET_ALIGN_RIGHT;
4115     else if(!strcmp(alignstr, "center")) align = ET_ALIGN_CENTER;
4116     else if(!strcmp(alignstr, "justify")) align = ET_ALIGN_JUSTIFY;
4117     else syntaxerror("Unknown alignment: %s", alignstr);
4118 
4119     s_edittext(name, font, size, width, height, text, &color, maxlength, variable, flags, align);
4120     return 0;
4121 }
4122 
c_morphshape(map_t * args)4123 static int c_morphshape(map_t*args) {return fakechar(args);}
c_movie(map_t * args)4124 static int c_movie(map_t*args) {return fakechar(args);}
4125 
readfile(char * filename)4126 static char* readfile(char*filename)
4127 {
4128     FILE*fi = fopen(filename, "rb");
4129     int l;
4130     char*text;
4131     if(!fi)
4132 	syntaxerror("Couldn't find file %s: %s", filename, strerror(errno));
4133     fseek(fi, 0, SEEK_END);
4134     l = ftell(fi);
4135     fseek(fi, 0, SEEK_SET);
4136     text = rfx_alloc(l+1);
4137     int r = fread(text, l, 1, fi);
4138     if(r<1)
4139 	syntaxerror("Couldn't read file %s: %s", filename, strerror(errno));
4140     text[l]=0;
4141     fclose(fi);
4142     return text;
4143 }
4144 
c_action(map_t * args)4145 static int c_action(map_t*args)
4146 {
4147     const char* filename  = map_lookup(args, "filename");
4148     if(!filename ||!*filename) {
4149 	readToken();
4150 	if(type != RAWDATA) {
4151 	    syntaxerror("colon (:) expected");
4152 	}
4153 	s_action(text);
4154     } else {
4155 	s_action(readfile((char*)filename));
4156     }
4157 
4158     return 0;
4159 }
4160 
c_initaction(map_t * args)4161 static int c_initaction(map_t*args)
4162 {
4163     const char* character = lu(args, "name");
4164     const char* filename  = map_lookup(args, "filename");
4165     if(!filename ||!*filename) {
4166 	readToken();
4167 	if(type != RAWDATA) {
4168 	    syntaxerror("colon (:) expected");
4169 	}
4170 	s_initaction(character, text);
4171     } else {
4172 	s_initaction(character, readfile((char*)filename));
4173     }
4174 
4175     return 0;
4176 }
4177 
4178 static struct {
4179     char*command;
4180     command_func_t* func;
4181     char*arguments;
4182 } arguments[] =
4183 {{"flash", c_flash, "bbox=autocrop background=black version=6 fps=50 name= filename= @compress=default @change-sets-all=no @export=1 @mainclass="},
4184  {"frame", c_frame, "n=<plus>1 name= @cut=no @anchor=no"},
4185  // "import" type stuff
4186  {"swf", c_swf, "name filename as3name="},
4187  {"shape", c_swf, "name filename"},
4188  {"jpeg", c_image, "name filename quality=80%"},
4189  {"png", c_image, "name filename"},
4190  {"movie", c_movie, "name filename"},
4191  {"sound", c_sound, "name filename"},
4192  {"font", c_font, "name filename glyphs= @flashtype="},
4193  {"soundtrack", c_soundtrack, "filename"},
4194  {"quicktime", c_quicktime, "url"},
4195  {"video", c_video, "name width= height="},
4196 
4197     // generators of primitives
4198 
4199  {"define", c_define, "name value=0"},
4200  {"point", c_point, "name x=0 y=0"},
4201  {"gradient", c_gradient, "name @radial=0 rotate=0 scale= scalex= scaley= x= y= width= height= r= shear="}, //extra parameters like .texture
4202  {"interpolation", c_interpolation, "name function=linear speed=1.3 amplitude=0 bounces=2 growth=1.5 damping=2 slope=0"},
4203  {"outline", c_outline, "name format=simple"},
4204  {"textshape", c_textshape, "name font size=100% text"},
4205 
4206     // filters
4207  {"blur", c_blur, "name blur= blurx= blury= passes=1"},
4208  {"gradientglow", c_gradientglow, "name gradient blur= blurx= blury= angle=0.0 distance=0.0 strength=1.0 @innershadow=0 @knockout=0 @composite=0 @ontop=0 passes=1"},
4209  {"dropshadow", c_dropshadow, "name color blur= blurx= blury= angle=0.0 distance=0.0 strength=1.0 @innershadow=0 @knockout=0 @composite=0 passes=1"},
4210  {"bevel", c_bevel, "name shadow highlight blur= blurx= blury= angle=0.0 distance=0.0 strength=1.0 @innershadow=0 @knockout=0 @composite=0 @ontop=0 passes=1"},
4211 
4212     // character generators
4213  {"box", c_primitive, "name width height color=white line=1 @fill=none"},
4214  {"circle", c_primitive, "name r color=white line=1 @fill=none"},
4215  {"filled", c_primitive, "name outline color=white line=1 @fill=none"},
4216 
4217  {"egon", c_egon, "name vertices color=white line=1 @fill=none"},
4218  {"text", c_text, "name text font size=100% color=white"},
4219  {"edittext", c_edittext, "name font= size=100% width height text="" color=white maxlength=0 variable="" @password=0 @wordwrap=0 @multiline=0 @html=0 @noselect=0 @readonly=0 @border=0 @autosize=0 align="},
4220  {"morphshape", c_morphshape, "name start end"},
4221  {"button", c_button, "name as3name="},
4222     {"show", c_show,             "name x=0 y=0 red=+0 green=+0 blue=+0 alpha=+0 luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below= as="},
4223     {"on_press", c_on_press, "position=inside"},
4224     {"on_release", c_on_release, "position=anywhere"},
4225     {"on_move_in", c_on_move_in, "state=not_pressed"},
4226     {"on_move_out", c_on_move_out, "state=not_pressed"},
4227     {"on_key", c_on_key, "key=any"},
4228 
4229     // control tags
4230  {"play", c_play, "name loop=0 @nomultiple=0"},
4231  {"stop", c_stop, "name= "},
4232  {"nextframe", c_nextframe, "name"},
4233  {"previousframe", c_previousframe, "name"},
4234 
4235     // object placement tags
4236  {"put", c_put,             "<i> x=0 y=0 red=+0 green=+0 blue=+0 alpha=+0 luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below= @noinstancename=0"},
4237  {"startclip", c_startclip, "<i> x=0 y=0 red=+0 green=+0 blue=+0 alpha=+0 luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below= @noinstancename=0"},
4238  {"move", c_move,	"name x= y= interpolation=linear"},
4239  {"smove", c_smove, 	"name x= y= interpolation=linear"},
4240  {"sweep", c_sweep,	"name x= y= r= dir=counterclockwise arc=short interpolation=linear"},
4241  {"change", c_change,   "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below= interpolation=linear"},
4242  //{"arcchange", c_arcchange,   "name pivot= angle= red= green= blue= alpha= luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below="},
4243  {"schange", c_schange, "name red= green= blue= alpha= luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below= interpolation=linear"},
4244  {"jump", c_jump,       "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= blend= filter= pivot= pin= shear= rotate= ratio= above= below="},
4245  {"del", c_del, "name"},
4246     // virtual object placement
4247  {"texture", c_texture, "<i> x=0 y=0 width= height= scale= scalex= scaley= r= shear= rotate="},
4248     // switching
4249  {"toggle", c_toggle, "name fixed_alignment="},
4250 
4251     // commands which start a block
4252 //startclip (see above)
4253  {"sprite", c_sprite, "name scalinggrid= as3name="},
4254  {"action", c_action, "filename="},
4255  {"initaction", c_initaction, "name filename="},
4256 
4257  {"end", c_end, ""}
4258 };
4259 
4260 
parseArguments(char * command,char * pattern)4261 static map_t parseArguments(char*command, char*pattern)
4262 {
4263     char*x;
4264     char*d,*e;
4265 
4266     string_t name[64];
4267     string_t value[64];
4268     int set[64];
4269     int isboolean[64];
4270     int pos;
4271     int len;
4272     int t;
4273     string_t t1,t2;
4274     map_t result;
4275     map_init(&result);
4276 
4277     string_set(&t1, "commandname");
4278     string_set(&t2, command);
4279     map_put(&result, t1, t2);
4280 
4281     if(!pattern || !*pattern)
4282 	return result;
4283 
4284     x = pattern;
4285 
4286     pos = 0;
4287 
4288     if(!strncmp("<i> ", x, 3)) {
4289 	readToken();
4290 	if(type == COMMAND || type == RAWDATA) {
4291 	    pushBack();
4292 	    syntaxerror("character name expected");
4293 	}
4294 	name[pos].str = "instance";
4295 	name[pos].len = 8;
4296 	value[pos].str = text;
4297 	value[pos].len = strlen(text);
4298 	set[pos] = 1;
4299 	pos++;
4300 
4301 	if(type == ASSIGNMENT)
4302 	    readToken();
4303 
4304 	name[pos].str = "character";
4305 	name[pos].len = 9;
4306 	value[pos].str = text;
4307 	value[pos].len = strlen(text);
4308 	set[pos] = 1;
4309 	pos++;
4310 
4311 	x+=4;
4312     }
4313 
4314     while(*x) {
4315 	isboolean[pos] = (x[0] =='@');
4316 	if(isboolean[pos])
4317 	    x++;
4318 
4319 	d = strchr(x, ' ');
4320 	e = strchr(x, '=');
4321 	if(!d)
4322 	    d=&x[strlen(x)];
4323 	set[pos] = 0;
4324 
4325 	if(!e || d<e) {
4326 	    // no default
4327 	    name[pos].str = x;
4328 	    name[pos].len = d-x;
4329 	    value[pos].str = 0;
4330 	    value[pos].len = 0;
4331 	} else {
4332 	    name[pos].str = x;
4333 	    name[pos].len = e-x;
4334 	    value[pos].str = e+1;
4335 	    value[pos].len = d-e-1;
4336 	}
4337 	pos++;
4338 	if(!*d) break;
4339 	x=d+1;
4340     }
4341     len = pos;
4342 
4343 /*    for(t=0;t<len;t++) {
4344 	printf("(%d) %s=%s %s\n", t, strdup_n(name[t], namelen[t]), strdup_n(value[t], valuelen[t]),
4345 		isboolean[t]?"(boolean)":"");
4346     }*/
4347 
4348     while(1) {
4349 	readToken();
4350 	if(type == RAWDATA || type == COMMAND) {
4351 	    pushBack();
4352 	    break;
4353 	}
4354 
4355 	// first, search for boolean arguments
4356 	for(pos=0;pos<len;pos++)
4357 	{
4358 	    if(!set[pos] && isboolean[pos] && !strncmp(name[pos].str, text, name[pos].len>textlen?name[pos].len:textlen)) {
4359 		set[pos] = 1;
4360 		if(type == ASSIGNMENT)
4361 		    readToken();
4362 		value[pos].str = text;
4363 		value[pos].len = strlen(text);
4364 		/*printf("setting boolean parameter %s (to %s)\n",
4365 			strdup_n(name[pos], namelen[pos]),
4366 			strdup_n(value[pos], valuelen[pos]));*/
4367 		break;
4368 	    }
4369 	}
4370 
4371 	// second, search for normal arguments
4372 	if(pos==len)
4373 	for(pos=0;pos<len;pos++)
4374 	{
4375 	    if((type == ASSIGNMENT && !strncmp(name[pos].str, text, name[pos].len>textlen?name[pos].len:textlen)) ||
4376 	       (type != ASSIGNMENT && !set[pos])) {
4377 		if(set[pos]) {
4378 		    syntaxerror("value %s set twice (old value:%s)", text, strdup_n(value[pos].str, value[pos].len));
4379 		}
4380 		if(type == ASSIGNMENT)
4381 		    readToken();
4382 		set[pos] = 1;
4383 		value[pos].str = text;
4384 		value[pos].len = strlen(text);
4385 #if 0//def DEBUG
4386 		printf("setting parameter %s (to %s)\n",
4387 			strdup_n(name[pos].str, name[pos].len),
4388 			strdup_n(value[pos].str, value[pos].len));
4389 #endif
4390 		break;
4391 	    }
4392 	}
4393 	if(pos==len) {
4394 	    syntaxerror("Illegal argument \"%s\" to .%s", text, command);
4395 	}
4396     }
4397 #if 0//def DEBUG
4398     for(t=0;t<len;t++) {
4399 	printf("%s=%s\n", strdup_n(name[t].str, name[t].len), strdup_n(value[t].str, value[t].len));
4400     }
4401 #endif
4402     for(t=0;t<len;t++) {
4403 	if(value[t].str && value[t].str[0] == '*') {
4404 	    //relative default- take value from some other parameter
4405 	    int s;
4406 	    for(s=0;s<len;s++) {
4407 		if(value[s].len == value[t].len-1 &&
4408 		   !strncmp(&value[t].str[1], value[s].str, value[s].len))
4409 		    value[t].str = value[s].str;
4410 	    }
4411 	}
4412 	if(value[t].str == 0) {
4413 	    pushBack();
4414 	    syntaxerror("value for parameter %s missing (no default)", strdup_n(name[t].str, name[t].len));
4415 	}
4416     }
4417 
4418     /* ok, now construct the dictionary from the parameters */
4419 
4420     for(t=0;t<len;t++)
4421     {
4422 	map_put(&result, name[t], value[t]);
4423     }
4424     return result;
4425 }
parseArgumentsForCommand(char * command)4426 static void parseArgumentsForCommand(char*command)
4427 {
4428     int t;
4429     map_t args;
4430     int nr = -1;
4431     msg("<verbose> parse Command: %s (line %d)", command, line);
4432 
4433     for(t=0;t<sizeof(arguments)/sizeof(arguments[0]);t++) {
4434 	if(!strcmp(arguments[t].command, command)) {
4435 
4436 	    /* ugly hack- will be removed soon (once documentation and .sc generating
4437 	       utilities have been changed) */
4438 	    if(!strcmp(command, "swf") && !stackpos) {
4439 		warning("Please use .flash instead of .swf- this will be mandatory soon");
4440 		command = "flash";
4441 		t = 0;
4442 	    }
4443 
4444 	    args = parseArguments(command, arguments[t].arguments);
4445 	    nr = t;
4446 	    break;
4447 	}
4448     }
4449     if(nr<0)
4450 	syntaxerror("command %s not known", command);
4451 
4452 #ifndef EMPTY
4453     // catch missing .flash directives at the beginning of a file
4454     if(strcmp(command, "flash") && !stackpos)
4455     {
4456         syntaxerror("No movie defined- use .flash first");
4457     }
4458 #endif
4459 
4460 #ifdef DEBUG
4461     printf(".%s\n", command);fflush(stdout);
4462     map_dump(&args, stdout, "\t");fflush(stdout);
4463 #endif
4464 
4465 #ifndef EMPTY
4466     (*arguments[nr].func)(&args);
4467 #else
4468     if(!strcmp(command, "action")  || !strcmp(command, "initaction") ||
4469        !strcmp(command, "outline") || !strcmp(command, "gradient")) {
4470 	readToken();
4471 	if(type != RAWDATA) {
4472 	    syntaxerror("colon (:) expected");
4473 	}
4474     }
4475 #endif
4476     map_clear(&args);
4477     return;
4478 }
4479 
4480 
4481 /* for now only intended to find what glyphs of each font are to be included in the swf file.
4482  * Therefore some knowledge about the command is assumed i.e. it is font/text-related
4483  * No syntax checking is done */
analyseArgumentsForCommand(char * command)4484 static void analyseArgumentsForCommand(char*command)
4485 {
4486     int t;
4487     map_t args;
4488     int nr = -1;
4489     U8* glyphs_to_include;
4490     msg("<verbose> analyse Command: %s (line %d)", command, line);
4491 
4492     for(t=0;t<sizeof(arguments)/sizeof(arguments[0]);t++)
4493     {
4494         if(!strcmp(arguments[t].command, command))
4495         {
4496             args = parseArguments(command, arguments[t].arguments);
4497             nr = t;
4498             break;
4499         }
4500     }
4501 #ifdef DEBUG
4502     printf(".%s\n", command);fflush(stdout);
4503     map_dump(&args, stdout, "\t");fflush(stdout);
4504 #endif
4505     const char* name = lu(&args, "name");
4506     if(!strcmp(command, "font"))
4507     {
4508 	const char* fontfile = lu(&args, "filename");
4509 	const char* glyphs = lu(&args, "glyphs");
4510 	const char* flashtype = lu(&args, "flashtype");
4511 	s_createfont(name, fontfile, glyphs, flashtype[0]);
4512     } else {
4513         SWFFONT* font = dict_lookup(&fonts, lu(&args, "font"));
4514         if(!font) {
4515 	    //that's ok... it might be an edittext with a system font
4516             //syntaxerror("font %s is not known in line %d", lu(&args, "font"), line);
4517 	} else
4518             if(font->use && !font->use->glyphs_specified) {
4519 		if(!strcmp(command, "edittext"))
4520 		{
4521             	    swf_FontUseAll(font);
4522             	    font->use->glyphs_specified = 1;
4523 		}
4524             	else
4525             	    swf_FontUseUTF8(font, (U8*)lu(&args, "text"), 0xffff);
4526             }
4527     }
4528     map_clear(&args);
4529     return;
4530 }
4531 
skipParameters()4532 void skipParameters()
4533 {
4534 	do
4535 		readToken();
4536 	while (type != COMMAND);
4537 	pushBack();
4538 }
4539 
findFontUsage()4540 void findFontUsage()
4541 {
4542     char* fontRelated = "font;text;textshape;edittext;";
4543     while(!noMoreTokens())
4544     {
4545         readToken();
4546         if(type != COMMAND)
4547             syntaxerror("command expected");
4548         if(strstr(fontRelated, text))
4549             analyseArgumentsForCommand(text);
4550         else
4551             if(strcmp(text, "end"))
4552                 skipParameters();
4553     }
4554 }
4555 
firstPass()4556 void firstPass()
4557 {
4558     pos = 0;
4559     id = 0;
4560     dict_init(&fonts, 16);
4561     cleanUp = &freeFontDictionary;
4562     findFontUsage();
4563 }
4564 
main(int argc,char ** argv)4565 int main (int argc,char ** argv)
4566 {
4567     int t;
4568     processargs(argc, argv);
4569     initLog(0,-1,0,0,-1,verbose);
4570 
4571     if(!filename) {
4572 	args_callback_usage(argv[0]);
4573 	exit(1);
4574     }
4575 
4576     file = generateTokens(filename);
4577     if(!file) {
4578 	fprintf(stderr, "parser returned error.\n");
4579 	return 1;
4580     }
4581     firstPass();
4582     pos=0;
4583     t=0;
4584 
4585     while(!noMoreTokens()) {
4586 	readToken();
4587 	if(type != COMMAND)
4588 	    syntaxerror("command expected");
4589 	parseArgumentsForCommand(text);
4590     }
4591 
4592     s_close();
4593     freeTokens(file);
4594 
4595     return 0;
4596 }
4597 
4598