1 %{ 2 3 /* 4 * Implementation of the Microsoft Installer (msi.dll) 5 * 6 * Copyright 2003 Mike McCormack for CodeWeavers 7 * 8 * This library is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU Lesser General Public 10 * License as published by the Free Software Foundation; either 11 * version 2.1 of the License, or (at your option) any later version. 12 * 13 * This library is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 * Lesser General Public License for more details. 17 * 18 * You should have received a copy of the GNU Lesser General Public 19 * License along with this library; if not, write to the Free Software 20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 21 */ 22 23 #define COBJMACROS 24 25 #include <stdarg.h> 26 #include <stdio.h> 27 #include <stdlib.h> 28 29 #include "windef.h" 30 #include "winbase.h" 31 #include "winuser.h" 32 #include "msi.h" 33 #include "msiquery.h" 34 #include "objbase.h" 35 #include "oleauto.h" 36 37 #include "msipriv.h" 38 #include "winemsi_s.h" 39 #include "wine/debug.h" 40 #include "wine/exception.h" 41 #include "wine/unicode.h" 42 #include "wine/list.h" 43 44 WINE_DEFAULT_DEBUG_CHANNEL(msi); 45 46 typedef struct tag_yyinput 47 { 48 MSIPACKAGE *package; 49 LPCWSTR str; 50 INT n; 51 MSICONDITION result; 52 struct list mem; 53 } COND_input; 54 55 struct cond_str { 56 LPCWSTR data; 57 INT len; 58 }; 59 60 struct value { 61 enum value_type { 62 VALUE_INTEGER, 63 VALUE_LITERAL, 64 VALUE_SYMBOL 65 } type; 66 union { 67 INT integer; 68 WCHAR *string; 69 } u; 70 }; 71 72 static LPWSTR COND_GetString( COND_input *info, const struct cond_str *str ); 73 static LPWSTR COND_GetLiteral( COND_input *info, const struct cond_str *str ); 74 static int cond_lex( void *COND_lval, COND_input *info); 75 static int cond_error( COND_input *info, const char *str); 76 77 static void *cond_alloc( COND_input *cond, unsigned int sz ); 78 static void *cond_track_mem( COND_input *cond, void *ptr, unsigned int sz ); 79 static void cond_free( void *ptr ); 80 81 static INT compare_int( INT a, INT operator, INT b ); 82 static INT compare_string( LPCWSTR a, INT operator, LPCWSTR b, BOOL convert ); 83 84 static BOOL num_from_prop( LPCWSTR p, INT *val ) 85 { 86 INT ret = 0, sign = 1; 87 88 if (!p) 89 return FALSE; 90 if (*p == '-') 91 { 92 sign = -1; 93 p++; 94 } 95 if (!*p) 96 return FALSE; 97 while (*p) 98 { 99 if( *p < '0' || *p > '9' ) 100 return FALSE; 101 ret = ret*10 + (*p - '0'); 102 p++; 103 } 104 *val = ret*sign; 105 return TRUE; 106 } 107 108 static void value_free( struct value val ) 109 { 110 if (val.type != VALUE_INTEGER) 111 cond_free( val.u.string ); 112 } 113 114 %} 115 116 %lex-param { COND_input *info } 117 %parse-param { COND_input *info } 118 %define api.prefix {cond_} 119 %define api.pure 120 121 %union 122 { 123 struct cond_str str; 124 struct value value; 125 LPWSTR identifier; 126 INT operator; 127 BOOL bool; 128 } 129 130 %token COND_SPACE 131 %token COND_OR COND_AND COND_NOT COND_XOR COND_IMP COND_EQV 132 %token COND_LT COND_GT COND_EQ COND_NE COND_GE COND_LE 133 %token COND_ILT COND_IGT COND_IEQ COND_INE COND_IGE COND_ILE 134 %token COND_LPAR COND_RPAR COND_TILDA COND_SS COND_ISS 135 %token COND_ILHS COND_IRHS COND_LHS COND_RHS 136 %token COND_PERCENT COND_DOLLARS COND_QUESTION COND_AMPER COND_EXCLAM 137 %token <str> COND_IDENT <str> COND_NUMBER <str> COND_LITER 138 139 %nonassoc COND_ERROR 140 141 %type <bool> expression boolean_term boolean_factor 142 %type <value> value 143 %type <identifier> identifier 144 %type <operator> operator 145 146 %% 147 148 condition: 149 expression 150 { 151 COND_input* cond = (COND_input*) info; 152 cond->result = $1; 153 } 154 | /* empty */ 155 { 156 COND_input* cond = (COND_input*) info; 157 cond->result = MSICONDITION_NONE; 158 } 159 ; 160 161 expression: 162 boolean_term 163 { 164 $$ = $1; 165 } 166 | expression COND_OR boolean_term 167 { 168 $$ = $1 || $3; 169 } 170 | expression COND_IMP boolean_term 171 { 172 $$ = !$1 || $3; 173 } 174 | expression COND_XOR boolean_term 175 { 176 $$ = ( $1 || $3 ) && !( $1 && $3 ); 177 } 178 | expression COND_EQV boolean_term 179 { 180 $$ = ( $1 && $3 ) || ( !$1 && !$3 ); 181 } 182 ; 183 184 boolean_term: 185 boolean_factor 186 { 187 $$ = $1; 188 } 189 | boolean_term COND_AND boolean_factor 190 { 191 $$ = $1 && $3; 192 } 193 ; 194 195 boolean_factor: 196 COND_NOT boolean_factor 197 { 198 $$ = !$2; 199 } 200 | value 201 { 202 if ($1.type == VALUE_INTEGER) 203 $$ = $1.u.integer ? 1 : 0; 204 else 205 $$ = $1.u.string && $1.u.string[0]; 206 value_free( $1 ); 207 } 208 | value operator value 209 { 210 if ($1.type == VALUE_INTEGER && $3.type == VALUE_INTEGER) 211 { 212 $$ = compare_int($1.u.integer, $2, $3.u.integer); 213 } 214 else if ($1.type != VALUE_INTEGER && $3.type != VALUE_INTEGER) 215 { 216 $$ = compare_string($1.u.string, $2, $3.u.string, 217 $1.type == VALUE_SYMBOL || $3.type == VALUE_SYMBOL); 218 } 219 else if ($1.type == VALUE_LITERAL || $3.type == VALUE_LITERAL) 220 { 221 $$ = ($2 == COND_NE || $2 == COND_INE ); 222 } 223 else if ($1.type == VALUE_SYMBOL) /* symbol operator integer */ 224 { 225 int num; 226 if (num_from_prop( $1.u.string, &num )) 227 $$ = compare_int( num, $2, $3.u.integer ); 228 else 229 $$ = ($2 == COND_NE || $2 == COND_INE ); 230 } 231 else /* integer operator symbol */ 232 { 233 int num; 234 if (num_from_prop( $3.u.string, &num )) 235 $$ = compare_int( $1.u.integer, $2, num ); 236 else 237 $$ = ($2 == COND_NE || $2 == COND_INE ); 238 } 239 240 value_free( $1 ); 241 value_free( $3 ); 242 } 243 | COND_LPAR expression COND_RPAR 244 { 245 $$ = $2; 246 } 247 ; 248 249 operator: 250 /* common functions */ 251 COND_EQ { $$ = COND_EQ; } 252 | COND_NE { $$ = COND_NE; } 253 | COND_LT { $$ = COND_LT; } 254 | COND_GT { $$ = COND_GT; } 255 | COND_LE { $$ = COND_LE; } 256 | COND_GE { $$ = COND_GE; } 257 | COND_SS { $$ = COND_SS; } 258 | COND_IEQ { $$ = COND_IEQ; } 259 | COND_INE { $$ = COND_INE; } 260 | COND_ILT { $$ = COND_ILT; } 261 | COND_IGT { $$ = COND_IGT; } 262 | COND_ILE { $$ = COND_ILE; } 263 | COND_IGE { $$ = COND_IGE; } 264 | COND_ISS { $$ = COND_ISS; } 265 | COND_LHS { $$ = COND_LHS; } 266 | COND_RHS { $$ = COND_RHS; } 267 | COND_ILHS { $$ = COND_ILHS; } 268 | COND_IRHS { $$ = COND_IRHS; } 269 ; 270 271 value: 272 identifier 273 { 274 COND_input* cond = (COND_input*) info; 275 UINT len; 276 277 $$.type = VALUE_SYMBOL; 278 $$.u.string = msi_dup_property( cond->package->db, $1 ); 279 if ($$.u.string) 280 { 281 len = (lstrlenW($$.u.string) + 1) * sizeof (WCHAR); 282 $$.u.string = cond_track_mem( cond, $$.u.string, len ); 283 } 284 cond_free( $1 ); 285 } 286 | COND_PERCENT identifier 287 { 288 COND_input* cond = (COND_input*) info; 289 UINT len = GetEnvironmentVariableW( $2, NULL, 0 ); 290 $$.type = VALUE_SYMBOL; 291 $$.u.string = NULL; 292 if (len++) 293 { 294 $$.u.string = cond_alloc( cond, len*sizeof (WCHAR) ); 295 if( !$$.u.string ) 296 YYABORT; 297 GetEnvironmentVariableW( $2, $$.u.string, len ); 298 } 299 cond_free( $2 ); 300 } 301 | COND_LITER 302 { 303 COND_input* cond = (COND_input*) info; 304 $$.type = VALUE_LITERAL; 305 $$.u.string = COND_GetLiteral( cond, &$1 ); 306 if( !$$.u.string ) 307 YYABORT; 308 } 309 | COND_NUMBER 310 { 311 COND_input* cond = (COND_input*) info; 312 LPWSTR szNum = COND_GetString( cond, &$1 ); 313 if( !szNum ) 314 YYABORT; 315 $$.type = VALUE_INTEGER; 316 $$.u.integer = wcstol( szNum, NULL, 10 ); 317 cond_free( szNum ); 318 } 319 | COND_DOLLARS identifier 320 { 321 COND_input* cond = (COND_input*) info; 322 INSTALLSTATE install = INSTALLSTATE_UNKNOWN, action = INSTALLSTATE_UNKNOWN; 323 324 if(MSI_GetComponentStateW(cond->package, $2, &install, &action ) != ERROR_SUCCESS) 325 { 326 $$.type = VALUE_LITERAL; 327 $$.u.string = NULL; 328 } 329 else 330 { 331 $$.type = VALUE_INTEGER; 332 $$.u.integer = action; 333 } 334 cond_free( $2 ); 335 } 336 | COND_QUESTION identifier 337 { 338 COND_input* cond = (COND_input*) info; 339 INSTALLSTATE install = INSTALLSTATE_UNKNOWN, action = INSTALLSTATE_UNKNOWN; 340 341 if(MSI_GetComponentStateW(cond->package, $2, &install, &action ) != ERROR_SUCCESS) 342 { 343 $$.type = VALUE_LITERAL; 344 $$.u.string = NULL; 345 } 346 else 347 { 348 $$.type = VALUE_INTEGER; 349 $$.u.integer = install; 350 } 351 cond_free( $2 ); 352 } 353 | COND_AMPER identifier 354 { 355 COND_input* cond = (COND_input*) info; 356 INSTALLSTATE install, action; 357 358 if (MSI_GetFeatureStateW(cond->package, $2, &install, &action ) != ERROR_SUCCESS) 359 { 360 $$.type = VALUE_LITERAL; 361 $$.u.string = NULL; 362 } 363 else 364 { 365 $$.type = VALUE_INTEGER; 366 $$.u.integer = action; 367 } 368 cond_free( $2 ); 369 } 370 | COND_EXCLAM identifier 371 { 372 COND_input* cond = (COND_input*) info; 373 INSTALLSTATE install = INSTALLSTATE_UNKNOWN, action = INSTALLSTATE_UNKNOWN; 374 375 if(MSI_GetFeatureStateW(cond->package, $2, &install, &action ) != ERROR_SUCCESS) 376 { 377 $$.type = VALUE_LITERAL; 378 $$.u.string = NULL; 379 } 380 else 381 { 382 $$.type = VALUE_INTEGER; 383 $$.u.integer = install; 384 } 385 cond_free( $2 ); 386 } 387 ; 388 389 identifier: 390 COND_IDENT 391 { 392 COND_input* cond = (COND_input*) info; 393 $$ = COND_GetString( cond, &$1 ); 394 if( !$$ ) 395 YYABORT; 396 } 397 ; 398 399 %% 400 401 402 static int COND_IsAlpha( WCHAR x ) 403 { 404 return( ( ( x >= 'A' ) && ( x <= 'Z' ) ) || 405 ( ( x >= 'a' ) && ( x <= 'z' ) ) || 406 ( ( x == '_' ) ) ); 407 } 408 409 static int COND_IsNumber( WCHAR x ) 410 { 411 return( (( x >= '0' ) && ( x <= '9' )) || (x =='-') || (x =='.') ); 412 } 413 414 static WCHAR *strstriW( const WCHAR *str, const WCHAR *sub ) 415 { 416 LPWSTR strlower, sublower, r; 417 strlower = CharLowerW( strdupW( str ) ); 418 sublower = CharLowerW( strdupW( sub ) ); 419 r = wcsstr( strlower, sublower ); 420 if (r) 421 r = (LPWSTR)str + (r - strlower); 422 msi_free( strlower ); 423 msi_free( sublower ); 424 return r; 425 } 426 427 static BOOL str_is_number( LPCWSTR str ) 428 { 429 int i; 430 431 if (!*str) 432 return FALSE; 433 434 for (i = 0; i < lstrlenW( str ); i++) 435 if (!iswdigit(str[i])) 436 return FALSE; 437 438 return TRUE; 439 } 440 441 static INT compare_substring( LPCWSTR a, INT operator, LPCWSTR b ) 442 { 443 int lhs, rhs; 444 445 /* substring operators return 0 if LHS is missing */ 446 if (!a || !*a) 447 return 0; 448 449 /* substring operators return 1 if RHS is missing */ 450 if (!b || !*b) 451 return 1; 452 453 /* if both strings contain only numbers, use integer comparison */ 454 lhs = wcstol(a, NULL, 10); 455 rhs = wcstol(b, NULL, 10); 456 if (str_is_number(a) && str_is_number(b)) 457 return compare_int( lhs, operator, rhs ); 458 459 switch (operator) 460 { 461 case COND_SS: 462 return wcsstr( a, b ) != 0; 463 case COND_ISS: 464 return strstriW( a, b ) != 0; 465 case COND_LHS: 466 { 467 int l = lstrlenW( a ); 468 int r = lstrlenW( b ); 469 if (r > l) return 0; 470 return !wcsncmp( a, b, r ); 471 } 472 case COND_RHS: 473 { 474 int l = lstrlenW( a ); 475 int r = lstrlenW( b ); 476 if (r > l) return 0; 477 return !wcsncmp( a + (l - r), b, r ); 478 } 479 case COND_ILHS: 480 { 481 int l = lstrlenW( a ); 482 int r = lstrlenW( b ); 483 if (r > l) return 0; 484 return !wcsnicmp( a, b, r ); 485 } 486 case COND_IRHS: 487 { 488 int l = lstrlenW( a ); 489 int r = lstrlenW( b ); 490 if (r > l) return 0; 491 return !wcsnicmp( a + (l - r), b, r ); 492 } 493 default: 494 ERR("invalid substring operator\n"); 495 return 0; 496 } 497 return 0; 498 } 499 500 static INT compare_string( LPCWSTR a, INT operator, LPCWSTR b, BOOL convert ) 501 { 502 if (operator >= COND_SS && operator <= COND_RHS) 503 return compare_substring( a, operator, b ); 504 505 /* null and empty string are equivalent */ 506 if (!a) a = L""; 507 if (!b) b = L""; 508 509 if (convert && str_is_number(a) && str_is_number(b)) 510 return compare_int( wcstol(a, NULL, 10), operator, wcstol(b, NULL, 10) ); 511 512 /* a or b may be NULL */ 513 switch (operator) 514 { 515 case COND_LT: 516 return wcscmp( a, b ) < 0; 517 case COND_GT: 518 return wcscmp( a, b ) > 0; 519 case COND_EQ: 520 return wcscmp( a, b ) == 0; 521 case COND_NE: 522 return wcscmp( a, b ) != 0; 523 case COND_GE: 524 return wcscmp( a, b ) >= 0; 525 case COND_LE: 526 return wcscmp( a, b ) <= 0; 527 case COND_ILT: 528 return wcsicmp( a, b ) < 0; 529 case COND_IGT: 530 return wcsicmp( a, b ) > 0; 531 case COND_IEQ: 532 return wcsicmp( a, b ) == 0; 533 case COND_INE: 534 return wcsicmp( a, b ) != 0; 535 case COND_IGE: 536 return wcsicmp( a, b ) >= 0; 537 case COND_ILE: 538 return wcsicmp( a, b ) <= 0; 539 default: 540 ERR("invalid string operator\n"); 541 return 0; 542 } 543 return 0; 544 } 545 546 547 static INT compare_int( INT a, INT operator, INT b ) 548 { 549 switch (operator) 550 { 551 case COND_LT: 552 case COND_ILT: 553 return a < b; 554 case COND_GT: 555 case COND_IGT: 556 return a > b; 557 case COND_EQ: 558 case COND_IEQ: 559 return a == b; 560 case COND_NE: 561 case COND_INE: 562 return a != b; 563 case COND_GE: 564 case COND_IGE: 565 return a >= b; 566 case COND_LE: 567 case COND_ILE: 568 return a <= b; 569 case COND_SS: 570 case COND_ISS: 571 return ( a & b ) ? 1 : 0; 572 case COND_RHS: 573 return ( ( a & 0xffff ) == b ) ? 1 : 0; 574 case COND_LHS: 575 return ( ( (a>>16) & 0xffff ) == b ) ? 1 : 0; 576 default: 577 ERR("invalid integer operator\n"); 578 return 0; 579 } 580 return 0; 581 } 582 583 584 static int COND_IsIdent( WCHAR x ) 585 { 586 return( COND_IsAlpha( x ) || COND_IsNumber( x ) || ( x == '_' ) 587 || ( x == '#' ) || (x == '.') ); 588 } 589 590 static int COND_GetOperator( COND_input *cond ) 591 { 592 static const struct { 593 const WCHAR str[4]; 594 int id; 595 } table[] = { 596 { L"~<=", COND_ILE }, 597 { L"~><", COND_ISS }, 598 { L"~>>", COND_IRHS }, 599 { L"~<>", COND_INE }, 600 { L"~>=", COND_IGE }, 601 { L"~<<", COND_ILHS }, 602 { L"~=", COND_IEQ }, 603 { L"~<", COND_ILT }, 604 { L"~>", COND_IGT }, 605 { L">=", COND_GE }, 606 { L"><", COND_SS }, 607 { L"<<", COND_LHS }, 608 { L"<>", COND_NE }, 609 { L"<=", COND_LE }, 610 { L">>", COND_RHS }, 611 { L">", COND_GT }, 612 { L"<", COND_LT }, 613 { L"", 0 } 614 }; 615 LPCWSTR p = &cond->str[cond->n]; 616 int i = 0, len; 617 618 while ( 1 ) 619 { 620 len = lstrlenW( table[i].str ); 621 if ( !len || 0 == wcsncmp( table[i].str, p, len ) ) 622 break; 623 i++; 624 } 625 cond->n += len; 626 return table[i].id; 627 } 628 629 static int COND_GetOne( struct cond_str *str, COND_input *cond ) 630 { 631 int rc, len = 1; 632 WCHAR ch; 633 634 str->data = &cond->str[cond->n]; 635 636 ch = str->data[0]; 637 638 switch( ch ) 639 { 640 case 0: return 0; 641 case '(': rc = COND_LPAR; break; 642 case ')': rc = COND_RPAR; break; 643 case '&': rc = COND_AMPER; break; 644 case '!': rc = COND_EXCLAM; break; 645 case '$': rc = COND_DOLLARS; break; 646 case '?': rc = COND_QUESTION; break; 647 case '%': rc = COND_PERCENT; break; 648 case ' ': rc = COND_SPACE; break; 649 case '=': rc = COND_EQ; break; 650 651 case '~': 652 case '<': 653 case '>': 654 rc = COND_GetOperator( cond ); 655 if (!rc) 656 rc = COND_ERROR; 657 return rc; 658 default: 659 rc = 0; 660 } 661 662 if ( rc ) 663 { 664 cond->n += len; 665 return rc; 666 } 667 668 if (ch == '"' ) 669 { 670 LPCWSTR p = wcschr( str->data + 1, '"' ); 671 if (!p) return COND_ERROR; 672 len = p - str->data + 1; 673 rc = COND_LITER; 674 } 675 else if( COND_IsAlpha( ch ) ) 676 { 677 while( COND_IsIdent( str->data[len] ) ) 678 len++; 679 rc = COND_IDENT; 680 681 if ( len == 3 ) 682 { 683 if ( !wcsnicmp( str->data, L"NOT", len ) ) 684 rc = COND_NOT; 685 else if( !wcsnicmp( str->data, L"AND", len ) ) 686 rc = COND_AND; 687 else if( !wcsnicmp( str->data, L"XOR", len ) ) 688 rc = COND_XOR; 689 else if( !wcsnicmp( str->data, L"EQV", len ) ) 690 rc = COND_EQV; 691 else if( !wcsnicmp( str->data, L"IMP", len ) ) 692 rc = COND_IMP; 693 } 694 else if( (len == 2) && !wcsnicmp( str->data, L"OR", len ) ) 695 rc = COND_OR; 696 } 697 else if( COND_IsNumber( ch ) ) 698 { 699 while( COND_IsNumber( str->data[len] ) ) 700 len++; 701 rc = COND_NUMBER; 702 } 703 else 704 { 705 ERR("Got unknown character %c(%x)\n",ch,ch); 706 return COND_ERROR; 707 } 708 709 cond->n += len; 710 str->len = len; 711 712 return rc; 713 } 714 715 static int cond_lex( void *COND_lval, COND_input *cond ) 716 { 717 int rc; 718 struct cond_str *str = COND_lval; 719 720 do { 721 rc = COND_GetOne( str, cond ); 722 } while (rc == COND_SPACE); 723 724 return rc; 725 } 726 727 static LPWSTR COND_GetString( COND_input *cond, const struct cond_str *str ) 728 { 729 LPWSTR ret; 730 731 ret = cond_alloc( cond, (str->len+1) * sizeof (WCHAR) ); 732 if( ret ) 733 { 734 memcpy( ret, str->data, str->len * sizeof(WCHAR)); 735 ret[str->len]=0; 736 } 737 TRACE("Got identifier %s\n",debugstr_w(ret)); 738 return ret; 739 } 740 741 static LPWSTR COND_GetLiteral( COND_input *cond, const struct cond_str *str ) 742 { 743 LPWSTR ret; 744 745 ret = cond_alloc( cond, (str->len-1) * sizeof (WCHAR) ); 746 if( ret ) 747 { 748 memcpy( ret, str->data+1, (str->len-2) * sizeof(WCHAR) ); 749 ret[str->len - 2]=0; 750 } 751 TRACE("Got literal %s\n",debugstr_w(ret)); 752 return ret; 753 } 754 755 static void *cond_alloc( COND_input *cond, unsigned int sz ) 756 { 757 struct list *mem; 758 759 mem = msi_alloc( sizeof (struct list) + sz ); 760 if( !mem ) 761 return NULL; 762 763 list_add_head( &(cond->mem), mem ); 764 return mem + 1; 765 } 766 767 static void *cond_track_mem( COND_input *cond, void *ptr, unsigned int sz ) 768 { 769 void *new_ptr; 770 771 if( !ptr ) 772 return ptr; 773 774 new_ptr = cond_alloc( cond, sz ); 775 if( !new_ptr ) 776 { 777 msi_free( ptr ); 778 return NULL; 779 } 780 781 memcpy( new_ptr, ptr, sz ); 782 msi_free( ptr ); 783 return new_ptr; 784 } 785 786 static void cond_free( void *ptr ) 787 { 788 struct list *mem = (struct list *)ptr - 1; 789 790 if( ptr ) 791 { 792 list_remove( mem ); 793 msi_free( mem ); 794 } 795 } 796 797 static int cond_error( COND_input *info, const char *str ) 798 { 799 TRACE("%s\n", str ); 800 return 0; 801 } 802 803 MSICONDITION MSI_EvaluateConditionW( MSIPACKAGE *package, LPCWSTR szCondition ) 804 { 805 COND_input cond; 806 MSICONDITION r; 807 struct list *mem, *safety; 808 809 TRACE("%s\n", debugstr_w( szCondition ) ); 810 811 if (szCondition == NULL) return MSICONDITION_NONE; 812 813 cond.package = package; 814 cond.str = szCondition; 815 cond.n = 0; 816 cond.result = MSICONDITION_ERROR; 817 818 list_init( &cond.mem ); 819 820 if ( !cond_parse( &cond ) ) 821 r = cond.result; 822 else 823 r = MSICONDITION_ERROR; 824 825 LIST_FOR_EACH_SAFE( mem, safety, &cond.mem ) 826 { 827 /* The tracked memory lives directly after the list struct */ 828 void *ptr = mem + 1; 829 if ( r != MSICONDITION_ERROR ) 830 WARN( "condition parser failed to free up some memory: %p\n", ptr ); 831 cond_free( ptr ); 832 } 833 834 TRACE("%i <- %s\n", r, debugstr_w(szCondition)); 835 return r; 836 } 837 838 MSICONDITION WINAPI MsiEvaluateConditionW( MSIHANDLE hInstall, LPCWSTR szCondition ) 839 { 840 MSIPACKAGE *package; 841 UINT ret; 842 843 package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE); 844 if( !package ) 845 { 846 MSIHANDLE remote; 847 848 if (!(remote = msi_get_remote(hInstall))) 849 return MSICONDITION_ERROR; 850 851 if (!szCondition) 852 return MSICONDITION_NONE; 853 854 __TRY 855 { 856 ret = remote_EvaluateCondition(remote, szCondition); 857 } 858 __EXCEPT(rpc_filter) 859 { 860 ret = GetExceptionCode(); 861 } 862 __ENDTRY 863 864 return ret; 865 } 866 867 ret = MSI_EvaluateConditionW( package, szCondition ); 868 msiobj_release( &package->hdr ); 869 return ret; 870 } 871 872 MSICONDITION WINAPI MsiEvaluateConditionA( MSIHANDLE hInstall, LPCSTR szCondition ) 873 { 874 LPWSTR szwCond = NULL; 875 MSICONDITION r; 876 877 szwCond = strdupAtoW( szCondition ); 878 if( szCondition && !szwCond ) 879 return MSICONDITION_ERROR; 880 881 r = MsiEvaluateConditionW( hInstall, szwCond ); 882 msi_free( szwCond ); 883 return r; 884 } 885