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
40 #include "msiserver.h"
41 #include "wine/debug.h"
42 #include "wine/unicode.h"
43 #include "wine/list.h"
45 WINE_DEFAULT_DEBUG_CHANNEL
(msi
);
47 typedef
struct tag_yyinput
61 static LPWSTR COND_GetString
( COND_input
*info
, const struct cond_str
*str
);
62 static LPWSTR COND_GetLiteral
( COND_input
*info
, const struct cond_str
*str
);
63 static int cond_lex
( void *COND_lval
, COND_input
*info
);
64 static int cond_error
( COND_input
*info
, const char *str
);
66 static void *cond_alloc
( COND_input
*cond
, unsigned int sz
);
67 static void *cond_track_mem
( COND_input
*cond
, void *ptr
, unsigned int sz
);
68 static void cond_free
( void *ptr
);
70 static INT compare_int
( INT a
, INT operator
, INT b
);
71 static INT compare_string
( LPCWSTR a
, INT operator
, LPCWSTR b
, BOOL convert
);
73 static INT compare_and_free_strings
( LPWSTR a
, INT op
, LPWSTR b
, BOOL convert
)
77 r
= compare_string
( a
, op
, b
, convert
);
83 static BOOL num_from_prop
( LPCWSTR p
, INT
*val
)
85 INT ret
= 0, sign
= 1;
98 if
( *p
< '0' ||
*p
> '9' )
100 ret
= ret
*10 + (*p
- '0');
109 %lex
-param
{ COND_input
*info
}
110 %parse
-param
{ COND_input
*info
}
120 %token COND_SPACE COND_EOF
121 %token COND_OR COND_AND COND_NOT COND_XOR COND_IMP COND_EQV
122 %token COND_LT COND_GT COND_EQ COND_NE COND_GE COND_LE
123 %token COND_ILT COND_IGT COND_IEQ COND_INE COND_IGE COND_ILE
124 %token COND_LPAR COND_RPAR COND_TILDA COND_SS COND_ISS
125 %token COND_ILHS COND_IRHS COND_LHS COND_RHS
126 %token COND_PERCENT COND_DOLLARS COND_QUESTION COND_AMPER COND_EXCLAM
127 %token
<str
> COND_IDENT
<str
> COND_NUMBER
<str
> COND_LITER
129 %nonassoc COND_ERROR COND_EOF
131 %type
<value
> expression boolean_term boolean_factor
132 %type
<value
> value_i integer operator
133 %type
<string> identifier symbol_s value_s literal
140 COND_input
* cond
= (COND_input
*) info
;
145 COND_input
* cond
= (COND_input
*) info
;
146 cond
->result
= MSICONDITION_NONE
;
155 | expression COND_OR boolean_term
159 | expression COND_IMP boolean_term
163 | expression COND_XOR boolean_term
165 $$
= ( $1 ||
$3 ) && !( $1 && $3 );
167 | expression COND_EQV boolean_term
169 $$
= ( $1 && $3 ) ||
( !$1 && !$3 );
178 | boolean_term COND_AND boolean_factor
185 COND_NOT boolean_factor
195 $$
= ($1 && $1[0]) ?
1 : 0;
198 | value_i operator value_i
200 $$
= compare_int
( $1, $2, $3 );
202 | symbol_s operator value_i
205 if
(num_from_prop
( $1, &num
))
206 $$
= compare_int
( num
, $2, $3 );
208 $$
= ($2 == COND_NE ||
$2 == COND_INE
);
211 | value_i operator symbol_s
214 if
(num_from_prop
( $3, &num
))
215 $$
= compare_int
( $1, $2, num
);
217 $$
= ($2 == COND_NE ||
$2 == COND_INE
);
220 | symbol_s operator symbol_s
222 $$
= compare_and_free_strings
( $1, $2, $3, TRUE
);
224 | symbol_s operator literal
226 $$
= compare_and_free_strings
( $1, $2, $3, TRUE
);
228 | literal operator symbol_s
230 $$
= compare_and_free_strings
( $1, $2, $3, TRUE
);
232 | literal operator literal
234 $$
= compare_and_free_strings
( $1, $2, $3, FALSE
);
236 | literal operator value_i
241 | value_i operator literal
246 | COND_LPAR expression COND_RPAR
253 /* common functions */
254 COND_EQ
{ $$
= COND_EQ
; }
255 | COND_NE
{ $$
= COND_NE
; }
256 | COND_LT
{ $$
= COND_LT
; }
257 | COND_GT
{ $$
= COND_GT
; }
258 | COND_LE
{ $$
= COND_LE
; }
259 | COND_GE
{ $$
= COND_GE
; }
260 | COND_SS
{ $$
= COND_SS
; }
261 | COND_IEQ
{ $$
= COND_IEQ
; }
262 | COND_INE
{ $$
= COND_INE
; }
263 | COND_ILT
{ $$
= COND_ILT
; }
264 | COND_IGT
{ $$
= COND_IGT
; }
265 | COND_ILE
{ $$
= COND_ILE
; }
266 | COND_IGE
{ $$
= COND_IGE
; }
267 | COND_ISS
{ $$
= COND_ISS
; }
268 | COND_LHS
{ $$
= COND_LHS
; }
269 | COND_RHS
{ $$
= COND_RHS
; }
270 | COND_ILHS
{ $$
= COND_ILHS
; }
271 | COND_IRHS
{ $$
= COND_IRHS
; }
288 COND_input
* cond
= (COND_input
*) info
;
289 $$
= COND_GetLiteral
( cond
, &$1 );
300 | COND_DOLLARS identifier
302 COND_input
* cond
= (COND_input
*) info
;
303 INSTALLSTATE install
= INSTALLSTATE_UNKNOWN
, action
= INSTALLSTATE_UNKNOWN
;
305 MSI_GetComponentStateW
(cond
->package
, $2, &install
, &action
);
309 | COND_QUESTION identifier
311 COND_input
* cond
= (COND_input
*) info
;
312 INSTALLSTATE install
= INSTALLSTATE_UNKNOWN
, action
= INSTALLSTATE_UNKNOWN
;
314 MSI_GetComponentStateW
(cond
->package
, $2, &install
, &action
);
318 | COND_AMPER identifier
320 COND_input
* cond
= (COND_input
*) info
;
321 INSTALLSTATE install
= INSTALLSTATE_UNKNOWN
, action
= INSTALLSTATE_UNKNOWN
;
323 MSI_GetFeatureStateW
(cond
->package
, $2, &install
, &action
);
324 if
(action
== INSTALLSTATE_UNKNOWN
)
325 $$
= MSICONDITION_FALSE
;
331 | COND_EXCLAM identifier
333 COND_input
* cond
= (COND_input
*) info
;
334 INSTALLSTATE install
= INSTALLSTATE_UNKNOWN
, action
= INSTALLSTATE_UNKNOWN
;
336 MSI_GetFeatureStateW
(cond
->package
, $2, &install
, &action
);
345 COND_input
* cond
= (COND_input
*) info
;
348 $$
= msi_dup_property
( cond
->package
->db
, $1 );
351 len
= (lstrlenW
($$
) + 1) * sizeof
(WCHAR
);
352 $$
= cond_track_mem
( cond
, $$
, len
);
356 | COND_PERCENT identifier
358 COND_input
* cond
= (COND_input
*) info
;
359 UINT len
= GetEnvironmentVariableW
( $2, NULL
, 0 );
363 $$
= cond_alloc
( cond
, len
*sizeof
(WCHAR
) );
366 GetEnvironmentVariableW
( $2, $$
, len
);
375 COND_input
* cond
= (COND_input
*) info
;
376 $$
= COND_GetString
( cond
, &$1 );
385 COND_input
* cond
= (COND_input
*) info
;
386 LPWSTR szNum
= COND_GetString
( cond
, &$1 );
397 static int COND_IsAlpha
( WCHAR x
)
399 return
( ( ( x
>= 'A' ) && ( x
<= 'Z' ) ) ||
400 ( ( x
>= 'a' ) && ( x
<= 'z' ) ) ||
404 static int COND_IsNumber
( WCHAR x
)
406 return
( (( x
>= '0' ) && ( x
<= '9' )) ||
(x
=='-') ||
(x
=='.') );
409 static WCHAR
*strstriW
( const WCHAR
*str
, const WCHAR
*sub
)
411 LPWSTR strlower
, sublower
, r
;
412 strlower
= CharLowerW
( strdupW
( str
) );
413 sublower
= CharLowerW
( strdupW
( sub
) );
414 r
= strstrW
( strlower
, sublower
);
416 r
= (LPWSTR
)str
+ (r
- strlower
);
417 msi_free
( strlower
);
418 msi_free
( sublower
);
422 static BOOL str_is_number
( LPCWSTR str
)
429 for
(i
= 0; i
< lstrlenW
( str
); i
++)
430 if
(!isdigitW
(str
[i
]))
436 static INT compare_substring
( LPCWSTR a
, INT operator
, LPCWSTR b
)
440 /* substring operators return 0 if LHS is missing */
444 /* substring operators return 1 if RHS is missing */
448 /* if both strings contain only numbers, use integer comparison */
451 if
(str_is_number
(a
) && str_is_number
(b
))
452 return compare_int
( lhs
, operator
, rhs
);
457 return strstrW
( a
, b
) != 0;
459 return strstriW
( a
, b
) != 0;
462 int l
= strlenW
( a
);
463 int r
= strlenW
( b
);
465 return
!strncmpW
( a
, b
, r
);
469 int l
= strlenW
( a
);
470 int r
= strlenW
( b
);
472 return
!strncmpW
( a
+ (l
- r
), b
, r
);
476 int l
= strlenW
( a
);
477 int r
= strlenW
( b
);
479 return
!strncmpiW
( a
, b
, r
);
483 int l
= strlenW
( a
);
484 int r
= strlenW
( b
);
486 return
!strncmpiW
( a
+ (l
- r
), b
, r
);
489 ERR
("invalid substring operator\n");
495 static INT compare_string
( LPCWSTR a
, INT operator
, LPCWSTR b
, BOOL convert
)
497 if
(operator
>= COND_SS
&& operator
<= COND_RHS
)
498 return compare_substring
( a
, operator
, b
);
500 /* null and empty string are equivalent */
504 if
(convert
&& str_is_number
(a
) && str_is_number
(b
))
505 return compare_int
( atoiW
(a
), operator
, atoiW
(b
) );
507 /* a or b may be NULL */
511 return strcmpW
( a
, b
) < 0;
513 return strcmpW
( a
, b
) > 0;
515 return strcmpW
( a
, b
) == 0;
517 return strcmpW
( a
, b
) != 0;
519 return strcmpW
( a
, b
) >= 0;
521 return strcmpW
( a
, b
) <= 0;
523 return strcmpiW
( a
, b
) < 0;
525 return strcmpiW
( a
, b
) > 0;
527 return strcmpiW
( a
, b
) == 0;
529 return strcmpiW
( a
, b
) != 0;
531 return strcmpiW
( a
, b
) >= 0;
533 return strcmpiW
( a
, b
) <= 0;
535 ERR
("invalid string operator\n");
542 static INT compare_int
( INT a
, INT operator
, INT b
)
566 return
( a
& b
) ?
1 : 0;
568 return
( ( a
& 0xffff ) == b
) ?
1 : 0;
570 return
( ( (a
>>16) & 0xffff ) == b
) ?
1 : 0;
572 ERR
("invalid integer operator\n");
579 static int COND_IsIdent
( WCHAR x
)
581 return
( COND_IsAlpha
( x
) || COND_IsNumber
( x
) ||
( x
== '_' )
582 ||
( x
== '#' ) ||
(x
== '.') );
585 static int COND_GetOperator
( COND_input
*cond
)
587 static const struct {
591 { {'~','<','=',0}, COND_ILE
},
592 { {'~','>','<',0}, COND_ISS
},
593 { {'~','>','>',0}, COND_IRHS
},
594 { {'~','<','>',0}, COND_INE
},
595 { {'~','>','=',0}, COND_IGE
},
596 { {'~','<','<',0}, COND_ILHS
},
597 { {'~','=',0}, COND_IEQ
},
598 { {'~','<',0}, COND_ILT
},
599 { {'~','>',0}, COND_IGT
},
600 { {'>','=',0}, COND_GE
},
601 { {'>','<',0}, COND_SS
},
602 { {'<','<',0}, COND_LHS
},
603 { {'<','>',0}, COND_NE
},
604 { {'<','=',0}, COND_LE
},
605 { {'>','>',0}, COND_RHS
},
606 { {'>',0}, COND_GT
},
607 { {'<',0}, COND_LT
},
610 LPCWSTR p
= &cond
->str
[cond
->n
];
615 len
= lstrlenW
( table
[i
].str
);
616 if
( !len ||
0 == strncmpW
( table
[i
].str
, p
, len
) )
624 static int COND_GetOne
( struct cond_str
*str
, COND_input
*cond
)
629 str
->data
= &cond
->str
[cond
->n
];
636 case
'(': rc
= COND_LPAR
; break
;
637 case
')': rc
= COND_RPAR
; break
;
638 case
'&': rc
= COND_AMPER
; break
;
639 case
'!': rc
= COND_EXCLAM
; break
;
640 case
'$': rc
= COND_DOLLARS
; break
;
641 case
'?': rc
= COND_QUESTION
; break
;
642 case
'%': rc
= COND_PERCENT
; break
;
643 case
' ': rc
= COND_SPACE
; break
;
644 case
'=': rc
= COND_EQ
; break
;
649 rc
= COND_GetOperator
( cond
);
665 LPCWSTR p
= strchrW
( str
->data
+ 1, '"' );
666 if
(!p
) return COND_ERROR
;
667 len
= p
- str
->data
+ 1;
670 else if
( COND_IsAlpha
( ch
) )
672 static const WCHAR szNot
[] = {'N','O','T',0};
673 static const WCHAR szAnd
[] = {'A','N','D',0};
674 static const WCHAR szXor
[] = {'X','O','R',0};
675 static const WCHAR szEqv
[] = {'E','Q','V',0};
676 static const WCHAR szImp
[] = {'I','M','P',0};
677 static const WCHAR szOr
[] = {'O','R',0};
679 while
( COND_IsIdent
( str
->data
[len
] ) )
685 if
( !strncmpiW
( str
->data
, szNot
, len
) )
687 else if
( !strncmpiW
( str
->data
, szAnd
, len
) )
689 else if
( !strncmpiW
( str
->data
, szXor
, len
) )
691 else if
( !strncmpiW
( str
->data
, szEqv
, len
) )
693 else if
( !strncmpiW
( str
->data
, szImp
, len
) )
696 else if
( (len
== 2) && !strncmpiW
( str
->data
, szOr
, len
) )
699 else if
( COND_IsNumber
( ch
) )
701 while
( COND_IsNumber
( str
->data
[len
] ) )
707 ERR
("Got unknown character %c(%x)\n",ch
,ch
);
717 static int cond_lex
( void *COND_lval
, COND_input
*cond
)
720 struct cond_str
*str
= COND_lval
;
723 rc
= COND_GetOne
( str
, cond
);
724 } while
(rc
== COND_SPACE
);
729 static LPWSTR COND_GetString
( COND_input
*cond
, const struct cond_str
*str
)
733 ret
= cond_alloc
( cond
, (str
->len
+1) * sizeof
(WCHAR
) );
736 memcpy
( ret
, str
->data
, str
->len
* sizeof
(WCHAR
));
739 TRACE
("Got identifier %s\n",debugstr_w
(ret
));
743 static LPWSTR COND_GetLiteral
( COND_input
*cond
, const struct cond_str
*str
)
747 ret
= cond_alloc
( cond
, (str
->len
-1) * sizeof
(WCHAR
) );
750 memcpy
( ret
, str
->data
+1, (str
->len
-2) * sizeof
(WCHAR
) );
753 TRACE
("Got literal %s\n",debugstr_w
(ret
));
757 static void *cond_alloc
( COND_input
*cond
, unsigned int sz
)
761 mem
= msi_alloc
( sizeof
(struct list
) + sz
);
765 list_add_head
( &(cond
->mem
), mem
);
769 static void *cond_track_mem
( COND_input
*cond
, void *ptr
, unsigned int sz
)
776 new_ptr
= cond_alloc
( cond
, sz
);
783 memcpy
( new_ptr
, ptr
, sz
);
788 static void cond_free
( void *ptr
)
790 struct list
*mem
= (struct list
*)ptr
- 1;
799 static int cond_error
( COND_input
*info
, const char *str
)
805 MSICONDITION MSI_EvaluateConditionW
( MSIPACKAGE
*package
, LPCWSTR szCondition
)
809 struct list
*mem
, *safety
;
811 TRACE
("%s\n", debugstr_w
( szCondition
) );
813 if
(szCondition
== NULL
) return MSICONDITION_NONE
;
815 cond.package
= package
;
816 cond.str
= szCondition
;
818 cond.result
= MSICONDITION_ERROR
;
820 list_init
( &cond.mem
);
822 if
( !cond_parse
( &cond
) )
825 r
= MSICONDITION_ERROR
;
827 LIST_FOR_EACH_SAFE
( mem
, safety
, &cond.mem
)
829 /* The tracked memory lives directly after the list struct */
831 if
( r
!= MSICONDITION_ERROR
)
832 WARN
( "condition parser failed to free up some memory: %p\n", ptr
);
836 TRACE
("%i <- %s\n", r
, debugstr_w
(szCondition
));
840 MSICONDITION WINAPI MsiEvaluateConditionW
( MSIHANDLE hInstall
, LPCWSTR szCondition
)
845 package
= msihandle2msiinfo
( hInstall
, MSIHANDLETYPE_PACKAGE
);
850 IWineMsiRemotePackage
*remote_package
;
852 remote_package
= (IWineMsiRemotePackage
*)msi_get_remote
( hInstall
);
854 return MSICONDITION_ERROR
;
856 condition
= SysAllocString
( szCondition
);
859 IWineMsiRemotePackage_Release
( remote_package
);
860 return ERROR_OUTOFMEMORY
;
863 hr
= IWineMsiRemotePackage_EvaluateCondition
( remote_package
, condition
);
865 SysFreeString
( condition
);
866 IWineMsiRemotePackage_Release
( remote_package
);
870 if
(HRESULT_FACILITY
(hr
) == FACILITY_WIN32
)
871 return HRESULT_CODE
(hr
);
873 return ERROR_FUNCTION_FAILED
;
876 return ERROR_SUCCESS
;
879 ret
= MSI_EvaluateConditionW
( package
, szCondition
);
880 msiobj_release
( &package
->hdr
);
884 MSICONDITION WINAPI MsiEvaluateConditionA
( MSIHANDLE hInstall
, LPCSTR szCondition
)
886 LPWSTR szwCond
= NULL
;
889 szwCond
= strdupAtoW
( szCondition
);
890 if
( szCondition
&& !szwCond
)
891 return MSICONDITION_ERROR
;
893 r
= MsiEvaluateConditionW
( hInstall
, szwCond
);