aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSean Hall <r.sean.hall@gmail.com>2020-10-18 14:05:51 -0500
committerSean Hall <r.sean.hall@gmail.com>2020-10-24 20:07:21 -0500
commitbafc4f682a798eb375d32c1f4777664aceb1e15f (patch)
treecc9bcec75252a7e4025e6efc28f1918ac8361e62
parent273c69f34311f4f4e5f6b5896e71d0788f12d96a (diff)
downloadwix-bafc4f682a798eb375d32c1f4777664aceb1e15f.tar.gz
wix-bafc4f682a798eb375d32c1f4777664aceb1e15f.tar.bz2
wix-bafc4f682a798eb375d32c1f4777664aceb1e15f.zip
Update string versioning.
Update condition parsing to allow specific characters for versions. Log every time an invalid version is parsed.
-rw-r--r--src/engine/condition.cpp125
-rw-r--r--src/engine/engine.mc42
-rw-r--r--src/engine/msiengine.cpp35
-rw-r--r--src/engine/registration.cpp5
-rw-r--r--src/engine/relatedbundle.cpp5
-rw-r--r--src/engine/variable.cpp12
-rw-r--r--src/engine/variant.cpp46
-rw-r--r--src/engine/variant.h10
-rw-r--r--src/test/BurnUnitTest/VariableTest.cpp1
9 files changed, 225 insertions, 56 deletions
diff --git a/src/engine/condition.cpp b/src/engine/condition.cpp
index 32a7a0b8..224eb0da 100644
--- a/src/engine/condition.cpp
+++ b/src/engine/condition.cpp
@@ -73,6 +73,12 @@ struct BURN_CONDITION_PARSE_CONTEXT
73 BOOL fError; 73 BOOL fError;
74}; 74};
75 75
76struct BURN_CONDITION_OPERAND
77{
78 BOOL fHidden;
79 BURN_VARIANT Value;
80};
81
76 82
77// internal function declarations 83// internal function declarations
78 84
@@ -92,9 +98,9 @@ static HRESULT ParseTerm(
92 __in BURN_CONDITION_PARSE_CONTEXT* pContext, 98 __in BURN_CONDITION_PARSE_CONTEXT* pContext,
93 __out BOOL* pf 99 __out BOOL* pf
94 ); 100 );
95static HRESULT ParseValue( 101static HRESULT ParseOperand(
96 __in BURN_CONDITION_PARSE_CONTEXT* pContext, 102 __in BURN_CONDITION_PARSE_CONTEXT* pContext,
97 __out BURN_VARIANT* pValue 103 __out BURN_CONDITION_OPERAND* pOperand
98 ); 104 );
99static HRESULT Expect( 105static HRESULT Expect(
100 __in BURN_CONDITION_PARSE_CONTEXT* pContext, 106 __in BURN_CONDITION_PARSE_CONTEXT* pContext,
@@ -103,10 +109,10 @@ static HRESULT Expect(
103static HRESULT NextSymbol( 109static HRESULT NextSymbol(
104 __in BURN_CONDITION_PARSE_CONTEXT* pContext 110 __in BURN_CONDITION_PARSE_CONTEXT* pContext
105 ); 111 );
106static HRESULT CompareValues( 112static HRESULT CompareOperands(
107 __in BURN_SYMBOL_TYPE comparison, 113 __in BURN_SYMBOL_TYPE comparison,
108 __in BURN_VARIANT leftOperand, 114 __in BURN_CONDITION_OPERAND* pLeftOperand,
109 __in BURN_VARIANT rightOperand, 115 __in BURN_CONDITION_OPERAND* pRightOperand,
110 __out BOOL* pfResult 116 __out BOOL* pfResult
111 ); 117 );
112static HRESULT CompareStringValues( 118static HRESULT CompareStringValues(
@@ -342,8 +348,8 @@ static HRESULT ParseTerm(
342 ) 348 )
343{ 349{
344 HRESULT hr = S_OK; 350 HRESULT hr = S_OK;
345 BURN_VARIANT firstValue = { }; 351 BURN_CONDITION_OPERAND firstOperand = { };
346 BURN_VARIANT secondValue = { }; 352 BURN_CONDITION_OPERAND secondOperand = { };
347 353
348 if (BURN_SYMBOL_TYPE_LPAREN == pContext->NextSymbol.Type) 354 if (BURN_SYMBOL_TYPE_LPAREN == pContext->NextSymbol.Type)
349 { 355 {
@@ -359,8 +365,8 @@ static HRESULT ParseTerm(
359 ExitFunction1(hr = S_OK); 365 ExitFunction1(hr = S_OK);
360 } 366 }
361 367
362 hr = ParseValue(pContext, &firstValue); 368 hr = ParseOperand(pContext, &firstOperand);
363 ExitOnFailure(hr, "Failed to parse value."); 369 ExitOnFailure(hr, "Failed to parse operand.");
364 370
365 if (COMPARISON & pContext->NextSymbol.Type) 371 if (COMPARISON & pContext->NextSymbol.Type)
366 { 372 {
@@ -369,24 +375,24 @@ static HRESULT ParseTerm(
369 hr = NextSymbol(pContext); 375 hr = NextSymbol(pContext);
370 ExitOnFailure(hr, "Failed to read next symbol."); 376 ExitOnFailure(hr, "Failed to read next symbol.");
371 377
372 hr = ParseValue(pContext, &secondValue); 378 hr = ParseOperand(pContext, &secondOperand);
373 ExitOnFailure(hr, "Failed to parse value."); 379 ExitOnFailure(hr, "Failed to parse operand.");
374 380
375 hr = CompareValues(comparison, firstValue, secondValue, pf); 381 hr = CompareOperands(comparison, &firstOperand, &secondOperand, pf);
376 ExitOnFailure(hr, "Failed to compare value."); 382 ExitOnFailure(hr, "Failed to compare operands.");
377 } 383 }
378 else 384 else
379 { 385 {
380 LONGLONG llValue = 0; 386 LONGLONG llValue = 0;
381 LPWSTR sczValue = NULL; 387 LPWSTR sczValue = NULL;
382 VERUTIL_VERSION* pVersion = NULL; 388 VERUTIL_VERSION* pVersion = NULL;
383 switch (firstValue.Type) 389 switch (firstOperand.Value.Type)
384 { 390 {
385 case BURN_VARIANT_TYPE_NONE: 391 case BURN_VARIANT_TYPE_NONE:
386 *pf = FALSE; 392 *pf = FALSE;
387 break; 393 break;
388 case BURN_VARIANT_TYPE_STRING: 394 case BURN_VARIANT_TYPE_STRING:
389 hr = BVariantGetString(&firstValue, &sczValue); 395 hr = BVariantGetString(&firstOperand.Value, &sczValue);
390 if (SUCCEEDED(hr)) 396 if (SUCCEEDED(hr))
391 { 397 {
392 *pf = sczValue && *sczValue; 398 *pf = sczValue && *sczValue;
@@ -394,7 +400,7 @@ static HRESULT ParseTerm(
394 StrSecureZeroFreeString(sczValue); 400 StrSecureZeroFreeString(sczValue);
395 break; 401 break;
396 case BURN_VARIANT_TYPE_NUMERIC: 402 case BURN_VARIANT_TYPE_NUMERIC:
397 hr = BVariantGetNumeric(&firstValue, &llValue); 403 hr = BVariantGetNumeric(&firstOperand.Value, &llValue);
398 if (SUCCEEDED(hr)) 404 if (SUCCEEDED(hr))
399 { 405 {
400 *pf = 0 != llValue; 406 *pf = 0 != llValue;
@@ -402,7 +408,7 @@ static HRESULT ParseTerm(
402 SecureZeroMemory(&llValue, sizeof(llValue)); 408 SecureZeroMemory(&llValue, sizeof(llValue));
403 break; 409 break;
404 case BURN_VARIANT_TYPE_VERSION: 410 case BURN_VARIANT_TYPE_VERSION:
405 hr = BVariantGetVersion(&firstValue, &pVersion); 411 hr = BVariantGetVersionHidden(&firstOperand.Value, firstOperand.fHidden, &pVersion);
406 if (SUCCEEDED(hr)) 412 if (SUCCEEDED(hr))
407 { 413 {
408 *pf = 0 != *pVersion->sczVersion; 414 *pf = 0 != *pVersion->sczVersion;
@@ -415,14 +421,14 @@ static HRESULT ParseTerm(
415 } 421 }
416 422
417LExit: 423LExit:
418 BVariantUninitialize(&firstValue); 424 BVariantUninitialize(&firstOperand.Value);
419 BVariantUninitialize(&secondValue); 425 BVariantUninitialize(&secondOperand.Value);
420 return hr; 426 return hr;
421} 427}
422 428
423static HRESULT ParseValue( 429static HRESULT ParseOperand(
424 __in BURN_CONDITION_PARSE_CONTEXT* pContext, 430 __in BURN_CONDITION_PARSE_CONTEXT* pContext,
425 __out BURN_VARIANT* pValue 431 __out BURN_CONDITION_OPERAND* pOperand
426 ) 432 )
427{ 433{
428 HRESULT hr = S_OK; 434 HRESULT hr = S_OK;
@@ -434,16 +440,19 @@ static HRESULT ParseValue(
434 Assert(BURN_VARIANT_TYPE_STRING == pContext->NextSymbol.Value.Type); 440 Assert(BURN_VARIANT_TYPE_STRING == pContext->NextSymbol.Value.Type);
435 441
436 // find variable 442 // find variable
437 hr = VariableGetVariant(pContext->pVariables, pContext->NextSymbol.Value.sczValue, pValue); 443 hr = VariableGetVariant(pContext->pVariables, pContext->NextSymbol.Value.sczValue, &pOperand->Value);
438 if (E_NOTFOUND != hr) 444 if (E_NOTFOUND != hr)
439 { 445 {
440 ExitOnRootFailure(hr, "Failed to find variable."); 446 ExitOnRootFailure(hr, "Failed to find variable.");
447
448 hr = VariableIsHidden(pContext->pVariables, pContext->NextSymbol.Value.sczValue, &pOperand->fHidden);
449 ExitOnRootFailure(hr, "Failed to get if variable is hidden.");
441 } 450 }
442 451
443 if (BURN_VARIANT_TYPE_FORMATTED == pValue->Type) 452 if (BURN_VARIANT_TYPE_FORMATTED == pOperand->Value.Type)
444 { 453 {
445 // TODO: actually format the value? 454 // TODO: actually format the value?
446 hr = BVariantChangeType(pValue, BURN_VARIANT_TYPE_STRING); 455 hr = BVariantChangeType(&pOperand->Value, BURN_VARIANT_TYPE_STRING);
447 ExitOnRootFailure(hr, "Failed to change variable '%ls' type for condition '%ls'", pContext->NextSymbol.Value.sczValue, pContext->wzCondition); 456 ExitOnRootFailure(hr, "Failed to change variable '%ls' type for condition '%ls'", pContext->NextSymbol.Value.sczValue, pContext->wzCondition);
448 } 457 }
449 break; 458 break;
@@ -451,8 +460,9 @@ static HRESULT ParseValue(
451 case BURN_SYMBOL_TYPE_NUMBER: __fallthrough; 460 case BURN_SYMBOL_TYPE_NUMBER: __fallthrough;
452 case BURN_SYMBOL_TYPE_LITERAL: __fallthrough; 461 case BURN_SYMBOL_TYPE_LITERAL: __fallthrough;
453 case BURN_SYMBOL_TYPE_VERSION: 462 case BURN_SYMBOL_TYPE_VERSION:
463 pOperand->fHidden = FALSE;
454 // steal value of symbol 464 // steal value of symbol
455 memcpy_s(pValue, sizeof(BURN_VARIANT), &pContext->NextSymbol.Value, sizeof(BURN_VARIANT)); 465 memcpy_s(&pOperand->Value, sizeof(BURN_VARIANT), &pContext->NextSymbol.Value, sizeof(BURN_VARIANT));
456 memset(&pContext->NextSymbol.Value, 0, sizeof(BURN_VARIANT)); 466 memset(&pContext->NextSymbol.Value, 0, sizeof(BURN_VARIANT));
457 break; 467 break;
458 468
@@ -692,8 +702,13 @@ static HRESULT NextSymbol(
692 do 702 do
693 { 703 {
694 ++n; 704 ++n;
695 ::GetStringTypeW(CT_CTYPE1, &pContext->wzRead[n], 1, &charType); 705 } while (pContext->wzRead[n] >= L'0' && pContext->wzRead[n] <= L'9' ||
696 } while (L'\0' != pContext->wzRead[n] && C1_BLANK != (C1_BLANK & charType)); 706 pContext->wzRead[n] >= L'A' && pContext->wzRead[n] <= L'Z' ||
707 pContext->wzRead[n] >= L'a' && pContext->wzRead[n] <= L'z' ||
708 pContext->wzRead[n] == L'_' ||
709 pContext->wzRead[n] == L'+' ||
710 pContext->wzRead[n] == L'-' ||
711 pContext->wzRead[n] == L'.');
697 712
698 // Symbols don't encrypt their value, so can access the value directly. 713 // Symbols don't encrypt their value, so can access the value directly.
699 hr = VerParseVersion(&pContext->wzRead[1], n - 1, FALSE, &pContext->NextSymbol.Value.pValue); 714 hr = VerParseVersion(&pContext->wzRead[1], n - 1, FALSE, &pContext->NextSymbol.Value.pValue);
@@ -703,6 +718,10 @@ static HRESULT NextSymbol(
703 hr = E_INVALIDDATA; 718 hr = E_INVALIDDATA;
704 ExitOnRootFailure(hr, "Failed to parse condition \"%ls\". Invalid version format, at position %d.", pContext->wzCondition, iPosition); 719 ExitOnRootFailure(hr, "Failed to parse condition \"%ls\". Invalid version format, at position %d.", pContext->wzCondition, iPosition);
705 } 720 }
721 else if (pContext->NextSymbol.Value.pValue->fInvalid)
722 {
723 LogId(REPORT_WARNING, MSG_CONDITION_INVALID_VERSION, pContext->wzCondition, pContext->NextSymbol.Value.pValue->sczVersion);
724 }
706 725
707 pContext->NextSymbol.Value.Type = BURN_VARIANT_TYPE_VERSION; 726 pContext->NextSymbol.Value.Type = BURN_VARIANT_TYPE_VERSION;
708 pContext->NextSymbol.Type = BURN_SYMBOL_TYPE_VERSION; 727 pContext->NextSymbol.Type = BURN_SYMBOL_TYPE_VERSION;
@@ -755,12 +774,12 @@ LExit:
755} 774}
756 775
757// 776//
758// CompareValues - compares two variant values using a given comparison. 777// CompareOperands - compares two variant values using a given comparison.
759// 778//
760static HRESULT CompareValues( 779static HRESULT CompareOperands(
761 __in BURN_SYMBOL_TYPE comparison, 780 __in BURN_SYMBOL_TYPE comparison,
762 __in BURN_VARIANT leftOperand, 781 __in BURN_CONDITION_OPERAND* pLeftOperand,
763 __in BURN_VARIANT rightOperand, 782 __in BURN_CONDITION_OPERAND* pRightOperand,
764 __out BOOL* pfResult 783 __out BOOL* pfResult
765 ) 784 )
766{ 785{
@@ -771,37 +790,39 @@ static HRESULT CompareValues(
771 LONGLONG llRight = 0; 790 LONGLONG llRight = 0;
772 VERUTIL_VERSION* pVersionRight = 0; 791 VERUTIL_VERSION* pVersionRight = 0;
773 LPWSTR sczRight = NULL; 792 LPWSTR sczRight = NULL;
793 BURN_VARIANT* pLeftValue = &pLeftOperand->Value;
794 BURN_VARIANT* pRightValue = &pRightOperand->Value;
774 795
775 // get values to compare based on type 796 // get values to compare based on type
776 if (BURN_VARIANT_TYPE_STRING == leftOperand.Type && BURN_VARIANT_TYPE_STRING == rightOperand.Type) 797 if (BURN_VARIANT_TYPE_STRING == pLeftValue->Type && BURN_VARIANT_TYPE_STRING == pRightValue->Type)
777 { 798 {
778 hr = BVariantGetString(&leftOperand, &sczLeft); 799 hr = BVariantGetString(pLeftValue, &sczLeft);
779 ExitOnFailure(hr, "Failed to get the left string"); 800 ExitOnFailure(hr, "Failed to get the left string");
780 hr = BVariantGetString(&rightOperand, &sczRight); 801 hr = BVariantGetString(pRightValue, &sczRight);
781 ExitOnFailure(hr, "Failed to get the right string"); 802 ExitOnFailure(hr, "Failed to get the right string");
782 hr = CompareStringValues(comparison, sczLeft, sczRight, pfResult); 803 hr = CompareStringValues(comparison, sczLeft, sczRight, pfResult);
783 } 804 }
784 else if (BURN_VARIANT_TYPE_NUMERIC == leftOperand.Type && BURN_VARIANT_TYPE_NUMERIC == rightOperand.Type) 805 else if (BURN_VARIANT_TYPE_NUMERIC == pLeftValue->Type && BURN_VARIANT_TYPE_NUMERIC == pRightValue->Type)
785 { 806 {
786 hr = BVariantGetNumeric(&leftOperand, &llLeft); 807 hr = BVariantGetNumeric(pLeftValue, &llLeft);
787 ExitOnFailure(hr, "Failed to get the left numeric"); 808 ExitOnFailure(hr, "Failed to get the left numeric");
788 hr = BVariantGetNumeric(&rightOperand, &llRight); 809 hr = BVariantGetNumeric(pRightValue, &llRight);
789 ExitOnFailure(hr, "Failed to get the right numeric"); 810 ExitOnFailure(hr, "Failed to get the right numeric");
790 hr = CompareIntegerValues(comparison, llLeft, llRight, pfResult); 811 hr = CompareIntegerValues(comparison, llLeft, llRight, pfResult);
791 } 812 }
792 else if (BURN_VARIANT_TYPE_VERSION == leftOperand.Type && BURN_VARIANT_TYPE_VERSION == rightOperand.Type) 813 else if (BURN_VARIANT_TYPE_VERSION == pLeftValue->Type && BURN_VARIANT_TYPE_VERSION == pRightValue->Type)
793 { 814 {
794 hr = BVariantGetVersion(&leftOperand, &pVersionLeft); 815 hr = BVariantGetVersionHidden(pLeftValue, pLeftOperand->fHidden, &pVersionLeft);
795 ExitOnFailure(hr, "Failed to get the left version"); 816 ExitOnFailure(hr, "Failed to get the left version");
796 hr = BVariantGetVersion(&rightOperand, &pVersionRight); 817 hr = BVariantGetVersionHidden(pRightValue, pRightOperand->fHidden, &pVersionRight);
797 ExitOnFailure(hr, "Failed to get the right version"); 818 ExitOnFailure(hr, "Failed to get the right version");
798 hr = CompareVersionValues(comparison, pVersionLeft, pVersionRight, pfResult); 819 hr = CompareVersionValues(comparison, pVersionLeft, pVersionRight, pfResult);
799 } 820 }
800 else if (BURN_VARIANT_TYPE_VERSION == leftOperand.Type && BURN_VARIANT_TYPE_STRING == rightOperand.Type) 821 else if (BURN_VARIANT_TYPE_VERSION == pLeftValue->Type && BURN_VARIANT_TYPE_STRING == pRightValue->Type)
801 { 822 {
802 hr = BVariantGetVersion(&leftOperand, &pVersionLeft); 823 hr = BVariantGetVersionHidden(pLeftValue, pLeftOperand->fHidden, &pVersionLeft);
803 ExitOnFailure(hr, "Failed to get the left version"); 824 ExitOnFailure(hr, "Failed to get the left version");
804 hr = BVariantGetVersion(&rightOperand, &pVersionRight); 825 hr = BVariantGetVersionHidden(pRightValue, pRightOperand->fHidden, &pVersionRight);
805 if (FAILED(hr)) 826 if (FAILED(hr))
806 { 827 {
807 if (DISP_E_TYPEMISMATCH != hr) 828 if (DISP_E_TYPEMISMATCH != hr)
@@ -816,11 +837,11 @@ static HRESULT CompareValues(
816 hr = CompareVersionValues(comparison, pVersionLeft, pVersionRight, pfResult); 837 hr = CompareVersionValues(comparison, pVersionLeft, pVersionRight, pfResult);
817 } 838 }
818 } 839 }
819 else if (BURN_VARIANT_TYPE_STRING == leftOperand.Type && BURN_VARIANT_TYPE_VERSION == rightOperand.Type) 840 else if (BURN_VARIANT_TYPE_STRING == pLeftValue->Type && BURN_VARIANT_TYPE_VERSION == pRightValue->Type)
820 { 841 {
821 hr = BVariantGetVersion(&rightOperand, &pVersionRight); 842 hr = BVariantGetVersionHidden(pRightValue, pRightOperand->fHidden, &pVersionRight);
822 ExitOnFailure(hr, "Failed to get the right version"); 843 ExitOnFailure(hr, "Failed to get the right version");
823 hr = BVariantGetVersion(&leftOperand, &pVersionLeft); 844 hr = BVariantGetVersionHidden(pLeftValue, pLeftOperand->fHidden, &pVersionLeft);
824 if (FAILED(hr)) 845 if (FAILED(hr))
825 { 846 {
826 if (DISP_E_TYPEMISMATCH != hr) 847 if (DISP_E_TYPEMISMATCH != hr)
@@ -835,11 +856,11 @@ static HRESULT CompareValues(
835 hr = CompareVersionValues(comparison, pVersionLeft, pVersionRight, pfResult); 856 hr = CompareVersionValues(comparison, pVersionLeft, pVersionRight, pfResult);
836 } 857 }
837 } 858 }
838 else if (BURN_VARIANT_TYPE_NUMERIC == leftOperand.Type && BURN_VARIANT_TYPE_STRING == rightOperand.Type) 859 else if (BURN_VARIANT_TYPE_NUMERIC == pLeftValue->Type && BURN_VARIANT_TYPE_STRING == pRightValue->Type)
839 { 860 {
840 hr = BVariantGetNumeric(&leftOperand, &llLeft); 861 hr = BVariantGetNumeric(pLeftValue, &llLeft);
841 ExitOnFailure(hr, "Failed to get the left numeric"); 862 ExitOnFailure(hr, "Failed to get the left numeric");
842 hr = BVariantGetNumeric(&rightOperand, &llRight); 863 hr = BVariantGetNumeric(pRightValue, &llRight);
843 if (FAILED(hr)) 864 if (FAILED(hr))
844 { 865 {
845 if (DISP_E_TYPEMISMATCH != hr) 866 if (DISP_E_TYPEMISMATCH != hr)
@@ -854,11 +875,11 @@ static HRESULT CompareValues(
854 hr = CompareIntegerValues(comparison, llLeft, llRight, pfResult); 875 hr = CompareIntegerValues(comparison, llLeft, llRight, pfResult);
855 } 876 }
856 } 877 }
857 else if (BURN_VARIANT_TYPE_STRING == leftOperand.Type && BURN_VARIANT_TYPE_NUMERIC == rightOperand.Type) 878 else if (BURN_VARIANT_TYPE_STRING == pLeftValue->Type && BURN_VARIANT_TYPE_NUMERIC == pRightValue->Type)
858 { 879 {
859 hr = BVariantGetNumeric(&rightOperand, &llRight); 880 hr = BVariantGetNumeric(pRightValue, &llRight);
860 ExitOnFailure(hr, "Failed to get the right numeric"); 881 ExitOnFailure(hr, "Failed to get the right numeric");
861 hr = BVariantGetNumeric(&leftOperand, &llLeft); 882 hr = BVariantGetNumeric(pLeftValue, &llLeft);
862 if (FAILED(hr)) 883 if (FAILED(hr))
863 { 884 {
864 if (DISP_E_TYPEMISMATCH != hr) 885 if (DISP_E_TYPEMISMATCH != hr)
diff --git a/src/engine/engine.mc b/src/engine/engine.mc
index fb2dd6e9..c8cd6d37 100644
--- a/src/engine/engine.mc
+++ b/src/engine/engine.mc
@@ -114,6 +114,13 @@ Language=English
114Connected to elevated engine. 114Connected to elevated engine.
115. 115.
116 116
117MessageId=13
118Severity=Warning
119SymbolicName=MSG_MANIFEST_INVALID_VERSION
120Language=English
121The manifest contains an invalid version string: '%1!ls!'
122.
123
117MessageId=51 124MessageId=51
118Severity=Error 125Severity=Error
119SymbolicName=MSG_FAILED_PARSE_CONDITION 126SymbolicName=MSG_FAILED_PARSE_CONDITION
@@ -156,6 +163,13 @@ Language=English
156Application canceled operation: %2!ls!, error: %1!ls! 163Application canceled operation: %2!ls!, error: %1!ls!
157. 164.
158 165
166MessageId=57
167Severity=Warning
168SymbolicName=MSG_CONDITION_INVALID_VERSION
169Language=English
170Condition '%1!ls!' contains invalid version string '%2!ls!'.
171.
172
159MessageId=100 173MessageId=100
160Severity=Success 174Severity=Success
161SymbolicName=MSG_DETECT_BEGIN 175SymbolicName=MSG_DETECT_BEGIN
@@ -233,6 +247,20 @@ Language=English
233Could not calculate patch applicability for target product code: %1!ls!, context: %2!hs!, reason: 0x%3!x! 247Could not calculate patch applicability for target product code: %1!ls!, context: %2!hs!, reason: 0x%3!x!
234. 248.
235 249
250MessageId=122
251Severity=Warning
252SymbolicName=MSG_RELATED_PACKAGE_INVALID_VERSION
253Language=English
254Related package: '%1!ls!' has invalid version: %2!ls!
255.
256
257MessageId=123
258Severity=Warning
259SymbolicName=MSG_DETECTED_MSI_PACKAGE_INVALID_VERSION
260Language=English
261Detected msi package with invalid version, product code: '%1!ls!', version: '%2!ls!'
262.
263
236MessageId=151 264MessageId=151
237Severity=Error 265Severity=Error
238SymbolicName=MSG_FAILED_DETECT_PACKAGE 266SymbolicName=MSG_FAILED_DETECT_PACKAGE
@@ -836,6 +864,20 @@ Language=English
836Variable: %1!ls! 864Variable: %1!ls!
837. 865.
838 866
867MessageId=411
868Severity=Warning
869SymbolicName=MSG_VARIABLE_INVALID_VERSION
870Language=English
871The variable '%1!ls!' is being set with an invalid version string.
872.
873
874MessageId=412
875Severity=Warning
876SymbolicName=MSG_INVALID_VERSION_COERSION
877Language=English
878The string '%1!ls!' could not be coerced to a valid version.
879.
880
839MessageId=420 881MessageId=420
840Severity=Success 882Severity=Success
841SymbolicName=MSG_RESUME_AU_STARTING 883SymbolicName=MSG_RESUME_AU_STARTING
diff --git a/src/engine/msiengine.cpp b/src/engine/msiengine.cpp
index e274df28..47211309 100644
--- a/src/engine/msiengine.cpp
+++ b/src/engine/msiengine.cpp
@@ -82,6 +82,11 @@ extern "C" HRESULT MsiEngineParsePackageFromXml(
82 hr = VerParseVersion(scz, 0, FALSE, &pPackage->Msi.pVersion); 82 hr = VerParseVersion(scz, 0, FALSE, &pPackage->Msi.pVersion);
83 ExitOnFailure(hr, "Failed to parse @Version: %ls", scz); 83 ExitOnFailure(hr, "Failed to parse @Version: %ls", scz);
84 84
85 if (pPackage->Msi.pVersion->fInvalid)
86 {
87 LogId(REPORT_WARNING, MSG_MANIFEST_INVALID_VERSION, scz);
88 }
89
85 // @UpgradeCode 90 // @UpgradeCode
86 hr = XmlGetAttributeEx(pixnMsiPackage, L"UpgradeCode", &pPackage->Msi.sczUpgradeCode); 91 hr = XmlGetAttributeEx(pixnMsiPackage, L"UpgradeCode", &pPackage->Msi.sczUpgradeCode);
87 if (E_NOTFOUND != hr) 92 if (E_NOTFOUND != hr)
@@ -420,6 +425,11 @@ extern "C" HRESULT MsiEngineDetectPackage(
420 hr = VerParseVersion(sczInstalledVersion, 0, FALSE, &pPackage->Msi.pInstalledVersion); 425 hr = VerParseVersion(sczInstalledVersion, 0, FALSE, &pPackage->Msi.pInstalledVersion);
421 ExitOnFailure(hr, "Failed to parse installed version: '%ls' for ProductCode: %ls", sczInstalledVersion, pPackage->Msi.sczProductCode); 426 ExitOnFailure(hr, "Failed to parse installed version: '%ls' for ProductCode: %ls", sczInstalledVersion, pPackage->Msi.sczProductCode);
422 427
428 if (pPackage->Msi.pInstalledVersion->fInvalid)
429 {
430 LogId(REPORT_WARNING, MSG_DETECTED_MSI_PACKAGE_INVALID_VERSION, pPackage->Msi.sczProductCode, sczInstalledVersion);
431 }
432
423 // compare versions 433 // compare versions
424 hr = VerCompareParsedVersions(pPackage->Msi.pVersion, pPackage->Msi.pInstalledVersion, &nCompareResult); 434 hr = VerCompareParsedVersions(pPackage->Msi.pVersion, pPackage->Msi.pInstalledVersion, &nCompareResult);
425 ExitOnFailure(hr, "Failed to compare version '%ls' to installed version: '%ls'", pPackage->Msi.pVersion->sczVersion, pPackage->Msi.pInstalledVersion->sczVersion); 435 ExitOnFailure(hr, "Failed to compare version '%ls' to installed version: '%ls'", pPackage->Msi.pVersion->sczVersion, pPackage->Msi.pInstalledVersion->sczVersion);
@@ -460,6 +470,11 @@ extern "C" HRESULT MsiEngineDetectPackage(
460 hr = VerParseVersion(sczInstalledVersion, 0, FALSE, &pVersion); 470 hr = VerParseVersion(sczInstalledVersion, 0, FALSE, &pVersion);
461 ExitOnFailure(hr, "Failed to parse dependency version: '%ls' for ProductCode: %ls", sczInstalledVersion, sczInstalledProductCode); 471 ExitOnFailure(hr, "Failed to parse dependency version: '%ls' for ProductCode: %ls", sczInstalledVersion, sczInstalledProductCode);
462 472
473 if (pVersion->fInvalid)
474 {
475 LogId(REPORT_WARNING, MSG_DETECTED_MSI_PACKAGE_INVALID_VERSION, sczInstalledProductCode, sczInstalledVersion);
476 }
477
463 // compare versions 478 // compare versions
464 hr = VerCompareParsedVersions(pPackage->Msi.pVersion, pVersion, &nCompareResult); 479 hr = VerCompareParsedVersions(pPackage->Msi.pVersion, pVersion, &nCompareResult);
465 ExitOnFailure(hr, "Failed to compare version '%ls' to dependency version: '%ls'", pPackage->Msi.pVersion->sczVersion, pVersion->sczVersion); 480 ExitOnFailure(hr, "Failed to compare version '%ls' to dependency version: '%ls'", pPackage->Msi.pVersion->sczVersion, pVersion->sczVersion);
@@ -536,6 +551,11 @@ extern "C" HRESULT MsiEngineDetectPackage(
536 hr = VerParseVersion(sczInstalledVersion, 0, FALSE, &pVersion); 551 hr = VerParseVersion(sczInstalledVersion, 0, FALSE, &pVersion);
537 ExitOnFailure(hr, "Failed to parse related installed version: '%ls' for ProductCode: %ls", sczInstalledVersion, wzProductCode); 552 ExitOnFailure(hr, "Failed to parse related installed version: '%ls' for ProductCode: %ls", sczInstalledVersion, wzProductCode);
538 553
554 if (pVersion->fInvalid)
555 {
556 LogId(REPORT_WARNING, MSG_DETECTED_MSI_PACKAGE_INVALID_VERSION, wzProductCode, sczInstalledVersion);
557 }
558
539 // compare versions 559 // compare versions
540 if (pRelatedMsi->fMinProvided) 560 if (pRelatedMsi->fMinProvided)
541 { 561 {
@@ -1052,6 +1072,11 @@ extern "C" HRESULT MsiEngineAddCompatiblePackage(
1052 1072
1053 hr = VerParseVersion(sczInstalledVersion, 0, FALSE, &pCompatiblePackage->Msi.pVersion); 1073 hr = VerParseVersion(sczInstalledVersion, 0, FALSE, &pCompatiblePackage->Msi.pVersion);
1054 ExitOnFailure(hr, "Failed to parse version: '%ls' for ProductCode: %ls", sczInstalledVersion, pCompatiblePackage->Msi.sczProductCode); 1074 ExitOnFailure(hr, "Failed to parse version: '%ls' for ProductCode: %ls", sczInstalledVersion, pCompatiblePackage->Msi.sczProductCode);
1075
1076 if (pCompatiblePackage->Msi.pVersion->fInvalid)
1077 {
1078 LogId(REPORT_WARNING, MSG_DETECTED_MSI_PACKAGE_INVALID_VERSION, pCompatiblePackage->Msi.sczProductCode, sczInstalledVersion);
1079 }
1055 } 1080 }
1056 1081
1057 // For now, copy enough information to support uninstalling the newer, compatible package. 1082 // For now, copy enough information to support uninstalling the newer, compatible package.
@@ -1506,6 +1531,11 @@ static HRESULT ParseRelatedMsiFromXml(
1506 hr = VerParseVersion(scz, 0, FALSE, &pRelatedMsi->pMinVersion); 1531 hr = VerParseVersion(scz, 0, FALSE, &pRelatedMsi->pMinVersion);
1507 ExitOnFailure(hr, "Failed to parse @MinVersion: %ls", scz); 1532 ExitOnFailure(hr, "Failed to parse @MinVersion: %ls", scz);
1508 1533
1534 if (pRelatedMsi->pMinVersion->fInvalid)
1535 {
1536 LogId(REPORT_WARNING, MSG_MANIFEST_INVALID_VERSION, scz);
1537 }
1538
1509 // flag that we have a min version 1539 // flag that we have a min version
1510 pRelatedMsi->fMinProvided = TRUE; 1540 pRelatedMsi->fMinProvided = TRUE;
1511 1541
@@ -1523,6 +1553,11 @@ static HRESULT ParseRelatedMsiFromXml(
1523 hr = VerParseVersion(scz, 0, FALSE, &pRelatedMsi->pMaxVersion); 1553 hr = VerParseVersion(scz, 0, FALSE, &pRelatedMsi->pMaxVersion);
1524 ExitOnFailure(hr, "Failed to parse @MaxVersion: %ls", scz); 1554 ExitOnFailure(hr, "Failed to parse @MaxVersion: %ls", scz);
1525 1555
1556 if (pRelatedMsi->pMaxVersion->fInvalid)
1557 {
1558 LogId(REPORT_WARNING, MSG_MANIFEST_INVALID_VERSION, scz);
1559 }
1560
1526 // flag that we have a max version 1561 // flag that we have a max version
1527 pRelatedMsi->fMaxProvided = TRUE; 1562 pRelatedMsi->fMaxProvided = TRUE;
1528 1563
diff --git a/src/engine/registration.cpp b/src/engine/registration.cpp
index 3c3dc95d..4e8c810d 100644
--- a/src/engine/registration.cpp
+++ b/src/engine/registration.cpp
@@ -136,6 +136,11 @@ extern "C" HRESULT RegistrationParseFromXml(
136 hr = VerParseVersion(scz, 0, FALSE, &pRegistration->pVersion); 136 hr = VerParseVersion(scz, 0, FALSE, &pRegistration->pVersion);
137 ExitOnFailure(hr, "Failed to parse @Version: %ls", scz); 137 ExitOnFailure(hr, "Failed to parse @Version: %ls", scz);
138 138
139 if (pRegistration->pVersion->fInvalid)
140 {
141 LogId(REPORT_WARNING, MSG_MANIFEST_INVALID_VERSION, scz);
142 }
143
139 // @ProviderKey 144 // @ProviderKey
140 hr = XmlGetAttributeEx(pixnRegistrationNode, L"ProviderKey", &pRegistration->sczProviderKey); 145 hr = XmlGetAttributeEx(pixnRegistrationNode, L"ProviderKey", &pRegistration->sczProviderKey);
141 ExitOnFailure(hr, "Failed to get @ProviderKey."); 146 ExitOnFailure(hr, "Failed to get @ProviderKey.");
diff --git a/src/engine/relatedbundle.cpp b/src/engine/relatedbundle.cpp
index e6d6516a..7b0da4a4 100644
--- a/src/engine/relatedbundle.cpp
+++ b/src/engine/relatedbundle.cpp
@@ -414,6 +414,11 @@ static HRESULT LoadRelatedBundleFromKey(
414 hr = VerParseVersion(sczBundleVersion, 0, FALSE, &pRelatedBundle->pVersion); 414 hr = VerParseVersion(sczBundleVersion, 0, FALSE, &pRelatedBundle->pVersion);
415 ExitOnFailure(hr, "Failed to parse pseudo bundle version: %ls", sczBundleVersion); 415 ExitOnFailure(hr, "Failed to parse pseudo bundle version: %ls", sczBundleVersion);
416 416
417 if (pRelatedBundle->pVersion->fInvalid)
418 {
419 LogId(REPORT_WARNING, MSG_RELATED_PACKAGE_INVALID_VERSION, wzRelatedBundleId, sczBundleVersion);
420 }
421
417 hr = RegReadString(hkBundleId, BURN_REGISTRATION_REGISTRY_BUNDLE_CACHE_PATH, &sczCachePath); 422 hr = RegReadString(hkBundleId, BURN_REGISTRATION_REGISTRY_BUNDLE_CACHE_PATH, &sczCachePath);
418 ExitOnFailure(hr, "Failed to read cache path from registry for bundle: %ls", wzRelatedBundleId); 423 ExitOnFailure(hr, "Failed to read cache path from registry for bundle: %ls", wzRelatedBundleId);
419 424
diff --git a/src/engine/variable.cpp b/src/engine/variable.cpp
index 3069ccf7..c2192346 100644
--- a/src/engine/variable.cpp
+++ b/src/engine/variable.cpp
@@ -393,6 +393,11 @@ extern "C" HRESULT VariablesParseFromXml(
393 hr = BVariantChangeType(&value, valueType); 393 hr = BVariantChangeType(&value, valueType);
394 ExitOnFailure(hr, "Failed to change variant type."); 394 ExitOnFailure(hr, "Failed to change variant type.");
395 395
396 if (BURN_VARIANT_TYPE_VERSION == valueType && value.pValue->fInvalid)
397 {
398 LogId(REPORT_WARNING, MSG_VARIABLE_INVALID_VERSION, sczId);
399 }
400
396 // find existing variable 401 // find existing variable
397 hr = FindVariableIndexByName(pVariables, sczId, &iVariable); 402 hr = FindVariableIndexByName(pVariables, sczId, &iVariable);
398 ExitOnFailure(hr, "Failed to find variable value '%ls'.", sczId); 403 ExitOnFailure(hr, "Failed to find variable value '%ls'.", sczId);
@@ -584,7 +589,7 @@ extern "C" HRESULT VariableGetVersion(
584 } 589 }
585 ExitOnFailure(hr, "Failed to get value of variable: %ls", wzVariable); 590 ExitOnFailure(hr, "Failed to get value of variable: %ls", wzVariable);
586 591
587 hr = BVariantGetVersion(&pVariable->Value, ppValue); 592 hr = BVariantGetVersionHidden(&pVariable->Value, pVariable->fHidden, ppValue);
588 ExitOnFailure(hr, "Failed to get value as version for variable: %ls", wzVariable); 593 ExitOnFailure(hr, "Failed to get value as version for variable: %ls", wzVariable);
589 594
590LExit: 595LExit:
@@ -1575,6 +1580,11 @@ static HRESULT SetVariableValue(
1575 break; 1580 break;
1576 } 1581 }
1577 } 1582 }
1583
1584 if (BURN_VARIANT_TYPE_VERSION == pVariant->Type && pVariant->pValue->fInvalid)
1585 {
1586 LogId(REPORT_WARNING, MSG_VARIABLE_INVALID_VERSION, wzVariable);
1587 }
1578 } 1588 }
1579 1589
1580 // Update variable value. 1590 // Update variable value.
diff --git a/src/engine/variant.cpp b/src/engine/variant.cpp
index 28578691..9fdb82cd 100644
--- a/src/engine/variant.cpp
+++ b/src/engine/variant.cpp
@@ -6,6 +6,12 @@
6 6
7// internal function declarations 7// internal function declarations
8 8
9static HRESULT GetVersionInternal(
10 __in BURN_VARIANT* pVariant,
11 __in BOOL fHidden,
12 __in BOOL fSilent,
13 __out VERUTIL_VERSION** ppValue
14 );
9static HRESULT BVariantEncryptString( 15static HRESULT BVariantEncryptString(
10 __in BURN_VARIANT* pVariant, 16 __in BURN_VARIANT* pVariant,
11 __in BOOL fEncrypt 17 __in BOOL fEncrypt
@@ -130,6 +136,36 @@ extern "C" HRESULT BVariantGetVersion(
130 __out VERUTIL_VERSION** ppValue 136 __out VERUTIL_VERSION** ppValue
131 ) 137 )
132{ 138{
139 return GetVersionInternal(pVariant, FALSE, FALSE, ppValue);
140}
141
142// The contents of ppValue may be sensitive, should keep encrypted and SecureZeroMemory.
143extern "C" HRESULT BVariantGetVersionHidden(
144 __in BURN_VARIANT* pVariant,
145 __in BOOL fHidden,
146 __out VERUTIL_VERSION** ppValue
147 )
148{
149 return GetVersionInternal(pVariant, fHidden, FALSE, ppValue);
150}
151
152// The contents of ppValue may be sensitive, should keep encrypted and SecureZeroMemory.
153extern "C" HRESULT BVariantGetVersionSilent(
154 __in BURN_VARIANT* pVariant,
155 __in BOOL fSilent,
156 __out VERUTIL_VERSION** ppValue
157 )
158{
159 return GetVersionInternal(pVariant, FALSE, fSilent, ppValue);
160}
161
162static HRESULT GetVersionInternal(
163 __in BURN_VARIANT* pVariant,
164 __in BOOL fHidden,
165 __in BOOL fSilent,
166 __out VERUTIL_VERSION** ppValue
167 )
168{
133 HRESULT hr = S_OK; 169 HRESULT hr = S_OK;
134 LONGLONG llValue = 0; 170 LONGLONG llValue = 0;
135 LPWSTR sczValue = NULL; 171 LPWSTR sczValue = NULL;
@@ -152,6 +188,10 @@ extern "C" HRESULT BVariantGetVersion(
152 { 188 {
153 hr = DISP_E_TYPEMISMATCH; 189 hr = DISP_E_TYPEMISMATCH;
154 } 190 }
191 else if (!fSilent && (*ppValue)->fInvalid)
192 {
193 LogId(REPORT_WARNING, MSG_INVALID_VERSION_COERSION, fHidden ? L"*****" : sczValue);
194 }
155 } 195 }
156 StrSecureZeroFreeString(sczValue); 196 StrSecureZeroFreeString(sczValue);
157 break; 197 break;
@@ -282,7 +322,7 @@ extern "C" HRESULT BVariantSetValue(
282 StrSecureZeroFreeString(sczValue); 322 StrSecureZeroFreeString(sczValue);
283 break; 323 break;
284 case BURN_VARIANT_TYPE_VERSION: 324 case BURN_VARIANT_TYPE_VERSION:
285 hr = BVariantGetVersion(pValue, &pVersionValue); 325 hr = BVariantGetVersionSilent(pValue, TRUE, &pVersionValue);
286 if (SUCCEEDED(hr)) 326 if (SUCCEEDED(hr))
287 { 327 {
288 hr = BVariantSetVersion(pVariant, pVersionValue); 328 hr = BVariantSetVersion(pVariant, pVersionValue);
@@ -333,7 +373,7 @@ extern "C" HRESULT BVariantCopy(
333 StrSecureZeroFreeString(sczValue); 373 StrSecureZeroFreeString(sczValue);
334 break; 374 break;
335 case BURN_VARIANT_TYPE_VERSION: 375 case BURN_VARIANT_TYPE_VERSION:
336 hr = BVariantGetVersion(pSource, &pVersionValue); 376 hr = BVariantGetVersionSilent(pSource, TRUE, &pVersionValue);
337 if (SUCCEEDED(hr)) 377 if (SUCCEEDED(hr))
338 { 378 {
339 hr = BVariantSetVersion(pTarget, pVersionValue); 379 hr = BVariantSetVersion(pTarget, pVersionValue);
@@ -383,7 +423,7 @@ extern "C" HRESULT BVariantChangeType(
383 hr = BVariantGetString(pVariant, &variant.sczValue); 423 hr = BVariantGetString(pVariant, &variant.sczValue);
384 break; 424 break;
385 case BURN_VARIANT_TYPE_VERSION: 425 case BURN_VARIANT_TYPE_VERSION:
386 hr = BVariantGetVersion(pVariant, &variant.pValue); 426 hr = BVariantGetVersionSilent(pVariant, TRUE, &variant.pValue);
387 break; 427 break;
388 default: 428 default:
389 ExitFunction1(hr = E_INVALIDARG); 429 ExitFunction1(hr = E_INVALIDARG);
diff --git a/src/engine/variant.h b/src/engine/variant.h
index 23303e02..34d7a187 100644
--- a/src/engine/variant.h
+++ b/src/engine/variant.h
@@ -51,6 +51,16 @@ HRESULT BVariantGetVersion(
51 __in BURN_VARIANT* pVariant, 51 __in BURN_VARIANT* pVariant,
52 __out VERUTIL_VERSION** ppValue 52 __out VERUTIL_VERSION** ppValue
53 ); 53 );
54HRESULT BVariantGetVersionHidden(
55 __in BURN_VARIANT* pVariant,
56 __in BOOL fHidden,
57 __out VERUTIL_VERSION** ppValue
58 );
59HRESULT BVariantGetVersionSilent(
60 __in BURN_VARIANT* pVariant,
61 __in BOOL fSilent,
62 __out VERUTIL_VERSION** ppValue
63 );
54HRESULT BVariantSetNumeric( 64HRESULT BVariantSetNumeric(
55 __in BURN_VARIANT* pVariant, 65 __in BURN_VARIANT* pVariant,
56 __in LONGLONG llValue 66 __in LONGLONG llValue
diff --git a/src/test/BurnUnitTest/VariableTest.cpp b/src/test/BurnUnitTest/VariableTest.cpp
index 405c8fab..f5511199 100644
--- a/src/test/BurnUnitTest/VariableTest.cpp
+++ b/src/test/BurnUnitTest/VariableTest.cpp
@@ -273,6 +273,7 @@ namespace Bootstrapper
273 Assert::True(EvaluateConditionHelper(&variables, L"vPROP21 = 1")); 273 Assert::True(EvaluateConditionHelper(&variables, L"vPROP21 = 1"));
274 Assert::True(EvaluateConditionHelper(&variables, L"PROP23 = v1.1.1")); 274 Assert::True(EvaluateConditionHelper(&variables, L"PROP23 = v1.1.1"));
275 Assert::True(EvaluateConditionHelper(&variables, L"v1.1.1 = PROP23")); 275 Assert::True(EvaluateConditionHelper(&variables, L"v1.1.1 = PROP23"));
276 Assert::False(EvaluateConditionHelper(&variables, L"v1.1.1<>PROP23"));
276 Assert::True(EvaluateConditionHelper(&variables, L"PROP1 <> v1.1.1")); 277 Assert::True(EvaluateConditionHelper(&variables, L"PROP1 <> v1.1.1"));
277 Assert::True(EvaluateConditionHelper(&variables, L"v1.1.1 <> PROP1")); 278 Assert::True(EvaluateConditionHelper(&variables, L"v1.1.1 <> PROP1"));
278 279