Include the preprocessed include files with the processed document
This change also cleans up the internal state handling of the preprocesor to pass the processing state around rather than depend on "global state" in member variables. This removes the need to "reset" the member variables before preprocessing which is much cleaner.
Rob Mensching committed
Mar 1, 2019 at 16:45 UTC
615bc202834ac45a9a107e5fccd900081a4abf74
8 files changed
+266
-177
src/WixToolset.Core/CommandLine/BuildCommand.cs
+3
-3
@@ -377,18 +377,18 @@ namespace WixToolset.Core.CommandLine
377
context.SourcePath = sourcePath;
378
context.Variables = preprocessorVariables;
379
380
- XDocument document = null;
380
+ IPreprocessResult result = null;
381
try
382
{
383
var preprocessor = this.ServiceProvider.GetService<IPreprocessor>();
384
- document = preprocessor.Preprocess(context);
384
+ result = preprocessor.Preprocess(context);
385
}
386
catch (WixException e)
387
{
388
this.Messaging.Write(e.Error);
389
}
390
391
- return document;
391
+ return result?.Document;
392
}
393
394
private class CommandLine
src/WixToolset.Core/CommandLine/CompileCommand.cs
+3
-3
@@ -63,11 +63,11 @@ namespace WixToolset.Core.CommandLine
63
context.SourcePath = sourceFile.SourcePath;
64
context.Variables = this.PreprocessorVariables;
65
66
- XDocument document = null;
66
+ IPreprocessResult result = null;
67
try
68
{
69
var preprocessor = this.ServiceProvider.GetService<IPreprocessor>();
70
- document = preprocessor.Preprocess(context);
70
+ result = preprocessor.Preprocess(context);
71
}
72
catch (WixException e)
73
{
@@ -83,7 +83,7 @@ namespace WixToolset.Core.CommandLine
83
compileContext.Extensions = this.ExtensionManager.Create<ICompilerExtension>();
84
compileContext.OutputPath = sourceFile.OutputPath;
85
compileContext.Platform = this.Platform;
86
- compileContext.Source = document;
86
+ compileContext.Source = result?.Document;
87
88
var compiler = this.ServiceProvider.GetService<ICompiler>();
89
var intermediate = compiler.Compile(compileContext);
src/WixToolset.Core/IPreprocessor.cs
+2
-3
@@ -3,13 +3,12 @@
3
namespace WixToolset.Core
4
{
5
using System.Xml;
6
- using System.Xml.Linq;
6
using WixToolset.Extensibility.Data;
7
8
public interface IPreprocessor
9
{
11
- XDocument Preprocess(IPreprocessContext context);
10
+ IPreprocessResult Preprocess(IPreprocessContext context);
11
13
- XDocument Preprocess(IPreprocessContext context, XmlReader reader);
12
+ IPreprocessResult Preprocess(IPreprocessContext context, XmlReader reader);
13
}
14
}
src/WixToolset.Core/IncludedFile.cs
new
+14
@@ -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
+}
src/WixToolset.Core/PreprocessResult.cs
new
+15
@@ -0,0 +1,15 @@
1
+// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
+
3
+namespace WixToolset.Core
4
+{
5
+ using System.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
+}
src/WixToolset.Core/Preprocessor.cs
+198
-164
@@ -48,18 +48,6 @@ namespace WixToolset.Core
48
49
private IMessaging Messaging { get; }
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
-
51
/// <summary>
52
/// Event for ifdef/ifndef directives.
53
/// </summary>
@@ -100,21 +88,21 @@ namespace WixToolset.Core
88
/// </summary>
89
/// <param name="context">The preprocessing context.</param>
90
/// <returns>XDocument with the postprocessed data.</returns>
103
- public XDocument Preprocess(IPreprocessContext context)
91
+ public IPreprocessResult Preprocess(IPreprocessContext context)
92
{
105
- this.Context = context;
106
- this.Context.CurrentSourceLineNumber = new SourceLineNumber(context.SourcePath);
107
- this.Context.Variables = this.Context.Variables == null ? new Dictionary<string, string>() : new Dictionary<string, string>(this.Context.Variables);
93
+ var state = new ProcessingState(this.ServiceProvider, context);
94
109
- this.PreProcess();
95
+ this.PreProcess(state);
96
111
- XDocument document;
112
- using (var reader = XmlReader.Create(this.Context.SourcePath, DocumentXmlReaderSettings))
97
+ IPreprocessResult result;
98
+ using (var reader = XmlReader.Create(state.Context.SourcePath, DocumentXmlReaderSettings))
99
{
114
- document = this.Process(reader);
100
+ result = this.Process(state, reader);
101
}
102
117
- return this.PostProcess(document);
103
+ this.PostProcess(state, result);
104
+
105
+ return result;
106
}
107
108
/// <summary>
@@ -123,7 +111,7 @@ namespace WixToolset.Core
111
/// <param name="context">The preprocessing context.</param>
112
/// <param name="reader">XmlReader to processing the context.</param>
113
/// <returns>XDocument with the postprocessed data.</returns>
126
- public XDocument Preprocess(IPreprocessContext context, XmlReader reader)
114
+ public IPreprocessResult Preprocess(IPreprocessContext context, XmlReader reader)
115
{
116
if (String.IsNullOrEmpty(context.SourcePath) && !String.IsNullOrEmpty(reader.BaseURI))
117
{
@@ -131,15 +119,15 @@ namespace WixToolset.Core
119
context.SourcePath = uri.AbsolutePath;
120
}
121
134
- this.Context = context;
135
- this.Context.CurrentSourceLineNumber = new SourceLineNumber(context.SourcePath);
136
- this.Context.Variables = (this.Context.Variables == null) ? new Dictionary<string, string>() : new Dictionary<string, string>(this.Context.Variables);
122
+ var state = new ProcessingState(this.ServiceProvider, context);
123
138
- this.PreProcess();
124
+ this.PreProcess(state);
125
140
- var document = this.Process(reader);
126
+ var result = this.Process(state, reader);
127
142
- return this.PostProcess(document);
128
+ this.PostProcess(state, result);
129
+
130
+ return result;
131
}
132
133
/// <summary>
@@ -148,29 +136,33 @@ namespace WixToolset.Core
136
/// <param name="context">The preprocessing context.</param>
137
/// <param name="reader">XmlReader to processing the context.</param>
138
/// <returns>XDocument with the postprocessed data.</returns>
151
- private XDocument Process(XmlReader reader)
139
+ private IPreprocessResult Process(ProcessingState state, XmlReader reader)
140
{
153
- this.Helper = this.ServiceProvider.GetService<IPreprocessHelper>();
154
-
155
- this.CurrentFileStack.Clear();
156
- this.CurrentFileStack.Push(this.Helper.GetVariableValue(this.Context, "sys", "SOURCEFILEDIR"));
141
+ state.CurrentFileStack.Push(state.Helper.GetVariableValue(state.Context, "sys", "SOURCEFILEDIR"));
142
143
// Process the reader into the output.
159
- var output = new XDocument();
144
+ IPreprocessResult result = null;
145
try
146
{
162
- this.PreprocessReader(false, reader, output, 0);
147
+ this.PreprocessReader(state, false, reader, state.Output, 0);
148
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
+ }
158
}
159
catch (XmlException e)
160
{
169
- this.UpdateCurrentLineNumber(reader, 0);
170
- throw new WixException(ErrorMessages.InvalidXml(this.Context.CurrentSourceLineNumber, "source", e.Message));
161
+ this.UpdateCurrentLineNumber(state, reader, 0);
162
+ throw new WixException(ErrorMessages.InvalidXml(state.Context.CurrentSourceLineNumber, "source", e.Message));
163
}
164
173
- return this.Messaging.EncounteredError ? null : output;
165
+ return result;
166
}
167
168
/// <summary>
@@ -277,7 +269,7 @@ namespace WixToolset.Core
269
/// <param name="reader">Reader for the source document.</param>
270
/// <param name="container">Node where content should be added.</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)
273
{
274
var currentContainer = container;
275
var containerStack = new Stack<XContainer>();
@@ -289,9 +281,9 @@ namespace WixToolset.Core
281
while (reader.Read())
282
{
283
// update information here in case an error occurs before the next read
292
- this.UpdateCurrentLineNumber(reader, offset);
284
+ this.UpdateCurrentLineNumber(state, reader, offset);
285
294
- var sourceLineNumbers = this.Context.CurrentSourceLineNumber;
286
+ var sourceLineNumbers = state.Context.CurrentSourceLineNumber;
287
288
// check for changes in conditional processing
289
if (XmlNodeType.ProcessingInstruction == reader.NodeType)
@@ -305,7 +297,7 @@ namespace WixToolset.Core
297
ifStack.Push(ifContext);
298
if (ifContext.IsTrue)
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);
301
}
302
else // Use a default IfContext object so we don't try to evaluate the expression if the context isn't true
303
{
@@ -319,7 +311,7 @@ namespace WixToolset.Core
311
name = reader.Value.Trim();
312
if (ifContext.IsTrue)
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);
315
}
316
else // Use a default IfContext object so we don't try to evaluate the expression if the context isn't true
317
{
@@ -334,7 +326,7 @@ namespace WixToolset.Core
326
name = reader.Value.Trim();
327
if (ifContext.IsTrue)
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);
330
}
331
else // Use a default IfContext object so we don't try to evaluate the expression if the context isn't true
332
{
@@ -358,7 +350,7 @@ namespace WixToolset.Core
350
ifContext.IfState = IfState.ElseIf; // we're now in an elseif
351
if (!ifContext.WasEverTrue) // if we've never evaluated the if context to true, then we can try this test
352
{
361
- ifContext.IsTrue = this.EvaluateExpression(reader.Value);
353
+ ifContext.IsTrue = this.EvaluateExpression(state, reader.Value);
354
}
355
else if (ifContext.IsTrue)
356
{
@@ -441,35 +433,35 @@ namespace WixToolset.Core
433
switch (reader.LocalName)
434
{
435
case "define":
444
- this.PreprocessDefine(reader.Value);
436
+ this.PreprocessDefine(state, reader.Value);
437
break;
438
439
case "error":
448
- this.PreprocessError(reader.Value);
440
+ this.PreprocessError(state, reader.Value);
441
break;
442
443
case "warning":
452
- this.PreprocessWarning(reader.Value);
444
+ this.PreprocessWarning(state, reader.Value);
445
break;
446
447
case "undef":
456
- this.PreprocessUndef(reader.Value);
448
+ this.PreprocessUndef(state, reader.Value);
449
break;
450
451
case "include":
460
- this.UpdateCurrentLineNumber(reader, offset);
461
- this.PreprocessInclude(reader.Value, currentContainer);
452
+ this.UpdateCurrentLineNumber(state, reader, offset);
453
+ this.PreprocessInclude(state, reader.Value, currentContainer);
454
break;
455
456
case "foreach":
465
- this.PreprocessForeach(reader, currentContainer, offset);
457
+ this.PreprocessForeach(state, reader, currentContainer, offset);
458
break;
459
460
case "endforeach": // endforeach is handled in PreprocessForeach, so seeing it here is an error
461
throw new WixException(ErrorMessages.UnmatchedPreprocessorInstruction(sourceLineNumbers, "foreach", "endforeach"));
462
463
case "pragma":
472
- this.PreprocessPragma(reader.Value, currentContainer);
464
+ this.PreprocessPragma(state, reader.Value, currentContainer);
465
break;
466
467
default:
@@ -479,15 +471,15 @@ namespace WixToolset.Core
471
break;
472
473
case XmlNodeType.Element:
482
- if (0 < this.IncludeNextStack.Count && this.IncludeNextStack.Peek())
474
+ if (0 < state.IncludeNextStack.Count && state.IncludeNextStack.Peek())
475
{
476
if ("Include" != reader.LocalName)
477
{
478
this.Messaging.Write(ErrorMessages.InvalidDocumentElement(sourceLineNumbers, reader.Name, "include", "Include"));
479
}
480
489
- this.IncludeNextStack.Pop();
490
- this.IncludeNextStack.Push(false);
481
+ state.IncludeNextStack.Pop();
482
+ state.IncludeNextStack.Push(false);
483
break;
484
}
485
@@ -496,12 +488,12 @@ namespace WixToolset.Core
488
var element = new XElement(ns + reader.LocalName);
489
currentContainer.Add(element);
490
499
- this.UpdateCurrentLineNumber(reader, offset);
491
+ this.UpdateCurrentLineNumber(state, reader, offset);
492
element.AddAnnotation(sourceLineNumbers);
493
494
while (reader.MoveToNextAttribute())
495
{
504
- var value = this.Helper.PreprocessString(this.Context, reader.Value);
496
+ var value = state.Helper.PreprocessString(state.Context, reader.Value);
497
498
var attribNamespace = XNamespace.Get(reader.NamespaceURI);
499
attribNamespace = XNamespace.Xmlns == attribNamespace && reader.LocalName.Equals("xmlns") ? XNamespace.None : attribNamespace;
@@ -524,12 +516,12 @@ namespace WixToolset.Core
516
break;
517
518
case XmlNodeType.Text:
527
- var postprocessedText = this.Helper.PreprocessString(this.Context, reader.Value);
519
+ var postprocessedText = state.Helper.PreprocessString(state.Context, reader.Value);
520
currentContainer.Add(postprocessedText);
521
break;
522
523
case XmlNodeType.CDATA:
532
- var postprocessedValue = this.Helper.PreprocessString(this.Context, reader.Value);
524
+ var postprocessedValue = state.Helper.PreprocessString(state.Context, reader.Value);
525
currentContainer.Add(new XCData(postprocessedValue));
526
break;
527
@@ -540,13 +532,13 @@ namespace WixToolset.Core
532
533
if (0 != ifStack.Count)
534
{
543
- throw new WixException(ErrorMessages.NonterminatedPreprocessorInstruction(this.Context.CurrentSourceLineNumber, "if", "endif"));
535
+ throw new WixException(ErrorMessages.NonterminatedPreprocessorInstruction(state.Context.CurrentSourceLineNumber, "if", "endif"));
536
}
537
538
// TODO: can this actually happen?
539
if (0 != containerStack.Count)
540
{
549
- throw new WixException(ErrorMessages.NonterminatedPreprocessorInstruction(this.Context.CurrentSourceLineNumber, "nodes", "nodes"));
541
+ throw new WixException(ErrorMessages.NonterminatedPreprocessorInstruction(state.Context.CurrentSourceLineNumber, "nodes", "nodes"));
542
}
543
}
544
@@ -554,37 +546,37 @@ namespace WixToolset.Core
546
/// Processes an error processing instruction.
547
/// </summary>
548
/// <param name="errorMessage">Text from source.</param>
557
- private void PreprocessError(string errorMessage)
549
+ private void PreprocessError(ProcessingState state, string errorMessage)
550
{
551
// Resolve other variables in the error message.
560
- errorMessage = this.Helper.PreprocessString(this.Context, errorMessage);
552
+ errorMessage = state.Helper.PreprocessString(state.Context, errorMessage);
553
562
- throw new WixException(ErrorMessages.PreprocessorError(this.Context.CurrentSourceLineNumber, errorMessage));
554
+ throw new WixException(ErrorMessages.PreprocessorError(state.Context.CurrentSourceLineNumber, errorMessage));
555
}
556
557
/// <summary>
558
/// Processes a warning processing instruction.
559
/// </summary>
560
/// <param name="warningMessage">Text from source.</param>
569
- private void PreprocessWarning(string warningMessage)
561
+ private void PreprocessWarning(ProcessingState state, string warningMessage)
562
{
563
// Resolve other variables in the warning message.
572
- warningMessage = this.Helper.PreprocessString(this.Context, warningMessage);
564
+ warningMessage = state.Helper.PreprocessString(state.Context, warningMessage);
565
574
- this.Messaging.Write(WarningMessages.PreprocessorWarning(this.Context.CurrentSourceLineNumber, warningMessage));
566
+ this.Messaging.Write(WarningMessages.PreprocessorWarning(state.Context.CurrentSourceLineNumber, warningMessage));
567
}
568
569
/// <summary>
570
/// Processes a define processing instruction and creates the appropriate parameter.
571
/// </summary>
572
/// <param name="originalDefine">Text from source.</param>
581
- private void PreprocessDefine(string originalDefine)
573
+ private void PreprocessDefine(ProcessingState state, string originalDefine)
574
{
575
var match = DefineRegex.Match(originalDefine);
576
577
if (!match.Success)
578
{
587
- throw new WixException(ErrorMessages.IllegalDefineStatement(this.Context.CurrentSourceLineNumber, originalDefine));
579
+ throw new WixException(ErrorMessages.IllegalDefineStatement(state.Context.CurrentSourceLineNumber, originalDefine));
580
}
581
582
var defineName = match.Groups["varName"].Value;
@@ -599,15 +591,15 @@ namespace WixToolset.Core
591
}
592
593
// resolve other variables in the variable value
602
- defineValue = this.Helper.PreprocessString(this.Context, defineValue);
594
+ defineValue = state.Helper.PreprocessString(state.Context, defineValue);
595
596
if (defineName.StartsWith("var.", StringComparison.Ordinal))
597
{
606
- this.Helper.AddVariable(this.Context, defineName.Substring(4), defineValue);
598
+ state.Helper.AddVariable(state.Context, defineName.Substring(4), defineValue);
599
}
600
else
601
{
610
- this.Helper.AddVariable(this.Context, defineName, defineValue);
602
+ state.Helper.AddVariable(state.Context, defineName, defineValue);
603
}
604
}
605
@@ -615,17 +607,17 @@ namespace WixToolset.Core
607
/// Processes an undef processing instruction and creates the appropriate parameter.
608
/// </summary>
609
/// <param name="originalDefine">Text from source.</param>
618
- private void PreprocessUndef(string originalDefine)
610
+ private void PreprocessUndef(ProcessingState state, string originalDefine)
611
{
620
- var name = this.Helper.PreprocessString(this.Context, originalDefine.Trim());
612
+ var name = state.Helper.PreprocessString(state.Context, originalDefine.Trim());
613
614
if (name.StartsWith("var.", StringComparison.Ordinal))
615
{
624
- this.Helper.RemoveVariable(this.Context, name.Substring(4));
616
+ state.Helper.RemoveVariable(state.Context, name.Substring(4));
617
}
618
else
619
{
628
- this.Helper.RemoveVariable(this.Context, name);
620
+ state.Helper.RemoveVariable(state.Context, name);
621
}
622
}
623
@@ -634,14 +626,14 @@ namespace WixToolset.Core
626
/// </summary>
627
/// <param name="includePath">Path to included file.</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)
630
{
639
- var sourceLineNumbers = this.Context.CurrentSourceLineNumber;
631
+ var sourceLineNumbers = state.Context.CurrentSourceLineNumber;
632
633
// Preprocess variables in the path.
642
- includePath = this.Helper.PreprocessString(this.Context, includePath);
634
+ includePath = state.Helper.PreprocessString(state.Context, includePath);
635
644
- var includeFile = this.GetIncludeFile(includePath);
636
+ var includeFile = this.GetIncludeFile(state, includePath);
637
638
if (null == includeFile)
639
{
@@ -650,22 +642,28 @@ namespace WixToolset.Core
642
643
using (var reader = XmlReader.Create(includeFile, DocumentXmlReaderSettings))
644
{
653
- this.PushInclude(includeFile);
645
+ this.PushInclude(state, includeFile);
646
647
// process the included reader into the writer
648
try
649
{
658
- this.PreprocessReader(true, reader, parent, 0);
650
+ this.PreprocessReader(state, true, reader, parent, 0);
651
}
652
catch (XmlException e)
653
{
662
- this.UpdateCurrentLineNumber(reader, 0);
654
+ this.UpdateCurrentLineNumber(state, reader, 0);
655
throw new WixException(ErrorMessages.InvalidXml(sourceLineNumbers, "source", e.Message));
656
}
657
658
this.IncludedFile?.Invoke(this, new IncludedFileEventArgs(sourceLineNumbers, includeFile));
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);
667
}
668
}
669
@@ -675,13 +673,13 @@ namespace WixToolset.Core
673
/// <param name="reader">The xml reader.</param>
674
/// <param name="container">The container where to output processed data.</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)
677
{
678
// Find the "in" token.
679
var indexOfInToken = reader.Value.IndexOf(" in ", StringComparison.Ordinal);
680
if (0 > indexOfInToken)
681
{
684
- throw new WixException(ErrorMessages.IllegalForeach(this.Context.CurrentSourceLineNumber, reader.Value));
682
+ throw new WixException(ErrorMessages.IllegalForeach(state.Context.CurrentSourceLineNumber, reader.Value));
683
}
684
685
// parse out the variable name
@@ -689,7 +687,7 @@ namespace WixToolset.Core
687
var varValuesString = reader.Value.Substring(indexOfInToken + 4).Trim();
688
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);
691
692
var varValues = varValuesString.Split(';');
693
@@ -751,7 +749,7 @@ namespace WixToolset.Core
749
}
750
else if (reader.NodeType == XmlNodeType.None)
751
{
754
- throw new WixException(ErrorMessages.ExpectedEndforeach(this.Context.CurrentSourceLineNumber));
752
+ throw new WixException(ErrorMessages.ExpectedEndforeach(state.Context.CurrentSourceLineNumber));
753
}
754
755
reader.Read();
@@ -765,16 +763,16 @@ namespace WixToolset.Core
763
using (var loopReader = XmlReader.Create(fragmentStream, FragmentXmlReaderSettings))
764
{
765
// Always overwrite foreach variables.
768
- this.Helper.AddVariable(this.Context, varName, varValue, false);
766
+ state.Helper.AddVariable(state.Context, varName, varValue, false);
767
768
try
769
{
772
- this.PreprocessReader(false, loopReader, container, offset);
770
+ this.PreprocessReader(state, false, loopReader, container, offset);
771
}
772
catch (XmlException e)
773
{
776
- this.UpdateCurrentLineNumber(loopReader, offset);
777
- throw new WixException(ErrorMessages.InvalidXml(this.Context.CurrentSourceLineNumber, "source", e.Message));
774
+ this.UpdateCurrentLineNumber(state, loopReader, offset);
775
+ throw new WixException(ErrorMessages.InvalidXml(state.Context.CurrentSourceLineNumber, "source", e.Message));
776
}
777
778
fragmentStream.Position = 0; // seek back to the beginning for the next loop.
@@ -787,25 +785,25 @@ namespace WixToolset.Core
785
/// Processes a pragma processing instruction
786
/// </summary>
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)
789
{
790
var match = PragmaRegex.Match(pragmaText);
791
792
if (!match.Success)
793
{
796
- throw new WixException(ErrorMessages.InvalidPreprocessorPragma(this.Context.CurrentSourceLineNumber, pragmaText));
794
+ throw new WixException(ErrorMessages.InvalidPreprocessorPragma(state.Context.CurrentSourceLineNumber, pragmaText));
795
}
796
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();
799
800
try
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);
803
}
804
catch (Exception e)
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));
807
}
808
}
809
@@ -816,7 +814,7 @@ namespace WixToolset.Core
814
/// <param name="expression">Expression with token removed.</param>
815
/// <param name="stringLiteral">Flag if token is a string literal instead of a variable.</param>
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)
818
{
819
stringLiteral = false;
820
var token = String.Empty;
@@ -832,11 +830,11 @@ namespace WixToolset.Core
830
var endingQuotes = expression.IndexOf('\"', 1);
831
if (-1 == endingQuotes)
832
{
835
- throw new WixException(ErrorMessages.UnmatchedQuotesInExpression(this.Context.CurrentSourceLineNumber, originalExpression));
833
+ throw new WixException(ErrorMessages.UnmatchedQuotesInExpression(state.Context.CurrentSourceLineNumber, originalExpression));
834
}
835
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));
838
839
// advance past this string
840
expression = expression.Substring(endingQuotes + 1).Trim();
@@ -866,7 +864,7 @@ namespace WixToolset.Core
864
865
if (-1 == endingParen)
866
{
869
- throw new WixException(ErrorMessages.UnmatchedParenthesisInExpression(this.Context.CurrentSourceLineNumber, originalExpression));
867
+ throw new WixException(ErrorMessages.UnmatchedParenthesisInExpression(state.Context.CurrentSourceLineNumber, originalExpression));
868
}
869
token = expression.Substring(0, endingParen + 1);
870
@@ -962,7 +960,7 @@ namespace WixToolset.Core
960
/// <param name="originalExpression">Original expression for error message.</param>
961
/// <param name="variable">Variable to evaluate.</param>
962
/// <returns>Value of variable.</returns>
965
- private string EvaluateVariable(string originalExpression, string variable)
963
+ private string EvaluateVariable(ProcessingState state, string originalExpression, string variable)
964
{
965
// By default it's a literal and will only be evaluated if it
966
// matches the variable format
@@ -972,7 +970,7 @@ namespace WixToolset.Core
970
{
971
try
972
{
975
- varValue = this.Helper.PreprocessString(this.Context, variable);
973
+ varValue = state.Helper.PreprocessString(state.Context, variable);
974
}
975
catch (ArgumentNullException)
976
{
@@ -983,12 +981,12 @@ namespace WixToolset.Core
981
else if (variable.IndexOf("(", StringComparison.Ordinal) != -1 || variable.IndexOf(")", StringComparison.Ordinal) != -1)
982
{
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));
985
}
986
else if (variable.IndexOf("\"", StringComparison.Ordinal) != -1)
987
{
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));
990
}
991
992
return varValue;
@@ -1002,31 +1000,31 @@ namespace WixToolset.Core
1000
/// <param name="leftValue">Left side value from expression.</param>
1001
/// <param name="operation">Operation in 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)
1004
{
1007
- leftValue = this.GetNextToken(originalExpression, ref expression, out var stringLiteral);
1005
+ leftValue = this.GetNextToken(state, originalExpression, ref expression, out var stringLiteral);
1006
1007
// If it wasn't a string literal, evaluate it
1008
if (!stringLiteral)
1009
{
1012
- leftValue = this.EvaluateVariable(originalExpression, leftValue);
1010
+ leftValue = this.EvaluateVariable(state, originalExpression, leftValue);
1011
}
1012
1013
// Get the operation
1016
- operation = this.GetNextToken(originalExpression, ref expression, out stringLiteral);
1014
+ operation = this.GetNextToken(state, originalExpression, ref expression, out stringLiteral);
1015
if (IsOperator(operation))
1016
{
1017
if (stringLiteral)
1018
{
1021
- throw new WixException(ErrorMessages.UnmatchedQuotesInExpression(this.Context.CurrentSourceLineNumber, originalExpression));
1019
+ throw new WixException(ErrorMessages.UnmatchedQuotesInExpression(state.Context.CurrentSourceLineNumber, originalExpression));
1020
}
1021
1024
- rightValue = this.GetNextToken(originalExpression, ref expression, out stringLiteral);
1022
+ rightValue = this.GetNextToken(state, originalExpression, ref expression, out stringLiteral);
1023
1024
// If it wasn't a string literal, evaluate it
1025
if (!stringLiteral)
1026
{
1029
- rightValue = this.EvaluateVariable(originalExpression, rightValue);
1027
+ rightValue = this.EvaluateVariable(state, originalExpression, rightValue);
1028
}
1029
}
1030
else
@@ -1052,11 +1050,11 @@ namespace WixToolset.Core
1050
/// <param name="originalExpression">Original expression to evaluate.</param>
1051
/// <param name="expression">Expression modified while processing.</param>
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)
1054
{
1055
// Quick test to see if the first token is a variable
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);
1058
1059
var expressionValue = false;
1060
@@ -1065,7 +1063,7 @@ namespace WixToolset.Core
1063
{
1064
if (operation.Length > 0)
1065
{
1068
- throw new WixException(ErrorMessages.ExpectedVariable(this.Context.CurrentSourceLineNumber, originalExpression));
1066
+ throw new WixException(ErrorMessages.ExpectedVariable(state.Context.CurrentSourceLineNumber, originalExpression));
1067
}
1068
1069
// false expression
@@ -1080,7 +1078,7 @@ namespace WixToolset.Core
1078
}
1079
else
1080
{
1083
- throw new WixException(ErrorMessages.UnexpectedLiteral(this.Context.CurrentSourceLineNumber, originalExpression));
1081
+ throw new WixException(ErrorMessages.UnexpectedLiteral(state.Context.CurrentSourceLineNumber, originalExpression));
1082
}
1083
}
1084
else
@@ -1120,11 +1118,11 @@ namespace WixToolset.Core
1118
}
1119
catch (FormatException)
1120
{
1123
- throw new WixException(ErrorMessages.IllegalIntegerInExpression(this.Context.CurrentSourceLineNumber, originalExpression));
1121
+ throw new WixException(ErrorMessages.IllegalIntegerInExpression(state.Context.CurrentSourceLineNumber, originalExpression));
1122
}
1123
catch (OverflowException)
1124
{
1127
- throw new WixException(ErrorMessages.IllegalIntegerInExpression(this.Context.CurrentSourceLineNumber, originalExpression));
1125
+ throw new WixException(ErrorMessages.IllegalIntegerInExpression(state.Context.CurrentSourceLineNumber, originalExpression));
1126
}
1127
1128
// Compare the numbers
@@ -1148,7 +1146,7 @@ namespace WixToolset.Core
1146
/// <param name="expression">Expression modified while processing.</param>
1147
/// <param name="endSubExpression">Index of end of sub-expression.</param>
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)
1150
{
1151
endSubExpression = 0;
1152
@@ -1166,7 +1164,7 @@ namespace WixToolset.Core
1164
closeParenIndex = expression.IndexOf(')', closeParenIndex);
1165
if (closeParenIndex == -1)
1166
{
1169
- throw new WixException(ErrorMessages.UnmatchedParenthesisInExpression(this.Context.CurrentSourceLineNumber, originalExpression));
1167
+ throw new WixException(ErrorMessages.UnmatchedParenthesisInExpression(state.Context.CurrentSourceLineNumber, originalExpression));
1168
}
1169
1170
if (InsideQuotes(expression, closeParenIndex))
@@ -1201,7 +1199,7 @@ namespace WixToolset.Core
1199
/// <param name="currentValue">State to update.</param>
1200
/// <param name="operation">Operation to apply to current value.</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)
1203
{
1204
switch (operation)
1205
{
@@ -1215,7 +1213,7 @@ namespace WixToolset.Core
1213
currentValue = !currentValue;
1214
break;
1215
default:
1218
- throw new WixException(ErrorMessages.UnexpectedPreprocessorOperator(this.Context.CurrentSourceLineNumber, operation.ToString()));
1216
+ throw new WixException(ErrorMessages.UnexpectedPreprocessorOperator(state.Context.CurrentSourceLineNumber, operation.ToString()));
1217
}
1218
}
1219
@@ -1224,10 +1222,10 @@ namespace WixToolset.Core
1222
/// </summary>
1223
/// <param name="expression">Expression to evaluate.</param>
1224
/// <returns>Boolean result of expression.</returns>
1227
- private bool EvaluateExpression(string expression)
1225
+ private bool EvaluateExpression(ProcessingState state, string expression)
1226
{
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);
1229
}
1230
1231
/// <summary>
@@ -1258,20 +1256,20 @@ namespace WixToolset.Core
1256
/// <param name="prevResultOperation">The operation to apply to this result</param>
1257
/// <param name="prevResult">The previous result to apply to this result</param>
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)
1260
{
1261
var expressionValue = false;
1262
expression = expression.Trim();
1263
if (expression.Length == 0)
1264
{
1267
- throw new WixException(ErrorMessages.UnexpectedEmptySubexpression(this.Context.CurrentSourceLineNumber, originalExpression));
1265
+ throw new WixException(ErrorMessages.UnexpectedEmptySubexpression(state.Context.CurrentSourceLineNumber, originalExpression));
1266
}
1267
1268
// If the expression starts with parenthesis, evaluate it
1269
if (expression.IndexOf('(') == 0)
1270
{
1273
- var subExpression = this.GetParenthesisExpression(originalExpression, expression, out var endSubExpressionIndex);
1274
- expressionValue = this.EvaluateExpressionRecurse(originalExpression, ref subExpression, PreprocessorOperation.And, true);
1271
+ var subExpression = this.GetParenthesisExpression(state, originalExpression, expression, out var endSubExpressionIndex);
1272
+ expressionValue = this.EvaluateExpressionRecurse(state, originalExpression, ref subExpression, PreprocessorOperation.And, true);
1273
1274
// Now get the rest of the expression that hasn't been evaluated
1275
expression = expression.Substring(endSubExpressionIndex).Trim();
@@ -1284,19 +1282,19 @@ namespace WixToolset.Core
1282
expression = expression.Substring(3).Trim();
1283
if (expression.Length == 0)
1284
{
1287
- throw new WixException(ErrorMessages.ExpectedExpressionAfterNot(this.Context.CurrentSourceLineNumber, originalExpression));
1285
+ throw new WixException(ErrorMessages.ExpectedExpressionAfterNot(state.Context.CurrentSourceLineNumber, originalExpression));
1286
}
1287
1290
- expressionValue = this.EvaluateExpressionRecurse(originalExpression, ref expression, PreprocessorOperation.Not, true);
1288
+ expressionValue = this.EvaluateExpressionRecurse(state, originalExpression, ref expression, PreprocessorOperation.Not, true);
1289
}
1290
else // Expect a literal
1291
{
1294
- expressionValue = this.EvaluateAtomicExpression(originalExpression, ref expression);
1292
+ expressionValue = this.EvaluateAtomicExpression(state, originalExpression, ref expression);
1293
1294
// Expect the literal that was just evaluated to already be cut off
1295
}
1296
}
1299
- this.UpdateExpressionValue(ref expressionValue, prevResultOperation, prevResult);
1297
+ this.UpdateExpressionValue(state, ref expressionValue, prevResultOperation, prevResult);
1298
1299
// If there's still an expression left, it must start with AND or OR.
1300
if (expression.Trim().Length > 0)
@@ -1304,16 +1302,16 @@ namespace WixToolset.Core
1302
if (StartsWithKeyword(expression, PreprocessorOperation.And))
1303
{
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);
1306
}
1307
else if (StartsWithKeyword(expression, PreprocessorOperation.Or))
1308
{
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);
1311
}
1312
else
1313
{
1316
- throw new WixException(ErrorMessages.InvalidSubExpression(this.Context.CurrentSourceLineNumber, expression, originalExpression));
1314
+ throw new WixException(ErrorMessages.InvalidSubExpression(state.Context.CurrentSourceLineNumber, expression, originalExpression));
1315
}
1316
}
1317
@@ -1325,16 +1323,16 @@ namespace WixToolset.Core
1323
/// </summary>
1324
/// <param name="reader">The xml reader for the preprocessor.</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)
1327
{
1328
var lineInfoReader = reader as IXmlLineInfo;
1329
if (null != lineInfoReader)
1330
{
1331
var newLine = lineInfoReader.LineNumber + offset;
1332
1335
- if (this.Context.CurrentSourceLineNumber.LineNumber != newLine)
1333
+ if (state.Context.CurrentSourceLineNumber.LineNumber != newLine)
1334
{
1337
- this.Context.CurrentSourceLineNumber = new SourceLineNumber(this.Context.CurrentSourceLineNumber.FileName, newLine);
1335
+ state.Context.CurrentSourceLineNumber = new SourceLineNumber(state.Context.CurrentSourceLineNumber.FileName, newLine);
1336
}
1337
}
1338
}
@@ -1343,28 +1341,28 @@ namespace WixToolset.Core
1341
/// Pushes a file name on the stack of included files.
1342
/// </summary>
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)
1345
{
1348
- if (1023 < this.CurrentFileStack.Count)
1346
+ if (1023 < state.CurrentFileStack.Count)
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));
1349
}
1350
1353
- this.CurrentFileStack.Push(fileName);
1354
- this.SourceStack.Push(this.Context.CurrentSourceLineNumber);
1355
- this.Context.CurrentSourceLineNumber = new SourceLineNumber(fileName);
1356
- this.IncludeNextStack.Push(true);
1351
+ state.CurrentFileStack.Push(fileName);
1352
+ state.SourceStack.Push(state.Context.CurrentSourceLineNumber);
1353
+ state.Context.CurrentSourceLineNumber = new SourceLineNumber(fileName);
1354
+ state.IncludeNextStack.Push(true);
1355
}
1356
1357
/// <summary>
1358
/// Pops a file name from the stack of included files.
1359
/// </summary>
1362
- private void PopInclude()
1360
+ private void PopInclude(ProcessingState state)
1361
{
1364
- this.Context.CurrentSourceLineNumber = this.SourceStack.Pop();
1362
+ state.Context.CurrentSourceLineNumber = state.SourceStack.Pop();
1363
1366
- this.CurrentFileStack.Pop();
1367
- this.IncludeNextStack.Pop();
1364
+ state.CurrentFileStack.Pop();
1365
+ state.IncludeNextStack.Pop();
1366
}
1367
1368
/// <summary>
@@ -1375,7 +1373,7 @@ namespace WixToolset.Core
1373
/// </summary>
1374
/// <param name="includePath">User-specified path to the included file (usually just the file name).</param>
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)
1377
{
1378
string finalIncludePath = null;
1379
@@ -1399,7 +1397,7 @@ namespace WixToolset.Core
1397
else // relative path
1398
{
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();
1401
var includeTestPath = Path.Combine(Path.GetDirectoryName(currentFolder), includePath);
1402
1403
// test the source file directory
@@ -1407,9 +1405,9 @@ namespace WixToolset.Core
1405
{
1406
finalIncludePath = includeTestPath;
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
1409
{
1412
- foreach (var includeSearchPath in this.Context.IncludeSearchPaths)
1410
+ foreach (var includeSearchPath in state.Context.IncludeSearchPaths)
1411
{
1412
// if the path exists, we have found the final string
1413
includeTestPath = Path.Combine(includeSearchPath, includePath);
@@ -1425,17 +1423,22 @@ namespace WixToolset.Core
1423
return finalIncludePath;
1424
}
1425
1428
- private void PreProcess()
1426
+ private void PreProcess(ProcessingState state)
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)
1434
{
1435
if (extension.Prefixes != null)
1436
{
1437
foreach (var prefix in extension.Prefixes)
1438
{
1436
- if (!this.ExtensionsByPrefix.TryGetValue(prefix, out var collidingExtension))
1439
+ if (!state.ExtensionsByPrefix.TryGetValue(prefix, out var collidingExtension))
1440
{
1438
- this.ExtensionsByPrefix.Add(prefix, extension);
1441
+ state.ExtensionsByPrefix.Add(prefix, extension);
1442
}
1443
else
1444
{
@@ -1444,18 +1447,49 @@ namespace WixToolset.Core
1447
}
1448
}
1449
1447
- extension.PrePreprocess(this.Context);
1450
+ extension.PrePreprocess(state.Context);
1451
}
1452
}
1453
1451
- private XDocument PostProcess(XDocument document)
1454
+ private void PostProcess(ProcessingState state, IPreprocessResult result)
1455
{
1453
- foreach (var extension in this.Context.Extensions)
1456
+ if (state.Context.Extensions == null)
1457
{
1455
- extension.PostPreprocess(document);
1458
+ return;
1459
}
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>();
1493
}
1494
}
1495
}
src/WixToolset.Core/WixToolsetServiceProvider.cs
+2
@@ -45,6 +45,8 @@ namespace WixToolset.Core
45
this.AddService<IBindResult>((provider, singletons) => new BindResult());
46
this.AddService<IComponentKeyPath>((provider, singletons) => new ComponentKeyPath());
47
this.AddService<IDecompileResult>((provider, singletons) => new DecompileResult());
48
+ this.AddService<IIncludedFile>((provider, singletons) => new IncludedFile());
49
+ this.AddService<IPreprocessResult>((provider, singletons) => new PreprocessResult());
50
this.AddService<IResolveFileResult>((provider, singletons) => new ResolveFileResult());
51
this.AddService<IResolveResult>((provider, singletons) => new ResolveResult());
52
this.AddService<IResolvedCabinet>((provider, singletons) => new ResolvedCabinet());
src/test/WixToolsetTest.CoreIntegration/PreprocessorFixture.cs
+29
-4
@@ -1,18 +1,43 @@
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
3
namespace WixToolsetTest.CoreIntegration
4
{
5
using System.IO;
6
using System.Linq;
7
using WixBuildTools.TestSupport;
8
+ using WixToolset.Core;
9
using WixToolset.Core.TestPackage;
9
- using WixToolset.Data;
10
- using WixToolset.Data.Tuples;
11
- using WixToolset.Data.WindowsInstaller;
10
+ using WixToolset.Extensibility.Data;
11
using Xunit;
12
13
public class PreprocessorFixture
14
{
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]
42
public void VariableRedefinitionIsAWarning()
43
{