xref: /reactos/dll/win32/msi/cond.y (revision 1734f297)
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