cond.y 21 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
%{

/*
 * Implementation of the Microsoft Installer (msi.dll)
 *
 * Copyright 2003 Mike McCormack for CodeWeavers
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * 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 24
#define COBJMACROS

25 26 27 28 29 30 31 32
#include "config.h"

#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>

#include "windef.h"
#include "winbase.h"
33
#include "winuser.h"
34 35
#include "msi.h"
#include "msiquery.h"
36 37 38
#include "objbase.h"
#include "oleauto.h"

39
#include "msipriv.h"
40 41 42
#include "msiserver.h"
#include "wine/debug.h"
#include "wine/unicode.h"
43
#include "wine/list.h"
44 45 46 47 48

WINE_DEFAULT_DEBUG_CHANNEL(msi);

typedef struct tag_yyinput
{
49
    MSIPACKAGE *package;
50 51 52
    LPCWSTR str;
    INT    n;
    MSICONDITION result;
53
    struct list mem;
54 55
} COND_input;

56 57 58 59 60
struct cond_str {
    LPCWSTR data;
    INT len;
};

61 62
static LPWSTR COND_GetString( COND_input *info, const struct cond_str *str );
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);
65

66 67 68 69
static void *cond_alloc( COND_input *cond, unsigned int sz );
static void *cond_track_mem( COND_input *cond, void *ptr, unsigned int sz );
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 );
72

73
static INT compare_and_free_strings( LPWSTR a, INT op, LPWSTR b, BOOL convert )
74 75 76
{
    INT r;

77
    r = compare_string( a, op, b, convert );
78 79
    cond_free( a );
    cond_free( b );
80 81
    return r;
}
82

83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106
static BOOL num_from_prop( LPCWSTR p, INT *val )
{
    INT ret = 0, sign = 1;

    if (!p)
        return FALSE;
    if (*p == '-')
    {
        sign = -1;
        p++;
    }
    if (!*p)
        return FALSE;
    while (*p)
    {
        if( *p < '0' || *p > '9' )
            return FALSE;
        ret = ret*10 + (*p - '0');
        p++;
    }
    *val = ret*sign;
    return TRUE;
}

107 108
%}

109 110
%lex-param { COND_input *info }
%parse-param { COND_input *info }
111 112 113 114
%pure-parser

%union
{
115
    struct cond_str str;
116 117 118 119
    LPWSTR    string;
    INT       value;
}

120
%token COND_SPACE COND_EOF
121 122 123 124 125
%token COND_OR COND_AND COND_NOT COND_XOR COND_IMP COND_EQV
%token COND_LT COND_GT COND_EQ COND_NE COND_GE COND_LE
%token COND_ILT COND_IGT COND_IEQ COND_INE COND_IGE COND_ILE
%token COND_LPAR COND_RPAR COND_TILDA COND_SS COND_ISS
%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
128

129
%nonassoc COND_ERROR COND_EOF
130

131
%type <value> expression boolean_term boolean_factor 
132 133
%type <value> value_i integer operator
%type <string> identifier symbol_s value_s literal
134 135 136 137

%%

condition:
138
    expression 
139 140 141 142
        {
            COND_input* cond = (COND_input*) info;
            cond->result = $1;
        }
143 144 145 146 147
  | /* empty */
        {
            COND_input* cond = (COND_input*) info;
            cond->result = MSICONDITION_NONE;
        }
148 149 150 151 152 153 154
    ;

expression:
    boolean_term 
        {
            $$ = $1;
        }
155
  | expression COND_OR boolean_term
156 157 158
        {
            $$ = $1 || $3;
        }
159
  | expression COND_IMP boolean_term
160
        {
161
            $$ = !$1 || $3;
162
        }
163
  | expression COND_XOR boolean_term
164
        {
165
            $$ = ( $1 || $3 ) && !( $1 && $3 );
166
        }
167
  | expression COND_EQV boolean_term
168
        {
169
            $$ = ( $1 && $3 ) || ( !$1 && !$3 );
170 171 172
        }
    ;

173 174
boolean_term:
    boolean_factor
175 176 177
        {
            $$ = $1;
        }
178
  | boolean_term COND_AND boolean_factor
179
        {
180
            $$ = $1 && $3;
181 182 183
        }
    ;

184 185
boolean_factor:
    COND_NOT boolean_factor
186
        {
187
            $$ = $2 ? 0 : 1;
188
        }
189
  | value_i
190
        {
191
            $$ = $1 ? 1 : 0;
192
        }
193
  | value_s
194
        {
195
            $$ = ($1 && $1[0]) ? 1 : 0;
196
            cond_free( $1 );
197
        }
198
  | value_i operator value_i
199
        {
200
            $$ = compare_int( $1, $2, $3 );
201
        }
202
  | symbol_s operator value_i
203
        {
204
            int num;
205 206 207 208
            if (num_from_prop( $1, &num ))
                $$ = compare_int( num, $2, $3 );
            else 
                $$ = ($2 == COND_NE || $2 == COND_INE );
209
            cond_free( $1 );
210
        }
211
  | value_i operator symbol_s
212
        {
213
            int num;
214 215 216 217
            if (num_from_prop( $3, &num ))
                $$ = compare_int( $1, $2, num );
            else 
                $$ = ($2 == COND_NE || $2 == COND_INE );
218
            cond_free( $3 );
219
        }
220
  | symbol_s operator symbol_s
221
        {
222
            $$ = compare_and_free_strings( $1, $2, $3, TRUE );
223
        }
224
  | symbol_s operator literal
225
        {
226
            $$ = compare_and_free_strings( $1, $2, $3, TRUE );
227
        }
228
  | literal operator symbol_s
229
        {
230
            $$ = compare_and_free_strings( $1, $2, $3, TRUE );
231
        }
232
  | literal operator literal
233
        {
234
            $$ = compare_and_free_strings( $1, $2, $3, FALSE );
235
        }
236
  | literal operator value_i
237
        {
238
            $$ = 0;
239
            cond_free( $1 );
240
        }
241
  | value_i operator literal
242
        {
243
            $$ = 0;
244
            cond_free( $3 );
245
        }
246
  | COND_LPAR expression COND_RPAR
247
        {
248
            $$ = $2;
249 250 251
        }
    ;

252
operator:
253
    /* common functions */
254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271
    COND_EQ { $$ = COND_EQ; }
  | COND_NE { $$ = COND_NE; }
  | COND_LT { $$ = COND_LT; }
  | COND_GT { $$ = COND_GT; }
  | COND_LE { $$ = COND_LE; }
  | COND_GE { $$ = COND_GE; }
  | COND_SS { $$ = COND_SS; }
  | COND_IEQ { $$ = COND_IEQ; }
  | COND_INE { $$ = COND_INE; }
  | COND_ILT { $$ = COND_ILT; }
  | COND_IGT { $$ = COND_IGT; }
  | COND_ILE { $$ = COND_ILE; }
  | COND_IGE { $$ = COND_IGE; }
  | COND_ISS { $$ = COND_ISS; }
  | COND_LHS { $$ = COND_LHS; }
  | COND_RHS { $$ = COND_RHS; }
  | COND_ILHS { $$ = COND_ILHS; }
  | COND_IRHS { $$ = COND_IRHS; }
272 273
    ;

274
value_s:
275
    symbol_s
276 277 278 279 280 281 282 283 284 285
    {
        $$ = $1;
    } 
  | literal
    {
        $$ = $1;
    }
    ;

literal:
286 287
    COND_LITER
        {
288 289
            COND_input* cond = (COND_input*) info;
            $$ = COND_GetLiteral( cond, &$1 );
290 291 292
            if( !$$ )
                YYABORT;
        }
293 294
    ;

295 296 297 298 299 300
value_i:
    integer
        {
            $$ = $1;
        }
  | COND_DOLLARS identifier
301 302 303 304
        {
            COND_input* cond = (COND_input*) info;
            INSTALLSTATE install = INSTALLSTATE_UNKNOWN, action = INSTALLSTATE_UNKNOWN;
      
305
            MSI_GetComponentStateW(cond->package, $2, &install, &action );
306
            $$ = action;
307
            cond_free( $2 );
308 309 310 311 312 313
        }
  | COND_QUESTION identifier
        {
            COND_input* cond = (COND_input*) info;
            INSTALLSTATE install = INSTALLSTATE_UNKNOWN, action = INSTALLSTATE_UNKNOWN;
      
314
            MSI_GetComponentStateW(cond->package, $2, &install, &action );
315
            $$ = install;
316
            cond_free( $2 );
317 318 319 320 321 322
        }
  | COND_AMPER identifier
        {
            COND_input* cond = (COND_input*) info;
            INSTALLSTATE install = INSTALLSTATE_UNKNOWN, action = INSTALLSTATE_UNKNOWN;
      
323
            MSI_GetFeatureStateW(cond->package, $2, &install, &action );
324 325 326 327 328
            if (action == INSTALLSTATE_UNKNOWN)
                $$ = MSICONDITION_FALSE;
            else
                $$ = action;

329
            cond_free( $2 );
330 331 332 333 334 335
        }
  | COND_EXCLAM identifier
        {
            COND_input* cond = (COND_input*) info;
            INSTALLSTATE install = INSTALLSTATE_UNKNOWN, action = INSTALLSTATE_UNKNOWN;
      
336
            MSI_GetFeatureStateW(cond->package, $2, &install, &action );
337
            $$ = install;
338
            cond_free( $2 );
339 340 341
        }
    ;

342 343
symbol_s:
    identifier
344 345
        {
            COND_input* cond = (COND_input*) info;
346
            UINT len;
347

348
            $$ = msi_dup_property( cond->package->db, $1 );
349 350 351 352 353 354
            if ($$)
            {
                len = (lstrlenW($$) + 1) * sizeof (WCHAR);
                $$ = cond_track_mem( cond, $$, len );
            }
            cond_free( $1 );
355
        }
356
    | COND_PERCENT identifier
357
        {
358
            COND_input* cond = (COND_input*) info;
359
            UINT len = GetEnvironmentVariableW( $2, NULL, 0 );
360 361
            $$ = NULL;
            if (len++)
362
            {
363 364 365
                $$ = cond_alloc( cond, len*sizeof (WCHAR) );
                if( !$$ )
                    YYABORT;
366
                GetEnvironmentVariableW( $2, $$, len );
367
            }
368
            cond_free( $2 );
369 370 371
        }
    ;

372 373 374
identifier:
    COND_IDENT
        {
375 376
            COND_input* cond = (COND_input*) info;
            $$ = COND_GetString( cond, &$1 );
377 378 379 380 381
            if( !$$ )
                YYABORT;
        }
    ;

382 383 384
integer:
    COND_NUMBER
        {
385 386
            COND_input* cond = (COND_input*) info;
            LPWSTR szNum = COND_GetString( cond, &$1 );
387 388 389
            if( !szNum )
                YYABORT;
            $$ = atoiW( szNum );
390
            cond_free( szNum );
391 392 393 394 395 396
        }
    ;

%%


397 398 399 400 401 402 403 404 405
static int COND_IsAlpha( WCHAR x )
{
    return( ( ( x >= 'A' ) && ( x <= 'Z' ) ) ||
            ( ( x >= 'a' ) && ( x <= 'z' ) ) ||
            ( ( x == '_' ) ) );
}

static int COND_IsNumber( WCHAR x )
{
406
    return( (( x >= '0' ) && ( x <= '9' ))  || (x =='-') || (x =='.') );
407 408
}

409 410 411 412 413 414 415 416 417 418 419 420
static WCHAR *strstriW( const WCHAR *str, const WCHAR *sub )
{
    LPWSTR strlower, sublower, r;
    strlower = CharLowerW( strdupW( str ) );
    sublower = CharLowerW( strdupW( sub ) );
    r = strstrW( strlower, sublower );
    if (r)
        r = (LPWSTR)str + (r - strlower);
    msi_free( strlower );
    msi_free( sublower );
    return r;
}
421

422 423 424 425
static BOOL str_is_number( LPCWSTR str )
{
    int i;

426 427 428
    if (!*str)
        return FALSE;

429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456
    for (i = 0; i < lstrlenW( str ); i++)
        if (!isdigitW(str[i]))
            return FALSE;

    return TRUE;
}

static INT compare_substring( LPCWSTR a, INT operator, LPCWSTR b )
{
    int lhs, rhs;

    /* substring operators return 0 if LHS is missing */
    if (!a || !*a)
        return 0;

    /* substring operators return 1 if RHS is missing */
    if (!b || !*b)
        return 1;

    /* if both strings contain only numbers, use integer comparison */
    lhs = atoiW(a);
    rhs = atoiW(b);
    if (str_is_number(a) && str_is_number(b))
        return compare_int( lhs, operator, rhs );

    switch (operator)
    {
    case COND_SS:
457
        return strstrW( a, b ) != 0;
458
    case COND_ISS:
459
        return strstriW( a, b ) != 0;
460
    case COND_LHS:
461 462 463 464 465 466
    {
        int l = strlenW( a );
        int r = strlenW( b );
        if (r > l) return 0;
        return !strncmpW( a, b, r );
    }
467
    case COND_RHS:
468
    {
469 470
        int l = strlenW( a );
        int r = strlenW( b );
471
        if (r > l) return 0;
472
        return !strncmpW( a + (l - r), b, r );
473
    }
474
    case COND_ILHS:
475 476 477 478 479 480
    {
        int l = strlenW( a );
        int r = strlenW( b );
        if (r > l) return 0;
        return !strncmpiW( a, b, r );
    }
481
    case COND_IRHS:
482
    {
483 484
        int l = strlenW( a );
        int r = strlenW( b );
485
        if (r > l) return 0;
486
        return !strncmpiW( a + (l - r), b, r );
487
    }
488
    default:
489
        ERR("invalid substring operator\n");
490 491 492 493 494
        return 0;
    }
    return 0;
}

495
static INT compare_string( LPCWSTR a, INT operator, LPCWSTR b, BOOL convert )
496
{
497 498
    if (operator >= COND_SS && operator <= COND_RHS)
        return compare_substring( a, operator, b );
499

500 501 502
    /* null and empty string are equivalent */
    if (!a) a = szEmpty;
    if (!b) b = szEmpty;
503

504 505 506
    if (convert && str_is_number(a) && str_is_number(b))
        return compare_int( atoiW(a), operator, atoiW(b) );

507
    /* a or b may be NULL */
508 509 510
    switch (operator)
    {
    case COND_LT:
511
        return strcmpW( a, b ) < 0;
512
    case COND_GT:
513
        return strcmpW( a, b ) > 0;
514
    case COND_EQ:
515
        return strcmpW( a, b ) == 0;
516
    case COND_NE:
517
        return strcmpW( a, b ) != 0;
518
    case COND_GE:
519
        return strcmpW( a, b ) >= 0;
520
    case COND_LE:
521
        return strcmpW( a, b ) <= 0;
522
    case COND_ILT:
523
        return strcmpiW( a, b ) < 0;
524
    case COND_IGT:
525
        return strcmpiW( a, b ) > 0;
526
    case COND_IEQ:
527
        return strcmpiW( a, b ) == 0;
528
    case COND_INE:
529
        return strcmpiW( a, b ) != 0;
530
    case COND_IGE:
531
        return strcmpiW( a, b ) >= 0;
532
    case COND_ILE:
533
        return strcmpiW( a, b ) <= 0;
534
    default:
535
        ERR("invalid string operator\n");
536
        return 0;
537 538
    }
    return 0;
539 540 541
}


542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562
static INT compare_int( INT a, INT operator, INT b )
{
    switch (operator)
    {
    case COND_LT:
    case COND_ILT:
        return a < b;
    case COND_GT:
    case COND_IGT:
        return a > b;
    case COND_EQ:
    case COND_IEQ:
        return a == b;
    case COND_NE:
    case COND_INE:
        return a != b;
    case COND_GE:
    case COND_IGE:
        return a >= b;
    case COND_LE:
    case COND_ILE:
563
        return a <= b;
564 565 566 567 568 569 570 571 572 573 574 575 576
    case COND_SS:
    case COND_ISS:
        return ( a & b ) ? 1 : 0;
    case COND_RHS:
        return ( ( a & 0xffff ) == b ) ? 1 : 0;
    case COND_LHS:
        return ( ( (a>>16) & 0xffff ) == b ) ? 1 : 0;
    default:
        ERR("invalid integer operator\n");
        return 0;
    }
    return 0;
}
577 578 579 580


static int COND_IsIdent( WCHAR x )
{
581 582
    return( COND_IsAlpha( x ) || COND_IsNumber( x ) || ( x == '_' ) 
            || ( x == '#' ) || (x == '.') );
583 584
}

585 586 587 588 589 590
static int COND_GetOperator( COND_input *cond )
{
    static const struct {
        const WCHAR str[4];
        int id;
    } table[] = {
591
        { {'~','<','=',0}, COND_ILE },
592 593 594
        { {'~','>','<',0}, COND_ISS },
        { {'~','>','>',0}, COND_IRHS },
        { {'~','<','>',0}, COND_INE },
595
        { {'~','>','=',0}, COND_IGE },
596
        { {'~','<','<',0}, COND_ILHS },
597 598
        { {'~','=',0},     COND_IEQ },
        { {'~','<',0},     COND_ILT },
599
        { {'~','>',0},     COND_IGT },
600 601
        { {'>','=',0},     COND_GE  },
        { {'>','<',0},     COND_SS  },
602
        { {'<','<',0},     COND_LHS },
603 604
        { {'<','>',0},     COND_NE  },
        { {'<','=',0},     COND_LE  },
605
        { {'>','>',0},     COND_RHS },
606
        { {'>',0},         COND_GT  },
607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623
        { {'<',0},         COND_LT  },
        { {0},             0        }
    };
    LPCWSTR p = &cond->str[cond->n];
    int i = 0, len;

    while ( 1 )
    {
        len = lstrlenW( table[i].str );
        if ( !len || 0 == strncmpW( table[i].str, p, len ) )
            break;
        i++;
    }
    cond->n += len;
    return table[i].id;
}

624
static int COND_GetOne( struct cond_str *str, COND_input *cond )
625
{
626
    int rc, len = 1;
627
    WCHAR ch;
628

629
    str->data = &cond->str[cond->n];
630

631
    ch = str->data[0];
632

633 634
    switch( ch )
    {
635
    case 0: return 0;
636 637 638 639 640 641 642 643 644
    case '(': rc = COND_LPAR; break;
    case ')': rc = COND_RPAR; break;
    case '&': rc = COND_AMPER; break;
    case '!': rc = COND_EXCLAM; break;
    case '$': rc = COND_DOLLARS; break;
    case '?': rc = COND_QUESTION; break;
    case '%': rc = COND_PERCENT; break;
    case ' ': rc = COND_SPACE; break;
    case '=': rc = COND_EQ; break;
645

646 647 648 649 650 651 652 653 654 655
    case '~':
    case '<':
    case '>':
        rc = COND_GetOperator( cond );
        if (!rc)
            rc = COND_ERROR;
        return rc;
    default:
        rc = 0;
    }
656

657 658 659 660
    if ( rc )
    {
        cond->n += len;
        return rc;
661
    }
662

663
    if (ch == '"' )
664
    {
665
        LPCWSTR p = strchrW( str->data + 1, '"' );
666
        if (!p) return COND_ERROR;
667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696
        len = p - str->data + 1;
        rc = COND_LITER;
    }
    else if( COND_IsAlpha( ch ) )
    {
        static const WCHAR szNot[] = {'N','O','T',0};
        static const WCHAR szAnd[] = {'A','N','D',0};
        static const WCHAR szXor[] = {'X','O','R',0};
        static const WCHAR szEqv[] = {'E','Q','V',0};
        static const WCHAR szImp[] = {'I','M','P',0};
        static const WCHAR szOr[] = {'O','R',0};

        while( COND_IsIdent( str->data[len] ) )
            len++;
        rc = COND_IDENT;

        if ( len == 3 )
        {
            if ( !strncmpiW( str->data, szNot, len ) )
                rc = COND_NOT;
            else if( !strncmpiW( str->data, szAnd, len ) )
                rc = COND_AND;
            else if( !strncmpiW( str->data, szXor, len ) )
                rc = COND_XOR;
            else if( !strncmpiW( str->data, szEqv, len ) )
                rc = COND_EQV;
            else if( !strncmpiW( str->data, szImp, len ) )
                rc = COND_IMP;
        }
        else if( (len == 2) && !strncmpiW( str->data, szOr, len ) )
697
            rc = COND_OR;
698
    }
699 700 701 702 703 704 705 706 707 708 709
    else if( COND_IsNumber( ch ) )
    {
        while( COND_IsNumber( str->data[len] ) )
            len++;
        rc = COND_NUMBER;
    }
    else
    {
        ERR("Got unknown character %c(%x)\n",ch,ch);
        return COND_ERROR;
    }
710 711 712 713 714 715 716

    cond->n += len;
    str->len = len;

    return rc;
}

717
static int cond_lex( void *COND_lval, COND_input *cond )
718 719 720 721 722 723 724
{
    int rc;
    struct cond_str *str = COND_lval;

    do {
        rc = COND_GetOne( str, cond );
    } while (rc == COND_SPACE);
725 726
    
    return rc;
727 728
}

729
static LPWSTR COND_GetString( COND_input *cond, const struct cond_str *str )
730
{
731
    LPWSTR ret;
732

733
    ret = cond_alloc( cond, (str->len+1) * sizeof (WCHAR) );
734
    if( ret )
735
    {
736
        memcpy( ret, str->data, str->len * sizeof(WCHAR));
737
        ret[str->len]=0;
738
    }
739 740
    TRACE("Got identifier %s\n",debugstr_w(ret));
    return ret;
741 742
}

743
static LPWSTR COND_GetLiteral( COND_input *cond, const struct cond_str *str )
744 745 746
{
    LPWSTR ret;

747
    ret = cond_alloc( cond, (str->len-1) * sizeof (WCHAR) );
748 749 750 751 752 753 754 755 756
    if( ret )
    {
        memcpy( ret, str->data+1, (str->len-2) * sizeof(WCHAR) );
        ret[str->len - 2]=0;
    }
    TRACE("Got literal %s\n",debugstr_w(ret));
    return ret;
}

757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798
static void *cond_alloc( COND_input *cond, unsigned int sz )
{
    struct list *mem;

    mem = msi_alloc( sizeof (struct list) + sz );
    if( !mem )
        return NULL;

    list_add_head( &(cond->mem), mem );
    return mem + 1;
}

static void *cond_track_mem( COND_input *cond, void *ptr, unsigned int sz )
{
    void *new_ptr;

    if( !ptr )
        return ptr;

    new_ptr = cond_alloc( cond, sz );
    if( !new_ptr )
    {
        msi_free( ptr );
        return NULL;
    }

    memcpy( new_ptr, ptr, sz );
    msi_free( ptr );
    return new_ptr;
}

static void cond_free( void *ptr )
{
    struct list *mem = (struct list *)ptr - 1;

    if( ptr )
    {
        list_remove( mem );
        msi_free( mem );
    }
}

799
static int cond_error( COND_input *info, const char *str )
800
{
801
    TRACE("%s\n", str );
802 803 804
    return 0;
}

805
MSICONDITION MSI_EvaluateConditionW( MSIPACKAGE *package, LPCWSTR szCondition )
806 807 808
{
    COND_input cond;
    MSICONDITION r;
809
    struct list *mem, *safety;
810

811 812
    TRACE("%s\n", debugstr_w( szCondition ) );

813
    if (szCondition == NULL) return MSICONDITION_NONE;
814

815
    cond.package = package;
816 817
    cond.str   = szCondition;
    cond.n     = 0;
818
    cond.result = MSICONDITION_ERROR;
819 820 821

    list_init( &cond.mem );

822
    if ( !cond_parse( &cond ) )
823 824 825 826
        r = cond.result;
    else
        r = MSICONDITION_ERROR;

827 828 829 830 831 832 833 834 835
    LIST_FOR_EACH_SAFE( mem, safety, &cond.mem )
    {
        /* The tracked memory lives directly after the list struct */
        void *ptr = mem + 1;
        if ( r != MSICONDITION_ERROR )
            WARN( "condition parser failed to free up some memory: %p\n", ptr );
        cond_free( ptr );
    }

836
    TRACE("%i <- %s\n", r, debugstr_w(szCondition));
837 838 839
    return r;
}

840 841 842 843 844 845
MSICONDITION WINAPI MsiEvaluateConditionW( MSIHANDLE hInstall, LPCWSTR szCondition )
{
    MSIPACKAGE *package;
    UINT ret;

    package = msihandle2msiinfo( hInstall, MSIHANDLETYPE_PACKAGE);
846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878
    if( !package )
    {
        HRESULT hr;
        BSTR condition;
        IWineMsiRemotePackage *remote_package;

        remote_package = (IWineMsiRemotePackage *)msi_get_remote( hInstall );
        if (!remote_package)
            return MSICONDITION_ERROR;

        condition = SysAllocString( szCondition );
        if (!condition)
        {
            IWineMsiRemotePackage_Release( remote_package );
            return ERROR_OUTOFMEMORY;
        }

        hr = IWineMsiRemotePackage_EvaluateCondition( remote_package, condition );

        SysFreeString( condition );
        IWineMsiRemotePackage_Release( remote_package );

        if (FAILED(hr))
        {
            if (HRESULT_FACILITY(hr) == FACILITY_WIN32)
                return HRESULT_CODE(hr);

            return ERROR_FUNCTION_FAILED;
        }

        return ERROR_SUCCESS;
    }

879 880 881 882 883
    ret = MSI_EvaluateConditionW( package, szCondition );
    msiobj_release( &package->hdr );
    return ret;
}

884 885 886 887 888
MSICONDITION WINAPI MsiEvaluateConditionA( MSIHANDLE hInstall, LPCSTR szCondition )
{
    LPWSTR szwCond = NULL;
    MSICONDITION r;

889 890 891
    szwCond = strdupAtoW( szCondition );
    if( szCondition && !szwCond )
        return MSICONDITION_ERROR;
892 893

    r = MsiEvaluateConditionW( hInstall, szwCond );
894
    msi_free( szwCond );
895 896
    return r;
}