main
cs 311 lines 11.9 KB
Raw
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.Burn.ExtensibilityServices
4 {
5 using System;
6 using System.Collections.Generic;
7 using System.IO;
8 using System.Text;
9 using System.Xml;
10 using WixToolset.Core.Burn.Bundles;
11 using WixToolset.Data;
12 using WixToolset.Data.Burn;
13 using WixToolset.Data.Symbols;
14 using WixToolset.Data.WindowsInstaller.Rows;
15 using WixToolset.Extensibility.Data;
16 using WixToolset.Extensibility.Services;
17
18 internal class BurnBackendHelper : IInternalBurnBackendHelper
19 {
20 public static readonly XmlReaderSettings ReaderSettings = new XmlReaderSettings { ConformanceLevel = ConformanceLevel.Fragment };
21 public static readonly XmlWriterSettings WriterSettings = new XmlWriterSettings { ConformanceLevel = ConformanceLevel.Fragment };
22
23 private readonly IBackendHelper backendHelper;
24 private readonly IBundleValidator bundleValidator;
25
26 private ManifestData BootstrapperApplicationManifestData { get; } = new ManifestData();
27
28 private Dictionary<string, ManifestData> BootstrapperExtensionDataById { get; } = new Dictionary<string, ManifestData>();
29
30 public BurnBackendHelper(IServiceProvider serviceProvider)
31 {
32 this.backendHelper = serviceProvider.GetService<IBackendHelper>();
33 this.bundleValidator = serviceProvider.GetService<IBundleValidator>();
34 }
35
36 #region IBackendHelper interfaces
37
38 public IFileTransfer CreateFileTransfer(string source, string destination, bool move, SourceLineNumber sourceLineNumbers = null)
39 {
40 return this.backendHelper.CreateFileTransfer(source, destination, move, sourceLineNumbers);
41 }
42
43 public string CreateGuid()
44 {
45 return this.backendHelper.CreateGuid();
46 }
47
48 public string CreateGuid(Guid namespaceGuid, string value)
49 {
50 return this.backendHelper.CreateGuid(namespaceGuid, value);
51 }
52
53 public IResolvedDirectory CreateResolvedDirectory(string directoryParent, string name)
54 {
55 return this.backendHelper.CreateResolvedDirectory(directoryParent, name);
56 }
57
58 public IReadOnlyList<ITrackedFile> ExtractEmbeddedFiles(IEnumerable<IExpectedExtractFile> embeddedFiles)
59 {
60 return this.backendHelper.ExtractEmbeddedFiles(embeddedFiles);
61 }
62
63 public string GenerateIdentifier(string prefix, params string[] args)
64 {
65 return this.backendHelper.GenerateIdentifier(prefix, args);
66 }
67
68 public int GetValidCodePage(string value, bool allowNoChange, bool onlyAnsi = false, SourceLineNumber sourceLineNumbers = null)
69 {
70 return this.backendHelper.GetValidCodePage(value, allowNoChange, onlyAnsi, sourceLineNumbers);
71 }
72
73 public string GetMsiFileName(string value, bool source, bool longName)
74 {
75 return this.backendHelper.GetMsiFileName(value, source, longName);
76 }
77
78 public bool IsValidBinderVariable(string variable)
79 {
80 return this.backendHelper.IsValidBinderVariable(variable);
81 }
82
83 public bool IsValidFourPartVersion(string version)
84 {
85 return this.backendHelper.IsValidFourPartVersion(version);
86 }
87
88 public bool IsValidIdentifier(string id)
89 {
90 return this.backendHelper.IsValidIdentifier(id);
91 }
92
93 public bool IsValidMsiProductVersion(string version)
94 {
95 return this.backendHelper.IsValidMsiProductVersion(version);
96 }
97
98 public bool IsValidWixVersion(string version)
99 {
100 return this.backendHelper.IsValidWixVersion(version);
101 }
102
103 public bool IsValidLongFilename(string filename, bool allowWildcards, bool allowRelative)
104 {
105 return this.backendHelper.IsValidLongFilename(filename, allowWildcards, allowRelative);
106 }
107
108 public bool IsValidShortFilename(string filename, bool allowWildcards)
109 {
110 return this.backendHelper.IsValidShortFilename(filename, allowWildcards);
111 }
112
113 public void ResolveDelayedFields(IEnumerable<IDelayedField> delayedFields, Dictionary<string, string> variableCache)
114 {
115 this.backendHelper.ResolveDelayedFields(delayedFields, variableCache);
116 }
117
118 public string[] SplitMsiFileName(string value)
119 {
120 return this.backendHelper.SplitMsiFileName(value);
121 }
122
123 public bool TryParseFourPartVersion(string version, out string parsedVersion)
124 {
125 return this.backendHelper.TryParseFourPartVersion(version, out parsedVersion);
126 }
127
128 public bool TryParseMsiProductVersion(string version, bool strict, out string parsedVersion)
129 {
130 return this.backendHelper.TryParseMsiProductVersion(version, strict, out parsedVersion);
131 }
132
133 public ITrackedFile TrackFile(string path, TrackedFileType type, SourceLineNumber sourceLineNumbers = null)
134 {
135 return this.backendHelper.TrackFile(path, type, sourceLineNumbers);
136 }
137
138 #endregion
139
140 #region IBurnBackendHelper interfaces
141
142 public void AddBootstrapperApplicationData(string xml)
143 {
144 this.BootstrapperApplicationManifestData.AddXml(xml);
145 }
146
147 public void AddBootstrapperApplicationData(IntermediateSymbol symbol, bool symbolIdIsIdAttribute = false)
148 {
149 this.BootstrapperApplicationManifestData.AddSymbol(symbol, symbolIdIsIdAttribute, BurnConstants.BootstrapperApplicationDataNamespace);
150 }
151
152 public void AddBootstrapperExtensionData(string extensionId, string xml)
153 {
154 var manifestData = this.GetBootstrapperExtensionManifestData(extensionId);
155 manifestData.AddXml(xml);
156 }
157
158 public void AddBootstrapperExtensionData(string extensionId, IntermediateSymbol symbol, bool symbolIdIsIdAttribute = false)
159 {
160 var manifestData = this.GetBootstrapperExtensionManifestData(extensionId);
161 manifestData.AddSymbol(symbol, symbolIdIsIdAttribute, BurnConstants.BootstrapperExtensionDataNamespace);
162 }
163
164 #endregion
165
166 #region IBundleValidator
167
168 public string GetCanonicalRelativePath(SourceLineNumber sourceLineNumbers, string elementName, string attributeName, string relativePath)
169 {
170 return this.bundleValidator.GetCanonicalRelativePath(sourceLineNumbers, elementName, attributeName, relativePath);
171 }
172
173 public bool ValidateBundleMsiPropertyName(SourceLineNumber sourceLineNumbers, string elementName, string attributeName, string propertyName)
174 {
175 return this.bundleValidator.ValidateBundleMsiPropertyName(sourceLineNumbers, elementName, attributeName, propertyName);
176 }
177
178 public bool ValidateBundleVariableNameDeclaration(SourceLineNumber sourceLineNumbers, string elementName, string attributeName, string variableName)
179 {
180 return this.bundleValidator.ValidateBundleVariableNameDeclaration(sourceLineNumbers, elementName, attributeName, variableName);
181 }
182
183 public bool ValidateBundleVariableNameValue(SourceLineNumber sourceLineNumbers, string elementName, string attributeName, string variableName, BundleVariableNameRule nameRule)
184 {
185 return this.bundleValidator.ValidateBundleVariableNameValue(sourceLineNumbers, elementName, attributeName, variableName, nameRule);
186 }
187
188 public bool ValidateBundleVariableNameTarget(SourceLineNumber sourceLineNumbers, string elementName, string attributeName, string variableName)
189 {
190 return this.bundleValidator.ValidateBundleVariableNameTarget(sourceLineNumbers, elementName, attributeName, variableName);
191 }
192
193 public bool ValidateBundleCondition(SourceLineNumber sourceLineNumbers, string elementName, string attributeName, string condition, BundleConditionPhase phase)
194 {
195 return this.bundleValidator.ValidateBundleCondition(sourceLineNumbers, elementName, attributeName, condition, phase);
196 }
197
198 #endregion
199
200 #region IInternalBurnBackendHelper interfaces
201
202 public void WriteBootstrapperApplicationData(XmlWriter writer)
203 {
204 this.BootstrapperApplicationManifestData.Write(writer);
205 }
206
207 public void WriteBootstrapperExtensionData(XmlWriter writer)
208 {
209 foreach (var kvp in this.BootstrapperExtensionDataById)
210 {
211 this.WriteExtension(writer, kvp.Key, kvp.Value);
212 }
213 }
214
215 #endregion
216
217 private ManifestData GetBootstrapperExtensionManifestData(string extensionId)
218 {
219 if (!this.backendHelper.IsValidIdentifier(extensionId))
220 {
221 throw new ArgumentException($"'{extensionId}' is not a valid extensionId");
222 }
223
224 if (!this.BootstrapperExtensionDataById.TryGetValue(extensionId, out var manifestData))
225 {
226 manifestData = new ManifestData();
227 this.BootstrapperExtensionDataById.Add(extensionId, manifestData);
228 }
229
230 return manifestData;
231 }
232
233 private void WriteExtension(XmlWriter writer, string extensionId, ManifestData manifestData)
234 {
235 writer.WriteStartElement("BootstrapperExtension");
236
237 writer.WriteAttributeString("Id", extensionId);
238
239 manifestData.Write(writer);
240
241 writer.WriteEndElement();
242 }
243
244 private class ManifestData
245 {
246 public ManifestData()
247 {
248 this.Builder = new StringBuilder();
249 }
250
251 private StringBuilder Builder { get; }
252
253 public void AddSymbol(IntermediateSymbol symbol, bool symbolIdIsIdAttribute, string ns)
254 {
255 // There might be a more efficient way to do this,
256 // but this is an easy way to ensure we're creating valid XML.
257 var sb = new StringBuilder();
258 using (var writer = XmlWriter.Create(sb, WriterSettings))
259 {
260 writer.WriteStartElement(symbol.Definition.Name, ns);
261
262 if (symbolIdIsIdAttribute && symbol.Id != null)
263 {
264 writer.WriteAttributeString("Id", symbol.Id.Id);
265 }
266
267 foreach (var field in symbol.Fields)
268 {
269 if (!field.IsNull())
270 {
271 writer.WriteAttributeString(field.Definition.Name, field.AsString());
272 }
273 }
274
275 writer.WriteEndElement();
276 }
277
278 this.AddXml(sb.ToString());
279 }
280
281 public void AddXml(string xml)
282 {
283 // There might be a more efficient way to do this,
284 // but this is an easy way to ensure we're given valid XML.
285 var sb = new StringBuilder();
286 using (var xmlWriter = XmlWriter.Create(sb, WriterSettings))
287 {
288 AddManifestDataFromString(xmlWriter, xml);
289 }
290 this.Builder.Append(sb.ToString());
291 }
292
293 public void Write(XmlWriter writer)
294 {
295 AddManifestDataFromString(writer, this.Builder.ToString());
296 }
297
298 private static void AddManifestDataFromString(XmlWriter xmlWriter, string xml)
299 {
300 using (var stringReader = new StringReader(xml))
301 using (var xmlReader = XmlReader.Create(stringReader, ReaderSettings))
302 {
303 while (xmlReader.MoveToContent() != XmlNodeType.None)
304 {
305 xmlWriter.WriteNode(xmlReader, false);
306 }
307 }
308 }
309 }
310 }
311 }