fixed bug in jpeg2000 decoding
[swftools.git] / src / parser.lex
index bf520e5..a4338e8 100644 (file)
@@ -1,8 +1,11 @@
 %{
 
 #include <string.h>
-#include "q.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include "../lib/q.h"
 #include "parser.h"
+#include "../lib/utf8.h"
 
 //RVALUE        {NUMBER}|{PERCENT}|{NAME}|\"{STRING}\"|{DIM}
 //<a>.                {printf("<a>%s\n", yytext);}
@@ -35,21 +38,58 @@ static void unescapeString(string_t * tmp)
     /* fixme - this routine expects the string to be
        null-terminated */
 
-    for (p1=tmp->str; (p=strchr(p1, '\\')); p1 = p+1) 
+    for (p1=(char*)tmp->str; (p=strchr(p1, '\\')); p1 = p+1) 
     {
+       int nr=2;
+       int new=1;
        switch(p[1])
        {
-           case '\\': p[1] = '\\'; tmp->len--; break;
-           case '"': p[1] = '"'; tmp->len--; break;
-           case 'b': p[1] = '\b'; tmp->len--; break;
-           case 'f': p[1] = '\f'; tmp->len--; break;
-           case 'n': p[1] = '\n'; tmp->len--; break;
-           case 'r': p[1] = '\r'; tmp->len--; break;
-           case 't': p[1] = '\t'; tmp->len--; break;
+           case '\\': p[0] = '\\'; break;
+           case '"': p[0] = '"'; break;
+           case 'b': p[0] = '\b'; break;
+           case 'f': p[0] = '\f'; break;
+           case 'n': p[0] = '\n'; break;
+           case 'r': p[0] = '\r'; break;
+           case 't': p[0] = '\t'; break;
+           case 'x':  case 'u': {
+               int max=4;
+               int num=0;
+               char*utf8;
+               char bracket = 0;
+               if(p[1] == 'u')
+                   max = 6;
+               if(p[2] == '{')  {
+                   bracket = 1;nr++;max++;
+               }
+               while(strchr("0123456789abcdefABCDEF", p[nr]) && (bracket || nr < max)) {
+                   num <<= 4;
+                   if(p[nr]>='0' && p[nr]<='9') num |= p[nr] - '0';
+                   if(p[nr]>='a' && p[nr]<='f') num |= p[nr] - 'a' + 10;
+                   if(p[nr]>='A' && p[nr]<='F') num |= p[nr] - 'A' + 10;
+                   nr++;
+               }
+               if(bracket && p[nr]=='}') {
+                   bracket = 0;
+                   nr++;
+               }
+               utf8 = getUTF8(num);
+               new = strlen(utf8);
+               memcpy(p, utf8, new); // do not copy the terminating zero
+               break;
+           }
            default:
                continue;
        }
-       strcpy(p, p+1);
+       tmp->len -= (nr-new); 
+       {
+           int t;
+           char*to=p+new,*from=p+nr;
+           while(*from) {
+               *to = *from;
+               to++;
+               from++;
+           }
+       }
     }
 }
 
@@ -86,8 +126,8 @@ static void store(enum type_t type, int line, int column, char*text, int length)
            }
            prefix = 0;
        break;
-       case LABEL:
-           string_set2(&tmp, text, length-1);
+       case RAWDATA:
+           string_set2(&tmp, text+1/*:*/, length-5/*.end*/);
            token.text = (char*)mem_putstring(&strings, tmp);
        break;
        case COMMAND:
@@ -116,6 +156,51 @@ static void store(enum type_t type, int line, int column, char*text, int length)
     prefix = 0;
 }
 
+#define MAX_INCLUDE_DEPTH 16
+static YY_BUFFER_STATE include_stack[MAX_INCLUDE_DEPTH];
+static int line_stack[MAX_INCLUDE_DEPTH];
+static int column_stack[MAX_INCLUDE_DEPTH];
+static int include_stack_ptr = 0;
+
+static void handleInclude(char*text, int len)
+{
+    text+=9;len-=9;
+    while(len >=1 && (text[0] == ' ' || text[0] == '\t')) {
+       text++;len--;
+    }
+    while(len >= 1 && 
+          (text[len-1] == ' ' || 
+           text[len-1] == '\r' || 
+           text[len-1] == '\n')) {
+       len--;
+    }
+    if(len >= 2 && text[0] == '"' && text[len-1] == '"') {
+       text++; len-=2;
+    }
+    text[len] = 0;
+    if(include_stack_ptr >= MAX_INCLUDE_DEPTH) {
+       fprintf( stderr, "Includes nested too deeply" );
+       exit( 1 );
+    }
+    include_stack[include_stack_ptr] = YY_CURRENT_BUFFER;
+    line_stack[include_stack_ptr] = line;
+    column_stack[include_stack_ptr] = column;
+    include_stack_ptr++;
+    yyin = fopen(text, "rb");
+    if (!yyin) {
+       fprintf(stderr, "Couldn't open %s\n", text);
+       exit(1);
+    }
+    yy_switch_to_buffer(yy_create_buffer( yyin, YY_BUF_SIZE ) );
+
+#ifdef INITIAL
+    BEGIN(INITIAL);
+#else
+    // best guess
+    BEGIN(0);
+#endif
+}
+
 #define c() {count(yytext, yyleng, YY_START);}
 #define s(type) {store(type, line, column, yytext, yyleng);}
 %}
@@ -124,8 +209,8 @@ static void store(enum type_t type, int line, int column, char*text, int length)
 %x BINARY
 
 NAME    [a-zA-Z_./](-*[a-zA-Z0-9_./])*
-TWIP    ([0-9]+(\.([0-9]([05])?)?)?)
-NUMBER  [0-9]+(\.[0-9]*)?
+TWIP    (-?[0-9]+(\.([0-9]([05])?)?)?)
+NUMBER  -?[0-9]+(\.[0-9]*)?
 PERCENT         {NUMBER}%
 STRING   (\\.|[^\\"\n])*
 S       [ \n\r\t]
@@ -146,18 +231,18 @@ RVALUE     \"{STRING}\"|([^ \n\r\t]+)
 {NAME}{S}*-=               {s(ASSIGNMENT);prefix="<minus>";c();BEGIN(R);}
 {NAME}{S}*=                {s(ASSIGNMENT);c();BEGIN(R);}
 <R>{ /* values which appear only on the right-hand side of assignments, like: x=50% */
-    [^ \n\t\r]*                    {s(IDENTIFIER);c();BEGIN(0);}
+    [^ :\n\t\r]*                   {s(IDENTIFIER);c();BEGIN(0);}
 }
+\.include{S}.*\n                   {handleInclude(yytext, yyleng);}
 \.{NAME}                   {s(COMMAND);c();}
-{NAME}{S}*:                 {s(LABEL);c();}
+:([^.]|\.[^e]|\.e[^n]|\.en[^d]|\.end[^ \n\r\t]|[ \n\r\t])*\.end            {s(RAWDATA);c();}
 {NAME}                      {s(IDENTIFIER);c();}
 "["                        {c();BEGIN(BINARY);}
 {S}                        {c();}
-.                          {char c,c1=0;
+.                          {char c,c1=yytext[0];
                             printf("Syntax error in line %d, %d: %s", line, column, yytext);
                             while(1) {
                                 c=input();
-                                if(!c1) c1=c;
                                 if(c=='\n' || c==EOF) 
                                     break;
                                printf("%c", c);
@@ -168,7 +253,19 @@ RVALUE      \"{STRING}\"|([^ \n\r\t]+)
                             exit(1);
                             yyterminate();
                            }
-<<EOF>>                            {c();s(END);yyterminate();}
+<<EOF>>                            {c();
+                            if ( --include_stack_ptr < 0 ) {
+                               s(END);
+                               yyterminate();
+                            } else {
+                                yy_delete_buffer( YY_CURRENT_BUFFER );
+                                yy_switch_to_buffer(
+                                     include_stack[include_stack_ptr] );
+                                column = column_stack[include_stack_ptr];
+                                line = line_stack[include_stack_ptr];
+                            }
+                           }
+
 %%
 
 int yywrap()
@@ -184,10 +281,19 @@ void freeTokens(struct token_t*file)
 
 struct token_t* generateTokens(char*filename)
 {
-    FILE*fi = fopen(filename, "rb");
+    FILE*fi;
     int t;
     struct token_t*result;
     int num;
+
+    if(!filename)
+       return 0;
+
+    if(!strcmp(filename,"-"))
+       fi = stdin;
+    else
+       fi = fopen(filename, "rb");
+
     if(!fi) {
        printf("Couldn't find file %s\n", filename);
        return 0;
@@ -202,7 +308,12 @@ struct token_t* generateTokens(char*filename)
     column=1;
 
     yylex();
+#ifdef YY_CURRENT_BUFFER
+    // some newer flex versions require it like this:
+    yy_delete_buffer(YY_CURRENT_BUFFER);
+#else
     yy_delete_buffer(yy_current_buffer);
+#endif
 
     result = (struct token_t*)tokens.buffer;
     num = tokens.pos/sizeof(struct token_t);
@@ -212,7 +323,8 @@ struct token_t* generateTokens(char*filename)
            result[t].text += (int)strings.buffer;
     }
 
-    fclose(fi);
+    if(fi!=stdin)
+       fclose(fi);
     return result;
 }