aboutsummaryrefslogtreecommitdiff
path: root/src/WixToolset.Core/CommandLine/CommandLineResponseFile.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/WixToolset.Core/CommandLine/CommandLineResponseFile.cs')
-rw-r--r--src/WixToolset.Core/CommandLine/CommandLineResponseFile.cs137
1 files changed, 137 insertions, 0 deletions
diff --git a/src/WixToolset.Core/CommandLine/CommandLineResponseFile.cs b/src/WixToolset.Core/CommandLine/CommandLineResponseFile.cs
new file mode 100644
index 00000000..f27296b7
--- /dev/null
+++ b/src/WixToolset.Core/CommandLine/CommandLineResponseFile.cs
@@ -0,0 +1,137 @@
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
3namespace WixToolset
4{
5 using System;
6 using System.Collections;
7 using System.Collections.Generic;
8 using System.IO;
9 using System.Text;
10 using System.Text.RegularExpressions;
11
12 /// <summary>
13 /// Common utilities for Wix command-line processing.
14 /// </summary>
15 public static class CommandLineResponseFile
16 {
17 /// <summary>
18 /// Parses a response file.
19 /// </summary>
20 /// <param name="responseFile">The file to parse.</param>
21 /// <returns>The array of arguments.</returns>
22 public static string[] Parse(string responseFile)
23 {
24 string arguments;
25
26 using (StreamReader reader = new StreamReader(responseFile))
27 {
28 arguments = reader.ReadToEnd();
29 }
30
31 return CommandLineResponseFile.ParseArgumentsToArray(arguments);
32 }
33
34 /// <summary>
35 /// Parses an argument string into an argument array based on whitespace and quoting.
36 /// </summary>
37 /// <param name="arguments">Argument string.</param>
38 /// <returns>Argument array.</returns>
39 public static string[] ParseArgumentsToArray(string arguments)
40 {
41 // Scan and parse the arguments string, dividing up the arguments based on whitespace.
42 // Unescaped quotes cause whitespace to be ignored, while the quotes themselves are removed.
43 // Quotes may begin and end inside arguments; they don't necessarily just surround whole arguments.
44 // Escaped quotes and escaped backslashes also need to be unescaped by this process.
45
46 // Collects the final list of arguments to be returned.
47 List<string> argsList = new List<string>();
48
49 // True if we are inside an unescaped quote, meaning whitespace should be ignored.
50 bool insideQuote = false;
51
52 // Index of the start of the current argument substring; either the start of the argument
53 // or the start of a quoted or unquoted sequence within it.
54 int partStart = 0;
55
56 // The current argument string being built; when completed it will be added to the list.
57 StringBuilder arg = new StringBuilder();
58
59 for (int i = 0; i <= arguments.Length; i++)
60 {
61 if (i == arguments.Length || (Char.IsWhiteSpace(arguments[i]) && !insideQuote))
62 {
63 // Reached a whitespace separator or the end of the string.
64
65 // Finish building the current argument.
66 arg.Append(arguments.Substring(partStart, i - partStart));
67
68 // Skip over the whitespace character.
69 partStart = i + 1;
70
71 // Add the argument to the list if it's not empty.
72 if (arg.Length > 0)
73 {
74 argsList.Add(CommandLineResponseFile.ExpandEnvVars(arg.ToString()));
75 arg.Length = 0;
76 }
77 }
78 else if (i > partStart && arguments[i - 1] == '\\')
79 {
80 // Check the character following an unprocessed backslash.
81 // Unescape quotes, and backslashes followed by a quote.
82 if (arguments[i] == '"' || (arguments[i] == '\\' && arguments.Length > i + 1 && arguments[i + 1] == '"'))
83 {
84 // Unescape the quote or backslash by skipping the preceeding backslash.
85 arg.Append(arguments.Substring(partStart, i - 1 - partStart));
86 arg.Append(arguments[i]);
87 partStart = i + 1;
88 }
89 }
90 else if (arguments[i] == '"')
91 {
92 // Add the quoted or unquoted section to the argument string.
93 arg.Append(arguments.Substring(partStart, i - partStart));
94
95 // And skip over the quote character.
96 partStart = i + 1;
97
98 insideQuote = !insideQuote;
99 }
100 }
101
102 return argsList.ToArray();
103 }
104
105 /// <summary>
106 /// Expand enxironment variables contained in the passed string
107 /// </summary>
108 /// <param name="arguments"></param>
109 /// <returns></returns>
110 static private string ExpandEnvVars(string arguments)
111 {
112 IDictionary id = Environment.GetEnvironmentVariables();
113
114 Regex regex = new Regex("(?<=\\%)(?:[\\w\\.]+)(?=\\%)");
115 MatchCollection matches = regex.Matches(arguments);
116
117 string value = String.Empty;
118 for (int i = 0; i <= (matches.Count - 1); i++)
119 {
120 try
121 {
122 string key = matches[i].Value;
123 regex = new Regex(String.Concat("(?i)(?:\\%)(?:" , key , ")(?:\\%)"));
124 value = id[key].ToString();
125 arguments = regex.Replace(arguments, value);
126 }
127 catch (NullReferenceException)
128 {
129 // Collapse unresolved environment variables.
130 arguments = regex.Replace(arguments, value);
131 }
132 }
133
134 return arguments;
135 }
136 }
137}