Add DetectSHA2Support "search".
Sean Hall committed
Mar 30, 2020 at 19:46 UTC
0afd76e4c5d46f237591d860e7d445e267522187
20 files changed
+611
-501
nuget.config
+2
@@ -2,6 +2,8 @@
2
<configuration>
3
<packageSources>
4
<clear />
5
+ <add key="wixtoolset-balutil" value="https://ci.appveyor.com/nuget/wixtoolset-balutil" />
6
+ <add key="wixtoolset-bootstrappercore" value="https://ci.appveyor.com/nuget/wixtoolset-bootstrappercore" />
7
<add key="wixtoolset-data" value="https://ci.appveyor.com/nuget/wixtoolset-data" />
8
<add key="wixtoolset-extensibility" value="https://ci.appveyor.com/nuget/wixtoolset-extensibility" />
9
<add key="wixtoolset-core" value="https://ci.appveyor.com/nuget/wixtoolset-core" />
src/be/UtilBundleExtension.cpp
new
+87
@@ -0,0 +1,87 @@
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
+#include "BextBaseBundleExtension.h"
5
+
6
+class CWixUtilBundleExtension : public CBextBaseBundleExtension
7
+{
8
+public: // IBundleExtension
9
+ virtual STDMETHODIMP Search(
10
+ __in LPCWSTR wzId,
11
+ __in LPCWSTR wzVariable
12
+ )
13
+ {
14
+ HRESULT hr = S_OK;
15
+
16
+ hr = UtilSearchExecute(&m_searches, wzId, wzVariable, m_pEngine);
17
+
18
+ return hr;
19
+ }
20
+
21
+public: //CBextBaseBundleExtension
22
+ virtual STDMETHODIMP Initialize(
23
+ __in const BUNDLE_EXTENSION_CREATE_ARGS* pCreateArgs
24
+ )
25
+ {
26
+ HRESULT hr = S_OK;
27
+ IXMLDOMDocument* pixdManifest = NULL;
28
+ IXMLDOMNode* pixnBundleExtension = NULL;
29
+
30
+ hr = CBextBaseBundleExtension::Initialize(pCreateArgs);
31
+ ExitOnFailure(hr, "CBextBaseBundleExtension initialization failed.");
32
+
33
+ hr = XmlLoadDocumentFromFile(m_sczBundleExtensionDataPath, &pixdManifest);
34
+ ExitOnFailure(hr, "Failed to load bundle extension manifest from path: %ls", m_sczBundleExtensionDataPath);
35
+
36
+ hr = BextGetBundleExtensionDataNode(pixdManifest, UTIL_BUNDLE_EXTENSION_ID, &pixnBundleExtension);
37
+ ExitOnFailure(hr, "Failed to get BundleExtension '%ls'", UTIL_BUNDLE_EXTENSION_ID);
38
+
39
+ hr = UtilSearchParseFromXml(&m_searches, pixnBundleExtension);
40
+ ExitOnFailure(hr, "Failed to parse searches from bundle extension manifest.");
41
+
42
+ LExit:
43
+ ReleaseObject(pixnBundleExtension);
44
+ ReleaseObject(pixdManifest);
45
+
46
+ return hr;
47
+ }
48
+
49
+public:
50
+ CWixUtilBundleExtension(
51
+ __in IBundleExtensionEngine* pEngine
52
+ ) : CBextBaseBundleExtension(pEngine)
53
+ {
54
+ m_searches = { };
55
+ }
56
+
57
+ ~CWixUtilBundleExtension()
58
+ {
59
+ UtilSearchUninitialize(&m_searches);
60
+ }
61
+
62
+private:
63
+ UTIL_SEARCHES m_searches;
64
+};
65
+
66
+HRESULT UtilBundleExtensionCreate(
67
+ __in IBundleExtensionEngine* pEngine,
68
+ __in const BUNDLE_EXTENSION_CREATE_ARGS* pArgs,
69
+ __out IBundleExtension** ppBundleExtension
70
+ )
71
+{
72
+ HRESULT hr = S_OK;
73
+ CWixUtilBundleExtension* pExtension = NULL;
74
+
75
+ pExtension = new CWixUtilBundleExtension(pEngine);
76
+ ExitOnNull(pExtension, hr, E_OUTOFMEMORY, "Failed to create new CWixUtilBundleExtension.");
77
+
78
+ hr = pExtension->Initialize(pArgs);
79
+ ExitOnFailure(hr, "CWixUtilBundleExtension initialization failed");
80
+
81
+ *ppBundleExtension = pExtension;
82
+ pExtension = NULL;
83
+
84
+LExit:
85
+ ReleaseObject(pExtension);
86
+ return hr;
87
+}
src/be/UtilBundleExtension.h
new
+16
@@ -0,0 +1,16 @@
1
+#pragma once
2
+// 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.
3
+
4
+
5
+// constants
6
+
7
+#define UTIL_BUNDLE_EXTENSION_ID L"WixUtilBundleExtension"
8
+
9
+
10
+// function declarations
11
+
12
+HRESULT UtilBundleExtensionCreate(
13
+ __in IBundleExtensionEngine* pEngine,
14
+ __in const BUNDLE_EXTENSION_CREATE_ARGS* pArgs,
15
+ __out IBundleExtension** ppBundleExtension
16
+ );
src/be/detectsha2support.cpp
new
+58
@@ -0,0 +1,58 @@
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
+// https://gist.github.com/navossoc/7572c7d82243e9f818989e2765e7793a
6
+HRESULT DetectSHA2Support(
7
+ __out BOOL* pfSupported
8
+ )
9
+{
10
+ HRESULT hr = S_OK;
11
+ HMODULE hModule = NULL;
12
+ FARPROC pfn = NULL;
13
+ DWORD er = ERROR_SUCCESS;
14
+
15
+ hr = LoadSystemLibrary(L"wintrust.dll", &hModule);
16
+ ExitOnFailure(hr, "Failed to load wintrust.dll");
17
+
18
+ pfn = ::GetProcAddress(hModule, "CryptCATAdminAcquireContext2");
19
+ if (pfn)
20
+ {
21
+ *pfSupported = TRUE;
22
+ ExitFunction1(hr = S_OK);
23
+ }
24
+
25
+ er = ::GetLastError();
26
+ if (er == ERROR_PROC_NOT_FOUND)
27
+ {
28
+ *pfSupported = FALSE;
29
+ ExitFunction1(hr = S_OK);
30
+ }
31
+
32
+ hr = HRESULT_FROM_WIN32(er);
33
+ ExitOnFailure(hr, "Failed to probe for CryptCATAdminAcquireContext2 in wintrust.dll");
34
+
35
+LExit:
36
+ ::FreeLibrary(hModule);
37
+
38
+ return hr;
39
+}
40
+
41
+HRESULT UtilPerformDetectSHA2Support(
42
+ __in LPCWSTR wzVariable,
43
+ __in UTIL_SEARCH* /*pSearch*/,
44
+ __in IBundleExtensionEngine* pEngine
45
+ )
46
+{
47
+ HRESULT hr = S_OK;
48
+ BOOL fSupported = FALSE;
49
+
50
+ hr = DetectSHA2Support(&fSupported);
51
+ ExitOnFailure(hr, "DetectSHA2Support failed.");
52
+
53
+ hr = pEngine->SetVariableNumeric(wzVariable, fSupported ? 1 : 0);
54
+ ExitOnFailure(hr, "Failed to set variable '%ls'", wzVariable);
55
+
56
+LExit:
57
+ return hr;
58
+}
src/be/detectsha2support.h
new
+8
@@ -0,0 +1,8 @@
1
+#pragma once
2
+// 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.
3
+
4
+HRESULT UtilPerformDetectSHA2Support(
5
+ __in LPCWSTR wzVariable,
6
+ __in UTIL_SEARCH* pSearch,
7
+ __in IBundleExtensionEngine* pEngine
8
+ );
\ No newline at end of file
src/be/packages.config
+1
@@ -1,5 +1,6 @@
1
<?xml version="1.0" encoding="utf-8"?>
2
<packages>
3
+ <package id="WixToolset.BextUtil" version="4.0.16" targetFramework="native" />
4
<package id="WixToolset.BootstrapperCore.Native" version="4.0.13" targetFramework="native" />
5
<package id="WixToolset.DUtil" version="4.0.18" targetFramework="native" />
6
</packages>
\ No newline at end of file
src/be/precomp.h
+17
-6
@@ -17,9 +17,20 @@
17
18
#define MAXUINT USHRT_MAX
19
20
-#include "dutil.h"
21
-#include "memutil.h"
22
-
23
-#include "BootstrapperEngine.h"
24
-#include "BundleExtensionEngine.h"
25
-#include "BundleExtension.h"
20
+#include <dutil.h>
21
+#include <memutil.h>
22
+#include <strutil.h>
23
+#include <pathutil.h>
24
+#include <xmlutil.h>
25
+
26
+#include <BundleExtensionEngine.h>
27
+#include <BundleExtension.h>
28
+
29
+#include <IBundleExtensionEngine.h>
30
+#include <IBundleExtension.h>
31
+#include <bextutil.h>
32
+#include <BextBundleExtensionEngine.h>
33
+
34
+#include "utilsearch.h"
35
+#include "detectsha2support.h"
36
+#include "UtilBundleExtension.h"
src/be/utilbe.cpp
+25
-3
@@ -1,19 +1,41 @@
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
+#include "BextBaseBundleExtensionProc.h"
5
+
6
+static IBundleExtension* vpBundleExtension = NULL;
7
8
// function definitions
9
10
extern "C" HRESULT WINAPI BundleExtensionCreate(
8
- __in const BUNDLE_EXTENSION_CREATE_ARGS* /*pArgs*/,
9
- __inout BUNDLE_EXTENSION_CREATE_RESULTS* /*pResults*/
11
+ __in const BUNDLE_EXTENSION_CREATE_ARGS* pArgs,
12
+ __inout BUNDLE_EXTENSION_CREATE_RESULTS* pResults
13
)
14
{
12
- HRESULT hr = S_OK;
15
+ HRESULT hr = S_OK;
16
+ IBundleExtensionEngine* pEngine = NULL;
17
+
18
+ hr = XmlInitialize();
19
+ ExitOnFailure(hr, "Failed to initialize XML.");
20
+
21
+ hr = BextInitializeFromCreateArgs(pArgs, &pEngine);
22
+ ExitOnFailure(hr, "Failed to initialize bext");
23
+
24
+ hr = UtilBundleExtensionCreate(pEngine, pArgs, &vpBundleExtension);
25
+ BextExitOnFailure(hr, "Failed to create WixUtilBundleExtension");
26
+
27
+ pResults->pfnBundleExtensionProc = BextBaseBundleExtensionProc;
28
+ pResults->pvBundleExtensionProcContext = vpBundleExtension;
29
+
30
+LExit:
31
+ ReleaseObject(pEngine);
32
33
return hr;
34
}
35
36
extern "C" void WINAPI BundleExtensionDestroy()
37
{
38
+ BextUninitialize();
39
+ ReleaseNullObject(vpBundleExtension);
40
+ XmlUninitialize();
41
}
\ No newline at end of file
src/be/utilbe.vcxproj
+9
-11
@@ -1,10 +1,9 @@
1
<?xml version="1.0" encoding="utf-8"?>
2
<!-- 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. -->
3
-
3
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
4
+ <Import Project="..\..\packages\WixToolset.BextUtil.4.0.16\build\WixToolset.BextUtil.props" Condition="Exists('..\..\packages\WixToolset.BextUtil.4.0.16\build\WixToolset.BextUtil.props')" />
5
<Import Project="..\..\packages\WixToolset.BootstrapperCore.Native.4.0.13\build\WixToolset.BootstrapperCore.Native.props" Condition="Exists('..\..\packages\WixToolset.BootstrapperCore.Native.4.0.13\build\WixToolset.BootstrapperCore.Native.props')" />
6
<Import Project="..\..\packages\WixToolset.DUtil.4.0.18\build\WixToolset.DUtil.props" Condition="Exists('..\..\packages\WixToolset.DUtil.4.0.18\build\WixToolset.DUtil.props')" />
7
-
7
<ItemGroup Label="ProjectConfigurations">
8
<ProjectConfiguration Include="Debug|Win32">
9
<Configuration>Debug</Configuration>
@@ -15,7 +14,6 @@
14
<Platform>Win32</Platform>
15
</ProjectConfiguration>
16
</ItemGroup>
18
-
17
<PropertyGroup Label="Globals">
18
<ProjectGuid>{630C1EE7-2517-4A8C-83E3-DA1150308B58}</ProjectGuid>
19
<ConfigurationType>DynamicLibrary</ConfigurationType>
@@ -25,37 +23,37 @@
23
<ProjectModuleDefinitionFile>utilbe.def</ProjectModuleDefinitionFile>
24
<Description>WiX Toolset Util BundleExtension</Description>
25
</PropertyGroup>
28
-
26
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
27
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
31
-
28
<PropertyGroup>
29
<ProjectAdditionalLinkLibraries>msi.lib</ProjectAdditionalLinkLibraries>
30
</PropertyGroup>
35
-
31
<ItemGroup>
32
+ <ClCompile Include="detectsha2support.cpp" />
33
<ClCompile Include="precomp.cpp">
34
<PrecompiledHeader>Create</PrecompiledHeader>
35
</ClCompile>
36
<ClCompile Include="utilbe.cpp" />
37
+ <ClCompile Include="UtilBundleExtension.cpp" />
38
+ <ClCompile Include="utilsearch.cpp" />
39
</ItemGroup>
42
-
40
<ItemGroup>
41
+ <ClInclude Include="detectsha2support.h" />
42
<ClInclude Include="precomp.h" />
43
+ <ClInclude Include="UtilBundleExtension.h" />
44
+ <ClInclude Include="utilsearch.h" />
45
</ItemGroup>
46
-
46
<ItemGroup>
47
<None Include="packages.config" />
48
<None Include="utilbe.def" />
49
</ItemGroup>
51
-
50
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
53
-
51
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
52
<PropertyGroup>
53
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
54
</PropertyGroup>
55
+ <Error Condition="!Exists('..\..\packages\WixToolset.BextUtil.4.0.16\build\WixToolset.BextUtil.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\WixToolset.BextUtil.4.0.16\build\WixToolset.BextUtil.props'))" />
56
<Error Condition="!Exists('..\..\packages\WixToolset.BootstrapperCore.Native.4.0.13\build\WixToolset.BootstrapperCore.Native.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\WixToolset.BootstrapperCore.Native.4.0.13\build\WixToolset.BootstrapperCore.Native.props'))" />
57
<Error Condition="!Exists('..\..\packages\WixToolset.DUtil.4.0.18\build\WixToolset.DUtil.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\WixToolset.DUtil.4.0.18\build\WixToolset.DUtil.props'))" />
58
</Target>
61
-</Project>
59
+</Project>
\ No newline at end of file
src/be/utilsearch.cpp
new
+137
@@ -0,0 +1,137 @@
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
+STDMETHODIMP UtilSearchParseFromXml(
7
+ __in UTIL_SEARCHES* pSearches,
8
+ __in IXMLDOMNode* pixnBundleExtension
9
+ )
10
+{
11
+ HRESULT hr = S_OK;
12
+ IXMLDOMNodeList* pixnNodes = NULL;
13
+ IXMLDOMNode* pixnNode = NULL;
14
+ DWORD cNodes = 0;
15
+ BSTR bstrNodeName = NULL;
16
+
17
+ // Select Util search nodes.
18
+ hr = XmlSelectNodes(pixnBundleExtension, L"WixDetectSHA2Support", &pixnNodes);
19
+ ExitOnFailure(hr, "Failed to select Util search nodes.");
20
+
21
+ // Get Util search node count.
22
+ hr = pixnNodes->get_length((long*)&cNodes);
23
+ ExitOnFailure(hr, "Failed to get Util search node count.");
24
+
25
+ if (!cNodes)
26
+ {
27
+ ExitFunction();
28
+ }
29
+
30
+ // Allocate memory for searches.
31
+ pSearches->rgSearches = (UTIL_SEARCH*)MemAlloc(sizeof(UTIL_SEARCH) * cNodes, TRUE);
32
+ ExitOnNull(pSearches->rgSearches, hr, E_OUTOFMEMORY, "Failed to allocate memory for search structs.");
33
+
34
+ pSearches->cSearches = cNodes;
35
+
36
+ // Parse search elements.
37
+ for (DWORD i = 0; i < cNodes; ++i)
38
+ {
39
+ UTIL_SEARCH* pSearch = &pSearches->rgSearches[i];
40
+
41
+ hr = XmlNextElement(pixnNodes, &pixnNode, &bstrNodeName);
42
+ ExitOnFailure(hr, "Failed to get next node.");
43
+
44
+ // @Id
45
+ hr = XmlGetAttributeEx(pixnNode, L"Id", &pSearch->sczId);
46
+ ExitOnFailure(hr, "Failed to get @Id.");
47
+
48
+ // Read type specific attributes.
49
+ if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, bstrNodeName, -1, L"WixDetectSHA2Support", -1))
50
+ {
51
+ pSearch->Type = UTIL_SEARCH_TYPE_DETECT_SHA2_SUPPORT;
52
+ }
53
+ else
54
+ {
55
+ hr = E_UNEXPECTED;
56
+ ExitOnFailure(hr, "Unexpected element name: %ls", bstrNodeName);
57
+ }
58
+
59
+ // prepare next iteration
60
+ ReleaseNullObject(pixnNode);
61
+ ReleaseNullBSTR(bstrNodeName);
62
+ }
63
+
64
+LExit:
65
+ ReleaseBSTR(bstrNodeName);
66
+ ReleaseObject(pixnNode);
67
+ ReleaseObject(pixnNodes);
68
+
69
+ return hr;
70
+}
71
+
72
+void UtilSearchUninitialize(
73
+ __in UTIL_SEARCHES* pSearches
74
+ )
75
+{
76
+ if (pSearches->rgSearches)
77
+ {
78
+ for (DWORD i = 0; i < pSearches->cSearches; ++i)
79
+ {
80
+ UTIL_SEARCH* pSearch = &pSearches->rgSearches[i];
81
+
82
+ ReleaseStr(pSearch->sczId);
83
+ }
84
+ MemFree(pSearches->rgSearches);
85
+ }
86
+}
87
+
88
+STDMETHODIMP UtilSearchExecute(
89
+ __in UTIL_SEARCHES* pSearches,
90
+ __in LPCWSTR wzSearchId,
91
+ __in LPCWSTR wzVariable,
92
+ __in IBundleExtensionEngine* pEngine
93
+ )
94
+{
95
+ HRESULT hr = S_OK;
96
+ UTIL_SEARCH* pSearch = NULL;
97
+
98
+ hr = UtilSearchFindById(pSearches, wzSearchId, &pSearch);
99
+ ExitOnFailure(hr, "Search id '%ls' is unknown to the util extension.");
100
+
101
+ switch (pSearch->Type)
102
+ {
103
+ case UTIL_SEARCH_TYPE_DETECT_SHA2_SUPPORT:
104
+ hr = UtilPerformDetectSHA2Support(wzVariable, pSearch, pEngine);
105
+ break;
106
+ default:
107
+ hr = E_UNEXPECTED;
108
+ }
109
+
110
+LExit:
111
+ return hr;
112
+}
113
+
114
+STDMETHODIMP UtilSearchFindById(
115
+ __in UTIL_SEARCHES* pSearches,
116
+ __in LPCWSTR wzId,
117
+ __out UTIL_SEARCH** ppSearch
118
+ )
119
+{
120
+ HRESULT hr = S_OK;
121
+
122
+ for (DWORD i = 0; i < pSearches->cSearches; ++i)
123
+ {
124
+ UTIL_SEARCH* pSearch = &pSearches->rgSearches[i];
125
+
126
+ if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, pSearch->sczId, -1, wzId, -1))
127
+ {
128
+ *ppSearch = pSearch;
129
+ ExitFunction1(hr = S_OK);
130
+ }
131
+ }
132
+
133
+ hr = E_NOTFOUND;
134
+
135
+LExit:
136
+ return hr;
137
+}
src/be/utilsearch.h
new
+52
@@ -0,0 +1,52 @@
1
+#pragma once
2
+// 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.
3
+
4
+
5
+// constants
6
+
7
+enum UTIL_SEARCH_TYPE
8
+{
9
+ UTIL_SEARCH_TYPE_NONE,
10
+ UTIL_SEARCH_TYPE_DETECT_SHA2_SUPPORT,
11
+};
12
+
13
+
14
+// structs
15
+
16
+typedef struct _UTIL_SEARCH
17
+{
18
+ LPWSTR sczId;
19
+
20
+ UTIL_SEARCH_TYPE Type;
21
+} UTIL_SEARCH;
22
+
23
+typedef struct _UTIL_SEARCHES
24
+{
25
+ UTIL_SEARCH* rgSearches;
26
+ DWORD cSearches;
27
+} UTIL_SEARCHES;
28
+
29
+
30
+// function declarations
31
+
32
+STDMETHODIMP UtilSearchParseFromXml(
33
+ __in UTIL_SEARCHES* pSearches,
34
+ __in IXMLDOMNode* pixnBundleExtension
35
+ );
36
+
37
+void UtilSearchUninitialize(
38
+ __in UTIL_SEARCHES* pSearches
39
+ );
40
+
41
+STDMETHODIMP UtilSearchExecute(
42
+ __in UTIL_SEARCHES* pSearches,
43
+ __in LPCWSTR wzSearchId,
44
+ __in LPCWSTR wzVariable,
45
+ __in IBundleExtensionEngine* pEngine
46
+ );
47
+
48
+STDMETHODIMP UtilSearchFindById(
49
+ __in UTIL_SEARCHES* pSearches,
50
+ __in LPCWSTR wzId,
51
+ __out UTIL_SEARCH** ppSearch
52
+ );
src/test/WixToolsetTest.Util/TestData/BundleWithSearches/Bundle.wxs
+5
@@ -7,6 +7,7 @@
7
<util:RegistrySearchRef Id="RegistrySearchId" />
8
<util:ProductSearchRef Id="ProductSearchId" />
9
<util:FileSearchRef Id="FileSearchId" />
10
+ <util:DetectSHA2SupportRef Id="DetectSHA2SupportId" />
11
12
<Chain>
13
<MsiPackage SourceFile="test.msi">
@@ -32,4 +33,8 @@
33
<Fragment>
34
<util:FileSearch Id="FileSearchId" Variable="FileSearchVariable" Path="%windir%\System32\mscoree.dll" Result="exists" />
35
</Fragment>
36
+
37
+ <Fragment>
38
+ <util:DetectSHA2Support Id="DetectSHA2SupportId" Variable="IsSHA2Supported" />
39
+ </Fragment>
40
</Wix>
src/test/WixToolsetTest.Util/UtilExtensionFixture.cs
+24
-31
@@ -146,6 +146,9 @@ namespace WixToolsetTest.Util
146
{
147
var baseFolder = fs.GetFolder();
148
var intermediateFolder = Path.Combine(baseFolder, "obj");
149
+ var bundlePath = Path.Combine(baseFolder, @"bin\test.exe");
150
+ var baFolderPath = Path.Combine(baseFolder, "ba");
151
+ var extractFolderPath = Path.Combine(baseFolder, "extract");
152
153
var result = WixRunner.Execute(new[]
154
{
@@ -156,45 +159,35 @@ namespace WixToolsetTest.Util
159
"-bindpath", Path.Combine(folder, "data"),
160
"-intermediateFolder", intermediateFolder,
161
"-burnStub", burnStubPath,
159
- "-o", Path.Combine(baseFolder, @"bin\test.exe")
162
+ "-o", bundlePath
163
});
164
165
result.AssertSuccess();
166
164
- Assert.True(File.Exists(Path.Combine(baseFolder, @"bin\test.exe")));
167
+ Assert.True(File.Exists(bundlePath));
168
#if TODO
169
Assert.True(File.Exists(Path.Combine(baseFolder, @"bin\test.wixpdb")));
170
#endif
171
169
- var intermediate = Intermediate.Load(Path.Combine(intermediateFolder, @"test.wir"));
170
- var section = intermediate.Sections.Single();
171
-
172
- var searchTuples = section.Tuples.OfType<WixSearchTuple>().OrderBy(t => t.Id.Id).ToList();
173
- Assert.Equal(3, searchTuples.Count);
174
- Assert.Equal("FileSearchId", searchTuples[0].Id.Id);
175
- Assert.Equal("FileSearchVariable", searchTuples[0].Variable);
176
- Assert.Equal("ProductSearchId", searchTuples[1].Id.Id);
177
- Assert.Equal("ProductSearchVariable", searchTuples[1].Variable);
178
- Assert.Equal("1 & 2 < 3", searchTuples[1].Condition);
179
- Assert.Equal("RegistrySearchId", searchTuples[2].Id.Id);
180
- Assert.Equal("RegistrySearchVariable", searchTuples[2].Variable);
181
-
182
- var fileSearchTuple = section.Tuples.OfType<WixFileSearchTuple>().Single();
183
- Assert.Equal("FileSearchId", fileSearchTuple.Id.Id);
184
- Assert.Equal(@"%windir%\System32\mscoree.dll", fileSearchTuple.Path);
185
- Assert.Equal(WixFileSearchAttributes.Default | WixFileSearchAttributes.WantExists, fileSearchTuple.Attributes);
186
-
187
- var productSearchTuple = section.Tuples.OfType<WixProductSearchTuple>().Single();
188
- Assert.Equal("ProductSearchId", productSearchTuple.Id.Id);
189
- Assert.Equal("{738D02BF-E231-4370-8209-E9FD4E1BE2A1}", productSearchTuple.Guid);
190
- Assert.Equal(WixProductSearchAttributes.Version | WixProductSearchAttributes.UpgradeCode, productSearchTuple.Attributes);
191
-
192
- var registrySearchTuple = section.Tuples.OfType<WixRegistrySearchTuple>().Single();
193
- Assert.Equal("RegistrySearchId", registrySearchTuple.Id.Id);
194
- Assert.Equal(RegistryRootType.LocalMachine, registrySearchTuple.Root);
195
- Assert.Equal(@"SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full", registrySearchTuple.Key);
196
- Assert.Equal("Release", registrySearchTuple.Value);
197
- Assert.Equal(WixRegistrySearchAttributes.WantValue | WixRegistrySearchAttributes.Raw, registrySearchTuple.Attributes);
172
+ var extractResult = BundleExtractor.ExtractBAContainer(null, bundlePath, baFolderPath, extractFolderPath);
173
+ extractResult.AssertSuccess();
174
+
175
+ var bundleExtensionDatas = extractResult.SelectBundleExtensionDataNodes("/be:BundleExtensionData/be:BundleExtension[@Id='WixUtilBundleExtension']");
176
+ Assert.Equal(1, bundleExtensionDatas.Count);
177
+ Assert.Equal("<BundleExtension Id='WixUtilBundleExtension'>" +
178
+ "<WixDetectSHA2Support Id='DetectSHA2SupportId' />" +
179
+ "</BundleExtension>", bundleExtensionDatas[0].GetTestXml());
180
+
181
+ var utilSearches = extractResult.SelectManifestNodes("/burn:BurnManifest/*[self::burn:ExtensionSearch or self::burn:FileSearch or self::burn:MsiProductSearch or self::burn:RegistrySearch]");
182
+ Assert.Equal(4, utilSearches.Count);
183
+ Assert.Equal("<ExtensionSearch Id='DetectSHA2SupportId' Variable='IsSHA2Supported' " +
184
+ "ExtensionId='WixUtilBundleExtension' />", utilSearches[0].GetTestXml());
185
+ Assert.Equal("<FileSearch Id='FileSearchId' Variable='FileSearchVariable' " +
186
+ $@"Path='%windir%\System32\mscoree.dll' Type='exists' />", utilSearches[1].GetTestXml());
187
+ Assert.Equal("<MsiProductSearch Id='ProductSearchId' Variable='ProductSearchVariable' Condition='1 & 2 < 3' " +
188
+ "UpgradeCode='{738D02BF-E231-4370-8209-E9FD4E1BE2A1}' Type='version' />", utilSearches[2].GetTestXml());
189
+ Assert.Equal("<RegistrySearch Id='RegistrySearchId' Variable='RegistrySearchVariable' " +
190
+ @"Root='HKLM' Key='SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full' Value='Release' Type='value' VariableType='string' />", utilSearches[3].GetTestXml());
191
}
192
}
193
src/wixext/Tuples/UtilTupleDefinitions.cs
+10
@@ -4,6 +4,7 @@ namespace WixToolset.Util
4
{
5
using System;
6
using WixToolset.Data;
7
+ using WixToolset.Data.Burn;
8
9
public enum UtilTupleDefinitionType
10
{
@@ -19,6 +20,7 @@ namespace WixToolset.Util
20
User,
21
UserGroup,
22
WixCloseApplication,
23
+ WixDetectSHA2Support,
24
WixFormatFiles,
25
WixInternetShortcut,
26
WixRemoveFolderEx,
@@ -82,6 +84,9 @@ namespace WixToolset.Util
84
case UtilTupleDefinitionType.WixCloseApplication:
85
return UtilTupleDefinitions.WixCloseApplication;
86
87
+ case UtilTupleDefinitionType.WixDetectSHA2Support:
88
+ return UtilTupleDefinitions.WixDetectSHA2Support;
89
+
90
case UtilTupleDefinitionType.WixFormatFiles:
91
return UtilTupleDefinitions.WixFormatFiles;
92
@@ -107,5 +112,10 @@ namespace WixToolset.Util
112
throw new ArgumentOutOfRangeException(nameof(type));
113
}
114
}
115
+
116
+ static UtilTupleDefinitions()
117
+ {
118
+ WixDetectSHA2Support.AddTag(BurnConstants.BundleExtensionSearchTupleDefinitionTag);
119
+ }
120
}
121
}
src/wixext/Tuples/WixDetectSHA2SupportTuple.cs
new
+33
@@ -0,0 +1,33 @@
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
+namespace WixToolset.Util
4
+{
5
+ using WixToolset.Data;
6
+ using WixToolset.Util.Tuples;
7
+
8
+ public static partial class UtilTupleDefinitions
9
+ {
10
+ public static readonly IntermediateTupleDefinition WixDetectSHA2Support = new IntermediateTupleDefinition(
11
+ UtilTupleDefinitionType.WixDetectSHA2Support.ToString(),
12
+ new IntermediateFieldDefinition[0],
13
+ typeof(WixDetectSHA2SupportTuple));
14
+ }
15
+}
16
+
17
+namespace WixToolset.Util.Tuples
18
+{
19
+ using WixToolset.Data;
20
+
21
+ public class WixDetectSHA2SupportTuple : IntermediateTuple
22
+ {
23
+ public WixDetectSHA2SupportTuple() : base(UtilTupleDefinitions.WixDetectSHA2Support, null, null)
24
+ {
25
+ }
26
+
27
+ public WixDetectSHA2SupportTuple(SourceLineNumber sourceLineNumber, Identifier id = null) : base(UtilTupleDefinitions.WixDetectSHA2Support, sourceLineNumber, id)
28
+ {
29
+ }
30
+
31
+ public IntermediateField this[GroupTupleFields index] => this.Fields[(int)index];
32
+ }
33
+}
src/wixext/UtilBinder.cs
deleted
-347
@@ -1,347 +0,0 @@
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
-namespace WixToolset.Extensions
4
-{
5
-#if TODO_BRINGBACK_FOR_BUNDLES
6
- using System;
7
- using System.Collections.Generic;
8
- using System.Globalization;
9
- using WixToolset.Data;
10
- using WixToolset.Extensibility;
11
-
12
- /// <summary>
13
- /// The binder for the WiX Toolset Utility Extension.
14
- /// </summary>
15
- public sealed class UtilBinder : BinderExtension
16
- {
17
- // TODO: When WixSearch is supported in Product, etc, we may need to call
18
- // ReorderWixSearch() from each of those initializers.
19
-
20
- // TODO: A general-purpose "reorder this table given these constraints"
21
- // mechanism may end up being helpful. This could be declaratively stated
22
- // in the table definitions, or exposed from the core Wix.dll and called
23
- // as-needed by any extensions.
24
-
25
- /// <summary>
26
- /// Called before bundle binding occurs.
27
- /// </summary>
28
- public override void Initialize(Output bundle)
29
- {
30
- if (OutputType.Bundle == bundle.Type)
31
- {
32
- this.ReorderWixSearch(bundle);
33
- }
34
- }
35
-
36
- /// <summary>
37
- /// Reorders Any WixSearch items.
38
- /// </summary>
39
- /// <param name="output">Output containing the tables to process.</param>
40
- private void ReorderWixSearch(Output output)
41
- {
42
- Table wixSearchTable = output.Tables["WixSearch"];
43
- if (null == wixSearchTable || wixSearchTable.Rows.Count == 0)
44
- {
45
- // nothing to do!
46
- return;
47
- }
48
-
49
- RowDictionary rowDictionary = new RowDictionary();
50
- foreach (Row row in wixSearchTable.Rows)
51
- {
52
- rowDictionary.AddRow(row);
53
- }
54
-
55
- Constraints constraints = new Constraints();
56
- Table wixSearchRelationTable = output.Tables["WixSearchRelation"];
57
- if (null != wixSearchRelationTable && wixSearchRelationTable.Rows.Count > 0)
58
- {
59
- // add relational info to our data...
60
- foreach (Row row in wixSearchRelationTable.Rows)
61
- {
62
- constraints.AddConstraint((string)row[0], (string)row[1]);
63
- }
64
- }
65
-
66
- this.FindCircularReference(constraints);
67
-
68
- if (this.Core.EncounteredError)
69
- {
70
- return;
71
- }
72
-
73
- this.FlattenDependentReferences(constraints);
74
-
75
- // Reorder by topographical sort (http://en.wikipedia.org/wiki/Topological_sorting)
76
- // We use a variation of Kahn (1962) algorithm as described in
77
- // Wikipedia, with the additional criteria that start nodes are sorted
78
- // lexicographically at each step to ensure a deterministic ordering
79
- // based on 'after' dependencies and ID.
80
- TopologicalSort sorter = new TopologicalSort();
81
- List <string> sortedIds = sorter.Sort(rowDictionary.Keys, constraints);
82
-
83
- // Now, re-write the table with the searches in order...
84
- wixSearchTable.Rows.Clear();
85
- foreach (string id in sortedIds)
86
- {
87
- wixSearchTable.Rows.Add(rowDictionary[id]);
88
- }
89
- }
90
-
91
- /// <summary>
92
- /// A dictionary of Row items, indexed by their first column.
93
- /// </summary>
94
- private class RowDictionary : Dictionary<string, Row>
95
- {
96
- public void AddRow(Row row)
97
- {
98
- this.Add((string)row[0], row);
99
- }
100
-
101
- // TODO: Hide other Add methods?
102
- }
103
-
104
- /// <summary>
105
- /// A dictionary of constraints, mapping an id to a list of ids.
106
- /// </summary>
107
- private class Constraints : Dictionary<string, List<string>>
108
- {
109
- public void AddConstraint(string id, string afterId)
110
- {
111
- if (!this.ContainsKey(id))
112
- {
113
- this.Add(id, new List<string>());
114
- }
115
-
116
- // TODO: Show warning if a constraint is seen twice?
117
- if (!this[id].Contains(afterId))
118
- {
119
- this[id].Add(afterId);
120
- }
121
- }
122
-
123
- // TODO: Hide other Add methods?
124
- }
125
-
126
- /// <summary>
127
- /// Finds circular references in the constraints.
128
- /// </summary>
129
- /// <param name="constraints">Constraints to check.</param>
130
- /// <remarks>This is not particularly performant, but it works.</remarks>
131
- private void FindCircularReference(Constraints constraints)
132
- {
133
- foreach (string id in constraints.Keys)
134
- {
135
- List<string> seenIds = new List<string>();
136
- string chain = null;
137
- if (FindCircularReference(constraints, id, id, seenIds, out chain))
138
- {
139
- // We will show a separate message for every ID that's in
140
- // the loop. We could bail after the first one, but then
141
- // we wouldn't catch disjoint loops in a single run.
142
- this.Core.OnMessage(UtilErrors.CircularSearchReference(chain));
143
- }
144
- }
145
- }
146
-
147
- /// <summary>
148
- /// Recursive function that finds circular references in the constraints.
149
- /// </summary>
150
- /// <param name="constraints">Constraints to check.</param>
151
- /// <param name="checkId">The identifier currently being looking for. (Fixed across a given run.)</param>
152
- /// <param name="currentId">The idenifier curently being tested.</param>
153
- /// <param name="seenIds">A list of identifiers seen, to ensure each identifier is only expanded once.</param>
154
- /// <param name="chain">If a circular reference is found, will contain the chain of references.</param>
155
- /// <returns>True if a circular reference is found, false otherwise.</returns>
156
- private bool FindCircularReference(Constraints constraints, string checkId, string currentId, List<string> seenIds, out string chain)
157
- {
158
- chain = null;
159
- List<string> afterList = null;
160
- if (constraints.TryGetValue(currentId, out afterList))
161
- {
162
- foreach (string afterId in afterList)
163
- {
164
- if (afterId == checkId)
165
- {
166
- chain = String.Format(CultureInfo.InvariantCulture, "{0} -> {1}", currentId, afterId);
167
- return true;
168
- }
169
-
170
- if (!seenIds.Contains(afterId))
171
- {
172
- seenIds.Add(afterId);
173
- if (FindCircularReference(constraints, checkId, afterId, seenIds, out chain))
174
- {
175
- chain = String.Format(CultureInfo.InvariantCulture, "{0} -> {1}", currentId, chain);
176
- return true;
177
- }
178
- }
179
- }
180
- }
181
-
182
- return false;
183
- }
184
-
185
- /// <summary>
186
- /// Flattens any dependency chains to simplify reordering.
187
- /// </summary>
188
- /// <param name="constraints"></param>
189
- private void FlattenDependentReferences(Constraints constraints)
190
- {
191
- foreach (string id in constraints.Keys)
192
- {
193
- List<string> flattenedIds = new List<string>();
194
- AddDependentReferences(constraints, id, flattenedIds);
195
- List<string> constraintList = constraints[id];
196
- foreach (string flattenedId in flattenedIds)
197
- {
198
- if (!constraintList.Contains(flattenedId))
199
- {
200
- constraintList.Add(flattenedId);
201
- }
202
- }
203
- }
204
- }
205
-
206
- /// <summary>
207
- /// Adds dependent references to a list.
208
- /// </summary>
209
- /// <param name="constraints"></param>
210
- /// <param name="currentId"></param>
211
- /// <param name="seenIds"></param>
212
- private void AddDependentReferences(Constraints constraints, string currentId, List<string> seenIds)
213
- {
214
- List<string> afterList = null;
215
- if (constraints.TryGetValue(currentId, out afterList))
216
- {
217
- foreach (string afterId in afterList)
218
- {
219
- if (!seenIds.Contains(afterId))
220
- {
221
- seenIds.Add(afterId);
222
- AddDependentReferences(constraints, afterId, seenIds);
223
- }
224
- }
225
- }
226
- }
227
-
228
- /// <summary>
229
- /// Reorder by topological sort
230
- /// </summary>
231
- /// <remarks>
232
- /// We use a variation of Kahn (1962) algorithm as described in
233
- /// Wikipedia (http://en.wikipedia.org/wiki/Topological_sorting), with
234
- /// the additional criteria that start nodes are sorted lexicographically
235
- /// at each step to ensure a deterministic ordering based on 'after'
236
- /// dependencies and ID.
237
- /// </remarks>
238
- private class TopologicalSort
239
- {
240
- private List<string> startIds = new List<string>();
241
- private Constraints constraints;
242
-
243
- /// <summary>
244
- /// Reorder by topological sort
245
- /// </summary>
246
- /// <param name="allIds">The complete list of IDs.</param>
247
- /// <param name="constraints">Constraints to use.</param>
248
- /// <returns>The topologically sorted list of IDs.</returns>
249
- internal List<string> Sort(IEnumerable<string> allIds, Constraints constraints)
250
- {
251
- this.startIds.Clear();
252
- this.CopyConstraints(constraints);
253
-
254
- this.FindInitialStartIds(allIds);
255
-
256
- // We always create a new sortedId list, because we return it
257
- // to the caller and don't know what its lifetime may be.
258
- List<string> sortedIds = new List<string>();
259
-
260
- while (this.startIds.Count > 0)
261
- {
262
- this.SortStartIds();
263
-
264
- string currentId = this.startIds[0];
265
- sortedIds.Add(currentId);
266
- this.startIds.RemoveAt(0);
267
-
268
- this.ResolveConstraint(currentId);
269
- }
270
-
271
- return sortedIds;
272
- }
273
-
274
- /// <summary>
275
- /// Copies a Constraints set (to prevent modifying the incoming data).
276
- /// </summary>
277
- /// <param name="constraints">Constraints to copy.</param>
278
- private void CopyConstraints(Constraints constraints)
279
- {
280
- this.constraints = new Constraints();
281
- foreach (string id in constraints.Keys)
282
- {
283
- foreach (string afterId in constraints[id])
284
- {
285
- this.constraints.AddConstraint(id, afterId);
286
- }
287
- }
288
- }
289
-
290
- /// <summary>
291
- /// Finds initial start IDs. (Those with no constraints.)
292
- /// </summary>
293
- /// <param name="allIds">The complete list of IDs.</param>
294
- private void FindInitialStartIds(IEnumerable<string> allIds)
295
- {
296
- foreach (string id in allIds)
297
- {
298
- if (!this.constraints.ContainsKey(id))
299
- {
300
- this.startIds.Add(id);
301
- }
302
- }
303
- }
304
-
305
- /// <summary>
306
- /// Sorts start IDs.
307
- /// </summary>
308
- private void SortStartIds()
309
- {
310
- this.startIds.Sort();
311
- }
312
-
313
- /// <summary>
314
- /// Removes the resolved constraint and updates the list of startIds
315
- /// with any now-valid (all constraints resolved) IDs.
316
- /// </summary>
317
- /// <param name="resolvedId">The ID to resolve from the set of constraints.</param>
318
- private void ResolveConstraint(string resolvedId)
319
- {
320
- List<string> newStartIds = new List<string>();
321
-
322
- foreach (string id in constraints.Keys)
323
- {
324
- if (this.constraints[id].Contains(resolvedId))
325
- {
326
- this.constraints[id].Remove(resolvedId);
327
-
328
- // If we just removed the last constraint for this
329
- // ID, it is now a valid start ID.
330
- if (0 == this.constraints[id].Count)
331
- {
332
- newStartIds.Add(id);
333
- }
334
- }
335
- }
336
-
337
- foreach (string id in newStartIds)
338
- {
339
- this.constraints.Remove(id);
340
- }
341
-
342
- this.startIds.AddRange(newStartIds);
343
- }
344
- }
345
- }
346
-#endif
347
-}
src/wixext/UtilCompiler.cs
+101
-97
@@ -230,6 +230,8 @@ namespace WixToolset.Util
230
break;
231
case "ComponentSearch":
232
case "ComponentSearchRef":
233
+ case "DetectSHA2Support":
234
+ case "DetectSHA2SupportRef":
235
case "DirectorySearch":
236
case "DirectorySearchRef":
237
case "FileSearch":
@@ -251,6 +253,12 @@ namespace WixToolset.Util
253
case "ComponentSearchRef":
254
this.ParseComponentSearchRefElement(intermediate, section, element);
255
break;
256
+ case "DetectSHA2Support":
257
+ this.ParseDetectSHA2SupportElement(intermediate, section, element);
258
+ break;
259
+ case "DetectSHA2SupportRef":
260
+ this.ParseDetectSHA2SupportRefElement(intermediate, section, element);
261
+ break;
262
case "DirectorySearch":
263
this.ParseDirectorySearchElement(intermediate, section, element);
264
break;
@@ -422,11 +430,6 @@ namespace WixToolset.Util
430
}
431
}
432
425
- if (null == variable)
426
- {
427
- this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Variable"));
428
- }
429
-
433
if (null == guid)
434
{
435
this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Guid"));
@@ -439,16 +442,10 @@ namespace WixToolset.Util
442
443
this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
444
445
+ this.ParseHelper.CreateWixSearchTuple(section, sourceLineNumbers, element.Name.LocalName, id, variable, condition, after, null);
446
+
447
if (!this.Messaging.EncounteredError)
448
{
444
- this.CreateWixSearchRow(section, sourceLineNumbers, id, variable, condition);
445
- if (after != null)
446
- {
447
- this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, "WixSearch", after);
448
- // TODO: We're currently defaulting to "always run after", which we will need to change...
449
- this.CreateWixSearchRelationRow(section, sourceLineNumbers, id, after, 2);
450
- }
451
-
449
WixComponentSearchAttributes attributes = WixComponentSearchAttributes.KeyPath;
450
switch (result)
451
{
@@ -505,6 +502,89 @@ namespace WixToolset.Util
502
this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
503
}
504
505
+ /// <summary>
506
+ /// Parses a DetectSHA2Support element.
507
+ /// </summary>
508
+ /// <param name="element">Element to parse.</param>
509
+ private void ParseDetectSHA2SupportElement(Intermediate intermediate, IntermediateSection section, XElement element)
510
+ {
511
+ var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
512
+ Identifier id = null;
513
+ string variable = null;
514
+ string condition = null;
515
+ string after = null;
516
+
517
+ foreach (var attrib in element.Attributes())
518
+ {
519
+ if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
520
+ {
521
+ switch (attrib.Name.LocalName)
522
+ {
523
+ case "Id":
524
+ case "Variable":
525
+ case "Condition":
526
+ case "After":
527
+ this.ParseCommonSearchAttributes(sourceLineNumbers, attrib, ref id, ref variable, ref condition, ref after);
528
+ break;
529
+ default:
530
+ this.ParseHelper.UnexpectedAttribute(element, attrib);
531
+ break;
532
+ }
533
+ }
534
+ else
535
+ {
536
+ this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
537
+ }
538
+ }
539
+
540
+ if (id == null)
541
+ {
542
+ id = this.ParseHelper.CreateIdentifier("wds2s", variable, condition, after);
543
+ }
544
+
545
+ this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
546
+
547
+ this.ParseHelper.CreateWixSearchTuple(section, sourceLineNumbers, element.Name.LocalName, id, variable, condition, after, UtilConstants.UtilBundleExtensionId);
548
+
549
+ if (!this.Messaging.EncounteredError)
550
+ {
551
+ section.Tuples.Add(new WixDetectSHA2SupportTuple(sourceLineNumbers, id));
552
+ }
553
+ }
554
+
555
+ /// <summary>
556
+ /// Parses a DetectSHA2SupportRef element
557
+ /// </summary>
558
+ /// <param name="element">Element to parse.</param>
559
+ private void ParseDetectSHA2SupportRefElement(Intermediate intermediate, IntermediateSection section, XElement element)
560
+ {
561
+ var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
562
+ string refId = null;
563
+
564
+ foreach (var attrib in element.Attributes())
565
+ {
566
+ if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
567
+ {
568
+ switch (attrib.Name.LocalName)
569
+ {
570
+ case "Id":
571
+ refId = this.ParseHelper.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
572
+ this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, "WixDetectSHA2Support", refId);
573
+ break;
574
+ default:
575
+ this.ParseHelper.UnexpectedAttribute(element, attrib);
576
+ break;
577
+ }
578
+ }
579
+ else
580
+ {
581
+ this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
582
+ }
583
+ }
584
+
585
+ this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
586
+ }
587
+
588
/// <summary>
589
/// Parses an event source element.
590
/// </summary>
@@ -868,11 +948,6 @@ namespace WixToolset.Util
948
}
949
}
950
871
- if (null == variable)
872
- {
873
- this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Variable"));
874
- }
875
-
951
if (null == path)
952
{
953
this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Path"));
@@ -885,16 +960,10 @@ namespace WixToolset.Util
960
961
this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
962
963
+ this.ParseHelper.CreateWixSearchTuple(section, sourceLineNumbers, element.Name.LocalName, id, variable, condition, after, null);
964
+
965
if (!this.Messaging.EncounteredError)
966
{
890
- this.CreateWixSearchRow(section, sourceLineNumbers, id, variable, condition);
891
- if (after != null)
892
- {
893
- this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, "WixSearch", after);
894
- // TODO: We're currently defaulting to "always run after", which we will need to change...
895
- this.CreateWixSearchRelationRow(section, sourceLineNumbers, id, after, 2);
896
- }
897
-
967
WixFileSearchAttributes attributes = WixFileSearchAttributes.IsDirectory;
968
switch (result)
969
{
@@ -990,11 +1059,6 @@ namespace WixToolset.Util
1059
}
1060
}
1061
993
- if (null == variable)
994
- {
995
- this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Variable"));
996
- }
997
-
1062
if (null == path)
1063
{
1064
this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Path"));
@@ -1007,16 +1071,10 @@ namespace WixToolset.Util
1071
1072
this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, node);
1073
1074
+ this.ParseHelper.CreateWixSearchTuple(section, sourceLineNumbers, node.Name.LocalName, id, variable, condition, after, null);
1075
+
1076
if (!this.Messaging.EncounteredError)
1077
{
1012
- this.CreateWixSearchRow(section, sourceLineNumbers, id, variable, condition);
1013
- if (after != null)
1014
- {
1015
- this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, "WixSearch", after);
1016
- // TODO: We're currently defaulting to "always run after", which we will need to change...
1017
- this.CreateWixSearchRelationRow(section, sourceLineNumbers, id, after, 2);
1018
- }
1019
-
1078
WixFileSearchAttributes attributes = WixFileSearchAttributes.Default;
1079
switch (result)
1080
{
@@ -1048,38 +1106,6 @@ namespace WixToolset.Util
1106
});
1107
}
1108
1051
- /// <summary>
1052
- /// Creates a row in the WixSearch table.
1053
- /// </summary>
1054
- /// <param name="sourceLineNumbers">Source line number for the parent element.</param>
1055
- /// <param name="id">Identifier of the search.</param>
1056
- /// <param name="variable">The Burn variable to store the result into.</param>
1057
- /// <param name="condition">A condition to test before evaluating the search.</param>
1058
- private void CreateWixSearchRow(IntermediateSection section, SourceLineNumber sourceLineNumbers, Identifier id, string variable, string condition)
1059
- {
1060
- section.Tuples.Add(new WixSearchTuple(sourceLineNumbers, id)
1061
- {
1062
- Variable = variable,
1063
- Condition = condition,
1064
- });
1065
- }
1066
-
1067
- /// <summary>
1068
- ///
1069
- /// </summary>
1070
- /// <param name="sourceLineNumbers">Source line number for the parent element.</param>
1071
- /// <param name="id">Identifier of the search (key into the WixSearch table)</param>
1072
- /// <param name="parentId">Identifier of the search that comes before (key into the WixSearch table)</param>
1073
- /// <param name="attributes">Further details about the relation between id and parentId.</param>
1074
- private void CreateWixSearchRelationRow(IntermediateSection section, SourceLineNumber sourceLineNumbers, Identifier id, string parentId, int attributes)
1075
- {
1076
- section.Tuples.Add(new WixSearchRelationTuple(sourceLineNumbers, id)
1077
- {
1078
- ParentSearchRef = parentId,
1079
- Attributes = attributes,
1080
- });
1081
- }
1082
-
1109
/// <summary>
1110
/// Parses a file share element.
1111
/// </summary>
@@ -2523,11 +2549,6 @@ namespace WixToolset.Util
2549
}
2550
}
2551
2526
- if (null == variable)
2527
- {
2528
- this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Variable"));
2529
- }
2530
-
2552
if (null == upgradeCode && null == productCode)
2553
{
2554
this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "ProductCode", "UpgradeCode", true));
@@ -2545,16 +2566,10 @@ namespace WixToolset.Util
2566
2567
this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
2568
2569
+ this.ParseHelper.CreateWixSearchTuple(section, sourceLineNumbers, element.Name.LocalName, id, variable, condition, after, null);
2570
+
2571
if (!this.Messaging.EncounteredError)
2572
{
2550
- this.CreateWixSearchRow(section, sourceLineNumbers, id, variable, condition);
2551
- if (after != null)
2552
- {
2553
- this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, "WixSearch", after);
2554
- // TODO: We're currently defaulting to "always run after", which we will need to change...
2555
- this.CreateWixSearchRelationRow(section, sourceLineNumbers, id, after, 2);
2556
- }
2557
-
2573
WixProductSearchAttributes attributes = WixProductSearchAttributes.Version;
2574
switch (result)
2575
{
@@ -2662,11 +2677,6 @@ namespace WixToolset.Util
2677
}
2678
}
2679
2665
- if (null == variable)
2666
- {
2667
- this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Variable"));
2668
- }
2669
-
2680
if (!root.HasValue)
2681
{
2682
this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Root"));
@@ -2726,16 +2736,10 @@ namespace WixToolset.Util
2736
2737
this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
2738
2739
+ this.ParseHelper.CreateWixSearchTuple(section, sourceLineNumbers, element.Name.LocalName, id, variable, condition, after, null);
2740
+
2741
if (!this.Messaging.EncounteredError)
2742
{
2731
- this.CreateWixSearchRow(section, sourceLineNumbers, id, variable, condition);
2732
- if (after != null)
2733
- {
2734
- this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, "WixSearch", after);
2735
- // TODO: We're currently defaulting to "always run after", which we will need to change...
2736
- this.CreateWixSearchRelationRow(section, sourceLineNumbers, id, after, 2);
2737
- }
2738
-
2743
section.Tuples.Add(new WixRegistrySearchTuple(sourceLineNumbers, id)
2744
{
2745
Root = (RegistryRootType)root,
src/wixext/UtilConstants.cs
+2
@@ -13,5 +13,7 @@ namespace WixToolset.Util
13
internal static readonly string[] RegistryPermissions = { "Read", "Write", "CreateSubkeys", "EnumerateSubkeys", "Notify", "CreateLink" };
14
internal static readonly string[] ServicePermissions = { "ServiceQueryConfig", "ServiceChangeConfig", "ServiceQueryStatus", "ServiceEnumerateDependents", "ServiceStart", "ServiceStop", "ServicePauseContinue", "ServiceInterrogate", "ServiceUserDefinedControl" };
15
internal static readonly string[] StandardPermissions = { "Delete", "ReadPermission", "ChangePermission", "TakeOwnership", "Synchronize" };
16
+
17
+ internal const string UtilBundleExtensionId = "WixUtilBundleExtension";
18
}
19
}
src/wixext/UtilErrors.cs
-6
@@ -13,11 +13,6 @@ namespace WixToolset.Util
13
return Message(null, Ids.ArgumentRequiresValue, "The argument '{0}' does not have a value specified and it is required.", argument);
14
}
15
16
- public static Message CircularSearchReference(string chain)
17
- {
18
- return Message(null, Ids.CircularSearchReference, "A circular reference of search ordering constraints was detected: {0}. Search ordering references must form a directed acyclic graph.", chain);
19
- }
20
-
16
public static Message DirectoryNotFound(string directory)
17
{
18
return Message(null, Ids.DirectoryNotFound, "The directory '{0}' could not be found.", directory);
@@ -102,7 +97,6 @@ namespace WixToolset.Util
97
FileNotFound = 5059,
98
PerformanceCategoryNotFound = 5060,
99
UnsupportedPerformanceCounterType = 5061,
105
- CircularSearchReference = 5062,
100
InvalidRegistryObject = 5063,
101
}
102
}
src/wixext/util.xsd
+24
@@ -172,6 +172,30 @@
172
<xs:attribute name="Id" type="xs:string" use="required" />
173
</xs:complexType>
174
</xs:element>
175
+ <xs:element name="DetectSHA2Support">
176
+ <xs:annotation>
177
+ <xs:documentation>Detects support for SHA2.</xs:documentation>
178
+ <xs:appinfo>
179
+ <xse:parent namespace="http://wixtoolset.org/schemas/v4/wxs" ref="Bundle" />
180
+ <xse:parent namespace="http://wixtoolset.org/schemas/v4/wxs" ref="Fragment" />
181
+ </xs:appinfo>
182
+ </xs:annotation>
183
+ <xs:complexType>
184
+ <xs:attributeGroup ref="SearchCommonAttributes" />
185
+ </xs:complexType>
186
+ </xs:element>
187
+ <xs:element name="DetectSHA2SupportRef">
188
+ <xs:annotation>
189
+ <xs:documentation>References a DetectSHA2Support.</xs:documentation>
190
+ <xs:appinfo>
191
+ <xse:parent namespace="http://wixtoolset.org/schemas/v4/wxs" ref="Bundle" />
192
+ <xse:parent namespace="http://wixtoolset.org/schemas/v4/wxs" ref="Fragment" />
193
+ </xs:appinfo>
194
+ </xs:annotation>
195
+ <xs:complexType>
196
+ <xs:attribute name="Id" type="xs:string" use="required" />
197
+ </xs:complexType>
198
+ </xs:element>
199
<xs:element name="DirectorySearch">
200
<xs:annotation>
201
<xs:documentation>Describes a directory search.</xs:documentation>