@joebigelow / wix / commits / 13eedbfc

Extract interfaces for Preprocess/Compile/Link/Bind/etc

Rob Mensching committed Oct 18, 2018 at 13:42 UTC 13eedbfcf97e402ade06f2be29f98723ef7ff286
30 files changed +928 -790
src/WixToolset.Core.Burn/BundleBackend.cs
+5
@@ -27,6 +27,11 @@ namespace WixToolset.Core.Burn
27 return new BindResult { FileTransfers = command.FileTransfers, TrackedFiles = command.TrackedFiles };
28 }
29
30 + public BindResult Decompile(IDecompileContext context)
31 + {
32 + throw new NotImplementedException();
33 + }
34 +
35 public bool Inscribe(IInscribeContext context)
36 {
37 if (String.IsNullOrEmpty(context.SignedEngineFile))
src/WixToolset.Core.Burn/BurnBackendFactory.cs
+1 -1
@@ -9,7 +9,7 @@ namespace WixToolset.Core.Burn
9
10 internal class BurnBackendFactory : IBackendFactory
11 {
12 - public bool TryCreateBackend(string outputType, string outputFile, IBindContext context, out IBackend backend)
12 + public bool TryCreateBackend(string outputType, string outputFile, out IBackend backend)
13 {
14 if (String.IsNullOrEmpty(outputType))
15 {
src/WixToolset.Core.WindowsInstaller/MsiBackend.cs
+5
@@ -38,6 +38,11 @@ namespace WixToolset.Core.WindowsInstaller
38 return result;
39 }
40
41 + public BindResult Decompile(IDecompileContext context)
42 + {
43 + throw new NotImplementedException();
44 + }
45 +
46 public bool Inscribe(IInscribeContext context)
47 {
48 var command = new InscribeMsiPackageCommand(context);
src/WixToolset.Core.WindowsInstaller/MsmBackend.cs
+5
@@ -43,6 +43,11 @@ namespace WixToolset.Core.WindowsInstaller
43 return result;
44 }
45
46 + public BindResult Decompile(IDecompileContext context)
47 + {
48 + throw new NotImplementedException();
49 + }
50 +
51 public bool Inscribe(IInscribeContext context)
52 {
53 return false;
src/WixToolset.Core.WindowsInstaller/MspBackend.cs
+5
@@ -21,6 +21,11 @@ namespace WixToolset.Core.WindowsInstaller
21 throw new NotImplementedException();
22 }
23
24 + public BindResult Decompile(IDecompileContext context)
25 + {
26 + throw new NotImplementedException();
27 + }
28 +
29 public bool Inscribe(IInscribeContext context)
30 {
31 throw new NotImplementedException();
src/WixToolset.Core.WindowsInstaller/MstBackend.cs
+5
@@ -25,6 +25,11 @@ namespace WixToolset.Core.WindowsInstaller
25 throw new NotImplementedException();
26 }
27
28 + public BindResult Decompile(IDecompileContext context)
29 + {
30 + throw new NotImplementedException();
31 + }
32 +
33 public bool Inscribe(IInscribeContext context)
34 {
35 throw new NotImplementedException();
src/WixToolset.Core.WindowsInstaller/Unbinder.cs
+1 -1
@@ -74,7 +74,7 @@ namespace WixToolset.Core
74
75 foreach (var factory in this.BackendFactories)
76 {
77 - if (factory.TryCreateBackend(outputType.ToString(), file, null, out var backend))
77 + if (factory.TryCreateBackend(outputType.ToString(), file, out var backend))
78 {
79 return backend.Unbind(context);
80 }
src/WixToolset.Core.WindowsInstaller/WindowsInstallerBackendFactory.cs
+1 -1
@@ -9,7 +9,7 @@ namespace WixToolset.Core.WindowsInstaller
9
10 internal class WindowsInstallerBackendFactory : IBackendFactory
11 {
12 - public bool TryCreateBackend(string outputType, string outputFile, IBindContext context, out IBackend backend)
12 + public bool TryCreateBackend(string outputType, string outputFile, out IBackend backend)
13 {
14 if (String.IsNullOrEmpty(outputType))
15 {
src/WixToolset.Core/Binder.cs
+6 -51
@@ -3,7 +3,6 @@
3 namespace WixToolset.Core
4 {
5 using System;
6 - using System.Collections.Generic;
6 using System.Diagnostics;
7 using System.Linq;
8 using System.Reflection;
@@ -16,61 +15,17 @@ namespace WixToolset.Core
15 /// <summary>
16 /// Binder of the WiX toolset.
17 /// </summary>
19 - internal class Binder
18 + internal class Binder : IBinder
19 {
20 internal Binder(IServiceProvider serviceProvider)
21 {
22 this.ServiceProvider = serviceProvider;
23 }
24
26 - public int CabbingThreadCount { get; set; }
27 -
28 - public string CabCachePath { get; set; }
29 -
30 - public int Codepage { get; set; }
31 -
32 - public CompressionLevel? DefaultCompressionLevel { get; set; }
33 -
34 - public IEnumerable<IDelayedField> DelayedFields { get; set; }
35 -
36 - public IEnumerable<IExpectedExtractFile> ExpectedEmbeddedFiles { get; set; }
37 -
38 - public IEnumerable<string> Ices { get; set; }
39 -
40 - public string IntermediateFolder { get; set; }
41 -
42 - public Intermediate IntermediateRepresentation { get; set; }
43 -
44 - public string OutputPath { get; set; }
45 -
46 - public string OutputPdbPath { get; set; }
47 -
48 - public IEnumerable<string> SuppressIces { get; set; }
49 -
50 - public bool SuppressValidation { get; set; }
51 -
52 - public bool DeltaBinaryPatch { get; set; }
53 -
25 public IServiceProvider ServiceProvider { get; }
26
56 - public BindResult Execute()
27 + public BindResult Bind(IBindContext context)
28 {
58 - var context = this.ServiceProvider.GetService<IBindContext>();
59 - context.CabbingThreadCount = this.CabbingThreadCount;
60 - context.CabCachePath = this.CabCachePath;
61 - context.Codepage = this.Codepage;
62 - context.DefaultCompressionLevel = this.DefaultCompressionLevel;
63 - context.DelayedFields = this.DelayedFields;
64 - context.ExpectedEmbeddedFiles = this.ExpectedEmbeddedFiles;
65 - context.Extensions = this.ServiceProvider.GetService<IExtensionManager>().Create<IBinderExtension>();
66 - context.Ices = this.Ices;
67 - context.IntermediateFolder = this.IntermediateFolder;
68 - context.IntermediateRepresentation = this.IntermediateRepresentation;
69 - context.OutputPath = this.OutputPath;
70 - context.OutputPdbPath = this.OutputPdbPath;
71 - context.SuppressIces = this.SuppressIces;
72 - context.SuppressValidation = this.SuppressValidation;
73 -
29 // Prebind.
30 //
31 foreach (var extension in context.Extensions)
@@ -80,7 +35,7 @@ namespace WixToolset.Core
35
36 // Bind.
37 //
83 - this.WriteBuildInfoTable(context.IntermediateRepresentation, context.OutputPath, context.OutputPdbPath);
38 + this.WriteBuildInfoTuple(context.IntermediateRepresentation, context.OutputPath, context.OutputPdbPath);
39
40 var bindResult = this.BackendBind(context);
41
@@ -107,7 +62,7 @@ namespace WixToolset.Core
62
63 foreach (var factory in backendFactories)
64 {
110 - if (factory.TryCreateBackend(entrySection.Type.ToString(), context.OutputPath, null, out var backend))
65 + if (factory.TryCreateBackend(entrySection.Type.ToString(), context.OutputPath, out var backend))
66 {
67 var result = backend.Bind(context);
68 return result;
@@ -118,8 +73,8 @@ namespace WixToolset.Core
73
74 return null;
75 }
121 -
122 - private void WriteBuildInfoTable(Intermediate output, string outputFile, string outputPdbPath)
76 +
77 + private void WriteBuildInfoTuple(Intermediate output, string outputFile, string outputPdbPath)
78 {
79 var entrySection = output.Sections.First(s => s.Type != SectionType.Fragment);
80
src/WixToolset.Core/CommandLine/BuildCommand.cs
+117 -77
@@ -8,6 +8,7 @@ namespace WixToolset.Core.CommandLine
8 using System.Linq;
9 using System.Xml.Linq;
10 using WixToolset.Data;
11 + using WixToolset.Extensibility;
12 using WixToolset.Extensibility.Data;
13 using WixToolset.Extensibility.Services;
14
@@ -172,16 +173,24 @@ namespace WixToolset.Core.CommandLine
173
174 foreach (var sourceFile in sourceFiles)
175 {
175 - var preprocessor = new Preprocessor(this.ServiceProvider);
176 - preprocessor.IncludeSearchPaths = this.IncludeSearchPaths;
177 - preprocessor.Platform = this.Platform;
178 - preprocessor.SourcePath = sourceFile.SourcePath;
179 - preprocessor.Variables = this.PreprocessorVariables;
176 + var document = this.Preprocess(sourceFile.SourcePath);
177
181 - XDocument document = null;
178 + if (this.Messaging.EncounteredError)
179 + {
180 + continue;
181 + }
182 +
183 + var context = this.ServiceProvider.GetService<ICompileContext>();
184 + context.Extensions = this.ExtensionManager.Create<ICompilerExtension>();
185 + context.OutputPath = sourceFile.OutputPath;
186 + context.Platform = this.Platform;
187 + context.Source = document;
188 +
189 + Intermediate intermediate = null;
190 try
191 {
184 - document = preprocessor.Execute();
192 + var compiler = this.ServiceProvider.GetService<ICompiler>();
193 + intermediate = compiler.Compile(context);
194 }
195 catch (WixException e)
196 {
@@ -193,17 +202,6 @@ namespace WixToolset.Core.CommandLine
202 continue;
203 }
204
196 - var compiler = new Compiler(this.ServiceProvider);
197 - compiler.OutputPath = sourceFile.OutputPath;
198 - compiler.Platform = this.Platform;
199 - compiler.SourceDocument = document;
200 - var intermediate = compiler.Execute();
201 -
202 - if (this.Messaging.EncounteredError)
203 - {
204 - continue;
205 - }
206 -
205 intermediates.Add(intermediate);
206 }
207
@@ -212,14 +210,27 @@ namespace WixToolset.Core.CommandLine
210
211 private Intermediate LibraryPhase(IEnumerable<Intermediate> intermediates, IEnumerable<Localization> localizations)
212 {
215 - var librarian = new Librarian(this.ServiceProvider);
216 - librarian.BindFiles = this.BindFiles;
217 - librarian.BindPaths = this.BindPaths;
218 - librarian.Intermediates = intermediates;
219 - librarian.Localizations = localizations;
220 - return librarian.Execute();
221 - }
213 + var context = this.ServiceProvider.GetService<ILibraryContext>();
214 + context.BindFiles = this.BindFiles;
215 + context.BindPaths = this.BindPaths;
216 + context.Extensions = this.ExtensionManager.Create<ILibrarianExtension>();
217 + context.Localizations = localizations;
218 + context.Intermediates = intermediates;
219 +
220 + Intermediate library = null;
221 + try
222 + {
223 + var librarian = this.ServiceProvider.GetService<ILibrarian>();
224 + library = librarian.Combine(context);
225 + }
226 + catch (WixException e)
227 + {
228 + this.Messaging.Write(e.Error);
229 + }
230
231 + return library;
232 + }
233 +
234 private Intermediate LinkPhase(IEnumerable<Intermediate> intermediates, ITupleDefinitionCreator creator)
235 {
236 var libraries = this.LoadLibraries(creator);
@@ -229,26 +240,39 @@ namespace WixToolset.Core.CommandLine
240 return null;
241 }
242
232 - var linker = new Linker(this.ServiceProvider);
233 - linker.OutputType = this.OutputType;
234 - linker.Intermediates = intermediates;
235 - linker.Libraries = libraries;
236 - linker.TupleDefinitionCreator = creator;
237 - return linker.Execute();
243 + var context = this.ServiceProvider.GetService<ILinkContext>();
244 + context.Extensions = this.ExtensionManager.Create<ILinkerExtension>();
245 + context.ExtensionData = this.ExtensionManager.Create<IExtensionData>();
246 + context.ExpectedOutputType = this.OutputType;
247 + context.Intermediates = intermediates.Concat(libraries).ToList();
248 + context.TupleDefinitionCreator = creator;
249 +
250 + var linker = this.ServiceProvider.GetService<ILinker>();
251 + return linker.Link(context);
252 }
253
254 private void BindPhase(Intermediate output, IEnumerable<Localization> localizations)
255 {
256 + var intermediateFolder = this.IntermediateFolder;
257 + if (String.IsNullOrEmpty(intermediateFolder))
258 + {
259 + intermediateFolder = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
260 + }
261 +
262 ResolveResult resolveResult;
263 {
244 - var resolver = new Resolver(this.ServiceProvider);
245 - resolver.BindPaths = this.BindPaths;
246 - resolver.FilterCultures = this.FilterCultures;
247 - resolver.IntermediateFolder = this.IntermediateFolder;
248 - resolver.IntermediateRepresentation = output;
249 - resolver.Localizations = localizations;
250 -
251 - resolveResult = resolver.Execute();
264 + var context = this.ServiceProvider.GetService<IResolveContext>();
265 + context.BindPaths = this.BindPaths;
266 + context.Extensions = this.ExtensionManager.Create<IResolverExtension>();
267 + context.ExtensionData = this.ExtensionManager.Create<IExtensionData>();
268 + context.FilterCultures = this.FilterCultures;
269 + context.IntermediateFolder = intermediateFolder;
270 + context.IntermediateRepresentation = output;
271 + context.Localizations = localizations;
272 + context.VariableResolver = new WixVariableResolver(this.Messaging);
273 +
274 + var resolver = this.ServiceProvider.GetService<IResolver>();
275 + resolveResult = resolver.Resolve(context);
276 }
277
278 if (this.Messaging.EncounteredError)
@@ -258,28 +282,24 @@ namespace WixToolset.Core.CommandLine
282
283 BindResult bindResult;
284 {
261 - var intermediateFolder = this.IntermediateFolder;
262 - if (String.IsNullOrEmpty(intermediateFolder))
263 - {
264 - intermediateFolder = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
265 - }
266 -
267 - var binder = new Binder(this.ServiceProvider);
268 - //binder.CabbingThreadCount = this.CabbingThreadCount;
269 - binder.CabCachePath = this.CabCachePath;
270 - binder.Codepage = resolveResult.Codepage;
271 - //binder.DefaultCompressionLevel = this.DefaultCompressionLevel;
272 - binder.DelayedFields = resolveResult.DelayedFields;
273 - binder.ExpectedEmbeddedFiles = resolveResult.ExpectedEmbeddedFiles;
274 - binder.Ices = Array.Empty<string>(); // TODO: set this correctly
275 - binder.IntermediateFolder = intermediateFolder;
276 - binder.IntermediateRepresentation = resolveResult.IntermediateRepresentation;
277 - binder.OutputPath = this.OutputPath;
278 - binder.OutputPdbPath = Path.ChangeExtension(this.OutputPath, ".wixpdb");
279 - binder.SuppressIces = Array.Empty<string>(); // TODO: set this correctly
280 - binder.SuppressValidation = true; // TODO: set this correctly
281 -
282 - bindResult = binder.Execute();
285 + var context = this.ServiceProvider.GetService<IBindContext>();
286 + //context.CabbingThreadCount = this.CabbingThreadCount;
287 + context.CabCachePath = this.CabCachePath;
288 + context.Codepage = resolveResult.Codepage;
289 + //context.DefaultCompressionLevel = this.DefaultCompressionLevel;
290 + context.DelayedFields = resolveResult.DelayedFields;
291 + context.ExpectedEmbeddedFiles = resolveResult.ExpectedEmbeddedFiles;
292 + context.Extensions = this.ExtensionManager.Create<IBinderExtension>();
293 + context.Ices = Array.Empty<string>(); // TODO: set this correctly
294 + context.IntermediateFolder = intermediateFolder;
295 + context.IntermediateRepresentation = resolveResult.IntermediateRepresentation;
296 + context.OutputPath = this.OutputPath;
297 + context.OutputPdbPath = Path.ChangeExtension(this.OutputPath, ".wixpdb");
298 + context.SuppressIces = Array.Empty<string>(); // TODO: set this correctly
299 + context.SuppressValidation = true; // TODO: set this correctly
300 +
301 + var binder = this.ServiceProvider.GetService<IBinder>();
302 + bindResult = binder.Bind(context);
303 }
304
305 if (this.Messaging.EncounteredError)
@@ -288,16 +308,18 @@ namespace WixToolset.Core.CommandLine
308 }
309
310 {
291 - var layout = new Layout(this.ServiceProvider);
292 - layout.TrackedFiles = bindResult.TrackedFiles;
293 - layout.FileTransfers = bindResult.FileTransfers;
294 - layout.IntermediateFolder = this.IntermediateFolder;
295 - layout.ContentsFile = this.ContentsFile;
296 - layout.OutputsFile = this.OutputsFile;
297 - layout.BuiltOutputsFile = this.BuiltOutputsFile;
298 - layout.SuppressAclReset = false; // TODO: correctly set SuppressAclReset
299 -
300 - layout.Execute();
311 + var context = this.ServiceProvider.GetService<ILayoutContext>();
312 + context.Extensions = this.ExtensionManager.Create<ILayoutExtension>();
313 + context.TrackedFiles = bindResult.TrackedFiles;
314 + context.FileTransfers = bindResult.FileTransfers;
315 + context.IntermediateFolder = intermediateFolder;
316 + context.ContentsFile = this.ContentsFile;
317 + context.OutputsFile = this.OutputsFile;
318 + context.BuiltOutputsFile = this.BuiltOutputsFile;
319 + context.SuppressAclReset = false; // TODO: correctly set SuppressAclReset
320 +
321 + var layout = this.ServiceProvider.GetService<ILayoutCreator>();
322 + layout.Layout(context);
323 }
324 }
325
@@ -335,12 +357,7 @@ namespace WixToolset.Core.CommandLine
357
358 foreach (var loc in this.LocFiles)
359 {
338 - var preprocessor = new Preprocessor(this.ServiceProvider);
339 - preprocessor.IncludeSearchPaths = this.IncludeSearchPaths;
340 - preprocessor.Platform = Platform.X86; // TODO: set this correctly
341 - preprocessor.SourcePath = loc;
342 - preprocessor.Variables = this.PreprocessorVariables;
343 - var document = preprocessor.Execute();
360 + var document = this.Preprocess(loc);
361
362 if (this.Messaging.EncounteredError)
363 {
@@ -351,5 +368,28 @@ namespace WixToolset.Core.CommandLine
368 yield return localization;
369 }
370 }
371 +
372 + private XDocument Preprocess(string sourcePath)
373 + {
374 + var context = this.ServiceProvider.GetService<IPreprocessContext>();
375 + context.Extensions = this.ExtensionManager.Create<IPreprocessorExtension>();
376 + context.Platform = this.Platform;
377 + context.IncludeSearchPaths = this.IncludeSearchPaths;
378 + context.SourcePath = sourcePath;
379 + context.Variables = this.PreprocessorVariables;
380 +
381 + XDocument document = null;
382 + try
383 + {
384 + var preprocessor = this.ServiceProvider.GetService<IPreprocessor>();
385 + document = preprocessor.Preprocess(context);
386 + }
387 + catch (WixException e)
388 + {
389 + this.Messaging.Write(e.Error);
390 + }
391 +
392 + return document;
393 + }
394 }
395 }
src/WixToolset.Core/CommandLine/CompileCommand.cs
+20 -11
@@ -6,6 +6,7 @@ namespace WixToolset.Core.CommandLine
6 using System.Collections.Generic;
7 using System.Xml.Linq;
8 using WixToolset.Data;
9 + using WixToolset.Extensibility;
10 using WixToolset.Extensibility.Data;
11 using WixToolset.Extensibility.Services;
12
@@ -15,6 +16,7 @@ namespace WixToolset.Core.CommandLine
16 {
17 this.ServiceProvider = serviceProvider;
18 this.Messaging = serviceProvider.GetService<IMessaging>();
19 + this.ExtensionManager = serviceProvider.GetService<IExtensionManager>();
20 this.SourceFiles = sources;
21 this.PreprocessorVariables = preprocessorVariables;
22 this.Platform = platform;
@@ -24,6 +26,8 @@ namespace WixToolset.Core.CommandLine
26
27 public IMessaging Messaging { get; }
28
29 + public IExtensionManager ExtensionManager { get; }
30 +
31 private IEnumerable<SourceFile> SourceFiles { get; }
32
33 private IDictionary<string, string> PreprocessorVariables { get; }
@@ -36,16 +40,18 @@ namespace WixToolset.Core.CommandLine
40 {
41 foreach (var sourceFile in this.SourceFiles)
42 {
39 - var preprocessor = new Preprocessor(this.ServiceProvider);
40 - preprocessor.IncludeSearchPaths = this.IncludeSearchPaths;
41 - preprocessor.Platform = Platform.X86; // TODO: set this correctly
42 - preprocessor.SourcePath = sourceFile.SourcePath;
43 - preprocessor.Variables = new Dictionary<string, string>(this.PreprocessorVariables);
43 + var context = this.ServiceProvider.GetService<IPreprocessContext>();
44 + context.Extensions = this.ExtensionManager.Create<IPreprocessorExtension>();
45 + context.Platform = this.Platform;
46 + context.IncludeSearchPaths = this.IncludeSearchPaths;
47 + context.SourcePath = sourceFile.SourcePath;
48 + context.Variables = this.PreprocessorVariables;
49
50 XDocument document = null;
51 try
52 {
48 - document = preprocessor.Execute();
53 + var preprocessor = this.ServiceProvider.GetService<IPreprocessor>();
54 + document = preprocessor.Preprocess(context);
55 }
56 catch (WixException e)
57 {
@@ -57,11 +63,14 @@ namespace WixToolset.Core.CommandLine
63 continue;
64 }
65
60 - var compiler = new Compiler(this.ServiceProvider);
61 - compiler.OutputPath = sourceFile.OutputPath;
62 - compiler.Platform = this.Platform;
63 - compiler.SourceDocument = document;
64 - var intermediate = compiler.Execute();
66 + var compileContext = this.ServiceProvider.GetService<ICompileContext>();
67 + compileContext.Extensions = this.ExtensionManager.Create<ICompilerExtension>();
68 + compileContext.OutputPath = sourceFile.OutputPath;
69 + compileContext.Platform = this.Platform;
70 + compileContext.Source = document;
71 +
72 + var compiler = this.ServiceProvider.GetService<ICompiler>();
73 + var intermediate = compiler.Compile(compileContext);
74
75 intermediate.Save(sourceFile.OutputPath);
76 }
src/WixToolset.Core/Compiler.cs
+6 -19
@@ -22,7 +22,7 @@ namespace WixToolset.Core
22 /// <summary>
23 /// Compiler of the WiX toolset.
24 /// </summary>
25 - internal class Compiler
25 + internal class Compiler : ICompiler
26 {
27 public const string UpgradeDetectedProperty = "WIX_UPGRADE_DETECTED";
28 public const string UpgradePreventedCondition = "NOT WIX_UPGRADE_DETECTED";
@@ -84,14 +84,6 @@ namespace WixToolset.Core
84
85 private CompilerCore Core { get; set; }
86
87 - public string CompliationId { get; set; }
88 -
89 - public string OutputPath { get; set; }
90 -
91 - public Platform Platform { get; set; }
92 -
93 - public XDocument SourceDocument { get; set; }
94 -
87 /// <summary>
88 /// Gets or sets the platform which the compiler will use when defaulting 64-bit attributes and elements.
89 /// </summary>
@@ -109,22 +101,17 @@ namespace WixToolset.Core
101 /// </summary>
102 /// <returns>Intermediate object representing compiled source document.</returns>
103 /// <remarks>This method is not thread-safe.</remarks>
112 - public Intermediate Execute()
104 + public Intermediate Compile(ICompileContext context)
105 {
114 - this.Context = this.ServiceProvider.GetService<ICompileContext>();
115 - this.Context.Extensions = this.ServiceProvider.GetService<IExtensionManager>().Create<ICompilerExtension>();
116 - this.Context.CompilationId = this.CompliationId;
117 - this.Context.OutputPath = this.OutputPath;
118 - this.Context.Platform = this.Platform;
119 - this.Context.Source = this.SourceDocument;
120 -
106 var target = new Intermediate();
107
123 - if (String.IsNullOrEmpty(this.Context.CompilationId))
108 + if (String.IsNullOrEmpty(context.CompilationId))
109 {
125 - this.Context.CompilationId = target.Id;
110 + context.CompilationId = target.Id;
111 }
112
113 + this.Context = context;
114 +
115 var extensionsByNamespace = new Dictionary<XNamespace, ICompilerExtension>();
116
117 foreach (var extension in this.Context.Extensions)
src/WixToolset.Core/DecompileContext.cs new
+28
@@ -0,0 +1,28 @@
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.Core
4 +{
5 + using System;
6 + using System.Collections.Generic;
7 + using WixToolset.Data;
8 + using WixToolset.Extensibility;
9 + using WixToolset.Extensibility.Data;
10 +
11 + internal class DecompileContext : IDecompileContext
12 + {
13 + internal DecompileContext(IServiceProvider serviceProvider)
14 + {
15 + this.ServiceProvider = serviceProvider;
16 + }
17 +
18 + public IServiceProvider ServiceProvider { get; }
19 +
20 + public OutputType DecompileType { get; set; }
21 +
22 + public IEnumerable<IDecompilerExtension> Extensions { get; set; }
23 +
24 + public string IntermediateFolder { get; set; }
25 +
26 + public string OutputPath { get; set; }
27 + }
28 +}
src/WixToolset.Core/Decompiler.cs new
+75
@@ -0,0 +1,75 @@
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.Core
4 +{
5 + using System;
6 + using WixToolset.Data;
7 + using WixToolset.Extensibility;
8 + using WixToolset.Extensibility.Data;
9 + using WixToolset.Extensibility.Services;
10 +
11 + /// <summary>
12 + /// Decompiler of the WiX toolset.
13 + /// </summary>
14 + internal class Decompiler : IDecompiler
15 + {
16 + internal Decompiler(IServiceProvider serviceProvider)
17 + {
18 + this.ServiceProvider = serviceProvider;
19 + }
20 +
21 + public OutputType DecompileType { get; set; }
22 +
23 + public string IntermediateFolder { get; set; }
24 +
25 + public string OutputPath { get; set; }
26 +
27 + public IServiceProvider ServiceProvider { get; }
28 +
29 + public BindResult Decompile(IDecompileContext context)
30 + {
31 + // Pre-decompile.
32 + //
33 + foreach (var extension in context.Extensions)
34 + {
35 + extension.PreDecompile(context);
36 + }
37 +
38 + // Decompile.
39 + //
40 + var bindResult = this.BackendDecompile(context);
41 +
42 + if (bindResult != null)
43 + {
44 + // Post-decompile.
45 + //
46 + foreach (var extension in context.Extensions)
47 + {
48 + extension.PostDecompile(bindResult);
49 + }
50 + }
51 +
52 + return bindResult;
53 + }
54 +
55 + private BindResult BackendDecompile(IDecompileContext context)
56 + {
57 + var extensionManager = context.ServiceProvider.GetService<IExtensionManager>();
58 +
59 + var backendFactories = extensionManager.Create<IBackendFactory>();
60 +
61 + foreach (var factory in backendFactories)
62 + {
63 + if (factory.TryCreateBackend(context.DecompileType.ToString(), context.OutputPath, out var backend))
64 + {
65 + var result = backend.Decompile(context);
66 + return result;
67 + }
68 + }
69 +
70 + // TODO: messaging that a backend could not be found to decompile the decompile type?
71 +
72 + return null;
73 + }
74 + }
75 +}
src/WixToolset.Core/IBinder.cs new
+11
@@ -0,0 +1,11 @@
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.Core
4 +{
5 + using WixToolset.Extensibility.Data;
6 +
7 + public interface IBinder
8 + {
9 + BindResult Bind(IBindContext context);
10 + }
11 +}
src/WixToolset.Core/ICompiler.cs new
+12
@@ -0,0 +1,12 @@
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.Core
4 +{
5 + using WixToolset.Data;
6 + using WixToolset.Extensibility.Data;
7 +
8 + public interface ICompiler
9 + {
10 + Intermediate Compile(ICompileContext context);
11 + }
12 +}
src/WixToolset.Core/IDecompiler.cs new
+11
@@ -0,0 +1,11 @@
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.Core
4 +{
5 + using WixToolset.Extensibility.Data;
6 +
7 + public interface IDecompiler
8 + {
9 + BindResult Decompile(IDecompileContext context);
10 + }
11 +}
src/WixToolset.Core/ILayoutCreator.cs new
+11
@@ -0,0 +1,11 @@
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.Core
4 +{
5 + using WixToolset.Extensibility.Data;
6 +
7 + public interface ILayoutCreator
8 + {
9 + void Layout(ILayoutContext context);
10 + }
11 +}
src/WixToolset.Core/ILibrarian.cs new
+12
@@ -0,0 +1,12 @@
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.Core
4 +{
5 + using WixToolset.Data;
6 + using WixToolset.Extensibility.Data;
7 +
8 + public interface ILibrarian
9 + {
10 + Intermediate Combine(ILibraryContext context);
11 + }
12 +}
src/WixToolset.Core/ILinker.cs new
+12
@@ -0,0 +1,12 @@
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.Core
4 +{
5 + using WixToolset.Data;
6 + using WixToolset.Extensibility.Data;
7 +
8 + public interface ILinker
9 + {
10 + Intermediate Link(ILinkContext context);
11 + }
12 +}
src/WixToolset.Core/IPreprocessor.cs new
+15
@@ -0,0 +1,15 @@
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.Core
4 +{
5 + using System.Xml;
6 + using System.Xml.Linq;
7 + using WixToolset.Extensibility.Data;
8 +
9 + internal interface IPreprocessor
10 + {
11 + XDocument Preprocess(IPreprocessContext context);
12 +
13 + XDocument Preprocess(IPreprocessContext context, XmlReader reader);
14 + }
15 +}
src/WixToolset.Core/IResolver.cs new
+11
@@ -0,0 +1,11 @@
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.Core
4 +{
5 + using WixToolset.Extensibility.Data;
6 +
7 + public interface IResolver
8 + {
9 + ResolveResult Resolve(IResolveContext context);
10 + }
11 +}
src/WixToolset.Core/LayoutContext.cs
+1 -1
@@ -24,7 +24,7 @@ namespace WixToolset.Core
24
25 public IEnumerable<ITrackedFile> TrackedFiles { get; set; }
26
27 - public string OutputPdbPath { get; set; }
27 + public string IntermediateFolder { get; set; }
28
29 public string ContentsFile { get; set; }
30
src/WixToolset.Core/LayoutCreator.cs renamed
+12 -38
@@ -8,16 +8,15 @@ namespace WixToolset.Core
8 using System.Linq;
9 using WixToolset.Core.Bind;
10 using WixToolset.Data;
11 - using WixToolset.Extensibility;
11 using WixToolset.Extensibility.Data;
12 using WixToolset.Extensibility.Services;
13
14 /// <summary>
15 /// Layout for the WiX toolset.
16 /// </summary>
18 - internal class Layout
17 + internal class LayoutCreator : ILayoutCreator
18 {
20 - internal Layout(IServiceProvider serviceProvider)
19 + internal LayoutCreator(IServiceProvider serviceProvider)
20 {
21 this.ServiceProvider = serviceProvider;
22
@@ -28,33 +27,8 @@ namespace WixToolset.Core
27
28 private IMessaging Messaging { get; }
29
31 - public IEnumerable<ITrackedFile> TrackedFiles { get; set; }
32 -
33 - public IEnumerable<IFileTransfer> FileTransfers { get; set; }
34 -
35 - public string IntermediateFolder { get; set; }
36 -
37 - public string ContentsFile { get; set; }
38 -
39 - public string OutputsFile { get; set; }
40 -
41 - public string BuiltOutputsFile { get; set; }
42 -
43 - public bool SuppressAclReset { get; set; }
44 -
45 - public void Execute()
30 + public void Layout(ILayoutContext context)
31 {
47 - var extensionManager = this.ServiceProvider.GetService<IExtensionManager>();
48 -
49 - var context = this.ServiceProvider.GetService<ILayoutContext>();
50 - context.Extensions = extensionManager.Create<ILayoutExtension>();
51 - context.TrackedFiles = this.TrackedFiles;
52 - context.FileTransfers = this.FileTransfers;
53 - context.ContentsFile = this.ContentsFile;
54 - context.OutputsFile = this.OutputsFile;
55 - context.BuiltOutputsFile = this.BuiltOutputsFile;
56 - context.SuppressAclReset = this.SuppressAclReset;
57 -
32 // Pre-layout.
33 //
34 foreach (var extension in context.Extensions)
@@ -76,7 +50,7 @@ namespace WixToolset.Core
50
51 if (context.TrackedFiles != null)
52 {
79 - this.CleanTempFiles(context.TrackedFiles);
53 + this.CleanTempFiles(context.IntermediateFolder, context.TrackedFiles);
54 }
55 }
56 finally
@@ -126,7 +100,7 @@ namespace WixToolset.Core
100
101 using (var contents = new StreamWriter(path, false))
102 {
129 - foreach (string inputPath in uniqueInputFilePaths)
103 + foreach (var inputPath in uniqueInputFilePaths)
104 {
105 contents.WriteLine(inputPath);
106 }
@@ -190,7 +164,7 @@ namespace WixToolset.Core
164 }
165 }
166
193 - private void CleanTempFiles(IEnumerable<ITrackedFile> trackedFiles)
167 + private void CleanTempFiles(string intermediateFolder, IEnumerable<ITrackedFile> trackedFiles)
168 {
169 var uniqueTempPaths = new SortedSet<string>(trackedFiles.Where(t => t.Type == TrackedFileType.Temporary).Select(t => t.Path), StringComparer.OrdinalIgnoreCase);
170
@@ -201,7 +175,7 @@ namespace WixToolset.Core
175
176 var uniqueFolders = new SortedSet<string>(StringComparer.OrdinalIgnoreCase)
177 {
204 - this.IntermediateFolder
178 + intermediateFolder
179 };
180
181 // Clean up temp files.
@@ -209,7 +183,7 @@ namespace WixToolset.Core
183 {
184 try
185 {
212 - this.SplitUniqueFolders(tempPath, uniqueFolders);
186 + this.SplitUniqueFolders(intermediateFolder, tempPath, uniqueFolders);
187
188 File.Delete(tempPath);
189 }
@@ -231,15 +205,15 @@ namespace WixToolset.Core
205 }
206 }
207
234 - private void SplitUniqueFolders(string tempPath, SortedSet<string> uniqueFolders)
208 + private void SplitUniqueFolders(string intermediateFolder, string tempPath, SortedSet<string> uniqueFolders)
209 {
236 - if (tempPath.StartsWith(this.IntermediateFolder, StringComparison.OrdinalIgnoreCase))
210 + if (tempPath.StartsWith(intermediateFolder, StringComparison.OrdinalIgnoreCase))
211 {
238 - var folder = Path.GetDirectoryName(tempPath).Substring(this.IntermediateFolder.Length);
212 + var folder = Path.GetDirectoryName(tempPath).Substring(intermediateFolder.Length);
213
214 var parts = folder.Split(new[] { '\\', '/' }, StringSplitOptions.RemoveEmptyEntries);
215
242 - folder = this.IntermediateFolder;
216 + folder = intermediateFolder;
217
218 foreach (var part in parts)
219 {
src/WixToolset.Core/Librarian.cs
+19 -33
@@ -8,14 +8,13 @@ namespace WixToolset.Core
8 using WixToolset.Core.Bind;
9 using WixToolset.Core.Link;
10 using WixToolset.Data;
11 - using WixToolset.Extensibility;
11 using WixToolset.Extensibility.Data;
12 using WixToolset.Extensibility.Services;
13
14 /// <summary>
15 /// Core librarian tool.
16 /// </summary>
18 - internal class Librarian
17 + internal class Librarian : ILibrarian
18 {
19 internal Librarian(IServiceProvider serviceProvider)
20 {
@@ -28,42 +27,29 @@ namespace WixToolset.Core
27
28 private IMessaging Messaging { get; }
29
31 - private ILibraryContext Context { get; set; }
32 -
33 - public bool BindFiles { get; set; }
34 -
35 - public IEnumerable<BindPath> BindPaths { get; set; }
36 -
37 - public IEnumerable<Localization> Localizations { get; set; }
38 -
39 - public IEnumerable<Intermediate> Intermediates { get; set; }
40 -
30 /// <summary>
31 /// Create a library by combining several intermediates (objects).
32 /// </summary>
33 /// <param name="sections">The sections to combine into a library.</param>
34 /// <returns>Returns the new library.</returns>
46 - public Intermediate Execute()
35 + public Intermediate Combine(ILibraryContext context)
36 {
48 - this.Context = new LibraryContext(this.ServiceProvider);
49 - this.Context.BindFiles = this.BindFiles;
50 - this.Context.BindPaths = this.BindPaths;
51 - this.Context.Extensions = this.ServiceProvider.GetService<IExtensionManager>().Create<ILibrarianExtension>();
52 - this.Context.Localizations = this.Localizations;
53 - this.Context.LibraryId = Convert.ToBase64String(Guid.NewGuid().ToByteArray()).TrimEnd('=').Replace('+', '.').Replace('/', '_');
54 - this.Context.Intermediates = this.Intermediates;
55 -
56 - foreach (var extension in this.Context.Extensions)
37 + if (String.IsNullOrEmpty(context.LibraryId))
38 + {
39 + context.LibraryId = Convert.ToBase64String(Guid.NewGuid().ToByteArray()).TrimEnd('=').Replace('+', '.').Replace('/', '_');
40 + }
41 +
42 + foreach (var extension in context.Extensions)
43 {
58 - extension.PreCombine(this.Context);
44 + extension.PreCombine(context);
45 }
46
47 Intermediate library = null;
48 try
49 {
64 - var sections = this.Context.Intermediates.SelectMany(i => i.Sections).ToList();
50 + var sections = context.Intermediates.SelectMany(i => i.Sections).ToList();
51
66 - var collate = new CollateLocalizationsCommand(this.Messaging, this.Context.Localizations);
52 + var collate = new CollateLocalizationsCommand(this.Messaging, context.Localizations);
53 var localizationsByCulture = collate.Execute();
54
55 if (this.Messaging.EncounteredError)
@@ -71,20 +57,20 @@ namespace WixToolset.Core
57 return null;
58 }
59
74 - var embedFilePaths = this.ResolveFilePathsToEmbed(sections);
60 + var embedFilePaths = this.ResolveFilePathsToEmbed(context, sections);
61
62 foreach (var section in sections)
63 {
78 - section.LibraryId = this.Context.LibraryId;
64 + section.LibraryId = context.LibraryId;
65 }
66
81 - library = new Intermediate(this.Context.LibraryId, sections, localizationsByCulture, embedFilePaths);
67 + library = new Intermediate(context.LibraryId, sections, localizationsByCulture, embedFilePaths);
68
69 this.Validate(library);
70 }
71 finally
72 {
87 - foreach (var extension in this.Context.Extensions)
73 + foreach (var extension in context.Extensions)
74 {
75 extension.PostCombine(library);
76 }
@@ -99,7 +85,7 @@ namespace WixToolset.Core
85 /// <param name="library">Library to validate.</param>
86 private void Validate(Intermediate library)
87 {
102 - FindEntrySectionAndLoadSymbolsCommand find = new FindEntrySectionAndLoadSymbolsCommand(this.Messaging, library.Sections);
88 + var find = new FindEntrySectionAndLoadSymbolsCommand(this.Messaging, library.Sections);
89 find.Execute();
90
91 // TODO: Consider bringing this sort of verification back.
@@ -113,16 +99,16 @@ namespace WixToolset.Core
99 // }
100 }
101
116 - private List<string> ResolveFilePathsToEmbed(IEnumerable<IntermediateSection> sections)
102 + private List<string> ResolveFilePathsToEmbed(ILibraryContext context, IEnumerable<IntermediateSection> sections)
103 {
104 var embedFilePaths = new List<string>();
105
106 // Resolve paths to files that are to be embedded in the library.
121 - if (this.Context.BindFiles)
107 + if (context.BindFiles)
108 {
109 var variableResolver = new WixVariableResolver(this.Messaging);
110
125 - var fileResolver = new FileResolver(this.Context.BindPaths, this.Context.Extensions);
111 + var fileResolver = new FileResolver(context.BindPaths, context.Extensions);
112
113 foreach (var tuple in sections.SelectMany(s => s.Tuples))
114 {
src/WixToolset.Core/Linker.cs
+214 -227
@@ -11,19 +11,18 @@ namespace WixToolset.Core
11 using WixToolset.Core.Link;
12 using WixToolset.Data;
13 using WixToolset.Data.Tuples;
14 - using WixToolset.Extensibility;
14 using WixToolset.Extensibility.Data;
15 using WixToolset.Extensibility.Services;
16
17 /// <summary>
18 /// Linker core of the WiX toolset.
19 /// </summary>
21 - internal class Linker
20 + internal class Linker : ILinker
21 {
22 private static readonly char[] colonCharacter = ":".ToCharArray();
23 private static readonly string emptyGuid = Guid.Empty.ToString("B");
24
26 - private bool sectionIdOnRows;
25 + private readonly bool sectionIdOnRows;
26
27 /// <summary>
28 /// Creates a linker.
@@ -53,32 +52,20 @@ namespace WixToolset.Core
52 /// <value>The option to show pedantic messages.</value>
53 public bool ShowPedanticMessages { get; set; }
54
56 - public OutputType OutputType { get; set; }
57 -
58 - public IEnumerable<Intermediate> Intermediates { get; set; }
59 -
60 - public IEnumerable<Intermediate> Libraries { get; set; }
61 -
62 - public ITupleDefinitionCreator TupleDefinitionCreator { get; set; }
63 -
55 /// <summary>
56 /// Links a collection of sections into an output.
57 /// </summary>
58 /// <param name="inputs">The collection of sections to link together.</param>
59 /// <param name="expectedOutputType">Expected output type, based on output file extension provided to the linker.</param>
60 /// <returns>Output object from the linking.</returns>
70 - public Intermediate Execute()
61 + public Intermediate Link(ILinkContext context)
62 {
72 - var extensionManager = this.ServiceProvider.GetService<IExtensionManager>();
73 -
74 - var creator = this.TupleDefinitionCreator ?? this.ServiceProvider.GetService<ITupleDefinitionCreator>();
63 + this.Context = context;
64
76 - this.Context = this.ServiceProvider.GetService<ILinkContext>();
77 - this.Context.Extensions = extensionManager.Create<ILinkerExtension>();
78 - this.Context.ExtensionData = extensionManager.Create<IExtensionData>();
79 - this.Context.ExpectedOutputType = this.OutputType;
80 - this.Context.Intermediates = this.Intermediates.Concat(this.Libraries).ToList();
81 - this.Context.TupleDefinitionCreator = creator;
65 + if (this.Context.TupleDefinitionCreator == null)
66 + {
67 + this.Context.TupleDefinitionCreator = this.ServiceProvider.GetService<ITupleDefinitionCreator>();
68 + }
69
70 foreach (var extension in this.Context.Extensions)
71 {
@@ -117,7 +104,7 @@ namespace WixToolset.Core
104 Hashtable generatedShortFileNames = new Hashtable();
105 #endif
106
120 - Hashtable multipleFeatureComponents = new Hashtable();
107 + var multipleFeatureComponents = new Hashtable();
108
109 var wixVariables = new Dictionary<string, WixVariableTuple>();
110
@@ -238,7 +225,7 @@ namespace WixToolset.Core
225 sectionCount++;
226
227 var sectionId = section.Id;
241 - if (null == sectionId && this.sectionIdOnRows)
228 + if (null == sectionId && sectionIdOnRows)
229 {
230 sectionId = "wix.section." + sectionCount.ToString(CultureInfo.InvariantCulture);
231 }
@@ -256,12 +243,12 @@ namespace WixToolset.Core
243 break;
244 #endif
245
259 - case TupleDefinitionType.Class:
260 - if (SectionType.Product == resolvedSection.Type)
261 - {
262 - this.ResolveFeatures(tuple, 2, 11, componentsToFeatures, multipleFeatureComponents);
263 - }
264 - break;
246 + case TupleDefinitionType.Class:
247 + if (SectionType.Product == resolvedSection.Type)
248 + {
249 + this.ResolveFeatures(tuple, 2, 11, componentsToFeatures, multipleFeatureComponents);
250 + }
251 + break;
252
253 #if MOVE_TO_BACKEND
254 case "CustomAction":
@@ -315,12 +302,12 @@ namespace WixToolset.Core
302 }
303 break;
304 #endif
318 - case TupleDefinitionType.Extension:
319 - if (SectionType.Product == resolvedSection.Type)
320 - {
321 - this.ResolveFeatures(tuple, 1, 4, componentsToFeatures, multipleFeatureComponents);
322 - }
323 - break;
305 + case TupleDefinitionType.Extension:
306 + if (SectionType.Product == resolvedSection.Type)
307 + {
308 + this.ResolveFeatures(tuple, 1, 4, componentsToFeatures, multipleFeatureComponents);
309 + }
310 + break;
311
312 #if MOVE_TO_BACKEND
313 case TupleDefinitionType.ModuleSubstitution:
@@ -332,12 +319,12 @@ namespace WixToolset.Core
319 break;
320 #endif
321
335 - case TupleDefinitionType.MsiAssembly:
336 - if (SectionType.Product == resolvedSection.Type)
337 - {
338 - this.ResolveFeatures(tuple, 0, 1, componentsToFeatures, multipleFeatureComponents);
339 - }
340 - break;
322 + case TupleDefinitionType.MsiAssembly:
323 + if (SectionType.Product == resolvedSection.Type)
324 + {
325 + this.ResolveFeatures(tuple, 0, 1, componentsToFeatures, multipleFeatureComponents);
326 + }
327 + break;
328
329 #if MOVE_TO_BACKEND
330 case "ProgId":
@@ -359,26 +346,26 @@ namespace WixToolset.Core
346 break;
347 #endif
348
362 - case TupleDefinitionType.PublishComponent:
363 - if (SectionType.Product == resolvedSection.Type)
364 - {
365 - this.ResolveFeatures(tuple, 2, 4, componentsToFeatures, multipleFeatureComponents);
366 - }
367 - break;
349 + case TupleDefinitionType.PublishComponent:
350 + if (SectionType.Product == resolvedSection.Type)
351 + {
352 + this.ResolveFeatures(tuple, 2, 4, componentsToFeatures, multipleFeatureComponents);
353 + }
354 + break;
355
369 - case TupleDefinitionType.Shortcut:
370 - if (SectionType.Product == resolvedSection.Type)
371 - {
372 - this.ResolveFeatures(tuple, 3, 4, componentsToFeatures, multipleFeatureComponents);
373 - }
374 - break;
356 + case TupleDefinitionType.Shortcut:
357 + if (SectionType.Product == resolvedSection.Type)
358 + {
359 + this.ResolveFeatures(tuple, 3, 4, componentsToFeatures, multipleFeatureComponents);
360 + }
361 + break;
362
376 - case TupleDefinitionType.TypeLib:
377 - if (SectionType.Product == resolvedSection.Type)
378 - {
379 - this.ResolveFeatures(tuple, 2, 6, componentsToFeatures, multipleFeatureComponents);
380 - }
381 - break;
363 + case TupleDefinitionType.TypeLib:
364 + if (SectionType.Product == resolvedSection.Type)
365 + {
366 + this.ResolveFeatures(tuple, 2, 6, componentsToFeatures, multipleFeatureComponents);
367 + }
368 + break;
369
370 #if SOLVE_CUSTOM_TABLE
371 case "WixCustomTable":
@@ -396,9 +383,9 @@ namespace WixToolset.Core
383 break;
384 #endif
385
399 - case TupleDefinitionType.WixEnsureTable:
400 - ensureTableRows.Add(tuple);
401 - break;
386 + case TupleDefinitionType.WixEnsureTable:
387 + ensureTableRows.Add(tuple);
388 + break;
389
390
391 #if MOVE_TO_BACKEND
@@ -421,45 +408,45 @@ namespace WixToolset.Core
408 break;
409 #endif
410
424 - case TupleDefinitionType.WixMerge:
425 - if (SectionType.Product == resolvedSection.Type)
426 - {
427 - this.ResolveFeatures(tuple, 0, 7, modulesToFeatures, null);
428 - }
429 - break;
411 + case TupleDefinitionType.WixMerge:
412 + if (SectionType.Product == resolvedSection.Type)
413 + {
414 + this.ResolveFeatures(tuple, 0, 7, modulesToFeatures, null);
415 + }
416 + break;
417
431 - case TupleDefinitionType.WixComplexReference:
432 - copyTuple = false;
433 - break;
418 + case TupleDefinitionType.WixComplexReference:
419 + copyTuple = false;
420 + break;
421
435 - case TupleDefinitionType.WixSimpleReference:
436 - copyTuple = false;
437 - break;
422 + case TupleDefinitionType.WixSimpleReference:
423 + copyTuple = false;
424 + break;
425
439 - case TupleDefinitionType.WixVariable:
440 - // check for colliding values and collect the wix variable rows
441 - {
442 - var row = (WixVariableTuple)tuple;
426 + case TupleDefinitionType.WixVariable:
427 + // check for colliding values and collect the wix variable rows
428 + {
429 + var row = (WixVariableTuple)tuple;
430
444 - if (wixVariables.TryGetValue(row.WixVariable, out var collidingRow))
445 - {
446 - if (collidingRow.Overridable && !row.Overridable)
447 - {
448 - wixVariables[row.WixVariable] = row;
449 - }
450 - else if (!row.Overridable || (collidingRow.Overridable && row.Overridable))
451 - {
452 - this.OnMessage(ErrorMessages.WixVariableCollision(row.SourceLineNumbers, row.WixVariable));
453 - }
454 - }
455 - else
456 - {
457 - wixVariables.Add(row.WixVariable, row);
458 - }
431 + if (wixVariables.TryGetValue(row.WixVariable, out var collidingRow))
432 + {
433 + if (collidingRow.Overridable && !row.Overridable)
434 + {
435 + wixVariables[row.WixVariable] = row;
436 + }
437 + else if (!row.Overridable || (collidingRow.Overridable && row.Overridable))
438 + {
439 + this.OnMessage(ErrorMessages.WixVariableCollision(row.SourceLineNumbers, row.WixVariable));
440 }
441 + }
442 + else
443 + {
444 + wixVariables.Add(row.WixVariable, row);
445 + }
446 + }
447
461 - copyTuple = false;
462 - break;
448 + copyTuple = false;
449 + break;
450 }
451
452 if (copyTuple)
@@ -624,7 +611,7 @@ namespace WixToolset.Core
611 #endif
612
613 //correct the section Id in FeatureComponents table
627 - if (this.sectionIdOnRows)
614 + if (sectionIdOnRows)
615 {
616 //var componentSectionIds = new Dictionary<string, string>();
617
@@ -1152,7 +1139,7 @@ namespace WixToolset.Core
1139 /// <param name="modulesToFeatures">Module to feature complex references.</param>
1140 private void ProcessComplexReferences(IntermediateSection resolvedSection, IEnumerable<IntermediateSection> sections, ISet<string> referencedComponents, ConnectToFeatureCollection componentsToFeatures, ConnectToFeatureCollection featuresToFeatures, ConnectToFeatureCollection modulesToFeatures)
1141 {
1155 - Hashtable componentsToModules = new Hashtable();
1142 + var componentsToModules = new Hashtable();
1143
1144 foreach (var section in sections)
1145 {
@@ -1163,154 +1150,154 @@ namespace WixToolset.Core
1150 ConnectToFeature connection;
1151 switch (wixComplexReferenceRow.ParentType)
1152 {
1166 - case ComplexReferenceParentType.Feature:
1167 - switch (wixComplexReferenceRow.ChildType)
1153 + case ComplexReferenceParentType.Feature:
1154 + switch (wixComplexReferenceRow.ChildType)
1155 + {
1156 + case ComplexReferenceChildType.Component:
1157 + connection = componentsToFeatures[wixComplexReferenceRow.Child];
1158 + if (null == connection)
1159 {
1169 - case ComplexReferenceChildType.Component:
1170 - connection = componentsToFeatures[wixComplexReferenceRow.Child];
1171 - if (null == connection)
1172 - {
1173 - componentsToFeatures.Add(new ConnectToFeature(section, wixComplexReferenceRow.Child, wixComplexReferenceRow.Parent, wixComplexReferenceRow.IsPrimary));
1174 - }
1175 - else if (wixComplexReferenceRow.IsPrimary)
1176 - {
1177 - if (connection.IsExplicitPrimaryFeature)
1178 - {
1179 - this.OnMessage(ErrorMessages.MultiplePrimaryReferences(wixComplexReferenceRow.SourceLineNumbers, wixComplexReferenceRow.ChildType.ToString(), wixComplexReferenceRow.Child, wixComplexReferenceRow.ParentType.ToString(), wixComplexReferenceRow.Parent, (null != connection.PrimaryFeature ? "Feature" : "Product"), connection.PrimaryFeature ?? resolvedSection.Id));
1180 - continue;
1181 - }
1182 - else
1183 - {
1184 - connection.ConnectFeatures.Add(connection.PrimaryFeature); // move the guessed primary feature to the list of connects
1185 - connection.PrimaryFeature = wixComplexReferenceRow.Parent; // set the new primary feature
1186 - connection.IsExplicitPrimaryFeature = true; // and make sure we remember that we set it so we can fail if we try to set it again
1187 - }
1188 - }
1189 - else
1190 - {
1191 - connection.ConnectFeatures.Add(wixComplexReferenceRow.Parent);
1192 - }
1193 -
1194 - // add a row to the FeatureComponents table
1195 - var featureComponent = new FeatureComponentsTuple();
1196 - featureComponent.Feature_ = wixComplexReferenceRow.Parent;
1197 - featureComponent.Component_ = wixComplexReferenceRow.Child;
1160 + componentsToFeatures.Add(new ConnectToFeature(section, wixComplexReferenceRow.Child, wixComplexReferenceRow.Parent, wixComplexReferenceRow.IsPrimary));
1161 + }
1162 + else if (wixComplexReferenceRow.IsPrimary)
1163 + {
1164 + if (connection.IsExplicitPrimaryFeature)
1165 + {
1166 + this.OnMessage(ErrorMessages.MultiplePrimaryReferences(wixComplexReferenceRow.SourceLineNumbers, wixComplexReferenceRow.ChildType.ToString(), wixComplexReferenceRow.Child, wixComplexReferenceRow.ParentType.ToString(), wixComplexReferenceRow.Parent, (null != connection.PrimaryFeature ? "Feature" : "Product"), connection.PrimaryFeature ?? resolvedSection.Id));
1167 + continue;
1168 + }
1169 + else
1170 + {
1171 + connection.ConnectFeatures.Add(connection.PrimaryFeature); // move the guessed primary feature to the list of connects
1172 + connection.PrimaryFeature = wixComplexReferenceRow.Parent; // set the new primary feature
1173 + connection.IsExplicitPrimaryFeature = true; // and make sure we remember that we set it so we can fail if we try to set it again
1174 + }
1175 + }
1176 + else
1177 + {
1178 + connection.ConnectFeatures.Add(wixComplexReferenceRow.Parent);
1179 + }
1180
1199 - featureComponents.Add(featureComponent);
1181 + // add a row to the FeatureComponents table
1182 + var featureComponent = new FeatureComponentsTuple();
1183 + featureComponent.Feature_ = wixComplexReferenceRow.Parent;
1184 + featureComponent.Component_ = wixComplexReferenceRow.Child;
1185
1201 - // index the component for finding orphaned records
1202 - var symbolName = String.Concat("Component:", wixComplexReferenceRow.Child);
1203 - referencedComponents.Add(symbolName);
1186 + featureComponents.Add(featureComponent);
1187
1205 - break;
1188 + // index the component for finding orphaned records
1189 + var symbolName = String.Concat("Component:", wixComplexReferenceRow.Child);
1190 + referencedComponents.Add(symbolName);
1191
1207 - case ComplexReferenceChildType.Feature:
1208 - connection = featuresToFeatures[wixComplexReferenceRow.Child];
1209 - if (null != connection)
1210 - {
1211 - this.OnMessage(ErrorMessages.MultiplePrimaryReferences(wixComplexReferenceRow.SourceLineNumbers, wixComplexReferenceRow.ChildType.ToString(), wixComplexReferenceRow.Child, wixComplexReferenceRow.ParentType.ToString(), wixComplexReferenceRow.Parent, (null != connection.PrimaryFeature ? "Feature" : "Product"), (null != connection.PrimaryFeature ? connection.PrimaryFeature : resolvedSection.Id)));
1212 - continue;
1213 - }
1192 + break;
1193
1215 - featuresToFeatures.Add(new ConnectToFeature(section, wixComplexReferenceRow.Child, wixComplexReferenceRow.Parent, wixComplexReferenceRow.IsPrimary));
1216 - break;
1194 + case ComplexReferenceChildType.Feature:
1195 + connection = featuresToFeatures[wixComplexReferenceRow.Child];
1196 + if (null != connection)
1197 + {
1198 + this.OnMessage(ErrorMessages.MultiplePrimaryReferences(wixComplexReferenceRow.SourceLineNumbers, wixComplexReferenceRow.ChildType.ToString(), wixComplexReferenceRow.Child, wixComplexReferenceRow.ParentType.ToString(), wixComplexReferenceRow.Parent, (null != connection.PrimaryFeature ? "Feature" : "Product"), (null != connection.PrimaryFeature ? connection.PrimaryFeature : resolvedSection.Id)));
1199 + continue;
1200 + }
1201
1218 - case ComplexReferenceChildType.Module:
1219 - connection = modulesToFeatures[wixComplexReferenceRow.Child];
1220 - if (null == connection)
1221 - {
1222 - modulesToFeatures.Add(new ConnectToFeature(section, wixComplexReferenceRow.Child, wixComplexReferenceRow.Parent, wixComplexReferenceRow.IsPrimary));
1223 - }
1224 - else if (wixComplexReferenceRow.IsPrimary)
1225 - {
1226 - if (connection.IsExplicitPrimaryFeature)
1227 - {
1228 - this.OnMessage(ErrorMessages.MultiplePrimaryReferences(wixComplexReferenceRow.SourceLineNumbers, wixComplexReferenceRow.ChildType.ToString(), wixComplexReferenceRow.Child, wixComplexReferenceRow.ParentType.ToString(), wixComplexReferenceRow.Parent, (null != connection.PrimaryFeature ? "Feature" : "Product"), (null != connection.PrimaryFeature ? connection.PrimaryFeature : resolvedSection.Id)));
1229 - continue;
1230 - }
1231 - else
1232 - {
1233 - connection.ConnectFeatures.Add(connection.PrimaryFeature); // move the guessed primary feature to the list of connects
1234 - connection.PrimaryFeature = wixComplexReferenceRow.Parent; // set the new primary feature
1235 - connection.IsExplicitPrimaryFeature = true; // and make sure we remember that we set it so we can fail if we try to set it again
1236 - }
1237 - }
1238 - else
1239 - {
1240 - connection.ConnectFeatures.Add(wixComplexReferenceRow.Parent);
1241 - }
1242 - break;
1202 + featuresToFeatures.Add(new ConnectToFeature(section, wixComplexReferenceRow.Child, wixComplexReferenceRow.Parent, wixComplexReferenceRow.IsPrimary));
1203 + break;
1204
1244 - default:
1245 - throw new InvalidOperationException(String.Format(CultureInfo.CurrentUICulture, WixStrings.EXP_UnexpectedComplexReferenceChildType, Enum.GetName(typeof(ComplexReferenceChildType), wixComplexReferenceRow.ChildType)));
1205 + case ComplexReferenceChildType.Module:
1206 + connection = modulesToFeatures[wixComplexReferenceRow.Child];
1207 + if (null == connection)
1208 + {
1209 + modulesToFeatures.Add(new ConnectToFeature(section, wixComplexReferenceRow.Child, wixComplexReferenceRow.Parent, wixComplexReferenceRow.IsPrimary));
1210 + }
1211 + else if (wixComplexReferenceRow.IsPrimary)
1212 + {
1213 + if (connection.IsExplicitPrimaryFeature)
1214 + {
1215 + this.OnMessage(ErrorMessages.MultiplePrimaryReferences(wixComplexReferenceRow.SourceLineNumbers, wixComplexReferenceRow.ChildType.ToString(), wixComplexReferenceRow.Child, wixComplexReferenceRow.ParentType.ToString(), wixComplexReferenceRow.Parent, (null != connection.PrimaryFeature ? "Feature" : "Product"), (null != connection.PrimaryFeature ? connection.PrimaryFeature : resolvedSection.Id)));
1216 + continue;
1217 + }
1218 + else
1219 + {
1220 + connection.ConnectFeatures.Add(connection.PrimaryFeature); // move the guessed primary feature to the list of connects
1221 + connection.PrimaryFeature = wixComplexReferenceRow.Parent; // set the new primary feature
1222 + connection.IsExplicitPrimaryFeature = true; // and make sure we remember that we set it so we can fail if we try to set it again
1223 + }
1224 + }
1225 + else
1226 + {
1227 + connection.ConnectFeatures.Add(wixComplexReferenceRow.Parent);
1228 }
1229 break;
1230
1249 - case ComplexReferenceParentType.Module:
1250 - switch (wixComplexReferenceRow.ChildType)
1251 - {
1252 - case ComplexReferenceChildType.Component:
1253 - if (componentsToModules.ContainsKey(wixComplexReferenceRow.Child))
1254 - {
1255 - this.OnMessage(ErrorMessages.ComponentReferencedTwice(wixComplexReferenceRow.SourceLineNumbers, wixComplexReferenceRow.Child));
1256 - continue;
1257 - }
1258 - else
1259 - {
1260 - componentsToModules.Add(wixComplexReferenceRow.Child, wixComplexReferenceRow); // should always be new
1231 + default:
1232 + throw new InvalidOperationException(String.Format(CultureInfo.CurrentUICulture, WixStrings.EXP_UnexpectedComplexReferenceChildType, Enum.GetName(typeof(ComplexReferenceChildType), wixComplexReferenceRow.ChildType)));
1233 + }
1234 + break;
1235
1262 - // add a row to the ModuleComponents table
1263 - var moduleComponent = new ModuleComponentsTuple();
1264 - moduleComponent.Component = wixComplexReferenceRow.Child;
1265 - moduleComponent.ModuleID = wixComplexReferenceRow.Parent;
1266 - moduleComponent.Language = Convert.ToInt32(wixComplexReferenceRow.ParentLanguage);
1267 - }
1236 + case ComplexReferenceParentType.Module:
1237 + switch (wixComplexReferenceRow.ChildType)
1238 + {
1239 + case ComplexReferenceChildType.Component:
1240 + if (componentsToModules.ContainsKey(wixComplexReferenceRow.Child))
1241 + {
1242 + this.OnMessage(ErrorMessages.ComponentReferencedTwice(wixComplexReferenceRow.SourceLineNumbers, wixComplexReferenceRow.Child));
1243 + continue;
1244 + }
1245 + else
1246 + {
1247 + componentsToModules.Add(wixComplexReferenceRow.Child, wixComplexReferenceRow); // should always be new
1248
1269 - // index the component for finding orphaned records
1270 - string componentSymbolName = String.Concat("Component:", wixComplexReferenceRow.Child);
1271 - referencedComponents.Add(componentSymbolName);
1249 + // add a row to the ModuleComponents table
1250 + var moduleComponent = new ModuleComponentsTuple();
1251 + moduleComponent.Component = wixComplexReferenceRow.Child;
1252 + moduleComponent.ModuleID = wixComplexReferenceRow.Parent;
1253 + moduleComponent.Language = Convert.ToInt32(wixComplexReferenceRow.ParentLanguage);
1254 + }
1255
1273 - break;
1256 + // index the component for finding orphaned records
1257 + var componentSymbolName = String.Concat("Component:", wixComplexReferenceRow.Child);
1258 + referencedComponents.Add(componentSymbolName);
1259
1275 - default:
1276 - throw new InvalidOperationException(String.Format(CultureInfo.CurrentUICulture, WixStrings.EXP_UnexpectedComplexReferenceChildType, Enum.GetName(typeof(ComplexReferenceChildType), wixComplexReferenceRow.ChildType)));
1277 - }
1260 break;
1261
1280 - case ComplexReferenceParentType.Patch:
1281 - switch (wixComplexReferenceRow.ChildType)
1282 - {
1283 - case ComplexReferenceChildType.PatchFamily:
1284 - case ComplexReferenceChildType.PatchFamilyGroup:
1285 - break;
1262 + default:
1263 + throw new InvalidOperationException(String.Format(CultureInfo.CurrentUICulture, WixStrings.EXP_UnexpectedComplexReferenceChildType, Enum.GetName(typeof(ComplexReferenceChildType), wixComplexReferenceRow.ChildType)));
1264 + }
1265 + break;
1266
1287 - default:
1288 - throw new InvalidOperationException(String.Format(CultureInfo.CurrentUICulture, WixStrings.EXP_UnexpectedComplexReferenceChildType, Enum.GetName(typeof(ComplexReferenceChildType), wixComplexReferenceRow.ChildType)));
1289 - }
1267 + case ComplexReferenceParentType.Patch:
1268 + switch (wixComplexReferenceRow.ChildType)
1269 + {
1270 + case ComplexReferenceChildType.PatchFamily:
1271 + case ComplexReferenceChildType.PatchFamilyGroup:
1272 break;
1273
1292 - case ComplexReferenceParentType.Product:
1293 - switch (wixComplexReferenceRow.ChildType)
1294 - {
1295 - case ComplexReferenceChildType.Feature:
1296 - connection = featuresToFeatures[wixComplexReferenceRow.Child];
1297 - if (null != connection)
1298 - {
1299 - this.OnMessage(ErrorMessages.MultiplePrimaryReferences(wixComplexReferenceRow.SourceLineNumbers, wixComplexReferenceRow.ChildType.ToString(), wixComplexReferenceRow.Child, wixComplexReferenceRow.ParentType.ToString(), wixComplexReferenceRow.Parent, (null != connection.PrimaryFeature ? "Feature" : "Product"), (null != connection.PrimaryFeature ? connection.PrimaryFeature : resolvedSection.Id)));
1300 - continue;
1301 - }
1302 -
1303 - featuresToFeatures.Add(new ConnectToFeature(section, wixComplexReferenceRow.Child, null, wixComplexReferenceRow.IsPrimary));
1304 - break;
1274 + default:
1275 + throw new InvalidOperationException(String.Format(CultureInfo.CurrentUICulture, WixStrings.EXP_UnexpectedComplexReferenceChildType, Enum.GetName(typeof(ComplexReferenceChildType), wixComplexReferenceRow.ChildType)));
1276 + }
1277 + break;
1278
1306 - default:
1307 - throw new InvalidOperationException(String.Format(CultureInfo.CurrentUICulture, WixStrings.EXP_UnexpectedComplexReferenceChildType, Enum.GetName(typeof(ComplexReferenceChildType), wixComplexReferenceRow.ChildType)));
1279 + case ComplexReferenceParentType.Product:
1280 + switch (wixComplexReferenceRow.ChildType)
1281 + {
1282 + case ComplexReferenceChildType.Feature:
1283 + connection = featuresToFeatures[wixComplexReferenceRow.Child];
1284 + if (null != connection)
1285 + {
1286 + this.OnMessage(ErrorMessages.MultiplePrimaryReferences(wixComplexReferenceRow.SourceLineNumbers, wixComplexReferenceRow.ChildType.ToString(), wixComplexReferenceRow.Child, wixComplexReferenceRow.ParentType.ToString(), wixComplexReferenceRow.Parent, (null != connection.PrimaryFeature ? "Feature" : "Product"), (null != connection.PrimaryFeature ? connection.PrimaryFeature : resolvedSection.Id)));
1287 + continue;
1288 }
1289 +
1290 + featuresToFeatures.Add(new ConnectToFeature(section, wixComplexReferenceRow.Child, null, wixComplexReferenceRow.IsPrimary));
1291 break;
1292
1293 default:
1312 - // Note: Groups have been processed before getting here so they are not handled by any case above.
1313 - throw new InvalidOperationException(String.Format(CultureInfo.CurrentUICulture, WixStrings.EXP_UnexpectedComplexReferenceChildType, Enum.GetName(typeof(ComplexReferenceParentType), wixComplexReferenceRow.ParentType)));
1294 + throw new InvalidOperationException(String.Format(CultureInfo.CurrentUICulture, WixStrings.EXP_UnexpectedComplexReferenceChildType, Enum.GetName(typeof(ComplexReferenceChildType), wixComplexReferenceRow.ChildType)));
1295 + }
1296 + break;
1297 +
1298 + default:
1299 + // Note: Groups have been processed before getting here so they are not handled by any case above.
1300 + throw new InvalidOperationException(String.Format(CultureInfo.CurrentUICulture, WixStrings.EXP_UnexpectedComplexReferenceChildType, Enum.GetName(typeof(ComplexReferenceParentType), wixComplexReferenceRow.ParentType)));
1301 }
1302 }
1303
@@ -1341,7 +1328,7 @@ namespace WixToolset.Core
1328 foreach (var section in sections)
1329 {
1330 // Count down because we'll sometimes remove items from the list.
1344 - for (int i = section.Tuples.Count - 1; i >= 0; --i)
1331 + for (var i = section.Tuples.Count - 1; i >= 0; --i)
1332 {
1333 // Only process the "grouping parents" such as FeatureGroup, ComponentGroup, Feature,
1334 // and Module. Non-grouping complex references are simple and
@@ -1354,7 +1341,7 @@ namespace WixToolset.Core
1341 ComplexReferenceParentType.PatchFamilyGroup == wixComplexReferenceRow.ParentType ||
1342 ComplexReferenceParentType.Product == wixComplexReferenceRow.ParentType))
1343 {
1357 - var parentTypeAndId = CombineTypeAndId(wixComplexReferenceRow.ParentType, wixComplexReferenceRow.Parent);
1344 + var parentTypeAndId = this.CombineTypeAndId(wixComplexReferenceRow.ParentType, wixComplexReferenceRow.Parent);
1345
1346 // Group all complex references with a common parent
1347 // together so we can find them quickly while processing in
@@ -1402,7 +1389,7 @@ namespace WixToolset.Core
1389 // complex references should all be flattened.
1390 var keys = parentGroupsNeedingProcessing.Keys.ToList();
1391
1405 - foreach (string key in keys)
1392 + foreach (var key in keys)
1393 {
1394 if (parentGroupsNeedingProcessing.ContainsKey(key))
1395 {
@@ -1466,14 +1453,14 @@ namespace WixToolset.Core
1453 foreach (var wixComplexReferenceRow in referencesToParent)
1454 {
1455 Debug.Assert(ComplexReferenceParentType.ComponentGroup == wixComplexReferenceRow.ParentType || ComplexReferenceParentType.FeatureGroup == wixComplexReferenceRow.ParentType || ComplexReferenceParentType.Feature == wixComplexReferenceRow.ParentType || ComplexReferenceParentType.Module == wixComplexReferenceRow.ParentType || ComplexReferenceParentType.Product == wixComplexReferenceRow.ParentType || ComplexReferenceParentType.PatchFamilyGroup == wixComplexReferenceRow.ParentType || ComplexReferenceParentType.Patch == wixComplexReferenceRow.ParentType);
1469 - Debug.Assert(parentTypeAndId == CombineTypeAndId(wixComplexReferenceRow.ParentType, wixComplexReferenceRow.Parent));
1456 + Debug.Assert(parentTypeAndId == this.CombineTypeAndId(wixComplexReferenceRow.ParentType, wixComplexReferenceRow.Parent));
1457
1458 // We are only interested processing when the child is a group.
1459 if ((ComplexReferenceChildType.ComponentGroup == wixComplexReferenceRow.ChildType) ||
1460 (ComplexReferenceChildType.FeatureGroup == wixComplexReferenceRow.ChildType) ||
1461 (ComplexReferenceChildType.PatchFamilyGroup == wixComplexReferenceRow.ChildType))
1462 {
1476 - string childTypeAndId = CombineTypeAndId(wixComplexReferenceRow.ChildType, wixComplexReferenceRow.Child);
1463 + var childTypeAndId = this.CombineTypeAndId(wixComplexReferenceRow.ChildType, wixComplexReferenceRow.Child);
1464 if (loopDetector.Contains(childTypeAndId))
1465 {
1466 // Create a comma delimited list of the references that participate in the
@@ -1531,7 +1518,7 @@ namespace WixToolset.Core
1518 // duplicate complex references that occurred during the merge.
1519 referencesToParent.AddRange(allNewChildComplexReferences);
1520 referencesToParent.Sort(ComplexReferenceComparision);
1534 - for (int i = referencesToParent.Count - 1; i >= 0; --i)
1521 + for (var i = referencesToParent.Count - 1; i >= 0; --i)
1522 {
1523 var wixComplexReferenceRow = referencesToParent[i];
1524
@@ -1716,7 +1703,7 @@ namespace WixToolset.Core
1703
1704 if (emptyGuid == featureId)
1705 {
1719 - ConnectToFeature connection = connectToFeatures[connectionId];
1706 + var connection = connectToFeatures[connectionId];
1707
1708 if (null == connection)
1709 {
src/WixToolset.Core/PreprocessContext.cs
+2 -2
@@ -21,9 +21,9 @@ namespace WixToolset.Core
21
22 public Platform Platform { get; set; }
23
24 - public IList<string> IncludeSearchPaths { get; set; }
24 + public IEnumerable<string> IncludeSearchPaths { get; set; }
25
26 - public string SourceFile { get; set; }
26 + public string SourcePath { get; set; }
27
28 public IDictionary<string, string> Variables { get; set; }
29
src/WixToolset.Core/Preprocessor.cs
+287 -310
@@ -6,7 +6,6 @@ namespace WixToolset.Core
6 using System.Collections.Generic;
7 using System.Globalization;
8 using System.IO;
9 - using System.Linq;
9 using System.Text;
10 using System.Text.RegularExpressions;
11 using System.Xml;
@@ -20,7 +19,7 @@ namespace WixToolset.Core
19 /// <summary>
20 /// Preprocessor object
21 /// </summary>
23 - internal class Preprocessor
22 + internal class Preprocessor : IPreprocessor
23 {
24 private static readonly Regex DefineRegex = new Regex(@"^\s*(?<varName>.+?)\s*(=\s*(?<varValue>.+?)\s*)?$", RegexOptions.Compiled | RegexOptions.Singleline | RegexOptions.ExplicitCapture);
25 private static readonly Regex PragmaRegex = new Regex(@"^\s*(?<pragmaName>.+?)(?<pragmaValue>[\s\(].+?)?$", RegexOptions.Compiled | RegexOptions.Singleline | RegexOptions.ExplicitCapture);
@@ -30,6 +29,7 @@ namespace WixToolset.Core
29 ValidationFlags = System.Xml.Schema.XmlSchemaValidationFlags.None,
30 XmlResolver = null,
31 };
32 +
33 private static readonly XmlReaderSettings FragmentXmlReaderSettings = new XmlReaderSettings()
34 {
35 ConformanceLevel = ConformanceLevel.Fragment,
@@ -44,14 +44,6 @@ namespace WixToolset.Core
44 this.Messaging = this.ServiceProvider.GetService<IMessaging>();
45 }
46
47 - public IEnumerable<string> IncludeSearchPaths { get; set; }
48 -
49 - public Platform Platform { get; set; }
50 -
51 - public string SourcePath { get; set; }
52 -
53 - public IDictionary<string, string> Variables { get; set; }
54 -
47 private IServiceProvider ServiceProvider { get; }
48
49 private IMessaging Messaging { get; }
@@ -108,19 +100,21 @@ namespace WixToolset.Core
100 /// </summary>
101 /// <param name="context">The preprocessing context.</param>
102 /// <returns>XDocument with the postprocessed data.</returns>
111 - public XDocument Execute()
103 + public XDocument Preprocess(IPreprocessContext context)
104 {
113 - this.Context = this.CreateContext();
105 + this.Context = context;
106 + this.Context.CurrentSourceLineNumber = new SourceLineNumber(context.SourcePath);
107 + this.Context.Variables = this.Context.Variables == null ? new Dictionary<string, string>() : new Dictionary<string, string>(this.Context.Variables);
108
109 this.PreProcess();
110
111 XDocument document;
118 - using (XmlReader reader = XmlReader.Create(this.Context.SourceFile, DocumentXmlReaderSettings))
112 + using (var reader = XmlReader.Create(this.Context.SourcePath, DocumentXmlReaderSettings))
113 {
114 document = this.Process(reader);
115 }
116
123 - return PostProcess(document);
117 + return this.PostProcess(document);
118 }
119
120 /// <summary>
@@ -129,21 +123,23 @@ namespace WixToolset.Core
123 /// <param name="context">The preprocessing context.</param>
124 /// <param name="reader">XmlReader to processing the context.</param>
125 /// <returns>XDocument with the postprocessed data.</returns>
132 - public XDocument Execute(XmlReader reader)
126 + public XDocument Preprocess(IPreprocessContext context, XmlReader reader)
127 {
134 - if (String.IsNullOrEmpty(this.SourcePath) && !String.IsNullOrEmpty(reader.BaseURI))
128 + if (String.IsNullOrEmpty(context.SourcePath) && !String.IsNullOrEmpty(reader.BaseURI))
129 {
130 var uri = new Uri(reader.BaseURI);
137 - this.SourcePath = uri.AbsolutePath;
131 + context.SourcePath = uri.AbsolutePath;
132 }
133
140 - this.Context = this.CreateContext();
134 + this.Context = context;
135 + this.Context.CurrentSourceLineNumber = new SourceLineNumber(context.SourcePath);
136 + this.Context.Variables = this.Context.Variables == null ? new Dictionary<string, string>() : new Dictionary<string, string>(this.Context.Variables);
137
138 this.PreProcess();
139
140 var document = this.Process(reader);
141
146 - return PostProcess(document);
142 + return this.PostProcess(document);
143 }
144
145 /// <summary>
@@ -160,13 +156,13 @@ namespace WixToolset.Core
156 this.CurrentFileStack.Push(this.Helper.GetVariableValue(this.Context, "sys", "SOURCEFILEDIR"));
157
158 // Process the reader into the output.
163 - XDocument output = new XDocument();
159 + var output = new XDocument();
160 try
161 {
162 this.PreprocessReader(false, reader, output, 0);
163
164 // Fire event with post-processed document.
169 - this.ProcessedStream?.Invoke(this, new ProcessedStreamEventArgs(this.Context.SourceFile, output));
165 + this.ProcessedStream?.Invoke(this, new ProcessedStreamEventArgs(this.Context.SourcePath, output));
166 }
167 catch (XmlException e)
168 {
@@ -221,8 +217,8 @@ namespace WixToolset.Core
217 return false;
218 }
219
224 - int numQuotes = 0;
225 - int tmpIndex = 0;
220 + var numQuotes = 0;
221 + var tmpIndex = 0;
222 while (-1 != (tmpIndex = expression.IndexOf('\"', tmpIndex, index - tmpIndex)))
223 {
224 numQuotes++;
@@ -250,26 +246,26 @@ namespace WixToolset.Core
246 expression = expression.ToUpperInvariant();
247 switch (operation)
248 {
253 - case PreprocessorOperation.Not:
254 - if (expression.StartsWith("NOT ", StringComparison.Ordinal) || expression.StartsWith("NOT(", StringComparison.Ordinal))
255 - {
256 - return true;
257 - }
258 - break;
259 - case PreprocessorOperation.And:
260 - if (expression.StartsWith("AND ", StringComparison.Ordinal) || expression.StartsWith("AND(", StringComparison.Ordinal))
261 - {
262 - return true;
263 - }
264 - break;
265 - case PreprocessorOperation.Or:
266 - if (expression.StartsWith("OR ", StringComparison.Ordinal) || expression.StartsWith("OR(", StringComparison.Ordinal))
267 - {
268 - return true;
269 - }
270 - break;
271 - default:
272 - break;
249 + case PreprocessorOperation.Not:
250 + if (expression.StartsWith("NOT ", StringComparison.Ordinal) || expression.StartsWith("NOT(", StringComparison.Ordinal))
251 + {
252 + return true;
253 + }
254 + break;
255 + case PreprocessorOperation.And:
256 + if (expression.StartsWith("AND ", StringComparison.Ordinal) || expression.StartsWith("AND(", StringComparison.Ordinal))
257 + {
258 + return true;
259 + }
260 + break;
261 + case PreprocessorOperation.Or:
262 + if (expression.StartsWith("OR ", StringComparison.Ordinal) || expression.StartsWith("OR(", StringComparison.Ordinal))
263 + {
264 + return true;
265 + }
266 + break;
267 + default:
268 + break;
269 }
270 return false;
271 }
@@ -283,11 +279,11 @@ namespace WixToolset.Core
279 /// <param name="offset">Original offset for the line numbers being processed.</param>
280 private void PreprocessReader(bool include, XmlReader reader, XContainer container, int offset)
281 {
286 - XContainer currentContainer = container;
287 - Stack<XContainer> containerStack = new Stack<XContainer>();
282 + var currentContainer = container;
283 + var containerStack = new Stack<XContainer>();
284
289 - IfContext ifContext = new IfContext(true, true, IfState.Unknown); // start by assuming we want to keep the nodes in the source code
290 - Stack<IfContext> ifStack = new Stack<IfContext>();
285 + var ifContext = new IfContext(true, true, IfState.Unknown); // start by assuming we want to keep the nodes in the source code
286 + var ifStack = new Stack<IfContext>();
287
288 // process the reader into the writer
289 while (reader.Read())
@@ -300,102 +296,102 @@ namespace WixToolset.Core
296 // check for changes in conditional processing
297 if (XmlNodeType.ProcessingInstruction == reader.NodeType)
298 {
303 - bool ignore = false;
299 + var ignore = false;
300 string name = null;
301
302 switch (reader.LocalName)
303 {
308 - case "if":
309 - ifStack.Push(ifContext);
310 - if (ifContext.IsTrue)
311 - {
312 - ifContext = new IfContext(ifContext.IsTrue & ifContext.Active, this.EvaluateExpression(reader.Value), IfState.If);
313 - }
314 - else // Use a default IfContext object so we don't try to evaluate the expression if the context isn't true
315 - {
316 - ifContext = new IfContext();
317 - }
318 - ignore = true;
319 - break;
304 + case "if":
305 + ifStack.Push(ifContext);
306 + if (ifContext.IsTrue)
307 + {
308 + ifContext = new IfContext(ifContext.IsTrue & ifContext.Active, this.EvaluateExpression(reader.Value), IfState.If);
309 + }
310 + else // Use a default IfContext object so we don't try to evaluate the expression if the context isn't true
311 + {
312 + ifContext = new IfContext();
313 + }
314 + ignore = true;
315 + break;
316
321 - case "ifdef":
322 - ifStack.Push(ifContext);
323 - name = reader.Value.Trim();
324 - if (ifContext.IsTrue)
325 - {
326 - ifContext = new IfContext(ifContext.IsTrue & ifContext.Active, (null != this.Helper.GetVariableValue(this.Context, name, true)), IfState.If);
327 - }
328 - else // Use a default IfContext object so we don't try to evaluate the expression if the context isn't true
329 - {
330 - ifContext = new IfContext();
331 - }
332 - ignore = true;
333 - this.IfDef?.Invoke(this, new IfDefEventArgs(sourceLineNumbers, true, ifContext.IsTrue, name));
334 - break;
317 + case "ifdef":
318 + ifStack.Push(ifContext);
319 + name = reader.Value.Trim();
320 + if (ifContext.IsTrue)
321 + {
322 + ifContext = new IfContext(ifContext.IsTrue & ifContext.Active, (null != this.Helper.GetVariableValue(this.Context, name, true)), IfState.If);
323 + }
324 + else // Use a default IfContext object so we don't try to evaluate the expression if the context isn't true
325 + {
326 + ifContext = new IfContext();
327 + }
328 + ignore = true;
329 + this.IfDef?.Invoke(this, new IfDefEventArgs(sourceLineNumbers, true, ifContext.IsTrue, name));
330 + break;
331
336 - case "ifndef":
337 - ifStack.Push(ifContext);
338 - name = reader.Value.Trim();
339 - if (ifContext.IsTrue)
340 - {
341 - ifContext = new IfContext(ifContext.IsTrue & ifContext.Active, (null == this.Helper.GetVariableValue(this.Context, name, true)), IfState.If);
342 - }
343 - else // Use a default IfContext object so we don't try to evaluate the expression if the context isn't true
344 - {
345 - ifContext = new IfContext();
346 - }
347 - ignore = true;
348 - this.IfDef?.Invoke(this, new IfDefEventArgs(sourceLineNumbers, false, !ifContext.IsTrue, name));
349 - break;
332 + case "ifndef":
333 + ifStack.Push(ifContext);
334 + name = reader.Value.Trim();
335 + if (ifContext.IsTrue)
336 + {
337 + ifContext = new IfContext(ifContext.IsTrue & ifContext.Active, (null == this.Helper.GetVariableValue(this.Context, name, true)), IfState.If);
338 + }
339 + else // Use a default IfContext object so we don't try to evaluate the expression if the context isn't true
340 + {
341 + ifContext = new IfContext();
342 + }
343 + ignore = true;
344 + this.IfDef?.Invoke(this, new IfDefEventArgs(sourceLineNumbers, false, !ifContext.IsTrue, name));
345 + break;
346
351 - case "elseif":
352 - if (0 == ifStack.Count)
353 - {
354 - throw new WixException(ErrorMessages.UnmatchedPreprocessorInstruction(sourceLineNumbers, "if", "elseif"));
355 - }
347 + case "elseif":
348 + if (0 == ifStack.Count)
349 + {
350 + throw new WixException(ErrorMessages.UnmatchedPreprocessorInstruction(sourceLineNumbers, "if", "elseif"));
351 + }
352
357 - if (IfState.If != ifContext.IfState && IfState.ElseIf != ifContext.IfState)
358 - {
359 - throw new WixException(ErrorMessages.UnmatchedPreprocessorInstruction(sourceLineNumbers, "if", "elseif"));
360 - }
353 + if (IfState.If != ifContext.IfState && IfState.ElseIf != ifContext.IfState)
354 + {
355 + throw new WixException(ErrorMessages.UnmatchedPreprocessorInstruction(sourceLineNumbers, "if", "elseif"));
356 + }
357
362 - ifContext.IfState = IfState.ElseIf; // we're now in an elseif
363 - if (!ifContext.WasEverTrue) // if we've never evaluated the if context to true, then we can try this test
364 - {
365 - ifContext.IsTrue = this.EvaluateExpression(reader.Value);
366 - }
367 - else if (ifContext.IsTrue)
368 - {
369 - ifContext.IsTrue = false;
370 - }
371 - ignore = true;
372 - break;
358 + ifContext.IfState = IfState.ElseIf; // we're now in an elseif
359 + if (!ifContext.WasEverTrue) // if we've never evaluated the if context to true, then we can try this test
360 + {
361 + ifContext.IsTrue = this.EvaluateExpression(reader.Value);
362 + }
363 + else if (ifContext.IsTrue)
364 + {
365 + ifContext.IsTrue = false;
366 + }
367 + ignore = true;
368 + break;
369
374 - case "else":
375 - if (0 == ifStack.Count)
376 - {
377 - throw new WixException(ErrorMessages.UnmatchedPreprocessorInstruction(sourceLineNumbers, "if", "else"));
378 - }
370 + case "else":
371 + if (0 == ifStack.Count)
372 + {
373 + throw new WixException(ErrorMessages.UnmatchedPreprocessorInstruction(sourceLineNumbers, "if", "else"));
374 + }
375
380 - if (IfState.If != ifContext.IfState && IfState.ElseIf != ifContext.IfState)
381 - {
382 - throw new WixException(ErrorMessages.UnmatchedPreprocessorInstruction(sourceLineNumbers, "if", "else"));
383 - }
376 + if (IfState.If != ifContext.IfState && IfState.ElseIf != ifContext.IfState)
377 + {
378 + throw new WixException(ErrorMessages.UnmatchedPreprocessorInstruction(sourceLineNumbers, "if", "else"));
379 + }
380
385 - ifContext.IfState = IfState.Else; // we're now in an else
386 - ifContext.IsTrue = !ifContext.WasEverTrue; // if we were never true, we can be true now
387 - ignore = true;
388 - break;
381 + ifContext.IfState = IfState.Else; // we're now in an else
382 + ifContext.IsTrue = !ifContext.WasEverTrue; // if we were never true, we can be true now
383 + ignore = true;
384 + break;
385
390 - case "endif":
391 - if (0 == ifStack.Count)
392 - {
393 - throw new WixException(ErrorMessages.UnmatchedPreprocessorInstruction(sourceLineNumbers, "if", "endif"));
394 - }
386 + case "endif":
387 + if (0 == ifStack.Count)
388 + {
389 + throw new WixException(ErrorMessages.UnmatchedPreprocessorInstruction(sourceLineNumbers, "if", "endif"));
390 + }
391
396 - ifContext = (IfContext)ifStack.Pop();
397 - ignore = true;
398 - break;
392 + ifContext = ifStack.Pop();
393 + ignore = true;
394 + break;
395 }
396
397 if (ignore) // ignore this node since we just handled it above
@@ -411,134 +407,134 @@ namespace WixToolset.Core
407
408 switch (reader.NodeType)
409 {
414 - case XmlNodeType.XmlDeclaration:
415 - XDocument document = currentContainer as XDocument;
416 - if (null != document)
410 + case XmlNodeType.XmlDeclaration:
411 + var document = currentContainer as XDocument;
412 + if (null != document)
413 + {
414 + document.Declaration = new XDeclaration(null, null, null);
415 + while (reader.MoveToNextAttribute())
416 {
418 - document.Declaration = new XDeclaration(null, null, null);
419 - while (reader.MoveToNextAttribute())
417 + switch (reader.LocalName)
418 {
421 - switch (reader.LocalName)
422 - {
423 - case "version":
424 - document.Declaration.Version = reader.Value;
425 - break;
426 -
427 - case "encoding":
428 - document.Declaration.Encoding = reader.Value;
429 - break;
430 -
431 - case "standalone":
432 - document.Declaration.Standalone = reader.Value;
433 - break;
434 - }
435 - }
436 -
437 - }
438 - //else
439 - //{
440 - // display an error? Can this happen?
441 - //}
442 - break;
443 -
444 - case XmlNodeType.ProcessingInstruction:
445 - switch (reader.LocalName)
446 - {
447 - case "define":
448 - this.PreprocessDefine(reader.Value);
449 - break;
450 -
451 - case "error":
452 - this.PreprocessError(reader.Value);
453 - break;
454 -
455 - case "warning":
456 - this.PreprocessWarning(reader.Value);
419 + case "version":
420 + document.Declaration.Version = reader.Value;
421 break;
422
459 - case "undef":
460 - this.PreprocessUndef(reader.Value);
423 + case "encoding":
424 + document.Declaration.Encoding = reader.Value;
425 break;
426
463 - case "include":
464 - this.UpdateCurrentLineNumber(reader, offset);
465 - this.PreprocessInclude(reader.Value, currentContainer);
427 + case "standalone":
428 + document.Declaration.Standalone = reader.Value;
429 break;
430 + }
431 + }
432
468 - case "foreach":
469 - this.PreprocessForeach(reader, currentContainer, offset);
470 - break;
471 -
472 - case "endforeach": // endforeach is handled in PreprocessForeach, so seeing it here is an error
473 - throw new WixException(ErrorMessages.UnmatchedPreprocessorInstruction(sourceLineNumbers, "foreach", "endforeach"));
474 -
475 - case "pragma":
476 - this.PreprocessPragma(reader.Value, currentContainer);
477 - break;
433 + }
434 + //else
435 + //{
436 + // display an error? Can this happen?
437 + //}
438 + break;
439
479 - default:
480 - // unknown processing instructions are currently ignored
481 - break;
482 - }
440 + case XmlNodeType.ProcessingInstruction:
441 + switch (reader.LocalName)
442 + {
443 + case "define":
444 + this.PreprocessDefine(reader.Value);
445 break;
446
485 - case XmlNodeType.Element:
486 - if (0 < this.IncludeNextStack.Count && this.IncludeNextStack.Peek())
487 - {
488 - if ("Include" != reader.LocalName)
489 - {
490 - this.Messaging.Write(ErrorMessages.InvalidDocumentElement(sourceLineNumbers, reader.Name, "include", "Include"));
491 - }
447 + case "error":
448 + this.PreprocessError(reader.Value);
449 + break;
450
493 - this.IncludeNextStack.Pop();
494 - this.IncludeNextStack.Push(false);
495 - break;
496 - }
451 + case "warning":
452 + this.PreprocessWarning(reader.Value);
453 + break;
454
498 - var empty = reader.IsEmptyElement;
499 - var ns = XNamespace.Get(reader.NamespaceURI);
500 - var element = new XElement(ns + reader.LocalName);
501 - currentContainer.Add(element);
455 + case "undef":
456 + this.PreprocessUndef(reader.Value);
457 + break;
458
459 + case "include":
460 this.UpdateCurrentLineNumber(reader, offset);
504 - element.AddAnnotation(sourceLineNumbers);
461 + this.PreprocessInclude(reader.Value, currentContainer);
462 + break;
463
506 - while (reader.MoveToNextAttribute())
507 - {
508 - var value = this.Helper.PreprocessString(this.Context, reader.Value);
464 + case "foreach":
465 + this.PreprocessForeach(reader, currentContainer, offset);
466 + break;
467
510 - var attribNamespace = XNamespace.Get(reader.NamespaceURI);
511 - attribNamespace = XNamespace.Xmlns == attribNamespace && reader.LocalName.Equals("xmlns") ? XNamespace.None : attribNamespace;
468 + case "endforeach": // endforeach is handled in PreprocessForeach, so seeing it here is an error
469 + throw new WixException(ErrorMessages.UnmatchedPreprocessorInstruction(sourceLineNumbers, "foreach", "endforeach"));
470
513 - element.Add(new XAttribute(attribNamespace + reader.LocalName, value));
514 - }
471 + case "pragma":
472 + this.PreprocessPragma(reader.Value, currentContainer);
473 + break;
474
516 - if (!empty)
517 - {
518 - containerStack.Push(currentContainer);
519 - currentContainer = element;
520 - }
475 + default:
476 + // unknown processing instructions are currently ignored
477 break;
478 + }
479 + break;
480
523 - case XmlNodeType.EndElement:
524 - if (0 < reader.Depth || !include)
481 + case XmlNodeType.Element:
482 + if (0 < this.IncludeNextStack.Count && this.IncludeNextStack.Peek())
483 + {
484 + if ("Include" != reader.LocalName)
485 {
526 - currentContainer = containerStack.Pop();
486 + this.Messaging.Write(ErrorMessages.InvalidDocumentElement(sourceLineNumbers, reader.Name, "include", "Include"));
487 }
528 - break;
488
530 - case XmlNodeType.Text:
531 - string postprocessedText = this.Helper.PreprocessString(this.Context, reader.Value);
532 - currentContainer.Add(postprocessedText);
489 + this.IncludeNextStack.Pop();
490 + this.IncludeNextStack.Push(false);
491 break;
492 + }
493
535 - case XmlNodeType.CDATA:
536 - string postprocessedValue = this.Helper.PreprocessString(this.Context, reader.Value);
537 - currentContainer.Add(new XCData(postprocessedValue));
538 - break;
494 + var empty = reader.IsEmptyElement;
495 + var ns = XNamespace.Get(reader.NamespaceURI);
496 + var element = new XElement(ns + reader.LocalName);
497 + currentContainer.Add(element);
498
540 - default:
541 - break;
499 + this.UpdateCurrentLineNumber(reader, offset);
500 + element.AddAnnotation(sourceLineNumbers);
501 +
502 + while (reader.MoveToNextAttribute())
503 + {
504 + var value = this.Helper.PreprocessString(this.Context, reader.Value);
505 +
506 + var attribNamespace = XNamespace.Get(reader.NamespaceURI);
507 + attribNamespace = XNamespace.Xmlns == attribNamespace && reader.LocalName.Equals("xmlns") ? XNamespace.None : attribNamespace;
508 +
509 + element.Add(new XAttribute(attribNamespace + reader.LocalName, value));
510 + }
511 +
512 + if (!empty)
513 + {
514 + containerStack.Push(currentContainer);
515 + currentContainer = element;
516 + }
517 + break;
518 +
519 + case XmlNodeType.EndElement:
520 + if (0 < reader.Depth || !include)
521 + {
522 + currentContainer = containerStack.Pop();
523 + }
524 + break;
525 +
526 + case XmlNodeType.Text:
527 + var postprocessedText = this.Helper.PreprocessString(this.Context, reader.Value);
528 + currentContainer.Add(postprocessedText);
529 + break;
530 +
531 + case XmlNodeType.CDATA:
532 + var postprocessedValue = this.Helper.PreprocessString(this.Context, reader.Value);
533 + currentContainer.Add(new XCData(postprocessedValue));
534 + break;
535 +
536 + default:
537 + break;
538 }
539 }
540
@@ -652,7 +648,7 @@ namespace WixToolset.Core
648 throw new WixException(ErrorMessages.FileNotFound(sourceLineNumbers, includePath, "include"));
649 }
650
655 - using (XmlReader reader = XmlReader.Create(includeFile, DocumentXmlReaderSettings))
651 + using (var reader = XmlReader.Create(includeFile, DocumentXmlReaderSettings))
652 {
653 this.PushInclude(includeFile);
654
@@ -689,13 +685,13 @@ namespace WixToolset.Core
685 }
686
687 // parse out the variable name
692 - string varName = reader.Value.Substring(0, indexOfInToken).Trim();
693 - string varValuesString = reader.Value.Substring(indexOfInToken + 4).Trim();
688 + var varName = reader.Value.Substring(0, indexOfInToken).Trim();
689 + var varValuesString = reader.Value.Substring(indexOfInToken + 4).Trim();
690
691 // preprocess the variable values string because it might be a variable itself
692 varValuesString = this.Helper.PreprocessString(this.Context, varValuesString);
693
698 - string[] varValues = varValuesString.Split(';');
694 + var varValues = varValuesString.Split(';');
695
696 // go through all the empty strings
697 while (reader.Read() && XmlNodeType.Whitespace == reader.NodeType)
@@ -703,44 +699,44 @@ namespace WixToolset.Core
699 }
700
701 // get the offset of this xml fragment (for some reason its always off by 1)
706 - IXmlLineInfo lineInfoReader = reader as IXmlLineInfo;
702 + var lineInfoReader = reader as IXmlLineInfo;
703 if (null != lineInfoReader)
704 {
705 offset += lineInfoReader.LineNumber - 1;
706 }
707
712 - XmlTextReader textReader = reader as XmlTextReader;
708 + var textReader = reader as XmlTextReader;
709 // dump the xml to a string (maintaining whitespace if possible)
710 if (null != textReader)
711 {
712 textReader.WhitespaceHandling = WhitespaceHandling.All;
713 }
714
719 - StringBuilder fragmentBuilder = new StringBuilder();
720 - int nestedForeachCount = 1;
715 + var fragmentBuilder = new StringBuilder();
716 + var nestedForeachCount = 1;
717 while (nestedForeachCount != 0)
718 {
719 if (reader.NodeType == XmlNodeType.ProcessingInstruction)
720 {
721 switch (reader.LocalName)
722 {
727 - case "foreach":
728 - ++nestedForeachCount;
729 - // Output the foreach statement
730 - fragmentBuilder.AppendFormat("<?foreach {0}?>", reader.Value);
731 - break;
723 + case "foreach":
724 + ++nestedForeachCount;
725 + // Output the foreach statement
726 + fragmentBuilder.AppendFormat("<?foreach {0}?>", reader.Value);
727 + break;
728
733 - case "endforeach":
734 - --nestedForeachCount;
735 - if (0 != nestedForeachCount)
736 - {
737 - fragmentBuilder.Append("<?endforeach ?>");
738 - }
739 - break;
729 + case "endforeach":
730 + --nestedForeachCount;
731 + if (0 != nestedForeachCount)
732 + {
733 + fragmentBuilder.Append("<?endforeach ?>");
734 + }
735 + break;
736
741 - default:
742 - fragmentBuilder.AppendFormat("<?{0} {1}?>", reader.LocalName, reader.Value);
743 - break;
737 + default:
738 + fragmentBuilder.AppendFormat("<?{0} {1}?>", reader.LocalName, reader.Value);
739 + break;
740 }
741 }
742 else if (reader.NodeType == XmlNodeType.Element)
@@ -764,7 +760,7 @@ namespace WixToolset.Core
760 using (var fragmentStream = new MemoryStream(Encoding.UTF8.GetBytes(fragmentBuilder.ToString())))
761 {
762 // process each iteration, updating the variable's value each time
767 - foreach (string varValue in varValues)
763 + foreach (var varValue in varValues)
764 {
765 using (var loopReader = XmlReader.Create(fragmentStream, FragmentXmlReaderSettings))
766 {
@@ -801,7 +797,7 @@ namespace WixToolset.Core
797 }
798
799 // resolve other variables in the pragma argument(s)
804 - string pragmaArgs = this.Helper.PreprocessString(this.Context, match.Groups["pragmaValue"].Value).Trim();
800 + var pragmaArgs = this.Helper.PreprocessString(this.Context, match.Groups["pragmaValue"].Value).Trim();
801
802 try
803 {
@@ -823,7 +819,7 @@ namespace WixToolset.Core
819 private string GetNextToken(string originalExpression, ref string expression, out bool stringLiteral)
820 {
821 stringLiteral = false;
826 - string token = String.Empty;
822 + var token = String.Empty;
823 expression = expression.Trim();
824 if (0 == expression.Length)
825 {
@@ -833,7 +829,7 @@ namespace WixToolset.Core
829 if (expression.StartsWith("\"", StringComparison.Ordinal))
830 {
831 stringLiteral = true;
836 - int endingQuotes = expression.IndexOf('\"', 1);
832 + var endingQuotes = expression.IndexOf('\"', 1);
833 if (-1 == endingQuotes)
834 {
835 throw new WixException(ErrorMessages.UnmatchedQuotesInExpression(this.Context.CurrentSourceLineNumber, originalExpression));
@@ -848,9 +844,9 @@ namespace WixToolset.Core
844 else if (expression.StartsWith("$(", StringComparison.Ordinal))
845 {
846 // Find the ending paren of the expression
851 - int endingParen = -1;
852 - int openedCount = 1;
853 - for (int i = 2; i < expression.Length; i++)
847 + var endingParen = -1;
848 + var openedCount = 1;
849 + for (var i = 2; i < expression.Length; i++)
850 {
851 if ('(' == expression[i])
852 {
@@ -881,14 +877,14 @@ namespace WixToolset.Core
877 {
878 // Cut the token off at the next equal, space, inequality operator,
879 // or end of string, whichever comes first
884 - int space = expression.IndexOf(" ", StringComparison.Ordinal);
885 - int equals = expression.IndexOf("=", StringComparison.Ordinal);
886 - int lessThan = expression.IndexOf("<", StringComparison.Ordinal);
887 - int lessThanEquals = expression.IndexOf("<=", StringComparison.Ordinal);
888 - int greaterThan = expression.IndexOf(">", StringComparison.Ordinal);
889 - int greaterThanEquals = expression.IndexOf(">=", StringComparison.Ordinal);
890 - int notEquals = expression.IndexOf("!=", StringComparison.Ordinal);
891 - int equalsNoCase = expression.IndexOf("~=", StringComparison.Ordinal);
880 + var space = expression.IndexOf(" ", StringComparison.Ordinal);
881 + var equals = expression.IndexOf("=", StringComparison.Ordinal);
882 + var lessThan = expression.IndexOf("<", StringComparison.Ordinal);
883 + var lessThanEquals = expression.IndexOf("<=", StringComparison.Ordinal);
884 + var greaterThan = expression.IndexOf(">", StringComparison.Ordinal);
885 + var greaterThanEquals = expression.IndexOf(">=", StringComparison.Ordinal);
886 + var notEquals = expression.IndexOf("!=", StringComparison.Ordinal);
887 + var equalsNoCase = expression.IndexOf("~=", StringComparison.Ordinal);
888 int closingIndex;
889
890 if (space == -1)
@@ -970,7 +966,7 @@ namespace WixToolset.Core
966 {
967 // By default it's a literal and will only be evaluated if it
968 // matches the variable format
973 - string varValue = variable;
969 + var varValue = variable;
970
971 if (variable.StartsWith("$(", StringComparison.Ordinal))
972 {
@@ -1008,8 +1004,7 @@ namespace WixToolset.Core
1004 /// <param name="rightValue">Right side value from expression.</param>
1005 private void GetNameValuePair(string originalExpression, ref string expression, out string leftValue, out string operation, out string rightValue)
1006 {
1011 - bool stringLiteral;
1012 - leftValue = this.GetNextToken(originalExpression, ref expression, out stringLiteral);
1007 + leftValue = this.GetNextToken(originalExpression, ref expression, out var stringLiteral);
1008
1009 // If it wasn't a string literal, evaluate it
1010 if (!stringLiteral)
@@ -1060,14 +1055,10 @@ namespace WixToolset.Core
1055 private bool EvaluateAtomicExpression(string originalExpression, ref string expression)
1056 {
1057 // Quick test to see if the first token is a variable
1063 - bool startsWithVariable = expression.StartsWith("$(", StringComparison.Ordinal);
1064 -
1065 - string leftValue;
1066 - string rightValue;
1067 - string operation;
1068 - this.GetNameValuePair(originalExpression, ref expression, out leftValue, out operation, out rightValue);
1058 + var startsWithVariable = expression.StartsWith("$(", StringComparison.Ordinal);
1059 + this.GetNameValuePair(originalExpression, ref expression, out var leftValue, out var operation, out var rightValue);
1060
1070 - bool expressionValue = false;
1061 + var expressionValue = false;
1062
1063 // If the variables don't exist, they were evaluated to null
1064 if (null == leftValue || null == rightValue)
@@ -1168,8 +1159,8 @@ namespace WixToolset.Core
1159 }
1160
1161 // search for the end of the expression with the matching paren
1171 - int openParenIndex = 0;
1172 - int closeParenIndex = 1;
1162 + var openParenIndex = 0;
1163 + var closeParenIndex = 1;
1164 while (openParenIndex != -1 && openParenIndex < closeParenIndex)
1165 {
1166 closeParenIndex = expression.IndexOf(')', closeParenIndex);
@@ -1214,17 +1205,17 @@ namespace WixToolset.Core
1205 {
1206 switch (operation)
1207 {
1217 - case PreprocessorOperation.And:
1218 - currentValue = currentValue && prevResult;
1219 - break;
1220 - case PreprocessorOperation.Or:
1221 - currentValue = currentValue || prevResult;
1222 - break;
1223 - case PreprocessorOperation.Not:
1224 - currentValue = !currentValue;
1225 - break;
1226 - default:
1227 - throw new WixException(ErrorMessages.UnexpectedPreprocessorOperator(this.Context.CurrentSourceLineNumber, operation.ToString()));
1208 + case PreprocessorOperation.And:
1209 + currentValue = currentValue && prevResult;
1210 + break;
1211 + case PreprocessorOperation.Or:
1212 + currentValue = currentValue || prevResult;
1213 + break;
1214 + case PreprocessorOperation.Not:
1215 + currentValue = !currentValue;
1216 + break;
1217 + default:
1218 + throw new WixException(ErrorMessages.UnexpectedPreprocessorOperator(this.Context.CurrentSourceLineNumber, operation.ToString()));
1219 }
1220 }
1221
@@ -1235,7 +1226,7 @@ namespace WixToolset.Core
1226 /// <returns>Boolean result of expression.</returns>
1227 private bool EvaluateExpression(string expression)
1228 {
1238 - string tmpExpression = expression;
1229 + var tmpExpression = expression;
1230 return this.EvaluateExpressionRecurse(expression, ref tmpExpression, PreprocessorOperation.And, true);
1231 }
1232
@@ -1269,7 +1260,7 @@ namespace WixToolset.Core
1260 /// <returns>Boolean to indicate if the expression is true or false</returns>
1261 private bool EvaluateExpressionRecurse(string originalExpression, ref string expression, PreprocessorOperation prevResultOperation, bool prevResult)
1262 {
1272 - bool expressionValue = false;
1263 + var expressionValue = false;
1264 expression = expression.Trim();
1265 if (expression.Length == 0)
1266 {
@@ -1279,8 +1270,7 @@ namespace WixToolset.Core
1270 // If the expression starts with parenthesis, evaluate it
1271 if (expression.IndexOf('(') == 0)
1272 {
1282 - int endSubExpressionIndex;
1283 - string subExpression = this.GetParenthesisExpression(originalExpression, expression, out endSubExpressionIndex);
1273 + var subExpression = this.GetParenthesisExpression(originalExpression, expression, out var endSubExpressionIndex);
1274 expressionValue = this.EvaluateExpressionRecurse(originalExpression, ref subExpression, PreprocessorOperation.And, true);
1275
1276 // Now get the rest of the expression that hasn't been evaluated
@@ -1337,10 +1327,10 @@ namespace WixToolset.Core
1327 /// <param name="offset">This is the artificial offset of the line numbers from the reader. Used for the foreach processing.</param>
1328 private void UpdateCurrentLineNumber(XmlReader reader, int offset)
1329 {
1340 - IXmlLineInfo lineInfoReader = reader as IXmlLineInfo;
1330 + var lineInfoReader = reader as IXmlLineInfo;
1331 if (null != lineInfoReader)
1332 {
1343 - int newLine = lineInfoReader.LineNumber + offset;
1333 + var newLine = lineInfoReader.LineNumber + offset;
1334
1335 if (this.Context.CurrentSourceLineNumber.LineNumber != newLine)
1336 {
@@ -1435,19 +1425,6 @@ namespace WixToolset.Core
1425 return finalIncludePath;
1426 }
1427
1438 - private IPreprocessContext CreateContext()
1439 - {
1440 - var context = this.ServiceProvider.GetService<IPreprocessContext>();
1441 - context.Extensions = this.ServiceProvider.GetService<IExtensionManager>().Create<IPreprocessorExtension>();
1442 - context.CurrentSourceLineNumber = new SourceLineNumber(this.SourcePath);
1443 - context.Platform = this.Platform;
1444 - context.IncludeSearchPaths = this.IncludeSearchPaths?.ToList() ?? new List<string>();
1445 - context.SourceFile = this.SourcePath;
1446 - context.Variables = new Dictionary<string, string>(this.Variables);
1447 -
1448 - return context;
1449 - }
1450 -
1428 private void PreProcess()
1429 {
1430 foreach (var extension in this.Context.Extensions)
src/WixToolset.Core/Resolver.cs
+7 -18
@@ -15,7 +15,7 @@ namespace WixToolset.Core
15 /// <summary>
16 /// Resolver for the WiX toolset.
17 /// </summary>
18 - internal class Resolver
18 + internal class Resolver : IResolver
19 {
20 internal Resolver(IServiceProvider serviceProvider)
21 {
@@ -38,21 +38,10 @@ namespace WixToolset.Core
38
39 public IEnumerable<string> FilterCultures { get; set; }
40
41 - public ResolveResult Execute()
41 + public ResolveResult Resolve(IResolveContext context)
42 {
43 - var extensionManager = this.ServiceProvider.GetService<IExtensionManager>();
44 -
45 - var context = this.ServiceProvider.GetService<IResolveContext>();
46 - context.BindPaths = this.BindPaths;
47 - context.Extensions = extensionManager.Create<IResolverExtension>();
48 - context.ExtensionData = extensionManager.Create<IExtensionData>();
49 - context.FilterCultures = this.FilterCultures;
50 - context.IntermediateFolder = this.IntermediateFolder;
51 - context.IntermediateRepresentation = this.IntermediateRepresentation;
52 - context.Localizations = this.Localizations;
53 - context.VariableResolver = new WixVariableResolver(this.Messaging);
54 -
55 - foreach (IResolverExtension extension in context.Extensions)
43 +
44 + foreach (var extension in context.Extensions)
45 {
46 extension.PreResolve(context);
47 }
@@ -64,11 +53,11 @@ namespace WixToolset.Core
53
54 this.LocalizeUI(context);
55
67 - resolveResult = this.Resolve(context);
56 + resolveResult = this.DoResolve(context);
57 }
58 finally
59 {
71 - foreach (IResolverExtension extension in context.Extensions)
60 + foreach (var extension in context.Extensions)
61 {
62 extension.PostResolve(resolveResult);
63 }
@@ -77,7 +66,7 @@ namespace WixToolset.Core
66 return resolveResult;
67 }
68
80 - private ResolveResult Resolve(IResolveContext context)
69 + private ResolveResult DoResolve(IResolveContext context)
70 {
71 var buildingPatch = context.IntermediateRepresentation.Sections.Any(s => s.Type == SectionType.Patch);
72
src/WixToolset.Core/WixToolsetServiceProvider.cs
+11
@@ -32,12 +32,23 @@ namespace WixToolset.Core
32 this.AddService<ICommandLineParser>((provider, singletons) => new CommandLineParser(provider));
33 this.AddService<IPreprocessContext>((provider, singletons) => new PreprocessContext(provider));
34 this.AddService<ICompileContext>((provider, singletons) => new CompileContext(provider));
35 + this.AddService<ILibraryContext>((provider, singletons) => new LibraryContext(provider));
36 this.AddService<ILinkContext>((provider, singletons) => new LinkContext(provider));
37 this.AddService<IResolveContext>((provider, singletons) => new ResolveContext(provider));
38 this.AddService<IBindContext>((provider, singletons) => new BindContext(provider));
39 + this.AddService<IDecompileContext>((provider, singletons) => new DecompileContext(provider));
40 this.AddService<ILayoutContext>((provider, singletons) => new LayoutContext(provider));
41 this.AddService<IInscribeContext>((provider, singletons) => new InscribeContext(provider));
42
43 + this.AddService<IBinder>((provider, singletons) => new Binder(provider));
44 + this.AddService<ICompiler>((provider, singletons) => new Compiler(provider));
45 + this.AddService<IDecompiler>((provider, singletons) => new Decompiler(provider));
46 + this.AddService<ILayoutCreator>((provider, singletons) => new LayoutCreator(provider));
47 + this.AddService<IPreprocessor>((provider, singletons) => new Preprocessor(provider));
48 + this.AddService<ILibrarian>((provider, singletons) => new Librarian(provider));
49 + this.AddService<ILinker>((provider, singletons) => new Linker(provider));
50 + this.AddService<IResolver>((provider, singletons) => new Resolver(provider));
51 +
52 // Internal implementations.
53 this.AddService<ILocalizer>((provider, singletons) => new Localizer(provider));
54 }