2 Compiles swf code (.sc) files into .swf files.
4 Part of the swftools package.
6 Copyright (c) 2001 Matthias Kramm <kramm@quiss.org>
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.
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.
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 */
29 #include "../config.h"
30 #include "../lib/rfxswf.h"
31 #include "../lib/drawer.h"
32 #include "../lib/log.h"
33 #include "../lib/args.h"
40 static char * filename = 0;
41 static char * outputname = "output.swf";
42 static int verbose = 2;
43 static int optimize = 0;
44 static int override_outputname = 0;
46 static struct options_t options[] = {
55 int args_callback_option(char*name,char*val)
57 if(!strcmp(name, "V")) {
58 printf("swfc - part of %s %s\n", PACKAGE, VERSION);
61 else if(!strcmp(name, "o")) {
63 override_outputname = 1;
66 else if(!strcmp(name, "O")) {
70 else if(!strcmp(name, "v")) {
75 printf("Unknown option: -%s\n", name);
80 int args_callback_longoption(char*name,char*val)
82 return args_long2shortoption(options, name, val);
84 void args_callback_usage(char *name)
87 printf("Usage: %s [-o file.swf] file.sc\n", name);
89 printf("-h , --help Print short help message and exit\n");
90 printf("-V , --version Print version info and exit\n");
91 printf("-v , --verbose Increase verbosity. \n");
92 printf("-o , --output <filename> Set output file to <filename>.\n");
95 int args_callback_command(char*name,char*val)
98 fprintf(stderr, "Only one file allowed. You supplied at least two. (%s and %s)\n",
105 static struct token_t* file;
114 static void syntaxerror(char*format, ...)
118 va_start(arglist, format);
119 vsprintf(buf, format, arglist);
121 printf("\"%s\", line %d column %d: error- %s\n", filename, line, column, buf);
125 static void warning(char*format, ...)
129 va_start(arglist, format);
130 vsprintf(buf, format, arglist);
132 printf("\"%s\", line %d column %d: warning- %s\n", filename, line, column, buf);
135 static void readToken()
137 type = file[pos].type;
139 syntaxerror("unexpected end of file");
141 text = file[pos].text;
142 textlen = strlen(text);
143 line = file[pos].line;
144 column = file[pos].column;
146 //printf("---> %d(%s) %s\n", type, type_names[type], text);
149 static void pushBack()
152 if(!pos) syntaxerror("internal error 3");
157 textlen = strlen(text);
160 column = file[p].column;
163 static int noMoreTokens()
165 if(file[pos].type == END)
170 // ------------------------------ swf routines ----------------------------
174 int type; //0=swf, 1=sprite, 2=clip, 3=button
180 /* for sprites (1): */
186 dictionary_t oldinstances;
191 static int stackpos = 0;
193 static dictionary_t characters;
194 static dictionary_t images;
195 static dictionary_t outlines;
196 static dictionary_t gradients;
197 static char idmap[65536];
198 static TAG*tag = 0; //current tag
200 static int id; //current character id
201 static int currentframe; //current frame in current level
202 static SRECT currentrect; //current bounding box in current level
203 static U16 currentdepth;
204 static dictionary_t instances;
205 static dictionary_t fonts;
206 static dictionary_t sounds;
208 typedef struct _parameters {
210 float scalex, scaley;
218 typedef struct _character {
224 typedef struct _instance {
225 character_t*character;
227 parameters_t parameters;
228 TAG* lastTag; //last tag which set the object
229 U16 lastFrame; //frame lastTag is in
232 typedef struct _outline {
237 typedef struct _gradient {
243 static void character_init(character_t*c)
245 memset(c, 0, sizeof(character_t));
247 static character_t* character_new()
250 c = (character_t*)malloc(sizeof(character_t));
254 static void instance_init(instance_t*i)
256 memset(i, 0, sizeof(instance_t));
258 static instance_t* instance_new()
261 c = (instance_t*)malloc(sizeof(instance_t));
266 static void incrementid()
270 syntaxerror("Out of character ids.");
275 static void s_addcharacter(char*name, U16 id, TAG*ctag, SRECT r)
277 character_t* c = character_new();
279 c->definingTag = ctag;
282 if(dictionary_lookup(&characters, name))
283 syntaxerror("character %s defined twice", name);
284 dictionary_put2(&characters, name, c);
286 tag = swf_InsertTag(tag, ST_NAMECHARACTER);
288 swf_SetString(tag, name);
289 tag = swf_InsertTag(tag, ST_EXPORTASSETS);
292 swf_SetString(tag, name);
294 static void s_addimage(char*name, U16 id, TAG*ctag, SRECT r)
296 character_t* c = character_new();
297 c->definingTag = ctag;
301 if(dictionary_lookup(&images, name))
302 syntaxerror("image %s defined twice", name);
303 dictionary_put2(&images, name, c);
305 static instance_t* s_addinstance(char*name, character_t*c, U16 depth)
307 instance_t* i = instance_new();
310 //swf_GetMatrix(0, &i->matrix);
311 if(dictionary_lookup(&instances, name))
312 syntaxerror("object %s defined twice", name);
313 dictionary_put2(&instances, name, i);
317 static void parameters_set(parameters_t*p, int x,int y, float scalex, float scaley, float rotate, float shear, SPOINT pivot, SPOINT pin, CXFORM cxform)
320 p->scalex = scalex; p->scaley = scaley;
321 p->pin = pin; p->pivot = pivot;
322 p->rotate = rotate; p->cxform = cxform;
326 static void parameters_clear(parameters_t*p)
329 p->scalex = 1.0; p->scaley = 1.0;
332 p->pivot.x = 0; p->pivot.y = 0;
335 swf_GetCXForm(0, &p->cxform, 1);
338 static void makeMatrix(MATRIX*m, parameters_t*p)
347 sx = p->scalex*cos(p->rotate/360*2*3.14159265358979);
348 r1 = -p->scalex*sin(p->rotate/360*2*3.14159265358979)+sx*p->shear;
349 r0 = p->scaley*sin(p->rotate/360*2*3.14159265358979);
350 sy = p->scaley*cos(p->rotate/360*2*3.14159265358979)+r0*p->shear;
352 m->sx = (int)(sx*65536+0.5);
353 m->r1 = (int)(r1*65536+0.5);
354 m->r0 = (int)(r0*65536+0.5);
355 m->sy = (int)(sy*65536+0.5);
359 h = swf_TurnPoint(p->pin, m);
364 static MATRIX s_instancepos(SRECT rect, parameters_t*p)
369 r = swf_TurnRect(rect, &m);
370 if(currentrect.xmin == 0 && currentrect.ymin == 0 &&
371 currentrect.xmax == 0 && currentrect.ymax == 0)
374 swf_ExpandRect2(¤trect, &r);
378 void s_swf(char*name, SRECT r, int version, int fps, int compress, RGBA background)
380 SWF*swf = (SWF*)malloc(sizeof(SWF));
383 syntaxerror(".swf blocks can't be nested");
385 memset(swf, 0, sizeof(swf));
386 swf->fileVersion = version;
388 swf->frameRate = fps;
389 swf->firstTag = tag = swf_InsertTag(0, ST_SETBACKGROUNDCOLOR);
390 swf->compressed = compress;
391 swf_SetRGB(tag,&background);
393 if(stackpos==sizeof(stack)/sizeof(stack[0]))
394 syntaxerror("too many levels of recursion");
396 dictionary_init(&characters);
397 dictionary_init(&images);
398 dictionary_init(&outlines);
399 dictionary_init(&gradients);
400 dictionary_init(&instances);
401 dictionary_init(&fonts);
402 dictionary_init(&sounds);
404 memset(&stack[stackpos], 0, sizeof(stack[0]));
405 stack[stackpos].type = 0;
406 stack[stackpos].filename = strdup(name);
407 stack[stackpos].swf = swf;
408 stack[stackpos].oldframe = -1;
413 memset(¤trect, 0, sizeof(currentrect));
416 memset(idmap, 0, sizeof(idmap));
420 void s_sprite(char*name)
422 tag = swf_InsertTag(tag, ST_DEFINESPRITE);
423 swf_SetU16(tag, id); //id
424 swf_SetU16(tag, 0); //frames
426 memset(&stack[stackpos], 0, sizeof(stack[0]));
427 stack[stackpos].type = 1;
428 stack[stackpos].oldframe = currentframe;
429 stack[stackpos].olddepth = currentdepth;
430 stack[stackpos].oldrect = currentrect;
431 stack[stackpos].oldinstances = instances;
432 stack[stackpos].tag = tag;
433 stack[stackpos].id = id;
434 stack[stackpos].name = strdup(name);
436 /* FIXME: those four fields should be bundled together */
437 dictionary_init(&instances);
440 memset(¤trect, 0, sizeof(currentrect));
446 typedef struct _buttonrecord
454 typedef struct _button
458 buttonrecord_t records[4];
461 static button_t mybutton;
463 void s_button(char*name)
465 tag = swf_InsertTag(tag, ST_DEFINEBUTTON2);
466 swf_SetU16(tag, id); //id
467 swf_ButtonSetFlags(tag, 0); //menu=no
469 memset(&mybutton, 0, sizeof(mybutton));
471 memset(&stack[stackpos], 0, sizeof(stack[0]));
472 stack[stackpos].type = 3;
473 stack[stackpos].tag = tag;
474 stack[stackpos].id = id;
475 stack[stackpos].name = strdup(name);
476 stack[stackpos].oldrect = currentrect;
477 memset(¤trect, 0, sizeof(currentrect));
482 void s_buttonput(char*character, char*as, parameters_t p)
484 character_t* c = dictionary_lookup(&characters, character);
489 if(!stackpos || (stack[stackpos-1].type != 3)) {
490 syntaxerror(".show may only appear in .button");
493 syntaxerror("character %s not known (in .shape %s)", character, character);
495 if(mybutton.endofshapes) {
496 syntaxerror("a .do may not precede a .show", character, character);
499 m = s_instancepos(c->size, &p);
507 if(*s==',' || *s==0) {
508 if(!strncmp(o,"idle",s-o)) {mybutton.records[0]=r;o=s+1;}
509 else if(!strncmp(o,"shape",s-o)) {mybutton.records[0]=r;o=s+1;}
510 else if(!strncmp(o,"hover",s-o)) {mybutton.records[1]=r;o=s+1;}
511 else if(!strncmp(o,"pressed",s-o)) {mybutton.records[2]=r;o=s+1;}
512 else if(!strncmp(o,"area",s-o)) {mybutton.records[3]=r;o=s+1;}
513 else syntaxerror("unknown \"as\" argument: \"%s\"", strdup_n(o,s-o));
520 static void setbuttonrecords(TAG*tag)
522 int flags[] = {BS_UP,BS_OVER,BS_DOWN,BS_HIT};
523 if(!mybutton.endofshapes) {
526 if(!mybutton.records[3].set) {
527 memcpy(&mybutton.records[3], &mybutton.records[0], sizeof(buttonrecord_t));
531 if(mybutton.records[t].set) {
532 swf_ButtonSetRecord(tag,flags[t],mybutton.records[t].id,1,&mybutton.records[t].matrix,&mybutton.records[t].cxform);
535 swf_SetU8(tag,0); // end of button records
536 mybutton.endofshapes = 1;
540 void s_buttonaction(int flags, char*action)
546 setbuttonrecords(stack[stackpos-1].tag);
548 a = swf_ActionCompile(text, stack[0].swf->fileVersion);
550 syntaxerror("Couldn't compile ActionScript");
553 swf_ButtonSetCondition(stack[stackpos-1].tag, flags);
554 swf_ActionSet(stack[stackpos-1].tag, a);
555 mybutton.nr_actions++;
560 static void setactionend(TAG*tag)
562 if(!mybutton.nr_actions) {
563 /* no actions means we didn't have an actionoffset,
564 which means we can't signal the end of the
565 buttonaction records, so, *sigh*, we have
566 to insert a dummy record */
567 swf_SetU16(tag, 0); //offset
568 swf_SetU16(tag, 0); //condition
569 swf_SetU8(tag, 0); //action
573 static void s_endButton()
576 setbuttonrecords(stack[stackpos-1].tag);
577 setactionend(stack[stackpos-1].tag);
580 swf_ButtonPostProcess(stack[stackpos].tag, mybutton.nr_actions);
584 tag = stack[stackpos].tag;
585 currentrect = stack[stackpos].oldrect;
587 s_addcharacter(stack[stackpos].name, stack[stackpos].id, stack[stackpos].tag, r);
588 free(stack[stackpos].name);
591 TAG* removeFromTo(TAG*from, TAG*to)
593 TAG*save = from->prev;
595 TAG*next = from->next;
603 static void s_endSprite()
605 SRECT r = currentrect;
607 if(stack[stackpos].cut)
608 tag = removeFromTo(stack[stackpos].cut, tag);
612 /* TODO: before clearing, prepend "<spritename>." to names and
613 copy into old instances dict */
614 dictionary_clear(&instances);
616 currentframe = stack[stackpos].oldframe;
617 currentrect = stack[stackpos].oldrect;
618 currentdepth = stack[stackpos].olddepth;
619 instances = stack[stackpos].oldinstances;
621 tag = swf_InsertTag(tag, ST_SHOWFRAME);
622 tag = swf_InsertTag(tag, ST_END);
624 tag = stack[stackpos].tag;
627 syntaxerror("internal error(7)");
629 s_addcharacter(stack[stackpos].name, stack[stackpos].id, stack[stackpos].tag, r);
630 free(stack[stackpos].name);
633 static void s_endSWF()
639 if(stack[stackpos].cut)
640 tag = removeFromTo(stack[stackpos].cut, tag);
644 swf = stack[stackpos].swf;
645 filename = stack[stackpos].filename;
647 //if(tag->prev && tag->prev->id != ST_SHOWFRAME)
648 // tag = swf_InsertTag(tag, ST_SHOWFRAME);
649 tag = swf_InsertTag(tag, ST_SHOWFRAME);
651 tag = swf_InsertTag(tag, ST_END);
653 swf_OptimizeTagOrder(swf);
659 if(!(swf->movieSize.xmax-swf->movieSize.xmin) || !(swf->movieSize.ymax-swf->movieSize.ymin)) {
660 swf->movieSize = currentrect; /* "autocrop" */
663 if(!(swf->movieSize.xmax-swf->movieSize.xmin) || !(swf->movieSize.ymax-swf->movieSize.ymin)) {
664 swf->movieSize.xmax += 20; /* 1 by 1 pixels */
665 swf->movieSize.ymax += 20;
666 warning("Empty bounding box for movie");
669 fi = open(filename, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0644);
671 syntaxerror("couldn't create output file %s", filename);
674 {if(swf_WriteSWC(fi, swf)<0) syntaxerror("WriteSWC() failed.\n");}
676 {if(swf_WriteSWF(fi, swf)<0) syntaxerror("WriteSWF() failed.\n");}
680 dictionary_clear(&instances);
681 dictionary_clear(&characters);
682 dictionary_clear(&images);
683 dictionary_clear(&outlines);
684 dictionary_clear(&gradients);
685 dictionary_clear(&fonts);
686 dictionary_clear(&sounds);
696 if(stack[stackpos-1].type == 0)
697 syntaxerror("End of file encountered in .flash block");
698 if(stack[stackpos-1].type == 1)
699 syntaxerror("End of file encountered in .sprite block");
700 if(stack[stackpos-1].type == 2)
701 syntaxerror("End of file encountered in .clip block");
707 return currentframe+1;
710 void s_frame(int nr, int cut, char*name)
716 syntaxerror("Illegal frame number");
717 nr--; // internally, frame 1 is frame 0
719 for(t=currentframe;t<nr;t++) {
720 tag = swf_InsertTag(tag, ST_SHOWFRAME);
721 if(t==nr-1 && name && *name) {
722 tag = swf_InsertTag(tag, ST_FRAMELABEL);
723 swf_SetString(tag, name);
726 if(nr == 0 && currentframe == 0 && name) {
727 tag = swf_InsertTag(tag, ST_FRAMELABEL);
728 swf_SetString(tag, name);
733 syntaxerror("Can't cut, frame empty");
735 stack[stackpos].cut = tag;
741 int parseColor2(char*str, RGBA*color);
743 int addFillStyle(SHAPE*s, SRECT*r, char*texture)
748 if(texture[0] == '#') {
749 parseColor2(texture, &color);
750 return swf_ShapeAddSolidFillStyle(s, &color);
751 } else if((image = dictionary_lookup(&images, texture))) {
753 swf_GetMatrix(0, &m);
754 m.sx = 65536.0*20.0*(r->xmax - r->xmin)/image->size.xmax;
755 m.sy = 65536.0*20.0*(r->ymax - r->ymin)/image->size.ymax;
758 return swf_ShapeAddBitmapFillStyle(s, &m, image->id, 0);
759 } /*else if ((texture = dictionary_lookup(&textures, texture))) {
760 } */ else if ((gradient = dictionary_lookup(&gradients, texture))) {
764 swf_GetMatrix(0, &rot);
765 ccos = cos(-gradient->rotate*2*3.14159265358979/360);
766 csin = sin(-gradient->rotate*2*3.14159265358979/360);
768 rot.r1 = -csin*65536;
771 r2 = swf_TurnRect(*r, &rot);
772 swf_GetMatrix(0, &m);
773 m.sx = (r2.xmax - r2.xmin)*2*ccos;
774 m.r1 = -(r2.xmax - r2.xmin)*2*csin;
775 m.r0 = (r2.ymax - r2.ymin)*2*csin;
776 m.sy = (r2.ymax - r2.ymin)*2*ccos;
777 m.tx = r->xmin + (r->xmax - r->xmin)/2;
778 m.ty = r->ymin + (r->ymax - r->ymin)/2;
779 return swf_ShapeAddGradientFillStyle(s, &m, &gradient->gradient, gradient->radial);
780 } else if (parseColor2(texture, &color)) {
781 return swf_ShapeAddSolidFillStyle(s, &color);
783 syntaxerror("not a color/fillstyle: %s", texture);
788 RGBA black={r:0,g:0,b:0,a:0};
789 void s_box(char*name, int width, int height, RGBA color, int linewidth, char*texture)
798 tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
801 ls1 = swf_ShapeAddLineStyle(s,linewidth>=20?linewidth-20:0,&color);
803 fs1 = addFillStyle(s, &r2, texture);
806 r.xmin = r2.xmin-linewidth-linewidth/2;
807 r.ymin = r2.ymin-linewidth-linewidth/2;
808 r.xmax = r2.xmax+linewidth+linewidth/2;
809 r.ymax = r2.ymax+linewidth+linewidth/2;
811 swf_SetShapeHeader(tag,s);
812 swf_ShapeSetAll(tag,s,0,0,ls1,fs1,0);
813 swf_ShapeSetLine(tag,s,width,0);
814 swf_ShapeSetLine(tag,s,0,height);
815 swf_ShapeSetLine(tag,s,-width,0);
816 swf_ShapeSetLine(tag,s,0,-height);
817 swf_ShapeSetEnd(tag);
820 s_addcharacter(name, id, tag, r);
824 void s_filled(char*name, char*outlinename, RGBA color, int linewidth, char*texture)
830 outline = dictionary_lookup(&outlines, outlinename);
832 syntaxerror("outline %s not defined", outlinename);
836 tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
839 ls1 = swf_ShapeAddLineStyle(s,linewidth>=20?linewidth-20:0,&color);
841 fs1 = addFillStyle(s, &r2, texture);
844 rect.xmin = r2.xmin-linewidth-linewidth/2;
845 rect.ymin = r2.ymin-linewidth-linewidth/2;
846 rect.xmax = r2.xmax+linewidth+linewidth/2;
847 rect.ymax = r2.ymax+linewidth+linewidth/2;
849 swf_SetRect(tag,&rect);
850 swf_SetShapeStyles(tag, s);
851 swf_ShapeCountBits(s,0,0);
852 swf_RecodeShapeData(outline->shape->data, outline->shape->bitlen, 1, 1,
853 &s->data, &s->bitlen, s->bits.fill, s->bits.line);
854 swf_SetShapeBits(tag, s);
855 swf_SetBlock(tag, s->data, (s->bitlen+7)/8);
858 s_addcharacter(name, id, tag, rect);
862 void s_circle(char*name, int r, RGBA color, int linewidth, char*texture)
867 r2.xmin = r2.ymin = 0;
871 tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
874 ls1 = swf_ShapeAddLineStyle(s,linewidth>=20?linewidth-20:0,&color);
876 fs1 = addFillStyle(s, &r2, texture);
878 rect.xmin = r2.xmin-linewidth-linewidth/2;
879 rect.ymin = r2.ymin-linewidth-linewidth/2;
880 rect.xmax = r2.xmax+linewidth+linewidth/2;
881 rect.ymax = r2.ymax+linewidth+linewidth/2;
883 swf_SetRect(tag,&rect);
884 swf_SetShapeHeader(tag,s);
885 swf_ShapeSetAll(tag,s,0,0,ls1,fs1,0);
886 swf_ShapeSetCircle(tag, s, r,r,r,r);
887 swf_ShapeSetEnd(tag);
890 s_addcharacter(name, id, tag, rect);
894 void s_textshape(char*name, char*fontname, float size, char*_text)
897 U8*text = (U8*)_text;
901 font = dictionary_lookup(&fonts, fontname);
903 syntaxerror("font \"%s\" not known!", fontname);
905 if(text[0] >= font->maxascii || font->ascii2glyph[text[0]]<0) {
906 warning("no character 0x%02x (%c) in font \"%s\"", text[0], text[0], fontname);
907 s_box(name, 0, 0, black, 20, 0);
910 g = font->ascii2glyph[text[0]];
912 outline = malloc(sizeof(outline_t));
913 memset(outline, 0, sizeof(outline_t));
914 outline->shape = font->glyph[g].shape;
915 outline->bbox = font->layout->bounds[g];
919 swf_Shape11DrawerInit(&draw, 0);
920 swf_DrawText(&draw, font, (int)(size*100), _text);
922 outline->shape = swf_ShapeDrawerToShape(&draw);
923 outline->bbox = swf_ShapeDrawerGetBBox(&draw);
927 if(dictionary_lookup(&outlines, name))
928 syntaxerror("outline %s defined twice", name);
929 dictionary_put2(&outlines, name, outline);
932 void s_text(char*name, char*fontname, char*text, int size, RGBA color)
937 font = dictionary_lookup(&fonts, fontname);
939 syntaxerror("font \"%s\" not known!", fontname);
941 tag = swf_InsertTag(tag, ST_DEFINETEXT2);
943 if(!font->numchars) {
944 s_box(name, 0, 0, black, 20, 0);
947 r = swf_SetDefineText(tag, font, &color, text, size);
949 s_addcharacter(name, id, tag, r);
953 void s_quicktime(char*name, char*url)
958 memset(&r, 0, sizeof(r));
960 tag = swf_InsertTag(tag, ST_DEFINEMOVIE);
962 swf_SetString(tag, url);
964 s_addcharacter(name, id, tag, r);
968 void s_edittext(char*name, char*fontname, int size, int width, int height, char*text, RGBA*color, int maxlength, char*variable, int flags)
971 EditTextLayout layout;
974 if(fontname && *fontname) {
975 flags |= ET_USEOUTLINES;
976 font = dictionary_lookup(&fonts, fontname);
978 syntaxerror("font \"%s\" not known!", fontname);
980 tag = swf_InsertTag(tag, ST_DEFINEEDITTEXT);
983 layout.leftmargin = 0;
984 layout.rightmargin = 0;
992 swf_SetEditText(tag, flags, r, text, color, maxlength, font?font->id:0, size, &layout, variable);
994 s_addcharacter(name, id, tag, r);
998 /* type: either "jpeg" or "png"
1000 void s_image(char*name, char*type, char*filename, int quality)
1002 /* an image is actually two folded: 1st bitmap, 2nd character.
1003 Both of them can be used separately */
1005 /* step 1: the bitmap */
1010 warning("image type \"png\" not supported yet!");
1011 s_box(name, 0, 0, black, 20, 0);
1015 #ifndef HAVE_LIBJPEG
1016 warning("no jpeg support compiled in");
1017 s_box(name, 0, 0, black, 20, 0);
1020 tag = swf_InsertTag(tag, ST_DEFINEBITSJPEG2);
1021 swf_SetU16(tag, imageID);
1023 if(swf_SetJPEGBits(tag, filename, quality) < 0) {
1024 syntaxerror("Image \"%s\" not found, or contains errors", filename);
1027 swf_GetJPEGSize(filename, &width, &height);
1034 s_addimage(name, id, tag, r);
1039 /* step 2: the character */
1040 tag = swf_InsertTag(tag, ST_DEFINESHAPE); // todo: should be defineshape2/3 once images can be transparent.(?)
1041 swf_SetU16(tag, id);
1042 swf_ShapeSetBitmapRect(tag, imageID, width, height);
1044 s_addcharacter(name, id, tag, r);
1048 void dumpSWF(SWF*swf)
1050 TAG* tag = swf->firstTag;
1051 printf("vvvvvvvvvvvvvvvvvvvvv\n");
1053 printf("%8d %s\n", tag->len, swf_TagGetName(tag));
1056 printf("^^^^^^^^^^^^^^^^^^^^^\n");
1059 void s_font(char*name, char*filename)
1062 font = swf_LoadFont(filename);
1065 warning("Couldn't open font file \"%s\"", filename);
1066 font = (SWFFONT*)malloc(sizeof(SWFFONT));
1067 memset(font, 0, sizeof(SWFFONT));
1068 dictionary_put2(&fonts, name, font);
1074 /* fix the layout. Only needed for old fonts */
1076 for(t=0;t<font->numchars;t++) {
1077 font->glyph[t].advance = 0;
1080 swf_FontCreateLayout(font);
1082 /* just in case this thing is used in .edittext later on */
1083 swf_FontPrepareForEditText(font);
1086 tag = swf_InsertTag(tag, ST_DEFINEFONT2);
1087 swf_FontSetDefine2(tag, font);
1090 if(dictionary_lookup(&fonts, name))
1091 syntaxerror("font %s defined twice", name);
1092 dictionary_put2(&fonts, name, font);
1097 typedef struct _sound_t
1103 void s_sound(char*name, char*filename)
1105 struct WAV wav, wav2;
1111 if(!readWAV(filename, &wav)) {
1112 warning("Couldn't read wav file \"%s\"", filename);
1116 convertWAV2mono(&wav, &wav2, 44100);
1117 samples = (U16*)wav2.data;
1118 numsamples = wav2.size/2;
1120 #ifdef WORDS_BIGENDIAN
1122 for(t=0;t<numsamples;t++) {
1123 samples[t] = (samples[t]>>8)&0xff | (samples[t]<<8)&0xff00;
1128 tag = swf_InsertTag(tag, ST_DEFINESOUND);
1129 swf_SetU16(tag, id); //id
1130 swf_SetSoundDefine(tag, samples, numsamples);
1132 sound = (sound_t*)malloc(sizeof(sound_t)); /* mem leak */
1136 if(dictionary_lookup(&sounds, name))
1137 syntaxerror("sound %s defined twice", name);
1138 dictionary_put2(&sounds, name, sound);
1146 static char* gradient_getToken(const char**p)
1150 while(**p && strchr(" \t\n\r", **p)) {
1154 while(**p && !strchr(" \t\n\r", **p)) {
1157 result = malloc((*p)-start+1);
1158 memcpy(result,start,(*p)-start+1);
1159 result[(*p)-start] = 0;
1163 float parsePercent(char*str);
1164 RGBA parseColor(char*str);
1166 GRADIENT parseGradient(const char*str)
1169 const char* p = str;
1170 memset(&gradient, 0, sizeof(GRADIENT));
1172 char*posstr,*colorstr;
1175 posstr = gradient_getToken(&p);
1178 pos = parsePercent(posstr);
1179 if(!*p) syntaxerror("Error in shape data: Color expected after %s", posstr);
1180 colorstr = gradient_getToken(&p);
1181 color = parseColor(colorstr);
1182 if(gradient.num == sizeof(gradient.ratios)/sizeof(gradient.ratios[0])) {
1183 warning("gradient record too big- max size is 8, rest ignored");
1186 gradient.ratios[gradient.num] = (int)(pos*255.0);
1187 gradient.rgba[gradient.num] = color;
1195 void s_gradient(char*name, const char*text, int radial, int rotate)
1197 gradient_t* gradient;
1198 gradient = malloc(sizeof(gradient_t));
1199 memset(gradient, 0, sizeof(gradient_t));
1200 gradient->gradient = parseGradient(text);
1201 gradient->radial = radial;
1202 gradient->rotate = rotate;
1204 if(dictionary_lookup(&gradients, name))
1205 syntaxerror("gradient %s defined twice", name);
1206 dictionary_put2(&gradients, name, gradient);
1209 void s_action(const char*text)
1212 a = swf_ActionCompile(text, stack[0].swf->fileVersion);
1214 syntaxerror("Couldn't compile ActionScript");
1217 tag = swf_InsertTag(tag, ST_DOACTION);
1219 swf_ActionSet(tag, a);
1224 int s_swf3action(char*name, char*action)
1227 instance_t* object = 0;
1229 dictionary_lookup(&instances, name);
1230 if(!object && name && *name) {
1231 /* we have a name, but couldn't find it. Abort. */
1234 a = action_SetTarget(0, name);
1235 if(!strcmp(action, "nextframe")) a = action_NextFrame(a);
1236 else if(!strcmp(action, "previousframe")) a = action_PreviousFrame(a);
1237 else if(!strcmp(action, "stop")) a = action_Stop(a);
1238 else if(!strcmp(action, "play")) a = action_Play(a);
1239 a = action_SetTarget(a, "");
1242 tag = swf_InsertTag(tag, ST_DOACTION);
1243 swf_ActionSet(tag, a);
1248 void s_outline(char*name, char*format, char*source)
1257 swf_Shape11DrawerInit(&draw, 0);
1258 draw_string(&draw, source);
1260 shape = swf_ShapeDrawerToShape(&draw);
1261 bounds = swf_ShapeDrawerGetBBox(&draw);
1262 draw.dealloc(&draw);
1264 outline = (outline_t*)rfx_calloc(sizeof(outline_t));
1265 outline->shape = shape;
1266 outline->bbox = bounds;
1268 if(dictionary_lookup(&outlines, name))
1269 syntaxerror("outline %s defined twice", name);
1270 dictionary_put2(&outlines, name, outline);
1273 int s_playsound(char*name, int loops, int nomultiple, int stop)
1279 sound = dictionary_lookup(&sounds, name);
1283 tag = swf_InsertTag(tag, ST_STARTSOUND);
1284 swf_SetU16(tag, sound->id); //id
1285 memset(&info, 0, sizeof(info));
1288 info.nomultiple = nomultiple;
1289 swf_SetSoundInfo(tag, &info);
1293 void s_includeswf(char*name, char*filename)
1301 U16 cutout[] = {ST_SETBACKGROUNDCOLOR, ST_PROTECT, ST_FREEALL, ST_REFLEX};
1302 f = open(filename,O_RDONLY|O_BINARY);
1304 warning("Couldn't open file \"%s\": %s", filename, strerror(errno));
1305 s_box(name, 0, 0, black, 20, 0);
1308 if (swf_ReadSWF(f,&swf)<0) {
1309 warning("Only SWF files supported in .shape for now. File \"%s\" wasn't SWF.", filename);
1310 s_box(name, 0, 0, black, 20, 0);
1315 /* FIXME: The following sets the bounding Box for the character.
1316 It is wrong for two reasons:
1317 a) It may be too small (in case objects in the movie clip at the borders)
1318 b) it may be too big (because the poor movie never got autocropped)
1322 s = tag = swf_InsertTag(tag, ST_DEFINESPRITE);
1323 swf_SetU16(tag, id);
1324 swf_SetU16(tag, swf.frameCount);
1326 swf_Relocate(&swf, idmap);
1328 ftag = swf.firstTag;
1332 for(t=0;t<sizeof(cutout)/sizeof(cutout[0]);t++)
1333 if(cutout[t] == ftag->id) {
1337 if(ftag->id == ST_DEFINESPRITE && !swf_IsFolded(ftag))
1339 if(ftag->id == ST_END)
1343 /* We simply dump all tags right after the sprite
1344 header, relying on the fact that swf_OptimizeTagOrder() will
1345 sort things out for us later.
1346 We also rely on the fact that the imported SWF is well-formed.
1348 tag = swf_InsertTag(tag, ftag->id);
1349 swf_SetBlock(tag, ftag->data, ftag->len);
1353 syntaxerror("Included file %s contains errors", filename);
1354 tag = swf_InsertTag(tag, ST_END);
1358 s_addcharacter(name, id, tag, r);
1361 SRECT s_getCharBBox(char*name)
1363 character_t* c = dictionary_lookup(&characters, name);
1364 if(!c) syntaxerror("character '%s' unknown(2)", name);
1367 SRECT s_getInstanceBBox(char*name)
1369 instance_t * i = dictionary_lookup(&instances, name);
1371 if(!i) syntaxerror("instance '%s' unknown(4)", name);
1373 if(!c) syntaxerror("internal error(5)");
1376 parameters_t s_getParameters(char*name)
1378 instance_t * i = dictionary_lookup(&instances, name);
1379 if(!i) syntaxerror("instance '%s' unknown(10)", name);
1380 return i->parameters;
1382 void s_startclip(char*instance, char*character, parameters_t p)
1384 character_t* c = dictionary_lookup(&characters, character);
1388 syntaxerror("character %s not known", character);
1390 i = s_addinstance(instance, c, currentdepth);
1392 m = s_instancepos(i->character->size, &p);
1394 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1395 /* TODO: should be ObjectPlaceClip, with clipdepth backpatched */
1396 swf_ObjectPlace(tag, c->id, currentdepth, &m, &p.cxform, instance);
1398 i->lastFrame= currentframe;
1400 stack[stackpos].tag = tag;
1401 stack[stackpos].type = 2;
1410 swf_SetTagPos(stack[stackpos].tag, 0);
1411 swf_GetPlaceObject(stack[stackpos].tag, &p);
1412 p.clipdepth = currentdepth;
1414 swf_ClearTag(stack[stackpos].tag);
1415 swf_SetPlaceObject(stack[stackpos].tag, &p);
1419 void s_put(char*instance, char*character, parameters_t p)
1421 character_t* c = dictionary_lookup(&characters, character);
1425 syntaxerror("character %s not known (in .put %s=%s)", character, instance, character);
1428 i = s_addinstance(instance, c, currentdepth);
1430 m = s_instancepos(i->character->size, &p);
1432 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1433 swf_ObjectPlace(tag, c->id, currentdepth, &m, &p.cxform, instance);
1435 i->lastFrame = currentframe;
1439 void s_jump(char*instance, parameters_t p)
1441 instance_t* i = dictionary_lookup(&instances, instance);
1444 syntaxerror("instance %s not known", instance);
1448 m = s_instancepos(i->character->size, &p);
1450 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1451 swf_ObjectMove(tag, i->depth, &m, &p.cxform);
1453 i->lastFrame = currentframe;
1456 parameters_t s_interpolate(parameters_t*p1, parameters_t*p2, int pos, int num)
1460 if(num==0 || num==1)
1462 ratio = (float)pos/(float)num;
1464 p.x = (p2->x-p1->x)*ratio + p1->x;
1465 p.y = (p2->y-p1->y)*ratio + p1->y;
1466 p.scalex = (p2->scalex-p1->scalex)*ratio + p1->scalex;
1467 p.scaley = (p2->scaley-p1->scaley)*ratio + p1->scaley;
1468 p.rotate = (p2->rotate-p1->rotate)*ratio + p1->rotate;
1469 p.shear = (p2->shear-p1->shear)*ratio + p1->shear;
1471 p.cxform.r0 = ((float)p2->cxform.r0-(float)p1->cxform.r0)*ratio + p1->cxform.r0;
1472 p.cxform.g0 = ((float)p2->cxform.g0-(float)p1->cxform.g0)*ratio + p1->cxform.g0;
1473 p.cxform.b0 = ((float)p2->cxform.b0-(float)p1->cxform.b0)*ratio + p1->cxform.b0;
1474 p.cxform.a0 = ((float)p2->cxform.a0-(float)p1->cxform.a0)*ratio + p1->cxform.a0;
1476 p.cxform.r1 = (p2->cxform.r1-p1->cxform.r1)*ratio + p1->cxform.r1;
1477 p.cxform.g1 = (p2->cxform.g1-p1->cxform.g1)*ratio + p1->cxform.g1;
1478 p.cxform.b1 = (p2->cxform.b1-p1->cxform.b1)*ratio + p1->cxform.b1;
1479 p.cxform.a1 = (p2->cxform.a1-p1->cxform.a1)*ratio + p1->cxform.a1;
1481 p.pivot.x = (p2->pivot.x-p1->pivot.x)*ratio + p1->pivot.x;
1482 p.pivot.y = (p2->pivot.y-p1->pivot.y)*ratio + p1->pivot.y;
1483 p.pin.x = (p2->pin.x-p1->pin.x)*ratio + p1->pin.x;
1484 p.pin.y = (p2->pin.y-p1->pin.y)*ratio + p1->pin.y;
1488 void s_change(char*instance, parameters_t p2)
1490 instance_t* i = dictionary_lookup(&instances, instance);
1494 int frame, allframes;
1496 syntaxerror("instance %s not known", instance);
1500 allframes = currentframe - i->lastFrame - 1;
1502 warning(".change ignored. can only .put/.change an object once per frame.");
1506 m = s_instancepos(i->character->size, &p2);
1507 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1508 swf_ObjectMove(tag, i->depth, &m, &p2.cxform);
1511 /* o.k., we got the start and end point set. Now iterate though all the
1512 tags in between, inserting object changes after each new frame */
1515 if(!t) syntaxerror("internal error(6)");
1517 while(frame < allframes) {
1518 if(t->id == ST_SHOWFRAME) {
1523 p = s_interpolate(&p1, &p2, frame, allframes);
1524 m = s_instancepos(i->character->size, &p); //needed?
1525 lt = swf_InsertTag(t, ST_PLACEOBJECT2);
1526 i->lastFrame = currentframe;
1527 swf_ObjectMove(lt, i->depth, &m, &p.cxform);
1529 if(frame == allframes)
1534 syntaxerror("internal error(8) (frame=%d/%d)", frame, allframes);
1538 void s_delinstance(char*instance)
1540 instance_t* i = dictionary_lookup(&instances, instance);
1542 syntaxerror("instance %s not known", instance);
1544 tag = swf_InsertTag(tag, ST_REMOVEOBJECT2);
1545 swf_SetU16(tag, i->depth);
1546 dictionary_del(&instances, instance);
1549 void s_qchange(char*instance, parameters_t p)
1556 syntaxerror(".end unexpected");
1557 if(stack[stackpos-1].type == 0)
1559 else if(stack[stackpos-1].type == 1)
1561 else if(stack[stackpos-1].type == 2)
1563 else if(stack[stackpos-1].type == 3)
1565 else syntaxerror("internal error 1");
1568 // ------------------------------------------------------------------------
1570 typedef int command_func_t(map_t*args);
1572 SRECT parseBox(char*str)
1575 float xmin, xmax, ymin, ymax;
1576 char*x = strchr(str, 'x');
1578 if(!strcmp(str, "autocrop")) {
1579 r.xmin = r.ymin = r.xmax = r.ymax = 0;
1583 d1 = strchr(x+1, ':');
1585 d2 = strchr(d1+1, ':');
1587 if(sscanf(str, "%fx%f", &xmax, &ymax) < 2)
1591 else if(d1 && !d2) {
1592 if(sscanf(str, "%fx%f:%f", &xmax, &ymax, &xmin) < 3)
1598 if(sscanf(str, "%fx%f:%f:%f", &xmax, &ymax, &xmin, &ymin) < 4)
1603 r.xmin = (SCOORD)(xmin*20);
1604 r.ymin = (SCOORD)(ymin*20);
1605 r.xmax = (SCOORD)(xmax*20);
1606 r.ymax = (SCOORD)(ymax*20);
1609 syntaxerror("expression %s is not a valid bound Box.\nE.g. 1024x768 or 1024x768:30:30 would have been valid bounding Boxes.", str);
1612 float parseFloat(char*str)
1616 int parseInt(char*str)
1621 if(str[0]=='+' || str[0]=='-')
1625 if(str[t]<'0' || str[t]>'9')
1626 syntaxerror("Not an Integer: \"%s\"", str);
1629 int parseTwip(char*str)
1633 if(str[0]=='+' || str[0]=='-') {
1638 dot = strchr(str, '.');
1642 return sign*parseInt(str)*20;
1644 int l=strlen(++dot);
1646 for(s=str;s<dot-1;s++)
1647 if(*s<'0' || *s>'9')
1648 syntaxerror("Not a coordinate: \"%s\"", str);
1650 if(*s<'0' || *s>'9')
1651 syntaxerror("Not a coordinate: \"%s\"", str);
1653 if(l>2 || (l==2 && (dot[1]!='0' && dot[1]!='5'))) {
1654 warning("precision loss: %s converted to twip: %s", str, dot);
1659 return sign*atoi(str)*20;
1661 return sign*atoi(str)*20+atoi(dot)*2;
1663 return sign*atoi(str)*20+atoi(dot)/5;
1668 int isPoint(char*str)
1670 if(strchr(str, '('))
1676 SPOINT parsePoint(char*str)
1680 int l = strlen(str);
1681 char*comma = strchr(str, ',');
1682 if(str[0]!='(' || str[l-1]!=')' || !comma || l>70)
1683 syntaxerror("\"%s\" is not a valid point of the form (x,y)", str);
1684 strncpy(tmp, str+1, comma-(str+1));tmp[comma-(str+1)]=0;
1685 p.x = parseTwip(tmp);
1686 strncpy(tmp, comma+1, l-1-(comma+1-str));tmp[l-1-(comma+1-str)]=0;
1687 p.y = parseTwip(tmp);
1691 int parseColor2(char*str, RGBA*color)
1693 int l = strlen(str);
1697 struct {unsigned char r,g,b;char*name;} colors[] =
1698 {{255,250,250,"snow"},{220,220,220,"gainsboro"},{250,240,230,"linen"},{255,228,196,"bisque"},
1699 {255,228,181,"moccasin"},{255,248,220,"cornsilk"},{255,255,240,"ivory"},{255,245,238,"seashell"},
1700 {240,255,240,"honeydew"},{240,255,255,"azure"},{230,230,250,"lavender"},{255,255,255,"white"},
1701 {0,0,0,"black"},{190,190,190,"gray"},{190,190,190,"grey"},{0,0,128,"navy"},{0,0,255,"blue"},
1702 {64,224,208,"turquoise"},{0,255,255,"cyan"},{127,255,212,"aquamarine"}, {0,255,0,"green"},
1703 {127,255,0,"chartreuse"},{240,230,140,"khaki"},{255,255,0,"yellow"},
1704 {255,215,0,"gold"},{218,165,32,"goldenrod"},{160,82,45,"sienna"},{205,133,63,"peru"},
1705 {222,184,135,"burlywood"},{245,245,220,"beige"},{245,222,179,"wheat"},{210,180,140,"tan"},
1706 {210,105,30,"chocolate"},{178,34,34,"firebrick"},{165,42,42,"brown"},{250,128,114,"salmon"},
1707 {255,165,0,"orange"},{255,127,80,"coral"},{255,99,71,"tomato"},{255,0,0,"red"},
1708 {255,192,203,"pink"},{176,48,96,"maroon"},{255,0,255,"magenta"},{238,130,238,"violet"},
1709 {221,160,221,"plum"},{218,112,214,"orchid"},{160,32,240,"purple"},{216,191,216,"thistle"}};
1713 if(str[0]=='#' && (l==7 || l==9)) {
1714 if(l == 7 && !(sscanf(str, "#%02x%02x%02x", &r, &g, &b)))
1716 if(l == 9 && !(sscanf(str, "#%02x%02x%02x%02x", &r, &g, &b, &a)))
1718 color->r = r; color->g = g; color->b = b; color->a = a;
1721 for(t=0;t<sizeof(colors)/sizeof(colors[0]);t++)
1722 if(!strcmp(str, colors[t].name)) {
1727 color->r = r; color->g = g; color->b = b; color->a = a;
1733 RGBA parseColor(char*str)
1736 if(!parseColor2(str, &c))
1737 syntaxerror("Expression '%s' is not a color", str);
1741 typedef struct _muladd {
1746 MULADD parseMulAdd(char*str)
1749 char* str2 = (char*)malloc(strlen(str)+5);
1756 if(sscanf(str2, "%f%f %d", &mul, &add, &i)==2+1) { add/=256.0; i=1;}
1757 else if(sscanf(str2, "%f%%%f %d", &mul, &add, &i)==2+1) { mul/=100.0; add/=256.0; i=2;}
1758 else if(sscanf(str2, "%f%f%% %d", &mul, &add, &i)==2+1) { add/=100.0; i=3;}
1759 else if(sscanf(str2, "%f%%%f%% %d", &mul, &add, &i)==2+1) { mul/=100.0; add/=100.0; i=4;}
1760 else if(sscanf(str2, "+%f%% %d", &add, &i)==1+1) { mul=1.0;add/=100.0; i=5;}
1761 else if(sscanf(str2, "+%f %d", &add, &i)==1+1) { mul=1.0;add/=256.0; i=6;}
1762 else if(sscanf(str2, "-%f%% %d", &add, &i)==1+1) { mul=1.0;add/=-100.0; i=7;}
1763 else if(sscanf(str2, "-%f %d", &add, &i)==1+1) { mul=1.0;add/=-256.0; i=8;}
1764 else if(sscanf(str2, "%f%% %d", &mul, &i)==1+1) { mul/=100.0;add=0; i=9;}
1765 else if(sscanf(str2, "%f %d", &mul, &i)==1+1) { add=0; i=10;}
1767 syntaxerror("'%s' is not a valid color transform expression", str);
1769 m.add = (int)(add*256);
1770 m.mul = (int)(mul*256);
1775 MULADD mergeMulAdd(MULADD m1, MULADD m2)
1777 int a = (int)((double)m2.add+((double)m1.add*(double)m2.mul)/256.0);
1778 double m = ((double)m1.mul*(double)m2.mul)/256.0;
1780 if(a<-32768) a=-32768;
1781 if(a>32767) a=32767;
1782 if(m<-32768) m=-32768;
1783 if(m>32767) m=32767;
1789 float parsePxOrPercent(char*fontname, char*str)
1791 int l = strlen(str);
1792 if(strchr(str, '%'))
1793 return parsePercent(str);
1794 if(l>2 && str[l-2]=='p' && str[l-1]=='t') {
1795 float p = atof(str);
1796 return p/64.0; /*64 = FT_SUBPIXELS- see ../lib/modules/swffont.c */
1798 syntaxerror("Expression '%s' is neither a point size (?pt) nor a percentage (?%)", str);
1802 float parsePercent(char*str)
1804 int l = strlen(str);
1808 return atoi(str)/100.0;
1810 syntaxerror("Expression '%s' is not a percentage", str);
1813 int isPercent(char*str)
1815 return str[strlen(str)-1]=='%';
1817 int parseNewSize(char*str, int size)
1820 return parsePercent(str)*size;
1822 return (int)(atof(str)*20);
1825 int isColor(char*str)
1828 return parseColor2(str, &c);
1831 static char* lu(map_t* args, char*name)
1833 char* value = map_lookup(args, name);
1835 map_dump(args, stdout, "");
1836 syntaxerror("internal error 2: value %s should be set", name);
1841 static int c_flash(map_t*args)
1843 char* filename = map_lookup(args, "filename");
1844 char* compressstr = lu(args, "compress");
1845 SRECT bbox = parseBox(lu(args, "bbox"));
1846 int version = parseInt(lu(args, "version"));
1847 int fps = (int)(parseFloat(lu(args, "fps"))*256);
1849 RGBA color = parseColor(lu(args, "background"));
1851 if(!filename || !*filename) {
1852 /* for compatibility */
1853 filename = map_lookup(args, "name");
1854 if(!filename || !*filename) {
1857 //msg("<warning> line %d: .flash name=... is deprecated, use .flash filename=...", line);
1858 msg("<notice> line %d: .flash name=... is deprecated, use .flash filename=...", line);
1862 if(!filename || override_outputname)
1863 filename = outputname;
1865 if(!strcmp(compressstr, "default"))
1866 compress = version==6;
1867 else if(!strcmp(compressstr, "yes") || !strcmp(compressstr, "compress"))
1869 else if(!strcmp(compressstr, "no"))
1871 else syntaxerror("value \"%s\" not supported for the compress argument", compressstr);
1873 s_swf(filename, bbox, version, fps, compress, color);
1876 int isRelative(char*str)
1878 return !strncmp(str, "<plus>", 6) ||
1879 !strncmp(str, "<minus>", 7);
1881 char* getOffset(char*str)
1883 if(!strncmp(str, "<plus>", 6))
1885 if(!strncmp(str, "<minus>", 7))
1887 syntaxerror("internal error (347)");
1890 int getSign(char*str)
1892 if(!strncmp(str, "<plus>", 6))
1894 if(!strncmp(str, "<minus>", 7))
1896 syntaxerror("internal error (348)");
1899 static dictionary_t points;
1900 static mem_t mpoints;
1901 int points_initialized = 0;
1903 SPOINT getPoint(SRECT r, char*name)
1906 if(!strcmp(name, "center")) {
1908 p.x = (r.xmin + r.xmax)/2;
1909 p.y = (r.ymin + r.ymax)/2;
1913 if(points_initialized)
1914 l = (int)dictionary_lookup(&points, name);
1916 syntaxerror("Invalid point: \"%s\".", name);
1919 return *(SPOINT*)&mpoints.buffer[l];
1921 static int c_gradient(map_t*args)
1923 char*name = lu(args, "name");
1924 int radial= strcmp(lu(args, "radial"), "radial")?0:1;
1925 int rotate = parseInt(lu(args, "rotate"));
1929 syntaxerror("colon (:) expected");
1931 s_gradient(name, text, radial,rotate);
1934 static int c_point(map_t*args)
1936 char*name = lu(args, "name");
1940 if(!points_initialized) {
1941 dictionary_init(&points);
1943 points_initialized = 1;
1945 p.x = parseTwip(lu(args, "x"));
1946 p.y = parseTwip(lu(args, "y"));
1947 pos = mem_put(&mpoints, &p, sizeof(p));
1948 string_set(&s1, name);
1950 dictionary_put(&points, s1, (void*)pos);
1953 static int c_play(map_t*args)
1955 char*name = lu(args, "name");
1956 char*loop = lu(args, "loop");
1957 char*nomultiple = lu(args, "nomultiple");
1959 if(!strcmp(nomultiple, "nomultiple"))
1962 nm = parseInt(nomultiple);
1964 if(s_playsound(name, parseInt(loop), nm, 0)) {
1966 } else if(s_swf3action(name, "play")) {
1972 static int c_stop(map_t*args)
1974 char*name = map_lookup(args, "name");
1976 if(s_playsound(name, 0,0,1)) {
1978 } else if(s_swf3action(name, "stop")) {
1981 syntaxerror("I don't know anything about sound/movie \"%s\"", name);
1985 static int c_nextframe(map_t*args)
1987 char*name = lu(args, "name");
1989 if(s_swf3action(name, "nextframe")) {
1992 syntaxerror("I don't know anything about movie \"%s\"", name);
1996 static int c_previousframe(map_t*args)
1998 char*name = lu(args, "name");
2000 if(s_swf3action(name, "previousframe")) {
2003 syntaxerror("I don't know anything about movie \"%s\"", name);
2007 static int c_placement(map_t*args, int type)
2009 char*instance = lu(args, (type==0||type==4)?"instance":"name");
2012 char* luminancestr = lu(args, "luminance");
2013 char* scalestr = lu(args, "scale");
2014 char* scalexstr = lu(args, "scalex");
2015 char* scaleystr = lu(args, "scaley");
2016 char* rotatestr = lu(args, "rotate");
2017 char* shearstr = lu(args, "shear");
2018 char* xstr="", *pivotstr="";
2019 char* ystr="", *anglestr="";
2020 char*above = lu(args, "above"); /*FIXME*/
2021 char*below = lu(args, "below");
2022 char* rstr = lu(args, "red");
2023 char* gstr = lu(args, "green");
2024 char* bstr = lu(args, "blue");
2025 char* astr = lu(args, "alpha");
2026 char* pinstr = lu(args, "pin");
2027 char* as = map_lookup(args, "as");
2035 if(type==9) { // (?) .rotate or .arcchange
2036 pivotstr = lu(args, "pivot");
2037 anglestr = lu(args, "angle");
2039 xstr = lu(args, "x");
2040 ystr = lu(args, "y");
2043 luminance = parseMulAdd(luminancestr);
2046 luminance.mul = 256;
2050 if(scalexstr[0]||scaleystr[0])
2051 syntaxerror("scalex/scaley and scale cannot both be set");
2052 scalexstr = scaleystr = scalestr;
2055 if(type == 0 || type == 4) {
2057 character = lu(args, "character");
2058 parameters_clear(&p);
2059 } else if (type == 5) {
2060 character = lu(args, "name");
2061 parameters_clear(&p);
2064 p = s_getParameters(instance);
2069 if(isRelative(xstr)) {
2070 if(type == 0 || type == 4)
2071 syntaxerror("relative x values not allowed for initial put or startclip");
2072 p.x += parseTwip(getOffset(xstr))*getSign(xstr);
2074 p.x = parseTwip(xstr);
2078 if(isRelative(ystr)) {
2079 if(type == 0 || type == 4)
2080 syntaxerror("relative y values not allowed for initial put or startclip");
2081 p.y += parseTwip(getOffset(ystr))*getSign(ystr);
2083 p.y = parseTwip(ystr);
2087 /* scale, scalex, scaley */
2089 oldbbox = s_getCharBBox(character);
2091 oldbbox = s_getInstanceBBox(instance);
2093 oldwidth = oldbbox.xmax - oldbbox.xmin;
2094 oldheight = oldbbox.ymax - oldbbox.ymin;
2096 if(oldwidth==0) p.scalex = 1.0;
2099 p.scalex = (float)(parseNewSize(scalexstr, oldwidth))/oldwidth;
2103 if(oldheight==0) p.scaley = 1.0;
2106 p.scaley = (float)(parseNewSize(scaleystr, oldheight))/oldheight;
2112 if(isRelative(rotatestr)) {
2113 p.rotate += parseFloat(getOffset(rotatestr))*getSign(rotatestr);
2115 p.rotate = parseFloat(rotatestr);
2121 if(isRelative(shearstr)) {
2122 p.shear += parseFloat(getOffset(shearstr))*getSign(shearstr);
2124 p.shear = parseFloat(shearstr);
2129 if(isPoint(pivotstr))
2130 p.pivot = parsePoint(pivotstr);
2132 p.pivot = getPoint(oldbbox, pivotstr);
2136 p.pin = parsePoint(pinstr);
2138 p.pin = getPoint(oldbbox, pinstr);
2141 /* color transform */
2143 if(rstr[0] || luminancestr[0]) {
2146 r = parseMulAdd(rstr);
2148 r.add = p.cxform.r0;
2149 r.mul = p.cxform.r1;
2151 r = mergeMulAdd(r, luminance);
2152 p.cxform.r0 = r.mul;p.cxform.r1 = r.add;
2154 if(gstr[0] || luminancestr[0]) {
2157 g = parseMulAdd(gstr);
2159 g.add = p.cxform.g0;
2160 g.mul = p.cxform.g1;
2162 g = mergeMulAdd(g, luminance);
2163 p.cxform.g0 = g.mul;p.cxform.g1 = g.add;
2165 if(bstr[0] || luminancestr[0]) {
2168 b = parseMulAdd(bstr);
2170 b.add = p.cxform.b0;
2171 b.mul = p.cxform.b1;
2173 b = mergeMulAdd(b, luminance);
2174 p.cxform.b0 = b.mul;p.cxform.b1 = b.add;
2177 MULADD a = parseMulAdd(astr);
2178 p.cxform.a0 = a.mul;p.cxform.a1 = a.add;
2182 s_put(instance, character, p);
2184 s_change(instance, p);
2186 s_qchange(instance, p);
2188 s_jump(instance, p);
2190 s_startclip(instance, character, p);
2191 else if(type == 5) {
2193 s_buttonput(character, as, p);
2195 s_buttonput(character, "shape", p);
2200 static int c_put(map_t*args)
2202 c_placement(args, 0);
2205 static int c_change(map_t*args)
2207 c_placement(args, 1);
2210 static int c_qchange(map_t*args)
2212 c_placement(args, 2);
2215 static int c_arcchange(map_t*args)
2217 c_placement(args, 2);
2220 static int c_jump(map_t*args)
2222 c_placement(args, 3);
2225 static int c_startclip(map_t*args)
2227 c_placement(args, 4);
2230 static int c_show(map_t*args)
2232 c_placement(args, 5);
2235 static int c_del(map_t*args)
2237 char*instance = lu(args, "name");
2238 s_delinstance(instance);
2241 static int c_end(map_t*args)
2246 static int c_sprite(map_t*args)
2248 char* name = lu(args, "name");
2252 static int c_frame(map_t*args)
2254 char*framestr = lu(args, "n");
2255 char*cutstr = lu(args, "cut");
2256 char*name = lu(args, "name");
2259 if(strcmp(cutstr, "no"))
2261 if(isRelative(framestr)) {
2262 frame = s_getframe();
2263 if(getSign(framestr)<0)
2264 syntaxerror("relative frame expressions must be positive");
2265 frame += parseInt(getOffset(framestr));
2268 frame = parseInt(framestr);
2269 if(s_getframe() >= frame
2270 && !(frame==1 && s_getframe()==frame)) // equality is o.k. for frame 0
2271 syntaxerror("frame expression must be >%d (is:%s)", s_getframe(), framestr);
2273 s_frame(frame, cut, name);
2276 static int c_primitive(map_t*args)
2278 char*name = lu(args, "name");
2279 char*command = lu(args, "commandname");
2280 int width=0, height=0, r=0;
2281 int linewidth = parseTwip(lu(args, "line"));
2282 char*colorstr = lu(args, "color");
2283 RGBA color = parseColor(colorstr);
2284 char*fillstr = lu(args, "fill");
2291 if(!strcmp(command, "circle"))
2293 else if(!strcmp(command, "filled"))
2297 width = parseTwip(lu(args, "width"));
2298 height = parseTwip(lu(args, "height"));
2299 } else if (type==1) {
2300 r = parseTwip(lu(args, "r"));
2301 } else if (type==2) {
2302 outline = lu(args, "outline");
2305 if(!strcmp(fillstr, "fill"))
2307 if(!strcmp(fillstr, "none"))
2309 if(width<0 || height<0 || linewidth<0 || r<0)
2310 syntaxerror("values width, height, line, r must be positive");
2312 if(type == 0) s_box(name, width, height, color, linewidth, fillstr);
2313 else if(type==1) s_circle(name, r, color, linewidth, fillstr);
2314 else if(type==2) s_filled(name, outline, color, linewidth, fillstr);
2318 static int c_textshape(map_t*args)
2320 char*name = lu(args, "name");
2321 char*text = lu(args, "text");
2322 char*font = lu(args, "font");
2323 float size = parsePxOrPercent(font, lu(args, "size"));
2325 s_textshape(name, font, size, text);
2329 static int c_swf(map_t*args)
2331 char*name = lu(args, "name");
2332 char*filename = lu(args, "filename");
2333 char*command = lu(args, "commandname");
2334 if(!strcmp(command, "shape"))
2335 warning("Please use .swf instead of .shape");
2336 s_includeswf(name, filename);
2340 static int c_font(map_t*args)
2342 char*name = lu(args, "name");
2343 char*filename = lu(args, "filename");
2344 s_font(name, filename);
2348 static int c_sound(map_t*args)
2350 char*name = lu(args, "name");
2351 char*filename = lu(args, "filename");
2352 s_sound(name, filename);
2356 static int c_text(map_t*args)
2358 char*name = lu(args, "name");
2359 char*text = lu(args, "text");
2360 char*font = lu(args, "font");
2361 float size = parsePxOrPercent(font, lu(args, "size"));
2362 RGBA color = parseColor(lu(args, "color"));
2363 s_text(name, font, text, (int)(size*100), color);
2367 static int c_soundtrack(map_t*args)
2372 static int c_quicktime(map_t*args)
2374 char*name = lu(args, "name");
2375 char*url = lu(args, "url");
2376 s_quicktime(name, url);
2380 static int c_image(map_t*args)
2382 char*command = lu(args, "commandname");
2383 char*name = lu(args, "name");
2384 char*filename = lu(args, "filename");
2385 if(!strcmp(command,"jpeg")) {
2386 int quality = (int)(parsePercent(lu(args, "quality"))*100);
2387 s_image(name, "jpeg", filename, quality);
2389 s_image(name, "png", filename, 0);
2394 static int c_outline(map_t*args)
2396 char*name = lu(args, "name");
2397 char*format = lu(args, "format");
2401 syntaxerror("colon (:) expected");
2403 s_outline(name, format, text);
2407 int fakechar(map_t*args)
2409 char*name = lu(args, "name");
2410 s_box(name, 0, 0, black, 20, 0);
2414 static int c_egon(map_t*args) {return fakechar(args);}
2415 static int c_button(map_t*args) {
2416 char*name = lu(args, "name");
2420 static int current_button_flags = 0;
2421 static int c_on_press(map_t*args)
2423 char*position = lu(args, "position");
2425 if(!strcmp(position, "inside")) {
2426 current_button_flags |= BC_OVERUP_OVERDOWN;
2427 } else if(!strcmp(position, "outside")) {
2428 //current_button_flags |= BC_IDLE_OUTDOWN;
2429 syntaxerror("IDLE_OVERDOWN not supported by SWF");
2430 } else if(!strcmp(position, "anywhere")) {
2431 current_button_flags |= /*BC_IDLE_OUTDOWN|*/BC_OVERUP_OVERDOWN|BC_IDLE_OVERDOWN;
2434 if(type == RAWDATA) {
2436 s_buttonaction(current_button_flags, action);
2437 current_button_flags = 0;
2443 static int c_on_release(map_t*args)
2445 char*position = lu(args, "position");
2447 if(!strcmp(position, "inside")) {
2448 current_button_flags |= BC_OVERDOWN_OVERUP;
2449 } else if(!strcmp(position, "outside")) {
2450 current_button_flags |= BC_OUTDOWN_IDLE;
2451 } else if(!strcmp(position, "anywhere")) {
2452 current_button_flags |= BC_OVERDOWN_OVERUP|BC_OUTDOWN_IDLE|BC_OVERDOWN_IDLE;
2455 if(type == RAWDATA) {
2457 s_buttonaction(current_button_flags, action);
2458 current_button_flags = 0;
2464 static int c_on_move_in(map_t*args)
2466 char*position = lu(args, "state");
2468 if(!strcmp(position, "pressed")) {
2469 current_button_flags |= BC_OUTDOWN_OVERDOWN;
2470 } else if(!strcmp(position, "not_pressed")) {
2471 current_button_flags |= BC_IDLE_OVERUP;
2472 } else if(!strcmp(position, "any")) {
2473 current_button_flags |= BC_OUTDOWN_OVERDOWN|BC_IDLE_OVERUP|BC_IDLE_OVERDOWN;
2476 if(type == RAWDATA) {
2478 s_buttonaction(current_button_flags, action);
2479 current_button_flags = 0;
2485 static int c_on_move_out(map_t*args)
2487 char*position = lu(args, "state");
2489 if(!strcmp(position, "pressed")) {
2490 current_button_flags |= BC_OVERDOWN_OUTDOWN;
2491 } else if(!strcmp(position, "not_pressed")) {
2492 current_button_flags |= BC_OVERUP_IDLE;
2493 } else if(!strcmp(position, "any")) {
2494 current_button_flags |= BC_OVERDOWN_OUTDOWN|BC_OVERUP_IDLE|BC_OVERDOWN_IDLE;
2497 if(type == RAWDATA) {
2499 s_buttonaction(current_button_flags, action);
2500 current_button_flags = 0;
2506 static int c_on_key(map_t*args)
2508 char*key = lu(args, "key");
2510 if(strlen(key)==1) {
2513 current_button_flags |= 0x4000 + (key[0]*0x200);
2515 syntaxerror("invalid character: %c"+key[0]);
2520 <ctrl-x> = 0x200*(x-'a')
2524 syntaxerror("invalid key: %s",key);
2527 if(type == RAWDATA) {
2529 s_buttonaction(current_button_flags, action);
2530 current_button_flags = 0;
2537 static int c_edittext(map_t*args)
2539 //"name font size width height text="" color=black maxlength=0 variable="" @password=0 @wordwrap=0 @multiline=0 @html=0 @noselect=0 @readonly=0"},
2540 char*name = lu(args, "name");
2541 char*font = lu(args, "font");
2542 int size = (int)(1024*parsePxOrPercent(font, lu(args, "size")));
2543 int width = parseTwip(lu(args, "width"));
2544 int height = parseTwip(lu(args, "height"));
2545 char*text = lu(args, "text");
2546 RGBA color = parseColor(lu(args, "color"));
2547 int maxlength = parseInt(lu(args, "maxlength"));
2548 char*variable = lu(args, "variable");
2549 char*passwordstr = lu(args, "password");
2550 char*wordwrapstr = lu(args, "wordwrap");
2551 char*multilinestr = lu(args, "multiline");
2552 char*htmlstr = lu(args, "html");
2553 char*noselectstr = lu(args, "noselect");
2554 char*readonlystr = lu(args, "readonly");
2555 char*borderstr = lu(args, "border");
2558 if(!strcmp(passwordstr, "password")) flags |= ET_PASSWORD;
2559 if(!strcmp(wordwrapstr, "wordwrap")) flags |= ET_WORDWRAP;
2560 if(!strcmp(multilinestr, "multiline")) flags |= ET_MULTILINE;
2561 if(!strcmp(readonlystr, "readonly")) flags |= ET_READONLY;
2562 if(!strcmp(htmlstr, "html")) flags |= ET_HTML;
2563 if(!strcmp(noselectstr, "noselect")) flags |= ET_NOSELECT;
2564 if(!strcmp(borderstr, "border")) flags |= ET_BORDER;
2566 s_edittext(name, font, size, width, height, text, &color, maxlength, variable, flags);
2570 static int c_morphshape(map_t*args) {return fakechar(args);}
2571 static int c_movie(map_t*args) {return fakechar(args);}
2573 static int c_texture(map_t*args) {return 0;}
2575 static int c_action(map_t*args)
2577 char* filename = map_lookup(args, "filename");
2578 if(!filename ||!*filename) {
2580 if(type != RAWDATA) {
2581 syntaxerror("colon (:) expected");
2585 FILE*fi = fopen(filename, "rb");
2589 syntaxerror("Couldn't find file %s: %s", filename, strerror(errno));
2590 fseek(fi, 0, SEEK_END);
2592 fseek(fi, 0, SEEK_SET);
2593 text = rfx_alloc(l+1);
2594 fread(text, l, 1, fi);
2606 command_func_t* func;
2609 {{"flash", c_flash, "bbox=autocrop background=black version=6 fps=50 name= filename= @compress=default"},
2610 {"frame", c_frame, "n=<plus>1 name= @cut=no"},
2611 // "import" type stuff
2612 {"swf", c_swf, "name filename"},
2613 {"shape", c_swf, "name filename"},
2614 {"jpeg", c_image, "name filename quality=80%"},
2615 {"png", c_image, "name filename"},
2616 {"movie", c_movie, "name filename"},
2617 {"sound", c_sound, "name filename"},
2618 {"font", c_font, "name filename"},
2619 {"soundtrack", c_soundtrack, "filename"},
2620 {"quicktime", c_quicktime, "url"},
2622 // generators of primitives
2624 {"point", c_point, "name x=0 y=0"},
2625 {"gradient", c_gradient, "name @radial=0 rotate=0"},
2626 {"outline", c_outline, "name format=simple"},
2627 {"textshape", c_textshape, "name font size=100% text"},
2629 // character generators
2630 {"box", c_primitive, "name width height color=white line=1 @fill=none"},
2631 {"circle", c_primitive, "name r color=white line=1 @fill=none"},
2632 {"filled", c_primitive, "name outline color=white line=1 @fill=none"},
2634 {"egon", c_egon, "name vertices color=white line=1 @fill=none"},
2635 {"text", c_text, "name text font size=100% color=white"},
2636 {"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"},
2637 {"morphshape", c_morphshape, "name start end"},
2638 {"button", c_button, "name"},
2639 {"show", c_show, "name x=0 y=0 red=+0 green=+0 blue=+0 alpha=+0 luminance= scale= scalex= scaley= pivot= pin= shear= rotate= ratio= above= below= as="},
2640 {"on_press", c_on_press, "position=inside"},
2641 {"on_release", c_on_release, "position=anywhere"},
2642 {"on_move_in", c_on_move_in, "state=not_pressed"},
2643 {"on_move_out", c_on_move_out, "state=not_pressed"},
2644 {"on_key", c_on_key, "key=any"},
2647 {"play", c_play, "name loop=0 @nomultiple=0"},
2648 {"stop", c_stop, "name= "},
2649 {"nextframe", c_nextframe, "name"},
2650 {"previousframe", c_previousframe, "name"},
2652 // object placement tags
2653 {"put", c_put, "<i> x=0 y=0 red=+0 green=+0 blue=+0 alpha=+0 luminance= scale= scalex= scaley= pivot= pin= shear= rotate= ratio= above= below="},
2654 {"startclip", c_startclip, "<i> x=0 y=0 red=+0 green=+0 blue=+0 alpha=+0 luminance= scale= scalex= scaley= pivot= pin= shear= rotate= ratio= above= below="},
2655 {"change", c_change, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= ratio= above= below="},
2656 {"arcchange", c_arcchange, "name pivot= angle= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= ratio= above= below="},
2657 {"qchange", c_qchange, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= ratio= above= below="},
2658 {"jump", c_jump, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= ratio= above= below="},
2659 {"del", c_del, "name"},
2660 // virtual object placement
2661 {"texture", c_texture, "<i> x=0 y=0 scale= scalex=100% scaley=100% shear=0 rotate=0"},
2663 // commands which start a block
2664 //startclip (see above)
2665 {"sprite", c_sprite, "name"},
2666 {"action", c_action, "filename="},
2672 static map_t parseArguments(char*command, char*pattern)
2688 string_set(&t1, "commandname");
2689 string_set(&t2, command);
2690 map_put(&result, t1, t2);
2692 if(!pattern || !*pattern)
2699 if(!strncmp("<i> ", x, 3)) {
2701 if(type == COMMAND || type == RAWDATA) {
2703 syntaxerror("character name expected");
2705 name[pos].str = "instance";
2707 value[pos].str = text;
2708 value[pos].len = strlen(text);
2712 if(type == ASSIGNMENT)
2715 name[pos].str = "character";
2717 value[pos].str = text;
2718 value[pos].len = strlen(text);
2726 isboolean[pos] = (x[0] =='@');
2739 name[pos].len = d-x;
2744 name[pos].len = e-x;
2745 value[pos].str = e+1;
2746 value[pos].len = d-e-1;
2754 /* for(t=0;t<len;t++) {
2755 printf("(%d) %s=%s %s\n", t, strdup_n(name[t], namelen[t]), strdup_n(value[t], valuelen[t]),
2756 isboolean[t]?"(boolean)":"");
2761 if(type == RAWDATA || type == COMMAND) {
2766 // first, search for boolean arguments
2767 for(pos=0;pos<len;pos++)
2769 if(!set[pos] && isboolean[pos] && !strncmp(name[pos].str, text, name[pos].len>textlen?name[pos].len:textlen)) {
2771 if(type == ASSIGNMENT)
2773 value[pos].str = text;
2774 value[pos].len = strlen(text);
2775 /*printf("setting boolean parameter %s (to %s)\n",
2776 strdup_n(name[pos], namelen[pos]),
2777 strdup_n(value[pos], valuelen[pos]));*/
2782 // second, search for normal arguments
2784 for(pos=0;pos<len;pos++)
2786 if((type == ASSIGNMENT && !strncmp(name[pos].str, text, name[pos].len>textlen?name[pos].len:textlen)) ||
2787 (type != ASSIGNMENT && !set[pos])) {
2789 syntaxerror("value %s set twice (old value:%s)", text, strdup_n(value[pos].str, value[pos].len));
2791 if(type == ASSIGNMENT)
2794 value[pos].str = text;
2795 value[pos].len = strlen(text);
2797 printf("setting parameter %s (to %s)\n",
2798 strdup_n(name[pos].str, name[pos].len),
2799 strdup_n(value[pos].str, value[pos].len));
2805 syntaxerror("Illegal argument \"%s\" to .%s", text, command);
2809 for(t=0;t<len;t++) {
2810 printf("%s=%s\n", strdup_n(name[t].str, name[t].len), strdup_n(value[t].str, value[t].len));
2813 for(t=0;t<len;t++) {
2814 if(value[t].str && value[t].str[0] == '*') {
2815 //relative default- take value from some other parameter
2817 for(s=0;s<len;s++) {
2818 if(value[s].len == value[t].len-1 &&
2819 !strncmp(&value[t].str[1], value[s].str, value[s].len))
2820 value[t].str = value[s].str;
2823 if(value[t].str == 0) {
2825 syntaxerror("value for parameter %s missing (no default)", strdup_n(name[t].str, name[t].len));
2829 /* ok, now construct the dictionary from the parameters */
2833 map_put(&result, name[t], value[t]);
2837 static void parseArgumentsForCommand(char*command)
2842 msg("<verbose> parse Command: %s (line %d)", command, line);
2844 for(t=0;t<sizeof(arguments)/sizeof(arguments[0]);t++) {
2845 if(!strcmp(arguments[t].command, command)) {
2847 /* ugly hack- will be removed soon (once documentation and .sc generating
2848 utilities have been changed) */
2849 if(!strcmp(command, "swf") && !stackpos) {
2850 warning("Please use .flash instead of .swf- this will be mandatory soon");
2855 args = parseArguments(command, arguments[t].arguments);
2861 syntaxerror("command %s not known", command);
2863 // catch missing .flash directives at the beginning of a file
2864 if(strcmp(command, "flash") && !stackpos)
2866 syntaxerror("No movie defined- use .flash first");
2870 printf(".%s\n", command);fflush(stdout);
2871 map_dump(&args, stdout, "\t");fflush(stdout);
2874 (*arguments[nr].func)(&args);
2876 /*if(!strcmp(command, "button") ||
2877 !strcmp(command, "action")) {
2880 if(type == COMMAND) {
2881 if(!strcmp(text, "end"))
2895 int main (int argc,char ** argv)
2898 processargs(argc, argv);
2899 initLog(0,-1,0,0,-1,verbose);
2902 args_callback_usage(argv[0]);
2906 file = generateTokens(filename);
2908 printf("parser returned error.\n");
2914 while(!noMoreTokens()) {
2917 syntaxerror("command expected");
2918 parseArgumentsForCommand(text);