home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Acorn User 10
/
AU_CD10.iso
/
Archived
/
Updates
/
Flash
/
writeflash
/
!MakeFlash
/
c
/
parser
< prev
next >
Wrap
Text File
|
2000-06-04
|
57KB
|
2,061 lines
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <math.h>
#include <ctype.h>
//
#include "proto.h"
#include "flash.h"
#include "main.h"
#include "shape.h"
#include "bbox.h"
#include "bucket.h"
#include "bitcount.h"
#include "matrix.h"
#include "cxform.h"
#include "bitmap.h"
#include "rectangle.h"
#include "gradient.h"
#include "action.h"
#include "button.h"
#include "fonttext.h"
#include "parser.h"
#include "sound.h"
#include "preprocess.h"
#include "evaluate.h"
#include "dictionary.h"
static int get_token(char *out, int max);
static int get_tokenl(char *out, int max);
static int get_valueS8(S8 *result);
static int get_valueU8(U8 *result);
static int get_valueS16(S16 *result);
static int get_valueU16(U16 *result);
static int get_valueU32(U32 *result);
static int get_valueS32(S32 *result);
static int get_value(S32 *result);
static int get_token_bm(char *out, int max);
static int getchr(void);
static int get_rgb(U32 *rgb);
static int get_id(U16 *id);
static int place_object(PLACEOBJECT *place);
static int remove_object(U16 depth, U16 frame);
static int show_frame(void);
static int parse_file_version(void);
static int parse_button(void);
static int parse_frame_area(void);
static int parse_bg_colour(void);
static int parse_actions(ACTION **list, unsigned int *count);
static int parse_define_shape(void);
static int parse_bitmap(int bmtype);
static int parse_place_object(void);
static int parse_remove_object(void);
static int parse_show_frame(void);
static int parse_cxform(CXFORM *cxform);
static int parse_fillstyles(SHAPE *shape);
static int parse_linestyles(SHAPE *shape);
static int parse_gradient(GRADIENT *gradient);
static int parse_matrix(MATRIX *matrix);
static int parse_rect(RECT *rect);
static int parse_font(void);
static int parse_text(void);
static int parse_define_sound(void);
static int parse_play_sound(void);
static int parse_text_style_record(TEXTREC *rec);
static int parse_glyph(GLYPH *glyph);
static int parse_initialise(void);
#define MAXFRAMECOUNT 8192
#define RESERVED_FRAMENO 65535
#define TOKEN_NOT_FOUND -1
#define TOKEN 0
#define TOKEN_STRING 1
#define TOKEN_LB 2
#define TOKEN_RB 3
// local to this file
static U32 framecount, framerate, bgcolour, protected;
static U8 fileversion;
static RECT framesize;
static S32 scalex, scaley, scaleboth; // 1000 = 100%
static FRAME frames[MAXFRAMECOUNT];
static char linebuffer[MAXLINELENGTH];
static U32 bufferpos;
int parse_initialise() {
// reset everything
memset(frames+0, 0, sizeof(FRAME));
scalex = scaley = scaleboth = 1000;
framesize.minx = framesize.miny = 0;
framesize.maxx = framesize.maxy = 4000;
dictionary_init();
// default values
framecount = 0;
fileversion = 1;
bgcolour = 0x00fffff;
framerate = 0x0a00;
protected = 0;
if (create_variable("frameno")) return 1;
if (set_variable_value("frameno", 0)) return 1;
return 0;
}
int get_rgb(U32 *rgb) {
int i, type;
char token[100];
type = get_token(token, 100);
if (type == TOKEN_LB) {
S32 r, g, b, a;
type = get_value(&r);
if (type != TOKEN) return type;
type = get_value(&g);
if (type != TOKEN) return type;
type = get_value(&b);
if (type != TOKEN) return type;
type = get_value(&a);
if (type == TOKEN_RB)
a = 255;
else if (type != TOKEN)
return type;
else if (get_token(token, 100) != TOKEN_RB)
return type;
if (r < 0) r = 0;
if (r > 255) r = 255;
if (g < 0) g = 0;
if (g > 255) g = 255;
if (b < 0) b = 0;
if (b > 255) b = 255;
if (a < 0) a = 0;
if (a > 255) a = 255;
*rgb = r | (g<<8) | (b<<16) | (a<<24);
return TOKEN;
} else if (type != TOKEN) return type;
*rgb = 0;
i = 0;
while (isxdigit(token[i])) {
int c;
c = token[i];
if (c >= 'a') c -= 'a' - 'A';
if (c >= 'A')
c -= 'A'-10;
else
c -= '0';
*rgb = (*rgb<<4) | c;
i++;
}
return TOKEN;
}
int update_record_header(int tag, U32 ptr) {
U32 ptr2, size;
U16 rechdr;
U8 *buf;
if (flush_bucket()) return 1;
ptr2 = read_position(&buf);
buf += ptr;
size = ptr2 - ptr - 2;
if (size >= 63) {
U8 hdr[4];
rechdr = (tag<<6) | 0x3f;
buf[0] = rechdr & 0xff;
buf[1] = (rechdr>>8) & 0xff;
hdr[0] = size & 0xff;
hdr[1] = (size>> 8) & 0xff;
hdr[2] = (size>>16) & 0xff;
hdr[3] = (size>>24) & 0xff;
if (bucket_insert(ptr+2, hdr, 4)) return 1;
} else {
rechdr = (tag<<6) | size;
buf[0] = rechdr & 0xff;
buf[1] = (rechdr>>8) & 0xff;
}
return 0;
}
int getchr() {
while (!linebuffer[bufferpos]) {
if (get_line(linebuffer)) return -1;
if (debug_print_lines) printf("%s\n", linebuffer);
bufferpos = 0;
}
return linebuffer[bufferpos++];
}
int get_tokenl(char *out, int max) {
int type, i;
type = get_token(out, max);
if (type == TOKEN) {
i = 0;
while (out[i]) {
out[i] = tolower(out[i]);
i++;
}
}
return type;
}
int get_valueS8(S8 *result) {
S32 res;
int type;
type = get_value(&res);
if (type != TOKEN) return type;
*result = (S8)res;
return TOKEN;
}
int get_valueU8(U8 *result) {
S32 res;
int type;
type = get_value(&res);
if (type != TOKEN) return type;
*result = (U8)res;
return TOKEN;
}
int get_valueS16(S16 *result) {
S32 res;
int type;
type = get_value(&res);
if (type != TOKEN) return type;
*result = (S16)res;
return TOKEN;
}
int get_id(U16 *id) {
int type;
type = get_valueU16(id);
if (!type != TOKEN) return type;
if (*id == RESERVED_ID) {
fprintf(stderr, "Id %d (%04x) is reserved\n", RESERVED_ID, RESERVED_ID);
return TOKEN_NOT_FOUND;
}
return TOKEN;
}
int get_valueU16(U16 *result) {
S32 res;
int type;
type = get_value(&res);
if (type != TOKEN) return type;
*result = (U16)res;
return TOKEN;
}
int get_valueU32(U32 *result) {
return get_value((S32 *)result);
}
int get_value(S32 *result) {
return get_valueS32(result);
}
int get_valueS32(S32 *result) {
char token[100];
int type;
type = get_token_bm(token, 100);
if (type != TOKEN) return type;
if (evaluate(token, result)) return TOKEN_NOT_FOUND;
return TOKEN;
}
int get_token_bm(char *out, int max) { // bracket-matching
int len, type, bm, i;
char token[MAXLINELENGTH];
type = get_token(out, max);
if (type != TOKEN) return type;
if (out[0] != '(') return type;
do {
type = get_token(token, max-len);
if (type != TOKEN) {
fprintf(stderr, "Unmatched brackets or expression is too long\n");
return type;
}
strcat(out+len, token);
len = strlen(out);
printf("%s\n", out);
bm = 0;
for (i = 0; i < len; i++) {
if (out[i] == '(')
bm++;
else if (out[i] == ')')
bm--;
}
} while (bm);
return TOKEN;
}
int get_token(char *out, int max) {
// disgusting to say the least - not the prettiest piece
// of code I've ever had to take credit for...
int len, c, token;
len = 0;
max -= 1;
token = TOKEN_NOT_FOUND;
do {
// skip white spaces
do {
c = getchr();
if (c == -1) return TOKEN_NOT_FOUND;
if ((c <= ' ') && (len > 0)) {
// end of token
out[len] = '\0';
return TOKEN;
}
} while (c <= ' ');
if ((c == '{') && (len == 0)) return TOKEN_LB;
if ((c == '}') && (len == 0)) return TOKEN_RB;
// is it a comment??
if (c == '/') {
int c2;
c2 = getchr();
if (c2 == -1) return TOKEN_NOT_FOUND;
if (c2 == '/') {
// it is a comment, so skip to end of line
bufferpos = 0; linebuffer[bufferpos] ='\0';
if (len > 0) {
// if we had already read something,
}
} else {
if (len+2 >= max) return TOKEN_NOT_FOUND;
out[len++] = c;
out[len++] = c2;
}
// mark char as processed
c = -1;
}
if (c > 0) {
if (len+1 >= max) return TOKEN_NOT_FOUND;
out[len++] = c;
if (c == '"') { // string, read to end of string
len--;
while ((c != -1) && (len < max)) {
c = getchr();
if (c == -1) return TOKEN_NOT_FOUND;
if (c == '"') {
// end of string
out[len] = '\0';
return TOKEN_STRING;
} else if (c == '\\') {
// escaped char
if (len+1 >= max) return TOKEN_NOT_FOUND;
c = getchr();
if (c == -1) return TOKEN_NOT_FOUND;
switch (c) {
case 'r':
out[len++] = '\r';
break;
case 'n':
out[len++] = '\n';
break;
case 't':
out[len++] = '\t';
break;
case '"':
out[len++] = '"';
break;
case '\\':
out[len++] = '\\';
break;
default:
break;
}
} else
// normal char
out[len++] = c;
}
} else { // normal token, read to next space
}
}
} while (1);
return TOKEN_NOT_FOUND;
}
void report_error(char *err) {
fprintf(stderr, "%s\n", err);
exit(-1);
}
int parse_rect(RECT *rect) {
char token[100];
S32 val;
if (get_token(token, 100) != TOKEN_LB) return 1;
if (get_value(&val) != TOKEN) return 1;
rect->minx = (scalex*val)/1000;
if (get_value(&val) != TOKEN) return 1;
rect->miny = (scaley*val)/1000;
if (get_value(&val) != TOKEN) return 1;
rect->maxx = (scalex*val)/1000;
if (get_value(&val) != TOKEN) return 1;
rect->maxy = (scaley*val)/1000;
if (get_token(token, 100) != TOKEN_RB) return 1;
return 0;
}
int parse_gradient(GRADIENT *gradient) {
char token[100];
int type, i;
U8 grad;
memset(gradient, 0, sizeof(GRADIENT));
gradient->usealpha = 1;
if (get_token(token, 100) != TOKEN_LB) return 1;
do {
type = get_valueU8(&grad);
if (type == TOKEN) {
gradient->ratio[gradient->n] = grad;
if (get_rgb(&gradient->rgba[gradient->n]) != TOKEN) return 1;
gradient->n++;
} else if (type != TOKEN_RB)
return 1;
} while (type != TOKEN_RB);
for (i = 0; i < gradient->n-1; i++)
if (gradient->ratio[i] >= gradient->ratio[i+1]) return 1;
return 0;
}
int parse_matrix(MATRIX *matrix) {
char token[100];
S32 v[7], val;
int n, type;
matrix->scalex = matrix->scaley = (scaleboth*65536)/1000;
matrix->rotate0 = matrix->rotate1 = 0;
matrix->tx = matrix->ty = 0;
if (get_token(token, 100) != TOKEN_LB) return 1;
n = 0;
do {
type = get_value(&val);
if (type == TOKEN)
v[n++] = val;
else if (type != TOKEN_RB) return 1;
} while ((type != TOKEN_RB) && (n <= 6));
if (type != TOKEN_RB) return 1;
switch (n) {
case 1:
matrix->scalex = matrix->scaley = (scaleboth*v[0])/1000;
break;
case 2:
matrix->scalex = (scaleboth*v[0])/1000;
matrix->scaley = (scaleboth*v[1])/1000;
break;
case 3:
matrix->scalex = matrix->scaley = (scaleboth*v[0])/1000;
matrix->tx = (scalex*v[1])/1000;
matrix->ty = (scaley*v[2])/1000;
break;
case 4:
matrix->scalex = (scaleboth*v[0])/1000;
matrix->scaley = (scaleboth*v[1])/1000;
matrix->tx = (scalex*v[2])/1000;
matrix->ty = (scaley*v[3])/1000;
break;
case 6:
matrix->scalex = (scaleboth*v[0])/1000;
matrix->scaley = (scaleboth*v[1])/1000;
matrix->rotate0 = (scaleboth*v[2])/1000;
matrix->rotate1 = (scaleboth*v[3])/1000;
matrix->tx = (scalex*v[4])/1000;
matrix->ty = (scaley*v[5])/1000;
break;
case 5:
report_error("Bad matrix");
break;
}
return 0;
}
int parse_actions(ACTION **list, unsigned int *count) {
char token[MAXLINELENGTH];
int type;
ACTION action;
if (get_token(token, 100) != TOKEN_LB) return 1;
do {
memset(&action, 0, sizeof(ACTION));
type = get_tokenl(token, 100);
if (type == TOKEN_RB) return 0;
if (type != TOKEN) return 1;
if (strcmp(token, "gotoframe") == 0) {
U16 frame;
if (get_valueU16(&frame) != TOKEN) return 1;
action.action = ACTION_GOTOFRAME;
action.data.gotoframe = frame;
if (add_action(list, count, &action)) return 1;
} else if (strcmp(token, "play") == 0) {
action.action = ACTION_PLAY;
if (add_action(list, count, &action)) return 1;
} else if (strcmp(token, "stop") == 0) {
action.action = ACTION_STOP;
if (add_action(list, count, &action)) return 1;
} else if (strcmp(token, "stopsounds") == 0) {
action.action = ACTION_STOPSOUNDS;
if (add_action(list, count, &action)) return 1;
} else if (strcmp(token, "nextframe") == 0) {
action.action = ACTION_NEXTFRAME;
if (add_action(list, count, &action)) return 1;
} else if (strcmp(token, "previousframe") == 0) {
action.action = ACTION_PREVIOUSFRAME;
if (add_action(list, count, &action)) return 1;
} else if (strcmp(token, "geturl") == 0) {
int type;
if (get_token(token, 100) != TOKEN_LB) return 1;
do {
type = get_tokenl(token, 100);
if (type == TOKEN) {
if (strcmp(token, "url") == 0) {
type = get_token(token, MAXLINELENGTH);
if (type != TOKEN_STRING) return 1;
action.data.geturl.url = malloc(strlen(token)+1);
if (!action.data.geturl.url) return 1;
strcpy(action.data.geturl.url, token);
} else if (strcmp(token, "target") == 0) {
type = get_token(token, MAXLINELENGTH);
if (type != TOKEN_STRING) return 1;
action.data.geturl.target = malloc(strlen(token)+1);
if (!action.data.geturl.target) return 1;
strcpy(action.data.geturl.target, token);
}
} else if (type != TOKEN_RB) return 1;
} while (type != TOKEN_RB);
if (!action.data.geturl.url) report_error("No URL specified");
if (!action.data.geturl.target) {
action.data.geturl.target = malloc(1);
if (!action.data.geturl.target) return 1;
action.data.geturl.target[0] = '\0';
}
action.action = ACTION_GETURL;
if (add_action(list, count, &action)) return 1;
} else {
fprintf(stderr, "Unsupported field '%s'\n", token);
return 1;
}
} while (1);
return 1;
}
int parse_play_sound() {
char token[MAXLINELENGTH];
PLAYSOUND *play;
int type;
U16 framei;
FRAME *frame;
play = malloc(sizeof(PLAYSOUND));
if (!play) return 1;
memset(play, 0, sizeof(PLAYSOUND));
play->id = RESERVED_ID;
play->loops = 1;
framei = RESERVED_FRAMENO;
if (get_token(token, 100) != TOKEN_LB) return 1;
do {
type = get_tokenl(token, 100);
if (type == TOKEN) {
if (strcmp(token, "id") == 0) {
if (get_id(&play->id) != TOKEN) return 1;
if (!is_id_used(play->id)) {
fprintf(stderr, "Unknown character (id=%d)\n", play->id);
return 1;
}
} else if (strcmp(token, "loops") == 0) {
if (get_valueU16(&play->loops) != TOKEN) return 1;
} else if (strcmp(token, "frame") == 0) {
if (get_valueU16(&framei) != TOKEN) return 1;
}
} else if (type != TOKEN_RB) return 1;
} while (type != TOKEN_RB);
if (framei == RESERVED_FRAMENO)
frame = frames+framecount;
else {
if (framei >= framecount)
report_error("Illegal frame no. in PlaySound { }");
frame = frames+framei;
}
if (!frame->sounds) {
frame->sounds = malloc(sizeof(PLAYSOUND));
if (!frame->sounds) return 1;
} else {
PLAYSOUND *newsounds;
newsounds = realloc(frame->sounds, (frame->soundcount+1)*sizeof(PLAYSOUND));
if (!newsounds) return 1;
frame->sounds = newsounds;
}
memcpy(frame->sounds + frame->soundcount, play, sizeof(PLAYSOUND));
frame->soundcount++;
return 0;
return 0;
}
int parse_define_sound() {
char token[MAXLINELENGTH];
int type;
SOUND *sound;
if (sound_create(&sound)) return 1;
if (get_token(token, 100) != TOKEN_LB) return 1;
do {
type = get_tokenl(token, MAXLINELENGTH);
if (type == TOKEN) {
if (strcmp(token, "id") == 0) {
if (get_id(&sound->id) != TOKEN) return 1;
if (is_id_used(sound->id)) report_error("Dublicate character ID");
} else if (strcmp(token, "format") == 0) {
if (get_token(token, 100) != TOKEN_STRING) return 1;
if (strcmp(token, "LIN8") == 0)
sound->format = SOUNDFORMAT_LIN8;
else if (strcmp(token, "LIN16") == 0)
sound->format = SOUNDFORMAT_LIN16;
else if (strcmp(token, "ADPCM2") == 0)
sound->format = SOUNDFORMAT_ADPCM2;
else if (strcmp(token, "ADPCM3") == 0)
sound->format = SOUNDFORMAT_ADPCM3;
else if (strcmp(token, "ADPCM4") == 0)
sound->format = SOUNDFORMAT_ADPCM4;
else if (strcmp(token, "ADPCM5") == 0)
sound->format = SOUNDFORMAT_ADPCM5;
else
return 1;
} else if (strcmp(token, "file") == 0) {
if (get_token(token, 100) != TOKEN_STRING) return 1;
sound->file = malloc(strlen(token)+1);
if (!sound->file) return 1;
strcpy(sound->file, token);
} else if (strcmp(token, "channels") == 0) {
int chns;
if (get_value(&chns) != TOKEN) return 1;
if (chns == 1)
sound->stereo = 0;
else
sound->stereo = 1;
} else if (strcmp(token, "freq") == 0) {
if (get_value(&sound->freq) != TOKEN) return 1;
}
} else if (type != TOKEN_RB)
return 1;
} while (type != TOKEN_RB);
return add_character(sound->id, sound, CHARACTER_SOUND);
}
int parse_bitmap(int bmtype) {
char token[MAXLINELENGTH];
int type;
BITMAP *bitmap;
if (bitmap_create(&bitmap)) return 1;
if (get_token(token, 100) != TOKEN_LB) return 1;
switch (bmtype) {
case BITMAP_JPEG:
bitmap->type = BITMAP_JPEG;
do {
type = get_tokenl(token, MAXLINELENGTH);
if (type == TOKEN) {
if (strcmp(token, "id") == 0) {
if (get_id(&bitmap->id) != TOKEN) return 1;
if (is_id_used(bitmap->id)) report_error("Dublicate character ID");
} else if (strcmp(token, "width") == 0) {
if (get_valueU16(&bitmap->width) != TOKEN) return 1;
} else if (strcmp(token, "height") == 0) {
if (get_valueU16(&bitmap->height) != TOKEN) return 1;
} else if (strcmp(token, "file") == 0) {
if (get_token(token, 100) != TOKEN_STRING) return 1;
bitmap->file = malloc(strlen(token)+1);
if (!bitmap->file) return 1;
strcpy(bitmap->file, token);
} else if (strcmp(token, "alphafile") == 0) {
if (get_token(token, 100) != TOKEN_STRING) return 1;
bitmap->alphafile = malloc(strlen(token)+1);
if (!bitmap->alphafile) return 1;
strcpy(bitmap->alphafile, token);
}
} else if (type != TOKEN_RB)
return 1;
} while (type != TOKEN_RB);
break;
}
return add_character(bitmap->id, bitmap, CHARACTER_BITMAP);
}
int parse_fillstyles(SHAPE *shape) {
char token[100];
int type;
FILLSTYLE style;
do {
type = get_tokenl(token, 100);
if (type == TOKEN) {
if (strcmp(token, "solid") == 0) {
style.type = FILLSTYLE_SOLID;
if (get_rgb(&style.fill.solid) != TOKEN) return 1;
} else if ((strcmp(token, "linear") == 0) || (strcmp(token, "radial") == 0)) {
int type;
matrix_reset(&style.fill.gradient.matrix);
if (strcmp(token, "radial") == 0)
style.type = FILLSTYLE_RADIAL;
else
style.type = FILLSTYLE_LINEAR;
if (get_token(token, 100) != TOKEN_LB) return 1;
do {
type = get_tokenl(token, 100);
if (type == TOKEN) {
if (strcmp(token, "matrix") == 0) {
if (parse_matrix(&style.fill.gradient.matrix)) return 1;
} else if (strcmp(token, "gradient") == 0) {
if (parse_gradient(&style.fill.gradient.gradient)) return 1;
}
} else if (type != TOKEN_RB) return 1;
} while (type != TOKEN_RB);
} else if ((strcmp(token, "tiled") == 0) || (strcmp(token, "clipped") == 0)) {
int type;
matrix_reset(&style.fill.gradient.matrix);
if (strcmp(token, "clipped") == 0)
style.type = FILLSTYLE_CLIPPED;
else
style.type = FILLSTYLE_TILED;
if (get_token(token, 100) != TOKEN_LB) return 1;
do {
type = get_tokenl(token, 100);
if (type == TOKEN) {
if (strcmp(token, "matrix") == 0) {
if (parse_matrix(&style.fill.bitmap.matrix)) return 1;
} else if (strcmp(token, "id") == 0) {
if (get_id(&style.fill.bitmap.id) != TOKEN) return 1;
if (get_character_type(style.fill.bitmap.id) != CHARACTER_BITMAP) {
fprintf(stderr, "Character (id=%d) is unknown or does not refer to a bitmap\n", style.fill.bitmap.id);
return 1;
}
}
} else if (type != TOKEN_RB) return 1;
} while (type != TOKEN_RB);
}
if (shape_add_fillstyle(shape, &style)) return 1;
} else if (type != TOKEN_RB) return 1;
} while (type != TOKEN_RB);
return 0;
}
int parse_linestyles(SHAPE *shape) {
int type;
U16 width;
LINESTYLE style;
do {
type = get_valueU16(&width);
if (type == TOKEN) {
style.width = (scaleboth*width)/1000;
if (get_rgb(&style.rgba) != TOKEN) return 1;
if (shape_add_linestyle(shape, &style)) return 1;
} else if (type != TOKEN_RB)
return 1;
} while (type != TOKEN_RB);
return 0;
}
int parse_file_version() {
if (get_valueU8(&fileversion) != TOKEN) return 1;
return 0;
}
int parse_frame_area() {
char token[100];
int type;
if (get_token(token, 100) != TOKEN_LB) return 1;
do {
type = get_tokenl(token, 100);
if (type == TOKEN) {
if (strcmp(token, "width") == 0) {
if (get_value(&framesize.maxx) != TOKEN) return 1;
if (create_variable("framesizex")) return 1;
if (set_variable_value("framesizex", framesize.maxx)) return 1;
} else if (strcmp(token, "height") == 0) {
if (get_value(&framesize.maxy) != TOKEN) return 1;
if (create_variable("framesizey")) return 1;
if (set_variable_value("framesizey", framesize.maxy)) return 1;
} else if (strcmp(token, "scalex") == 0) {
if (get_value(&scalex) != TOKEN) return 1;
} else if (strcmp(token, "scaley") == 0) {
if (get_value(&scaley) != TOKEN) return 1;
}
} else if (type != TOKEN_RB) return 1;
} while (type != TOKEN_RB);
scaleboth = (S32)sqrt((int)abs(scalex*scaley));
return 0;
}
int parse_frame_rate() {
char token[100], *p;
U8 i, f;
if (get_token(token, 100)) return 1;
p = strchr(token, '.');
if (p) {
*p = '\0';
f = atoi(p+1);
} else
f = 0;
i = atoi(token);
if ((i > 255) || (i < 0) || (f > 255) || (f < 0)) return 1;
framerate = (i<<8) | f;
return 0;
}
int parse_cxform(CXFORM *cxform) {
char token[100];
S16 values[8];
int n, type;
cxform->mula = 255;
cxform->adda = 0;
if (get_token(token, 100) != TOKEN_LB) return 1;
n = 0;
do {
type = get_valueS16(values+n);
if (type == TOKEN)
n++;
else if (type != TOKEN_RB)
return 1;
} while ((n < 8) && (type != TOKEN_RB));
if (n == 8)
if (get_token(token, 100) != TOKEN_RB) return 1;
if ((n != 6) && (n != 8)) {
fprintf(stderr, "Bad value-count in cxform\n");
return 1;
}
if (n == 6) {
cxform->mulr = values[0];
cxform->mulg = values[1];
cxform->mulb = values[2];
cxform->addr = values[3];
cxform->addg = values[4];
cxform->addb = values[5];
cxform->mula = 255;
cxform->adda = 0;
} else {
cxform->mulr = values[0];
cxform->mulg = values[1];
cxform->mulb = values[2];
cxform->mula = values[3];
cxform->addr = values[4];
cxform->addg = values[5];
cxform->addb = values[6];
cxform->adda = values[7];
}
return 0;
}
int parse_bg_colour() {
return get_rgb(&bgcolour);
}
int parse_define_shape(void) {
char token[100];
int type;
S32 x, y;
SHAPE *shape;
SHAPERECORD rec;
if (shape_create(&shape)) return 1;
if (get_token(token, 100) != TOKEN_LB) return 1;
x = y = 0;
do {
// repeatedly read a token and parse the arguments
type = get_tokenl(token, 100);
if (type == TOKEN) {
if (strcmp(token, "id") == 0) {
if (get_id(&shape->id) != TOKEN) return 1;
if (is_id_used(shape->id)) report_error("Dublicate character ID");
} else if (strcmp(token, "bbox") == 0) {
// bbox { } is not used from version 0.02 onwards
RECT unused;
if (parse_rect(&unused)) return 1;
} else if (strcmp(token, "fillstyle") == 0) {
if (get_token(token, 100) != TOKEN_LB) return 1;
if (parse_fillstyles(shape)) return 1;
} else if (strcmp(token, "linestyle") == 0) {
if (get_token(token, 100) != TOKEN_LB) return 1;
if (parse_linestyles(shape)) return 1;
} else if ((strcmp(token, "selectfillstyle0") == 0) ||
(strcmp(token, "fill0") == 0)) {
rec.type = SHAPERECORD_STYLE;
rec.flags = SHAPERECORD_STYLE_FILL0;
if (get_valueU8(&rec.fillstyle0) != TOKEN) return 1;
if (shape_add_record(shape, &rec)) return 1;
} else if ((strcmp(token, "selectfillstyle1") == 0) ||
(strcmp(token, "fill1") == 0)) {
rec.type = SHAPERECORD_STYLE;
rec.flags = SHAPERECORD_STYLE_FILL1;
if (get_valueU8(&rec.fillstyle1) != TOKEN) return 1;
if (shape_add_record(shape, &rec)) return 1;
} else if (strcmp(token, "selectlinestyle") == 0) {
rec.type = SHAPERECORD_STYLE;
rec.flags = SHAPERECORD_STYLE_LINE;
if (get_valueU8(&rec.linestyle) != TOKEN) return 1;
if (shape_add_record(shape, &rec)) return 1;
} else if (strcmp(token, "moveto") == 0) {
if (get_token(token, 100) != TOKEN_LB) return 1;
rec.type = SHAPERECORD_STYLE;
rec.flags = SHAPERECORD_STYLE_MOVE;
if (get_value(&x) != TOKEN) return 1;
x = (scalex*x)/1000;
if (get_value(&y) != TOKEN) return 1;
y = (scaley*y)/1000;
rec.x = x;
rec.y = y;
if (shape_add_record(shape, &rec)) return 1;
if (get_token(token, 100) != TOKEN_RB) return 1;
} else if (strcmp(token, "moveby") == 0) {
S32 dx, dy;
if (get_token(token, 100) != TOKEN_LB) return 1;
rec.type = SHAPERECORD_STYLE;
rec.flags = SHAPERECORD_STYLE_MOVE;
if (get_value(&dx) != TOKEN) return 1;
dx = (scalex*dx)/1000;
if (get_value(&dy) != TOKEN) return 1;
dy = (scaley*dy)/1000;
if ((dx != 0) || (dy != 0)) {
x += dx;
y += dy;
rec.x = x;
rec.y = y;
if (shape_add_record(shape, &rec)) return 1;
}
if (get_token(token, 100) != TOKEN_RB) return 1;
} else if (strcmp(token, "lineby") == 0) {
S32 dx, dy;
if (get_token(token, 100) != TOKEN_LB) return 1;
rec.type = SHAPERECORD_STRAIGHT;
if (get_value(&dx) != TOKEN) return 1;
dx = (scalex*dx)/1000;
if (get_value(&dy) != TOKEN) return 1;
dy = (scaley*dy)/1000;
if ((dx != 0) || (dy != 0)) {
x += dx;
y += dy;
rec.x = dx;
rec.y = dy;
if (shape_add_record(shape, &rec)) return 1;
}
if (get_token(token, 100) != TOKEN_RB) return 1;
} else if (strcmp(token, "curveby") == 0) {
S32 dxc, dyc, dx, dy;
if (get_token(token, 100) != TOKEN_LB) return 1;
rec.type = SHAPERECORD_CURVE;
if (get_value(&dxc) != TOKEN) return 1;
dxc = (scalex*dxc)/1000;
if (get_value(&dyc) != TOKEN) return 1;
dyc = (scaley*dyc)/1000;
if (get_value(&dx) != TOKEN) return 1;
dx = (scalex*dx)/1000;
if (get_value(&dy) != TOKEN) return 1;
dy = (scaley*dy)/1000;
if ((dx != 0) || (dy != 0) || (dxc != 0) || (dyc != 0)) {
x += dxc + dx;
y += dyc + dy;
rec.x = dx;
rec.y = dy;
rec.ctrlx = dxc;
rec.ctrly = dyc;
if (shape_add_record(shape, &rec)) return 1;
}
if (get_token(token, 100) != TOKEN_RB) return 1;
}
} else if (type != TOKEN_RB) return 1;
} while (type != TOKEN_RB);
rec.type = SHAPERECORD_END;
if (shape_add_record(shape, &rec)) return 1;
return add_character(shape->id, shape, CHARACTER_SHAPE);
}
int parse_button_state(BUTTON *button, int which) {
char token[100];
int type;
unsigned int *count;
BUTTONSTATE **states, state;
switch (which) {
case BUTTONSTATE_UP:
states = &button->up;
count = &button->upcount;
break;
case BUTTONSTATE_OVER:
states = &button->over;
count = &button->overcount;
break;
case BUTTONSTATE_DOWN:
states = &button->down;
count = &button->downcount;
break;
case BUTTONSTATE_SHAPE:
states = &button->shape;
count = &button->shapecount;
break;
}
memset(&state, 0, sizeof(BUTTONSTATE));
matrix_reset(&state.matrix);
cxform_reset(&state.cxform);
if (get_token(token, 100) != TOKEN_LB) return 1;
do {
type = get_tokenl(token, 100);
if (type == TOKEN) {
if (strcmp(token, "id") == 0) {
int type;
if (get_id(&state.id) != TOKEN) return 1;
type = get_character_type(state.id);
if (type == CHARACTER_NOT_FOUND) {
fprintf(stderr, "Character (id=%d) is undefined\n", state.id);
return 1;
}
if ((type != CHARACTER_BITMAP) &&
(type != CHARACTER_SHAPE) &&
(type != CHARACTER_TEXT)) {
fprintf(stderr, "Character (id=%d) can not be used for a button-state\n", state.id);
return 1;
}
} else if (strcmp(token, "depth") == 0) {
if (get_valueU16(&state.depth) != TOKEN) return 1;
} else if (strcmp(token, "matrix") == 0) {
if (parse_matrix(&state.matrix)) return 1;
} else if (strcmp(token, "cxform") == 0) {
if (parse_cxform(&state.cxform)) return 1;
}
} else if (type != TOKEN_RB) return 1;
} while (type != TOKEN_RB);
if (*count == 0) {
*states = malloc(sizeof(BUTTONSTATE));
if (!*states) {
fprintf(stderr, "No room\n");
return 1;
}
} else {
BUTTONSTATE *newstates;
newstates = realloc(*states, (*count+1)*sizeof(BUTTONSTATE));
if (!newstates) {
fprintf(stderr, "No room\n");
return 1;
}
*states = newstates;
}
memcpy(*states + *count, &state, sizeof(BUTTONSTATE));
*count = *count+1;
return 0;
}
int parse_button() {
char token[100];
int type;
BUTTON *button;
// create and reset structure
button = malloc(sizeof(BUTTON));
if (!button) return 1;
memset(button, 0, sizeof(BUTTON));
if (get_token(token, 100) != TOKEN_LB) return 1;
do {
type = get_tokenl(token, 100);
if (type == TOKEN) {
if (strcmp(token, "id") == 0) {
if (get_id(&button->id) != TOKEN) return 1;
if (is_id_used(button->id)) report_error("Dublicate character ID");
} else if (strcmp(token, "actions") == 0) {
if (parse_actions(&button->actions, &button->actioncount))
return 1;
} else if (strcmp(token, "up") == 0) {
if (parse_button_state(button, BUTTONSTATE_UP)) {
fprintf(stderr, "Failed to parse 'up' state\n");
return 1;
}
} else if (strcmp(token, "over") == 0) {
if (parse_button_state(button, BUTTONSTATE_OVER)) {
fprintf(stderr, "Failed to parse 'over' state\n");
return 1;
}
} else if (strcmp(token, "down") == 0) {
if (parse_button_state(button, BUTTONSTATE_DOWN)) {
fprintf(stderr, "Failed to parse 'down' state\n");
return 1;
}
} else if (strcmp(token, "activearea") == 0) {
if (parse_button_state(button, BUTTONSTATE_SHAPE)) {
fprintf(stderr, "Failed to parse 'shape' state\n");
return 1;
}
} else {
fprintf(stderr, "Unsupported field '%s'\n", token);
return 1;
}
} else if (type != TOKEN_RB) return 1;
} while (type != TOKEN_RB);
return add_character(button->id, button, CHARACTER_BUTTON);
}
int parse_place_object() {
char token[100];
int type;
PLACEOBJECT place;
// reset the structure
memset(&place, 0, sizeof(PLACEOBJECT));
cxform_reset(&place.cxform);
matrix_reset(&place.matrix);
place.usealpha = 1;
place.flags = PLACEOBJECT_MOVE | PLACEOBJECT_MATRIX;
place.frameno = RESERVED_FRAMENO;
if (get_token(token, 100) != TOKEN_LB) return 1;
do {
type = get_tokenl(token, 100);
if (type == TOKEN) {
if (strcmp(token, "id") == 0) {
if (get_id(&place.id) != TOKEN) return 1;
if (!is_id_used(place.id)) {
fprintf(stderr, "Unknown character (id=%d)\n", place.id);
return 1;
}
place.flags &= ~PLACEOBJECT_MOVE;
place.flags |= PLACEOBJECT_CHARACTER;
} else if (strcmp(token, "depth") == 0) {
if (get_valueU16(&place.depth) != TOKEN) return 1;
} else if (strcmp(token, "matrix") == 0) {
if (parse_matrix(&place.matrix)) return 1;
place.flags |= PLACEOBJECT_MATRIX;
} else if (strcmp(token, "cxform") == 0) {
if (parse_cxform(&place.cxform)) return 1;
place.flags |= PLACEOBJECT_CXFORM;
} else if (strcmp(token, "clip") == 0) {
if (get_valueU16(&place.clip) != TOKEN) return 1;
place.flags |= PLACEOBJECT_CLIP;
} else if (strcmp(token, "frame") == 0) {
if (get_valueU16(&place.frameno) != TOKEN) return 1;
}
} else if (type != TOKEN_RB) return 1;
} while (type != TOKEN_RB);
place_object(&place);
return 0;
}
int parse_remove_object() {
// handles both RemoveObject and RemoveObject2
char token[100];
int type;
U16 depth, frameno;
frameno = RESERVED_FRAMENO;
if (get_token(token, 100) != TOKEN_LB) return 1;
do {
type = get_tokenl(token, 100);
if (type == TOKEN) {
if (strcmp(token, "id") == 0) {
if (get_token(token, 100) != TOKEN) return 1;
} else if (strcmp(token, "depth") == 0) {
if (get_valueU16(&depth) != TOKEN) return 1;
} else if (strcmp(token, "frame") == 0) {
if (get_valueU16(&frameno) != TOKEN) return 1;
}
} else if (type != TOKEN_RB)
return 1;
} while (type != TOKEN_RB);
remove_object(depth, frameno);
return 0;
}
int parse_show_frame() {
char token[100];
if (get_token(token, 100) != TOKEN_LB) return 1;
if (get_token(token, 100) != TOKEN_RB) return 1;
if (show_frame()) return 1;
return 0;
}
int parse_text_style_record(TEXTREC *rec) {
char token[100];
int type;
rec->flags = 0;
if (get_token(token, 100) != TOKEN_LB) return 1;
do {
type = get_tokenl(token, 100);
if (type == TOKEN) {
if (strcmp(token, "font") == 0) {
rec->flags |= TEXTREC_FONT;
if (get_id(&rec->data.style.font) != TOKEN) return 1;
if (find_font(rec->data.style.font) == -1) {
fprintf(stderr, "Font (id=%d) not defined\n", rec->data.style.font);
return 1;
}
} else if (strcmp(token, "size") == 0) {
rec->flags |= TEXTREC_SIZE;
if (get_valueU16(&rec->data.style.size) != TOKEN)
return 1;
} else if (strcmp(token, "colour") == 0) {
rec->flags |= TEXTREC_COLOUR;
if (get_rgb(&rec->data.style.colour) != TOKEN)
return 1;
} else if (strcmp(token, "move") == 0) {
rec->flags |= TEXTREC_MOVE;
if (get_token(token, 100) != TOKEN_LB) return 1;
if (get_value(&rec->data.style.x) != TOKEN) return 1;
if (get_value(&rec->data.style.y) != TOKEN) return 1;
if (get_token(token, 100) != TOKEN_RB) return 1;
}
} else if (type != TOKEN_RB) return 1;
} while (type != TOKEN_RB);
if (rec->flags == 0) {
fprintf(stderr, "Empty text-record\n");
return 1;
}
return 0;
}
int parse_text() {
char token[MAXLINELENGTH];
int type;
TEXT *text;
int fontindex;
// reset structure
text = malloc(sizeof(TEXT));
if (!text) {
fprintf(stderr, "No room\n");
return 1;
}
memset(text, 0, sizeof(TEXT));
matrix_reset(&text->matrix);
if (get_token(token, 100) != TOKEN_LB) return 1;
fontindex = -1;
do {
type = get_tokenl(token, MAXLINELENGTH);
if (type == TOKEN) {
if (strcmp(token, "id") == 0) {
if (get_id(&text->id) != TOKEN) return 1;
if (is_id_used(text->id)) {
fprintf(stderr, "Dublicate character id (%d)\n", text->id);
return 1;
}
} else if (strcmp(token, "matrix") == 0) {
if (parse_matrix(&text->matrix)) return 1;
} else if (strcmp(token, "style") == 0) {
TEXTREC *rec;
rec = malloc(sizeof(TEXTREC));
if (!rec) {
fprintf(stderr, "No room\n");
return 1;
}
if (parse_text_style_record(rec)) return 1;
if (rec->flags & TEXTREC_FONT)
fontindex = find_font(rec->data.style.font);
if (add_text_record(text, rec)) return 1;
} else if (strcmp(token, "text") == 0) {
TEXTREC *rec;
// make sure a font has been selected
if (fontindex == -1) {
fprintf(stderr, "No font has been selected\n");
return 1;
}
// reset record
rec = malloc(sizeof(TEXTREC));
if (!rec) {
fprintf(stderr, "No room\n");
return 1;
}
memset(rec, 0, sizeof(TEXTREC));
rec->flags = 0;
// read string to display
if (get_token(token, MAXLINELENGTH) != TOKEN_STRING)
return 1;
if (strlen(token) >= 127) {
fprintf(stderr, "String too long\n");
return 1;
}
rec->data.text.text = malloc(strlen(token)+1);
if (!rec->data.text.text) {
fprintf(stderr, "No room\n");
return 1;
}
strcpy((char *)rec->data.text.text, token);
rec->data.text.length = strlen((char *)rec->data.text.text);
if (add_text_record(text, rec)) return 1;
// mark the glyphs as being used
mark_glyphs_as_used(fontindex, rec->data.text.text, rec->data.text.length);
}
} else if (type != TOKEN_RB) return 1;
} while (type != TOKEN_RB);
return add_character(text->id, text, CHARACTER_TEXT);
}
int parse_glyph(GLYPH *glyph) {
char token[100];
int type;
GLYPHSHAPE shape;
S32 x, y;
if (get_token(token, 100) != TOKEN_LB) return 1;
x = y = 0;
do {
type = get_tokenl(token, 100);
if (type == TOKEN) {
if (strcmp(token, "char") == 0) {
type = get_token(token, 100);
if (type == TOKEN_STRING) {
if (strlen(token) != 1) {
fprintf(stderr, "Bad glyph-specifier (argument to 'char' is too long)\n");
return 1;
}
glyph->letter = token[0];
} else if (type == TOKEN) {
S32 v;
if (evaluate(token, &v)) return 1;
glyph->letter = v;
} else {
fprintf(stderr, "Bad glyph-specifier (bad argument to 'char')\n");
return 1;
}
} else if (strcmp(token, "index") == 0) {
if (get_valueU8(&glyph->letter) != TOKEN) return 1;
} else if (strcmp(token, "moveby") == 0) {
S32 dx, dy;
shape.type = GLYPHSHAPE_MOVE;
if (get_token(token, 100) != TOKEN_LB) return 1;
if (get_value(&dx) != TOKEN) return 1;
if (get_value(&dy) != TOKEN) return 1;
if (get_token(token, 100) != TOKEN_RB) return 1;
x += dx;
y += dy;
shape.x = x;
shape.y = y;
if (add_glyph_shape(glyph, &shape)) return 1;
} else if (strcmp(token, "moveto") == 0) {
shape.type = GLYPHSHAPE_MOVE;
if (get_token(token, 100) != TOKEN_LB) return 1;
if (get_value(&x) != TOKEN) return 1;
if (get_value(&y) != TOKEN) return 1;
if (get_token(token, 100) != TOKEN_RB) return 1;
shape.x = x;
shape.y = y;
if (add_glyph_shape(glyph, &shape)) return 1;
} else if (strcmp(token, "lineby") == 0) {
shape.type = GLYPHSHAPE_LINE;
if (get_token(token, 100) != TOKEN_LB) return 1;
if (get_value(&shape.x) != TOKEN) return 1;
if (get_value(&shape.y) != TOKEN) return 1;
if (get_token(token, 100) != TOKEN_RB) return 1;
x += shape.x;
y += shape.y;
if (add_glyph_shape(glyph, &shape)) return 1;
} else if (strcmp(token, "curveby") == 0) {
shape.type = GLYPHSHAPE_CURVE;
if (get_token(token, 100) != TOKEN_LB) return 1;
if (get_value(&shape.ctrlx) != TOKEN) return 1;
if (get_value(&shape.ctrly) != TOKEN) return 1;
if (get_value(&shape.x) != TOKEN) return 1;
if (get_value(&shape.y) != TOKEN) return 1;
if (get_token(token, 100) != TOKEN_RB) return 1;
x += shape.ctrlx + shape.x;
y += shape.ctrly + shape.y;
if (add_glyph_shape(glyph, &shape)) return 1;
}
} else if (type != TOKEN_RB) return 1;
} while (type != TOKEN_RB);
return 0;
}
int parse_font() {
char token[MAXLINELENGTH];
int type, i;
S32 scalex, scaley;
FONT *font;
font = malloc(sizeof(FONT));
if (!font) {
fprintf(stderr, "No room\n");
return 1;
}
memset(font, 0, sizeof(FONT));
scalex = scaley = 65536;
if (get_token(token, 100) != TOKEN_LB) return 1;
do {
type = get_tokenl(token, MAXLINELENGTH);
if (type == TOKEN) {
if (strcmp(token, "id") == 0) {
if (get_id(&font->id) != TOKEN) return 1;
if (is_id_used(font->id)) {
fprintf(stderr, "Dublicate character id (%d)\n", font->id);
return 1;
}
} else if (strcmp(token, "spacing") == 0) {
if (get_valueS16(&font->spacing)) return 1;
} else if (strcmp(token, "scale") == 0) {
if (get_token(token, 100) != TOKEN_LB) return 1;
if (get_value(&scalex) != TOKEN) return 1;
if (get_value(&scaley) != TOKEN) return 1;
if (get_token(token, 100) != TOKEN_RB) return 1;
} else if (strcmp(token, "glyph") == 0) {
GLYPH *glyph;
glyph = malloc(sizeof(GLYPH));
if (!glyph) {
fprintf(stderr, "No room\n");
return 1;
}
memset(glyph, 0, sizeof(GLYPH));
if (parse_glyph(glyph)) return 1;
if (add_glyph(font, glyph)) return 1;
}
} else if (type != TOKEN_RB) return 1;
} while (type != TOKEN_RB);
// if scaling or offset is specified for the font...
if ((scalex != 65536) || (scaley != 65536)) {
for (i = 0; i < font->glyphcount; i++) {
GLYPH *glyph;
int shape;
glyph = font->glyphs + i;
for (shape = 0; shape < glyph->shapecount; shape++) {
GLYPHSHAPE *gs;
gs = glyph->shapes + shape;
gs->x = (gs->x * scalex)>>16;
gs->y = (gs->y * scaley)>>16;
gs->ctrlx = (gs->ctrlx * scalex)>>16;
gs->ctrly = (gs->ctrly * scaley)>>16;
}
}
}
// calculate glyph bbox
for (i = 0; i < font->glyphcount; i++) {
GLYPH *glyph;
int shape, context;
S32 x, y;
glyph = font->glyphs + i;
bbox_init(&glyph->bbox, &context);
x = y = 0;
for (shape = 0; shape < glyph->shapecount; shape++) {
GLYPHSHAPE *gs;
gs = glyph->shapes + shape;
if (gs->type == GLYPHSHAPE_MOVE) {
x = gs->x;
y = gs->y;
bbox_add_point(&glyph->bbox, &context, x, y, 0);
} else if (gs->type == GLYPHSHAPE_LINE) {
x += gs->x;
y += gs->y;
bbox_add_point(&glyph->bbox, &context, x, y, 0);
} else if (gs->type == GLYPHSHAPE_CURVE) {
x += gs->ctrlx;
y += gs->ctrly;
bbox_add_point(&glyph->bbox, &context, x, y, 0);
x += gs->x;
y += gs->y;
bbox_add_point(&glyph->bbox, &context, x, y, 0);
}
}
}
if (add_font(font)) return 1;
return add_character(font->id, font, CHARACTER_FONT);
}
// ---------------------------------------------------------------------
int place_object(PLACEOBJECT *place) {
FRAME *frame;
if (!(place->flags & PLACEOBJECT_MOVE))
if (is_depth_used(place->depth)) report_error("Depth is already used");
use_depth(place->depth, 1);
use_id(place->id);
if (place->frameno == RESERVED_FRAMENO)
frame = frames+framecount;
else {
if (place->frameno >= framecount)
report_error("Illegal frame no. in PlaceObject { }");
frame = frames+place->frameno;
}
if (!frame->place) {
frame->place = malloc(sizeof(PLACEOBJECT));
if (!frame->place) return 1;
} else {
PLACEOBJECT *newplace;
newplace = realloc(frame->place, (frame->placecount+1)*sizeof(PLACEOBJECT));
if (!newplace) return 1;
frame->place = newplace;
}
memcpy(frame->place + frame->placecount, place, sizeof(PLACEOBJECT));
frame->placecount++;
return 0;
}
int remove_object(U16 depth, U16 frameno) {
FRAME *frame;
char err[256];
if (!is_depth_used(depth)) {
sprintf(err, "No object at this depth (%d)", depth);
report_error(err);
}
use_depth(depth, 0);
if (frameno == RESERVED_FRAMENO)
frame = frames+framecount;
else {
if (frameno >= framecount)
report_error("Illegal frame number in RemoveObject { }");
frame = frames+frameno;
}
if (!frame->removedepths) {
frame->removedepths = malloc(sizeof(U16));
if (!frame->removedepths) return 1;
} else {
U16 *newremove;
newremove = realloc(frame->removedepths, (frame->removecount+1)*sizeof(U16));
if (!newremove) return 1;
frame->removedepths = newremove;
}
frame->removedepths[frame->removecount++] = depth;
return 0;
}
int show_frame() {
framecount++;
if (framecount >= MAXFRAMECOUNT) return 1;
// clear next frame
memset(frames+framecount, 0, sizeof(FRAME));
if (set_variable_value("frameno", framecount)) return 1;
return 0;
}
int write_tag(int tag, int size) {
if (size >= 0x3f) {
if (write_ushort((tag<<6) | 0x3f)) return 1;
if (write_uint((U32)size)) return 1;
} else
if (write_ushort((tag<<6) | size)) return 1;
return 0;
}
int write_place_object(PLACEOBJECT *place) {
U32 ptr;
if (cxform_is_empty(&place->cxform))
place->flags &= ~PLACEOBJECT_CXFORM;
if (flush_bucket()) return 1;
ptr = read_position(NULL);
if (write_ushort(0)) return 1;
if (write_ubyte(place->flags)) return 1;
if (write_ushort(place->depth)) return 1;
if (place->flags & PLACEOBJECT_CHARACTER)
if (write_ushort(place->id)) return 1;
if (place->flags & PLACEOBJECT_MATRIX)
if (matrix_write(&place->matrix)) return 1;
if (place->flags & PLACEOBJECT_CXFORM)
if (cxform_write(&place->cxform, place->usealpha)) return 1;
if (place->flags & PLACEOBJECT_CLIP)
if (write_ushort(place->clip)) return 1;
if (update_record_header(stagPlaceObject2, ptr)) return 1;
return 0;
}
int write_flash_file() {
U32 i;
if (framecount < 1) return 1;
if (write_ubyte('F')) return 1;
if (write_ubyte('W')) return 1;
if (write_ubyte('S')) return 1;
if (write_ubyte(fileversion)) return 1;
if (write_uint(0)) return 1;
if (rect_write(&framesize)) return 1;
if (write_ushort(framerate)) return 1;
if (write_ushort(framecount)) return 1;
if (protected)
if (write_tag(stagProtect, 0)) return 1;
// pass one - characters that may be used by other characters
for (i = 0; i < used_characters; i++) {
switch (dictionary[i]->type) {
case CHARACTER_BITMAP:
if (bitmap_write(dictionary[i]->data.bitmap)) return 1;
break;
case CHARACTER_FONT:
if (fonttext_write_font(dictionary[i]->data.font)) return 1;
break;
case CHARACTER_SOUND:
if (sound_write(dictionary[i]->data.sound)) return 1;
break;
}
}
// pass two - characters that use other characters
for (i = 0; i < used_characters; i++) {
switch (dictionary[i]->type) {
case CHARACTER_SHAPE:
if (shape_write(dictionary[i]->data.shape)) return 1;
break;
case CHARACTER_TEXT:
if (fonttext_write_text(dictionary[i]->data.text)) return 1;
break;
}
}
// pass three - characters that use characters that use other characters
for (i = 0; i < used_characters; i++) {
switch (dictionary[i]->type) {
case CHARACTER_BUTTON:
if (button_write(dictionary[i]->data.button)) return 1;
break;
}
}
if (write_tag(stagSetBackgroundColour, 3)) return 1;
if (write_ubyte( bgcolour &255)) return 1;
if (write_ubyte((bgcolour>>8 ) &255)) return 1;
if (write_ubyte((bgcolour>>16) &255)) return 1;
for (i = 0; i < framecount; i++) {
unsigned int obj;
// remove objects
for (obj = 0; obj < frames[i].removecount; obj++) {
if (write_tag(stagRemoveObject2, 2)) return 1;
if (write_ushort(frames[i].removedepths[obj])) return 1;
}
// play sounds
for (obj = 0; obj < frames[i].soundcount; obj++)
if (write_play_sound(frames[i].sounds+obj)) return 1;
// place objects
for (obj = 0; obj < frames[i].placecount; obj++)
if (write_place_object(frames[i].place+obj)) return 1;
// actions
if (action_write(frames[i].actions, frames[i].actioncount)) return 1;
if (write_tag(stagShowFrame, 0)) return 1;
}
if (write_tag(stagEnd, 0)) return 1;
return 0;
}
int parse_file() {
char token[MAXLINELENGTH];
int type;
if (parse_initialise()) return 1;
linebuffer[0] = '\0';
bufferpos = 0;
do {
type = get_tokenl(token, MAXLINELENGTH-1);
if (type == TOKEN) {
if (strcmp(token, "fileversion") == 0) {
if (parse_file_version()) report_error("Bad FileVersion");
} else if (strcmp(token, "end") == 0) {
return 0;
} else if (strcmp(token, "framearea") == 0) {
if (parse_frame_area()) report_error("Bad FrameArea");
} else if (strcmp(token, "protect") == 0) {
if (get_token(token, MAXLINELENGTH-1) != TOKEN_LB)
report_error("Error in script-file");
if (get_token(token, MAXLINELENGTH-1) != TOKEN_RB)
report_error("Error in script-file");
protected = 1;
} else if (strcmp(token, "framerate") == 0) {
if (parse_frame_rate()) report_error("Bad FrameRate");
} else if ((strcmp(token, "backgroundcolour") == 0) ||
(strcmp(token, "bgcolour") == 0)) {
if (parse_bg_colour()) report_error("Bad BackgroundColour");
} else if (strcmp(token, "button") == 0) {
if (parse_button()) report_error("Bad Button");
} else if ((strcmp(token, "defineshape") == 0) ||
(strcmp(token, "shape") == 0)) {
if (parse_define_shape()) report_error("Bad DefineShape");
} else if (strcmp(token, "jpeg") == 0) {
if (parse_bitmap(BITMAP_JPEG)) report_error("Bad JPEG");
} else if (strcmp(token, "font") == 0) {
if (parse_font()) report_error("Bad font definition");
} else if (strcmp(token, "text") == 0) {
if (parse_text()) report_error("Bad text definition");
} else if ((strcmp(token, "placeobject") == 0) ||
(strcmp(token, "place") == 0)) {
if (parse_place_object()) report_error("Bad PlaceObject");
} else if ((strcmp(token, "removeobject") == 0) ||
(strcmp(token, "remove") == 0)) {
if (parse_remove_object()) report_error("Bad RemoveObject");
} else if ((strcmp(token, "definesound") == 0) ||
(strcmp(token, "sound") == 0)) {
if (parse_define_sound()) report_error("Bad DefineSound");
} else if (strcmp(token, "playsound") == 0) {
if (parse_play_sound()) report_error("Bad PlaySound");
} else if (strcmp(token, "doaction") == 0) {
FRAME *frame;
frame = frames+framecount;
if (parse_actions(&frame->actions, &frame->actioncount))
report_error("Bad DoAction");
} else if (strcmp(token, "showframe") == 0) {
if (parse_show_frame()) report_error("Bad ShowFrame");
} else
fprintf(stderr, "Unknown tag '%s'\n", token);
} else if (!end_of_file()) {
fprintf(stderr, "Unexpected token :");
switch (type) {
case TOKEN_LB:
fprintf(stderr, "'{'\n");
break;
case TOKEN_RB:
fprintf(stderr, "'}'\n");
break;
case TOKEN:
case TOKEN_STRING:
fprintf(stderr, "'%s'\n", token);
break;
}
}
} while (!end_of_file());
return 0;
}