@joebigelow / wix-1 / commits / 6f6c4851

Initial code commit

Rob Mensching committed May 15, 2019 at 16:09 UTC 6f6c485118796f044a278447722eaf18ac5bf86e
24 files changed +3015
WixToolset.Converters.sln
+67
@@ -3,6 +3,16 @@ Microsoft Visual Studio Solution File, Format Version 12.00
3 # Visual Studio 15
4 VisualStudioVersion = 15.0.26124.0
5 MinimumVisualStudioVersion = 15.0.26124.0
6 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WixToolset.Converters", "src\WixToolset.Converters\WixToolset.Converters.csproj", "{6FAF6385-6598-4B89-972B-C31AFCA14538}"
7 +EndProject
8 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WixToolset.Converters.Tupleizer", "src\WixToolset.Converters.Tupleizer\WixToolset.Converters.Tupleizer.csproj", "{F051BCAF-698C-41D5-8427-164537CE5C5C}"
9 +EndProject
10 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Test", "Test", "{1B16A6C1-2B5D-4F9A-9DD5-FBC89B3CE31E}"
11 +EndProject
12 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WixToolsetTest.Converters", "src\test\WixToolsetTest.Converters\WixToolsetTest.Converters.csproj", "{485C5038-97E1-4729-A54D-848CC69569FD}"
13 +EndProject
14 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WixToolsetTest.Converters.Tupleizer", "src\test\WixToolsetTest.Converters.Tupleizer\WixToolsetTest.Converters.Tupleizer.csproj", "{9DB36DB1-24A1-47A7-9E57-D48A2E33C13C}"
15 +EndProject
16 Global
17 GlobalSection(SolutionConfigurationPlatforms) = preSolution
18 Debug|Any CPU = Debug|Any CPU
@@ -12,7 +22,64 @@ Global
22 Release|x64 = Release|x64
23 Release|x86 = Release|x86
24 EndGlobalSection
25 + GlobalSection(ProjectConfigurationPlatforms) = postSolution
26 + {F051BCAF-698C-41D5-8427-164537CE5C5C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
27 + {F051BCAF-698C-41D5-8427-164537CE5C5C}.Debug|Any CPU.Build.0 = Debug|Any CPU
28 + {F051BCAF-698C-41D5-8427-164537CE5C5C}.Debug|x64.ActiveCfg = Debug|Any CPU
29 + {F051BCAF-698C-41D5-8427-164537CE5C5C}.Debug|x64.Build.0 = Debug|Any CPU
30 + {F051BCAF-698C-41D5-8427-164537CE5C5C}.Debug|x86.ActiveCfg = Debug|Any CPU
31 + {F051BCAF-698C-41D5-8427-164537CE5C5C}.Debug|x86.Build.0 = Debug|Any CPU
32 + {F051BCAF-698C-41D5-8427-164537CE5C5C}.Release|Any CPU.ActiveCfg = Release|Any CPU
33 + {F051BCAF-698C-41D5-8427-164537CE5C5C}.Release|Any CPU.Build.0 = Release|Any CPU
34 + {F051BCAF-698C-41D5-8427-164537CE5C5C}.Release|x64.ActiveCfg = Release|Any CPU
35 + {F051BCAF-698C-41D5-8427-164537CE5C5C}.Release|x64.Build.0 = Release|Any CPU
36 + {F051BCAF-698C-41D5-8427-164537CE5C5C}.Release|x86.ActiveCfg = Release|Any CPU
37 + {F051BCAF-698C-41D5-8427-164537CE5C5C}.Release|x86.Build.0 = Release|Any CPU
38 + {9DB36DB1-24A1-47A7-9E57-D48A2E33C13C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
39 + {9DB36DB1-24A1-47A7-9E57-D48A2E33C13C}.Debug|Any CPU.Build.0 = Debug|Any CPU
40 + {9DB36DB1-24A1-47A7-9E57-D48A2E33C13C}.Debug|x64.ActiveCfg = Debug|Any CPU
41 + {9DB36DB1-24A1-47A7-9E57-D48A2E33C13C}.Debug|x64.Build.0 = Debug|Any CPU
42 + {9DB36DB1-24A1-47A7-9E57-D48A2E33C13C}.Debug|x86.ActiveCfg = Debug|Any CPU
43 + {9DB36DB1-24A1-47A7-9E57-D48A2E33C13C}.Debug|x86.Build.0 = Debug|Any CPU
44 + {9DB36DB1-24A1-47A7-9E57-D48A2E33C13C}.Release|Any CPU.ActiveCfg = Release|Any CPU
45 + {9DB36DB1-24A1-47A7-9E57-D48A2E33C13C}.Release|Any CPU.Build.0 = Release|Any CPU
46 + {9DB36DB1-24A1-47A7-9E57-D48A2E33C13C}.Release|x64.ActiveCfg = Release|Any CPU
47 + {9DB36DB1-24A1-47A7-9E57-D48A2E33C13C}.Release|x64.Build.0 = Release|Any CPU
48 + {9DB36DB1-24A1-47A7-9E57-D48A2E33C13C}.Release|x86.ActiveCfg = Release|Any CPU
49 + {9DB36DB1-24A1-47A7-9E57-D48A2E33C13C}.Release|x86.Build.0 = Release|Any CPU
50 + {6FAF6385-6598-4B89-972B-C31AFCA14538}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
51 + {6FAF6385-6598-4B89-972B-C31AFCA14538}.Debug|Any CPU.Build.0 = Debug|Any CPU
52 + {6FAF6385-6598-4B89-972B-C31AFCA14538}.Debug|x64.ActiveCfg = Debug|Any CPU
53 + {6FAF6385-6598-4B89-972B-C31AFCA14538}.Debug|x64.Build.0 = Debug|Any CPU
54 + {6FAF6385-6598-4B89-972B-C31AFCA14538}.Debug|x86.ActiveCfg = Debug|Any CPU
55 + {6FAF6385-6598-4B89-972B-C31AFCA14538}.Debug|x86.Build.0 = Debug|Any CPU
56 + {6FAF6385-6598-4B89-972B-C31AFCA14538}.Release|Any CPU.ActiveCfg = Release|Any CPU
57 + {6FAF6385-6598-4B89-972B-C31AFCA14538}.Release|Any CPU.Build.0 = Release|Any CPU
58 + {6FAF6385-6598-4B89-972B-C31AFCA14538}.Release|x64.ActiveCfg = Release|Any CPU
59 + {6FAF6385-6598-4B89-972B-C31AFCA14538}.Release|x64.Build.0 = Release|Any CPU
60 + {6FAF6385-6598-4B89-972B-C31AFCA14538}.Release|x86.ActiveCfg = Release|Any CPU
61 + {6FAF6385-6598-4B89-972B-C31AFCA14538}.Release|x86.Build.0 = Release|Any CPU
62 + {485C5038-97E1-4729-A54D-848CC69569FD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
63 + {485C5038-97E1-4729-A54D-848CC69569FD}.Debug|Any CPU.Build.0 = Debug|Any CPU
64 + {485C5038-97E1-4729-A54D-848CC69569FD}.Debug|x64.ActiveCfg = Debug|Any CPU
65 + {485C5038-97E1-4729-A54D-848CC69569FD}.Debug|x64.Build.0 = Debug|Any CPU
66 + {485C5038-97E1-4729-A54D-848CC69569FD}.Debug|x86.ActiveCfg = Debug|Any CPU
67 + {485C5038-97E1-4729-A54D-848CC69569FD}.Debug|x86.Build.0 = Debug|Any CPU
68 + {485C5038-97E1-4729-A54D-848CC69569FD}.Release|Any CPU.ActiveCfg = Release|Any CPU
69 + {485C5038-97E1-4729-A54D-848CC69569FD}.Release|Any CPU.Build.0 = Release|Any CPU
70 + {485C5038-97E1-4729-A54D-848CC69569FD}.Release|x64.ActiveCfg = Release|Any CPU
71 + {485C5038-97E1-4729-A54D-848CC69569FD}.Release|x64.Build.0 = Release|Any CPU
72 + {485C5038-97E1-4729-A54D-848CC69569FD}.Release|x86.ActiveCfg = Release|Any CPU
73 + {485C5038-97E1-4729-A54D-848CC69569FD}.Release|x86.Build.0 = Release|Any CPU
74 + EndGlobalSection
75 GlobalSection(SolutionProperties) = preSolution
76 HideSolutionNode = FALSE
77 EndGlobalSection
78 + GlobalSection(NestedProjects) = preSolution
79 + {9DB36DB1-24A1-47A7-9E57-D48A2E33C13C} = {1B16A6C1-2B5D-4F9A-9DD5-FBC89B3CE31E}
80 + {485C5038-97E1-4729-A54D-848CC69569FD} = {1B16A6C1-2B5D-4F9A-9DD5-FBC89B3CE31E}
81 + EndGlobalSection
82 + GlobalSection(ExtensibilityGlobals) = postSolution
83 + SolutionGuid = {2E71F0EC-CF75-44DA-8353-7066EBD06564}
84 + EndGlobalSection
85 EndGlobal
WixToolset.Converters.v3.ncrunchsolution new
+6
@@ -0,0 +1,6 @@
1 +<SolutionConfiguration>
2 + <Settings>
3 + <AllowParallelTestExecution>False</AllowParallelTestExecution>
4 + <SolutionConfigured>True</SolutionConfigured>
5 + </Settings>
6 +</SolutionConfiguration>
\ No newline at end of file
appveyor.cmd new
+12
@@ -0,0 +1,12 @@
1 +@setlocal
2 +@pushd %~dp0
3 +@set _P=%~dp0build\Release\publish
4 +
5 +dotnet pack -c Release src\WixToolset.Converters
6 +dotnet pack -c Release src\WixToolset.Converters.Tupleizer
7 +
8 +dotnet build -c Release src\test\WixToolsetTest.Converters
9 +dotnet build -c Release src\test\WixToolsetTest.Converters.Tupleizer
10 +
11 +@popd
12 +@endlocal
src/WixToolset.Converters.Tupleizer/ConvertTuplesCommand.cs new
+609
@@ -0,0 +1,609 @@
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.Converters.Tupleizer
4 +{
5 + using System;
6 + using System.Linq;
7 + using WixToolset.Data;
8 + using WixToolset.Data.Tuples;
9 + using WixToolset.Data.WindowsInstaller;
10 + using Wix3 = Microsoft.Tools.WindowsInstallerXml;
11 +
12 + public class ConvertTuplesCommand
13 + {
14 + public Intermediate Execute(string path)
15 + {
16 + var output = Wix3.Output.Load(path, suppressVersionCheck: true, suppressSchema: true);
17 + return this.Execute(output);
18 + }
19 +
20 + public Intermediate Execute(Wix3.Output output)
21 + {
22 + var section = new IntermediateSection(String.Empty, OutputType3ToSectionType4(output.Type), output.Codepage);
23 +
24 + foreach (Wix3.Table table in output.Tables)
25 + {
26 + foreach (Wix3.Row row in table.Rows)
27 + {
28 + var tuple = GenerateTupleFromRow(row);
29 + if (tuple != null)
30 + {
31 + section.Tuples.Add(tuple);
32 + }
33 + }
34 + }
35 +
36 + return new Intermediate(String.Empty, new[] { section }, localizationsByCulture: null, embedFilePaths: null);
37 + }
38 +
39 + private static IntermediateTuple GenerateTupleFromRow(Wix3.Row row)
40 + {
41 + var name = row.Table.Name;
42 + switch (name)
43 + {
44 + case "_SummaryInformation":
45 + return DefaultTupleFromRow(typeof(_SummaryInformationTuple), row, columnZeroIsId: false);
46 + case "ActionText":
47 + return DefaultTupleFromRow(typeof(ActionTextTuple), row, columnZeroIsId: false);
48 + case "AdvtExecuteSequence":
49 + return DefaultTupleFromRow(typeof(AdvtExecuteSequenceTuple), row, columnZeroIsId: false);
50 + case "AppId":
51 + return DefaultTupleFromRow(typeof(AppIdTuple), row, columnZeroIsId: false);
52 + case "AppSearch":
53 + return DefaultTupleFromRow(typeof(AppSearchTuple), row, columnZeroIsId: false);
54 + case "Binary":
55 + return DefaultTupleFromRow(typeof(BinaryTuple), row, columnZeroIsId: false);
56 + case "Class":
57 + return DefaultTupleFromRow(typeof(ClassTuple), row, columnZeroIsId: false);
58 + case "CompLocator":
59 + return DefaultTupleFromRow(typeof(CompLocatorTuple), row, columnZeroIsId: true);
60 + case "Component":
61 + {
62 + var attributes = FieldAsNullableInt(row, 3);
63 +
64 + var location = ComponentLocation.LocalOnly;
65 + if ((attributes & WindowsInstallerConstants.MsidbComponentAttributesSourceOnly) == WindowsInstallerConstants.MsidbComponentAttributesSourceOnly)
66 + {
67 + location = ComponentLocation.SourceOnly;
68 + }
69 + else if ((attributes & WindowsInstallerConstants.MsidbComponentAttributesOptional) == WindowsInstallerConstants.MsidbComponentAttributesOptional)
70 + {
71 + location = ComponentLocation.Either;
72 + }
73 +
74 + var keyPathType = ComponentKeyPathType.File;
75 + if ((attributes & WindowsInstallerConstants.MsidbComponentAttributesRegistryKeyPath) == WindowsInstallerConstants.MsidbComponentAttributesRegistryKeyPath)
76 + {
77 + keyPathType = ComponentKeyPathType.Registry;
78 + }
79 + else if ((attributes & WindowsInstallerConstants.MsidbComponentAttributesODBCDataSource) == WindowsInstallerConstants.MsidbComponentAttributesODBCDataSource)
80 + {
81 + keyPathType = ComponentKeyPathType.OdbcDataSource;
82 + }
83 +
84 + return new ComponentTuple(SourceLineNumber4(row.SourceLineNumbers), new Identifier(AccessModifier.Public, FieldAsString(row, 0)))
85 + {
86 + ComponentId = FieldAsString(row, 1),
87 + Directory_ = FieldAsString(row, 2),
88 + Condition = FieldAsString(row, 4),
89 + KeyPath = FieldAsString(row, 5),
90 + Location = location,
91 + DisableRegistryReflection = (attributes & WindowsInstallerConstants.MsidbComponentAttributesDisableRegistryReflection) == WindowsInstallerConstants.MsidbComponentAttributesDisableRegistryReflection,
92 + NeverOverwrite = (attributes & WindowsInstallerConstants.MsidbComponentAttributesNeverOverwrite) == WindowsInstallerConstants.MsidbComponentAttributesNeverOverwrite,
93 + Permanent = (attributes & WindowsInstallerConstants.MsidbComponentAttributesPermanent) == WindowsInstallerConstants.MsidbComponentAttributesPermanent,
94 + SharedDllRefCount = (attributes & WindowsInstallerConstants.MsidbComponentAttributesSharedDllRefCount) == WindowsInstallerConstants.MsidbComponentAttributesSharedDllRefCount,
95 + Shared = (attributes & WindowsInstallerConstants.MsidbComponentAttributesShared) == WindowsInstallerConstants.MsidbComponentAttributesShared,
96 + Transitive = (attributes & WindowsInstallerConstants.MsidbComponentAttributesTransitive) == WindowsInstallerConstants.MsidbComponentAttributesTransitive,
97 + UninstallWhenSuperseded = (attributes & WindowsInstallerConstants.MsidbComponentAttributesUninstallOnSupersedence) == WindowsInstallerConstants.MsidbComponentAttributesUninstallOnSupersedence,
98 + Win64 = (attributes & WindowsInstallerConstants.MsidbComponentAttributes64bit) == WindowsInstallerConstants.MsidbComponentAttributes64bit,
99 + KeyPathType = keyPathType,
100 + };
101 + }
102 +
103 + case "Condition":
104 + return DefaultTupleFromRow(typeof(ConditionTuple), row, columnZeroIsId: false);
105 + case "CreateFolder":
106 + return DefaultTupleFromRow(typeof(CreateFolderTuple), row, columnZeroIsId: false);
107 + case "CustomAction":
108 + {
109 + var caType = FieldAsInt(row, 1);
110 + var executionType = DetermineCustomActionExecutionType(caType);
111 + var sourceType = DetermineCustomActionSourceType(caType);
112 + var targetType = DetermineCustomActionTargetType(caType);
113 +
114 + return new CustomActionTuple(SourceLineNumber4(row.SourceLineNumbers), new Identifier(AccessModifier.Public, FieldAsString(row, 0)))
115 + {
116 + ExecutionType = executionType,
117 + SourceType = sourceType,
118 + Source = FieldAsString(row, 2),
119 + TargetType = targetType,
120 + Target = FieldAsString(row, 3),
121 + Win64 = (caType & WindowsInstallerConstants.MsidbCustomActionType64BitScript) == WindowsInstallerConstants.MsidbCustomActionType64BitScript,
122 + TSAware = (caType & WindowsInstallerConstants.MsidbCustomActionTypeTSAware) == WindowsInstallerConstants.MsidbCustomActionTypeTSAware,
123 + Impersonate = (caType & WindowsInstallerConstants.MsidbCustomActionTypeNoImpersonate) != WindowsInstallerConstants.MsidbCustomActionTypeNoImpersonate,
124 + IgnoreResult = (caType & WindowsInstallerConstants.MsidbCustomActionTypeContinue) == WindowsInstallerConstants.MsidbCustomActionTypeContinue,
125 + Hidden = (caType & WindowsInstallerConstants.MsidbCustomActionTypeHideTarget) == WindowsInstallerConstants.MsidbCustomActionTypeHideTarget,
126 + Async = (caType & WindowsInstallerConstants.MsidbCustomActionTypeAsync) == WindowsInstallerConstants.MsidbCustomActionTypeAsync,
127 + };
128 + }
129 +
130 + case "Directory":
131 + return DefaultTupleFromRow(typeof(DirectoryTuple), row, columnZeroIsId: false);
132 + case "DrLocator":
133 + return DefaultTupleFromRow(typeof(DrLocatorTuple), row, columnZeroIsId: false);
134 + case "Error":
135 + return DefaultTupleFromRow(typeof(ErrorTuple), row, columnZeroIsId: false);
136 + case "Extension":
137 + return DefaultTupleFromRow(typeof(ExtensionTuple), row, columnZeroIsId: false);
138 + case "Feature":
139 + {
140 + int attributes = FieldAsInt(row, 7);
141 + var installDefault = FeatureInstallDefault.Local;
142 + if ((attributes & WindowsInstallerConstants.MsidbFeatureAttributesFollowParent) == WindowsInstallerConstants.MsidbFeatureAttributesFollowParent)
143 + {
144 + installDefault = FeatureInstallDefault.FollowParent;
145 + }
146 + else
147 + if ((attributes & WindowsInstallerConstants.MsidbFeatureAttributesFavorSource) == WindowsInstallerConstants.MsidbFeatureAttributesFavorSource)
148 + {
149 + installDefault = FeatureInstallDefault.Source;
150 + }
151 +
152 + return new FeatureTuple(SourceLineNumber4(row.SourceLineNumbers), new Identifier(AccessModifier.Public, FieldAsString(row, 0)))
153 + {
154 + Feature_Parent = FieldAsString(row, 1),
155 + Title = FieldAsString(row, 2),
156 + Description = FieldAsString(row, 3),
157 + Display = FieldAsInt(row, 4), // BUGBUGBUG: FieldAsNullableInt(row, 4),
158 + Level = FieldAsInt(row, 5),
159 + Directory_ = FieldAsString(row, 6),
160 + DisallowAbsent = (attributes & WindowsInstallerConstants.MsidbFeatureAttributesUIDisallowAbsent) == WindowsInstallerConstants.MsidbFeatureAttributesUIDisallowAbsent,
161 + DisallowAdvertise = (attributes & WindowsInstallerConstants.MsidbFeatureAttributesDisallowAdvertise) == WindowsInstallerConstants.MsidbFeatureAttributesDisallowAdvertise,
162 + InstallDefault = installDefault,
163 + TypicalDefault = (attributes & WindowsInstallerConstants.MsidbFeatureAttributesFavorAdvertise) == WindowsInstallerConstants.MsidbFeatureAttributesFavorAdvertise ? FeatureTypicalDefault.Advertise : FeatureTypicalDefault.Install,
164 + };
165 + }
166 +
167 + case "FeatureComponents":
168 + return DefaultTupleFromRow(typeof(FeatureComponentsTuple), row, columnZeroIsId: false);
169 + case "File":
170 + {
171 + var attributes = FieldAsNullableInt(row, 6);
172 + var readOnly = (attributes & WindowsInstallerConstants.MsidbFileAttributesReadOnly) == WindowsInstallerConstants.MsidbFileAttributesReadOnly;
173 + var hidden = (attributes & WindowsInstallerConstants.MsidbFileAttributesHidden) == WindowsInstallerConstants.MsidbFileAttributesHidden;
174 + var system = (attributes & WindowsInstallerConstants.MsidbFileAttributesSystem) == WindowsInstallerConstants.MsidbFileAttributesSystem;
175 + var vital = (attributes & WindowsInstallerConstants.MsidbFileAttributesVital) == WindowsInstallerConstants.MsidbFileAttributesVital;
176 + var checksum = (attributes & WindowsInstallerConstants.MsidbFileAttributesChecksum) == WindowsInstallerConstants.MsidbFileAttributesChecksum;
177 + bool? compressed = null;
178 + if ((attributes & WindowsInstallerConstants.MsidbFileAttributesNoncompressed) == WindowsInstallerConstants.MsidbFileAttributesNoncompressed)
179 + {
180 + compressed = false;
181 + }
182 + else if ((attributes & WindowsInstallerConstants.MsidbFileAttributesCompressed) == WindowsInstallerConstants.MsidbFileAttributesCompressed)
183 + {
184 + compressed = true;
185 + }
186 +
187 + return new FileTuple(SourceLineNumber4(row.SourceLineNumbers), new Identifier(AccessModifier.Public, FieldAsString(row, 0)))
188 + {
189 + Component_ = FieldAsString(row, 1),
190 + LongFileName = FieldAsString(row, 2),
191 + FileSize = FieldAsInt(row, 3),
192 + Version = FieldAsString(row, 4),
193 + Language = FieldAsString(row, 5),
194 + ReadOnly = readOnly,
195 + Hidden = hidden,
196 + System = system,
197 + Vital = vital,
198 + Checksum = checksum,
199 + Compressed = compressed,
200 + };
201 + }
202 +
203 + case "Font":
204 + return DefaultTupleFromRow(typeof(FontTuple), row, columnZeroIsId: false);
205 + case "Icon":
206 + return DefaultTupleFromRow(typeof(IconTuple), row, columnZeroIsId: false);
207 + case "InstallExecuteSequence":
208 + return DefaultTupleFromRow(typeof(InstallExecuteSequenceTuple), row, columnZeroIsId: false);
209 + case "LockPermissions":
210 + return DefaultTupleFromRow(typeof(LockPermissionsTuple), row, columnZeroIsId: false);
211 + case "Media":
212 + return DefaultTupleFromRow(typeof(MediaTuple), row, columnZeroIsId: false);
213 + case "MIME":
214 + return DefaultTupleFromRow(typeof(MIMETuple), row, columnZeroIsId: false);
215 + case "MoveFile":
216 + return DefaultTupleFromRow(typeof(MoveFileTuple), row, columnZeroIsId: false);
217 + case "MsiAssembly":
218 + return DefaultTupleFromRow(typeof(MsiAssemblyTuple), row, columnZeroIsId: false);
219 + case "MsiShortcutProperty":
220 + return DefaultTupleFromRow(typeof(MsiShortcutPropertyTuple), row, columnZeroIsId: false);
221 + case "ProgId":
222 + return DefaultTupleFromRow(typeof(ProgIdTuple), row, columnZeroIsId: false);
223 + case "Property":
224 + return DefaultTupleFromRow(typeof(PropertyTuple), row, columnZeroIsId: false);
225 + case "PublishComponent":
226 + return DefaultTupleFromRow(typeof(PublishComponentTuple), row, columnZeroIsId: false);
227 + case "Registry":
228 + {
229 + var value = FieldAsString(row, 4);
230 + var valueType = RegistryValueType.String;
231 + var valueAction = RegistryValueActionType.Write;
232 +
233 + if (!String.IsNullOrEmpty(value))
234 + {
235 + if (value.StartsWith("#x", StringComparison.Ordinal))
236 + {
237 + valueType = RegistryValueType.Binary;
238 + value = value.Substring(2);
239 + }
240 + else if (value.StartsWith("#%", StringComparison.Ordinal))
241 + {
242 + valueType = RegistryValueType.Expandable;
243 + value = value.Substring(2);
244 + }
245 + else if (value.StartsWith("#", StringComparison.Ordinal))
246 + {
247 + valueType = RegistryValueType.Integer;
248 + value = value.Substring(1);
249 + }
250 + else if (value.StartsWith("[~]", StringComparison.Ordinal) && value.EndsWith("[~]", StringComparison.Ordinal))
251 + {
252 + value = value.Substring(3, value.Length - 6);
253 + valueType = RegistryValueType.MultiString;
254 + valueAction = RegistryValueActionType.Write;
255 + }
256 + else if (value.StartsWith("[~]", StringComparison.Ordinal))
257 + {
258 + value = value.Substring(3);
259 + valueType = RegistryValueType.MultiString;
260 + valueAction = RegistryValueActionType.Append;
261 + }
262 + else if (value.EndsWith("[~]", StringComparison.Ordinal))
263 + {
264 + value = value.Substring(0, value.Length - 3);
265 + valueType = RegistryValueType.MultiString;
266 + valueAction = RegistryValueActionType.Prepend;
267 + }
268 + }
269 +
270 + return new RegistryTuple(SourceLineNumber4(row.SourceLineNumbers), new Identifier(AccessModifier.Public, FieldAsString(row, 0)))
271 + {
272 + Root = (RegistryRootType)FieldAsInt(row, 1),
273 + Key = FieldAsString(row, 2),
274 + Name = FieldAsString(row, 3),
275 + Value = value,
276 + Component_ = FieldAsString(row, 5),
277 + ValueAction = valueAction,
278 + ValueType = valueType,
279 + };
280 + }
281 +
282 + case "RegLocator":
283 + return DefaultTupleFromRow(typeof(RegLocatorTuple), row, columnZeroIsId: false);
284 + case "RemoveFile":
285 + return DefaultTupleFromRow(typeof(RemoveFileTuple), row, columnZeroIsId: false);
286 + case "RemoveRegistry":
287 + {
288 + return new RemoveRegistryTuple(SourceLineNumber4(row.SourceLineNumbers), new Identifier(AccessModifier.Public, FieldAsString(row, 0)))
289 + {
290 + Action = RemoveRegistryActionType.RemoveOnInstall,
291 + Root = (RegistryRootType)FieldAsInt(row, 1),
292 + Key = FieldAsString(row, 2),
293 + Name = FieldAsString(row, 3),
294 + Component_ = FieldAsString(row, 4),
295 + };
296 + }
297 +
298 + case "ReserveCost":
299 + return DefaultTupleFromRow(typeof(ReserveCostTuple), row, columnZeroIsId: false);
300 + case "ServiceControl":
301 + {
302 + var events = FieldAsInt(row, 2);
303 + var wait = FieldAsNullableInt(row, 4);
304 + return new ServiceControlTuple(SourceLineNumber4(row.SourceLineNumbers), new Identifier(AccessModifier.Public, FieldAsString(row, 0)))
305 + {
306 + Name = FieldAsString(row, 1),
307 + Arguments = FieldAsString(row, 3),
308 + Wait = !wait.HasValue || wait.Value == 1,
309 + Component_ = FieldAsString(row, 5),
310 + InstallRemove = (events & WindowsInstallerConstants.MsidbServiceControlEventDelete) == WindowsInstallerConstants.MsidbServiceControlEventDelete,
311 + UninstallRemove = (events & WindowsInstallerConstants.MsidbServiceControlEventUninstallDelete) == WindowsInstallerConstants.MsidbServiceControlEventUninstallDelete,
312 + InstallStart = (events & WindowsInstallerConstants.MsidbServiceControlEventStart) == WindowsInstallerConstants.MsidbServiceControlEventStart,
313 + UninstallStart = (events & WindowsInstallerConstants.MsidbServiceControlEventUninstallStart) == WindowsInstallerConstants.MsidbServiceControlEventUninstallStart,
314 + InstallStop = (events & WindowsInstallerConstants.MsidbServiceControlEventStop) == WindowsInstallerConstants.MsidbServiceControlEventStop,
315 + UninstallStop = (events & WindowsInstallerConstants.MsidbServiceControlEventUninstallStop) == WindowsInstallerConstants.MsidbServiceControlEventUninstallStop,
316 + };
317 + }
318 +
319 + case "ServiceInstall":
320 + return DefaultTupleFromRow(typeof(ServiceInstallTuple), row, columnZeroIsId: true);
321 + case "Shortcut":
322 + return DefaultTupleFromRow(typeof(ShortcutTuple), row, columnZeroIsId: true);
323 + case "Signature":
324 + return DefaultTupleFromRow(typeof(SignatureTuple), row, columnZeroIsId: false);
325 + case "Upgrade":
326 + {
327 + var attributes = FieldAsInt(row, 4);
328 + return new UpgradeTuple(SourceLineNumber4(row.SourceLineNumbers), new Identifier(AccessModifier.Public, FieldAsString(row, 0)))
329 + {
330 + UpgradeCode = FieldAsString(row, 0),
331 + VersionMin = FieldAsString(row, 1),
332 + VersionMax = FieldAsString(row, 2),
333 + Language = FieldAsString(row, 3),
334 + Remove = FieldAsString(row, 5),
335 + ActionProperty = FieldAsString(row, 6),
336 + MigrateFeatures = (attributes & WindowsInstallerConstants.MsidbUpgradeAttributesMigrateFeatures) == WindowsInstallerConstants.MsidbUpgradeAttributesMigrateFeatures,
337 + OnlyDetect = (attributes & WindowsInstallerConstants.MsidbUpgradeAttributesOnlyDetect) == WindowsInstallerConstants.MsidbUpgradeAttributesOnlyDetect,
338 + IgnoreRemoveFailures = (attributes & WindowsInstallerConstants.MsidbUpgradeAttributesIgnoreRemoveFailure) == WindowsInstallerConstants.MsidbUpgradeAttributesIgnoreRemoveFailure,
339 + VersionMinInclusive = (attributes & WindowsInstallerConstants.MsidbUpgradeAttributesVersionMinInclusive) == WindowsInstallerConstants.MsidbUpgradeAttributesVersionMinInclusive,
340 + VersionMaxInclusive = (attributes & WindowsInstallerConstants.MsidbUpgradeAttributesVersionMaxInclusive) == WindowsInstallerConstants.MsidbUpgradeAttributesVersionMaxInclusive,
341 + ExcludeLanguages = (attributes & WindowsInstallerConstants.MsidbUpgradeAttributesLanguagesExclusive) == WindowsInstallerConstants.MsidbUpgradeAttributesLanguagesExclusive,
342 + };
343 + }
344 +
345 + case "Verb":
346 + return DefaultTupleFromRow(typeof(VerbTuple), row, columnZeroIsId: false);
347 + //case "WixAction":
348 + // return new WixActionTuple(SourceLineNumber4(row.SourceLineNumbers))
349 + // {
350 + // SequenceTable = (SequenceTable)Enum.Parse(typeof(SequenceTable), FieldAsString(row, 0)),
351 + // Action = FieldAsString(row, 1),
352 + // Condition = FieldAsString(row, 2),
353 + // Sequence = FieldAsInt(row, 3),
354 + // Before = FieldAsString(row, 4),
355 + // After = FieldAsString(row, 5),
356 + // Overridable = FieldAsNullableInt(row, 6) != 0,
357 + // };
358 + case "WixFile":
359 + var assemblyAttributes3 = FieldAsNullableInt(row, 1);
360 + return new WixFileTuple(SourceLineNumber4(row.SourceLineNumbers), new Identifier(AccessModifier.Public, FieldAsString(row, 0)))
361 + {
362 + AssemblyType = assemblyAttributes3 == 0 ? FileAssemblyType.DotNetAssembly : assemblyAttributes3 == 1 ? FileAssemblyType.Win32Assembly : FileAssemblyType.NotAnAssembly,
363 + File_AssemblyManifest = FieldAsString(row, 2),
364 + File_AssemblyApplication = FieldAsString(row, 3),
365 + Directory_ = FieldAsString(row, 4),
366 + DiskId = FieldAsInt(row, 5), // TODO: BUGBUGBUG: AB#2626: DiskId is nullable in WiX v3.
367 + Source = new IntermediateFieldPathValue() { Path = FieldAsString(row, 6) },
368 + ProcessorArchitecture = FieldAsString(row, 7),
369 + PatchGroup = FieldAsInt(row, 8),
370 + Attributes = FieldAsInt(row, 9),
371 + };
372 + case "WixProperty":
373 + {
374 + var attributes = FieldAsInt(row, 1);
375 + return new WixPropertyTuple(SourceLineNumber4(row.SourceLineNumbers))
376 + {
377 + Property_ = FieldAsString(row, 0),
378 + Admin = (attributes & 0x1) == 0x1,
379 + Hidden = (attributes & 0x2) == 0x2,
380 + Secure = (attributes & 0x4) == 0x4,
381 + };
382 + }
383 +
384 + default:
385 + return GenericTupleFromCustomRow(row, columnZeroIsId: false);
386 + }
387 + }
388 +
389 + private static CustomActionTargetType DetermineCustomActionTargetType(int type)
390 + {
391 + var targetType = default(CustomActionTargetType);
392 +
393 + if ((type & WindowsInstallerConstants.MsidbCustomActionTypeVBScript) == WindowsInstallerConstants.MsidbCustomActionTypeVBScript)
394 + {
395 + targetType = CustomActionTargetType.VBScript;
396 + }
397 + else if ((type & WindowsInstallerConstants.MsidbCustomActionTypeJScript) == WindowsInstallerConstants.MsidbCustomActionTypeJScript)
398 + {
399 + targetType = CustomActionTargetType.JScript;
400 + }
401 + else if ((type & WindowsInstallerConstants.MsidbCustomActionTypeTextData) == WindowsInstallerConstants.MsidbCustomActionTypeTextData)
402 + {
403 + targetType = CustomActionTargetType.TextData;
404 + }
405 + else if ((type & WindowsInstallerConstants.MsidbCustomActionTypeExe) == WindowsInstallerConstants.MsidbCustomActionTypeExe)
406 + {
407 + targetType = CustomActionTargetType.Exe;
408 + }
409 + else if ((type & WindowsInstallerConstants.MsidbCustomActionTypeDll) == WindowsInstallerConstants.MsidbCustomActionTypeDll)
410 + {
411 + targetType = CustomActionTargetType.Dll;
412 + }
413 +
414 + return targetType;
415 + }
416 +
417 + private static CustomActionSourceType DetermineCustomActionSourceType(int type)
418 + {
419 + var sourceType = CustomActionSourceType.Binary;
420 +
421 + if ((type & WindowsInstallerConstants.MsidbCustomActionTypeProperty) == WindowsInstallerConstants.MsidbCustomActionTypeProperty)
422 + {
423 + sourceType = CustomActionSourceType.Property;
424 + }
425 + else if ((type & WindowsInstallerConstants.MsidbCustomActionTypeDirectory) == WindowsInstallerConstants.MsidbCustomActionTypeDirectory)
426 + {
427 + sourceType = CustomActionSourceType.Directory;
428 + }
429 + else if ((type & WindowsInstallerConstants.MsidbCustomActionTypeSourceFile) == WindowsInstallerConstants.MsidbCustomActionTypeSourceFile)
430 + {
431 + sourceType = CustomActionSourceType.File;
432 + }
433 +
434 + return sourceType;
435 + }
436 +
437 + private static CustomActionExecutionType DetermineCustomActionExecutionType(int type)
438 + {
439 + var executionType = CustomActionExecutionType.Immediate;
440 +
441 + if ((type & (WindowsInstallerConstants.MsidbCustomActionTypeInScript | WindowsInstallerConstants.MsidbCustomActionTypeCommit)) == (WindowsInstallerConstants.MsidbCustomActionTypeInScript | WindowsInstallerConstants.MsidbCustomActionTypeCommit))
442 + {
443 + executionType = CustomActionExecutionType.Commit;
444 + }
445 + else if ((type & (WindowsInstallerConstants.MsidbCustomActionTypeInScript | WindowsInstallerConstants.MsidbCustomActionTypeRollback)) == (WindowsInstallerConstants.MsidbCustomActionTypeInScript | WindowsInstallerConstants.MsidbCustomActionTypeRollback))
446 + {
447 + executionType = CustomActionExecutionType.Rollback;
448 + }
449 + else if ((type & WindowsInstallerConstants.MsidbCustomActionTypeInScript) == WindowsInstallerConstants.MsidbCustomActionTypeInScript)
450 + {
451 + executionType = CustomActionExecutionType.Deferred;
452 + }
453 + else if ((type & WindowsInstallerConstants.MsidbCustomActionTypeClientRepeat) == WindowsInstallerConstants.MsidbCustomActionTypeClientRepeat)
454 + {
455 + executionType = CustomActionExecutionType.ClientRepeat;
456 + }
457 + else if ((type & WindowsInstallerConstants.MsidbCustomActionTypeOncePerProcess) == WindowsInstallerConstants.MsidbCustomActionTypeOncePerProcess)
458 + {
459 + executionType = CustomActionExecutionType.OncePerProcess;
460 + }
461 + else if ((type & WindowsInstallerConstants.MsidbCustomActionTypeFirstSequence) == WindowsInstallerConstants.MsidbCustomActionTypeFirstSequence)
462 + {
463 + executionType = CustomActionExecutionType.FirstSequence;
464 + }
465 +
466 + return executionType;
467 + }
468 +
469 + private static IntermediateFieldType ColumnType3ToIntermediateFieldType4(Wix3.ColumnType columnType)
470 + {
471 + switch (columnType)
472 + {
473 + case Wix3.ColumnType.Number:
474 + return IntermediateFieldType.Number;
475 + case Wix3.ColumnType.Object:
476 + return IntermediateFieldType.Path;
477 + case Wix3.ColumnType.Unknown:
478 + case Wix3.ColumnType.String:
479 + case Wix3.ColumnType.Localized:
480 + case Wix3.ColumnType.Preserved:
481 + default:
482 + return IntermediateFieldType.String;
483 + }
484 + }
485 +
486 + private static IntermediateTuple DefaultTupleFromRow(Type tupleType, Wix3.Row row, bool columnZeroIsId)
487 + {
488 + var tuple = Activator.CreateInstance(tupleType) as IntermediateTuple;
489 +
490 + SetTupleFieldsFromRow(row, tuple, columnZeroIsId);
491 +
492 + tuple.SourceLineNumbers = SourceLineNumber4(row.SourceLineNumbers);
493 + return tuple;
494 + }
495 +
496 + private static IntermediateTuple GenericTupleFromCustomRow(Wix3.Row row, bool columnZeroIsId)
497 + {
498 + var columnDefinitions = row.Table.Definition.Columns.Cast<Wix3.ColumnDefinition>();
499 + var fieldDefinitions = columnDefinitions.Select(columnDefinition =>
500 + new IntermediateFieldDefinition(columnDefinition.Name, ColumnType3ToIntermediateFieldType4(columnDefinition.Type))).ToArray();
501 + var tupleDefinition = new IntermediateTupleDefinition(row.Table.Name, fieldDefinitions, null);
502 + var tuple = new IntermediateTuple(tupleDefinition, SourceLineNumber4(row.SourceLineNumbers));
503 +
504 + SetTupleFieldsFromRow(row, tuple, columnZeroIsId);
505 +
506 + return tuple;
507 + }
508 +
509 + private static void SetTupleFieldsFromRow(Wix3.Row row, IntermediateTuple tuple, bool columnZeroIsId)
510 + {
511 + int offset = 0;
512 + if (columnZeroIsId)
513 + {
514 + tuple.Id = GetIdentifierForRow(row);
515 + offset = 1;
516 + }
517 +
518 + for (var i = offset; i < row.Fields.Length; ++i)
519 + {
520 + var column = row.Fields[i].Column;
521 + switch (column.Type)
522 + {
523 + case Wix3.ColumnType.String:
524 + case Wix3.ColumnType.Localized:
525 + case Wix3.ColumnType.Object:
526 + case Wix3.ColumnType.Preserved:
527 + tuple.Set(i - offset, FieldAsString(row, i));
528 + break;
529 + case Wix3.ColumnType.Number:
530 + int? nullableValue = FieldAsNullableInt(row, i);
531 + // TODO: Consider whether null values should be coerced to their default value when
532 + // a column is not nullable. For now, just pass through the null.
533 + //int value = FieldAsInt(row, i);
534 + //tuple.Set(i - offset, column.IsNullable ? nullableValue : value);
535 + tuple.Set(i - offset, nullableValue);
536 + break;
537 + case Wix3.ColumnType.Unknown:
538 + break;
539 + }
540 + }
541 + }
542 +
543 + private static Identifier GetIdentifierForRow(Wix3.Row row)
544 + {
545 + var column = row.Fields[0].Column;
546 + switch (column.Type)
547 + {
548 + case Wix3.ColumnType.String:
549 + case Wix3.ColumnType.Localized:
550 + case Wix3.ColumnType.Object:
551 + case Wix3.ColumnType.Preserved:
552 + return new Identifier(AccessModifier.Public, (string)row.Fields[0].Data);
553 + case Wix3.ColumnType.Number:
554 + return new Identifier(AccessModifier.Public, FieldAsInt(row, 0));
555 + default:
556 + return null;
557 + }
558 + }
559 +
560 + private static SectionType OutputType3ToSectionType4(Wix3.OutputType outputType)
561 + {
562 + switch (outputType)
563 + {
564 + case Wix3.OutputType.Bundle:
565 + return SectionType.Bundle;
566 + case Wix3.OutputType.Module:
567 + return SectionType.Module;
568 + case Wix3.OutputType.Patch:
569 + return SectionType.Patch;
570 + case Wix3.OutputType.PatchCreation:
571 + return SectionType.PatchCreation;
572 + case Wix3.OutputType.Product:
573 + return SectionType.Product;
574 + case Wix3.OutputType.Transform:
575 + case Wix3.OutputType.Unknown:
576 + default:
577 + return SectionType.Unknown;
578 + }
579 + }
580 +
581 + private static SourceLineNumber SourceLineNumber4(Wix3.SourceLineNumberCollection source)
582 + {
583 + return String.IsNullOrEmpty(source?.EncodedSourceLineNumbers) ? null : SourceLineNumber.CreateFromEncoded(source.EncodedSourceLineNumbers);
584 + }
585 +
586 + private static string FieldAsString(Wix3.Row row, int column)
587 + {
588 + return (string)row[column];
589 + }
590 +
591 + private static int FieldAsInt(Wix3.Row row, int column)
592 + {
593 + return Convert.ToInt32(row[column]);
594 + }
595 +
596 + private static int? FieldAsNullableInt(Wix3.Row row, int column)
597 + {
598 + var field = row.Fields[column];
599 + if (field.Data == null)
600 + {
601 + return null;
602 + }
603 + else
604 + {
605 + return Convert.ToInt32(field.Data);
606 + }
607 + }
608 + }
609 +}
src/WixToolset.Converters.Tupleizer/WixToolset.Converters.Tupleizer.csproj new
+32
@@ -0,0 +1,32 @@
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 +
4 +<Project Sdk="Microsoft.NET.Sdk">
5 +
6 + <PropertyGroup>
7 + <TargetFramework>netstandard2.0</TargetFramework>
8 + <Description>Tupleizer</Description>
9 + <Title>WiX Toolset Converters Tuplizer</Title>
10 + <DebugType>embedded</DebugType>
11 + <PublishRepositoryUrl>true</PublishRepositoryUrl>
12 + </PropertyGroup>
13 +
14 + <PropertyGroup>
15 + <NoWarn>NU1701</NoWarn>
16 + </PropertyGroup>
17 +
18 + <ItemGroup>
19 + <Reference Include="wix" HintPath="..\deps\wix.dll" />
20 + <None Include="..\deps\wix.dll" Pack="true" PackagePath="lib\net461" />
21 + </ItemGroup>
22 +
23 + <ItemGroup>
24 + <PackageReference Include="WixToolset.Core" Version="4.0.*" />
25 + <PackageReference Include="WixToolset.Core.WindowsInstaller" Version="4.0.*" />
26 + </ItemGroup>
27 +
28 + <ItemGroup>
29 + <PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0-beta2-18618-05" PrivateAssets="All"/>
30 + <PackageReference Include="Nerdbank.GitVersioning" Version="2.1.65" PrivateAssets="All" />
31 + </ItemGroup>
32 +</Project>
src/WixToolset.Converters/Wix3Converter.cs new
+652
@@ -0,0 +1,652 @@
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.Converters
4 +{
5 + using System;
6 + using System.Collections.Generic;
7 + using System.Globalization;
8 + using System.IO;
9 + using System.Linq;
10 + using System.Text;
11 + using System.Text.RegularExpressions;
12 + using System.Xml;
13 + using System.Xml.Linq;
14 + using WixToolset.Data;
15 + using WixToolset.Extensibility.Services;
16 +
17 + /// <summary>
18 + /// WiX source code converter.
19 + /// </summary>
20 + public class Wix3Converter
21 + {
22 + private static readonly Regex AddPrefix = new Regex(@"^[^a-zA-Z_]", RegexOptions.Compiled);
23 + private static readonly Regex IllegalIdentifierCharacters = new Regex(@"[^A-Za-z0-9_\.]|\.{2,}", RegexOptions.Compiled); // non 'words' and assorted valid characters
24 +
25 + private const char XDocumentNewLine = '\n'; // XDocument normalizes "\r\n" to just "\n".
26 + private static readonly XNamespace WixNamespace = "http://wixtoolset.org/schemas/v4/wxs";
27 +
28 + private static readonly XName DirectoryElementName = WixNamespace + "Directory";
29 + private static readonly XName FileElementName = WixNamespace + "File";
30 + private static readonly XName ExePackageElementName = WixNamespace + "ExePackage";
31 + private static readonly XName MsiPackageElementName = WixNamespace + "MsiPackage";
32 + private static readonly XName MspPackageElementName = WixNamespace + "MspPackage";
33 + private static readonly XName MsuPackageElementName = WixNamespace + "MsuPackage";
34 + private static readonly XName PayloadElementName = WixNamespace + "Payload";
35 + private static readonly XName CustomActionElementName = WixNamespace + "CustomAction";
36 + private static readonly XName PropertyElementName = WixNamespace + "Property";
37 + private static readonly XName WixElementWithoutNamespaceName = XNamespace.None + "Wix";
38 +
39 + private static readonly Dictionary<string, XNamespace> OldToNewNamespaceMapping = new Dictionary<string, XNamespace>()
40 + {
41 + { "http://schemas.microsoft.com/wix/BalExtension", "http://wixtoolset.org/schemas/v4/wxs/bal" },
42 + { "http://schemas.microsoft.com/wix/ComPlusExtension", "http://wixtoolset.org/schemas/v4/wxs/complus" },
43 + { "http://schemas.microsoft.com/wix/DependencyExtension", "http://wixtoolset.org/schemas/v4/wxs/dependency" },
44 + { "http://schemas.microsoft.com/wix/DifxAppExtension", "http://wixtoolset.org/schemas/v4/wxs/difxapp" },
45 + { "http://schemas.microsoft.com/wix/FirewallExtension", "http://wixtoolset.org/schemas/v4/wxs/firewall" },
46 + { "http://schemas.microsoft.com/wix/GamingExtension", "http://wixtoolset.org/schemas/v4/wxs/gaming" },
47 + { "http://schemas.microsoft.com/wix/IIsExtension", "http://wixtoolset.org/schemas/v4/wxs/iis" },
48 + { "http://schemas.microsoft.com/wix/MsmqExtension", "http://wixtoolset.org/schemas/v4/wxs/msmq" },
49 + { "http://schemas.microsoft.com/wix/NetFxExtension", "http://wixtoolset.org/schemas/v4/wxs/netfx" },
50 + { "http://schemas.microsoft.com/wix/PSExtension", "http://wixtoolset.org/schemas/v4/wxs/powershell" },
51 + { "http://schemas.microsoft.com/wix/SqlExtension", "http://wixtoolset.org/schemas/v4/wxs/sql" },
52 + { "http://schemas.microsoft.com/wix/TagExtension", "http://wixtoolset.org/schemas/v4/wxs/tag" },
53 + { "http://schemas.microsoft.com/wix/UtilExtension", "http://wixtoolset.org/schemas/v4/wxs/util" },
54 + { "http://schemas.microsoft.com/wix/VSExtension", "http://wixtoolset.org/schemas/v4/wxs/vs" },
55 + { "http://wixtoolset.org/schemas/thmutil/2010", "http://wixtoolset.org/schemas/v4/thmutil" },
56 + { "http://schemas.microsoft.com/wix/2009/Lux", "http://wixtoolset.org/schemas/v4/lux" },
57 + { "http://schemas.microsoft.com/wix/2006/wi", "http://wixtoolset.org/schemas/v4/wxs" },
58 + { "http://schemas.microsoft.com/wix/2006/localization", "http://wixtoolset.org/schemas/v4/wxl" },
59 + { "http://schemas.microsoft.com/wix/2006/libraries", "http://wixtoolset.org/schemas/v4/wixlib" },
60 + { "http://schemas.microsoft.com/wix/2006/objects", "http://wixtoolset.org/schemas/v4/wixobj" },
61 + { "http://schemas.microsoft.com/wix/2006/outputs", "http://wixtoolset.org/schemas/v4/wixout" },
62 + { "http://schemas.microsoft.com/wix/2007/pdbs", "http://wixtoolset.org/schemas/v4/wixpdb" },
63 + { "http://schemas.microsoft.com/wix/2003/04/actions", "http://wixtoolset.org/schemas/v4/wi/actions" },
64 + { "http://schemas.microsoft.com/wix/2006/tables", "http://wixtoolset.org/schemas/v4/wi/tables" },
65 + { "http://schemas.microsoft.com/wix/2006/WixUnit", "http://wixtoolset.org/schemas/v4/wixunit" },
66 + };
67 +
68 + private readonly Dictionary<XName, Action<XElement>> ConvertElementMapping;
69 +
70 + /// <summary>
71 + /// Instantiate a new Converter class.
72 + /// </summary>
73 + /// <param name="indentationAmount">Indentation value to use when validating leading whitespace.</param>
74 + /// <param name="errorsAsWarnings">Test errors to display as warnings.</param>
75 + /// <param name="ignoreErrors">Test errors to ignore.</param>
76 + public Wix3Converter(IMessaging messaging, int indentationAmount, IEnumerable<string> errorsAsWarnings = null, IEnumerable<string> ignoreErrors = null)
77 + {
78 + this.ConvertElementMapping = new Dictionary<XName, Action<XElement>>
79 + {
80 + { Wix3Converter.DirectoryElementName, this.ConvertDirectoryElement },
81 + { Wix3Converter.FileElementName, this.ConvertFileElement },
82 + { Wix3Converter.ExePackageElementName, this.ConvertSuppressSignatureValidation },
83 + { Wix3Converter.MsiPackageElementName, this.ConvertSuppressSignatureValidation },
84 + { Wix3Converter.MspPackageElementName, this.ConvertSuppressSignatureValidation },
85 + { Wix3Converter.MsuPackageElementName, this.ConvertSuppressSignatureValidation },
86 + { Wix3Converter.PayloadElementName, this.ConvertSuppressSignatureValidation },
87 + { Wix3Converter.CustomActionElementName, this.ConvertCustomActionElement },
88 + { Wix3Converter.PropertyElementName, this.ConvertPropertyElement },
89 + { Wix3Converter.WixElementWithoutNamespaceName, this.ConvertWixElementWithoutNamespace },
90 + };
91 +
92 + this.Messaging = messaging;
93 +
94 + this.IndentationAmount = indentationAmount;
95 +
96 + this.ErrorsAsWarnings = new HashSet<ConverterTestType>(this.YieldConverterTypes(errorsAsWarnings));
97 +
98 + this.IgnoreErrors = new HashSet<ConverterTestType>(this.YieldConverterTypes(ignoreErrors));
99 + }
100 +
101 + private int Errors { get; set; }
102 +
103 + private HashSet<ConverterTestType> ErrorsAsWarnings { get; set; }
104 +
105 + private HashSet<ConverterTestType> IgnoreErrors { get; set; }
106 +
107 + private IMessaging Messaging { get; }
108 +
109 + private int IndentationAmount { get; set; }
110 +
111 + private string SourceFile { get; set; }
112 +
113 + /// <summary>
114 + /// Convert a file.
115 + /// </summary>
116 + /// <param name="sourceFile">The file to convert.</param>
117 + /// <param name="saveConvertedFile">Option to save the converted errors that are found.</param>
118 + /// <returns>The number of errors found.</returns>
119 + public int ConvertFile(string sourceFile, bool saveConvertedFile)
120 + {
121 + XDocument document;
122 +
123 + // Set the instance info.
124 + this.Errors = 0;
125 + this.SourceFile = sourceFile;
126 +
127 + try
128 + {
129 + document = XDocument.Load(this.SourceFile, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo);
130 + }
131 + catch (XmlException e)
132 + {
133 + this.OnError(ConverterTestType.XmlException, null, "The xml is invalid. Detail: '{0}'", e.Message);
134 +
135 + return this.Errors;
136 + }
137 +
138 + this.ConvertDocument(document);
139 +
140 + // Fix errors if requested and necessary.
141 + if (saveConvertedFile && 0 < this.Errors)
142 + {
143 + try
144 + {
145 + using (var writer = File.CreateText(this.SourceFile))
146 + {
147 + document.Save(writer, SaveOptions.DisableFormatting | SaveOptions.OmitDuplicateNamespaces);
148 + }
149 + }
150 + catch (UnauthorizedAccessException)
151 + {
152 + this.OnError(ConverterTestType.UnauthorizedAccessException, null, "Could not write to file.");
153 + }
154 + }
155 +
156 + return this.Errors;
157 + }
158 +
159 + /// <summary>
160 + /// Convert a document.
161 + /// </summary>
162 + /// <param name="document">The document to convert.</param>
163 + /// <returns>The number of errors found.</returns>
164 + public int ConvertDocument(XDocument document)
165 + {
166 + var declaration = document.Declaration;
167 +
168 + // Convert the declaration.
169 + if (null != declaration)
170 + {
171 + if (!String.Equals("utf-8", declaration.Encoding, StringComparison.OrdinalIgnoreCase))
172 + {
173 + if (this.OnError(ConverterTestType.DeclarationEncodingWrong, document.Root, "The XML declaration encoding is not properly set to 'utf-8'."))
174 + {
175 + declaration.Encoding = "utf-8";
176 + }
177 + }
178 + }
179 + else // missing declaration
180 + {
181 + if (this.OnError(ConverterTestType.DeclarationMissing, null, "This file is missing an XML declaration on the first line."))
182 + {
183 + document.Declaration = new XDeclaration("1.0", "utf-8", null);
184 + document.Root.AddBeforeSelf(new XText(XDocumentNewLine.ToString()));
185 + }
186 + }
187 +
188 + // Start converting the nodes at the top.
189 + this.ConvertNodes(document.Nodes(), 0);
190 +
191 + return this.Errors;
192 + }
193 +
194 + private void ConvertNodes(IEnumerable<XNode> nodes, int level)
195 + {
196 + // Note we operate on a copy of the node list since we may
197 + // remove some whitespace nodes during this processing.
198 + foreach (var node in nodes.ToList())
199 + {
200 + if (node is XText text)
201 + {
202 + if (!String.IsNullOrWhiteSpace(text.Value))
203 + {
204 + text.Value = text.Value.Trim();
205 + }
206 + else if (node.NextNode is XCData cdata)
207 + {
208 + this.EnsurePrecedingWhitespaceRemoved(text, node, ConverterTestType.WhitespacePrecedingNodeWrong);
209 + }
210 + else if (node.NextNode is XElement element)
211 + {
212 + this.EnsurePrecedingWhitespaceCorrect(text, node, level, ConverterTestType.WhitespacePrecedingNodeWrong);
213 + }
214 + else if (node.NextNode is null) // this is the space before the close element
215 + {
216 + if (node.PreviousNode is null || node.PreviousNode is XCData)
217 + {
218 + this.EnsurePrecedingWhitespaceRemoved(text, node.Parent, ConverterTestType.WhitespacePrecedingEndElementWrong);
219 + }
220 + else if (level == 0) // root element's close tag
221 + {
222 + this.EnsurePrecedingWhitespaceCorrect(text, node, 0, ConverterTestType.WhitespacePrecedingEndElementWrong);
223 + }
224 + else
225 + {
226 + this.EnsurePrecedingWhitespaceCorrect(text, node, level - 1, ConverterTestType.WhitespacePrecedingEndElementWrong);
227 + }
228 + }
229 + }
230 + else if (node is XElement element)
231 + {
232 + this.ConvertElement(element);
233 +
234 + this.ConvertNodes(element.Nodes(), level + 1);
235 + }
236 + }
237 + }
238 +
239 + private void EnsurePrecedingWhitespaceCorrect(XText whitespace, XNode node, int level, ConverterTestType testType)
240 + {
241 + if (!Wix3Converter.LeadingWhitespaceValid(this.IndentationAmount, level, whitespace.Value))
242 + {
243 + var message = testType == ConverterTestType.WhitespacePrecedingEndElementWrong ? "The whitespace preceding this end element is incorrect." : "The whitespace preceding this node is incorrect.";
244 +
245 + if (this.OnError(testType, node, message))
246 + {
247 + Wix3Converter.FixupWhitespace(this.IndentationAmount, level, whitespace);
248 + }
249 + }
250 + }
251 +
252 + private void EnsurePrecedingWhitespaceRemoved(XText whitespace, XNode node, ConverterTestType testType)
253 + {
254 + if (!String.IsNullOrEmpty(whitespace.Value))
255 + {
256 + var message = testType == ConverterTestType.WhitespacePrecedingEndElementWrong ? "The whitespace preceding this end element is incorrect." : "The whitespace preceding this node is incorrect.";
257 +
258 + if (this.OnError(testType, node, message))
259 + {
260 + whitespace.Remove();
261 + }
262 + }
263 + }
264 +
265 + private void ConvertElement(XElement element)
266 + {
267 + // Gather any deprecated namespaces, then update this element tree based on those deprecations.
268 + var deprecatedToUpdatedNamespaces = new Dictionary<XNamespace, XNamespace>();
269 +
270 + foreach (var declaration in element.Attributes().Where(a => a.IsNamespaceDeclaration))
271 + {
272 + if (Wix3Converter.OldToNewNamespaceMapping.TryGetValue(declaration.Value, out var ns))
273 + {
274 + if (this.OnError(ConverterTestType.XmlnsValueWrong, declaration, "The namespace '{0}' is out of date. It must be '{1}'.", declaration.Value, ns.NamespaceName))
275 + {
276 + deprecatedToUpdatedNamespaces.Add(declaration.Value, ns);
277 + }
278 + }
279 + }
280 +
281 + if (deprecatedToUpdatedNamespaces.Any())
282 + {
283 + Wix3Converter.UpdateElementsWithDeprecatedNamespaces(element.DescendantsAndSelf(), deprecatedToUpdatedNamespaces);
284 + }
285 +
286 + // Apply any specialized conversion actions.
287 + if (this.ConvertElementMapping.TryGetValue(element.Name, out var convert))
288 + {
289 + convert(element);
290 + }
291 + }
292 +
293 + private void ConvertDirectoryElement(XElement element)
294 + {
295 + if (null == element.Attribute("Name"))
296 + {
297 + var attribute = element.Attribute("ShortName");
298 + if (null != attribute)
299 + {
300 + var shortName = attribute.Value;
301 + if (this.OnError(ConverterTestType.AssignDirectoryNameFromShortName, element, "The directory ShortName attribute is being renamed to Name since Name wasn't specified for value '{0}'", shortName))
302 + {
303 + element.Add(new XAttribute("Name", shortName));
304 + attribute.Remove();
305 + }
306 + }
307 + }
308 + }
309 +
310 + private void ConvertFileElement(XElement element)
311 + {
312 + if (null == element.Attribute("Id"))
313 + {
314 + var attribute = element.Attribute("Name");
315 +
316 + if (null == attribute)
317 + {
318 + attribute = element.Attribute("Source");
319 + }
320 +
321 + if (null != attribute)
322 + {
323 + var name = Path.GetFileName(attribute.Value);
324 +
325 + if (this.OnError(ConverterTestType.AssignAnonymousFileId, element, "The file id is being updated to '{0}' to ensure it remains the same as the default", name))
326 + {
327 + IEnumerable<XAttribute> attributes = element.Attributes().ToList();
328 + element.RemoveAttributes();
329 + element.Add(new XAttribute("Id", GetIdentifierFromName(name)));
330 + element.Add(attributes);
331 + }
332 + }
333 + }
334 + }
335 +
336 + private void ConvertSuppressSignatureValidation(XElement element)
337 + {
338 + var suppressSignatureValidation = element.Attribute("SuppressSignatureValidation");
339 +
340 + if (null != suppressSignatureValidation)
341 + {
342 + if (this.OnError(ConverterTestType.SuppressSignatureValidationDeprecated, element, "The chain package element contains deprecated '{0}' attribute. Use the 'EnableSignatureValidation' attribute instead.", suppressSignatureValidation))
343 + {
344 + if ("no" == suppressSignatureValidation.Value)
345 + {
346 + element.Add(new XAttribute("EnableSignatureValidation", "yes"));
347 + }
348 + }
349 +
350 + suppressSignatureValidation.Remove();
351 + }
352 + }
353 +
354 + private void ConvertCustomActionElement(XElement xCustomAction)
355 + {
356 + var xBinaryKey = xCustomAction.Attribute("BinaryKey");
357 +
358 + if (xBinaryKey?.Value == "WixCA")
359 + {
360 + if (this.OnError(ConverterTestType.WixCABinaryIdRenamed, xCustomAction, "The WixCA custom action DLL Binary table id has been renamed. Use the id 'UtilCA' instead."))
361 + {
362 + xBinaryKey.Value = "UtilCA";
363 + }
364 + }
365 +
366 + var xDllEntry = xCustomAction.Attribute("DllEntry");
367 +
368 + if (xDllEntry?.Value == "CAQuietExec" || xDllEntry?.Value == "CAQuietExec64")
369 + {
370 + if (this.OnError(ConverterTestType.QuietExecCustomActionsRenamed, xCustomAction, "The CAQuietExec and CAQuietExec64 custom action ids have been renamed. Use the ids 'WixQuietExec' and 'WixQuietExec64' instead."))
371 + {
372 + xDllEntry.Value = xDllEntry.Value.Replace("CAQuietExec", "WixQuietExec");
373 + }
374 + }
375 +
376 + var xProperty = xCustomAction.Attribute("Property");
377 +
378 + if (xProperty?.Value == "QtExecCmdLine" || xProperty?.Value == "QtExec64CmdLine")
379 + {
380 + if (this.OnError(ConverterTestType.QuietExecCustomActionsRenamed, xCustomAction, "The QtExecCmdLine and QtExec64CmdLine property ids have been renamed. Use the ids 'WixQuietExecCmdLine' and 'WixQuietExec64CmdLine' instead."))
381 + {
382 + xProperty.Value = xProperty.Value.Replace("QtExec", "WixQuietExec");
383 + }
384 + }
385 + }
386 +
387 + private void ConvertPropertyElement(XElement xProperty)
388 + {
389 + var xId = xProperty.Attribute("Id");
390 +
391 + if (xId.Value == "QtExecCmdTimeout")
392 + {
393 + this.OnError(ConverterTestType.QtExecCmdTimeoutAmbiguous, xProperty, "QtExecCmdTimeout was previously used for both CAQuietExec and CAQuietExec64. For WixQuietExec, use WixQuietExecCmdTimeout. For WixQuietExec64, use WixQuietExec64CmdTimeout.");
394 + }
395 + }
396 +
397 + /// <summary>
398 + /// Converts a Wix element.
399 + /// </summary>
400 + /// <param name="element">The Wix element to convert.</param>
401 + /// <returns>The converted element.</returns>
402 + private void ConvertWixElementWithoutNamespace(XElement element)
403 + {
404 + if (this.OnError(ConverterTestType.XmlnsMissing, element, "The xmlns attribute is missing. It must be present with a value of '{0}'.", WixNamespace.NamespaceName))
405 + {
406 + element.Name = WixNamespace.GetName(element.Name.LocalName);
407 +
408 + element.Add(new XAttribute("xmlns", WixNamespace.NamespaceName)); // set the default namespace.
409 +
410 + foreach (var elementWithoutNamespace in element.Elements().Where(e => XNamespace.None == e.Name.Namespace))
411 + {
412 + elementWithoutNamespace.Name = WixNamespace.GetName(elementWithoutNamespace.Name.LocalName);
413 + }
414 + }
415 + }
416 +
417 + private IEnumerable<ConverterTestType> YieldConverterTypes(IEnumerable<string> types)
418 + {
419 + if (null != types)
420 + {
421 + foreach (var type in types)
422 + {
423 +
424 + if (Enum.TryParse<ConverterTestType>(type, true, out var itt))
425 + {
426 + yield return itt;
427 + }
428 + else // not a known ConverterTestType
429 + {
430 + this.OnError(ConverterTestType.ConverterTestTypeUnknown, null, "Unknown error type: '{0}'.", type);
431 + }
432 + }
433 + }
434 + }
435 +
436 + private static void UpdateElementsWithDeprecatedNamespaces(IEnumerable<XElement> elements, Dictionary<XNamespace, XNamespace> deprecatedToUpdatedNamespaces)
437 + {
438 + foreach (var element in elements)
439 + {
440 +
441 + if (deprecatedToUpdatedNamespaces.TryGetValue(element.Name.Namespace, out var ns))
442 + {
443 + element.Name = ns.GetName(element.Name.LocalName);
444 + }
445 +
446 + // Remove all the attributes and add them back to with their namespace updated (as necessary).
447 + IEnumerable<XAttribute> attributes = element.Attributes().ToList();
448 + element.RemoveAttributes();
449 +
450 + foreach (var attribute in attributes)
451 + {
452 + var convertedAttribute = attribute;
453 +
454 + if (attribute.IsNamespaceDeclaration)
455 + {
456 + if (deprecatedToUpdatedNamespaces.TryGetValue(attribute.Value, out ns))
457 + {
458 + convertedAttribute = ("xmlns" == attribute.Name.LocalName) ? new XAttribute(attribute.Name.LocalName, ns.NamespaceName) : new XAttribute(XNamespace.Xmlns + attribute.Name.LocalName, ns.NamespaceName);
459 + }
460 + }
461 + else if (deprecatedToUpdatedNamespaces.TryGetValue(attribute.Name.Namespace, out ns))
462 + {
463 + convertedAttribute = new XAttribute(ns.GetName(attribute.Name.LocalName), attribute.Value);
464 + }
465 +
466 + element.Add(convertedAttribute);
467 + }
468 + }
469 + }
470 +
471 + /// <summary>
472 + /// Determine if the whitespace preceding a node is appropriate for its depth level.
473 + /// </summary>
474 + /// <param name="indentationAmount">Indentation value to use when validating leading whitespace.</param>
475 + /// <param name="level">The depth level that should match this whitespace.</param>
476 + /// <param name="whitespace">The whitespace to validate.</param>
477 + /// <returns>true if the whitespace is legal; false otherwise.</returns>
478 + private static bool LeadingWhitespaceValid(int indentationAmount, int level, string whitespace)
479 + {
480 + // Strip off leading newlines; there can be an arbitrary number of these.
481 + whitespace = whitespace.TrimStart(XDocumentNewLine);
482 +
483 + var indentation = new string(' ', level * indentationAmount);
484 +
485 + return whitespace == indentation;
486 + }
487 +
488 + /// <summary>
489 + /// Fix the whitespace in a whitespace node.
490 + /// </summary>
491 + /// <param name="indentationAmount">Indentation value to use when validating leading whitespace.</param>
492 + /// <param name="level">The depth level of the desired whitespace.</param>
493 + /// <param name="whitespace">The whitespace node to fix.</param>
494 + private static void FixupWhitespace(int indentationAmount, int level, XText whitespace)
495 + {
496 + var value = new StringBuilder(whitespace.Value.Length);
497 +
498 + // Keep any previous preceeding new lines.
499 + var newlines = whitespace.Value.TakeWhile(c => c == XDocumentNewLine).Count();
500 +
501 + // Ensure there is always at least one new line before the indentation.
502 + value.Append(XDocumentNewLine, newlines == 0 ? 1 : newlines);
503 +
504 + whitespace.Value = value.Append(' ', level * indentationAmount).ToString();
505 + }
506 +
507 + /// <summary>
508 + /// Output an error message to the console.
509 + /// </summary>
510 + /// <param name="converterTestType">The type of converter test.</param>
511 + /// <param name="node">The node that caused the error.</param>
512 + /// <param name="message">Detailed error message.</param>
513 + /// <param name="args">Additional formatted string arguments.</param>
514 + /// <returns>Returns true indicating that action should be taken on this error, and false if it should be ignored.</returns>
515 + private bool OnError(ConverterTestType converterTestType, XObject node, string message, params object[] args)
516 + {
517 + if (this.IgnoreErrors.Contains(converterTestType)) // ignore the error
518 + {
519 + return false;
520 + }
521 +
522 + // Increase the error count.
523 + this.Errors++;
524 +
525 + var sourceLine = (null == node) ? new SourceLineNumber(this.SourceFile ?? "wixcop.exe") : new SourceLineNumber(this.SourceFile, ((IXmlLineInfo)node).LineNumber);
526 + var warning = this.ErrorsAsWarnings.Contains(converterTestType);
527 + var display = String.Format(CultureInfo.CurrentCulture, message, args);
528 +
529 + var msg = new Message(sourceLine, warning ? MessageLevel.Warning : MessageLevel.Error, (int)converterTestType, "{0} ({1})", display, converterTestType.ToString());
530 +
531 + this.Messaging.Write(msg);
532 +
533 + return true;
534 + }
535 +
536 + /// <summary>
537 + /// Return an identifier based on passed file/directory name
538 + /// </summary>
539 + /// <param name="name">File/directory name to generate identifer from</param>
540 + /// <returns>A version of the name that is a legal identifier.</returns>
541 + /// <remarks>This is duplicated from WiX's Common class.</remarks>
542 + private static string GetIdentifierFromName(string name)
543 + {
544 + string result = IllegalIdentifierCharacters.Replace(name, "_"); // replace illegal characters with "_".
545 +
546 + // MSI identifiers must begin with an alphabetic character or an
547 + // underscore. Prefix all other values with an underscore.
548 + if (AddPrefix.IsMatch(name))
549 + {
550 + result = String.Concat("_", result);
551 + }
552 +
553 + return result;
554 + }
555 +
556 + /// <summary>
557 + /// Converter test types. These are used to condition error messages down to warnings.
558 + /// </summary>
559 + private enum ConverterTestType
560 + {
561 + /// <summary>
562 + /// Internal-only: displayed when a string cannot be converted to an ConverterTestType.
563 + /// </summary>
564 + ConverterTestTypeUnknown,
565 +
566 + /// <summary>
567 + /// Displayed when an XML loading exception has occurred.
568 + /// </summary>
569 + XmlException,
570 +
571 + /// <summary>
572 + /// Displayed when a file cannot be accessed; typically when trying to save back a fixed file.
573 + /// </summary>
574 + UnauthorizedAccessException,
575 +
576 + /// <summary>
577 + /// Displayed when the encoding attribute in the XML declaration is not 'UTF-8'.
578 + /// </summary>
579 + DeclarationEncodingWrong,
580 +
581 + /// <summary>
582 + /// Displayed when the XML declaration is missing from the source file.
583 + /// </summary>
584 + DeclarationMissing,
585 +
586 + /// <summary>
587 + /// Displayed when the whitespace preceding a CDATA node is wrong.
588 + /// </summary>
589 + WhitespacePrecedingCDATAWrong,
590 +
591 + /// <summary>
592 + /// Displayed when the whitespace preceding a node is wrong.
593 + /// </summary>
594 + WhitespacePrecedingNodeWrong,
595 +
596 + /// <summary>
597 + /// Displayed when an element is not empty as it should be.
598 + /// </summary>
599 + NotEmptyElement,
600 +
601 + /// <summary>
602 + /// Displayed when the whitespace following a CDATA node is wrong.
603 + /// </summary>
604 + WhitespaceFollowingCDATAWrong,
605 +
606 + /// <summary>
607 + /// Displayed when the whitespace preceding an end element is wrong.
608 + /// </summary>
609 + WhitespacePrecedingEndElementWrong,
610 +
611 + /// <summary>
612 + /// Displayed when the xmlns attribute is missing from the document element.
613 + /// </summary>
614 + XmlnsMissing,
615 +
616 + /// <summary>
617 + /// Displayed when the xmlns attribute on the document element is wrong.
618 + /// </summary>
619 + XmlnsValueWrong,
620 +
621 + /// <summary>
622 + /// Assign an identifier to a File element when on Id attribute is specified.
623 + /// </summary>
624 + AssignAnonymousFileId,
625 +
626 + /// <summary>
627 + /// SuppressSignatureValidation attribute is deprecated and replaced with EnableSignatureValidation.
628 + /// </summary>
629 + SuppressSignatureValidationDeprecated,
630 +
631 + /// <summary>
632 + /// WixCA Binary/@Id has been renamed to UtilCA.
633 + /// </summary>
634 + WixCABinaryIdRenamed,
635 +
636 + /// <summary>
637 + /// QtExec custom actions have been renamed.
638 + /// </summary>
639 + QuietExecCustomActionsRenamed,
640 +
641 + /// <summary>
642 + /// QtExecCmdTimeout was previously used for both CAQuietExec and CAQuietExec64. For WixQuietExec, use WixQuietExecCmdTimeout. For WixQuietExec64, use WixQuietExec64CmdTimeout.
643 + /// </summary>
644 + QtExecCmdTimeoutAmbiguous,
645 +
646 + /// <summary>
647 + /// Directory/@ShortName may only be specified with Directory/@Name.
648 + /// </summary>
649 + AssignDirectoryNameFromShortName,
650 + }
651 + }
652 +}
src/WixToolset.Converters/WixToolset.Converters.csproj new
+26
@@ -0,0 +1,26 @@
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 +
4 +<Project Sdk="Microsoft.NET.Sdk">
5 +
6 + <PropertyGroup>
7 + <TargetFramework>netstandard2.0</TargetFramework>
8 + <Description>Converter</Description>
9 + <Title>WiX Toolset Converters</Title>
10 + <DebugType>embedded</DebugType>
11 + <PublishRepositoryUrl>true</PublishRepositoryUrl>
12 + </PropertyGroup>
13 +
14 + <PropertyGroup>
15 + <NoWarn>NU1701</NoWarn>
16 + </PropertyGroup>
17 +
18 + <ItemGroup>
19 + <PackageReference Include="WixToolset.Core" Version="4.0.*" />
20 + </ItemGroup>
21 +
22 + <ItemGroup>
23 + <PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0-beta2-18618-05" PrivateAssets="All"/>
24 + <PackageReference Include="Nerdbank.GitVersioning" Version="2.1.65" PrivateAssets="All" />
25 + </ItemGroup>
26 +</Project>
src/deps/wix.dll
Binary files /dev/null and b/src/deps/wix.dll differ
src/test/WixToolsetTest.Converters.Tupleizer/ConvertTuplesFixture.cs new
+391
@@ -0,0 +1,391 @@
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 WixToolsetTest.Converters.Tupleizer
4 +{
5 + using System;
6 + using System.IO;
7 + using System.Linq;
8 + using WixBuildTools.TestSupport;
9 + using Wix3 = Microsoft.Tools.WindowsInstallerXml;
10 + using WixToolset.Converters.Tupleizer;
11 + using WixToolset.Data;
12 + using WixToolset.Data.WindowsInstaller;
13 + using WixToolset.Data.Tuples;
14 + using Xunit;
15 +
16 + public class ConvertTuplesFixture
17 + {
18 + [Fact]
19 + public void CanLoadWixoutAndConvertToIntermediate()
20 + {
21 + var rootFolder = TestData.Get();
22 + var dataFolder = TestData.Get(@"TestData\Integration");
23 +
24 + using (var fs = new DisposableFileSystem())
25 + {
26 + var intermediateFolder = fs.GetFolder();
27 +
28 + var path = Path.Combine(dataFolder, "test.wixout");
29 + var output = Wix3.Output.Load(path, suppressVersionCheck: true, suppressSchema: true);
30 +
31 + var command = new ConvertTuplesCommand();
32 + var intermediate = command.Execute(output);
33 +
34 + Assert.NotNull(intermediate);
35 + Assert.Single(intermediate.Sections);
36 + Assert.Equal(String.Empty, intermediate.Id);
37 +
38 + // Save and load to guarantee round-tripping support.
39 + //
40 + var wixiplFile = Path.Combine(intermediateFolder, "test.wixipl");
41 + intermediate.Save(wixiplFile);
42 +
43 + intermediate = Intermediate.Load(wixiplFile);
44 +
45 + // Dump to text for easy diffing, with some massaging to keep v3 and v4 diffable.
46 + //
47 + var tables = output.Tables.Cast<Wix3.Table>();
48 + var wix3Dump = tables
49 + .SelectMany(table => table.Rows.Cast<Wix3.Row>()
50 + .Select(row => RowToString(row)))
51 + .ToArray();
52 +
53 + var tuples = intermediate.Sections.SelectMany(s => s.Tuples);
54 + var wix4Dump = tuples.Select(tuple => TupleToString(tuple)).ToArray();
55 +
56 + Assert.Equal(wix3Dump, wix4Dump);
57 +
58 + // Useful when you want to diff the outputs with another diff tool...
59 + //
60 + //var wix3TextDump = String.Join(Environment.NewLine, wix3Dump.OrderBy(val => val));
61 + //var wix4TextDump = String.Join(Environment.NewLine, wix4Dump.OrderBy(val => val));
62 + //Assert.Equal(wix3TextDump, wix4TextDump);
63 + }
64 + }
65 +
66 + private static string RowToString(Wix3.Row row)
67 + {
68 + var fields = String.Join(",", row.Fields.Select(field => field.Data?.ToString()));
69 +
70 + // Massage output to match WiX v3 rows and v4 tuples.
71 + //
72 + switch (row.Table.Name)
73 + {
74 + case "File":
75 + var fieldValues = row.Fields.Take(7).Select(field => field.Data?.ToString()).ToArray();
76 + if (fieldValues[3] == null)
77 + {
78 + // "Somebody" sometimes writes out a null field even when the column definition says
79 + // it's non-nullable. Not naming names or anything. (SWID tags.)
80 + fieldValues[3] = "0";
81 + }
82 + fields = String.Join(",", fieldValues);
83 + break;
84 + case "WixFile":
85 + fields = String.Join(",", row.Fields.Take(8).Select(field => field.Data?.ToString()));
86 + break;
87 + }
88 +
89 + return $"{row.Table.Name},{fields}";
90 + }
91 +
92 + private static string TupleToString(WixToolset.Data.IntermediateTuple tuple)
93 + {
94 + var fields = String.Join(",", tuple.Fields.Select(field => field?.AsString()));
95 +
96 + switch (tuple.Definition.Name)
97 + {
98 + // Massage output to match WiX v3 rows and v4 tuples.
99 + //
100 + case "Component":
101 + {
102 + var componentTuple = (ComponentTuple)tuple;
103 + var attributes = ComponentLocation.Either == componentTuple.Location ? WindowsInstallerConstants.MsidbComponentAttributesOptional : 0;
104 + attributes |= ComponentLocation.SourceOnly == componentTuple.Location ? WindowsInstallerConstants.MsidbComponentAttributesSourceOnly : 0;
105 + attributes |= ComponentKeyPathType.Registry == componentTuple.KeyPathType ? WindowsInstallerConstants.MsidbComponentAttributesRegistryKeyPath : 0;
106 + attributes |= ComponentKeyPathType.OdbcDataSource == componentTuple.KeyPathType ? WindowsInstallerConstants.MsidbComponentAttributesODBCDataSource : 0;
107 + attributes |= componentTuple.DisableRegistryReflection ? WindowsInstallerConstants.MsidbComponentAttributesDisableRegistryReflection : 0;
108 + attributes |= componentTuple.NeverOverwrite ? WindowsInstallerConstants.MsidbComponentAttributesNeverOverwrite : 0;
109 + attributes |= componentTuple.Permanent ? WindowsInstallerConstants.MsidbComponentAttributesPermanent : 0;
110 + attributes |= componentTuple.SharedDllRefCount ? WindowsInstallerConstants.MsidbComponentAttributesSharedDllRefCount : 0;
111 + attributes |= componentTuple.Shared ? WindowsInstallerConstants.MsidbComponentAttributesShared : 0;
112 + attributes |= componentTuple.Transitive ? WindowsInstallerConstants.MsidbComponentAttributesTransitive : 0;
113 + attributes |= componentTuple.UninstallWhenSuperseded ? WindowsInstallerConstants.MsidbComponentAttributes64bit : 0;
114 + attributes |= componentTuple.Win64 ? WindowsInstallerConstants.MsidbComponentAttributes64bit : 0;
115 +
116 + fields = String.Join(",",
117 + componentTuple.ComponentId,
118 + componentTuple.Directory_,
119 + attributes.ToString(),
120 + componentTuple.Condition,
121 + componentTuple.KeyPath
122 + );
123 + break;
124 + }
125 + case "CustomAction":
126 + {
127 + var customActionTuple = (CustomActionTuple)tuple;
128 + var type = customActionTuple.Win64 ? WindowsInstallerConstants.MsidbCustomActionType64BitScript : 0;
129 + type |= customActionTuple.TSAware ? WindowsInstallerConstants.MsidbCustomActionTypeTSAware : 0;
130 + type |= customActionTuple.Impersonate ? 0 : WindowsInstallerConstants.MsidbCustomActionTypeNoImpersonate;
131 + type |= customActionTuple.IgnoreResult ? WindowsInstallerConstants.MsidbCustomActionTypeContinue : 0;
132 + type |= customActionTuple.Hidden ? WindowsInstallerConstants.MsidbCustomActionTypeHideTarget : 0;
133 + type |= customActionTuple.Async ? WindowsInstallerConstants.MsidbCustomActionTypeAsync : 0;
134 + type |= CustomActionExecutionType.FirstSequence == customActionTuple.ExecutionType ? WindowsInstallerConstants.MsidbCustomActionTypeFirstSequence : 0;
135 + type |= CustomActionExecutionType.OncePerProcess == customActionTuple.ExecutionType ? WindowsInstallerConstants.MsidbCustomActionTypeOncePerProcess : 0;
136 + type |= CustomActionExecutionType.ClientRepeat == customActionTuple.ExecutionType ? WindowsInstallerConstants.MsidbCustomActionTypeClientRepeat : 0;
137 + type |= CustomActionExecutionType.Deferred == customActionTuple.ExecutionType ? WindowsInstallerConstants.MsidbCustomActionTypeInScript : 0;
138 + type |= CustomActionExecutionType.Rollback == customActionTuple.ExecutionType ? WindowsInstallerConstants.MsidbCustomActionTypeInScript | WindowsInstallerConstants.MsidbCustomActionTypeRollback : 0;
139 + type |= CustomActionExecutionType.Commit == customActionTuple.ExecutionType ? WindowsInstallerConstants.MsidbCustomActionTypeInScript | WindowsInstallerConstants.MsidbCustomActionTypeCommit : 0;
140 + type |= CustomActionSourceType.File == customActionTuple.SourceType ? WindowsInstallerConstants.MsidbCustomActionTypeSourceFile : 0;
141 + type |= CustomActionSourceType.Directory == customActionTuple.SourceType ? WindowsInstallerConstants.MsidbCustomActionTypeDirectory : 0;
142 + type |= CustomActionSourceType.Property == customActionTuple.SourceType ? WindowsInstallerConstants.MsidbCustomActionTypeProperty : 0;
143 + type |= CustomActionTargetType.Dll == customActionTuple.TargetType ? WindowsInstallerConstants.MsidbCustomActionTypeDll : 0;
144 + type |= CustomActionTargetType.Exe == customActionTuple.TargetType ? WindowsInstallerConstants.MsidbCustomActionTypeExe : 0;
145 + type |= CustomActionTargetType.TextData == customActionTuple.TargetType ? WindowsInstallerConstants.MsidbCustomActionTypeTextData : 0;
146 + type |= CustomActionTargetType.JScript == customActionTuple.TargetType ? WindowsInstallerConstants.MsidbCustomActionTypeJScript : 0;
147 + type |= CustomActionTargetType.VBScript == customActionTuple.TargetType ? WindowsInstallerConstants.MsidbCustomActionTypeVBScript : 0;
148 +
149 + fields = String.Join(",",
150 + type.ToString(),
151 + customActionTuple.Source,
152 + customActionTuple.Target,
153 + customActionTuple.PatchUninstall ? WindowsInstallerConstants.MsidbCustomActionTypePatchUninstall.ToString() : null
154 + );
155 + break;
156 + }
157 + case "Feature":
158 + {
159 + var featureTuple = (FeatureTuple)tuple;
160 + var attributes = featureTuple.DisallowAbsent ? WindowsInstallerConstants.MsidbFeatureAttributesUIDisallowAbsent : 0;
161 + attributes |= featureTuple.DisallowAdvertise ? WindowsInstallerConstants.MsidbFeatureAttributesDisallowAdvertise : 0;
162 + attributes |= FeatureInstallDefault.FollowParent == featureTuple.InstallDefault ? WindowsInstallerConstants.MsidbFeatureAttributesFollowParent : 0;
163 + attributes |= FeatureInstallDefault.Source == featureTuple.InstallDefault ? WindowsInstallerConstants.MsidbFeatureAttributesFavorSource : 0;
164 + attributes |= FeatureTypicalDefault.Advertise == featureTuple.TypicalDefault ? WindowsInstallerConstants.MsidbFeatureAttributesFavorAdvertise : 0;
165 +
166 + fields = String.Join(",",
167 + featureTuple.Feature_Parent,
168 + featureTuple.Title,
169 + featureTuple.Description,
170 + featureTuple.Display.ToString(),
171 + featureTuple.Level.ToString(),
172 + featureTuple.Directory_,
173 + attributes.ToString());
174 + break;
175 + }
176 + case "File":
177 + {
178 + var fileTuple = (FileTuple)tuple;
179 + fields = String.Join(",",
180 + fileTuple.Component_,
181 + fileTuple.LongFileName,
182 + fileTuple.FileSize.ToString(),
183 + fileTuple.Version,
184 + fileTuple.Language,
185 + ((fileTuple.ReadOnly ? WindowsInstallerConstants.MsidbFileAttributesReadOnly : 0)
186 + | (fileTuple.Hidden ? WindowsInstallerConstants.MsidbFileAttributesHidden : 0)
187 + | (fileTuple.System ? WindowsInstallerConstants.MsidbFileAttributesSystem : 0)
188 + | (fileTuple.Vital ? WindowsInstallerConstants.MsidbFileAttributesVital : 0)
189 + | (fileTuple.Checksum ? WindowsInstallerConstants.MsidbFileAttributesChecksum : 0)
190 + | ((fileTuple.Compressed.HasValue && fileTuple.Compressed.Value) ? WindowsInstallerConstants.MsidbFileAttributesCompressed : 0)
191 + | ((fileTuple.Compressed.HasValue && !fileTuple.Compressed.Value) ? WindowsInstallerConstants.MsidbFileAttributesNoncompressed : 0))
192 + .ToString());
193 + break;
194 + }
195 +
196 + case "Registry":
197 + {
198 + var registryTuple = (RegistryTuple)tuple;
199 + var value = registryTuple.Value;
200 +
201 + switch (registryTuple.ValueType)
202 + {
203 + case RegistryValueType.Binary:
204 + value = String.Concat("#x", value);
205 + break;
206 + case RegistryValueType.Expandable:
207 + value = String.Concat("#%", value);
208 + break;
209 + case RegistryValueType.Integer:
210 + value = String.Concat("#", value);
211 + break;
212 + case RegistryValueType.MultiString:
213 + switch (registryTuple.ValueAction)
214 + {
215 + case RegistryValueActionType.Append:
216 + value = String.Concat("[~]", value);
217 + break;
218 + case RegistryValueActionType.Prepend:
219 + value = String.Concat(value, "[~]");
220 + break;
221 + case RegistryValueActionType.Write:
222 + default:
223 + if (null != value && -1 == value.IndexOf("[~]", StringComparison.Ordinal))
224 + {
225 + value = String.Concat("[~]", value, "[~]");
226 + }
227 + break;
228 + }
229 + break;
230 + case RegistryValueType.String:
231 + // escape the leading '#' character for string registry keys
232 + if (null != value && value.StartsWith("#", StringComparison.Ordinal))
233 + {
234 + value = String.Concat("#", value);
235 + }
236 + break;
237 + }
238 +
239 + fields = String.Join(",",
240 + ((int)registryTuple.Root).ToString(),
241 + registryTuple.Key,
242 + registryTuple.Name,
243 + value,
244 + registryTuple.Component_
245 + );
246 + break;
247 + }
248 +
249 + case "RemoveRegistry":
250 + {
251 + var removeRegistryTuple = (RemoveRegistryTuple)tuple;
252 + fields = String.Join(",",
253 + ((int)removeRegistryTuple.Root).ToString(),
254 + removeRegistryTuple.Key,
255 + removeRegistryTuple.Name,
256 + removeRegistryTuple.Component_
257 + );
258 + break;
259 + }
260 +
261 + case "ServiceControl":
262 + {
263 + var serviceControlTuple = (ServiceControlTuple)tuple;
264 +
265 + var events = serviceControlTuple.InstallRemove ? WindowsInstallerConstants.MsidbServiceControlEventDelete : 0;
266 + events |= serviceControlTuple.UninstallRemove ? WindowsInstallerConstants.MsidbServiceControlEventUninstallDelete : 0;
267 + events |= serviceControlTuple.InstallStart ? WindowsInstallerConstants.MsidbServiceControlEventStart : 0;
268 + events |= serviceControlTuple.UninstallStart ? WindowsInstallerConstants.MsidbServiceControlEventUninstallStart : 0;
269 + events |= serviceControlTuple.InstallStop ? WindowsInstallerConstants.MsidbServiceControlEventStop : 0;
270 + events |= serviceControlTuple.UninstallStop ? WindowsInstallerConstants.MsidbServiceControlEventUninstallStop : 0;
271 +
272 + fields = String.Join(",",
273 + serviceControlTuple.Name,
274 + events.ToString(),
275 + serviceControlTuple.Arguments,
276 + serviceControlTuple.Wait == true ? "1" : "0",
277 + serviceControlTuple.Component_
278 + );
279 + break;
280 + }
281 +
282 + case "ServiceInstall":
283 + {
284 + var serviceInstallTuple = (ServiceInstallTuple)tuple;
285 +
286 + var errorControl = (int)serviceInstallTuple.ErrorControl;
287 + errorControl |= serviceInstallTuple.Vital ? WindowsInstallerConstants.MsidbServiceInstallErrorControlVital : 0;
288 +
289 + var serviceType = (int)serviceInstallTuple.ServiceType;
290 + serviceType |= serviceInstallTuple.Interactive ? WindowsInstallerConstants.MsidbServiceInstallInteractive : 0;
291 +
292 + fields = String.Join(",",
293 + serviceInstallTuple.Name,
294 + serviceInstallTuple.DisplayName,
295 + serviceType.ToString(),
296 + ((int)serviceInstallTuple.StartType).ToString(),
297 + errorControl.ToString(),
298 + serviceInstallTuple.LoadOrderGroup,
299 + serviceInstallTuple.Dependencies,
300 + serviceInstallTuple.StartName,
301 + serviceInstallTuple.Password,
302 + serviceInstallTuple.Arguments,
303 + serviceInstallTuple.Component_,
304 + serviceInstallTuple.Description
305 + );
306 + break;
307 + }
308 +
309 + case "Upgrade":
310 + {
311 + var upgradeTuple = (UpgradeTuple)tuple;
312 +
313 + var attributes = upgradeTuple.MigrateFeatures ? WindowsInstallerConstants.MsidbUpgradeAttributesMigrateFeatures : 0;
314 + attributes |= upgradeTuple.OnlyDetect ? WindowsInstallerConstants.MsidbUpgradeAttributesOnlyDetect : 0;
315 + attributes |= upgradeTuple.IgnoreRemoveFailures ? WindowsInstallerConstants.MsidbUpgradeAttributesIgnoreRemoveFailure : 0;
316 + attributes |= upgradeTuple.VersionMinInclusive ? WindowsInstallerConstants.MsidbUpgradeAttributesVersionMinInclusive : 0;
317 + attributes |= upgradeTuple.VersionMaxInclusive ? WindowsInstallerConstants.MsidbUpgradeAttributesVersionMaxInclusive : 0;
318 + attributes |= upgradeTuple.ExcludeLanguages ? WindowsInstallerConstants.MsidbUpgradeAttributesLanguagesExclusive : 0;
319 +
320 + fields = String.Join(",",
321 + upgradeTuple.VersionMin,
322 + upgradeTuple.VersionMax,
323 + upgradeTuple.Language,
324 + attributes.ToString(),
325 + upgradeTuple.Remove,
326 + upgradeTuple.ActionProperty
327 + );
328 + break;
329 + }
330 +
331 + case "WixAction":
332 + {
333 + var wixActionTuple = (WixActionTuple)tuple;
334 + fields = String.Join(",",
335 + wixActionTuple.SequenceTable,
336 + wixActionTuple.Action,
337 + wixActionTuple.Condition,
338 + // BUGBUGBUG: AB#2626
339 + wixActionTuple.Sequence == 0 ? String.Empty : wixActionTuple.Sequence.ToString(),
340 + wixActionTuple.Before,
341 + wixActionTuple.After,
342 + wixActionTuple.Overridable == true ? "1" : "0"
343 + );
344 + break;
345 + }
346 +
347 + case "WixComplexReference":
348 + {
349 + var wixComplexReferenceTuple = (WixComplexReferenceTuple)tuple;
350 + fields = String.Join(",",
351 + wixComplexReferenceTuple.Parent,
352 + ((int)wixComplexReferenceTuple.ParentType).ToString(),
353 + wixComplexReferenceTuple.ParentLanguage,
354 + wixComplexReferenceTuple.Child,
355 + ((int)wixComplexReferenceTuple.ChildType).ToString(),
356 + wixComplexReferenceTuple.IsPrimary ? "1" : "0"
357 + );
358 + break;
359 + }
360 +
361 + case "WixFile":
362 + {
363 + var wixFileTuple = (WixFileTuple)tuple;
364 + fields = String.Concat(
365 + wixFileTuple.AssemblyType == FileAssemblyType.DotNetAssembly ? "0" : wixFileTuple.AssemblyType == FileAssemblyType.Win32Assembly ? "1" : String.Empty, ",",
366 + String.Join(",", tuple.Fields.Skip(2).Take(6).Select(field => (string)field).ToArray()));
367 + break;
368 + }
369 +
370 + case "WixProperty":
371 + {
372 + var wixPropertyTuple = (WixPropertyTuple)tuple;
373 + var attributes = 0;
374 + attributes |= wixPropertyTuple.Admin ? 0x1 : 0;
375 + attributes |= wixPropertyTuple.Hidden ? 0x2 : 0;
376 + attributes |= wixPropertyTuple.Secure ? 0x4 : 0;
377 +
378 + fields = String.Join(",",
379 + wixPropertyTuple.Property_,
380 + attributes.ToString()
381 + );
382 + break;
383 + }
384 +
385 + }
386 +
387 + var id = tuple.Id == null ? String.Empty : String.Concat(",", tuple.Id.Id);
388 + return $"{tuple.Definition.Name}{id},{fields}";
389 + }
390 + }
391 +}
src/test/WixToolsetTest.Converters.Tupleizer/TestData/Integration/test.wixout
Binary files /dev/null and b/src/test/WixToolsetTest.Converters.Tupleizer/TestData/Integration/test.wixout differ
src/test/WixToolsetTest.Converters.Tupleizer/TestData/Integration/test.wixproj new
+47
@@ -0,0 +1,47 @@
1 +<?xml version="1.0" encoding="utf-8"?>
2 +<Project ToolsVersion="4.0" DefaultTargets="Build" InitialTargets="EnsureWixToolsetInstalled" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3 + <PropertyGroup>
4 + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
5 + <Platform Condition=" '$(Platform)' == '' ">x86</Platform>
6 + <ProductVersion>3.10</ProductVersion>
7 + <ProjectGuid>d59f1c1e-9238-49fa-bfa2-ec1d9c2dda1d</ProjectGuid>
8 + <SchemaVersion>2.0</SchemaVersion>
9 + <OutputName>TupleizerWixout</OutputName>
10 + <OutputType>Package</OutputType>
11 + </PropertyGroup>
12 + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
13 + <OutputPath>bin\$(Configuration)\</OutputPath>
14 + <IntermediateOutputPath>obj\$(Configuration)\</IntermediateOutputPath>
15 + <DefineConstants>Debug</DefineConstants>
16 + </PropertyGroup>
17 + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
18 + <OutputPath>bin\$(Configuration)\</OutputPath>
19 + <IntermediateOutputPath>obj\$(Configuration)\</IntermediateOutputPath>
20 + </PropertyGroup>
21 + <ItemGroup>
22 + <Compile Include="Product.wxs" />
23 + </ItemGroup>
24 + <ItemGroup>
25 + <WixExtension Include="WixUtilExtension">
26 + <HintPath>$(WixExtDir)\WixUtilExtension.dll</HintPath>
27 + <Name>WixUtilExtension</Name>
28 + </WixExtension>
29 + <WixExtension Include="WixNetFxExtension">
30 + <HintPath>$(WixExtDir)\WixNetFxExtension.dll</HintPath>
31 + <Name>WixNetFxExtension</Name>
32 + </WixExtension>
33 + </ItemGroup>
34 + <Import Project="$(WixTargetsPath)" Condition=" '$(WixTargetsPath)' != '' " />
35 + <Import Project="$(MSBuildExtensionsPath32)\Microsoft\WiX\v3.x\Wix.targets" Condition=" '$(WixTargetsPath)' == '' AND Exists('$(MSBuildExtensionsPath32)\Microsoft\WiX\v3.x\Wix.targets') " />
36 + <Target Name="EnsureWixToolsetInstalled" Condition=" '$(WixTargetsImported)' != 'true' ">
37 + <Error Text="The WiX Toolset v3.11 (or newer) build tools must be installed to build this project. To download the WiX Toolset, see http://wixtoolset.org/releases/" />
38 + </Target>
39 + <!--
40 + To modify your build process, add your task inside one of the targets below and uncomment it.
41 + Other similar extension points exist, see Wix.targets.
42 + <Target Name="BeforeBuild">
43 + </Target>
44 + <Target Name="AfterBuild">
45 + </Target>
46 + -->
47 +</Project>
\ No newline at end of file
src/test/WixToolsetTest.Converters.Tupleizer/TestData/Integration/test.wxs new
+36
@@ -0,0 +1,36 @@
1 +<?xml version="1.0" encoding="UTF-8"?>
2 +<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
3 + <Product Id="*" Name="TupleizerWixout" Language="1033" Version="1.0.0.0" Manufacturer="FireGiant" UpgradeCode="14a02d7f-9b32-4c92-b1f1-da518bf4e32a">
4 + <Package InstallerVersion="200" Compressed="yes" InstallScope="perMachine" />
5 +
6 + <MajorUpgrade DowngradeErrorMessage="A newer version of [ProductName] is already installed." AllowSameVersionUpgrades="yes" IgnoreRemoveFailure="yes" />
7 + <MediaTemplate />
8 +
9 + <Feature Id="ProductFeature" Title="TupleizerWixout" Level="1">
10 + <Feature Id="ChildFeature">
11 + <ComponentGroupRef Id="ProductComponents" />
12 + </Feature>
13 + </Feature>
14 +
15 + <PropertyRef Id="WIX_IS_NETFRAMEWORK_462_OR_LATER_INSTALLED" />
16 + <CustomActionRef Id="WixFailWhenDeferred" />
17 + <Property Id="WIXFAILWHENDEFERRED" Value="1" Secure="yes" />
18 + </Product>
19 +
20 + <Fragment>
21 + <Directory Id="TARGETDIR" Name="SourceDir">
22 + <Directory Id="ProgramFilesFolder">
23 + <Directory Id="INSTALLFOLDER" Name="TupleizerWixout" />
24 + </Directory>
25 + </Directory>
26 + </Fragment>
27 +
28 + <Fragment>
29 + <ComponentGroup Id="ProductComponents" Directory="INSTALLFOLDER">
30 + <Component Id="ProductComponent">
31 + <File Checksum="yes" ReadOnly="yes" Source="$(env.WIX)\bin\candle.exe" Assembly=".net" AssemblyApplication="candle.exe" />
32 + <RegistryValue Root="HKLM" Key="SOFTWARE\WiX Toolset" Name="[ProductName]Installed" Value="1" Type="integer" />
33 + </Component>
34 + </ComponentGroup>
35 + </Fragment>
36 +</Wix>
src/test/WixToolsetTest.Converters.Tupleizer/WixToolsetTest.Converters.Tupleizer.csproj new
+33
@@ -0,0 +1,33 @@
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 +
4 +<Project Sdk="Microsoft.NET.Sdk">
5 +
6 + <PropertyGroup>
7 + <TargetFramework>net461</TargetFramework>
8 + <IsPackable>false</IsPackable>
9 + </PropertyGroup>
10 +
11 + <ItemGroup>
12 + <Content Include="TestData\Integration\test.wixout" CopyToOutputDirectory="PreserveNewest" />
13 + </ItemGroup>
14 +
15 + <ItemGroup>
16 + <ProjectReference Include="..\..\WixToolset.Converters.Tupleizer\WixToolset.Converters.Tupleizer.csproj" />
17 + </ItemGroup>
18 +
19 + <ItemGroup>
20 + <PackageReference Include="WixToolset.Data" Version="4.0.*" />
21 + <PackageReference Include="WixBuildTools.TestSupport" Version="4.0.*" />
22 + </ItemGroup>
23 +
24 + <ItemGroup>
25 + <Reference Include="wix" HintPath="..\..\deps\wix.dll" />
26 + </ItemGroup>
27 +
28 + <ItemGroup>
29 + <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.1.0" />
30 + <PackageReference Include="xunit" Version="2.4.1" />
31 + <PackageReference Include="xunit.runner.visualstudio" Version="2.4.1" PrivateAssets="All" />
32 + </ItemGroup>
33 +</Project>
src/test/WixToolsetTest.Converters/ConverterFixture.cs new
+554
@@ -0,0 +1,554 @@
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 WixToolsetTest.Converters
4 +{
5 + using System;
6 + using System.IO;
7 + using System.Text;
8 + using System.Xml.Linq;
9 + using WixToolset.Converters;
10 + using WixToolset.Data;
11 + using WixToolset.Extensibility;
12 + using WixToolset.Extensibility.Services;
13 + using Xunit;
14 +
15 + public class ConverterFixture
16 + {
17 + private static readonly XNamespace Wix4Namespace = "http://wixtoolset.org/schemas/v4/wxs";
18 +
19 + [Fact]
20 + public void EnsuresDeclaration()
21 + {
22 + var parse = String.Join(Environment.NewLine,
23 + "<Wix xmlns='http://wixtoolset.org/schemas/v4/wxs'>",
24 + " <Fragment />",
25 + "</Wix>");
26 +
27 + var expected = String.Join(Environment.NewLine,
28 + "<?xml version=\"1.0\" encoding=\"utf-16\"?>",
29 + "<Wix xmlns=\"http://wixtoolset.org/schemas/v4/wxs\">",
30 + " <Fragment />",
31 + "</Wix>");
32 +
33 + var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo);
34 +
35 + var messaging = new DummyMessaging();
36 + var converter = new Wix3Converter(messaging, 2, null, null);
37 +
38 + var errors = converter.ConvertDocument(document);
39 +
40 + var actual = UnformattedDocumentString(document);
41 +
42 + Assert.Equal(1, errors);
43 + Assert.Equal(expected, actual);
44 + }
45 +
46 + [Fact]
47 + public void EnsuresUtf8Declaration()
48 + {
49 + var parse = String.Join(Environment.NewLine,
50 + "<?xml version='1.0'?>",
51 + "<Wix xmlns='http://wixtoolset.org/schemas/v4/wxs'>",
52 + " <Fragment />",
53 + "</Wix>");
54 +
55 + var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo);
56 +
57 + var messaging = new DummyMessaging();
58 + var converter = new Wix3Converter(messaging, 4, null, null);
59 +
60 + var errors = converter.ConvertDocument(document);
61 +
62 + Assert.Equal(1, errors);
63 + Assert.Equal("1.0", document.Declaration.Version);
64 + Assert.Equal("utf-8", document.Declaration.Encoding);
65 + }
66 +
67 + [Fact]
68 + public void CanFixWhitespace()
69 + {
70 + var parse = String.Join(Environment.NewLine,
71 + "<?xml version='1.0' encoding='utf-8'?>",
72 + "<Wix xmlns='http://wixtoolset.org/schemas/v4/wxs'>",
73 + " <Fragment>",
74 + " <Property Id='Prop'",
75 + " Value='Val'>",
76 + " </Property>",
77 + " </Fragment>",
78 + "</Wix>");
79 +
80 + var expected = String.Join(Environment.NewLine,
81 + "<?xml version=\"1.0\" encoding=\"utf-16\"?>",
82 + "<Wix xmlns=\"http://wixtoolset.org/schemas/v4/wxs\">",
83 + " <Fragment>",
84 + " <Property Id=\"Prop\" Value=\"Val\" />",
85 + " </Fragment>",
86 + "</Wix>");
87 +
88 + var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo);
89 +
90 + var messaging = new DummyMessaging();
91 + var converter = new Wix3Converter(messaging, 4, null, null);
92 +
93 + var errors = converter.ConvertDocument(document);
94 +
95 + var actual = UnformattedDocumentString(document);
96 +
97 + Assert.Equal(expected, actual);
98 + Assert.Equal(4, errors);
99 + }
100 +
101 + [Fact]
102 + public void CanPreserveNewLines()
103 + {
104 + var parse = String.Join(Environment.NewLine,
105 + "<?xml version='1.0' encoding='utf-8'?>",
106 + "<Wix xmlns='http://wixtoolset.org/schemas/v4/wxs'>",
107 + " <Fragment>",
108 + "",
109 + " <Property Id='Prop' Value='Val' />",
110 + "",
111 + " </Fragment>",
112 + "</Wix>");
113 +
114 + var expected = String.Join(Environment.NewLine,
115 + "<?xml version=\"1.0\" encoding=\"utf-16\"?>",
116 + "<Wix xmlns=\"http://wixtoolset.org/schemas/v4/wxs\">",
117 + " <Fragment>",
118 + "",
119 + " <Property Id=\"Prop\" Value=\"Val\" />",
120 + "",
121 + " </Fragment>",
122 + "</Wix>");
123 +
124 + var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo);
125 +
126 + var messaging = new DummyMessaging();
127 + var converter = new Wix3Converter(messaging, 4, null, null);
128 +
129 + var conversions = converter.ConvertDocument(document);
130 +
131 + var actual = UnformattedDocumentString(document);
132 +
133 + Assert.Equal(expected, actual);
134 + Assert.Equal(3, conversions);
135 + }
136 +
137 + [Fact]
138 + public void CanConvertWithNewLineAtEndOfFile()
139 + {
140 + var parse = String.Join(Environment.NewLine,
141 + "<?xml version='1.0' encoding='utf-8'?>",
142 + "<Wix xmlns='http://wixtoolset.org/schemas/v4/wxs'>",
143 + " <Fragment>",
144 + "",
145 + " <Property Id='Prop' Value='Val' />",
146 + "",
147 + " </Fragment>",
148 + "</Wix>",
149 + "");
150 +
151 + var expected = String.Join(Environment.NewLine,
152 + "<?xml version=\"1.0\" encoding=\"utf-16\"?>",
153 + "<Wix xmlns=\"http://wixtoolset.org/schemas/v4/wxs\">",
154 + " <Fragment>",
155 + "",
156 + " <Property Id=\"Prop\" Value=\"Val\" />",
157 + "",
158 + " </Fragment>",
159 + "</Wix>",
160 + "");
161 +
162 + var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo);
163 +
164 + var messaging = new DummyMessaging();
165 + var converter = new Wix3Converter(messaging, 4, null, null);
166 +
167 + var conversions = converter.ConvertDocument(document);
168 +
169 + var actual = UnformattedDocumentString(document);
170 +
171 + Assert.Equal(expected, actual);
172 + Assert.Equal(3, conversions);
173 + }
174 +
175 + [Fact]
176 + public void CanFixCdataWhitespace()
177 + {
178 + var parse = String.Join(Environment.NewLine,
179 + "<?xml version='1.0' encoding='utf-8'?>",
180 + "<Wix xmlns='http://wixtoolset.org/schemas/v4/wxs'>",
181 + " <Fragment>",
182 + " <Property Id='Prop'>",
183 + " <![CDATA[1<2]]>",
184 + " </Property>",
185 + " </Fragment>",
186 + "</Wix>");
187 +
188 + var expected = String.Join(Environment.NewLine,
189 + "<?xml version=\"1.0\" encoding=\"utf-16\"?>",
190 + "<Wix xmlns=\"http://wixtoolset.org/schemas/v4/wxs\">",
191 + " <Fragment>",
192 + " <Property Id=\"Prop\"><![CDATA[1<2]]></Property>",
193 + " </Fragment>",
194 + "</Wix>");
195 +
196 + var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo);
197 +
198 + var messaging = new DummyMessaging();
199 + var converter = new Wix3Converter(messaging, 2, null, null);
200 +
201 + var errors = converter.ConvertDocument(document);
202 +
203 + var actual = UnformattedDocumentString(document);
204 +
205 + Assert.Equal(expected, actual);
206 + Assert.Equal(2, errors);
207 + }
208 +
209 + [Fact]
210 + public void CanFixCdataWithWhitespace()
211 + {
212 + var parse = String.Join(Environment.NewLine,
213 + "<?xml version='1.0' encoding='utf-8'?>",
214 + "<Wix xmlns='http://wixtoolset.org/schemas/v4/wxs'>",
215 + " <Fragment>",
216 + " <Property Id='Prop'>",
217 + " <![CDATA[",
218 + " 1<2",
219 + " ]]>",
220 + " </Property>",
221 + " </Fragment>",
222 + "</Wix>");
223 +
224 + var expected = String.Join(Environment.NewLine,
225 + "<?xml version=\"1.0\" encoding=\"utf-16\"?>",
226 + "<Wix xmlns=\"http://wixtoolset.org/schemas/v4/wxs\">",
227 + " <Fragment>",
228 + " <Property Id=\"Prop\"><![CDATA[1<2]]></Property>",
229 + " </Fragment>",
230 + "</Wix>");
231 +
232 + var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo);
233 +
234 + var messaging = new DummyMessaging();
235 + var converter = new Wix3Converter(messaging, 2, null, null);
236 +
237 + var errors = converter.ConvertDocument(document);
238 +
239 + var actual = UnformattedDocumentString(document);
240 +
241 + Assert.Equal(expected, actual);
242 + Assert.Equal(2, errors);
243 + }
244 +
245 + [Fact]
246 + public void CanConvertMainNamespace()
247 + {
248 + var parse = String.Join(Environment.NewLine,
249 + "<?xml version='1.0' encoding='utf-8'?>",
250 + "<Wix xmlns='http://schemas.microsoft.com/wix/2006/wi'>",
251 + " <Fragment />",
252 + "</Wix>");
253 +
254 + var expected = String.Join(Environment.NewLine,
255 + "<?xml version=\"1.0\" encoding=\"utf-16\"?>",
256 + "<Wix xmlns=\"http://wixtoolset.org/schemas/v4/wxs\">",
257 + " <Fragment />",
258 + "</Wix>");
259 +
260 + var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo);
261 +
262 + var messaging = new DummyMessaging();
263 + var converter = new Wix3Converter(messaging, 2, null, null);
264 +
265 + var errors = converter.ConvertDocument(document);
266 +
267 + var actual = UnformattedDocumentString(document);
268 +
269 + Assert.Equal(1, errors);
270 + //Assert.Equal(Wix4Namespace, document.Root.GetDefaultNamespace());
271 + Assert.Equal(expected, actual);
272 + }
273 +
274 + [Fact]
275 + public void CanConvertNamedMainNamespace()
276 + {
277 + var parse = String.Join(Environment.NewLine,
278 + "<?xml version='1.0' encoding='utf-8'?>",
279 + "<w:Wix xmlns:w='http://schemas.microsoft.com/wix/2006/wi'>",
280 + " <w:Fragment />",
281 + "</w:Wix>");
282 +
283 + var expected = String.Join(Environment.NewLine,
284 + "<?xml version=\"1.0\" encoding=\"utf-16\"?>",
285 + "<w:Wix xmlns:w=\"http://wixtoolset.org/schemas/v4/wxs\">",
286 + " <w:Fragment />",
287 + "</w:Wix>");
288 +
289 + var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo);
290 +
291 + var messaging = new DummyMessaging();
292 + var converter = new Wix3Converter(messaging, 2, null, null);
293 +
294 + var errors = converter.ConvertDocument(document);
295 +
296 + var actual = UnformattedDocumentString(document);
297 +
298 + Assert.Equal(1, errors);
299 + Assert.Equal(expected, actual);
300 + Assert.Equal(Wix4Namespace, document.Root.GetNamespaceOfPrefix("w"));
301 + }
302 +
303 + [Fact]
304 + public void CanConvertNonWixDefaultNamespace()
305 + {
306 + var parse = String.Join(Environment.NewLine,
307 + "<?xml version='1.0' encoding='utf-8'?>",
308 + "<w:Wix xmlns:w='http://schemas.microsoft.com/wix/2006/wi' xmlns='http://schemas.microsoft.com/wix/UtilExtension'>",
309 + " <w:Fragment>",
310 + " <Test />",
311 + " </w:Fragment>",
312 + "</w:Wix>");
313 +
314 + var expected = String.Join(Environment.NewLine,
315 + "<?xml version=\"1.0\" encoding=\"utf-16\"?>",
316 + "<w:Wix xmlns:w=\"http://wixtoolset.org/schemas/v4/wxs\" xmlns=\"http://wixtoolset.org/schemas/v4/wxs/util\">",
317 + " <w:Fragment>",
318 + " <Test />",
319 + " </w:Fragment>",
320 + "</w:Wix>");
321 +
322 + var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo);
323 +
324 + var messaging = new DummyMessaging();
325 + var converter = new Wix3Converter(messaging, 2, null, null);
326 +
327 + var errors = converter.ConvertDocument(document);
328 +
329 + var actual = UnformattedDocumentString(document);
330 +
331 + Assert.Equal(expected, actual);
332 + Assert.Equal(2, errors);
333 + Assert.Equal(Wix4Namespace, document.Root.GetNamespaceOfPrefix("w"));
334 + Assert.Equal("http://wixtoolset.org/schemas/v4/wxs/util", document.Root.GetDefaultNamespace());
335 + }
336 +
337 + [Fact]
338 + public void CanConvertExtensionNamespace()
339 + {
340 + var parse = String.Join(Environment.NewLine,
341 + "<?xml version='1.0' encoding='utf-8'?>",
342 + "<Wix xmlns='http://schemas.microsoft.com/wix/2006/wi' xmlns:util='http://schemas.microsoft.com/wix/UtilExtension'>",
343 + " <Fragment />",
344 + "</Wix>");
345 +
346 + var expected = String.Join(Environment.NewLine,
347 + "<?xml version=\"1.0\" encoding=\"utf-16\"?>",
348 + "<Wix xmlns=\"http://wixtoolset.org/schemas/v4/wxs\" xmlns:util=\"http://wixtoolset.org/schemas/v4/wxs/util\">",
349 + " <Fragment />",
350 + "</Wix>");
351 +
352 + var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo);
353 +
354 + var messaging = new DummyMessaging();
355 + var converter = new Wix3Converter(messaging, 2, null, null);
356 +
357 + var errors = converter.ConvertDocument(document);
358 +
359 + var actual = UnformattedDocumentString(document);
360 +
361 + Assert.Equal(2, errors);
362 + Assert.Equal(expected, actual);
363 + Assert.Equal(Wix4Namespace, document.Root.GetDefaultNamespace());
364 + }
365 +
366 + [Fact]
367 + public void CanConvertMissingNamespace()
368 + {
369 + var parse = String.Join(Environment.NewLine,
370 + "<?xml version='1.0' encoding='utf-8'?>",
371 + "<Wix>",
372 + " <Fragment />",
373 + "</Wix>");
374 +
375 + var expected = String.Join(Environment.NewLine,
376 + "<?xml version=\"1.0\" encoding=\"utf-16\"?>",
377 + "<Wix xmlns=\"http://wixtoolset.org/schemas/v4/wxs\">",
378 + " <Fragment />",
379 + "</Wix>");
380 +
381 + var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo);
382 +
383 + var messaging = new DummyMessaging();
384 + var converter = new Wix3Converter(messaging, 2, null, null);
385 +
386 + var errors = converter.ConvertDocument(document);
387 +
388 + var actual = UnformattedDocumentString(document);
389 +
390 + Assert.Equal(1, errors);
391 + Assert.Equal(expected, actual);
392 + Assert.Equal(Wix4Namespace, document.Root.GetDefaultNamespace());
393 + }
394 +
395 + [Fact]
396 + public void CanConvertAnonymousFile()
397 + {
398 + var parse = String.Join(Environment.NewLine,
399 + "<?xml version='1.0' encoding='utf-8'?>",
400 + "<Wix xmlns='http://wixtoolset.org/schemas/v4/wxs'>",
401 + " <File Source='path\\to\\foo.txt' />",
402 + "</Wix>");
403 +
404 + var expected = String.Join(Environment.NewLine,
405 + "<?xml version=\"1.0\" encoding=\"utf-16\"?>",
406 + "<Wix xmlns=\"http://wixtoolset.org/schemas/v4/wxs\">",
407 + " <File Id=\"foo.txt\" Source=\"path\\to\\foo.txt\" />",
408 + "</Wix>");
409 +
410 + var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo);
411 +
412 + var messaging = new DummyMessaging();
413 + var converter = new Wix3Converter(messaging, 2, null, null);
414 +
415 + var errors = converter.ConvertDocument(document);
416 +
417 + var actual = UnformattedDocumentString(document);
418 +
419 + Assert.Equal(1, errors);
420 + Assert.Equal(expected, actual);
421 + }
422 +
423 + [Fact]
424 + public void CanConvertShortNameDirectoryWithoutName()
425 + {
426 + var parse = String.Join(Environment.NewLine,
427 + "<?xml version='1.0' encoding='utf-8'?>",
428 + "<Wix xmlns='http://wixtoolset.org/schemas/v4/wxs'>",
429 + " <Directory ShortName='iamshort' />",
430 + "</Wix>");
431 +
432 + var expected = String.Join(Environment.NewLine,
433 + "<?xml version=\"1.0\" encoding=\"utf-16\"?>",
434 + "<Wix xmlns=\"http://wixtoolset.org/schemas/v4/wxs\">",
435 + " <Directory Name=\"iamshort\" />",
436 + "</Wix>");
437 +
438 + var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo);
439 +
440 + var messaging = new DummyMessaging();
441 + var converter = new Wix3Converter(messaging, 2, null, null);
442 +
443 + var errors = converter.ConvertDocument(document);
444 +
445 + var actual = UnformattedDocumentString(document);
446 +
447 + Assert.Equal(1, errors);
448 + Assert.Equal(expected, actual);
449 + }
450 +
451 + [Fact]
452 + public void CanConvertSuppressSignatureValidationNo()
453 + {
454 + var parse = String.Join(Environment.NewLine,
455 + "<?xml version='1.0' encoding='utf-8'?>",
456 + "<Wix xmlns='http://wixtoolset.org/schemas/v4/wxs'>",
457 + " <MsiPackage SuppressSignatureValidation='no' />",
458 + "</Wix>");
459 +
460 + var expected = String.Join(Environment.NewLine,
461 + "<?xml version=\"1.0\" encoding=\"utf-16\"?>",
462 + "<Wix xmlns=\"http://wixtoolset.org/schemas/v4/wxs\">",
463 + " <MsiPackage EnableSignatureValidation=\"yes\" />",
464 + "</Wix>");
465 +
466 + var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo);
467 +
468 + var messaging = new DummyMessaging();
469 + var converter = new Wix3Converter(messaging, 2, null, null);
470 +
471 + var errors = converter.ConvertDocument(document);
472 +
473 + var actual = UnformattedDocumentString(document);
474 +
475 + Assert.Equal(1, errors);
476 + Assert.Equal(expected, actual);
477 + }
478 +
479 + [Fact]
480 + public void CanConvertSuppressSignatureValidationYes()
481 + {
482 + var parse = String.Join(Environment.NewLine,
483 + "<?xml version='1.0' encoding='utf-8'?>",
484 + "<Wix xmlns='http://wixtoolset.org/schemas/v4/wxs'>",
485 + " <Payload SuppressSignatureValidation='yes' />",
486 + "</Wix>");
487 +
488 + var expected = String.Join(Environment.NewLine,
489 + "<?xml version=\"1.0\" encoding=\"utf-16\"?>",
490 + "<Wix xmlns=\"http://wixtoolset.org/schemas/v4/wxs\">",
491 + " <Payload />",
492 + "</Wix>");
493 +
494 + var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo);
495 +
496 + var messaging = new DummyMessaging();
497 + var converter = new Wix3Converter(messaging, 2, null, null);
498 +
499 + var errors = converter.ConvertDocument(document);
500 +
501 + var actual = UnformattedDocumentString(document);
502 +
503 + Assert.Equal(1, errors);
504 + Assert.Equal(expected, actual);
505 + }
506 +
507 + private static string UnformattedDocumentString(XDocument document)
508 + {
509 + var sb = new StringBuilder();
510 +
511 + using (var writer = new StringWriter(sb))
512 + {
513 + document.Save(writer, SaveOptions.DisableFormatting);
514 + }
515 +
516 + return sb.ToString();
517 + }
518 +
519 + private class DummyMessaging : IMessaging
520 + {
521 + public bool EncounteredError { get; set; }
522 +
523 + public int LastErrorNumber { get; set; }
524 +
525 + public bool ShowVerboseMessages { get; set; }
526 +
527 + public bool SuppressAllWarnings { get; set; }
528 +
529 + public bool WarningsAsError { get; set; }
530 +
531 + public void ElevateWarningMessage(int warningNumber)
532 + {
533 + }
534 +
535 + public string FormatMessage(Message message) => String.Empty;
536 +
537 + public void SetListener(IMessageListener listener)
538 + {
539 + }
540 +
541 + public void SuppressWarningMessage(int warningNumber)
542 + {
543 + }
544 +
545 + public void Write(Message message)
546 + {
547 + }
548 +
549 + public void Write(string message, bool verbose = false)
550 + {
551 + }
552 + }
553 + }
554 +}
src/test/WixToolsetTest.Converters/TestData/Preprocessor/ConvertedPreprocessor.wxs new
+62
@@ -0,0 +1,62 @@
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 +
4 +
5 +
6 +<?include WixVer.wxi ?>
7 +
8 +<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs" xmlns:swid="http://wixtoolset.org/schemas/v4/wxs/tag" xmlns:util="http://wixtoolset.org/schemas/v4/wxs/util">
9 + <Product Id="*" Name="!(loc.ShortProduct) v$(var.WixMajorMinor) Core" Language="1033" Manufacturer="!(loc.Company)" Version="$(var.WixMsiProductVersion)" UpgradeCode="3618724B-2523-44F9-A908-866AA619504D">
10 + <Package Compressed="yes" InstallerVersion="200" SummaryCodepage="1252" InstallScope="perMachine" />
11 + <swid:Tag Regid="!(loc.Regid)" InstallDirectory="INSTALLFOLDER" />
12 +
13 + <MajorUpgrade DowngradeErrorMessage="A later version of [ProductName] is already installed." />
14 +
15 + <MediaTemplate CabinetTemplate="core{0}.cab" />
16 +
17 + <Feature Id="Feature_WiX" Title="WiX Toolset" Level="1">
18 + <Component Id="Licensing" Directory="INSTALLFOLDER">
19 + <File Id="LICENSE.TXT" Source="LICENSE.TXT" />
20 + </Component>
21 +
22 + <Component Id="ProductRegistration" Directory="INSTALLFOLDER">
23 + <RegistryKey Root="HKLM" Key="SOFTWARE\Microsoft\Windows Installer XML\$(var.WixMajorMinor)">
24 + <RegistryValue Name="InstallFolder" Value="[INSTALLFOLDER]" Type="string" />
25 + </RegistryKey>
26 + </Component>
27 +
28 + <Component Id="ProductFamilyRegistration" Directory="INSTALLFOLDER">
29 + <RegistryKey Root="HKLM" Key="SOFTWARE\Microsoft\Windows Installer XML\$(var.WixMajor).x">
30 + <RegistryValue Name="v$(var.WixMajorMinor)" Value="[INSTALLFOLDER]" Type="string" />
31 + </RegistryKey>
32 + </Component>
33 +
34 + <Component Id="ProductInformation" Directory="BinFolder">
35 + <RegistryKey Root="HKLM" Key="SOFTWARE\Microsoft\Windows Installer XML\$(var.WixMajorMinor)">
36 + <RegistryValue Name="InstallRoot" Value="[BinFolder]" Type="string" />
37 + <RegistryValue Name="ProductVersion" Value="[ProductVersion]" Type="string" />
38 + </RegistryKey>
39 +
40 + <RemoveFolder Id="CleanupShortcutFolder" Directory="ShortcutFolder" On="uninstall" />
41 + </Component>
42 +
43 + <Component Directory="BinFolder">
44 + <File Id="wixtoolset.org.ico" Source="common\wixtoolset.org.ico">
45 + <?include ComRegistration.wxi ?>
46 + </File>
47 + <util:InternetShortcut Id="wixtoolset.org" Directory="ShortcutFolder" Name="WiX Home Page" Target="http://wixtoolset.org/" IconFile="file://[#wixtoolset.org.ico]" />
48 + </Component>
49 +
50 + <ComponentGroupRef Id="ToolsetComponents" />
51 + <ComponentGroupRef Id="ExtensionComponents" />
52 + <ComponentGroupRef Id="LuxComponents" />
53 + <ComponentGroupRef Id="DocComponents" />
54 + </Feature>
55 +
56 + <FeatureRef Id="Feature_MSBuild" />
57 + <FeatureRef Id="Feature_Intellisense2010" />
58 + <FeatureRef Id="Feature_Intellisense2012" />
59 + <FeatureRef Id="Feature_Intellisense2013" />
60 + <FeatureRef Id="Feature_Intellisense2015" />
61 + </Product>
62 +</Wix>
src/test/WixToolsetTest.Converters/TestData/Preprocessor/Preprocessor.wxs new
+63
@@ -0,0 +1,63 @@
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 +
4 +
5 +
6 +<?include WixVer.wxi ?>
7 +
8 +<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi" xmlns:swid="http://schemas.microsoft.com/wix/TagExtension" xmlns:util="http://schemas.microsoft.com/wix/UtilExtension">
9 + <Product Id="*" Name="!(loc.ShortProduct) v$(var.WixMajorMinor) Core" Language="1033" Manufacturer="!(loc.Company)"
10 + Version="$(var.WixMsiProductVersion)" UpgradeCode="3618724B-2523-44F9-A908-866AA619504D">
11 + <Package Compressed="yes" InstallerVersion="200" SummaryCodepage="1252" InstallScope="perMachine" />
12 + <swid:Tag Regid="!(loc.Regid)" InstallDirectory="INSTALLFOLDER" />
13 +
14 + <MajorUpgrade DowngradeErrorMessage="A later version of [ProductName] is already installed." />
15 +
16 + <MediaTemplate CabinetTemplate="core{0}.cab" />
17 +
18 + <Feature Id="Feature_WiX" Title="WiX Toolset" Level="1">
19 + <Component Id="Licensing" Directory="INSTALLFOLDER">
20 + <File Source="LICENSE.TXT" />
21 + </Component>
22 +
23 + <Component Id="ProductRegistration" Directory="INSTALLFOLDER">
24 + <RegistryKey Root="HKLM" Key="SOFTWARE\Microsoft\Windows Installer XML\$(var.WixMajorMinor)">
25 + <RegistryValue Name="InstallFolder" Value="[INSTALLFOLDER]" Type="string" />
26 + </RegistryKey>
27 + </Component>
28 +
29 + <Component Id="ProductFamilyRegistration" Directory="INSTALLFOLDER">
30 + <RegistryKey Root="HKLM" Key="SOFTWARE\Microsoft\Windows Installer XML\$(var.WixMajor).x">
31 + <RegistryValue Name="v$(var.WixMajorMinor)" Value="[INSTALLFOLDER]" Type="string" />
32 + </RegistryKey>
33 + </Component>
34 +
35 + <Component Id="ProductInformation" Directory="BinFolder">
36 + <RegistryKey Root="HKLM" Key="SOFTWARE\Microsoft\Windows Installer XML\$(var.WixMajorMinor)">
37 + <RegistryValue Name="InstallRoot" Value="[BinFolder]" Type="string"/>
38 + <RegistryValue Name="ProductVersion" Value="[ProductVersion]" Type="string" />
39 + </RegistryKey>
40 +
41 + <RemoveFolder Id="CleanupShortcutFolder" Directory="ShortcutFolder" On="uninstall" />
42 + </Component>
43 +
44 + <Component Directory="BinFolder">
45 + <File Source="common\wixtoolset.org.ico">
46 + <?include ComRegistration.wxi ?>
47 + </File>
48 + <util:InternetShortcut Id="wixtoolset.org" Directory="ShortcutFolder" Name="WiX Home Page" Target="http://wixtoolset.org/" IconFile="file://[#wixtoolset.org.ico]" />
49 + </Component>
50 +
51 + <ComponentGroupRef Id="ToolsetComponents" />
52 + <ComponentGroupRef Id="ExtensionComponents" />
53 + <ComponentGroupRef Id="LuxComponents" />
54 + <ComponentGroupRef Id="DocComponents" />
55 + </Feature>
56 +
57 + <FeatureRef Id="Feature_MSBuild" />
58 + <FeatureRef Id="Feature_Intellisense2010" />
59 + <FeatureRef Id="Feature_Intellisense2012" />
60 + <FeatureRef Id="Feature_Intellisense2013" />
61 + <FeatureRef Id="Feature_Intellisense2015" />
62 + </Product>
63 +</Wix>
src/test/WixToolsetTest.Converters/TestData/Preprocessor/wixcop.settings.xml new
+9
@@ -0,0 +1,9 @@
1 +<?xml version="1.0"?>
2 +<Settings>
3 + <IgnoreErrors>
4 + <Test Id="WhitespacePrecedingNodeWrong"/>
5 + <Test Id="WhitespacePrecedingEndElementWrong"/>
6 + </IgnoreErrors>
7 + <ErrorsAsWarnings/>
8 + <ExemptFiles/>
9 +</Settings>
\ No newline at end of file
src/test/WixToolsetTest.Converters/TestData/QtExec.bad/v3.wxs new
+65
@@ -0,0 +1,65 @@
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 +
4 +
5 +
6 +<?include WixVer.wxi ?>
7 +
8 +<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi" xmlns:swid="http://schemas.microsoft.com/wix/TagExtension" xmlns:util="http://schemas.microsoft.com/wix/UtilExtension">
9 + <Product Id="*" Name="!(loc.ShortProduct) v$(var.WixMajorMinor) Core" Language="1033" Manufacturer="!(loc.Company)"
10 + Version="$(var.WixMsiProductVersion)" UpgradeCode="3618724B-2523-44F9-A908-866AA619504D">
11 + <Package Compressed="yes" InstallerVersion="200" SummaryCodepage="1252" InstallScope="perMachine" />
12 + <swid:Tag Regid="!(loc.Regid)" InstallDirectory="INSTALLFOLDER" />
13 +
14 + <MajorUpgrade DowngradeErrorMessage="A later version of [ProductName] is already installed." />
15 +
16 + <MediaTemplate CabinetTemplate="core{0}.cab" />
17 +
18 + <Property Id="QtExecCmdTimeout" Value="600000" />
19 + <CustomAction Id="InstallVSTemplateCommand" Property="QtExecCmdLine" Value="&quot;[VSENVPRODUCT80]\devenv.exe&quot; /setup" />
20 + <CustomAction Id="InstallVSTemplate" BinaryKey="WixCA" DllEntry="CAQuietExec" Return="asyncWait" />
21 +
22 + <Feature Id="Feature_WiX" Title="WiX Toolset" Level="1">
23 + <Component Id="Licensing" Directory="INSTALLFOLDER">
24 + <File Source="LICENSE.TXT" />
25 + </Component>
26 +
27 + <Component Id="ProductRegistration" Directory="INSTALLFOLDER">
28 + <RegistryKey Root="HKLM" Key="SOFTWARE\Microsoft\Windows Installer XML\$(var.WixMajorMinor)">
29 + <RegistryValue Name="InstallFolder" Value="[INSTALLFOLDER]" Type="string" />
30 + </RegistryKey>
31 + </Component>
32 +
33 + <Component Id="ProductFamilyRegistration" Directory="INSTALLFOLDER">
34 + <RegistryKey Root="HKLM" Key="SOFTWARE\Microsoft\Windows Installer XML\$(var.WixMajor).x">
35 + <RegistryValue Name="v$(var.WixMajorMinor)" Value="[INSTALLFOLDER]" Type="string" />
36 + </RegistryKey>
37 + </Component>
38 +
39 + <Component Id="ProductInformation" Directory="BinFolder">
40 + <RegistryKey Root="HKLM" Key="SOFTWARE\Microsoft\Windows Installer XML\$(var.WixMajorMinor)">
41 + <RegistryValue Name="InstallRoot" Value="[BinFolder]" Type="string"/>
42 + <RegistryValue Name="ProductVersion" Value="[ProductVersion]" Type="string" />
43 + </RegistryKey>
44 +
45 + <RemoveFolder Id="CleanupShortcutFolder" Directory="ShortcutFolder" On="uninstall" />
46 + </Component>
47 +
48 + <Component Directory="BinFolder">
49 + <File Source="common\wixtoolset.org.ico" />
50 + <util:InternetShortcut Id="wixtoolset.org" Directory="ShortcutFolder" Name="WiX Home Page" Target="http://wixtoolset.org/" IconFile="file://[#wixtoolset.org.ico]" />
51 + </Component>
52 +
53 + <ComponentGroupRef Id="ToolsetComponents" />
54 + <ComponentGroupRef Id="ExtensionComponents" />
55 + <ComponentGroupRef Id="LuxComponents" />
56 + <ComponentGroupRef Id="DocComponents" />
57 + </Feature>
58 +
59 + <FeatureRef Id="Feature_MSBuild" />
60 + <FeatureRef Id="Feature_Intellisense2010" />
61 + <FeatureRef Id="Feature_Intellisense2012" />
62 + <FeatureRef Id="Feature_Intellisense2013" />
63 + <FeatureRef Id="Feature_Intellisense2015" />
64 + </Product>
65 +</Wix>
src/test/WixToolsetTest.Converters/TestData/QtExec.bad/v4_expected.wxs new
+64
@@ -0,0 +1,64 @@
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 +
4 +
5 +
6 +<?include WixVer.wxi ?>
7 +
8 +<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs" xmlns:swid="http://wixtoolset.org/schemas/v4/wxs/tag" xmlns:util="http://wixtoolset.org/schemas/v4/wxs/util">
9 + <Product Id="*" Name="!(loc.ShortProduct) v$(var.WixMajorMinor) Core" Language="1033" Manufacturer="!(loc.Company)" Version="$(var.WixMsiProductVersion)" UpgradeCode="3618724B-2523-44F9-A908-866AA619504D">
10 + <Package Compressed="yes" InstallerVersion="200" SummaryCodepage="1252" InstallScope="perMachine" />
11 + <swid:Tag Regid="!(loc.Regid)" InstallDirectory="INSTALLFOLDER" />
12 +
13 + <MajorUpgrade DowngradeErrorMessage="A later version of [ProductName] is already installed." />
14 +
15 + <MediaTemplate CabinetTemplate="core{0}.cab" />
16 +
17 + <Property Id="QtExecCmdTimeout" Value="600000" />
18 + <CustomAction Id="InstallVSTemplateCommand" Property="WixQuietExecCmdLine" Value="&quot;[VSENVPRODUCT80]\devenv.exe&quot; /setup" />
19 + <CustomAction Id="InstallVSTemplate" BinaryKey="UtilCA" DllEntry="WixQuietExec" Return="asyncWait" />
20 +
21 + <Feature Id="Feature_WiX" Title="WiX Toolset" Level="1">
22 + <Component Id="Licensing" Directory="INSTALLFOLDER">
23 + <File Id="LICENSE.TXT" Source="LICENSE.TXT" />
24 + </Component>
25 +
26 + <Component Id="ProductRegistration" Directory="INSTALLFOLDER">
27 + <RegistryKey Root="HKLM" Key="SOFTWARE\Microsoft\Windows Installer XML\$(var.WixMajorMinor)">
28 + <RegistryValue Name="InstallFolder" Value="[INSTALLFOLDER]" Type="string" />
29 + </RegistryKey>
30 + </Component>
31 +
32 + <Component Id="ProductFamilyRegistration" Directory="INSTALLFOLDER">
33 + <RegistryKey Root="HKLM" Key="SOFTWARE\Microsoft\Windows Installer XML\$(var.WixMajor).x">
34 + <RegistryValue Name="v$(var.WixMajorMinor)" Value="[INSTALLFOLDER]" Type="string" />
35 + </RegistryKey>
36 + </Component>
37 +
38 + <Component Id="ProductInformation" Directory="BinFolder">
39 + <RegistryKey Root="HKLM" Key="SOFTWARE\Microsoft\Windows Installer XML\$(var.WixMajorMinor)">
40 + <RegistryValue Name="InstallRoot" Value="[BinFolder]" Type="string" />
41 + <RegistryValue Name="ProductVersion" Value="[ProductVersion]" Type="string" />
42 + </RegistryKey>
43 +
44 + <RemoveFolder Id="CleanupShortcutFolder" Directory="ShortcutFolder" On="uninstall" />
45 + </Component>
46 +
47 + <Component Directory="BinFolder">
48 + <File Id="wixtoolset.org.ico" Source="common\wixtoolset.org.ico" />
49 + <util:InternetShortcut Id="wixtoolset.org" Directory="ShortcutFolder" Name="WiX Home Page" Target="http://wixtoolset.org/" IconFile="file://[#wixtoolset.org.ico]" />
50 + </Component>
51 +
52 + <ComponentGroupRef Id="ToolsetComponents" />
53 + <ComponentGroupRef Id="ExtensionComponents" />
54 + <ComponentGroupRef Id="LuxComponents" />
55 + <ComponentGroupRef Id="DocComponents" />
56 + </Feature>
57 +
58 + <FeatureRef Id="Feature_MSBuild" />
59 + <FeatureRef Id="Feature_Intellisense2010" />
60 + <FeatureRef Id="Feature_Intellisense2012" />
61 + <FeatureRef Id="Feature_Intellisense2013" />
62 + <FeatureRef Id="Feature_Intellisense2015" />
63 + </Product>
64 +</Wix>
src/test/WixToolsetTest.Converters/TestData/QtExec/v3.wxs new
+64
@@ -0,0 +1,64 @@
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 +
4 +
5 +
6 +<?include WixVer.wxi ?>
7 +
8 +<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi" xmlns:swid="http://schemas.microsoft.com/wix/TagExtension" xmlns:util="http://schemas.microsoft.com/wix/UtilExtension">
9 + <Product Id="*" Name="!(loc.ShortProduct) v$(var.WixMajorMinor) Core" Language="1033" Manufacturer="!(loc.Company)"
10 + Version="$(var.WixMsiProductVersion)" UpgradeCode="3618724B-2523-44F9-A908-866AA619504D">
11 + <Package Compressed="yes" InstallerVersion="200" SummaryCodepage="1252" InstallScope="perMachine" />
12 + <swid:Tag Regid="!(loc.Regid)" InstallDirectory="INSTALLFOLDER" />
13 +
14 + <MajorUpgrade DowngradeErrorMessage="A later version of [ProductName] is already installed." />
15 +
16 + <MediaTemplate CabinetTemplate="core{0}.cab" />
17 +
18 + <CustomAction Id="InstallVSTemplateCommand" Property="QtExecCmdLine" Value="&quot;[VSENVPRODUCT80]\devenv.exe&quot; /setup" />
19 + <CustomAction Id="InstallVSTemplate" BinaryKey="WixCA" DllEntry="CAQuietExec" Return="asyncWait" />
20 +
21 + <Feature Id="Feature_WiX" Title="WiX Toolset" Level="1">
22 + <Component Id="Licensing" Directory="INSTALLFOLDER">
23 + <File Source="LICENSE.TXT" />
24 + </Component>
25 +
26 + <Component Id="ProductRegistration" Directory="INSTALLFOLDER">
27 + <RegistryKey Root="HKLM" Key="SOFTWARE\Microsoft\Windows Installer XML\$(var.WixMajorMinor)">
28 + <RegistryValue Name="InstallFolder" Value="[INSTALLFOLDER]" Type="string" />
29 + </RegistryKey>
30 + </Component>
31 +
32 + <Component Id="ProductFamilyRegistration" Directory="INSTALLFOLDER">
33 + <RegistryKey Root="HKLM" Key="SOFTWARE\Microsoft\Windows Installer XML\$(var.WixMajor).x">
34 + <RegistryValue Name="v$(var.WixMajorMinor)" Value="[INSTALLFOLDER]" Type="string" />
35 + </RegistryKey>
36 + </Component>
37 +
38 + <Component Id="ProductInformation" Directory="BinFolder">
39 + <RegistryKey Root="HKLM" Key="SOFTWARE\Microsoft\Windows Installer XML\$(var.WixMajorMinor)">
40 + <RegistryValue Name="InstallRoot" Value="[BinFolder]" Type="string"/>
41 + <RegistryValue Name="ProductVersion" Value="[ProductVersion]" Type="string" />
42 + </RegistryKey>
43 +
44 + <RemoveFolder Id="CleanupShortcutFolder" Directory="ShortcutFolder" On="uninstall" />
45 + </Component>
46 +
47 + <Component Directory="BinFolder">
48 + <File Source="common\wixtoolset.org.ico" />
49 + <util:InternetShortcut Id="wixtoolset.org" Directory="ShortcutFolder" Name="WiX Home Page" Target="http://wixtoolset.org/" IconFile="file://[#wixtoolset.org.ico]" />
50 + </Component>
51 +
52 + <ComponentGroupRef Id="ToolsetComponents" />
53 + <ComponentGroupRef Id="ExtensionComponents" />
54 + <ComponentGroupRef Id="LuxComponents" />
55 + <ComponentGroupRef Id="DocComponents" />
56 + </Feature>
57 +
58 + <FeatureRef Id="Feature_MSBuild" />
59 + <FeatureRef Id="Feature_Intellisense2010" />
60 + <FeatureRef Id="Feature_Intellisense2012" />
61 + <FeatureRef Id="Feature_Intellisense2013" />
62 + <FeatureRef Id="Feature_Intellisense2015" />
63 + </Product>
64 +</Wix>
src/test/WixToolsetTest.Converters/TestData/QtExec/v4_expected.wxs new
+63
@@ -0,0 +1,63 @@
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 +
4 +
5 +
6 +<?include WixVer.wxi ?>
7 +
8 +<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs" xmlns:swid="http://wixtoolset.org/schemas/v4/wxs/tag" xmlns:util="http://wixtoolset.org/schemas/v4/wxs/util">
9 + <Product Id="*" Name="!(loc.ShortProduct) v$(var.WixMajorMinor) Core" Language="1033" Manufacturer="!(loc.Company)" Version="$(var.WixMsiProductVersion)" UpgradeCode="3618724B-2523-44F9-A908-866AA619504D">
10 + <Package Compressed="yes" InstallerVersion="200" SummaryCodepage="1252" InstallScope="perMachine" />
11 + <swid:Tag Regid="!(loc.Regid)" InstallDirectory="INSTALLFOLDER" />
12 +
13 + <MajorUpgrade DowngradeErrorMessage="A later version of [ProductName] is already installed." />
14 +
15 + <MediaTemplate CabinetTemplate="core{0}.cab" />
16 +
17 + <CustomAction Id="InstallVSTemplateCommand" Property="WixQuietExecCmdLine" Value="&quot;[VSENVPRODUCT80]\devenv.exe&quot; /setup" />
18 + <CustomAction Id="InstallVSTemplate" BinaryKey="UtilCA" DllEntry="WixQuietExec" Return="asyncWait" />
19 +
20 + <Feature Id="Feature_WiX" Title="WiX Toolset" Level="1">
21 + <Component Id="Licensing" Directory="INSTALLFOLDER">
22 + <File Id="LICENSE.TXT" Source="LICENSE.TXT" />
23 + </Component>
24 +
25 + <Component Id="ProductRegistration" Directory="INSTALLFOLDER">
26 + <RegistryKey Root="HKLM" Key="SOFTWARE\Microsoft\Windows Installer XML\$(var.WixMajorMinor)">
27 + <RegistryValue Name="InstallFolder" Value="[INSTALLFOLDER]" Type="string" />
28 + </RegistryKey>
29 + </Component>
30 +
31 + <Component Id="ProductFamilyRegistration" Directory="INSTALLFOLDER">
32 + <RegistryKey Root="HKLM" Key="SOFTWARE\Microsoft\Windows Installer XML\$(var.WixMajor).x">
33 + <RegistryValue Name="v$(var.WixMajorMinor)" Value="[INSTALLFOLDER]" Type="string" />
34 + </RegistryKey>
35 + </Component>
36 +
37 + <Component Id="ProductInformation" Directory="BinFolder">
38 + <RegistryKey Root="HKLM" Key="SOFTWARE\Microsoft\Windows Installer XML\$(var.WixMajorMinor)">
39 + <RegistryValue Name="InstallRoot" Value="[BinFolder]" Type="string" />
40 + <RegistryValue Name="ProductVersion" Value="[ProductVersion]" Type="string" />
41 + </RegistryKey>
42 +
43 + <RemoveFolder Id="CleanupShortcutFolder" Directory="ShortcutFolder" On="uninstall" />
44 + </Component>
45 +
46 + <Component Directory="BinFolder">
47 + <File Id="wixtoolset.org.ico" Source="common\wixtoolset.org.ico" />
48 + <util:InternetShortcut Id="wixtoolset.org" Directory="ShortcutFolder" Name="WiX Home Page" Target="http://wixtoolset.org/" IconFile="file://[#wixtoolset.org.ico]" />
49 + </Component>
50 +
51 + <ComponentGroupRef Id="ToolsetComponents" />
52 + <ComponentGroupRef Id="ExtensionComponents" />
53 + <ComponentGroupRef Id="LuxComponents" />
54 + <ComponentGroupRef Id="DocComponents" />
55 + </Feature>
56 +
57 + <FeatureRef Id="Feature_MSBuild" />
58 + <FeatureRef Id="Feature_Intellisense2010" />
59 + <FeatureRef Id="Feature_Intellisense2012" />
60 + <FeatureRef Id="Feature_Intellisense2013" />
61 + <FeatureRef Id="Feature_Intellisense2015" />
62 + </Product>
63 +</Wix>
src/test/WixToolsetTest.Converters/TestData/SingleFile/ConvertedSingleFile.wxs new
+60
@@ -0,0 +1,60 @@
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 +
4 +
5 +
6 +<?include WixVer.wxi ?>
7 +
8 +<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs" xmlns:swid="http://wixtoolset.org/schemas/v4/wxs/tag" xmlns:util="http://wixtoolset.org/schemas/v4/wxs/util">
9 + <Product Id="*" Name="!(loc.ShortProduct) v$(var.WixMajorMinor) Core" Language="1033" Manufacturer="!(loc.Company)" Version="$(var.WixMsiProductVersion)" UpgradeCode="3618724B-2523-44F9-A908-866AA619504D">
10 + <Package Compressed="yes" InstallerVersion="200" SummaryCodepage="1252" InstallScope="perMachine" />
11 + <swid:Tag Regid="!(loc.Regid)" InstallDirectory="INSTALLFOLDER" />
12 +
13 + <MajorUpgrade DowngradeErrorMessage="A later version of [ProductName] is already installed." />
14 +
15 + <MediaTemplate CabinetTemplate="core{0}.cab" />
16 +
17 + <Feature Id="Feature_WiX" Title="WiX Toolset" Level="1">
18 + <Component Id="Licensing" Directory="INSTALLFOLDER">
19 + <File Id="LICENSE.TXT" Source="LICENSE.TXT" />
20 + </Component>
21 +
22 + <Component Id="ProductRegistration" Directory="INSTALLFOLDER">
23 + <RegistryKey Root="HKLM" Key="SOFTWARE\Microsoft\Windows Installer XML\$(var.WixMajorMinor)">
24 + <RegistryValue Name="InstallFolder" Value="[INSTALLFOLDER]" Type="string" />
25 + </RegistryKey>
26 + </Component>
27 +
28 + <Component Id="ProductFamilyRegistration" Directory="INSTALLFOLDER">
29 + <RegistryKey Root="HKLM" Key="SOFTWARE\Microsoft\Windows Installer XML\$(var.WixMajor).x">
30 + <RegistryValue Name="v$(var.WixMajorMinor)" Value="[INSTALLFOLDER]" Type="string" />
31 + </RegistryKey>
32 + </Component>
33 +
34 + <Component Id="ProductInformation" Directory="BinFolder">
35 + <RegistryKey Root="HKLM" Key="SOFTWARE\Microsoft\Windows Installer XML\$(var.WixMajorMinor)">
36 + <RegistryValue Name="InstallRoot" Value="[BinFolder]" Type="string" />
37 + <RegistryValue Name="ProductVersion" Value="[ProductVersion]" Type="string" />
38 + </RegistryKey>
39 +
40 + <RemoveFolder Id="CleanupShortcutFolder" Directory="ShortcutFolder" On="uninstall" />
41 + </Component>
42 +
43 + <Component Directory="BinFolder">
44 + <File Id="wixtoolset.org.ico" Source="common\wixtoolset.org.ico" />
45 + <util:InternetShortcut Id="wixtoolset.org" Directory="ShortcutFolder" Name="WiX Home Page" Target="http://wixtoolset.org/" IconFile="file://[#wixtoolset.org.ico]" />
46 + </Component>
47 +
48 + <ComponentGroupRef Id="ToolsetComponents" />
49 + <ComponentGroupRef Id="ExtensionComponents" />
50 + <ComponentGroupRef Id="LuxComponents" />
51 + <ComponentGroupRef Id="DocComponents" />
52 + </Feature>
53 +
54 + <FeatureRef Id="Feature_MSBuild" />
55 + <FeatureRef Id="Feature_Intellisense2010" />
56 + <FeatureRef Id="Feature_Intellisense2012" />
57 + <FeatureRef Id="Feature_Intellisense2013" />
58 + <FeatureRef Id="Feature_Intellisense2015" />
59 + </Product>
60 +</Wix>
src/test/WixToolsetTest.Converters/TestData/SingleFile/SingleFile.wxs new
+61
@@ -0,0 +1,61 @@
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 +
4 +
5 +
6 +<?include WixVer.wxi ?>
7 +
8 +<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi" xmlns:swid="http://schemas.microsoft.com/wix/TagExtension" xmlns:util="http://schemas.microsoft.com/wix/UtilExtension">
9 + <Product Id="*" Name="!(loc.ShortProduct) v$(var.WixMajorMinor) Core" Language="1033" Manufacturer="!(loc.Company)"
10 + Version="$(var.WixMsiProductVersion)" UpgradeCode="3618724B-2523-44F9-A908-866AA619504D">
11 + <Package Compressed="yes" InstallerVersion="200" SummaryCodepage="1252" InstallScope="perMachine" />
12 + <swid:Tag Regid="!(loc.Regid)" InstallDirectory="INSTALLFOLDER" />
13 +
14 + <MajorUpgrade DowngradeErrorMessage="A later version of [ProductName] is already installed." />
15 +
16 + <MediaTemplate CabinetTemplate="core{0}.cab" />
17 +
18 + <Feature Id="Feature_WiX" Title="WiX Toolset" Level="1">
19 + <Component Id="Licensing" Directory="INSTALLFOLDER">
20 + <File Source="LICENSE.TXT" />
21 + </Component>
22 +
23 + <Component Id="ProductRegistration" Directory="INSTALLFOLDER">
24 + <RegistryKey Root="HKLM" Key="SOFTWARE\Microsoft\Windows Installer XML\$(var.WixMajorMinor)">
25 + <RegistryValue Name="InstallFolder" Value="[INSTALLFOLDER]" Type="string" />
26 + </RegistryKey>
27 + </Component>
28 +
29 + <Component Id="ProductFamilyRegistration" Directory="INSTALLFOLDER">
30 + <RegistryKey Root="HKLM" Key="SOFTWARE\Microsoft\Windows Installer XML\$(var.WixMajor).x">
31 + <RegistryValue Name="v$(var.WixMajorMinor)" Value="[INSTALLFOLDER]" Type="string" />
32 + </RegistryKey>
33 + </Component>
34 +
35 + <Component Id="ProductInformation" Directory="BinFolder">
36 + <RegistryKey Root="HKLM" Key="SOFTWARE\Microsoft\Windows Installer XML\$(var.WixMajorMinor)">
37 + <RegistryValue Name="InstallRoot" Value="[BinFolder]" Type="string"/>
38 + <RegistryValue Name="ProductVersion" Value="[ProductVersion]" Type="string" />
39 + </RegistryKey>
40 +
41 + <RemoveFolder Id="CleanupShortcutFolder" Directory="ShortcutFolder" On="uninstall" />
42 + </Component>
43 +
44 + <Component Directory="BinFolder">
45 + <File Source="common\wixtoolset.org.ico" />
46 + <util:InternetShortcut Id="wixtoolset.org" Directory="ShortcutFolder" Name="WiX Home Page" Target="http://wixtoolset.org/" IconFile="file://[#wixtoolset.org.ico]" />
47 + </Component>
48 +
49 + <ComponentGroupRef Id="ToolsetComponents" />
50 + <ComponentGroupRef Id="ExtensionComponents" />
51 + <ComponentGroupRef Id="LuxComponents" />
52 + <ComponentGroupRef Id="DocComponents" />
53 + </Feature>
54 +
55 + <FeatureRef Id="Feature_MSBuild" />
56 + <FeatureRef Id="Feature_Intellisense2010" />
57 + <FeatureRef Id="Feature_Intellisense2012" />
58 + <FeatureRef Id="Feature_Intellisense2013" />
59 + <FeatureRef Id="Feature_Intellisense2015" />
60 + </Product>
61 +</Wix>
src/test/WixToolsetTest.Converters/WixToolsetTest.Converters.csproj new
+39
@@ -0,0 +1,39 @@
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 +
4 +<Project Sdk="Microsoft.NET.Sdk">
5 + <PropertyGroup>
6 + <TargetFramework>netcoreapp2.1</TargetFramework>
7 + <IsPackable>false</IsPackable>
8 + </PropertyGroup>
9 +
10 + <ItemGroup>
11 + <None Remove="TestData\SingleFile\ConvertedSingleFile.wxs" />
12 + <None Remove="TestData\SingleFile\SingleFile.wxs" />
13 + </ItemGroup>
14 + <ItemGroup>
15 + <Content Include="TestData\SingleFile\ConvertedSingleFile.wxs" CopyToOutputDirectory="PreserveNewest" />
16 + <Content Include="TestData\SingleFile\SingleFile.wxs" CopyToOutputDirectory="PreserveNewest" />
17 + <Content Include="TestData\Preprocessor\ConvertedPreprocessor.wxs" CopyToOutputDirectory="PreserveNewest" />
18 + <Content Include="TestData\Preprocessor\Preprocessor.wxs" CopyToOutputDirectory="PreserveNewest" />
19 + <Content Include="TestData\Preprocessor\wixcop.settings.xml" CopyToOutputDirectory="PreserveNewest" />
20 + <Content Include="TestData\QtExec\v3.wxs" CopyToOutputDirectory="PreserveNewest" />
21 + <Content Include="TestData\QtExec\v4_expected.wxs" CopyToOutputDirectory="PreserveNewest" />
22 + <Content Include="TestData\QtExec.bad\v3.wxs" CopyToOutputDirectory="PreserveNewest" />
23 + <Content Include="TestData\QtExec.bad\v4_expected.wxs" CopyToOutputDirectory="PreserveNewest" />
24 + </ItemGroup>
25 +
26 + <ItemGroup>
27 + <ProjectReference Include="..\..\WixToolset.Converters\WixToolset.Converters.csproj" />
28 + </ItemGroup>
29 +
30 + <ItemGroup>
31 + <PackageReference Include="WixBuildTools.TestSupport" Version="4.0.*" />
32 + </ItemGroup>
33 +
34 + <ItemGroup>
35 + <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.1.0" />
36 + <PackageReference Include="xunit" Version="2.4.1" />
37 + <PackageReference Include="xunit.runner.visualstudio" Version="2.4.1" PrivateAssets="All" />
38 + </ItemGroup>
39 +</Project>