diff --git a/dlls/msi/cond.y b/dlls/msi/cond.y index fecced79988..0b1d74e4b87 100644 --- a/dlls/msi/cond.y +++ b/dlls/msi/cond.y @@ -28,12 +28,14 @@ #include "windef.h" #include "winbase.h" +#include "winuser.h" #include "wine/debug.h" #include "wine/unicode.h" #include "msi.h" #include "msiquery.h" #include "msipriv.h" +#include "action.h" #define YYLEX_PARAM info #define YYPARSE_PARAM info @@ -58,45 +60,20 @@ struct cond_str { static LPWSTR COND_GetString( struct cond_str *str ); static LPWSTR COND_GetLiteral( struct cond_str *str ); static int COND_lex( void *COND_lval, COND_input *info); +static const WCHAR szEmpty[] = { 0 }; -typedef INT (*comp_int)(INT a, INT b); -typedef INT (*comp_str)(LPWSTR a, LPWSTR b, BOOL caseless); -typedef INT (*comp_m1)(LPWSTR a,int b); -typedef INT (*comp_m2)(int a,LPWSTR b); +static INT compare_int( INT a, INT operator, INT b ); +static INT compare_string( LPCWSTR a, INT operator, LPCWSTR b ); -static INT comp_lt_i(INT a, INT b); -static INT comp_gt_i(INT a, INT b); -static INT comp_le_i(INT a, INT b); -static INT comp_ge_i(INT a, INT b); -static INT comp_eq_i(INT a, INT b); -static INT comp_ne_i(INT a, INT b); -static INT comp_bitand(INT a, INT b); -static INT comp_highcomp(INT a, INT b); -static INT comp_lowcomp(INT a, INT b); +static INT compare_and_free_strings( LPWSTR a, INT op, LPWSTR b ) +{ + INT r; -static INT comp_eq_s(LPWSTR a, LPWSTR b, BOOL casless); -static INT comp_ne_s(LPWSTR a, LPWSTR b, BOOL casless); -static INT comp_lt_s(LPWSTR a, LPWSTR b, BOOL casless); -static INT comp_gt_s(LPWSTR a, LPWSTR b, BOOL casless); -static INT comp_le_s(LPWSTR a, LPWSTR b, BOOL casless); -static INT comp_ge_s(LPWSTR a, LPWSTR b, BOOL casless); -static INT comp_substring(LPWSTR a, LPWSTR b, BOOL casless); -static INT comp_start(LPWSTR a, LPWSTR b, BOOL casless); -static INT comp_end(LPWSTR a, LPWSTR b, BOOL casless); - -static INT comp_eq_m1(LPWSTR a, INT b); -static INT comp_ne_m1(LPWSTR a, INT b); -static INT comp_lt_m1(LPWSTR a, INT b); -static INT comp_gt_m1(LPWSTR a, INT b); -static INT comp_le_m1(LPWSTR a, INT b); -static INT comp_ge_m1(LPWSTR a, INT b); - -static INT comp_eq_m2(INT a, LPWSTR b); -static INT comp_ne_m2(INT a, LPWSTR b); -static INT comp_lt_m2(INT a, LPWSTR b); -static INT comp_gt_m2(INT a, LPWSTR b); -static INT comp_le_m2(INT a, LPWSTR b); -static INT comp_ge_m2(INT a, LPWSTR b); + r = compare_string( a, op, b ); + msi_free( a ); + msi_free( b ); + return r; +} %} @@ -107,33 +84,27 @@ static INT comp_ge_m2(INT a, LPWSTR b); struct cond_str str; LPWSTR string; INT value; - comp_int fn_comp_int; - comp_str fn_comp_str; - comp_m1 fn_comp_m1; - comp_m2 fn_comp_m2; } %token COND_SPACE COND_EOF COND_SPACE -%token COND_OR COND_AND COND_NOT -%token COND_LT COND_GT COND_EQ -%token COND_LPAR COND_RPAR COND_TILDA +%token COND_OR COND_AND COND_NOT COND_XOR COND_IMP COND_EQV +%token COND_LT COND_GT COND_EQ COND_NE COND_GE COND_LE +%token COND_ILT COND_IGT COND_IEQ COND_INE COND_IGE COND_ILE +%token COND_LPAR COND_RPAR COND_TILDA COND_SS COND_ISS +%token COND_ILHS COND_IRHS COND_LHS COND_RHS %token COND_PERCENT COND_DOLLARS COND_QUESTION COND_AMPER COND_EXCLAM %token COND_IDENT COND_NUMBER COND_LITER -%nonassoc COND_EOF COND_ERROR +%nonassoc COND_ERROR COND_EOF %type expression boolean_term boolean_factor -%type term value_i symbol_i integer -%type identifier value_s symbol_s literal -%type comp_op_i -%type comp_op_s -%type comp_op_m1 -%type comp_op_m2 +%type value_i integer operator +%type identifier symbol_s value_s literal %% condition: - expression + expression { COND_input* cond = (COND_input*) info; cond->result = $1; @@ -150,10 +121,22 @@ expression: { $$ = $1; } - | boolean_term COND_OR expression + | expression COND_OR boolean_term { $$ = $1 || $3; } + | expression COND_IMP boolean_term + { + $$ = !$1 || $3; + } + | expression COND_XOR boolean_term + { + $$ = ( $1 || $3 ) && !( $1 && $3 ); + } + | expression COND_EQV boolean_term + { + $$ = ( $1 && $3 ) || ( !$1 && !$3 ); + } ; boolean_term: @@ -161,59 +144,60 @@ boolean_term: { $$ = $1; } - | boolean_term COND_AND boolean_factor + | boolean_term COND_AND boolean_factor { $$ = $1 && $3; } ; boolean_factor: - term + COND_NOT boolean_factor { - $$ = $1; + $$ = $2 ? 0 : 1; } - | COND_NOT term + | value_i { - $$ = ! $2; - } - ; - - -term: - value_i - { - $$ = $1; + $$ = $1 ? 1 : 0; } | value_s { - $$ = ($1 && $1[0]) ? MSICONDITION_TRUE : MSICONDITION_FALSE; - msi_free( $1 ); + $$ = ($1 && $1[0]) ? 1 : 0; } - | value_i comp_op_i value_i + | value_i operator value_i { - $$ = $2( $1, $3 ); + $$ = compare_int( $1, $2, $3 ); } - | value_s comp_op_s value_s + | symbol_s operator value_i { - $$ = $2( $1, $3, FALSE ); - msi_free( $1 ); - msi_free( $3 ); + $$ = compare_int( $1 ? atoiW($1) : 0, $2, $3 ); } - | value_s COND_TILDA comp_op_s value_s + | value_i operator symbol_s { - $$ = $3( $1, $4, TRUE ); - msi_free( $1 ); - msi_free( $4 ); + $$ = compare_int( $1, $2, $3 ? atoiW($3) : 0 ); } - | value_s comp_op_m1 value_i + | symbol_s operator symbol_s { - $$ = $2( $1, $3 ); - msi_free( $1 ); + $$ = compare_and_free_strings( $1, $2, $3 ); } - | value_i comp_op_m2 value_s + | symbol_s operator literal { - $$ = $2( $1, $3 ); - msi_free( $3 ); + $$ = compare_and_free_strings( $1, $2, $3 ); + } + | literal operator symbol_s + { + $$ = compare_and_free_strings( $1, $2, $3 ); + } + | literal operator literal + { + $$ = compare_and_free_strings( $1, $2, $3 ); + } + | literal operator value_i + { + $$ = 0; + } + | value_i operator literal + { + $$ = 0; } | COND_LPAR expression COND_RPAR { @@ -221,183 +205,30 @@ term: } ; -comp_op_i: +operator: /* common functions */ - COND_EQ - { - $$ = comp_eq_i; - } - | COND_LT COND_GT - { - $$ = comp_ne_i; - } - | COND_LT - { - $$ = comp_lt_i; - } - | COND_GT - { - $$ = comp_gt_i; - } - | COND_LT COND_EQ - { - $$ = comp_le_i; - } - | COND_GT COND_EQ - { - $$ = comp_ge_i; - } - /*Int only*/ - | COND_GT COND_LT - { - $$ = comp_bitand; - } - | COND_LT COND_LT - { - $$ = comp_highcomp; - } - | COND_GT COND_GT - { - $$ = comp_lowcomp; - } - ; - -comp_op_s: - /* common functions */ - COND_EQ - { - $$ = comp_eq_s; - } - | COND_LT COND_GT - { - $$ = comp_ne_s; - } - | COND_LT - { - $$ = comp_lt_s; - } - | COND_GT - { - $$ = comp_gt_s; - } - | COND_LT COND_EQ - { - $$ = comp_le_s; - } - | COND_GT COND_EQ - { - $$ = comp_ge_s; - } - /*string only*/ - | COND_GT COND_LT - { - $$ = comp_substring; - } - | COND_LT COND_LT - { - $$ = comp_start; - } - | COND_GT COND_GT - { - $$ = comp_end; - } - ; - -comp_op_m1: - /* common functions */ - COND_EQ - { - $$ = comp_eq_m1; - } - | COND_LT COND_GT - { - $$ = comp_ne_m1; - } - | COND_LT - { - $$ = comp_lt_m1; - } - | COND_GT - { - $$ = comp_gt_m1; - } - | COND_LT COND_EQ - { - $$ = comp_le_m1; - } - | COND_GT COND_EQ - { - $$ = comp_ge_m1; - } - /*Not valid for mixed compares*/ - | COND_GT COND_LT - { - $$ = 0; - } - | COND_LT COND_LT - { - $$ = 0; - } - | COND_GT COND_GT - { - $$ = 0; - } - ; - -comp_op_m2: - /* common functions */ - COND_EQ - { - $$ = comp_eq_m2; - } - | COND_LT COND_GT - { - $$ = comp_ne_m2; - } - | COND_LT - { - $$ = comp_lt_m2; - } - | COND_GT - { - $$ = comp_gt_m2; - } - | COND_LT COND_EQ - { - $$ = comp_le_m2; - } - | COND_GT COND_EQ - { - $$ = comp_ge_m2; - } - /*Not valid for mixed compares*/ - | COND_GT COND_LT - { - $$ = 0; - } - | COND_LT COND_LT - { - $$ = 0; - } - | COND_GT COND_GT - { - $$ = 0; - } - ; - -value_i: - symbol_i - { - $$ = $1; - } - | integer - { - $$ = $1; - } + COND_EQ { $$ = COND_EQ } + | COND_NE { $$ = COND_NE } + | COND_LT { $$ = COND_LT } + | COND_GT { $$ = COND_GT } + | COND_LE { $$ = COND_LE } + | COND_GE { $$ = COND_GE } + | COND_SS { $$ = COND_SS } + | COND_IEQ { $$ = COND_IEQ } + | COND_INE { $$ = COND_INE } + | COND_ILT { $$ = COND_ILT } + | COND_IGT { $$ = COND_IGT } + | COND_ILE { $$ = COND_ILE } + | COND_IGE { $$ = COND_IGE } + | COND_ISS { $$ = COND_ISS } + | COND_LHS { $$ = COND_LHS } + | COND_RHS { $$ = COND_RHS } + | COND_ILHS { $$ = COND_ILHS } + | COND_IRHS { $$ = COND_IRHS } ; value_s: - symbol_s + symbol_s { $$ = $1; } @@ -416,8 +247,12 @@ literal: } ; -symbol_i: - COND_DOLLARS identifier +value_i: + integer + { + $$ = $1; + } + | COND_DOLLARS identifier { COND_input* cond = (COND_input*) info; INSTALLSTATE install = INSTALLSTATE_UNKNOWN, action = INSTALLSTATE_UNKNOWN; @@ -458,35 +293,19 @@ symbol_i: symbol_s: identifier { - DWORD sz; COND_input* cond = (COND_input*) info; - sz = 0; - MSI_GetPropertyW(cond->package, $1, NULL, &sz); - if (sz == 0) - { - $$ = msi_alloc( sizeof(WCHAR)); - $$[0] = 0; - } - else - { - sz ++; - $$ = msi_alloc( sz*sizeof (WCHAR) ); - - /* Lookup the identifier */ - - MSI_GetPropertyW(cond->package,$1,$$,&sz); - } + $$ = msi_dup_property( cond->package, $1 ); msi_free( $1 ); } | COND_PERCENT identifier { UINT len = GetEnvironmentVariableW( $2, NULL, 0 ); - if( len++ ) + $$ = NULL; + if (len++) { $$ = msi_alloc( len*sizeof (WCHAR) ); - if( $$ ) - GetEnvironmentVariableW( $2, $$, len ); + GetEnvironmentVariableW( $2, $$, len ); } msi_free( $2 ); } @@ -527,83 +346,101 @@ static int COND_IsNumber( WCHAR x ) return( (( x >= '0' ) && ( x <= '9' )) || (x =='-') || (x =='.') ); } +static WCHAR *strstriW( const WCHAR *str, const WCHAR *sub ) +{ + LPWSTR strlower, sublower, r; + strlower = CharLowerW( strdupW( str ) ); + sublower = CharLowerW( strdupW( sub ) ); + r = strstrW( strlower, sublower ); + if (r) + r = (LPWSTR)str + (r - strlower); + msi_free( strlower ); + msi_free( sublower ); + return r; +} -/* the mess of comparison functions */ - -static INT comp_lt_i(INT a, INT b) -{ return (a < b); } -static INT comp_gt_i(INT a, INT b) -{ return (a > b); } -static INT comp_le_i(INT a, INT b) -{ return (a <= b); } -static INT comp_ge_i(INT a, INT b) -{ return (a >= b); } -static INT comp_eq_i(INT a, INT b) -{ return (a == b); } -static INT comp_ne_i(INT a, INT b) -{ return (a != b); } -static INT comp_bitand(INT a, INT b) -{ return a & b;} -static INT comp_highcomp(INT a, INT b) -{ return HIWORD(a)==b; } -static INT comp_lowcomp(INT a, INT b) -{ return LOWORD(a)==b; } - -static INT comp_eq_s(LPWSTR a, LPWSTR b, BOOL casless) -{ if (casless) return !strcmpiW(a,b); else return !strcmpW(a,b);} -static INT comp_ne_s(LPWSTR a, LPWSTR b, BOOL casless) -{ if (casless) return strcmpiW(a,b); else return strcmpW(a,b);} -static INT comp_lt_s(LPWSTR a, LPWSTR b, BOOL casless) -{ if (casless) return strcmpiW(a,b)<0; else return strcmpW(a,b)<0;} -static INT comp_gt_s(LPWSTR a, LPWSTR b, BOOL casless) -{ if (casless) return strcmpiW(a,b)>0; else return strcmpW(a,b)>0;} -static INT comp_le_s(LPWSTR a, LPWSTR b, BOOL casless) -{ if (casless) return strcmpiW(a,b)<=0; else return strcmpW(a,b)<=0;} -static INT comp_ge_s(LPWSTR a, LPWSTR b, BOOL casless) -{ if (casless) return strcmpiW(a,b)>=0; else return strcmpW(a,b)>=0;} -static INT comp_substring(LPWSTR a, LPWSTR b, BOOL casless) -/* ERROR NOT WORKING REWRITE */ -{ if (casless) return strstrW(a,b)!=NULL; else return strstrW(a,b)!=NULL;} -static INT comp_start(LPWSTR a, LPWSTR b, BOOL casless) -{ if (casless) return strncmpiW(a,b,strlenW(b))==0; - else return strncmpW(a,b,strlenW(b))==0;} -static INT comp_end(LPWSTR a, LPWSTR b, BOOL casless) -{ - int i = strlenW(a); - int j = strlenW(b); - if (j>i) +static INT compare_string( LPCWSTR a, INT operator, LPCWSTR b ) +{ + /* a or b may be NULL */ + switch (operator) + { + case COND_LT: + return -1 == lstrcmpW( a, b ); + case COND_GT: + return 1 == lstrcmpW( a, b ); + case COND_EQ: + return 0 == lstrcmpW( a, b ); + case COND_NE: + return 0 != lstrcmpW( a, b ); + case COND_GE: + return -1 != lstrcmpW( a, b ); + case COND_LE: + return 1 != lstrcmpW( a, b ); + case COND_SS: /* substring */ + return ( a && b && strstrW( a, b ) ) ? 1 : 0; + case COND_ILT: + return -1 == lstrcmpiW( a, b ); + case COND_IGT: + return 1 == lstrcmpiW( a, b ); + case COND_IEQ: + return 0 == lstrcmpiW( a, b ); + case COND_INE: + return 0 != lstrcmpiW( a, b ); + case COND_IGE: + return -1 != lstrcmpiW( a, b ); + case COND_ILE: + return 1 != lstrcmpiW( a, b ); + case COND_ISS: + return ( a && b && strstriW( a, b ) ) ? 1 : 0; + case COND_LHS: + case COND_RHS: + case COND_ILHS: + case COND_IRHS: + ERR("unimplemented string comparison\n"); + break; + default: + ERR("invalid integer operator\n"); return 0; - if (casless) return (!strcmpiW(&a[i-j-1],b)); - else return (!strcmpW(&a[i-j-1],b)); + } + return 0; } -static INT comp_eq_m1(LPWSTR a, INT b) -{ if (COND_IsNumber(a[0])) return atoiW(a)==b; else return 0;} -static INT comp_ne_m1(LPWSTR a, INT b) -{ if (COND_IsNumber(a[0])) return atoiW(a)!=b; else return 1;} -static INT comp_lt_m1(LPWSTR a, INT b) -{ if (COND_IsNumber(a[0])) return atoiW(a)b; else return 0;} -static INT comp_le_m1(LPWSTR a, INT b) -{ if (COND_IsNumber(a[0])) return atoiW(a)<=b; else return 0;} -static INT comp_ge_m1(LPWSTR a, INT b) -{ if (COND_IsNumber(a[0])) return atoiW(a)>=b; else return 0;} - -static INT comp_eq_m2(INT a, LPWSTR b) -{ if (COND_IsNumber(b[0])) return a == atoiW(b); else return 0;} -static INT comp_ne_m2(INT a, LPWSTR b) -{ if (COND_IsNumber(b[0])) return a != atoiW(b); else return 1;} -static INT comp_lt_m2(INT a, LPWSTR b) -{ if (COND_IsNumber(b[0])) return a < atoiW(b); else return 0;} -static INT comp_gt_m2(INT a, LPWSTR b) -{ if (COND_IsNumber(b[0])) return a > atoiW(b); else return 0;} -static INT comp_le_m2(INT a, LPWSTR b) -{ if (COND_IsNumber(b[0])) return a <= atoiW(b); else return 0;} -static INT comp_ge_m2(INT a, LPWSTR b) -{ if (COND_IsNumber(b[0])) return a >= atoiW(b); else return 0;} - +static INT compare_int( INT a, INT operator, INT b ) +{ + switch (operator) + { + case COND_LT: + case COND_ILT: + return a < b; + case COND_GT: + case COND_IGT: + return a > b; + case COND_EQ: + case COND_IEQ: + return a == b; + case COND_NE: + case COND_INE: + return a != b; + case COND_GE: + case COND_IGE: + return a >= b; + case COND_LE: + case COND_ILE: + return a >= b; + case COND_SS: + case COND_ISS: + return ( a & b ) ? 1 : 0; + case COND_RHS: + return ( ( a & 0xffff ) == b ) ? 1 : 0; + case COND_LHS: + return ( ( (a>>16) & 0xffff ) == b ) ? 1 : 0; + default: + ERR("invalid integer operator\n"); + return 0; + } + return 0; +} static int COND_IsIdent( WCHAR x ) @@ -612,17 +449,54 @@ static int COND_IsIdent( WCHAR x ) || ( x == '#' ) || (x == '.') ); } +static int COND_GetOperator( COND_input *cond ) +{ + static const struct { + const WCHAR str[4]; + int id; + } table[] = { + { {'~','=',0}, COND_IEQ }, + { {'~','>','=',0}, COND_ILE }, + { {'~','>','<',0}, COND_ISS }, + { {'~','>','>',0}, COND_IRHS }, + { {'~','>',0}, COND_ILT }, + { {'~','<','>',0}, COND_INE }, + { {'~','<','=',0}, COND_IGE }, + { {'~','<','<',0}, COND_ILHS }, + { {'~','<',0}, COND_IGT }, + { {'>','=',0}, COND_GE }, + { {'>','<',0}, COND_SS }, + { {'>','>',0}, COND_LHS }, + { {'>',0}, COND_GT }, + { {'<','>',0}, COND_NE }, + { {'<','=',0}, COND_LE }, + { {'<','<',0}, COND_RHS }, + { {'<',0}, COND_LT }, + { {0}, 0 } + }; + LPCWSTR p = &cond->str[cond->n]; + int i = 0, len; + + while ( 1 ) + { + len = lstrlenW( table[i].str ); + if ( !len || 0 == strncmpW( table[i].str, p, len ) ) + break; + i++; + } + cond->n += len; + return table[i].id; +} + static int COND_GetOne( struct cond_str *str, COND_input *cond ) { - static const WCHAR szNot[] = {'N','O','T',0}; - static const WCHAR szAnd[] = {'A','N','D',0}; - static const WCHAR szOr[] = {'O','R',0}; - WCHAR ch; int rc, len = 1; + WCHAR ch; str->data = &cond->str[cond->n]; ch = str->data[0]; + switch( ch ) { case 0: return 0; @@ -635,58 +509,73 @@ static int COND_GetOne( struct cond_str *str, COND_input *cond ) case '%': rc = COND_PERCENT; break; case ' ': rc = COND_SPACE; break; case '=': rc = COND_EQ; break; - case '~': rc = COND_TILDA; break; - case '<': rc = COND_LT; break; - case '>': rc = COND_GT; break; - case '"': - { - const WCHAR *ch2 = str->data + 1; - - - while ( *ch2 && *ch2 != '"' ) - ++ch2; - if (*ch2 == '"') - { - len = ch2 - str->data + 1; - rc = COND_LITER; - break; - } - } - ERR("Unterminated string\n"); - rc = COND_ERROR; - break; - default: - if( COND_IsAlpha( ch ) ) - { - while( COND_IsIdent( str->data[len] ) ) - len++; - rc = COND_IDENT; - break; - } - - if( COND_IsNumber( ch ) ) - { - while( COND_IsNumber( str->data[len] ) ) - len++; - rc = COND_NUMBER; - break; - } - - ERR("Got unknown character %c(%x)\n",ch,ch); - rc = COND_ERROR; break; + + case '~': + case '<': + case '>': + rc = COND_GetOperator( cond ); + if (!rc) + rc = COND_ERROR; + return rc; + default: + rc = 0; } - /* keyword identifiers */ - if( rc == COND_IDENT ) + if ( rc ) { - if( (len==3) && (strncmpiW(str->data,szNot,len)==0) ) - rc = COND_NOT; - else if( (len==3) && (strncmpiW(str->data,szAnd,len)==0) ) - rc = COND_AND; - else if( (len==2) && (strncmpiW(str->data,szOr,len)==0) ) + cond->n += len; + return rc; + } + + if (ch == '"' ) + { + LPCWSTR p = strchrW( str->data + 1, '"' ); + if (!p) + return COND_ERROR; + len = p - str->data + 1; + rc = COND_LITER; + } + else if( COND_IsAlpha( ch ) ) + { + static const WCHAR szNot[] = {'N','O','T',0}; + static const WCHAR szAnd[] = {'A','N','D',0}; + static const WCHAR szXor[] = {'X','O','R',0}; + static const WCHAR szEqv[] = {'E','Q','V',0}; + static const WCHAR szImp[] = {'I','M','P',0}; + static const WCHAR szOr[] = {'O','R',0}; + + while( COND_IsIdent( str->data[len] ) ) + len++; + rc = COND_IDENT; + + if ( len == 3 ) + { + if ( !strncmpiW( str->data, szNot, len ) ) + rc = COND_NOT; + else if( !strncmpiW( str->data, szAnd, len ) ) + rc = COND_AND; + else if( !strncmpiW( str->data, szXor, len ) ) + rc = COND_XOR; + else if( !strncmpiW( str->data, szEqv, len ) ) + rc = COND_EQV; + else if( !strncmpiW( str->data, szImp, len ) ) + rc = COND_IMP; + } + else if( (len == 2) && !strncmpiW( str->data, szOr, len ) ) rc = COND_OR; } + else if( COND_IsNumber( ch ) ) + { + while( COND_IsNumber( str->data[len] ) ) + len++; + rc = COND_NUMBER; + } + else + { + ERR("Got unknown character %c(%x)\n",ch,ch); + return COND_ERROR; + } cond->n += len; str->len = len; @@ -745,6 +634,8 @@ MSICONDITION MSI_EvaluateConditionW( MSIPACKAGE *package, LPCWSTR szCondition ) COND_input cond; MSICONDITION r; + TRACE("%s\n", debugstr_w( szCondition ) ); + if ( szCondition == NULL ) return MSICONDITION_NONE; @@ -753,14 +644,12 @@ MSICONDITION MSI_EvaluateConditionW( MSIPACKAGE *package, LPCWSTR szCondition ) cond.n = 0; cond.result = MSICONDITION_ERROR; - TRACE("Evaluating %s\n",debugstr_w(szCondition)); - if ( !COND_parse( &cond ) ) r = cond.result; else r = MSICONDITION_ERROR; - TRACE("Evaluates to %i\n",r); + TRACE("%i <- %s\n", r, debugstr_w(szCondition)); return r; } diff --git a/dlls/msi/tests/package.c b/dlls/msi/tests/package.c index ea92a2147c3..d10e45d7806 100644 --- a/dlls/msi/tests/package.c +++ b/dlls/msi/tests/package.c @@ -326,6 +326,247 @@ static void test_gettargetpath_bad(void) MsiCloseHandle( hpkg ); } +void test_condition(void) +{ + MSICONDITION r; + MSIHANDLE hpkg; + + hpkg = package_from_db(create_package_db()); + ok( hpkg, "failed to create package\n"); + + r = MsiEvaluateCondition(0, NULL); + ok( r == MSICONDITION_ERROR, "wrong return val\n"); + + r = MsiEvaluateCondition(hpkg, NULL); + ok( r == MSICONDITION_NONE, "wrong return val\n"); + + r = MsiEvaluateCondition(hpkg, ""); + ok( r == MSICONDITION_NONE, "wrong return val\n"); + + r = MsiEvaluateCondition(hpkg, "1"); + ok( r == MSICONDITION_TRUE, "wrong return val\n"); + + r = MsiEvaluateCondition(hpkg, "0"); + ok( r == MSICONDITION_FALSE, "wrong return val\n"); + + r = MsiEvaluateCondition(hpkg, "0 = 0"); + ok( r == MSICONDITION_TRUE, "wrong return val\n"); + + r = MsiEvaluateCondition(hpkg, "0 <> 0"); + ok( r == MSICONDITION_FALSE, "wrong return val\n"); + + r = MsiEvaluateCondition(hpkg, "0 = 1"); + ok( r == MSICONDITION_FALSE, "wrong return val\n"); + + r = MsiEvaluateCondition(hpkg, "0 >= 1"); + ok( r == MSICONDITION_FALSE, "wrong return val\n"); + + r = MsiEvaluateCondition(hpkg, "0 >="); + ok( r == MSICONDITION_ERROR, "wrong return val\n"); + + r = MsiEvaluateCondition(hpkg, " "); + ok( r == MSICONDITION_NONE, "wrong return val\n"); + + r = MsiEvaluateCondition(hpkg, "LicView <> \"1\""); + ok( r == MSICONDITION_TRUE, "wrong return val\n"); + + r = MsiEvaluateCondition(hpkg, "LicView <> \"0\""); + ok( r == MSICONDITION_TRUE, "wrong return val\n"); + + r = MsiEvaluateCondition(hpkg, "LicView <> LicView"); + ok( r == MSICONDITION_FALSE, "wrong return val\n"); + + r = MsiEvaluateCondition(hpkg, "not 0"); + ok( r == MSICONDITION_TRUE, "wrong return val\n"); + + r = MsiEvaluateCondition(hpkg, "not LicView"); + ok( r == MSICONDITION_TRUE, "wrong return val\n"); + + r = MsiEvaluateCondition(hpkg, "not \"A\""); + ok( r == MSICONDITION_FALSE, "wrong return val\n"); + + r = MsiEvaluateCondition(hpkg, "~not \"A\""); + ok( r == MSICONDITION_ERROR, "wrong return val\n"); + + r = MsiEvaluateCondition(hpkg, "\"0\""); + ok( r == MSICONDITION_TRUE, "wrong return val\n"); + + r = MsiEvaluateCondition(hpkg, "1 and 2"); + ok( r == MSICONDITION_TRUE, "wrong return val\n"); + + r = MsiEvaluateCondition(hpkg, "not 0 and 3"); + ok( r == MSICONDITION_TRUE, "wrong return val\n"); + + r = MsiEvaluateCondition(hpkg, "not 0 and 0"); + ok( r == MSICONDITION_FALSE, "wrong return val\n"); + + r = MsiEvaluateCondition(hpkg, "not 0 or 1"); + ok( r == MSICONDITION_TRUE, "wrong return val\n"); + + r = MsiEvaluateCondition(hpkg, "(0)"); + ok( r == MSICONDITION_FALSE, "wrong return val\n"); + + r = MsiEvaluateCondition(hpkg, "(((((1))))))"); + ok( r == MSICONDITION_ERROR, "wrong return val\n"); + + r = MsiEvaluateCondition(hpkg, "(((((1)))))"); + ok( r == MSICONDITION_TRUE, "wrong return val\n"); + + r = MsiEvaluateCondition(hpkg, " \"A\" < \"B\" "); + ok( r == MSICONDITION_TRUE, "wrong return val\n"); + + r = MsiEvaluateCondition(hpkg, " \"A\" > \"B\" "); + ok( r == MSICONDITION_FALSE, "wrong return val\n"); + + r = MsiEvaluateCondition(hpkg, " \"1\" > \"12\" "); + ok( r == MSICONDITION_FALSE, "wrong return val\n"); + + r = MsiEvaluateCondition(hpkg, " \"100\" < \"21\" "); + ok( r == MSICONDITION_TRUE, "wrong return val\n"); + + r = MsiEvaluateCondition(hpkg, "0 < > 0"); + ok( r == MSICONDITION_ERROR, "wrong return val\n"); + + r = MsiEvaluateCondition(hpkg, "(1<<1) == 2"); + ok( r == MSICONDITION_ERROR, "wrong return val\n"); + + r = MsiEvaluateCondition(hpkg, " \"A\" = \"a\" "); + ok( r == MSICONDITION_FALSE, "wrong return val\n"); + + r = MsiEvaluateCondition(hpkg, " \"A\" ~ = \"a\" "); + ok( r == MSICONDITION_ERROR, "wrong return val\n"); + + r = MsiEvaluateCondition(hpkg, " \"A\" ~= \"a\" "); + ok( r == MSICONDITION_TRUE, "wrong return val\n"); + + r = MsiEvaluateCondition(hpkg, " \"A\" ~= 1 "); + ok( r == MSICONDITION_FALSE, "wrong return val\n"); + + r = MsiEvaluateCondition(hpkg, " \"A\" = 1 "); + ok( r == MSICONDITION_FALSE, "wrong return val\n"); + + r = MsiEvaluateCondition(hpkg, " 1 ~= 1 "); + ok( r == MSICONDITION_TRUE, "wrong return val\n"); + + r = MsiEvaluateCondition(hpkg, " 1 ~= \"1\" "); + ok( r == MSICONDITION_FALSE, "wrong return val\n"); + + r = MsiEvaluateCondition(hpkg, " 1 = \"1\" "); + ok( r == MSICONDITION_FALSE, "wrong return val\n"); + + r = MsiEvaluateCondition(hpkg, " 0 = \"1\" "); + ok( r == MSICONDITION_FALSE, "wrong return val\n"); + + r = MsiEvaluateCondition(hpkg, " 0 < \"100\" "); + ok( r == MSICONDITION_FALSE, "wrong return val\n"); + + r = MsiEvaluateCondition(hpkg, " 100 > \"0\" "); + ok( r == MSICONDITION_FALSE, "wrong return val\n"); + + r = MsiEvaluateCondition(hpkg, "1 XOR 1"); + ok( r == MSICONDITION_FALSE, "wrong return val\n"); + + r = MsiEvaluateCondition(hpkg, "1 IMP 1"); + ok( r == MSICONDITION_TRUE, "wrong return val\n"); + + r = MsiEvaluateCondition(hpkg, "1 IMP 0"); + ok( r == MSICONDITION_FALSE, "wrong return val\n"); + + r = MsiEvaluateCondition(hpkg, "0 IMP 0"); + ok( r == MSICONDITION_TRUE, "wrong return val\n"); + + r = MsiEvaluateCondition(hpkg, "0 EQV 0"); + ok( r == MSICONDITION_TRUE, "wrong return val\n"); + + r = MsiEvaluateCondition(hpkg, "0 EQV 1"); + ok( r == MSICONDITION_FALSE, "wrong return val\n"); + + r = MsiEvaluateCondition(hpkg, "1 IMP 1 OR 0"); + ok( r == MSICONDITION_TRUE, "wrong return val\n"); + + r = MsiEvaluateCondition(hpkg, "1 IMPL 1"); + ok( r == MSICONDITION_ERROR, "wrong return val\n"); + + r = MsiEvaluateCondition(hpkg, "\"ASFD\" >< \"S\" "); + ok( r == MSICONDITION_TRUE, "wrong return val\n"); + + r = MsiEvaluateCondition(hpkg, "\"ASFD\" ~>< \"s\" "); + ok( r == MSICONDITION_TRUE, "wrong return val\n"); + + r = MsiEvaluateCondition(hpkg, "\"ASFD\" ~>< \"\" "); + ok( r == MSICONDITION_TRUE, "wrong return val\n"); + + r = MsiEvaluateCondition(hpkg, "\"ASFD\" ~>< \"sss\" "); + ok( r == MSICONDITION_FALSE, "wrong return val\n"); + + MsiSetProperty(hpkg, "mm", "5" ); + + r = MsiEvaluateCondition(hpkg, "mm = 5"); + ok( r == MSICONDITION_TRUE, "wrong return val\n"); + + r = MsiEvaluateCondition(hpkg, "mm < 6"); + ok( r == MSICONDITION_TRUE, "wrong return val\n"); + + r = MsiEvaluateCondition(hpkg, "mm <= 5"); + ok( r == MSICONDITION_TRUE, "wrong return val\n"); + + r = MsiEvaluateCondition(hpkg, "mm > 4"); + ok( r == MSICONDITION_TRUE, "wrong return val\n"); + + r = MsiEvaluateCondition(hpkg, "mm < 12"); + ok( r == MSICONDITION_TRUE, "wrong return val\n"); + + r = MsiEvaluateCondition(hpkg, "mm = \"5\""); + ok( r == MSICONDITION_TRUE, "wrong return val\n"); + + r = MsiEvaluateCondition(hpkg, "0 = \"\""); + ok( r == MSICONDITION_FALSE, "wrong return val\n"); + + r = MsiEvaluateCondition(hpkg, "0 AND \"\""); + ok( r == MSICONDITION_FALSE, "wrong return val\n"); + + r = MsiEvaluateCondition(hpkg, "1 AND \"\""); + ok( r == MSICONDITION_FALSE, "wrong return val\n"); + + r = MsiEvaluateCondition(hpkg, "1 AND \"1\""); + ok( r == MSICONDITION_TRUE, "wrong return val\n"); + + r = MsiEvaluateCondition(hpkg, "3 >< 1"); + ok( r == MSICONDITION_TRUE, "wrong return val\n"); + + r = MsiEvaluateCondition(hpkg, "3 >< 4"); + ok( r == MSICONDITION_FALSE, "wrong return val\n"); + + r = MsiEvaluateCondition(hpkg, "NOT 0 AND 0"); + ok( r == MSICONDITION_FALSE, "wrong return val\n"); + + r = MsiEvaluateCondition(hpkg, "NOT 0 AND 1"); + ok( r == MSICONDITION_TRUE, "wrong return val\n"); + + r = MsiEvaluateCondition(hpkg, "NOT 1 OR 0"); + ok( r == MSICONDITION_FALSE, "wrong return val\n"); + + r = MsiEvaluateCondition(hpkg, "0 AND 1 OR 1"); + ok( r == MSICONDITION_TRUE, "wrong return val\n"); + + r = MsiEvaluateCondition(hpkg, "0 AND 0 OR 1"); + ok( r == MSICONDITION_TRUE, "wrong return val\n"); + + r = MsiEvaluateCondition(hpkg, "NOT 0 AND 1 OR 0"); + ok( r == MSICONDITION_TRUE, "wrong return val\n"); + + r = MsiEvaluateCondition(hpkg, "_1 = _1"); + ok( r == MSICONDITION_TRUE, "wrong return val\n"); + + r = MsiEvaluateCondition(hpkg, "( 1 AND 1 ) = 2"); + ok( r == MSICONDITION_ERROR, "wrong return val\n"); + + r = MsiEvaluateCondition(hpkg, "NOT ( 1 AND 1 )"); + ok( r == MSICONDITION_FALSE, "wrong return val\n"); + + MsiCloseHandle( hpkg ); +} + START_TEST(package) { test_createpackage();