xref: /reactos/dll/win32/msi/cond.y (revision c81af08f)
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 "config.h"
26 
27 #include <stdarg.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 
31 #include "windef.h"
32 #include "winbase.h"
33 #include "winuser.h"
34 #include "msi.h"
35 #include "msiquery.h"
36 #include "objbase.h"
37 #include "oleauto.h"
38 
39 #include "msipriv.h"
40 #include "msiserver.h"
41 #include "wine/debug.h"
42 #include "wine/unicode.h"
43 #include "wine/list.h"
44 
45 WINE_DEFAULT_DEBUG_CHANNEL(msi);
46 
47 typedef struct tag_yyinput
48 {
49     MSIPACKAGE *package;
50     LPCWSTR str;
51     INT    n;
52     MSICONDITION result;
53     struct list mem;
54 } COND_input;
55 
56 struct cond_str {
57     LPCWSTR data;
58     INT len;
59 };
60 
61 struct value {
62     enum value_type {
63         VALUE_INTEGER,
64         VALUE_LITERAL,
65         VALUE_SYMBOL
66     } type;
67     union {
68         INT integer;
69         WCHAR *string;
70     } u;
71 };
72 
73 static LPWSTR COND_GetString( COND_input *info, const struct cond_str *str );
74 static LPWSTR COND_GetLiteral( COND_input *info, const struct cond_str *str );
75 static int cond_lex( void *COND_lval, COND_input *info);
76 static int cond_error( COND_input *info, const char *str);
77 
78 static void *cond_alloc( COND_input *cond, unsigned int sz );
79 static void *cond_track_mem( COND_input *cond, void *ptr, unsigned int sz );
80 static void cond_free( void *ptr );
81 
82 static INT compare_int( INT a, INT operator, INT b );
83 static INT compare_string( LPCWSTR a, INT operator, LPCWSTR b, BOOL convert );
84 
85 static BOOL num_from_prop( LPCWSTR p, INT *val )
86 {
87     INT ret = 0, sign = 1;
88 
89     if (!p)
90         return FALSE;
91     if (*p == '-')
92     {
93         sign = -1;
94         p++;
95     }
96     if (!*p)
97         return FALSE;
98     while (*p)
99     {
100         if( *p < '0' || *p > '9' )
101             return FALSE;
102         ret = ret*10 + (*p - '0');
103         p++;
104     }
105     *val = ret*sign;
106     return TRUE;
107 }
108 
109 static void value_free( struct value val )
110 {
111     if (val.type != VALUE_INTEGER)
112         cond_free( val.u.string );
113 }
114 
115 %}
116 
117 %lex-param { COND_input *info }
118 %parse-param { COND_input *info }
119 %pure-parser
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 COND_EOF
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 COND_EOF
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 = atoiW( szNum );
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 = strstrW( 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 (!isdigitW(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 = atoiW(a);
455     rhs = atoiW(b);
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 strstrW( a, b ) != 0;
463     case COND_ISS:
464         return strstriW( a, b ) != 0;
465     case COND_LHS:
466     {
467         int l = strlenW( a );
468         int r = strlenW( b );
469         if (r > l) return 0;
470         return !strncmpW( a, b, r );
471     }
472     case COND_RHS:
473     {
474         int l = strlenW( a );
475         int r = strlenW( b );
476         if (r > l) return 0;
477         return !strncmpW( a + (l - r), b, r );
478     }
479     case COND_ILHS:
480     {
481         int l = strlenW( a );
482         int r = strlenW( b );
483         if (r > l) return 0;
484         return !strncmpiW( a, b, r );
485     }
486     case COND_IRHS:
487     {
488         int l = strlenW( a );
489         int r = strlenW( b );
490         if (r > l) return 0;
491         return !strncmpiW( 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 = szEmpty;
507     if (!b) b = szEmpty;
508 
509     if (convert && str_is_number(a) && str_is_number(b))
510         return compare_int( atoiW(a), operator, atoiW(b) );
511 
512     /* a or b may be NULL */
513     switch (operator)
514     {
515     case COND_LT:
516         return strcmpW( a, b ) < 0;
517     case COND_GT:
518         return strcmpW( a, b ) > 0;
519     case COND_EQ:
520         return strcmpW( a, b ) == 0;
521     case COND_NE:
522         return strcmpW( a, b ) != 0;
523     case COND_GE:
524         return strcmpW( a, b ) >= 0;
525     case COND_LE:
526         return strcmpW( a, b ) <= 0;
527     case COND_ILT:
528         return strcmpiW( a, b ) < 0;
529     case COND_IGT:
530         return strcmpiW( a, b ) > 0;
531     case COND_IEQ:
532         return strcmpiW( a, b ) == 0;
533     case COND_INE:
534         return strcmpiW( a, b ) != 0;
535     case COND_IGE:
536         return strcmpiW( a, b ) >= 0;
537     case COND_ILE:
538         return strcmpiW( 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         { {'~','<','=',0}, COND_ILE },
597         { {'~','>','<',0}, COND_ISS },
598         { {'~','>','>',0}, COND_IRHS },
599         { {'~','<','>',0}, COND_INE },
600         { {'~','>','=',0}, COND_IGE },
601         { {'~','<','<',0}, COND_ILHS },
602         { {'~','=',0},     COND_IEQ },
603         { {'~','<',0},     COND_ILT },
604         { {'~','>',0},     COND_IGT },
605         { {'>','=',0},     COND_GE  },
606         { {'>','<',0},     COND_SS  },
607         { {'<','<',0},     COND_LHS },
608         { {'<','>',0},     COND_NE  },
609         { {'<','=',0},     COND_LE  },
610         { {'>','>',0},     COND_RHS },
611         { {'>',0},         COND_GT  },
612         { {'<',0},         COND_LT  },
613         { {0},             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 == strncmpW( 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 = strchrW( 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         static const WCHAR szNot[] = {'N','O','T',0};
678         static const WCHAR szAnd[] = {'A','N','D',0};
679         static const WCHAR szXor[] = {'X','O','R',0};
680         static const WCHAR szEqv[] = {'E','Q','V',0};
681         static const WCHAR szImp[] = {'I','M','P',0};
682         static const WCHAR szOr[] = {'O','R',0};
683 
684         while( COND_IsIdent( str->data[len] ) )
685             len++;
686         rc = COND_IDENT;
687 
688         if ( len == 3 )
689         {
690             if ( !strncmpiW( str->data, szNot, len ) )
691                 rc = COND_NOT;
692             else if( !strncmpiW( str->data, szAnd, len ) )
693                 rc = COND_AND;
694             else if( !strncmpiW( str->data, szXor, len ) )
695                 rc = COND_XOR;
696             else if( !strncmpiW( str->data, szEqv, len ) )
697                 rc = COND_EQV;
698             else if( !strncmpiW( str->data, szImp, len ) )
699                 rc = COND_IMP;
700         }
701         else if( (len == 2) && !strncmpiW( str->data, szOr, len ) )
702             rc = COND_OR;
703     }
704     else if( COND_IsNumber( ch ) )
705     {
706         while( COND_IsNumber( str->data[len] ) )
707             len++;
708         rc = COND_NUMBER;
709     }
710     else
711     {
712         ERR("Got unknown character %c(%x)\n",ch,ch);
713         return COND_ERROR;
714     }
715 
716     cond->n += len;
717     str->len = len;
718 
719     return rc;
720 }
721 
722 static int cond_lex( void *COND_lval, COND_input *cond )
723 {
724     int rc;
725     struct cond_str *str = COND_lval;
726 
727     do {
728         rc = COND_GetOne( str, cond );
729     } while (rc == COND_SPACE);
730 
731     return rc;
732 }
733 
734 static LPWSTR COND_GetString( COND_input *cond, const struct cond_str *str )
735 {
736     LPWSTR ret;
737 
738     ret = cond_alloc( cond, (str->len+1) * sizeof (WCHAR) );
739     if( ret )
740     {
741         memcpy( ret, str->data, str->len * sizeof(WCHAR));
742         ret[str->len]=0;
743     }
744     TRACE("Got identifier %s\n",debugstr_w(ret));
745     return ret;
746 }
747 
748 static LPWSTR COND_GetLiteral( COND_input *cond, const struct cond_str *str )
749 {
750     LPWSTR ret;
751 
752     ret = cond_alloc( cond, (str->len-1) * sizeof (WCHAR) );
753     if( ret )
754     {
755         memcpy( ret, str->data+1, (str->len-2) * sizeof(WCHAR) );
756         ret[str->len - 2]=0;
757     }
758     TRACE("Got literal %s\n",debugstr_w(ret));
759     return ret;
760 }
761 
762 static void *cond_alloc( COND_input *cond, unsigned int sz )
763 {
764     struct list *mem;
765 
766     mem = msi_alloc( sizeof (struct list) + sz );
767     if( !mem )
768         return NULL;
769 
770     list_add_head( &(cond->mem), mem );
771     return mem + 1;
772 }
773 
774 static void *cond_track_mem( COND_input *cond, void *ptr, unsigned int sz )
775 {
776     void *new_ptr;
777 
778     if( !ptr )
779         return ptr;
780 
781     new_ptr = cond_alloc( cond, sz );
782     if( !new_ptr )
783     {
784         msi_free( ptr );
785         return NULL;
786     }
787 
788     memcpy( new_ptr, ptr, sz );
789     msi_free( ptr );
790     return new_ptr;
791 }
792 
793 static void cond_free( void *ptr )
794 {
795     struct list *mem = (struct list *)ptr - 1;
796 
797     if( ptr )
798     {
799         list_remove( mem );
800         msi_free( mem );
801     }
802 }
803 
804 static int cond_error( COND_input *info, const char *str )
805 {
806     TRACE("%s\n", str );
807     return 0;
808 }
809 
810 MSICONDITION MSI_EvaluateConditionW( MSIPACKAGE *package, LPCWSTR szCondition )
811 {
812     COND_input cond;
813     MSICONDITION r;
814     struct list *mem, *safety;
815 
816     TRACE("%s\n", debugstr_w( szCondition ) );
817 
818     if (szCondition == NULL) return MSICONDITION_NONE;
819 
820     cond.package = package;
821     cond.str   = szCondition;
822     cond.n     = 0;
823     cond.result = MSICONDITION_ERROR;
824 
825     list_init( &cond.mem );
826 
827     if ( !cond_parse( &cond ) )
828         r = cond.result;
829     else
830         r = MSICONDITION_ERROR;
831 
832     LIST_FOR_EACH_SAFE( mem, safety, &cond.mem )
833     {
834         /* The tracked memory lives directly after the list struct */
835         void *ptr = mem + 1;
836         if ( r != MSICONDITION_ERROR )
837             WARN( "condition parser failed to free up some memory: %p\n", ptr );
838         cond_free( ptr );
839     }
840 
841     TRACE("%i <- %s\n", r, debugstr_w(szCondition));
842     return r;
843 }
844 
845 MSICONDITION WINAPI MsiEvaluateConditionW( MSIHANDLE hInstall, LPCWSTR szCondition )
846 {
847     MSIPACKAGE *package;
848     UINT ret;
849 
850     package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE);
851     if( !package )
852     {
853         HRESULT hr;
854         BSTR condition;
855         IWineMsiRemotePackage *remote_package;
856 
857         remote_package = (IWineMsiRemotePackage *)msi_get_remote( hInstall );
858         if (!remote_package)
859             return MSICONDITION_ERROR;
860 
861         condition = SysAllocString( szCondition );
862         if (!condition)
863         {
864             IWineMsiRemotePackage_Release( remote_package );
865             return ERROR_OUTOFMEMORY;
866         }
867 
868         hr = IWineMsiRemotePackage_EvaluateCondition( remote_package, condition );
869 
870         SysFreeString( condition );
871         IWineMsiRemotePackage_Release( remote_package );
872 
873         if (FAILED(hr))
874         {
875             if (HRESULT_FACILITY(hr) == FACILITY_WIN32)
876                 return HRESULT_CODE(hr);
877 
878             return ERROR_FUNCTION_FAILED;
879         }
880 
881         return ERROR_SUCCESS;
882     }
883 
884     ret = MSI_EvaluateConditionW( package, szCondition );
885     msiobj_release( &package->hdr );
886     return ret;
887 }
888 
889 MSICONDITION WINAPI MsiEvaluateConditionA( MSIHANDLE hInstall, LPCSTR szCondition )
890 {
891     LPWSTR szwCond = NULL;
892     MSICONDITION r;
893 
894     szwCond = strdupAtoW( szCondition );
895     if( szCondition && !szwCond )
896         return MSICONDITION_ERROR;
897 
898     r = MsiEvaluateConditionW( hInstall, szwCond );
899     msi_free( szwCond );
900     return r;
901 }
902