4 * Implementation of the Microsoft Installer (msi.dll)
6 * Copyright 2003 Mike McCormack for CodeWeavers
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.
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.
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
32 #include "wine/debug.h"
33 #include "wine/unicode.h"
40 #define YYLEX_PARAM info
41 #define YYPARSE_PARAM info
43 static int COND_error
(const char *str
);
45 WINE_DEFAULT_DEBUG_CHANNEL
(msi
);
47 typedef
struct tag_yyinput
60 static LPWSTR COND_GetString
( struct cond_str
*str
);
61 static LPWSTR COND_GetLiteral
( struct cond_str
*str
);
62 static int COND_lex
( void *COND_lval
, COND_input
*info
);
63 static const WCHAR szEmpty
[] = { 0 };
65 static INT compare_int
( INT a
, INT operator
, INT b
);
66 static INT compare_string
( LPCWSTR a
, INT operator
, LPCWSTR b
);
68 static INT compare_and_free_strings
( LPWSTR a
, INT op
, LPWSTR b
)
72 r
= compare_string
( a
, op
, b
);
78 static BOOL num_from_prop
( LPCWSTR p
, INT
*val
)
80 INT ret
= 0, sign
= 1;
93 if
( *p
< '0' ||
*p
> '9' )
95 ret
= ret
*10 + (*p
- '0');
113 %token COND_SPACE COND_EOF
114 %token COND_OR COND_AND COND_NOT COND_XOR COND_IMP COND_EQV
115 %token COND_LT COND_GT COND_EQ COND_NE COND_GE COND_LE
116 %token COND_ILT COND_IGT COND_IEQ COND_INE COND_IGE COND_ILE
117 %token COND_LPAR COND_RPAR COND_TILDA COND_SS COND_ISS
118 %token COND_ILHS COND_IRHS COND_LHS COND_RHS
119 %token COND_PERCENT COND_DOLLARS COND_QUESTION COND_AMPER COND_EXCLAM
120 %token
<str
> COND_IDENT
<str
> COND_NUMBER
<str
> COND_LITER
122 %nonassoc COND_ERROR COND_EOF
124 %type
<value
> expression boolean_term boolean_factor
125 %type
<value
> value_i integer operator
126 %type
<string> identifier symbol_s value_s literal
133 COND_input
* cond
= (COND_input
*) info
;
138 COND_input
* cond
= (COND_input
*) info
;
139 cond
->result
= MSICONDITION_NONE
;
148 | expression COND_OR boolean_term
152 | expression COND_IMP boolean_term
156 | expression COND_XOR boolean_term
158 $$
= ( $1 ||
$3 ) && !( $1 && $3 );
160 | expression COND_EQV boolean_term
162 $$
= ( $1 && $3 ) ||
( !$1 && !$3 );
171 | boolean_term COND_AND boolean_factor
178 COND_NOT boolean_factor
188 $$
= ($1 && $1[0]) ?
1 : 0;
190 | value_i operator value_i
192 $$
= compare_int
( $1, $2, $3 );
194 | symbol_s operator value_i
197 if
(num_from_prop
( $1, &num
))
198 $$
= compare_int
( num
, $2, $3 );
200 $$
= ($2 == COND_NE ||
$2 == COND_INE
);
202 | value_i operator symbol_s
205 if
(num_from_prop
( $3, &num
))
206 $$
= compare_int
( $1, $2, num
);
208 $$
= ($2 == COND_NE ||
$2 == COND_INE
);
210 | symbol_s operator symbol_s
212 $$
= compare_and_free_strings
( $1, $2, $3 );
214 | symbol_s operator literal
216 $$
= compare_and_free_strings
( $1, $2, $3 );
218 | literal operator symbol_s
220 $$
= compare_and_free_strings
( $1, $2, $3 );
222 | literal operator literal
224 $$
= compare_and_free_strings
( $1, $2, $3 );
226 | literal operator value_i
230 | value_i operator literal
234 | COND_LPAR expression COND_RPAR
241 /* common functions */
242 COND_EQ
{ $$
= COND_EQ
; }
243 | COND_NE
{ $$
= COND_NE
; }
244 | COND_LT
{ $$
= COND_LT
; }
245 | COND_GT
{ $$
= COND_GT
; }
246 | COND_LE
{ $$
= COND_LE
; }
247 | COND_GE
{ $$
= COND_GE
; }
248 | COND_SS
{ $$
= COND_SS
; }
249 | COND_IEQ
{ $$
= COND_IEQ
; }
250 | COND_INE
{ $$
= COND_INE
; }
251 | COND_ILT
{ $$
= COND_ILT
; }
252 | COND_IGT
{ $$
= COND_IGT
; }
253 | COND_ILE
{ $$
= COND_ILE
; }
254 | COND_IGE
{ $$
= COND_IGE
; }
255 | COND_ISS
{ $$
= COND_ISS
; }
256 | COND_LHS
{ $$
= COND_LHS
; }
257 | COND_RHS
{ $$
= COND_RHS
; }
258 | COND_ILHS
{ $$
= COND_ILHS
; }
259 | COND_IRHS
{ $$
= COND_IRHS
; }
276 $$
= COND_GetLiteral
(&$1);
287 | COND_DOLLARS identifier
289 COND_input
* cond
= (COND_input
*) info
;
290 INSTALLSTATE install
= INSTALLSTATE_UNKNOWN
, action
= INSTALLSTATE_UNKNOWN
;
292 MSI_GetComponentStateW
(cond
->package
, $2, &install
, &action
);
296 | COND_QUESTION identifier
298 COND_input
* cond
= (COND_input
*) info
;
299 INSTALLSTATE install
= INSTALLSTATE_UNKNOWN
, action
= INSTALLSTATE_UNKNOWN
;
301 MSI_GetComponentStateW
(cond
->package
, $2, &install
, &action
);
305 | COND_AMPER identifier
307 COND_input
* cond
= (COND_input
*) info
;
308 INSTALLSTATE install
= INSTALLSTATE_UNKNOWN
, action
= INSTALLSTATE_UNKNOWN
;
310 MSI_GetFeatureStateW
(cond
->package
, $2, &install
, &action
);
314 | COND_EXCLAM identifier
316 COND_input
* cond
= (COND_input
*) info
;
317 INSTALLSTATE install
= INSTALLSTATE_UNKNOWN
, action
= INSTALLSTATE_UNKNOWN
;
319 MSI_GetFeatureStateW
(cond
->package
, $2, &install
, &action
);
328 COND_input
* cond
= (COND_input
*) info
;
330 $$
= msi_dup_property
( cond
->package
, $1 );
333 | COND_PERCENT identifier
335 UINT len
= GetEnvironmentVariableW
( $2, NULL
, 0 );
339 $$
= msi_alloc
( len
*sizeof
(WCHAR
) );
340 GetEnvironmentVariableW
( $2, $$
, len
);
349 $$
= COND_GetString
(&$1);
358 LPWSTR szNum
= COND_GetString
(&$1);
369 static int COND_IsAlpha
( WCHAR x
)
371 return
( ( ( x
>= 'A' ) && ( x
<= 'Z' ) ) ||
372 ( ( x
>= 'a' ) && ( x
<= 'z' ) ) ||
376 static int COND_IsNumber
( WCHAR x
)
378 return
( (( x
>= '0' ) && ( x
<= '9' )) ||
(x
=='-') ||
(x
=='.') );
381 static WCHAR
*strstriW
( const WCHAR
*str
, const WCHAR
*sub
)
383 LPWSTR strlower
, sublower
, r
;
384 strlower
= CharLowerW
( strdupW
( str
) );
385 sublower
= CharLowerW
( strdupW
( sub
) );
386 r
= strstrW
( strlower
, sublower
);
388 r
= (LPWSTR
)str
+ (r
- strlower
);
389 msi_free
( strlower
);
390 msi_free
( sublower
);
394 static INT compare_string
( LPCWSTR a
, INT operator
, LPCWSTR b
)
396 /* null and empty string are equivalent */
400 /* a or b may be NULL */
404 return
-1 == lstrcmpW
( a
, b
);
406 return
1 == lstrcmpW
( a
, b
);
408 return
0 == lstrcmpW
( a
, b
);
410 return
0 != lstrcmpW
( a
, b
);
412 return
-1 != lstrcmpW
( a
, b
);
414 return
1 != lstrcmpW
( a
, b
);
415 case COND_SS
: /* substring */
416 return strstrW
( a
, b
) ?
1 : 0;
418 return
-1 == lstrcmpiW
( a
, b
);
420 return
1 == lstrcmpiW
( a
, b
);
422 return
0 == lstrcmpiW
( a
, b
);
424 return
0 != lstrcmpiW
( a
, b
);
426 return
-1 != lstrcmpiW
( a
, b
);
428 return
1 != lstrcmpiW
( a
, b
);
430 return strstriW
( a
, b
) ?
1 : 0;
435 ERR
("unimplemented string comparison\n");
438 ERR
("invalid integer operator\n");
445 static INT compare_int
( INT a
, INT operator
, INT b
)
469 return
( a
& b
) ?
1 : 0;
471 return
( ( a
& 0xffff ) == b
) ?
1 : 0;
473 return
( ( (a
>>16) & 0xffff ) == b
) ?
1 : 0;
475 ERR
("invalid integer operator\n");
482 static int COND_IsIdent
( WCHAR x
)
484 return
( COND_IsAlpha
( x
) || COND_IsNumber
( x
) ||
( x
== '_' )
485 ||
( x
== '#' ) ||
(x
== '.') );
488 static int COND_GetOperator
( COND_input
*cond
)
490 static const struct {
494 { {'~','=',0}, COND_IEQ
},
495 { {'~','<','=',0}, COND_ILE
},
496 { {'~','>','<',0}, COND_ISS
},
497 { {'~','>','>',0}, COND_IRHS
},
498 { {'~','<','>',0}, COND_INE
},
499 { {'~','<',0}, COND_ILT
},
500 { {'~','>','=',0}, COND_IGE
},
501 { {'~','<','<',0}, COND_ILHS
},
502 { {'~','>',0}, COND_IGT
},
503 { {'>','=',0}, COND_GE
},
504 { {'>','<',0}, COND_SS
},
505 { {'<','<',0}, COND_LHS
},
506 { {'>',0}, COND_GT
},
507 { {'<','>',0}, COND_NE
},
508 { {'<','=',0}, COND_LE
},
509 { {'>','>',0}, COND_RHS
},
510 { {'<',0}, COND_LT
},
513 LPCWSTR p
= &cond
->str
[cond
->n
];
518 len
= lstrlenW
( table
[i
].str
);
519 if
( !len ||
0 == strncmpW
( table
[i
].str
, p
, len
) )
527 static int COND_GetOne
( struct cond_str
*str
, COND_input
*cond
)
532 str
->data
= &cond
->str
[cond
->n
];
539 case
'(': rc
= COND_LPAR
; break
;
540 case
')': rc
= COND_RPAR
; break
;
541 case
'&': rc
= COND_AMPER
; break
;
542 case
'!': rc
= COND_EXCLAM
; break
;
543 case
'$': rc
= COND_DOLLARS
; break
;
544 case
'?': rc
= COND_QUESTION
; break
;
545 case
'%': rc
= COND_PERCENT
; break
;
546 case
' ': rc
= COND_SPACE
; break
;
547 case
'=': rc
= COND_EQ
; break
;
553 rc
= COND_GetOperator
( cond
);
569 LPCWSTR p
= strchrW
( str
->data
+ 1, '"' );
572 len
= p
- str
->data
+ 1;
575 else if
( COND_IsAlpha
( ch
) )
577 static const WCHAR szNot
[] = {'N','O','T',0};
578 static const WCHAR szAnd
[] = {'A','N','D',0};
579 static const WCHAR szXor
[] = {'X','O','R',0};
580 static const WCHAR szEqv
[] = {'E','Q','V',0};
581 static const WCHAR szImp
[] = {'I','M','P',0};
582 static const WCHAR szOr
[] = {'O','R',0};
584 while
( COND_IsIdent
( str
->data
[len
] ) )
590 if
( !strncmpiW
( str
->data
, szNot
, len
) )
592 else if
( !strncmpiW
( str
->data
, szAnd
, len
) )
594 else if
( !strncmpiW
( str
->data
, szXor
, len
) )
596 else if
( !strncmpiW
( str
->data
, szEqv
, len
) )
598 else if
( !strncmpiW
( str
->data
, szImp
, len
) )
601 else if
( (len
== 2) && !strncmpiW
( str
->data
, szOr
, len
) )
604 else if
( COND_IsNumber
( ch
) )
606 while
( COND_IsNumber
( str
->data
[len
] ) )
612 ERR
("Got unknown character %c(%x)\n",ch
,ch
);
622 static int COND_lex
( void *COND_lval
, COND_input
*cond
)
625 struct cond_str
*str
= COND_lval
;
628 rc
= COND_GetOne
( str
, cond
);
629 } while
(rc
== COND_SPACE
);
634 static LPWSTR COND_GetString
( struct cond_str
*str
)
638 ret
= msi_alloc
( (str
->len
+1) * sizeof
(WCHAR
) );
641 memcpy
( ret
, str
->data
, str
->len
* sizeof
(WCHAR
));
644 TRACE
("Got identifier %s\n",debugstr_w
(ret
));
648 static LPWSTR COND_GetLiteral
( struct cond_str
*str
)
652 ret
= msi_alloc
( (str
->len
-1) * sizeof
(WCHAR
) );
655 memcpy
( ret
, str
->data
+1, (str
->len
-2) * sizeof
(WCHAR
) );
658 TRACE
("Got literal %s\n",debugstr_w
(ret
));
662 static int COND_error
(const char *str
)
668 MSICONDITION MSI_EvaluateConditionW
( MSIPACKAGE
*package
, LPCWSTR szCondition
)
673 TRACE
("%s\n", debugstr_w
( szCondition
) );
675 if
( szCondition
== NULL
)
676 return MSICONDITION_NONE
;
678 cond.package
= package
;
679 cond.str
= szCondition
;
681 cond.result
= MSICONDITION_ERROR
;
683 if
( !COND_parse
( &cond
) )
686 r
= MSICONDITION_ERROR
;
688 TRACE
("%i <- %s\n", r
, debugstr_w
(szCondition
));
692 MSICONDITION WINAPI MsiEvaluateConditionW
( MSIHANDLE hInstall
, LPCWSTR szCondition
)
697 package
= msihandle2msiinfo
( hInstall
, MSIHANDLETYPE_PACKAGE
);
699 return MSICONDITION_ERROR
;
700 ret
= MSI_EvaluateConditionW
( package
, szCondition
);
701 msiobj_release
( &package
->hdr
);
705 MSICONDITION WINAPI MsiEvaluateConditionA
( MSIHANDLE hInstall
, LPCSTR szCondition
)
707 LPWSTR szwCond
= NULL
;
710 szwCond
= strdupAtoW
( szCondition
);
711 if
( szCondition
&& !szwCond
)
712 return MSICONDITION_ERROR
;
714 r
= MsiEvaluateConditionW
( hInstall
, szwCond
);