home *** CD-ROM | disk | FTP | other *** search
/ Acorn User 10 / AU_CD10.iso / Archived / Updates / Flash / writeflash / !MakeFlash / c / parser < prev    next >
Text File  |  2000-06-04  |  57KB  |  2,061 lines

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <time.h>
  5. #include <math.h>
  6. #include <ctype.h>
  7. //
  8. #include "proto.h"
  9. #include "flash.h"
  10. #include "main.h"
  11. #include "shape.h"
  12. #include "bbox.h"
  13. #include "bucket.h"
  14. #include "bitcount.h"
  15. #include "matrix.h"
  16. #include "cxform.h"
  17. #include "bitmap.h"
  18. #include "rectangle.h"
  19. #include "gradient.h"
  20. #include "action.h"
  21. #include "button.h"
  22. #include "fonttext.h"
  23. #include "parser.h"
  24. #include "sound.h"
  25. #include "preprocess.h"
  26. #include "evaluate.h"
  27. #include "dictionary.h"
  28.  
  29.  
  30. static int get_token(char *out, int max);
  31. static int get_tokenl(char *out, int max);
  32. static int get_valueS8(S8 *result);
  33. static int get_valueU8(U8 *result);
  34. static int get_valueS16(S16 *result);
  35. static int get_valueU16(U16 *result);
  36. static int get_valueU32(U32 *result);
  37. static int get_valueS32(S32 *result);
  38. static int get_value(S32 *result);
  39. static int get_token_bm(char *out, int max);
  40. static int getchr(void);
  41. static int get_rgb(U32 *rgb);
  42. static int get_id(U16 *id);
  43.  
  44. static int place_object(PLACEOBJECT *place);
  45. static int remove_object(U16 depth, U16 frame);
  46. static int show_frame(void);
  47.  
  48. static int parse_file_version(void);
  49. static int parse_button(void);
  50. static int parse_frame_area(void);
  51. static int parse_bg_colour(void);
  52. static int parse_actions(ACTION **list, unsigned int *count);
  53. static int parse_define_shape(void);
  54. static int parse_bitmap(int bmtype);
  55. static int parse_place_object(void);
  56. static int parse_remove_object(void);
  57. static int parse_show_frame(void);
  58. static int parse_cxform(CXFORM *cxform);
  59. static int parse_fillstyles(SHAPE *shape);
  60. static int parse_linestyles(SHAPE *shape);
  61. static int parse_gradient(GRADIENT *gradient);
  62. static int parse_matrix(MATRIX *matrix);
  63. static int parse_rect(RECT *rect);
  64. static int parse_font(void);
  65. static int parse_text(void);
  66. static int parse_define_sound(void);
  67. static int parse_play_sound(void);
  68. static int parse_text_style_record(TEXTREC *rec);
  69. static int parse_glyph(GLYPH *glyph);
  70.  
  71. static int parse_initialise(void);
  72.  
  73.  
  74. #define MAXFRAMECOUNT         8192
  75. #define RESERVED_FRAMENO      65535
  76.  
  77. #define TOKEN_NOT_FOUND       -1
  78. #define TOKEN                 0
  79. #define TOKEN_STRING          1
  80. #define TOKEN_LB              2
  81. #define TOKEN_RB              3
  82.  
  83. // local to this file
  84. static U32 framecount, framerate, bgcolour, protected;
  85. static U8 fileversion;
  86. static RECT framesize;
  87. static S32 scalex, scaley, scaleboth;   // 1000 = 100%
  88.  
  89. static FRAME frames[MAXFRAMECOUNT];
  90.  
  91. static char linebuffer[MAXLINELENGTH];
  92. static U32 bufferpos;
  93.  
  94.  
  95.  
  96. int parse_initialise() {
  97.  
  98.   // reset everything
  99.   memset(frames+0, 0, sizeof(FRAME));
  100.   scalex = scaley = scaleboth = 1000;
  101.   framesize.minx = framesize.miny = 0;
  102.   framesize.maxx = framesize.maxy = 4000;
  103.   dictionary_init();
  104.  
  105.   // default values
  106.   framecount  = 0;
  107.   fileversion = 1;
  108.   bgcolour    = 0x00fffff;
  109.   framerate   = 0x0a00;
  110.   protected   = 0;
  111.  
  112.   if (create_variable("frameno"))       return 1;
  113.   if (set_variable_value("frameno", 0)) return 1;
  114.  
  115.   return 0;
  116. }
  117.  
  118.  
  119.  
  120. int get_rgb(U32 *rgb) {
  121.  
  122.   int i, type;
  123.   char token[100];
  124.  
  125.   type = get_token(token, 100);
  126.   if (type == TOKEN_LB) {
  127.     S32 r, g, b, a;
  128.     type = get_value(&r);
  129.     if (type != TOKEN)                  return type;
  130.     type = get_value(&g);
  131.     if (type != TOKEN)                  return type;
  132.     type = get_value(&b);
  133.     if (type != TOKEN)                  return type;
  134.     type = get_value(&a);
  135.     if (type == TOKEN_RB)
  136.       a = 255;
  137.     else if (type != TOKEN)
  138.       return type;
  139.     else if (get_token(token, 100) != TOKEN_RB)
  140.       return type;
  141.  
  142.     if (r < 0)     r = 0;
  143.     if (r > 255)   r = 255;
  144.     if (g < 0)     g = 0;
  145.     if (g > 255)   g = 255;
  146.     if (b < 0)     b = 0;
  147.     if (b > 255)   b = 255;
  148.     if (a < 0)     a = 0;
  149.     if (a > 255)   a = 255;
  150.  
  151.     *rgb = r | (g<<8) | (b<<16) | (a<<24);
  152.     return TOKEN;
  153.  
  154.   } else if (type != TOKEN)             return type;
  155.  
  156.   *rgb = 0;
  157.   i = 0;
  158.   while (isxdigit(token[i])) {
  159.     int c;
  160.  
  161.     c = token[i];
  162.     if (c >= 'a')  c -= 'a' - 'A';
  163.     if (c >= 'A')
  164.       c -= 'A'-10;
  165.     else
  166.       c -= '0';
  167.     *rgb = (*rgb<<4) | c;
  168.     i++;
  169.   }
  170.  
  171.   return TOKEN;
  172. }
  173.  
  174.  
  175. int update_record_header(int tag, U32 ptr) {
  176.  
  177.   U32 ptr2, size;
  178.   U16 rechdr;
  179.   U8 *buf;
  180.  
  181.   if (flush_bucket())                             return 1;
  182.   ptr2 = read_position(&buf);
  183.   buf += ptr;
  184.   size = ptr2 - ptr - 2;
  185.   if (size >= 63) {
  186.     U8 hdr[4];
  187.     rechdr = (tag<<6) | 0x3f;
  188.     buf[0] =  rechdr     & 0xff;
  189.     buf[1] = (rechdr>>8) & 0xff;
  190.     hdr[0] =  size       & 0xff;
  191.     hdr[1] = (size>> 8)  & 0xff;
  192.     hdr[2] = (size>>16)  & 0xff;
  193.     hdr[3] = (size>>24)  & 0xff;
  194.     if (bucket_insert(ptr+2, hdr, 4))               return 1;
  195.   } else {
  196.     rechdr = (tag<<6) | size;
  197.     buf[0] = rechdr      & 0xff;
  198.     buf[1] = (rechdr>>8) & 0xff;
  199.   }
  200.  
  201.   return 0;
  202. }
  203.  
  204.  
  205. int getchr() {
  206.  
  207.   while (!linebuffer[bufferpos]) {
  208.     if (get_line(linebuffer))   return -1;
  209.     if (debug_print_lines)  printf("%s\n", linebuffer);
  210.     bufferpos = 0;
  211.   }
  212.  
  213.   return linebuffer[bufferpos++];
  214. }
  215.  
  216.  
  217. int get_tokenl(char *out, int max) {
  218.  
  219.   int type, i;
  220.  
  221.   type = get_token(out, max);
  222.   if (type == TOKEN) {
  223.     i = 0;
  224.     while (out[i]) {
  225.       out[i] = tolower(out[i]);
  226.       i++;
  227.     }
  228.   }
  229.   return type;
  230. }
  231.  
  232.  
  233. int get_valueS8(S8 *result) {
  234.  
  235.   S32 res;
  236.   int type;
  237.  
  238.   type = get_value(&res);
  239.   if (type != TOKEN)          return type;
  240.   *result = (S8)res;
  241.  
  242.   return TOKEN;
  243. }
  244.  
  245.  
  246. int get_valueU8(U8 *result) {
  247.  
  248.   S32 res;
  249.   int type;
  250.  
  251.   type = get_value(&res);
  252.   if (type != TOKEN)          return type;
  253.   *result = (U8)res;
  254.  
  255.   return TOKEN;
  256. }
  257.  
  258.  
  259. int get_valueS16(S16 *result) {
  260.  
  261.   S32 res;
  262.   int type;
  263.  
  264.   type = get_value(&res);
  265.   if (type != TOKEN)          return type;
  266.   *result = (S16)res;
  267.  
  268.   return TOKEN;
  269. }
  270.  
  271.  
  272. int get_id(U16 *id) {
  273.  
  274.   int type;
  275.  
  276.   type = get_valueU16(id);
  277.   if (!type != TOKEN)         return type;
  278.   if (*id == RESERVED_ID) {
  279.     fprintf(stderr, "Id %d (%04x) is reserved\n", RESERVED_ID, RESERVED_ID);
  280.     return TOKEN_NOT_FOUND;
  281.   }
  282.  
  283.   return TOKEN;
  284. }
  285.  
  286.  
  287. int get_valueU16(U16 *result) {
  288.  
  289.   S32 res;
  290.   int type;
  291.  
  292.   type = get_value(&res);
  293.   if (type != TOKEN)          return type;
  294.   *result = (U16)res;
  295.  
  296.   return TOKEN;
  297. }
  298.  
  299.  
  300. int get_valueU32(U32 *result) {
  301.  
  302.   return get_value((S32 *)result);
  303. }
  304.  
  305.  
  306. int get_value(S32 *result) {
  307.  
  308.   return get_valueS32(result);
  309. }
  310.  
  311.  
  312. int get_valueS32(S32 *result) {
  313.  
  314.   char token[100];
  315.   int type;
  316.  
  317.   type = get_token_bm(token, 100);
  318.   if (type != TOKEN)                    return type;
  319.  
  320.   if (evaluate(token, result))          return TOKEN_NOT_FOUND;
  321.   return TOKEN;
  322. }
  323.  
  324.  
  325. int get_token_bm(char *out, int max) {  // bracket-matching
  326.  
  327.   int len, type, bm, i;
  328.   char token[MAXLINELENGTH];
  329.  
  330.   type = get_token(out, max);
  331.   if (type != TOKEN)          return type;
  332.   if (out[0] != '(')          return type;
  333.  
  334.   do {
  335.     type = get_token(token, max-len);
  336.     if (type != TOKEN) {
  337.       fprintf(stderr, "Unmatched brackets or expression is too long\n");
  338.       return type;
  339.     }
  340.  
  341.     strcat(out+len, token);
  342.     len = strlen(out);
  343.  
  344. printf("%s\n", out);
  345.     bm = 0;
  346.     for (i = 0; i < len; i++) {
  347.       if (out[i] == '(')
  348.         bm++;
  349.       else if (out[i] == ')')
  350.         bm--;
  351.     }
  352.   } while (bm);
  353.  
  354.   return TOKEN;
  355. }
  356.  
  357.  
  358. int get_token(char *out, int max) {
  359. // disgusting to say the least - not the prettiest piece
  360. // of code I've ever had to take credit for...
  361.   int len, c, token;
  362.  
  363.   len = 0;
  364.   max -= 1;
  365.  
  366.   token = TOKEN_NOT_FOUND;
  367.  
  368.   do {
  369.     // skip white spaces
  370.     do {
  371.       c = getchr();
  372.       if (c == -1)                      return TOKEN_NOT_FOUND;
  373.       if ((c <= ' ') && (len > 0)) {
  374.         // end of token
  375.         out[len] = '\0';
  376.         return TOKEN;
  377.       }
  378.     } while (c <= ' ');
  379.  
  380.     if ((c == '{') && (len == 0))        return TOKEN_LB;
  381.     if ((c == '}') && (len == 0))        return TOKEN_RB;
  382.  
  383.     // is it a comment??
  384.     if (c == '/') {
  385.       int c2;
  386.       c2 = getchr();
  387.       if (c2 == -1)                     return TOKEN_NOT_FOUND;
  388.       if (c2 == '/') {
  389.         // it is a comment, so skip to end of line
  390.         bufferpos = 0; linebuffer[bufferpos] ='\0';
  391.         if (len > 0) {
  392.           // if we had already read something,
  393.         }
  394.       } else {
  395.         if (len+2 >= max)               return TOKEN_NOT_FOUND;
  396.         out[len++] = c;
  397.         out[len++] = c2;
  398.       }
  399.       // mark char as processed
  400.       c = -1;
  401.     }
  402.  
  403.     if (c > 0) {
  404.       if (len+1 >= max)                 return TOKEN_NOT_FOUND;
  405.       out[len++] = c;
  406.       if (c == '"') {         // string, read to end of string
  407.         len--;
  408.         while ((c != -1) && (len < max)) {
  409.           c = getchr();
  410.           if (c == -1)                  return TOKEN_NOT_FOUND;
  411.           if (c == '"') {
  412.             // end of string
  413.             out[len] = '\0';
  414.             return TOKEN_STRING;
  415.           } else if (c == '\\') {
  416.             // escaped char
  417.             if (len+1 >= max)           return TOKEN_NOT_FOUND;
  418.             c = getchr();
  419.             if (c == -1)                return TOKEN_NOT_FOUND;
  420.             switch (c) {
  421.             case 'r':
  422.               out[len++] = '\r';
  423.               break;
  424.             case 'n':
  425.               out[len++] = '\n';
  426.               break;
  427.             case 't':
  428.               out[len++] = '\t';
  429.               break;
  430.             case '"':
  431.               out[len++] = '"';
  432.               break;
  433.             case '\\':
  434.               out[len++] = '\\';
  435.               break;
  436.             default:
  437.               break;
  438.             }
  439.           } else
  440.             // normal char
  441.             out[len++] = c;
  442.         }
  443.  
  444.       } else {                // normal token, read to next space
  445.       }
  446.     }
  447.  
  448.   } while (1);
  449.  
  450.   return TOKEN_NOT_FOUND;
  451. }
  452.  
  453.  
  454. void report_error(char *err) {
  455.  
  456.   fprintf(stderr, "%s\n", err);
  457.   exit(-1);
  458. }
  459.  
  460.  
  461. int parse_rect(RECT *rect) {
  462.  
  463.   char token[100];
  464.   S32 val;
  465.  
  466.   if (get_token(token, 100) != TOKEN_LB)  return 1;
  467.  
  468.   if (get_value(&val) != TOKEN)           return 1;
  469.   rect->minx = (scalex*val)/1000;
  470.  
  471.   if (get_value(&val) != TOKEN)           return 1;
  472.   rect->miny = (scaley*val)/1000;
  473.  
  474.   if (get_value(&val) != TOKEN)           return 1;
  475.   rect->maxx = (scalex*val)/1000;
  476.  
  477.   if (get_value(&val) != TOKEN)           return 1;
  478.   rect->maxy = (scaley*val)/1000;
  479.  
  480.   if (get_token(token, 100) != TOKEN_RB)  return 1;
  481.  
  482.   return 0;
  483. }
  484.  
  485.  
  486. int parse_gradient(GRADIENT *gradient) {
  487.  
  488.   char token[100];
  489.   int type, i;
  490.   U8 grad;
  491.  
  492.   memset(gradient, 0, sizeof(GRADIENT));
  493.   gradient->usealpha = 1;
  494.  
  495.   if (get_token(token, 100) != TOKEN_LB)  return 1;
  496.  
  497.   do {
  498.     type = get_valueU8(&grad);
  499.     if (type == TOKEN) {
  500.       gradient->ratio[gradient->n] = grad;
  501.       if (get_rgb(&gradient->rgba[gradient->n]) != TOKEN)  return 1;
  502.       gradient->n++;
  503.  
  504.     } else if (type != TOKEN_RB)
  505.       return 1;
  506.  
  507.   } while (type != TOKEN_RB);
  508.  
  509.   for (i = 0; i < gradient->n-1; i++)
  510.     if (gradient->ratio[i] >= gradient->ratio[i+1])         return 1;
  511.  
  512.   return 0;
  513. }
  514.  
  515.  
  516. int parse_matrix(MATRIX *matrix) {
  517.  
  518.   char token[100];
  519.   S32 v[7], val;
  520.   int n, type;
  521.  
  522.   matrix->scalex = matrix->scaley = (scaleboth*65536)/1000;
  523.   matrix->rotate0 = matrix->rotate1 = 0;
  524.   matrix->tx = matrix->ty = 0;
  525.  
  526.   if (get_token(token, 100) != TOKEN_LB)          return 1;
  527.  
  528.   n = 0;
  529.   do {
  530.     type = get_value(&val);
  531.     if (type == TOKEN)
  532.       v[n++] = val;
  533.     else if (type != TOKEN_RB)                    return 1;
  534.   } while ((type != TOKEN_RB) && (n <= 6));
  535.   if (type != TOKEN_RB)                           return 1;
  536.  
  537.   switch (n) {
  538.   case 1:
  539.     matrix->scalex = matrix->scaley = (scaleboth*v[0])/1000;
  540.     break;
  541.   case 2:
  542.     matrix->scalex = (scaleboth*v[0])/1000;
  543.     matrix->scaley = (scaleboth*v[1])/1000;
  544.     break;
  545.   case 3:
  546.     matrix->scalex = matrix->scaley = (scaleboth*v[0])/1000;
  547.     matrix->tx = (scalex*v[1])/1000;
  548.     matrix->ty = (scaley*v[2])/1000;
  549.     break;
  550.   case 4:
  551.     matrix->scalex = (scaleboth*v[0])/1000;
  552.     matrix->scaley = (scaleboth*v[1])/1000;
  553.     matrix->tx = (scalex*v[2])/1000;
  554.     matrix->ty = (scaley*v[3])/1000;
  555.     break;
  556.   case 6:
  557.     matrix->scalex = (scaleboth*v[0])/1000;
  558.     matrix->scaley = (scaleboth*v[1])/1000;
  559.     matrix->rotate0 = (scaleboth*v[2])/1000;
  560.     matrix->rotate1 = (scaleboth*v[3])/1000;
  561.     matrix->tx = (scalex*v[4])/1000;
  562.     matrix->ty = (scaley*v[5])/1000;
  563.     break;
  564.   case 5:
  565.     report_error("Bad matrix");
  566.     break;
  567.   }
  568.  
  569.   return 0;
  570. }
  571.  
  572.  
  573. int parse_actions(ACTION **list, unsigned int *count) {
  574.  
  575.   char token[MAXLINELENGTH];
  576.   int type;
  577.   ACTION action;
  578.  
  579.   if (get_token(token, 100) != TOKEN_LB)          return 1;
  580.   do {
  581.     memset(&action, 0, sizeof(ACTION));
  582.     type = get_tokenl(token, 100);
  583.     if (type == TOKEN_RB)                         return 0;
  584.     if (type != TOKEN)                            return 1;
  585.     if (strcmp(token, "gotoframe") == 0) {
  586.       U16 frame;
  587.       if (get_valueU16(&frame) != TOKEN)          return 1;
  588.       action.action = ACTION_GOTOFRAME;
  589.       action.data.gotoframe = frame;
  590.       if (add_action(list, count, &action))       return 1;
  591.  
  592.     } else if (strcmp(token, "play") == 0) {
  593.       action.action = ACTION_PLAY;
  594.       if (add_action(list, count, &action))       return 1;
  595.  
  596.     } else if (strcmp(token, "stop") == 0) {
  597.       action.action = ACTION_STOP;
  598.       if (add_action(list, count, &action))       return 1;
  599.  
  600.     } else if (strcmp(token, "stopsounds") == 0) {
  601.       action.action = ACTION_STOPSOUNDS;
  602.       if (add_action(list, count, &action))       return 1;
  603.  
  604.     } else if (strcmp(token, "nextframe") == 0) {
  605.       action.action = ACTION_NEXTFRAME;
  606.       if (add_action(list, count, &action))       return 1;
  607.  
  608.     } else if (strcmp(token, "previousframe") == 0) {
  609.       action.action = ACTION_PREVIOUSFRAME;
  610.       if (add_action(list, count, &action))       return 1;
  611.  
  612.     } else if (strcmp(token, "geturl") == 0) {
  613.       int type;
  614.  
  615.       if (get_token(token, 100) != TOKEN_LB)      return 1;
  616.       do {
  617.         type = get_tokenl(token, 100);
  618.         if (type == TOKEN) {
  619.           if (strcmp(token, "url") == 0) {
  620.             type = get_token(token, MAXLINELENGTH);
  621.             if (type != TOKEN_STRING)             return 1;
  622.             action.data.geturl.url = malloc(strlen(token)+1);
  623.             if (!action.data.geturl.url)          return 1;
  624.             strcpy(action.data.geturl.url, token);
  625.           } else if (strcmp(token, "target") == 0) {
  626.             type = get_token(token, MAXLINELENGTH);
  627.             if (type != TOKEN_STRING)             return 1;
  628.             action.data.geturl.target = malloc(strlen(token)+1);
  629.             if (!action.data.geturl.target)       return 1;
  630.             strcpy(action.data.geturl.target, token);
  631.           }
  632.         } else if (type != TOKEN_RB)              return 1;
  633.       } while (type != TOKEN_RB);
  634.  
  635.       if (!action.data.geturl.url)  report_error("No URL specified");
  636.       if (!action.data.geturl.target) {
  637.         action.data.geturl.target = malloc(1);
  638.         if (!action.data.geturl.target)           return 1;
  639.         action.data.geturl.target[0] = '\0';
  640.       }
  641.       action.action = ACTION_GETURL;
  642.       if (add_action(list, count, &action))       return 1;
  643.  
  644.     } else {
  645.       fprintf(stderr, "Unsupported field '%s'\n", token);
  646.       return 1;
  647.     }
  648.   } while (1);
  649.  
  650.   return 1;
  651. }
  652.  
  653.  
  654. int parse_play_sound() {
  655.  
  656.   char token[MAXLINELENGTH];
  657.   PLAYSOUND *play;
  658.   int type;
  659.   U16 framei;
  660.   FRAME *frame;
  661.  
  662.   play = malloc(sizeof(PLAYSOUND));
  663.   if (!play)                                                return 1;
  664.   memset(play, 0, sizeof(PLAYSOUND));
  665.   play->id = RESERVED_ID;
  666.   play->loops = 1;
  667.   framei = RESERVED_FRAMENO;
  668.  
  669.   if (get_token(token, 100) != TOKEN_LB)                    return 1;
  670.   do {
  671.     type = get_tokenl(token, 100);
  672.  
  673.     if (type == TOKEN) {
  674.       if (strcmp(token, "id") == 0) {
  675.         if (get_id(&play->id) != TOKEN)                     return 1;
  676.         if (!is_id_used(play->id)) {
  677.           fprintf(stderr, "Unknown character (id=%d)\n", play->id);
  678.           return 1;
  679.         }
  680.  
  681.       } else if (strcmp(token, "loops") == 0) {
  682.         if (get_valueU16(&play->loops) != TOKEN)            return 1;
  683.  
  684.       } else if (strcmp(token, "frame") == 0) {
  685.         if (get_valueU16(&framei) != TOKEN)                 return 1;
  686.       }
  687.  
  688.     } else if (type != TOKEN_RB)                            return 1;
  689.   } while (type != TOKEN_RB);
  690.  
  691.   if (framei == RESERVED_FRAMENO)
  692.     frame = frames+framecount;
  693.   else {
  694.     if (framei >= framecount)
  695.       report_error("Illegal frame no. in PlaySound { }");
  696.     frame = frames+framei;
  697.   }
  698.  
  699.   if (!frame->sounds) {
  700.     frame->sounds = malloc(sizeof(PLAYSOUND));
  701.     if (!frame->sounds)        return 1;
  702.   } else {
  703.     PLAYSOUND *newsounds;
  704.     newsounds = realloc(frame->sounds, (frame->soundcount+1)*sizeof(PLAYSOUND));
  705.     if (!newsounds)            return 1;
  706.     frame->sounds = newsounds;
  707.   }
  708.   memcpy(frame->sounds + frame->soundcount, play, sizeof(PLAYSOUND));
  709.   frame->soundcount++;
  710.  
  711.   return 0;
  712.  
  713.   return 0;
  714. }
  715.  
  716.  
  717. int parse_define_sound() {
  718.  
  719.   char token[MAXLINELENGTH];
  720.   int type;
  721.   SOUND *sound;
  722.  
  723.   if (sound_create(&sound))                                 return 1;
  724.  
  725.   if (get_token(token, 100) != TOKEN_LB)                    return 1;
  726.  
  727.   do {
  728.     type = get_tokenl(token, MAXLINELENGTH);
  729.     if (type == TOKEN) {
  730.       if (strcmp(token, "id") == 0) {
  731.         if (get_id(&sound->id) != TOKEN)                    return 1;
  732.         if (is_id_used(sound->id))   report_error("Dublicate character ID");
  733.  
  734.       } else if (strcmp(token, "format") == 0) {
  735.         if (get_token(token, 100) != TOKEN_STRING)          return 1;
  736.         if (strcmp(token, "LIN8") == 0)
  737.           sound->format = SOUNDFORMAT_LIN8;
  738.         else if (strcmp(token, "LIN16") == 0)
  739.           sound->format = SOUNDFORMAT_LIN16;
  740.         else if (strcmp(token, "ADPCM2") == 0)
  741.           sound->format = SOUNDFORMAT_ADPCM2;
  742.         else if (strcmp(token, "ADPCM3") == 0)
  743.           sound->format = SOUNDFORMAT_ADPCM3;
  744.         else if (strcmp(token, "ADPCM4") == 0)
  745.           sound->format = SOUNDFORMAT_ADPCM4;
  746.         else if (strcmp(token, "ADPCM5") == 0)
  747.           sound->format = SOUNDFORMAT_ADPCM5;
  748.         else
  749.           return 1;
  750.  
  751.       } else if (strcmp(token, "file") == 0) {
  752.           if (get_token(token, 100) != TOKEN_STRING)        return 1;
  753.           sound->file = malloc(strlen(token)+1);
  754.           if (!sound->file)                                 return 1;
  755.           strcpy(sound->file, token);
  756.  
  757.       } else if (strcmp(token, "channels") == 0) {
  758.         int chns;
  759.         if (get_value(&chns) != TOKEN)                      return 1;
  760.         if (chns == 1)
  761.           sound->stereo = 0;
  762.         else
  763.           sound->stereo = 1;
  764.  
  765.       } else if (strcmp(token, "freq") == 0) {
  766.         if (get_value(&sound->freq) != TOKEN)               return 1;
  767.  
  768.       }
  769.  
  770.     } else if (type != TOKEN_RB)
  771.       return 1;
  772.  
  773.   } while (type != TOKEN_RB);
  774.  
  775.   return add_character(sound->id, sound, CHARACTER_SOUND);
  776. }
  777.  
  778.  
  779. int parse_bitmap(int bmtype) {
  780.  
  781.   char token[MAXLINELENGTH];
  782.   int type;
  783.   BITMAP *bitmap;
  784.  
  785.   if (bitmap_create(&bitmap))                               return 1;
  786.  
  787.   if (get_token(token, 100) != TOKEN_LB)                    return 1;
  788.  
  789.   switch (bmtype) {
  790.   case BITMAP_JPEG:
  791.     bitmap->type = BITMAP_JPEG;
  792.     do {
  793.       type = get_tokenl(token, MAXLINELENGTH);
  794.       if (type == TOKEN) {
  795.         if (strcmp(token, "id") == 0) {
  796.           if (get_id(&bitmap->id) != TOKEN)                 return 1;
  797.           if (is_id_used(bitmap->id))   report_error("Dublicate character ID");
  798.  
  799.         } else if (strcmp(token, "width") == 0) {
  800.           if (get_valueU16(&bitmap->width) != TOKEN)        return 1;
  801.  
  802.         } else if (strcmp(token, "height") == 0) {
  803.           if (get_valueU16(&bitmap->height) != TOKEN)       return 1;
  804.  
  805.         } else if (strcmp(token, "file") == 0) {
  806.           if (get_token(token, 100) != TOKEN_STRING)        return 1;
  807.           bitmap->file = malloc(strlen(token)+1);
  808.           if (!bitmap->file)                                return 1;
  809.           strcpy(bitmap->file, token);
  810.  
  811.         } else if (strcmp(token, "alphafile") == 0) {
  812.           if (get_token(token, 100) != TOKEN_STRING)        return 1;
  813.           bitmap->alphafile = malloc(strlen(token)+1);
  814.           if (!bitmap->alphafile)                           return 1;
  815.           strcpy(bitmap->alphafile, token);
  816.         }
  817.  
  818.       } else if (type != TOKEN_RB)
  819.         return 1;
  820.     } while (type != TOKEN_RB);
  821.     break;
  822.  
  823.   }
  824.  
  825.   return add_character(bitmap->id, bitmap, CHARACTER_BITMAP);
  826. }
  827.  
  828.  
  829. int parse_fillstyles(SHAPE *shape) {
  830.  
  831.   char token[100];
  832.   int type;
  833.   FILLSTYLE style;
  834.  
  835.   do {
  836.     type = get_tokenl(token, 100);
  837.     if (type == TOKEN) {
  838.       if (strcmp(token, "solid") == 0) {
  839.         style.type = FILLSTYLE_SOLID;
  840.         if (get_rgb(&style.fill.solid) != TOKEN)            return 1;
  841.  
  842.       } else if ((strcmp(token, "linear") == 0) || (strcmp(token, "radial") == 0)) {
  843.         int type;
  844.  
  845.         matrix_reset(&style.fill.gradient.matrix);
  846.  
  847.         if (strcmp(token, "radial") == 0)
  848.           style.type = FILLSTYLE_RADIAL;
  849.         else
  850.           style.type = FILLSTYLE_LINEAR;
  851.         if (get_token(token, 100) != TOKEN_LB)              return 1;
  852.         do {
  853.           type = get_tokenl(token, 100);
  854.           if (type == TOKEN) {
  855.             if (strcmp(token, "matrix") == 0) {
  856.               if (parse_matrix(&style.fill.gradient.matrix))  return 1;
  857.             } else if (strcmp(token, "gradient") == 0) {
  858.               if (parse_gradient(&style.fill.gradient.gradient))  return 1;
  859.             }
  860.           } else if (type != TOKEN_RB)                      return 1;
  861.         } while (type != TOKEN_RB);
  862.  
  863.       } else if ((strcmp(token, "tiled") == 0) || (strcmp(token, "clipped") == 0)) {
  864.         int type;
  865.  
  866.         matrix_reset(&style.fill.gradient.matrix);
  867.  
  868.         if (strcmp(token, "clipped") == 0)
  869.           style.type = FILLSTYLE_CLIPPED;
  870.         else
  871.           style.type = FILLSTYLE_TILED;
  872.         if (get_token(token, 100) != TOKEN_LB)              return 1;
  873.         do {
  874.           type = get_tokenl(token, 100);
  875.           if (type == TOKEN) {
  876.             if (strcmp(token, "matrix") == 0) {
  877.               if (parse_matrix(&style.fill.bitmap.matrix))  return 1;
  878.  
  879.             } else if (strcmp(token, "id") == 0) {
  880.               if (get_id(&style.fill.bitmap.id) != TOKEN)   return 1;
  881.               if (get_character_type(style.fill.bitmap.id) != CHARACTER_BITMAP) {
  882.                 fprintf(stderr, "Character (id=%d) is unknown or does not refer to a bitmap\n", style.fill.bitmap.id);
  883.                 return 1;
  884.               }
  885.             }
  886.           } else if (type != TOKEN_RB)                      return 1;
  887.  
  888.         } while (type != TOKEN_RB);
  889.       }
  890.       if (shape_add_fillstyle(shape, &style))               return 1;
  891.  
  892.     } else if (type != TOKEN_RB)                            return 1;
  893.  
  894.   } while (type != TOKEN_RB);
  895.  
  896.   return 0;
  897. }
  898.  
  899.  
  900. int parse_linestyles(SHAPE *shape) {
  901.  
  902.   int type;
  903.   U16 width;
  904.   LINESTYLE style;
  905.  
  906.   do {
  907.     type = get_valueU16(&width);
  908.     if (type == TOKEN) {
  909.       style.width = (scaleboth*width)/1000;
  910.  
  911.       if (get_rgb(&style.rgba) != TOKEN)          return 1;
  912.  
  913.       if (shape_add_linestyle(shape, &style))     return 1;
  914.  
  915.     } else if (type != TOKEN_RB)
  916.       return 1;
  917.  
  918.   } while (type != TOKEN_RB);
  919.  
  920.   return 0;
  921. }
  922.  
  923.  
  924. int parse_file_version() {
  925.  
  926.   if (get_valueU8(&fileversion) != TOKEN)         return 1;
  927.  
  928.   return 0;
  929. }
  930.  
  931.  
  932. int parse_frame_area() {
  933.  
  934.   char token[100];
  935.   int type;
  936.  
  937.   if (get_token(token, 100) != TOKEN_LB)          return 1;
  938.  
  939.   do {
  940.     type = get_tokenl(token, 100);
  941.     if (type == TOKEN) {
  942.       if (strcmp(token, "width") == 0) {
  943.         if (get_value(&framesize.maxx) != TOKEN)  return 1;
  944.         if (create_variable("framesizex"))        return 1;
  945.         if (set_variable_value("framesizex", framesize.maxx)) return 1;
  946.  
  947.       } else if (strcmp(token, "height") == 0) {
  948.         if (get_value(&framesize.maxy) != TOKEN)  return 1;
  949.         if (create_variable("framesizey"))        return 1;
  950.         if (set_variable_value("framesizey", framesize.maxy)) return 1;
  951.  
  952.       } else if (strcmp(token, "scalex") == 0) {
  953.         if (get_value(&scalex) != TOKEN)          return 1;
  954.  
  955.       } else if (strcmp(token, "scaley") == 0) {
  956.         if (get_value(&scaley) != TOKEN)          return 1;
  957.  
  958.       }
  959.     } else if (type != TOKEN_RB)                  return 1;
  960.   } while (type != TOKEN_RB);
  961.  
  962.   scaleboth = (S32)sqrt((int)abs(scalex*scaley));
  963.  
  964.   return 0;
  965. }
  966.  
  967.  
  968. int parse_frame_rate() {
  969.  
  970.   char token[100], *p;
  971.   U8 i, f;
  972.  
  973.   if (get_token(token, 100))     return 1;
  974.   p = strchr(token, '.');
  975.   if (p) {
  976.     *p = '\0';
  977.     f = atoi(p+1);
  978.   } else
  979.     f = 0;
  980.  
  981.   i = atoi(token);
  982.  
  983.   if ((i > 255) || (i < 0) || (f > 255) || (f < 0))  return 1;
  984.  
  985.   framerate = (i<<8) | f;
  986.  
  987.   return 0;
  988. }
  989.  
  990.  
  991. int parse_cxform(CXFORM *cxform) {
  992.  
  993.   char token[100];
  994.   S16 values[8];
  995.   int n, type;
  996.  
  997.   cxform->mula = 255;
  998.   cxform->adda = 0;
  999.  
  1000.   if (get_token(token, 100) != TOKEN_LB)          return 1;
  1001.  
  1002.   n = 0;
  1003.   do {
  1004.     type = get_valueS16(values+n);
  1005.     if (type == TOKEN)
  1006.       n++;
  1007.     else if (type != TOKEN_RB)
  1008.       return 1;
  1009.   } while ((n < 8) && (type != TOKEN_RB));
  1010.  
  1011.   if (n == 8)
  1012.     if (get_token(token, 100) != TOKEN_RB)        return 1;
  1013.  
  1014.   if ((n != 6) && (n != 8)) {
  1015.     fprintf(stderr, "Bad value-count in cxform\n");
  1016.     return 1;
  1017.   }
  1018.  
  1019.   if (n == 6) {
  1020.     cxform->mulr = values[0];
  1021.     cxform->mulg = values[1];
  1022.     cxform->mulb = values[2];
  1023.     cxform->addr = values[3];
  1024.     cxform->addg = values[4];
  1025.     cxform->addb = values[5];
  1026.     cxform->mula = 255;
  1027.     cxform->adda = 0;
  1028.   } else {
  1029.     cxform->mulr = values[0];
  1030.     cxform->mulg = values[1];
  1031.     cxform->mulb = values[2];
  1032.     cxform->mula = values[3];
  1033.     cxform->addr = values[4];
  1034.     cxform->addg = values[5];
  1035.     cxform->addb = values[6];
  1036.     cxform->adda = values[7];
  1037.   }
  1038.  
  1039.   return 0;
  1040. }
  1041.  
  1042.  
  1043. int parse_bg_colour() {
  1044.  
  1045.   return get_rgb(&bgcolour);
  1046. }
  1047.  
  1048.  
  1049. int parse_define_shape(void) {
  1050.  
  1051.   char token[100];
  1052.   int type;
  1053.   S32 x, y;
  1054.   SHAPE *shape;
  1055.   SHAPERECORD rec;
  1056.  
  1057.   if (shape_create(&shape))                                 return 1;
  1058.  
  1059.   if (get_token(token, 100) != TOKEN_LB)                    return 1;
  1060.  
  1061.   x = y = 0;
  1062.  
  1063.   do {
  1064.     // repeatedly read a token and parse the arguments
  1065.     type = get_tokenl(token, 100);
  1066.     if (type == TOKEN) {
  1067.       if (strcmp(token, "id") == 0) {
  1068.         if (get_id(&shape->id) != TOKEN)                    return 1;
  1069.         if (is_id_used(shape->id))  report_error("Dublicate character ID");
  1070.  
  1071.       } else if (strcmp(token, "bbox") == 0) {
  1072.         // bbox { } is not used from version 0.02 onwards
  1073.         RECT unused;
  1074.         if (parse_rect(&unused))                            return 1;
  1075.  
  1076.       } else if (strcmp(token, "fillstyle") == 0) {
  1077.         if (get_token(token, 100) != TOKEN_LB)              return 1;
  1078.         if (parse_fillstyles(shape))                        return 1;
  1079.  
  1080.       } else if (strcmp(token, "linestyle") == 0) {
  1081.         if (get_token(token, 100) != TOKEN_LB)              return 1;
  1082.         if (parse_linestyles(shape))                        return 1;
  1083.  
  1084.       } else if ((strcmp(token, "selectfillstyle0") == 0) ||
  1085.                  (strcmp(token, "fill0") == 0))              {
  1086.         rec.type = SHAPERECORD_STYLE;
  1087.         rec.flags = SHAPERECORD_STYLE_FILL0;
  1088.         if (get_valueU8(&rec.fillstyle0) != TOKEN)          return 1;
  1089.         if (shape_add_record(shape, &rec))                  return 1;
  1090.  
  1091.       } else if ((strcmp(token, "selectfillstyle1") == 0) ||
  1092.                  (strcmp(token, "fill1") == 0))              {
  1093.         rec.type = SHAPERECORD_STYLE;
  1094.         rec.flags = SHAPERECORD_STYLE_FILL1;
  1095.         if (get_valueU8(&rec.fillstyle1) != TOKEN)          return 1;
  1096.         if (shape_add_record(shape, &rec))                  return 1;
  1097.  
  1098.       } else if (strcmp(token, "selectlinestyle") == 0) {
  1099.         rec.type = SHAPERECORD_STYLE;
  1100.         rec.flags = SHAPERECORD_STYLE_LINE;
  1101.         if (get_valueU8(&rec.linestyle) != TOKEN)           return 1;
  1102.         if (shape_add_record(shape, &rec))                  return 1;
  1103.  
  1104.       } else if (strcmp(token, "moveto") == 0) {
  1105.         if (get_token(token, 100) != TOKEN_LB)              return 1;
  1106.         rec.type = SHAPERECORD_STYLE;
  1107.         rec.flags = SHAPERECORD_STYLE_MOVE;
  1108.         if (get_value(&x) != TOKEN)                         return 1;
  1109.         x = (scalex*x)/1000;
  1110.         if (get_value(&y) != TOKEN)                         return 1;
  1111.         y = (scaley*y)/1000;
  1112.         rec.x = x;
  1113.         rec.y = y;
  1114.         if (shape_add_record(shape, &rec))                  return 1;
  1115.         if (get_token(token, 100) != TOKEN_RB)              return 1;
  1116.  
  1117.       } else if (strcmp(token, "moveby") == 0) {
  1118.         S32 dx, dy;
  1119.         if (get_token(token, 100) != TOKEN_LB)              return 1;
  1120.         rec.type = SHAPERECORD_STYLE;
  1121.         rec.flags = SHAPERECORD_STYLE_MOVE;
  1122.         if (get_value(&dx) != TOKEN)                        return 1;
  1123.         dx = (scalex*dx)/1000;
  1124.         if (get_value(&dy) != TOKEN)                        return 1;
  1125.         dy = (scaley*dy)/1000;
  1126.         if ((dx != 0) || (dy != 0)) {
  1127.           x += dx;
  1128.           y += dy;
  1129.           rec.x = x;
  1130.           rec.y = y;
  1131.           if (shape_add_record(shape, &rec))                return 1;
  1132.         }
  1133.         if (get_token(token, 100) != TOKEN_RB)              return 1;
  1134.  
  1135.       } else if (strcmp(token, "lineby") == 0) {
  1136.         S32 dx, dy;
  1137.         if (get_token(token, 100) != TOKEN_LB)              return 1;
  1138.         rec.type = SHAPERECORD_STRAIGHT;
  1139.         if (get_value(&dx) != TOKEN)                        return 1;
  1140.         dx = (scalex*dx)/1000;
  1141.         if (get_value(&dy) != TOKEN)                        return 1;
  1142.         dy = (scaley*dy)/1000;
  1143.         if ((dx != 0) || (dy != 0)) {
  1144.           x += dx;
  1145.           y += dy;
  1146.           rec.x = dx;
  1147.           rec.y = dy;
  1148.           if (shape_add_record(shape, &rec))                return 1;
  1149.         }
  1150.         if (get_token(token, 100) != TOKEN_RB)              return 1;
  1151.  
  1152.       } else if (strcmp(token, "curveby") == 0) {
  1153.         S32 dxc, dyc, dx, dy;
  1154.         if (get_token(token, 100) != TOKEN_LB)              return 1;
  1155.         rec.type = SHAPERECORD_CURVE;
  1156.         if (get_value(&dxc) != TOKEN)                       return 1;
  1157.         dxc = (scalex*dxc)/1000;
  1158.         if (get_value(&dyc) != TOKEN)                       return 1;
  1159.         dyc = (scaley*dyc)/1000;
  1160.         if (get_value(&dx) != TOKEN)                        return 1;
  1161.         dx = (scalex*dx)/1000;
  1162.         if (get_value(&dy) != TOKEN)                        return 1;
  1163.         dy = (scaley*dy)/1000;
  1164.         if ((dx != 0) || (dy != 0) || (dxc != 0) || (dyc != 0)) {
  1165.           x += dxc + dx;
  1166.           y += dyc + dy;
  1167.           rec.x = dx;
  1168.           rec.y = dy;
  1169.           rec.ctrlx = dxc;
  1170.           rec.ctrly = dyc;
  1171.           if (shape_add_record(shape, &rec))                return 1;
  1172.         }
  1173.         if (get_token(token, 100) != TOKEN_RB)              return 1;
  1174.  
  1175.       }
  1176.     } else if (type != TOKEN_RB)                            return 1;
  1177.   } while (type != TOKEN_RB);
  1178.  
  1179.   rec.type = SHAPERECORD_END;
  1180.   if (shape_add_record(shape, &rec))                        return 1;
  1181.  
  1182.   return add_character(shape->id, shape, CHARACTER_SHAPE);
  1183. }
  1184.  
  1185.  
  1186. int parse_button_state(BUTTON *button, int which) {
  1187.  
  1188.   char token[100];
  1189.   int type;
  1190.   unsigned int *count;
  1191.   BUTTONSTATE **states, state;
  1192.  
  1193.   switch (which) {
  1194.   case BUTTONSTATE_UP:
  1195.     states = &button->up;
  1196.     count = &button->upcount;
  1197.     break;
  1198.   case BUTTONSTATE_OVER:
  1199.     states = &button->over;
  1200.     count = &button->overcount;
  1201.     break;
  1202.   case BUTTONSTATE_DOWN:
  1203.     states = &button->down;
  1204.     count = &button->downcount;
  1205.     break;
  1206.   case BUTTONSTATE_SHAPE:
  1207.     states = &button->shape;
  1208.     count = &button->shapecount;
  1209.     break;
  1210.   }
  1211.  
  1212.   memset(&state, 0, sizeof(BUTTONSTATE));
  1213.   matrix_reset(&state.matrix);
  1214.   cxform_reset(&state.cxform);
  1215.  
  1216.   if (get_token(token, 100) != TOKEN_LB)                    return 1;
  1217.   do {
  1218.     type = get_tokenl(token, 100);
  1219.     if (type == TOKEN) {
  1220.       if (strcmp(token, "id") == 0) {
  1221.         int type;
  1222.         if (get_id(&state.id) != TOKEN)                     return 1;
  1223.         type = get_character_type(state.id);
  1224.         if (type == CHARACTER_NOT_FOUND) {
  1225.           fprintf(stderr, "Character (id=%d) is undefined\n", state.id);
  1226.           return 1;
  1227.         }
  1228.         if ((type != CHARACTER_BITMAP) &&
  1229.             (type != CHARACTER_SHAPE) &&
  1230.             (type != CHARACTER_TEXT)) {
  1231.           fprintf(stderr, "Character (id=%d) can not be used for a button-state\n", state.id);
  1232.           return 1;
  1233.         }
  1234.  
  1235.       } else if (strcmp(token, "depth") == 0) {
  1236.         if (get_valueU16(&state.depth) != TOKEN)            return 1;
  1237.  
  1238.       } else if (strcmp(token, "matrix") == 0) {
  1239.         if (parse_matrix(&state.matrix))                    return 1;
  1240.  
  1241.       } else if (strcmp(token, "cxform") == 0) {
  1242.         if (parse_cxform(&state.cxform))                    return 1;
  1243.  
  1244.       }
  1245.     } else if (type != TOKEN_RB)                            return 1;
  1246.   } while (type != TOKEN_RB);
  1247.  
  1248.   if (*count == 0) {
  1249.     *states = malloc(sizeof(BUTTONSTATE));
  1250.     if (!*states) {
  1251.       fprintf(stderr, "No room\n");
  1252.       return 1;
  1253.     }
  1254.   } else {
  1255.     BUTTONSTATE *newstates;
  1256.     newstates = realloc(*states, (*count+1)*sizeof(BUTTONSTATE));
  1257.     if (!newstates) {
  1258.       fprintf(stderr, "No room\n");
  1259.       return 1;
  1260.     }
  1261.     *states = newstates;
  1262.   }
  1263.  
  1264.   memcpy(*states + *count, &state, sizeof(BUTTONSTATE));
  1265.   *count = *count+1;
  1266.  
  1267.   return 0;
  1268. }
  1269.  
  1270.  
  1271. int parse_button() {
  1272.  
  1273.   char token[100];
  1274.   int type;
  1275.   BUTTON *button;
  1276.  
  1277.   // create and reset structure
  1278.   button = malloc(sizeof(BUTTON));
  1279.   if (!button)                                              return 1;
  1280.   memset(button, 0, sizeof(BUTTON));
  1281.  
  1282.   if (get_token(token, 100) != TOKEN_LB)                    return 1;
  1283.   do {
  1284.     type = get_tokenl(token, 100);
  1285.     if (type == TOKEN) {
  1286.       if (strcmp(token, "id") == 0) {
  1287.         if (get_id(&button->id) != TOKEN)                   return 1;
  1288.         if (is_id_used(button->id))   report_error("Dublicate character ID");
  1289.  
  1290.       } else if (strcmp(token, "actions") == 0) {
  1291.         if (parse_actions(&button->actions, &button->actioncount))
  1292.                                                             return 1;
  1293.       } else if (strcmp(token, "up") == 0) {
  1294.         if (parse_button_state(button, BUTTONSTATE_UP)) {
  1295.           fprintf(stderr, "Failed to parse 'up' state\n");
  1296.           return 1;
  1297.         }
  1298.  
  1299.       } else if (strcmp(token, "over") == 0) {
  1300.         if (parse_button_state(button, BUTTONSTATE_OVER)) {
  1301.           fprintf(stderr, "Failed to parse 'over' state\n");
  1302.           return 1;
  1303.         }
  1304.  
  1305.       } else if (strcmp(token, "down") == 0) {
  1306.         if (parse_button_state(button, BUTTONSTATE_DOWN)) {
  1307.           fprintf(stderr, "Failed to parse 'down' state\n");
  1308.           return 1;
  1309.         }
  1310.  
  1311.       } else if (strcmp(token, "activearea") == 0) {
  1312.         if (parse_button_state(button, BUTTONSTATE_SHAPE)) {
  1313.           fprintf(stderr, "Failed to parse 'shape' state\n");
  1314.           return 1;
  1315.         }
  1316.  
  1317.       } else {
  1318.         fprintf(stderr, "Unsupported field '%s'\n", token);
  1319.         return 1;
  1320.       }
  1321.     } else if (type != TOKEN_RB)                            return 1;
  1322.   } while (type != TOKEN_RB);
  1323.  
  1324.   return add_character(button->id, button, CHARACTER_BUTTON);
  1325. }
  1326.  
  1327.  
  1328. int parse_place_object() {
  1329.  
  1330.   char token[100];
  1331.   int type;
  1332.   PLACEOBJECT place;
  1333.  
  1334.   // reset the structure
  1335.   memset(&place, 0, sizeof(PLACEOBJECT));
  1336.   cxform_reset(&place.cxform);
  1337.   matrix_reset(&place.matrix);
  1338.   place.usealpha = 1;
  1339.   place.flags = PLACEOBJECT_MOVE | PLACEOBJECT_MATRIX;
  1340.   place.frameno = RESERVED_FRAMENO;
  1341.  
  1342.   if (get_token(token, 100) != TOKEN_LB)                    return 1;
  1343.   do {
  1344.     type = get_tokenl(token, 100);
  1345.     if (type == TOKEN) {
  1346.       if (strcmp(token, "id") == 0) {
  1347.         if (get_id(&place.id) != TOKEN)                     return 1;
  1348.         if (!is_id_used(place.id)) {
  1349.           fprintf(stderr, "Unknown character (id=%d)\n", place.id);
  1350.           return 1;
  1351.         }
  1352.         place.flags &= ~PLACEOBJECT_MOVE;
  1353.         place.flags |= PLACEOBJECT_CHARACTER;
  1354.  
  1355.       } else if (strcmp(token, "depth") == 0) {
  1356.         if (get_valueU16(&place.depth) != TOKEN)            return 1;
  1357.  
  1358.       } else if (strcmp(token, "matrix") == 0) {
  1359.         if (parse_matrix(&place.matrix))                    return 1;
  1360.         place.flags |= PLACEOBJECT_MATRIX;
  1361.  
  1362.       } else if (strcmp(token, "cxform") == 0) {
  1363.         if (parse_cxform(&place.cxform))                    return 1;
  1364.         place.flags |= PLACEOBJECT_CXFORM;
  1365.  
  1366.       } else if (strcmp(token, "clip") == 0) {
  1367.         if (get_valueU16(&place.clip) != TOKEN)             return 1;
  1368.         place.flags |= PLACEOBJECT_CLIP;
  1369.  
  1370.       } else if (strcmp(token, "frame") == 0) {
  1371.         if (get_valueU16(&place.frameno) != TOKEN)          return 1;
  1372.  
  1373.       }
  1374.  
  1375.     } else if (type != TOKEN_RB)                            return 1;
  1376.   } while (type != TOKEN_RB);
  1377.  
  1378.   place_object(&place);
  1379.  
  1380.   return 0;
  1381. }
  1382.  
  1383.  
  1384.  
  1385. int parse_remove_object() {
  1386. // handles both RemoveObject and RemoveObject2
  1387.   char token[100];
  1388.   int type;
  1389.   U16 depth, frameno;
  1390.  
  1391.   frameno = RESERVED_FRAMENO;
  1392.  
  1393.   if (get_token(token, 100) != TOKEN_LB)          return 1;
  1394.   do {
  1395.     type = get_tokenl(token, 100);
  1396.     if (type == TOKEN) {
  1397.       if (strcmp(token, "id") == 0) {
  1398.         if (get_token(token, 100) != TOKEN)       return 1;
  1399.  
  1400.       } else if (strcmp(token, "depth") == 0) {
  1401.         if (get_valueU16(&depth) != TOKEN)        return 1;
  1402.  
  1403.       } else if (strcmp(token, "frame") == 0) {
  1404.         if (get_valueU16(&frameno) != TOKEN)      return 1;
  1405.       }
  1406.  
  1407.     } else if (type != TOKEN_RB)
  1408.       return 1;
  1409.   } while (type != TOKEN_RB);
  1410.  
  1411.   remove_object(depth, frameno);
  1412.  
  1413.   return 0;
  1414. }
  1415.  
  1416.  
  1417. int parse_show_frame() {
  1418.  
  1419.   char token[100];
  1420.  
  1421.   if (get_token(token, 100) != TOKEN_LB)          return 1;
  1422.   if (get_token(token, 100) != TOKEN_RB)          return 1;
  1423.   if (show_frame())                               return 1;
  1424.   return 0;
  1425. }
  1426.  
  1427.  
  1428.  
  1429. int parse_text_style_record(TEXTREC *rec) {
  1430.  
  1431.   char token[100];
  1432.   int type;
  1433.  
  1434.   rec->flags = 0;
  1435.  
  1436.   if (get_token(token, 100) != TOKEN_LB)          return 1;
  1437.   do {
  1438.     type = get_tokenl(token, 100);
  1439.     if (type == TOKEN) {
  1440.       if (strcmp(token, "font") == 0) {
  1441.         rec->flags |= TEXTREC_FONT;
  1442.         if (get_id(&rec->data.style.font) != TOKEN)  return 1;
  1443.         if (find_font(rec->data.style.font) == -1) {
  1444.           fprintf(stderr, "Font (id=%d) not defined\n", rec->data.style.font);
  1445.           return 1;
  1446.         }
  1447.  
  1448.       } else if (strcmp(token, "size") == 0) {
  1449.         rec->flags |= TEXTREC_SIZE;
  1450.         if (get_valueU16(&rec->data.style.size) != TOKEN)
  1451.           return 1;
  1452.  
  1453.       } else if (strcmp(token, "colour") == 0) {
  1454.         rec->flags |= TEXTREC_COLOUR;
  1455.         if (get_rgb(&rec->data.style.colour) != TOKEN)
  1456.           return 1;
  1457.  
  1458.       } else if (strcmp(token, "move") == 0) {
  1459.         rec->flags |= TEXTREC_MOVE;
  1460.         if (get_token(token, 100) != TOKEN_LB)    return 1;
  1461.         if (get_value(&rec->data.style.x) != TOKEN)  return 1;
  1462.         if (get_value(&rec->data.style.y) != TOKEN)  return 1;
  1463.         if (get_token(token, 100) != TOKEN_RB)    return 1;
  1464.       }
  1465.  
  1466.     } else if (type != TOKEN_RB)                  return 1;
  1467.  
  1468.   } while (type != TOKEN_RB);
  1469.  
  1470.   if (rec->flags == 0) {
  1471.     fprintf(stderr, "Empty text-record\n");
  1472.     return 1;
  1473.   }
  1474.  
  1475.   return 0;
  1476. }
  1477.  
  1478.  
  1479. int parse_text() {
  1480.  
  1481.   char token[MAXLINELENGTH];
  1482.   int type;
  1483.   TEXT *text;
  1484.   int fontindex;
  1485.  
  1486.   // reset structure
  1487.   text = malloc(sizeof(TEXT));
  1488.   if (!text) {
  1489.     fprintf(stderr, "No room\n");
  1490.     return 1;
  1491.   }
  1492.   memset(text, 0, sizeof(TEXT));
  1493.   matrix_reset(&text->matrix);
  1494.  
  1495.   if (get_token(token, 100) != TOKEN_LB)          return 1;
  1496.  
  1497.   fontindex = -1;
  1498.  
  1499.   do {
  1500.     type = get_tokenl(token, MAXLINELENGTH);
  1501.     if (type == TOKEN) {
  1502.       if (strcmp(token, "id") == 0) {
  1503.         if (get_id(&text->id) != TOKEN)           return 1;
  1504.         if (is_id_used(text->id)) {
  1505.           fprintf(stderr, "Dublicate character id (%d)\n", text->id);
  1506.           return 1;
  1507.         }
  1508.  
  1509.       } else if (strcmp(token, "matrix") == 0) {
  1510.         if (parse_matrix(&text->matrix))          return 1;
  1511.  
  1512.       } else if (strcmp(token, "style") == 0) {
  1513.         TEXTREC *rec;
  1514.         rec = malloc(sizeof(TEXTREC));
  1515.         if (!rec) {
  1516.           fprintf(stderr, "No room\n");
  1517.           return 1;
  1518.         }
  1519.         if (parse_text_style_record(rec))         return 1;
  1520.         if (rec->flags & TEXTREC_FONT)
  1521.           fontindex = find_font(rec->data.style.font);
  1522.         if (add_text_record(text, rec))           return 1;
  1523.  
  1524.       } else if (strcmp(token, "text") == 0) {
  1525.         TEXTREC *rec;
  1526.  
  1527.         // make sure a font has been selected
  1528.         if (fontindex == -1) {
  1529.           fprintf(stderr, "No font has been selected\n");
  1530.           return 1;
  1531.         }
  1532.         // reset record
  1533.         rec = malloc(sizeof(TEXTREC));
  1534.         if (!rec) {
  1535.           fprintf(stderr, "No room\n");
  1536.           return 1;
  1537.         }
  1538.         memset(rec, 0, sizeof(TEXTREC));
  1539.         rec->flags = 0;
  1540.         // read string to display
  1541.         if (get_token(token, MAXLINELENGTH) != TOKEN_STRING)
  1542.           return 1;
  1543.         if (strlen(token) >= 127) {
  1544.           fprintf(stderr, "String too long\n");
  1545.           return 1;
  1546.         }
  1547.         rec->data.text.text = malloc(strlen(token)+1);
  1548.         if (!rec->data.text.text) {
  1549.           fprintf(stderr, "No room\n");
  1550.           return 1;
  1551.         }
  1552.         strcpy((char *)rec->data.text.text, token);
  1553.         rec->data.text.length = strlen((char *)rec->data.text.text);
  1554.         if (add_text_record(text, rec))           return 1;
  1555.         // mark the glyphs as being used
  1556.         mark_glyphs_as_used(fontindex, rec->data.text.text, rec->data.text.length);
  1557.       }
  1558.  
  1559.     } else if (type != TOKEN_RB)                  return 1;
  1560.  
  1561.   } while (type != TOKEN_RB);
  1562.  
  1563.   return add_character(text->id, text, CHARACTER_TEXT);
  1564. }
  1565.  
  1566.  
  1567. int parse_glyph(GLYPH *glyph) {
  1568.  
  1569.   char token[100];
  1570.   int type;
  1571.   GLYPHSHAPE shape;
  1572.   S32 x, y;
  1573.  
  1574.   if (get_token(token, 100) != TOKEN_LB)          return 1;
  1575.   x = y = 0;
  1576.   do {
  1577.     type = get_tokenl(token, 100);
  1578.     if (type == TOKEN) {
  1579.       if (strcmp(token, "char") == 0) {
  1580.         type = get_token(token, 100);
  1581.         if (type == TOKEN_STRING) {
  1582.           if (strlen(token) != 1) {
  1583.             fprintf(stderr, "Bad glyph-specifier (argument to 'char' is too long)\n");
  1584.             return 1;
  1585.           }
  1586.           glyph->letter = token[0];
  1587.         } else if (type == TOKEN) {
  1588.           S32 v;
  1589.           if (evaluate(token, &v))                return 1;
  1590.           glyph->letter = v;
  1591.         } else {
  1592.           fprintf(stderr, "Bad glyph-specifier (bad argument to 'char')\n");
  1593.           return 1;
  1594.         }
  1595.  
  1596.       } else if (strcmp(token, "index") == 0) {
  1597.         if (get_valueU8(&glyph->letter) != TOKEN) return 1;
  1598.  
  1599.       } else if (strcmp(token, "moveby") == 0) {
  1600.         S32 dx, dy;
  1601.         shape.type = GLYPHSHAPE_MOVE;
  1602.         if (get_token(token, 100) != TOKEN_LB)    return 1;
  1603.         if (get_value(&dx) != TOKEN)              return 1;
  1604.         if (get_value(&dy) != TOKEN)              return 1;
  1605.         if (get_token(token, 100) != TOKEN_RB)    return 1;
  1606.         x += dx;
  1607.         y += dy;
  1608.         shape.x = x;
  1609.         shape.y = y;
  1610.         if (add_glyph_shape(glyph, &shape))       return 1;
  1611.  
  1612.       } else if (strcmp(token, "moveto") == 0) {
  1613.         shape.type = GLYPHSHAPE_MOVE;
  1614.         if (get_token(token, 100) != TOKEN_LB)    return 1;
  1615.         if (get_value(&x) != TOKEN)               return 1;
  1616.         if (get_value(&y) != TOKEN)               return 1;
  1617.         if (get_token(token, 100) != TOKEN_RB)    return 1;
  1618.         shape.x = x;
  1619.         shape.y = y;
  1620.         if (add_glyph_shape(glyph, &shape))       return 1;
  1621.  
  1622.       } else if (strcmp(token, "lineby") == 0) {
  1623.         shape.type = GLYPHSHAPE_LINE;
  1624.         if (get_token(token, 100) != TOKEN_LB)    return 1;
  1625.         if (get_value(&shape.x) != TOKEN)         return 1;
  1626.         if (get_value(&shape.y) != TOKEN)         return 1;
  1627.         if (get_token(token, 100) != TOKEN_RB)    return 1;
  1628.         x += shape.x;
  1629.         y += shape.y;
  1630.         if (add_glyph_shape(glyph, &shape))       return 1;
  1631.  
  1632.       } else if (strcmp(token, "curveby") == 0) {
  1633.         shape.type = GLYPHSHAPE_CURVE;
  1634.         if (get_token(token, 100) != TOKEN_LB)    return 1;
  1635.         if (get_value(&shape.ctrlx) != TOKEN)     return 1;
  1636.         if (get_value(&shape.ctrly) != TOKEN)     return 1;
  1637.         if (get_value(&shape.x) != TOKEN)         return 1;
  1638.         if (get_value(&shape.y) != TOKEN)         return 1;
  1639.         if (get_token(token, 100) != TOKEN_RB)    return 1;
  1640.         x += shape.ctrlx + shape.x;
  1641.         y += shape.ctrly + shape.y;
  1642.         if (add_glyph_shape(glyph, &shape))       return 1;
  1643.       }
  1644.  
  1645.     } else if (type != TOKEN_RB)                  return 1;
  1646.  
  1647.   } while (type != TOKEN_RB);
  1648.  
  1649.   return 0;
  1650. }
  1651.  
  1652.  
  1653. int parse_font() {
  1654.  
  1655.   char token[MAXLINELENGTH];
  1656.   int type, i;
  1657.   S32 scalex, scaley;
  1658.   FONT *font;
  1659.  
  1660.   font = malloc(sizeof(FONT));
  1661.   if (!font) {
  1662.     fprintf(stderr, "No room\n");
  1663.     return 1;
  1664.   }
  1665.   memset(font, 0, sizeof(FONT));
  1666.  
  1667.   scalex = scaley = 65536;
  1668.  
  1669.   if (get_token(token, 100) != TOKEN_LB)          return 1;
  1670.  
  1671.   do {
  1672.     type = get_tokenl(token, MAXLINELENGTH);
  1673.     if (type == TOKEN) {
  1674.       if (strcmp(token, "id") == 0) {
  1675.         if (get_id(&font->id) != TOKEN)           return 1;
  1676.         if (is_id_used(font->id)) {
  1677.           fprintf(stderr, "Dublicate character id (%d)\n", font->id);
  1678.           return 1;
  1679.         }
  1680.  
  1681.       } else if (strcmp(token, "spacing") == 0) {
  1682.         if (get_valueS16(&font->spacing))         return 1;
  1683.  
  1684.       } else if (strcmp(token, "scale") == 0) {
  1685.         if (get_token(token, 100) != TOKEN_LB)    return 1;
  1686.         if (get_value(&scalex) != TOKEN)          return 1;
  1687.         if (get_value(&scaley) != TOKEN)          return 1;
  1688.         if (get_token(token, 100) != TOKEN_RB)    return 1;
  1689.  
  1690.       } else if (strcmp(token, "glyph") == 0) {
  1691.         GLYPH *glyph;
  1692.         glyph = malloc(sizeof(GLYPH));
  1693.         if (!glyph) {
  1694.           fprintf(stderr, "No room\n");
  1695.           return 1;
  1696.         }
  1697.         memset(glyph, 0, sizeof(GLYPH));
  1698.         if (parse_glyph(glyph))                   return 1;
  1699.         if (add_glyph(font, glyph))               return 1;
  1700.       }
  1701.  
  1702.     } else if (type != TOKEN_RB)                  return 1;
  1703.  
  1704.   } while (type != TOKEN_RB);
  1705.  
  1706.   // if scaling or offset is specified for the font...
  1707.   if ((scalex != 65536) || (scaley != 65536)) {
  1708.     for (i = 0; i < font->glyphcount; i++) {
  1709.       GLYPH *glyph;
  1710.       int shape;
  1711.  
  1712.       glyph = font->glyphs + i;
  1713.       for (shape = 0; shape < glyph->shapecount; shape++) {
  1714.         GLYPHSHAPE *gs;
  1715.         gs = glyph->shapes + shape;
  1716.         gs->x     = (gs->x     * scalex)>>16;
  1717.         gs->y     = (gs->y     * scaley)>>16;
  1718.         gs->ctrlx = (gs->ctrlx * scalex)>>16;
  1719.         gs->ctrly = (gs->ctrly * scaley)>>16;
  1720.       }
  1721.     }
  1722.   }
  1723.   // calculate glyph bbox
  1724.   for (i = 0; i < font->glyphcount; i++) {
  1725.     GLYPH *glyph;
  1726.     int shape, context;
  1727.     S32 x, y;
  1728.  
  1729.     glyph = font->glyphs + i;
  1730.  
  1731.     bbox_init(&glyph->bbox, &context);
  1732.     x = y = 0;
  1733.     for (shape = 0; shape < glyph->shapecount; shape++) {
  1734.       GLYPHSHAPE *gs;
  1735.  
  1736.       gs = glyph->shapes + shape;
  1737.       if (gs->type == GLYPHSHAPE_MOVE) {
  1738.         x = gs->x;
  1739.         y = gs->y;
  1740.         bbox_add_point(&glyph->bbox, &context, x, y, 0);
  1741.       } else if (gs->type == GLYPHSHAPE_LINE) {
  1742.         x += gs->x;
  1743.         y += gs->y;
  1744.         bbox_add_point(&glyph->bbox, &context, x, y, 0);
  1745.       } else if (gs->type == GLYPHSHAPE_CURVE) {
  1746.         x += gs->ctrlx;
  1747.         y += gs->ctrly;
  1748.         bbox_add_point(&glyph->bbox, &context, x, y, 0);
  1749.         x += gs->x;
  1750.         y += gs->y;
  1751.         bbox_add_point(&glyph->bbox, &context, x, y, 0);
  1752.       }
  1753.     }
  1754.   }
  1755.  
  1756.   if (add_font(font))                             return 1;
  1757.  
  1758.   return add_character(font->id, font, CHARACTER_FONT);
  1759. }
  1760.  
  1761. // ---------------------------------------------------------------------
  1762.  
  1763.  
  1764. int place_object(PLACEOBJECT *place) {
  1765.  
  1766.   FRAME *frame;
  1767.  
  1768.   if (!(place->flags & PLACEOBJECT_MOVE))
  1769.     if (is_depth_used(place->depth))   report_error("Depth is already used");
  1770.   use_depth(place->depth, 1);
  1771.   use_id(place->id);
  1772.  
  1773.   if (place->frameno == RESERVED_FRAMENO)
  1774.     frame = frames+framecount;
  1775.   else {
  1776.     if (place->frameno >= framecount)
  1777.       report_error("Illegal frame no. in PlaceObject { }");
  1778.     frame = frames+place->frameno;
  1779.   }
  1780.  
  1781.   if (!frame->place) {
  1782.     frame->place = malloc(sizeof(PLACEOBJECT));
  1783.     if (!frame->place)        return 1;
  1784.   } else {
  1785.     PLACEOBJECT *newplace;
  1786.     newplace = realloc(frame->place, (frame->placecount+1)*sizeof(PLACEOBJECT));
  1787.     if (!newplace)            return 1;
  1788.     frame->place = newplace;
  1789.   }
  1790.   memcpy(frame->place + frame->placecount, place, sizeof(PLACEOBJECT));
  1791.   frame->placecount++;
  1792.  
  1793.   return 0;
  1794. }
  1795.  
  1796.  
  1797. int remove_object(U16 depth, U16 frameno) {
  1798.  
  1799.   FRAME *frame;
  1800.   char err[256];
  1801.  
  1802.   if (!is_depth_used(depth)) {
  1803.      sprintf(err, "No object at this depth (%d)", depth);
  1804.      report_error(err);
  1805.   }
  1806.   use_depth(depth, 0);
  1807.  
  1808.   if (frameno == RESERVED_FRAMENO)
  1809.     frame = frames+framecount;
  1810.   else {
  1811.     if (frameno >= framecount)
  1812.       report_error("Illegal frame number in RemoveObject { }");
  1813.     frame = frames+frameno;
  1814.   }
  1815.   if (!frame->removedepths) {
  1816.     frame->removedepths = malloc(sizeof(U16));
  1817.     if (!frame->removedepths)       return 1;
  1818.   } else {
  1819.     U16 *newremove;
  1820.     newremove = realloc(frame->removedepths, (frame->removecount+1)*sizeof(U16));
  1821.     if (!newremove)           return 1;
  1822.     frame->removedepths = newremove;
  1823.   }
  1824.   frame->removedepths[frame->removecount++] = depth;
  1825.  
  1826.   return 0;
  1827. }
  1828.  
  1829.  
  1830. int show_frame() {
  1831.  
  1832.   framecount++;
  1833.   if (framecount >= MAXFRAMECOUNT)                return 1;
  1834.   // clear next frame
  1835.   memset(frames+framecount, 0, sizeof(FRAME));
  1836.  
  1837.   if (set_variable_value("frameno", framecount))  return 1;
  1838.   return 0;
  1839. }
  1840.  
  1841.  
  1842. int write_tag(int tag, int size) {
  1843.  
  1844.   if (size >= 0x3f) {
  1845.     if (write_ushort((tag<<6) | 0x3f))  return 1;
  1846.     if (write_uint((U32)size))          return 1;
  1847.   } else
  1848.     if (write_ushort((tag<<6) | size))  return 1;
  1849.  
  1850.   return 0;
  1851. }
  1852.  
  1853.  
  1854. int write_place_object(PLACEOBJECT *place) {
  1855.  
  1856.   U32 ptr;
  1857.  
  1858.   if (cxform_is_empty(&place->cxform))
  1859.     place->flags &= ~PLACEOBJECT_CXFORM;
  1860.  
  1861.   if (flush_bucket())                                       return 1;
  1862.   ptr = read_position(NULL);
  1863.   if (write_ushort(0))                                      return 1;
  1864.   if (write_ubyte(place->flags))                            return 1;
  1865.   if (write_ushort(place->depth))                           return 1;
  1866.   if (place->flags & PLACEOBJECT_CHARACTER)
  1867.     if (write_ushort(place->id))                            return 1;
  1868.   if (place->flags & PLACEOBJECT_MATRIX)
  1869.     if (matrix_write(&place->matrix))                       return 1;
  1870.   if (place->flags & PLACEOBJECT_CXFORM)
  1871.     if (cxform_write(&place->cxform, place->usealpha))      return 1;
  1872.   if (place->flags & PLACEOBJECT_CLIP)
  1873.       if (write_ushort(place->clip))                        return 1;
  1874.  
  1875.   if (update_record_header(stagPlaceObject2, ptr))          return 1;
  1876.  
  1877.   return 0;
  1878. }
  1879.  
  1880.  
  1881. int write_flash_file() {
  1882.  
  1883.   U32 i;
  1884.  
  1885.   if (framecount < 1)                                       return 1;
  1886.  
  1887.   if (write_ubyte('F'))                                     return 1;
  1888.   if (write_ubyte('W'))                                     return 1;
  1889.   if (write_ubyte('S'))                                     return 1;
  1890.   if (write_ubyte(fileversion))                             return 1;
  1891.   if (write_uint(0))                                        return 1;
  1892.   if (rect_write(&framesize))                               return 1;
  1893.   if (write_ushort(framerate))                              return 1;
  1894.   if (write_ushort(framecount))                             return 1;
  1895.  
  1896.   if (protected)
  1897.     if (write_tag(stagProtect, 0))                          return 1;
  1898.  
  1899.   // pass one - characters that may be used by other characters
  1900.   for (i = 0; i < used_characters; i++) {
  1901.     switch (dictionary[i]->type) {
  1902.     case CHARACTER_BITMAP:
  1903.       if (bitmap_write(dictionary[i]->data.bitmap))         return 1;
  1904.       break;
  1905.     case CHARACTER_FONT:
  1906.       if (fonttext_write_font(dictionary[i]->data.font))    return 1;
  1907.       break;
  1908.     case CHARACTER_SOUND:
  1909.       if (sound_write(dictionary[i]->data.sound))           return 1;
  1910.       break;
  1911.     }
  1912.   }
  1913.   // pass two - characters that use other characters
  1914.   for (i = 0; i < used_characters; i++) {
  1915.     switch (dictionary[i]->type) {
  1916.     case CHARACTER_SHAPE:
  1917.       if (shape_write(dictionary[i]->data.shape))           return 1;
  1918.       break;
  1919.     case CHARACTER_TEXT:
  1920.       if (fonttext_write_text(dictionary[i]->data.text))    return 1;
  1921.       break;
  1922.     }
  1923.   }
  1924.   // pass three - characters that use characters that use other characters
  1925.   for (i = 0; i < used_characters; i++) {
  1926.     switch (dictionary[i]->type) {
  1927.     case CHARACTER_BUTTON:
  1928.       if (button_write(dictionary[i]->data.button))         return 1;
  1929.       break;
  1930.     }
  1931.   }
  1932.  
  1933.   if (write_tag(stagSetBackgroundColour, 3))                return 1;
  1934.   if (write_ubyte( bgcolour      &255))                     return 1;
  1935.   if (write_ubyte((bgcolour>>8 ) &255))                     return 1;
  1936.   if (write_ubyte((bgcolour>>16) &255))                     return 1;
  1937.  
  1938.   for (i = 0; i < framecount; i++) {
  1939.     unsigned int obj;
  1940.     // remove objects
  1941.     for (obj = 0; obj < frames[i].removecount; obj++) {
  1942.       if (write_tag(stagRemoveObject2, 2))                  return 1;
  1943.       if (write_ushort(frames[i].removedepths[obj]))        return 1;
  1944.     }
  1945.     // play sounds
  1946.     for (obj = 0; obj < frames[i].soundcount; obj++)
  1947.       if (write_play_sound(frames[i].sounds+obj))           return 1;
  1948.     // place objects
  1949.     for (obj = 0; obj < frames[i].placecount; obj++)
  1950.       if (write_place_object(frames[i].place+obj))          return 1;
  1951.     // actions
  1952.     if (action_write(frames[i].actions, frames[i].actioncount))  return 1;
  1953.  
  1954.     if (write_tag(stagShowFrame, 0))                        return 1;
  1955.   }
  1956.  
  1957.   if (write_tag(stagEnd, 0))                                return 1;
  1958.   return 0;
  1959. }
  1960.  
  1961.  
  1962.  
  1963. int parse_file() {
  1964.  
  1965.   char token[MAXLINELENGTH];
  1966.   int type;
  1967.  
  1968.   if (parse_initialise())  return 1;
  1969.  
  1970.   linebuffer[0] = '\0';
  1971.   bufferpos = 0;
  1972.  
  1973.   do {
  1974.     type = get_tokenl(token, MAXLINELENGTH-1);
  1975.     if (type == TOKEN) {
  1976.       if (strcmp(token, "fileversion") == 0) {
  1977.         if (parse_file_version())   report_error("Bad FileVersion");
  1978.  
  1979.       } else if (strcmp(token, "end") == 0) {
  1980.         return 0;
  1981.  
  1982.       } else if (strcmp(token, "framearea") == 0) {
  1983.         if (parse_frame_area())     report_error("Bad FrameArea");
  1984.  
  1985.       } else if (strcmp(token, "protect") == 0) {
  1986.         if (get_token(token, MAXLINELENGTH-1) != TOKEN_LB)
  1987.           report_error("Error in script-file");
  1988.         if (get_token(token, MAXLINELENGTH-1) != TOKEN_RB)
  1989.           report_error("Error in script-file");
  1990.         protected = 1;
  1991.  
  1992.       } else if (strcmp(token, "framerate") == 0) {
  1993.         if (parse_frame_rate())     report_error("Bad FrameRate");
  1994.  
  1995.       } else if ((strcmp(token, "backgroundcolour") == 0) ||
  1996.                  (strcmp(token, "bgcolour") == 0))           {
  1997.         if (parse_bg_colour())      report_error("Bad BackgroundColour");
  1998.  
  1999.       } else if (strcmp(token, "button") == 0) {
  2000.         if (parse_button())         report_error("Bad Button");
  2001.  
  2002.       } else if ((strcmp(token, "defineshape") == 0) ||
  2003.                  (strcmp(token, "shape") == 0))         {
  2004.         if (parse_define_shape())   report_error("Bad DefineShape");
  2005.  
  2006.       } else if (strcmp(token, "jpeg") == 0) {
  2007.         if (parse_bitmap(BITMAP_JPEG))  report_error("Bad JPEG");
  2008.  
  2009.       } else if (strcmp(token, "font") == 0) {
  2010.         if (parse_font())  report_error("Bad font definition");
  2011.  
  2012.       } else if (strcmp(token, "text") == 0) {
  2013.         if (parse_text())  report_error("Bad text definition");
  2014.  
  2015.       } else if ((strcmp(token, "placeobject") == 0) ||
  2016.                  (strcmp(token, "place") == 0))         {
  2017.         if (parse_place_object())   report_error("Bad PlaceObject");
  2018.  
  2019.       } else if ((strcmp(token, "removeobject") == 0) ||
  2020.                  (strcmp(token, "remove") == 0))         {
  2021.         if (parse_remove_object())  report_error("Bad RemoveObject");
  2022.  
  2023.       } else if ((strcmp(token, "definesound") == 0) ||
  2024.                  (strcmp(token, "sound") == 0))         {
  2025.         if (parse_define_sound())  report_error("Bad DefineSound");
  2026.  
  2027.       } else if (strcmp(token, "playsound") == 0) {
  2028.         if (parse_play_sound())  report_error("Bad PlaySound");
  2029.  
  2030.       } else if (strcmp(token, "doaction") == 0) {
  2031.         FRAME *frame;
  2032.         frame = frames+framecount;
  2033.         if (parse_actions(&frame->actions, &frame->actioncount))
  2034.           report_error("Bad DoAction");
  2035.  
  2036.       } else if (strcmp(token, "showframe") == 0) {
  2037.         if (parse_show_frame())     report_error("Bad ShowFrame");
  2038.  
  2039.       } else
  2040.         fprintf(stderr, "Unknown tag '%s'\n", token);
  2041.  
  2042.     } else if (!end_of_file()) {
  2043.       fprintf(stderr, "Unexpected token :");
  2044.       switch (type) {
  2045.       case TOKEN_LB:
  2046.         fprintf(stderr, "'{'\n");
  2047.         break;
  2048.       case TOKEN_RB:
  2049.         fprintf(stderr, "'}'\n");
  2050.         break;
  2051.       case TOKEN:
  2052.       case TOKEN_STRING:
  2053.         fprintf(stderr, "'%s'\n", token);
  2054.         break;
  2055.       }
  2056.     }
  2057.   } while (!end_of_file());
  2058.  
  2059.   return 0;
  2060. }
  2061.