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