diff options
Diffstat (limited to 'src/engine/condition.cpp')
-rw-r--r-- | src/engine/condition.cpp | 1030 |
1 files changed, 1030 insertions, 0 deletions
diff --git a/src/engine/condition.cpp b/src/engine/condition.cpp new file mode 100644 index 00000000..28391d2d --- /dev/null +++ b/src/engine/condition.cpp | |||
@@ -0,0 +1,1030 @@ | |||
1 | // Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. | ||
2 | |||
3 | #include "precomp.h" | ||
4 | |||
5 | |||
6 | // | ||
7 | // parse rules | ||
8 | // | ||
9 | // value variable | literal | integer | version | ||
10 | // comparison-operator < | > | <= | >= | = | <> | >< | << | >> | ||
11 | // term value | value comparison-operator value | ( expression ) | ||
12 | // boolean-factor term | NOT term | ||
13 | // boolean-term boolean-factor | boolean-factor AND boolean-term | ||
14 | // expression boolean-term | boolean-term OR expression | ||
15 | // | ||
16 | |||
17 | |||
18 | // constants | ||
19 | |||
20 | #define COMPARISON 0x00010000 | ||
21 | #define INSENSITIVE 0x00020000 | ||
22 | |||
23 | enum BURN_SYMBOL_TYPE | ||
24 | { | ||
25 | // terminals | ||
26 | BURN_SYMBOL_TYPE_NONE = 0, | ||
27 | BURN_SYMBOL_TYPE_END = 1, | ||
28 | BURN_SYMBOL_TYPE_OR = 2, // OR | ||
29 | BURN_SYMBOL_TYPE_AND = 3, // AND | ||
30 | BURN_SYMBOL_TYPE_NOT = 4, // NOT | ||
31 | BURN_SYMBOL_TYPE_LT = 5 | COMPARISON, // < | ||
32 | BURN_SYMBOL_TYPE_GT = 6 | COMPARISON, // > | ||
33 | BURN_SYMBOL_TYPE_LE = 7 | COMPARISON, // <= | ||
34 | BURN_SYMBOL_TYPE_GE = 8 | COMPARISON, // >= | ||
35 | BURN_SYMBOL_TYPE_EQ = 9 | COMPARISON, // = | ||
36 | BURN_SYMBOL_TYPE_NE = 10 | COMPARISON, // <> | ||
37 | BURN_SYMBOL_TYPE_BAND = 11 | COMPARISON, // >< | ||
38 | BURN_SYMBOL_TYPE_HIEQ = 12 | COMPARISON, // << | ||
39 | BURN_SYMBOL_TYPE_LOEQ = 13 | COMPARISON, // >> | ||
40 | BURN_SYMBOL_TYPE_LT_I = 5 | COMPARISON | INSENSITIVE, // ~< | ||
41 | BURN_SYMBOL_TYPE_GT_I = 6 | COMPARISON | INSENSITIVE, // ~> | ||
42 | BURN_SYMBOL_TYPE_LE_I = 7 | COMPARISON | INSENSITIVE, // ~<= | ||
43 | BURN_SYMBOL_TYPE_GE_I = 8 | COMPARISON | INSENSITIVE, // ~>= | ||
44 | BURN_SYMBOL_TYPE_EQ_I = 9 | COMPARISON | INSENSITIVE, // ~= | ||
45 | BURN_SYMBOL_TYPE_NE_I = 10 | COMPARISON | INSENSITIVE, // ~<> | ||
46 | BURN_SYMBOL_TYPE_BAND_I = 11 | COMPARISON | INSENSITIVE, // ~>< | ||
47 | BURN_SYMBOL_TYPE_HIEQ_I = 12 | COMPARISON | INSENSITIVE, // ~<< | ||
48 | BURN_SYMBOL_TYPE_LOEQ_I = 13 | COMPARISON | INSENSITIVE, // ~>> | ||
49 | BURN_SYMBOL_TYPE_LPAREN = 14, // ( | ||
50 | BURN_SYMBOL_TYPE_RPAREN = 15, // ) | ||
51 | BURN_SYMBOL_TYPE_NUMBER = 16, | ||
52 | BURN_SYMBOL_TYPE_IDENTIFIER = 17, | ||
53 | BURN_SYMBOL_TYPE_LITERAL = 18, | ||
54 | BURN_SYMBOL_TYPE_VERSION = 19, | ||
55 | }; | ||
56 | |||
57 | |||
58 | // structs | ||
59 | |||
60 | struct BURN_SYMBOL | ||
61 | { | ||
62 | BURN_SYMBOL_TYPE Type; | ||
63 | DWORD iPosition; | ||
64 | BURN_VARIANT Value; | ||
65 | }; | ||
66 | |||
67 | struct BURN_CONDITION_PARSE_CONTEXT | ||
68 | { | ||
69 | BURN_VARIABLES* pVariables; | ||
70 | LPCWSTR wzCondition; | ||
71 | LPCWSTR wzRead; | ||
72 | BURN_SYMBOL NextSymbol; | ||
73 | BOOL fError; | ||
74 | }; | ||
75 | |||
76 | |||
77 | // internal function declarations | ||
78 | |||
79 | static HRESULT ParseExpression( | ||
80 | __in BURN_CONDITION_PARSE_CONTEXT* pContext, | ||
81 | __out BOOL* pf | ||
82 | ); | ||
83 | static HRESULT ParseBooleanTerm( | ||
84 | __in BURN_CONDITION_PARSE_CONTEXT* pContext, | ||
85 | __out BOOL* pf | ||
86 | ); | ||
87 | static HRESULT ParseBooleanFactor( | ||
88 | __in BURN_CONDITION_PARSE_CONTEXT* pContext, | ||
89 | __out BOOL* pf | ||
90 | ); | ||
91 | static HRESULT ParseTerm( | ||
92 | __in BURN_CONDITION_PARSE_CONTEXT* pContext, | ||
93 | __out BOOL* pf | ||
94 | ); | ||
95 | static HRESULT ParseValue( | ||
96 | __in BURN_CONDITION_PARSE_CONTEXT* pContext, | ||
97 | __out BURN_VARIANT* pValue | ||
98 | ); | ||
99 | static HRESULT Expect( | ||
100 | __in BURN_CONDITION_PARSE_CONTEXT* pContext, | ||
101 | __in BURN_SYMBOL_TYPE symbolType | ||
102 | ); | ||
103 | static HRESULT NextSymbol( | ||
104 | __in BURN_CONDITION_PARSE_CONTEXT* pContext | ||
105 | ); | ||
106 | static HRESULT CompareValues( | ||
107 | __in BURN_SYMBOL_TYPE comparison, | ||
108 | __in BURN_VARIANT leftOperand, | ||
109 | __in BURN_VARIANT rightOperand, | ||
110 | __out BOOL* pfResult | ||
111 | ); | ||
112 | static HRESULT CompareStringValues( | ||
113 | __in BURN_SYMBOL_TYPE comparison, | ||
114 | __in_z LPCWSTR wzLeftOperand, | ||
115 | __in_z LPCWSTR wzRightOperand, | ||
116 | __out BOOL* pfResult | ||
117 | ); | ||
118 | static HRESULT CompareIntegerValues( | ||
119 | __in BURN_SYMBOL_TYPE comparison, | ||
120 | __in LONGLONG llLeftOperand, | ||
121 | __in LONGLONG llRightOperand, | ||
122 | __out BOOL* pfResult | ||
123 | ); | ||
124 | static HRESULT CompareVersionValues( | ||
125 | __in BURN_SYMBOL_TYPE comparison, | ||
126 | __in DWORD64 qwLeftOperand, | ||
127 | __in DWORD64 qwRightOperand, | ||
128 | __out BOOL* pfResult | ||
129 | ); | ||
130 | |||
131 | |||
132 | // function definitions | ||
133 | |||
134 | extern "C" HRESULT ConditionEvaluate( | ||
135 | __in BURN_VARIABLES* pVariables, | ||
136 | __in_z LPCWSTR wzCondition, | ||
137 | __out BOOL* pf | ||
138 | ) | ||
139 | { | ||
140 | HRESULT hr = S_OK; | ||
141 | BURN_CONDITION_PARSE_CONTEXT context = { }; | ||
142 | BOOL f = FALSE; | ||
143 | |||
144 | context.pVariables = pVariables; | ||
145 | context.wzCondition = wzCondition; | ||
146 | context.wzRead = wzCondition; | ||
147 | |||
148 | hr = NextSymbol(&context); | ||
149 | ExitOnFailure(hr, "Failed to read next symbol."); | ||
150 | |||
151 | hr = ParseExpression(&context, &f); | ||
152 | ExitOnFailure(hr, "Failed to parse expression."); | ||
153 | |||
154 | hr = Expect(&context, BURN_SYMBOL_TYPE_END); | ||
155 | ExitOnFailure(hr, "Failed to expect end symbol."); | ||
156 | |||
157 | LogId(REPORT_VERBOSE, MSG_CONDITION_RESULT, wzCondition, LoggingTrueFalseToString(f)); | ||
158 | |||
159 | *pf = f; | ||
160 | hr = S_OK; | ||
161 | |||
162 | LExit: | ||
163 | if (context.fError) | ||
164 | { | ||
165 | Assert(FAILED(hr)); | ||
166 | LogErrorId(hr, MSG_FAILED_PARSE_CONDITION, wzCondition, NULL, NULL); | ||
167 | } | ||
168 | |||
169 | return hr; | ||
170 | } | ||
171 | |||
172 | extern "C" HRESULT ConditionGlobalCheck( | ||
173 | __in BURN_VARIABLES* pVariables, | ||
174 | __in BURN_CONDITION* pCondition, | ||
175 | __in BOOTSTRAPPER_DISPLAY display, | ||
176 | __in_z LPCWSTR wzBundleName, | ||
177 | __out DWORD *pdwExitCode, | ||
178 | __out BOOL *pfContinueExecution | ||
179 | ) | ||
180 | { | ||
181 | HRESULT hr = S_OK; | ||
182 | BOOL fSuccess = TRUE; | ||
183 | HRESULT hrError = HRESULT_FROM_WIN32(ERROR_OLD_WIN_VERSION); | ||
184 | OS_VERSION osv = OS_VERSION_UNKNOWN; | ||
185 | DWORD dwServicePack = 0; | ||
186 | |||
187 | OsGetVersion(&osv, &dwServicePack); | ||
188 | |||
189 | // Always error on Windows 2000 or lower | ||
190 | if (OS_VERSION_WIN2000 >= osv) | ||
191 | { | ||
192 | fSuccess = FALSE; | ||
193 | } | ||
194 | else | ||
195 | { | ||
196 | if (NULL != pCondition->sczConditionString) | ||
197 | { | ||
198 | hr = ConditionEvaluate(pVariables, pCondition->sczConditionString, &fSuccess); | ||
199 | ExitOnFailure(hr, "Failed to evaluate condition: %ls", pCondition->sczConditionString); | ||
200 | } | ||
201 | } | ||
202 | |||
203 | if (!fSuccess) | ||
204 | { | ||
205 | // Display the error messagebox, as long as we're in an appropriate display mode | ||
206 | hr = SplashScreenDisplayError(display, wzBundleName, hrError); | ||
207 | ExitOnFailure(hr, "Failed to display error dialog"); | ||
208 | |||
209 | *pdwExitCode = static_cast<DWORD>(hrError); | ||
210 | *pfContinueExecution = FALSE; | ||
211 | } | ||
212 | |||
213 | LExit: | ||
214 | return hr; | ||
215 | } | ||
216 | |||
217 | HRESULT ConditionGlobalParseFromXml( | ||
218 | __in BURN_CONDITION* pCondition, | ||
219 | __in IXMLDOMNode* pixnBundle | ||
220 | ) | ||
221 | { | ||
222 | HRESULT hr = S_OK; | ||
223 | IXMLDOMNode* pixnNode = NULL; | ||
224 | BSTR bstrExpression = NULL; | ||
225 | |||
226 | // select variable nodes | ||
227 | hr = XmlSelectSingleNode(pixnBundle, L"Condition", &pixnNode); | ||
228 | if (S_FALSE == hr) | ||
229 | { | ||
230 | ExitFunction1(hr = S_OK); | ||
231 | } | ||
232 | ExitOnFailure(hr, "Failed to select condition node."); | ||
233 | |||
234 | // @Condition | ||
235 | hr = XmlGetText(pixnNode, &bstrExpression); | ||
236 | ExitOnFailure(hr, "Failed to get Condition inner text."); | ||
237 | |||
238 | hr = StrAllocString(&pCondition->sczConditionString, bstrExpression, 0); | ||
239 | ExitOnFailure(hr, "Failed to copy condition string from BSTR"); | ||
240 | |||
241 | LExit: | ||
242 | ReleaseBSTR(bstrExpression); | ||
243 | ReleaseObject(pixnNode); | ||
244 | |||
245 | return hr; | ||
246 | } | ||
247 | |||
248 | |||
249 | // internal function definitions | ||
250 | |||
251 | static HRESULT ParseExpression( | ||
252 | __in BURN_CONDITION_PARSE_CONTEXT* pContext, | ||
253 | __out BOOL* pf | ||
254 | ) | ||
255 | { | ||
256 | HRESULT hr = S_OK; | ||
257 | BOOL fFirst = FALSE; | ||
258 | BOOL fSecond = FALSE; | ||
259 | |||
260 | hr = ParseBooleanTerm(pContext, &fFirst); | ||
261 | ExitOnFailure(hr, "Failed to parse boolean-term."); | ||
262 | |||
263 | if (BURN_SYMBOL_TYPE_OR == pContext->NextSymbol.Type) | ||
264 | { | ||
265 | hr = NextSymbol(pContext); | ||
266 | ExitOnFailure(hr, "Failed to read next symbol."); | ||
267 | |||
268 | hr = ParseExpression(pContext, &fSecond); | ||
269 | ExitOnFailure(hr, "Failed to parse expression."); | ||
270 | |||
271 | *pf = fFirst || fSecond; | ||
272 | } | ||
273 | else | ||
274 | { | ||
275 | *pf = fFirst; | ||
276 | } | ||
277 | |||
278 | LExit: | ||
279 | return hr; | ||
280 | } | ||
281 | |||
282 | static HRESULT ParseBooleanTerm( | ||
283 | __in BURN_CONDITION_PARSE_CONTEXT* pContext, | ||
284 | __out BOOL* pf | ||
285 | ) | ||
286 | { | ||
287 | HRESULT hr = S_OK; | ||
288 | BOOL fFirst = FALSE; | ||
289 | BOOL fSecond = FALSE; | ||
290 | |||
291 | hr = ParseBooleanFactor(pContext, &fFirst); | ||
292 | ExitOnFailure(hr, "Failed to parse boolean-factor."); | ||
293 | |||
294 | if (BURN_SYMBOL_TYPE_AND == pContext->NextSymbol.Type) | ||
295 | { | ||
296 | hr = NextSymbol(pContext); | ||
297 | ExitOnFailure(hr, "Failed to read next symbol."); | ||
298 | |||
299 | hr = ParseBooleanTerm(pContext, &fSecond); | ||
300 | ExitOnFailure(hr, "Failed to parse boolean-term."); | ||
301 | |||
302 | *pf = fFirst && fSecond; | ||
303 | } | ||
304 | else | ||
305 | { | ||
306 | *pf = fFirst; | ||
307 | } | ||
308 | |||
309 | LExit: | ||
310 | return hr; | ||
311 | } | ||
312 | |||
313 | static HRESULT ParseBooleanFactor( | ||
314 | __in BURN_CONDITION_PARSE_CONTEXT* pContext, | ||
315 | __out BOOL* pf | ||
316 | ) | ||
317 | { | ||
318 | HRESULT hr = S_OK; | ||
319 | BOOL fNot = FALSE; | ||
320 | BOOL f = FALSE; | ||
321 | |||
322 | if (BURN_SYMBOL_TYPE_NOT == pContext->NextSymbol.Type) | ||
323 | { | ||
324 | hr = NextSymbol(pContext); | ||
325 | ExitOnFailure(hr, "Failed to read next symbol."); | ||
326 | |||
327 | fNot = TRUE; | ||
328 | } | ||
329 | |||
330 | hr = ParseTerm(pContext, &f); | ||
331 | ExitOnFailure(hr, "Failed to parse term."); | ||
332 | |||
333 | *pf = fNot ? !f : f; | ||
334 | |||
335 | LExit: | ||
336 | return hr; | ||
337 | } | ||
338 | |||
339 | static HRESULT ParseTerm( | ||
340 | __in BURN_CONDITION_PARSE_CONTEXT* pContext, | ||
341 | __out BOOL* pf | ||
342 | ) | ||
343 | { | ||
344 | HRESULT hr = S_OK; | ||
345 | BURN_VARIANT firstValue = { }; | ||
346 | BURN_VARIANT secondValue = { }; | ||
347 | |||
348 | if (BURN_SYMBOL_TYPE_LPAREN == pContext->NextSymbol.Type) | ||
349 | { | ||
350 | hr = NextSymbol(pContext); | ||
351 | ExitOnFailure(hr, "Failed to read next symbol."); | ||
352 | |||
353 | hr = ParseExpression(pContext, pf); | ||
354 | ExitOnFailure(hr, "Failed to parse expression."); | ||
355 | |||
356 | hr = Expect(pContext, BURN_SYMBOL_TYPE_RPAREN); | ||
357 | ExitOnFailure(hr, "Failed to expect right parenthesis."); | ||
358 | |||
359 | ExitFunction1(hr = S_OK); | ||
360 | } | ||
361 | |||
362 | hr = ParseValue(pContext, &firstValue); | ||
363 | ExitOnFailure(hr, "Failed to parse value."); | ||
364 | |||
365 | if (COMPARISON & pContext->NextSymbol.Type) | ||
366 | { | ||
367 | BURN_SYMBOL_TYPE comparison = pContext->NextSymbol.Type; | ||
368 | |||
369 | hr = NextSymbol(pContext); | ||
370 | ExitOnFailure(hr, "Failed to read next symbol."); | ||
371 | |||
372 | hr = ParseValue(pContext, &secondValue); | ||
373 | ExitOnFailure(hr, "Failed to parse value."); | ||
374 | |||
375 | hr = CompareValues(comparison, firstValue, secondValue, pf); | ||
376 | ExitOnFailure(hr, "Failed to compare value."); | ||
377 | } | ||
378 | else | ||
379 | { | ||
380 | LONGLONG llValue = 0; | ||
381 | LPWSTR sczValue = NULL; | ||
382 | DWORD64 qwValue = 0; | ||
383 | switch (firstValue.Type) | ||
384 | { | ||
385 | case BURN_VARIANT_TYPE_NONE: | ||
386 | *pf = FALSE; | ||
387 | break; | ||
388 | case BURN_VARIANT_TYPE_STRING: | ||
389 | hr = BVariantGetString(&firstValue, &sczValue); | ||
390 | if (SUCCEEDED(hr)) | ||
391 | { | ||
392 | *pf = sczValue && *sczValue; | ||
393 | } | ||
394 | StrSecureZeroFreeString(sczValue); | ||
395 | break; | ||
396 | case BURN_VARIANT_TYPE_NUMERIC: | ||
397 | hr = BVariantGetNumeric(&firstValue, &llValue); | ||
398 | if (SUCCEEDED(hr)) | ||
399 | { | ||
400 | *pf = 0 != llValue; | ||
401 | } | ||
402 | SecureZeroMemory(&llValue, sizeof(llValue)); | ||
403 | break; | ||
404 | case BURN_VARIANT_TYPE_VERSION: | ||
405 | hr = BVariantGetVersion(&firstValue, &qwValue); | ||
406 | if (SUCCEEDED(hr)) | ||
407 | { | ||
408 | *pf = 0 != qwValue; | ||
409 | } | ||
410 | SecureZeroMemory(&llValue, sizeof(qwValue)); | ||
411 | break; | ||
412 | default: | ||
413 | ExitFunction1(hr = E_UNEXPECTED); | ||
414 | } | ||
415 | } | ||
416 | |||
417 | LExit: | ||
418 | BVariantUninitialize(&firstValue); | ||
419 | BVariantUninitialize(&secondValue); | ||
420 | return hr; | ||
421 | } | ||
422 | |||
423 | static HRESULT ParseValue( | ||
424 | __in BURN_CONDITION_PARSE_CONTEXT* pContext, | ||
425 | __out BURN_VARIANT* pValue | ||
426 | ) | ||
427 | { | ||
428 | HRESULT hr = S_OK; | ||
429 | |||
430 | // Symbols don't encrypt their value, so can access the value directly. | ||
431 | switch (pContext->NextSymbol.Type) | ||
432 | { | ||
433 | case BURN_SYMBOL_TYPE_IDENTIFIER: | ||
434 | Assert(BURN_VARIANT_TYPE_STRING == pContext->NextSymbol.Value.Type); | ||
435 | |||
436 | // find variable | ||
437 | hr = VariableGetVariant(pContext->pVariables, pContext->NextSymbol.Value.sczValue, pValue); | ||
438 | if (E_NOTFOUND != hr) | ||
439 | { | ||
440 | ExitOnRootFailure(hr, "Failed to find variable."); | ||
441 | } | ||
442 | break; | ||
443 | |||
444 | case BURN_SYMBOL_TYPE_NUMBER: __fallthrough; | ||
445 | case BURN_SYMBOL_TYPE_LITERAL: __fallthrough; | ||
446 | case BURN_SYMBOL_TYPE_VERSION: | ||
447 | // steal value of symbol | ||
448 | memcpy_s(pValue, sizeof(BURN_VARIANT), &pContext->NextSymbol.Value, sizeof(BURN_VARIANT)); | ||
449 | memset(&pContext->NextSymbol.Value, 0, sizeof(BURN_VARIANT)); | ||
450 | break; | ||
451 | |||
452 | default: | ||
453 | pContext->fError = TRUE; | ||
454 | hr = E_INVALIDDATA; | ||
455 | ExitOnRootFailure(hr, "Failed to parse condition '%ls' at position: %u", pContext->wzCondition, pContext->NextSymbol.iPosition); | ||
456 | } | ||
457 | |||
458 | // get next symbol | ||
459 | hr = NextSymbol(pContext); | ||
460 | ExitOnFailure(hr, "Failed to read next symbol."); | ||
461 | |||
462 | LExit: | ||
463 | return hr; | ||
464 | } | ||
465 | |||
466 | // | ||
467 | // Expect - expects a symbol. | ||
468 | // | ||
469 | static HRESULT Expect( | ||
470 | __in BURN_CONDITION_PARSE_CONTEXT* pContext, | ||
471 | __in BURN_SYMBOL_TYPE symbolType | ||
472 | ) | ||
473 | { | ||
474 | HRESULT hr = S_OK; | ||
475 | |||
476 | if (pContext->NextSymbol.Type != symbolType) | ||
477 | { | ||
478 | pContext->fError = TRUE; | ||
479 | hr = E_INVALIDDATA; | ||
480 | ExitOnRootFailure(hr, "Failed to parse condition '%ls' at position: %u", pContext->wzCondition, pContext->NextSymbol.iPosition); | ||
481 | } | ||
482 | |||
483 | hr = NextSymbol(pContext); | ||
484 | ExitOnFailure(hr, "Failed to read next symbol."); | ||
485 | |||
486 | LExit: | ||
487 | return hr; | ||
488 | } | ||
489 | |||
490 | // | ||
491 | // NextSymbol - finds the next symbol in an expression string. | ||
492 | // | ||
493 | static HRESULT NextSymbol( | ||
494 | __in BURN_CONDITION_PARSE_CONTEXT* pContext | ||
495 | ) | ||
496 | { | ||
497 | HRESULT hr = S_OK; | ||
498 | WORD charType = 0; | ||
499 | DWORD iPosition = 0; | ||
500 | DWORD n = 0; | ||
501 | |||
502 | // free existing symbol | ||
503 | BVariantUninitialize(&pContext->NextSymbol.Value); | ||
504 | memset(&pContext->NextSymbol, 0, sizeof(BURN_SYMBOL)); | ||
505 | |||
506 | // skip past blanks | ||
507 | while (L'\0' != pContext->wzRead[0]) | ||
508 | { | ||
509 | ::GetStringTypeW(CT_CTYPE1, pContext->wzRead, 1, &charType); | ||
510 | if (0 == (C1_BLANK & charType)) | ||
511 | { | ||
512 | break; // no blank, done | ||
513 | } | ||
514 | ++pContext->wzRead; | ||
515 | } | ||
516 | iPosition = (DWORD)(pContext->wzRead - pContext->wzCondition); | ||
517 | |||
518 | // read depending on first character type | ||
519 | switch (pContext->wzRead[0]) | ||
520 | { | ||
521 | case L'\0': | ||
522 | pContext->NextSymbol.Type = BURN_SYMBOL_TYPE_END; | ||
523 | break; | ||
524 | case L'~': | ||
525 | switch (pContext->wzRead[1]) | ||
526 | { | ||
527 | case L'=': | ||
528 | pContext->NextSymbol.Type = BURN_SYMBOL_TYPE_EQ_I; | ||
529 | n = 2; | ||
530 | break; | ||
531 | case L'>': | ||
532 | switch (pContext->wzRead[2]) | ||
533 | { | ||
534 | case '=': | ||
535 | pContext->NextSymbol.Type = BURN_SYMBOL_TYPE_GE_I; | ||
536 | n = 3; | ||
537 | break; | ||
538 | case L'>': | ||
539 | pContext->NextSymbol.Type = BURN_SYMBOL_TYPE_LOEQ_I; | ||
540 | n = 3; | ||
541 | break; | ||
542 | case L'<': | ||
543 | pContext->NextSymbol.Type = BURN_SYMBOL_TYPE_BAND_I; | ||
544 | n = 3; | ||
545 | break; | ||
546 | default: | ||
547 | pContext->NextSymbol.Type = BURN_SYMBOL_TYPE_GT_I; | ||
548 | n = 2; | ||
549 | } | ||
550 | break; | ||
551 | case L'<': | ||
552 | switch (pContext->wzRead[2]) | ||
553 | { | ||
554 | case '=': | ||
555 | pContext->NextSymbol.Type = BURN_SYMBOL_TYPE_LE_I; | ||
556 | n = 3; | ||
557 | break; | ||
558 | case L'<': | ||
559 | pContext->NextSymbol.Type = BURN_SYMBOL_TYPE_HIEQ_I; | ||
560 | n = 3; | ||
561 | break; | ||
562 | case '>': | ||
563 | pContext->NextSymbol.Type = BURN_SYMBOL_TYPE_NE_I; | ||
564 | n = 3; | ||
565 | break; | ||
566 | default: | ||
567 | pContext->NextSymbol.Type = BURN_SYMBOL_TYPE_LT_I; | ||
568 | n = 2; | ||
569 | } | ||
570 | break; | ||
571 | default: | ||
572 | // error | ||
573 | pContext->fError = TRUE; | ||
574 | hr = E_INVALIDDATA; | ||
575 | ExitOnRootFailure(hr, "Failed to parse condition \"%ls\". Unexpected '~' operator at position %d.", pContext->wzCondition, iPosition); | ||
576 | } | ||
577 | break; | ||
578 | case L'>': | ||
579 | switch (pContext->wzRead[1]) | ||
580 | { | ||
581 | case L'=': | ||
582 | pContext->NextSymbol.Type = BURN_SYMBOL_TYPE_GE; | ||
583 | n = 2; | ||
584 | break; | ||
585 | case L'>': | ||
586 | pContext->NextSymbol.Type = BURN_SYMBOL_TYPE_LOEQ; | ||
587 | n = 2; | ||
588 | break; | ||
589 | case L'<': | ||
590 | pContext->NextSymbol.Type = BURN_SYMBOL_TYPE_BAND; | ||
591 | n = 2; | ||
592 | break; | ||
593 | default: | ||
594 | pContext->NextSymbol.Type = BURN_SYMBOL_TYPE_GT; | ||
595 | n = 1; | ||
596 | } | ||
597 | break; | ||
598 | case L'<': | ||
599 | switch (pContext->wzRead[1]) | ||
600 | { | ||
601 | case L'=': | ||
602 | pContext->NextSymbol.Type = BURN_SYMBOL_TYPE_LE; | ||
603 | n = 2; | ||
604 | break; | ||
605 | case L'<': | ||
606 | pContext->NextSymbol.Type = BURN_SYMBOL_TYPE_HIEQ; | ||
607 | n = 2; | ||
608 | break; | ||
609 | case L'>': | ||
610 | pContext->NextSymbol.Type = BURN_SYMBOL_TYPE_NE; | ||
611 | n = 2; | ||
612 | break; | ||
613 | default: | ||
614 | pContext->NextSymbol.Type = BURN_SYMBOL_TYPE_LT; | ||
615 | n = 1; | ||
616 | } | ||
617 | break; | ||
618 | case L'=': | ||
619 | pContext->NextSymbol.Type = BURN_SYMBOL_TYPE_EQ; | ||
620 | n = 1; | ||
621 | break; | ||
622 | case L'(': | ||
623 | pContext->NextSymbol.Type = BURN_SYMBOL_TYPE_LPAREN; | ||
624 | n = 1; | ||
625 | break; | ||
626 | case L')': | ||
627 | pContext->NextSymbol.Type = BURN_SYMBOL_TYPE_RPAREN; | ||
628 | n = 1; | ||
629 | break; | ||
630 | case L'"': // literal | ||
631 | do | ||
632 | { | ||
633 | ++n; | ||
634 | if (L'\0' == pContext->wzRead[n]) | ||
635 | { | ||
636 | // error | ||
637 | pContext->fError = TRUE; | ||
638 | hr = E_INVALIDDATA; | ||
639 | ExitOnRootFailure(hr, "Failed to parse condition \"%ls\". Unterminated literal at position %d.", pContext->wzCondition, iPosition); | ||
640 | } | ||
641 | } while (L'"' != pContext->wzRead[n]); | ||
642 | ++n; // terminating '"' | ||
643 | |||
644 | pContext->NextSymbol.Type = BURN_SYMBOL_TYPE_LITERAL; | ||
645 | hr = BVariantSetString(&pContext->NextSymbol.Value, &pContext->wzRead[1], n - 2); | ||
646 | ExitOnFailure(hr, "Failed to set symbol value."); | ||
647 | break; | ||
648 | default: | ||
649 | if (C1_DIGIT & charType || L'-' == pContext->wzRead[0]) | ||
650 | { | ||
651 | do | ||
652 | { | ||
653 | ++n; | ||
654 | ::GetStringTypeW(CT_CTYPE1, &pContext->wzRead[n], 1, &charType); | ||
655 | if (C1_ALPHA & charType || L'_' == pContext->wzRead[n]) | ||
656 | { | ||
657 | // error, identifier cannot start with a digit | ||
658 | pContext->fError = TRUE; | ||
659 | hr = E_INVALIDDATA; | ||
660 | ExitOnRootFailure(hr, "Failed to parse condition \"%ls\". Identifier cannot start at a digit, at position %d.", pContext->wzCondition, iPosition); | ||
661 | } | ||
662 | } while (C1_DIGIT & charType); | ||
663 | |||
664 | // number | ||
665 | pContext->NextSymbol.Type = BURN_SYMBOL_TYPE_NUMBER; | ||
666 | |||
667 | LONGLONG ll = 0; | ||
668 | hr = StrStringToInt64(pContext->wzRead, n, &ll); | ||
669 | if (FAILED(hr)) | ||
670 | { | ||
671 | pContext->fError = TRUE; | ||
672 | hr = E_INVALIDDATA; | ||
673 | ExitOnRootFailure(hr, "Failed to parse condition \"%ls\". Constant too big, at position %d.", pContext->wzCondition, iPosition); | ||
674 | } | ||
675 | |||
676 | hr = BVariantSetNumeric(&pContext->NextSymbol.Value, ll); | ||
677 | ExitOnFailure(hr, "Failed to set symbol value."); | ||
678 | } | ||
679 | else if (C1_ALPHA & charType || L'_' == pContext->wzRead[0]) | ||
680 | { | ||
681 | ::GetStringTypeW(CT_CTYPE1, &pContext->wzRead[1], 1, &charType); | ||
682 | if (L'v' == pContext->wzRead[0] && C1_DIGIT & charType) | ||
683 | { | ||
684 | // version | ||
685 | DWORD cParts = 1; | ||
686 | for (;;) | ||
687 | { | ||
688 | ++n; | ||
689 | if (L'.' == pContext->wzRead[n]) | ||
690 | { | ||
691 | ++cParts; | ||
692 | if (4 < cParts) | ||
693 | { | ||
694 | // error, too many parts in version | ||
695 | pContext->fError = TRUE; | ||
696 | hr = E_INVALIDDATA; | ||
697 | ExitOnRootFailure(hr, "Failed to parse condition \"%ls\". Version can have a maximum of 4 parts, at position %d.", pContext->wzCondition, iPosition); | ||
698 | } | ||
699 | } | ||
700 | else | ||
701 | { | ||
702 | ::GetStringTypeW(CT_CTYPE1, &pContext->wzRead[n], 1, &charType); | ||
703 | if (C1_DIGIT != (C1_DIGIT & charType)) | ||
704 | { | ||
705 | break; | ||
706 | } | ||
707 | } | ||
708 | } | ||
709 | |||
710 | // Symbols don't encrypt their value, so can access the value directly. | ||
711 | hr = FileVersionFromStringEx(&pContext->wzRead[1], n - 1, &pContext->NextSymbol.Value.qwValue); | ||
712 | if (FAILED(hr)) | ||
713 | { | ||
714 | pContext->fError = TRUE; | ||
715 | hr = E_INVALIDDATA; | ||
716 | ExitOnRootFailure(hr, "Failed to parse condition \"%ls\". Invalid version format, at position %d.", pContext->wzCondition, iPosition); | ||
717 | } | ||
718 | |||
719 | pContext->NextSymbol.Value.Type = BURN_VARIANT_TYPE_VERSION; | ||
720 | pContext->NextSymbol.Type = BURN_SYMBOL_TYPE_VERSION; | ||
721 | } | ||
722 | else | ||
723 | { | ||
724 | do | ||
725 | { | ||
726 | ++n; | ||
727 | ::GetStringTypeW(CT_CTYPE1, &pContext->wzRead[n], 1, &charType); | ||
728 | } while (C1_ALPHA & charType || C1_DIGIT & charType || L'_' == pContext->wzRead[n]); | ||
729 | |||
730 | if (2 == n && CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, pContext->wzRead, 2, L"OR", 2)) | ||
731 | { | ||
732 | // OR | ||
733 | pContext->NextSymbol.Type = BURN_SYMBOL_TYPE_OR; | ||
734 | } | ||
735 | else if (3 == n && CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, pContext->wzRead, 3, L"AND", 3)) | ||
736 | { | ||
737 | // AND | ||
738 | pContext->NextSymbol.Type = BURN_SYMBOL_TYPE_AND; | ||
739 | } | ||
740 | else if (3 == n && CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, pContext->wzRead, 3, L"NOT", 3)) | ||
741 | { | ||
742 | // NOT | ||
743 | pContext->NextSymbol.Type = BURN_SYMBOL_TYPE_NOT; | ||
744 | } | ||
745 | else | ||
746 | { | ||
747 | // identifier | ||
748 | pContext->NextSymbol.Type = BURN_SYMBOL_TYPE_IDENTIFIER; | ||
749 | hr = BVariantSetString(&pContext->NextSymbol.Value, pContext->wzRead, n); | ||
750 | ExitOnFailure(hr, "Failed to set symbol value."); | ||
751 | } | ||
752 | } | ||
753 | } | ||
754 | else | ||
755 | { | ||
756 | // error, unexpected character | ||
757 | pContext->fError = TRUE; | ||
758 | hr = E_INVALIDDATA; | ||
759 | ExitOnRootFailure(hr, "Failed to parse condition \"%ls\". Unexpected character at position %d.", pContext->wzCondition, iPosition); | ||
760 | } | ||
761 | } | ||
762 | pContext->NextSymbol.iPosition = iPosition; | ||
763 | pContext->wzRead += n; | ||
764 | |||
765 | LExit: | ||
766 | return hr; | ||
767 | } | ||
768 | |||
769 | // | ||
770 | // CompareValues - compares two variant values using a given comparison. | ||
771 | // | ||
772 | static HRESULT CompareValues( | ||
773 | __in BURN_SYMBOL_TYPE comparison, | ||
774 | __in BURN_VARIANT leftOperand, | ||
775 | __in BURN_VARIANT rightOperand, | ||
776 | __out BOOL* pfResult | ||
777 | ) | ||
778 | { | ||
779 | HRESULT hr = S_OK; | ||
780 | LONGLONG llLeft = 0; | ||
781 | DWORD64 qwLeft = 0; | ||
782 | LPWSTR sczLeft = NULL; | ||
783 | LONGLONG llRight = 0; | ||
784 | DWORD64 qwRight = 0; | ||
785 | LPWSTR sczRight = NULL; | ||
786 | |||
787 | // get values to compare based on type | ||
788 | if (BURN_VARIANT_TYPE_STRING == leftOperand.Type && BURN_VARIANT_TYPE_STRING == rightOperand.Type) | ||
789 | { | ||
790 | hr = BVariantGetString(&leftOperand, &sczLeft); | ||
791 | ExitOnFailure(hr, "Failed to get the left string"); | ||
792 | hr = BVariantGetString(&rightOperand, &sczRight); | ||
793 | ExitOnFailure(hr, "Failed to get the right string"); | ||
794 | hr = CompareStringValues(comparison, sczLeft, sczRight, pfResult); | ||
795 | } | ||
796 | else if (BURN_VARIANT_TYPE_NUMERIC == leftOperand.Type && BURN_VARIANT_TYPE_NUMERIC == rightOperand.Type) | ||
797 | { | ||
798 | hr = BVariantGetNumeric(&leftOperand, &llLeft); | ||
799 | ExitOnFailure(hr, "Failed to get the left numeric"); | ||
800 | hr = BVariantGetNumeric(&rightOperand, &llRight); | ||
801 | ExitOnFailure(hr, "Failed to get the right numeric"); | ||
802 | hr = CompareIntegerValues(comparison, llLeft, llRight, pfResult); | ||
803 | } | ||
804 | else if (BURN_VARIANT_TYPE_VERSION == leftOperand.Type && BURN_VARIANT_TYPE_VERSION == rightOperand.Type) | ||
805 | { | ||
806 | hr = BVariantGetVersion(&leftOperand, &qwLeft); | ||
807 | ExitOnFailure(hr, "Failed to get the left version"); | ||
808 | hr = BVariantGetVersion(&rightOperand, &qwRight); | ||
809 | ExitOnFailure(hr, "Failed to get the right version"); | ||
810 | hr = CompareVersionValues(comparison, qwLeft, qwRight, pfResult); | ||
811 | } | ||
812 | else if (BURN_VARIANT_TYPE_VERSION == leftOperand.Type && BURN_VARIANT_TYPE_STRING == rightOperand.Type) | ||
813 | { | ||
814 | hr = BVariantGetVersion(&leftOperand, &qwLeft); | ||
815 | ExitOnFailure(hr, "Failed to get the left version"); | ||
816 | hr = BVariantGetVersion(&rightOperand, &qwRight); | ||
817 | if (FAILED(hr)) | ||
818 | { | ||
819 | if (DISP_E_TYPEMISMATCH != hr) | ||
820 | { | ||
821 | ExitOnFailure(hr, "Failed to get the right version"); | ||
822 | } | ||
823 | *pfResult = (BURN_SYMBOL_TYPE_NE == comparison); | ||
824 | hr = S_OK; | ||
825 | } | ||
826 | else | ||
827 | { | ||
828 | hr = CompareVersionValues(comparison, qwLeft, qwRight, pfResult); | ||
829 | } | ||
830 | } | ||
831 | else if (BURN_VARIANT_TYPE_STRING == leftOperand.Type && BURN_VARIANT_TYPE_VERSION == rightOperand.Type) | ||
832 | { | ||
833 | hr = BVariantGetVersion(&rightOperand, &qwRight); | ||
834 | ExitOnFailure(hr, "Failed to get the right version"); | ||
835 | hr = BVariantGetVersion(&leftOperand, &qwLeft); | ||
836 | if (FAILED(hr)) | ||
837 | { | ||
838 | if (DISP_E_TYPEMISMATCH != hr) | ||
839 | { | ||
840 | ExitOnFailure(hr, "Failed to get the left version"); | ||
841 | } | ||
842 | *pfResult = (BURN_SYMBOL_TYPE_NE == comparison); | ||
843 | hr = S_OK; | ||
844 | } | ||
845 | else | ||
846 | { | ||
847 | hr = CompareVersionValues(comparison, qwLeft, qwRight, pfResult); | ||
848 | } | ||
849 | } | ||
850 | else if (BURN_VARIANT_TYPE_NUMERIC == leftOperand.Type && BURN_VARIANT_TYPE_STRING == rightOperand.Type) | ||
851 | { | ||
852 | hr = BVariantGetNumeric(&leftOperand, &llLeft); | ||
853 | ExitOnFailure(hr, "Failed to get the left numeric"); | ||
854 | hr = BVariantGetNumeric(&rightOperand, &llRight); | ||
855 | if (FAILED(hr)) | ||
856 | { | ||
857 | if (DISP_E_TYPEMISMATCH != hr) | ||
858 | { | ||
859 | ExitOnFailure(hr, "Failed to get the right numeric"); | ||
860 | } | ||
861 | *pfResult = (BURN_SYMBOL_TYPE_NE == comparison); | ||
862 | hr = S_OK; | ||
863 | } | ||
864 | else | ||
865 | { | ||
866 | hr = CompareIntegerValues(comparison, llLeft, llRight, pfResult); | ||
867 | } | ||
868 | } | ||
869 | else if (BURN_VARIANT_TYPE_STRING == leftOperand.Type && BURN_VARIANT_TYPE_NUMERIC == rightOperand.Type) | ||
870 | { | ||
871 | hr = BVariantGetNumeric(&rightOperand, &llRight); | ||
872 | ExitOnFailure(hr, "Failed to get the right numeric"); | ||
873 | hr = BVariantGetNumeric(&leftOperand, &llLeft); | ||
874 | if (FAILED(hr)) | ||
875 | { | ||
876 | if (DISP_E_TYPEMISMATCH != hr) | ||
877 | { | ||
878 | ExitOnFailure(hr, "Failed to get the left numeric"); | ||
879 | } | ||
880 | *pfResult = (BURN_SYMBOL_TYPE_NE == comparison); | ||
881 | hr = S_OK; | ||
882 | } | ||
883 | else | ||
884 | { | ||
885 | hr = CompareIntegerValues(comparison, llLeft, llRight, pfResult); | ||
886 | } | ||
887 | } | ||
888 | else | ||
889 | { | ||
890 | // not a combination that can be compared | ||
891 | *pfResult = (BURN_SYMBOL_TYPE_NE == comparison); | ||
892 | } | ||
893 | |||
894 | LExit: | ||
895 | SecureZeroMemory(&qwLeft, sizeof(DWORD64)); | ||
896 | SecureZeroMemory(&llLeft, sizeof(LONGLONG)); | ||
897 | StrSecureZeroFreeString(sczLeft); | ||
898 | SecureZeroMemory(&qwRight, sizeof(DWORD64)); | ||
899 | SecureZeroMemory(&llRight, sizeof(LONGLONG)); | ||
900 | StrSecureZeroFreeString(sczRight); | ||
901 | |||
902 | return hr; | ||
903 | } | ||
904 | |||
905 | // | ||
906 | // CompareStringValues - compares two string values using a given comparison. | ||
907 | // | ||
908 | static HRESULT CompareStringValues( | ||
909 | __in BURN_SYMBOL_TYPE comparison, | ||
910 | __in_z LPCWSTR wzLeftOperand, | ||
911 | __in_z LPCWSTR wzRightOperand, | ||
912 | __out BOOL* pfResult | ||
913 | ) | ||
914 | { | ||
915 | HRESULT hr = S_OK; | ||
916 | DWORD dwCompareString = (comparison & INSENSITIVE) ? NORM_IGNORECASE : 0; | ||
917 | int cchLeft = lstrlenW(wzLeftOperand); | ||
918 | int cchRight = lstrlenW(wzRightOperand); | ||
919 | |||
920 | switch (comparison) | ||
921 | { | ||
922 | case BURN_SYMBOL_TYPE_LT: | ||
923 | case BURN_SYMBOL_TYPE_GT: | ||
924 | case BURN_SYMBOL_TYPE_LE: | ||
925 | case BURN_SYMBOL_TYPE_GE: | ||
926 | case BURN_SYMBOL_TYPE_EQ: | ||
927 | case BURN_SYMBOL_TYPE_NE: | ||
928 | case BURN_SYMBOL_TYPE_LT_I: | ||
929 | case BURN_SYMBOL_TYPE_GT_I: | ||
930 | case BURN_SYMBOL_TYPE_LE_I: | ||
931 | case BURN_SYMBOL_TYPE_GE_I: | ||
932 | case BURN_SYMBOL_TYPE_EQ_I: | ||
933 | case BURN_SYMBOL_TYPE_NE_I: | ||
934 | { | ||
935 | int i = ::CompareStringW(LOCALE_INVARIANT, dwCompareString, wzLeftOperand, cchLeft, wzRightOperand, cchRight); | ||
936 | hr = CompareIntegerValues(comparison, i, CSTR_EQUAL, pfResult); | ||
937 | } | ||
938 | break; | ||
939 | case BURN_SYMBOL_TYPE_BAND: | ||
940 | case BURN_SYMBOL_TYPE_BAND_I: | ||
941 | // test if left string contains right string | ||
942 | for (int i = 0; (i + cchRight) <= cchLeft; ++i) | ||
943 | { | ||
944 | if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, dwCompareString, wzLeftOperand + i, cchRight, wzRightOperand, cchRight)) | ||
945 | { | ||
946 | *pfResult = TRUE; | ||
947 | ExitFunction(); | ||
948 | } | ||
949 | } | ||
950 | *pfResult = FALSE; | ||
951 | break; | ||
952 | case BURN_SYMBOL_TYPE_HIEQ: | ||
953 | case BURN_SYMBOL_TYPE_HIEQ_I: | ||
954 | // test if left string starts with right string | ||
955 | *pfResult = cchLeft >= cchRight && CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, dwCompareString, wzLeftOperand, cchRight, wzRightOperand, cchRight); | ||
956 | break; | ||
957 | case BURN_SYMBOL_TYPE_LOEQ: | ||
958 | case BURN_SYMBOL_TYPE_LOEQ_I: | ||
959 | // test if left string ends with right string | ||
960 | *pfResult = cchLeft >= cchRight && CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, dwCompareString, wzLeftOperand + (cchLeft - cchRight), cchRight, wzRightOperand, cchRight); | ||
961 | break; | ||
962 | default: | ||
963 | ExitFunction1(hr = E_INVALIDARG); | ||
964 | } | ||
965 | |||
966 | LExit: | ||
967 | return hr; | ||
968 | } | ||
969 | |||
970 | // | ||
971 | // CompareIntegerValues - compares two integer values using a given comparison. | ||
972 | // | ||
973 | static HRESULT CompareIntegerValues( | ||
974 | __in BURN_SYMBOL_TYPE comparison, | ||
975 | __in LONGLONG llLeftOperand, | ||
976 | __in LONGLONG llRightOperand, | ||
977 | __out BOOL* pfResult | ||
978 | ) | ||
979 | { | ||
980 | HRESULT hr = S_OK; | ||
981 | |||
982 | switch (comparison) | ||
983 | { | ||
984 | case BURN_SYMBOL_TYPE_LT: case BURN_SYMBOL_TYPE_LT_I: *pfResult = llLeftOperand < llRightOperand; break; | ||
985 | case BURN_SYMBOL_TYPE_GT: case BURN_SYMBOL_TYPE_GT_I: *pfResult = llLeftOperand > llRightOperand; break; | ||
986 | case BURN_SYMBOL_TYPE_LE: case BURN_SYMBOL_TYPE_LE_I: *pfResult = llLeftOperand <= llRightOperand; break; | ||
987 | case BURN_SYMBOL_TYPE_GE: case BURN_SYMBOL_TYPE_GE_I: *pfResult = llLeftOperand >= llRightOperand; break; | ||
988 | case BURN_SYMBOL_TYPE_EQ: case BURN_SYMBOL_TYPE_EQ_I: *pfResult = llLeftOperand == llRightOperand; break; | ||
989 | case BURN_SYMBOL_TYPE_NE: case BURN_SYMBOL_TYPE_NE_I: *pfResult = llLeftOperand != llRightOperand; break; | ||
990 | case BURN_SYMBOL_TYPE_BAND: case BURN_SYMBOL_TYPE_BAND_I: *pfResult = (llLeftOperand & llRightOperand) ? TRUE : FALSE; break; | ||
991 | case BURN_SYMBOL_TYPE_HIEQ: case BURN_SYMBOL_TYPE_HIEQ_I: *pfResult = ((llLeftOperand >> 16) & 0xFFFF) == llRightOperand; break; | ||
992 | case BURN_SYMBOL_TYPE_LOEQ: case BURN_SYMBOL_TYPE_LOEQ_I: *pfResult = (llLeftOperand & 0xFFFF) == llRightOperand; break; | ||
993 | default: | ||
994 | ExitFunction1(hr = E_INVALIDARG); | ||
995 | } | ||
996 | |||
997 | LExit: | ||
998 | return hr; | ||
999 | } | ||
1000 | |||
1001 | // | ||
1002 | // CompareVersionValues - compares two quad-word version values using a given comparison. | ||
1003 | // | ||
1004 | static HRESULT CompareVersionValues( | ||
1005 | __in BURN_SYMBOL_TYPE comparison, | ||
1006 | __in DWORD64 qwLeftOperand, | ||
1007 | __in DWORD64 qwRightOperand, | ||
1008 | __out BOOL* pfResult | ||
1009 | ) | ||
1010 | { | ||
1011 | HRESULT hr = S_OK; | ||
1012 | |||
1013 | switch (comparison) | ||
1014 | { | ||
1015 | case BURN_SYMBOL_TYPE_LT: *pfResult = qwLeftOperand < qwRightOperand; break; | ||
1016 | case BURN_SYMBOL_TYPE_GT: *pfResult = qwLeftOperand > qwRightOperand; break; | ||
1017 | case BURN_SYMBOL_TYPE_LE: *pfResult = qwLeftOperand <= qwRightOperand; break; | ||
1018 | case BURN_SYMBOL_TYPE_GE: *pfResult = qwLeftOperand >= qwRightOperand; break; | ||
1019 | case BURN_SYMBOL_TYPE_EQ: *pfResult = qwLeftOperand == qwRightOperand; break; | ||
1020 | case BURN_SYMBOL_TYPE_NE: *pfResult = qwLeftOperand != qwRightOperand; break; | ||
1021 | case BURN_SYMBOL_TYPE_BAND: *pfResult = (qwLeftOperand & qwRightOperand) ? TRUE : FALSE; break; | ||
1022 | case BURN_SYMBOL_TYPE_HIEQ: *pfResult = ((qwLeftOperand >> 16) & 0xFFFF) == qwRightOperand; break; | ||
1023 | case BURN_SYMBOL_TYPE_LOEQ: *pfResult = (qwLeftOperand & 0xFFFF) == qwRightOperand; break; | ||
1024 | default: | ||
1025 | ExitFunction1(hr = E_INVALIDARG); | ||
1026 | } | ||
1027 | |||
1028 | LExit: | ||
1029 | return hr; | ||
1030 | } | ||