msi: Ignore a file that has a missing component.
[wine] / dlls / 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 #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
44 #define YYLEX_PARAM info
45 #define YYPARSE_PARAM info
46
47 static int cond_error(const char *str);
48
49 WINE_DEFAULT_DEBUG_CHANNEL(msi);
50
51 typedef struct tag_yyinput
52 {
53     MSIPACKAGE *package;
54     LPCWSTR str;
55     INT    n;
56     MSICONDITION result;
57 } COND_input;
58
59 struct cond_str {
60     LPCWSTR data;
61     INT len;
62 };
63
64 static LPWSTR COND_GetString( const struct cond_str *str );
65 static LPWSTR COND_GetLiteral( const struct cond_str *str );
66 static int cond_lex( void *COND_lval, COND_input *info);
67 static const WCHAR szEmpty[] = { 0 };
68
69 static INT compare_int( INT a, INT operator, INT b );
70 static INT compare_string( LPCWSTR a, INT operator, LPCWSTR b, BOOL convert );
71
72 static INT compare_and_free_strings( LPWSTR a, INT op, LPWSTR b, BOOL convert )
73 {
74     INT r;
75
76     r = compare_string( a, op, b, convert );
77     msi_free( a );
78     msi_free( b );
79     return r;
80 }
81
82 static BOOL num_from_prop( LPCWSTR p, INT *val )
83 {
84     INT ret = 0, sign = 1;
85
86     if (!p)
87         return FALSE;
88     if (*p == '-')
89     {
90         sign = -1;
91         p++;
92     }
93     if (!*p)
94         return FALSE;
95     while (*p)
96     {
97         if( *p < '0' || *p > '9' )
98             return FALSE;
99         ret = ret*10 + (*p - '0');
100         p++;
101     }
102     *val = ret*sign;
103     return TRUE;
104 }
105
106 %}
107
108 %pure-parser
109
110 %union
111 {
112     struct cond_str str;
113     LPWSTR    string;
114     INT       value;
115 }
116
117 %token COND_SPACE COND_EOF
118 %token COND_OR COND_AND COND_NOT COND_XOR COND_IMP COND_EQV
119 %token COND_LT COND_GT COND_EQ COND_NE COND_GE COND_LE
120 %token COND_ILT COND_IGT COND_IEQ COND_INE COND_IGE COND_ILE
121 %token COND_LPAR COND_RPAR COND_TILDA COND_SS COND_ISS
122 %token COND_ILHS COND_IRHS COND_LHS COND_RHS
123 %token COND_PERCENT COND_DOLLARS COND_QUESTION COND_AMPER COND_EXCLAM
124 %token <str> COND_IDENT <str> COND_NUMBER <str> COND_LITER
125
126 %nonassoc COND_ERROR COND_EOF
127
128 %type <value> expression boolean_term boolean_factor 
129 %type <value> value_i integer operator
130 %type <string> identifier symbol_s value_s literal
131
132 %%
133
134 condition:
135     expression 
136         {
137             COND_input* cond = (COND_input*) info;
138             cond->result = $1;
139         }
140   | /* empty */
141         {
142             COND_input* cond = (COND_input*) info;
143             cond->result = MSICONDITION_NONE;
144         }
145     ;
146
147 expression:
148     boolean_term 
149         {
150             $$ = $1;
151         }
152   | expression COND_OR boolean_term
153         {
154             $$ = $1 || $3;
155         }
156   | expression COND_IMP boolean_term
157         {
158             $$ = !$1 || $3;
159         }
160   | expression COND_XOR boolean_term
161         {
162             $$ = ( $1 || $3 ) && !( $1 && $3 );
163         }
164   | expression COND_EQV boolean_term
165         {
166             $$ = ( $1 && $3 ) || ( !$1 && !$3 );
167         }
168     ;
169
170 boolean_term:
171     boolean_factor
172         {
173             $$ = $1;
174         }
175   | boolean_term COND_AND boolean_factor
176         {
177             $$ = $1 && $3;
178         }
179     ;
180
181 boolean_factor:
182     COND_NOT boolean_factor
183         {
184             $$ = $2 ? 0 : 1;
185         }
186   | value_i
187         {
188             $$ = $1 ? 1 : 0;
189         }
190   | value_s
191         {
192             $$ = ($1 && $1[0]) ? 1 : 0;
193             msi_free($1);
194         }
195   | value_i operator value_i
196         {
197             $$ = compare_int( $1, $2, $3 );
198         }
199   | symbol_s operator value_i
200         {
201             int num;
202             if (num_from_prop( $1, &num ))
203                 $$ = compare_int( num, $2, $3 );
204             else 
205                 $$ = ($2 == COND_NE || $2 == COND_INE );
206             msi_free($1);
207         }
208   | value_i operator symbol_s
209         {
210             int num;
211             if (num_from_prop( $3, &num ))
212                 $$ = compare_int( $1, $2, num );
213             else 
214                 $$ = ($2 == COND_NE || $2 == COND_INE );
215             msi_free($3);
216         }
217   | symbol_s operator symbol_s
218         {
219             $$ = compare_and_free_strings( $1, $2, $3, TRUE );
220         }
221   | symbol_s operator literal
222         {
223             $$ = compare_and_free_strings( $1, $2, $3, TRUE );
224         }
225   | literal operator symbol_s
226         {
227             $$ = compare_and_free_strings( $1, $2, $3, TRUE );
228         }
229   | literal operator literal
230         {
231             $$ = compare_and_free_strings( $1, $2, $3, FALSE );
232         }
233   | literal operator value_i
234         {
235             $$ = 0;
236             msi_free($1);
237         }
238   | value_i operator literal
239         {
240             $$ = 0;
241             msi_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_s:
272     symbol_s
273     {
274         $$ = $1;
275     } 
276   | literal
277     {
278         $$ = $1;
279     }
280     ;
281
282 literal:
283     COND_LITER
284         {
285             $$ = COND_GetLiteral(&$1);
286             if( !$$ )
287                 YYABORT;
288         }
289     ;
290
291 value_i:
292     integer
293         {
294             $$ = $1;
295         }
296   | COND_DOLLARS identifier
297         {
298             COND_input* cond = (COND_input*) info;
299             INSTALLSTATE install = INSTALLSTATE_UNKNOWN, action = INSTALLSTATE_UNKNOWN;
300       
301             MSI_GetComponentStateW(cond->package, $2, &install, &action );
302             $$ = action;
303             msi_free( $2 );
304         }
305   | COND_QUESTION identifier
306         {
307             COND_input* cond = (COND_input*) info;
308             INSTALLSTATE install = INSTALLSTATE_UNKNOWN, action = INSTALLSTATE_UNKNOWN;
309       
310             MSI_GetComponentStateW(cond->package, $2, &install, &action );
311             $$ = install;
312             msi_free( $2 );
313         }
314   | COND_AMPER identifier
315         {
316             COND_input* cond = (COND_input*) info;
317             INSTALLSTATE install = INSTALLSTATE_UNKNOWN, action = INSTALLSTATE_UNKNOWN;
318       
319             MSI_GetFeatureStateW(cond->package, $2, &install, &action );
320             if (action == INSTALLSTATE_UNKNOWN)
321                 $$ = MSICONDITION_FALSE;
322             else
323                 $$ = action;
324
325             msi_free( $2 );
326         }
327   | COND_EXCLAM identifier
328         {
329             COND_input* cond = (COND_input*) info;
330             INSTALLSTATE install = INSTALLSTATE_UNKNOWN, action = INSTALLSTATE_UNKNOWN;
331       
332             MSI_GetFeatureStateW(cond->package, $2, &install, &action );
333             $$ = install;
334             msi_free( $2 );
335         }
336     ;
337
338 symbol_s:
339     identifier
340         {
341             COND_input* cond = (COND_input*) info;
342
343             $$ = msi_dup_property( cond->package, $1 );
344             msi_free( $1 );
345         }
346     | COND_PERCENT identifier
347         {
348             UINT len = GetEnvironmentVariableW( $2, NULL, 0 );
349             $$ = NULL;
350             if (len++)
351             {
352                 $$ = msi_alloc( len*sizeof (WCHAR) );
353                 GetEnvironmentVariableW( $2, $$, len );
354             }
355             msi_free( $2 );
356         }
357     ;
358
359 identifier:
360     COND_IDENT
361         {
362             $$ = COND_GetString(&$1);
363             if( !$$ )
364                 YYABORT;
365         }
366     ;
367
368 integer:
369     COND_NUMBER
370         {
371             LPWSTR szNum = COND_GetString(&$1);
372             if( !szNum )
373                 YYABORT;
374             $$ = atoiW( szNum );
375             msi_free( szNum );
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 ) ? 1 : 0;
443     case COND_ISS:
444         return strstriW( a, b ) ? 1 : 0;
445     case COND_LHS:
446         return 0 == strncmpW( a, b, lstrlenW( b ) );
447     case COND_RHS:
448         return 0 == lstrcmpW( a + (lstrlenW( a ) - lstrlenW( b )), b );
449     case COND_ILHS:
450         return 0 == strncmpiW( a, b, lstrlenW( b ) );
451     case COND_IRHS:
452         return 0 == lstrcmpiW( a + (lstrlenW( a ) - lstrlenW( b )), b );
453     default:
454         ERR("invalid substring operator\n");
455         return 0;
456     }
457     return 0;
458 }
459
460 static INT compare_string( LPCWSTR a, INT operator, LPCWSTR b, BOOL convert )
461 {
462     if (operator >= COND_SS && operator <= COND_RHS)
463         return compare_substring( a, operator, b );
464         
465     /* null and empty string are equivalent */
466     if (!a) a = szEmpty;
467     if (!b) b = szEmpty;
468
469     if (convert && str_is_number(a) && str_is_number(b))
470         return compare_int( atoiW(a), operator, atoiW(b) );
471
472     /* a or b may be NULL */
473     switch (operator)
474     {
475     case COND_LT:
476         return -1 == lstrcmpW( a, b );
477     case COND_GT:
478         return  1 == lstrcmpW( a, b );
479     case COND_EQ:
480         return  0 == lstrcmpW( a, b );
481     case COND_NE:
482         return  0 != lstrcmpW( a, b );
483     case COND_GE:
484         return -1 != lstrcmpW( a, b );
485     case COND_LE:
486         return  1 != lstrcmpW( a, b );
487     case COND_ILT:
488         return -1 == lstrcmpiW( a, b );
489     case COND_IGT:
490         return  1 == lstrcmpiW( a, b );
491     case COND_IEQ:
492         return  0 == lstrcmpiW( a, b );
493     case COND_INE:
494         return  0 != lstrcmpiW( a, b );
495     case COND_IGE:
496         return -1 != lstrcmpiW( a, b );
497     case COND_ILE:
498         return  1 != lstrcmpiW( a, b );
499     default:
500         ERR("invalid string operator\n");
501         return 0;
502     }
503     return 0;
504 }
505
506
507 static INT compare_int( INT a, INT operator, INT b )
508 {
509     switch (operator)
510     {
511     case COND_LT:
512     case COND_ILT:
513         return a < b;
514     case COND_GT:
515     case COND_IGT:
516         return a > b;
517     case COND_EQ:
518     case COND_IEQ:
519         return a == b;
520     case COND_NE:
521     case COND_INE:
522         return a != b;
523     case COND_GE:
524     case COND_IGE:
525         return a >= b;
526     case COND_LE:
527     case COND_ILE:
528         return a <= b;
529     case COND_SS:
530     case COND_ISS:
531         return ( a & b ) ? 1 : 0;
532     case COND_RHS:
533         return ( ( a & 0xffff ) == b ) ? 1 : 0;
534     case COND_LHS:
535         return ( ( (a>>16) & 0xffff ) == b ) ? 1 : 0;
536     default:
537         ERR("invalid integer operator\n");
538         return 0;
539     }
540     return 0;
541 }
542
543
544 static int COND_IsIdent( WCHAR x )
545 {
546     return( COND_IsAlpha( x ) || COND_IsNumber( x ) || ( x == '_' ) 
547             || ( x == '#' ) || (x == '.') );
548 }
549
550 static int COND_GetOperator( COND_input *cond )
551 {
552     static const struct {
553         const WCHAR str[4];
554         int id;
555     } table[] = {
556         { {'~','=',0},     COND_IEQ },
557         { {'~','<','=',0}, COND_ILE },
558         { {'~','>','<',0}, COND_ISS },
559         { {'~','>','>',0}, COND_IRHS },
560         { {'~','<','>',0}, COND_INE },
561         { {'~','<',0},     COND_ILT },
562         { {'~','>','=',0}, COND_IGE },
563         { {'~','<','<',0}, COND_ILHS },
564         { {'~','>',0},     COND_IGT },
565         { {'>','=',0},     COND_GE  },
566         { {'>','<',0},     COND_SS  },
567         { {'<','<',0},     COND_LHS },
568         { {'<','>',0},     COND_NE  },
569         { {'<','=',0},     COND_LE  },
570         { {'>','>',0},     COND_RHS },
571         { {'>',0},         COND_GT  },
572         { {'<',0},         COND_LT  },
573         { {0},             0        }
574     };
575     LPCWSTR p = &cond->str[cond->n];
576     int i = 0, len;
577
578     while ( 1 )
579     {
580         len = lstrlenW( table[i].str );
581         if ( !len || 0 == strncmpW( table[i].str, p, len ) )
582             break;
583         i++;
584     }
585     cond->n += len;
586     return table[i].id;
587 }
588
589 static int COND_GetOne( struct cond_str *str, COND_input *cond )
590 {
591     int rc, len = 1;
592     WCHAR ch;
593
594     str->data = &cond->str[cond->n];
595
596     ch = str->data[0];
597
598     switch( ch )
599     {
600     case 0: return 0;
601     case '(': rc = COND_LPAR; break;
602     case ')': rc = COND_RPAR; break;
603     case '&': rc = COND_AMPER; break;
604     case '!': rc = COND_EXCLAM; break;
605     case '$': rc = COND_DOLLARS; break;
606     case '?': rc = COND_QUESTION; break;
607     case '%': rc = COND_PERCENT; break;
608     case ' ': rc = COND_SPACE; break;
609     case '=': rc = COND_EQ; break;
610
611     case '~':
612     case '<':
613     case '>':
614         rc = COND_GetOperator( cond );
615         if (!rc)
616             rc = COND_ERROR;
617         return rc;
618     default:
619         rc = 0;
620     }
621
622     if ( rc )
623     {
624         cond->n += len;
625         return rc;
626     }
627
628     if (ch == '"' )
629     {
630         LPCWSTR p = strchrW( str->data + 1, '"' );
631         if (!p)
632             return COND_ERROR;
633         len = p - str->data + 1;
634         rc = COND_LITER;
635     }
636     else if( COND_IsAlpha( ch ) )
637     {
638         static const WCHAR szNot[] = {'N','O','T',0};
639         static const WCHAR szAnd[] = {'A','N','D',0};
640         static const WCHAR szXor[] = {'X','O','R',0};
641         static const WCHAR szEqv[] = {'E','Q','V',0};
642         static const WCHAR szImp[] = {'I','M','P',0};
643         static const WCHAR szOr[] = {'O','R',0};
644
645         while( COND_IsIdent( str->data[len] ) )
646             len++;
647         rc = COND_IDENT;
648
649         if ( len == 3 )
650         {
651             if ( !strncmpiW( str->data, szNot, len ) )
652                 rc = COND_NOT;
653             else if( !strncmpiW( str->data, szAnd, len ) )
654                 rc = COND_AND;
655             else if( !strncmpiW( str->data, szXor, len ) )
656                 rc = COND_XOR;
657             else if( !strncmpiW( str->data, szEqv, len ) )
658                 rc = COND_EQV;
659             else if( !strncmpiW( str->data, szImp, len ) )
660                 rc = COND_IMP;
661         }
662         else if( (len == 2) && !strncmpiW( str->data, szOr, len ) )
663             rc = COND_OR;
664     }
665     else if( COND_IsNumber( ch ) )
666     {
667         while( COND_IsNumber( str->data[len] ) )
668             len++;
669         rc = COND_NUMBER;
670     }
671     else
672     {
673         ERR("Got unknown character %c(%x)\n",ch,ch);
674         return COND_ERROR;
675     }
676
677     cond->n += len;
678     str->len = len;
679
680     return rc;
681 }
682
683 static int cond_lex( void *COND_lval, COND_input *cond )
684 {
685     int rc;
686     struct cond_str *str = COND_lval;
687
688     do {
689         rc = COND_GetOne( str, cond );
690     } while (rc == COND_SPACE);
691     
692     return rc;
693 }
694
695 static LPWSTR COND_GetString( const struct cond_str *str )
696 {
697     LPWSTR ret;
698
699     ret = msi_alloc( (str->len+1) * sizeof (WCHAR) );
700     if( ret )
701     {
702         memcpy( ret, str->data, str->len * sizeof(WCHAR));
703         ret[str->len]=0;
704     }
705     TRACE("Got identifier %s\n",debugstr_w(ret));
706     return ret;
707 }
708
709 static LPWSTR COND_GetLiteral( const struct cond_str *str )
710 {
711     LPWSTR ret;
712
713     ret = msi_alloc( (str->len-1) * sizeof (WCHAR) );
714     if( ret )
715     {
716         memcpy( ret, str->data+1, (str->len-2) * sizeof(WCHAR) );
717         ret[str->len - 2]=0;
718     }
719     TRACE("Got literal %s\n",debugstr_w(ret));
720     return ret;
721 }
722
723 static int cond_error(const char *str)
724 {
725     TRACE("%s\n", str );
726     return 0;
727 }
728
729 MSICONDITION MSI_EvaluateConditionW( MSIPACKAGE *package, LPCWSTR szCondition )
730 {
731     COND_input cond;
732     MSICONDITION r;
733
734     TRACE("%s\n", debugstr_w( szCondition ) );
735
736     if ( szCondition == NULL )
737         return MSICONDITION_NONE;
738
739     cond.package = package;
740     cond.str   = szCondition;
741     cond.n     = 0;
742     cond.result = MSICONDITION_ERROR;
743     
744     if ( !cond_parse( &cond ) )
745         r = cond.result;
746     else
747         r = MSICONDITION_ERROR;
748
749     TRACE("%i <- %s\n", r, debugstr_w(szCondition));
750     return r;
751 }
752
753 MSICONDITION WINAPI MsiEvaluateConditionW( MSIHANDLE hInstall, LPCWSTR szCondition )
754 {
755     MSIPACKAGE *package;
756     UINT ret;
757
758     package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE);
759     if( !package )
760     {
761         HRESULT hr;
762         BSTR condition;
763         IWineMsiRemotePackage *remote_package;
764
765         remote_package = (IWineMsiRemotePackage *)msi_get_remote( hInstall );
766         if (!remote_package)
767             return MSICONDITION_ERROR;
768
769         condition = SysAllocString( szCondition );
770         if (!condition)
771         {
772             IWineMsiRemotePackage_Release( remote_package );
773             return ERROR_OUTOFMEMORY;
774         }
775
776         hr = IWineMsiRemotePackage_EvaluateCondition( remote_package, condition );
777
778         SysFreeString( condition );
779         IWineMsiRemotePackage_Release( remote_package );
780
781         if (FAILED(hr))
782         {
783             if (HRESULT_FACILITY(hr) == FACILITY_WIN32)
784                 return HRESULT_CODE(hr);
785
786             return ERROR_FUNCTION_FAILED;
787         }
788
789         return ERROR_SUCCESS;
790     }
791
792     ret = MSI_EvaluateConditionW( package, szCondition );
793     msiobj_release( &package->hdr );
794     return ret;
795 }
796
797 MSICONDITION WINAPI MsiEvaluateConditionA( MSIHANDLE hInstall, LPCSTR szCondition )
798 {
799     LPWSTR szwCond = NULL;
800     MSICONDITION r;
801
802     szwCond = strdupAtoW( szCondition );
803     if( szCondition && !szwCond )
804         return MSICONDITION_ERROR;
805
806     r = MsiEvaluateConditionW( hInstall, szwCond );
807     msi_free( szwCond );
808     return r;
809 }