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_END);
623 tag = stack[stackpos].tag;
626 syntaxerror("internal error(7)");
628 s_addcharacter(stack[stackpos].name, stack[stackpos].id, stack[stackpos].tag, r);
629 free(stack[stackpos].name);
632 static void s_endSWF()
638 if(stack[stackpos].cut)
639 tag = removeFromTo(stack[stackpos].cut, tag);
643 swf = stack[stackpos].swf;
644 filename = stack[stackpos].filename;
646 //if(tag->prev && tag->prev->id != ST_SHOWFRAME)
647 // tag = swf_InsertTag(tag, ST_SHOWFRAME);
648 tag = swf_InsertTag(tag, ST_SHOWFRAME);
650 tag = swf_InsertTag(tag, ST_END);
652 swf_OptimizeTagOrder(swf);
658 if(!(swf->movieSize.xmax-swf->movieSize.xmin) || !(swf->movieSize.ymax-swf->movieSize.ymin)) {
659 swf->movieSize = currentrect; /* "autocrop" */
662 if(!(swf->movieSize.xmax-swf->movieSize.xmin) || !(swf->movieSize.ymax-swf->movieSize.ymin)) {
663 swf->movieSize.xmax += 20; /* 1 by 1 pixels */
664 swf->movieSize.ymax += 20;
667 fi = open(filename, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0644);
669 syntaxerror("couldn't create output file %s", filename);
672 {if(swf_WriteSWC(fi, swf)<0) syntaxerror("WriteSWC() failed.\n");}
674 {if(swf_WriteSWF(fi, swf)<0) syntaxerror("WriteSWF() failed.\n");}
678 dictionary_clear(&instances);
679 dictionary_clear(&characters);
680 dictionary_clear(&images);
681 dictionary_clear(&outlines);
682 dictionary_clear(&gradients);
683 dictionary_clear(&fonts);
684 dictionary_clear(&sounds);
694 if(stack[stackpos-1].type == 0)
695 syntaxerror("End of file encountered in .flash block");
696 if(stack[stackpos-1].type == 1)
697 syntaxerror("End of file encountered in .sprite block");
698 if(stack[stackpos-1].type == 2)
699 syntaxerror("End of file encountered in .clip block");
705 return currentframe+1;
708 void s_frame(int nr, int cut, char*name)
714 syntaxerror("Illegal frame number");
715 nr--; // internally, frame 1 is frame 0
717 for(t=currentframe;t<nr;t++) {
718 tag = swf_InsertTag(tag, ST_SHOWFRAME);
719 if(t==nr-1 && name && *name) {
720 tag = swf_InsertTag(tag, ST_FRAMELABEL);
721 swf_SetString(tag, name);
724 if(nr == 0 && currentframe == 0 && name) {
725 tag = swf_InsertTag(tag, ST_FRAMELABEL);
726 swf_SetString(tag, name);
731 syntaxerror("Can't cut, frame empty");
733 stack[stackpos].cut = tag;
739 int parseColor2(char*str, RGBA*color);
741 int addFillStyle(SHAPE*s, SRECT*r, char*texture)
746 if(texture[0] == '#') {
747 parseColor2(texture, &color);
748 return swf_ShapeAddSolidFillStyle(s, &color);
749 } else if((image = dictionary_lookup(&images, texture))) {
751 swf_GetMatrix(0, &m);
752 m.sx = 65536.0*20.0*(r->xmax - r->xmin)/image->size.xmax;
753 m.sy = 65536.0*20.0*(r->ymax - r->ymin)/image->size.ymax;
756 return swf_ShapeAddBitmapFillStyle(s, &m, image->id, 0);
757 } /*else if ((texture = dictionary_lookup(&textures, texture))) {
758 } */ else if ((gradient = dictionary_lookup(&gradients, texture))) {
762 swf_GetMatrix(0, &rot);
763 ccos = cos(-gradient->rotate*2*3.14159265358979/360);
764 csin = sin(-gradient->rotate*2*3.14159265358979/360);
766 rot.r1 = -csin*65536;
769 r2 = swf_TurnRect(*r, &rot);
770 swf_GetMatrix(0, &m);
771 m.sx = (r2.xmax - r2.xmin)*2*ccos;
772 m.r1 = -(r2.xmax - r2.xmin)*2*csin;
773 m.r0 = (r2.ymax - r2.ymin)*2*csin;
774 m.sy = (r2.ymax - r2.ymin)*2*ccos;
775 m.tx = r->xmin + (r->xmax - r->xmin)/2;
776 m.ty = r->ymin + (r->ymax - r->ymin)/2;
777 return swf_ShapeAddGradientFillStyle(s, &m, &gradient->gradient, gradient->radial);
778 } else if (parseColor2(texture, &color)) {
779 return swf_ShapeAddSolidFillStyle(s, &color);
781 syntaxerror("not a color/fillstyle: %s", texture);
786 RGBA black={r:0,g:0,b:0,a:0};
787 void s_box(char*name, int width, int height, RGBA color, int linewidth, char*texture)
796 tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
799 ls1 = swf_ShapeAddLineStyle(s,linewidth,&color);
801 fs1 = addFillStyle(s, &r2, texture);
804 r.xmin = r2.xmin-linewidth-linewidth/2;
805 r.ymin = r2.ymin-linewidth-linewidth/2;
806 r.xmax = r2.xmax+linewidth+linewidth/2;
807 r.ymax = r2.ymax+linewidth+linewidth/2;
809 swf_SetShapeHeader(tag,s);
810 swf_ShapeSetAll(tag,s,0,0,ls1,fs1,0);
811 swf_ShapeSetLine(tag,s,width,0);
812 swf_ShapeSetLine(tag,s,0,height);
813 swf_ShapeSetLine(tag,s,-width,0);
814 swf_ShapeSetLine(tag,s,0,-height);
815 swf_ShapeSetEnd(tag);
818 s_addcharacter(name, id, tag, r);
822 void swf_RecodeShapeData(U8*data, int bitlen, int in_bits_fill, int in_bits_line,
823 U8**destdata, U32*destbitlen, int out_bits_fill, int out_bits_line)
828 memset(&s2, 0, sizeof(s2));
829 s2.lines = swf_ParseShapeData(data, bitlen, in_bits_fill, in_bits_line);
830 s2.numfillstyles = out_bits_fill?1<<(out_bits_fill-1):0;
831 s2.numlinestyles = out_bits_line?1<<(out_bits_line-1):0;
832 s2.fillstyles = rfx_calloc(sizeof(FILLSTYLE)*s2.numfillstyles);
833 s2.linestyles = rfx_calloc(sizeof(LINESTYLE)*s2.numlinestyles);
837 if(line->fillstyle0 > s2.numfillstyles) line->fillstyle0 = 0;
838 if(line->fillstyle1 > s2.numfillstyles) line->fillstyle1 = 0;
839 if(line->linestyle > s2.numlinestyles) line->linestyle = 0;
843 swf_Shape2ToShape(&s2,&s);
847 free(s.fillstyle.data);
848 free(s.linestyle.data);
850 *destbitlen = s.bitlen;
853 void s_filled(char*name, char*outlinename, RGBA color, int linewidth, char*texture)
859 outline = dictionary_lookup(&outlines, outlinename);
861 syntaxerror("outline %s not defined", outlinename);
865 tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
868 ls1 = swf_ShapeAddLineStyle(s,linewidth,&color);
870 fs1 = addFillStyle(s, &r2, texture);
873 rect.xmin = r2.xmin-linewidth-linewidth/2;
874 rect.ymin = r2.ymin-linewidth-linewidth/2;
875 rect.xmax = r2.xmax+linewidth+linewidth/2;
876 rect.ymax = r2.ymax+linewidth+linewidth/2;
878 swf_SetRect(tag,&rect);
879 swf_SetShapeStyles(tag, s);
880 swf_ShapeCountBits(s,0,0);
881 swf_RecodeShapeData(outline->shape->data, outline->shape->bitlen, 1, 1,
882 &s->data, &s->bitlen, s->bits.fill, s->bits.line);
883 swf_SetShapeBits(tag, s);
884 swf_SetBlock(tag, s->data, (s->bitlen+7)/8);
887 s_addcharacter(name, id, tag, rect);
891 void s_circle(char*name, int r, RGBA color, int linewidth, char*texture)
896 r2.xmin = r2.ymin = 0;
900 tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
903 ls1 = swf_ShapeAddLineStyle(s,linewidth,&color);
905 fs1 = addFillStyle(s, &r2, texture);
907 rect.xmin = r2.xmin-linewidth-linewidth/2;
908 rect.ymin = r2.ymin-linewidth-linewidth/2;
909 rect.xmax = r2.xmax+linewidth+linewidth/2;
910 rect.ymax = r2.ymax+linewidth+linewidth/2;
912 swf_SetRect(tag,&rect);
913 swf_SetShapeHeader(tag,s);
914 swf_ShapeSetAll(tag,s,0,0,ls1,fs1,0);
915 swf_ShapeSetCircle(tag, s, r,r,r,r);
916 swf_ShapeSetEnd(tag);
919 s_addcharacter(name, id, tag, rect);
923 void s_textshape(char*name, char*fontname, float size, char*_text)
926 U8*text = (U8*)_text;
930 font = dictionary_lookup(&fonts, fontname);
932 syntaxerror("font \"%s\" not known!", fontname);
934 if(text[0] >= font->maxascii || font->ascii2glyph[text[0]]<0) {
935 warning("no character 0x%02x (%c) in font \"%s\"", text[0], text[0], fontname);
936 s_box(name, 0, 0, black, 20, 0);
939 g = font->ascii2glyph[text[0]];
941 outline = malloc(sizeof(outline_t));
942 memset(outline, 0, sizeof(outline_t));
943 outline->shape = font->glyph[g].shape;
944 outline->bbox = font->layout->bounds[g];
948 swf_Shape11DrawerInit(&draw, 0);
949 swf_DrawText(&draw, font, (int)(size*100), _text);
951 outline->shape = swf_ShapeDrawerToShape(&draw);
952 outline->bbox = swf_ShapeDrawerGetBBox(&draw);
956 if(dictionary_lookup(&outlines, name))
957 syntaxerror("outline %s defined twice", name);
958 dictionary_put2(&outlines, name, outline);
961 void s_text(char*name, char*fontname, char*text, int size, RGBA color)
966 font = dictionary_lookup(&fonts, fontname);
968 syntaxerror("font \"%s\" not known!", fontname);
970 tag = swf_InsertTag(tag, ST_DEFINETEXT2);
972 if(!font->numchars) {
973 s_box(name, 0, 0, black, 20, 0);
976 r = swf_SetDefineText(tag, font, &color, text, size);
978 s_addcharacter(name, id, tag, r);
982 void s_quicktime(char*name, char*url)
987 memset(&r, 0, sizeof(r));
989 tag = swf_InsertTag(tag, ST_DEFINEMOVIE);
991 swf_SetString(tag, url);
993 s_addcharacter(name, id, tag, r);
997 void s_edittext(char*name, char*fontname, int size, int width, int height, char*text, RGBA*color, int maxlength, char*variable, int flags)
1000 EditTextLayout layout;
1003 font = dictionary_lookup(&fonts, fontname);
1005 syntaxerror("font \"%s\" not known!", fontname);
1006 tag = swf_InsertTag(tag, ST_DEFINEEDITTEXT);
1007 swf_SetU16(tag, id);
1009 layout.leftmargin = 0;
1010 layout.rightmargin = 0;
1017 swf_SetEditText(tag, flags|ET_USEOUTLINES, r, text, color, maxlength, font->id, size, &layout, variable);
1019 s_addcharacter(name, id, tag, r);
1023 /* type: either "jpeg" or "png"
1025 void s_image(char*name, char*type, char*filename, int quality)
1027 /* an image is actually two folded: 1st bitmap, 2nd character.
1028 Both of them can be used separately */
1030 /* step 1: the bitmap */
1035 warning("image type \"png\" not supported yet!");
1036 s_box(name, 0, 0, black, 20, 0);
1040 #ifndef HAVE_LIBJPEG
1041 warning("no jpeg support compiled in");
1042 s_box(name, 0, 0, black, 20, 0);
1045 tag = swf_InsertTag(tag, ST_DEFINEBITSJPEG2);
1046 swf_SetU16(tag, imageID);
1048 if(swf_SetJPEGBits(tag, filename, quality) < 0) {
1049 syntaxerror("Image \"%s\" not found, or contains errors", filename);
1052 swf_GetJPEGSize(filename, &width, &height);
1059 s_addimage(name, id, tag, r);
1064 /* step 2: the character */
1065 tag = swf_InsertTag(tag, ST_DEFINESHAPE); // todo: should be defineshape2/3 once images can be transparent.(?)
1066 swf_SetU16(tag, id);
1067 swf_ShapeSetBitmapRect(tag, imageID, width, height);
1069 s_addcharacter(name, id, tag, r);
1073 void dumpSWF(SWF*swf)
1075 TAG* tag = swf->firstTag;
1076 printf("vvvvvvvvvvvvvvvvvvvvv\n");
1078 printf("%8d %s\n", tag->len, swf_TagGetName(tag));
1081 printf("^^^^^^^^^^^^^^^^^^^^^\n");
1084 void s_font(char*name, char*filename)
1087 font = swf_LoadFont(filename);
1090 warning("Couldn't open font file \"%s\"", filename);
1091 font = (SWFFONT*)malloc(sizeof(SWFFONT));
1092 memset(font, 0, sizeof(SWFFONT));
1093 dictionary_put2(&fonts, name, font);
1099 /* fix the layout. Only needed for old fonts */
1101 for(t=0;t<font->numchars;t++) {
1102 font->glyph[t].advance = 0;
1105 swf_FontCreateLayout(font);
1107 /* just in case this thing is used in .edittext later on */
1108 swf_FontPrepareForEditText(font);
1111 tag = swf_InsertTag(tag, ST_DEFINEFONT2);
1112 swf_FontSetDefine2(tag, font);
1115 if(dictionary_lookup(&fonts, name))
1116 syntaxerror("font %s defined twice", name);
1117 dictionary_put2(&fonts, name, font);
1122 typedef struct _sound_t
1128 void s_sound(char*name, char*filename)
1130 struct WAV wav, wav2;
1135 if(!readWAV(filename, &wav)) {
1136 warning("Couldn't read wav file \"%s\"", filename);
1140 convertWAV2mono(&wav, &wav2, 44100);
1141 samples = (U16*)wav2.data;
1142 numsamples = wav2.size/2;
1146 tag = swf_InsertTag(tag, ST_DEFINESOUND);
1147 swf_SetU16(tag, id); //id
1148 swf_SetSoundDefine(tag, samples, numsamples);
1150 sound = (sound_t*)malloc(sizeof(sound_t)); /* mem leak */
1154 if(dictionary_lookup(&sounds, name))
1155 syntaxerror("sound %s defined twice", name);
1156 dictionary_put2(&sounds, name, sound);
1164 static char* gradient_getToken(const char**p)
1168 while(**p && strchr(" \t\n\r", **p)) {
1172 while(**p && !strchr(" \t\n\r", **p)) {
1175 result = malloc((*p)-start+1);
1176 memcpy(result,start,(*p)-start+1);
1177 result[(*p)-start] = 0;
1181 float parsePercent(char*str);
1182 RGBA parseColor(char*str);
1184 GRADIENT parseGradient(const char*str)
1187 const char* p = str;
1188 memset(&gradient, 0, sizeof(GRADIENT));
1190 char*posstr,*colorstr;
1193 posstr = gradient_getToken(&p);
1196 pos = parsePercent(posstr);
1197 if(!*p) syntaxerror("Error in shape data: Color expected after %s", posstr);
1198 colorstr = gradient_getToken(&p);
1199 color = parseColor(colorstr);
1200 if(gradient.num == sizeof(gradient.ratios)/sizeof(gradient.ratios[0])) {
1201 warning("gradient record too big- max size is 8, rest ignored");
1204 gradient.ratios[gradient.num] = (int)(pos*255.0);
1205 gradient.rgba[gradient.num] = color;
1213 void s_gradient(char*name, const char*text, int radial, int rotate)
1215 gradient_t* gradient;
1216 gradient = malloc(sizeof(gradient_t));
1217 memset(gradient, 0, sizeof(gradient_t));
1218 gradient->gradient = parseGradient(text);
1219 gradient->radial = radial;
1220 gradient->rotate = rotate;
1222 if(dictionary_lookup(&gradients, name))
1223 syntaxerror("gradient %s defined twice", name);
1224 dictionary_put2(&gradients, name, gradient);
1227 void s_action(const char*text)
1230 a = swf_ActionCompile(text, stack[0].swf->fileVersion);
1232 syntaxerror("Couldn't compile ActionScript");
1235 tag = swf_InsertTag(tag, ST_DOACTION);
1237 swf_ActionSet(tag, a);
1242 int s_swf3action(char*name, char*action)
1245 instance_t* object = 0;
1247 dictionary_lookup(&instances, name);
1248 if(!object && name && *name) {
1249 /* we have a name, but couldn't find it. Abort. */
1252 a = action_SetTarget(0, name);
1253 if(!strcmp(action, "nextframe")) a = action_NextFrame(a);
1254 else if(!strcmp(action, "previousframe")) a = action_PreviousFrame(a);
1255 else if(!strcmp(action, "stop")) a = action_Stop(a);
1256 else if(!strcmp(action, "play")) a = action_Play(a);
1257 a = action_SetTarget(a, "");
1260 tag = swf_InsertTag(tag, ST_DOACTION);
1261 swf_ActionSet(tag, a);
1266 void s_outline(char*name, char*format, char*source)
1275 swf_Shape11DrawerInit(&draw, 0);
1276 draw_string(&draw, source);
1278 shape = swf_ShapeDrawerToShape(&draw);
1279 bounds = swf_ShapeDrawerGetBBox(&draw);
1280 draw.dealloc(&draw);
1282 outline = (outline_t*)rfx_calloc(sizeof(outline_t));
1283 outline->shape = shape;
1284 outline->bbox = bounds;
1286 if(dictionary_lookup(&outlines, name))
1287 syntaxerror("outline %s defined twice", name);
1288 dictionary_put2(&outlines, name, outline);
1291 int s_playsound(char*name, int loops, int nomultiple, int stop)
1296 sound = dictionary_lookup(&sounds, name);
1301 tag = swf_InsertTag(tag, ST_STARTSOUND);
1302 swf_SetU16(tag, sound->id); //id
1303 memset(&info, 0, sizeof(info));
1306 info.nomultiple = nomultiple;
1307 swf_SetSoundInfo(tag, &info);
1311 void s_includeswf(char*name, char*filename)
1319 U16 cutout[] = {ST_SETBACKGROUNDCOLOR, ST_PROTECT, ST_FREEALL, ST_REFLEX};
1320 f = open(filename,O_RDONLY|O_BINARY);
1322 warning("Couldn't open file \"%s\": %s", filename, strerror(errno));
1323 s_box(name, 0, 0, black, 20, 0);
1326 if (swf_ReadSWF(f,&swf)<0) {
1327 warning("Only SWF files supported in .shape for now. File \"%s\" wasn't SWF.", filename);
1328 s_box(name, 0, 0, black, 20, 0);
1333 /* FIXME: The following sets the bounding Box for the character.
1334 It is wrong for two reasons:
1335 a) It may be too small (in case objects in the movie clip at the borders)
1336 b) it may be too big (because the poor movie never got autocropped)
1340 s = tag = swf_InsertTag(tag, ST_DEFINESPRITE);
1341 swf_SetU16(tag, id);
1344 swf_Relocate(&swf, idmap);
1346 ftag = swf.firstTag;
1350 for(t=0;t<sizeof(cutout)/sizeof(cutout[0]);t++)
1351 if(cutout[t] == ftag->id) {
1355 if(ftag->id == ST_DEFINESPRITE && !swf_IsFolded(ftag))
1357 if(ftag->id == ST_END)
1361 /* We simply dump all tags right after the sprite
1362 header, relying on the fact that swf_OptimizeTagOrder() will
1363 sort things out for us later.
1364 We also rely on the fact that the imported SWF is well-formed.
1366 tag = swf_InsertTag(tag, ftag->id);
1367 swf_SetBlock(tag, ftag->data, ftag->len);
1371 syntaxerror("Included file %s contains errors", filename);
1372 tag = swf_InsertTag(tag, ST_END);
1376 s_addcharacter(name, id, tag, r);
1379 SRECT s_getCharBBox(char*name)
1381 character_t* c = dictionary_lookup(&characters, name);
1382 if(!c) syntaxerror("character '%s' unknown(2)", name);
1385 SRECT s_getInstanceBBox(char*name)
1387 instance_t * i = dictionary_lookup(&instances, name);
1389 if(!i) syntaxerror("instance '%s' unknown(4)", name);
1391 if(!c) syntaxerror("internal error(5)");
1394 parameters_t s_getParameters(char*name)
1396 instance_t * i = dictionary_lookup(&instances, name);
1397 if(!i) syntaxerror("instance '%s' unknown(10)", name);
1398 return i->parameters;
1400 void s_startclip(char*instance, char*character, parameters_t p)
1402 character_t* c = dictionary_lookup(&characters, character);
1406 syntaxerror("character %s not known", character);
1408 i = s_addinstance(instance, c, currentdepth);
1410 m = s_instancepos(i->character->size, &p);
1412 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1413 /* TODO: should be ObjectPlaceClip, with clipdepth backpatched */
1414 swf_ObjectPlace(tag, c->id, currentdepth, &m, &p.cxform, instance);
1416 i->lastFrame= currentframe;
1418 stack[stackpos].tag = tag;
1419 stack[stackpos].type = 2;
1428 swf_SetTagPos(stack[stackpos].tag, 0);
1429 swf_GetPlaceObject(stack[stackpos].tag, &p);
1430 p.clipdepth = currentdepth;
1432 swf_ClearTag(stack[stackpos].tag);
1433 swf_SetPlaceObject(stack[stackpos].tag, &p);
1437 void s_put(char*instance, char*character, parameters_t p)
1439 character_t* c = dictionary_lookup(&characters, character);
1443 syntaxerror("character %s not known (in .put %s=%s)", character, instance, character);
1446 i = s_addinstance(instance, c, currentdepth);
1448 m = s_instancepos(i->character->size, &p);
1450 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1451 swf_ObjectPlace(tag, c->id, currentdepth, &m, &p.cxform, instance);
1453 i->lastFrame = currentframe;
1457 void s_jump(char*instance, parameters_t p)
1459 instance_t* i = dictionary_lookup(&instances, instance);
1462 syntaxerror("instance %s not known", instance);
1466 m = s_instancepos(i->character->size, &p);
1468 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1469 swf_ObjectMove(tag, i->depth, &m, &p.cxform);
1471 i->lastFrame = currentframe;
1474 parameters_t s_interpolate(parameters_t*p1, parameters_t*p2, int pos, int num)
1478 if(num==0 || num==1)
1480 ratio = (float)pos/(float)num;
1482 p.x = (p2->x-p1->x)*ratio + p1->x;
1483 p.y = (p2->y-p1->y)*ratio + p1->y;
1484 p.scalex = (p2->scalex-p1->scalex)*ratio + p1->scalex;
1485 p.scaley = (p2->scaley-p1->scaley)*ratio + p1->scaley;
1486 p.rotate = (p2->rotate-p1->rotate)*ratio + p1->rotate;
1487 p.shear = (p2->shear-p1->shear)*ratio + p1->shear;
1489 p.cxform.r0 = ((float)p2->cxform.r0-(float)p1->cxform.r0)*ratio + p1->cxform.r0;
1490 p.cxform.g0 = ((float)p2->cxform.g0-(float)p1->cxform.g0)*ratio + p1->cxform.g0;
1491 p.cxform.b0 = ((float)p2->cxform.b0-(float)p1->cxform.b0)*ratio + p1->cxform.b0;
1492 p.cxform.a0 = ((float)p2->cxform.a0-(float)p1->cxform.a0)*ratio + p1->cxform.a0;
1494 p.cxform.r1 = (p2->cxform.r1-p1->cxform.r1)*ratio + p1->cxform.r1;
1495 p.cxform.g1 = (p2->cxform.g1-p1->cxform.g1)*ratio + p1->cxform.g1;
1496 p.cxform.b1 = (p2->cxform.b1-p1->cxform.b1)*ratio + p1->cxform.b1;
1497 p.cxform.a1 = (p2->cxform.a1-p1->cxform.a1)*ratio + p1->cxform.a1;
1499 p.pivot.x = (p2->pivot.x-p1->pivot.x)*ratio + p1->pivot.x;
1500 p.pivot.y = (p2->pivot.y-p1->pivot.y)*ratio + p1->pivot.y;
1501 p.pin.x = (p2->pin.x-p1->pin.x)*ratio + p1->pin.x;
1502 p.pin.y = (p2->pin.y-p1->pin.y)*ratio + p1->pin.y;
1506 void s_change(char*instance, parameters_t p2)
1508 instance_t* i = dictionary_lookup(&instances, instance);
1512 int frame, allframes;
1514 syntaxerror("instance %s not known", instance);
1518 allframes = currentframe - i->lastFrame - 1;
1520 warning(".change ignored. can only .put/.change an object once per frame.");
1524 m = s_instancepos(i->character->size, &p2);
1525 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1526 swf_ObjectMove(tag, i->depth, &m, &p2.cxform);
1529 /* o.k., we got the start and end point set. Now iterate though all the
1530 tags in between, inserting object changes after each new frame */
1533 if(!t) syntaxerror("internal error(6)");
1535 while(frame < allframes) {
1536 if(t->id == ST_SHOWFRAME) {
1541 p = s_interpolate(&p1, &p2, frame, allframes);
1542 m = s_instancepos(i->character->size, &p); //needed?
1543 lt = swf_InsertTag(t, ST_PLACEOBJECT2);
1544 i->lastFrame = currentframe;
1545 swf_ObjectMove(lt, i->depth, &m, &p.cxform);
1547 if(frame == allframes)
1552 syntaxerror("internal error(8) (frame=%d/%d)", frame, allframes);
1556 void s_delinstance(char*instance)
1558 instance_t* i = dictionary_lookup(&instances, instance);
1560 syntaxerror("instance %s not known", instance);
1562 tag = swf_InsertTag(tag, ST_REMOVEOBJECT2);
1563 swf_SetU16(tag, i->depth);
1564 dictionary_del(&instances, instance);
1567 void s_qchange(char*instance, parameters_t p)
1574 syntaxerror(".end unexpected");
1575 if(stack[stackpos-1].type == 0)
1577 else if(stack[stackpos-1].type == 1)
1579 else if(stack[stackpos-1].type == 2)
1581 else if(stack[stackpos-1].type == 3)
1583 else syntaxerror("internal error 1");
1586 // ------------------------------------------------------------------------
1588 typedef int command_func_t(map_t*args);
1590 SRECT parseBox(char*str)
1593 float xmin, xmax, ymin, ymax;
1594 char*x = strchr(str, 'x');
1596 if(!strcmp(str, "autocrop")) {
1597 r.xmin = r.ymin = r.xmax = r.ymax = 0;
1601 d1 = strchr(x+1, ':');
1603 d2 = strchr(d1+1, ':');
1605 if(sscanf(str, "%fx%f", &xmax, &ymax) < 2)
1609 else if(d1 && !d2) {
1610 if(sscanf(str, "%fx%f:%f", &xmax, &ymax, &xmin) < 3)
1616 if(sscanf(str, "%fx%f:%f:%f", &xmax, &ymax, &xmin, &ymin) < 4)
1621 r.xmin = (SCOORD)(xmin*20);
1622 r.ymin = (SCOORD)(ymin*20);
1623 r.xmax = (SCOORD)(xmax*20);
1624 r.ymax = (SCOORD)(ymax*20);
1627 syntaxerror("expression %s is not a valid bound Box.\nE.g. 1024x768 or 1024x768:30:30 would have been valid bounding Boxes.", str);
1630 float parseFloat(char*str)
1634 int parseInt(char*str)
1639 if(str[0]=='+' || str[0]=='-')
1643 if(str[t]<'0' || str[t]>'9')
1644 syntaxerror("Not an Integer: \"%s\"", str);
1647 int parseTwip(char*str)
1651 if(str[0]=='+' || str[0]=='-') {
1656 dot = strchr(str, '.');
1660 return sign*parseInt(str)*20;
1662 int l=strlen(++dot);
1664 for(s=str;s<dot-1;s++)
1665 if(*s<'0' || *s>'9')
1666 syntaxerror("Not a coordinate: \"%s\"", str);
1668 if(*s<'0' || *s>'9')
1669 syntaxerror("Not a coordinate: \"%s\"", str);
1671 if(l>2 || (l==2 && (dot[1]!='0' || dot[1]!='5'))) {
1672 warning("precision loss: %s converted to twip", str);
1677 return sign*atoi(str)*20;
1679 return sign*atoi(str)*20+atoi(dot)*2;
1681 return sign*atoi(str)*20+atoi(dot)/5;
1686 int isPoint(char*str)
1688 if(strchr(str, '('))
1694 SPOINT parsePoint(char*str)
1698 int l = strlen(str);
1699 char*comma = strchr(str, ',');
1700 if(str[0]!='(' || str[l-1]!=')' || !comma || l>70)
1701 syntaxerror("\"%s\" is not a valid point of the form (x,y)", str);
1702 strncpy(tmp, str+1, comma-(str+1));tmp[comma-(str+1)]=0;
1703 p.x = parseTwip(tmp);
1704 strncpy(tmp, comma+1, l-1-(comma+1-str));tmp[l-1-(comma+1-str)]=0;
1705 p.y = parseTwip(tmp);
1709 int parseColor2(char*str, RGBA*color)
1711 int l = strlen(str);
1715 struct {unsigned char r,g,b;char*name;} colors[] =
1716 {{255,250,250,"snow"},{220,220,220,"gainsboro"},{250,240,230,"linen"},{255,228,196,"bisque"},
1717 {255,228,181,"moccasin"},{255,248,220,"cornsilk"},{255,255,240,"ivory"},{255,245,238,"seashell"},
1718 {240,255,240,"honeydew"},{240,255,255,"azure"},{230,230,250,"lavender"},{255,255,255,"white"},
1719 {0,0,0,"black"},{190,190,190,"gray"},{190,190,190,"grey"},{0,0,128,"navy"},{0,0,255,"blue"},
1720 {64,224,208,"turquoise"},{0,255,255,"cyan"},{127,255,212,"aquamarine"}, {0,255,0,"green"},
1721 {127,255,0,"chartreuse"},{240,230,140,"khaki"},{255,255,0,"yellow"},
1722 {255,215,0,"gold"},{218,165,32,"goldenrod"},{160,82,45,"sienna"},{205,133,63,"peru"},
1723 {222,184,135,"burlywood"},{245,245,220,"beige"},{245,222,179,"wheat"},{210,180,140,"tan"},
1724 {210,105,30,"chocolate"},{178,34,34,"firebrick"},{165,42,42,"brown"},{250,128,114,"salmon"},
1725 {255,165,0,"orange"},{255,127,80,"coral"},{255,99,71,"tomato"},{255,0,0,"red"},
1726 {255,192,203,"pink"},{176,48,96,"maroon"},{255,0,255,"magenta"},{238,130,238,"violet"},
1727 {221,160,221,"plum"},{218,112,214,"orchid"},{160,32,240,"purple"},{216,191,216,"thistle"}};
1731 if(str[0]=='#' && (l==7 || l==9)) {
1732 if(l == 7 && !(sscanf(str, "#%02x%02x%02x", &r, &g, &b)))
1734 if(l == 9 && !(sscanf(str, "#%02x%02x%02x%02x", &r, &g, &b, &a)))
1736 color->r = r; color->g = g; color->b = b; color->a = a;
1739 for(t=0;t<sizeof(colors)/sizeof(colors[0]);t++)
1740 if(!strcmp(str, colors[t].name)) {
1745 color->r = r; color->g = g; color->b = b; color->a = a;
1751 RGBA parseColor(char*str)
1754 if(!parseColor2(str, &c))
1755 syntaxerror("Expression '%s' is not a color", str);
1759 typedef struct _muladd {
1764 MULADD parseMulAdd(char*str)
1767 char* str2 = (char*)malloc(strlen(str)+5);
1774 if(sscanf(str2, "%f%f %d", &mul, &add, &i)==2+1) { add/=256.0; i=1;}
1775 else if(sscanf(str2, "%f%%%f %d", &mul, &add, &i)==2+1) { mul/=100.0; add/=256.0; i=2;}
1776 else if(sscanf(str2, "%f%f%% %d", &mul, &add, &i)==2+1) { add/=100.0; i=3;}
1777 else if(sscanf(str2, "%f%%%f%% %d", &mul, &add, &i)==2+1) { mul/=100.0; add/=100.0; i=4;}
1778 else if(sscanf(str2, "+%f%% %d", &add, &i)==1+1) { mul=1.0;add/=100.0; i=5;}
1779 else if(sscanf(str2, "+%f %d", &add, &i)==1+1) { mul=1.0;add/=256.0; i=6;}
1780 else if(sscanf(str2, "-%f%% %d", &add, &i)==1+1) { mul=1.0;add/=-100.0; i=7;}
1781 else if(sscanf(str2, "-%f %d", &add, &i)==1+1) { mul=1.0;add/=-256.0; i=8;}
1782 else if(sscanf(str2, "%f%% %d", &mul, &i)==1+1) { mul/=100.0;add=0; i=9;}
1783 else if(sscanf(str2, "%f %d", &mul, &i)==1+1) { add=0; i=10;}
1785 syntaxerror("'%s' is not a valid color transform expression", str);
1787 m.add = (int)(add*256);
1788 m.mul = (int)(mul*256);
1793 MULADD mergeMulAdd(MULADD m1, MULADD m2)
1795 int a = (int)((double)m2.add+((double)m1.add*(double)m2.mul)/256.0);
1796 double m = ((double)m1.mul*(double)m2.mul)/256.0;
1798 if(a<-32768) a=-32768;
1799 if(a>32767) a=32767;
1800 if(m<-32768) m=-32768;
1801 if(m>32767) m=32767;
1807 float parsePercent(char*str)
1809 int l = strlen(str);
1813 return atoi(str)/100.0;
1815 syntaxerror("Expression '%s' is not a percentage", str);
1818 int isPercent(char*str)
1820 return str[strlen(str)-1]=='%';
1822 int parseNewSize(char*str, int size)
1825 return parsePercent(str)*size;
1827 return (int)(atof(str)*20);
1830 int isColor(char*str)
1833 return parseColor2(str, &c);
1836 static char* lu(map_t* args, char*name)
1838 char* value = map_lookup(args, name);
1840 map_dump(args, stdout, "");
1841 syntaxerror("internal error 2: value %s should be set", name);
1846 static int c_flash(map_t*args)
1848 char* name = lu(args, "name");
1849 char* compressstr = lu(args, "compress");
1850 SRECT bbox = parseBox(lu(args, "bbox"));
1851 int version = parseInt(lu(args, "version"));
1852 int fps = (int)(parseFloat(lu(args, "fps"))*256);
1854 RGBA color = parseColor(lu(args, "background"));
1855 if(!strcmp(name, "!default!") || override_outputname)
1858 if(!strcmp(compressstr, "default"))
1859 compress = version==6;
1860 else if(!strcmp(compressstr, "yes") || !strcmp(compressstr, "compress"))
1862 else if(!strcmp(compressstr, "no"))
1864 else syntaxerror("value \"%s\" not supported for the compress argument", compressstr);
1866 s_swf(name, bbox, version, fps, compress, color);
1869 int isRelative(char*str)
1871 return !strncmp(str, "<plus>", 6) ||
1872 !strncmp(str, "<minus>", 7);
1874 char* getOffset(char*str)
1876 if(!strncmp(str, "<plus>", 6))
1878 if(!strncmp(str, "<minus>", 7))
1880 syntaxerror("internal error (347)");
1883 int getSign(char*str)
1885 if(!strncmp(str, "<plus>", 6))
1887 if(!strncmp(str, "<minus>", 7))
1889 syntaxerror("internal error (348)");
1892 static dictionary_t points;
1893 static mem_t mpoints;
1894 int points_initialized = 0;
1896 SPOINT getPoint(SRECT r, char*name)
1899 if(!strcmp(name, "center")) {
1901 p.x = (r.xmin + r.xmax)/2;
1902 p.y = (r.ymin + r.ymax)/2;
1906 if(points_initialized)
1907 l = (int)dictionary_lookup(&points, name);
1909 syntaxerror("Invalid point: \"%s\".", name);
1912 return *(SPOINT*)&mpoints.buffer[l];
1914 static int c_gradient(map_t*args)
1916 char*name = lu(args, "name");
1917 int radial= strcmp(lu(args, "radial"), "radial")?0:1;
1918 int rotate = parseInt(lu(args, "rotate"));
1922 syntaxerror("colon (:) expected");
1924 s_gradient(name, text, radial,rotate);
1927 static int c_point(map_t*args)
1929 char*name = lu(args, "name");
1933 if(!points_initialized) {
1934 dictionary_init(&points);
1936 points_initialized = 1;
1938 p.x = parseTwip(lu(args, "x"));
1939 p.y = parseTwip(lu(args, "y"));
1940 pos = mem_put(&mpoints, &p, sizeof(p));
1941 string_set(&s1, name);
1943 dictionary_put(&points, s1, (void*)pos);
1946 static int c_play(map_t*args)
1948 char*name = lu(args, "name");
1949 char*loop = lu(args, "loop");
1950 char*nomultiple = lu(args, "nomultiple");
1952 if(!strcmp(nomultiple, "nomultiple"))
1955 nm = parseInt(nomultiple);
1957 if(s_playsound(name, parseInt(loop), nm, 0)) {
1959 } else if(s_swf3action(name, "play")) {
1965 static int c_stop(map_t*args)
1967 char*name = map_lookup(args, "name");
1969 if(s_playsound(name, 0,0,1)) {
1971 } else if(s_swf3action(name, "stop")) {
1974 syntaxerror("I don't know anything about sound/movie \"%s\"", name);
1978 static int c_nextframe(map_t*args)
1980 char*name = lu(args, "name");
1982 if(s_swf3action(name, "nextframe")) {
1985 syntaxerror("I don't know anything about movie \"%s\"", name);
1989 static int c_previousframe(map_t*args)
1991 char*name = lu(args, "name");
1993 if(s_swf3action(name, "previousframe")) {
1996 syntaxerror("I don't know anything about movie \"%s\"", name);
2000 static int c_placement(map_t*args, int type)
2002 char*instance = lu(args, (type==0||type==4)?"instance":"name");
2005 char* luminancestr = lu(args, "luminance");
2006 char* scalestr = lu(args, "scale");
2007 char* scalexstr = lu(args, "scalex");
2008 char* scaleystr = lu(args, "scaley");
2009 char* rotatestr = lu(args, "rotate");
2010 char* shearstr = lu(args, "shear");
2011 char* xstr="", *pivotstr="";
2012 char* ystr="", *anglestr="";
2013 char*above = lu(args, "above"); /*FIXME*/
2014 char*below = lu(args, "below");
2015 char* rstr = lu(args, "red");
2016 char* gstr = lu(args, "green");
2017 char* bstr = lu(args, "blue");
2018 char* astr = lu(args, "alpha");
2019 char* pinstr = lu(args, "pin");
2020 char* as = map_lookup(args, "as");
2028 if(type==9) { // (?) .rotate or .arcchange
2029 pivotstr = lu(args, "pivot");
2030 anglestr = lu(args, "angle");
2032 xstr = lu(args, "x");
2033 ystr = lu(args, "y");
2036 luminance = parseMulAdd(luminancestr);
2039 luminance.mul = 256;
2043 if(scalexstr[0]||scaleystr[0])
2044 syntaxerror("scalex/scaley and scale cannot both be set");
2045 scalexstr = scaleystr = scalestr;
2048 if(type == 0 || type == 4) {
2050 character = lu(args, "character");
2051 parameters_clear(&p);
2052 } else if (type == 5) {
2053 character = lu(args, "name");
2054 parameters_clear(&p);
2057 p = s_getParameters(instance);
2062 if(isRelative(xstr)) {
2063 if(type == 0 || type == 4)
2064 syntaxerror("relative x values not allowed for initial put or startclip");
2065 p.x += parseTwip(getOffset(xstr))*getSign(xstr);
2067 p.x = parseTwip(xstr);
2071 if(isRelative(ystr)) {
2072 if(type == 0 || type == 4)
2073 syntaxerror("relative y values not allowed for initial put or startclip");
2074 p.y += parseTwip(getOffset(ystr))*getSign(ystr);
2076 p.y = parseTwip(ystr);
2080 /* scale, scalex, scaley */
2082 oldbbox = s_getCharBBox(character);
2084 oldbbox = s_getInstanceBBox(instance);
2086 oldwidth = oldbbox.xmax - oldbbox.xmin;
2087 oldheight = oldbbox.ymax - oldbbox.ymin;
2089 if(oldwidth==0) p.scalex = 1.0;
2092 p.scalex = (float)(parseNewSize(scalexstr, oldwidth))/oldwidth;
2096 if(oldheight==0) p.scaley = 1.0;
2099 p.scaley = (float)(parseNewSize(scaleystr, oldheight))/oldheight;
2105 if(isRelative(rotatestr)) {
2106 p.rotate += parseFloat(getOffset(rotatestr))*getSign(rotatestr);
2108 p.rotate = parseFloat(rotatestr);
2114 if(isRelative(shearstr)) {
2115 p.shear += parseFloat(getOffset(shearstr))*getSign(shearstr);
2117 p.shear = parseFloat(shearstr);
2122 if(isPoint(pivotstr))
2123 p.pivot = parsePoint(pivotstr);
2125 p.pivot = getPoint(oldbbox, pivotstr);
2129 p.pin = parsePoint(pinstr);
2131 p.pin = getPoint(oldbbox, pinstr);
2134 /* color transform */
2136 if(rstr[0] || luminancestr[0]) {
2139 r = parseMulAdd(rstr);
2141 r.add = p.cxform.r0;
2142 r.mul = p.cxform.r1;
2144 r = mergeMulAdd(r, luminance);
2145 p.cxform.r0 = r.mul;p.cxform.r1 = r.add;
2147 if(gstr[0] || luminancestr[0]) {
2150 g = parseMulAdd(gstr);
2152 g.add = p.cxform.g0;
2153 g.mul = p.cxform.g1;
2155 g = mergeMulAdd(g, luminance);
2156 p.cxform.g0 = g.mul;p.cxform.g1 = g.add;
2158 if(bstr[0] || luminancestr[0]) {
2161 b = parseMulAdd(bstr);
2163 b.add = p.cxform.b0;
2164 b.mul = p.cxform.b1;
2166 b = mergeMulAdd(b, luminance);
2167 p.cxform.b0 = b.mul;p.cxform.b1 = b.add;
2170 MULADD a = parseMulAdd(astr);
2171 p.cxform.a0 = a.mul;p.cxform.a1 = a.add;
2175 s_put(instance, character, p);
2177 s_change(instance, p);
2179 s_qchange(instance, p);
2181 s_jump(instance, p);
2183 s_startclip(instance, character, p);
2184 else if(type == 5) {
2186 s_buttonput(character, as, p);
2188 s_buttonput(character, "shape", p);
2193 static int c_put(map_t*args)
2195 c_placement(args, 0);
2198 static int c_change(map_t*args)
2200 c_placement(args, 1);
2203 static int c_qchange(map_t*args)
2205 c_placement(args, 2);
2208 static int c_arcchange(map_t*args)
2210 c_placement(args, 2);
2213 static int c_jump(map_t*args)
2215 c_placement(args, 3);
2218 static int c_startclip(map_t*args)
2220 c_placement(args, 4);
2223 static int c_show(map_t*args)
2225 c_placement(args, 5);
2228 static int c_del(map_t*args)
2230 char*instance = lu(args, "name");
2231 s_delinstance(instance);
2234 static int c_end(map_t*args)
2239 static int c_sprite(map_t*args)
2241 char* name = lu(args, "name");
2245 static int c_frame(map_t*args)
2247 char*framestr = lu(args, "n");
2248 char*cutstr = lu(args, "cut");
2249 char*name = lu(args, "name");
2252 if(strcmp(cutstr, "no"))
2254 if(isRelative(framestr)) {
2255 frame = s_getframe();
2256 if(getSign(framestr)<0)
2257 syntaxerror("relative frame expressions must be positive");
2258 frame += parseInt(getOffset(framestr));
2261 frame = parseInt(framestr);
2262 if(s_getframe() >= frame
2263 && !(frame==1 && s_getframe()==frame)) // equality is o.k. for frame 0
2264 syntaxerror("frame expression must be >%d (is:%s)", s_getframe(), framestr);
2266 s_frame(frame, cut, name);
2269 static int c_primitive(map_t*args)
2271 char*name = lu(args, "name");
2272 char*command = lu(args, "commandname");
2273 int width=0, height=0, r=0;
2274 int linewidth = parseTwip(lu(args, "line"));
2275 char*colorstr = lu(args, "color");
2276 RGBA color = parseColor(colorstr);
2277 char*fillstr = lu(args, "fill");
2284 if(!strcmp(command, "circle"))
2286 else if(!strcmp(command, "filled"))
2290 width = parseTwip(lu(args, "width"));
2291 height = parseTwip(lu(args, "height"));
2292 } else if (type==1) {
2293 r = parseTwip(lu(args, "r"));
2294 } else if (type==2) {
2295 outline = lu(args, "outline");
2298 if(!strcmp(fillstr, "fill"))
2300 if(!strcmp(fillstr, "none"))
2302 if(width<0 || height<0 || linewidth<0 || r<0)
2303 syntaxerror("values width, height, line, r must be positive");
2305 if(type == 0) s_box(name, width, height, color, linewidth, fillstr);
2306 else if(type==1) s_circle(name, r, color, linewidth, fillstr);
2307 else if(type==2) s_filled(name, outline, color, linewidth, fillstr);
2311 static int c_textshape(map_t*args)
2313 char*name = lu(args, "name");
2314 char*text = lu(args, "text");
2315 char*font = lu(args, "font");
2316 float size = parsePercent(lu(args, "size"));
2318 s_textshape(name, font, size, text);
2322 static int c_swf(map_t*args)
2324 char*name = lu(args, "name");
2325 char*filename = lu(args, "filename");
2326 char*command = lu(args, "commandname");
2327 if(!strcmp(command, "shape"))
2328 warning("Please use .swf instead of .shape");
2329 s_includeswf(name, filename);
2333 static int c_font(map_t*args)
2335 char*name = lu(args, "name");
2336 char*filename = lu(args, "filename");
2337 s_font(name, filename);
2341 static int c_sound(map_t*args)
2343 char*name = lu(args, "name");
2344 char*filename = lu(args, "filename");
2345 s_sound(name, filename);
2349 static int c_text(map_t*args)
2351 char*name = lu(args, "name");
2352 char*text = lu(args, "text");
2353 char*font = lu(args, "font");
2354 float size = parsePercent(lu(args, "size"));
2355 RGBA color = parseColor(lu(args, "color"));
2356 s_text(name, font, text, (int)(size*100), color);
2360 static int c_soundtrack(map_t*args)
2365 static int c_quicktime(map_t*args)
2367 char*name = lu(args, "name");
2368 char*url = lu(args, "url");
2369 s_quicktime(name, url);
2373 static int c_image(map_t*args)
2375 char*command = lu(args, "commandname");
2376 char*name = lu(args, "name");
2377 char*filename = lu(args, "filename");
2378 if(!strcmp(command,"jpeg")) {
2379 int quality = (int)(parsePercent(lu(args, "quality"))*100);
2380 s_image(name, "jpeg", filename, quality);
2382 s_image(name, "png", filename, 0);
2387 static int c_outline(map_t*args)
2389 char*name = lu(args, "name");
2390 char*format = lu(args, "format");
2394 syntaxerror("colon (:) expected");
2396 s_outline(name, format, text);
2400 int fakechar(map_t*args)
2402 char*name = lu(args, "name");
2403 s_box(name, 0, 0, black, 20, 0);
2407 static int c_egon(map_t*args) {return fakechar(args);}
2408 static int c_button(map_t*args) {
2409 char*name = lu(args, "name");
2413 static int current_button_flags = 0;
2414 static int c_on_press(map_t*args)
2416 char*position = lu(args, "position");
2418 if(!strcmp(position, "inside")) {
2419 current_button_flags |= BC_OVERUP_OVERDOWN;
2420 } else if(!strcmp(position, "outside")) {
2421 //current_button_flags |= BC_IDLE_OUTDOWN;
2422 syntaxerror("IDLE_OVERDOWN not supported by SWF");
2423 } else if(!strcmp(position, "anywhere")) {
2424 current_button_flags |= /*BC_IDLE_OUTDOWN|*/BC_OVERUP_OVERDOWN|BC_IDLE_OVERDOWN;
2427 if(type == RAWDATA) {
2429 s_buttonaction(current_button_flags, action);
2430 current_button_flags = 0;
2436 static int c_on_release(map_t*args)
2438 char*position = lu(args, "position");
2440 if(!strcmp(position, "inside")) {
2441 current_button_flags |= BC_OVERDOWN_OVERUP;
2442 } else if(!strcmp(position, "outside")) {
2443 current_button_flags |= BC_OUTDOWN_IDLE;
2444 } else if(!strcmp(position, "anywhere")) {
2445 current_button_flags |= BC_OVERDOWN_OVERUP|BC_OUTDOWN_IDLE|BC_OVERDOWN_IDLE;
2448 if(type == RAWDATA) {
2450 s_buttonaction(current_button_flags, action);
2451 current_button_flags = 0;
2457 static int c_on_move_in(map_t*args)
2459 char*position = lu(args, "state");
2461 if(!strcmp(position, "pressed")) {
2462 current_button_flags |= BC_OUTDOWN_OVERDOWN;
2463 } else if(!strcmp(position, "not_pressed")) {
2464 current_button_flags |= BC_IDLE_OVERUP;
2465 } else if(!strcmp(position, "any")) {
2466 current_button_flags |= BC_OUTDOWN_OVERDOWN|BC_IDLE_OVERUP|BC_IDLE_OVERDOWN;
2469 if(type == RAWDATA) {
2471 s_buttonaction(current_button_flags, action);
2472 current_button_flags = 0;
2478 static int c_on_move_out(map_t*args)
2480 char*position = lu(args, "state");
2482 if(!strcmp(position, "pressed")) {
2483 current_button_flags |= BC_OVERDOWN_OUTDOWN;
2484 } else if(!strcmp(position, "not_pressed")) {
2485 current_button_flags |= BC_OVERUP_IDLE;
2486 } else if(!strcmp(position, "any")) {
2487 current_button_flags |= BC_OVERDOWN_OUTDOWN|BC_OVERUP_IDLE|BC_OVERDOWN_IDLE;
2490 if(type == RAWDATA) {
2492 s_buttonaction(current_button_flags, action);
2493 current_button_flags = 0;
2499 static int c_on_key(map_t*args)
2501 char*key = lu(args, "key");
2503 if(strlen(key)==1) {
2506 current_button_flags |= 0x4000 + (key[0]*0x200);
2508 syntaxerror("invalid character: %c"+key[0]);
2513 <ctrl-x> = 0x200*(x-'a')
2517 syntaxerror("invalid key: %s",key);
2520 if(type == RAWDATA) {
2522 s_buttonaction(current_button_flags, action);
2523 current_button_flags = 0;
2530 static int c_edittext(map_t*args)
2532 //"name font size width height text="" color=black maxlength=0 variable="" @password=0 @wordwrap=0 @multiline=0 @html=0 @noselect=0 @readonly=0"},
2533 char*name = lu(args, "name");
2534 char*font = lu(args, "font");
2535 int size = (int)(1024*parsePercent(lu(args, "size")));
2536 int width = parseTwip(lu(args, "width"));
2537 int height = parseTwip(lu(args, "height"));
2538 char*text = lu(args, "text");
2539 RGBA color = parseColor(lu(args, "color"));
2540 int maxlength = parseInt(lu(args, "maxlength"));
2541 char*variable = lu(args, "variable");
2542 char*passwordstr = lu(args, "password");
2543 char*wordwrapstr = lu(args, "wordwrap");
2544 char*multilinestr = lu(args, "multiline");
2545 char*htmlstr = lu(args, "html");
2546 char*noselectstr = lu(args, "noselect");
2547 char*readonlystr = lu(args, "readonly");
2548 char*borderstr = lu(args, "border");
2551 if(!strcmp(passwordstr, "password")) flags |= ET_PASSWORD;
2552 if(!strcmp(wordwrapstr, "wordwrap")) flags |= ET_WORDWRAP;
2553 if(!strcmp(multilinestr, "multiline")) flags |= ET_MULTILINE;
2554 if(!strcmp(readonlystr, "readonly")) flags |= ET_READONLY;
2555 if(!strcmp(htmlstr, "html")) flags |= ET_HTML;
2556 if(!strcmp(noselectstr, "noselect")) flags |= ET_NOSELECT;
2557 if(!strcmp(borderstr, "border")) flags |= ET_BORDER;
2559 s_edittext(name, font, size, width, height, text, &color, maxlength, variable, flags);
2563 static int c_morphshape(map_t*args) {return fakechar(args);}
2564 static int c_movie(map_t*args) {return fakechar(args);}
2566 static int c_texture(map_t*args) {return 0;}
2568 static int c_action(map_t*args)
2571 if(type != RAWDATA) {
2572 syntaxerror("colon (:) expected");
2582 command_func_t* func;
2585 {{"flash", c_flash, "bbox=autocrop background=black version=5 fps=50 name=!default! @compress=default"},
2586 {"frame", c_frame, "n=<plus>1 name= @cut=no"},
2587 // "import" type stuff
2588 {"swf", c_swf, "name filename"},
2589 {"shape", c_swf, "name filename"},
2590 {"jpeg", c_image, "name filename quality=80%"},
2591 {"png", c_image, "name filename"},
2592 {"movie", c_movie, "name filename"},
2593 {"sound", c_sound, "name filename"},
2594 {"font", c_font, "name filename"},
2595 {"soundtrack", c_soundtrack, "filename"},
2596 {"quicktime", c_quicktime, "url"},
2598 // generators of primitives
2600 {"point", c_point, "name x=0 y=0"},
2601 {"gradient", c_gradient, "name @radial=0 rotate=0"},
2602 {"outline", c_outline, "name format=simple"},
2603 {"textshape", c_textshape, "name font size=100% text"},
2605 // character generators
2606 {"box", c_primitive, "name width height color=white line=1 @fill=none"},
2607 {"circle", c_primitive, "name r color=white line=1 @fill=none"},
2608 {"filled", c_primitive, "name outline color=white line=1 @fill=none"},
2610 {"egon", c_egon, "name vertices color=white line=1 @fill=none"},
2611 {"text", c_text, "name text font size=100% color=white"},
2612 {"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"},
2613 {"morphshape", c_morphshape, "name start end"},
2614 {"button", c_button, "name"},
2615 {"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="},
2616 {"on_press", c_on_press, "position=inside"},
2617 {"on_release", c_on_release, "position=anywhere"},
2618 {"on_move_in", c_on_move_in, "state=not_pressed"},
2619 {"on_move_out", c_on_move_out, "state=not_pressed"},
2620 {"on_key", c_on_key, "key=any"},
2623 {"play", c_play, "name loop=0 @nomultiple=0"},
2624 {"stop", c_stop, "name= "},
2625 {"nextframe", c_nextframe, "name"},
2626 {"previousframe", c_previousframe, "name"},
2628 // object placement tags
2629 {"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="},
2630 {"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="},
2631 {"change", c_change, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= ratio= above= below="},
2632 {"arcchange", c_arcchange, "name pivot= angle= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= ratio= above= below="},
2633 {"qchange", c_qchange, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= ratio= above= below="},
2634 {"jump", c_jump, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= ratio= above= below="},
2635 {"del", c_del, "name"},
2636 // virtual object placement
2637 {"texture", c_texture, "<i> x=0 y=0 scale= scalex=100% scaley=100% shear=0 rotate=0"},
2639 // commands which start a block
2640 //startclip (see above)
2641 {"sprite", c_sprite, "name"},
2642 {"action", c_action, ""},
2648 static map_t parseArguments(char*command, char*pattern)
2664 string_set(&t1, "commandname");
2665 string_set(&t2, command);
2666 map_put(&result, t1, t2);
2668 if(!pattern || !*pattern)
2675 if(!strncmp("<i> ", x, 3)) {
2677 if(type == COMMAND || type == RAWDATA) {
2679 syntaxerror("character name expected");
2681 name[pos].str = "instance";
2683 value[pos].str = text;
2684 value[pos].len = strlen(text);
2688 if(type == ASSIGNMENT)
2691 name[pos].str = "character";
2693 value[pos].str = text;
2694 value[pos].len = strlen(text);
2702 isboolean[pos] = (x[0] =='@');
2715 name[pos].len = d-x;
2720 name[pos].len = e-x;
2721 value[pos].str = e+1;
2722 value[pos].len = d-e-1;
2730 /* for(t=0;t<len;t++) {
2731 printf("(%d) %s=%s %s\n", t, strdup_n(name[t], namelen[t]), strdup_n(value[t], valuelen[t]),
2732 isboolean[t]?"(boolean)":"");
2737 if(type == RAWDATA || type == COMMAND) {
2742 // first, search for boolean arguments
2743 for(pos=0;pos<len;pos++)
2745 if(!set[pos] && isboolean[pos] && !strncmp(name[pos].str, text, name[pos].len>textlen?name[pos].len:textlen)) {
2747 if(type == ASSIGNMENT)
2749 value[pos].str = text;
2750 value[pos].len = strlen(text);
2751 /*printf("setting boolean parameter %s (to %s)\n",
2752 strdup_n(name[pos], namelen[pos]),
2753 strdup_n(value[pos], valuelen[pos]));*/
2758 // second, search for normal arguments
2760 for(pos=0;pos<len;pos++)
2762 if((type == ASSIGNMENT && !strncmp(name[pos].str, text, name[pos].len>textlen?name[pos].len:textlen)) ||
2763 (type != ASSIGNMENT && !set[pos])) {
2765 syntaxerror("value %s set twice (old value:%s)", text, strdup_n(value[pos].str, value[pos].len));
2767 if(type == ASSIGNMENT)
2770 value[pos].str = text;
2771 value[pos].len = strlen(text);
2773 printf("setting parameter %s (to %s)\n",
2774 strdup_n(name[pos].str, name[pos].len),
2775 strdup_n(value[pos].str, value[pos].len));
2781 syntaxerror("don't know what to do with \"%s\". (All parameters for .%s already set)", text, command);
2785 for(t=0;t<len;t++) {
2786 printf("%s=%s\n", strdup_n(name[t].str, name[t].len), strdup_n(value[t].str, value[t].len));
2789 for(t=0;t<len;t++) {
2790 if(value[t].str && value[t].str[0] == '*') {
2791 //relative default- take value from some other parameter
2793 for(s=0;s<len;s++) {
2794 if(value[s].len == value[t].len-1 &&
2795 !strncmp(&value[t].str[1], value[s].str, value[s].len))
2796 value[t].str = value[s].str;
2799 if(value[t].str == 0) {
2801 syntaxerror("value for parameter %s missing (no default)", strdup_n(name[t].str, name[t].len));
2805 /* ok, now construct the dictionary from the parameters */
2809 map_put(&result, name[t], value[t]);
2813 static void parseArgumentsForCommand(char*command)
2818 msg("<verbose> parse Command: %s (line %d)", command, line);
2820 for(t=0;t<sizeof(arguments)/sizeof(arguments[0]);t++) {
2821 if(!strcmp(arguments[t].command, command)) {
2823 /* ugly hack- will be removed soon (once documentation and .sc generating
2824 utilities have been changed) */
2825 if(!strcmp(command, "swf") && !stackpos) {
2826 warning("Please use .flash instead of .swf- this will be mandatory soon");
2831 args = parseArguments(command, arguments[t].arguments);
2837 syntaxerror("command %s not known", command);
2839 // catch missing .flash directives at the beginning of a file
2840 if(strcmp(command, "flash") && !stackpos)
2842 syntaxerror("No movie defined- use .flash first");
2846 printf(".%s\n", command);fflush(stdout);
2847 map_dump(&args, stdout, "\t");fflush(stdout);
2850 (*arguments[nr].func)(&args);
2852 /*if(!strcmp(command, "button") ||
2853 !strcmp(command, "action")) {
2856 if(type == COMMAND) {
2857 if(!strcmp(text, "end"))
2871 int main (int argc,char ** argv)
2874 processargs(argc, argv);
2875 initLog(0,-1,0,0,-1,verbose);
2878 args_callback_usage(argv[0]);
2882 file = generateTokens(filename);
2884 printf("parser returned error.\n");
2890 while(!noMoreTokens()) {
2893 syntaxerror("command expected");
2894 parseArgumentsForCommand(text);