diff options
-rw-r--r-- | src/WixToolset.Core/CommandLine/BuildCommand.cs | 6 | ||||
-rw-r--r-- | src/WixToolset.Core/CommandLine/CompileCommand.cs | 6 | ||||
-rw-r--r-- | src/WixToolset.Core/IPreprocessor.cs | 5 | ||||
-rw-r--r-- | src/WixToolset.Core/IncludedFile.cs | 14 | ||||
-rw-r--r-- | src/WixToolset.Core/PreprocessResult.cs | 15 | ||||
-rw-r--r-- | src/WixToolset.Core/Preprocessor.cs | 362 | ||||
-rw-r--r-- | src/WixToolset.Core/WixToolsetServiceProvider.cs | 2 | ||||
-rw-r--r-- | src/test/WixToolsetTest.CoreIntegration/PreprocessorFixture.cs | 33 |
8 files changed, 266 insertions, 177 deletions
diff --git a/src/WixToolset.Core/CommandLine/BuildCommand.cs b/src/WixToolset.Core/CommandLine/BuildCommand.cs index b83aaec4..7e6ddd64 100644 --- a/src/WixToolset.Core/CommandLine/BuildCommand.cs +++ b/src/WixToolset.Core/CommandLine/BuildCommand.cs | |||
@@ -377,18 +377,18 @@ namespace WixToolset.Core.CommandLine | |||
377 | context.SourcePath = sourcePath; | 377 | context.SourcePath = sourcePath; |
378 | context.Variables = preprocessorVariables; | 378 | context.Variables = preprocessorVariables; |
379 | 379 | ||
380 | XDocument document = null; | 380 | IPreprocessResult result = null; |
381 | try | 381 | try |
382 | { | 382 | { |
383 | var preprocessor = this.ServiceProvider.GetService<IPreprocessor>(); | 383 | var preprocessor = this.ServiceProvider.GetService<IPreprocessor>(); |
384 | document = preprocessor.Preprocess(context); | 384 | result = preprocessor.Preprocess(context); |
385 | } | 385 | } |
386 | catch (WixException e) | 386 | catch (WixException e) |
387 | { | 387 | { |
388 | this.Messaging.Write(e.Error); | 388 | this.Messaging.Write(e.Error); |
389 | } | 389 | } |
390 | 390 | ||
391 | return document; | 391 | return result?.Document; |
392 | } | 392 | } |
393 | 393 | ||
394 | private class CommandLine | 394 | private class CommandLine |
diff --git a/src/WixToolset.Core/CommandLine/CompileCommand.cs b/src/WixToolset.Core/CommandLine/CompileCommand.cs index 69e35cab..bc37ee8c 100644 --- a/src/WixToolset.Core/CommandLine/CompileCommand.cs +++ b/src/WixToolset.Core/CommandLine/CompileCommand.cs | |||
@@ -63,11 +63,11 @@ namespace WixToolset.Core.CommandLine | |||
63 | context.SourcePath = sourceFile.SourcePath; | 63 | context.SourcePath = sourceFile.SourcePath; |
64 | context.Variables = this.PreprocessorVariables; | 64 | context.Variables = this.PreprocessorVariables; |
65 | 65 | ||
66 | XDocument document = null; | 66 | IPreprocessResult result = null; |
67 | try | 67 | try |
68 | { | 68 | { |
69 | var preprocessor = this.ServiceProvider.GetService<IPreprocessor>(); | 69 | var preprocessor = this.ServiceProvider.GetService<IPreprocessor>(); |
70 | document = preprocessor.Preprocess(context); | 70 | result = preprocessor.Preprocess(context); |
71 | } | 71 | } |
72 | catch (WixException e) | 72 | catch (WixException e) |
73 | { | 73 | { |
@@ -83,7 +83,7 @@ namespace WixToolset.Core.CommandLine | |||
83 | compileContext.Extensions = this.ExtensionManager.Create<ICompilerExtension>(); | 83 | compileContext.Extensions = this.ExtensionManager.Create<ICompilerExtension>(); |
84 | compileContext.OutputPath = sourceFile.OutputPath; | 84 | compileContext.OutputPath = sourceFile.OutputPath; |
85 | compileContext.Platform = this.Platform; | 85 | compileContext.Platform = this.Platform; |
86 | compileContext.Source = document; | 86 | compileContext.Source = result?.Document; |
87 | 87 | ||
88 | var compiler = this.ServiceProvider.GetService<ICompiler>(); | 88 | var compiler = this.ServiceProvider.GetService<ICompiler>(); |
89 | var intermediate = compiler.Compile(compileContext); | 89 | var intermediate = compiler.Compile(compileContext); |
diff --git a/src/WixToolset.Core/IPreprocessor.cs b/src/WixToolset.Core/IPreprocessor.cs index d892399c..151f8111 100644 --- a/src/WixToolset.Core/IPreprocessor.cs +++ b/src/WixToolset.Core/IPreprocessor.cs | |||
@@ -3,13 +3,12 @@ | |||
3 | namespace WixToolset.Core | 3 | namespace WixToolset.Core |
4 | { | 4 | { |
5 | using System.Xml; | 5 | using System.Xml; |
6 | using System.Xml.Linq; | ||
7 | using WixToolset.Extensibility.Data; | 6 | using WixToolset.Extensibility.Data; |
8 | 7 | ||
9 | public interface IPreprocessor | 8 | public interface IPreprocessor |
10 | { | 9 | { |
11 | XDocument Preprocess(IPreprocessContext context); | 10 | IPreprocessResult Preprocess(IPreprocessContext context); |
12 | 11 | ||
13 | XDocument Preprocess(IPreprocessContext context, XmlReader reader); | 12 | IPreprocessResult Preprocess(IPreprocessContext context, XmlReader reader); |
14 | } | 13 | } |
15 | } | 14 | } |
diff --git a/src/WixToolset.Core/IncludedFile.cs b/src/WixToolset.Core/IncludedFile.cs new file mode 100644 index 00000000..25d51191 --- /dev/null +++ b/src/WixToolset.Core/IncludedFile.cs | |||
@@ -0,0 +1,14 @@ | |||
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 | internal class IncludedFile : IIncludedFile | ||
9 | { | ||
10 | public string Path { get; set; } | ||
11 | |||
12 | public SourceLineNumber SourceLineNumbers { get; set; } | ||
13 | } | ||
14 | } | ||
diff --git a/src/WixToolset.Core/PreprocessResult.cs b/src/WixToolset.Core/PreprocessResult.cs new file mode 100644 index 00000000..8595d21d --- /dev/null +++ b/src/WixToolset.Core/PreprocessResult.cs | |||
@@ -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.Collections.Generic; | ||
6 | using System.Xml.Linq; | ||
7 | using WixToolset.Extensibility.Data; | ||
8 | |||
9 | public class PreprocessResult : IPreprocessResult | ||
10 | { | ||
11 | public XDocument Document { get; set; } | ||
12 | |||
13 | public IEnumerable<IIncludedFile> IncludedFiles { get; set; } | ||
14 | } | ||
15 | } | ||
diff --git a/src/WixToolset.Core/Preprocessor.cs b/src/WixToolset.Core/Preprocessor.cs index a829f7c4..5a255234 100644 --- a/src/WixToolset.Core/Preprocessor.cs +++ b/src/WixToolset.Core/Preprocessor.cs | |||
@@ -48,18 +48,6 @@ namespace WixToolset.Core | |||
48 | 48 | ||
49 | private IMessaging Messaging { get; } | 49 | private IMessaging Messaging { get; } |
50 | 50 | ||
51 | private IPreprocessContext Context { get; set; } | ||
52 | |||
53 | private Stack<string> CurrentFileStack { get; } = new Stack<string>(); | ||
54 | |||
55 | private Dictionary<string, IPreprocessorExtension> ExtensionsByPrefix { get; } = new Dictionary<string, IPreprocessorExtension>(); | ||
56 | |||
57 | private Stack<bool> IncludeNextStack { get; } = new Stack<bool>(); | ||
58 | |||
59 | private Stack<SourceLineNumber> SourceStack { get; } = new Stack<SourceLineNumber>(); | ||
60 | |||
61 | private IPreprocessHelper Helper { get; set; } | ||
62 | |||
63 | /// <summary> | 51 | /// <summary> |
64 | /// Event for ifdef/ifndef directives. | 52 | /// Event for ifdef/ifndef directives. |
65 | /// </summary> | 53 | /// </summary> |
@@ -100,21 +88,21 @@ namespace WixToolset.Core | |||
100 | /// </summary> | 88 | /// </summary> |
101 | /// <param name="context">The preprocessing context.</param> | 89 | /// <param name="context">The preprocessing context.</param> |
102 | /// <returns>XDocument with the postprocessed data.</returns> | 90 | /// <returns>XDocument with the postprocessed data.</returns> |
103 | public XDocument Preprocess(IPreprocessContext context) | 91 | public IPreprocessResult Preprocess(IPreprocessContext context) |
104 | { | 92 | { |
105 | this.Context = context; | 93 | var state = new ProcessingState(this.ServiceProvider, 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 | 94 | ||
109 | this.PreProcess(); | 95 | this.PreProcess(state); |
110 | 96 | ||
111 | XDocument document; | 97 | IPreprocessResult result; |
112 | using (var reader = XmlReader.Create(this.Context.SourcePath, DocumentXmlReaderSettings)) | 98 | using (var reader = XmlReader.Create(state.Context.SourcePath, DocumentXmlReaderSettings)) |
113 | { | 99 | { |
114 | document = this.Process(reader); | 100 | result = this.Process(state, reader); |
115 | } | 101 | } |
116 | 102 | ||
117 | return this.PostProcess(document); | 103 | this.PostProcess(state, result); |
104 | |||
105 | return result; | ||
118 | } | 106 | } |
119 | 107 | ||
120 | /// <summary> | 108 | /// <summary> |
@@ -123,7 +111,7 @@ namespace WixToolset.Core | |||
123 | /// <param name="context">The preprocessing context.</param> | 111 | /// <param name="context">The preprocessing context.</param> |
124 | /// <param name="reader">XmlReader to processing the context.</param> | 112 | /// <param name="reader">XmlReader to processing the context.</param> |
125 | /// <returns>XDocument with the postprocessed data.</returns> | 113 | /// <returns>XDocument with the postprocessed data.</returns> |
126 | public XDocument Preprocess(IPreprocessContext context, XmlReader reader) | 114 | public IPreprocessResult Preprocess(IPreprocessContext context, XmlReader reader) |
127 | { | 115 | { |
128 | if (String.IsNullOrEmpty(context.SourcePath) && !String.IsNullOrEmpty(reader.BaseURI)) | 116 | if (String.IsNullOrEmpty(context.SourcePath) && !String.IsNullOrEmpty(reader.BaseURI)) |
129 | { | 117 | { |
@@ -131,15 +119,15 @@ namespace WixToolset.Core | |||
131 | context.SourcePath = uri.AbsolutePath; | 119 | context.SourcePath = uri.AbsolutePath; |
132 | } | 120 | } |
133 | 121 | ||
134 | this.Context = context; | 122 | var state = new ProcessingState(this.ServiceProvider, 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 | 123 | ||
138 | this.PreProcess(); | 124 | this.PreProcess(state); |
139 | 125 | ||
140 | var document = this.Process(reader); | 126 | var result = this.Process(state, reader); |
141 | 127 | ||
142 | return this.PostProcess(document); | 128 | this.PostProcess(state, result); |
129 | |||
130 | return result; | ||
143 | } | 131 | } |
144 | 132 | ||
145 | /// <summary> | 133 | /// <summary> |
@@ -148,29 +136,33 @@ namespace WixToolset.Core | |||
148 | /// <param name="context">The preprocessing context.</param> | 136 | /// <param name="context">The preprocessing context.</param> |
149 | /// <param name="reader">XmlReader to processing the context.</param> | 137 | /// <param name="reader">XmlReader to processing the context.</param> |
150 | /// <returns>XDocument with the postprocessed data.</returns> | 138 | /// <returns>XDocument with the postprocessed data.</returns> |
151 | private XDocument Process(XmlReader reader) | 139 | private IPreprocessResult Process(ProcessingState state, XmlReader reader) |
152 | { | 140 | { |
153 | this.Helper = this.ServiceProvider.GetService<IPreprocessHelper>(); | 141 | state.CurrentFileStack.Push(state.Helper.GetVariableValue(state.Context, "sys", "SOURCEFILEDIR")); |
154 | |||
155 | this.CurrentFileStack.Clear(); | ||
156 | this.CurrentFileStack.Push(this.Helper.GetVariableValue(this.Context, "sys", "SOURCEFILEDIR")); | ||
157 | 142 | ||
158 | // Process the reader into the output. | 143 | // Process the reader into the output. |
159 | var output = new XDocument(); | 144 | IPreprocessResult result = null; |
160 | try | 145 | try |
161 | { | 146 | { |
162 | this.PreprocessReader(false, reader, output, 0); | 147 | this.PreprocessReader(state, false, reader, state.Output, 0); |
163 | 148 | ||
164 | // Fire event with post-processed document. | 149 | // Fire event with post-processed document. |
165 | this.ProcessedStream?.Invoke(this, new ProcessedStreamEventArgs(this.Context.SourcePath, output)); | 150 | this.ProcessedStream?.Invoke(this, new ProcessedStreamEventArgs(state.Context.SourcePath, state.Output)); |
151 | |||
152 | if (!this.Messaging.EncounteredError) | ||
153 | { | ||
154 | result = this.ServiceProvider.GetService<IPreprocessResult>(); | ||
155 | result.Document = state.Output; | ||
156 | result.IncludedFiles = state.IncludedFiles; | ||
157 | } | ||
166 | } | 158 | } |
167 | catch (XmlException e) | 159 | catch (XmlException e) |
168 | { | 160 | { |
169 | this.UpdateCurrentLineNumber(reader, 0); | 161 | this.UpdateCurrentLineNumber(state, reader, 0); |
170 | throw new WixException(ErrorMessages.InvalidXml(this.Context.CurrentSourceLineNumber, "source", e.Message)); | 162 | throw new WixException(ErrorMessages.InvalidXml(state.Context.CurrentSourceLineNumber, "source", e.Message)); |
171 | } | 163 | } |
172 | 164 | ||
173 | return this.Messaging.EncounteredError ? null : output; | 165 | return result; |
174 | } | 166 | } |
175 | 167 | ||
176 | /// <summary> | 168 | /// <summary> |
@@ -277,7 +269,7 @@ namespace WixToolset.Core | |||
277 | /// <param name="reader">Reader for the source document.</param> | 269 | /// <param name="reader">Reader for the source document.</param> |
278 | /// <param name="container">Node where content should be added.</param> | 270 | /// <param name="container">Node where content should be added.</param> |
279 | /// <param name="offset">Original offset for the line numbers being processed.</param> | 271 | /// <param name="offset">Original offset for the line numbers being processed.</param> |
280 | private void PreprocessReader(bool include, XmlReader reader, XContainer container, int offset) | 272 | private void PreprocessReader(ProcessingState state, bool include, XmlReader reader, XContainer container, int offset) |
281 | { | 273 | { |
282 | var currentContainer = container; | 274 | var currentContainer = container; |
283 | var containerStack = new Stack<XContainer>(); | 275 | var containerStack = new Stack<XContainer>(); |
@@ -289,9 +281,9 @@ namespace WixToolset.Core | |||
289 | while (reader.Read()) | 281 | while (reader.Read()) |
290 | { | 282 | { |
291 | // update information here in case an error occurs before the next read | 283 | // update information here in case an error occurs before the next read |
292 | this.UpdateCurrentLineNumber(reader, offset); | 284 | this.UpdateCurrentLineNumber(state, reader, offset); |
293 | 285 | ||
294 | var sourceLineNumbers = this.Context.CurrentSourceLineNumber; | 286 | var sourceLineNumbers = state.Context.CurrentSourceLineNumber; |
295 | 287 | ||
296 | // check for changes in conditional processing | 288 | // check for changes in conditional processing |
297 | if (XmlNodeType.ProcessingInstruction == reader.NodeType) | 289 | if (XmlNodeType.ProcessingInstruction == reader.NodeType) |
@@ -305,7 +297,7 @@ namespace WixToolset.Core | |||
305 | ifStack.Push(ifContext); | 297 | ifStack.Push(ifContext); |
306 | if (ifContext.IsTrue) | 298 | if (ifContext.IsTrue) |
307 | { | 299 | { |
308 | ifContext = new IfContext(ifContext.IsTrue & ifContext.Active, this.EvaluateExpression(reader.Value), IfState.If); | 300 | ifContext = new IfContext(ifContext.IsTrue & ifContext.Active, this.EvaluateExpression(state, reader.Value), IfState.If); |
309 | } | 301 | } |
310 | else // Use a default IfContext object so we don't try to evaluate the expression if the context isn't true | 302 | else // Use a default IfContext object so we don't try to evaluate the expression if the context isn't true |
311 | { | 303 | { |
@@ -319,7 +311,7 @@ namespace WixToolset.Core | |||
319 | name = reader.Value.Trim(); | 311 | name = reader.Value.Trim(); |
320 | if (ifContext.IsTrue) | 312 | if (ifContext.IsTrue) |
321 | { | 313 | { |
322 | ifContext = new IfContext(ifContext.IsTrue & ifContext.Active, (null != this.Helper.GetVariableValue(this.Context, name, true)), IfState.If); | 314 | ifContext = new IfContext(ifContext.IsTrue & ifContext.Active, (null != state.Helper.GetVariableValue(state.Context, name, true)), IfState.If); |
323 | } | 315 | } |
324 | else // Use a default IfContext object so we don't try to evaluate the expression if the context isn't true | 316 | else // Use a default IfContext object so we don't try to evaluate the expression if the context isn't true |
325 | { | 317 | { |
@@ -334,7 +326,7 @@ namespace WixToolset.Core | |||
334 | name = reader.Value.Trim(); | 326 | name = reader.Value.Trim(); |
335 | if (ifContext.IsTrue) | 327 | if (ifContext.IsTrue) |
336 | { | 328 | { |
337 | ifContext = new IfContext(ifContext.IsTrue & ifContext.Active, (null == this.Helper.GetVariableValue(this.Context, name, true)), IfState.If); | 329 | ifContext = new IfContext(ifContext.IsTrue & ifContext.Active, (null == state.Helper.GetVariableValue(state.Context, name, true)), IfState.If); |
338 | } | 330 | } |
339 | else // Use a default IfContext object so we don't try to evaluate the expression if the context isn't true | 331 | else // Use a default IfContext object so we don't try to evaluate the expression if the context isn't true |
340 | { | 332 | { |
@@ -358,7 +350,7 @@ namespace WixToolset.Core | |||
358 | ifContext.IfState = IfState.ElseIf; // we're now in an elseif | 350 | 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 | 351 | if (!ifContext.WasEverTrue) // if we've never evaluated the if context to true, then we can try this test |
360 | { | 352 | { |
361 | ifContext.IsTrue = this.EvaluateExpression(reader.Value); | 353 | ifContext.IsTrue = this.EvaluateExpression(state, reader.Value); |
362 | } | 354 | } |
363 | else if (ifContext.IsTrue) | 355 | else if (ifContext.IsTrue) |
364 | { | 356 | { |
@@ -441,35 +433,35 @@ namespace WixToolset.Core | |||
441 | switch (reader.LocalName) | 433 | switch (reader.LocalName) |
442 | { | 434 | { |
443 | case "define": | 435 | case "define": |
444 | this.PreprocessDefine(reader.Value); | 436 | this.PreprocessDefine(state, reader.Value); |
445 | break; | 437 | break; |
446 | 438 | ||
447 | case "error": | 439 | case "error": |
448 | this.PreprocessError(reader.Value); | 440 | this.PreprocessError(state, reader.Value); |
449 | break; | 441 | break; |
450 | 442 | ||
451 | case "warning": | 443 | case "warning": |
452 | this.PreprocessWarning(reader.Value); | 444 | this.PreprocessWarning(state, reader.Value); |
453 | break; | 445 | break; |
454 | 446 | ||
455 | case "undef": | 447 | case "undef": |
456 | this.PreprocessUndef(reader.Value); | 448 | this.PreprocessUndef(state, reader.Value); |
457 | break; | 449 | break; |
458 | 450 | ||
459 | case "include": | 451 | case "include": |
460 | this.UpdateCurrentLineNumber(reader, offset); | 452 | this.UpdateCurrentLineNumber(state, reader, offset); |
461 | this.PreprocessInclude(reader.Value, currentContainer); | 453 | this.PreprocessInclude(state, reader.Value, currentContainer); |
462 | break; | 454 | break; |
463 | 455 | ||
464 | case "foreach": | 456 | case "foreach": |
465 | this.PreprocessForeach(reader, currentContainer, offset); | 457 | this.PreprocessForeach(state, reader, currentContainer, offset); |
466 | break; | 458 | break; |
467 | 459 | ||
468 | case "endforeach": // endforeach is handled in PreprocessForeach, so seeing it here is an error | 460 | case "endforeach": // endforeach is handled in PreprocessForeach, so seeing it here is an error |
469 | throw new WixException(ErrorMessages.UnmatchedPreprocessorInstruction(sourceLineNumbers, "foreach", "endforeach")); | 461 | throw new WixException(ErrorMessages.UnmatchedPreprocessorInstruction(sourceLineNumbers, "foreach", "endforeach")); |
470 | 462 | ||
471 | case "pragma": | 463 | case "pragma": |
472 | this.PreprocessPragma(reader.Value, currentContainer); | 464 | this.PreprocessPragma(state, reader.Value, currentContainer); |
473 | break; | 465 | break; |
474 | 466 | ||
475 | default: | 467 | default: |
@@ -479,15 +471,15 @@ namespace WixToolset.Core | |||
479 | break; | 471 | break; |
480 | 472 | ||
481 | case XmlNodeType.Element: | 473 | case XmlNodeType.Element: |
482 | if (0 < this.IncludeNextStack.Count && this.IncludeNextStack.Peek()) | 474 | if (0 < state.IncludeNextStack.Count && state.IncludeNextStack.Peek()) |
483 | { | 475 | { |
484 | if ("Include" != reader.LocalName) | 476 | if ("Include" != reader.LocalName) |
485 | { | 477 | { |
486 | this.Messaging.Write(ErrorMessages.InvalidDocumentElement(sourceLineNumbers, reader.Name, "include", "Include")); | 478 | this.Messaging.Write(ErrorMessages.InvalidDocumentElement(sourceLineNumbers, reader.Name, "include", "Include")); |
487 | } | 479 | } |
488 | 480 | ||
489 | this.IncludeNextStack.Pop(); | 481 | state.IncludeNextStack.Pop(); |
490 | this.IncludeNextStack.Push(false); | 482 | state.IncludeNextStack.Push(false); |
491 | break; | 483 | break; |
492 | } | 484 | } |
493 | 485 | ||
@@ -496,12 +488,12 @@ namespace WixToolset.Core | |||
496 | var element = new XElement(ns + reader.LocalName); | 488 | var element = new XElement(ns + reader.LocalName); |
497 | currentContainer.Add(element); | 489 | currentContainer.Add(element); |
498 | 490 | ||
499 | this.UpdateCurrentLineNumber(reader, offset); | 491 | this.UpdateCurrentLineNumber(state, reader, offset); |
500 | element.AddAnnotation(sourceLineNumbers); | 492 | element.AddAnnotation(sourceLineNumbers); |
501 | 493 | ||
502 | while (reader.MoveToNextAttribute()) | 494 | while (reader.MoveToNextAttribute()) |
503 | { | 495 | { |
504 | var value = this.Helper.PreprocessString(this.Context, reader.Value); | 496 | var value = state.Helper.PreprocessString(state.Context, reader.Value); |
505 | 497 | ||
506 | var attribNamespace = XNamespace.Get(reader.NamespaceURI); | 498 | var attribNamespace = XNamespace.Get(reader.NamespaceURI); |
507 | attribNamespace = XNamespace.Xmlns == attribNamespace && reader.LocalName.Equals("xmlns") ? XNamespace.None : attribNamespace; | 499 | attribNamespace = XNamespace.Xmlns == attribNamespace && reader.LocalName.Equals("xmlns") ? XNamespace.None : attribNamespace; |
@@ -524,12 +516,12 @@ namespace WixToolset.Core | |||
524 | break; | 516 | break; |
525 | 517 | ||
526 | case XmlNodeType.Text: | 518 | case XmlNodeType.Text: |
527 | var postprocessedText = this.Helper.PreprocessString(this.Context, reader.Value); | 519 | var postprocessedText = state.Helper.PreprocessString(state.Context, reader.Value); |
528 | currentContainer.Add(postprocessedText); | 520 | currentContainer.Add(postprocessedText); |
529 | break; | 521 | break; |
530 | 522 | ||
531 | case XmlNodeType.CDATA: | 523 | case XmlNodeType.CDATA: |
532 | var postprocessedValue = this.Helper.PreprocessString(this.Context, reader.Value); | 524 | var postprocessedValue = state.Helper.PreprocessString(state.Context, reader.Value); |
533 | currentContainer.Add(new XCData(postprocessedValue)); | 525 | currentContainer.Add(new XCData(postprocessedValue)); |
534 | break; | 526 | break; |
535 | 527 | ||
@@ -540,13 +532,13 @@ namespace WixToolset.Core | |||
540 | 532 | ||
541 | if (0 != ifStack.Count) | 533 | if (0 != ifStack.Count) |
542 | { | 534 | { |
543 | throw new WixException(ErrorMessages.NonterminatedPreprocessorInstruction(this.Context.CurrentSourceLineNumber, "if", "endif")); | 535 | throw new WixException(ErrorMessages.NonterminatedPreprocessorInstruction(state.Context.CurrentSourceLineNumber, "if", "endif")); |
544 | } | 536 | } |
545 | 537 | ||
546 | // TODO: can this actually happen? | 538 | // TODO: can this actually happen? |
547 | if (0 != containerStack.Count) | 539 | if (0 != containerStack.Count) |
548 | { | 540 | { |
549 | throw new WixException(ErrorMessages.NonterminatedPreprocessorInstruction(this.Context.CurrentSourceLineNumber, "nodes", "nodes")); | 541 | throw new WixException(ErrorMessages.NonterminatedPreprocessorInstruction(state.Context.CurrentSourceLineNumber, "nodes", "nodes")); |
550 | } | 542 | } |
551 | } | 543 | } |
552 | 544 | ||
@@ -554,37 +546,37 @@ namespace WixToolset.Core | |||
554 | /// Processes an error processing instruction. | 546 | /// Processes an error processing instruction. |
555 | /// </summary> | 547 | /// </summary> |
556 | /// <param name="errorMessage">Text from source.</param> | 548 | /// <param name="errorMessage">Text from source.</param> |
557 | private void PreprocessError(string errorMessage) | 549 | private void PreprocessError(ProcessingState state, string errorMessage) |
558 | { | 550 | { |
559 | // Resolve other variables in the error message. | 551 | // Resolve other variables in the error message. |
560 | errorMessage = this.Helper.PreprocessString(this.Context, errorMessage); | 552 | errorMessage = state.Helper.PreprocessString(state.Context, errorMessage); |
561 | 553 | ||
562 | throw new WixException(ErrorMessages.PreprocessorError(this.Context.CurrentSourceLineNumber, errorMessage)); | 554 | throw new WixException(ErrorMessages.PreprocessorError(state.Context.CurrentSourceLineNumber, errorMessage)); |
563 | } | 555 | } |
564 | 556 | ||
565 | /// <summary> | 557 | /// <summary> |
566 | /// Processes a warning processing instruction. | 558 | /// Processes a warning processing instruction. |
567 | /// </summary> | 559 | /// </summary> |
568 | /// <param name="warningMessage">Text from source.</param> | 560 | /// <param name="warningMessage">Text from source.</param> |
569 | private void PreprocessWarning(string warningMessage) | 561 | private void PreprocessWarning(ProcessingState state, string warningMessage) |
570 | { | 562 | { |
571 | // Resolve other variables in the warning message. | 563 | // Resolve other variables in the warning message. |
572 | warningMessage = this.Helper.PreprocessString(this.Context, warningMessage); | 564 | warningMessage = state.Helper.PreprocessString(state.Context, warningMessage); |
573 | 565 | ||
574 | this.Messaging.Write(WarningMessages.PreprocessorWarning(this.Context.CurrentSourceLineNumber, warningMessage)); | 566 | this.Messaging.Write(WarningMessages.PreprocessorWarning(state.Context.CurrentSourceLineNumber, warningMessage)); |
575 | } | 567 | } |
576 | 568 | ||
577 | /// <summary> | 569 | /// <summary> |
578 | /// Processes a define processing instruction and creates the appropriate parameter. | 570 | /// Processes a define processing instruction and creates the appropriate parameter. |
579 | /// </summary> | 571 | /// </summary> |
580 | /// <param name="originalDefine">Text from source.</param> | 572 | /// <param name="originalDefine">Text from source.</param> |
581 | private void PreprocessDefine(string originalDefine) | 573 | private void PreprocessDefine(ProcessingState state, string originalDefine) |
582 | { | 574 | { |
583 | var match = DefineRegex.Match(originalDefine); | 575 | var match = DefineRegex.Match(originalDefine); |
584 | 576 | ||
585 | if (!match.Success) | 577 | if (!match.Success) |
586 | { | 578 | { |
587 | throw new WixException(ErrorMessages.IllegalDefineStatement(this.Context.CurrentSourceLineNumber, originalDefine)); | 579 | throw new WixException(ErrorMessages.IllegalDefineStatement(state.Context.CurrentSourceLineNumber, originalDefine)); |
588 | } | 580 | } |
589 | 581 | ||
590 | var defineName = match.Groups["varName"].Value; | 582 | var defineName = match.Groups["varName"].Value; |
@@ -599,15 +591,15 @@ namespace WixToolset.Core | |||
599 | } | 591 | } |
600 | 592 | ||
601 | // resolve other variables in the variable value | 593 | // resolve other variables in the variable value |
602 | defineValue = this.Helper.PreprocessString(this.Context, defineValue); | 594 | defineValue = state.Helper.PreprocessString(state.Context, defineValue); |
603 | 595 | ||
604 | if (defineName.StartsWith("var.", StringComparison.Ordinal)) | 596 | if (defineName.StartsWith("var.", StringComparison.Ordinal)) |
605 | { | 597 | { |
606 | this.Helper.AddVariable(this.Context, defineName.Substring(4), defineValue); | 598 | state.Helper.AddVariable(state.Context, defineName.Substring(4), defineValue); |
607 | } | 599 | } |
608 | else | 600 | else |
609 | { | 601 | { |
610 | this.Helper.AddVariable(this.Context, defineName, defineValue); | 602 | state.Helper.AddVariable(state.Context, defineName, defineValue); |
611 | } | 603 | } |
612 | } | 604 | } |
613 | 605 | ||
@@ -615,17 +607,17 @@ namespace WixToolset.Core | |||
615 | /// Processes an undef processing instruction and creates the appropriate parameter. | 607 | /// Processes an undef processing instruction and creates the appropriate parameter. |
616 | /// </summary> | 608 | /// </summary> |
617 | /// <param name="originalDefine">Text from source.</param> | 609 | /// <param name="originalDefine">Text from source.</param> |
618 | private void PreprocessUndef(string originalDefine) | 610 | private void PreprocessUndef(ProcessingState state, string originalDefine) |
619 | { | 611 | { |
620 | var name = this.Helper.PreprocessString(this.Context, originalDefine.Trim()); | 612 | var name = state.Helper.PreprocessString(state.Context, originalDefine.Trim()); |
621 | 613 | ||
622 | if (name.StartsWith("var.", StringComparison.Ordinal)) | 614 | if (name.StartsWith("var.", StringComparison.Ordinal)) |
623 | { | 615 | { |
624 | this.Helper.RemoveVariable(this.Context, name.Substring(4)); | 616 | state.Helper.RemoveVariable(state.Context, name.Substring(4)); |
625 | } | 617 | } |
626 | else | 618 | else |
627 | { | 619 | { |
628 | this.Helper.RemoveVariable(this.Context, name); | 620 | state.Helper.RemoveVariable(state.Context, name); |
629 | } | 621 | } |
630 | } | 622 | } |
631 | 623 | ||
@@ -634,14 +626,14 @@ namespace WixToolset.Core | |||
634 | /// </summary> | 626 | /// </summary> |
635 | /// <param name="includePath">Path to included file.</param> | 627 | /// <param name="includePath">Path to included file.</param> |
636 | /// <param name="parent">Parent container for included content.</param> | 628 | /// <param name="parent">Parent container for included content.</param> |
637 | private void PreprocessInclude(string includePath, XContainer parent) | 629 | private void PreprocessInclude(ProcessingState state, string includePath, XContainer parent) |
638 | { | 630 | { |
639 | var sourceLineNumbers = this.Context.CurrentSourceLineNumber; | 631 | var sourceLineNumbers = state.Context.CurrentSourceLineNumber; |
640 | 632 | ||
641 | // Preprocess variables in the path. | 633 | // Preprocess variables in the path. |
642 | includePath = this.Helper.PreprocessString(this.Context, includePath); | 634 | includePath = state.Helper.PreprocessString(state.Context, includePath); |
643 | 635 | ||
644 | var includeFile = this.GetIncludeFile(includePath); | 636 | var includeFile = this.GetIncludeFile(state, includePath); |
645 | 637 | ||
646 | if (null == includeFile) | 638 | if (null == includeFile) |
647 | { | 639 | { |
@@ -650,22 +642,28 @@ namespace WixToolset.Core | |||
650 | 642 | ||
651 | using (var reader = XmlReader.Create(includeFile, DocumentXmlReaderSettings)) | 643 | using (var reader = XmlReader.Create(includeFile, DocumentXmlReaderSettings)) |
652 | { | 644 | { |
653 | this.PushInclude(includeFile); | 645 | this.PushInclude(state, includeFile); |
654 | 646 | ||
655 | // process the included reader into the writer | 647 | // process the included reader into the writer |
656 | try | 648 | try |
657 | { | 649 | { |
658 | this.PreprocessReader(true, reader, parent, 0); | 650 | this.PreprocessReader(state, true, reader, parent, 0); |
659 | } | 651 | } |
660 | catch (XmlException e) | 652 | catch (XmlException e) |
661 | { | 653 | { |
662 | this.UpdateCurrentLineNumber(reader, 0); | 654 | this.UpdateCurrentLineNumber(state, reader, 0); |
663 | throw new WixException(ErrorMessages.InvalidXml(sourceLineNumbers, "source", e.Message)); | 655 | throw new WixException(ErrorMessages.InvalidXml(sourceLineNumbers, "source", e.Message)); |
664 | } | 656 | } |
665 | 657 | ||
666 | this.IncludedFile?.Invoke(this, new IncludedFileEventArgs(sourceLineNumbers, includeFile)); | 658 | this.IncludedFile?.Invoke(this, new IncludedFileEventArgs(sourceLineNumbers, includeFile)); |
667 | 659 | ||
668 | this.PopInclude(); | 660 | var includedFile = this.ServiceProvider.GetService<IIncludedFile>(); |
661 | includedFile.Path = includeFile; | ||
662 | includedFile.SourceLineNumbers = sourceLineNumbers; | ||
663 | |||
664 | state.IncludedFiles.Add(includedFile); | ||
665 | |||
666 | this.PopInclude(state); | ||
669 | } | 667 | } |
670 | } | 668 | } |
671 | 669 | ||
@@ -675,13 +673,13 @@ namespace WixToolset.Core | |||
675 | /// <param name="reader">The xml reader.</param> | 673 | /// <param name="reader">The xml reader.</param> |
676 | /// <param name="container">The container where to output processed data.</param> | 674 | /// <param name="container">The container where to output processed data.</param> |
677 | /// <param name="offset">Offset for the line numbers.</param> | 675 | /// <param name="offset">Offset for the line numbers.</param> |
678 | private void PreprocessForeach(XmlReader reader, XContainer container, int offset) | 676 | private void PreprocessForeach(ProcessingState state, XmlReader reader, XContainer container, int offset) |
679 | { | 677 | { |
680 | // Find the "in" token. | 678 | // Find the "in" token. |
681 | var indexOfInToken = reader.Value.IndexOf(" in ", StringComparison.Ordinal); | 679 | var indexOfInToken = reader.Value.IndexOf(" in ", StringComparison.Ordinal); |
682 | if (0 > indexOfInToken) | 680 | if (0 > indexOfInToken) |
683 | { | 681 | { |
684 | throw new WixException(ErrorMessages.IllegalForeach(this.Context.CurrentSourceLineNumber, reader.Value)); | 682 | throw new WixException(ErrorMessages.IllegalForeach(state.Context.CurrentSourceLineNumber, reader.Value)); |
685 | } | 683 | } |
686 | 684 | ||
687 | // parse out the variable name | 685 | // parse out the variable name |
@@ -689,7 +687,7 @@ namespace WixToolset.Core | |||
689 | var varValuesString = reader.Value.Substring(indexOfInToken + 4).Trim(); | 687 | var varValuesString = reader.Value.Substring(indexOfInToken + 4).Trim(); |
690 | 688 | ||
691 | // preprocess the variable values string because it might be a variable itself | 689 | // preprocess the variable values string because it might be a variable itself |
692 | varValuesString = this.Helper.PreprocessString(this.Context, varValuesString); | 690 | varValuesString = state.Helper.PreprocessString(state.Context, varValuesString); |
693 | 691 | ||
694 | var varValues = varValuesString.Split(';'); | 692 | var varValues = varValuesString.Split(';'); |
695 | 693 | ||
@@ -751,7 +749,7 @@ namespace WixToolset.Core | |||
751 | } | 749 | } |
752 | else if (reader.NodeType == XmlNodeType.None) | 750 | else if (reader.NodeType == XmlNodeType.None) |
753 | { | 751 | { |
754 | throw new WixException(ErrorMessages.ExpectedEndforeach(this.Context.CurrentSourceLineNumber)); | 752 | throw new WixException(ErrorMessages.ExpectedEndforeach(state.Context.CurrentSourceLineNumber)); |
755 | } | 753 | } |
756 | 754 | ||
757 | reader.Read(); | 755 | reader.Read(); |
@@ -765,16 +763,16 @@ namespace WixToolset.Core | |||
765 | using (var loopReader = XmlReader.Create(fragmentStream, FragmentXmlReaderSettings)) | 763 | using (var loopReader = XmlReader.Create(fragmentStream, FragmentXmlReaderSettings)) |
766 | { | 764 | { |
767 | // Always overwrite foreach variables. | 765 | // Always overwrite foreach variables. |
768 | this.Helper.AddVariable(this.Context, varName, varValue, false); | 766 | state.Helper.AddVariable(state.Context, varName, varValue, false); |
769 | 767 | ||
770 | try | 768 | try |
771 | { | 769 | { |
772 | this.PreprocessReader(false, loopReader, container, offset); | 770 | this.PreprocessReader(state, false, loopReader, container, offset); |
773 | } | 771 | } |
774 | catch (XmlException e) | 772 | catch (XmlException e) |
775 | { | 773 | { |
776 | this.UpdateCurrentLineNumber(loopReader, offset); | 774 | this.UpdateCurrentLineNumber(state, loopReader, offset); |
777 | throw new WixException(ErrorMessages.InvalidXml(this.Context.CurrentSourceLineNumber, "source", e.Message)); | 775 | throw new WixException(ErrorMessages.InvalidXml(state.Context.CurrentSourceLineNumber, "source", e.Message)); |
778 | } | 776 | } |
779 | 777 | ||
780 | fragmentStream.Position = 0; // seek back to the beginning for the next loop. | 778 | fragmentStream.Position = 0; // seek back to the beginning for the next loop. |
@@ -787,25 +785,25 @@ namespace WixToolset.Core | |||
787 | /// Processes a pragma processing instruction | 785 | /// Processes a pragma processing instruction |
788 | /// </summary> | 786 | /// </summary> |
789 | /// <param name="pragmaText">Text from source.</param> | 787 | /// <param name="pragmaText">Text from source.</param> |
790 | private void PreprocessPragma(string pragmaText, XContainer parent) | 788 | private void PreprocessPragma(ProcessingState state, string pragmaText, XContainer parent) |
791 | { | 789 | { |
792 | var match = PragmaRegex.Match(pragmaText); | 790 | var match = PragmaRegex.Match(pragmaText); |
793 | 791 | ||
794 | if (!match.Success) | 792 | if (!match.Success) |
795 | { | 793 | { |
796 | throw new WixException(ErrorMessages.InvalidPreprocessorPragma(this.Context.CurrentSourceLineNumber, pragmaText)); | 794 | throw new WixException(ErrorMessages.InvalidPreprocessorPragma(state.Context.CurrentSourceLineNumber, pragmaText)); |
797 | } | 795 | } |
798 | 796 | ||
799 | // resolve other variables in the pragma argument(s) | 797 | // resolve other variables in the pragma argument(s) |
800 | var pragmaArgs = this.Helper.PreprocessString(this.Context, match.Groups["pragmaValue"].Value).Trim(); | 798 | var pragmaArgs = state.Helper.PreprocessString(state.Context, match.Groups["pragmaValue"].Value).Trim(); |
801 | 799 | ||
802 | try | 800 | try |
803 | { | 801 | { |
804 | this.Helper.PreprocessPragma(this.Context, match.Groups["pragmaName"].Value.Trim(), pragmaArgs, parent); | 802 | state.Helper.PreprocessPragma(state.Context, match.Groups["pragmaName"].Value.Trim(), pragmaArgs, parent); |
805 | } | 803 | } |
806 | catch (Exception e) | 804 | catch (Exception e) |
807 | { | 805 | { |
808 | throw new WixException(ErrorMessages.PreprocessorExtensionPragmaFailed(this.Context.CurrentSourceLineNumber, pragmaText, e.Message)); | 806 | throw new WixException(ErrorMessages.PreprocessorExtensionPragmaFailed(state.Context.CurrentSourceLineNumber, pragmaText, e.Message)); |
809 | } | 807 | } |
810 | } | 808 | } |
811 | 809 | ||
@@ -816,7 +814,7 @@ namespace WixToolset.Core | |||
816 | /// <param name="expression">Expression with token removed.</param> | 814 | /// <param name="expression">Expression with token removed.</param> |
817 | /// <param name="stringLiteral">Flag if token is a string literal instead of a variable.</param> | 815 | /// <param name="stringLiteral">Flag if token is a string literal instead of a variable.</param> |
818 | /// <returns>Next token.</returns> | 816 | /// <returns>Next token.</returns> |
819 | private string GetNextToken(string originalExpression, ref string expression, out bool stringLiteral) | 817 | private string GetNextToken(ProcessingState state, string originalExpression, ref string expression, out bool stringLiteral) |
820 | { | 818 | { |
821 | stringLiteral = false; | 819 | stringLiteral = false; |
822 | var token = String.Empty; | 820 | var token = String.Empty; |
@@ -832,11 +830,11 @@ namespace WixToolset.Core | |||
832 | var endingQuotes = expression.IndexOf('\"', 1); | 830 | var endingQuotes = expression.IndexOf('\"', 1); |
833 | if (-1 == endingQuotes) | 831 | if (-1 == endingQuotes) |
834 | { | 832 | { |
835 | throw new WixException(ErrorMessages.UnmatchedQuotesInExpression(this.Context.CurrentSourceLineNumber, originalExpression)); | 833 | throw new WixException(ErrorMessages.UnmatchedQuotesInExpression(state.Context.CurrentSourceLineNumber, originalExpression)); |
836 | } | 834 | } |
837 | 835 | ||
838 | // cut the quotes off the string | 836 | // cut the quotes off the string |
839 | token = this.Helper.PreprocessString(this.Context, expression.Substring(1, endingQuotes - 1)); | 837 | token = state.Helper.PreprocessString(state.Context, expression.Substring(1, endingQuotes - 1)); |
840 | 838 | ||
841 | // advance past this string | 839 | // advance past this string |
842 | expression = expression.Substring(endingQuotes + 1).Trim(); | 840 | expression = expression.Substring(endingQuotes + 1).Trim(); |
@@ -866,7 +864,7 @@ namespace WixToolset.Core | |||
866 | 864 | ||
867 | if (-1 == endingParen) | 865 | if (-1 == endingParen) |
868 | { | 866 | { |
869 | throw new WixException(ErrorMessages.UnmatchedParenthesisInExpression(this.Context.CurrentSourceLineNumber, originalExpression)); | 867 | throw new WixException(ErrorMessages.UnmatchedParenthesisInExpression(state.Context.CurrentSourceLineNumber, originalExpression)); |
870 | } | 868 | } |
871 | token = expression.Substring(0, endingParen + 1); | 869 | token = expression.Substring(0, endingParen + 1); |
872 | 870 | ||
@@ -962,7 +960,7 @@ namespace WixToolset.Core | |||
962 | /// <param name="originalExpression">Original expression for error message.</param> | 960 | /// <param name="originalExpression">Original expression for error message.</param> |
963 | /// <param name="variable">Variable to evaluate.</param> | 961 | /// <param name="variable">Variable to evaluate.</param> |
964 | /// <returns>Value of variable.</returns> | 962 | /// <returns>Value of variable.</returns> |
965 | private string EvaluateVariable(string originalExpression, string variable) | 963 | private string EvaluateVariable(ProcessingState state, string originalExpression, string variable) |
966 | { | 964 | { |
967 | // By default it's a literal and will only be evaluated if it | 965 | // By default it's a literal and will only be evaluated if it |
968 | // matches the variable format | 966 | // matches the variable format |
@@ -972,7 +970,7 @@ namespace WixToolset.Core | |||
972 | { | 970 | { |
973 | try | 971 | try |
974 | { | 972 | { |
975 | varValue = this.Helper.PreprocessString(this.Context, variable); | 973 | varValue = state.Helper.PreprocessString(state.Context, variable); |
976 | } | 974 | } |
977 | catch (ArgumentNullException) | 975 | catch (ArgumentNullException) |
978 | { | 976 | { |
@@ -983,12 +981,12 @@ namespace WixToolset.Core | |||
983 | else if (variable.IndexOf("(", StringComparison.Ordinal) != -1 || variable.IndexOf(")", StringComparison.Ordinal) != -1) | 981 | else if (variable.IndexOf("(", StringComparison.Ordinal) != -1 || variable.IndexOf(")", StringComparison.Ordinal) != -1) |
984 | { | 982 | { |
985 | // make sure it doesn't contain parenthesis | 983 | // make sure it doesn't contain parenthesis |
986 | throw new WixException(ErrorMessages.UnmatchedParenthesisInExpression(this.Context.CurrentSourceLineNumber, originalExpression)); | 984 | throw new WixException(ErrorMessages.UnmatchedParenthesisInExpression(state.Context.CurrentSourceLineNumber, originalExpression)); |
987 | } | 985 | } |
988 | else if (variable.IndexOf("\"", StringComparison.Ordinal) != -1) | 986 | else if (variable.IndexOf("\"", StringComparison.Ordinal) != -1) |
989 | { | 987 | { |
990 | // shouldn't contain quotes | 988 | // shouldn't contain quotes |
991 | throw new WixException(ErrorMessages.UnmatchedQuotesInExpression(this.Context.CurrentSourceLineNumber, originalExpression)); | 989 | throw new WixException(ErrorMessages.UnmatchedQuotesInExpression(state.Context.CurrentSourceLineNumber, originalExpression)); |
992 | } | 990 | } |
993 | 991 | ||
994 | return varValue; | 992 | return varValue; |
@@ -1002,31 +1000,31 @@ namespace WixToolset.Core | |||
1002 | /// <param name="leftValue">Left side value from expression.</param> | 1000 | /// <param name="leftValue">Left side value from expression.</param> |
1003 | /// <param name="operation">Operation in expression.</param> | 1001 | /// <param name="operation">Operation in expression.</param> |
1004 | /// <param name="rightValue">Right side value from expression.</param> | 1002 | /// <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) | 1003 | private void GetNameValuePair(ProcessingState state, string originalExpression, ref string expression, out string leftValue, out string operation, out string rightValue) |
1006 | { | 1004 | { |
1007 | leftValue = this.GetNextToken(originalExpression, ref expression, out var stringLiteral); | 1005 | leftValue = this.GetNextToken(state, originalExpression, ref expression, out var stringLiteral); |
1008 | 1006 | ||
1009 | // If it wasn't a string literal, evaluate it | 1007 | // If it wasn't a string literal, evaluate it |
1010 | if (!stringLiteral) | 1008 | if (!stringLiteral) |
1011 | { | 1009 | { |
1012 | leftValue = this.EvaluateVariable(originalExpression, leftValue); | 1010 | leftValue = this.EvaluateVariable(state, originalExpression, leftValue); |
1013 | } | 1011 | } |
1014 | 1012 | ||
1015 | // Get the operation | 1013 | // Get the operation |
1016 | operation = this.GetNextToken(originalExpression, ref expression, out stringLiteral); | 1014 | operation = this.GetNextToken(state, originalExpression, ref expression, out stringLiteral); |
1017 | if (IsOperator(operation)) | 1015 | if (IsOperator(operation)) |
1018 | { | 1016 | { |
1019 | if (stringLiteral) | 1017 | if (stringLiteral) |
1020 | { | 1018 | { |
1021 | throw new WixException(ErrorMessages.UnmatchedQuotesInExpression(this.Context.CurrentSourceLineNumber, originalExpression)); | 1019 | throw new WixException(ErrorMessages.UnmatchedQuotesInExpression(state.Context.CurrentSourceLineNumber, originalExpression)); |
1022 | } | 1020 | } |
1023 | 1021 | ||
1024 | rightValue = this.GetNextToken(originalExpression, ref expression, out stringLiteral); | 1022 | rightValue = this.GetNextToken(state, originalExpression, ref expression, out stringLiteral); |
1025 | 1023 | ||
1026 | // If it wasn't a string literal, evaluate it | 1024 | // If it wasn't a string literal, evaluate it |
1027 | if (!stringLiteral) | 1025 | if (!stringLiteral) |
1028 | { | 1026 | { |
1029 | rightValue = this.EvaluateVariable(originalExpression, rightValue); | 1027 | rightValue = this.EvaluateVariable(state, originalExpression, rightValue); |
1030 | } | 1028 | } |
1031 | } | 1029 | } |
1032 | else | 1030 | else |
@@ -1052,11 +1050,11 @@ namespace WixToolset.Core | |||
1052 | /// <param name="originalExpression">Original expression to evaluate.</param> | 1050 | /// <param name="originalExpression">Original expression to evaluate.</param> |
1053 | /// <param name="expression">Expression modified while processing.</param> | 1051 | /// <param name="expression">Expression modified while processing.</param> |
1054 | /// <returns>true if expression evaluates to true.</returns> | 1052 | /// <returns>true if expression evaluates to true.</returns> |
1055 | private bool EvaluateAtomicExpression(string originalExpression, ref string expression) | 1053 | private bool EvaluateAtomicExpression(ProcessingState state, string originalExpression, ref string expression) |
1056 | { | 1054 | { |
1057 | // Quick test to see if the first token is a variable | 1055 | // Quick test to see if the first token is a variable |
1058 | var startsWithVariable = expression.StartsWith("$(", StringComparison.Ordinal); | 1056 | var startsWithVariable = expression.StartsWith("$(", StringComparison.Ordinal); |
1059 | this.GetNameValuePair(originalExpression, ref expression, out var leftValue, out var operation, out var rightValue); | 1057 | this.GetNameValuePair(state, originalExpression, ref expression, out var leftValue, out var operation, out var rightValue); |
1060 | 1058 | ||
1061 | var expressionValue = false; | 1059 | var expressionValue = false; |
1062 | 1060 | ||
@@ -1065,7 +1063,7 @@ namespace WixToolset.Core | |||
1065 | { | 1063 | { |
1066 | if (operation.Length > 0) | 1064 | if (operation.Length > 0) |
1067 | { | 1065 | { |
1068 | throw new WixException(ErrorMessages.ExpectedVariable(this.Context.CurrentSourceLineNumber, originalExpression)); | 1066 | throw new WixException(ErrorMessages.ExpectedVariable(state.Context.CurrentSourceLineNumber, originalExpression)); |
1069 | } | 1067 | } |
1070 | 1068 | ||
1071 | // false expression | 1069 | // false expression |
@@ -1080,7 +1078,7 @@ namespace WixToolset.Core | |||
1080 | } | 1078 | } |
1081 | else | 1079 | else |
1082 | { | 1080 | { |
1083 | throw new WixException(ErrorMessages.UnexpectedLiteral(this.Context.CurrentSourceLineNumber, originalExpression)); | 1081 | throw new WixException(ErrorMessages.UnexpectedLiteral(state.Context.CurrentSourceLineNumber, originalExpression)); |
1084 | } | 1082 | } |
1085 | } | 1083 | } |
1086 | else | 1084 | else |
@@ -1120,11 +1118,11 @@ namespace WixToolset.Core | |||
1120 | } | 1118 | } |
1121 | catch (FormatException) | 1119 | catch (FormatException) |
1122 | { | 1120 | { |
1123 | throw new WixException(ErrorMessages.IllegalIntegerInExpression(this.Context.CurrentSourceLineNumber, originalExpression)); | 1121 | throw new WixException(ErrorMessages.IllegalIntegerInExpression(state.Context.CurrentSourceLineNumber, originalExpression)); |
1124 | } | 1122 | } |
1125 | catch (OverflowException) | 1123 | catch (OverflowException) |
1126 | { | 1124 | { |
1127 | throw new WixException(ErrorMessages.IllegalIntegerInExpression(this.Context.CurrentSourceLineNumber, originalExpression)); | 1125 | throw new WixException(ErrorMessages.IllegalIntegerInExpression(state.Context.CurrentSourceLineNumber, originalExpression)); |
1128 | } | 1126 | } |
1129 | 1127 | ||
1130 | // Compare the numbers | 1128 | // Compare the numbers |
@@ -1148,7 +1146,7 @@ namespace WixToolset.Core | |||
1148 | /// <param name="expression">Expression modified while processing.</param> | 1146 | /// <param name="expression">Expression modified while processing.</param> |
1149 | /// <param name="endSubExpression">Index of end of sub-expression.</param> | 1147 | /// <param name="endSubExpression">Index of end of sub-expression.</param> |
1150 | /// <returns>Sub-expression in parenthesis.</returns> | 1148 | /// <returns>Sub-expression in parenthesis.</returns> |
1151 | private string GetParenthesisExpression(string originalExpression, string expression, out int endSubExpression) | 1149 | private string GetParenthesisExpression(ProcessingState state, string originalExpression, string expression, out int endSubExpression) |
1152 | { | 1150 | { |
1153 | endSubExpression = 0; | 1151 | endSubExpression = 0; |
1154 | 1152 | ||
@@ -1166,7 +1164,7 @@ namespace WixToolset.Core | |||
1166 | closeParenIndex = expression.IndexOf(')', closeParenIndex); | 1164 | closeParenIndex = expression.IndexOf(')', closeParenIndex); |
1167 | if (closeParenIndex == -1) | 1165 | if (closeParenIndex == -1) |
1168 | { | 1166 | { |
1169 | throw new WixException(ErrorMessages.UnmatchedParenthesisInExpression(this.Context.CurrentSourceLineNumber, originalExpression)); | 1167 | throw new WixException(ErrorMessages.UnmatchedParenthesisInExpression(state.Context.CurrentSourceLineNumber, originalExpression)); |
1170 | } | 1168 | } |
1171 | 1169 | ||
1172 | if (InsideQuotes(expression, closeParenIndex)) | 1170 | if (InsideQuotes(expression, closeParenIndex)) |
@@ -1201,7 +1199,7 @@ namespace WixToolset.Core | |||
1201 | /// <param name="currentValue">State to update.</param> | 1199 | /// <param name="currentValue">State to update.</param> |
1202 | /// <param name="operation">Operation to apply to current value.</param> | 1200 | /// <param name="operation">Operation to apply to current value.</param> |
1203 | /// <param name="prevResult">Previous result.</param> | 1201 | /// <param name="prevResult">Previous result.</param> |
1204 | private void UpdateExpressionValue(ref bool currentValue, PreprocessorOperation operation, bool prevResult) | 1202 | private void UpdateExpressionValue(ProcessingState state, ref bool currentValue, PreprocessorOperation operation, bool prevResult) |
1205 | { | 1203 | { |
1206 | switch (operation) | 1204 | switch (operation) |
1207 | { | 1205 | { |
@@ -1215,7 +1213,7 @@ namespace WixToolset.Core | |||
1215 | currentValue = !currentValue; | 1213 | currentValue = !currentValue; |
1216 | break; | 1214 | break; |
1217 | default: | 1215 | default: |
1218 | throw new WixException(ErrorMessages.UnexpectedPreprocessorOperator(this.Context.CurrentSourceLineNumber, operation.ToString())); | 1216 | throw new WixException(ErrorMessages.UnexpectedPreprocessorOperator(state.Context.CurrentSourceLineNumber, operation.ToString())); |
1219 | } | 1217 | } |
1220 | } | 1218 | } |
1221 | 1219 | ||
@@ -1224,10 +1222,10 @@ namespace WixToolset.Core | |||
1224 | /// </summary> | 1222 | /// </summary> |
1225 | /// <param name="expression">Expression to evaluate.</param> | 1223 | /// <param name="expression">Expression to evaluate.</param> |
1226 | /// <returns>Boolean result of expression.</returns> | 1224 | /// <returns>Boolean result of expression.</returns> |
1227 | private bool EvaluateExpression(string expression) | 1225 | private bool EvaluateExpression(ProcessingState state, string expression) |
1228 | { | 1226 | { |
1229 | var tmpExpression = expression; | 1227 | var tmpExpression = expression; |
1230 | return this.EvaluateExpressionRecurse(expression, ref tmpExpression, PreprocessorOperation.And, true); | 1228 | return this.EvaluateExpressionRecurse(state, expression, ref tmpExpression, PreprocessorOperation.And, true); |
1231 | } | 1229 | } |
1232 | 1230 | ||
1233 | /// <summary> | 1231 | /// <summary> |
@@ -1258,20 +1256,20 @@ namespace WixToolset.Core | |||
1258 | /// <param name="prevResultOperation">The operation to apply to this result</param> | 1256 | /// <param name="prevResultOperation">The operation to apply to this result</param> |
1259 | /// <param name="prevResult">The previous result to apply to this result</param> | 1257 | /// <param name="prevResult">The previous result to apply to this result</param> |
1260 | /// <returns>Boolean to indicate if the expression is true or false</returns> | 1258 | /// <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) | 1259 | private bool EvaluateExpressionRecurse(ProcessingState state, string originalExpression, ref string expression, PreprocessorOperation prevResultOperation, bool prevResult) |
1262 | { | 1260 | { |
1263 | var expressionValue = false; | 1261 | var expressionValue = false; |
1264 | expression = expression.Trim(); | 1262 | expression = expression.Trim(); |
1265 | if (expression.Length == 0) | 1263 | if (expression.Length == 0) |
1266 | { | 1264 | { |
1267 | throw new WixException(ErrorMessages.UnexpectedEmptySubexpression(this.Context.CurrentSourceLineNumber, originalExpression)); | 1265 | throw new WixException(ErrorMessages.UnexpectedEmptySubexpression(state.Context.CurrentSourceLineNumber, originalExpression)); |
1268 | } | 1266 | } |
1269 | 1267 | ||
1270 | // If the expression starts with parenthesis, evaluate it | 1268 | // If the expression starts with parenthesis, evaluate it |
1271 | if (expression.IndexOf('(') == 0) | 1269 | if (expression.IndexOf('(') == 0) |
1272 | { | 1270 | { |
1273 | var subExpression = this.GetParenthesisExpression(originalExpression, expression, out var endSubExpressionIndex); | 1271 | var subExpression = this.GetParenthesisExpression(state, originalExpression, expression, out var endSubExpressionIndex); |
1274 | expressionValue = this.EvaluateExpressionRecurse(originalExpression, ref subExpression, PreprocessorOperation.And, true); | 1272 | expressionValue = this.EvaluateExpressionRecurse(state, originalExpression, ref subExpression, PreprocessorOperation.And, true); |
1275 | 1273 | ||
1276 | // Now get the rest of the expression that hasn't been evaluated | 1274 | // Now get the rest of the expression that hasn't been evaluated |
1277 | expression = expression.Substring(endSubExpressionIndex).Trim(); | 1275 | expression = expression.Substring(endSubExpressionIndex).Trim(); |
@@ -1284,19 +1282,19 @@ namespace WixToolset.Core | |||
1284 | expression = expression.Substring(3).Trim(); | 1282 | expression = expression.Substring(3).Trim(); |
1285 | if (expression.Length == 0) | 1283 | if (expression.Length == 0) |
1286 | { | 1284 | { |
1287 | throw new WixException(ErrorMessages.ExpectedExpressionAfterNot(this.Context.CurrentSourceLineNumber, originalExpression)); | 1285 | throw new WixException(ErrorMessages.ExpectedExpressionAfterNot(state.Context.CurrentSourceLineNumber, originalExpression)); |
1288 | } | 1286 | } |
1289 | 1287 | ||
1290 | expressionValue = this.EvaluateExpressionRecurse(originalExpression, ref expression, PreprocessorOperation.Not, true); | 1288 | expressionValue = this.EvaluateExpressionRecurse(state, originalExpression, ref expression, PreprocessorOperation.Not, true); |
1291 | } | 1289 | } |
1292 | else // Expect a literal | 1290 | else // Expect a literal |
1293 | { | 1291 | { |
1294 | expressionValue = this.EvaluateAtomicExpression(originalExpression, ref expression); | 1292 | expressionValue = this.EvaluateAtomicExpression(state, originalExpression, ref expression); |
1295 | 1293 | ||
1296 | // Expect the literal that was just evaluated to already be cut off | 1294 | // Expect the literal that was just evaluated to already be cut off |
1297 | } | 1295 | } |
1298 | } | 1296 | } |
1299 | this.UpdateExpressionValue(ref expressionValue, prevResultOperation, prevResult); | 1297 | this.UpdateExpressionValue(state, ref expressionValue, prevResultOperation, prevResult); |
1300 | 1298 | ||
1301 | // If there's still an expression left, it must start with AND or OR. | 1299 | // If there's still an expression left, it must start with AND or OR. |
1302 | if (expression.Trim().Length > 0) | 1300 | if (expression.Trim().Length > 0) |
@@ -1304,16 +1302,16 @@ namespace WixToolset.Core | |||
1304 | if (StartsWithKeyword(expression, PreprocessorOperation.And)) | 1302 | if (StartsWithKeyword(expression, PreprocessorOperation.And)) |
1305 | { | 1303 | { |
1306 | expression = expression.Substring(3); | 1304 | expression = expression.Substring(3); |
1307 | return this.EvaluateExpressionRecurse(originalExpression, ref expression, PreprocessorOperation.And, expressionValue); | 1305 | return this.EvaluateExpressionRecurse(state, originalExpression, ref expression, PreprocessorOperation.And, expressionValue); |
1308 | } | 1306 | } |
1309 | else if (StartsWithKeyword(expression, PreprocessorOperation.Or)) | 1307 | else if (StartsWithKeyword(expression, PreprocessorOperation.Or)) |
1310 | { | 1308 | { |
1311 | expression = expression.Substring(2); | 1309 | expression = expression.Substring(2); |
1312 | return this.EvaluateExpressionRecurse(originalExpression, ref expression, PreprocessorOperation.Or, expressionValue); | 1310 | return this.EvaluateExpressionRecurse(state, originalExpression, ref expression, PreprocessorOperation.Or, expressionValue); |
1313 | } | 1311 | } |
1314 | else | 1312 | else |
1315 | { | 1313 | { |
1316 | throw new WixException(ErrorMessages.InvalidSubExpression(this.Context.CurrentSourceLineNumber, expression, originalExpression)); | 1314 | throw new WixException(ErrorMessages.InvalidSubExpression(state.Context.CurrentSourceLineNumber, expression, originalExpression)); |
1317 | } | 1315 | } |
1318 | } | 1316 | } |
1319 | 1317 | ||
@@ -1325,16 +1323,16 @@ namespace WixToolset.Core | |||
1325 | /// </summary> | 1323 | /// </summary> |
1326 | /// <param name="reader">The xml reader for the preprocessor.</param> | 1324 | /// <param name="reader">The xml reader for the preprocessor.</param> |
1327 | /// <param name="offset">This is the artificial offset of the line numbers from the reader. Used for the foreach processing.</param> | 1325 | /// <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) | 1326 | private void UpdateCurrentLineNumber(ProcessingState state, XmlReader reader, int offset) |
1329 | { | 1327 | { |
1330 | var lineInfoReader = reader as IXmlLineInfo; | 1328 | var lineInfoReader = reader as IXmlLineInfo; |
1331 | if (null != lineInfoReader) | 1329 | if (null != lineInfoReader) |
1332 | { | 1330 | { |
1333 | var newLine = lineInfoReader.LineNumber + offset; | 1331 | var newLine = lineInfoReader.LineNumber + offset; |
1334 | 1332 | ||
1335 | if (this.Context.CurrentSourceLineNumber.LineNumber != newLine) | 1333 | if (state.Context.CurrentSourceLineNumber.LineNumber != newLine) |
1336 | { | 1334 | { |
1337 | this.Context.CurrentSourceLineNumber = new SourceLineNumber(this.Context.CurrentSourceLineNumber.FileName, newLine); | 1335 | state.Context.CurrentSourceLineNumber = new SourceLineNumber(state.Context.CurrentSourceLineNumber.FileName, newLine); |
1338 | } | 1336 | } |
1339 | } | 1337 | } |
1340 | } | 1338 | } |
@@ -1343,28 +1341,28 @@ namespace WixToolset.Core | |||
1343 | /// Pushes a file name on the stack of included files. | 1341 | /// Pushes a file name on the stack of included files. |
1344 | /// </summary> | 1342 | /// </summary> |
1345 | /// <param name="fileName">Name to push on to the stack of included files.</param> | 1343 | /// <param name="fileName">Name to push on to the stack of included files.</param> |
1346 | private void PushInclude(string fileName) | 1344 | private void PushInclude(ProcessingState state, string fileName) |
1347 | { | 1345 | { |
1348 | if (1023 < this.CurrentFileStack.Count) | 1346 | if (1023 < state.CurrentFileStack.Count) |
1349 | { | 1347 | { |
1350 | throw new WixException(ErrorMessages.TooDeeplyIncluded(this.Context.CurrentSourceLineNumber, this.CurrentFileStack.Count)); | 1348 | throw new WixException(ErrorMessages.TooDeeplyIncluded(state.Context.CurrentSourceLineNumber, state.CurrentFileStack.Count)); |
1351 | } | 1349 | } |
1352 | 1350 | ||
1353 | this.CurrentFileStack.Push(fileName); | 1351 | state.CurrentFileStack.Push(fileName); |
1354 | this.SourceStack.Push(this.Context.CurrentSourceLineNumber); | 1352 | state.SourceStack.Push(state.Context.CurrentSourceLineNumber); |
1355 | this.Context.CurrentSourceLineNumber = new SourceLineNumber(fileName); | 1353 | state.Context.CurrentSourceLineNumber = new SourceLineNumber(fileName); |
1356 | this.IncludeNextStack.Push(true); | 1354 | state.IncludeNextStack.Push(true); |
1357 | } | 1355 | } |
1358 | 1356 | ||
1359 | /// <summary> | 1357 | /// <summary> |
1360 | /// Pops a file name from the stack of included files. | 1358 | /// Pops a file name from the stack of included files. |
1361 | /// </summary> | 1359 | /// </summary> |
1362 | private void PopInclude() | 1360 | private void PopInclude(ProcessingState state) |
1363 | { | 1361 | { |
1364 | this.Context.CurrentSourceLineNumber = this.SourceStack.Pop(); | 1362 | state.Context.CurrentSourceLineNumber = state.SourceStack.Pop(); |
1365 | 1363 | ||
1366 | this.CurrentFileStack.Pop(); | 1364 | state.CurrentFileStack.Pop(); |
1367 | this.IncludeNextStack.Pop(); | 1365 | state.IncludeNextStack.Pop(); |
1368 | } | 1366 | } |
1369 | 1367 | ||
1370 | /// <summary> | 1368 | /// <summary> |
@@ -1375,7 +1373,7 @@ namespace WixToolset.Core | |||
1375 | /// </summary> | 1373 | /// </summary> |
1376 | /// <param name="includePath">User-specified path to the included file (usually just the file name).</param> | 1374 | /// <param name="includePath">User-specified path to the included file (usually just the file name).</param> |
1377 | /// <returns>Returns a FileInfo for the found include file, or null if the file cannot be found.</returns> | 1375 | /// <returns>Returns a FileInfo for the found include file, or null if the file cannot be found.</returns> |
1378 | private string GetIncludeFile(string includePath) | 1376 | private string GetIncludeFile(ProcessingState state, string includePath) |
1379 | { | 1377 | { |
1380 | string finalIncludePath = null; | 1378 | string finalIncludePath = null; |
1381 | 1379 | ||
@@ -1399,7 +1397,7 @@ namespace WixToolset.Core | |||
1399 | else // relative path | 1397 | else // relative path |
1400 | { | 1398 | { |
1401 | // build a string to test the directory containing the source file first | 1399 | // build a string to test the directory containing the source file first |
1402 | var currentFolder = this.CurrentFileStack.Peek(); | 1400 | var currentFolder = state.CurrentFileStack.Peek(); |
1403 | var includeTestPath = Path.Combine(Path.GetDirectoryName(currentFolder), includePath); | 1401 | var includeTestPath = Path.Combine(Path.GetDirectoryName(currentFolder), includePath); |
1404 | 1402 | ||
1405 | // test the source file directory | 1403 | // test the source file directory |
@@ -1407,9 +1405,9 @@ namespace WixToolset.Core | |||
1407 | { | 1405 | { |
1408 | finalIncludePath = includeTestPath; | 1406 | finalIncludePath = includeTestPath; |
1409 | } | 1407 | } |
1410 | else // test all search paths in the order specified on the command line | 1408 | else if (state.Context.IncludeSearchPaths != null) // test all search paths in the order specified on the command line |
1411 | { | 1409 | { |
1412 | foreach (var includeSearchPath in this.Context.IncludeSearchPaths) | 1410 | foreach (var includeSearchPath in state.Context.IncludeSearchPaths) |
1413 | { | 1411 | { |
1414 | // if the path exists, we have found the final string | 1412 | // if the path exists, we have found the final string |
1415 | includeTestPath = Path.Combine(includeSearchPath, includePath); | 1413 | includeTestPath = Path.Combine(includeSearchPath, includePath); |
@@ -1425,17 +1423,22 @@ namespace WixToolset.Core | |||
1425 | return finalIncludePath; | 1423 | return finalIncludePath; |
1426 | } | 1424 | } |
1427 | 1425 | ||
1428 | private void PreProcess() | 1426 | private void PreProcess(ProcessingState state) |
1429 | { | 1427 | { |
1430 | foreach (var extension in this.Context.Extensions) | 1428 | if (state.Context.Extensions == null) |
1429 | { | ||
1430 | return; | ||
1431 | } | ||
1432 | |||
1433 | foreach (var extension in state.Context.Extensions) | ||
1431 | { | 1434 | { |
1432 | if (extension.Prefixes != null) | 1435 | if (extension.Prefixes != null) |
1433 | { | 1436 | { |
1434 | foreach (var prefix in extension.Prefixes) | 1437 | foreach (var prefix in extension.Prefixes) |
1435 | { | 1438 | { |
1436 | if (!this.ExtensionsByPrefix.TryGetValue(prefix, out var collidingExtension)) | 1439 | if (!state.ExtensionsByPrefix.TryGetValue(prefix, out var collidingExtension)) |
1437 | { | 1440 | { |
1438 | this.ExtensionsByPrefix.Add(prefix, extension); | 1441 | state.ExtensionsByPrefix.Add(prefix, extension); |
1439 | } | 1442 | } |
1440 | else | 1443 | else |
1441 | { | 1444 | { |
@@ -1444,18 +1447,49 @@ namespace WixToolset.Core | |||
1444 | } | 1447 | } |
1445 | } | 1448 | } |
1446 | 1449 | ||
1447 | extension.PrePreprocess(this.Context); | 1450 | extension.PrePreprocess(state.Context); |
1448 | } | 1451 | } |
1449 | } | 1452 | } |
1450 | 1453 | ||
1451 | private XDocument PostProcess(XDocument document) | 1454 | private void PostProcess(ProcessingState state, IPreprocessResult result) |
1452 | { | 1455 | { |
1453 | foreach (var extension in this.Context.Extensions) | 1456 | if (state.Context.Extensions == null) |
1454 | { | 1457 | { |
1455 | extension.PostPreprocess(document); | 1458 | return; |
1456 | } | 1459 | } |
1457 | 1460 | ||
1458 | return document; | 1461 | foreach (var extension in state.Context.Extensions) |
1462 | { | ||
1463 | extension.PostPreprocess(result); | ||
1464 | } | ||
1465 | } | ||
1466 | |||
1467 | private class ProcessingState | ||
1468 | { | ||
1469 | public ProcessingState(IServiceProvider serviceProvider, IPreprocessContext context) | ||
1470 | { | ||
1471 | this.Context = context; | ||
1472 | this.Context.CurrentSourceLineNumber = new SourceLineNumber(context.SourcePath); | ||
1473 | this.Context.Variables = this.Context.Variables == null ? new Dictionary<string, string>() : new Dictionary<string, string>(this.Context.Variables); | ||
1474 | |||
1475 | this.Helper = serviceProvider.GetService<IPreprocessHelper>(); | ||
1476 | } | ||
1477 | |||
1478 | public IPreprocessContext Context { get; } | ||
1479 | |||
1480 | public IPreprocessHelper Helper { get; } | ||
1481 | |||
1482 | public List<IIncludedFile> IncludedFiles { get; } = new List<IIncludedFile>(); | ||
1483 | |||
1484 | public XDocument Output { get; } = new XDocument(); | ||
1485 | |||
1486 | public Stack<string> CurrentFileStack { get; } = new Stack<string>(); | ||
1487 | |||
1488 | public Dictionary<string, IPreprocessorExtension> ExtensionsByPrefix { get; } = new Dictionary<string, IPreprocessorExtension>(); | ||
1489 | |||
1490 | public Stack<bool> IncludeNextStack { get; } = new Stack<bool>(); | ||
1491 | |||
1492 | public Stack<SourceLineNumber> SourceStack { get; } = new Stack<SourceLineNumber>(); | ||
1459 | } | 1493 | } |
1460 | } | 1494 | } |
1461 | } | 1495 | } |
diff --git a/src/WixToolset.Core/WixToolsetServiceProvider.cs b/src/WixToolset.Core/WixToolsetServiceProvider.cs index e03be0b2..267e4524 100644 --- a/src/WixToolset.Core/WixToolsetServiceProvider.cs +++ b/src/WixToolset.Core/WixToolsetServiceProvider.cs | |||
@@ -45,6 +45,8 @@ namespace WixToolset.Core | |||
45 | this.AddService<IBindResult>((provider, singletons) => new BindResult()); | 45 | this.AddService<IBindResult>((provider, singletons) => new BindResult()); |
46 | this.AddService<IComponentKeyPath>((provider, singletons) => new ComponentKeyPath()); | 46 | this.AddService<IComponentKeyPath>((provider, singletons) => new ComponentKeyPath()); |
47 | this.AddService<IDecompileResult>((provider, singletons) => new DecompileResult()); | 47 | this.AddService<IDecompileResult>((provider, singletons) => new DecompileResult()); |
48 | this.AddService<IIncludedFile>((provider, singletons) => new IncludedFile()); | ||
49 | this.AddService<IPreprocessResult>((provider, singletons) => new PreprocessResult()); | ||
48 | this.AddService<IResolveFileResult>((provider, singletons) => new ResolveFileResult()); | 50 | this.AddService<IResolveFileResult>((provider, singletons) => new ResolveFileResult()); |
49 | this.AddService<IResolveResult>((provider, singletons) => new ResolveResult()); | 51 | this.AddService<IResolveResult>((provider, singletons) => new ResolveResult()); |
50 | this.AddService<IResolvedCabinet>((provider, singletons) => new ResolvedCabinet()); | 52 | this.AddService<IResolvedCabinet>((provider, singletons) => new ResolvedCabinet()); |
diff --git a/src/test/WixToolsetTest.CoreIntegration/PreprocessorFixture.cs b/src/test/WixToolsetTest.CoreIntegration/PreprocessorFixture.cs index f9a9fe83..633a1b46 100644 --- a/src/test/WixToolsetTest.CoreIntegration/PreprocessorFixture.cs +++ b/src/test/WixToolsetTest.CoreIntegration/PreprocessorFixture.cs | |||
@@ -1,19 +1,44 @@ | |||
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. | 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 | 2 | ||
3 | namespace WixToolsetTest.CoreIntegration | 3 | namespace WixToolsetTest.CoreIntegration |
4 | { | 4 | { |
5 | using System.IO; | 5 | using System.IO; |
6 | using System.Linq; | 6 | using System.Linq; |
7 | using WixBuildTools.TestSupport; | 7 | using WixBuildTools.TestSupport; |
8 | using WixToolset.Core; | ||
8 | using WixToolset.Core.TestPackage; | 9 | using WixToolset.Core.TestPackage; |
9 | using WixToolset.Data; | 10 | using WixToolset.Extensibility.Data; |
10 | using WixToolset.Data.Tuples; | ||
11 | using WixToolset.Data.WindowsInstaller; | ||
12 | using Xunit; | 11 | using Xunit; |
13 | 12 | ||
14 | public class PreprocessorFixture | 13 | public class PreprocessorFixture |
15 | { | 14 | { |
16 | [Fact] | 15 | [Fact] |
16 | public void PreprocessDirectly() | ||
17 | { | ||
18 | var folder = TestData.Get(@"TestData\IncludePath"); | ||
19 | var sourcePath = Path.Combine(folder, "Package.wxs"); | ||
20 | var includeFolder = Path.Combine(folder, "data"); | ||
21 | var includeFile = Path.Combine(includeFolder, "Package.wxi"); | ||
22 | |||
23 | var serviceProvider = new WixToolsetServiceProvider(); | ||
24 | |||
25 | var context = (IPreprocessContext)serviceProvider.GetService(typeof(IPreprocessContext)); | ||
26 | context.SourcePath = sourcePath; | ||
27 | context.IncludeSearchPaths = new[] { includeFolder }; | ||
28 | |||
29 | var preprocessor = (IPreprocessor)serviceProvider.GetService(typeof(IPreprocessor)); | ||
30 | var result = preprocessor.Preprocess(context); | ||
31 | |||
32 | var includedFile = result.IncludedFiles.Single(); | ||
33 | Assert.NotNull(result.Document); | ||
34 | Assert.Equal(includeFile, includedFile.Path); | ||
35 | Assert.Equal(sourcePath, includedFile.SourceLineNumbers.FileName); | ||
36 | Assert.Equal(2, includedFile.SourceLineNumbers.LineNumber.Value); | ||
37 | Assert.Equal($"{sourcePath}*2", includedFile.SourceLineNumbers.QualifiedFileName); | ||
38 | Assert.Null(includedFile.SourceLineNumbers.Parent); | ||
39 | } | ||
40 | |||
41 | [Fact] | ||
17 | public void VariableRedefinitionIsAWarning() | 42 | public void VariableRedefinitionIsAWarning() |
18 | { | 43 | { |
19 | var folder = TestData.Get(@"TestData\Variables"); | 44 | var folder = TestData.Get(@"TestData\Variables"); |