diff options
Diffstat (limited to 'src')
| -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"); |
