Index: class.c ================================================================== --- class.c +++ class.c @@ -199,11 +199,11 @@ if(c>='0' && c<='9') n|=c-'0'; else if(c>='A' && c<='F') n|=c+10-'A'; else if(c>='a' && c<='f') n|=c+10-'a'; else ParseError("Invalid string escape: \\x%X%c\n",n>>4,c); if(n<32) tokenstr[i++]=31; - tokenstr[i++]=n; + tokenstr[i++]=n?:255; break; default: ParseError("Invalid string escape: \\%c\n",c); } } else if(c=='"') { if(isimg) ParseError("Unterminated \\i escape in string literal\n"); Index: function.c ================================================================== --- function.c +++ function.c @@ -93,10 +93,62 @@ int a; if(sqlite3_value_type(*argv)==SQLITE_NULL) return; a=sqlite3_value_int(*argv)&0xFFFF; sqlite3_result_int64(cxt,a|((sqlite3_int64)TY_CLASS<<32)); } + +static void fn_heromesh_escape(sqlite3_context*cxt,int argc,sqlite3_value**argv) { + const unsigned char*u=sqlite3_value_blob(*argv); + int un=sqlite3_value_bytes(*argv); + char*e; + int en=0; + int i=0; + int c; + int isimg=0; + if(!u) return; + if(!un) { + sqlite3_result_zeroblob(cxt,0); + return; + } + e=sqlite3_malloc((un<<2)+1); + if(!e) { + sqlite3_result_error_nomem(cxt); + return; + } + while(i>4)<10?(c>>4)+'0':(c>>4)+'A'-10; + e[en++]=c<10?c+'0':c+'A'-10; + break; + case 32 ... 127: + if(c=='\\') { + if(!isimg) e[en++]=c; + isimg=0; + } else if(c=='"') { + e[en++]='\\'; + } + e[en++]=c; + break; + default: + e[en++]='\\'; + e[en++]='x'; + e[en++]=(c>>4)<10?(c>>4)+'0':(c>>4)+'A'-10; + e[en++]=c<10?c+'0':c+'A'-10; + } + sqlite3_result_text(cxt,sqlite3_realloc(e,en+1)?:e,en,sqlite3_free); +} static void fn_heromesh_type(sqlite3_context*cxt,int argc,sqlite3_value**argv) { static const char*const n[16]={ [TY_NUMBER]="number", [TY_CLASS]="class", @@ -109,10 +161,73 @@ int i; if(sqlite3_value_type(*argv)!=SQLITE_INTEGER) return; i=sqlite3_value_int64(*argv)>>32; sqlite3_result_text(cxt,i<0||i>TY_MAXTYPE?"object":n[i]?:"???",-1,SQLITE_STATIC); } + +static void fn_heromesh_unescape(sqlite3_context*cxt,int argc,sqlite3_value**argv) { + const unsigned char*e=sqlite3_value_text(*argv); + int en=sqlite3_value_bytes(*argv); + char*u; + int un=0; + int c,n; + int isimg=0; + if(!e) return; + if(!*e) { + sqlite3_result_text(cxt,"",0,SQLITE_STATIC); + return; + } + u=sqlite3_malloc(en+1); + if(!u) { + sqlite3_result_error_nomem(cxt); + return; + } + while(c=*e++) { + if(c=='\\') { + if(isimg) { + u[un++]=c; + isimg=0; + } else switch(c=*e++) { + case '0' ... '7': u[un++]=c-'0'+1; break; + case 'b': u[un++]=15; break; + case 'c': u[un++]=12; break; + case 'i': u[un++]=14; isimg=1; break; + case 'l': u[un++]=11; break; + case 'n': u[un++]=10; break; + case 'q': u[un++]=16; break; + case 'x': + c=*e++; + if(c>='0' && c<='9') n=c-'0'; + else if(c>='A' && c<='F') n=c+10-'A'; + else if(c>='a' && c<='f') n=c+10-'a'; + else break; + n<<=4; + c=*e++; + if(c>='0' && c<='9') n|=c-'0'; + else if(c>='A' && c<='F') n|=c+10-'A'; + else if(c>='a' && c<='f') n|=c+10-'a'; + else break; + if(n<32) u[un++]=31; + u[un++]=n?:255; + break; + default: u[un++]=c; + } + } else { + u[un++]=c; + } + } + done: + sqlite3_result_blob(cxt,u,un,sqlite3_free); +} + +static void fn_level(sqlite3_context*cxt,int argc,sqlite3_value**argv) { + sqlite3_result_int(cxt,*(Uint16*)sqlite3_user_data(cxt)); +} + +static void fn_level_title(sqlite3_context*cxt,int argc,sqlite3_value**argv) { + if(level_title) sqlite3_result_blob(cxt,level_title,strlen(level_title),SQLITE_TRANSIENT); +} static void fn_load_level(sqlite3_context*cxt,int argc,sqlite3_value**argv) { const char*s; if(!main_options['x']) { sqlite3_result_error(cxt,"LOAD_LEVEL function requires -x switch",-1); @@ -751,12 +866,17 @@ void init_sql_functions(sqlite3_int64*ptr0,sqlite3_int64*ptr1) { sqlite3_create_function(userdb,"BASENAME",0,SQLITE_UTF8|SQLITE_DETERMINISTIC,0,fn_basename,0,0); sqlite3_create_function(userdb,"CLASS_DATA",2,SQLITE_UTF8|SQLITE_DETERMINISTIC,0,fn_class_data,0,0); sqlite3_create_function(userdb,"CVALUE",1,SQLITE_UTF8|SQLITE_DETERMINISTIC,0,fn_cvalue,0,0); + sqlite3_create_function(userdb,"HEROMESH_ESCAPE",1,SQLITE_UTF8|SQLITE_DETERMINISTIC,0,fn_heromesh_escape,0,0); sqlite3_create_function(userdb,"HEROMESH_TYPE",1,SQLITE_UTF8|SQLITE_DETERMINISTIC,0,fn_heromesh_type,0,0); + sqlite3_create_function(userdb,"HEROMESH_UNESCAPE",1,SQLITE_UTF8|SQLITE_DETERMINISTIC,0,fn_heromesh_unescape,0,0); + sqlite3_create_function(userdb,"LEVEL",0,SQLITE_UTF8,&level_ord,fn_level,0,0); sqlite3_create_function(userdb,"LEVEL_CACHEID",0,SQLITE_UTF8|SQLITE_DETERMINISTIC,ptr0,fn_cacheid,0,0); + sqlite3_create_function(userdb,"LEVEL_ID",0,SQLITE_UTF8,&level_id,fn_level,0,0); + sqlite3_create_function(userdb,"LEVEL_TITLE",0,SQLITE_UTF8,0,fn_level_title,0,0); sqlite3_create_function(userdb,"LOAD_LEVEL",1,SQLITE_UTF8,0,fn_load_level,0,0); sqlite3_create_function(userdb,"MODSTATE",0,SQLITE_UTF8,0,fn_modstate,0,0); sqlite3_create_function(userdb,"MVALUE",1,SQLITE_UTF8|SQLITE_DETERMINISTIC,0,fn_mvalue,0,0); sqlite3_create_function(userdb,"NVALUE",1,SQLITE_UTF8|SQLITE_DETERMINISTIC,0,fn_zero_extend,0,0); sqlite3_create_function(userdb,"OVALUE",1,SQLITE_UTF8,0,fn_ovalue,0,0); Index: heromesh.h ================================================================== --- heromesh.h +++ heromesh.h @@ -42,10 +42,14 @@ extern xrm_db*resourcedb; extern const char*basefilename; extern xrm_quark optionquery[16]; extern char main_options[128]; extern Uint8 message_trace[0x4100/8]; +extern Uint16 level_id,level_ord,level_version,level_code; +extern unsigned char*level_title; +extern Uint16*level_index; +extern int level_nindex; #ifdef __GNUC__ extern char stack_protect_mode; extern void*stack_protect_mark; extern void*stack_protect_low; Index: main.c ================================================================== --- main.c +++ main.c @@ -41,10 +41,14 @@ xrm_db*resourcedb; const char*basefilename; xrm_quark optionquery[16]; char main_options[128]; Uint8 message_trace[0x4100/8]; +Uint16 level_id,level_ord,level_version,level_code; +unsigned char*level_title; +Uint16*level_index; +int level_nindex; #ifdef __GNUC__ char stack_protect_mode=0; void*stack_protect_mark; void*stack_protect_low; @@ -187,18 +191,24 @@ int i,n,x,y,z; Uint32 o; Uint32 mru[2]; if(lvl<0) return "Invalid level ID"; if(!buf) return "Cannot find level"; + free(level_title); + level_title=0; annihilate(); generation_number=TY_MAXTYPE+1; - p+=4; // skip level version and level code for now + level_version=p[0]|(p[1]<<8); + level_code=p[2]|(p[3]<<8); + p+=4; pfwidth=(*p++&63)+1; pfheight=(*p++&63)+1; while(*p && p=end) goto bad1; + level_title=strdup(buf+6); + if(!level_title) fatal("Allocation failed\n"); x=0; y=1; n=0; mru[0]=mru[1]=VOIDLINK; for(;;) { @@ -285,10 +295,11 @@ } } // skip level strings for now if(p>end) goto bad1; free(buf); + level_id=lvl; return 0; bad1: free(buf); return "Corrupted level data"; bad2: