diff options
Diffstat (limited to 'src/WixToolset.Core/Compiler.cs')
-rw-r--r-- | src/WixToolset.Core/Compiler.cs | 20667 |
1 files changed, 20667 insertions, 0 deletions
diff --git a/src/WixToolset.Core/Compiler.cs b/src/WixToolset.Core/Compiler.cs new file mode 100644 index 00000000..00618152 --- /dev/null +++ b/src/WixToolset.Core/Compiler.cs | |||
@@ -0,0 +1,20667 @@ | |||
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 | ||
4 | { | ||
5 | using System; | ||
6 | using System.Collections; | ||
7 | using System.Collections.Generic; | ||
8 | using System.Diagnostics; | ||
9 | using System.Diagnostics.CodeAnalysis; | ||
10 | using System.Globalization; | ||
11 | using System.IO; | ||
12 | using System.Text.RegularExpressions; | ||
13 | using System.Xml.Linq; | ||
14 | using WixToolset.Data; | ||
15 | using WixToolset.Data.Rows; | ||
16 | using WixToolset.Extensibility; | ||
17 | using WixToolset.Msi; | ||
18 | using WixToolset.Core.Native; | ||
19 | using Wix = WixToolset.Data.Serialize; | ||
20 | |||
21 | /// <summary> | ||
22 | /// Compiler of the WiX toolset. | ||
23 | /// </summary> | ||
24 | [SuppressMessage("Microsoft.Naming", "CA1724:TypeNamesShouldNotMatchNamespaces")] | ||
25 | public sealed class Compiler | ||
26 | { | ||
27 | public const string UpgradeDetectedProperty = "WIX_UPGRADE_DETECTED"; | ||
28 | public const string UpgradePreventedCondition = "NOT WIX_UPGRADE_DETECTED"; | ||
29 | public const string DowngradeDetectedProperty = "WIX_DOWNGRADE_DETECTED"; | ||
30 | public const string DowngradePreventedCondition = "NOT WIX_DOWNGRADE_DETECTED"; | ||
31 | public const string DefaultComponentIdPlaceholderFormat = "WixComponentIdPlaceholder{0}"; | ||
32 | public const string DefaultComponentIdPlaceholderWixVariableFormat = "!(wix.{0})"; | ||
33 | public const string BurnUXContainerId = "WixUXContainer"; | ||
34 | public const string BurnDefaultAttachedContainerId = "WixAttachedContainer"; | ||
35 | |||
36 | // The following constants must stay in sync with src\burn\engine\core.h | ||
37 | private const string BURN_BUNDLE_NAME = "WixBundleName"; | ||
38 | private const string BURN_BUNDLE_ORIGINAL_SOURCE = "WixBundleOriginalSource"; | ||
39 | private const string BURN_BUNDLE_ORIGINAL_SOURCE_FOLDER = "WixBundleOriginalSourceFolder"; | ||
40 | private const string BURN_BUNDLE_LAST_USED_SOURCE = "WixBundleLastUsedSource"; | ||
41 | |||
42 | private TableDefinitionCollection tableDefinitions; | ||
43 | private Dictionary<XNamespace, ICompilerExtension> extensions; | ||
44 | private List<InspectorExtension> inspectorExtensions; | ||
45 | private CompilerCore core; | ||
46 | private bool showPedanticMessages; | ||
47 | |||
48 | // if these are true you know you are building a module or product | ||
49 | // but if they are false you cannot not be sure they will not end | ||
50 | // up a product or module. Use these flags carefully. | ||
51 | private bool compilingModule; | ||
52 | private bool compilingProduct; | ||
53 | |||
54 | private bool useShortFileNames; | ||
55 | private string activeName; | ||
56 | private string activeLanguage; | ||
57 | |||
58 | private WixVariableResolver componentIdPlaceholdersResolver; | ||
59 | |||
60 | /// <summary> | ||
61 | /// Creates a new compiler object with a default set of table definitions. | ||
62 | /// </summary> | ||
63 | public Compiler() | ||
64 | { | ||
65 | this.tableDefinitions = new TableDefinitionCollection(WindowsInstallerStandard.GetTableDefinitions()); | ||
66 | this.extensions = new Dictionary<XNamespace, ICompilerExtension>(); | ||
67 | this.inspectorExtensions = new List<InspectorExtension>(); | ||
68 | |||
69 | this.CurrentPlatform = Platform.X86; | ||
70 | } | ||
71 | |||
72 | /// <summary> | ||
73 | /// Type of RadioButton element in a group. | ||
74 | /// </summary> | ||
75 | private enum RadioButtonType | ||
76 | { | ||
77 | /// <summary>Not set, yet.</summary> | ||
78 | NotSet, | ||
79 | |||
80 | /// <summary>Text</summary> | ||
81 | Text, | ||
82 | |||
83 | /// <summary>Bitmap</summary> | ||
84 | Bitmap, | ||
85 | |||
86 | /// <summary>Icon</summary> | ||
87 | Icon, | ||
88 | } | ||
89 | |||
90 | /// <summary> | ||
91 | /// Gets or sets the platform which the compiler will use when defaulting 64-bit attributes and elements. | ||
92 | /// </summary> | ||
93 | /// <value>The platform which the compiler will use when defaulting 64-bit attributes and elements.</value> | ||
94 | public Platform CurrentPlatform { get; set; } | ||
95 | |||
96 | /// <summary> | ||
97 | /// Gets or sets the option to show pedantic messages. | ||
98 | /// </summary> | ||
99 | /// <value>The option to show pedantic messages.</value> | ||
100 | public bool ShowPedanticMessages | ||
101 | { | ||
102 | get { return this.showPedanticMessages; } | ||
103 | set { this.showPedanticMessages = value; } | ||
104 | } | ||
105 | |||
106 | /// <summary> | ||
107 | /// Adds a compiler extension. | ||
108 | /// </summary> | ||
109 | /// <param name="extension">The extension to add.</param> | ||
110 | public void AddExtension(ICompilerExtension extension) | ||
111 | { | ||
112 | // Check if this extension is adding a schema namespace that already exists. | ||
113 | ICompilerExtension collidingExtension; | ||
114 | if (!this.extensions.TryGetValue(extension.Namespace, out collidingExtension)) | ||
115 | { | ||
116 | this.extensions.Add(extension.Namespace, extension); | ||
117 | } | ||
118 | else | ||
119 | { | ||
120 | Messaging.Instance.OnMessage(WixErrors.DuplicateExtensionXmlSchemaNamespace(extension.GetType().ToString(), extension.Namespace.NamespaceName, collidingExtension.GetType().ToString())); | ||
121 | } | ||
122 | |||
123 | //if (null != extension.InspectorExtension) | ||
124 | //{ | ||
125 | // this.inspectorExtensions.Add(extension.InspectorExtension); | ||
126 | //} | ||
127 | } | ||
128 | |||
129 | /// <summary> | ||
130 | /// Adds table definitions from an extension | ||
131 | /// </summary> | ||
132 | /// <param name="extension">Extension with table definitions.</param> | ||
133 | public void AddExtensionData(IExtensionData extension) | ||
134 | { | ||
135 | if (null != extension.TableDefinitions) | ||
136 | { | ||
137 | foreach (TableDefinition tableDefinition in extension.TableDefinitions) | ||
138 | { | ||
139 | if (!this.tableDefinitions.Contains(tableDefinition.Name)) | ||
140 | { | ||
141 | this.tableDefinitions.Add(tableDefinition); | ||
142 | } | ||
143 | else | ||
144 | { | ||
145 | Messaging.Instance.OnMessage(WixErrors.DuplicateExtensionTable(extension.GetType().ToString(), tableDefinition.Name)); | ||
146 | } | ||
147 | } | ||
148 | } | ||
149 | } | ||
150 | |||
151 | /// <summary> | ||
152 | /// Compiles the provided Xml document into an intermediate object | ||
153 | /// </summary> | ||
154 | /// <param name="source">Source xml document to compile. The BaseURI property | ||
155 | /// should be properly set to get messages containing source line information.</param> | ||
156 | /// <returns>Intermediate object representing compiled source document.</returns> | ||
157 | /// <remarks>This method is not thread-safe.</remarks> | ||
158 | [SuppressMessage("Microsoft.Design", "CA1059:MembersShouldNotExposeCertainConcreteTypes")] | ||
159 | public Intermediate Compile(XDocument source) | ||
160 | { | ||
161 | if (null == source) | ||
162 | { | ||
163 | throw new ArgumentNullException("source"); | ||
164 | } | ||
165 | |||
166 | bool encounteredError = false; | ||
167 | |||
168 | // create the intermediate | ||
169 | Intermediate target = new Intermediate(); | ||
170 | |||
171 | // try to compile it | ||
172 | try | ||
173 | { | ||
174 | this.core = new CompilerCore(target, this.tableDefinitions, this.extensions); | ||
175 | this.core.ShowPedanticMessages = this.showPedanticMessages; | ||
176 | this.core.CurrentPlatform = this.CurrentPlatform; | ||
177 | this.componentIdPlaceholdersResolver = new WixVariableResolver(); | ||
178 | |||
179 | foreach (CompilerExtension extension in this.extensions.Values) | ||
180 | { | ||
181 | extension.Core = this.core; | ||
182 | extension.Initialize(); | ||
183 | } | ||
184 | |||
185 | // parse the document | ||
186 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(source.Root); | ||
187 | if ("Wix" == source.Root.Name.LocalName) | ||
188 | { | ||
189 | if (CompilerCore.WixNamespace == source.Root.Name.Namespace) | ||
190 | { | ||
191 | this.ParseWixElement(source.Root); | ||
192 | } | ||
193 | else // invalid or missing namespace | ||
194 | { | ||
195 | if (String.IsNullOrEmpty(source.Root.Name.NamespaceName)) | ||
196 | { | ||
197 | this.core.OnMessage(WixErrors.InvalidWixXmlNamespace(sourceLineNumbers, "Wix", CompilerCore.WixNamespace.ToString())); | ||
198 | } | ||
199 | else | ||
200 | { | ||
201 | this.core.OnMessage(WixErrors.InvalidWixXmlNamespace(sourceLineNumbers, "Wix", source.Root.Name.NamespaceName, CompilerCore.WixNamespace.ToString())); | ||
202 | } | ||
203 | } | ||
204 | } | ||
205 | else | ||
206 | { | ||
207 | this.core.OnMessage(WixErrors.InvalidDocumentElement(sourceLineNumbers, source.Root.Name.LocalName, "source", "Wix")); | ||
208 | } | ||
209 | |||
210 | // Resolve any Component Id placeholders compiled into the intermediate. | ||
211 | if (0 < this.componentIdPlaceholdersResolver.VariableCount) | ||
212 | { | ||
213 | foreach (var section in target.Sections) | ||
214 | { | ||
215 | foreach (Table table in section.Tables) | ||
216 | { | ||
217 | foreach (Row row in table.Rows) | ||
218 | { | ||
219 | foreach (Field field in row.Fields) | ||
220 | { | ||
221 | if (field.Data is string) | ||
222 | { | ||
223 | bool isDefault = false; | ||
224 | bool delayedResolve = false; | ||
225 | field.Data = this.componentIdPlaceholdersResolver.ResolveVariables(row.SourceLineNumbers, (string)field.Data, false, false, ref isDefault, ref delayedResolve); | ||
226 | } | ||
227 | } | ||
228 | } | ||
229 | } | ||
230 | } | ||
231 | } | ||
232 | |||
233 | // inspect the document | ||
234 | InspectorCore inspectorCore = new InspectorCore(); | ||
235 | foreach (InspectorExtension inspectorExtension in this.inspectorExtensions) | ||
236 | { | ||
237 | inspectorExtension.Core = inspectorCore; | ||
238 | inspectorExtension.InspectIntermediate(target); | ||
239 | |||
240 | // reset | ||
241 | inspectorExtension.Core = null; | ||
242 | } | ||
243 | |||
244 | if (inspectorCore.EncounteredError) | ||
245 | { | ||
246 | encounteredError = true; | ||
247 | } | ||
248 | } | ||
249 | finally | ||
250 | { | ||
251 | if (this.core.EncounteredError) | ||
252 | { | ||
253 | encounteredError = true; | ||
254 | } | ||
255 | |||
256 | foreach (CompilerExtension extension in this.extensions.Values) | ||
257 | { | ||
258 | extension.Finish(); | ||
259 | extension.Core = null; | ||
260 | } | ||
261 | this.core = null; | ||
262 | } | ||
263 | |||
264 | // return the compiled intermediate only if it completed successfully | ||
265 | return (encounteredError ? null : target); | ||
266 | } | ||
267 | |||
268 | /// <summary> | ||
269 | /// Uppercases the first character of a string. | ||
270 | /// </summary> | ||
271 | /// <param name="s">String to uppercase first character of.</param> | ||
272 | /// <returns>String with first character uppercased.</returns> | ||
273 | private static string UppercaseFirstChar(string s) | ||
274 | { | ||
275 | if (0 == s.Length) | ||
276 | { | ||
277 | return s; | ||
278 | } | ||
279 | |||
280 | return String.Concat(s.Substring(0, 1).ToUpper(CultureInfo.InvariantCulture), s.Substring(1)); | ||
281 | } | ||
282 | |||
283 | /// <summary> | ||
284 | /// Lowercases the string if present. | ||
285 | /// </summary> | ||
286 | /// <param name="s">String to lowercase.</param> | ||
287 | /// <returns>Null if the string is null, otherwise returns the lowercase.</returns> | ||
288 | private static string LowercaseOrNull(string s) | ||
289 | { | ||
290 | return (null == s) ? s : s.ToLowerInvariant(); | ||
291 | } | ||
292 | |||
293 | /// <summary> | ||
294 | /// Given a possible short and long file name, create an msi filename value. | ||
295 | /// </summary> | ||
296 | /// <param name="shortName">The short file name.</param> | ||
297 | /// <param name="longName">Possibly the long file name.</param> | ||
298 | /// <returns>The value in the msi filename data type.</returns> | ||
299 | private string GetMsiFilenameValue(string shortName, string longName) | ||
300 | { | ||
301 | if (null != shortName && null != longName && !String.Equals(shortName, longName, StringComparison.OrdinalIgnoreCase)) | ||
302 | { | ||
303 | return String.Format(CultureInfo.InvariantCulture, "{0}|{1}", shortName, longName); | ||
304 | } | ||
305 | else | ||
306 | { | ||
307 | if (this.core.IsValidShortFilename(longName, false)) | ||
308 | { | ||
309 | return longName; | ||
310 | } | ||
311 | else | ||
312 | { | ||
313 | return shortName; | ||
314 | } | ||
315 | } | ||
316 | } | ||
317 | |||
318 | /// <summary> | ||
319 | /// Adds a search property to the active section. | ||
320 | /// </summary> | ||
321 | /// <param name="sourceLineNumbers">Current source/line number of processing.</param> | ||
322 | /// <param name="property">Property to add to search.</param> | ||
323 | /// <param name="signature">Signature for search.</param> | ||
324 | private void AddAppSearch(SourceLineNumber sourceLineNumbers, Identifier property, string signature) | ||
325 | { | ||
326 | if (!this.core.EncounteredError) | ||
327 | { | ||
328 | if (property.Id != property.Id.ToUpperInvariant()) | ||
329 | { | ||
330 | this.core.OnMessage(WixErrors.SearchPropertyNotUppercase(sourceLineNumbers, "Property", "Id", property.Id)); | ||
331 | } | ||
332 | |||
333 | Row row = this.core.CreateRow(sourceLineNumbers, "AppSearch", property); | ||
334 | row[1] = signature; | ||
335 | } | ||
336 | } | ||
337 | |||
338 | /// <summary> | ||
339 | /// Adds a property to the active section. | ||
340 | /// </summary> | ||
341 | /// <param name="sourceLineNumbers">Current source/line number of processing.</param> | ||
342 | /// <param name="property">Name of property to add.</param> | ||
343 | /// <param name="value">Value of property.</param> | ||
344 | /// <param name="admin">Flag if property is an admin property.</param> | ||
345 | /// <param name="secure">Flag if property is a secure property.</param> | ||
346 | /// <param name="hidden">Flag if property is to be hidden.</param> | ||
347 | /// <param name="fragment">Adds the property to a new section.</param> | ||
348 | private void AddProperty(SourceLineNumber sourceLineNumbers, Identifier property, string value, bool admin, bool secure, bool hidden, bool fragment) | ||
349 | { | ||
350 | // properties without a valid identifier should not be processed any further | ||
351 | if (null == property || String.IsNullOrEmpty(property.Id)) | ||
352 | { | ||
353 | return; | ||
354 | } | ||
355 | |||
356 | if (!String.IsNullOrEmpty(value)) | ||
357 | { | ||
358 | Regex regex = new Regex(@"\[(?<identifier>[a-zA-Z_][a-zA-Z0-9_\.]*)]", RegexOptions.Compiled | RegexOptions.Singleline | RegexOptions.ExplicitCapture); | ||
359 | MatchCollection matches = regex.Matches(value); | ||
360 | |||
361 | foreach (Match match in matches) | ||
362 | { | ||
363 | Group group = match.Groups["identifier"]; | ||
364 | if (group.Success) | ||
365 | { | ||
366 | this.core.OnMessage(WixWarnings.PropertyValueContainsPropertyReference(sourceLineNumbers, property.Id, group.Value)); | ||
367 | } | ||
368 | } | ||
369 | } | ||
370 | |||
371 | if (!this.core.EncounteredError) | ||
372 | { | ||
373 | Section section = this.core.ActiveSection; | ||
374 | |||
375 | // Add the row to a separate section if requested. | ||
376 | if (fragment) | ||
377 | { | ||
378 | string id = String.Concat(this.core.ActiveSection.Id, ".", property.Id); | ||
379 | |||
380 | section = this.core.CreateSection(id, SectionType.Fragment, this.core.ActiveSection.Codepage); | ||
381 | |||
382 | // Reference the property in the active section. | ||
383 | this.core.CreateSimpleReference(sourceLineNumbers, "Property", property.Id); | ||
384 | } | ||
385 | |||
386 | Row row = this.core.CreateRow(sourceLineNumbers, "Property", section, property); | ||
387 | |||
388 | // Allow row to exist with no value so that PropertyRefs can be made for *Search elements | ||
389 | // the linker will remove these rows before the final output is created. | ||
390 | if (null != value) | ||
391 | { | ||
392 | row[1] = value; | ||
393 | } | ||
394 | |||
395 | if (admin || hidden || secure) | ||
396 | { | ||
397 | this.AddWixPropertyRow(sourceLineNumbers, property, admin, secure, hidden, section); | ||
398 | } | ||
399 | } | ||
400 | } | ||
401 | |||
402 | private WixPropertyRow AddWixPropertyRow(SourceLineNumber sourceLineNumbers, Identifier property, bool admin, bool secure, bool hidden, Section section = null) | ||
403 | { | ||
404 | if (secure && property.Id != property.Id.ToUpperInvariant()) | ||
405 | { | ||
406 | this.core.OnMessage(WixErrors.SecurePropertyNotUppercase(sourceLineNumbers, "Property", "Id", property.Id)); | ||
407 | } | ||
408 | |||
409 | if (null == section) | ||
410 | { | ||
411 | section = this.core.ActiveSection; | ||
412 | |||
413 | this.core.EnsureTable(sourceLineNumbers, "Property"); // Property table is always required when using WixProperty table. | ||
414 | } | ||
415 | |||
416 | WixPropertyRow row = (WixPropertyRow)this.core.CreateRow(sourceLineNumbers, "WixProperty", section, property); | ||
417 | row.Admin = admin; | ||
418 | row.Hidden = hidden; | ||
419 | row.Secure = secure; | ||
420 | |||
421 | return row; | ||
422 | } | ||
423 | |||
424 | /// <summary> | ||
425 | /// Adds a "implemented category" registry key to active section. | ||
426 | /// </summary> | ||
427 | /// <param name="sourceLineNumbers">Current source/line number of processing.</param> | ||
428 | /// <param name="categoryId">GUID for category.</param> | ||
429 | /// <param name="classId">ClassId for to mark "implemented".</param> | ||
430 | /// <param name="componentId">Identifier of parent component.</param> | ||
431 | private void RegisterImplementedCategories(SourceLineNumber sourceLineNumbers, string categoryId, string classId, string componentId) | ||
432 | { | ||
433 | this.core.CreateRegistryRow(sourceLineNumbers, MsiInterop.MsidbRegistryRootClassesRoot, String.Concat("CLSID\\", classId, "\\Implemented Categories\\", categoryId), "*", null, componentId); | ||
434 | } | ||
435 | |||
436 | /// <summary> | ||
437 | /// Parses an application identifer element. | ||
438 | /// </summary> | ||
439 | /// <param name="node">Element to parse.</param> | ||
440 | /// <param name="componentId">Identifier of parent component.</param> | ||
441 | /// <param name="advertise">The required advertise state (set depending upon the parent).</param> | ||
442 | /// <param name="fileServer">Optional file identifier for CLSID when not advertised.</param> | ||
443 | /// <param name="typeLibId">Optional TypeLib GUID for CLSID.</param> | ||
444 | /// <param name="typeLibVersion">Optional TypeLib Version for CLSID Interfaces (if any).</param> | ||
445 | private void ParseAppIdElement(XElement node, string componentId, YesNoType advertise, string fileServer, string typeLibId, string typeLibVersion) | ||
446 | { | ||
447 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
448 | string appId = null; | ||
449 | string remoteServerName = null; | ||
450 | string localService = null; | ||
451 | string serviceParameters = null; | ||
452 | string dllSurrogate = null; | ||
453 | YesNoType activateAtStorage = YesNoType.NotSet; | ||
454 | YesNoType appIdAdvertise = YesNoType.NotSet; | ||
455 | YesNoType runAsInteractiveUser = YesNoType.NotSet; | ||
456 | string description = null; | ||
457 | |||
458 | foreach (XAttribute attrib in node.Attributes()) | ||
459 | { | ||
460 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
461 | { | ||
462 | switch (attrib.Name.LocalName) | ||
463 | { | ||
464 | case "Id": | ||
465 | appId = this.core.GetAttributeGuidValue(sourceLineNumbers, attrib, false); | ||
466 | break; | ||
467 | case "ActivateAtStorage": | ||
468 | activateAtStorage = this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
469 | break; | ||
470 | case "Advertise": | ||
471 | appIdAdvertise = this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
472 | break; | ||
473 | case "Description": description = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
474 | break; | ||
475 | case "DllSurrogate": | ||
476 | dllSurrogate = this.core.GetAttributeValue(sourceLineNumbers, attrib, EmptyRule.CanBeEmpty); | ||
477 | break; | ||
478 | case "LocalService": | ||
479 | localService = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
480 | break; | ||
481 | case "RemoteServerName": | ||
482 | remoteServerName = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
483 | break; | ||
484 | case "RunAsInteractiveUser": | ||
485 | runAsInteractiveUser = this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
486 | break; | ||
487 | case "ServiceParameters": | ||
488 | serviceParameters = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
489 | break; | ||
490 | default: | ||
491 | this.core.UnexpectedAttribute(node, attrib); | ||
492 | break; | ||
493 | } | ||
494 | } | ||
495 | else | ||
496 | { | ||
497 | this.core.ParseExtensionAttribute(node, attrib); | ||
498 | } | ||
499 | } | ||
500 | |||
501 | if (null == appId) | ||
502 | { | ||
503 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
504 | } | ||
505 | |||
506 | if ((YesNoType.No == advertise && YesNoType.Yes == appIdAdvertise) || (YesNoType.Yes == advertise && YesNoType.No == appIdAdvertise)) | ||
507 | { | ||
508 | this.core.OnMessage(WixErrors.AppIdIncompatibleAdvertiseState(sourceLineNumbers, node.Name.LocalName, "Advertise", appIdAdvertise.ToString(), advertise.ToString())); | ||
509 | } | ||
510 | else | ||
511 | { | ||
512 | advertise = appIdAdvertise; | ||
513 | } | ||
514 | |||
515 | // if the advertise state has not been set, default to non-advertised | ||
516 | if (YesNoType.NotSet == advertise) | ||
517 | { | ||
518 | advertise = YesNoType.No; | ||
519 | } | ||
520 | |||
521 | foreach (XElement child in node.Elements()) | ||
522 | { | ||
523 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
524 | { | ||
525 | switch (child.Name.LocalName) | ||
526 | { | ||
527 | case "Class": | ||
528 | this.ParseClassElement(child, componentId, advertise, fileServer, typeLibId, typeLibVersion, appId); | ||
529 | break; | ||
530 | default: | ||
531 | this.core.UnexpectedElement(node, child); | ||
532 | break; | ||
533 | } | ||
534 | } | ||
535 | else | ||
536 | { | ||
537 | this.core.ParseExtensionElement(node, child); | ||
538 | } | ||
539 | } | ||
540 | |||
541 | if (YesNoType.Yes == advertise) | ||
542 | { | ||
543 | if (null != description) | ||
544 | { | ||
545 | this.core.OnMessage(WixErrors.IllegalAttributeWhenAdvertised(sourceLineNumbers, node.Name.LocalName, "Description")); | ||
546 | } | ||
547 | |||
548 | if (!this.core.EncounteredError) | ||
549 | { | ||
550 | Row row = this.core.CreateRow(sourceLineNumbers, "AppId"); | ||
551 | row[0] = appId; | ||
552 | row[1] = remoteServerName; | ||
553 | row[2] = localService; | ||
554 | row[3] = serviceParameters; | ||
555 | row[4] = dllSurrogate; | ||
556 | if (YesNoType.Yes == activateAtStorage) | ||
557 | { | ||
558 | row[5] = 1; | ||
559 | } | ||
560 | |||
561 | if (YesNoType.Yes == runAsInteractiveUser) | ||
562 | { | ||
563 | row[6] = 1; | ||
564 | } | ||
565 | } | ||
566 | } | ||
567 | else if (YesNoType.No == advertise) | ||
568 | { | ||
569 | if (null != description) | ||
570 | { | ||
571 | this.core.CreateRegistryRow(sourceLineNumbers, MsiInterop.MsidbRegistryRootClassesRoot, String.Concat("AppID\\", appId), null, description, componentId); | ||
572 | } | ||
573 | else | ||
574 | { | ||
575 | this.core.CreateRegistryRow(sourceLineNumbers, MsiInterop.MsidbRegistryRootClassesRoot, String.Concat("AppID\\", appId), "+", null, componentId); | ||
576 | } | ||
577 | |||
578 | if (null != remoteServerName) | ||
579 | { | ||
580 | this.core.CreateRegistryRow(sourceLineNumbers, MsiInterop.MsidbRegistryRootClassesRoot, String.Concat("AppID\\", appId), "RemoteServerName", remoteServerName, componentId); | ||
581 | } | ||
582 | |||
583 | if (null != localService) | ||
584 | { | ||
585 | this.core.CreateRegistryRow(sourceLineNumbers, MsiInterop.MsidbRegistryRootClassesRoot, String.Concat("AppID\\", appId), "LocalService", localService, componentId); | ||
586 | } | ||
587 | |||
588 | if (null != serviceParameters) | ||
589 | { | ||
590 | this.core.CreateRegistryRow(sourceLineNumbers, MsiInterop.MsidbRegistryRootClassesRoot, String.Concat("AppID\\", appId), "ServiceParameters", serviceParameters, componentId); | ||
591 | } | ||
592 | |||
593 | if (null != dllSurrogate) | ||
594 | { | ||
595 | this.core.CreateRegistryRow(sourceLineNumbers, MsiInterop.MsidbRegistryRootClassesRoot, String.Concat("AppID\\", appId), "DllSurrogate", dllSurrogate, componentId); | ||
596 | } | ||
597 | |||
598 | if (YesNoType.Yes == activateAtStorage) | ||
599 | { | ||
600 | this.core.CreateRegistryRow(sourceLineNumbers, MsiInterop.MsidbRegistryRootClassesRoot, String.Concat("AppID\\", appId), "ActivateAtStorage", "Y", componentId); | ||
601 | } | ||
602 | |||
603 | if (YesNoType.Yes == runAsInteractiveUser) | ||
604 | { | ||
605 | this.core.CreateRegistryRow(sourceLineNumbers, MsiInterop.MsidbRegistryRootClassesRoot, String.Concat("AppID\\", appId), "RunAs", "Interactive User", componentId); | ||
606 | } | ||
607 | } | ||
608 | } | ||
609 | |||
610 | /// <summary> | ||
611 | /// Parses an AssemblyName element. | ||
612 | /// </summary> | ||
613 | /// <param name="node">File element to parse.</param> | ||
614 | /// <param name="componentId">Parent's component id.</param> | ||
615 | private void ParseAssemblyName(XElement node, string componentId) | ||
616 | { | ||
617 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
618 | string id = null; | ||
619 | string value = null; | ||
620 | |||
621 | foreach (XAttribute attrib in node.Attributes()) | ||
622 | { | ||
623 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
624 | { | ||
625 | switch (attrib.Name.LocalName) | ||
626 | { | ||
627 | case "Id": | ||
628 | id = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
629 | break; | ||
630 | case "Value": | ||
631 | value = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
632 | break; | ||
633 | default: | ||
634 | this.core.UnexpectedAttribute(node, attrib); | ||
635 | break; | ||
636 | } | ||
637 | } | ||
638 | else | ||
639 | { | ||
640 | this.core.ParseExtensionAttribute(node, attrib); | ||
641 | } | ||
642 | } | ||
643 | |||
644 | if (null == id) | ||
645 | { | ||
646 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
647 | } | ||
648 | |||
649 | this.core.ParseForExtensionElements(node); | ||
650 | |||
651 | if (!this.core.EncounteredError) | ||
652 | { | ||
653 | Row row = this.core.CreateRow(sourceLineNumbers, "MsiAssemblyName"); | ||
654 | row[0] = componentId; | ||
655 | row[1] = id; | ||
656 | row[2] = value; | ||
657 | } | ||
658 | } | ||
659 | |||
660 | /// <summary> | ||
661 | /// Parses a binary element. | ||
662 | /// </summary> | ||
663 | /// <param name="node">Element to parse.</param> | ||
664 | /// <returns>Identifier for the new row.</returns> | ||
665 | [SuppressMessage("Microsoft.Performance", "CA1800:DoNotCastUnnecessarily")] | ||
666 | private Identifier ParseBinaryElement(XElement node) | ||
667 | { | ||
668 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
669 | Identifier id = null; | ||
670 | string sourceFile = null; | ||
671 | YesNoType suppressModularization = YesNoType.NotSet; | ||
672 | |||
673 | foreach (XAttribute attrib in node.Attributes()) | ||
674 | { | ||
675 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
676 | { | ||
677 | switch (attrib.Name.LocalName) | ||
678 | { | ||
679 | case "Id": | ||
680 | id = this.core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
681 | break; | ||
682 | case "SourceFile": | ||
683 | case "src": | ||
684 | if (null != sourceFile) | ||
685 | { | ||
686 | this.core.OnMessage(WixErrors.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "SourceFile", "src")); | ||
687 | } | ||
688 | |||
689 | if ("src" == attrib.Name.LocalName) | ||
690 | { | ||
691 | this.core.OnMessage(WixWarnings.DeprecatedAttribute(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, "SourceFile")); | ||
692 | } | ||
693 | sourceFile = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
694 | break; | ||
695 | case "SuppressModularization": | ||
696 | suppressModularization = this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
697 | break; | ||
698 | default: | ||
699 | this.core.UnexpectedAttribute(node, attrib); | ||
700 | break; | ||
701 | } | ||
702 | } | ||
703 | else | ||
704 | { | ||
705 | this.core.ParseExtensionAttribute(node, attrib); | ||
706 | } | ||
707 | } | ||
708 | |||
709 | if (null == id) | ||
710 | { | ||
711 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
712 | id = Identifier.Invalid; | ||
713 | } | ||
714 | else if (!String.IsNullOrEmpty(id.Id)) // only check legal values | ||
715 | { | ||
716 | if (55 < id.Id.Length) | ||
717 | { | ||
718 | this.core.OnMessage(WixErrors.StreamNameTooLong(sourceLineNumbers, node.Name.LocalName, "Id", id.Id, id.Id.Length, 55)); | ||
719 | } | ||
720 | else if (!this.compilingProduct) // if we're not doing a product then we can't be sure that a binary identifier will fit when modularized | ||
721 | { | ||
722 | if (18 < id.Id.Length) | ||
723 | { | ||
724 | this.core.OnMessage(WixWarnings.IdentifierCannotBeModularized(sourceLineNumbers, node.Name.LocalName, "Id", id.Id, id.Id.Length, 18)); | ||
725 | } | ||
726 | } | ||
727 | } | ||
728 | |||
729 | if (null == sourceFile) | ||
730 | { | ||
731 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "SourceFile")); | ||
732 | } | ||
733 | |||
734 | this.core.ParseForExtensionElements(node); | ||
735 | |||
736 | if (!this.core.EncounteredError) | ||
737 | { | ||
738 | Row row = this.core.CreateRow(sourceLineNumbers, "Binary", id); | ||
739 | row[1] = sourceFile; | ||
740 | |||
741 | if (YesNoType.Yes == suppressModularization) | ||
742 | { | ||
743 | Row wixSuppressModularizationRow = this.core.CreateRow(sourceLineNumbers, "WixSuppressModularization"); | ||
744 | wixSuppressModularizationRow[0] = id; | ||
745 | } | ||
746 | } | ||
747 | |||
748 | return id; | ||
749 | } | ||
750 | |||
751 | /// <summary> | ||
752 | /// Parses an icon element. | ||
753 | /// </summary> | ||
754 | /// <param name="node">Element to parse.</param> | ||
755 | /// <returns>Identifier for the new row.</returns> | ||
756 | private string ParseIconElement(XElement node) | ||
757 | { | ||
758 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
759 | Identifier id = null; | ||
760 | string sourceFile = null; | ||
761 | |||
762 | foreach (XAttribute attrib in node.Attributes()) | ||
763 | { | ||
764 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
765 | { | ||
766 | switch (attrib.Name.LocalName) | ||
767 | { | ||
768 | case "Id": | ||
769 | id = this.core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
770 | break; | ||
771 | case "SourceFile": | ||
772 | sourceFile = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
773 | break; | ||
774 | default: | ||
775 | this.core.UnexpectedAttribute(node, attrib); | ||
776 | break; | ||
777 | } | ||
778 | } | ||
779 | else | ||
780 | { | ||
781 | this.core.ParseExtensionAttribute(node, attrib); | ||
782 | } | ||
783 | } | ||
784 | |||
785 | if (null == id) | ||
786 | { | ||
787 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
788 | id = Identifier.Invalid; | ||
789 | } | ||
790 | else if (!String.IsNullOrEmpty(id.Id)) // only check legal values | ||
791 | { | ||
792 | if (57 < id.Id.Length) | ||
793 | { | ||
794 | this.core.OnMessage(WixErrors.StreamNameTooLong(sourceLineNumbers, node.Name.LocalName, "Id", id.Id, id.Id.Length, 57)); | ||
795 | } | ||
796 | else if (!this.compilingProduct) // if we're not doing a product then we can't be sure that a binary identifier will fit when modularized | ||
797 | { | ||
798 | if (20 < id.Id.Length) | ||
799 | { | ||
800 | this.core.OnMessage(WixWarnings.IdentifierCannotBeModularized(sourceLineNumbers, node.Name.LocalName, "Id", id.Id, id.Id.Length, 20)); | ||
801 | } | ||
802 | } | ||
803 | } | ||
804 | |||
805 | if (null == sourceFile) | ||
806 | { | ||
807 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "SourceFile")); | ||
808 | } | ||
809 | |||
810 | this.core.ParseForExtensionElements(node); | ||
811 | |||
812 | if (!this.core.EncounteredError) | ||
813 | { | ||
814 | Row row = this.core.CreateRow(sourceLineNumbers, "Icon", id); | ||
815 | row[1] = sourceFile; | ||
816 | } | ||
817 | |||
818 | return id.Id; | ||
819 | } | ||
820 | |||
821 | /// <summary> | ||
822 | /// Parses an InstanceTransforms element. | ||
823 | /// </summary> | ||
824 | /// <param name="node">Element to parse.</param> | ||
825 | private void ParseInstanceTransformsElement(XElement node) | ||
826 | { | ||
827 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
828 | string property = null; | ||
829 | |||
830 | foreach (XAttribute attrib in node.Attributes()) | ||
831 | { | ||
832 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
833 | { | ||
834 | switch (attrib.Name.LocalName) | ||
835 | { | ||
836 | case "Property": | ||
837 | property = this.core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
838 | this.core.CreateSimpleReference(sourceLineNumbers, "Property", property); | ||
839 | break; | ||
840 | default: | ||
841 | this.core.UnexpectedAttribute(node, attrib); | ||
842 | break; | ||
843 | } | ||
844 | } | ||
845 | else | ||
846 | { | ||
847 | this.core.ParseExtensionAttribute(node, attrib); | ||
848 | } | ||
849 | } | ||
850 | |||
851 | if (null == property) | ||
852 | { | ||
853 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Property")); | ||
854 | } | ||
855 | |||
856 | // find unexpected child elements | ||
857 | foreach (XElement child in node.Elements()) | ||
858 | { | ||
859 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
860 | { | ||
861 | switch (child.Name.LocalName) | ||
862 | { | ||
863 | case "Instance": | ||
864 | ParseInstanceElement(child, property); | ||
865 | break; | ||
866 | default: | ||
867 | this.core.UnexpectedElement(node, child); | ||
868 | break; | ||
869 | } | ||
870 | } | ||
871 | else | ||
872 | { | ||
873 | this.core.ParseExtensionElement(node, child); | ||
874 | } | ||
875 | } | ||
876 | } | ||
877 | |||
878 | /// <summary> | ||
879 | /// Parses an instance element. | ||
880 | /// </summary> | ||
881 | /// <param name="node">Element to parse.</param> | ||
882 | /// <param name="componentId">Identifier of instance property.</param> | ||
883 | private void ParseInstanceElement(XElement node, string propertyId) | ||
884 | { | ||
885 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
886 | string id = null; | ||
887 | string productCode = null; | ||
888 | string productName = null; | ||
889 | string upgradeCode = null; | ||
890 | |||
891 | foreach (XAttribute attrib in node.Attributes()) | ||
892 | { | ||
893 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
894 | { | ||
895 | switch (attrib.Name.LocalName) | ||
896 | { | ||
897 | case "Id": | ||
898 | id = this.core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
899 | break; | ||
900 | case "ProductCode": | ||
901 | productCode = this.core.GetAttributeGuidValue(sourceLineNumbers, attrib, true); | ||
902 | break; | ||
903 | case "ProductName": | ||
904 | productName = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
905 | break; | ||
906 | case "UpgradeCode": | ||
907 | upgradeCode = this.core.GetAttributeGuidValue(sourceLineNumbers, attrib, false); | ||
908 | break; | ||
909 | default: | ||
910 | this.core.UnexpectedAttribute(node, attrib); | ||
911 | break; | ||
912 | } | ||
913 | } | ||
914 | else | ||
915 | { | ||
916 | this.core.ParseExtensionAttribute(node, attrib); | ||
917 | } | ||
918 | } | ||
919 | |||
920 | if (null == id) | ||
921 | { | ||
922 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
923 | } | ||
924 | |||
925 | if (null == productCode) | ||
926 | { | ||
927 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "ProductCode")); | ||
928 | } | ||
929 | |||
930 | this.core.ParseForExtensionElements(node); | ||
931 | |||
932 | if (!this.core.EncounteredError) | ||
933 | { | ||
934 | Row row = this.core.CreateRow(sourceLineNumbers, "WixInstanceTransforms"); | ||
935 | row[0] = id; | ||
936 | row[1] = propertyId; | ||
937 | row[2] = productCode; | ||
938 | if (null != productName) | ||
939 | { | ||
940 | row[3] = productName; | ||
941 | } | ||
942 | if (null != upgradeCode) | ||
943 | { | ||
944 | row[4] = upgradeCode; | ||
945 | } | ||
946 | } | ||
947 | } | ||
948 | |||
949 | /// <summary> | ||
950 | /// Parses a category element. | ||
951 | /// </summary> | ||
952 | /// <param name="node">Element to parse.</param> | ||
953 | /// <param name="componentId">Identifier of parent component.</param> | ||
954 | private void ParseCategoryElement(XElement node, string componentId) | ||
955 | { | ||
956 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
957 | string id = null; | ||
958 | string appData = null; | ||
959 | string feature = null; | ||
960 | string qualifier = null; | ||
961 | |||
962 | foreach (XAttribute attrib in node.Attributes()) | ||
963 | { | ||
964 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
965 | { | ||
966 | switch (attrib.Name.LocalName) | ||
967 | { | ||
968 | case "Id": | ||
969 | id = this.core.GetAttributeGuidValue(sourceLineNumbers, attrib, false); | ||
970 | break; | ||
971 | case "AppData": | ||
972 | appData = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
973 | break; | ||
974 | case "Feature": | ||
975 | feature = this.core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
976 | this.core.CreateSimpleReference(sourceLineNumbers, "Feature", feature); | ||
977 | break; | ||
978 | case "Qualifier": | ||
979 | qualifier = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
980 | break; | ||
981 | default: | ||
982 | this.core.UnexpectedAttribute(node, attrib); | ||
983 | break; | ||
984 | } | ||
985 | } | ||
986 | else | ||
987 | { | ||
988 | this.core.ParseExtensionAttribute(node, attrib); | ||
989 | } | ||
990 | } | ||
991 | |||
992 | if (null == id) | ||
993 | { | ||
994 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
995 | } | ||
996 | |||
997 | if (null == qualifier) | ||
998 | { | ||
999 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Qualifier")); | ||
1000 | } | ||
1001 | |||
1002 | this.core.ParseForExtensionElements(node); | ||
1003 | |||
1004 | if (!this.core.EncounteredError) | ||
1005 | { | ||
1006 | Row row = this.core.CreateRow(sourceLineNumbers, "PublishComponent"); | ||
1007 | row[0] = id; | ||
1008 | row[1] = qualifier; | ||
1009 | row[2] = componentId; | ||
1010 | row[3] = appData; | ||
1011 | if (null == feature) | ||
1012 | { | ||
1013 | row[4] = Guid.Empty.ToString("B"); | ||
1014 | } | ||
1015 | else | ||
1016 | { | ||
1017 | row[4] = feature; | ||
1018 | } | ||
1019 | } | ||
1020 | } | ||
1021 | |||
1022 | /// <summary> | ||
1023 | /// Parses a class element. | ||
1024 | /// </summary> | ||
1025 | /// <param name="node">Element to parse.</param> | ||
1026 | /// <param name="componentId">Identifier of parent component.</param> | ||
1027 | /// <param name="advertise">Optional Advertise State for the parent AppId element (if any).</param> | ||
1028 | /// <param name="fileServer">Optional file identifier for CLSID when not advertised.</param> | ||
1029 | /// <param name="typeLibId">Optional TypeLib GUID for CLSID.</param> | ||
1030 | /// <param name="typeLibVersion">Optional TypeLib Version for CLSID Interfaces (if any).</param> | ||
1031 | /// <param name="parentAppId">Optional parent AppId.</param> | ||
1032 | private void ParseClassElement(XElement node, string componentId, YesNoType advertise, string fileServer, string typeLibId, string typeLibVersion, string parentAppId) | ||
1033 | { | ||
1034 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
1035 | |||
1036 | string appId = null; | ||
1037 | string argument = null; | ||
1038 | bool class16bit = false; | ||
1039 | bool class32bit = false; | ||
1040 | string classId = null; | ||
1041 | YesNoType classAdvertise = YesNoType.NotSet; | ||
1042 | string[] contexts = null; | ||
1043 | string formattedContextString = null; | ||
1044 | bool control = false; | ||
1045 | string defaultInprocHandler = null; | ||
1046 | string defaultProgId = null; | ||
1047 | string description = null; | ||
1048 | string fileTypeMask = null; | ||
1049 | string foreignServer = null; | ||
1050 | string icon = null; | ||
1051 | int iconIndex = CompilerConstants.IntegerNotSet; | ||
1052 | string insertable = null; | ||
1053 | string localFileServer = null; | ||
1054 | bool programmable = false; | ||
1055 | YesNoType relativePath = YesNoType.NotSet; | ||
1056 | bool safeForInit = false; | ||
1057 | bool safeForScripting = false; | ||
1058 | bool shortServerPath = false; | ||
1059 | string threadingModel = null; | ||
1060 | string version = null; | ||
1061 | |||
1062 | foreach (XAttribute attrib in node.Attributes()) | ||
1063 | { | ||
1064 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
1065 | { | ||
1066 | switch (attrib.Name.LocalName) | ||
1067 | { | ||
1068 | case "Id": | ||
1069 | classId = this.core.GetAttributeGuidValue(sourceLineNumbers, attrib, false); | ||
1070 | break; | ||
1071 | case "Advertise": | ||
1072 | classAdvertise = this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
1073 | break; | ||
1074 | case "AppId": | ||
1075 | appId = this.core.GetAttributeGuidValue(sourceLineNumbers, attrib, false); | ||
1076 | break; | ||
1077 | case "Argument": | ||
1078 | argument = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
1079 | break; | ||
1080 | case "Context": | ||
1081 | contexts = this.core.GetAttributeValue(sourceLineNumbers, attrib).Split("\r\n\t ".ToCharArray(), StringSplitOptions.RemoveEmptyEntries); | ||
1082 | break; | ||
1083 | case "Control": | ||
1084 | control = YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
1085 | break; | ||
1086 | case "Description": | ||
1087 | description = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
1088 | break; | ||
1089 | case "Handler": | ||
1090 | defaultInprocHandler = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
1091 | break; | ||
1092 | case "Icon": | ||
1093 | icon = this.core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
1094 | break; | ||
1095 | case "IconIndex": | ||
1096 | iconIndex = this.core.GetAttributeIntegerValue(sourceLineNumbers, attrib, short.MinValue + 1, short.MaxValue); | ||
1097 | break; | ||
1098 | case "RelativePath": | ||
1099 | relativePath = this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
1100 | break; | ||
1101 | |||
1102 | // The following attributes result in rows always added to the Registry table rather than the Class table | ||
1103 | case "Insertable": | ||
1104 | insertable = (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) ? "Insertable" : "NotInsertable"; | ||
1105 | break; | ||
1106 | case "Programmable": | ||
1107 | programmable = YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
1108 | break; | ||
1109 | case "SafeForInitializing": | ||
1110 | safeForInit = YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
1111 | break; | ||
1112 | case "SafeForScripting": | ||
1113 | safeForScripting = YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
1114 | break; | ||
1115 | case "ForeignServer": | ||
1116 | foreignServer = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
1117 | break; | ||
1118 | case "Server": | ||
1119 | localFileServer = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
1120 | break; | ||
1121 | case "ShortPath": | ||
1122 | shortServerPath = YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
1123 | break; | ||
1124 | case "ThreadingModel": | ||
1125 | threadingModel = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
1126 | break; | ||
1127 | case "Version": | ||
1128 | version = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
1129 | break; | ||
1130 | default: | ||
1131 | this.core.UnexpectedAttribute(node, attrib); | ||
1132 | break; | ||
1133 | } | ||
1134 | } | ||
1135 | else | ||
1136 | { | ||
1137 | this.core.ParseExtensionAttribute(node, attrib); | ||
1138 | } | ||
1139 | } | ||
1140 | |||
1141 | if (null == classId) | ||
1142 | { | ||
1143 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
1144 | } | ||
1145 | |||
1146 | HashSet<string> uniqueContexts = new HashSet<string>(); | ||
1147 | foreach (string context in contexts) | ||
1148 | { | ||
1149 | if (uniqueContexts.Contains(context)) | ||
1150 | { | ||
1151 | this.core.OnMessage(WixErrors.DuplicateContextValue(sourceLineNumbers, context)); | ||
1152 | } | ||
1153 | else | ||
1154 | { | ||
1155 | uniqueContexts.Add(context); | ||
1156 | } | ||
1157 | |||
1158 | if (context.EndsWith("32", StringComparison.Ordinal)) | ||
1159 | { | ||
1160 | class32bit = true; | ||
1161 | } | ||
1162 | else | ||
1163 | { | ||
1164 | class16bit = true; | ||
1165 | } | ||
1166 | } | ||
1167 | |||
1168 | if ((YesNoType.No == advertise && YesNoType.Yes == classAdvertise) || (YesNoType.Yes == advertise && YesNoType.No == classAdvertise)) | ||
1169 | { | ||
1170 | this.core.OnMessage(WixErrors.AdvertiseStateMustMatch(sourceLineNumbers, classAdvertise.ToString(), advertise.ToString())); | ||
1171 | } | ||
1172 | else | ||
1173 | { | ||
1174 | advertise = classAdvertise; | ||
1175 | } | ||
1176 | |||
1177 | // If the advertise state has not been set, default to non-advertised. | ||
1178 | if (YesNoType.NotSet == advertise) | ||
1179 | { | ||
1180 | advertise = YesNoType.No; | ||
1181 | } | ||
1182 | |||
1183 | if (YesNoType.Yes == advertise && 0 == contexts.Length) | ||
1184 | { | ||
1185 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Context", "Advertise", "yes")); | ||
1186 | } | ||
1187 | |||
1188 | if (!String.IsNullOrEmpty(parentAppId) && !String.IsNullOrEmpty(appId)) | ||
1189 | { | ||
1190 | this.core.OnMessage(WixErrors.IllegalAttributeWhenNested(sourceLineNumbers, node.Name.LocalName, "AppId", node.Parent.Name.LocalName)); | ||
1191 | } | ||
1192 | |||
1193 | if (!String.IsNullOrEmpty(localFileServer)) | ||
1194 | { | ||
1195 | this.core.CreateSimpleReference(sourceLineNumbers, "File", localFileServer); | ||
1196 | } | ||
1197 | |||
1198 | // Local variables used strictly for child node processing. | ||
1199 | int fileTypeMaskIndex = 0; | ||
1200 | YesNoType firstProgIdForClass = YesNoType.Yes; | ||
1201 | |||
1202 | foreach (XElement child in node.Elements()) | ||
1203 | { | ||
1204 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
1205 | { | ||
1206 | switch (child.Name.LocalName) | ||
1207 | { | ||
1208 | case "FileTypeMask": | ||
1209 | if (YesNoType.Yes == advertise) | ||
1210 | { | ||
1211 | fileTypeMask = String.Concat(fileTypeMask, null == fileTypeMask ? String.Empty : ";", this.ParseFileTypeMaskElement(child)); | ||
1212 | } | ||
1213 | else if (YesNoType.No == advertise) | ||
1214 | { | ||
1215 | SourceLineNumber childSourceLineNumbers = Preprocessor.GetSourceLineNumbers(child); | ||
1216 | this.core.CreateRegistryRow(childSourceLineNumbers, MsiInterop.MsidbRegistryRootClassesRoot, String.Concat("FileType\\", classId, "\\", fileTypeMaskIndex.ToString()), String.Empty, this.ParseFileTypeMaskElement(child), componentId); | ||
1217 | fileTypeMaskIndex++; | ||
1218 | } | ||
1219 | break; | ||
1220 | case "Interface": | ||
1221 | this.ParseInterfaceElement(child, componentId, class16bit ? classId : null, class32bit ? classId : null, typeLibId, typeLibVersion); | ||
1222 | break; | ||
1223 | case "ProgId": | ||
1224 | { | ||
1225 | bool foundExtension = false; | ||
1226 | string progId = this.ParseProgIdElement(child, componentId, advertise, classId, description, null, ref foundExtension, firstProgIdForClass); | ||
1227 | if (null == defaultProgId) | ||
1228 | { | ||
1229 | defaultProgId = progId; | ||
1230 | } | ||
1231 | firstProgIdForClass = YesNoType.No; | ||
1232 | } | ||
1233 | break; | ||
1234 | default: | ||
1235 | this.core.UnexpectedElement(node, child); | ||
1236 | break; | ||
1237 | } | ||
1238 | } | ||
1239 | else | ||
1240 | { | ||
1241 | this.core.ParseExtensionElement(node, child); | ||
1242 | } | ||
1243 | } | ||
1244 | |||
1245 | // If this Class is being advertised. | ||
1246 | if (YesNoType.Yes == advertise) | ||
1247 | { | ||
1248 | if (null != fileServer || null != localFileServer) | ||
1249 | { | ||
1250 | this.core.OnMessage(WixErrors.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Server", "Advertise", "yes")); | ||
1251 | } | ||
1252 | |||
1253 | if (null != foreignServer) | ||
1254 | { | ||
1255 | this.core.OnMessage(WixErrors.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "ForeignServer", "Advertise", "yes")); | ||
1256 | } | ||
1257 | |||
1258 | if (null == appId && null != parentAppId) | ||
1259 | { | ||
1260 | appId = parentAppId; | ||
1261 | } | ||
1262 | |||
1263 | // add a Class row for each context | ||
1264 | if (!this.core.EncounteredError) | ||
1265 | { | ||
1266 | foreach (string context in contexts) | ||
1267 | { | ||
1268 | Row row = this.core.CreateRow(sourceLineNumbers, "Class"); | ||
1269 | row[0] = classId; | ||
1270 | row[1] = context; | ||
1271 | row[2] = componentId; | ||
1272 | row[3] = defaultProgId; | ||
1273 | row[4] = description; | ||
1274 | if (null != appId) | ||
1275 | { | ||
1276 | row[5] = appId; | ||
1277 | this.core.CreateSimpleReference(sourceLineNumbers, "AppId", appId); | ||
1278 | } | ||
1279 | row[6] = fileTypeMask; | ||
1280 | if (null != icon) | ||
1281 | { | ||
1282 | row[7] = icon; | ||
1283 | this.core.CreateSimpleReference(sourceLineNumbers, "Icon", icon); | ||
1284 | } | ||
1285 | if (CompilerConstants.IntegerNotSet != iconIndex) | ||
1286 | { | ||
1287 | row[8] = iconIndex; | ||
1288 | } | ||
1289 | row[9] = defaultInprocHandler; | ||
1290 | row[10] = argument; | ||
1291 | row[11] = Guid.Empty.ToString("B"); | ||
1292 | if (YesNoType.Yes == relativePath) | ||
1293 | { | ||
1294 | row[12] = MsiInterop.MsidbClassAttributesRelativePath; | ||
1295 | } | ||
1296 | } | ||
1297 | } | ||
1298 | } | ||
1299 | else if (YesNoType.No == advertise) | ||
1300 | { | ||
1301 | if (null == fileServer && null == localFileServer && null == foreignServer) | ||
1302 | { | ||
1303 | this.core.OnMessage(WixErrors.ExpectedAttributes(sourceLineNumbers, node.Name.LocalName, "ForeignServer", "Server")); | ||
1304 | } | ||
1305 | |||
1306 | if (null != fileServer && null != foreignServer) | ||
1307 | { | ||
1308 | this.core.OnMessage(WixErrors.IllegalAttributeWhenNested(sourceLineNumbers, node.Name.LocalName, "ForeignServer", "File")); | ||
1309 | } | ||
1310 | else if (null != localFileServer && null != foreignServer) | ||
1311 | { | ||
1312 | this.core.OnMessage(WixErrors.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "ForeignServer", "Server")); | ||
1313 | } | ||
1314 | else if (null == fileServer) | ||
1315 | { | ||
1316 | fileServer = localFileServer; | ||
1317 | } | ||
1318 | |||
1319 | if (null != appId) // need to use nesting (not a reference) for the unadvertised Class elements | ||
1320 | { | ||
1321 | this.core.OnMessage(WixErrors.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "AppId", "Advertise", "no")); | ||
1322 | } | ||
1323 | |||
1324 | // add the core registry keys for each context in the class | ||
1325 | foreach (string context in contexts) | ||
1326 | { | ||
1327 | if (context.StartsWith("InprocServer", StringComparison.Ordinal)) // dll server | ||
1328 | { | ||
1329 | if (null != argument) | ||
1330 | { | ||
1331 | this.core.OnMessage(WixErrors.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Arguments", "Context", context)); | ||
1332 | } | ||
1333 | |||
1334 | if (null != fileServer) | ||
1335 | { | ||
1336 | formattedContextString = String.Concat("[", shortServerPath ? "!" : "#", fileServer, "]"); | ||
1337 | } | ||
1338 | else if (null != foreignServer) | ||
1339 | { | ||
1340 | formattedContextString = foreignServer; | ||
1341 | } | ||
1342 | } | ||
1343 | else if (context.StartsWith("LocalServer", StringComparison.Ordinal)) // exe server (quote the long path) | ||
1344 | { | ||
1345 | if (null != fileServer) | ||
1346 | { | ||
1347 | if (shortServerPath) | ||
1348 | { | ||
1349 | formattedContextString = String.Concat("[!", fileServer, "]"); | ||
1350 | } | ||
1351 | else | ||
1352 | { | ||
1353 | formattedContextString = String.Concat("\"[#", fileServer, "]\""); | ||
1354 | } | ||
1355 | } | ||
1356 | else if (null != foreignServer) | ||
1357 | { | ||
1358 | formattedContextString = foreignServer; | ||
1359 | } | ||
1360 | |||
1361 | if (null != argument) | ||
1362 | { | ||
1363 | formattedContextString = String.Concat(formattedContextString, " ", argument); | ||
1364 | } | ||
1365 | } | ||
1366 | else | ||
1367 | { | ||
1368 | this.core.OnMessage(WixErrors.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, "Context", context, "InprocServer", "InprocServer32", "LocalServer", "LocalServer32")); | ||
1369 | } | ||
1370 | |||
1371 | this.core.CreateRegistryRow(sourceLineNumbers, MsiInterop.MsidbRegistryRootClassesRoot, String.Concat("CLSID\\", classId, "\\", context), String.Empty, formattedContextString, componentId); // ClassId context | ||
1372 | |||
1373 | if (null != icon) // ClassId default icon | ||
1374 | { | ||
1375 | this.core.CreateSimpleReference(sourceLineNumbers, "File", icon); | ||
1376 | |||
1377 | icon = String.Format(CultureInfo.InvariantCulture, "\"[#{0}]\"", icon); | ||
1378 | |||
1379 | if (CompilerConstants.IntegerNotSet != iconIndex) | ||
1380 | { | ||
1381 | icon = String.Concat(icon, ",", iconIndex); | ||
1382 | } | ||
1383 | this.core.CreateRegistryRow(sourceLineNumbers, MsiInterop.MsidbRegistryRootClassesRoot, String.Concat("CLSID\\", classId, "\\", context, "\\DefaultIcon"), String.Empty, icon, componentId); | ||
1384 | } | ||
1385 | } | ||
1386 | |||
1387 | if (null != parentAppId) // ClassId AppId (must be specified via nesting, not with the AppId attribute) | ||
1388 | { | ||
1389 | this.core.CreateRegistryRow(sourceLineNumbers, MsiInterop.MsidbRegistryRootClassesRoot, String.Concat("CLSID\\", classId), "AppID", parentAppId, componentId); | ||
1390 | } | ||
1391 | |||
1392 | if (null != description) // ClassId description | ||
1393 | { | ||
1394 | this.core.CreateRegistryRow(sourceLineNumbers, MsiInterop.MsidbRegistryRootClassesRoot, String.Concat("CLSID\\", classId), String.Empty, description, componentId); | ||
1395 | } | ||
1396 | |||
1397 | if (null != defaultInprocHandler) | ||
1398 | { | ||
1399 | switch (defaultInprocHandler) // ClassId Default Inproc Handler | ||
1400 | { | ||
1401 | case "1": | ||
1402 | this.core.CreateRegistryRow(sourceLineNumbers, MsiInterop.MsidbRegistryRootClassesRoot, String.Concat("CLSID\\", classId, "\\InprocHandler"), String.Empty, "ole.dll", componentId); | ||
1403 | break; | ||
1404 | case "2": | ||
1405 | this.core.CreateRegistryRow(sourceLineNumbers, MsiInterop.MsidbRegistryRootClassesRoot, String.Concat("CLSID\\", classId, "\\InprocHandler32"), String.Empty, "ole32.dll", componentId); | ||
1406 | break; | ||
1407 | case "3": | ||
1408 | this.core.CreateRegistryRow(sourceLineNumbers, MsiInterop.MsidbRegistryRootClassesRoot, String.Concat("CLSID\\", classId, "\\InprocHandler"), String.Empty, "ole.dll", componentId); | ||
1409 | this.core.CreateRegistryRow(sourceLineNumbers, MsiInterop.MsidbRegistryRootClassesRoot, String.Concat("CLSID\\", classId, "\\InprocHandler32"), String.Empty, "ole32.dll", componentId); | ||
1410 | break; | ||
1411 | default: | ||
1412 | this.core.CreateRegistryRow(sourceLineNumbers, MsiInterop.MsidbRegistryRootClassesRoot, String.Concat("CLSID\\", classId, "\\InprocHandler32"), String.Empty, defaultInprocHandler, componentId); | ||
1413 | break; | ||
1414 | } | ||
1415 | } | ||
1416 | |||
1417 | if (YesNoType.NotSet != relativePath) // ClassId's RelativePath | ||
1418 | { | ||
1419 | this.core.OnMessage(WixErrors.RelativePathForRegistryElement(sourceLineNumbers)); | ||
1420 | } | ||
1421 | } | ||
1422 | |||
1423 | if (null != threadingModel) | ||
1424 | { | ||
1425 | threadingModel = Compiler.UppercaseFirstChar(threadingModel); | ||
1426 | |||
1427 | // add a threading model for each context in the class | ||
1428 | foreach (string context in contexts) | ||
1429 | { | ||
1430 | this.core.CreateRegistryRow(sourceLineNumbers, MsiInterop.MsidbRegistryRootClassesRoot, String.Concat("CLSID\\", classId, "\\", context), "ThreadingModel", threadingModel, componentId); | ||
1431 | } | ||
1432 | } | ||
1433 | |||
1434 | if (null != typeLibId) | ||
1435 | { | ||
1436 | this.core.CreateRegistryRow(sourceLineNumbers, MsiInterop.MsidbRegistryRootClassesRoot, String.Concat("CLSID\\", classId, "\\TypeLib"), null, typeLibId, componentId); | ||
1437 | } | ||
1438 | |||
1439 | if (null != version) | ||
1440 | { | ||
1441 | this.core.CreateRegistryRow(sourceLineNumbers, MsiInterop.MsidbRegistryRootClassesRoot, String.Concat("CLSID\\", classId, "\\Version"), null, version, componentId); | ||
1442 | } | ||
1443 | |||
1444 | if (null != insertable) | ||
1445 | { | ||
1446 | // Add "*" for name so that any subkeys (shouldn't be any) are removed on uninstall. | ||
1447 | this.core.CreateRegistryRow(sourceLineNumbers, MsiInterop.MsidbRegistryRootClassesRoot, String.Concat("CLSID\\", classId, "\\", insertable), "*", null, componentId); | ||
1448 | } | ||
1449 | |||
1450 | if (control) | ||
1451 | { | ||
1452 | // Add "*" for name so that any subkeys (shouldn't be any) are removed on uninstall. | ||
1453 | this.core.CreateRegistryRow(sourceLineNumbers, MsiInterop.MsidbRegistryRootClassesRoot, String.Concat("CLSID\\", classId, "\\Control"), "*", null, componentId); | ||
1454 | } | ||
1455 | |||
1456 | if (programmable) | ||
1457 | { | ||
1458 | // Add "*" for name so that any subkeys (shouldn't be any) are removed on uninstall. | ||
1459 | this.core.CreateRegistryRow(sourceLineNumbers, MsiInterop.MsidbRegistryRootClassesRoot, String.Concat("CLSID\\", classId, "\\Programmable"), "*", null, componentId); | ||
1460 | } | ||
1461 | |||
1462 | if (safeForInit) | ||
1463 | { | ||
1464 | this.RegisterImplementedCategories(sourceLineNumbers, "{7DD95802-9882-11CF-9FA9-00AA006C42C4}", classId, componentId); | ||
1465 | } | ||
1466 | |||
1467 | if (safeForScripting) | ||
1468 | { | ||
1469 | this.RegisterImplementedCategories(sourceLineNumbers, "{7DD95801-9882-11CF-9FA9-00AA006C42C4}", classId, componentId); | ||
1470 | } | ||
1471 | } | ||
1472 | |||
1473 | /// <summary> | ||
1474 | /// Parses an Interface element. | ||
1475 | /// </summary> | ||
1476 | /// <param name="node">Element to parse.</param> | ||
1477 | /// <param name="componentId">Identifier of parent component.</param> | ||
1478 | /// <param name="proxyId">16-bit proxy for interface.</param> | ||
1479 | /// <param name="proxyId32">32-bit proxy for interface.</param> | ||
1480 | /// <param name="typeLibId">Optional TypeLib GUID for CLSID.</param> | ||
1481 | /// <param name="typelibVersion">Version of the TypeLib to which this interface belongs. Required if typeLibId is specified</param> | ||
1482 | private void ParseInterfaceElement(XElement node, string componentId, string proxyId, string proxyId32, string typeLibId, string typelibVersion) | ||
1483 | { | ||
1484 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
1485 | string baseInterface = null; | ||
1486 | string interfaceId = null; | ||
1487 | string name = null; | ||
1488 | int numMethods = CompilerConstants.IntegerNotSet; | ||
1489 | bool versioned = true; | ||
1490 | |||
1491 | foreach (XAttribute attrib in node.Attributes()) | ||
1492 | { | ||
1493 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
1494 | { | ||
1495 | switch (attrib.Name.LocalName) | ||
1496 | { | ||
1497 | case "Id": | ||
1498 | interfaceId = this.core.GetAttributeGuidValue(sourceLineNumbers, attrib, false); | ||
1499 | break; | ||
1500 | case "BaseInterface": | ||
1501 | baseInterface = this.core.GetAttributeGuidValue(sourceLineNumbers, attrib, false); | ||
1502 | break; | ||
1503 | case "Name": | ||
1504 | name = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
1505 | break; | ||
1506 | case "NumMethods": | ||
1507 | numMethods = this.core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, int.MaxValue); | ||
1508 | break; | ||
1509 | case "ProxyStubClassId": | ||
1510 | proxyId = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
1511 | break; | ||
1512 | case "ProxyStubClassId32": | ||
1513 | proxyId32 = this.core.GetAttributeGuidValue(sourceLineNumbers, attrib, false); | ||
1514 | break; | ||
1515 | case "Versioned": | ||
1516 | versioned = YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
1517 | break; | ||
1518 | default: | ||
1519 | this.core.UnexpectedAttribute(node, attrib); | ||
1520 | break; | ||
1521 | } | ||
1522 | } | ||
1523 | else | ||
1524 | { | ||
1525 | this.core.ParseExtensionAttribute(node, attrib); | ||
1526 | } | ||
1527 | } | ||
1528 | |||
1529 | if (null == interfaceId) | ||
1530 | { | ||
1531 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
1532 | } | ||
1533 | |||
1534 | if (null == name) | ||
1535 | { | ||
1536 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Name")); | ||
1537 | } | ||
1538 | |||
1539 | this.core.ParseForExtensionElements(node); | ||
1540 | |||
1541 | this.core.CreateRegistryRow(sourceLineNumbers, MsiInterop.MsidbRegistryRootClassesRoot, String.Concat("Interface\\", interfaceId), null, name, componentId); | ||
1542 | if (null != typeLibId) | ||
1543 | { | ||
1544 | this.core.CreateRegistryRow(sourceLineNumbers, MsiInterop.MsidbRegistryRootClassesRoot, String.Concat("Interface\\", interfaceId, "\\TypeLib"), null, typeLibId, componentId); | ||
1545 | if (versioned) | ||
1546 | { | ||
1547 | this.core.CreateRegistryRow(sourceLineNumbers, MsiInterop.MsidbRegistryRootClassesRoot, String.Concat("Interface\\", interfaceId, "\\TypeLib"), "Version", typelibVersion, componentId); | ||
1548 | } | ||
1549 | } | ||
1550 | |||
1551 | if (null != baseInterface) | ||
1552 | { | ||
1553 | this.core.CreateRegistryRow(sourceLineNumbers, MsiInterop.MsidbRegistryRootClassesRoot, String.Concat("Interface\\", interfaceId, "\\BaseInterface"), null, baseInterface, componentId); | ||
1554 | } | ||
1555 | |||
1556 | if (CompilerConstants.IntegerNotSet != numMethods) | ||
1557 | { | ||
1558 | this.core.CreateRegistryRow(sourceLineNumbers, MsiInterop.MsidbRegistryRootClassesRoot, String.Concat("Interface\\", interfaceId, "\\NumMethods"), null, numMethods.ToString(), componentId); | ||
1559 | } | ||
1560 | |||
1561 | if (null != proxyId) | ||
1562 | { | ||
1563 | this.core.CreateRegistryRow(sourceLineNumbers, MsiInterop.MsidbRegistryRootClassesRoot, String.Concat("Interface\\", interfaceId, "\\ProxyStubClsid"), null, proxyId, componentId); | ||
1564 | } | ||
1565 | |||
1566 | if (null != proxyId32) | ||
1567 | { | ||
1568 | this.core.CreateRegistryRow(sourceLineNumbers, MsiInterop.MsidbRegistryRootClassesRoot, String.Concat("Interface\\", interfaceId, "\\ProxyStubClsid32"), null, proxyId32, componentId); | ||
1569 | } | ||
1570 | } | ||
1571 | |||
1572 | /// <summary> | ||
1573 | /// Parses a CLSID's file type mask element. | ||
1574 | /// </summary> | ||
1575 | /// <param name="node">Element to parse.</param> | ||
1576 | /// <returns>String representing the file type mask elements.</returns> | ||
1577 | private string ParseFileTypeMaskElement(XElement node) | ||
1578 | { | ||
1579 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
1580 | int cb = 0; | ||
1581 | int offset = CompilerConstants.IntegerNotSet; | ||
1582 | string mask = null; | ||
1583 | string value = null; | ||
1584 | |||
1585 | foreach (XAttribute attrib in node.Attributes()) | ||
1586 | { | ||
1587 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
1588 | { | ||
1589 | switch (attrib.Name.LocalName) | ||
1590 | { | ||
1591 | case "Mask": | ||
1592 | mask = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
1593 | break; | ||
1594 | case "Offset": | ||
1595 | offset = this.core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, int.MaxValue); | ||
1596 | break; | ||
1597 | case "Value": | ||
1598 | value = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
1599 | break; | ||
1600 | default: | ||
1601 | this.core.UnexpectedAttribute(node, attrib); | ||
1602 | break; | ||
1603 | } | ||
1604 | } | ||
1605 | else | ||
1606 | { | ||
1607 | this.core.ParseExtensionAttribute(node, attrib); | ||
1608 | } | ||
1609 | } | ||
1610 | |||
1611 | |||
1612 | if (null == mask) | ||
1613 | { | ||
1614 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Mask")); | ||
1615 | } | ||
1616 | |||
1617 | if (CompilerConstants.IntegerNotSet == offset) | ||
1618 | { | ||
1619 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Offset")); | ||
1620 | } | ||
1621 | |||
1622 | if (null == value) | ||
1623 | { | ||
1624 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Value")); | ||
1625 | } | ||
1626 | |||
1627 | this.core.ParseForExtensionElements(node); | ||
1628 | |||
1629 | if (!this.core.EncounteredError) | ||
1630 | { | ||
1631 | if (mask.Length != value.Length) | ||
1632 | { | ||
1633 | this.core.OnMessage(WixErrors.ValueAndMaskMustBeSameLength(sourceLineNumbers)); | ||
1634 | } | ||
1635 | cb = mask.Length / 2; | ||
1636 | } | ||
1637 | |||
1638 | return String.Concat(offset.ToString(CultureInfo.InvariantCulture.NumberFormat), ",", cb.ToString(CultureInfo.InvariantCulture.NumberFormat), ",", mask, ",", value); | ||
1639 | } | ||
1640 | |||
1641 | /// <summary> | ||
1642 | /// Parses a product search element. | ||
1643 | /// </summary> | ||
1644 | /// <param name="node">Element to parse.</param> | ||
1645 | /// <returns>Signature for search element.</returns> | ||
1646 | private void ParseProductSearchElement(XElement node, string propertyId) | ||
1647 | { | ||
1648 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
1649 | |||
1650 | string upgradeCode = null; | ||
1651 | string language = null; | ||
1652 | string maximum = null; | ||
1653 | string minimum = null; | ||
1654 | int options = MsiInterop.MsidbUpgradeAttributesVersionMinInclusive | MsiInterop.MsidbUpgradeAttributesOnlyDetect; | ||
1655 | |||
1656 | foreach (XAttribute attrib in node.Attributes()) | ||
1657 | { | ||
1658 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
1659 | { | ||
1660 | switch (attrib.Name.LocalName) | ||
1661 | { | ||
1662 | case "ExcludeLanguages": | ||
1663 | if (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
1664 | { | ||
1665 | options |= MsiInterop.MsidbUpgradeAttributesLanguagesExclusive; | ||
1666 | } | ||
1667 | break; | ||
1668 | case "IncludeMaximum": | ||
1669 | if (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
1670 | { | ||
1671 | options |= MsiInterop.MsidbUpgradeAttributesVersionMaxInclusive; | ||
1672 | } | ||
1673 | break; | ||
1674 | case "IncludeMinimum": // this is "yes" by default | ||
1675 | if (YesNoType.No == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
1676 | { | ||
1677 | options &= ~MsiInterop.MsidbUpgradeAttributesVersionMinInclusive; | ||
1678 | } | ||
1679 | break; | ||
1680 | case "Language": | ||
1681 | language = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
1682 | break; | ||
1683 | case "Minimum": | ||
1684 | minimum = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
1685 | break; | ||
1686 | case "Maximum": | ||
1687 | maximum = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
1688 | break; | ||
1689 | case "UpgradeCode": | ||
1690 | upgradeCode = this.core.GetAttributeGuidValue(sourceLineNumbers, attrib, false); | ||
1691 | break; | ||
1692 | default: | ||
1693 | this.core.UnexpectedAttribute(node, attrib); | ||
1694 | break; | ||
1695 | } | ||
1696 | } | ||
1697 | else | ||
1698 | { | ||
1699 | this.core.ParseExtensionAttribute(node, attrib); | ||
1700 | } | ||
1701 | } | ||
1702 | |||
1703 | if (null == minimum && null == maximum) | ||
1704 | { | ||
1705 | this.core.OnMessage(WixErrors.ExpectedAttributes(sourceLineNumbers, node.Name.LocalName, "Minimum", "Maximum")); | ||
1706 | } | ||
1707 | |||
1708 | this.core.ParseForExtensionElements(node); | ||
1709 | |||
1710 | if (!this.core.EncounteredError) | ||
1711 | { | ||
1712 | Row row = this.core.CreateRow(sourceLineNumbers, "Upgrade"); | ||
1713 | row[0] = upgradeCode; | ||
1714 | row[1] = minimum; | ||
1715 | row[2] = maximum; | ||
1716 | row[3] = language; | ||
1717 | row[4] = options; | ||
1718 | row[6] = propertyId; | ||
1719 | } | ||
1720 | } | ||
1721 | |||
1722 | /// <summary> | ||
1723 | /// Parses a registry search element. | ||
1724 | /// </summary> | ||
1725 | /// <param name="node">Element to parse.</param> | ||
1726 | /// <returns>Signature for search element.</returns> | ||
1727 | private string ParseRegistrySearchElement(XElement node) | ||
1728 | { | ||
1729 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
1730 | bool explicitWin64 = false; | ||
1731 | Identifier id = null; | ||
1732 | string key = null; | ||
1733 | string name = null; | ||
1734 | string signature = null; | ||
1735 | int root = CompilerConstants.IntegerNotSet; | ||
1736 | int type = CompilerConstants.IntegerNotSet; | ||
1737 | bool search64bit = false; | ||
1738 | |||
1739 | foreach (XAttribute attrib in node.Attributes()) | ||
1740 | { | ||
1741 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
1742 | { | ||
1743 | switch (attrib.Name.LocalName) | ||
1744 | { | ||
1745 | case "Id": | ||
1746 | id = this.core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
1747 | break; | ||
1748 | case "Key": | ||
1749 | key = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
1750 | break; | ||
1751 | case "Name": | ||
1752 | name = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
1753 | break; | ||
1754 | case "Root": | ||
1755 | root = this.core.GetAttributeMsidbRegistryRootValue(sourceLineNumbers, attrib, false); | ||
1756 | break; | ||
1757 | case "Type": | ||
1758 | string typeValue = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
1759 | if (0 < typeValue.Length) | ||
1760 | { | ||
1761 | Wix.RegistrySearch.TypeType typeType = Wix.RegistrySearch.ParseTypeType(typeValue); | ||
1762 | switch (typeType) | ||
1763 | { | ||
1764 | case Wix.RegistrySearch.TypeType.directory: | ||
1765 | type = 0; | ||
1766 | break; | ||
1767 | case Wix.RegistrySearch.TypeType.file: | ||
1768 | type = 1; | ||
1769 | break; | ||
1770 | case Wix.RegistrySearch.TypeType.raw: | ||
1771 | type = 2; | ||
1772 | break; | ||
1773 | default: | ||
1774 | this.core.OnMessage(WixErrors.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, "Type", typeValue, "directory", "file", "raw")); | ||
1775 | break; | ||
1776 | } | ||
1777 | } | ||
1778 | break; | ||
1779 | case "Win64": | ||
1780 | explicitWin64 = true; | ||
1781 | search64bit = YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
1782 | break; | ||
1783 | default: | ||
1784 | this.core.UnexpectedAttribute(node, attrib); | ||
1785 | break; | ||
1786 | } | ||
1787 | } | ||
1788 | else | ||
1789 | { | ||
1790 | this.core.ParseExtensionAttribute(node, attrib); | ||
1791 | } | ||
1792 | } | ||
1793 | |||
1794 | if (!explicitWin64 && (Platform.IA64 == this.CurrentPlatform || Platform.X64 == this.CurrentPlatform)) | ||
1795 | { | ||
1796 | search64bit = true; | ||
1797 | } | ||
1798 | |||
1799 | if (null == id) | ||
1800 | { | ||
1801 | id = this.core.CreateIdentifier("reg", root.ToString(), key, name, type.ToString(), search64bit.ToString()); | ||
1802 | } | ||
1803 | |||
1804 | if (null == key) | ||
1805 | { | ||
1806 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Key")); | ||
1807 | } | ||
1808 | |||
1809 | if (CompilerConstants.IntegerNotSet == root) | ||
1810 | { | ||
1811 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Root")); | ||
1812 | } | ||
1813 | |||
1814 | if (CompilerConstants.IntegerNotSet == type) | ||
1815 | { | ||
1816 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Type")); | ||
1817 | } | ||
1818 | |||
1819 | signature = id.Id; | ||
1820 | bool oneChild = false; | ||
1821 | foreach (XElement child in node.Elements()) | ||
1822 | { | ||
1823 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
1824 | { | ||
1825 | switch (child.Name.LocalName) | ||
1826 | { | ||
1827 | case "DirectorySearch": | ||
1828 | if (oneChild) | ||
1829 | { | ||
1830 | this.core.OnMessage(WixErrors.TooManySearchElements(sourceLineNumbers, node.Name.LocalName)); | ||
1831 | } | ||
1832 | oneChild = true; | ||
1833 | |||
1834 | // directorysearch parentage should work like directory element, not the rest of the signature type because of the DrLocator.Parent column | ||
1835 | signature = this.ParseDirectorySearchElement(child, id.Id); | ||
1836 | break; | ||
1837 | case "DirectorySearchRef": | ||
1838 | if (oneChild) | ||
1839 | { | ||
1840 | this.core.OnMessage(WixErrors.TooManySearchElements(sourceLineNumbers, node.Name.LocalName)); | ||
1841 | } | ||
1842 | oneChild = true; | ||
1843 | signature = this.ParseDirectorySearchRefElement(child, id.Id); | ||
1844 | break; | ||
1845 | case "FileSearch": | ||
1846 | if (oneChild) | ||
1847 | { | ||
1848 | this.core.OnMessage(WixErrors.TooManySearchElements(sourceLineNumbers, node.Name.LocalName)); | ||
1849 | } | ||
1850 | oneChild = true; | ||
1851 | signature = this.ParseFileSearchElement(child, id.Id, false, CompilerConstants.IntegerNotSet); | ||
1852 | id = new Identifier(signature, AccessModifier.Private); // FileSearch signatures override parent signatures | ||
1853 | break; | ||
1854 | case "FileSearchRef": | ||
1855 | if (oneChild) | ||
1856 | { | ||
1857 | this.core.OnMessage(WixErrors.TooManySearchElements(sourceLineNumbers, node.Name.LocalName)); | ||
1858 | } | ||
1859 | oneChild = true; | ||
1860 | string newId = this.ParseSimpleRefElement(child, "Signature"); // FileSearch signatures override parent signatures | ||
1861 | id = new Identifier(newId, AccessModifier.Private); | ||
1862 | signature = null; | ||
1863 | break; | ||
1864 | default: | ||
1865 | this.core.UnexpectedElement(node, child); | ||
1866 | break; | ||
1867 | } | ||
1868 | } | ||
1869 | else | ||
1870 | { | ||
1871 | this.core.ParseExtensionElement(node, child); | ||
1872 | } | ||
1873 | } | ||
1874 | |||
1875 | |||
1876 | if (!this.core.EncounteredError) | ||
1877 | { | ||
1878 | Row row = this.core.CreateRow(sourceLineNumbers, "RegLocator", id); | ||
1879 | row[1] = root; | ||
1880 | row[2] = key; | ||
1881 | row[3] = name; | ||
1882 | row[4] = search64bit ? (type | 16) : type; | ||
1883 | } | ||
1884 | |||
1885 | return signature; | ||
1886 | } | ||
1887 | |||
1888 | /// <summary> | ||
1889 | /// Parses a registry search reference element. | ||
1890 | /// </summary> | ||
1891 | /// <param name="node">Element to parse.</param> | ||
1892 | /// <returns>Signature of referenced search element.</returns> | ||
1893 | private string ParseRegistrySearchRefElement(XElement node) | ||
1894 | { | ||
1895 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
1896 | string id = null; | ||
1897 | |||
1898 | foreach (XAttribute attrib in node.Attributes()) | ||
1899 | { | ||
1900 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
1901 | { | ||
1902 | switch (attrib.Name.LocalName) | ||
1903 | { | ||
1904 | case "Id": | ||
1905 | id = this.core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
1906 | this.core.CreateSimpleReference(sourceLineNumbers, "RegLocator", id); | ||
1907 | break; | ||
1908 | default: | ||
1909 | this.core.UnexpectedAttribute(node, attrib); | ||
1910 | break; | ||
1911 | } | ||
1912 | } | ||
1913 | else | ||
1914 | { | ||
1915 | this.core.ParseExtensionAttribute(node, attrib); | ||
1916 | } | ||
1917 | } | ||
1918 | |||
1919 | if (null == id) | ||
1920 | { | ||
1921 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
1922 | } | ||
1923 | |||
1924 | this.core.ParseForExtensionElements(node); | ||
1925 | |||
1926 | return id; // the id of the RegistrySearchRef element is its signature | ||
1927 | } | ||
1928 | |||
1929 | /// <summary> | ||
1930 | /// Parses child elements for search signatures. | ||
1931 | /// </summary> | ||
1932 | /// <param name="node">Node whose children we are parsing.</param> | ||
1933 | /// <returns>Returns list of string signatures.</returns> | ||
1934 | private List<string> ParseSearchSignatures(XElement node) | ||
1935 | { | ||
1936 | List<string> signatures = new List<string>(); | ||
1937 | |||
1938 | foreach (XElement child in node.Elements()) | ||
1939 | { | ||
1940 | string signature = null; | ||
1941 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
1942 | { | ||
1943 | switch (child.Name.LocalName) | ||
1944 | { | ||
1945 | case "ComplianceDrive": | ||
1946 | signature = this.ParseComplianceDriveElement(child); | ||
1947 | break; | ||
1948 | case "ComponentSearch": | ||
1949 | signature = this.ParseComponentSearchElement(child); | ||
1950 | break; | ||
1951 | case "DirectorySearch": | ||
1952 | signature = this.ParseDirectorySearchElement(child, String.Empty); | ||
1953 | break; | ||
1954 | case "DirectorySearchRef": | ||
1955 | signature = this.ParseDirectorySearchRefElement(child, String.Empty); | ||
1956 | break; | ||
1957 | case "IniFileSearch": | ||
1958 | signature = this.ParseIniFileSearchElement(child); | ||
1959 | break; | ||
1960 | case "ProductSearch": | ||
1961 | // handled in ParsePropertyElement | ||
1962 | break; | ||
1963 | case "RegistrySearch": | ||
1964 | signature = this.ParseRegistrySearchElement(child); | ||
1965 | break; | ||
1966 | case "RegistrySearchRef": | ||
1967 | signature = this.ParseRegistrySearchRefElement(child); | ||
1968 | break; | ||
1969 | default: | ||
1970 | this.core.UnexpectedElement(node, child); | ||
1971 | break; | ||
1972 | } | ||
1973 | } | ||
1974 | else | ||
1975 | { | ||
1976 | this.core.ParseExtensionElement(node, child); | ||
1977 | } | ||
1978 | |||
1979 | |||
1980 | if (!String.IsNullOrEmpty(signature)) | ||
1981 | { | ||
1982 | signatures.Add(signature); | ||
1983 | } | ||
1984 | } | ||
1985 | |||
1986 | return signatures; | ||
1987 | } | ||
1988 | |||
1989 | /// <summary> | ||
1990 | /// Parses a compliance drive element. | ||
1991 | /// </summary> | ||
1992 | /// <param name="node">Element to parse.</param> | ||
1993 | /// <returns>Signature of nested search elements.</returns> | ||
1994 | private string ParseComplianceDriveElement(XElement node) | ||
1995 | { | ||
1996 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
1997 | string signature = null; | ||
1998 | |||
1999 | bool oneChild = false; | ||
2000 | foreach (XElement child in node.Elements()) | ||
2001 | { | ||
2002 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
2003 | { | ||
2004 | SourceLineNumber childSourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
2005 | switch (child.Name.LocalName) | ||
2006 | { | ||
2007 | case "DirectorySearch": | ||
2008 | if (oneChild) | ||
2009 | { | ||
2010 | this.core.OnMessage(WixErrors.TooManySearchElements(childSourceLineNumbers, node.Name.LocalName)); | ||
2011 | } | ||
2012 | oneChild = true; | ||
2013 | signature = this.ParseDirectorySearchElement(child, "CCP_DRIVE"); | ||
2014 | break; | ||
2015 | case "DirectorySearchRef": | ||
2016 | if (oneChild) | ||
2017 | { | ||
2018 | this.core.OnMessage(WixErrors.TooManySearchElements(childSourceLineNumbers, node.Name.LocalName)); | ||
2019 | } | ||
2020 | oneChild = true; | ||
2021 | signature = this.ParseDirectorySearchRefElement(child, "CCP_DRIVE"); | ||
2022 | break; | ||
2023 | default: | ||
2024 | this.core.UnexpectedElement(node, child); | ||
2025 | break; | ||
2026 | } | ||
2027 | } | ||
2028 | else | ||
2029 | { | ||
2030 | this.core.ParseExtensionElement(node, child); | ||
2031 | } | ||
2032 | } | ||
2033 | |||
2034 | if (null == signature) | ||
2035 | { | ||
2036 | this.core.OnMessage(WixErrors.SearchElementRequired(sourceLineNumbers, node.Name.LocalName)); | ||
2037 | } | ||
2038 | |||
2039 | return signature; | ||
2040 | } | ||
2041 | |||
2042 | /// <summary> | ||
2043 | /// Parses a compilance check element. | ||
2044 | /// </summary> | ||
2045 | /// <param name="node">Element to parse.</param> | ||
2046 | private void ParseComplianceCheckElement(XElement node) | ||
2047 | { | ||
2048 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
2049 | |||
2050 | foreach (XAttribute attrib in node.Attributes()) | ||
2051 | { | ||
2052 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
2053 | { | ||
2054 | switch (attrib.Name.LocalName) | ||
2055 | { | ||
2056 | default: | ||
2057 | this.core.UnexpectedAttribute(node, attrib); | ||
2058 | break; | ||
2059 | } | ||
2060 | } | ||
2061 | else | ||
2062 | { | ||
2063 | this.core.ParseExtensionAttribute(node, attrib); | ||
2064 | } | ||
2065 | } | ||
2066 | |||
2067 | string signature = null; | ||
2068 | |||
2069 | // see if this property is used for appSearch | ||
2070 | List<string> signatures = this.ParseSearchSignatures(node); | ||
2071 | foreach (string sig in signatures) | ||
2072 | { | ||
2073 | // if we haven't picked a signature for this ComplianceCheck pick | ||
2074 | // this one | ||
2075 | if (null == signature) | ||
2076 | { | ||
2077 | signature = sig; | ||
2078 | } | ||
2079 | else if (signature != sig) | ||
2080 | { | ||
2081 | // all signatures under a ComplianceCheck must be the same | ||
2082 | this.core.OnMessage(WixErrors.MultipleIdentifiersFound(sourceLineNumbers, node.Name.LocalName, sig, signature)); | ||
2083 | } | ||
2084 | } | ||
2085 | |||
2086 | if (null == signature) | ||
2087 | { | ||
2088 | this.core.OnMessage(WixErrors.SearchElementRequired(sourceLineNumbers, node.Name.LocalName)); | ||
2089 | } | ||
2090 | |||
2091 | if (!this.core.EncounteredError) | ||
2092 | { | ||
2093 | Row row = this.core.CreateRow(sourceLineNumbers, "CCPSearch"); | ||
2094 | row[0] = signature; | ||
2095 | } | ||
2096 | } | ||
2097 | |||
2098 | /// <summary> | ||
2099 | /// Parses a component element. | ||
2100 | /// </summary> | ||
2101 | /// <param name="node">Element to parse.</param> | ||
2102 | /// <param name="parentType">Type of component's complex reference parent. Will be Uknown if there is no parent.</param> | ||
2103 | /// <param name="parentId">Optional identifier for component's primary parent.</param> | ||
2104 | /// <param name="parentLanguage">Optional string for component's parent's language.</param> | ||
2105 | /// <param name="diskId">Optional disk id inherited from parent directory.</param> | ||
2106 | /// <param name="directoryId">Optional identifier for component's directory.</param> | ||
2107 | /// <param name="srcPath">Optional source path for files up to this point.</param> | ||
2108 | [SuppressMessage("Microsoft.Performance", "CA1800:DoNotCastUnnecessarily")] | ||
2109 | private void ParseComponentElement(XElement node, ComplexReferenceParentType parentType, string parentId, string parentLanguage, int diskId, string directoryId, string srcPath) | ||
2110 | { | ||
2111 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
2112 | |||
2113 | int bits = 0; | ||
2114 | int comPlusBits = CompilerConstants.IntegerNotSet; | ||
2115 | string condition = null; | ||
2116 | bool encounteredODBCDataSource = false; | ||
2117 | bool explicitWin64 = false; | ||
2118 | int files = 0; | ||
2119 | string guid = "*"; | ||
2120 | string componentIdPlaceholder = String.Format(Compiler.DefaultComponentIdPlaceholderFormat, this.componentIdPlaceholdersResolver.VariableCount); // placeholder id for defaulting Component/@Id to keypath id. | ||
2121 | string componentIdPlaceholderWixVariable = String.Format(Compiler.DefaultComponentIdPlaceholderWixVariableFormat, componentIdPlaceholder); | ||
2122 | Identifier id = new Identifier(componentIdPlaceholderWixVariable, AccessModifier.Private); | ||
2123 | int keyBits = 0; | ||
2124 | bool keyFound = false; | ||
2125 | string keyPath = null; | ||
2126 | bool shouldAddCreateFolder = false; | ||
2127 | bool win64 = false; | ||
2128 | bool multiInstance = false; | ||
2129 | List<string> symbols = new List<string>(); | ||
2130 | string feature = null; | ||
2131 | |||
2132 | foreach (XAttribute attrib in node.Attributes()) | ||
2133 | { | ||
2134 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
2135 | { | ||
2136 | switch (attrib.Name.LocalName) | ||
2137 | { | ||
2138 | case "Id": | ||
2139 | id = this.core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
2140 | break; | ||
2141 | case "ComPlusFlags": | ||
2142 | comPlusBits = this.core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, short.MaxValue); | ||
2143 | break; | ||
2144 | case "DisableRegistryReflection": | ||
2145 | if (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
2146 | { | ||
2147 | bits |= MsiInterop.MsidbComponentAttributesDisableRegistryReflection; | ||
2148 | } | ||
2149 | break; | ||
2150 | case "Directory": | ||
2151 | directoryId = this.core.CreateDirectoryReferenceFromInlineSyntax(sourceLineNumbers, attrib, directoryId); | ||
2152 | break; | ||
2153 | case "DiskId": | ||
2154 | diskId = this.core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 1, short.MaxValue); | ||
2155 | break; | ||
2156 | case "Feature": | ||
2157 | feature = this.core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
2158 | break; | ||
2159 | case "Guid": | ||
2160 | guid = this.core.GetAttributeGuidValue(sourceLineNumbers, attrib, true, true); | ||
2161 | break; | ||
2162 | case "KeyPath": | ||
2163 | if (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
2164 | { | ||
2165 | keyFound = true; | ||
2166 | keyPath = null; | ||
2167 | keyBits = 0; | ||
2168 | shouldAddCreateFolder = true; | ||
2169 | } | ||
2170 | break; | ||
2171 | case "Location": | ||
2172 | string location = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
2173 | if (0 < location.Length) | ||
2174 | { | ||
2175 | Wix.Component.LocationType locationType = Wix.Component.ParseLocationType(location); | ||
2176 | switch (locationType) | ||
2177 | { | ||
2178 | case Wix.Component.LocationType.either: | ||
2179 | bits |= MsiInterop.MsidbComponentAttributesOptional; | ||
2180 | break; | ||
2181 | case Wix.Component.LocationType.local: // this is the default | ||
2182 | break; | ||
2183 | case Wix.Component.LocationType.source: | ||
2184 | bits |= MsiInterop.MsidbComponentAttributesSourceOnly; | ||
2185 | break; | ||
2186 | default: | ||
2187 | this.core.OnMessage(WixErrors.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, "either", "local", "source")); | ||
2188 | break; | ||
2189 | } | ||
2190 | } | ||
2191 | break; | ||
2192 | case "MultiInstance": | ||
2193 | multiInstance = YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
2194 | break; | ||
2195 | case "NeverOverwrite": | ||
2196 | if (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
2197 | { | ||
2198 | bits |= MsiInterop.MsidbComponentAttributesNeverOverwrite; | ||
2199 | } | ||
2200 | break; | ||
2201 | case "Permanent": | ||
2202 | if (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
2203 | { | ||
2204 | bits |= MsiInterop.MsidbComponentAttributesPermanent; | ||
2205 | } | ||
2206 | break; | ||
2207 | case "Shared": | ||
2208 | if (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
2209 | { | ||
2210 | bits |= MsiInterop.MsidbComponentAttributesShared; | ||
2211 | } | ||
2212 | break; | ||
2213 | case "SharedDllRefCount": | ||
2214 | if (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
2215 | { | ||
2216 | bits |= MsiInterop.MsidbComponentAttributesSharedDllRefCount; | ||
2217 | } | ||
2218 | break; | ||
2219 | case "Transitive": | ||
2220 | if (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
2221 | { | ||
2222 | bits |= MsiInterop.MsidbComponentAttributesTransitive; | ||
2223 | } | ||
2224 | break; | ||
2225 | case "UninstallWhenSuperseded": | ||
2226 | if (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
2227 | { | ||
2228 | bits |= MsiInterop.MsidbComponentAttributesUninstallOnSupersedence; | ||
2229 | } | ||
2230 | break; | ||
2231 | case "Win64": | ||
2232 | explicitWin64 = true; | ||
2233 | if (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
2234 | { | ||
2235 | bits |= MsiInterop.MsidbComponentAttributes64bit; | ||
2236 | win64 = true; | ||
2237 | } | ||
2238 | break; | ||
2239 | default: | ||
2240 | this.core.UnexpectedAttribute(node, attrib); | ||
2241 | break; | ||
2242 | } | ||
2243 | } | ||
2244 | else | ||
2245 | { | ||
2246 | this.core.ParseExtensionAttribute(node, attrib); | ||
2247 | } | ||
2248 | } | ||
2249 | |||
2250 | if (!explicitWin64 && (Platform.IA64 == this.CurrentPlatform || Platform.X64 == this.CurrentPlatform)) | ||
2251 | { | ||
2252 | bits |= MsiInterop.MsidbComponentAttributes64bit; | ||
2253 | win64 = true; | ||
2254 | } | ||
2255 | |||
2256 | if (null == directoryId) | ||
2257 | { | ||
2258 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Directory")); | ||
2259 | } | ||
2260 | |||
2261 | if (String.IsNullOrEmpty(guid) && MsiInterop.MsidbComponentAttributesShared == (bits & MsiInterop.MsidbComponentAttributesShared)) | ||
2262 | { | ||
2263 | this.core.OnMessage(WixErrors.IllegalAttributeValueWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Shared", "yes", "Guid", "")); | ||
2264 | } | ||
2265 | |||
2266 | if (String.IsNullOrEmpty(guid) && MsiInterop.MsidbComponentAttributesPermanent == (bits & MsiInterop.MsidbComponentAttributesPermanent)) | ||
2267 | { | ||
2268 | this.core.OnMessage(WixErrors.IllegalAttributeValueWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Permanent", "yes", "Guid", "")); | ||
2269 | } | ||
2270 | |||
2271 | if (null != feature) | ||
2272 | { | ||
2273 | if (this.compilingModule) | ||
2274 | { | ||
2275 | this.core.OnMessage(WixErrors.IllegalAttributeInMergeModule(sourceLineNumbers, node.Name.LocalName, "Feature")); | ||
2276 | } | ||
2277 | else | ||
2278 | { | ||
2279 | if (ComplexReferenceParentType.Feature == parentType || ComplexReferenceParentType.FeatureGroup == parentType) | ||
2280 | { | ||
2281 | this.core.OnMessage(WixErrors.IllegalAttributeWhenNested(sourceLineNumbers, node.Name.LocalName, "Feature", node.Parent.Name.LocalName)); | ||
2282 | } | ||
2283 | else | ||
2284 | { | ||
2285 | this.core.CreateComplexReference(sourceLineNumbers, ComplexReferenceParentType.Feature, feature, null, ComplexReferenceChildType.Component, id.Id, true); | ||
2286 | } | ||
2287 | } | ||
2288 | } | ||
2289 | |||
2290 | foreach (XElement child in node.Elements()) | ||
2291 | { | ||
2292 | YesNoType keyPathSet = YesNoType.NotSet; | ||
2293 | string keyPossible = null; | ||
2294 | int keyBit = 0; | ||
2295 | |||
2296 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
2297 | { | ||
2298 | switch (child.Name.LocalName) | ||
2299 | { | ||
2300 | case "AppId": | ||
2301 | this.ParseAppIdElement(child, id.Id, YesNoType.NotSet, null, null, null); | ||
2302 | break; | ||
2303 | case "Category": | ||
2304 | this.ParseCategoryElement(child, id.Id); | ||
2305 | break; | ||
2306 | case "Class": | ||
2307 | this.ParseClassElement(child, id.Id, YesNoType.NotSet, null, null, null, null); | ||
2308 | break; | ||
2309 | case "Condition": | ||
2310 | if (null != condition) | ||
2311 | { | ||
2312 | SourceLineNumber childSourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
2313 | this.core.OnMessage(WixErrors.TooManyChildren(childSourceLineNumbers, node.Name.LocalName, child.Name.LocalName)); | ||
2314 | } | ||
2315 | condition = this.ParseConditionElement(child, node.Name.LocalName, null, null); | ||
2316 | break; | ||
2317 | case "CopyFile": | ||
2318 | this.ParseCopyFileElement(child, id.Id, null); | ||
2319 | break; | ||
2320 | case "CreateFolder": | ||
2321 | string createdFolder = this.ParseCreateFolderElement(child, id.Id, directoryId, win64); | ||
2322 | if (directoryId == createdFolder) | ||
2323 | { | ||
2324 | shouldAddCreateFolder = false; | ||
2325 | } | ||
2326 | break; | ||
2327 | case "Environment": | ||
2328 | this.ParseEnvironmentElement(child, id.Id); | ||
2329 | break; | ||
2330 | case "Extension": | ||
2331 | this.ParseExtensionElement(child, id.Id, YesNoType.NotSet, null); | ||
2332 | break; | ||
2333 | case "File": | ||
2334 | keyPathSet = this.ParseFileElement(child, id.Id, directoryId, diskId, srcPath, out keyPossible, win64, guid); | ||
2335 | if (null != keyPossible) | ||
2336 | { | ||
2337 | keyBit = 0; | ||
2338 | } | ||
2339 | files++; | ||
2340 | break; | ||
2341 | case "IniFile": | ||
2342 | this.ParseIniFileElement(child, id.Id); | ||
2343 | break; | ||
2344 | case "Interface": | ||
2345 | this.ParseInterfaceElement(child, id.Id, null, null, null, null); | ||
2346 | break; | ||
2347 | case "IsolateComponent": | ||
2348 | this.ParseIsolateComponentElement(child, id.Id); | ||
2349 | break; | ||
2350 | case "ODBCDataSource": | ||
2351 | keyPathSet = this.ParseODBCDataSource(child, id.Id, null, out keyPossible); | ||
2352 | keyBit = MsiInterop.MsidbComponentAttributesODBCDataSource; | ||
2353 | encounteredODBCDataSource = true; | ||
2354 | break; | ||
2355 | case "ODBCDriver": | ||
2356 | this.ParseODBCDriverOrTranslator(child, id.Id, null, this.tableDefinitions["ODBCDriver"]); | ||
2357 | break; | ||
2358 | case "ODBCTranslator": | ||
2359 | this.ParseODBCDriverOrTranslator(child, id.Id, null, this.tableDefinitions["ODBCTranslator"]); | ||
2360 | break; | ||
2361 | case "ProgId": | ||
2362 | bool foundExtension = false; | ||
2363 | this.ParseProgIdElement(child, id.Id, YesNoType.NotSet, null, null, null, ref foundExtension, YesNoType.NotSet); | ||
2364 | break; | ||
2365 | case "RegistryKey": | ||
2366 | keyPathSet = this.ParseRegistryKeyElement(child, id.Id, CompilerConstants.IntegerNotSet, null, win64, out keyPossible); | ||
2367 | keyBit = MsiInterop.MsidbComponentAttributesRegistryKeyPath; | ||
2368 | break; | ||
2369 | case "RegistryValue": | ||
2370 | keyPathSet = this.ParseRegistryValueElement(child, id.Id, CompilerConstants.IntegerNotSet, null, win64, out keyPossible); | ||
2371 | keyBit = MsiInterop.MsidbComponentAttributesRegistryKeyPath; | ||
2372 | break; | ||
2373 | case "RemoveFile": | ||
2374 | this.ParseRemoveFileElement(child, id.Id, directoryId); | ||
2375 | break; | ||
2376 | case "RemoveFolder": | ||
2377 | this.ParseRemoveFolderElement(child, id.Id, directoryId); | ||
2378 | break; | ||
2379 | case "RemoveRegistryKey": | ||
2380 | this.ParseRemoveRegistryKeyElement(child, id.Id); | ||
2381 | break; | ||
2382 | case "RemoveRegistryValue": | ||
2383 | this.ParseRemoveRegistryValueElement(child, id.Id); | ||
2384 | break; | ||
2385 | case "ReserveCost": | ||
2386 | this.ParseReserveCostElement(child, id.Id, directoryId); | ||
2387 | break; | ||
2388 | case "ServiceConfig": | ||
2389 | this.ParseServiceConfigElement(child, id.Id, null); | ||
2390 | break; | ||
2391 | case "ServiceConfigFailureActions": | ||
2392 | this.ParseServiceConfigFailureActionsElement(child, id.Id, null); | ||
2393 | break; | ||
2394 | case "ServiceControl": | ||
2395 | this.ParseServiceControlElement(child, id.Id); | ||
2396 | break; | ||
2397 | case "ServiceInstall": | ||
2398 | this.ParseServiceInstallElement(child, id.Id, win64); | ||
2399 | break; | ||
2400 | case "Shortcut": | ||
2401 | this.ParseShortcutElement(child, id.Id, node.Name.LocalName, directoryId, YesNoType.No); | ||
2402 | break; | ||
2403 | case "SymbolPath": | ||
2404 | symbols.Add(this.ParseSymbolPathElement(child)); | ||
2405 | break; | ||
2406 | case "TypeLib": | ||
2407 | this.ParseTypeLibElement(child, id.Id, null, win64); | ||
2408 | break; | ||
2409 | default: | ||
2410 | this.core.UnexpectedElement(node, child); | ||
2411 | break; | ||
2412 | } | ||
2413 | } | ||
2414 | else | ||
2415 | { | ||
2416 | Dictionary<string, string> context = new Dictionary<string, string>() { { "ComponentId", id.Id }, { "DirectoryId", directoryId }, { "Win64", win64.ToString() }, }; | ||
2417 | ComponentKeyPath possibleKeyPath = this.core.ParsePossibleKeyPathExtensionElement(node, child, context); | ||
2418 | if (null != possibleKeyPath) | ||
2419 | { | ||
2420 | if (ComponentKeyPathType.None == possibleKeyPath.Type) | ||
2421 | { | ||
2422 | keyPathSet = YesNoType.No; | ||
2423 | } | ||
2424 | else | ||
2425 | { | ||
2426 | keyPathSet = possibleKeyPath.Explicit ? YesNoType.Yes : YesNoType.NotSet; | ||
2427 | |||
2428 | if (!String.IsNullOrEmpty(possibleKeyPath.Id)) | ||
2429 | { | ||
2430 | keyPossible = possibleKeyPath.Id; | ||
2431 | } | ||
2432 | |||
2433 | if (ComponentKeyPathType.Registry == possibleKeyPath.Type || ComponentKeyPathType.RegistryFormatted == possibleKeyPath.Type) | ||
2434 | { | ||
2435 | keyBit = MsiInterop.MsidbComponentAttributesRegistryKeyPath; | ||
2436 | } | ||
2437 | } | ||
2438 | } | ||
2439 | } | ||
2440 | |||
2441 | // Verify that either the key path is not set, or it is set along with a key path ID. | ||
2442 | Debug.Assert(YesNoType.Yes != keyPathSet || (YesNoType.Yes == keyPathSet && null != keyPossible)); | ||
2443 | |||
2444 | if (keyFound && YesNoType.Yes == keyPathSet) | ||
2445 | { | ||
2446 | this.core.OnMessage(WixErrors.ComponentMultipleKeyPaths(sourceLineNumbers, node.Name.LocalName, "KeyPath", "yes", "File", "RegistryValue", "ODBCDataSource")); | ||
2447 | } | ||
2448 | |||
2449 | // if a possible KeyPath has been found and that value was explicitly set as | ||
2450 | // the KeyPath of the component, set it now. Alternatively, if a possible | ||
2451 | // KeyPath has been found and no KeyPath has been previously set, use this | ||
2452 | // value as the default KeyPath of the component | ||
2453 | if (!String.IsNullOrEmpty(keyPossible) && (YesNoType.Yes == keyPathSet || (YesNoType.NotSet == keyPathSet && String.IsNullOrEmpty(keyPath) && !keyFound))) | ||
2454 | { | ||
2455 | keyFound = YesNoType.Yes == keyPathSet; | ||
2456 | keyPath = keyPossible; | ||
2457 | keyBits = keyBit; | ||
2458 | } | ||
2459 | } | ||
2460 | |||
2461 | |||
2462 | if (shouldAddCreateFolder) | ||
2463 | { | ||
2464 | Row row = this.core.CreateRow(sourceLineNumbers, "CreateFolder"); | ||
2465 | row[0] = directoryId; | ||
2466 | row[1] = id.Id; | ||
2467 | } | ||
2468 | |||
2469 | // check for conditions that exclude this component from using generated guids | ||
2470 | bool isGeneratableGuidOk = "*" == guid; | ||
2471 | if (isGeneratableGuidOk) | ||
2472 | { | ||
2473 | if (encounteredODBCDataSource) | ||
2474 | { | ||
2475 | this.core.OnMessage(WixErrors.IllegalComponentWithAutoGeneratedGuid(sourceLineNumbers)); | ||
2476 | isGeneratableGuidOk = false; | ||
2477 | } | ||
2478 | |||
2479 | if (0 != files && MsiInterop.MsidbComponentAttributesRegistryKeyPath == keyBits) | ||
2480 | { | ||
2481 | this.core.OnMessage(WixErrors.IllegalComponentWithAutoGeneratedGuid(sourceLineNumbers, true)); | ||
2482 | isGeneratableGuidOk = false; | ||
2483 | } | ||
2484 | } | ||
2485 | |||
2486 | // check for implicit KeyPath which can easily be accidentally changed | ||
2487 | if (this.showPedanticMessages && !keyFound && !isGeneratableGuidOk) | ||
2488 | { | ||
2489 | this.core.OnMessage(WixErrors.ImplicitComponentKeyPath(sourceLineNumbers, id.Id)); | ||
2490 | } | ||
2491 | |||
2492 | // if there isn't an @Id attribute value, replace the placeholder with the id of the keypath. | ||
2493 | // either an explicit KeyPath="yes" attribute must be specified or requirements for | ||
2494 | // generatable guid must be met. | ||
2495 | if (componentIdPlaceholderWixVariable == id.Id) | ||
2496 | { | ||
2497 | if (isGeneratableGuidOk || keyFound && !String.IsNullOrEmpty(keyPath)) | ||
2498 | { | ||
2499 | this.componentIdPlaceholdersResolver.AddVariable(componentIdPlaceholder, keyPath); | ||
2500 | |||
2501 | id = new Identifier(keyPath, AccessModifier.Private); | ||
2502 | } | ||
2503 | else | ||
2504 | { | ||
2505 | this.core.OnMessage(WixErrors.CannotDefaultComponentId(sourceLineNumbers)); | ||
2506 | } | ||
2507 | } | ||
2508 | |||
2509 | // If an id was not determined by now, we have to error. | ||
2510 | if (null == id) | ||
2511 | { | ||
2512 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
2513 | } | ||
2514 | |||
2515 | // finally add the Component table row | ||
2516 | if (!this.core.EncounteredError) | ||
2517 | { | ||
2518 | Row row = this.core.CreateRow(sourceLineNumbers, "Component", id); | ||
2519 | row[1] = guid; | ||
2520 | row[2] = directoryId; | ||
2521 | row[3] = bits | keyBits; | ||
2522 | row[4] = condition; | ||
2523 | row[5] = keyPath; | ||
2524 | |||
2525 | if (multiInstance) | ||
2526 | { | ||
2527 | Row instanceComponentRow = this.core.CreateRow(sourceLineNumbers, "WixInstanceComponent"); | ||
2528 | instanceComponentRow[0] = id; | ||
2529 | } | ||
2530 | |||
2531 | if (0 < symbols.Count) | ||
2532 | { | ||
2533 | WixDeltaPatchSymbolPathsRow symbolRow = (WixDeltaPatchSymbolPathsRow)this.core.CreateRow(sourceLineNumbers, "WixDeltaPatchSymbolPaths", id); | ||
2534 | symbolRow.Type = SymbolPathType.Component; | ||
2535 | symbolRow.SymbolPaths = String.Join(";", symbols); | ||
2536 | } | ||
2537 | |||
2538 | // Complus | ||
2539 | if (CompilerConstants.IntegerNotSet != comPlusBits) | ||
2540 | { | ||
2541 | row = this.core.CreateRow(sourceLineNumbers, "Complus"); | ||
2542 | row[0] = id; | ||
2543 | row[1] = comPlusBits; | ||
2544 | } | ||
2545 | |||
2546 | // if this is a module, automatically add this component to the references to ensure it gets in the ModuleComponents table | ||
2547 | if (this.compilingModule) | ||
2548 | { | ||
2549 | this.core.CreateComplexReference(sourceLineNumbers, ComplexReferenceParentType.Module, this.activeName, this.activeLanguage, ComplexReferenceChildType.Component, id.Id, false); | ||
2550 | } | ||
2551 | else if (ComplexReferenceParentType.Unknown != parentType && null != parentId) // if parent was provided, add a complex reference to that. | ||
2552 | { | ||
2553 | // If the Component is defined directly under a feature, then mark the complex reference primary. | ||
2554 | this.core.CreateComplexReference(sourceLineNumbers, parentType, parentId, parentLanguage, ComplexReferenceChildType.Component, id.Id, ComplexReferenceParentType.Feature == parentType); | ||
2555 | } | ||
2556 | } | ||
2557 | } | ||
2558 | |||
2559 | /// <summary> | ||
2560 | /// Parses a component group element. | ||
2561 | /// </summary> | ||
2562 | /// <param name="node">Element to parse.</param> | ||
2563 | [SuppressMessage("Microsoft.Performance", "CA1800:DoNotCastUnnecessarily")] | ||
2564 | private void ParseComponentGroupElement(XElement node, ComplexReferenceParentType parentType, string parentId) | ||
2565 | { | ||
2566 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
2567 | Identifier id = null; | ||
2568 | string directoryId = null; | ||
2569 | string source = null; | ||
2570 | |||
2571 | foreach (XAttribute attrib in node.Attributes()) | ||
2572 | { | ||
2573 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
2574 | { | ||
2575 | switch (attrib.Name.LocalName) | ||
2576 | { | ||
2577 | case "Id": | ||
2578 | id = this.core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
2579 | break; | ||
2580 | case "Directory": | ||
2581 | // If the inline syntax is invalid it returns null. Use a static error identifier so the null | ||
2582 | // directory identifier here doesn't trickle down false errors into child elements. | ||
2583 | directoryId = this.core.CreateDirectoryReferenceFromInlineSyntax(sourceLineNumbers, attrib, null) ?? "ErrorParsingInlineSyntax"; | ||
2584 | break; | ||
2585 | case "Source": | ||
2586 | source = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
2587 | break; | ||
2588 | default: | ||
2589 | this.core.UnexpectedAttribute(node, attrib); | ||
2590 | break; | ||
2591 | } | ||
2592 | } | ||
2593 | else | ||
2594 | { | ||
2595 | this.core.ParseExtensionAttribute(node, attrib); | ||
2596 | } | ||
2597 | } | ||
2598 | |||
2599 | if (null == id) | ||
2600 | { | ||
2601 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
2602 | id = Identifier.Invalid; | ||
2603 | } | ||
2604 | |||
2605 | if (!String.IsNullOrEmpty(source) && !source.EndsWith(Path.DirectorySeparatorChar.ToString(), StringComparison.Ordinal)) | ||
2606 | { | ||
2607 | source = String.Concat(source, Path.DirectorySeparatorChar); | ||
2608 | } | ||
2609 | |||
2610 | foreach (XElement child in node.Elements()) | ||
2611 | { | ||
2612 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
2613 | { | ||
2614 | switch (child.Name.LocalName) | ||
2615 | { | ||
2616 | case "ComponentGroupRef": | ||
2617 | this.ParseComponentGroupRefElement(child, ComplexReferenceParentType.ComponentGroup, id.Id, null); | ||
2618 | break; | ||
2619 | case "ComponentRef": | ||
2620 | this.ParseComponentRefElement(child, ComplexReferenceParentType.ComponentGroup, id.Id, null); | ||
2621 | break; | ||
2622 | case "Component": | ||
2623 | this.ParseComponentElement(child, ComplexReferenceParentType.ComponentGroup, id.Id, null, CompilerConstants.IntegerNotSet, directoryId, source); | ||
2624 | break; | ||
2625 | default: | ||
2626 | this.core.UnexpectedElement(node, child); | ||
2627 | break; | ||
2628 | } | ||
2629 | } | ||
2630 | else | ||
2631 | { | ||
2632 | this.core.ParseExtensionElement(node, child); | ||
2633 | } | ||
2634 | } | ||
2635 | |||
2636 | if (!this.core.EncounteredError) | ||
2637 | { | ||
2638 | Row row = this.core.CreateRow(sourceLineNumbers, "WixComponentGroup", id); | ||
2639 | |||
2640 | // Add this componentGroup and its parent in WixGroup. | ||
2641 | this.core.CreateWixGroupRow(sourceLineNumbers, parentType, parentId, ComplexReferenceChildType.ComponentGroup, id.Id); | ||
2642 | } | ||
2643 | } | ||
2644 | |||
2645 | /// <summary> | ||
2646 | /// Parses a component group reference element. | ||
2647 | /// </summary> | ||
2648 | /// <param name="node">Element to parse.</param> | ||
2649 | /// <param name="parentType">ComplexReferenceParentType of parent element.</param> | ||
2650 | /// <param name="parentId">Identifier of parent element (usually a Feature or Module).</param> | ||
2651 | /// <param name="parentLanguage">Optional language of parent (only useful for Modules).</param> | ||
2652 | private void ParseComponentGroupRefElement(XElement node, ComplexReferenceParentType parentType, string parentId, string parentLanguage) | ||
2653 | { | ||
2654 | Debug.Assert(ComplexReferenceParentType.ComponentGroup == parentType || ComplexReferenceParentType.FeatureGroup == parentType || ComplexReferenceParentType.Feature == parentType || ComplexReferenceParentType.Module == parentType); | ||
2655 | |||
2656 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
2657 | string id = null; | ||
2658 | YesNoType primary = YesNoType.NotSet; | ||
2659 | |||
2660 | foreach (XAttribute attrib in node.Attributes()) | ||
2661 | { | ||
2662 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
2663 | { | ||
2664 | switch (attrib.Name.LocalName) | ||
2665 | { | ||
2666 | case "Id": | ||
2667 | id = this.core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
2668 | this.core.CreateSimpleReference(sourceLineNumbers, "WixComponentGroup", id); | ||
2669 | break; | ||
2670 | case "Primary": | ||
2671 | primary = this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
2672 | break; | ||
2673 | default: | ||
2674 | this.core.UnexpectedAttribute(node, attrib); | ||
2675 | break; | ||
2676 | } | ||
2677 | } | ||
2678 | else | ||
2679 | { | ||
2680 | this.core.ParseExtensionAttribute(node, attrib); | ||
2681 | } | ||
2682 | } | ||
2683 | |||
2684 | if (null == id) | ||
2685 | { | ||
2686 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
2687 | } | ||
2688 | |||
2689 | this.core.ParseForExtensionElements(node); | ||
2690 | |||
2691 | this.core.CreateComplexReference(sourceLineNumbers, parentType, parentId, parentLanguage, ComplexReferenceChildType.ComponentGroup, id, (YesNoType.Yes == primary)); | ||
2692 | } | ||
2693 | |||
2694 | /// <summary> | ||
2695 | /// Parses a component reference element. | ||
2696 | /// </summary> | ||
2697 | /// <param name="node">Element to parse.</param> | ||
2698 | /// <param name="parentType">ComplexReferenceParentType of parent element.</param> | ||
2699 | /// <param name="parentId">Identifier of parent element (usually a Feature or Module).</param> | ||
2700 | /// <param name="parentLanguage">Optional language of parent (only useful for Modules).</param> | ||
2701 | private void ParseComponentRefElement(XElement node, ComplexReferenceParentType parentType, string parentId, string parentLanguage) | ||
2702 | { | ||
2703 | Debug.Assert(ComplexReferenceParentType.FeatureGroup == parentType || ComplexReferenceParentType.ComponentGroup == parentType || ComplexReferenceParentType.Feature == parentType || ComplexReferenceParentType.Module == parentType); | ||
2704 | |||
2705 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
2706 | string id = null; | ||
2707 | YesNoType primary = YesNoType.NotSet; | ||
2708 | |||
2709 | foreach (XAttribute attrib in node.Attributes()) | ||
2710 | { | ||
2711 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
2712 | { | ||
2713 | switch (attrib.Name.LocalName) | ||
2714 | { | ||
2715 | case "Id": | ||
2716 | id = this.core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
2717 | this.core.CreateSimpleReference(sourceLineNumbers, "Component", id); | ||
2718 | break; | ||
2719 | case "Primary": | ||
2720 | primary = this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
2721 | break; | ||
2722 | default: | ||
2723 | this.core.UnexpectedAttribute(node, attrib); | ||
2724 | break; | ||
2725 | } | ||
2726 | } | ||
2727 | else | ||
2728 | { | ||
2729 | this.core.ParseExtensionAttribute(node, attrib); | ||
2730 | } | ||
2731 | } | ||
2732 | |||
2733 | if (null == id) | ||
2734 | { | ||
2735 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
2736 | } | ||
2737 | |||
2738 | this.core.ParseForExtensionElements(node); | ||
2739 | |||
2740 | this.core.CreateComplexReference(sourceLineNumbers, parentType, parentId, parentLanguage, ComplexReferenceChildType.Component, id, (YesNoType.Yes == primary)); | ||
2741 | } | ||
2742 | |||
2743 | /// <summary> | ||
2744 | /// Parses a component search element. | ||
2745 | /// </summary> | ||
2746 | /// <param name="node">Element to parse.</param> | ||
2747 | /// <returns>Signature for search element.</returns> | ||
2748 | private string ParseComponentSearchElement(XElement node) | ||
2749 | { | ||
2750 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
2751 | Identifier id = null; | ||
2752 | string componentId = null; | ||
2753 | int type = MsiInterop.MsidbLocatorTypeFileName; | ||
2754 | string signature = null; | ||
2755 | |||
2756 | foreach (XAttribute attrib in node.Attributes()) | ||
2757 | { | ||
2758 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
2759 | { | ||
2760 | switch (attrib.Name.LocalName) | ||
2761 | { | ||
2762 | case "Id": | ||
2763 | id = this.core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
2764 | break; | ||
2765 | case "Guid": | ||
2766 | componentId = this.core.GetAttributeGuidValue(sourceLineNumbers, attrib, false); | ||
2767 | break; | ||
2768 | case "Type": | ||
2769 | string typeValue = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
2770 | if (0 < typeValue.Length) | ||
2771 | { | ||
2772 | Wix.ComponentSearch.TypeType typeType = Wix.ComponentSearch.ParseTypeType(typeValue); | ||
2773 | switch (typeType) | ||
2774 | { | ||
2775 | case Wix.ComponentSearch.TypeType.directory: | ||
2776 | type = MsiInterop.MsidbLocatorTypeDirectory; | ||
2777 | break; | ||
2778 | case Wix.ComponentSearch.TypeType.file: | ||
2779 | type = MsiInterop.MsidbLocatorTypeFileName; | ||
2780 | break; | ||
2781 | default: | ||
2782 | this.core.OnMessage(WixErrors.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, typeValue, "directory", "file")); | ||
2783 | break; | ||
2784 | } | ||
2785 | } | ||
2786 | break; | ||
2787 | default: | ||
2788 | this.core.UnexpectedAttribute(node, attrib); | ||
2789 | break; | ||
2790 | } | ||
2791 | } | ||
2792 | else | ||
2793 | { | ||
2794 | this.core.ParseExtensionAttribute(node, attrib); | ||
2795 | } | ||
2796 | } | ||
2797 | |||
2798 | if (null == id) | ||
2799 | { | ||
2800 | id = this.core.CreateIdentifier("cmp", componentId, type.ToString()); | ||
2801 | } | ||
2802 | |||
2803 | signature = id.Id; | ||
2804 | bool oneChild = false; | ||
2805 | foreach (XElement child in node.Elements()) | ||
2806 | { | ||
2807 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
2808 | { | ||
2809 | switch (child.Name.LocalName) | ||
2810 | { | ||
2811 | case "DirectorySearch": | ||
2812 | if (oneChild) | ||
2813 | { | ||
2814 | this.core.OnMessage(WixErrors.TooManySearchElements(sourceLineNumbers, node.Name.LocalName)); | ||
2815 | } | ||
2816 | oneChild = true; | ||
2817 | |||
2818 | // directorysearch parentage should work like directory element, not the rest of the signature type because of the DrLocator.Parent column | ||
2819 | signature = this.ParseDirectorySearchElement(child, id.Id); | ||
2820 | break; | ||
2821 | case "DirectorySearchRef": | ||
2822 | if (oneChild) | ||
2823 | { | ||
2824 | this.core.OnMessage(WixErrors.TooManySearchElements(sourceLineNumbers, node.Name.LocalName)); | ||
2825 | } | ||
2826 | oneChild = true; | ||
2827 | signature = this.ParseDirectorySearchRefElement(child, id.Id); | ||
2828 | break; | ||
2829 | case "FileSearch": | ||
2830 | if (oneChild) | ||
2831 | { | ||
2832 | this.core.OnMessage(WixErrors.TooManySearchElements(sourceLineNumbers, node.Name.LocalName)); | ||
2833 | } | ||
2834 | oneChild = true; | ||
2835 | signature = this.ParseFileSearchElement(child, id.Id, false, CompilerConstants.IntegerNotSet); | ||
2836 | id = new Identifier(signature, AccessModifier.Private); // FileSearch signatures override parent signatures | ||
2837 | break; | ||
2838 | case "FileSearchRef": | ||
2839 | if (oneChild) | ||
2840 | { | ||
2841 | this.core.OnMessage(WixErrors.TooManySearchElements(sourceLineNumbers, node.Name.LocalName)); | ||
2842 | } | ||
2843 | oneChild = true; | ||
2844 | string newId = this.ParseSimpleRefElement(child, "Signature"); // FileSearch signatures override parent signatures | ||
2845 | id = new Identifier(newId, AccessModifier.Private); | ||
2846 | signature = null; | ||
2847 | break; | ||
2848 | default: | ||
2849 | this.core.UnexpectedElement(node, child); | ||
2850 | break; | ||
2851 | } | ||
2852 | } | ||
2853 | else | ||
2854 | { | ||
2855 | this.core.ParseExtensionElement(node, child); | ||
2856 | } | ||
2857 | } | ||
2858 | |||
2859 | if (!this.core.EncounteredError) | ||
2860 | { | ||
2861 | Row row = this.core.CreateRow(sourceLineNumbers, "CompLocator", id); | ||
2862 | row[1] = componentId; | ||
2863 | row[2] = type; | ||
2864 | } | ||
2865 | |||
2866 | return signature; | ||
2867 | } | ||
2868 | |||
2869 | /// <summary> | ||
2870 | /// Parses a create folder element. | ||
2871 | /// </summary> | ||
2872 | /// <param name="node">Element to parse.</param> | ||
2873 | /// <param name="componentId">Identifier for parent component.</param> | ||
2874 | /// <param name="directoryId">Default identifier for directory to create.</param> | ||
2875 | /// <param name="win64Component">true if the component is 64-bit.</param> | ||
2876 | /// <returns>Identifier for the directory that will be created</returns> | ||
2877 | private string ParseCreateFolderElement(XElement node, string componentId, string directoryId, bool win64Component) | ||
2878 | { | ||
2879 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
2880 | foreach (XAttribute attrib in node.Attributes()) | ||
2881 | { | ||
2882 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
2883 | { | ||
2884 | switch (attrib.Name.LocalName) | ||
2885 | { | ||
2886 | case "Directory": | ||
2887 | directoryId = this.core.CreateDirectoryReferenceFromInlineSyntax(sourceLineNumbers, attrib, directoryId); | ||
2888 | break; | ||
2889 | default: | ||
2890 | this.core.UnexpectedAttribute(node, attrib); | ||
2891 | break; | ||
2892 | } | ||
2893 | } | ||
2894 | else | ||
2895 | { | ||
2896 | this.core.ParseExtensionAttribute(node, attrib); | ||
2897 | } | ||
2898 | } | ||
2899 | |||
2900 | foreach (XElement child in node.Elements()) | ||
2901 | { | ||
2902 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
2903 | { | ||
2904 | switch (child.Name.LocalName) | ||
2905 | { | ||
2906 | case "Shortcut": | ||
2907 | this.ParseShortcutElement(child, componentId, node.Name.LocalName, directoryId, YesNoType.No); | ||
2908 | break; | ||
2909 | case "Permission": | ||
2910 | this.ParsePermissionElement(child, directoryId, "CreateFolder"); | ||
2911 | break; | ||
2912 | case "PermissionEx": | ||
2913 | this.ParsePermissionExElement(child, directoryId, "CreateFolder"); | ||
2914 | break; | ||
2915 | default: | ||
2916 | this.core.UnexpectedElement(node, child); | ||
2917 | break; | ||
2918 | } | ||
2919 | } | ||
2920 | else | ||
2921 | { | ||
2922 | Dictionary<string, string> context = new Dictionary<string, string>() { { "DirectoryId", directoryId }, { "ComponentId", componentId }, { "Win64", win64Component.ToString() } }; | ||
2923 | this.core.ParseExtensionElement(node, child, context); | ||
2924 | } | ||
2925 | } | ||
2926 | |||
2927 | if (!this.core.EncounteredError) | ||
2928 | { | ||
2929 | Row row = this.core.CreateRow(sourceLineNumbers, "CreateFolder"); | ||
2930 | row[0] = directoryId; | ||
2931 | row[1] = componentId; | ||
2932 | } | ||
2933 | |||
2934 | return directoryId; | ||
2935 | } | ||
2936 | |||
2937 | /// <summary> | ||
2938 | /// Parses a copy file element. | ||
2939 | /// </summary> | ||
2940 | /// <param name="node">Element to parse.</param> | ||
2941 | /// <param name="componentId">Identifier of parent component.</param> | ||
2942 | /// <param name="fileId">Identifier of file to copy (null if moving the file).</param> | ||
2943 | private void ParseCopyFileElement(XElement node, string componentId, string fileId) | ||
2944 | { | ||
2945 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
2946 | Identifier id = null; | ||
2947 | bool delete = false; | ||
2948 | string destinationDirectory = null; | ||
2949 | string destinationName = null; | ||
2950 | string destinationShortName = null; | ||
2951 | string destinationProperty = null; | ||
2952 | string sourceDirectory = null; | ||
2953 | string sourceFolder = null; | ||
2954 | string sourceName = null; | ||
2955 | string sourceProperty = null; | ||
2956 | |||
2957 | foreach (XAttribute attrib in node.Attributes()) | ||
2958 | { | ||
2959 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
2960 | { | ||
2961 | switch (attrib.Name.LocalName) | ||
2962 | { | ||
2963 | case "Id": | ||
2964 | id = this.core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
2965 | break; | ||
2966 | case "Delete": | ||
2967 | delete = YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
2968 | break; | ||
2969 | case "DestinationDirectory": | ||
2970 | destinationDirectory = this.core.CreateDirectoryReferenceFromInlineSyntax(sourceLineNumbers, attrib, null); | ||
2971 | break; | ||
2972 | case "DestinationName": | ||
2973 | destinationName = this.core.GetAttributeLongFilename(sourceLineNumbers, attrib, false); | ||
2974 | break; | ||
2975 | case "DestinationProperty": | ||
2976 | destinationProperty = this.core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
2977 | break; | ||
2978 | case "DestinationShortName": | ||
2979 | destinationShortName = this.core.GetAttributeShortFilename(sourceLineNumbers, attrib, false); | ||
2980 | break; | ||
2981 | case "FileId": | ||
2982 | if (null != fileId) | ||
2983 | { | ||
2984 | this.core.OnMessage(WixErrors.IllegalAttributeWhenNested(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, node.Parent.Name.LocalName)); | ||
2985 | } | ||
2986 | fileId = this.core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
2987 | this.core.CreateSimpleReference(sourceLineNumbers, "File", fileId); | ||
2988 | break; | ||
2989 | case "SourceDirectory": | ||
2990 | sourceDirectory = this.core.CreateDirectoryReferenceFromInlineSyntax(sourceLineNumbers, attrib, null); | ||
2991 | break; | ||
2992 | case "SourceName": | ||
2993 | sourceName = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
2994 | break; | ||
2995 | case "SourceProperty": | ||
2996 | sourceProperty = this.core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
2997 | break; | ||
2998 | default: | ||
2999 | this.core.UnexpectedAttribute(node, attrib); | ||
3000 | break; | ||
3001 | } | ||
3002 | } | ||
3003 | else | ||
3004 | { | ||
3005 | this.core.ParseExtensionAttribute(node, attrib); | ||
3006 | } | ||
3007 | } | ||
3008 | |||
3009 | if (null != sourceFolder && null != sourceDirectory) // SourceFolder and SourceDirectory cannot coexist | ||
3010 | { | ||
3011 | this.core.OnMessage(WixErrors.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "SourceFolder", "SourceDirectory")); | ||
3012 | } | ||
3013 | |||
3014 | if (null != sourceFolder && null != sourceProperty) // SourceFolder and SourceProperty cannot coexist | ||
3015 | { | ||
3016 | this.core.OnMessage(WixErrors.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "SourceFolder", "SourceProperty")); | ||
3017 | } | ||
3018 | |||
3019 | if (null != sourceDirectory && null != sourceProperty) // SourceDirectory and SourceProperty cannot coexist | ||
3020 | { | ||
3021 | this.core.OnMessage(WixErrors.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "SourceProperty", "SourceDirectory")); | ||
3022 | } | ||
3023 | |||
3024 | if (null != destinationDirectory && null != destinationProperty) // DestinationDirectory and DestinationProperty cannot coexist | ||
3025 | { | ||
3026 | this.core.OnMessage(WixErrors.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "DestinationProperty", "DestinationDirectory")); | ||
3027 | } | ||
3028 | |||
3029 | // generate a short file name | ||
3030 | if (null == destinationShortName && (null != destinationName && !this.core.IsValidShortFilename(destinationName, false))) | ||
3031 | { | ||
3032 | destinationShortName = this.core.CreateShortName(destinationName, true, false, node.Name.LocalName, componentId); | ||
3033 | } | ||
3034 | |||
3035 | if (null == id) | ||
3036 | { | ||
3037 | id = this.core.CreateIdentifier("cf", sourceFolder, sourceDirectory, sourceProperty, destinationDirectory, destinationProperty, destinationName); | ||
3038 | } | ||
3039 | |||
3040 | this.core.ParseForExtensionElements(node); | ||
3041 | |||
3042 | if (null == fileId) | ||
3043 | { | ||
3044 | // DestinationDirectory or DestinationProperty must be specified | ||
3045 | if (null == destinationDirectory && null == destinationProperty) | ||
3046 | { | ||
3047 | this.core.OnMessage(WixErrors.ExpectedAttributesWithoutOtherAttribute(sourceLineNumbers, node.Name.LocalName, "DestinationDirectory", "DestinationProperty", "FileId")); | ||
3048 | } | ||
3049 | |||
3050 | if (!this.core.EncounteredError) | ||
3051 | { | ||
3052 | Row row = this.core.CreateRow(sourceLineNumbers, "MoveFile", id); | ||
3053 | row[1] = componentId; | ||
3054 | row[2] = sourceName; | ||
3055 | row[3] = String.IsNullOrEmpty(destinationShortName) && String.IsNullOrEmpty(destinationName) ? null : GetMsiFilenameValue(destinationShortName, destinationName); | ||
3056 | if (null != sourceDirectory) | ||
3057 | { | ||
3058 | row[4] = sourceDirectory; | ||
3059 | } | ||
3060 | else if (null != sourceProperty) | ||
3061 | { | ||
3062 | row[4] = sourceProperty; | ||
3063 | } | ||
3064 | else | ||
3065 | { | ||
3066 | row[4] = sourceFolder; | ||
3067 | } | ||
3068 | |||
3069 | if (null != destinationDirectory) | ||
3070 | { | ||
3071 | row[5] = destinationDirectory; | ||
3072 | } | ||
3073 | else | ||
3074 | { | ||
3075 | row[5] = destinationProperty; | ||
3076 | } | ||
3077 | row[6] = delete ? 1 : 0; | ||
3078 | } | ||
3079 | } | ||
3080 | else // copy the file | ||
3081 | { | ||
3082 | if (null != sourceDirectory) | ||
3083 | { | ||
3084 | this.core.OnMessage(WixErrors.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "SourceDirectory", "FileId")); | ||
3085 | } | ||
3086 | |||
3087 | if (null != sourceFolder) | ||
3088 | { | ||
3089 | this.core.OnMessage(WixErrors.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "SourceFolder", "FileId")); | ||
3090 | } | ||
3091 | |||
3092 | if (null != sourceName) | ||
3093 | { | ||
3094 | this.core.OnMessage(WixErrors.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "SourceName", "FileId")); | ||
3095 | } | ||
3096 | |||
3097 | if (null != sourceProperty) | ||
3098 | { | ||
3099 | this.core.OnMessage(WixErrors.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "SourceProperty", "FileId")); | ||
3100 | } | ||
3101 | |||
3102 | if (delete) | ||
3103 | { | ||
3104 | this.core.OnMessage(WixErrors.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Delete", "FileId")); | ||
3105 | } | ||
3106 | |||
3107 | if (null == destinationName && null == destinationDirectory && null == destinationProperty) | ||
3108 | { | ||
3109 | this.core.OnMessage(WixWarnings.CopyFileFileIdUseless(sourceLineNumbers)); | ||
3110 | } | ||
3111 | |||
3112 | if (!this.core.EncounteredError) | ||
3113 | { | ||
3114 | Row row = this.core.CreateRow(sourceLineNumbers, "DuplicateFile", id); | ||
3115 | row[1] = componentId; | ||
3116 | row[2] = fileId; | ||
3117 | row[3] = String.IsNullOrEmpty(destinationShortName) && String.IsNullOrEmpty(destinationName) ? null : GetMsiFilenameValue(destinationShortName, destinationName); | ||
3118 | if (null != destinationDirectory) | ||
3119 | { | ||
3120 | row[4] = destinationDirectory; | ||
3121 | } | ||
3122 | else | ||
3123 | { | ||
3124 | row[4] = destinationProperty; | ||
3125 | } | ||
3126 | } | ||
3127 | } | ||
3128 | } | ||
3129 | |||
3130 | /// <summary> | ||
3131 | /// Parses a CustomAction element. | ||
3132 | /// </summary> | ||
3133 | /// <param name="node">Element to parse.</param> | ||
3134 | private void ParseCustomActionElement(XElement node) | ||
3135 | { | ||
3136 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
3137 | Identifier id = null; | ||
3138 | int bits = 0; | ||
3139 | int extendedBits = 0; | ||
3140 | bool inlineScript = false; | ||
3141 | string innerText = null; | ||
3142 | string source = null; | ||
3143 | int sourceBits = 0; | ||
3144 | YesNoType suppressModularization = YesNoType.NotSet; | ||
3145 | string target = null; | ||
3146 | int targetBits = 0; | ||
3147 | bool explicitWin64 = false; | ||
3148 | |||
3149 | foreach (XAttribute attrib in node.Attributes()) | ||
3150 | { | ||
3151 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
3152 | { | ||
3153 | switch (attrib.Name.LocalName) | ||
3154 | { | ||
3155 | case "Id": | ||
3156 | id = this.core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
3157 | break; | ||
3158 | case "BinaryKey": | ||
3159 | if (null != source) | ||
3160 | { | ||
3161 | this.core.OnMessage(WixErrors.CustomActionMultipleSources(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, "BinaryKey", "Directory", "FileKey", "Property", "Script")); | ||
3162 | } | ||
3163 | source = this.core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
3164 | sourceBits = MsiInterop.MsidbCustomActionTypeBinaryData; | ||
3165 | this.core.CreateSimpleReference(sourceLineNumbers, "Binary", source); // add a reference to the appropriate Binary | ||
3166 | break; | ||
3167 | case "Directory": | ||
3168 | if (null != source) | ||
3169 | { | ||
3170 | this.core.OnMessage(WixErrors.CustomActionMultipleSources(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, "BinaryKey", "Directory", "FileKey", "Property", "Script")); | ||
3171 | } | ||
3172 | source = this.core.CreateDirectoryReferenceFromInlineSyntax(sourceLineNumbers, attrib, null); | ||
3173 | sourceBits = MsiInterop.MsidbCustomActionTypeDirectory; | ||
3174 | break; | ||
3175 | case "DllEntry": | ||
3176 | if (null != target) | ||
3177 | { | ||
3178 | this.core.OnMessage(WixErrors.CustomActionMultipleTargets(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, "DllEntry", "Error", "ExeCommand", "JScriptCall", "Script", "Value", "VBScriptCall")); | ||
3179 | } | ||
3180 | target = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
3181 | targetBits = MsiInterop.MsidbCustomActionTypeDll; | ||
3182 | break; | ||
3183 | case "Error": | ||
3184 | if (null != target) | ||
3185 | { | ||
3186 | this.core.OnMessage(WixErrors.CustomActionMultipleTargets(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, "DllEntry", "Error", "ExeCommand", "JScriptCall", "Script", "Value", "VBScriptCall")); | ||
3187 | } | ||
3188 | target = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
3189 | targetBits = MsiInterop.MsidbCustomActionTypeTextData | MsiInterop.MsidbCustomActionTypeSourceFile; | ||
3190 | |||
3191 | bool errorReference = true; | ||
3192 | |||
3193 | try | ||
3194 | { | ||
3195 | // The target can be either a formatted error string or a literal | ||
3196 | // error number. Try to convert to error number to determine whether | ||
3197 | // to add a reference. No need to look at the value. | ||
3198 | Convert.ToInt32(target, CultureInfo.InvariantCulture.NumberFormat); | ||
3199 | } | ||
3200 | catch (FormatException) | ||
3201 | { | ||
3202 | errorReference = false; | ||
3203 | } | ||
3204 | catch (OverflowException) | ||
3205 | { | ||
3206 | errorReference = false; | ||
3207 | } | ||
3208 | |||
3209 | if (errorReference) | ||
3210 | { | ||
3211 | this.core.CreateSimpleReference(sourceLineNumbers, "Error", target); | ||
3212 | } | ||
3213 | break; | ||
3214 | case "ExeCommand": | ||
3215 | if (null != target) | ||
3216 | { | ||
3217 | this.core.OnMessage(WixErrors.CustomActionMultipleTargets(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, "DllEntry", "Error", "ExeCommand", "JScriptCall", "Script", "Value", "VBScriptCall")); | ||
3218 | } | ||
3219 | target = this.core.GetAttributeValue(sourceLineNumbers, attrib, EmptyRule.CanBeEmpty); // one of the few cases where an empty string value is valid | ||
3220 | targetBits = MsiInterop.MsidbCustomActionTypeExe; | ||
3221 | break; | ||
3222 | case "Execute": | ||
3223 | string execute = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
3224 | if (0 < execute.Length) | ||
3225 | { | ||
3226 | Wix.CustomAction.ExecuteType executeType = Wix.CustomAction.ParseExecuteType(execute); | ||
3227 | switch (executeType) | ||
3228 | { | ||
3229 | case Wix.CustomAction.ExecuteType.commit: | ||
3230 | bits |= MsiInterop.MsidbCustomActionTypeInScript | MsiInterop.MsidbCustomActionTypeCommit; | ||
3231 | break; | ||
3232 | case Wix.CustomAction.ExecuteType.deferred: | ||
3233 | bits |= MsiInterop.MsidbCustomActionTypeInScript; | ||
3234 | break; | ||
3235 | case Wix.CustomAction.ExecuteType.firstSequence: | ||
3236 | bits |= MsiInterop.MsidbCustomActionTypeFirstSequence; | ||
3237 | break; | ||
3238 | case Wix.CustomAction.ExecuteType.immediate: | ||
3239 | break; | ||
3240 | case Wix.CustomAction.ExecuteType.oncePerProcess: | ||
3241 | bits |= MsiInterop.MsidbCustomActionTypeOncePerProcess; | ||
3242 | break; | ||
3243 | case Wix.CustomAction.ExecuteType.rollback: | ||
3244 | bits |= MsiInterop.MsidbCustomActionTypeInScript | MsiInterop.MsidbCustomActionTypeRollback; | ||
3245 | break; | ||
3246 | case Wix.CustomAction.ExecuteType.secondSequence: | ||
3247 | bits |= MsiInterop.MsidbCustomActionTypeClientRepeat; | ||
3248 | break; | ||
3249 | default: | ||
3250 | this.core.OnMessage(WixErrors.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, execute, "commit", "deferred", "firstSequence", "immediate", "oncePerProcess", "rollback", "secondSequence")); | ||
3251 | break; | ||
3252 | } | ||
3253 | } | ||
3254 | break; | ||
3255 | case "FileKey": | ||
3256 | if (null != source) | ||
3257 | { | ||
3258 | this.core.OnMessage(WixErrors.CustomActionMultipleSources(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, "BinaryKey", "Directory", "FileKey", "Property", "Script")); | ||
3259 | } | ||
3260 | source = this.core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
3261 | sourceBits = MsiInterop.MsidbCustomActionTypeSourceFile; | ||
3262 | this.core.CreateSimpleReference(sourceLineNumbers, "File", source); // add a reference to the appropriate File | ||
3263 | break; | ||
3264 | case "HideTarget": | ||
3265 | if (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
3266 | { | ||
3267 | bits |= MsiInterop.MsidbCustomActionTypeHideTarget; | ||
3268 | } | ||
3269 | break; | ||
3270 | case "Impersonate": | ||
3271 | if (YesNoType.No == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
3272 | { | ||
3273 | bits |= MsiInterop.MsidbCustomActionTypeNoImpersonate; | ||
3274 | } | ||
3275 | break; | ||
3276 | case "JScriptCall": | ||
3277 | if (null != target) | ||
3278 | { | ||
3279 | this.core.OnMessage(WixErrors.CustomActionMultipleTargets(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, "DllEntry", "Error", "ExeCommand", "JScriptCall", "Script", "Value", "VBScriptCall")); | ||
3280 | } | ||
3281 | target = this.core.GetAttributeValue(sourceLineNumbers, attrib, EmptyRule.CanBeEmpty); // one of the few cases where an empty string value is valid | ||
3282 | targetBits = MsiInterop.MsidbCustomActionTypeJScript; | ||
3283 | break; | ||
3284 | case "PatchUninstall": | ||
3285 | if (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
3286 | { | ||
3287 | extendedBits |= MsiInterop.MsidbCustomActionTypePatchUninstall; | ||
3288 | } | ||
3289 | break; | ||
3290 | case "Property": | ||
3291 | if (null != source) | ||
3292 | { | ||
3293 | this.core.OnMessage(WixErrors.CustomActionMultipleSources(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, "BinaryKey", "Directory", "FileKey", "Property", "Script")); | ||
3294 | } | ||
3295 | source = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
3296 | sourceBits = MsiInterop.MsidbCustomActionTypeProperty; | ||
3297 | break; | ||
3298 | case "Return": | ||
3299 | string returnValue = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
3300 | if (0 < returnValue.Length) | ||
3301 | { | ||
3302 | Wix.CustomAction.ReturnType returnType = Wix.CustomAction.ParseReturnType(returnValue); | ||
3303 | switch (returnType) | ||
3304 | { | ||
3305 | case Wix.CustomAction.ReturnType.asyncNoWait: | ||
3306 | bits |= MsiInterop.MsidbCustomActionTypeAsync | MsiInterop.MsidbCustomActionTypeContinue; | ||
3307 | break; | ||
3308 | case Wix.CustomAction.ReturnType.asyncWait: | ||
3309 | bits |= MsiInterop.MsidbCustomActionTypeAsync; | ||
3310 | break; | ||
3311 | case Wix.CustomAction.ReturnType.check: | ||
3312 | break; | ||
3313 | case Wix.CustomAction.ReturnType.ignore: | ||
3314 | bits |= MsiInterop.MsidbCustomActionTypeContinue; | ||
3315 | break; | ||
3316 | default: | ||
3317 | this.core.OnMessage(WixErrors.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, returnValue, "asyncNoWait", "asyncWait", "check", "ignore")); | ||
3318 | break; | ||
3319 | } | ||
3320 | } | ||
3321 | break; | ||
3322 | case "Script": | ||
3323 | if (null != source) | ||
3324 | { | ||
3325 | this.core.OnMessage(WixErrors.CustomActionMultipleSources(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, "BinaryKey", "Directory", "FileKey", "Property", "Script")); | ||
3326 | } | ||
3327 | |||
3328 | if (null != target) | ||
3329 | { | ||
3330 | this.core.OnMessage(WixErrors.CustomActionMultipleTargets(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, "DllEntry", "Error", "ExeCommand", "JScriptCall", "Script", "Value", "VBScriptCall")); | ||
3331 | } | ||
3332 | |||
3333 | // set the source and target to empty string for error messages when the user sets multiple sources or targets | ||
3334 | source = string.Empty; | ||
3335 | target = string.Empty; | ||
3336 | |||
3337 | inlineScript = true; | ||
3338 | |||
3339 | string script = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
3340 | if (0 < script.Length) | ||
3341 | { | ||
3342 | Wix.CustomAction.ScriptType scriptType = Wix.CustomAction.ParseScriptType(script); | ||
3343 | switch (scriptType) | ||
3344 | { | ||
3345 | case Wix.CustomAction.ScriptType.jscript: | ||
3346 | sourceBits = MsiInterop.MsidbCustomActionTypeDirectory; | ||
3347 | targetBits = MsiInterop.MsidbCustomActionTypeJScript; | ||
3348 | break; | ||
3349 | case Wix.CustomAction.ScriptType.vbscript: | ||
3350 | sourceBits = MsiInterop.MsidbCustomActionTypeDirectory; | ||
3351 | targetBits = MsiInterop.MsidbCustomActionTypeVBScript; | ||
3352 | break; | ||
3353 | default: | ||
3354 | this.core.OnMessage(WixErrors.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, script, "jscript", "vbscript")); | ||
3355 | break; | ||
3356 | } | ||
3357 | } | ||
3358 | break; | ||
3359 | case "SuppressModularization": | ||
3360 | suppressModularization = this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
3361 | break; | ||
3362 | case "TerminalServerAware": | ||
3363 | if (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
3364 | { | ||
3365 | bits |= MsiInterop.MsidbCustomActionTypeTSAware; | ||
3366 | } | ||
3367 | break; | ||
3368 | case "Value": | ||
3369 | if (null != target) | ||
3370 | { | ||
3371 | this.core.OnMessage(WixErrors.CustomActionMultipleTargets(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, "DllEntry", "Error", "ExeCommand", "JScriptCall", "Script", "Value", "VBScriptCall")); | ||
3372 | } | ||
3373 | target = this.core.GetAttributeValue(sourceLineNumbers, attrib, EmptyRule.CanBeEmpty); // one of the few cases where an empty string value is valid | ||
3374 | targetBits = MsiInterop.MsidbCustomActionTypeTextData; | ||
3375 | break; | ||
3376 | case "VBScriptCall": | ||
3377 | if (null != target) | ||
3378 | { | ||
3379 | this.core.OnMessage(WixErrors.CustomActionMultipleTargets(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, "DllEntry", "Error", "ExeCommand", "JScriptCall", "Script", "Value", "VBScriptCall")); | ||
3380 | } | ||
3381 | target = this.core.GetAttributeValue(sourceLineNumbers, attrib, EmptyRule.CanBeEmpty); // one of the few cases where an empty string value is valid | ||
3382 | targetBits = MsiInterop.MsidbCustomActionTypeVBScript; | ||
3383 | break; | ||
3384 | case "Win64": | ||
3385 | explicitWin64 = true; | ||
3386 | if (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
3387 | { | ||
3388 | bits |= MsiInterop.MsidbCustomActionType64BitScript; | ||
3389 | } | ||
3390 | break; | ||
3391 | default: | ||
3392 | this.core.UnexpectedAttribute(node, attrib); | ||
3393 | break; | ||
3394 | } | ||
3395 | } | ||
3396 | else | ||
3397 | { | ||
3398 | this.core.ParseExtensionAttribute(node, attrib); | ||
3399 | } | ||
3400 | } | ||
3401 | |||
3402 | if (null == id) | ||
3403 | { | ||
3404 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
3405 | id = Identifier.Invalid; | ||
3406 | } | ||
3407 | |||
3408 | if (!explicitWin64 && (MsiInterop.MsidbCustomActionTypeVBScript == targetBits || MsiInterop.MsidbCustomActionTypeJScript == targetBits) && (Platform.IA64 == this.CurrentPlatform || Platform.X64 == this.CurrentPlatform)) | ||
3409 | { | ||
3410 | bits |= MsiInterop.MsidbCustomActionType64BitScript; | ||
3411 | } | ||
3412 | |||
3413 | // get the inner text if any exists | ||
3414 | innerText = this.core.GetTrimmedInnerText(node); | ||
3415 | |||
3416 | // if we have an in-lined Script CustomAction ensure no source or target attributes were provided | ||
3417 | if (inlineScript) | ||
3418 | { | ||
3419 | target = innerText; | ||
3420 | } | ||
3421 | else if (MsiInterop.MsidbCustomActionTypeVBScript == targetBits) // non-inline vbscript | ||
3422 | { | ||
3423 | if (null == source) | ||
3424 | { | ||
3425 | this.core.OnMessage(WixErrors.IllegalAttributeWithoutOtherAttributes(sourceLineNumbers, node.Name.LocalName, "VBScriptCall", "BinaryKey", "FileKey", "Property")); | ||
3426 | } | ||
3427 | else if (MsiInterop.MsidbCustomActionTypeDirectory == sourceBits) | ||
3428 | { | ||
3429 | this.core.OnMessage(WixErrors.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "VBScriptCall", "Directory")); | ||
3430 | } | ||
3431 | } | ||
3432 | else if (MsiInterop.MsidbCustomActionTypeJScript == targetBits) // non-inline jscript | ||
3433 | { | ||
3434 | if (null == source) | ||
3435 | { | ||
3436 | this.core.OnMessage(WixErrors.IllegalAttributeWithoutOtherAttributes(sourceLineNumbers, node.Name.LocalName, "JScriptCall", "BinaryKey", "FileKey", "Property")); | ||
3437 | } | ||
3438 | else if (MsiInterop.MsidbCustomActionTypeDirectory == sourceBits) | ||
3439 | { | ||
3440 | this.core.OnMessage(WixErrors.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "JScriptCall", "Directory")); | ||
3441 | } | ||
3442 | } | ||
3443 | else if (MsiInterop.MsidbCustomActionTypeExe == targetBits) // exe-command | ||
3444 | { | ||
3445 | if (null == source) | ||
3446 | { | ||
3447 | this.core.OnMessage(WixErrors.IllegalAttributeWithoutOtherAttributes(sourceLineNumbers, node.Name.LocalName, "ExeCommand", "BinaryKey", "Directory", "FileKey", "Property")); | ||
3448 | } | ||
3449 | } | ||
3450 | else if (MsiInterop.MsidbCustomActionTypeTextData == (bits | sourceBits | targetBits)) | ||
3451 | { | ||
3452 | this.core.OnMessage(WixErrors.IllegalAttributeWithoutOtherAttributes(sourceLineNumbers, node.Name.LocalName, "Value", "Directory", "Property")); | ||
3453 | } | ||
3454 | else if (!String.IsNullOrEmpty(innerText)) // inner text cannot be specified with non-script CAs | ||
3455 | { | ||
3456 | this.core.OnMessage(WixErrors.CustomActionIllegalInnerText(sourceLineNumbers, node.Name.LocalName, innerText, "Script")); | ||
3457 | } | ||
3458 | |||
3459 | if (MsiInterop.MsidbCustomActionType64BitScript == (bits & MsiInterop.MsidbCustomActionType64BitScript) && MsiInterop.MsidbCustomActionTypeVBScript != targetBits && MsiInterop.MsidbCustomActionTypeJScript != targetBits) | ||
3460 | { | ||
3461 | this.core.OnMessage(WixErrors.IllegalAttributeWithoutOtherAttributes(sourceLineNumbers, node.Name.LocalName, "Win64", "Script", "VBScriptCall", "JScriptCall")); | ||
3462 | } | ||
3463 | |||
3464 | if ((MsiInterop.MsidbCustomActionTypeAsync | MsiInterop.MsidbCustomActionTypeContinue) == (bits & (MsiInterop.MsidbCustomActionTypeAsync | MsiInterop.MsidbCustomActionTypeContinue)) && MsiInterop.MsidbCustomActionTypeExe != targetBits) | ||
3465 | { | ||
3466 | this.core.OnMessage(WixErrors.IllegalAttributeValueWithoutOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Return", "asyncNoWait", "ExeCommand")); | ||
3467 | } | ||
3468 | |||
3469 | if (MsiInterop.MsidbCustomActionTypeTSAware == (bits & MsiInterop.MsidbCustomActionTypeTSAware)) | ||
3470 | { | ||
3471 | // TS-aware CAs are valid only when deferred so require the in-script Type bit... | ||
3472 | if (0 == (bits & MsiInterop.MsidbCustomActionTypeInScript)) | ||
3473 | { | ||
3474 | this.core.OnMessage(WixErrors.IllegalTerminalServerCustomActionAttributes(sourceLineNumbers)); | ||
3475 | } | ||
3476 | } | ||
3477 | |||
3478 | // MSI doesn't support in-script property setting, so disallow it | ||
3479 | if (MsiInterop.MsidbCustomActionTypeProperty == sourceBits && | ||
3480 | MsiInterop.MsidbCustomActionTypeTextData == targetBits && | ||
3481 | 0 != (bits & MsiInterop.MsidbCustomActionTypeInScript)) | ||
3482 | { | ||
3483 | this.core.OnMessage(WixErrors.IllegalPropertyCustomActionAttributes(sourceLineNumbers)); | ||
3484 | } | ||
3485 | |||
3486 | if (0 == targetBits) | ||
3487 | { | ||
3488 | this.core.OnMessage(WixErrors.ExpectedAttributes(sourceLineNumbers, node.Name.LocalName, "DllEntry", "Error", "ExeCommand", "JScriptCall", "Script", "Value", "VBScriptCall")); | ||
3489 | } | ||
3490 | |||
3491 | this.core.ParseForExtensionElements(node); | ||
3492 | |||
3493 | if (!this.core.EncounteredError) | ||
3494 | { | ||
3495 | Row row = this.core.CreateRow(sourceLineNumbers, "CustomAction", id); | ||
3496 | row[1] = bits | sourceBits | targetBits; | ||
3497 | row[2] = source; | ||
3498 | row[3] = target; | ||
3499 | if (0 != extendedBits) | ||
3500 | { | ||
3501 | row[4] = extendedBits; | ||
3502 | } | ||
3503 | |||
3504 | if (YesNoType.Yes == suppressModularization) | ||
3505 | { | ||
3506 | this.core.CreateRow(sourceLineNumbers, "WixSuppressModularization", id); | ||
3507 | } | ||
3508 | |||
3509 | // For deferred CAs that specify HideTarget we should also hide the CA data property for the action. | ||
3510 | if (MsiInterop.MsidbCustomActionTypeHideTarget == (bits & MsiInterop.MsidbCustomActionTypeHideTarget) && | ||
3511 | MsiInterop.MsidbCustomActionTypeInScript == (bits & MsiInterop.MsidbCustomActionTypeInScript)) | ||
3512 | { | ||
3513 | this.AddWixPropertyRow(sourceLineNumbers, id, false, false, true); | ||
3514 | } | ||
3515 | } | ||
3516 | } | ||
3517 | |||
3518 | /// <summary> | ||
3519 | /// Parses a simple reference element. | ||
3520 | /// </summary> | ||
3521 | /// <param name="node">Element to parse.</param> | ||
3522 | /// <param name="table">Table which contains the target of the simple reference.</param> | ||
3523 | /// <returns>Id of the referenced element.</returns> | ||
3524 | private string ParseSimpleRefElement(XElement node, string table) | ||
3525 | { | ||
3526 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
3527 | string id = null; | ||
3528 | |||
3529 | foreach (XAttribute attrib in node.Attributes()) | ||
3530 | { | ||
3531 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
3532 | { | ||
3533 | switch (attrib.Name.LocalName) | ||
3534 | { | ||
3535 | case "Id": | ||
3536 | id = this.core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
3537 | this.core.CreateSimpleReference(sourceLineNumbers, table, id); | ||
3538 | break; | ||
3539 | default: | ||
3540 | this.core.UnexpectedAttribute(node, attrib); | ||
3541 | break; | ||
3542 | } | ||
3543 | } | ||
3544 | else | ||
3545 | { | ||
3546 | this.core.ParseExtensionAttribute(node, attrib); | ||
3547 | } | ||
3548 | } | ||
3549 | |||
3550 | if (null == id) | ||
3551 | { | ||
3552 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
3553 | } | ||
3554 | |||
3555 | this.core.ParseForExtensionElements(node); | ||
3556 | |||
3557 | return id; | ||
3558 | } | ||
3559 | |||
3560 | /// <summary> | ||
3561 | /// Parses a PatchFamilyRef element. | ||
3562 | /// </summary> | ||
3563 | /// <param name="node">Element to parse.</param> | ||
3564 | /// <param name="parentType">The parent type.</param> | ||
3565 | /// <param name="parentId">The ID of the parent.</param> | ||
3566 | /// <returns>Id of the referenced element.</returns> | ||
3567 | private void ParsePatchFamilyRefElement(XElement node, ComplexReferenceParentType parentType, string parentId) | ||
3568 | { | ||
3569 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
3570 | string[] primaryKeys = new string[2]; | ||
3571 | |||
3572 | foreach (XAttribute attrib in node.Attributes()) | ||
3573 | { | ||
3574 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
3575 | { | ||
3576 | switch (attrib.Name.LocalName) | ||
3577 | { | ||
3578 | case "Id": | ||
3579 | primaryKeys[0] = this.core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
3580 | break; | ||
3581 | case "ProductCode": | ||
3582 | primaryKeys[1] = this.core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
3583 | break; | ||
3584 | default: | ||
3585 | this.core.UnexpectedAttribute(node, attrib); | ||
3586 | break; | ||
3587 | } | ||
3588 | } | ||
3589 | else | ||
3590 | { | ||
3591 | this.core.ParseExtensionAttribute(node, attrib); | ||
3592 | } | ||
3593 | } | ||
3594 | |||
3595 | if (null == primaryKeys[0]) | ||
3596 | { | ||
3597 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
3598 | } | ||
3599 | |||
3600 | this.core.CreateSimpleReference(sourceLineNumbers, "MsiPatchSequence", primaryKeys); | ||
3601 | |||
3602 | this.core.ParseForExtensionElements(node); | ||
3603 | |||
3604 | if (!this.core.EncounteredError) | ||
3605 | { | ||
3606 | this.core.CreateComplexReference(sourceLineNumbers, parentType, parentId, null, ComplexReferenceChildType.PatchFamily, primaryKeys[0], true); | ||
3607 | } | ||
3608 | } | ||
3609 | |||
3610 | /// <summary> | ||
3611 | /// Parses a PatchFamilyGroup element. | ||
3612 | /// </summary> | ||
3613 | /// <param name="node">Element to parse.</param> | ||
3614 | [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1800:DoNotCastUnnecessarily")] | ||
3615 | private void ParsePatchFamilyGroupElement(XElement node, ComplexReferenceParentType parentType, string parentId) | ||
3616 | { | ||
3617 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
3618 | Identifier id = null; | ||
3619 | |||
3620 | foreach (XAttribute attrib in node.Attributes()) | ||
3621 | { | ||
3622 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
3623 | { | ||
3624 | switch (attrib.Name.LocalName) | ||
3625 | { | ||
3626 | case "Id": | ||
3627 | id = this.core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
3628 | break; | ||
3629 | default: | ||
3630 | this.core.UnexpectedAttribute(node, attrib); | ||
3631 | break; | ||
3632 | } | ||
3633 | } | ||
3634 | else | ||
3635 | { | ||
3636 | this.core.ParseExtensionAttribute(node, attrib); | ||
3637 | } | ||
3638 | } | ||
3639 | |||
3640 | if (null == id) | ||
3641 | { | ||
3642 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
3643 | id = Identifier.Invalid; | ||
3644 | } | ||
3645 | |||
3646 | foreach (XElement child in node.Elements()) | ||
3647 | { | ||
3648 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
3649 | { | ||
3650 | switch (child.Name.LocalName) | ||
3651 | { | ||
3652 | case "PatchFamily": | ||
3653 | this.ParsePatchFamilyElement(child, ComplexReferenceParentType.PatchFamilyGroup, id.Id); | ||
3654 | break; | ||
3655 | case "PatchFamilyRef": | ||
3656 | this.ParsePatchFamilyRefElement(child, ComplexReferenceParentType.PatchFamilyGroup, id.Id); | ||
3657 | break; | ||
3658 | case "PatchFamilyGroupRef": | ||
3659 | this.ParsePatchFamilyGroupRefElement(child, ComplexReferenceParentType.PatchFamilyGroup, id.Id); | ||
3660 | break; | ||
3661 | default: | ||
3662 | this.core.UnexpectedElement(node, child); | ||
3663 | break; | ||
3664 | } | ||
3665 | } | ||
3666 | else | ||
3667 | { | ||
3668 | this.core.ParseExtensionElement(node, child); | ||
3669 | } | ||
3670 | } | ||
3671 | |||
3672 | if (!this.core.EncounteredError) | ||
3673 | { | ||
3674 | Row row = this.core.CreateRow(sourceLineNumbers, "WixPatchFamilyGroup", id); | ||
3675 | |||
3676 | //Add this PatchFamilyGroup and its parent in WixGroup. | ||
3677 | this.core.CreateWixGroupRow(sourceLineNumbers, parentType, parentId, ComplexReferenceChildType.PatchFamilyGroup, id.Id); | ||
3678 | } | ||
3679 | } | ||
3680 | |||
3681 | /// <summary> | ||
3682 | /// Parses a PatchFamilyGroup reference element. | ||
3683 | /// </summary> | ||
3684 | /// <param name="node">Element to parse.</param> | ||
3685 | /// <param name="parentType">The type of parent.</param> | ||
3686 | /// <param name="parentId">Identifier of parent element.</param> | ||
3687 | private void ParsePatchFamilyGroupRefElement(XElement node, ComplexReferenceParentType parentType, string parentId) | ||
3688 | { | ||
3689 | Debug.Assert(ComplexReferenceParentType.PatchFamilyGroup == parentType || ComplexReferenceParentType.Patch == parentType); | ||
3690 | |||
3691 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
3692 | string id = null; | ||
3693 | |||
3694 | foreach (XAttribute attrib in node.Attributes()) | ||
3695 | { | ||
3696 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
3697 | { | ||
3698 | switch (attrib.Name.LocalName) | ||
3699 | { | ||
3700 | case "Id": | ||
3701 | id = this.core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
3702 | this.core.CreateSimpleReference(sourceLineNumbers, "WixPatchFamilyGroup", id); | ||
3703 | break; | ||
3704 | default: | ||
3705 | this.core.UnexpectedAttribute(node, attrib); | ||
3706 | break; | ||
3707 | } | ||
3708 | } | ||
3709 | else | ||
3710 | { | ||
3711 | this.core.ParseExtensionAttribute(node, attrib); | ||
3712 | } | ||
3713 | } | ||
3714 | |||
3715 | if (null == id) | ||
3716 | { | ||
3717 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
3718 | } | ||
3719 | |||
3720 | this.core.ParseForExtensionElements(node); | ||
3721 | |||
3722 | if (!this.core.EncounteredError) | ||
3723 | { | ||
3724 | this.core.CreateComplexReference(sourceLineNumbers, parentType, parentId, null, ComplexReferenceChildType.PatchFamilyGroup, id, true); | ||
3725 | } | ||
3726 | } | ||
3727 | |||
3728 | /// <summary> | ||
3729 | /// Parses an ensure table element. | ||
3730 | /// </summary> | ||
3731 | /// <param name="node">Element to parse.</param> | ||
3732 | private void ParseEnsureTableElement(XElement node) | ||
3733 | { | ||
3734 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
3735 | string id = null; | ||
3736 | |||
3737 | foreach (XAttribute attrib in node.Attributes()) | ||
3738 | { | ||
3739 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
3740 | { | ||
3741 | switch (attrib.Name.LocalName) | ||
3742 | { | ||
3743 | case "Id": | ||
3744 | id = this.core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
3745 | break; | ||
3746 | default: | ||
3747 | this.core.UnexpectedAttribute(node, attrib); | ||
3748 | break; | ||
3749 | } | ||
3750 | } | ||
3751 | else | ||
3752 | { | ||
3753 | this.core.ParseExtensionAttribute(node, attrib); | ||
3754 | } | ||
3755 | } | ||
3756 | |||
3757 | if (null == id) | ||
3758 | { | ||
3759 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
3760 | } | ||
3761 | else if (31 < id.Length) | ||
3762 | { | ||
3763 | this.core.OnMessage(WixErrors.TableNameTooLong(sourceLineNumbers, node.Name.LocalName, "Id", id)); | ||
3764 | } | ||
3765 | |||
3766 | this.core.ParseForExtensionElements(node); | ||
3767 | |||
3768 | this.core.EnsureTable(sourceLineNumbers, id); | ||
3769 | } | ||
3770 | |||
3771 | /// <summary> | ||
3772 | /// Parses a custom table element. | ||
3773 | /// </summary> | ||
3774 | /// <param name="node">Element to parse.</param> | ||
3775 | /// <remarks>not cleaned</remarks> | ||
3776 | [SuppressMessage("Microsoft.Globalization", "CA1308:NormalizeStringsToUppercase", Justification = "Changing the way this string normalizes would result " + | ||
3777 | "in a change to the way the WixCustomTable table is generated. Furthermore, there is no security hole here, as the strings won't need to " + | ||
3778 | "make a round trip")] | ||
3779 | private void ParseCustomTableElement(XElement node) | ||
3780 | { | ||
3781 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
3782 | string tableId = null; | ||
3783 | |||
3784 | string categories = null; | ||
3785 | int columnCount = 0; | ||
3786 | string columnNames = null; | ||
3787 | string columnTypes = null; | ||
3788 | string descriptions = null; | ||
3789 | string keyColumns = null; | ||
3790 | string keyTables = null; | ||
3791 | string maxValues = null; | ||
3792 | string minValues = null; | ||
3793 | string modularizations = null; | ||
3794 | string primaryKeys = null; | ||
3795 | string sets = null; | ||
3796 | bool bootstrapperApplicationData = false; | ||
3797 | |||
3798 | foreach (XAttribute attrib in node.Attributes()) | ||
3799 | { | ||
3800 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
3801 | { | ||
3802 | switch (attrib.Name.LocalName) | ||
3803 | { | ||
3804 | case "Id": | ||
3805 | tableId = this.core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
3806 | break; | ||
3807 | case "BootstrapperApplicationData": | ||
3808 | bootstrapperApplicationData = YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
3809 | break; | ||
3810 | default: | ||
3811 | this.core.UnexpectedAttribute(node, attrib); | ||
3812 | break; | ||
3813 | } | ||
3814 | } | ||
3815 | else | ||
3816 | { | ||
3817 | this.core.ParseExtensionAttribute(node, attrib); | ||
3818 | } | ||
3819 | } | ||
3820 | |||
3821 | if (null == tableId) | ||
3822 | { | ||
3823 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
3824 | } | ||
3825 | else if (31 < tableId.Length) | ||
3826 | { | ||
3827 | this.core.OnMessage(WixErrors.CustomTableNameTooLong(sourceLineNumbers, node.Name.LocalName, "Id", tableId)); | ||
3828 | } | ||
3829 | |||
3830 | foreach (XElement child in node.Elements()) | ||
3831 | { | ||
3832 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
3833 | { | ||
3834 | SourceLineNumber childSourceLineNumbers = Preprocessor.GetSourceLineNumbers(child); | ||
3835 | switch (child.Name.LocalName) | ||
3836 | { | ||
3837 | case "Column": | ||
3838 | ++columnCount; | ||
3839 | |||
3840 | string category = String.Empty; | ||
3841 | string columnName = null; | ||
3842 | string columnType = null; | ||
3843 | string description = String.Empty; | ||
3844 | int keyColumn = CompilerConstants.IntegerNotSet; | ||
3845 | string keyTable = String.Empty; | ||
3846 | bool localizable = false; | ||
3847 | long maxValue = CompilerConstants.LongNotSet; | ||
3848 | long minValue = CompilerConstants.LongNotSet; | ||
3849 | string modularization = "None"; | ||
3850 | bool nullable = false; | ||
3851 | bool primaryKey = false; | ||
3852 | string setValues = String.Empty; | ||
3853 | string typeName = null; | ||
3854 | int width = 0; | ||
3855 | |||
3856 | foreach (XAttribute childAttrib in child.Attributes()) | ||
3857 | { | ||
3858 | switch (childAttrib.Name.LocalName) | ||
3859 | { | ||
3860 | case "Id": | ||
3861 | columnName = this.core.GetAttributeIdentifierValue(childSourceLineNumbers, childAttrib); | ||
3862 | break; | ||
3863 | case "Category": | ||
3864 | category = this.core.GetAttributeValue(childSourceLineNumbers, childAttrib); | ||
3865 | break; | ||
3866 | case "Description": | ||
3867 | description = this.core.GetAttributeValue(childSourceLineNumbers, childAttrib); | ||
3868 | break; | ||
3869 | case "KeyColumn": | ||
3870 | keyColumn = this.core.GetAttributeIntegerValue(childSourceLineNumbers, childAttrib, 1, 32); | ||
3871 | break; | ||
3872 | case "KeyTable": | ||
3873 | keyTable = this.core.GetAttributeValue(childSourceLineNumbers, childAttrib); | ||
3874 | break; | ||
3875 | case "Localizable": | ||
3876 | localizable = YesNoType.Yes == this.core.GetAttributeYesNoValue(childSourceLineNumbers, childAttrib); | ||
3877 | break; | ||
3878 | case "MaxValue": | ||
3879 | maxValue = this.core.GetAttributeLongValue(childSourceLineNumbers, childAttrib, int.MinValue + 1, int.MaxValue); | ||
3880 | break; | ||
3881 | case "MinValue": | ||
3882 | minValue = this.core.GetAttributeLongValue(childSourceLineNumbers, childAttrib, int.MinValue + 1, int.MaxValue); | ||
3883 | break; | ||
3884 | case "Modularize": | ||
3885 | modularization = this.core.GetAttributeValue(childSourceLineNumbers, childAttrib); | ||
3886 | break; | ||
3887 | case "Nullable": | ||
3888 | nullable = YesNoType.Yes == this.core.GetAttributeYesNoValue(childSourceLineNumbers, childAttrib); | ||
3889 | break; | ||
3890 | case "PrimaryKey": | ||
3891 | primaryKey = YesNoType.Yes == this.core.GetAttributeYesNoValue(childSourceLineNumbers, childAttrib); | ||
3892 | break; | ||
3893 | case "Set": | ||
3894 | setValues = this.core.GetAttributeValue(childSourceLineNumbers, childAttrib); | ||
3895 | break; | ||
3896 | case "Type": | ||
3897 | string typeValue = this.core.GetAttributeValue(childSourceLineNumbers, childAttrib); | ||
3898 | if (0 < typeValue.Length) | ||
3899 | { | ||
3900 | Wix.Column.TypeType typeType = Wix.Column.ParseTypeType(typeValue); | ||
3901 | switch (typeType) | ||
3902 | { | ||
3903 | case Wix.Column.TypeType.binary: | ||
3904 | typeName = "OBJECT"; | ||
3905 | break; | ||
3906 | case Wix.Column.TypeType.@int: | ||
3907 | typeName = "SHORT"; | ||
3908 | break; | ||
3909 | case Wix.Column.TypeType.@string: | ||
3910 | typeName = "CHAR"; | ||
3911 | break; | ||
3912 | default: | ||
3913 | this.core.OnMessage(WixErrors.IllegalAttributeValue(childSourceLineNumbers, child.Name.LocalName, "Type", typeValue, "binary", "int", "string")); | ||
3914 | break; | ||
3915 | } | ||
3916 | } | ||
3917 | break; | ||
3918 | case "Width": | ||
3919 | width = this.core.GetAttributeIntegerValue(childSourceLineNumbers, childAttrib, 0, int.MaxValue); | ||
3920 | break; | ||
3921 | default: | ||
3922 | this.core.UnexpectedAttribute(child, childAttrib); | ||
3923 | break; | ||
3924 | } | ||
3925 | } | ||
3926 | |||
3927 | if (null == columnName) | ||
3928 | { | ||
3929 | this.core.OnMessage(WixErrors.ExpectedAttribute(childSourceLineNumbers, child.Name.LocalName, "Id")); | ||
3930 | } | ||
3931 | |||
3932 | if (null == typeName) | ||
3933 | { | ||
3934 | this.core.OnMessage(WixErrors.ExpectedAttribute(childSourceLineNumbers, child.Name.LocalName, "Type")); | ||
3935 | } | ||
3936 | else if ("SHORT" == typeName) | ||
3937 | { | ||
3938 | if (2 != width && 4 != width) | ||
3939 | { | ||
3940 | this.core.OnMessage(WixErrors.CustomTableIllegalColumnWidth(childSourceLineNumbers, child.Name.LocalName, "Width", width)); | ||
3941 | } | ||
3942 | columnType = String.Concat(nullable ? "I" : "i", width); | ||
3943 | } | ||
3944 | else if ("CHAR" == typeName) | ||
3945 | { | ||
3946 | string typeChar = localizable ? "l" : "s"; | ||
3947 | columnType = String.Concat(nullable ? typeChar.ToUpper(CultureInfo.InvariantCulture) : typeChar.ToLower(CultureInfo.InvariantCulture), width); | ||
3948 | } | ||
3949 | else if ("OBJECT" == typeName) | ||
3950 | { | ||
3951 | if ("Binary" != category) | ||
3952 | { | ||
3953 | this.core.OnMessage(WixErrors.ExpectedBinaryCategory(childSourceLineNumbers)); | ||
3954 | } | ||
3955 | columnType = String.Concat(nullable ? "V" : "v", width); | ||
3956 | } | ||
3957 | |||
3958 | this.core.ParseForExtensionElements(child); | ||
3959 | |||
3960 | columnNames = String.Concat(columnNames, null == columnNames ? String.Empty : "\t", columnName); | ||
3961 | columnTypes = String.Concat(columnTypes, null == columnTypes ? String.Empty : "\t", columnType); | ||
3962 | if (primaryKey) | ||
3963 | { | ||
3964 | primaryKeys = String.Concat(primaryKeys, null == primaryKeys ? String.Empty : "\t", columnName); | ||
3965 | } | ||
3966 | |||
3967 | minValues = String.Concat(minValues, null == minValues ? String.Empty : "\t", CompilerConstants.LongNotSet != minValue ? minValue.ToString(CultureInfo.InvariantCulture) : String.Empty); | ||
3968 | maxValues = String.Concat(maxValues, null == maxValues ? String.Empty : "\t", CompilerConstants.LongNotSet != maxValue ? maxValue.ToString(CultureInfo.InvariantCulture) : String.Empty); | ||
3969 | keyTables = String.Concat(keyTables, null == keyTables ? String.Empty : "\t", keyTable); | ||
3970 | keyColumns = String.Concat(keyColumns, null == keyColumns ? String.Empty : "\t", CompilerConstants.IntegerNotSet != keyColumn ? keyColumn.ToString(CultureInfo.InvariantCulture) : String.Empty); | ||
3971 | categories = String.Concat(categories, null == categories ? String.Empty : "\t", category); | ||
3972 | sets = String.Concat(sets, null == sets ? String.Empty : "\t", setValues); | ||
3973 | descriptions = String.Concat(descriptions, null == descriptions ? String.Empty : "\t", description); | ||
3974 | modularizations = String.Concat(modularizations, null == modularizations ? String.Empty : "\t", modularization); | ||
3975 | |||
3976 | break; | ||
3977 | case "Row": | ||
3978 | string dataValue = null; | ||
3979 | |||
3980 | foreach (XAttribute childAttrib in child.Attributes()) | ||
3981 | { | ||
3982 | this.core.ParseExtensionAttribute(child, childAttrib); | ||
3983 | } | ||
3984 | |||
3985 | foreach (XElement data in child.Elements()) | ||
3986 | { | ||
3987 | SourceLineNumber dataSourceLineNumbers = Preprocessor.GetSourceLineNumbers(data); | ||
3988 | switch (data.Name.LocalName) | ||
3989 | { | ||
3990 | case "Data": | ||
3991 | columnName = null; | ||
3992 | foreach (XAttribute dataAttrib in data.Attributes()) | ||
3993 | { | ||
3994 | switch (dataAttrib.Name.LocalName) | ||
3995 | { | ||
3996 | case "Column": | ||
3997 | columnName = this.core.GetAttributeValue(dataSourceLineNumbers, dataAttrib); | ||
3998 | break; | ||
3999 | default: | ||
4000 | this.core.UnexpectedAttribute(data, dataAttrib); | ||
4001 | break; | ||
4002 | } | ||
4003 | } | ||
4004 | |||
4005 | if (null == columnName) | ||
4006 | { | ||
4007 | this.core.OnMessage(WixErrors.ExpectedAttribute(dataSourceLineNumbers, data.Name.LocalName, "Column")); | ||
4008 | } | ||
4009 | |||
4010 | dataValue = String.Concat(dataValue, null == dataValue ? String.Empty : Common.CustomRowFieldSeparator.ToString(), columnName, ":", Common.GetInnerText(data)); | ||
4011 | break; | ||
4012 | } | ||
4013 | } | ||
4014 | |||
4015 | this.core.CreateSimpleReference(sourceLineNumbers, "WixCustomTable", tableId); | ||
4016 | |||
4017 | if (!this.core.EncounteredError) | ||
4018 | { | ||
4019 | Row rowRow = this.core.CreateRow(childSourceLineNumbers, "WixCustomRow"); | ||
4020 | rowRow[0] = tableId; | ||
4021 | rowRow[1] = dataValue; | ||
4022 | } | ||
4023 | break; | ||
4024 | default: | ||
4025 | this.core.UnexpectedElement(node, child); | ||
4026 | break; | ||
4027 | } | ||
4028 | } | ||
4029 | else | ||
4030 | { | ||
4031 | this.core.ParseExtensionElement(node, child); | ||
4032 | } | ||
4033 | } | ||
4034 | |||
4035 | if (0 < columnCount) | ||
4036 | { | ||
4037 | if (null == primaryKeys || 0 == primaryKeys.Length) | ||
4038 | { | ||
4039 | this.core.OnMessage(WixErrors.CustomTableMissingPrimaryKey(sourceLineNumbers)); | ||
4040 | } | ||
4041 | |||
4042 | if (!this.core.EncounteredError) | ||
4043 | { | ||
4044 | Row row = this.core.CreateRow(sourceLineNumbers, "WixCustomTable"); | ||
4045 | row[0] = tableId; | ||
4046 | row[1] = columnCount; | ||
4047 | row[2] = columnNames; | ||
4048 | row[3] = columnTypes; | ||
4049 | row[4] = primaryKeys; | ||
4050 | row[5] = minValues; | ||
4051 | row[6] = maxValues; | ||
4052 | row[7] = keyTables; | ||
4053 | row[8] = keyColumns; | ||
4054 | row[9] = categories; | ||
4055 | row[10] = sets; | ||
4056 | row[11] = descriptions; | ||
4057 | row[12] = modularizations; | ||
4058 | row[13] = bootstrapperApplicationData ? 1 : 0; | ||
4059 | } | ||
4060 | } | ||
4061 | } | ||
4062 | |||
4063 | /// <summary> | ||
4064 | /// Parses a directory element. | ||
4065 | /// </summary> | ||
4066 | /// <param name="node">Element to parse.</param> | ||
4067 | /// <param name="parentId">Optional identifier of parent directory.</param> | ||
4068 | /// <param name="diskId">Disk id inherited from parent directory.</param> | ||
4069 | /// <param name="fileSource">Path to source file as of yet.</param> | ||
4070 | [SuppressMessage("Microsoft.Performance", "CA1820:TestForEmptyStringsUsingStringLength")] | ||
4071 | private void ParseDirectoryElement(XElement node, string parentId, int diskId, string fileSource) | ||
4072 | { | ||
4073 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
4074 | Identifier id = null; | ||
4075 | string componentGuidGenerationSeed = null; | ||
4076 | bool fileSourceAttribSet = false; | ||
4077 | bool nameHasValue = false; | ||
4078 | string name = "."; // default to parent directory. | ||
4079 | string[] inlineSyntax = null; | ||
4080 | string shortName = null; | ||
4081 | string sourceName = null; | ||
4082 | string shortSourceName = null; | ||
4083 | string defaultDir = null; | ||
4084 | string symbols = null; | ||
4085 | |||
4086 | foreach (XAttribute attrib in node.Attributes()) | ||
4087 | { | ||
4088 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
4089 | { | ||
4090 | switch (attrib.Name.LocalName) | ||
4091 | { | ||
4092 | case "Id": | ||
4093 | id = this.core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
4094 | break; | ||
4095 | case "ComponentGuidGenerationSeed": | ||
4096 | componentGuidGenerationSeed = this.core.GetAttributeGuidValue(sourceLineNumbers, attrib, false); | ||
4097 | break; | ||
4098 | case "DiskId": | ||
4099 | diskId = this.core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 1, short.MaxValue); | ||
4100 | break; | ||
4101 | case "FileSource": | ||
4102 | fileSource = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
4103 | fileSourceAttribSet = true; | ||
4104 | break; | ||
4105 | case "Name": | ||
4106 | nameHasValue = true; | ||
4107 | if (attrib.Value.Equals(".")) | ||
4108 | { | ||
4109 | name = attrib.Value; | ||
4110 | } | ||
4111 | else | ||
4112 | { | ||
4113 | inlineSyntax = this.core.GetAttributeInlineDirectorySyntax(sourceLineNumbers, attrib); | ||
4114 | } | ||
4115 | break; | ||
4116 | case "ShortName": | ||
4117 | shortName = this.core.GetAttributeShortFilename(sourceLineNumbers, attrib, false); | ||
4118 | break; | ||
4119 | case "ShortSourceName": | ||
4120 | shortSourceName = this.core.GetAttributeShortFilename(sourceLineNumbers, attrib, false); | ||
4121 | break; | ||
4122 | case "SourceName": | ||
4123 | if ("." == attrib.Value) | ||
4124 | { | ||
4125 | sourceName = attrib.Value; | ||
4126 | } | ||
4127 | else | ||
4128 | { | ||
4129 | sourceName = this.core.GetAttributeLongFilename(sourceLineNumbers, attrib, false); | ||
4130 | } | ||
4131 | break; | ||
4132 | default: | ||
4133 | this.core.UnexpectedAttribute(node, attrib); | ||
4134 | break; | ||
4135 | } | ||
4136 | } | ||
4137 | else | ||
4138 | { | ||
4139 | this.core.ParseExtensionAttribute(node, attrib); | ||
4140 | } | ||
4141 | } | ||
4142 | |||
4143 | // Create the directory rows for the inline. | ||
4144 | if (null != inlineSyntax) | ||
4145 | { | ||
4146 | // Special case the single entry in the inline syntax since it is the most common case | ||
4147 | // and needs no extra processing. It's just the name of the directory. | ||
4148 | if (1 == inlineSyntax.Length) | ||
4149 | { | ||
4150 | name = inlineSyntax[0]; | ||
4151 | } | ||
4152 | else | ||
4153 | { | ||
4154 | int pathStartsAt = 0; | ||
4155 | if (inlineSyntax[0].EndsWith(":")) | ||
4156 | { | ||
4157 | parentId = inlineSyntax[0].TrimEnd(':'); | ||
4158 | this.core.CreateSimpleReference(sourceLineNumbers, "Directory", parentId); | ||
4159 | |||
4160 | pathStartsAt = 1; | ||
4161 | } | ||
4162 | |||
4163 | for (int i = pathStartsAt; i < inlineSyntax.Length - 1; ++i) | ||
4164 | { | ||
4165 | Identifier inlineId = this.core.CreateDirectoryRow(sourceLineNumbers, null, parentId, inlineSyntax[i]); | ||
4166 | parentId = inlineId.Id; | ||
4167 | } | ||
4168 | |||
4169 | name = inlineSyntax[inlineSyntax.Length - 1]; | ||
4170 | } | ||
4171 | } | ||
4172 | |||
4173 | if (!nameHasValue) | ||
4174 | { | ||
4175 | if (!String.IsNullOrEmpty(shortName)) | ||
4176 | { | ||
4177 | this.core.OnMessage(WixErrors.IllegalAttributeWithoutOtherAttributes(sourceLineNumbers, node.Name.LocalName, "ShortName", "Name")); | ||
4178 | } | ||
4179 | |||
4180 | if (null == parentId) | ||
4181 | { | ||
4182 | this.core.OnMessage(WixErrors.DirectoryRootWithoutName(sourceLineNumbers, node.Name.LocalName, "Name")); | ||
4183 | } | ||
4184 | } | ||
4185 | else if (!String.IsNullOrEmpty(name)) | ||
4186 | { | ||
4187 | if (String.IsNullOrEmpty(shortName)) | ||
4188 | { | ||
4189 | if (!name.Equals(".") && !name.Equals("SourceDir") && !this.core.IsValidShortFilename(name, false)) | ||
4190 | { | ||
4191 | shortName = this.core.CreateShortName(name, false, false, "Directory", parentId); | ||
4192 | } | ||
4193 | } | ||
4194 | else if (name.Equals(".")) | ||
4195 | { | ||
4196 | this.core.OnMessage(WixErrors.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "ShortName", "Name", name)); | ||
4197 | } | ||
4198 | else if (name.Equals(shortName)) | ||
4199 | { | ||
4200 | this.core.OnMessage(WixWarnings.DirectoryRedundantNames(sourceLineNumbers, node.Name.LocalName, "Name", "ShortName", name)); | ||
4201 | } | ||
4202 | } | ||
4203 | |||
4204 | if (String.IsNullOrEmpty(sourceName)) | ||
4205 | { | ||
4206 | if (!String.IsNullOrEmpty(shortSourceName)) | ||
4207 | { | ||
4208 | this.core.OnMessage(WixErrors.IllegalAttributeWithoutOtherAttributes(sourceLineNumbers, node.Name.LocalName, "ShortSourceName", "SourceName")); | ||
4209 | } | ||
4210 | } | ||
4211 | else | ||
4212 | { | ||
4213 | if (String.IsNullOrEmpty(shortSourceName)) | ||
4214 | { | ||
4215 | if (!sourceName.Equals(".") && !this.core.IsValidShortFilename(sourceName, false)) | ||
4216 | { | ||
4217 | shortSourceName = this.core.CreateShortName(sourceName, false, false, "Directory", parentId); | ||
4218 | } | ||
4219 | } | ||
4220 | else if (sourceName.Equals(".")) | ||
4221 | { | ||
4222 | this.core.OnMessage(WixErrors.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "ShortSourceName", "SourceName", sourceName)); | ||
4223 | } | ||
4224 | else if (sourceName.Equals(shortSourceName)) | ||
4225 | { | ||
4226 | this.core.OnMessage(WixWarnings.DirectoryRedundantNames(sourceLineNumbers, node.Name.LocalName, "SourceName", "ShortSourceName", sourceName)); | ||
4227 | } | ||
4228 | } | ||
4229 | |||
4230 | // Update the file source path appropriately. | ||
4231 | if (fileSourceAttribSet) | ||
4232 | { | ||
4233 | if (!fileSource.EndsWith(Path.DirectorySeparatorChar.ToString(), StringComparison.Ordinal)) | ||
4234 | { | ||
4235 | fileSource = String.Concat(fileSource, Path.DirectorySeparatorChar); | ||
4236 | } | ||
4237 | } | ||
4238 | else // add the appropriate part of this directory element to the file source. | ||
4239 | { | ||
4240 | string append = null; | ||
4241 | if (this.useShortFileNames) | ||
4242 | { | ||
4243 | append = !String.IsNullOrEmpty(shortSourceName) ? shortSourceName : shortName; | ||
4244 | } | ||
4245 | |||
4246 | if (String.IsNullOrEmpty(append)) | ||
4247 | { | ||
4248 | append = !String.IsNullOrEmpty(sourceName) ? sourceName : name; | ||
4249 | } | ||
4250 | |||
4251 | if (!String.IsNullOrEmpty(append)) | ||
4252 | { | ||
4253 | fileSource = String.Concat(fileSource, append, Path.DirectorySeparatorChar); | ||
4254 | } | ||
4255 | } | ||
4256 | |||
4257 | if (null == id) | ||
4258 | { | ||
4259 | id = this.core.CreateIdentifier("dir", parentId, name, shortName, sourceName, shortSourceName); | ||
4260 | } | ||
4261 | |||
4262 | // Calculate the DefaultDir for the directory row. | ||
4263 | defaultDir = String.IsNullOrEmpty(shortName) ? name : String.Concat(shortName, "|", name); | ||
4264 | if (!String.IsNullOrEmpty(sourceName)) | ||
4265 | { | ||
4266 | defaultDir = String.Concat(defaultDir, ":", String.IsNullOrEmpty(shortSourceName) ? sourceName : String.Concat(shortSourceName, "|", sourceName)); | ||
4267 | } | ||
4268 | |||
4269 | if ("TARGETDIR".Equals(id.Id) && !"SourceDir".Equals(defaultDir)) | ||
4270 | { | ||
4271 | this.core.OnMessage(WixErrors.IllegalTargetDirDefaultDir(sourceLineNumbers, defaultDir)); | ||
4272 | } | ||
4273 | |||
4274 | foreach (XElement child in node.Elements()) | ||
4275 | { | ||
4276 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
4277 | { | ||
4278 | switch (child.Name.LocalName) | ||
4279 | { | ||
4280 | case "Component": | ||
4281 | this.ParseComponentElement(child, ComplexReferenceParentType.Unknown, null, null, diskId, id.Id, fileSource); | ||
4282 | break; | ||
4283 | case "Directory": | ||
4284 | this.ParseDirectoryElement(child, id.Id, diskId, fileSource); | ||
4285 | break; | ||
4286 | case "Merge": | ||
4287 | this.ParseMergeElement(child, id.Id, diskId); | ||
4288 | break; | ||
4289 | case "SymbolPath": | ||
4290 | if (null != symbols) | ||
4291 | { | ||
4292 | symbols += ";" + this.ParseSymbolPathElement(child); | ||
4293 | } | ||
4294 | else | ||
4295 | { | ||
4296 | symbols = this.ParseSymbolPathElement(child); | ||
4297 | } | ||
4298 | break; | ||
4299 | default: | ||
4300 | this.core.UnexpectedElement(node, child); | ||
4301 | break; | ||
4302 | } | ||
4303 | } | ||
4304 | else | ||
4305 | { | ||
4306 | this.core.ParseExtensionElement(node, child); | ||
4307 | } | ||
4308 | } | ||
4309 | |||
4310 | if (!this.core.EncounteredError) | ||
4311 | { | ||
4312 | Row row = this.core.CreateRow(sourceLineNumbers, "Directory", id); | ||
4313 | row[1] = parentId; | ||
4314 | row[2] = defaultDir; | ||
4315 | |||
4316 | if (null != componentGuidGenerationSeed) | ||
4317 | { | ||
4318 | Row wixRow = this.core.CreateRow(sourceLineNumbers, "WixDirectory"); | ||
4319 | wixRow[0] = id.Id; | ||
4320 | wixRow[1] = componentGuidGenerationSeed; | ||
4321 | } | ||
4322 | |||
4323 | if (null != symbols) | ||
4324 | { | ||
4325 | WixDeltaPatchSymbolPathsRow symbolRow = (WixDeltaPatchSymbolPathsRow)this.core.CreateRow(sourceLineNumbers, "WixDeltaPatchSymbolPaths", id); | ||
4326 | symbolRow.Type = SymbolPathType.Directory; | ||
4327 | symbolRow.SymbolPaths = symbols; | ||
4328 | } | ||
4329 | } | ||
4330 | } | ||
4331 | |||
4332 | /// <summary> | ||
4333 | /// Parses a directory reference element. | ||
4334 | /// </summary> | ||
4335 | /// <param name="node">Element to parse.</param> | ||
4336 | [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1800:DoNotCastUnnecessarily")] | ||
4337 | private void ParseDirectoryRefElement(XElement node) | ||
4338 | { | ||
4339 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
4340 | string id = null; | ||
4341 | int diskId = CompilerConstants.IntegerNotSet; | ||
4342 | string fileSource = String.Empty; | ||
4343 | |||
4344 | foreach (XAttribute attrib in node.Attributes()) | ||
4345 | { | ||
4346 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
4347 | { | ||
4348 | switch (attrib.Name.LocalName) | ||
4349 | { | ||
4350 | case "Id": | ||
4351 | id = this.core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
4352 | this.core.CreateSimpleReference(sourceLineNumbers, "Directory", id); | ||
4353 | break; | ||
4354 | case "DiskId": | ||
4355 | diskId = this.core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 1, short.MaxValue); | ||
4356 | break; | ||
4357 | case "FileSource": | ||
4358 | fileSource = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
4359 | break; | ||
4360 | default: | ||
4361 | this.core.UnexpectedAttribute(node, attrib); | ||
4362 | break; | ||
4363 | } | ||
4364 | } | ||
4365 | else | ||
4366 | { | ||
4367 | this.core.ParseExtensionAttribute(node, attrib); | ||
4368 | } | ||
4369 | } | ||
4370 | |||
4371 | if (null == id) | ||
4372 | { | ||
4373 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
4374 | } | ||
4375 | |||
4376 | if (!String.IsNullOrEmpty(fileSource) && !fileSource.EndsWith(Path.DirectorySeparatorChar.ToString(), StringComparison.Ordinal)) | ||
4377 | { | ||
4378 | fileSource = String.Concat(fileSource, Path.DirectorySeparatorChar); | ||
4379 | } | ||
4380 | |||
4381 | foreach (XElement child in node.Elements()) | ||
4382 | { | ||
4383 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
4384 | { | ||
4385 | switch (child.Name.LocalName) | ||
4386 | { | ||
4387 | case "Component": | ||
4388 | this.ParseComponentElement(child, ComplexReferenceParentType.Unknown, null, null, diskId, id, fileSource); | ||
4389 | break; | ||
4390 | case "Directory": | ||
4391 | this.ParseDirectoryElement(child, id, diskId, fileSource); | ||
4392 | break; | ||
4393 | case "Merge": | ||
4394 | this.ParseMergeElement(child, id, diskId); | ||
4395 | break; | ||
4396 | default: | ||
4397 | this.core.UnexpectedElement(node, child); | ||
4398 | break; | ||
4399 | } | ||
4400 | } | ||
4401 | else | ||
4402 | { | ||
4403 | this.core.ParseExtensionElement(node, child); | ||
4404 | } | ||
4405 | } | ||
4406 | } | ||
4407 | |||
4408 | /// <summary> | ||
4409 | /// Parses a directory search element. | ||
4410 | /// </summary> | ||
4411 | /// <param name="node">Element to parse.</param> | ||
4412 | /// <param name="parentSignature">Signature of parent search element.</param> | ||
4413 | /// <returns>Signature of search element.</returns> | ||
4414 | private string ParseDirectorySearchElement(XElement node, string parentSignature) | ||
4415 | { | ||
4416 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
4417 | Identifier id = null; | ||
4418 | int depth = CompilerConstants.IntegerNotSet; | ||
4419 | string path = null; | ||
4420 | bool assignToProperty = false; | ||
4421 | string signature = null; | ||
4422 | |||
4423 | foreach (XAttribute attrib in node.Attributes()) | ||
4424 | { | ||
4425 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
4426 | { | ||
4427 | switch (attrib.Name.LocalName) | ||
4428 | { | ||
4429 | case "Id": | ||
4430 | id = this.core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
4431 | break; | ||
4432 | case "Depth": | ||
4433 | depth = this.core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, short.MaxValue); | ||
4434 | break; | ||
4435 | case "Path": | ||
4436 | path = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
4437 | break; | ||
4438 | case "AssignToProperty": | ||
4439 | assignToProperty = YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
4440 | break; | ||
4441 | default: | ||
4442 | this.core.UnexpectedAttribute(node, attrib); | ||
4443 | break; | ||
4444 | } | ||
4445 | } | ||
4446 | else | ||
4447 | { | ||
4448 | this.core.ParseExtensionAttribute(node, attrib); | ||
4449 | } | ||
4450 | } | ||
4451 | |||
4452 | if (null == id) | ||
4453 | { | ||
4454 | id = this.core.CreateIdentifier("dir", path, depth.ToString()); | ||
4455 | } | ||
4456 | |||
4457 | signature = id.Id; | ||
4458 | |||
4459 | bool oneChild = false; | ||
4460 | bool hasFileSearch = false; | ||
4461 | foreach (XElement child in node.Elements()) | ||
4462 | { | ||
4463 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
4464 | { | ||
4465 | SourceLineNumber childSourceLineNumbers = Preprocessor.GetSourceLineNumbers(child); | ||
4466 | switch (child.Name.LocalName) | ||
4467 | { | ||
4468 | case "DirectorySearch": | ||
4469 | if (oneChild) | ||
4470 | { | ||
4471 | this.core.OnMessage(WixErrors.TooManySearchElements(childSourceLineNumbers, node.Name.LocalName)); | ||
4472 | } | ||
4473 | oneChild = true; | ||
4474 | signature = this.ParseDirectorySearchElement(child, id.Id); | ||
4475 | break; | ||
4476 | case "DirectorySearchRef": | ||
4477 | if (oneChild) | ||
4478 | { | ||
4479 | this.core.OnMessage(WixErrors.TooManySearchElements(childSourceLineNumbers, node.Name.LocalName)); | ||
4480 | } | ||
4481 | oneChild = true; | ||
4482 | signature = this.ParseDirectorySearchRefElement(child, id.Id); | ||
4483 | break; | ||
4484 | case "FileSearch": | ||
4485 | if (oneChild) | ||
4486 | { | ||
4487 | this.core.OnMessage(WixErrors.TooManySearchElements(sourceLineNumbers, node.Name.LocalName)); | ||
4488 | } | ||
4489 | oneChild = true; | ||
4490 | hasFileSearch = true; | ||
4491 | signature = this.ParseFileSearchElement(child, id.Id, assignToProperty, depth); | ||
4492 | break; | ||
4493 | case "FileSearchRef": | ||
4494 | if (oneChild) | ||
4495 | { | ||
4496 | this.core.OnMessage(WixErrors.TooManySearchElements(sourceLineNumbers, node.Name.LocalName)); | ||
4497 | } | ||
4498 | oneChild = true; | ||
4499 | signature = this.ParseSimpleRefElement(child, "Signature"); | ||
4500 | break; | ||
4501 | default: | ||
4502 | this.core.UnexpectedElement(node, child); | ||
4503 | break; | ||
4504 | } | ||
4505 | |||
4506 | // If AssignToProperty is set, only a FileSearch | ||
4507 | // or no child element can be nested. | ||
4508 | if (assignToProperty) | ||
4509 | { | ||
4510 | if (!hasFileSearch) | ||
4511 | { | ||
4512 | this.core.OnMessage(WixErrors.IllegalParentAttributeWhenNested(sourceLineNumbers, node.Name.LocalName, "AssignToProperty", child.Name.LocalName)); | ||
4513 | } | ||
4514 | else if (!oneChild) | ||
4515 | { | ||
4516 | // This a normal directory search. | ||
4517 | assignToProperty = false; | ||
4518 | } | ||
4519 | } | ||
4520 | } | ||
4521 | else | ||
4522 | { | ||
4523 | this.core.ParseExtensionElement(node, child); | ||
4524 | } | ||
4525 | } | ||
4526 | |||
4527 | if (!this.core.EncounteredError) | ||
4528 | { | ||
4529 | Identifier rowId = id; | ||
4530 | |||
4531 | // If AssignToProperty is set, the DrLocator row created by | ||
4532 | // ParseFileSearchElement creates the directory entry to return | ||
4533 | // and the row created here is for the file search. | ||
4534 | if (assignToProperty) | ||
4535 | { | ||
4536 | rowId = new Identifier(signature, AccessModifier.Private); | ||
4537 | |||
4538 | // The property should be set to the directory search Id. | ||
4539 | signature = id.Id; | ||
4540 | } | ||
4541 | |||
4542 | Row row = this.core.CreateRow(sourceLineNumbers, "DrLocator", rowId); | ||
4543 | row[1] = parentSignature; | ||
4544 | row[2] = path; | ||
4545 | if (CompilerConstants.IntegerNotSet != depth) | ||
4546 | { | ||
4547 | row[3] = depth; | ||
4548 | } | ||
4549 | } | ||
4550 | |||
4551 | return signature; | ||
4552 | } | ||
4553 | |||
4554 | /// <summary> | ||
4555 | /// Parses a directory search reference element. | ||
4556 | /// </summary> | ||
4557 | /// <param name="node">Element to parse.</param> | ||
4558 | /// <param name="parentSignature">Signature of parent search element.</param> | ||
4559 | /// <returns>Signature of search element.</returns> | ||
4560 | private string ParseDirectorySearchRefElement(XElement node, string parentSignature) | ||
4561 | { | ||
4562 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
4563 | Identifier id = null; | ||
4564 | Identifier parent = null; | ||
4565 | string path = null; | ||
4566 | string signature = null; | ||
4567 | |||
4568 | foreach (XAttribute attrib in node.Attributes()) | ||
4569 | { | ||
4570 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
4571 | { | ||
4572 | switch (attrib.Name.LocalName) | ||
4573 | { | ||
4574 | case "Id": | ||
4575 | id = this.core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
4576 | break; | ||
4577 | case "Parent": | ||
4578 | parent = this.core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
4579 | break; | ||
4580 | case "Path": | ||
4581 | path = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
4582 | break; | ||
4583 | default: | ||
4584 | this.core.UnexpectedAttribute(node, attrib); | ||
4585 | break; | ||
4586 | } | ||
4587 | } | ||
4588 | else | ||
4589 | { | ||
4590 | this.core.ParseExtensionAttribute(node, attrib); | ||
4591 | } | ||
4592 | } | ||
4593 | |||
4594 | if (null != parent) | ||
4595 | { | ||
4596 | if (!String.IsNullOrEmpty(parentSignature)) | ||
4597 | { | ||
4598 | this.core.OnMessage(WixErrors.CanNotHaveTwoParents(sourceLineNumbers, id.Id, parent.Id, parentSignature)); | ||
4599 | } | ||
4600 | else | ||
4601 | { | ||
4602 | parentSignature = parent.Id; | ||
4603 | } | ||
4604 | } | ||
4605 | |||
4606 | if (null == id) | ||
4607 | { | ||
4608 | id = this.core.CreateIdentifier("dsr", parentSignature, path); | ||
4609 | } | ||
4610 | |||
4611 | signature = id.Id; | ||
4612 | |||
4613 | bool oneChild = false; | ||
4614 | foreach (XElement child in node.Elements()) | ||
4615 | { | ||
4616 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
4617 | { | ||
4618 | SourceLineNumber childSourceLineNumbers = Preprocessor.GetSourceLineNumbers(child); | ||
4619 | switch (child.Name.LocalName) | ||
4620 | { | ||
4621 | case "DirectorySearch": | ||
4622 | if (oneChild) | ||
4623 | { | ||
4624 | this.core.OnMessage(WixErrors.TooManySearchElements(childSourceLineNumbers, node.Name.LocalName)); | ||
4625 | } | ||
4626 | oneChild = true; | ||
4627 | signature = this.ParseDirectorySearchElement(child, id.Id); | ||
4628 | break; | ||
4629 | case "DirectorySearchRef": | ||
4630 | if (oneChild) | ||
4631 | { | ||
4632 | this.core.OnMessage(WixErrors.TooManySearchElements(childSourceLineNumbers, node.Name.LocalName)); | ||
4633 | } | ||
4634 | oneChild = true; | ||
4635 | signature = this.ParseDirectorySearchRefElement(child, id.Id); | ||
4636 | break; | ||
4637 | case "FileSearch": | ||
4638 | if (oneChild) | ||
4639 | { | ||
4640 | this.core.OnMessage(WixErrors.TooManySearchElements(childSourceLineNumbers, node.Name.LocalName)); | ||
4641 | } | ||
4642 | oneChild = true; | ||
4643 | signature = this.ParseFileSearchElement(child, id.Id, false, CompilerConstants.IntegerNotSet); | ||
4644 | break; | ||
4645 | case "FileSearchRef": | ||
4646 | if (oneChild) | ||
4647 | { | ||
4648 | this.core.OnMessage(WixErrors.TooManySearchElements(sourceLineNumbers, node.Name.LocalName)); | ||
4649 | } | ||
4650 | oneChild = true; | ||
4651 | signature = this.ParseSimpleRefElement(child, "Signature"); | ||
4652 | break; | ||
4653 | default: | ||
4654 | this.core.UnexpectedElement(node, child); | ||
4655 | break; | ||
4656 | } | ||
4657 | } | ||
4658 | else | ||
4659 | { | ||
4660 | this.core.ParseExtensionElement(node, child); | ||
4661 | } | ||
4662 | } | ||
4663 | |||
4664 | |||
4665 | this.core.CreateSimpleReference(sourceLineNumbers, "DrLocator", id.Id, parentSignature, path); | ||
4666 | |||
4667 | return signature; | ||
4668 | } | ||
4669 | |||
4670 | /// <summary> | ||
4671 | /// Parses a feature element. | ||
4672 | /// </summary> | ||
4673 | /// <param name="node">Element to parse.</param> | ||
4674 | /// <param name="parentType">The type of parent.</param> | ||
4675 | /// <param name="parentId">Optional identifer for parent feature.</param> | ||
4676 | /// <param name="lastDisplay">Display value for last feature used to get the features to display in the same order as specified | ||
4677 | /// in the source code.</param> | ||
4678 | [SuppressMessage("Microsoft.Performance", "CA1800:DoNotCastUnnecessarily")] | ||
4679 | private void ParseFeatureElement(XElement node, ComplexReferenceParentType parentType, string parentId, ref int lastDisplay) | ||
4680 | { | ||
4681 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
4682 | Identifier id = null; | ||
4683 | string allowAdvertise = null; | ||
4684 | int bits = 0; | ||
4685 | string configurableDirectory = null; | ||
4686 | string description = null; | ||
4687 | string display = "collapse"; | ||
4688 | YesNoType followParent = YesNoType.NotSet; | ||
4689 | string installDefault = null; | ||
4690 | int level = 1; | ||
4691 | string title = null; | ||
4692 | string typicalDefault = null; | ||
4693 | |||
4694 | foreach (XAttribute attrib in node.Attributes()) | ||
4695 | { | ||
4696 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
4697 | { | ||
4698 | switch (attrib.Name.LocalName) | ||
4699 | { | ||
4700 | case "Id": | ||
4701 | id = this.core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
4702 | break; | ||
4703 | case "Absent": | ||
4704 | string absent = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
4705 | if (0 < absent.Length) | ||
4706 | { | ||
4707 | Wix.Feature.AbsentType absentType = Wix.Feature.ParseAbsentType(absent); | ||
4708 | switch (absentType) | ||
4709 | { | ||
4710 | case Wix.Feature.AbsentType.allow: // this is the default | ||
4711 | break; | ||
4712 | case Wix.Feature.AbsentType.disallow: | ||
4713 | bits = bits | MsiInterop.MsidbFeatureAttributesUIDisallowAbsent; | ||
4714 | break; | ||
4715 | default: | ||
4716 | this.core.OnMessage(WixErrors.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, absent, "allow", "disallow")); | ||
4717 | break; | ||
4718 | } | ||
4719 | } | ||
4720 | break; | ||
4721 | case "AllowAdvertise": | ||
4722 | allowAdvertise = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
4723 | if (0 < allowAdvertise.Length) | ||
4724 | { | ||
4725 | Wix.Feature.AllowAdvertiseType allowAdvertiseType = Wix.Feature.ParseAllowAdvertiseType(allowAdvertise); | ||
4726 | switch (allowAdvertiseType) | ||
4727 | { | ||
4728 | case Wix.Feature.AllowAdvertiseType.no: | ||
4729 | bits |= MsiInterop.MsidbFeatureAttributesDisallowAdvertise; | ||
4730 | break; | ||
4731 | case Wix.Feature.AllowAdvertiseType.system: | ||
4732 | bits |= MsiInterop.MsidbFeatureAttributesNoUnsupportedAdvertise; | ||
4733 | break; | ||
4734 | case Wix.Feature.AllowAdvertiseType.yes: // this is the default | ||
4735 | break; | ||
4736 | default: | ||
4737 | this.core.OnMessage(WixErrors.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, allowAdvertise, "no", "system", "yes")); | ||
4738 | break; | ||
4739 | } | ||
4740 | } | ||
4741 | break; | ||
4742 | case "ConfigurableDirectory": | ||
4743 | configurableDirectory = this.core.CreateDirectoryReferenceFromInlineSyntax(sourceLineNumbers, attrib, null); | ||
4744 | break; | ||
4745 | case "Description": | ||
4746 | description = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
4747 | break; | ||
4748 | case "Display": | ||
4749 | display = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
4750 | break; | ||
4751 | case "InstallDefault": | ||
4752 | installDefault = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
4753 | if (0 < installDefault.Length) | ||
4754 | { | ||
4755 | Wix.Feature.InstallDefaultType installDefaultType = Wix.Feature.ParseInstallDefaultType(installDefault); | ||
4756 | switch (installDefaultType) | ||
4757 | { | ||
4758 | case Wix.Feature.InstallDefaultType.followParent: | ||
4759 | if (ComplexReferenceParentType.Product == parentType) | ||
4760 | { | ||
4761 | this.core.OnMessage(WixErrors.RootFeatureCannotFollowParent(sourceLineNumbers)); | ||
4762 | } | ||
4763 | bits = bits | MsiInterop.MsidbFeatureAttributesFollowParent; | ||
4764 | break; | ||
4765 | case Wix.Feature.InstallDefaultType.local: // this is the default | ||
4766 | break; | ||
4767 | case Wix.Feature.InstallDefaultType.source: | ||
4768 | bits = bits | MsiInterop.MsidbFeatureAttributesFavorSource; | ||
4769 | break; | ||
4770 | default: | ||
4771 | this.core.OnMessage(WixErrors.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, installDefault, "followParent", "local", "source")); | ||
4772 | break; | ||
4773 | } | ||
4774 | } | ||
4775 | break; | ||
4776 | case "Level": | ||
4777 | level = this.core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, short.MaxValue); | ||
4778 | break; | ||
4779 | case "Title": | ||
4780 | title = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
4781 | if ("PUT-FEATURE-TITLE-HERE" == title) | ||
4782 | { | ||
4783 | this.core.OnMessage(WixWarnings.PlaceholderValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, title)); | ||
4784 | } | ||
4785 | break; | ||
4786 | case "TypicalDefault": | ||
4787 | typicalDefault = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
4788 | if (0 < typicalDefault.Length) | ||
4789 | { | ||
4790 | Wix.Feature.TypicalDefaultType typicalDefaultType = Wix.Feature.ParseTypicalDefaultType(typicalDefault); | ||
4791 | switch (typicalDefaultType) | ||
4792 | { | ||
4793 | case Wix.Feature.TypicalDefaultType.advertise: | ||
4794 | bits = bits | MsiInterop.MsidbFeatureAttributesFavorAdvertise; | ||
4795 | break; | ||
4796 | case Wix.Feature.TypicalDefaultType.install: // this is the default | ||
4797 | break; | ||
4798 | default: | ||
4799 | this.core.OnMessage(WixErrors.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, typicalDefault, "advertise", "install")); | ||
4800 | break; | ||
4801 | } | ||
4802 | } | ||
4803 | break; | ||
4804 | default: | ||
4805 | this.core.UnexpectedAttribute(node, attrib); | ||
4806 | break; | ||
4807 | } | ||
4808 | } | ||
4809 | else | ||
4810 | { | ||
4811 | this.core.ParseExtensionAttribute(node, attrib); | ||
4812 | } | ||
4813 | } | ||
4814 | |||
4815 | if (null == id) | ||
4816 | { | ||
4817 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
4818 | id = Identifier.Invalid; | ||
4819 | } | ||
4820 | else if (38 < id.Id.Length) | ||
4821 | { | ||
4822 | this.core.OnMessage(WixErrors.FeatureNameTooLong(sourceLineNumbers, node.Name.LocalName, "Id", id.Id)); | ||
4823 | } | ||
4824 | |||
4825 | if (null != configurableDirectory && configurableDirectory.ToUpper(CultureInfo.InvariantCulture) != configurableDirectory) | ||
4826 | { | ||
4827 | this.core.OnMessage(WixErrors.FeatureConfigurableDirectoryNotUppercase(sourceLineNumbers, node.Name.LocalName, "ConfigurableDirectory", configurableDirectory)); | ||
4828 | } | ||
4829 | |||
4830 | if ("advertise" == typicalDefault && "no" == allowAdvertise) | ||
4831 | { | ||
4832 | this.core.OnMessage(WixErrors.FeatureCannotFavorAndDisallowAdvertise(sourceLineNumbers, node.Name.LocalName, "TypicalDefault", typicalDefault, "AllowAdvertise", allowAdvertise)); | ||
4833 | } | ||
4834 | |||
4835 | if (YesNoType.Yes == followParent && ("local" == installDefault || "source" == installDefault)) | ||
4836 | { | ||
4837 | this.core.OnMessage(WixErrors.FeatureCannotFollowParentAndFavorLocalOrSource(sourceLineNumbers, node.Name.LocalName, "InstallDefault", "FollowParent", "yes")); | ||
4838 | } | ||
4839 | |||
4840 | int childDisplay = 0; | ||
4841 | foreach (XElement child in node.Elements()) | ||
4842 | { | ||
4843 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
4844 | { | ||
4845 | switch (child.Name.LocalName) | ||
4846 | { | ||
4847 | case "ComponentGroupRef": | ||
4848 | this.ParseComponentGroupRefElement(child, ComplexReferenceParentType.Feature, id.Id, null); | ||
4849 | break; | ||
4850 | case "ComponentRef": | ||
4851 | this.ParseComponentRefElement(child, ComplexReferenceParentType.Feature, id.Id, null); | ||
4852 | break; | ||
4853 | case "Component": | ||
4854 | this.ParseComponentElement(child, ComplexReferenceParentType.Feature, id.Id, null, CompilerConstants.IntegerNotSet, null, null); | ||
4855 | break; | ||
4856 | case "Condition": | ||
4857 | this.ParseConditionElement(child, node.Name.LocalName, id.Id, null); | ||
4858 | break; | ||
4859 | case "Feature": | ||
4860 | this.ParseFeatureElement(child, ComplexReferenceParentType.Feature, id.Id, ref childDisplay); | ||
4861 | break; | ||
4862 | case "FeatureGroupRef": | ||
4863 | this.ParseFeatureGroupRefElement(child, ComplexReferenceParentType.Feature, id.Id); | ||
4864 | break; | ||
4865 | case "FeatureRef": | ||
4866 | this.ParseFeatureRefElement(child, ComplexReferenceParentType.Feature, id.Id); | ||
4867 | break; | ||
4868 | case "MergeRef": | ||
4869 | this.ParseMergeRefElement(child, ComplexReferenceParentType.Feature, id.Id); | ||
4870 | break; | ||
4871 | default: | ||
4872 | this.core.UnexpectedElement(node, child); | ||
4873 | break; | ||
4874 | } | ||
4875 | } | ||
4876 | else | ||
4877 | { | ||
4878 | this.core.ParseExtensionElement(node, child); | ||
4879 | } | ||
4880 | } | ||
4881 | |||
4882 | if (!this.core.EncounteredError) | ||
4883 | { | ||
4884 | Row row = this.core.CreateRow(sourceLineNumbers, "Feature", id); | ||
4885 | row[1] = null; // this column is set in the linker | ||
4886 | row[2] = title; | ||
4887 | row[3] = description; | ||
4888 | if (0 < display.Length) | ||
4889 | { | ||
4890 | switch (display) | ||
4891 | { | ||
4892 | case "collapse": | ||
4893 | lastDisplay = (lastDisplay | 1) + 1; | ||
4894 | row[4] = lastDisplay; | ||
4895 | break; | ||
4896 | case "expand": | ||
4897 | lastDisplay = (lastDisplay + 1) | 1; | ||
4898 | row[4] = lastDisplay; | ||
4899 | break; | ||
4900 | case "hidden": | ||
4901 | row[4] = 0; | ||
4902 | break; | ||
4903 | default: | ||
4904 | int value; | ||
4905 | if (!Int32.TryParse(display, NumberStyles.Integer, CultureInfo.InvariantCulture, out value)) | ||
4906 | { | ||
4907 | this.core.OnMessage(WixErrors.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, "Display", display, "collapse", "expand", "hidden")); | ||
4908 | } | ||
4909 | else | ||
4910 | { | ||
4911 | row[4] = value; | ||
4912 | // save the display value of this row (if its not hidden) for subsequent rows | ||
4913 | if (0 != (int)row[4]) | ||
4914 | { | ||
4915 | lastDisplay = (int)row[4]; | ||
4916 | } | ||
4917 | } | ||
4918 | break; | ||
4919 | } | ||
4920 | } | ||
4921 | row[5] = level; | ||
4922 | row[6] = configurableDirectory; | ||
4923 | row[7] = bits; | ||
4924 | |||
4925 | if (ComplexReferenceParentType.Unknown != parentType) | ||
4926 | { | ||
4927 | this.core.CreateComplexReference(sourceLineNumbers, parentType, parentId, null, ComplexReferenceChildType.Feature, id.Id, false); | ||
4928 | } | ||
4929 | } | ||
4930 | } | ||
4931 | |||
4932 | /// <summary> | ||
4933 | /// Parses a feature reference element. | ||
4934 | /// </summary> | ||
4935 | /// <param name="node">Element to parse.</param> | ||
4936 | /// <param name="parentType">The type of parent.</param> | ||
4937 | /// <param name="parentId">Optional identifier for parent feature.</param> | ||
4938 | [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1800:DoNotCastUnnecessarily")] | ||
4939 | private void ParseFeatureRefElement(XElement node, ComplexReferenceParentType parentType, string parentId) | ||
4940 | { | ||
4941 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
4942 | string id = null; | ||
4943 | YesNoType ignoreParent = YesNoType.NotSet; | ||
4944 | |||
4945 | foreach (XAttribute attrib in node.Attributes()) | ||
4946 | { | ||
4947 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
4948 | { | ||
4949 | switch (attrib.Name.LocalName) | ||
4950 | { | ||
4951 | case "Id": | ||
4952 | id = this.core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
4953 | this.core.CreateSimpleReference(sourceLineNumbers, "Feature", id); | ||
4954 | break; | ||
4955 | case "IgnoreParent": | ||
4956 | ignoreParent = this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
4957 | break; | ||
4958 | default: | ||
4959 | this.core.UnexpectedAttribute(node, attrib); | ||
4960 | break; | ||
4961 | } | ||
4962 | } | ||
4963 | else | ||
4964 | { | ||
4965 | this.core.ParseExtensionAttribute(node, attrib); | ||
4966 | } | ||
4967 | } | ||
4968 | |||
4969 | |||
4970 | if (null == id) | ||
4971 | { | ||
4972 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
4973 | } | ||
4974 | |||
4975 | int lastDisplay = 0; | ||
4976 | foreach (XElement child in node.Elements()) | ||
4977 | { | ||
4978 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
4979 | { | ||
4980 | switch (child.Name.LocalName) | ||
4981 | { | ||
4982 | case "ComponentGroupRef": | ||
4983 | this.ParseComponentGroupRefElement(child, ComplexReferenceParentType.Feature, id, null); | ||
4984 | break; | ||
4985 | case "ComponentRef": | ||
4986 | this.ParseComponentRefElement(child, ComplexReferenceParentType.Feature, id, null); | ||
4987 | break; | ||
4988 | case "Component": | ||
4989 | this.ParseComponentElement(child, ComplexReferenceParentType.Feature, id, null, CompilerConstants.IntegerNotSet, null, null); | ||
4990 | break; | ||
4991 | case "Feature": | ||
4992 | this.ParseFeatureElement(child, ComplexReferenceParentType.Feature, id, ref lastDisplay); | ||
4993 | break; | ||
4994 | case "FeatureGroup": | ||
4995 | this.ParseFeatureGroupElement(child, ComplexReferenceParentType.Feature, id); | ||
4996 | break; | ||
4997 | case "FeatureGroupRef": | ||
4998 | this.ParseFeatureGroupRefElement(child, ComplexReferenceParentType.Feature, id); | ||
4999 | break; | ||
5000 | case "FeatureRef": | ||
5001 | this.ParseFeatureRefElement(child, ComplexReferenceParentType.Feature, id); | ||
5002 | break; | ||
5003 | case "MergeRef": | ||
5004 | this.ParseMergeRefElement(child, ComplexReferenceParentType.Feature, id); | ||
5005 | break; | ||
5006 | default: | ||
5007 | this.core.UnexpectedElement(node, child); | ||
5008 | break; | ||
5009 | } | ||
5010 | } | ||
5011 | else | ||
5012 | { | ||
5013 | this.core.ParseExtensionElement(node, child); | ||
5014 | } | ||
5015 | } | ||
5016 | |||
5017 | if (!this.core.EncounteredError) | ||
5018 | { | ||
5019 | if (ComplexReferenceParentType.Unknown != parentType && YesNoType.Yes != ignoreParent) | ||
5020 | { | ||
5021 | this.core.CreateComplexReference(sourceLineNumbers, parentType, parentId, null, ComplexReferenceChildType.Feature, id, false); | ||
5022 | } | ||
5023 | } | ||
5024 | } | ||
5025 | |||
5026 | /// <summary> | ||
5027 | /// Parses a feature group element. | ||
5028 | /// </summary> | ||
5029 | /// <param name="node">Element to parse.</param> | ||
5030 | [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1800:DoNotCastUnnecessarily")] | ||
5031 | private void ParseFeatureGroupElement(XElement node, ComplexReferenceParentType parentType, string parentId) | ||
5032 | { | ||
5033 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
5034 | Identifier id = null; | ||
5035 | |||
5036 | foreach (XAttribute attrib in node.Attributes()) | ||
5037 | { | ||
5038 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
5039 | { | ||
5040 | switch (attrib.Name.LocalName) | ||
5041 | { | ||
5042 | case "Id": | ||
5043 | id = this.core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
5044 | break; | ||
5045 | default: | ||
5046 | this.core.UnexpectedAttribute(node, attrib); | ||
5047 | break; | ||
5048 | } | ||
5049 | } | ||
5050 | else | ||
5051 | { | ||
5052 | this.core.ParseExtensionAttribute(node, attrib); | ||
5053 | } | ||
5054 | } | ||
5055 | |||
5056 | if (null == id) | ||
5057 | { | ||
5058 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
5059 | id = Identifier.Invalid; | ||
5060 | } | ||
5061 | |||
5062 | int lastDisplay = 0; | ||
5063 | foreach (XElement child in node.Elements()) | ||
5064 | { | ||
5065 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
5066 | { | ||
5067 | switch (child.Name.LocalName) | ||
5068 | { | ||
5069 | case "ComponentGroupRef": | ||
5070 | this.ParseComponentGroupRefElement(child, ComplexReferenceParentType.FeatureGroup, id.Id, null); | ||
5071 | break; | ||
5072 | case "ComponentRef": | ||
5073 | this.ParseComponentRefElement(child, ComplexReferenceParentType.FeatureGroup, id.Id, null); | ||
5074 | break; | ||
5075 | case "Component": | ||
5076 | this.ParseComponentElement(child, ComplexReferenceParentType.FeatureGroup, id.Id, null, CompilerConstants.IntegerNotSet, null, null); | ||
5077 | break; | ||
5078 | case "Feature": | ||
5079 | this.ParseFeatureElement(child, ComplexReferenceParentType.FeatureGroup, id.Id, ref lastDisplay); | ||
5080 | break; | ||
5081 | case "FeatureGroupRef": | ||
5082 | this.ParseFeatureGroupRefElement(child, ComplexReferenceParentType.FeatureGroup, id.Id); | ||
5083 | break; | ||
5084 | case "FeatureRef": | ||
5085 | this.ParseFeatureRefElement(child, ComplexReferenceParentType.FeatureGroup, id.Id); | ||
5086 | break; | ||
5087 | case "MergeRef": | ||
5088 | this.ParseMergeRefElement(child, ComplexReferenceParentType.FeatureGroup, id.Id); | ||
5089 | break; | ||
5090 | default: | ||
5091 | this.core.UnexpectedElement(node, child); | ||
5092 | break; | ||
5093 | } | ||
5094 | } | ||
5095 | else | ||
5096 | { | ||
5097 | this.core.ParseExtensionElement(node, child); | ||
5098 | } | ||
5099 | } | ||
5100 | |||
5101 | if (!this.core.EncounteredError) | ||
5102 | { | ||
5103 | Row row = this.core.CreateRow(sourceLineNumbers, "WixFeatureGroup", id); | ||
5104 | |||
5105 | //Add this FeatureGroup and its parent in WixGroup. | ||
5106 | this.core.CreateWixGroupRow(sourceLineNumbers, parentType, parentId, ComplexReferenceChildType.FeatureGroup, id.Id); | ||
5107 | } | ||
5108 | } | ||
5109 | |||
5110 | /// <summary> | ||
5111 | /// Parses a feature group reference element. | ||
5112 | /// </summary> | ||
5113 | /// <param name="node">Element to parse.</param> | ||
5114 | /// <param name="parentType">The type of parent.</param> | ||
5115 | /// <param name="parentId">Identifier of parent element.</param> | ||
5116 | private void ParseFeatureGroupRefElement(XElement node, ComplexReferenceParentType parentType, string parentId) | ||
5117 | { | ||
5118 | Debug.Assert(ComplexReferenceParentType.Feature == parentType || ComplexReferenceParentType.FeatureGroup == parentType || ComplexReferenceParentType.ComponentGroup == parentType || ComplexReferenceParentType.Product == parentType); | ||
5119 | |||
5120 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
5121 | string id = null; | ||
5122 | YesNoType ignoreParent = YesNoType.NotSet; | ||
5123 | YesNoType primary = YesNoType.NotSet; | ||
5124 | |||
5125 | foreach (XAttribute attrib in node.Attributes()) | ||
5126 | { | ||
5127 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
5128 | { | ||
5129 | switch (attrib.Name.LocalName) | ||
5130 | { | ||
5131 | case "Id": | ||
5132 | id = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
5133 | this.core.CreateSimpleReference(sourceLineNumbers, "WixFeatureGroup", id); | ||
5134 | break; | ||
5135 | case "IgnoreParent": | ||
5136 | ignoreParent = this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
5137 | break; | ||
5138 | case "Primary": | ||
5139 | primary = this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
5140 | break; | ||
5141 | default: | ||
5142 | this.core.UnexpectedAttribute(node, attrib); | ||
5143 | break; | ||
5144 | } | ||
5145 | } | ||
5146 | else | ||
5147 | { | ||
5148 | this.core.ParseExtensionAttribute(node, attrib); | ||
5149 | } | ||
5150 | } | ||
5151 | |||
5152 | if (null == id) | ||
5153 | { | ||
5154 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
5155 | } | ||
5156 | |||
5157 | this.core.ParseForExtensionElements(node); | ||
5158 | |||
5159 | if (!this.core.EncounteredError) | ||
5160 | { | ||
5161 | if (YesNoType.Yes != ignoreParent) | ||
5162 | { | ||
5163 | this.core.CreateComplexReference(sourceLineNumbers, parentType, parentId, null, ComplexReferenceChildType.FeatureGroup, id, (YesNoType.Yes == primary)); | ||
5164 | } | ||
5165 | } | ||
5166 | } | ||
5167 | |||
5168 | /// <summary> | ||
5169 | /// Parses an environment element. | ||
5170 | /// </summary> | ||
5171 | /// <param name="node">Element to parse.</param> | ||
5172 | /// <param name="componentId">Identifier of parent component.</param> | ||
5173 | private void ParseEnvironmentElement(XElement node, string componentId) | ||
5174 | { | ||
5175 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
5176 | Identifier id = null; | ||
5177 | string action = null; | ||
5178 | string name = null; | ||
5179 | Wix.Environment.PartType partType = Wix.Environment.PartType.NotSet; | ||
5180 | string part = null; | ||
5181 | bool permanent = false; | ||
5182 | string separator = ";"; // default to ';' | ||
5183 | bool system = false; | ||
5184 | string text = null; | ||
5185 | string uninstall = "-"; // default to remove at uninstall | ||
5186 | |||
5187 | foreach (XAttribute attrib in node.Attributes()) | ||
5188 | { | ||
5189 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
5190 | { | ||
5191 | switch (attrib.Name.LocalName) | ||
5192 | { | ||
5193 | case "Id": | ||
5194 | id = this.core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
5195 | break; | ||
5196 | case "Action": | ||
5197 | string value = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
5198 | if (0 < value.Length) | ||
5199 | { | ||
5200 | Wix.Environment.ActionType actionType = Wix.Environment.ParseActionType(value); | ||
5201 | switch (actionType) | ||
5202 | { | ||
5203 | case Wix.Environment.ActionType.create: | ||
5204 | action = "+"; | ||
5205 | break; | ||
5206 | case Wix.Environment.ActionType.set: | ||
5207 | action = "="; | ||
5208 | break; | ||
5209 | case Wix.Environment.ActionType.remove: | ||
5210 | action = "!"; | ||
5211 | break; | ||
5212 | default: | ||
5213 | this.core.OnMessage(WixErrors.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, value, "create", "set", "remove")); | ||
5214 | break; | ||
5215 | } | ||
5216 | } | ||
5217 | break; | ||
5218 | case "Name": | ||
5219 | name = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
5220 | break; | ||
5221 | case "Part": | ||
5222 | part = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
5223 | if (!Wix.Environment.TryParsePartType(part, out partType)) | ||
5224 | { | ||
5225 | this.core.OnMessage(WixErrors.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, "Part", part, "all", "first", "last")); | ||
5226 | } | ||
5227 | break; | ||
5228 | case "Permanent": | ||
5229 | permanent = YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
5230 | break; | ||
5231 | case "Separator": | ||
5232 | separator = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
5233 | break; | ||
5234 | case "System": | ||
5235 | system = YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
5236 | break; | ||
5237 | case "Value": | ||
5238 | text = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
5239 | break; | ||
5240 | default: | ||
5241 | this.core.UnexpectedAttribute(node, attrib); | ||
5242 | break; | ||
5243 | } | ||
5244 | } | ||
5245 | else | ||
5246 | { | ||
5247 | this.core.ParseExtensionAttribute(node, attrib); | ||
5248 | } | ||
5249 | } | ||
5250 | |||
5251 | if (null == id) | ||
5252 | { | ||
5253 | id = this.core.CreateIdentifier("env", action, name, part, system.ToString()); | ||
5254 | } | ||
5255 | |||
5256 | if (null == name) | ||
5257 | { | ||
5258 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Name")); | ||
5259 | } | ||
5260 | |||
5261 | if (Wix.Environment.PartType.NotSet != partType) | ||
5262 | { | ||
5263 | if ("+" == action) | ||
5264 | { | ||
5265 | this.core.OnMessage(WixErrors.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Part", "Action", "create")); | ||
5266 | } | ||
5267 | |||
5268 | switch (partType) | ||
5269 | { | ||
5270 | case Wix.Environment.PartType.all: | ||
5271 | break; | ||
5272 | case Wix.Environment.PartType.first: | ||
5273 | text = String.Concat(text, separator, "[~]"); | ||
5274 | break; | ||
5275 | case Wix.Environment.PartType.last: | ||
5276 | text = String.Concat("[~]", separator, text); | ||
5277 | break; | ||
5278 | } | ||
5279 | } | ||
5280 | |||
5281 | if (permanent) | ||
5282 | { | ||
5283 | uninstall = null; | ||
5284 | } | ||
5285 | |||
5286 | this.core.ParseForExtensionElements(node); | ||
5287 | |||
5288 | if (!this.core.EncounteredError) | ||
5289 | { | ||
5290 | Row row = this.core.CreateRow(sourceLineNumbers, "Environment", id); | ||
5291 | row[1] = String.Concat(action, uninstall, system ? "*" : String.Empty, name); | ||
5292 | row[2] = text; | ||
5293 | row[3] = componentId; | ||
5294 | } | ||
5295 | } | ||
5296 | |||
5297 | /// <summary> | ||
5298 | /// Parses an error element. | ||
5299 | /// </summary> | ||
5300 | /// <param name="node">Element to parse.</param> | ||
5301 | private void ParseErrorElement(XElement node) | ||
5302 | { | ||
5303 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
5304 | int id = CompilerConstants.IntegerNotSet; | ||
5305 | |||
5306 | foreach (XAttribute attrib in node.Attributes()) | ||
5307 | { | ||
5308 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
5309 | { | ||
5310 | switch (attrib.Name.LocalName) | ||
5311 | { | ||
5312 | case "Id": | ||
5313 | id = this.core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, short.MaxValue); | ||
5314 | break; | ||
5315 | default: | ||
5316 | this.core.UnexpectedAttribute(node, attrib); | ||
5317 | break; | ||
5318 | } | ||
5319 | } | ||
5320 | else | ||
5321 | { | ||
5322 | this.core.ParseExtensionAttribute(node, attrib); | ||
5323 | } | ||
5324 | } | ||
5325 | |||
5326 | if (CompilerConstants.IntegerNotSet == id) | ||
5327 | { | ||
5328 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
5329 | id = CompilerConstants.IllegalInteger; | ||
5330 | } | ||
5331 | |||
5332 | this.core.ParseForExtensionElements(node); | ||
5333 | |||
5334 | if (!this.core.EncounteredError) | ||
5335 | { | ||
5336 | Row row = this.core.CreateRow(sourceLineNumbers, "Error"); | ||
5337 | row[0] = id; | ||
5338 | row[1] = Common.GetInnerText(node); // TODO: * | ||
5339 | } | ||
5340 | } | ||
5341 | |||
5342 | /// <summary> | ||
5343 | /// Parses an extension element. | ||
5344 | /// </summary> | ||
5345 | /// <param name="node">Element to parse.</param> | ||
5346 | /// <param name="componentId">Identifier of parent component.</param> | ||
5347 | /// <param name="advertise">Flag if this extension is advertised.</param> | ||
5348 | /// <param name="progId">ProgId for extension.</param> | ||
5349 | private void ParseExtensionElement(XElement node, string componentId, YesNoType advertise, string progId) | ||
5350 | { | ||
5351 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
5352 | string extension = null; | ||
5353 | string mime = null; | ||
5354 | |||
5355 | foreach (XAttribute attrib in node.Attributes()) | ||
5356 | { | ||
5357 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
5358 | { | ||
5359 | switch (attrib.Name.LocalName) | ||
5360 | { | ||
5361 | case "Id": | ||
5362 | extension = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
5363 | break; | ||
5364 | case "Advertise": | ||
5365 | YesNoType extensionAdvertise = this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
5366 | if ((YesNoType.No == advertise && YesNoType.Yes == extensionAdvertise) || (YesNoType.Yes == advertise && YesNoType.No == extensionAdvertise)) | ||
5367 | { | ||
5368 | this.core.OnMessage(WixErrors.AdvertiseStateMustMatch(sourceLineNumbers, extensionAdvertise.ToString(), advertise.ToString())); | ||
5369 | } | ||
5370 | advertise = extensionAdvertise; | ||
5371 | break; | ||
5372 | case "ContentType": | ||
5373 | mime = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
5374 | break; | ||
5375 | default: | ||
5376 | this.core.UnexpectedAttribute(node, attrib); | ||
5377 | break; | ||
5378 | } | ||
5379 | } | ||
5380 | else | ||
5381 | { | ||
5382 | Dictionary<string, string> context = new Dictionary<string, string>() { { "ProgId", progId }, { "ComponentId", componentId } }; | ||
5383 | this.core.ParseExtensionAttribute(node, attrib, context); | ||
5384 | } | ||
5385 | } | ||
5386 | |||
5387 | if (YesNoType.NotSet == advertise) | ||
5388 | { | ||
5389 | advertise = YesNoType.No; | ||
5390 | } | ||
5391 | |||
5392 | foreach (XElement child in node.Elements()) | ||
5393 | { | ||
5394 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
5395 | { | ||
5396 | switch (child.Name.LocalName) | ||
5397 | { | ||
5398 | case "Verb": | ||
5399 | this.ParseVerbElement(child, extension, progId, componentId, advertise); | ||
5400 | break; | ||
5401 | case "MIME": | ||
5402 | string newMime = this.ParseMIMEElement(child, extension, componentId, advertise); | ||
5403 | if (null != newMime && null == mime) | ||
5404 | { | ||
5405 | mime = newMime; | ||
5406 | } | ||
5407 | break; | ||
5408 | default: | ||
5409 | this.core.UnexpectedElement(node, child); | ||
5410 | break; | ||
5411 | } | ||
5412 | } | ||
5413 | else | ||
5414 | { | ||
5415 | this.core.ParseExtensionElement(node, child); | ||
5416 | } | ||
5417 | } | ||
5418 | |||
5419 | |||
5420 | if (YesNoType.Yes == advertise) | ||
5421 | { | ||
5422 | if (!this.core.EncounteredError) | ||
5423 | { | ||
5424 | Row row = this.core.CreateRow(sourceLineNumbers, "Extension"); | ||
5425 | row[0] = extension; | ||
5426 | row[1] = componentId; | ||
5427 | row[2] = progId; | ||
5428 | row[3] = mime; | ||
5429 | row[4] = Guid.Empty.ToString("B"); | ||
5430 | |||
5431 | this.core.EnsureTable(sourceLineNumbers, "Verb"); | ||
5432 | } | ||
5433 | } | ||
5434 | else if (YesNoType.No == advertise) | ||
5435 | { | ||
5436 | this.core.CreateRegistryRow(sourceLineNumbers, MsiInterop.MsidbRegistryRootClassesRoot, String.Concat(".", extension), String.Empty, progId, componentId); // Extension | ||
5437 | if (null != mime) | ||
5438 | { | ||
5439 | this.core.CreateRegistryRow(sourceLineNumbers, MsiInterop.MsidbRegistryRootClassesRoot, String.Concat(".", extension), "Content Type", mime, componentId); // Extension's MIME ContentType | ||
5440 | } | ||
5441 | } | ||
5442 | } | ||
5443 | |||
5444 | |||
5445 | /// <summary> | ||
5446 | /// Parses a file element. | ||
5447 | /// </summary> | ||
5448 | /// <param name="node">File element to parse.</param> | ||
5449 | /// <param name="componentId">Parent's component id.</param> | ||
5450 | /// <param name="directoryId">Ancestor's directory id.</param> | ||
5451 | /// <param name="diskId">Disk id inherited from parent component.</param> | ||
5452 | /// <param name="sourcePath">Default source path of parent directory.</param> | ||
5453 | /// <param name="possibleKeyPath">This will be set with the possible keyPath for the parent component.</param> | ||
5454 | /// <param name="win64Component">true if the component is 64-bit.</param> | ||
5455 | /// <returns>Yes if this element was marked as the parent component's key path, No if explicitly marked as not being a key path, or NotSet otherwise.</returns> | ||
5456 | [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1800:DoNotCastUnnecessarily")] | ||
5457 | private YesNoType ParseFileElement(XElement node, string componentId, string directoryId, int diskId, string sourcePath, out string possibleKeyPath, bool win64Component, string componentGuid) | ||
5458 | { | ||
5459 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
5460 | Identifier id = null; | ||
5461 | FileAssemblyType assemblyType = FileAssemblyType.NotAnAssembly; | ||
5462 | string assemblyApplication = null; | ||
5463 | string assemblyManifest = null; | ||
5464 | string bindPath = null; | ||
5465 | int bits = MsiInterop.MsidbFileAttributesVital; // assume all files are vital. | ||
5466 | string companionFile = null; | ||
5467 | string defaultLanguage = null; | ||
5468 | int defaultSize = 0; | ||
5469 | string defaultVersion = null; | ||
5470 | string fontTitle = null; | ||
5471 | bool generatedShortFileName = false; | ||
5472 | YesNoType keyPath = YesNoType.NotSet; | ||
5473 | string name = null; | ||
5474 | int patchGroup = CompilerConstants.IntegerNotSet; | ||
5475 | bool patchIgnore = false; | ||
5476 | bool patchIncludeWholeFile = false; | ||
5477 | bool patchAllowIgnoreOnError = false; | ||
5478 | |||
5479 | string ignoreLengths = null; | ||
5480 | string ignoreOffsets = null; | ||
5481 | string protectLengths = null; | ||
5482 | string protectOffsets = null; | ||
5483 | string symbols = null; | ||
5484 | |||
5485 | string procArch = null; | ||
5486 | int selfRegCost = CompilerConstants.IntegerNotSet; | ||
5487 | string shortName = null; | ||
5488 | string source = sourcePath; // assume we'll use the parents as the source for this file | ||
5489 | bool sourceSet = false; | ||
5490 | |||
5491 | foreach (XAttribute attrib in node.Attributes()) | ||
5492 | { | ||
5493 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
5494 | { | ||
5495 | switch (attrib.Name.LocalName) | ||
5496 | { | ||
5497 | case "Id": | ||
5498 | id = this.core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
5499 | break; | ||
5500 | case "Assembly": | ||
5501 | string assemblyValue = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
5502 | if (0 < assemblyValue.Length) | ||
5503 | { | ||
5504 | Wix.File.AssemblyType parsedAssemblyType = Wix.File.ParseAssemblyType(assemblyValue); | ||
5505 | switch (parsedAssemblyType) | ||
5506 | { | ||
5507 | case Wix.File.AssemblyType.net: | ||
5508 | assemblyType = FileAssemblyType.DotNetAssembly; | ||
5509 | break; | ||
5510 | case Wix.File.AssemblyType.no: | ||
5511 | assemblyType = FileAssemblyType.NotAnAssembly; | ||
5512 | break; | ||
5513 | case Wix.File.AssemblyType.win32: | ||
5514 | assemblyType = FileAssemblyType.Win32Assembly; | ||
5515 | break; | ||
5516 | default: | ||
5517 | this.core.OnMessage(WixErrors.IllegalAttributeValue(sourceLineNumbers, "File", "Assembly", assemblyValue, "no", "win32", ".net")); | ||
5518 | break; | ||
5519 | } | ||
5520 | } | ||
5521 | break; | ||
5522 | case "AssemblyApplication": | ||
5523 | assemblyApplication = this.core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
5524 | this.core.CreateSimpleReference(sourceLineNumbers, "File", assemblyApplication); | ||
5525 | break; | ||
5526 | case "AssemblyManifest": | ||
5527 | assemblyManifest = this.core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
5528 | this.core.CreateSimpleReference(sourceLineNumbers, "File", assemblyManifest); | ||
5529 | break; | ||
5530 | case "BindPath": | ||
5531 | bindPath = this.core.GetAttributeValue(sourceLineNumbers, attrib, EmptyRule.CanBeEmpty); | ||
5532 | break; | ||
5533 | case "Checksum": | ||
5534 | if (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
5535 | { | ||
5536 | bits |= MsiInterop.MsidbFileAttributesChecksum; | ||
5537 | } | ||
5538 | break; | ||
5539 | case "CompanionFile": | ||
5540 | companionFile = this.core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
5541 | this.core.CreateSimpleReference(sourceLineNumbers, "File", companionFile); | ||
5542 | break; | ||
5543 | case "Compressed": | ||
5544 | YesNoDefaultType compressed = this.core.GetAttributeYesNoDefaultValue(sourceLineNumbers, attrib); | ||
5545 | if (YesNoDefaultType.Yes == compressed) | ||
5546 | { | ||
5547 | bits |= MsiInterop.MsidbFileAttributesCompressed; | ||
5548 | } | ||
5549 | else if (YesNoDefaultType.No == compressed) | ||
5550 | { | ||
5551 | bits |= MsiInterop.MsidbFileAttributesNoncompressed; | ||
5552 | } | ||
5553 | break; | ||
5554 | case "DefaultLanguage": | ||
5555 | defaultLanguage = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
5556 | break; | ||
5557 | case "DefaultSize": | ||
5558 | defaultSize = this.core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, int.MaxValue); | ||
5559 | break; | ||
5560 | case "DefaultVersion": | ||
5561 | defaultVersion = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
5562 | break; | ||
5563 | case "DiskId": | ||
5564 | diskId = this.core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 1, short.MaxValue); | ||
5565 | break; | ||
5566 | case "FontTitle": | ||
5567 | fontTitle = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
5568 | break; | ||
5569 | case "Hidden": | ||
5570 | if (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
5571 | { | ||
5572 | bits |= MsiInterop.MsidbFileAttributesHidden; | ||
5573 | } | ||
5574 | break; | ||
5575 | case "KeyPath": | ||
5576 | keyPath = this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
5577 | break; | ||
5578 | case "Name": | ||
5579 | name = this.core.GetAttributeLongFilename(sourceLineNumbers, attrib, false); | ||
5580 | break; | ||
5581 | case "PatchGroup": | ||
5582 | patchGroup = this.core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 1, int.MaxValue); | ||
5583 | break; | ||
5584 | case "PatchIgnore": | ||
5585 | patchIgnore = YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
5586 | break; | ||
5587 | case "PatchWholeFile": | ||
5588 | patchIncludeWholeFile = YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
5589 | break; | ||
5590 | case "PatchAllowIgnoreOnError": | ||
5591 | patchAllowIgnoreOnError = YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
5592 | break; | ||
5593 | case "ProcessorArchitecture": | ||
5594 | string procArchValue = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
5595 | if (0 < procArchValue.Length) | ||
5596 | { | ||
5597 | Wix.File.ProcessorArchitectureType procArchType = Wix.File.ParseProcessorArchitectureType(procArchValue); | ||
5598 | switch (procArchType) | ||
5599 | { | ||
5600 | case Wix.File.ProcessorArchitectureType.msil: | ||
5601 | procArch = "MSIL"; | ||
5602 | break; | ||
5603 | case Wix.File.ProcessorArchitectureType.x86: | ||
5604 | procArch = "x86"; | ||
5605 | break; | ||
5606 | case Wix.File.ProcessorArchitectureType.x64: | ||
5607 | procArch = "amd64"; | ||
5608 | break; | ||
5609 | case Wix.File.ProcessorArchitectureType.ia64: | ||
5610 | procArch = "ia64"; | ||
5611 | break; | ||
5612 | default: | ||
5613 | this.core.OnMessage(WixErrors.IllegalAttributeValue(sourceLineNumbers, "File", "ProcessorArchitecture", procArchValue, "msil", "x86", "x64", "ia64")); | ||
5614 | break; | ||
5615 | } | ||
5616 | } | ||
5617 | break; | ||
5618 | case "ReadOnly": | ||
5619 | if (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
5620 | { | ||
5621 | bits |= MsiInterop.MsidbFileAttributesReadOnly; | ||
5622 | } | ||
5623 | break; | ||
5624 | case "SelfRegCost": | ||
5625 | selfRegCost = this.core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, short.MaxValue); | ||
5626 | break; | ||
5627 | case "ShortName": | ||
5628 | shortName = this.core.GetAttributeShortFilename(sourceLineNumbers, attrib, false); | ||
5629 | break; | ||
5630 | case "Source": | ||
5631 | source = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
5632 | sourceSet = true; | ||
5633 | break; | ||
5634 | case "System": | ||
5635 | if (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
5636 | { | ||
5637 | bits |= MsiInterop.MsidbFileAttributesSystem; | ||
5638 | } | ||
5639 | break; | ||
5640 | case "TrueType": | ||
5641 | if (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
5642 | { | ||
5643 | fontTitle = String.Empty; | ||
5644 | } | ||
5645 | break; | ||
5646 | case "Vital": | ||
5647 | YesNoType isVital = this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
5648 | if (YesNoType.Yes == isVital) | ||
5649 | { | ||
5650 | bits |= MsiInterop.MsidbFileAttributesVital; | ||
5651 | } | ||
5652 | else if (YesNoType.No == isVital) | ||
5653 | { | ||
5654 | bits &= ~MsiInterop.MsidbFileAttributesVital; | ||
5655 | } | ||
5656 | break; | ||
5657 | default: | ||
5658 | this.core.UnexpectedAttribute(node, attrib); | ||
5659 | break; | ||
5660 | } | ||
5661 | } | ||
5662 | else | ||
5663 | { | ||
5664 | this.core.ParseExtensionAttribute(node, attrib); | ||
5665 | } | ||
5666 | } | ||
5667 | |||
5668 | if (null != companionFile) | ||
5669 | { | ||
5670 | // the companion file cannot be the key path of a component | ||
5671 | if (YesNoType.Yes == keyPath) | ||
5672 | { | ||
5673 | this.core.OnMessage(WixErrors.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "CompanionFile", "KeyPath", "yes")); | ||
5674 | } | ||
5675 | } | ||
5676 | |||
5677 | if (sourceSet && !source.EndsWith(Path.DirectorySeparatorChar.ToString(), StringComparison.Ordinal) && null == name) | ||
5678 | { | ||
5679 | name = Path.GetFileName(source); | ||
5680 | if (!this.core.IsValidLongFilename(name, false)) | ||
5681 | { | ||
5682 | this.core.OnMessage(WixErrors.IllegalLongFilename(sourceLineNumbers, node.Name.LocalName, "Source", name)); | ||
5683 | } | ||
5684 | } | ||
5685 | |||
5686 | // generate a short file name | ||
5687 | if (null == shortName && (null != name && !this.core.IsValidShortFilename(name, false))) | ||
5688 | { | ||
5689 | shortName = this.core.CreateShortName(name, true, false, node.Name.LocalName, directoryId); | ||
5690 | generatedShortFileName = true; | ||
5691 | } | ||
5692 | |||
5693 | if (null == id) | ||
5694 | { | ||
5695 | id = this.core.CreateIdentifier("fil", directoryId, name ?? shortName); | ||
5696 | } | ||
5697 | |||
5698 | if (!this.compilingModule && CompilerConstants.IntegerNotSet == diskId) | ||
5699 | { | ||
5700 | diskId = 1; // default to first Media | ||
5701 | } | ||
5702 | |||
5703 | if (null != defaultVersion && null != companionFile) | ||
5704 | { | ||
5705 | this.core.OnMessage(WixErrors.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "DefaultVersion", "CompanionFile", companionFile)); | ||
5706 | } | ||
5707 | |||
5708 | if (FileAssemblyType.NotAnAssembly == assemblyType) | ||
5709 | { | ||
5710 | if (null != assemblyManifest) | ||
5711 | { | ||
5712 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Assembly", "AssemblyManifest")); | ||
5713 | } | ||
5714 | |||
5715 | if (null != assemblyApplication) | ||
5716 | { | ||
5717 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Assembly", "AssemblyApplication")); | ||
5718 | } | ||
5719 | } | ||
5720 | else | ||
5721 | { | ||
5722 | if (FileAssemblyType.Win32Assembly == assemblyType && null == assemblyManifest) | ||
5723 | { | ||
5724 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "AssemblyManifest", "Assembly", "win32")); | ||
5725 | } | ||
5726 | |||
5727 | // allow "*" guid components to omit explicit KeyPath as they can have only one file and therefore this file is the keypath | ||
5728 | if (YesNoType.Yes != keyPath && "*" != componentGuid) | ||
5729 | { | ||
5730 | this.core.OnMessage(WixErrors.IllegalAttributeValueWithoutOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Assembly", (FileAssemblyType.DotNetAssembly == assemblyType ? ".net" : "win32"), "KeyPath", "yes")); | ||
5731 | } | ||
5732 | } | ||
5733 | |||
5734 | foreach (XElement child in node.Elements()) | ||
5735 | { | ||
5736 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
5737 | { | ||
5738 | switch (child.Name.LocalName) | ||
5739 | { | ||
5740 | case "AppId": | ||
5741 | this.ParseAppIdElement(child, componentId, YesNoType.NotSet, id.Id, null, null); | ||
5742 | break; | ||
5743 | case "AssemblyName": | ||
5744 | this.ParseAssemblyName(child, componentId); | ||
5745 | break; | ||
5746 | case "Class": | ||
5747 | this.ParseClassElement(child, componentId, YesNoType.NotSet, id.Id, null, null, null); | ||
5748 | break; | ||
5749 | case "CopyFile": | ||
5750 | this.ParseCopyFileElement(child, componentId, id.Id); | ||
5751 | break; | ||
5752 | case "IgnoreRange": | ||
5753 | this.ParseRangeElement(child, ref ignoreOffsets, ref ignoreLengths); | ||
5754 | break; | ||
5755 | case "ODBCDriver": | ||
5756 | this.ParseODBCDriverOrTranslator(child, componentId, id.Id, this.tableDefinitions["ODBCDriver"]); | ||
5757 | break; | ||
5758 | case "ODBCTranslator": | ||
5759 | this.ParseODBCDriverOrTranslator(child, componentId, id.Id, this.tableDefinitions["ODBCTranslator"]); | ||
5760 | break; | ||
5761 | case "Permission": | ||
5762 | this.ParsePermissionElement(child, id.Id, "File"); | ||
5763 | break; | ||
5764 | case "PermissionEx": | ||
5765 | this.ParsePermissionExElement(child, id.Id, "File"); | ||
5766 | break; | ||
5767 | case "ProtectRange": | ||
5768 | this.ParseRangeElement(child, ref protectOffsets, ref protectLengths); | ||
5769 | break; | ||
5770 | case "Shortcut": | ||
5771 | this.ParseShortcutElement(child, componentId, node.Name.LocalName, id.Id, keyPath); | ||
5772 | break; | ||
5773 | case "SymbolPath": | ||
5774 | if (null != symbols) | ||
5775 | { | ||
5776 | symbols += ";" + this.ParseSymbolPathElement(child); | ||
5777 | } | ||
5778 | else | ||
5779 | { | ||
5780 | symbols = this.ParseSymbolPathElement(child); | ||
5781 | } | ||
5782 | break; | ||
5783 | case "TypeLib": | ||
5784 | this.ParseTypeLibElement(child, componentId, id.Id, win64Component); | ||
5785 | break; | ||
5786 | default: | ||
5787 | this.core.UnexpectedElement(node, child); | ||
5788 | break; | ||
5789 | } | ||
5790 | } | ||
5791 | else | ||
5792 | { | ||
5793 | Dictionary<string, string> context = new Dictionary<string, string>() { { "FileId", id.Id }, { "ComponentId", componentId }, { "Win64", win64Component.ToString() } }; | ||
5794 | this.core.ParseExtensionElement(node, child, context); | ||
5795 | } | ||
5796 | } | ||
5797 | |||
5798 | |||
5799 | if (!this.core.EncounteredError) | ||
5800 | { | ||
5801 | PatchAttributeType patchAttributes = PatchAttributeType.None; | ||
5802 | if (patchIgnore) | ||
5803 | { | ||
5804 | patchAttributes |= PatchAttributeType.Ignore; | ||
5805 | } | ||
5806 | if (patchIncludeWholeFile) | ||
5807 | { | ||
5808 | patchAttributes |= PatchAttributeType.IncludeWholeFile; | ||
5809 | } | ||
5810 | if (patchAllowIgnoreOnError) | ||
5811 | { | ||
5812 | patchAttributes |= PatchAttributeType.AllowIgnoreOnError; | ||
5813 | } | ||
5814 | |||
5815 | if (String.IsNullOrEmpty(source)) | ||
5816 | { | ||
5817 | if (!this.useShortFileNames && null != name) | ||
5818 | { | ||
5819 | source = name; | ||
5820 | } | ||
5821 | else | ||
5822 | { | ||
5823 | source = shortName; | ||
5824 | } | ||
5825 | } | ||
5826 | else if (source.EndsWith(Path.DirectorySeparatorChar.ToString(), StringComparison.Ordinal)) // if source relies on parent directories, append the file name | ||
5827 | { | ||
5828 | if (!this.useShortFileNames && null != name) | ||
5829 | { | ||
5830 | source = Path.Combine(source, name); | ||
5831 | } | ||
5832 | else | ||
5833 | { | ||
5834 | source = Path.Combine(source, shortName); | ||
5835 | } | ||
5836 | } | ||
5837 | |||
5838 | FileRow fileRow = (FileRow)this.core.CreateRow(sourceLineNumbers, "File", id); | ||
5839 | fileRow[1] = componentId; | ||
5840 | fileRow[2] = GetMsiFilenameValue(shortName, name); | ||
5841 | fileRow[3] = defaultSize; | ||
5842 | if (null != companionFile) | ||
5843 | { | ||
5844 | fileRow[4] = companionFile; | ||
5845 | } | ||
5846 | else if (null != defaultVersion) | ||
5847 | { | ||
5848 | fileRow[4] = defaultVersion; | ||
5849 | } | ||
5850 | fileRow[5] = defaultLanguage; | ||
5851 | fileRow[6] = bits; | ||
5852 | |||
5853 | // the Sequence row is set in the binder | ||
5854 | |||
5855 | WixFileRow wixFileRow = (WixFileRow)this.core.CreateRow(sourceLineNumbers, "WixFile", id); | ||
5856 | wixFileRow.AssemblyType = assemblyType; | ||
5857 | wixFileRow.AssemblyManifest = assemblyManifest; | ||
5858 | wixFileRow.AssemblyApplication = assemblyApplication; | ||
5859 | wixFileRow.Directory = directoryId; | ||
5860 | wixFileRow.DiskId = (CompilerConstants.IntegerNotSet == diskId) ? 0 : diskId; | ||
5861 | wixFileRow.Source = source; | ||
5862 | wixFileRow.ProcessorArchitecture = procArch; | ||
5863 | wixFileRow.PatchGroup = (CompilerConstants.IntegerNotSet != patchGroup ? patchGroup : -1); | ||
5864 | wixFileRow.Attributes = (generatedShortFileName ? 0x1 : 0x0); | ||
5865 | wixFileRow.PatchAttributes = patchAttributes; | ||
5866 | |||
5867 | // Always create a delta patch row for this file since other elements (like Component and Media) may | ||
5868 | // want to add symbol paths to it. | ||
5869 | WixDeltaPatchFileRow deltaPatchFileRow = (WixDeltaPatchFileRow)this.core.CreateRow(sourceLineNumbers, "WixDeltaPatchFile", id); | ||
5870 | deltaPatchFileRow.RetainLengths = protectLengths; | ||
5871 | deltaPatchFileRow.IgnoreOffsets = ignoreOffsets; | ||
5872 | deltaPatchFileRow.IgnoreLengths = ignoreLengths; | ||
5873 | deltaPatchFileRow.RetainOffsets = protectOffsets; | ||
5874 | |||
5875 | if (null != symbols) | ||
5876 | { | ||
5877 | WixDeltaPatchSymbolPathsRow symbolRow = (WixDeltaPatchSymbolPathsRow)this.core.CreateRow(sourceLineNumbers, "WixDeltaPatchSymbolPaths", id); | ||
5878 | symbolRow.Type = SymbolPathType.File; | ||
5879 | symbolRow.SymbolPaths = symbols; | ||
5880 | } | ||
5881 | |||
5882 | if (FileAssemblyType.NotAnAssembly != assemblyType) | ||
5883 | { | ||
5884 | Row row = this.core.CreateRow(sourceLineNumbers, "MsiAssembly"); | ||
5885 | row[0] = componentId; | ||
5886 | row[1] = Guid.Empty.ToString("B"); | ||
5887 | row[2] = assemblyManifest; | ||
5888 | row[3] = assemblyApplication; | ||
5889 | row[4] = (FileAssemblyType.DotNetAssembly == assemblyType) ? 0 : 1; | ||
5890 | } | ||
5891 | |||
5892 | if (null != bindPath) | ||
5893 | { | ||
5894 | Row row = this.core.CreateRow(sourceLineNumbers, "BindImage"); | ||
5895 | row[0] = id.Id; | ||
5896 | row[1] = bindPath; | ||
5897 | |||
5898 | // TODO: technically speaking each of the properties in the "bindPath" should be added as references, but how much do we really care about BindImage? | ||
5899 | } | ||
5900 | |||
5901 | if (CompilerConstants.IntegerNotSet != selfRegCost) | ||
5902 | { | ||
5903 | Row row = this.core.CreateRow(sourceLineNumbers, "SelfReg"); | ||
5904 | row[0] = id.Id; | ||
5905 | row[1] = selfRegCost; | ||
5906 | } | ||
5907 | |||
5908 | if (null != fontTitle) | ||
5909 | { | ||
5910 | Row row = this.core.CreateRow(sourceLineNumbers, "Font"); | ||
5911 | row[0] = id.Id; | ||
5912 | row[1] = fontTitle; | ||
5913 | } | ||
5914 | } | ||
5915 | |||
5916 | this.core.CreateSimpleReference(sourceLineNumbers, "Media", diskId.ToString(CultureInfo.InvariantCulture.NumberFormat)); | ||
5917 | |||
5918 | // If this component does not have a companion file this file is a possible keypath. | ||
5919 | possibleKeyPath = null; | ||
5920 | if (null == companionFile) | ||
5921 | { | ||
5922 | possibleKeyPath = id.Id; | ||
5923 | } | ||
5924 | |||
5925 | return keyPath; | ||
5926 | } | ||
5927 | |||
5928 | /// <summary> | ||
5929 | /// Parses a file search element. | ||
5930 | /// </summary> | ||
5931 | /// <param name="node">Element to parse.</param> | ||
5932 | /// <param name="parentSignature">Signature of parent search element.</param> | ||
5933 | /// <param name="parentDirectorySearch">Whether this search element is used to search for the parent directory.</param> | ||
5934 | /// <param name="parentDepth">The depth specified by the parent search element.</param> | ||
5935 | /// <returns>Signature of search element.</returns> | ||
5936 | private string ParseFileSearchElement(XElement node, string parentSignature, bool parentDirectorySearch, int parentDepth) | ||
5937 | { | ||
5938 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
5939 | Identifier id = null; | ||
5940 | string languages = null; | ||
5941 | int minDate = CompilerConstants.IntegerNotSet; | ||
5942 | int maxDate = CompilerConstants.IntegerNotSet; | ||
5943 | int maxSize = CompilerConstants.IntegerNotSet; | ||
5944 | int minSize = CompilerConstants.IntegerNotSet; | ||
5945 | string maxVersion = null; | ||
5946 | string minVersion = null; | ||
5947 | string name = null; | ||
5948 | string shortName = null; | ||
5949 | |||
5950 | foreach (XAttribute attrib in node.Attributes()) | ||
5951 | { | ||
5952 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
5953 | { | ||
5954 | switch (attrib.Name.LocalName) | ||
5955 | { | ||
5956 | case "Id": | ||
5957 | id = this.core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
5958 | break; | ||
5959 | case "Name": | ||
5960 | name = this.core.GetAttributeLongFilename(sourceLineNumbers, attrib, false); | ||
5961 | break; | ||
5962 | case "MinVersion": | ||
5963 | minVersion = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
5964 | break; | ||
5965 | case "MaxVersion": | ||
5966 | maxVersion = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
5967 | break; | ||
5968 | case "MinSize": | ||
5969 | minSize = this.core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, int.MaxValue); | ||
5970 | break; | ||
5971 | case "MaxSize": | ||
5972 | maxSize = this.core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, int.MaxValue); | ||
5973 | break; | ||
5974 | case "MinDate": | ||
5975 | minDate = this.core.GetAttributeDateTimeValue(sourceLineNumbers, attrib); | ||
5976 | break; | ||
5977 | case "MaxDate": | ||
5978 | maxDate = this.core.GetAttributeDateTimeValue(sourceLineNumbers, attrib); | ||
5979 | break; | ||
5980 | case "Languages": | ||
5981 | languages = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
5982 | break; | ||
5983 | case "ShortName": | ||
5984 | shortName = this.core.GetAttributeShortFilename(sourceLineNumbers, attrib, false); | ||
5985 | break; | ||
5986 | default: | ||
5987 | this.core.UnexpectedAttribute(node, attrib); | ||
5988 | break; | ||
5989 | } | ||
5990 | } | ||
5991 | else | ||
5992 | { | ||
5993 | this.core.ParseExtensionAttribute(node, attrib); | ||
5994 | } | ||
5995 | } | ||
5996 | |||
5997 | // Using both ShortName and Name will not always work due to a Windows Installer bug. | ||
5998 | if (null != shortName && null != name) | ||
5999 | { | ||
6000 | this.core.OnMessage(WixWarnings.FileSearchFileNameIssue(sourceLineNumbers, node.Name.LocalName, "ShortName", "Name")); | ||
6001 | } | ||
6002 | else if (null == shortName && null == name) // at least one name must be specified. | ||
6003 | { | ||
6004 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Name")); | ||
6005 | } | ||
6006 | |||
6007 | if (this.core.IsValidShortFilename(name, false)) | ||
6008 | { | ||
6009 | if (null == shortName) | ||
6010 | { | ||
6011 | shortName = name; | ||
6012 | name = null; | ||
6013 | } | ||
6014 | else | ||
6015 | { | ||
6016 | this.core.OnMessage(WixErrors.IllegalAttributeValueWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Name", name, "ShortName")); | ||
6017 | } | ||
6018 | } | ||
6019 | |||
6020 | if (null == id) | ||
6021 | { | ||
6022 | if (String.IsNullOrEmpty(parentSignature)) | ||
6023 | { | ||
6024 | id = this.core.CreateIdentifier("fs", name ?? shortName); | ||
6025 | } | ||
6026 | else // reuse parent signature in the Signature table | ||
6027 | { | ||
6028 | id = new Identifier(parentSignature, AccessModifier.Private); | ||
6029 | } | ||
6030 | } | ||
6031 | |||
6032 | bool isSameId = String.Equals(id.Id, parentSignature, StringComparison.Ordinal); | ||
6033 | if (parentDirectorySearch) | ||
6034 | { | ||
6035 | // If searching for the parent directory, the Id attribute | ||
6036 | // value must be specified and unique. | ||
6037 | if (isSameId) | ||
6038 | { | ||
6039 | this.core.OnMessage(WixErrors.UniqueFileSearchIdRequired(sourceLineNumbers, parentSignature, node.Name.LocalName)); | ||
6040 | } | ||
6041 | } | ||
6042 | else if (parentDepth > 1) | ||
6043 | { | ||
6044 | // Otherwise, if the depth > 1 the Id must be absent or the same | ||
6045 | // as the parent DirectorySearch if AssignToProperty is not set. | ||
6046 | if (!isSameId) | ||
6047 | { | ||
6048 | this.core.OnMessage(WixErrors.IllegalSearchIdForParentDepth(sourceLineNumbers, id.Id, parentSignature)); | ||
6049 | } | ||
6050 | } | ||
6051 | |||
6052 | this.core.ParseForExtensionElements(node); | ||
6053 | |||
6054 | if (!this.core.EncounteredError) | ||
6055 | { | ||
6056 | Row row = this.core.CreateRow(sourceLineNumbers, "Signature", id); | ||
6057 | row[1] = name ?? shortName; | ||
6058 | row[2] = minVersion; | ||
6059 | row[3] = maxVersion; | ||
6060 | |||
6061 | if (CompilerConstants.IntegerNotSet != minSize) | ||
6062 | { | ||
6063 | row[4] = minSize; | ||
6064 | } | ||
6065 | if (CompilerConstants.IntegerNotSet != maxSize) | ||
6066 | { | ||
6067 | row[5] = maxSize; | ||
6068 | } | ||
6069 | if (CompilerConstants.IntegerNotSet != minDate) | ||
6070 | { | ||
6071 | row[6] = minDate; | ||
6072 | } | ||
6073 | if (CompilerConstants.IntegerNotSet != maxDate) | ||
6074 | { | ||
6075 | row[7] = maxDate; | ||
6076 | } | ||
6077 | row[8] = languages; | ||
6078 | |||
6079 | // Create a DrLocator row to associate the file with a directory | ||
6080 | // when a different identifier is specified for the FileSearch. | ||
6081 | if (!isSameId) | ||
6082 | { | ||
6083 | if (parentDirectorySearch) | ||
6084 | { | ||
6085 | // Creates the DrLocator row for the directory search while | ||
6086 | // the parent DirectorySearch creates the file locator row. | ||
6087 | row = this.core.CreateRow(sourceLineNumbers, "DrLocator"); | ||
6088 | row[0] = parentSignature; | ||
6089 | row[1] = id; | ||
6090 | } | ||
6091 | else | ||
6092 | { | ||
6093 | row = this.core.CreateRow(sourceLineNumbers, "DrLocator", id); | ||
6094 | row[1] = parentSignature; | ||
6095 | } | ||
6096 | } | ||
6097 | } | ||
6098 | |||
6099 | return id.Id; // the id of the FileSearch element is its signature | ||
6100 | } | ||
6101 | |||
6102 | |||
6103 | /// <summary> | ||
6104 | /// Parses a fragment element. | ||
6105 | /// </summary> | ||
6106 | /// <param name="node">Element to parse.</param> | ||
6107 | private void ParseFragmentElement(XElement node) | ||
6108 | { | ||
6109 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
6110 | string id = null; | ||
6111 | |||
6112 | this.activeName = null; | ||
6113 | this.activeLanguage = null; | ||
6114 | |||
6115 | foreach (XAttribute attrib in node.Attributes()) | ||
6116 | { | ||
6117 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
6118 | { | ||
6119 | switch (attrib.Name.LocalName) | ||
6120 | { | ||
6121 | case "Id": | ||
6122 | id = this.core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
6123 | break; | ||
6124 | default: | ||
6125 | this.core.UnexpectedAttribute(node, attrib); | ||
6126 | break; | ||
6127 | } | ||
6128 | } | ||
6129 | else | ||
6130 | { | ||
6131 | this.core.ParseExtensionAttribute(node, attrib); | ||
6132 | } | ||
6133 | } | ||
6134 | |||
6135 | // NOTE: Id is not required for Fragments, this is a departure from the normal run of the mill processing. | ||
6136 | |||
6137 | this.core.CreateActiveSection(id, SectionType.Fragment, 0); | ||
6138 | |||
6139 | int featureDisplay = 0; | ||
6140 | foreach (XElement child in node.Elements()) | ||
6141 | { | ||
6142 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
6143 | { | ||
6144 | switch (child.Name.LocalName) | ||
6145 | { | ||
6146 | case "_locDefinition": | ||
6147 | break; | ||
6148 | case "AdminExecuteSequence": | ||
6149 | this.ParseSequenceElement(child, child.Name.LocalName); | ||
6150 | break; | ||
6151 | case "AdminUISequence": | ||
6152 | this.ParseSequenceElement(child, child.Name.LocalName); | ||
6153 | break; | ||
6154 | case "AdvertiseExecuteSequence": | ||
6155 | this.ParseSequenceElement(child, child.Name.LocalName); | ||
6156 | break; | ||
6157 | case "InstallExecuteSequence": | ||
6158 | this.ParseSequenceElement(child, child.Name.LocalName); | ||
6159 | break; | ||
6160 | case "InstallUISequence": | ||
6161 | this.ParseSequenceElement(child, child.Name.LocalName); | ||
6162 | break; | ||
6163 | case "AppId": | ||
6164 | this.ParseAppIdElement(child, null, YesNoType.Yes, null, null, null); | ||
6165 | break; | ||
6166 | case "Binary": | ||
6167 | this.ParseBinaryElement(child); | ||
6168 | break; | ||
6169 | case "BootstrapperApplication": | ||
6170 | this.ParseBootstrapperApplicationElement(child); | ||
6171 | break; | ||
6172 | case "BootstrapperApplicationRef": | ||
6173 | this.ParseBootstrapperApplicationRefElement(child); | ||
6174 | break; | ||
6175 | case "ComplianceCheck": | ||
6176 | this.ParseComplianceCheckElement(child); | ||
6177 | break; | ||
6178 | case "Component": | ||
6179 | this.ParseComponentElement(child, ComplexReferenceParentType.Unknown, null, null, CompilerConstants.IntegerNotSet, null, null); | ||
6180 | break; | ||
6181 | case "ComponentGroup": | ||
6182 | this.ParseComponentGroupElement(child, ComplexReferenceParentType.Unknown, id); | ||
6183 | break; | ||
6184 | case "Condition": | ||
6185 | this.ParseConditionElement(child, node.Name.LocalName, null, null); | ||
6186 | break; | ||
6187 | case "Container": | ||
6188 | this.ParseContainerElement(child); | ||
6189 | break; | ||
6190 | case "CustomAction": | ||
6191 | this.ParseCustomActionElement(child); | ||
6192 | break; | ||
6193 | case "CustomActionRef": | ||
6194 | this.ParseSimpleRefElement(child, "CustomAction"); | ||
6195 | break; | ||
6196 | case "CustomTable": | ||
6197 | this.ParseCustomTableElement(child); | ||
6198 | break; | ||
6199 | case "Directory": | ||
6200 | this.ParseDirectoryElement(child, null, CompilerConstants.IntegerNotSet, String.Empty); | ||
6201 | break; | ||
6202 | case "DirectoryRef": | ||
6203 | this.ParseDirectoryRefElement(child); | ||
6204 | break; | ||
6205 | case "EmbeddedChainer": | ||
6206 | this.ParseEmbeddedChainerElement(child); | ||
6207 | break; | ||
6208 | case "EmbeddedChainerRef": | ||
6209 | this.ParseSimpleRefElement(child, "MsiEmbeddedChainer"); | ||
6210 | break; | ||
6211 | case "EnsureTable": | ||
6212 | this.ParseEnsureTableElement(child); | ||
6213 | break; | ||
6214 | case "Feature": | ||
6215 | this.ParseFeatureElement(child, ComplexReferenceParentType.Unknown, null, ref featureDisplay); | ||
6216 | break; | ||
6217 | case "FeatureGroup": | ||
6218 | this.ParseFeatureGroupElement(child, ComplexReferenceParentType.Unknown, id); | ||
6219 | break; | ||
6220 | case "FeatureRef": | ||
6221 | this.ParseFeatureRefElement(child, ComplexReferenceParentType.Unknown, null); | ||
6222 | break; | ||
6223 | case "Icon": | ||
6224 | this.ParseIconElement(child); | ||
6225 | break; | ||
6226 | case "IgnoreModularization": | ||
6227 | this.ParseIgnoreModularizationElement(child); | ||
6228 | break; | ||
6229 | case "Media": | ||
6230 | this.ParseMediaElement(child, null); | ||
6231 | break; | ||
6232 | case "MediaTemplate": | ||
6233 | this.ParseMediaTemplateElement(child, null); | ||
6234 | break; | ||
6235 | case "PackageGroup": | ||
6236 | this.ParsePackageGroupElement(child); | ||
6237 | break; | ||
6238 | case "PackageCertificates": | ||
6239 | case "PatchCertificates": | ||
6240 | this.ParseCertificatesElement(child); | ||
6241 | break; | ||
6242 | case "PatchFamily": | ||
6243 | this.ParsePatchFamilyElement(child, ComplexReferenceParentType.Unknown, id); | ||
6244 | break; | ||
6245 | case "PatchFamilyGroup": | ||
6246 | this.ParsePatchFamilyGroupElement(child, ComplexReferenceParentType.Unknown, id); | ||
6247 | break; | ||
6248 | case "PatchFamilyGroupRef": | ||
6249 | this.ParsePatchFamilyGroupRefElement(child, ComplexReferenceParentType.Unknown, id); | ||
6250 | break; | ||
6251 | case "PayloadGroup": | ||
6252 | this.ParsePayloadGroupElement(child, ComplexReferenceParentType.Unknown, null); | ||
6253 | break; | ||
6254 | case "Property": | ||
6255 | this.ParsePropertyElement(child); | ||
6256 | break; | ||
6257 | case "PropertyRef": | ||
6258 | this.ParseSimpleRefElement(child, "Property"); | ||
6259 | break; | ||
6260 | case "RelatedBundle": | ||
6261 | this.ParseRelatedBundleElement(child); | ||
6262 | break; | ||
6263 | case "SetDirectory": | ||
6264 | this.ParseSetDirectoryElement(child); | ||
6265 | break; | ||
6266 | case "SetProperty": | ||
6267 | this.ParseSetPropertyElement(child); | ||
6268 | break; | ||
6269 | case "SFPCatalog": | ||
6270 | string parentName = null; | ||
6271 | this.ParseSFPCatalogElement(child, ref parentName); | ||
6272 | break; | ||
6273 | case "UI": | ||
6274 | this.ParseUIElement(child); | ||
6275 | break; | ||
6276 | case "UIRef": | ||
6277 | this.ParseSimpleRefElement(child, "WixUI"); | ||
6278 | break; | ||
6279 | case "Upgrade": | ||
6280 | this.ParseUpgradeElement(child); | ||
6281 | break; | ||
6282 | case "Variable": | ||
6283 | this.ParseVariableElement(child); | ||
6284 | break; | ||
6285 | case "WixVariable": | ||
6286 | this.ParseWixVariableElement(child); | ||
6287 | break; | ||
6288 | default: | ||
6289 | this.core.UnexpectedElement(node, child); | ||
6290 | break; | ||
6291 | } | ||
6292 | } | ||
6293 | else | ||
6294 | { | ||
6295 | this.core.ParseExtensionElement(node, child); | ||
6296 | } | ||
6297 | } | ||
6298 | |||
6299 | if (!this.core.EncounteredError && null != id) | ||
6300 | { | ||
6301 | Row row = this.core.CreateRow(sourceLineNumbers, "WixFragment"); | ||
6302 | row[0] = id; | ||
6303 | } | ||
6304 | } | ||
6305 | |||
6306 | |||
6307 | /// <summary> | ||
6308 | /// Parses a condition element. | ||
6309 | /// </summary> | ||
6310 | /// <param name="node">Element to parse.</param> | ||
6311 | /// <param name="parentElementLocalName">LocalName of the parent element.</param> | ||
6312 | /// <param name="id">Id of the parent element.</param> | ||
6313 | /// <param name="dialog">Dialog of the parent element if its a Control.</param> | ||
6314 | /// <returns>The condition if one was found.</returns> | ||
6315 | private string ParseConditionElement(XElement node, string parentElementLocalName, string id, string dialog) | ||
6316 | { | ||
6317 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
6318 | string action = null; | ||
6319 | string condition = null; | ||
6320 | int level = CompilerConstants.IntegerNotSet; | ||
6321 | string message = null; | ||
6322 | |||
6323 | foreach (XAttribute attrib in node.Attributes()) | ||
6324 | { | ||
6325 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
6326 | { | ||
6327 | switch (attrib.Name.LocalName) | ||
6328 | { | ||
6329 | case "Action": | ||
6330 | if ("Control" == parentElementLocalName) | ||
6331 | { | ||
6332 | action = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
6333 | if (0 < action.Length) | ||
6334 | { | ||
6335 | Wix.Condition.ActionType actionType; | ||
6336 | if (Wix.Condition.TryParseActionType(action, out actionType)) | ||
6337 | { | ||
6338 | action = Compiler.UppercaseFirstChar(action); | ||
6339 | } | ||
6340 | else | ||
6341 | { | ||
6342 | this.core.OnMessage(WixErrors.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, action, "default", "disable", "enable", "hide", "show")); | ||
6343 | } | ||
6344 | } | ||
6345 | } | ||
6346 | else | ||
6347 | { | ||
6348 | this.core.UnexpectedAttribute(node, attrib); | ||
6349 | } | ||
6350 | break; | ||
6351 | case "Level": | ||
6352 | if ("Feature" == parentElementLocalName) | ||
6353 | { | ||
6354 | level = this.core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, short.MaxValue); | ||
6355 | } | ||
6356 | else | ||
6357 | { | ||
6358 | this.core.UnexpectedAttribute(node, attrib); | ||
6359 | } | ||
6360 | break; | ||
6361 | case "Message": | ||
6362 | if ("Fragment" == parentElementLocalName || "Product" == parentElementLocalName) | ||
6363 | { | ||
6364 | message = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
6365 | } | ||
6366 | else | ||
6367 | { | ||
6368 | this.core.UnexpectedAttribute(node, attrib); | ||
6369 | } | ||
6370 | break; | ||
6371 | default: | ||
6372 | this.core.UnexpectedAttribute(node, attrib); | ||
6373 | break; | ||
6374 | } | ||
6375 | } | ||
6376 | else | ||
6377 | { | ||
6378 | this.core.ParseExtensionAttribute(node, attrib); | ||
6379 | } | ||
6380 | } | ||
6381 | |||
6382 | // get the condition from the inner text of the element | ||
6383 | condition = this.core.GetConditionInnerText(node); | ||
6384 | |||
6385 | this.core.ParseForExtensionElements(node); | ||
6386 | |||
6387 | // the condition should not be empty | ||
6388 | if (null == condition || 0 == condition.Length) | ||
6389 | { | ||
6390 | condition = null; | ||
6391 | this.core.OnMessage(WixErrors.ConditionExpected(sourceLineNumbers, node.Name.LocalName)); | ||
6392 | } | ||
6393 | |||
6394 | switch (parentElementLocalName) | ||
6395 | { | ||
6396 | case "Control": | ||
6397 | if (null == action) | ||
6398 | { | ||
6399 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Action")); | ||
6400 | } | ||
6401 | |||
6402 | if (!this.core.EncounteredError) | ||
6403 | { | ||
6404 | Row row = this.core.CreateRow(sourceLineNumbers, "ControlCondition"); | ||
6405 | row[0] = dialog; | ||
6406 | row[1] = id; | ||
6407 | row[2] = action; | ||
6408 | row[3] = condition; | ||
6409 | } | ||
6410 | break; | ||
6411 | case "Feature": | ||
6412 | if (CompilerConstants.IntegerNotSet == level) | ||
6413 | { | ||
6414 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Level")); | ||
6415 | level = CompilerConstants.IllegalInteger; | ||
6416 | } | ||
6417 | |||
6418 | if (!this.core.EncounteredError) | ||
6419 | { | ||
6420 | Row row = this.core.CreateRow(sourceLineNumbers, "Condition"); | ||
6421 | row[0] = id; | ||
6422 | row[1] = level; | ||
6423 | row[2] = condition; | ||
6424 | } | ||
6425 | break; | ||
6426 | case "Fragment": | ||
6427 | case "Product": | ||
6428 | if (null == message) | ||
6429 | { | ||
6430 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Message")); | ||
6431 | } | ||
6432 | |||
6433 | if (!this.core.EncounteredError) | ||
6434 | { | ||
6435 | Row row = this.core.CreateRow(sourceLineNumbers, "LaunchCondition"); | ||
6436 | row[0] = condition; | ||
6437 | row[1] = message; | ||
6438 | } | ||
6439 | break; | ||
6440 | } | ||
6441 | |||
6442 | return condition; | ||
6443 | } | ||
6444 | |||
6445 | /// <summary> | ||
6446 | /// Parses a IniFile element. | ||
6447 | /// </summary> | ||
6448 | /// <param name="node">Element to parse.</param> | ||
6449 | /// <param name="componentId">Identifier of the parent component.</param> | ||
6450 | private void ParseIniFileElement(XElement node, string componentId) | ||
6451 | { | ||
6452 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
6453 | Identifier id = null; | ||
6454 | int action = CompilerConstants.IntegerNotSet; | ||
6455 | string directory = null; | ||
6456 | string key = null; | ||
6457 | string name = null; | ||
6458 | string section = null; | ||
6459 | string shortName = null; | ||
6460 | string tableName = null; | ||
6461 | string value = null; | ||
6462 | |||
6463 | foreach (XAttribute attrib in node.Attributes()) | ||
6464 | { | ||
6465 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
6466 | { | ||
6467 | switch (attrib.Name.LocalName) | ||
6468 | { | ||
6469 | case "Id": | ||
6470 | id = this.core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
6471 | break; | ||
6472 | case "Action": | ||
6473 | string actionValue = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
6474 | if (0 < actionValue.Length) | ||
6475 | { | ||
6476 | Wix.IniFile.ActionType actionType = Wix.IniFile.ParseActionType(actionValue); | ||
6477 | switch (actionType) | ||
6478 | { | ||
6479 | case Wix.IniFile.ActionType.addLine: | ||
6480 | action = MsiInterop.MsidbIniFileActionAddLine; | ||
6481 | break; | ||
6482 | case Wix.IniFile.ActionType.addTag: | ||
6483 | action = MsiInterop.MsidbIniFileActionAddTag; | ||
6484 | break; | ||
6485 | case Wix.IniFile.ActionType.createLine: | ||
6486 | action = MsiInterop.MsidbIniFileActionCreateLine; | ||
6487 | break; | ||
6488 | case Wix.IniFile.ActionType.removeLine: | ||
6489 | action = MsiInterop.MsidbIniFileActionRemoveLine; | ||
6490 | break; | ||
6491 | case Wix.IniFile.ActionType.removeTag: | ||
6492 | action = MsiInterop.MsidbIniFileActionRemoveTag; | ||
6493 | break; | ||
6494 | default: | ||
6495 | this.core.OnMessage(WixErrors.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, "Action", actionValue, "addLine", "addTag", "createLine", "removeLine", "removeTag")); | ||
6496 | break; | ||
6497 | } | ||
6498 | } | ||
6499 | break; | ||
6500 | case "Directory": | ||
6501 | directory = this.core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
6502 | break; | ||
6503 | case "Key": | ||
6504 | key = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
6505 | break; | ||
6506 | case "Name": | ||
6507 | name = this.core.GetAttributeLongFilename(sourceLineNumbers, attrib, false); | ||
6508 | break; | ||
6509 | case "Section": | ||
6510 | section = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
6511 | break; | ||
6512 | case "ShortName": | ||
6513 | shortName = this.core.GetAttributeShortFilename(sourceLineNumbers, attrib, false); | ||
6514 | break; | ||
6515 | case "Value": | ||
6516 | value = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
6517 | break; | ||
6518 | default: | ||
6519 | this.core.UnexpectedAttribute(node, attrib); | ||
6520 | break; | ||
6521 | } | ||
6522 | } | ||
6523 | else | ||
6524 | { | ||
6525 | this.core.ParseExtensionAttribute(node, attrib); | ||
6526 | } | ||
6527 | } | ||
6528 | |||
6529 | if (CompilerConstants.IntegerNotSet == action) | ||
6530 | { | ||
6531 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Action")); | ||
6532 | action = CompilerConstants.IllegalInteger; | ||
6533 | } | ||
6534 | |||
6535 | if (null == key) | ||
6536 | { | ||
6537 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Key")); | ||
6538 | } | ||
6539 | |||
6540 | if (null == name) | ||
6541 | { | ||
6542 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Name")); | ||
6543 | } | ||
6544 | else if (0 < name.Length) | ||
6545 | { | ||
6546 | if (this.core.IsValidShortFilename(name, false)) | ||
6547 | { | ||
6548 | if (null == shortName) | ||
6549 | { | ||
6550 | shortName = name; | ||
6551 | name = null; | ||
6552 | } | ||
6553 | else | ||
6554 | { | ||
6555 | this.core.OnMessage(WixErrors.IllegalAttributeValueWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Name", name, "ShortName")); | ||
6556 | } | ||
6557 | } | ||
6558 | else // generate a short file name. | ||
6559 | { | ||
6560 | if (null == shortName) | ||
6561 | { | ||
6562 | shortName = this.core.CreateShortName(name, true, false, node.Name.LocalName, componentId); | ||
6563 | } | ||
6564 | } | ||
6565 | } | ||
6566 | |||
6567 | if (null == section) | ||
6568 | { | ||
6569 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Section")); | ||
6570 | } | ||
6571 | |||
6572 | if (null == id) | ||
6573 | { | ||
6574 | id = this.core.CreateIdentifier("ini", directory, name ?? shortName, section, key, name); | ||
6575 | } | ||
6576 | |||
6577 | this.core.ParseForExtensionElements(node); | ||
6578 | |||
6579 | if (MsiInterop.MsidbIniFileActionRemoveLine == action || MsiInterop.MsidbIniFileActionRemoveTag == action) | ||
6580 | { | ||
6581 | tableName = "RemoveIniFile"; | ||
6582 | } | ||
6583 | else | ||
6584 | { | ||
6585 | if (null == value) | ||
6586 | { | ||
6587 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Value")); | ||
6588 | } | ||
6589 | |||
6590 | tableName = "IniFile"; | ||
6591 | } | ||
6592 | |||
6593 | if (!this.core.EncounteredError) | ||
6594 | { | ||
6595 | Row row = this.core.CreateRow(sourceLineNumbers, tableName, id); | ||
6596 | row[1] = GetMsiFilenameValue(shortName, name); | ||
6597 | row[2] = directory; | ||
6598 | row[3] = section; | ||
6599 | row[4] = key; | ||
6600 | row[5] = value; | ||
6601 | row[6] = action; | ||
6602 | row[7] = componentId; | ||
6603 | } | ||
6604 | } | ||
6605 | |||
6606 | /// <summary> | ||
6607 | /// Parses an IniFile search element. | ||
6608 | /// </summary> | ||
6609 | /// <param name="node">Element to parse.</param> | ||
6610 | /// <returns>Signature for search element.</returns> | ||
6611 | private string ParseIniFileSearchElement(XElement node) | ||
6612 | { | ||
6613 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
6614 | Identifier id = null; | ||
6615 | int field = CompilerConstants.IntegerNotSet; | ||
6616 | string key = null; | ||
6617 | string name = null; | ||
6618 | string section = null; | ||
6619 | string shortName = null; | ||
6620 | string signature = null; | ||
6621 | int type = 1; // default is file | ||
6622 | |||
6623 | foreach (XAttribute attrib in node.Attributes()) | ||
6624 | { | ||
6625 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
6626 | { | ||
6627 | switch (attrib.Name.LocalName) | ||
6628 | { | ||
6629 | case "Id": | ||
6630 | id = this.core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
6631 | break; | ||
6632 | case "Field": | ||
6633 | field = this.core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, short.MaxValue); | ||
6634 | break; | ||
6635 | case "Key": | ||
6636 | key = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
6637 | break; | ||
6638 | case "Name": | ||
6639 | name = this.core.GetAttributeLongFilename(sourceLineNumbers, attrib, false); | ||
6640 | break; | ||
6641 | case "Section": | ||
6642 | section = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
6643 | break; | ||
6644 | case "ShortName": | ||
6645 | shortName = this.core.GetAttributeShortFilename(sourceLineNumbers, attrib, false); | ||
6646 | break; | ||
6647 | case "Type": | ||
6648 | string typeValue = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
6649 | if (0 < typeValue.Length) | ||
6650 | { | ||
6651 | Wix.IniFileSearch.TypeType typeType = Wix.IniFileSearch.ParseTypeType(typeValue); | ||
6652 | switch (typeType) | ||
6653 | { | ||
6654 | case Wix.IniFileSearch.TypeType.directory: | ||
6655 | type = 0; | ||
6656 | break; | ||
6657 | case Wix.IniFileSearch.TypeType.file: | ||
6658 | type = 1; | ||
6659 | break; | ||
6660 | case Wix.IniFileSearch.TypeType.raw: | ||
6661 | type = 2; | ||
6662 | break; | ||
6663 | default: | ||
6664 | this.core.OnMessage(WixErrors.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, "Type", typeValue, "directory", "file", "registry")); | ||
6665 | break; | ||
6666 | } | ||
6667 | } | ||
6668 | break; | ||
6669 | default: | ||
6670 | this.core.UnexpectedAttribute(node, attrib); | ||
6671 | break; | ||
6672 | } | ||
6673 | } | ||
6674 | else | ||
6675 | { | ||
6676 | this.core.ParseExtensionAttribute(node, attrib); | ||
6677 | } | ||
6678 | } | ||
6679 | |||
6680 | if (null == key) | ||
6681 | { | ||
6682 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Key")); | ||
6683 | } | ||
6684 | |||
6685 | if (null == name) | ||
6686 | { | ||
6687 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Name")); | ||
6688 | } | ||
6689 | else if (0 < name.Length) | ||
6690 | { | ||
6691 | if (this.core.IsValidShortFilename(name, false)) | ||
6692 | { | ||
6693 | if (null == shortName) | ||
6694 | { | ||
6695 | shortName = name; | ||
6696 | name = null; | ||
6697 | } | ||
6698 | else | ||
6699 | { | ||
6700 | this.core.OnMessage(WixErrors.IllegalAttributeValueWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Name", name, "ShortName")); | ||
6701 | } | ||
6702 | } | ||
6703 | else if (null == shortName) // generate a short file name. | ||
6704 | { | ||
6705 | shortName = this.core.CreateShortName(name, true, false, node.Name.LocalName); | ||
6706 | } | ||
6707 | } | ||
6708 | |||
6709 | if (null == section) | ||
6710 | { | ||
6711 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Section")); | ||
6712 | } | ||
6713 | |||
6714 | if (null == id) | ||
6715 | { | ||
6716 | id = this.core.CreateIdentifier("ini", name, section, key, field.ToString(), type.ToString()); | ||
6717 | } | ||
6718 | |||
6719 | signature = id.Id; | ||
6720 | |||
6721 | bool oneChild = false; | ||
6722 | foreach (XElement child in node.Elements()) | ||
6723 | { | ||
6724 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
6725 | { | ||
6726 | SourceLineNumber childSourceLineNumbers = Preprocessor.GetSourceLineNumbers(child); | ||
6727 | switch (child.Name.LocalName) | ||
6728 | { | ||
6729 | case "DirectorySearch": | ||
6730 | if (oneChild) | ||
6731 | { | ||
6732 | this.core.OnMessage(WixErrors.TooManySearchElements(childSourceLineNumbers, node.Name.LocalName)); | ||
6733 | } | ||
6734 | oneChild = true; | ||
6735 | |||
6736 | // directorysearch parentage should work like directory element, not the rest of the signature type because of the DrLocator.Parent column | ||
6737 | signature = this.ParseDirectorySearchElement(child, id.Id); | ||
6738 | break; | ||
6739 | case "DirectorySearchRef": | ||
6740 | if (oneChild) | ||
6741 | { | ||
6742 | this.core.OnMessage(WixErrors.TooManySearchElements(childSourceLineNumbers, node.Name.LocalName)); | ||
6743 | } | ||
6744 | oneChild = true; | ||
6745 | signature = this.ParseDirectorySearchRefElement(child, id.Id); | ||
6746 | break; | ||
6747 | case "FileSearch": | ||
6748 | if (oneChild) | ||
6749 | { | ||
6750 | this.core.OnMessage(WixErrors.TooManySearchElements(sourceLineNumbers, node.Name.LocalName)); | ||
6751 | } | ||
6752 | oneChild = true; | ||
6753 | signature = this.ParseFileSearchElement(child, id.Id, false, CompilerConstants.IntegerNotSet); | ||
6754 | id = new Identifier(signature, AccessModifier.Private); // FileSearch signatures override parent signatures | ||
6755 | break; | ||
6756 | case "FileSearchRef": | ||
6757 | if (oneChild) | ||
6758 | { | ||
6759 | this.core.OnMessage(WixErrors.TooManySearchElements(sourceLineNumbers, node.Name.LocalName)); | ||
6760 | } | ||
6761 | oneChild = true; | ||
6762 | string newId = this.ParseSimpleRefElement(child, "Signature"); // FileSearch signatures override parent signatures | ||
6763 | id = new Identifier(newId, AccessModifier.Private); | ||
6764 | signature = null; | ||
6765 | break; | ||
6766 | default: | ||
6767 | this.core.UnexpectedElement(node, child); | ||
6768 | break; | ||
6769 | } | ||
6770 | } | ||
6771 | else | ||
6772 | { | ||
6773 | this.core.ParseExtensionElement(node, child); | ||
6774 | } | ||
6775 | } | ||
6776 | |||
6777 | if (!this.core.EncounteredError) | ||
6778 | { | ||
6779 | Row row = this.core.CreateRow(sourceLineNumbers, "IniLocator", id); | ||
6780 | row[1] = GetMsiFilenameValue(shortName, name); | ||
6781 | row[2] = section; | ||
6782 | row[3] = key; | ||
6783 | if (CompilerConstants.IntegerNotSet != field) | ||
6784 | { | ||
6785 | row[4] = field; | ||
6786 | } | ||
6787 | row[5] = type; | ||
6788 | } | ||
6789 | |||
6790 | return signature; | ||
6791 | } | ||
6792 | |||
6793 | /// <summary> | ||
6794 | /// Parses an isolated component element. | ||
6795 | /// </summary> | ||
6796 | /// <param name="node">Element to parse.</param> | ||
6797 | /// <param name="componentId">Identifier of parent component.</param> | ||
6798 | private void ParseIsolateComponentElement(XElement node, string componentId) | ||
6799 | { | ||
6800 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
6801 | string shared = null; | ||
6802 | |||
6803 | foreach (XAttribute attrib in node.Attributes()) | ||
6804 | { | ||
6805 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
6806 | { | ||
6807 | switch (attrib.Name.LocalName) | ||
6808 | { | ||
6809 | case "Shared": | ||
6810 | shared = this.core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
6811 | this.core.CreateSimpleReference(sourceLineNumbers, "Component", shared); | ||
6812 | break; | ||
6813 | default: | ||
6814 | this.core.UnexpectedAttribute(node, attrib); | ||
6815 | break; | ||
6816 | } | ||
6817 | } | ||
6818 | else | ||
6819 | { | ||
6820 | this.core.ParseExtensionAttribute(node, attrib); | ||
6821 | } | ||
6822 | } | ||
6823 | |||
6824 | if (null == shared) | ||
6825 | { | ||
6826 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Shared")); | ||
6827 | } | ||
6828 | |||
6829 | this.core.ParseForExtensionElements(node); | ||
6830 | |||
6831 | if (!this.core.EncounteredError) | ||
6832 | { | ||
6833 | Row row = this.core.CreateRow(sourceLineNumbers, "IsolatedComponent"); | ||
6834 | row[0] = shared; | ||
6835 | row[1] = componentId; | ||
6836 | } | ||
6837 | } | ||
6838 | |||
6839 | /// <summary> | ||
6840 | /// Parses a PatchCertificates or PackageCertificates element. | ||
6841 | /// </summary> | ||
6842 | /// <param name="node">The element to parse.</param> | ||
6843 | private void ParseCertificatesElement(XElement node) | ||
6844 | { | ||
6845 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
6846 | |||
6847 | // no attributes are supported for this element | ||
6848 | foreach (XAttribute attrib in node.Attributes()) | ||
6849 | { | ||
6850 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
6851 | { | ||
6852 | this.core.UnexpectedAttribute(node, attrib); | ||
6853 | } | ||
6854 | else | ||
6855 | { | ||
6856 | this.core.ParseExtensionAttribute(node, attrib); | ||
6857 | } | ||
6858 | } | ||
6859 | |||
6860 | foreach (XElement child in node.Elements()) | ||
6861 | { | ||
6862 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
6863 | { | ||
6864 | switch (child.Name.LocalName) | ||
6865 | { | ||
6866 | case "DigitalCertificate": | ||
6867 | string name = this.ParseDigitalCertificateElement(child); | ||
6868 | |||
6869 | if (!this.core.EncounteredError) | ||
6870 | { | ||
6871 | Row row = this.core.CreateRow(sourceLineNumbers, "PatchCertificates" == node.Name.LocalName ? "MsiPatchCertificate" : "MsiPackageCertificate"); | ||
6872 | row[0] = name; | ||
6873 | row[1] = name; | ||
6874 | } | ||
6875 | break; | ||
6876 | default: | ||
6877 | this.core.UnexpectedElement(node, child); | ||
6878 | break; | ||
6879 | } | ||
6880 | } | ||
6881 | else | ||
6882 | { | ||
6883 | this.core.ParseExtensionElement(node, child); | ||
6884 | } | ||
6885 | } | ||
6886 | } | ||
6887 | |||
6888 | /// <summary> | ||
6889 | /// Parses an digital certificate element. | ||
6890 | /// </summary> | ||
6891 | /// <param name="node">Element to parse.</param> | ||
6892 | /// <returns>The identifier of the certificate.</returns> | ||
6893 | private string ParseDigitalCertificateElement(XElement node) | ||
6894 | { | ||
6895 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
6896 | Identifier id = null; | ||
6897 | string sourceFile = null; | ||
6898 | |||
6899 | foreach (XAttribute attrib in node.Attributes()) | ||
6900 | { | ||
6901 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
6902 | { | ||
6903 | switch (attrib.Name.LocalName) | ||
6904 | { | ||
6905 | case "Id": | ||
6906 | id = this.core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
6907 | break; | ||
6908 | case "SourceFile": | ||
6909 | sourceFile = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
6910 | break; | ||
6911 | default: | ||
6912 | this.core.UnexpectedAttribute(node, attrib); | ||
6913 | break; | ||
6914 | } | ||
6915 | } | ||
6916 | else | ||
6917 | { | ||
6918 | this.core.ParseExtensionAttribute(node, attrib); | ||
6919 | } | ||
6920 | } | ||
6921 | |||
6922 | if (null == id) | ||
6923 | { | ||
6924 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
6925 | id = Identifier.Invalid; | ||
6926 | } | ||
6927 | else if (40 < id.Id.Length) | ||
6928 | { | ||
6929 | this.core.OnMessage(WixErrors.StreamNameTooLong(sourceLineNumbers, node.Name.LocalName, "Id", id.Id, id.Id.Length, 40)); | ||
6930 | |||
6931 | // No need to check for modularization problems since DigitalSignature and thus DigitalCertificate | ||
6932 | // currently have no usage in merge modules. | ||
6933 | } | ||
6934 | |||
6935 | if (null == sourceFile) | ||
6936 | { | ||
6937 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "SourceFile")); | ||
6938 | } | ||
6939 | |||
6940 | this.core.ParseForExtensionElements(node); | ||
6941 | |||
6942 | if (!this.core.EncounteredError) | ||
6943 | { | ||
6944 | Row row = this.core.CreateRow(sourceLineNumbers, "MsiDigitalCertificate", id); | ||
6945 | row[1] = sourceFile; | ||
6946 | } | ||
6947 | |||
6948 | return id.Id; | ||
6949 | } | ||
6950 | |||
6951 | /// <summary> | ||
6952 | /// Parses an digital signature element. | ||
6953 | /// </summary> | ||
6954 | /// <param name="node">Element to parse.</param> | ||
6955 | /// <param name="diskId">Disk id inherited from parent media.</param> | ||
6956 | private void ParseDigitalSignatureElement(XElement node, string diskId) | ||
6957 | { | ||
6958 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
6959 | string certificateId = null; | ||
6960 | string sourceFile = null; | ||
6961 | |||
6962 | foreach (XAttribute attrib in node.Attributes()) | ||
6963 | { | ||
6964 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
6965 | { | ||
6966 | switch (attrib.Name.LocalName) | ||
6967 | { | ||
6968 | case "SourceFile": | ||
6969 | sourceFile = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
6970 | break; | ||
6971 | default: | ||
6972 | this.core.UnexpectedAttribute(node, attrib); | ||
6973 | break; | ||
6974 | } | ||
6975 | } | ||
6976 | else | ||
6977 | { | ||
6978 | this.core.ParseExtensionAttribute(node, attrib); | ||
6979 | } | ||
6980 | } | ||
6981 | |||
6982 | // sanity check for debug to ensure the stream name will not be a problem | ||
6983 | if (null != sourceFile) | ||
6984 | { | ||
6985 | Debug.Assert(62 >= "MsiDigitalSignature.Media.".Length + diskId.Length); | ||
6986 | } | ||
6987 | |||
6988 | foreach (XElement child in node.Elements()) | ||
6989 | { | ||
6990 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
6991 | { | ||
6992 | switch (child.Name.LocalName) | ||
6993 | { | ||
6994 | case "DigitalCertificate": | ||
6995 | certificateId = this.ParseDigitalCertificateElement(child); | ||
6996 | break; | ||
6997 | default: | ||
6998 | this.core.UnexpectedElement(node, child); | ||
6999 | break; | ||
7000 | } | ||
7001 | } | ||
7002 | else | ||
7003 | { | ||
7004 | this.core.ParseExtensionElement(node, child); | ||
7005 | } | ||
7006 | } | ||
7007 | |||
7008 | if (null == certificateId) | ||
7009 | { | ||
7010 | this.core.OnMessage(WixErrors.ExpectedElement(sourceLineNumbers, node.Name.LocalName, "DigitalCertificate")); | ||
7011 | } | ||
7012 | |||
7013 | if (!this.core.EncounteredError) | ||
7014 | { | ||
7015 | Row row = this.core.CreateRow(sourceLineNumbers, "MsiDigitalSignature"); | ||
7016 | row[0] = "Media"; | ||
7017 | row[1] = diskId; | ||
7018 | row[2] = certificateId; | ||
7019 | row[3] = sourceFile; | ||
7020 | } | ||
7021 | } | ||
7022 | |||
7023 | /// <summary> | ||
7024 | /// Parses a MajorUpgrade element. | ||
7025 | /// </summary> | ||
7026 | /// <param name="node">The element to parse.</param> | ||
7027 | /// <param name="parentElement">The parent element.</param> | ||
7028 | private void ParseMajorUpgradeElement(XElement node, IDictionary<string, string> contextValues) | ||
7029 | { | ||
7030 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
7031 | int options = MsiInterop.MsidbUpgradeAttributesMigrateFeatures; | ||
7032 | bool allowDowngrades = false; | ||
7033 | bool allowSameVersionUpgrades = false; | ||
7034 | bool blockUpgrades = false; | ||
7035 | string downgradeErrorMessage = null; | ||
7036 | string disallowUpgradeErrorMessage = null; | ||
7037 | string removeFeatures = null; | ||
7038 | string schedule = null; | ||
7039 | |||
7040 | string upgradeCode = contextValues["UpgradeCode"]; | ||
7041 | if (String.IsNullOrEmpty(upgradeCode)) | ||
7042 | { | ||
7043 | this.core.OnMessage(WixErrors.ParentElementAttributeRequired(sourceLineNumbers, "Product", "UpgradeCode", node.Name.LocalName)); | ||
7044 | } | ||
7045 | |||
7046 | string productVersion = contextValues["ProductVersion"]; | ||
7047 | if (String.IsNullOrEmpty(productVersion)) | ||
7048 | { | ||
7049 | this.core.OnMessage(WixErrors.ParentElementAttributeRequired(sourceLineNumbers, "Product", "Version", node.Name.LocalName)); | ||
7050 | } | ||
7051 | |||
7052 | string productLanguage = contextValues["ProductLanguage"]; | ||
7053 | |||
7054 | foreach (XAttribute attrib in node.Attributes()) | ||
7055 | { | ||
7056 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
7057 | { | ||
7058 | switch (attrib.Name.LocalName) | ||
7059 | { | ||
7060 | case "AllowDowngrades": | ||
7061 | allowDowngrades = YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
7062 | break; | ||
7063 | case "AllowSameVersionUpgrades": | ||
7064 | allowSameVersionUpgrades = YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
7065 | break; | ||
7066 | case "Disallow": | ||
7067 | blockUpgrades = YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
7068 | break; | ||
7069 | case "DowngradeErrorMessage": | ||
7070 | downgradeErrorMessage = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
7071 | break; | ||
7072 | case "DisallowUpgradeErrorMessage": | ||
7073 | disallowUpgradeErrorMessage = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
7074 | break; | ||
7075 | case "MigrateFeatures": | ||
7076 | if (YesNoType.No == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
7077 | { | ||
7078 | options &= ~MsiInterop.MsidbUpgradeAttributesMigrateFeatures; | ||
7079 | } | ||
7080 | break; | ||
7081 | case "IgnoreLanguage": | ||
7082 | if (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
7083 | { | ||
7084 | productLanguage = null; | ||
7085 | } | ||
7086 | break; | ||
7087 | case "IgnoreRemoveFailure": | ||
7088 | if (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
7089 | { | ||
7090 | options |= MsiInterop.MsidbUpgradeAttributesIgnoreRemoveFailure; | ||
7091 | } | ||
7092 | break; | ||
7093 | case "RemoveFeatures": | ||
7094 | removeFeatures = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
7095 | break; | ||
7096 | case "Schedule": | ||
7097 | schedule = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
7098 | break; | ||
7099 | default: | ||
7100 | this.core.UnexpectedAttribute(node, attrib); | ||
7101 | break; | ||
7102 | } | ||
7103 | } | ||
7104 | else | ||
7105 | { | ||
7106 | this.core.ParseExtensionAttribute(node, attrib); | ||
7107 | } | ||
7108 | } | ||
7109 | |||
7110 | this.core.ParseForExtensionElements(node); | ||
7111 | |||
7112 | if (!allowDowngrades && String.IsNullOrEmpty(downgradeErrorMessage)) | ||
7113 | { | ||
7114 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "DowngradeErrorMessage", "AllowDowngrades", "yes", true)); | ||
7115 | } | ||
7116 | |||
7117 | if (allowDowngrades && !String.IsNullOrEmpty(downgradeErrorMessage)) | ||
7118 | { | ||
7119 | this.core.OnMessage(WixErrors.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "DowngradeErrorMessage", "AllowDowngrades", "yes")); | ||
7120 | } | ||
7121 | |||
7122 | if (allowDowngrades && allowSameVersionUpgrades) | ||
7123 | { | ||
7124 | this.core.OnMessage(WixErrors.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "AllowSameVersionUpgrades", "AllowDowngrades", "yes")); | ||
7125 | } | ||
7126 | |||
7127 | if (blockUpgrades && String.IsNullOrEmpty(disallowUpgradeErrorMessage)) | ||
7128 | { | ||
7129 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "DisallowUpgradeErrorMessage", "Disallow", "yes", true)); | ||
7130 | } | ||
7131 | |||
7132 | if (!blockUpgrades && !String.IsNullOrEmpty(disallowUpgradeErrorMessage)) | ||
7133 | { | ||
7134 | this.core.OnMessage(WixErrors.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "DisallowUpgradeErrorMessage", "Disallow", "yes")); | ||
7135 | } | ||
7136 | |||
7137 | if (!this.core.EncounteredError) | ||
7138 | { | ||
7139 | // create the row that performs the upgrade (or downgrade) | ||
7140 | Row row = this.core.CreateRow(sourceLineNumbers, "Upgrade"); | ||
7141 | row[0] = upgradeCode; | ||
7142 | if (allowDowngrades) | ||
7143 | { | ||
7144 | row[1] = "0"; // let any version satisfy | ||
7145 | // row[2] = maximum version; omit so we don't have to fake a version like "255.255.65535"; | ||
7146 | row[3] = productLanguage; | ||
7147 | row[4] = options | MsiInterop.MsidbUpgradeAttributesVersionMinInclusive; | ||
7148 | } | ||
7149 | else | ||
7150 | { | ||
7151 | // row[1] = minimum version; skip it so we detect all prior versions. | ||
7152 | row[2] = productVersion; | ||
7153 | row[3] = productLanguage; | ||
7154 | row[4] = allowSameVersionUpgrades ? (options | MsiInterop.MsidbUpgradeAttributesVersionMaxInclusive) : options; | ||
7155 | } | ||
7156 | |||
7157 | row[5] = removeFeatures; | ||
7158 | row[6] = Compiler.UpgradeDetectedProperty; | ||
7159 | |||
7160 | // Ensure the action property is secure. | ||
7161 | this.AddWixPropertyRow(sourceLineNumbers, new Identifier(Compiler.UpgradeDetectedProperty, AccessModifier.Public), false, true, false); | ||
7162 | |||
7163 | // Add launch condition that blocks upgrades | ||
7164 | if (blockUpgrades) | ||
7165 | { | ||
7166 | row = this.core.CreateRow(sourceLineNumbers, "LaunchCondition"); | ||
7167 | row[0] = Compiler.UpgradePreventedCondition; | ||
7168 | row[1] = disallowUpgradeErrorMessage; | ||
7169 | } | ||
7170 | |||
7171 | // now create the Upgrade row and launch conditions to prevent downgrades (unless explicitly permitted) | ||
7172 | if (!allowDowngrades) | ||
7173 | { | ||
7174 | row = this.core.CreateRow(sourceLineNumbers, "Upgrade"); | ||
7175 | row[0] = upgradeCode; | ||
7176 | row[1] = productVersion; | ||
7177 | // row[2] = maximum version; skip it so we detect all future versions. | ||
7178 | row[3] = productLanguage; | ||
7179 | row[4] = MsiInterop.MsidbUpgradeAttributesOnlyDetect; | ||
7180 | // row[5] = removeFeatures; | ||
7181 | row[6] = Compiler.DowngradeDetectedProperty; | ||
7182 | |||
7183 | // Ensure the action property is secure. | ||
7184 | this.AddWixPropertyRow(sourceLineNumbers, new Identifier(Compiler.DowngradeDetectedProperty, AccessModifier.Public), false, true, false); | ||
7185 | |||
7186 | row = this.core.CreateRow(sourceLineNumbers, "LaunchCondition"); | ||
7187 | row[0] = Compiler.DowngradePreventedCondition; | ||
7188 | row[1] = downgradeErrorMessage; | ||
7189 | } | ||
7190 | |||
7191 | // finally, schedule RemoveExistingProducts | ||
7192 | row = this.core.CreateRow(sourceLineNumbers, "WixAction"); | ||
7193 | row[0] = "InstallExecuteSequence"; | ||
7194 | row[1] = "RemoveExistingProducts"; | ||
7195 | // row[2] = condition; | ||
7196 | // row[3] = sequence; | ||
7197 | row[6] = 0; // overridable | ||
7198 | |||
7199 | switch (schedule) | ||
7200 | { | ||
7201 | case null: | ||
7202 | case "afterInstallValidate": | ||
7203 | // row[4] = beforeAction; | ||
7204 | row[5] = "InstallValidate"; | ||
7205 | break; | ||
7206 | case "afterInstallInitialize": | ||
7207 | // row[4] = beforeAction; | ||
7208 | row[5] = "InstallInitialize"; | ||
7209 | break; | ||
7210 | case "afterInstallExecute": | ||
7211 | // row[4] = beforeAction; | ||
7212 | row[5] = "InstallExecute"; | ||
7213 | break; | ||
7214 | case "afterInstallExecuteAgain": | ||
7215 | // row[4] = beforeAction; | ||
7216 | row[5] = "InstallExecuteAgain"; | ||
7217 | break; | ||
7218 | case "afterInstallFinalize": | ||
7219 | // row[4] = beforeAction; | ||
7220 | row[5] = "InstallFinalize"; | ||
7221 | break; | ||
7222 | } | ||
7223 | } | ||
7224 | } | ||
7225 | |||
7226 | /// <summary> | ||
7227 | /// Parses a media element. | ||
7228 | /// </summary> | ||
7229 | /// <param name="node">Element to parse.</param> | ||
7230 | /// <param name="patchId">Set to the PatchId if parsing Patch/Media element otherwise null.</param> | ||
7231 | private void ParseMediaElement(XElement node, string patchId) | ||
7232 | { | ||
7233 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
7234 | int id = CompilerConstants.IntegerNotSet; | ||
7235 | string cabinet = null; | ||
7236 | CompressionLevel? compressionLevel = null; | ||
7237 | string diskPrompt = null; | ||
7238 | string layout = null; | ||
7239 | bool patch = null != patchId; | ||
7240 | string volumeLabel = null; | ||
7241 | string source = null; | ||
7242 | string symbols = null; | ||
7243 | |||
7244 | YesNoType embedCab = patch ? YesNoType.Yes : YesNoType.NotSet; | ||
7245 | |||
7246 | foreach (XAttribute attrib in node.Attributes()) | ||
7247 | { | ||
7248 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
7249 | { | ||
7250 | switch (attrib.Name.LocalName) | ||
7251 | { | ||
7252 | case "Id": | ||
7253 | id = this.core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 1, short.MaxValue); | ||
7254 | break; | ||
7255 | case "Cabinet": | ||
7256 | cabinet = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
7257 | break; | ||
7258 | case "CompressionLevel": | ||
7259 | string compressionLevelString = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
7260 | if (0 < compressionLevelString.Length) | ||
7261 | { | ||
7262 | Wix.CompressionLevelType compressionLevelType; | ||
7263 | if (!Wix.Enums.TryParseCompressionLevelType(compressionLevelString, out compressionLevelType)) | ||
7264 | { | ||
7265 | this.core.OnMessage(WixErrors.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, compressionLevelString, "high", "low", "medium", "mszip", "none")); | ||
7266 | } | ||
7267 | else | ||
7268 | { | ||
7269 | compressionLevel = (CompressionLevel)Enum.Parse(typeof(CompressionLevel), compressionLevelString, true); | ||
7270 | } | ||
7271 | } | ||
7272 | break; | ||
7273 | case "DiskPrompt": | ||
7274 | diskPrompt = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
7275 | this.core.CreateSimpleReference(sourceLineNumbers, "Property", "DiskPrompt"); // ensure the output has a DiskPrompt Property defined | ||
7276 | break; | ||
7277 | case "EmbedCab": | ||
7278 | embedCab = this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
7279 | break; | ||
7280 | case "Layout": | ||
7281 | case "src": | ||
7282 | if (null != layout) | ||
7283 | { | ||
7284 | this.core.OnMessage(WixErrors.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Layout", "src")); | ||
7285 | } | ||
7286 | |||
7287 | if ("src" == attrib.Name.LocalName) | ||
7288 | { | ||
7289 | this.core.OnMessage(WixWarnings.DeprecatedAttribute(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, "Layout")); | ||
7290 | } | ||
7291 | layout = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
7292 | break; | ||
7293 | case "VolumeLabel": | ||
7294 | volumeLabel = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
7295 | break; | ||
7296 | case "Source": | ||
7297 | source = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
7298 | break; | ||
7299 | default: | ||
7300 | this.core.UnexpectedAttribute(node, attrib); | ||
7301 | break; | ||
7302 | } | ||
7303 | } | ||
7304 | else | ||
7305 | { | ||
7306 | this.core.ParseExtensionAttribute(node, attrib); | ||
7307 | } | ||
7308 | } | ||
7309 | |||
7310 | if (CompilerConstants.IntegerNotSet == id) | ||
7311 | { | ||
7312 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
7313 | id = CompilerConstants.IllegalInteger; | ||
7314 | } | ||
7315 | |||
7316 | if (YesNoType.IllegalValue != embedCab) | ||
7317 | { | ||
7318 | if (YesNoType.Yes == embedCab) | ||
7319 | { | ||
7320 | if (null == cabinet) | ||
7321 | { | ||
7322 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Cabinet", "EmbedCab", "yes")); | ||
7323 | } | ||
7324 | else | ||
7325 | { | ||
7326 | if (62 < cabinet.Length) | ||
7327 | { | ||
7328 | this.core.OnMessage(WixErrors.MediaEmbeddedCabinetNameTooLong(sourceLineNumbers, node.Name.LocalName, "Cabinet", cabinet, cabinet.Length)); | ||
7329 | } | ||
7330 | |||
7331 | cabinet = String.Concat("#", cabinet); | ||
7332 | } | ||
7333 | } | ||
7334 | else // external cabinet file | ||
7335 | { | ||
7336 | // external cabinet files must use 8.3 filenames | ||
7337 | if (!String.IsNullOrEmpty(cabinet) && !this.core.IsValidShortFilename(cabinet, false)) | ||
7338 | { | ||
7339 | // WiX variables in the name will trip the "not a valid 8.3 name" switch, so let them through | ||
7340 | if (!Common.WixVariableRegex.Match(cabinet).Success) | ||
7341 | { | ||
7342 | this.core.OnMessage(WixWarnings.MediaExternalCabinetFilenameIllegal(sourceLineNumbers, node.Name.LocalName, "Cabinet", cabinet)); | ||
7343 | } | ||
7344 | } | ||
7345 | } | ||
7346 | } | ||
7347 | |||
7348 | if (null != compressionLevel && null == cabinet) | ||
7349 | { | ||
7350 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Cabinet", "CompressionLevel")); | ||
7351 | } | ||
7352 | |||
7353 | if (patch) | ||
7354 | { | ||
7355 | // Default Source to a form of the Patch Id if none is specified. | ||
7356 | if (null == source) | ||
7357 | { | ||
7358 | source = String.Concat("_", new Guid(patchId).ToString("N", CultureInfo.InvariantCulture).ToUpper(CultureInfo.InvariantCulture)); | ||
7359 | } | ||
7360 | } | ||
7361 | |||
7362 | foreach (XElement child in node.Elements()) | ||
7363 | { | ||
7364 | SourceLineNumber childSourceLineNumbers = Preprocessor.GetSourceLineNumbers(child); | ||
7365 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
7366 | { | ||
7367 | switch (child.Name.LocalName) | ||
7368 | { | ||
7369 | case "DigitalSignature": | ||
7370 | if (YesNoType.Yes == embedCab) | ||
7371 | { | ||
7372 | this.core.OnMessage(WixErrors.SignedEmbeddedCabinet(childSourceLineNumbers)); | ||
7373 | } | ||
7374 | else if (null == cabinet) | ||
7375 | { | ||
7376 | this.core.OnMessage(WixErrors.ExpectedSignedCabinetName(childSourceLineNumbers)); | ||
7377 | } | ||
7378 | else | ||
7379 | { | ||
7380 | this.ParseDigitalSignatureElement(child, id.ToString(CultureInfo.InvariantCulture.NumberFormat)); | ||
7381 | } | ||
7382 | break; | ||
7383 | case "PatchBaseline": | ||
7384 | if (patch) | ||
7385 | { | ||
7386 | this.ParsePatchBaselineElement(child, id); | ||
7387 | } | ||
7388 | else | ||
7389 | { | ||
7390 | this.core.UnexpectedElement(node, child); | ||
7391 | } | ||
7392 | break; | ||
7393 | case "SymbolPath": | ||
7394 | if (null != symbols) | ||
7395 | { | ||
7396 | symbols += "" + this.ParseSymbolPathElement(child); | ||
7397 | } | ||
7398 | else | ||
7399 | { | ||
7400 | symbols = this.ParseSymbolPathElement(child); | ||
7401 | } | ||
7402 | break; | ||
7403 | default: | ||
7404 | this.core.UnexpectedElement(node, child); | ||
7405 | break; | ||
7406 | } | ||
7407 | } | ||
7408 | else | ||
7409 | { | ||
7410 | this.core.ParseExtensionElement(node, child); | ||
7411 | } | ||
7412 | } | ||
7413 | |||
7414 | |||
7415 | |||
7416 | // add the row to the section | ||
7417 | if (!this.core.EncounteredError) | ||
7418 | { | ||
7419 | MediaRow mediaRow = (MediaRow)this.core.CreateRow(sourceLineNumbers, "Media"); | ||
7420 | mediaRow.DiskId = id; | ||
7421 | mediaRow.LastSequence = 0; // this is set in the binder | ||
7422 | mediaRow.DiskPrompt = diskPrompt; | ||
7423 | mediaRow.Cabinet = cabinet; | ||
7424 | mediaRow.VolumeLabel = volumeLabel; | ||
7425 | mediaRow.Source = source; | ||
7426 | |||
7427 | // the Source column is only set when creating a patch | ||
7428 | |||
7429 | if (null != compressionLevel || null != layout) | ||
7430 | { | ||
7431 | WixMediaRow row = (WixMediaRow)this.core.CreateRow(sourceLineNumbers, "WixMedia"); | ||
7432 | row.DiskId = id; | ||
7433 | row.CompressionLevel = compressionLevel; | ||
7434 | row.Layout = layout; | ||
7435 | } | ||
7436 | |||
7437 | if (null != symbols) | ||
7438 | { | ||
7439 | WixDeltaPatchSymbolPathsRow symbolRow = (WixDeltaPatchSymbolPathsRow)this.core.CreateRow(sourceLineNumbers, "WixDeltaPatchSymbolPaths"); | ||
7440 | symbolRow.Id = id.ToString(CultureInfo.InvariantCulture); | ||
7441 | symbolRow.Type = SymbolPathType.Media; | ||
7442 | symbolRow.SymbolPaths = symbols; | ||
7443 | } | ||
7444 | } | ||
7445 | } | ||
7446 | |||
7447 | /// <summary> | ||
7448 | /// Parses a media template element. | ||
7449 | /// </summary> | ||
7450 | /// <param name="node">Element to parse.</param> | ||
7451 | /// <param name="patchId">Set to the PatchId if parsing Patch/Media element otherwise null.</param> | ||
7452 | private void ParseMediaTemplateElement(XElement node, string patchId) | ||
7453 | { | ||
7454 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
7455 | string cabinetTemplate = "cab{0}.cab"; | ||
7456 | string compressionLevel = null; // this defaults to mszip in Binder | ||
7457 | string diskPrompt = null; | ||
7458 | bool patch = null != patchId; | ||
7459 | string volumeLabel = null; | ||
7460 | int maximumUncompressedMediaSize = CompilerConstants.IntegerNotSet; | ||
7461 | int maximumCabinetSizeForLargeFileSplitting = CompilerConstants.IntegerNotSet; | ||
7462 | Wix.CompressionLevelType compressionLevelType = Wix.CompressionLevelType.NotSet; | ||
7463 | |||
7464 | YesNoType embedCab = patch ? YesNoType.Yes : YesNoType.NotSet; | ||
7465 | |||
7466 | foreach (XAttribute attrib in node.Attributes()) | ||
7467 | { | ||
7468 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
7469 | { | ||
7470 | switch (attrib.Name.LocalName) | ||
7471 | { | ||
7472 | case "CabinetTemplate": | ||
7473 | string authoredCabinetTemplateValue = this.core.GetAttributeValue(sourceLineNumbers, attrib, EmptyRule.CanBeEmpty); | ||
7474 | if (!String.IsNullOrEmpty(authoredCabinetTemplateValue)) | ||
7475 | { | ||
7476 | cabinetTemplate = authoredCabinetTemplateValue; | ||
7477 | } | ||
7478 | |||
7479 | // Create an example cabinet name using the maximum number of cabinets supported, 999. | ||
7480 | string exampleCabinetName = String.Format(cabinetTemplate, "###"); | ||
7481 | if (!this.core.IsValidLocIdentifier(exampleCabinetName)) | ||
7482 | { | ||
7483 | // The example name should not match the authored template since that would nullify the | ||
7484 | // reason for having multiple cabients. External cabinet files must also be valid file names. | ||
7485 | if (exampleCabinetName.Equals(authoredCabinetTemplateValue) || !this.core.IsValidLongFilename(exampleCabinetName, false)) | ||
7486 | { | ||
7487 | this.core.OnMessage(WixErrors.InvalidCabinetTemplate(sourceLineNumbers, cabinetTemplate)); | ||
7488 | } | ||
7489 | else if (!this.core.IsValidShortFilename(exampleCabinetName, false) && !Common.WixVariableRegex.Match(exampleCabinetName).Success) // ignore short names with wix variables because it rarely works out. | ||
7490 | { | ||
7491 | this.core.OnMessage(WixWarnings.MediaExternalCabinetFilenameIllegal(sourceLineNumbers, node.Name.LocalName, "CabinetTemplate", cabinetTemplate)); | ||
7492 | } | ||
7493 | } | ||
7494 | break; | ||
7495 | case "CompressionLevel": | ||
7496 | compressionLevel = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
7497 | if (0 < compressionLevel.Length) | ||
7498 | { | ||
7499 | if (!Wix.Enums.TryParseCompressionLevelType(compressionLevel, out compressionLevelType)) | ||
7500 | { | ||
7501 | this.core.OnMessage(WixErrors.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, compressionLevel, "high", "low", "medium", "mszip", "none")); | ||
7502 | } | ||
7503 | } | ||
7504 | break; | ||
7505 | case "DiskPrompt": | ||
7506 | diskPrompt = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
7507 | this.core.CreateSimpleReference(sourceLineNumbers, "Property", "DiskPrompt"); // ensure the output has a DiskPrompt Property defined | ||
7508 | this.core.OnMessage(WixWarnings.ReservedAttribute(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); | ||
7509 | break; | ||
7510 | case "EmbedCab": | ||
7511 | embedCab = this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
7512 | break; | ||
7513 | case "VolumeLabel": | ||
7514 | volumeLabel = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
7515 | this.core.OnMessage(WixWarnings.ReservedAttribute(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); | ||
7516 | break; | ||
7517 | case "MaximumUncompressedMediaSize": | ||
7518 | maximumUncompressedMediaSize = this.core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 1, int.MaxValue); | ||
7519 | break; | ||
7520 | case "MaximumCabinetSizeForLargeFileSplitting": | ||
7521 | maximumCabinetSizeForLargeFileSplitting = this.core.GetAttributeIntegerValue(sourceLineNumbers, attrib, CompilerCore.MinValueOfMaxCabSizeForLargeFileSplitting, CompilerCore.MaxValueOfMaxCabSizeForLargeFileSplitting); | ||
7522 | break; | ||
7523 | default: | ||
7524 | this.core.UnexpectedAttribute(node, attrib); | ||
7525 | break; | ||
7526 | } | ||
7527 | } | ||
7528 | else | ||
7529 | { | ||
7530 | this.core.ParseExtensionAttribute(node, attrib); | ||
7531 | } | ||
7532 | } | ||
7533 | |||
7534 | if (YesNoType.IllegalValue != embedCab) | ||
7535 | { | ||
7536 | if (YesNoType.Yes == embedCab) | ||
7537 | { | ||
7538 | cabinetTemplate = String.Concat("#", cabinetTemplate); | ||
7539 | } | ||
7540 | } | ||
7541 | |||
7542 | if (!this.core.EncounteredError) | ||
7543 | { | ||
7544 | MediaRow temporaryMediaRow = (MediaRow)this.core.CreateRow(sourceLineNumbers, "Media"); | ||
7545 | temporaryMediaRow.DiskId = 1; | ||
7546 | WixMediaTemplateRow mediaTemplateRow = (WixMediaTemplateRow)this.core.CreateRow(sourceLineNumbers, "WixMediaTemplate"); | ||
7547 | mediaTemplateRow.CabinetTemplate = cabinetTemplate; | ||
7548 | mediaTemplateRow.VolumeLabel = volumeLabel; | ||
7549 | mediaTemplateRow.DiskPrompt = diskPrompt; | ||
7550 | mediaTemplateRow.VolumeLabel = volumeLabel; | ||
7551 | |||
7552 | if (maximumUncompressedMediaSize != CompilerConstants.IntegerNotSet) | ||
7553 | { | ||
7554 | mediaTemplateRow.MaximumUncompressedMediaSize = maximumUncompressedMediaSize; | ||
7555 | } | ||
7556 | else | ||
7557 | { | ||
7558 | mediaTemplateRow.MaximumUncompressedMediaSize = CompilerCore.DefaultMaximumUncompressedMediaSize; | ||
7559 | } | ||
7560 | |||
7561 | if (maximumCabinetSizeForLargeFileSplitting != CompilerConstants.IntegerNotSet) | ||
7562 | { | ||
7563 | mediaTemplateRow.MaximumCabinetSizeForLargeFileSplitting = maximumCabinetSizeForLargeFileSplitting; | ||
7564 | } | ||
7565 | else | ||
7566 | { | ||
7567 | mediaTemplateRow.MaximumCabinetSizeForLargeFileSplitting = 0; // Default value of 0 corresponds to max size of 2048 MB (i.e. 2 GB) | ||
7568 | } | ||
7569 | |||
7570 | switch (compressionLevelType) | ||
7571 | { | ||
7572 | case Wix.CompressionLevelType.high: | ||
7573 | mediaTemplateRow.CompressionLevel = CompressionLevel.High; | ||
7574 | break; | ||
7575 | case Wix.CompressionLevelType.low: | ||
7576 | mediaTemplateRow.CompressionLevel = CompressionLevel.Low; | ||
7577 | break; | ||
7578 | case Wix.CompressionLevelType.medium: | ||
7579 | mediaTemplateRow.CompressionLevel = CompressionLevel.Medium; | ||
7580 | break; | ||
7581 | case Wix.CompressionLevelType.none: | ||
7582 | mediaTemplateRow.CompressionLevel = CompressionLevel.None; | ||
7583 | break; | ||
7584 | case Wix.CompressionLevelType.mszip: | ||
7585 | mediaTemplateRow.CompressionLevel = CompressionLevel.Mszip; | ||
7586 | break; | ||
7587 | } | ||
7588 | } | ||
7589 | } | ||
7590 | |||
7591 | /// <summary> | ||
7592 | /// Parses a merge element. | ||
7593 | /// </summary> | ||
7594 | /// <param name="node">Element to parse.</param> | ||
7595 | /// <param name="directoryId">Identifier for parent directory.</param> | ||
7596 | /// <param name="diskId">Disk id inherited from parent directory.</param> | ||
7597 | private void ParseMergeElement(XElement node, string directoryId, int diskId) | ||
7598 | { | ||
7599 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
7600 | Identifier id = null; | ||
7601 | string configData = String.Empty; | ||
7602 | YesNoType fileCompression = YesNoType.NotSet; | ||
7603 | string language = null; | ||
7604 | string sourceFile = null; | ||
7605 | |||
7606 | foreach (XAttribute attrib in node.Attributes()) | ||
7607 | { | ||
7608 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
7609 | { | ||
7610 | switch (attrib.Name.LocalName) | ||
7611 | { | ||
7612 | case "Id": | ||
7613 | id = this.core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
7614 | break; | ||
7615 | case "DiskId": | ||
7616 | diskId = this.core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 1, short.MaxValue); | ||
7617 | this.core.CreateSimpleReference(sourceLineNumbers, "Media", diskId.ToString(CultureInfo.InvariantCulture.NumberFormat)); | ||
7618 | break; | ||
7619 | case "FileCompression": | ||
7620 | fileCompression = this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
7621 | break; | ||
7622 | case "Language": | ||
7623 | language = this.core.GetAttributeLocalizableIntegerValue(sourceLineNumbers, attrib, 0, short.MaxValue); | ||
7624 | break; | ||
7625 | case "SourceFile": | ||
7626 | sourceFile = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
7627 | break; | ||
7628 | default: | ||
7629 | this.core.UnexpectedAttribute(node, attrib); | ||
7630 | break; | ||
7631 | } | ||
7632 | } | ||
7633 | else | ||
7634 | { | ||
7635 | this.core.ParseExtensionAttribute(node, attrib); | ||
7636 | } | ||
7637 | } | ||
7638 | |||
7639 | if (null == id) | ||
7640 | { | ||
7641 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
7642 | } | ||
7643 | |||
7644 | if (null == language) | ||
7645 | { | ||
7646 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Language")); | ||
7647 | } | ||
7648 | |||
7649 | if (null == sourceFile) | ||
7650 | { | ||
7651 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "SourceFile")); | ||
7652 | } | ||
7653 | |||
7654 | if (CompilerConstants.IntegerNotSet == diskId) | ||
7655 | { | ||
7656 | this.core.OnMessage(WixErrors.ExpectedAttributeInElementOrParent(sourceLineNumbers, node.Name.LocalName, "DiskId", "Directory")); | ||
7657 | diskId = CompilerConstants.IllegalInteger; | ||
7658 | } | ||
7659 | |||
7660 | foreach (XElement child in node.Elements()) | ||
7661 | { | ||
7662 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
7663 | { | ||
7664 | switch (child.Name.LocalName) | ||
7665 | { | ||
7666 | case "ConfigurationData": | ||
7667 | if (0 == configData.Length) | ||
7668 | { | ||
7669 | configData = this.ParseConfigurationDataElement(child); | ||
7670 | } | ||
7671 | else | ||
7672 | { | ||
7673 | configData = String.Concat(configData, ",", this.ParseConfigurationDataElement(child)); | ||
7674 | } | ||
7675 | break; | ||
7676 | default: | ||
7677 | this.core.UnexpectedElement(node, child); | ||
7678 | break; | ||
7679 | } | ||
7680 | } | ||
7681 | else | ||
7682 | { | ||
7683 | this.core.ParseExtensionElement(node, child); | ||
7684 | } | ||
7685 | } | ||
7686 | |||
7687 | if (!this.core.EncounteredError) | ||
7688 | { | ||
7689 | Row row = this.core.CreateRow(sourceLineNumbers, "WixMerge", id); | ||
7690 | row[1] = language; | ||
7691 | row[2] = directoryId; | ||
7692 | row[3] = sourceFile; | ||
7693 | row[4] = diskId; | ||
7694 | if (YesNoType.Yes == fileCompression) | ||
7695 | { | ||
7696 | row[5] = 1; | ||
7697 | } | ||
7698 | else if (YesNoType.No == fileCompression) | ||
7699 | { | ||
7700 | row[5] = 0; | ||
7701 | } | ||
7702 | else // YesNoType.NotSet == fileCompression | ||
7703 | { | ||
7704 | // and we leave the column null | ||
7705 | } | ||
7706 | row[6] = configData; | ||
7707 | row[7] = Guid.Empty.ToString("B"); | ||
7708 | } | ||
7709 | } | ||
7710 | |||
7711 | /// <summary> | ||
7712 | /// Parses a configuration data element. | ||
7713 | /// </summary> | ||
7714 | /// <param name="node">Element to parse.</param> | ||
7715 | /// <returns>String in format "name=value" with '%', ',' and '=' hex encoded.</returns> | ||
7716 | private string ParseConfigurationDataElement(XElement node) | ||
7717 | { | ||
7718 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
7719 | string name = null; | ||
7720 | string value = null; | ||
7721 | |||
7722 | foreach (XAttribute attrib in node.Attributes()) | ||
7723 | { | ||
7724 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
7725 | { | ||
7726 | switch (attrib.Name.LocalName) | ||
7727 | { | ||
7728 | case "Name": | ||
7729 | name = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
7730 | break; | ||
7731 | case "Value": | ||
7732 | value = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
7733 | break; | ||
7734 | default: | ||
7735 | this.core.UnexpectedAttribute(node, attrib); | ||
7736 | break; | ||
7737 | } | ||
7738 | } | ||
7739 | else | ||
7740 | { | ||
7741 | this.core.ParseExtensionAttribute(node, attrib); | ||
7742 | } | ||
7743 | } | ||
7744 | |||
7745 | if (null == name) | ||
7746 | { | ||
7747 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Name")); | ||
7748 | } | ||
7749 | else // need to hex encode these characters | ||
7750 | { | ||
7751 | name = name.Replace("%", "%25"); | ||
7752 | name = name.Replace("=", "%3D"); | ||
7753 | name = name.Replace(",", "%2C"); | ||
7754 | } | ||
7755 | |||
7756 | if (null == value) | ||
7757 | { | ||
7758 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Value")); | ||
7759 | } | ||
7760 | else // need to hex encode these characters | ||
7761 | { | ||
7762 | value = value.Replace("%", "%25"); | ||
7763 | value = value.Replace("=", "%3D"); | ||
7764 | value = value.Replace(",", "%2C"); | ||
7765 | } | ||
7766 | |||
7767 | this.core.ParseForExtensionElements(node); | ||
7768 | |||
7769 | return String.Concat(name, "=", value); | ||
7770 | } | ||
7771 | |||
7772 | /// <summary> | ||
7773 | /// Parses a merge reference element. | ||
7774 | /// </summary> | ||
7775 | /// <param name="node">Element to parse.</param> | ||
7776 | /// <param name="parentType">Parents complex reference type.</param> | ||
7777 | /// <param name="parentId">Identifier for parent feature or feature group.</param> | ||
7778 | private void ParseMergeRefElement(XElement node, ComplexReferenceParentType parentType, string parentId) | ||
7779 | { | ||
7780 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
7781 | string id = null; | ||
7782 | YesNoType primary = YesNoType.NotSet; | ||
7783 | |||
7784 | foreach (XAttribute attrib in node.Attributes()) | ||
7785 | { | ||
7786 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
7787 | { | ||
7788 | switch (attrib.Name.LocalName) | ||
7789 | { | ||
7790 | case "Id": | ||
7791 | id = this.core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
7792 | this.core.CreateSimpleReference(sourceLineNumbers, "WixMerge", id); | ||
7793 | break; | ||
7794 | case "Primary": | ||
7795 | primary = this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
7796 | break; | ||
7797 | default: | ||
7798 | this.core.UnexpectedAttribute(node, attrib); | ||
7799 | break; | ||
7800 | } | ||
7801 | } | ||
7802 | else | ||
7803 | { | ||
7804 | this.core.ParseExtensionAttribute(node, attrib); | ||
7805 | } | ||
7806 | } | ||
7807 | |||
7808 | if (null == id) | ||
7809 | { | ||
7810 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
7811 | } | ||
7812 | |||
7813 | this.core.ParseForExtensionElements(node); | ||
7814 | |||
7815 | this.core.CreateComplexReference(sourceLineNumbers, parentType, parentId, null, ComplexReferenceChildType.Module, id, (YesNoType.Yes == primary)); | ||
7816 | } | ||
7817 | |||
7818 | /// <summary> | ||
7819 | /// Parses a mime element. | ||
7820 | /// </summary> | ||
7821 | /// <param name="node">Element to parse.</param> | ||
7822 | /// <param name="extension">Identifier for parent extension.</param> | ||
7823 | /// <param name="componentId">Identifier for parent component.</param> | ||
7824 | /// <param name="parentAdvertised">Flag if the parent element is advertised.</param> | ||
7825 | /// <returns>Content type if this is the default for the MIME type.</returns> | ||
7826 | private string ParseMIMEElement(XElement node, string extension, string componentId, YesNoType parentAdvertised) | ||
7827 | { | ||
7828 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
7829 | string classId = null; | ||
7830 | string contentType = null; | ||
7831 | YesNoType advertise = parentAdvertised; | ||
7832 | YesNoType returnContentType = YesNoType.NotSet; | ||
7833 | |||
7834 | foreach (XAttribute attrib in node.Attributes()) | ||
7835 | { | ||
7836 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
7837 | { | ||
7838 | switch (attrib.Name.LocalName) | ||
7839 | { | ||
7840 | case "Advertise": | ||
7841 | advertise = this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
7842 | break; | ||
7843 | case "Class": | ||
7844 | classId = this.core.GetAttributeGuidValue(sourceLineNumbers, attrib, false); | ||
7845 | break; | ||
7846 | case "ContentType": | ||
7847 | contentType = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
7848 | break; | ||
7849 | case "Default": | ||
7850 | returnContentType = this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
7851 | break; | ||
7852 | default: | ||
7853 | this.core.UnexpectedAttribute(node, attrib); | ||
7854 | break; | ||
7855 | } | ||
7856 | } | ||
7857 | else | ||
7858 | { | ||
7859 | this.core.ParseExtensionAttribute(node, attrib); | ||
7860 | } | ||
7861 | } | ||
7862 | |||
7863 | if (null == contentType) | ||
7864 | { | ||
7865 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "ContentType")); | ||
7866 | } | ||
7867 | |||
7868 | // if the advertise state has not been set, default to non-advertised | ||
7869 | if (YesNoType.NotSet == advertise) | ||
7870 | { | ||
7871 | advertise = YesNoType.No; | ||
7872 | } | ||
7873 | |||
7874 | this.core.ParseForExtensionElements(node); | ||
7875 | |||
7876 | if (YesNoType.Yes == advertise) | ||
7877 | { | ||
7878 | if (YesNoType.Yes != parentAdvertised) | ||
7879 | { | ||
7880 | this.core.OnMessage(WixErrors.AdvertiseStateMustMatch(sourceLineNumbers, advertise.ToString(), parentAdvertised.ToString())); | ||
7881 | } | ||
7882 | |||
7883 | if (!this.core.EncounteredError) | ||
7884 | { | ||
7885 | Row row = this.core.CreateRow(sourceLineNumbers, "MIME"); | ||
7886 | row[0] = contentType; | ||
7887 | row[1] = extension; | ||
7888 | row[2] = classId; | ||
7889 | } | ||
7890 | } | ||
7891 | else if (YesNoType.No == advertise) | ||
7892 | { | ||
7893 | if (YesNoType.Yes == returnContentType && YesNoType.Yes == parentAdvertised) | ||
7894 | { | ||
7895 | this.core.OnMessage(WixErrors.CannotDefaultMismatchedAdvertiseStates(sourceLineNumbers)); | ||
7896 | } | ||
7897 | |||
7898 | this.core.CreateRegistryRow(sourceLineNumbers, MsiInterop.MsidbRegistryRootClassesRoot, String.Concat("MIME\\Database\\Content Type\\", contentType), "Extension", String.Concat(".", extension), componentId); | ||
7899 | if (null != classId) | ||
7900 | { | ||
7901 | this.core.CreateRegistryRow(sourceLineNumbers, MsiInterop.MsidbRegistryRootClassesRoot, String.Concat("MIME\\Database\\Content Type\\", contentType), "CLSID", classId, componentId); | ||
7902 | } | ||
7903 | } | ||
7904 | |||
7905 | return YesNoType.Yes == returnContentType ? contentType : null; | ||
7906 | } | ||
7907 | |||
7908 | /// <summary> | ||
7909 | /// Parses a module element. | ||
7910 | /// </summary> | ||
7911 | /// <param name="node">Element to parse.</param> | ||
7912 | private void ParseModuleElement(XElement node) | ||
7913 | { | ||
7914 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
7915 | int codepage = 0; | ||
7916 | string moduleId = null; | ||
7917 | string version = null; | ||
7918 | |||
7919 | this.activeName = null; | ||
7920 | this.activeLanguage = null; | ||
7921 | |||
7922 | foreach (XAttribute attrib in node.Attributes()) | ||
7923 | { | ||
7924 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
7925 | { | ||
7926 | switch (attrib.Name.LocalName) | ||
7927 | { | ||
7928 | case "Id": | ||
7929 | this.activeName = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
7930 | if ("PUT-MODULE-NAME-HERE" == this.activeName) | ||
7931 | { | ||
7932 | this.core.OnMessage(WixWarnings.PlaceholderValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, this.activeName)); | ||
7933 | } | ||
7934 | else | ||
7935 | { | ||
7936 | this.activeName = this.core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
7937 | } | ||
7938 | break; | ||
7939 | case "Codepage": | ||
7940 | codepage = this.core.GetAttributeCodePageValue(sourceLineNumbers, attrib); | ||
7941 | break; | ||
7942 | case "Guid": | ||
7943 | moduleId = this.core.GetAttributeGuidValue(sourceLineNumbers, attrib, false); | ||
7944 | this.core.OnMessage(WixWarnings.DeprecatedModuleGuidAttribute(sourceLineNumbers)); | ||
7945 | break; | ||
7946 | case "Language": | ||
7947 | this.activeLanguage = this.core.GetAttributeLocalizableIntegerValue(sourceLineNumbers, attrib, 0, short.MaxValue); | ||
7948 | break; | ||
7949 | case "Version": | ||
7950 | version = this.core.GetAttributeVersionValue(sourceLineNumbers, attrib); | ||
7951 | break; | ||
7952 | default: | ||
7953 | this.core.UnexpectedAttribute(node, attrib); | ||
7954 | break; | ||
7955 | } | ||
7956 | } | ||
7957 | else | ||
7958 | { | ||
7959 | this.core.ParseExtensionAttribute(node, attrib); | ||
7960 | } | ||
7961 | } | ||
7962 | |||
7963 | if (null == this.activeName) | ||
7964 | { | ||
7965 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
7966 | } | ||
7967 | |||
7968 | if (null == this.activeLanguage) | ||
7969 | { | ||
7970 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Language")); | ||
7971 | } | ||
7972 | |||
7973 | if (null == version) | ||
7974 | { | ||
7975 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Version")); | ||
7976 | } | ||
7977 | else if (!CompilerCore.IsValidModuleOrBundleVersion(version)) | ||
7978 | { | ||
7979 | this.core.OnMessage(WixWarnings.InvalidModuleOrBundleVersion(sourceLineNumbers, "Module", version)); | ||
7980 | } | ||
7981 | |||
7982 | try | ||
7983 | { | ||
7984 | this.compilingModule = true; // notice that we are actually building a Merge Module here | ||
7985 | this.core.CreateActiveSection(this.activeName, SectionType.Module, codepage); | ||
7986 | |||
7987 | foreach (XElement child in node.Elements()) | ||
7988 | { | ||
7989 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
7990 | { | ||
7991 | switch (child.Name.LocalName) | ||
7992 | { | ||
7993 | case "AdminExecuteSequence": | ||
7994 | case "AdminUISequence": | ||
7995 | case "AdvertiseExecuteSequence": | ||
7996 | case "InstallExecuteSequence": | ||
7997 | case "InstallUISequence": | ||
7998 | this.ParseSequenceElement(child, child.Name.LocalName); | ||
7999 | break; | ||
8000 | case "AppId": | ||
8001 | this.ParseAppIdElement(child, null, YesNoType.Yes, null, null, null); | ||
8002 | break; | ||
8003 | case "Binary": | ||
8004 | this.ParseBinaryElement(child); | ||
8005 | break; | ||
8006 | case "Component": | ||
8007 | this.ParseComponentElement(child, ComplexReferenceParentType.Module, this.activeName, this.activeLanguage, CompilerConstants.IntegerNotSet, null, null); | ||
8008 | break; | ||
8009 | case "ComponentGroupRef": | ||
8010 | this.ParseComponentGroupRefElement(child, ComplexReferenceParentType.Module, this.activeName, this.activeLanguage); | ||
8011 | break; | ||
8012 | case "ComponentRef": | ||
8013 | this.ParseComponentRefElement(child, ComplexReferenceParentType.Module, this.activeName, this.activeLanguage); | ||
8014 | break; | ||
8015 | case "Configuration": | ||
8016 | this.ParseConfigurationElement(child); | ||
8017 | break; | ||
8018 | case "CustomAction": | ||
8019 | this.ParseCustomActionElement(child); | ||
8020 | break; | ||
8021 | case "CustomActionRef": | ||
8022 | this.ParseSimpleRefElement(child, "CustomAction"); | ||
8023 | break; | ||
8024 | case "CustomTable": | ||
8025 | this.ParseCustomTableElement(child); | ||
8026 | break; | ||
8027 | case "Dependency": | ||
8028 | this.ParseDependencyElement(child); | ||
8029 | break; | ||
8030 | case "Directory": | ||
8031 | this.ParseDirectoryElement(child, null, CompilerConstants.IntegerNotSet, String.Empty); | ||
8032 | break; | ||
8033 | case "DirectoryRef": | ||
8034 | this.ParseDirectoryRefElement(child); | ||
8035 | break; | ||
8036 | case "EmbeddedChainer": | ||
8037 | this.ParseEmbeddedChainerElement(child); | ||
8038 | break; | ||
8039 | case "EmbeddedChainerRef": | ||
8040 | this.ParseSimpleRefElement(child, "MsiEmbeddedChainer"); | ||
8041 | break; | ||
8042 | case "EnsureTable": | ||
8043 | this.ParseEnsureTableElement(child); | ||
8044 | break; | ||
8045 | case "Exclusion": | ||
8046 | this.ParseExclusionElement(child); | ||
8047 | break; | ||
8048 | case "Icon": | ||
8049 | this.ParseIconElement(child); | ||
8050 | break; | ||
8051 | case "IgnoreModularization": | ||
8052 | this.ParseIgnoreModularizationElement(child); | ||
8053 | break; | ||
8054 | case "IgnoreTable": | ||
8055 | this.ParseIgnoreTableElement(child); | ||
8056 | break; | ||
8057 | case "Package": | ||
8058 | this.ParsePackageElement(child, null, moduleId); | ||
8059 | break; | ||
8060 | case "Property": | ||
8061 | this.ParsePropertyElement(child); | ||
8062 | break; | ||
8063 | case "PropertyRef": | ||
8064 | this.ParseSimpleRefElement(child, "Property"); | ||
8065 | break; | ||
8066 | case "SetDirectory": | ||
8067 | this.ParseSetDirectoryElement(child); | ||
8068 | break; | ||
8069 | case "SetProperty": | ||
8070 | this.ParseSetPropertyElement(child); | ||
8071 | break; | ||
8072 | case "SFPCatalog": | ||
8073 | string parentName = null; | ||
8074 | this.ParseSFPCatalogElement(child, ref parentName); | ||
8075 | break; | ||
8076 | case "Substitution": | ||
8077 | this.ParseSubstitutionElement(child); | ||
8078 | break; | ||
8079 | case "UI": | ||
8080 | this.ParseUIElement(child); | ||
8081 | break; | ||
8082 | case "UIRef": | ||
8083 | this.ParseSimpleRefElement(child, "WixUI"); | ||
8084 | break; | ||
8085 | case "WixVariable": | ||
8086 | this.ParseWixVariableElement(child); | ||
8087 | break; | ||
8088 | default: | ||
8089 | this.core.UnexpectedElement(node, child); | ||
8090 | break; | ||
8091 | } | ||
8092 | } | ||
8093 | else | ||
8094 | { | ||
8095 | this.core.ParseExtensionElement(node, child); | ||
8096 | } | ||
8097 | } | ||
8098 | |||
8099 | |||
8100 | if (!this.core.EncounteredError) | ||
8101 | { | ||
8102 | Row row = this.core.CreateRow(sourceLineNumbers, "ModuleSignature"); | ||
8103 | row[0] = this.activeName; | ||
8104 | row[1] = this.activeLanguage; | ||
8105 | row[2] = version; | ||
8106 | } | ||
8107 | } | ||
8108 | finally | ||
8109 | { | ||
8110 | this.compilingModule = false; // notice that we are no longer building a Merge Module here | ||
8111 | } | ||
8112 | } | ||
8113 | |||
8114 | /// <summary> | ||
8115 | /// Parses a patch creation element. | ||
8116 | /// </summary> | ||
8117 | /// <param name="node">The element to parse.</param> | ||
8118 | private void ParsePatchCreationElement(XElement node) | ||
8119 | { | ||
8120 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
8121 | bool clean = true; // Default is to clean | ||
8122 | int codepage = 0; | ||
8123 | string outputPath = null; | ||
8124 | bool productMismatches = false; | ||
8125 | string replaceGuids = String.Empty; | ||
8126 | string sourceList = null; | ||
8127 | string symbolFlags = null; | ||
8128 | string targetProducts = String.Empty; | ||
8129 | bool versionMismatches = false; | ||
8130 | bool wholeFiles = false; | ||
8131 | |||
8132 | foreach (XAttribute attrib in node.Attributes()) | ||
8133 | { | ||
8134 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
8135 | { | ||
8136 | switch (attrib.Name.LocalName) | ||
8137 | { | ||
8138 | case "Id": | ||
8139 | this.activeName = this.core.GetAttributeGuidValue(sourceLineNumbers, attrib, false); | ||
8140 | break; | ||
8141 | case "AllowMajorVersionMismatches": | ||
8142 | versionMismatches = YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
8143 | break; | ||
8144 | case "AllowProductCodeMismatches": | ||
8145 | productMismatches = YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
8146 | break; | ||
8147 | case "CleanWorkingFolder": | ||
8148 | clean = YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
8149 | break; | ||
8150 | case "Codepage": | ||
8151 | codepage = this.core.GetAttributeCodePageValue(sourceLineNumbers, attrib); | ||
8152 | break; | ||
8153 | case "OutputPath": | ||
8154 | outputPath = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
8155 | break; | ||
8156 | case "SourceList": | ||
8157 | sourceList = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
8158 | break; | ||
8159 | case "SymbolFlags": | ||
8160 | symbolFlags = String.Format(CultureInfo.InvariantCulture, "0x{0:x8}", this.core.GetAttributeLongValue(sourceLineNumbers, attrib, 0, uint.MaxValue)); | ||
8161 | break; | ||
8162 | case "WholeFilesOnly": | ||
8163 | wholeFiles = YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
8164 | break; | ||
8165 | default: | ||
8166 | this.core.UnexpectedAttribute(node, attrib); | ||
8167 | break; | ||
8168 | } | ||
8169 | } | ||
8170 | else | ||
8171 | { | ||
8172 | this.core.ParseExtensionAttribute(node, attrib); | ||
8173 | } | ||
8174 | } | ||
8175 | |||
8176 | if (null == this.activeName) | ||
8177 | { | ||
8178 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
8179 | } | ||
8180 | |||
8181 | this.core.CreateActiveSection(this.activeName, SectionType.PatchCreation, codepage); | ||
8182 | |||
8183 | foreach (XElement child in node.Elements()) | ||
8184 | { | ||
8185 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
8186 | { | ||
8187 | switch (child.Name.LocalName) | ||
8188 | { | ||
8189 | case "Family": | ||
8190 | this.ParseFamilyElement(child); | ||
8191 | break; | ||
8192 | case "PatchInformation": | ||
8193 | this.ParsePatchInformationElement(child); | ||
8194 | break; | ||
8195 | case "PatchMetadata": | ||
8196 | this.ParsePatchMetadataElement(child); | ||
8197 | break; | ||
8198 | case "PatchProperty": | ||
8199 | this.ParsePatchPropertyElement(child, false); | ||
8200 | break; | ||
8201 | case "PatchSequence": | ||
8202 | this.ParsePatchSequenceElement(child); | ||
8203 | break; | ||
8204 | case "ReplacePatch": | ||
8205 | replaceGuids = String.Concat(replaceGuids, this.ParseReplacePatchElement(child)); | ||
8206 | break; | ||
8207 | case "TargetProductCode": | ||
8208 | string targetProduct = this.ParseTargetProductCodeElement(child); | ||
8209 | if (0 < targetProducts.Length) | ||
8210 | { | ||
8211 | targetProducts = String.Concat(targetProducts, ";"); | ||
8212 | } | ||
8213 | targetProducts = String.Concat(targetProducts, targetProduct); | ||
8214 | break; | ||
8215 | default: | ||
8216 | this.core.UnexpectedElement(node, child); | ||
8217 | break; | ||
8218 | } | ||
8219 | } | ||
8220 | else | ||
8221 | { | ||
8222 | this.core.ParseExtensionElement(node, child); | ||
8223 | } | ||
8224 | } | ||
8225 | |||
8226 | this.ProcessProperties(sourceLineNumbers, "PatchGUID", this.activeName); | ||
8227 | this.ProcessProperties(sourceLineNumbers, "AllowProductCodeMismatches", productMismatches ? "1" : "0"); | ||
8228 | this.ProcessProperties(sourceLineNumbers, "AllowProductVersionMajorMismatches", versionMismatches ? "1" : "0"); | ||
8229 | this.ProcessProperties(sourceLineNumbers, "DontRemoveTempFolderWhenFinished", clean ? "0" : "1"); | ||
8230 | this.ProcessProperties(sourceLineNumbers, "IncludeWholeFilesOnly", wholeFiles ? "1" : "0"); | ||
8231 | |||
8232 | if (null != symbolFlags) | ||
8233 | { | ||
8234 | this.ProcessProperties(sourceLineNumbers, "ApiPatchingSymbolFlags", symbolFlags); | ||
8235 | } | ||
8236 | |||
8237 | if (0 < replaceGuids.Length) | ||
8238 | { | ||
8239 | this.ProcessProperties(sourceLineNumbers, "ListOfPatchGUIDsToReplace", replaceGuids); | ||
8240 | } | ||
8241 | |||
8242 | if (0 < targetProducts.Length) | ||
8243 | { | ||
8244 | this.ProcessProperties(sourceLineNumbers, "ListOfTargetProductCodes", targetProducts); | ||
8245 | } | ||
8246 | |||
8247 | if (null != outputPath) | ||
8248 | { | ||
8249 | this.ProcessProperties(sourceLineNumbers, "PatchOutputPath", outputPath); | ||
8250 | } | ||
8251 | |||
8252 | if (null != sourceList) | ||
8253 | { | ||
8254 | this.ProcessProperties(sourceLineNumbers, "PatchSourceList", sourceList); | ||
8255 | } | ||
8256 | } | ||
8257 | |||
8258 | /// <summary> | ||
8259 | /// Parses a family element. | ||
8260 | /// </summary> | ||
8261 | /// <param name="node">The element to parse.</param> | ||
8262 | private void ParseFamilyElement(XElement node) | ||
8263 | { | ||
8264 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
8265 | int diskId = CompilerConstants.IntegerNotSet; | ||
8266 | string diskPrompt = null; | ||
8267 | string mediaSrcProp = null; | ||
8268 | string name = null; | ||
8269 | int sequenceStart = CompilerConstants.IntegerNotSet; | ||
8270 | string volumeLabel = null; | ||
8271 | |||
8272 | foreach (XAttribute attrib in node.Attributes()) | ||
8273 | { | ||
8274 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
8275 | { | ||
8276 | switch (attrib.Name.LocalName) | ||
8277 | { | ||
8278 | case "DiskId": | ||
8279 | diskId = this.core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 1, short.MaxValue); | ||
8280 | break; | ||
8281 | case "DiskPrompt": | ||
8282 | diskPrompt = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
8283 | break; | ||
8284 | case "MediaSrcProp": | ||
8285 | mediaSrcProp = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
8286 | break; | ||
8287 | case "Name": | ||
8288 | name = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
8289 | break; | ||
8290 | case "SequenceStart": | ||
8291 | sequenceStart = this.core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 1, int.MaxValue); | ||
8292 | break; | ||
8293 | case "VolumeLabel": | ||
8294 | volumeLabel = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
8295 | break; | ||
8296 | default: | ||
8297 | this.core.UnexpectedAttribute(node, attrib); | ||
8298 | break; | ||
8299 | } | ||
8300 | } | ||
8301 | else | ||
8302 | { | ||
8303 | this.core.ParseExtensionAttribute(node, attrib); | ||
8304 | } | ||
8305 | } | ||
8306 | |||
8307 | if (null == name) | ||
8308 | { | ||
8309 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Name")); | ||
8310 | } | ||
8311 | else if (0 < name.Length) | ||
8312 | { | ||
8313 | if (8 < name.Length) // check the length | ||
8314 | { | ||
8315 | this.core.OnMessage(WixErrors.FamilyNameTooLong(sourceLineNumbers, node.Name.LocalName, "Name", name, name.Length)); | ||
8316 | } | ||
8317 | else // check for illegal characters | ||
8318 | { | ||
8319 | foreach (char character in name) | ||
8320 | { | ||
8321 | if (!Char.IsLetterOrDigit(character) && '_' != character) | ||
8322 | { | ||
8323 | this.core.OnMessage(WixErrors.IllegalFamilyName(sourceLineNumbers, node.Name.LocalName, "Name", name)); | ||
8324 | } | ||
8325 | } | ||
8326 | } | ||
8327 | } | ||
8328 | |||
8329 | foreach (XElement child in node.Elements()) | ||
8330 | { | ||
8331 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
8332 | { | ||
8333 | switch (child.Name.LocalName) | ||
8334 | { | ||
8335 | case "UpgradeImage": | ||
8336 | this.ParseUpgradeImageElement(child, name); | ||
8337 | break; | ||
8338 | case "ExternalFile": | ||
8339 | this.ParseExternalFileElement(child, name); | ||
8340 | break; | ||
8341 | case "ProtectFile": | ||
8342 | this.ParseProtectFileElement(child, name); | ||
8343 | break; | ||
8344 | default: | ||
8345 | this.core.UnexpectedElement(node, child); | ||
8346 | break; | ||
8347 | } | ||
8348 | } | ||
8349 | else | ||
8350 | { | ||
8351 | this.core.ParseExtensionElement(node, child); | ||
8352 | } | ||
8353 | } | ||
8354 | |||
8355 | if (!this.core.EncounteredError) | ||
8356 | { | ||
8357 | Row row = this.core.CreateRow(sourceLineNumbers, "ImageFamilies"); | ||
8358 | row[0] = name; | ||
8359 | row[1] = mediaSrcProp; | ||
8360 | if (CompilerConstants.IntegerNotSet != diskId) | ||
8361 | { | ||
8362 | row[2] = diskId; | ||
8363 | } | ||
8364 | |||
8365 | if (CompilerConstants.IntegerNotSet != sequenceStart) | ||
8366 | { | ||
8367 | row[3] = sequenceStart; | ||
8368 | } | ||
8369 | row[4] = diskPrompt; | ||
8370 | row[5] = volumeLabel; | ||
8371 | } | ||
8372 | } | ||
8373 | |||
8374 | /// <summary> | ||
8375 | /// Parses an upgrade image element. | ||
8376 | /// </summary> | ||
8377 | /// <param name="node">The element to parse.</param> | ||
8378 | /// <param name="family">The family for this element.</param> | ||
8379 | private void ParseUpgradeImageElement(XElement node, string family) | ||
8380 | { | ||
8381 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
8382 | string sourceFile = null; | ||
8383 | string sourcePatch = null; | ||
8384 | List<string> symbols = new List<string>(); | ||
8385 | string upgrade = null; | ||
8386 | |||
8387 | foreach (XAttribute attrib in node.Attributes()) | ||
8388 | { | ||
8389 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
8390 | { | ||
8391 | switch (attrib.Name.LocalName) | ||
8392 | { | ||
8393 | case "Id": | ||
8394 | upgrade = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
8395 | if (13 < upgrade.Length) | ||
8396 | { | ||
8397 | this.core.OnMessage(WixErrors.IdentifierTooLongError(sourceLineNumbers, node.Name.LocalName, "Id", upgrade, 13)); | ||
8398 | } | ||
8399 | break; | ||
8400 | case "SourceFile": | ||
8401 | case "src": | ||
8402 | if (null != sourceFile) | ||
8403 | { | ||
8404 | this.core.OnMessage(WixErrors.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "src", "SourceFile")); | ||
8405 | } | ||
8406 | |||
8407 | if ("src" == attrib.Name.LocalName) | ||
8408 | { | ||
8409 | this.core.OnMessage(WixWarnings.DeprecatedAttribute(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, "SourceFile")); | ||
8410 | } | ||
8411 | sourceFile = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
8412 | break; | ||
8413 | case "SourcePatch": | ||
8414 | case "srcPatch": | ||
8415 | if (null != sourcePatch) | ||
8416 | { | ||
8417 | this.core.OnMessage(WixErrors.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "srcPatch", "SourcePatch")); | ||
8418 | } | ||
8419 | |||
8420 | if ("srcPatch" == attrib.Name.LocalName) | ||
8421 | { | ||
8422 | this.core.OnMessage(WixWarnings.DeprecatedAttribute(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, "SourcePatch")); | ||
8423 | } | ||
8424 | sourcePatch = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
8425 | break; | ||
8426 | default: | ||
8427 | this.core.UnexpectedAttribute(node, attrib); | ||
8428 | break; | ||
8429 | } | ||
8430 | } | ||
8431 | else | ||
8432 | { | ||
8433 | this.core.ParseExtensionAttribute(node, attrib); | ||
8434 | } | ||
8435 | } | ||
8436 | |||
8437 | if (null == upgrade) | ||
8438 | { | ||
8439 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
8440 | } | ||
8441 | |||
8442 | if (null == sourceFile) | ||
8443 | { | ||
8444 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "SourceFile")); | ||
8445 | } | ||
8446 | |||
8447 | foreach (XElement child in node.Elements()) | ||
8448 | { | ||
8449 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
8450 | { | ||
8451 | switch (child.Name.LocalName) | ||
8452 | { | ||
8453 | case "SymbolPath": | ||
8454 | symbols.Add(this.ParseSymbolPathElement(child)); | ||
8455 | break; | ||
8456 | case "TargetImage": | ||
8457 | this.ParseTargetImageElement(child, upgrade, family); | ||
8458 | break; | ||
8459 | case "UpgradeFile": | ||
8460 | this.ParseUpgradeFileElement(child, upgrade); | ||
8461 | break; | ||
8462 | default: | ||
8463 | this.core.UnexpectedElement(node, child); | ||
8464 | break; | ||
8465 | } | ||
8466 | } | ||
8467 | else | ||
8468 | { | ||
8469 | this.core.ParseExtensionElement(node, child); | ||
8470 | } | ||
8471 | } | ||
8472 | |||
8473 | if (!this.core.EncounteredError) | ||
8474 | { | ||
8475 | Row row = this.core.CreateRow(sourceLineNumbers, "UpgradedImages"); | ||
8476 | row[0] = upgrade; | ||
8477 | row[1] = sourceFile; | ||
8478 | row[2] = sourcePatch; | ||
8479 | row[3] = String.Join(";", symbols); | ||
8480 | row[4] = family; | ||
8481 | } | ||
8482 | } | ||
8483 | |||
8484 | /// <summary> | ||
8485 | /// Parses an upgrade file element. | ||
8486 | /// </summary> | ||
8487 | /// <param name="node">The element to parse.</param> | ||
8488 | /// <param name="upgrade">The upgrade key for this element.</param> | ||
8489 | private void ParseUpgradeFileElement(XElement node, string upgrade) | ||
8490 | { | ||
8491 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
8492 | bool allowIgnoreOnError = false; | ||
8493 | string file = null; | ||
8494 | bool ignore = false; | ||
8495 | List<string> symbols = new List<string>(); | ||
8496 | bool wholeFile = false; | ||
8497 | |||
8498 | foreach (XAttribute attrib in node.Attributes()) | ||
8499 | { | ||
8500 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
8501 | { | ||
8502 | switch (attrib.Name.LocalName) | ||
8503 | { | ||
8504 | case "AllowIgnoreOnError": | ||
8505 | allowIgnoreOnError = YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
8506 | break; | ||
8507 | case "File": | ||
8508 | file = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
8509 | break; | ||
8510 | case "Ignore": | ||
8511 | ignore = YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
8512 | break; | ||
8513 | case "WholeFile": | ||
8514 | wholeFile = YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
8515 | break; | ||
8516 | default: | ||
8517 | this.core.UnexpectedAttribute(node, attrib); | ||
8518 | break; | ||
8519 | } | ||
8520 | } | ||
8521 | else | ||
8522 | { | ||
8523 | this.core.ParseExtensionAttribute(node, attrib); | ||
8524 | } | ||
8525 | } | ||
8526 | |||
8527 | if (null == file) | ||
8528 | { | ||
8529 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "File")); | ||
8530 | } | ||
8531 | |||
8532 | foreach (XElement child in node.Elements()) | ||
8533 | { | ||
8534 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
8535 | { | ||
8536 | switch (child.Name.LocalName) | ||
8537 | { | ||
8538 | case "SymbolPath": | ||
8539 | symbols.Add(this.ParseSymbolPathElement(child)); | ||
8540 | break; | ||
8541 | default: | ||
8542 | this.core.UnexpectedElement(node, child); | ||
8543 | break; | ||
8544 | } | ||
8545 | } | ||
8546 | else | ||
8547 | { | ||
8548 | this.core.ParseExtensionElement(node, child); | ||
8549 | } | ||
8550 | } | ||
8551 | |||
8552 | if (!this.core.EncounteredError) | ||
8553 | { | ||
8554 | if (ignore) | ||
8555 | { | ||
8556 | Row row = this.core.CreateRow(sourceLineNumbers, "UpgradedFilesToIgnore"); | ||
8557 | row[0] = upgrade; | ||
8558 | row[1] = file; | ||
8559 | } | ||
8560 | else | ||
8561 | { | ||
8562 | Row row = this.core.CreateRow(sourceLineNumbers, "UpgradedFiles_OptionalData"); | ||
8563 | row[0] = upgrade; | ||
8564 | row[1] = file; | ||
8565 | row[2] = String.Join(";", symbols); | ||
8566 | row[3] = allowIgnoreOnError ? 1 : 0; | ||
8567 | row[4] = wholeFile ? 1 : 0; | ||
8568 | } | ||
8569 | } | ||
8570 | } | ||
8571 | |||
8572 | /// <summary> | ||
8573 | /// Parses a target image element. | ||
8574 | /// </summary> | ||
8575 | /// <param name="node">The element to parse.</param> | ||
8576 | /// <param name="upgrade">The upgrade key for this element.</param> | ||
8577 | /// <param name="family">The family key for this element.</param> | ||
8578 | private void ParseTargetImageElement(XElement node, string upgrade, string family) | ||
8579 | { | ||
8580 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
8581 | bool ignore = false; | ||
8582 | int order = CompilerConstants.IntegerNotSet; | ||
8583 | string sourceFile = null; | ||
8584 | string symbols = null; | ||
8585 | string target = null; | ||
8586 | string validation = null; | ||
8587 | |||
8588 | foreach (XAttribute attrib in node.Attributes()) | ||
8589 | { | ||
8590 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
8591 | { | ||
8592 | switch (attrib.Name.LocalName) | ||
8593 | { | ||
8594 | case "Id": | ||
8595 | target = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
8596 | if (target.Length > 13) | ||
8597 | { | ||
8598 | this.core.OnMessage(WixErrors.IdentifierTooLongError(sourceLineNumbers, node.Name.LocalName, "Id", target, 13)); | ||
8599 | } | ||
8600 | break; | ||
8601 | case "IgnoreMissingFiles": | ||
8602 | ignore = YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
8603 | break; | ||
8604 | case "Order": | ||
8605 | order = this.core.GetAttributeIntegerValue(sourceLineNumbers, attrib, int.MinValue + 2, int.MaxValue); | ||
8606 | break; | ||
8607 | case "SourceFile": | ||
8608 | case "src": | ||
8609 | if (null != sourceFile) | ||
8610 | { | ||
8611 | this.core.OnMessage(WixErrors.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "src", "SourceFile")); | ||
8612 | } | ||
8613 | |||
8614 | if ("src" == attrib.Name.LocalName) | ||
8615 | { | ||
8616 | this.core.OnMessage(WixWarnings.DeprecatedAttribute(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, "SourceFile")); | ||
8617 | } | ||
8618 | sourceFile = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
8619 | break; | ||
8620 | case "Validation": | ||
8621 | validation = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
8622 | break; | ||
8623 | default: | ||
8624 | this.core.UnexpectedAttribute(node, attrib); | ||
8625 | break; | ||
8626 | } | ||
8627 | } | ||
8628 | else | ||
8629 | { | ||
8630 | this.core.ParseExtensionAttribute(node, attrib); | ||
8631 | } | ||
8632 | } | ||
8633 | |||
8634 | if (null == target) | ||
8635 | { | ||
8636 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
8637 | } | ||
8638 | |||
8639 | if (null == sourceFile) | ||
8640 | { | ||
8641 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "SourceFile")); | ||
8642 | } | ||
8643 | |||
8644 | if (CompilerConstants.IntegerNotSet == order) | ||
8645 | { | ||
8646 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Order")); | ||
8647 | } | ||
8648 | |||
8649 | foreach (XElement child in node.Elements()) | ||
8650 | { | ||
8651 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
8652 | { | ||
8653 | switch (child.Name.LocalName) | ||
8654 | { | ||
8655 | case "SymbolPath": | ||
8656 | if (null != symbols) | ||
8657 | { | ||
8658 | symbols = String.Concat(symbols, ";", this.ParseSymbolPathElement(child)); | ||
8659 | } | ||
8660 | else | ||
8661 | { | ||
8662 | symbols = this.ParseSymbolPathElement(child); | ||
8663 | } | ||
8664 | break; | ||
8665 | case "TargetFile": | ||
8666 | this.ParseTargetFileElement(child, target, family); | ||
8667 | break; | ||
8668 | default: | ||
8669 | this.core.UnexpectedElement(node, child); | ||
8670 | break; | ||
8671 | } | ||
8672 | } | ||
8673 | else | ||
8674 | { | ||
8675 | this.core.ParseExtensionElement(node, child); | ||
8676 | } | ||
8677 | } | ||
8678 | |||
8679 | if (!this.core.EncounteredError) | ||
8680 | { | ||
8681 | Row row = this.core.CreateRow(sourceLineNumbers, "TargetImages"); | ||
8682 | row[0] = target; | ||
8683 | row[1] = sourceFile; | ||
8684 | row[2] = symbols; | ||
8685 | row[3] = upgrade; | ||
8686 | row[4] = order; | ||
8687 | row[5] = validation; | ||
8688 | row[6] = ignore ? 1 : 0; | ||
8689 | } | ||
8690 | } | ||
8691 | |||
8692 | /// <summary> | ||
8693 | /// Parses an upgrade file element. | ||
8694 | /// </summary> | ||
8695 | /// <param name="node">The element to parse.</param> | ||
8696 | /// <param name="target">The upgrade key for this element.</param> | ||
8697 | /// <param name="family">The family key for this element.</param> | ||
8698 | private void ParseTargetFileElement(XElement node, string target, string family) | ||
8699 | { | ||
8700 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
8701 | string file = null; | ||
8702 | string ignoreLengths = null; | ||
8703 | string ignoreOffsets = null; | ||
8704 | string protectLengths = null; | ||
8705 | string protectOffsets = null; | ||
8706 | string symbols = null; | ||
8707 | |||
8708 | foreach (XAttribute attrib in node.Attributes()) | ||
8709 | { | ||
8710 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
8711 | { | ||
8712 | switch (attrib.Name.LocalName) | ||
8713 | { | ||
8714 | case "Id": | ||
8715 | file = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
8716 | break; | ||
8717 | default: | ||
8718 | this.core.UnexpectedAttribute(node, attrib); | ||
8719 | break; | ||
8720 | } | ||
8721 | } | ||
8722 | else | ||
8723 | { | ||
8724 | this.core.ParseExtensionAttribute(node, attrib); | ||
8725 | } | ||
8726 | } | ||
8727 | |||
8728 | if (null == file) | ||
8729 | { | ||
8730 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
8731 | } | ||
8732 | |||
8733 | foreach (XElement child in node.Elements()) | ||
8734 | { | ||
8735 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
8736 | { | ||
8737 | switch (child.Name.LocalName) | ||
8738 | { | ||
8739 | case "IgnoreRange": | ||
8740 | this.ParseRangeElement(child, ref ignoreOffsets, ref ignoreLengths); | ||
8741 | break; | ||
8742 | case "ProtectRange": | ||
8743 | this.ParseRangeElement(child, ref protectOffsets, ref protectLengths); | ||
8744 | break; | ||
8745 | case "SymbolPath": | ||
8746 | symbols = this.ParseSymbolPathElement(child); | ||
8747 | break; | ||
8748 | default: | ||
8749 | this.core.UnexpectedElement(node, child); | ||
8750 | break; | ||
8751 | } | ||
8752 | } | ||
8753 | else | ||
8754 | { | ||
8755 | this.core.ParseExtensionElement(node, child); | ||
8756 | } | ||
8757 | } | ||
8758 | |||
8759 | if (!this.core.EncounteredError) | ||
8760 | { | ||
8761 | Row row = this.core.CreateRow(sourceLineNumbers, "TargetFiles_OptionalData"); | ||
8762 | row[0] = target; | ||
8763 | row[1] = file; | ||
8764 | row[2] = symbols; | ||
8765 | row[3] = ignoreOffsets; | ||
8766 | row[4] = ignoreLengths; | ||
8767 | |||
8768 | if (null != protectOffsets) | ||
8769 | { | ||
8770 | row[5] = protectOffsets; | ||
8771 | |||
8772 | Row row2 = this.core.CreateRow(sourceLineNumbers, "FamilyFileRanges"); | ||
8773 | row2[0] = family; | ||
8774 | row2[1] = file; | ||
8775 | row2[2] = protectOffsets; | ||
8776 | row2[3] = protectLengths; | ||
8777 | } | ||
8778 | } | ||
8779 | } | ||
8780 | |||
8781 | /// <summary> | ||
8782 | /// Parses an external file element. | ||
8783 | /// </summary> | ||
8784 | /// <param name="node">The element to parse.</param> | ||
8785 | /// <param name="family">The family for this element.</param> | ||
8786 | private void ParseExternalFileElement(XElement node, string family) | ||
8787 | { | ||
8788 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
8789 | string file = null; | ||
8790 | string ignoreLengths = null; | ||
8791 | string ignoreOffsets = null; | ||
8792 | int order = CompilerConstants.IntegerNotSet; | ||
8793 | string protectLengths = null; | ||
8794 | string protectOffsets = null; | ||
8795 | string source = null; | ||
8796 | string symbols = null; | ||
8797 | |||
8798 | foreach (XAttribute attrib in node.Attributes()) | ||
8799 | { | ||
8800 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
8801 | { | ||
8802 | switch (attrib.Name.LocalName) | ||
8803 | { | ||
8804 | case "File": | ||
8805 | file = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
8806 | break; | ||
8807 | case "Order": | ||
8808 | order = this.core.GetAttributeIntegerValue(sourceLineNumbers, attrib, int.MinValue + 2, int.MaxValue); | ||
8809 | break; | ||
8810 | case "Source": | ||
8811 | case "src": | ||
8812 | if (null != source) | ||
8813 | { | ||
8814 | this.core.OnMessage(WixErrors.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "src", "Source")); | ||
8815 | } | ||
8816 | |||
8817 | if ("src" == attrib.Name.LocalName) | ||
8818 | { | ||
8819 | this.core.OnMessage(WixWarnings.DeprecatedAttribute(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, "Source")); | ||
8820 | } | ||
8821 | source = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
8822 | break; | ||
8823 | default: | ||
8824 | this.core.UnexpectedAttribute(node, attrib); | ||
8825 | break; | ||
8826 | } | ||
8827 | } | ||
8828 | else | ||
8829 | { | ||
8830 | this.core.ParseExtensionAttribute(node, attrib); | ||
8831 | } | ||
8832 | } | ||
8833 | |||
8834 | if (null == file) | ||
8835 | { | ||
8836 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "File")); | ||
8837 | } | ||
8838 | |||
8839 | if (null == source) | ||
8840 | { | ||
8841 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Source")); | ||
8842 | } | ||
8843 | |||
8844 | if (CompilerConstants.IntegerNotSet == order) | ||
8845 | { | ||
8846 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Order")); | ||
8847 | } | ||
8848 | |||
8849 | foreach (XElement child in node.Elements()) | ||
8850 | { | ||
8851 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
8852 | { | ||
8853 | switch (child.Name.LocalName) | ||
8854 | { | ||
8855 | case "IgnoreRange": | ||
8856 | this.ParseRangeElement(child, ref ignoreOffsets, ref ignoreLengths); | ||
8857 | break; | ||
8858 | case "ProtectRange": | ||
8859 | this.ParseRangeElement(child, ref protectOffsets, ref protectLengths); | ||
8860 | break; | ||
8861 | case "SymbolPath": | ||
8862 | symbols = this.ParseSymbolPathElement(child); | ||
8863 | break; | ||
8864 | default: | ||
8865 | this.core.UnexpectedElement(node, child); | ||
8866 | break; | ||
8867 | } | ||
8868 | } | ||
8869 | else | ||
8870 | { | ||
8871 | this.core.ParseExtensionElement(node, child); | ||
8872 | } | ||
8873 | } | ||
8874 | |||
8875 | if (!this.core.EncounteredError) | ||
8876 | { | ||
8877 | Row row = this.core.CreateRow(sourceLineNumbers, "ExternalFiles"); | ||
8878 | row[0] = family; | ||
8879 | row[1] = file; | ||
8880 | row[2] = source; | ||
8881 | row[3] = symbols; | ||
8882 | row[4] = ignoreOffsets; | ||
8883 | row[5] = ignoreLengths; | ||
8884 | if (null != protectOffsets) | ||
8885 | { | ||
8886 | row[6] = protectOffsets; | ||
8887 | } | ||
8888 | |||
8889 | if (CompilerConstants.IntegerNotSet != order) | ||
8890 | { | ||
8891 | row[7] = order; | ||
8892 | } | ||
8893 | |||
8894 | if (null != protectOffsets) | ||
8895 | { | ||
8896 | Row row2 = this.core.CreateRow(sourceLineNumbers, "FamilyFileRanges"); | ||
8897 | row2[0] = family; | ||
8898 | row2[1] = file; | ||
8899 | row2[2] = protectOffsets; | ||
8900 | row2[3] = protectLengths; | ||
8901 | } | ||
8902 | } | ||
8903 | } | ||
8904 | |||
8905 | /// <summary> | ||
8906 | /// Parses a protect file element. | ||
8907 | /// </summary> | ||
8908 | /// <param name="node">The element to parse.</param> | ||
8909 | /// <param name="family">The family for this element.</param> | ||
8910 | private void ParseProtectFileElement(XElement node, string family) | ||
8911 | { | ||
8912 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
8913 | string file = null; | ||
8914 | string protectLengths = null; | ||
8915 | string protectOffsets = null; | ||
8916 | |||
8917 | foreach (XAttribute attrib in node.Attributes()) | ||
8918 | { | ||
8919 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
8920 | { | ||
8921 | switch (attrib.Name.LocalName) | ||
8922 | { | ||
8923 | case "File": | ||
8924 | file = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
8925 | break; | ||
8926 | default: | ||
8927 | this.core.UnexpectedAttribute(node, attrib); | ||
8928 | break; | ||
8929 | } | ||
8930 | } | ||
8931 | else | ||
8932 | { | ||
8933 | this.core.ParseExtensionAttribute(node, attrib); | ||
8934 | } | ||
8935 | } | ||
8936 | |||
8937 | if (null == file) | ||
8938 | { | ||
8939 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "File")); | ||
8940 | } | ||
8941 | |||
8942 | foreach (XElement child in node.Elements()) | ||
8943 | { | ||
8944 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
8945 | { | ||
8946 | switch (child.Name.LocalName) | ||
8947 | { | ||
8948 | case "ProtectRange": | ||
8949 | this.ParseRangeElement(child, ref protectOffsets, ref protectLengths); | ||
8950 | break; | ||
8951 | default: | ||
8952 | this.core.UnexpectedElement(node, child); | ||
8953 | break; | ||
8954 | } | ||
8955 | } | ||
8956 | else | ||
8957 | { | ||
8958 | this.core.ParseExtensionElement(node, child); | ||
8959 | } | ||
8960 | } | ||
8961 | |||
8962 | if (null == protectOffsets || null == protectLengths) | ||
8963 | { | ||
8964 | this.core.OnMessage(WixErrors.ExpectedElement(sourceLineNumbers, node.Name.LocalName, "ProtectRange")); | ||
8965 | } | ||
8966 | |||
8967 | if (!this.core.EncounteredError) | ||
8968 | { | ||
8969 | Row row = this.core.CreateRow(sourceLineNumbers, "FamilyFileRanges"); | ||
8970 | row[0] = family; | ||
8971 | row[1] = file; | ||
8972 | row[2] = protectOffsets; | ||
8973 | row[3] = protectLengths; | ||
8974 | } | ||
8975 | } | ||
8976 | |||
8977 | /// <summary> | ||
8978 | /// Parses a range element (ProtectRange, IgnoreRange, etc). | ||
8979 | /// </summary> | ||
8980 | /// <param name="node">The element to parse.</param> | ||
8981 | /// <param name="offsets">Reference to the offsets string.</param> | ||
8982 | /// <param name="lengths">Reference to the lengths string.</param> | ||
8983 | private void ParseRangeElement(XElement node, ref string offsets, ref string lengths) | ||
8984 | { | ||
8985 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
8986 | string length = null; | ||
8987 | string offset = null; | ||
8988 | |||
8989 | foreach (XAttribute attrib in node.Attributes()) | ||
8990 | { | ||
8991 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
8992 | { | ||
8993 | switch (attrib.Name.LocalName) | ||
8994 | { | ||
8995 | case "Length": | ||
8996 | length = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
8997 | break; | ||
8998 | case "Offset": | ||
8999 | offset = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
9000 | break; | ||
9001 | default: | ||
9002 | this.core.UnexpectedAttribute(node, attrib); | ||
9003 | break; | ||
9004 | } | ||
9005 | } | ||
9006 | else | ||
9007 | { | ||
9008 | this.core.ParseExtensionAttribute(node, attrib); | ||
9009 | } | ||
9010 | } | ||
9011 | |||
9012 | if (null == length) | ||
9013 | { | ||
9014 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Length")); | ||
9015 | } | ||
9016 | |||
9017 | if (null == offset) | ||
9018 | { | ||
9019 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Offset")); | ||
9020 | } | ||
9021 | |||
9022 | this.core.ParseForExtensionElements(node); | ||
9023 | |||
9024 | if (null != lengths) | ||
9025 | { | ||
9026 | lengths = String.Concat(lengths, ",", length); | ||
9027 | } | ||
9028 | else | ||
9029 | { | ||
9030 | lengths = length; | ||
9031 | } | ||
9032 | |||
9033 | if (null != offsets) | ||
9034 | { | ||
9035 | offsets = String.Concat(offsets, ",", offset); | ||
9036 | } | ||
9037 | else | ||
9038 | { | ||
9039 | offsets = offset; | ||
9040 | } | ||
9041 | } | ||
9042 | |||
9043 | /// <summary> | ||
9044 | /// Parses a patch property element. | ||
9045 | /// </summary> | ||
9046 | /// <param name="node">The element to parse.</param> | ||
9047 | /// <param name="patch">True if parsing an patch element.</param> | ||
9048 | private void ParsePatchPropertyElement(XElement node, bool patch) | ||
9049 | { | ||
9050 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
9051 | string name = null; | ||
9052 | string company = null; | ||
9053 | string value = null; | ||
9054 | |||
9055 | foreach (XAttribute attrib in node.Attributes()) | ||
9056 | { | ||
9057 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
9058 | { | ||
9059 | switch (attrib.Name.LocalName) | ||
9060 | { | ||
9061 | case "Id": | ||
9062 | case "Name": | ||
9063 | name = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
9064 | break; | ||
9065 | case "Company": | ||
9066 | company = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
9067 | break; | ||
9068 | case "Value": | ||
9069 | value = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
9070 | break; | ||
9071 | default: | ||
9072 | this.core.UnexpectedAttribute(node, attrib); | ||
9073 | break; | ||
9074 | } | ||
9075 | } | ||
9076 | else | ||
9077 | { | ||
9078 | this.core.ParseExtensionAttribute(node, attrib); | ||
9079 | } | ||
9080 | } | ||
9081 | |||
9082 | if (null == name) | ||
9083 | { | ||
9084 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Name")); | ||
9085 | } | ||
9086 | |||
9087 | if (null == value) | ||
9088 | { | ||
9089 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Value")); | ||
9090 | } | ||
9091 | |||
9092 | this.core.ParseForExtensionElements(node); | ||
9093 | |||
9094 | if (patch) | ||
9095 | { | ||
9096 | // /Patch/PatchProperty goes directly into MsiPatchMetadata table | ||
9097 | Row row = this.core.CreateRow(sourceLineNumbers, "MsiPatchMetadata"); | ||
9098 | row[0] = company; | ||
9099 | row[1] = name; | ||
9100 | row[2] = value; | ||
9101 | } | ||
9102 | else | ||
9103 | { | ||
9104 | if (null != company) | ||
9105 | { | ||
9106 | this.core.OnMessage(WixErrors.UnexpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Company")); | ||
9107 | } | ||
9108 | this.ProcessProperties(sourceLineNumbers, name, value); | ||
9109 | } | ||
9110 | } | ||
9111 | |||
9112 | /// <summary> | ||
9113 | /// Parses a patch sequence element. | ||
9114 | /// </summary> | ||
9115 | /// <param name="node">The element to parse.</param> | ||
9116 | private void ParsePatchSequenceElement(XElement node) | ||
9117 | { | ||
9118 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
9119 | string family = null; | ||
9120 | string target = null; | ||
9121 | string sequence = null; | ||
9122 | int attributes = 0; | ||
9123 | |||
9124 | foreach (XAttribute attrib in node.Attributes()) | ||
9125 | { | ||
9126 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
9127 | { | ||
9128 | switch (attrib.Name.LocalName) | ||
9129 | { | ||
9130 | case "PatchFamily": | ||
9131 | family = this.core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
9132 | break; | ||
9133 | case "ProductCode": | ||
9134 | if (null != target) | ||
9135 | { | ||
9136 | this.core.OnMessage(WixErrors.IllegalAttributeWithOtherAttributes(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, "Target", "TargetImage")); | ||
9137 | } | ||
9138 | target = this.core.GetAttributeGuidValue(sourceLineNumbers, attrib, false); | ||
9139 | break; | ||
9140 | case "Target": | ||
9141 | if (null != target) | ||
9142 | { | ||
9143 | this.core.OnMessage(WixErrors.IllegalAttributeWithOtherAttributes(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, "TargetImage", "ProductCode")); | ||
9144 | } | ||
9145 | this.core.OnMessage(WixWarnings.DeprecatedPatchSequenceTargetAttribute(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); | ||
9146 | target = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
9147 | break; | ||
9148 | case "TargetImage": | ||
9149 | if (null != target) | ||
9150 | { | ||
9151 | this.core.OnMessage(WixErrors.IllegalAttributeWithOtherAttributes(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, "Target", "ProductCode")); | ||
9152 | } | ||
9153 | target = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
9154 | this.core.CreateSimpleReference(sourceLineNumbers, "TargetImages", target); | ||
9155 | break; | ||
9156 | case "Sequence": | ||
9157 | sequence = this.core.GetAttributeVersionValue(sourceLineNumbers, attrib); | ||
9158 | break; | ||
9159 | case "Supersede": | ||
9160 | if (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
9161 | { | ||
9162 | attributes |= 0x1; | ||
9163 | } | ||
9164 | break; | ||
9165 | default: | ||
9166 | this.core.UnexpectedAttribute(node, attrib); | ||
9167 | break; | ||
9168 | } | ||
9169 | } | ||
9170 | else | ||
9171 | { | ||
9172 | this.core.ParseExtensionAttribute(node, attrib); | ||
9173 | } | ||
9174 | } | ||
9175 | |||
9176 | if (null == family) | ||
9177 | { | ||
9178 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "PatchFamily")); | ||
9179 | } | ||
9180 | |||
9181 | this.core.ParseForExtensionElements(node); | ||
9182 | |||
9183 | if (!this.core.EncounteredError) | ||
9184 | { | ||
9185 | Row row = this.core.CreateRow(sourceLineNumbers, "PatchSequence"); | ||
9186 | row[0] = family; | ||
9187 | row[1] = target; | ||
9188 | if (!String.IsNullOrEmpty(sequence)) | ||
9189 | { | ||
9190 | row[2] = sequence; | ||
9191 | } | ||
9192 | row[3] = attributes; | ||
9193 | } | ||
9194 | } | ||
9195 | |||
9196 | /// <summary> | ||
9197 | /// Parses a TargetProductCode element. | ||
9198 | /// </summary> | ||
9199 | /// <param name="node">The element to parse.</param> | ||
9200 | /// <returns>The id from the node.</returns> | ||
9201 | private string ParseTargetProductCodeElement(XElement node) | ||
9202 | { | ||
9203 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
9204 | string id = null; | ||
9205 | |||
9206 | foreach (XAttribute attrib in node.Attributes()) | ||
9207 | { | ||
9208 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
9209 | { | ||
9210 | switch (attrib.Name.LocalName) | ||
9211 | { | ||
9212 | case "Id": | ||
9213 | id = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
9214 | if (id.Length > 0 && "*" != id) | ||
9215 | { | ||
9216 | id = this.core.GetAttributeGuidValue(sourceLineNumbers, attrib, false); | ||
9217 | } | ||
9218 | break; | ||
9219 | default: | ||
9220 | this.core.UnexpectedAttribute(node, attrib); | ||
9221 | break; | ||
9222 | } | ||
9223 | } | ||
9224 | else | ||
9225 | { | ||
9226 | this.core.ParseExtensionAttribute(node, attrib); | ||
9227 | } | ||
9228 | } | ||
9229 | |||
9230 | if (null == id) | ||
9231 | { | ||
9232 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
9233 | } | ||
9234 | |||
9235 | this.core.ParseForExtensionElements(node); | ||
9236 | |||
9237 | return id; | ||
9238 | } | ||
9239 | |||
9240 | /// <summary> | ||
9241 | /// Parses a TargetProductCodes element. | ||
9242 | /// </summary> | ||
9243 | /// <param name="node">The element to parse.</param> | ||
9244 | private void ParseTargetProductCodesElement(XElement node) | ||
9245 | { | ||
9246 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
9247 | bool replace = false; | ||
9248 | List<string> targetProductCodes = new List<string>(); | ||
9249 | |||
9250 | foreach (XAttribute attrib in node.Attributes()) | ||
9251 | { | ||
9252 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
9253 | { | ||
9254 | switch (attrib.Name.LocalName) | ||
9255 | { | ||
9256 | case "Replace": | ||
9257 | replace = YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
9258 | break; | ||
9259 | default: | ||
9260 | this.core.UnexpectedAttribute(node, attrib); | ||
9261 | break; | ||
9262 | } | ||
9263 | } | ||
9264 | else | ||
9265 | { | ||
9266 | this.core.ParseExtensionAttribute(node, attrib); | ||
9267 | } | ||
9268 | } | ||
9269 | |||
9270 | foreach (XElement child in node.Elements()) | ||
9271 | { | ||
9272 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
9273 | { | ||
9274 | switch (child.Name.LocalName) | ||
9275 | { | ||
9276 | case "TargetProductCode": | ||
9277 | string id = this.ParseTargetProductCodeElement(child); | ||
9278 | if (0 == String.CompareOrdinal("*", id)) | ||
9279 | { | ||
9280 | this.core.OnMessage(WixErrors.IllegalAttributeValueWhenNested(sourceLineNumbers, child.Name.LocalName, "Id", id, node.Name.LocalName)); | ||
9281 | } | ||
9282 | else | ||
9283 | { | ||
9284 | targetProductCodes.Add(id); | ||
9285 | } | ||
9286 | break; | ||
9287 | default: | ||
9288 | this.core.UnexpectedElement(node, child); | ||
9289 | break; | ||
9290 | } | ||
9291 | } | ||
9292 | else | ||
9293 | { | ||
9294 | this.core.ParseExtensionElement(node, child); | ||
9295 | } | ||
9296 | } | ||
9297 | |||
9298 | if (!this.core.EncounteredError) | ||
9299 | { | ||
9300 | // By default, target ProductCodes should be added. | ||
9301 | if (!replace) | ||
9302 | { | ||
9303 | Row row = this.core.CreateRow(sourceLineNumbers, "WixPatchTarget"); | ||
9304 | row[0] = "*"; | ||
9305 | } | ||
9306 | |||
9307 | foreach (string targetProductCode in targetProductCodes) | ||
9308 | { | ||
9309 | Row row = this.core.CreateRow(sourceLineNumbers, "WixPatchTarget"); | ||
9310 | row[0] = targetProductCode; | ||
9311 | } | ||
9312 | } | ||
9313 | } | ||
9314 | |||
9315 | /// <summary> | ||
9316 | /// Parses a ReplacePatch element. | ||
9317 | /// </summary> | ||
9318 | /// <param name="node">The element to parse.</param> | ||
9319 | /// <returns>The id from the node.</returns> | ||
9320 | private string ParseReplacePatchElement(XElement node) | ||
9321 | { | ||
9322 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
9323 | string id = null; | ||
9324 | |||
9325 | foreach (XAttribute attrib in node.Attributes()) | ||
9326 | { | ||
9327 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
9328 | { | ||
9329 | switch (attrib.Name.LocalName) | ||
9330 | { | ||
9331 | case "Id": | ||
9332 | id = this.core.GetAttributeGuidValue(sourceLineNumbers, attrib, false); | ||
9333 | break; | ||
9334 | default: | ||
9335 | this.core.UnexpectedAttribute(node, attrib); | ||
9336 | break; | ||
9337 | } | ||
9338 | } | ||
9339 | else | ||
9340 | { | ||
9341 | this.core.ParseExtensionAttribute(node, attrib); | ||
9342 | } | ||
9343 | } | ||
9344 | |||
9345 | if (null == id) | ||
9346 | { | ||
9347 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
9348 | } | ||
9349 | |||
9350 | this.core.ParseForExtensionElements(node); | ||
9351 | |||
9352 | return id; | ||
9353 | } | ||
9354 | |||
9355 | /// <summary> | ||
9356 | /// Parses a symbol path element. | ||
9357 | /// </summary> | ||
9358 | /// <param name="node">The element to parse.</param> | ||
9359 | /// <returns>The path from the node.</returns> | ||
9360 | private string ParseSymbolPathElement(XElement node) | ||
9361 | { | ||
9362 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
9363 | string path = null; | ||
9364 | |||
9365 | foreach (XAttribute attrib in node.Attributes()) | ||
9366 | { | ||
9367 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
9368 | { | ||
9369 | switch (attrib.Name.LocalName) | ||
9370 | { | ||
9371 | case "Path": | ||
9372 | path = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
9373 | break; | ||
9374 | default: | ||
9375 | this.core.UnexpectedAttribute(node, attrib); | ||
9376 | break; | ||
9377 | } | ||
9378 | } | ||
9379 | else | ||
9380 | { | ||
9381 | this.core.ParseExtensionAttribute(node, attrib); | ||
9382 | } | ||
9383 | } | ||
9384 | |||
9385 | if (null == path) | ||
9386 | { | ||
9387 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Path")); | ||
9388 | } | ||
9389 | |||
9390 | this.core.ParseForExtensionElements(node); | ||
9391 | |||
9392 | return path; | ||
9393 | } | ||
9394 | |||
9395 | /// <summary> | ||
9396 | /// Parses an patch element. | ||
9397 | /// </summary> | ||
9398 | /// <param name="node">The element to parse.</param> | ||
9399 | private void ParsePatchElement(XElement node) | ||
9400 | { | ||
9401 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
9402 | string patchId = null; | ||
9403 | int codepage = 0; | ||
9404 | ////bool versionMismatches = false; | ||
9405 | ////bool productMismatches = false; | ||
9406 | bool allowRemoval = false; | ||
9407 | string classification = null; | ||
9408 | string clientPatchId = null; | ||
9409 | string description = null; | ||
9410 | string displayName = null; | ||
9411 | string comments = null; | ||
9412 | string manufacturer = null; | ||
9413 | YesNoType minorUpdateTargetRTM = YesNoType.NotSet; | ||
9414 | string moreInfoUrl = null; | ||
9415 | int optimizeCA = CompilerConstants.IntegerNotSet; | ||
9416 | YesNoType optimizedInstallMode = YesNoType.NotSet; | ||
9417 | string targetProductName = null; | ||
9418 | // string replaceGuids = String.Empty; | ||
9419 | int apiPatchingSymbolFlags = 0; | ||
9420 | bool optimizePatchSizeForLargeFiles = false; | ||
9421 | |||
9422 | foreach (XAttribute attrib in node.Attributes()) | ||
9423 | { | ||
9424 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
9425 | { | ||
9426 | switch (attrib.Name.LocalName) | ||
9427 | { | ||
9428 | case "Id": | ||
9429 | patchId = this.core.GetAttributeGuidValue(sourceLineNumbers, attrib, true); | ||
9430 | break; | ||
9431 | case "Codepage": | ||
9432 | codepage = this.core.GetAttributeCodePageValue(sourceLineNumbers, attrib); | ||
9433 | break; | ||
9434 | case "AllowMajorVersionMismatches": | ||
9435 | ////versionMismatches = (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)); | ||
9436 | break; | ||
9437 | case "AllowProductCodeMismatches": | ||
9438 | ////productMismatches = (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)); | ||
9439 | break; | ||
9440 | case "AllowRemoval": | ||
9441 | allowRemoval = (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)); | ||
9442 | break; | ||
9443 | case "Classification": | ||
9444 | classification = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
9445 | break; | ||
9446 | case "ClientPatchId": | ||
9447 | clientPatchId = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
9448 | break; | ||
9449 | case "Description": | ||
9450 | description = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
9451 | break; | ||
9452 | case "DisplayName": | ||
9453 | displayName = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
9454 | break; | ||
9455 | case "Comments": | ||
9456 | comments = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
9457 | break; | ||
9458 | case "Manufacturer": | ||
9459 | manufacturer = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
9460 | break; | ||
9461 | case "MinorUpdateTargetRTM": | ||
9462 | minorUpdateTargetRTM = this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
9463 | break; | ||
9464 | case "MoreInfoURL": | ||
9465 | moreInfoUrl = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
9466 | break; | ||
9467 | case "OptimizedInstallMode": | ||
9468 | optimizedInstallMode = this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
9469 | break; | ||
9470 | case "TargetProductName": | ||
9471 | targetProductName = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
9472 | break; | ||
9473 | case "ApiPatchingSymbolNoImagehlpFlag": | ||
9474 | apiPatchingSymbolFlags |= (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) ? (int)PatchAPI.PatchInterop.PatchSymbolFlagsType.PATCH_SYMBOL_NO_IMAGEHLP : 0; | ||
9475 | break; | ||
9476 | case "ApiPatchingSymbolNoFailuresFlag": | ||
9477 | apiPatchingSymbolFlags |= (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) ? (int)PatchAPI.PatchInterop.PatchSymbolFlagsType.PATCH_SYMBOL_NO_FAILURES : 0; | ||
9478 | break; | ||
9479 | case "ApiPatchingSymbolUndecoratedTooFlag": | ||
9480 | apiPatchingSymbolFlags |= (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) ? (int)PatchAPI.PatchInterop.PatchSymbolFlagsType.PATCH_SYMBOL_UNDECORATED_TOO : 0; | ||
9481 | break; | ||
9482 | case "OptimizePatchSizeForLargeFiles": | ||
9483 | optimizePatchSizeForLargeFiles = (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)); | ||
9484 | break; | ||
9485 | default: | ||
9486 | this.core.UnexpectedAttribute(node, attrib); | ||
9487 | break; | ||
9488 | } | ||
9489 | } | ||
9490 | else | ||
9491 | { | ||
9492 | this.core.ParseExtensionAttribute(node, attrib); | ||
9493 | } | ||
9494 | } | ||
9495 | |||
9496 | if (patchId == null || patchId == "*") | ||
9497 | { | ||
9498 | // auto-generate at compile time, since this value gets dispersed to several locations | ||
9499 | patchId = Common.GenerateGuid(); | ||
9500 | } | ||
9501 | this.activeName = patchId; | ||
9502 | |||
9503 | if (null == this.activeName) | ||
9504 | { | ||
9505 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
9506 | } | ||
9507 | if (null == classification) | ||
9508 | { | ||
9509 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Classification")); | ||
9510 | } | ||
9511 | if (null == clientPatchId) | ||
9512 | { | ||
9513 | clientPatchId = String.Concat("_", new Guid(patchId).ToString("N", CultureInfo.InvariantCulture).ToUpper(CultureInfo.InvariantCulture)); | ||
9514 | } | ||
9515 | if (null == description) | ||
9516 | { | ||
9517 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Description")); | ||
9518 | } | ||
9519 | if (null == displayName) | ||
9520 | { | ||
9521 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "DisplayName")); | ||
9522 | } | ||
9523 | if (null == manufacturer) | ||
9524 | { | ||
9525 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Manufacturer")); | ||
9526 | } | ||
9527 | |||
9528 | this.core.CreateActiveSection(this.activeName, SectionType.Patch, codepage); | ||
9529 | |||
9530 | foreach (XElement child in node.Elements()) | ||
9531 | { | ||
9532 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
9533 | { | ||
9534 | switch (child.Name.LocalName) | ||
9535 | { | ||
9536 | case "PatchInformation": | ||
9537 | this.ParsePatchInformationElement(child); | ||
9538 | break; | ||
9539 | case "Media": | ||
9540 | this.ParseMediaElement(child, patchId); | ||
9541 | break; | ||
9542 | case "OptimizeCustomActions": | ||
9543 | optimizeCA = this.ParseOptimizeCustomActionsElement(child); | ||
9544 | break; | ||
9545 | case "PatchFamily": | ||
9546 | this.ParsePatchFamilyElement(child, ComplexReferenceParentType.Patch, patchId); | ||
9547 | break; | ||
9548 | case "PatchFamilyRef": | ||
9549 | this.ParsePatchFamilyRefElement(child, ComplexReferenceParentType.Patch, patchId); | ||
9550 | break; | ||
9551 | case "PatchFamilyGroup": | ||
9552 | this.ParsePatchFamilyGroupElement(child, ComplexReferenceParentType.Patch, patchId); | ||
9553 | break; | ||
9554 | case "PatchFamilyGroupRef": | ||
9555 | this.ParsePatchFamilyGroupRefElement(child, ComplexReferenceParentType.Patch, patchId); | ||
9556 | break; | ||
9557 | case "PatchProperty": | ||
9558 | this.ParsePatchPropertyElement(child, true); | ||
9559 | break; | ||
9560 | case "TargetProductCodes": | ||
9561 | this.ParseTargetProductCodesElement(child); | ||
9562 | break; | ||
9563 | default: | ||
9564 | this.core.UnexpectedElement(node, child); | ||
9565 | break; | ||
9566 | } | ||
9567 | } | ||
9568 | else | ||
9569 | { | ||
9570 | this.core.ParseExtensionElement(node, child); | ||
9571 | } | ||
9572 | } | ||
9573 | |||
9574 | |||
9575 | if (!this.core.EncounteredError) | ||
9576 | { | ||
9577 | Row patchIdRow = this.core.CreateRow(sourceLineNumbers, "WixPatchId"); | ||
9578 | patchIdRow[0] = patchId; | ||
9579 | patchIdRow[1] = clientPatchId; | ||
9580 | patchIdRow[2] = optimizePatchSizeForLargeFiles ? 1 : 0; | ||
9581 | patchIdRow[3] = apiPatchingSymbolFlags; | ||
9582 | |||
9583 | if (allowRemoval) | ||
9584 | { | ||
9585 | Row row = this.core.CreateRow(sourceLineNumbers, "MsiPatchMetadata"); | ||
9586 | row[0] = null; | ||
9587 | row[1] = "AllowRemoval"; | ||
9588 | row[2] = allowRemoval ? "1" : "0"; | ||
9589 | } | ||
9590 | |||
9591 | if (null != classification) | ||
9592 | { | ||
9593 | Row row = this.core.CreateRow(sourceLineNumbers, "MsiPatchMetadata"); | ||
9594 | row[0] = null; | ||
9595 | row[1] = "Classification"; | ||
9596 | row[2] = classification; | ||
9597 | } | ||
9598 | |||
9599 | // always generate the CreationTimeUTC | ||
9600 | { | ||
9601 | Row row = this.core.CreateRow(sourceLineNumbers, "MsiPatchMetadata"); | ||
9602 | row[0] = null; | ||
9603 | row[1] = "CreationTimeUTC"; | ||
9604 | row[2] = DateTime.UtcNow.ToString("MM-dd-yy HH:mm", CultureInfo.InvariantCulture); | ||
9605 | } | ||
9606 | |||
9607 | if (null != description) | ||
9608 | { | ||
9609 | Row row = this.core.CreateRow(sourceLineNumbers, "MsiPatchMetadata"); | ||
9610 | row[0] = null; | ||
9611 | row[1] = "Description"; | ||
9612 | row[2] = description; | ||
9613 | } | ||
9614 | |||
9615 | if (null != displayName) | ||
9616 | { | ||
9617 | Row row = this.core.CreateRow(sourceLineNumbers, "MsiPatchMetadata"); | ||
9618 | row[0] = null; | ||
9619 | row[1] = "DisplayName"; | ||
9620 | row[2] = displayName; | ||
9621 | } | ||
9622 | |||
9623 | if (null != manufacturer) | ||
9624 | { | ||
9625 | Row row = this.core.CreateRow(sourceLineNumbers, "MsiPatchMetadata"); | ||
9626 | row[0] = null; | ||
9627 | row[1] = "ManufacturerName"; | ||
9628 | row[2] = manufacturer; | ||
9629 | } | ||
9630 | |||
9631 | if (YesNoType.NotSet != minorUpdateTargetRTM) | ||
9632 | { | ||
9633 | Row row = this.core.CreateRow(sourceLineNumbers, "MsiPatchMetadata"); | ||
9634 | row[0] = null; | ||
9635 | row[1] = "MinorUpdateTargetRTM"; | ||
9636 | row[2] = YesNoType.Yes == minorUpdateTargetRTM ? "1" : "0"; | ||
9637 | } | ||
9638 | |||
9639 | if (null != moreInfoUrl) | ||
9640 | { | ||
9641 | Row row = this.core.CreateRow(sourceLineNumbers, "MsiPatchMetadata"); | ||
9642 | row[0] = null; | ||
9643 | row[1] = "MoreInfoURL"; | ||
9644 | row[2] = moreInfoUrl; | ||
9645 | } | ||
9646 | |||
9647 | if (CompilerConstants.IntegerNotSet != optimizeCA) | ||
9648 | { | ||
9649 | Row row = this.core.CreateRow(sourceLineNumbers, "MsiPatchMetadata"); | ||
9650 | row[0] = null; | ||
9651 | row[1] = "OptimizeCA"; | ||
9652 | row[2] = optimizeCA.ToString(CultureInfo.InvariantCulture); | ||
9653 | } | ||
9654 | |||
9655 | if (YesNoType.NotSet != optimizedInstallMode) | ||
9656 | { | ||
9657 | Row row = this.core.CreateRow(sourceLineNumbers, "MsiPatchMetadata"); | ||
9658 | row[0] = null; | ||
9659 | row[1] = "OptimizedInstallMode"; | ||
9660 | row[2] = YesNoType.Yes == optimizedInstallMode ? "1" : "0"; | ||
9661 | } | ||
9662 | |||
9663 | if (null != targetProductName) | ||
9664 | { | ||
9665 | Row row = this.core.CreateRow(sourceLineNumbers, "MsiPatchMetadata"); | ||
9666 | row[0] = null; | ||
9667 | row[1] = "TargetProductName"; | ||
9668 | row[2] = targetProductName; | ||
9669 | } | ||
9670 | |||
9671 | if (null != comments) | ||
9672 | { | ||
9673 | Row row = this.core.CreateRow(sourceLineNumbers, "WixPatchMetadata"); | ||
9674 | row[0] = "Comments"; | ||
9675 | row[1] = comments; | ||
9676 | } | ||
9677 | } | ||
9678 | // TODO: do something with versionMismatches and productMismatches | ||
9679 | } | ||
9680 | |||
9681 | /// <summary> | ||
9682 | /// Parses a PatchFamily element. | ||
9683 | /// </summary> | ||
9684 | /// <param name="node">The element to parse.</param> | ||
9685 | private void ParsePatchFamilyElement(XElement node, ComplexReferenceParentType parentType, string parentId) | ||
9686 | { | ||
9687 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
9688 | Identifier id = null; | ||
9689 | string productCode = null; | ||
9690 | string version = null; | ||
9691 | int attributes = 0; | ||
9692 | |||
9693 | foreach (XAttribute attrib in node.Attributes()) | ||
9694 | { | ||
9695 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
9696 | { | ||
9697 | switch (attrib.Name.LocalName) | ||
9698 | { | ||
9699 | case "Id": | ||
9700 | id = this.core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
9701 | break; | ||
9702 | case "ProductCode": | ||
9703 | productCode = this.core.GetAttributeGuidValue(sourceLineNumbers, attrib, false); | ||
9704 | break; | ||
9705 | case "Version": | ||
9706 | version = this.core.GetAttributeVersionValue(sourceLineNumbers, attrib); | ||
9707 | break; | ||
9708 | case "Supersede": | ||
9709 | if (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
9710 | { | ||
9711 | attributes |= 0x1; | ||
9712 | } | ||
9713 | break; | ||
9714 | default: | ||
9715 | this.core.UnexpectedAttribute(node, attrib); | ||
9716 | break; | ||
9717 | } | ||
9718 | } | ||
9719 | else | ||
9720 | { | ||
9721 | this.core.ParseExtensionAttribute(node, attrib); | ||
9722 | } | ||
9723 | } | ||
9724 | |||
9725 | if (null == id) | ||
9726 | { | ||
9727 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
9728 | id = Identifier.Invalid; | ||
9729 | } | ||
9730 | |||
9731 | if (String.IsNullOrEmpty(version)) | ||
9732 | { | ||
9733 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Version")); | ||
9734 | } | ||
9735 | else if (!CompilerCore.IsValidProductVersion(version)) | ||
9736 | { | ||
9737 | this.core.OnMessage(WixErrors.InvalidProductVersion(sourceLineNumbers, version)); | ||
9738 | } | ||
9739 | |||
9740 | // find unexpected child elements | ||
9741 | foreach (XElement child in node.Elements()) | ||
9742 | { | ||
9743 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
9744 | { | ||
9745 | switch (child.Name.LocalName) | ||
9746 | { | ||
9747 | case "All": | ||
9748 | this.ParseAllElement(child); | ||
9749 | break; | ||
9750 | case "BinaryRef": | ||
9751 | this.ParsePatchChildRefElement(child, "Binary"); | ||
9752 | break; | ||
9753 | case "ComponentRef": | ||
9754 | this.ParsePatchChildRefElement(child, "Component"); | ||
9755 | break; | ||
9756 | case "CustomActionRef": | ||
9757 | this.ParsePatchChildRefElement(child, "CustomAction"); | ||
9758 | break; | ||
9759 | case "DirectoryRef": | ||
9760 | this.ParsePatchChildRefElement(child, "Directory"); | ||
9761 | break; | ||
9762 | case "DigitalCertificateRef": | ||
9763 | this.ParsePatchChildRefElement(child, "MsiDigitalCertificate"); | ||
9764 | break; | ||
9765 | case "FeatureRef": | ||
9766 | this.ParsePatchChildRefElement(child, "Feature"); | ||
9767 | break; | ||
9768 | case "IconRef": | ||
9769 | this.ParsePatchChildRefElement(child, "Icon"); | ||
9770 | break; | ||
9771 | case "PropertyRef": | ||
9772 | this.ParsePatchChildRefElement(child, "Property"); | ||
9773 | break; | ||
9774 | case "UIRef": | ||
9775 | this.ParsePatchChildRefElement(child, "WixUI"); | ||
9776 | break; | ||
9777 | default: | ||
9778 | this.core.UnexpectedElement(node, child); | ||
9779 | break; | ||
9780 | } | ||
9781 | } | ||
9782 | else | ||
9783 | { | ||
9784 | this.core.ParseExtensionElement(node, child); | ||
9785 | } | ||
9786 | } | ||
9787 | |||
9788 | |||
9789 | if (!this.core.EncounteredError) | ||
9790 | { | ||
9791 | Row row = this.core.CreateRow(sourceLineNumbers, "MsiPatchSequence", id); | ||
9792 | row[1] = productCode; | ||
9793 | row[2] = version; | ||
9794 | row[3] = attributes; | ||
9795 | |||
9796 | if (ComplexReferenceParentType.Unknown != parentType) | ||
9797 | { | ||
9798 | this.core.CreateComplexReference(sourceLineNumbers, parentType, parentId, null, ComplexReferenceChildType.PatchFamily, id.Id, ComplexReferenceParentType.Patch == parentType); | ||
9799 | } | ||
9800 | } | ||
9801 | } | ||
9802 | |||
9803 | /// <summary> | ||
9804 | /// Parses the All element under a PatchFamily. | ||
9805 | /// </summary> | ||
9806 | /// <param name="node">The element to parse.</param> | ||
9807 | private void ParseAllElement(XElement node) | ||
9808 | { | ||
9809 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
9810 | |||
9811 | // find unexpected attributes | ||
9812 | foreach (XAttribute attrib in node.Attributes()) | ||
9813 | { | ||
9814 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
9815 | { | ||
9816 | this.core.UnexpectedAttribute(node, attrib); | ||
9817 | } | ||
9818 | else | ||
9819 | { | ||
9820 | this.core.ParseExtensionAttribute(node, attrib); | ||
9821 | } | ||
9822 | } | ||
9823 | |||
9824 | this.core.ParseForExtensionElements(node); | ||
9825 | |||
9826 | // Always warn when using the All element. | ||
9827 | this.core.OnMessage(WixWarnings.AllChangesIncludedInPatch(sourceLineNumbers)); | ||
9828 | |||
9829 | if (!this.core.EncounteredError) | ||
9830 | { | ||
9831 | this.core.CreatePatchFamilyChildReference(sourceLineNumbers, "*", "*"); | ||
9832 | } | ||
9833 | } | ||
9834 | |||
9835 | /// <summary> | ||
9836 | /// Parses all reference elements under a PatchFamily. | ||
9837 | /// </summary> | ||
9838 | /// <param name="node">The element to parse.</param> | ||
9839 | /// <param name="tableName">Table that reference was made to.</param> | ||
9840 | private void ParsePatchChildRefElement(XElement node, string tableName) | ||
9841 | { | ||
9842 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
9843 | string id = null; | ||
9844 | |||
9845 | foreach (XAttribute attrib in node.Attributes()) | ||
9846 | { | ||
9847 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
9848 | { | ||
9849 | switch (attrib.Name.LocalName) | ||
9850 | { | ||
9851 | case "Id": | ||
9852 | id = this.core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
9853 | break; | ||
9854 | default: | ||
9855 | this.core.UnexpectedAttribute(node, attrib); | ||
9856 | break; | ||
9857 | } | ||
9858 | } | ||
9859 | else | ||
9860 | { | ||
9861 | this.core.ParseExtensionAttribute(node, attrib); | ||
9862 | } | ||
9863 | } | ||
9864 | |||
9865 | if (null == id) | ||
9866 | { | ||
9867 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
9868 | } | ||
9869 | |||
9870 | this.core.ParseForExtensionElements(node); | ||
9871 | |||
9872 | if (!this.core.EncounteredError) | ||
9873 | { | ||
9874 | this.core.CreatePatchFamilyChildReference(sourceLineNumbers, tableName, id); | ||
9875 | } | ||
9876 | } | ||
9877 | |||
9878 | /// <summary> | ||
9879 | /// Parses a PatchBaseline element. | ||
9880 | /// </summary> | ||
9881 | /// <param name="node">The element to parse.</param> | ||
9882 | /// <param name="diskId">Media index from parent element.</param> | ||
9883 | private void ParsePatchBaselineElement(XElement node, int diskId) | ||
9884 | { | ||
9885 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
9886 | Identifier id = null; | ||
9887 | bool parsedValidate = false; | ||
9888 | TransformFlags validationFlags = TransformFlags.PatchTransformDefault; | ||
9889 | |||
9890 | foreach (XAttribute attrib in node.Attributes()) | ||
9891 | { | ||
9892 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
9893 | { | ||
9894 | switch (attrib.Name.LocalName) | ||
9895 | { | ||
9896 | case "Id": | ||
9897 | id = this.core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
9898 | break; | ||
9899 | default: | ||
9900 | this.core.UnexpectedAttribute(node, attrib); | ||
9901 | break; | ||
9902 | } | ||
9903 | } | ||
9904 | else | ||
9905 | { | ||
9906 | this.core.ParseExtensionAttribute(node, attrib); | ||
9907 | } | ||
9908 | } | ||
9909 | |||
9910 | if (null == id) | ||
9911 | { | ||
9912 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
9913 | id = Identifier.Invalid; | ||
9914 | } | ||
9915 | else if (27 < id.Id.Length) | ||
9916 | { | ||
9917 | this.core.OnMessage(WixErrors.IdentifierTooLongError(sourceLineNumbers, node.Name.LocalName, "Id", id.Id, 27)); | ||
9918 | } | ||
9919 | |||
9920 | foreach (XElement child in node.Elements()) | ||
9921 | { | ||
9922 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
9923 | { | ||
9924 | switch (child.Name.LocalName) | ||
9925 | { | ||
9926 | case "Validate": | ||
9927 | if (parsedValidate) | ||
9928 | { | ||
9929 | SourceLineNumber childSourceLineNumbers = Preprocessor.GetSourceLineNumbers(child); | ||
9930 | this.core.OnMessage(WixErrors.TooManyChildren(childSourceLineNumbers, node.Name.LocalName, child.Name.LocalName)); | ||
9931 | } | ||
9932 | else | ||
9933 | { | ||
9934 | this.ParseValidateElement(child, ref validationFlags); | ||
9935 | parsedValidate = true; | ||
9936 | } | ||
9937 | break; | ||
9938 | default: | ||
9939 | this.core.UnexpectedElement(node, child); | ||
9940 | break; | ||
9941 | } | ||
9942 | } | ||
9943 | else | ||
9944 | { | ||
9945 | this.core.ParseExtensionElement(node, child); | ||
9946 | } | ||
9947 | } | ||
9948 | |||
9949 | if (!this.core.EncounteredError) | ||
9950 | { | ||
9951 | Row row = this.core.CreateRow(sourceLineNumbers, "WixPatchBaseline", id); | ||
9952 | row[1] = diskId; | ||
9953 | row[2] = (int)validationFlags; | ||
9954 | } | ||
9955 | } | ||
9956 | |||
9957 | /// <summary> | ||
9958 | /// Parses a Validate element. | ||
9959 | /// </summary> | ||
9960 | /// <param name="node">The element to parse.</param> | ||
9961 | /// <param name="validationFlags">TransformValidation flags to use when creating the authoring patch transform.</param> | ||
9962 | private void ParseValidateElement(XElement node, ref TransformFlags validationFlags) | ||
9963 | { | ||
9964 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
9965 | |||
9966 | foreach (XAttribute attrib in node.Attributes()) | ||
9967 | { | ||
9968 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
9969 | { | ||
9970 | switch (attrib.Name.LocalName) | ||
9971 | { | ||
9972 | case "ProductId": | ||
9973 | if (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
9974 | { | ||
9975 | validationFlags |= TransformFlags.ValidateProduct; | ||
9976 | } | ||
9977 | else | ||
9978 | { | ||
9979 | validationFlags &= ~TransformFlags.ValidateProduct; | ||
9980 | } | ||
9981 | break; | ||
9982 | case "ProductLanguage": | ||
9983 | if (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
9984 | { | ||
9985 | validationFlags |= TransformFlags.ValidateLanguage; | ||
9986 | } | ||
9987 | else | ||
9988 | { | ||
9989 | validationFlags &= ~TransformFlags.ValidateLanguage; | ||
9990 | } | ||
9991 | break; | ||
9992 | case "ProductVersion": | ||
9993 | string check = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
9994 | validationFlags &= ~TransformFlags.ProductVersionMask; | ||
9995 | Wix.Validate.ProductVersionType productVersionType = Wix.Validate.ParseProductVersionType(check); | ||
9996 | switch (productVersionType) | ||
9997 | { | ||
9998 | case Wix.Validate.ProductVersionType.Major: | ||
9999 | validationFlags |= TransformFlags.ValidateMajorVersion; | ||
10000 | break; | ||
10001 | case Wix.Validate.ProductVersionType.Minor: | ||
10002 | validationFlags |= TransformFlags.ValidateMinorVersion; | ||
10003 | break; | ||
10004 | case Wix.Validate.ProductVersionType.Update: | ||
10005 | validationFlags |= TransformFlags.ValidateUpdateVersion; | ||
10006 | break; | ||
10007 | default: | ||
10008 | this.core.OnMessage(WixErrors.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, "Version", check, "Major", "Minor", "Update")); | ||
10009 | break; | ||
10010 | } | ||
10011 | break; | ||
10012 | case "ProductVersionOperator": | ||
10013 | string op = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
10014 | validationFlags &= ~TransformFlags.ProductVersionOperatorMask; | ||
10015 | Wix.Validate.ProductVersionOperatorType opType = Wix.Validate.ParseProductVersionOperatorType(op); | ||
10016 | switch (opType) | ||
10017 | { | ||
10018 | case Wix.Validate.ProductVersionOperatorType.Lesser: | ||
10019 | validationFlags |= TransformFlags.ValidateNewLessBaseVersion; | ||
10020 | break; | ||
10021 | case Wix.Validate.ProductVersionOperatorType.LesserOrEqual: | ||
10022 | validationFlags |= TransformFlags.ValidateNewLessEqualBaseVersion; | ||
10023 | break; | ||
10024 | case Wix.Validate.ProductVersionOperatorType.Equal: | ||
10025 | validationFlags |= TransformFlags.ValidateNewEqualBaseVersion; | ||
10026 | break; | ||
10027 | case Wix.Validate.ProductVersionOperatorType.GreaterOrEqual: | ||
10028 | validationFlags |= TransformFlags.ValidateNewGreaterEqualBaseVersion; | ||
10029 | break; | ||
10030 | case Wix.Validate.ProductVersionOperatorType.Greater: | ||
10031 | validationFlags |= TransformFlags.ValidateNewGreaterBaseVersion; | ||
10032 | break; | ||
10033 | default: | ||
10034 | this.core.OnMessage(WixErrors.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, "Operator", op, "Lesser", "LesserOrEqual", "Equal", "GreaterOrEqual", "Greater")); | ||
10035 | break; | ||
10036 | } | ||
10037 | break; | ||
10038 | case "UpgradeCode": | ||
10039 | if (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
10040 | { | ||
10041 | validationFlags |= TransformFlags.ValidateUpgradeCode; | ||
10042 | } | ||
10043 | else | ||
10044 | { | ||
10045 | validationFlags &= ~TransformFlags.ValidateUpgradeCode; | ||
10046 | } | ||
10047 | break; | ||
10048 | case "IgnoreAddExistingRow": | ||
10049 | if (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
10050 | { | ||
10051 | validationFlags |= TransformFlags.ErrorAddExistingRow; | ||
10052 | } | ||
10053 | else | ||
10054 | { | ||
10055 | validationFlags &= ~TransformFlags.ErrorAddExistingRow; | ||
10056 | } | ||
10057 | break; | ||
10058 | case "IgnoreAddExistingTable": | ||
10059 | if (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
10060 | { | ||
10061 | validationFlags |= TransformFlags.ErrorAddExistingTable; | ||
10062 | } | ||
10063 | else | ||
10064 | { | ||
10065 | validationFlags &= ~TransformFlags.ErrorAddExistingTable; | ||
10066 | } | ||
10067 | break; | ||
10068 | case "IgnoreDeleteMissingRow": | ||
10069 | if (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
10070 | { | ||
10071 | validationFlags |= TransformFlags.ErrorDeleteMissingRow; | ||
10072 | } | ||
10073 | else | ||
10074 | { | ||
10075 | validationFlags &= ~TransformFlags.ErrorDeleteMissingRow; | ||
10076 | } | ||
10077 | break; | ||
10078 | case "IgnoreDeleteMissingTable": | ||
10079 | if (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
10080 | { | ||
10081 | validationFlags |= TransformFlags.ErrorDeleteMissingTable; | ||
10082 | } | ||
10083 | else | ||
10084 | { | ||
10085 | validationFlags &= ~TransformFlags.ErrorDeleteMissingTable; | ||
10086 | } | ||
10087 | break; | ||
10088 | case "IgnoreUpdateMissingRow": | ||
10089 | if (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
10090 | { | ||
10091 | validationFlags |= TransformFlags.ErrorUpdateMissingRow; | ||
10092 | } | ||
10093 | else | ||
10094 | { | ||
10095 | validationFlags &= ~TransformFlags.ErrorUpdateMissingRow; | ||
10096 | } | ||
10097 | break; | ||
10098 | case "IgnoreChangingCodePage": | ||
10099 | if (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
10100 | { | ||
10101 | validationFlags |= TransformFlags.ErrorChangeCodePage; | ||
10102 | } | ||
10103 | else | ||
10104 | { | ||
10105 | validationFlags &= ~TransformFlags.ErrorChangeCodePage; | ||
10106 | } | ||
10107 | break; | ||
10108 | default: | ||
10109 | this.core.UnexpectedAttribute(node, attrib); | ||
10110 | break; | ||
10111 | } | ||
10112 | } | ||
10113 | else | ||
10114 | { | ||
10115 | this.core.ParseExtensionAttribute(node, attrib); | ||
10116 | } | ||
10117 | } | ||
10118 | |||
10119 | } | ||
10120 | |||
10121 | /// <summary> | ||
10122 | /// Adds a row to the properties table. | ||
10123 | /// </summary> | ||
10124 | /// <param name="sourceLineNumbers">Source line numbers.</param> | ||
10125 | /// <param name="name">Name of the property.</param> | ||
10126 | /// <param name="value">Value of the property.</param> | ||
10127 | private void ProcessProperties(SourceLineNumber sourceLineNumbers, string name, string value) | ||
10128 | { | ||
10129 | if (!this.core.EncounteredError) | ||
10130 | { | ||
10131 | Row row = this.core.CreateRow(sourceLineNumbers, "Properties"); | ||
10132 | row[0] = name; | ||
10133 | row[1] = value; | ||
10134 | } | ||
10135 | } | ||
10136 | |||
10137 | /// <summary> | ||
10138 | /// Parses a dependency element. | ||
10139 | /// </summary> | ||
10140 | /// <param name="node">Element to parse.</param> | ||
10141 | private void ParseDependencyElement(XElement node) | ||
10142 | { | ||
10143 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
10144 | string requiredId = null; | ||
10145 | int requiredLanguage = CompilerConstants.IntegerNotSet; | ||
10146 | string requiredVersion = null; | ||
10147 | |||
10148 | foreach (XAttribute attrib in node.Attributes()) | ||
10149 | { | ||
10150 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
10151 | { | ||
10152 | switch (attrib.Name.LocalName) | ||
10153 | { | ||
10154 | case "RequiredId": | ||
10155 | requiredId = this.core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
10156 | break; | ||
10157 | case "RequiredLanguage": | ||
10158 | requiredLanguage = this.core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, short.MaxValue); | ||
10159 | break; | ||
10160 | case "RequiredVersion": | ||
10161 | requiredVersion = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
10162 | break; | ||
10163 | default: | ||
10164 | this.core.UnexpectedAttribute(node, attrib); | ||
10165 | break; | ||
10166 | } | ||
10167 | } | ||
10168 | else | ||
10169 | { | ||
10170 | this.core.ParseExtensionAttribute(node, attrib); | ||
10171 | } | ||
10172 | } | ||
10173 | |||
10174 | if (null == requiredId) | ||
10175 | { | ||
10176 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "RequiredId")); | ||
10177 | requiredId = String.Empty; | ||
10178 | } | ||
10179 | |||
10180 | if (CompilerConstants.IntegerNotSet == requiredLanguage) | ||
10181 | { | ||
10182 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "RequiredLanguage")); | ||
10183 | requiredLanguage = CompilerConstants.IllegalInteger; | ||
10184 | } | ||
10185 | |||
10186 | this.core.ParseForExtensionElements(node); | ||
10187 | |||
10188 | if (!this.core.EncounteredError) | ||
10189 | { | ||
10190 | Row row = this.core.CreateRow(sourceLineNumbers, "ModuleDependency"); | ||
10191 | row[0] = this.activeName; | ||
10192 | row[1] = this.activeLanguage; | ||
10193 | row[2] = requiredId; | ||
10194 | row[3] = requiredLanguage.ToString(CultureInfo.InvariantCulture); | ||
10195 | row[4] = requiredVersion; | ||
10196 | } | ||
10197 | } | ||
10198 | |||
10199 | /// <summary> | ||
10200 | /// Parses an exclusion element. | ||
10201 | /// </summary> | ||
10202 | /// <param name="node">Element to parse.</param> | ||
10203 | private void ParseExclusionElement(XElement node) | ||
10204 | { | ||
10205 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
10206 | string excludedId = null; | ||
10207 | int excludeExceptLanguage = CompilerConstants.IntegerNotSet; | ||
10208 | int excludeLanguage = CompilerConstants.IntegerNotSet; | ||
10209 | string excludedLanguageField = "0"; | ||
10210 | string excludedMaxVersion = null; | ||
10211 | string excludedMinVersion = null; | ||
10212 | |||
10213 | foreach (XAttribute attrib in node.Attributes()) | ||
10214 | { | ||
10215 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
10216 | { | ||
10217 | switch (attrib.Name.LocalName) | ||
10218 | { | ||
10219 | case "ExcludedId": | ||
10220 | excludedId = this.core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
10221 | break; | ||
10222 | case "ExcludeExceptLanguage": | ||
10223 | excludeExceptLanguage = this.core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, short.MaxValue); | ||
10224 | break; | ||
10225 | case "ExcludeLanguage": | ||
10226 | excludeLanguage = this.core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, short.MaxValue); | ||
10227 | break; | ||
10228 | case "ExcludedMaxVersion": | ||
10229 | excludedMaxVersion = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
10230 | break; | ||
10231 | case "ExcludedMinVersion": | ||
10232 | excludedMinVersion = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
10233 | break; | ||
10234 | default: | ||
10235 | this.core.UnexpectedAttribute(node, attrib); | ||
10236 | break; | ||
10237 | } | ||
10238 | } | ||
10239 | else | ||
10240 | { | ||
10241 | this.core.ParseExtensionAttribute(node, attrib); | ||
10242 | } | ||
10243 | } | ||
10244 | |||
10245 | if (null == excludedId) | ||
10246 | { | ||
10247 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "ExcludedId")); | ||
10248 | excludedId = String.Empty; | ||
10249 | } | ||
10250 | |||
10251 | if (CompilerConstants.IntegerNotSet != excludeExceptLanguage && CompilerConstants.IntegerNotSet != excludeLanguage) | ||
10252 | { | ||
10253 | this.core.OnMessage(WixErrors.IllegalModuleExclusionLanguageAttributes(sourceLineNumbers)); | ||
10254 | } | ||
10255 | else if (CompilerConstants.IntegerNotSet != excludeExceptLanguage) | ||
10256 | { | ||
10257 | excludedLanguageField = Convert.ToString(-excludeExceptLanguage, CultureInfo.InvariantCulture); | ||
10258 | } | ||
10259 | else if (CompilerConstants.IntegerNotSet != excludeLanguage) | ||
10260 | { | ||
10261 | excludedLanguageField = Convert.ToString(excludeLanguage, CultureInfo.InvariantCulture); | ||
10262 | } | ||
10263 | |||
10264 | this.core.ParseForExtensionElements(node); | ||
10265 | |||
10266 | if (!this.core.EncounteredError) | ||
10267 | { | ||
10268 | Row row = this.core.CreateRow(sourceLineNumbers, "ModuleExclusion"); | ||
10269 | row[0] = this.activeName; | ||
10270 | row[1] = this.activeLanguage; | ||
10271 | row[2] = excludedId; | ||
10272 | row[3] = excludedLanguageField; | ||
10273 | row[4] = excludedMinVersion; | ||
10274 | row[5] = excludedMaxVersion; | ||
10275 | } | ||
10276 | } | ||
10277 | |||
10278 | /// <summary> | ||
10279 | /// Parses a configuration element for a configurable merge module. | ||
10280 | /// </summary> | ||
10281 | /// <param name="node">Element to parse.</param> | ||
10282 | private void ParseConfigurationElement(XElement node) | ||
10283 | { | ||
10284 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
10285 | int attributes = 0; | ||
10286 | string contextData = null; | ||
10287 | string defaultValue = null; | ||
10288 | string description = null; | ||
10289 | string displayName = null; | ||
10290 | int format = CompilerConstants.IntegerNotSet; | ||
10291 | string helpKeyword = null; | ||
10292 | string helpLocation = null; | ||
10293 | string name = null; | ||
10294 | string type = null; | ||
10295 | |||
10296 | foreach (XAttribute attrib in node.Attributes()) | ||
10297 | { | ||
10298 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
10299 | { | ||
10300 | switch (attrib.Name.LocalName) | ||
10301 | { | ||
10302 | case "Name": | ||
10303 | name = this.core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
10304 | break; | ||
10305 | case "ContextData": | ||
10306 | contextData = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
10307 | break; | ||
10308 | case "Description": | ||
10309 | description = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
10310 | break; | ||
10311 | case "DefaultValue": | ||
10312 | defaultValue = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
10313 | break; | ||
10314 | case "DisplayName": | ||
10315 | displayName = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
10316 | break; | ||
10317 | case "Format": | ||
10318 | string formatStr = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
10319 | if (0 < formatStr.Length) | ||
10320 | { | ||
10321 | Wix.Configuration.FormatType formatType = Wix.Configuration.ParseFormatType(formatStr); | ||
10322 | switch (formatType) | ||
10323 | { | ||
10324 | case Wix.Configuration.FormatType.Text: | ||
10325 | format = 0; | ||
10326 | break; | ||
10327 | case Wix.Configuration.FormatType.Key: | ||
10328 | format = 1; | ||
10329 | break; | ||
10330 | case Wix.Configuration.FormatType.Integer: | ||
10331 | format = 2; | ||
10332 | break; | ||
10333 | case Wix.Configuration.FormatType.Bitfield: | ||
10334 | format = 3; | ||
10335 | break; | ||
10336 | default: | ||
10337 | this.core.OnMessage(WixErrors.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, "Format", formatStr, "Text", "Key", "Integer", "Bitfield")); | ||
10338 | break; | ||
10339 | } | ||
10340 | } | ||
10341 | break; | ||
10342 | case "HelpKeyword": | ||
10343 | helpKeyword = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
10344 | break; | ||
10345 | case "HelpLocation": | ||
10346 | helpLocation = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
10347 | break; | ||
10348 | case "KeyNoOrphan": | ||
10349 | if (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
10350 | { | ||
10351 | attributes |= MsiInterop.MsidbMsmConfigurableOptionKeyNoOrphan; | ||
10352 | } | ||
10353 | break; | ||
10354 | case "NonNullable": | ||
10355 | if (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
10356 | { | ||
10357 | attributes |= MsiInterop.MsidbMsmConfigurableOptionNonNullable; | ||
10358 | } | ||
10359 | break; | ||
10360 | case "Type": | ||
10361 | type = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
10362 | break; | ||
10363 | default: | ||
10364 | this.core.UnexpectedAttribute(node, attrib); | ||
10365 | break; | ||
10366 | } | ||
10367 | } | ||
10368 | else | ||
10369 | { | ||
10370 | this.core.ParseExtensionAttribute(node, attrib); | ||
10371 | } | ||
10372 | } | ||
10373 | |||
10374 | if (null == name) | ||
10375 | { | ||
10376 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Name")); | ||
10377 | name = String.Empty; | ||
10378 | } | ||
10379 | |||
10380 | if (CompilerConstants.IntegerNotSet == format) | ||
10381 | { | ||
10382 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Format")); | ||
10383 | format = CompilerConstants.IllegalInteger; | ||
10384 | } | ||
10385 | |||
10386 | this.core.ParseForExtensionElements(node); | ||
10387 | |||
10388 | if (!this.core.EncounteredError) | ||
10389 | { | ||
10390 | Row row = this.core.CreateRow(sourceLineNumbers, "ModuleConfiguration"); | ||
10391 | row[0] = name; | ||
10392 | row[1] = format; | ||
10393 | row[2] = type; | ||
10394 | row[3] = contextData; | ||
10395 | row[4] = defaultValue; | ||
10396 | row[5] = attributes; | ||
10397 | row[6] = displayName; | ||
10398 | row[7] = description; | ||
10399 | row[8] = helpLocation; | ||
10400 | row[9] = helpKeyword; | ||
10401 | } | ||
10402 | } | ||
10403 | |||
10404 | /// <summary> | ||
10405 | /// Parses a substitution element for a configurable merge module. | ||
10406 | /// </summary> | ||
10407 | /// <param name="node">Element to parse.</param> | ||
10408 | private void ParseSubstitutionElement(XElement node) | ||
10409 | { | ||
10410 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
10411 | string column = null; | ||
10412 | string rowKeys = null; | ||
10413 | string table = null; | ||
10414 | string value = null; | ||
10415 | |||
10416 | foreach (XAttribute attrib in node.Attributes()) | ||
10417 | { | ||
10418 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
10419 | { | ||
10420 | switch (attrib.Name.LocalName) | ||
10421 | { | ||
10422 | case "Column": | ||
10423 | column = this.core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
10424 | break; | ||
10425 | case "Row": | ||
10426 | rowKeys = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
10427 | break; | ||
10428 | case "Table": | ||
10429 | table = this.core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
10430 | break; | ||
10431 | case "Value": | ||
10432 | value = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
10433 | break; | ||
10434 | default: | ||
10435 | this.core.UnexpectedAttribute(node, attrib); | ||
10436 | break; | ||
10437 | } | ||
10438 | } | ||
10439 | else | ||
10440 | { | ||
10441 | this.core.ParseExtensionAttribute(node, attrib); | ||
10442 | } | ||
10443 | } | ||
10444 | |||
10445 | if (null == column) | ||
10446 | { | ||
10447 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Column")); | ||
10448 | column = String.Empty; | ||
10449 | } | ||
10450 | |||
10451 | if (null == table) | ||
10452 | { | ||
10453 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Table")); | ||
10454 | table = String.Empty; | ||
10455 | } | ||
10456 | |||
10457 | if (null == rowKeys) | ||
10458 | { | ||
10459 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Row")); | ||
10460 | } | ||
10461 | |||
10462 | this.core.ParseForExtensionElements(node); | ||
10463 | |||
10464 | if (!this.core.EncounteredError) | ||
10465 | { | ||
10466 | Row row = this.core.CreateRow(sourceLineNumbers, "ModuleSubstitution"); | ||
10467 | row[0] = table; | ||
10468 | row[1] = rowKeys; | ||
10469 | row[2] = column; | ||
10470 | row[3] = value; | ||
10471 | } | ||
10472 | } | ||
10473 | |||
10474 | /// <summary> | ||
10475 | /// Parses an IgnoreTable element. | ||
10476 | /// </summary> | ||
10477 | /// <param name="node">Element to parse.</param> | ||
10478 | private void ParseIgnoreTableElement(XElement node) | ||
10479 | { | ||
10480 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
10481 | string id = null; | ||
10482 | |||
10483 | foreach (XAttribute attrib in node.Attributes()) | ||
10484 | { | ||
10485 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
10486 | { | ||
10487 | switch (attrib.Name.LocalName) | ||
10488 | { | ||
10489 | case "Id": | ||
10490 | id = this.core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
10491 | break; | ||
10492 | default: | ||
10493 | this.core.UnexpectedAttribute(node, attrib); | ||
10494 | break; | ||
10495 | } | ||
10496 | } | ||
10497 | else | ||
10498 | { | ||
10499 | this.core.ParseExtensionAttribute(node, attrib); | ||
10500 | } | ||
10501 | } | ||
10502 | |||
10503 | if (null == id) | ||
10504 | { | ||
10505 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
10506 | } | ||
10507 | |||
10508 | this.core.ParseForExtensionElements(node); | ||
10509 | |||
10510 | if (!this.core.EncounteredError) | ||
10511 | { | ||
10512 | Row row = this.core.CreateRow(sourceLineNumbers, "ModuleIgnoreTable"); | ||
10513 | row[0] = id; | ||
10514 | } | ||
10515 | } | ||
10516 | |||
10517 | /// <summary> | ||
10518 | /// Parses an odbc driver or translator element. | ||
10519 | /// </summary> | ||
10520 | /// <param name="node">Element to parse.</param> | ||
10521 | /// <param name="componentId">Identifier of parent component.</param> | ||
10522 | /// <param name="fileId">Default identifer for driver/translator file.</param> | ||
10523 | /// <param name="table">Table we're processing for.</param> | ||
10524 | private void ParseODBCDriverOrTranslator(XElement node, string componentId, string fileId, TableDefinition table) | ||
10525 | { | ||
10526 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
10527 | Identifier id = null; | ||
10528 | string driver = fileId; | ||
10529 | string name = null; | ||
10530 | string setup = fileId; | ||
10531 | |||
10532 | foreach (XAttribute attrib in node.Attributes()) | ||
10533 | { | ||
10534 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
10535 | { | ||
10536 | switch (attrib.Name.LocalName) | ||
10537 | { | ||
10538 | case "Id": | ||
10539 | id = this.core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
10540 | break; | ||
10541 | case "File": | ||
10542 | driver = this.core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
10543 | this.core.CreateSimpleReference(sourceLineNumbers, "File", driver); | ||
10544 | break; | ||
10545 | case "Name": | ||
10546 | name = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
10547 | break; | ||
10548 | case "SetupFile": | ||
10549 | setup = this.core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
10550 | this.core.CreateSimpleReference(sourceLineNumbers, "File", setup); | ||
10551 | break; | ||
10552 | default: | ||
10553 | this.core.UnexpectedAttribute(node, attrib); | ||
10554 | break; | ||
10555 | } | ||
10556 | } | ||
10557 | else | ||
10558 | { | ||
10559 | this.core.ParseExtensionAttribute(node, attrib); | ||
10560 | } | ||
10561 | } | ||
10562 | |||
10563 | if (null == name) | ||
10564 | { | ||
10565 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Name")); | ||
10566 | } | ||
10567 | |||
10568 | if (null == id) | ||
10569 | { | ||
10570 | id = this.core.CreateIdentifier("odb", name, fileId, setup); | ||
10571 | } | ||
10572 | |||
10573 | // drivers have a few possible children | ||
10574 | if ("ODBCDriver" == table.Name) | ||
10575 | { | ||
10576 | // process any data sources for the driver | ||
10577 | foreach (XElement child in node.Elements()) | ||
10578 | { | ||
10579 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
10580 | { | ||
10581 | switch (child.Name.LocalName) | ||
10582 | { | ||
10583 | case "ODBCDataSource": | ||
10584 | string ignoredKeyPath = null; | ||
10585 | this.ParseODBCDataSource(child, componentId, name, out ignoredKeyPath); | ||
10586 | break; | ||
10587 | case "Property": | ||
10588 | this.ParseODBCProperty(child, id.Id, "ODBCAttribute"); | ||
10589 | break; | ||
10590 | default: | ||
10591 | this.core.UnexpectedElement(node, child); | ||
10592 | break; | ||
10593 | } | ||
10594 | } | ||
10595 | else | ||
10596 | { | ||
10597 | this.core.ParseExtensionElement(node, child); | ||
10598 | } | ||
10599 | } | ||
10600 | } | ||
10601 | else | ||
10602 | { | ||
10603 | this.core.ParseForExtensionElements(node); | ||
10604 | } | ||
10605 | |||
10606 | if (!this.core.EncounteredError) | ||
10607 | { | ||
10608 | Row row = this.core.CreateRow(sourceLineNumbers, table.Name, id); | ||
10609 | row[1] = componentId; | ||
10610 | row[2] = name; | ||
10611 | row[3] = driver; | ||
10612 | row[4] = setup; | ||
10613 | } | ||
10614 | } | ||
10615 | |||
10616 | /// <summary> | ||
10617 | /// Parses a Property element underneath an ODBC driver or translator. | ||
10618 | /// </summary> | ||
10619 | /// <param name="node">Element to parse.</param> | ||
10620 | /// <param name="parentId">Identifier of parent driver or translator.</param> | ||
10621 | /// <param name="tableName">Name of the table to create property in.</param> | ||
10622 | private void ParseODBCProperty(XElement node, string parentId, string tableName) | ||
10623 | { | ||
10624 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
10625 | string id = null; | ||
10626 | string propertyValue = null; | ||
10627 | |||
10628 | foreach (XAttribute attrib in node.Attributes()) | ||
10629 | { | ||
10630 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
10631 | { | ||
10632 | switch (attrib.Name.LocalName) | ||
10633 | { | ||
10634 | case "Id": | ||
10635 | id = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
10636 | break; | ||
10637 | case "Value": | ||
10638 | propertyValue = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
10639 | break; | ||
10640 | default: | ||
10641 | this.core.UnexpectedAttribute(node, attrib); | ||
10642 | break; | ||
10643 | } | ||
10644 | } | ||
10645 | else | ||
10646 | { | ||
10647 | this.core.ParseExtensionAttribute(node, attrib); | ||
10648 | } | ||
10649 | } | ||
10650 | |||
10651 | if (null == id) | ||
10652 | { | ||
10653 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
10654 | } | ||
10655 | |||
10656 | this.core.ParseForExtensionElements(node); | ||
10657 | |||
10658 | if (!this.core.EncounteredError) | ||
10659 | { | ||
10660 | Row row = this.core.CreateRow(sourceLineNumbers, tableName); | ||
10661 | row[0] = parentId; | ||
10662 | row[1] = id; | ||
10663 | row[2] = propertyValue; | ||
10664 | } | ||
10665 | } | ||
10666 | |||
10667 | /// <summary> | ||
10668 | /// Parse an odbc data source element. | ||
10669 | /// </summary> | ||
10670 | /// <param name="node">Element to parse.</param> | ||
10671 | /// <param name="componentId">Identifier of parent component.</param> | ||
10672 | /// <param name="driverName">Default name of driver.</param> | ||
10673 | /// <param name="possibleKeyPath">Identifier of this element in case it is a keypath.</param> | ||
10674 | /// <returns>Yes if this element was marked as the parent component's key path, No if explicitly marked as not being a key path, or NotSet otherwise.</returns> | ||
10675 | private YesNoType ParseODBCDataSource(XElement node, string componentId, string driverName, out string possibleKeyPath) | ||
10676 | { | ||
10677 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
10678 | Identifier id = null; | ||
10679 | YesNoType keyPath = YesNoType.NotSet; | ||
10680 | string name = null; | ||
10681 | int registration = CompilerConstants.IntegerNotSet; | ||
10682 | |||
10683 | foreach (XAttribute attrib in node.Attributes()) | ||
10684 | { | ||
10685 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
10686 | { | ||
10687 | switch (attrib.Name.LocalName) | ||
10688 | { | ||
10689 | case "Id": | ||
10690 | id = this.core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
10691 | break; | ||
10692 | case "DriverName": | ||
10693 | driverName = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
10694 | break; | ||
10695 | case "KeyPath": | ||
10696 | keyPath = this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
10697 | break; | ||
10698 | case "Name": | ||
10699 | name = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
10700 | break; | ||
10701 | case "Registration": | ||
10702 | string registrationValue = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
10703 | if (0 < registrationValue.Length) | ||
10704 | { | ||
10705 | Wix.ODBCDataSource.RegistrationType registrationType = Wix.ODBCDataSource.ParseRegistrationType(registrationValue); | ||
10706 | switch (registrationType) | ||
10707 | { | ||
10708 | case Wix.ODBCDataSource.RegistrationType.machine: | ||
10709 | registration = 0; | ||
10710 | break; | ||
10711 | case Wix.ODBCDataSource.RegistrationType.user: | ||
10712 | registration = 1; | ||
10713 | break; | ||
10714 | default: | ||
10715 | this.core.OnMessage(WixErrors.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, "Registration", registrationValue, "machine", "user")); | ||
10716 | break; | ||
10717 | } | ||
10718 | } | ||
10719 | break; | ||
10720 | default: | ||
10721 | this.core.UnexpectedAttribute(node, attrib); | ||
10722 | break; | ||
10723 | } | ||
10724 | } | ||
10725 | else | ||
10726 | { | ||
10727 | this.core.ParseExtensionAttribute(node, attrib); | ||
10728 | } | ||
10729 | } | ||
10730 | |||
10731 | if (CompilerConstants.IntegerNotSet == registration) | ||
10732 | { | ||
10733 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Registration")); | ||
10734 | registration = CompilerConstants.IllegalInteger; | ||
10735 | } | ||
10736 | |||
10737 | if (null == id) | ||
10738 | { | ||
10739 | id = this.core.CreateIdentifier("odc", name, driverName, registration.ToString()); | ||
10740 | } | ||
10741 | |||
10742 | foreach (XElement child in node.Elements()) | ||
10743 | { | ||
10744 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
10745 | { | ||
10746 | switch (child.Name.LocalName) | ||
10747 | { | ||
10748 | case "Property": | ||
10749 | this.ParseODBCProperty(child, id.Id, "ODBCSourceAttribute"); | ||
10750 | break; | ||
10751 | default: | ||
10752 | this.core.UnexpectedElement(node, child); | ||
10753 | break; | ||
10754 | } | ||
10755 | } | ||
10756 | else | ||
10757 | { | ||
10758 | this.core.ParseExtensionElement(node, child); | ||
10759 | } | ||
10760 | } | ||
10761 | |||
10762 | if (!this.core.EncounteredError) | ||
10763 | { | ||
10764 | Row row = this.core.CreateRow(sourceLineNumbers, "ODBCDataSource", id); | ||
10765 | row[1] = componentId; | ||
10766 | row[2] = name; | ||
10767 | row[3] = driverName; | ||
10768 | row[4] = registration; | ||
10769 | } | ||
10770 | |||
10771 | possibleKeyPath = id.Id; | ||
10772 | return keyPath; | ||
10773 | } | ||
10774 | |||
10775 | /// <summary> | ||
10776 | /// Parses a package element. | ||
10777 | /// </summary> | ||
10778 | /// <param name="node">Element to parse.</param> | ||
10779 | /// <param name="productAuthor">Default package author.</param> | ||
10780 | /// <param name="moduleId">The module guid - this is necessary until Module/@Guid is removed.</param> | ||
10781 | private void ParsePackageElement(XElement node, string productAuthor, string moduleId) | ||
10782 | { | ||
10783 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
10784 | string codepage = "65001"; | ||
10785 | string comments = String.Format(CultureInfo.InvariantCulture, "This installer database contains the logic and data required to install {0}.", this.activeName); | ||
10786 | string keywords = "Installer"; | ||
10787 | int msiVersion = 100; // lowest released version, really should be specified | ||
10788 | string packageAuthor = productAuthor; | ||
10789 | string packageCode = null; | ||
10790 | string packageLanguages = this.activeLanguage; | ||
10791 | string packageName = this.activeName; | ||
10792 | string platform = null; | ||
10793 | string platformValue = null; | ||
10794 | YesNoDefaultType security = YesNoDefaultType.Default; | ||
10795 | int sourceBits = (this.compilingModule ? 2 : 0); | ||
10796 | Row row; | ||
10797 | bool installPrivilegeSeen = false; | ||
10798 | bool installScopeSeen = false; | ||
10799 | |||
10800 | switch (this.CurrentPlatform) | ||
10801 | { | ||
10802 | case Platform.X86: | ||
10803 | platform = "Intel"; | ||
10804 | break; | ||
10805 | case Platform.X64: | ||
10806 | platform = "x64"; | ||
10807 | msiVersion = 200; | ||
10808 | break; | ||
10809 | case Platform.IA64: | ||
10810 | platform = "Intel64"; | ||
10811 | msiVersion = 200; | ||
10812 | break; | ||
10813 | case Platform.ARM: | ||
10814 | platform = "Arm"; | ||
10815 | msiVersion = 500; | ||
10816 | break; | ||
10817 | default: | ||
10818 | throw new ArgumentException(WixStrings.EXP_UnknownPlatformEnum, this.CurrentPlatform.ToString()); | ||
10819 | } | ||
10820 | |||
10821 | foreach (XAttribute attrib in node.Attributes()) | ||
10822 | { | ||
10823 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
10824 | { | ||
10825 | switch (attrib.Name.LocalName) | ||
10826 | { | ||
10827 | case "Id": | ||
10828 | packageCode = this.core.GetAttributeGuidValue(sourceLineNumbers, attrib, this.compilingProduct); | ||
10829 | break; | ||
10830 | case "AdminImage": | ||
10831 | if (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
10832 | { | ||
10833 | sourceBits = sourceBits | 4; | ||
10834 | } | ||
10835 | break; | ||
10836 | case "Comments": | ||
10837 | comments = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
10838 | break; | ||
10839 | case "Compressed": | ||
10840 | // merge modules must always be compressed, so this attribute is invalid | ||
10841 | if (this.compilingModule) | ||
10842 | { | ||
10843 | this.core.OnMessage(WixWarnings.DeprecatedPackageCompressedAttribute(sourceLineNumbers)); | ||
10844 | // this.core.OnMessage(WixErrors.IllegalAttributeWhenNested(sourceLineNumbers, node.Name.LocalName, "Compressed", "Module")); | ||
10845 | } | ||
10846 | else if (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
10847 | { | ||
10848 | sourceBits = sourceBits | 2; | ||
10849 | } | ||
10850 | break; | ||
10851 | case "Description": | ||
10852 | packageName = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
10853 | break; | ||
10854 | case "InstallPrivileges": | ||
10855 | string installPrivileges = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
10856 | if (0 < installPrivileges.Length) | ||
10857 | { | ||
10858 | installPrivilegeSeen = true; | ||
10859 | Wix.Package.InstallPrivilegesType installPrivilegesType = Wix.Package.ParseInstallPrivilegesType(installPrivileges); | ||
10860 | switch (installPrivilegesType) | ||
10861 | { | ||
10862 | case Wix.Package.InstallPrivilegesType.elevated: | ||
10863 | // this is the default setting | ||
10864 | break; | ||
10865 | case Wix.Package.InstallPrivilegesType.limited: | ||
10866 | sourceBits = sourceBits | 8; | ||
10867 | break; | ||
10868 | default: | ||
10869 | this.core.OnMessage(WixErrors.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, installPrivileges, "elevated", "limited")); | ||
10870 | break; | ||
10871 | } | ||
10872 | } | ||
10873 | break; | ||
10874 | case "InstallScope": | ||
10875 | string installScope = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
10876 | if (0 < installScope.Length) | ||
10877 | { | ||
10878 | installScopeSeen = true; | ||
10879 | Wix.Package.InstallScopeType installScopeType = Wix.Package.ParseInstallScopeType(installScope); | ||
10880 | switch (installScopeType) | ||
10881 | { | ||
10882 | case Wix.Package.InstallScopeType.perMachine: | ||
10883 | row = this.core.CreateRow(sourceLineNumbers, "Property"); | ||
10884 | row[0] = "ALLUSERS"; | ||
10885 | row[1] = "1"; | ||
10886 | break; | ||
10887 | case Wix.Package.InstallScopeType.perUser: | ||
10888 | sourceBits = sourceBits | 8; | ||
10889 | break; | ||
10890 | default: | ||
10891 | this.core.OnMessage(WixErrors.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, installScope, "perMachine", "perUser")); | ||
10892 | break; | ||
10893 | } | ||
10894 | } | ||
10895 | break; | ||
10896 | case "InstallerVersion": | ||
10897 | msiVersion = this.core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, int.MaxValue); | ||
10898 | break; | ||
10899 | case "Keywords": | ||
10900 | keywords = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
10901 | break; | ||
10902 | case "Languages": | ||
10903 | packageLanguages = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
10904 | break; | ||
10905 | case "Manufacturer": | ||
10906 | packageAuthor = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
10907 | if ("PUT-COMPANY-NAME-HERE" == packageAuthor) | ||
10908 | { | ||
10909 | this.core.OnMessage(WixWarnings.PlaceholderValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, packageAuthor)); | ||
10910 | } | ||
10911 | break; | ||
10912 | case "Platform": | ||
10913 | if (null != platformValue) | ||
10914 | { | ||
10915 | this.core.OnMessage(WixErrors.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, "Platforms")); | ||
10916 | } | ||
10917 | |||
10918 | platformValue = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
10919 | Wix.Package.PlatformType platformType = Wix.Package.ParsePlatformType(platformValue); | ||
10920 | switch (platformType) | ||
10921 | { | ||
10922 | case Wix.Package.PlatformType.intel: | ||
10923 | this.core.OnMessage(WixWarnings.DeprecatedAttributeValue(sourceLineNumbers, platformValue, node.Name.LocalName, attrib.Name.LocalName, "x86")); | ||
10924 | goto case Wix.Package.PlatformType.x86; | ||
10925 | case Wix.Package.PlatformType.x86: | ||
10926 | platform = "Intel"; | ||
10927 | break; | ||
10928 | case Wix.Package.PlatformType.x64: | ||
10929 | platform = "x64"; | ||
10930 | break; | ||
10931 | case Wix.Package.PlatformType.intel64: | ||
10932 | this.core.OnMessage(WixWarnings.DeprecatedAttributeValue(sourceLineNumbers, platformValue, node.Name.LocalName, attrib.Name.LocalName, "ia64")); | ||
10933 | goto case Wix.Package.PlatformType.ia64; | ||
10934 | case Wix.Package.PlatformType.ia64: | ||
10935 | platform = "Intel64"; | ||
10936 | break; | ||
10937 | case Wix.Package.PlatformType.arm: | ||
10938 | platform = "Arm"; | ||
10939 | break; | ||
10940 | default: | ||
10941 | this.core.OnMessage(WixErrors.InvalidPlatformValue(sourceLineNumbers, platformValue)); | ||
10942 | break; | ||
10943 | } | ||
10944 | break; | ||
10945 | case "Platforms": | ||
10946 | if (null != platformValue) | ||
10947 | { | ||
10948 | this.core.OnMessage(WixErrors.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, "Platform")); | ||
10949 | } | ||
10950 | |||
10951 | this.core.OnMessage(WixWarnings.DeprecatedAttribute(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, "Platform")); | ||
10952 | platformValue = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
10953 | platform = platformValue; | ||
10954 | break; | ||
10955 | case "ReadOnly": | ||
10956 | security = this.core.GetAttributeYesNoDefaultValue(sourceLineNumbers, attrib); | ||
10957 | break; | ||
10958 | case "ShortNames": | ||
10959 | if (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
10960 | { | ||
10961 | sourceBits = sourceBits | 1; | ||
10962 | this.useShortFileNames = true; | ||
10963 | } | ||
10964 | break; | ||
10965 | case "SummaryCodepage": | ||
10966 | codepage = this.core.GetAttributeLocalizableCodePageValue(sourceLineNumbers, attrib, true); | ||
10967 | break; | ||
10968 | default: | ||
10969 | this.core.UnexpectedAttribute(node, attrib); | ||
10970 | break; | ||
10971 | } | ||
10972 | } | ||
10973 | else | ||
10974 | { | ||
10975 | this.core.ParseExtensionAttribute(node, attrib); | ||
10976 | } | ||
10977 | } | ||
10978 | |||
10979 | if (installPrivilegeSeen && installScopeSeen) | ||
10980 | { | ||
10981 | this.core.OnMessage(WixErrors.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "InstallPrivileges", "InstallScope")); | ||
10982 | } | ||
10983 | |||
10984 | if ((0 != String.Compare(platform, "Intel", StringComparison.OrdinalIgnoreCase)) && 200 > msiVersion) | ||
10985 | { | ||
10986 | msiVersion = 200; | ||
10987 | this.core.OnMessage(WixWarnings.RequiresMsi200for64bitPackage(sourceLineNumbers)); | ||
10988 | } | ||
10989 | |||
10990 | if ((0 == String.Compare(platform, "Arm", StringComparison.OrdinalIgnoreCase)) && 500 > msiVersion) | ||
10991 | { | ||
10992 | msiVersion = 500; | ||
10993 | this.core.OnMessage(WixWarnings.RequiresMsi500forArmPackage(sourceLineNumbers)); | ||
10994 | } | ||
10995 | |||
10996 | if (null == packageAuthor) | ||
10997 | { | ||
10998 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Manufacturer")); | ||
10999 | } | ||
11000 | |||
11001 | if (this.compilingModule) | ||
11002 | { | ||
11003 | if (null == packageCode) | ||
11004 | { | ||
11005 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
11006 | } | ||
11007 | |||
11008 | // merge modules use the modularization guid as the package code | ||
11009 | if (null != moduleId) | ||
11010 | { | ||
11011 | packageCode = moduleId; | ||
11012 | } | ||
11013 | |||
11014 | // merge modules are always compressed | ||
11015 | sourceBits = 2; | ||
11016 | } | ||
11017 | else // product | ||
11018 | { | ||
11019 | if (null == packageCode) | ||
11020 | { | ||
11021 | packageCode = "*"; | ||
11022 | } | ||
11023 | |||
11024 | if ("*" != packageCode) | ||
11025 | { | ||
11026 | this.core.OnMessage(WixWarnings.PackageCodeSet(sourceLineNumbers)); | ||
11027 | } | ||
11028 | } | ||
11029 | |||
11030 | this.core.ParseForExtensionElements(node); | ||
11031 | |||
11032 | if (!this.core.EncounteredError) | ||
11033 | { | ||
11034 | row = this.core.CreateRow(sourceLineNumbers, "_SummaryInformation"); | ||
11035 | row[0] = 1; | ||
11036 | row[1] = codepage; | ||
11037 | |||
11038 | row = this.core.CreateRow(sourceLineNumbers, "_SummaryInformation"); | ||
11039 | row[0] = 2; | ||
11040 | row[1] = "Installation Database"; | ||
11041 | |||
11042 | row = this.core.CreateRow(sourceLineNumbers, "_SummaryInformation"); | ||
11043 | row[0] = 3; | ||
11044 | row[1] = packageName; | ||
11045 | |||
11046 | row = this.core.CreateRow(sourceLineNumbers, "_SummaryInformation"); | ||
11047 | row[0] = 4; | ||
11048 | row[1] = packageAuthor; | ||
11049 | |||
11050 | row = this.core.CreateRow(sourceLineNumbers, "_SummaryInformation"); | ||
11051 | row[0] = 5; | ||
11052 | row[1] = keywords; | ||
11053 | |||
11054 | row = this.core.CreateRow(sourceLineNumbers, "_SummaryInformation"); | ||
11055 | row[0] = 6; | ||
11056 | row[1] = comments; | ||
11057 | |||
11058 | row = this.core.CreateRow(sourceLineNumbers, "_SummaryInformation"); | ||
11059 | row[0] = 7; | ||
11060 | row[1] = String.Format(CultureInfo.InvariantCulture, "{0};{1}", platform, packageLanguages); | ||
11061 | |||
11062 | row = this.core.CreateRow(sourceLineNumbers, "_SummaryInformation"); | ||
11063 | row[0] = 9; | ||
11064 | row[1] = packageCode; | ||
11065 | |||
11066 | row = this.core.CreateRow(sourceLineNumbers, "_SummaryInformation"); | ||
11067 | row[0] = 14; | ||
11068 | row[1] = msiVersion.ToString(CultureInfo.InvariantCulture); | ||
11069 | |||
11070 | row = this.core.CreateRow(sourceLineNumbers, "_SummaryInformation"); | ||
11071 | row[0] = 15; | ||
11072 | row[1] = sourceBits.ToString(CultureInfo.InvariantCulture); | ||
11073 | |||
11074 | row = this.core.CreateRow(sourceLineNumbers, "_SummaryInformation"); | ||
11075 | row[0] = 19; | ||
11076 | switch (security) | ||
11077 | { | ||
11078 | case YesNoDefaultType.No: // no restriction | ||
11079 | row[1] = "0"; | ||
11080 | break; | ||
11081 | case YesNoDefaultType.Default: // read-only recommended | ||
11082 | row[1] = "2"; | ||
11083 | break; | ||
11084 | case YesNoDefaultType.Yes: // read-only enforced | ||
11085 | row[1] = "4"; | ||
11086 | break; | ||
11087 | } | ||
11088 | } | ||
11089 | } | ||
11090 | |||
11091 | /// <summary> | ||
11092 | /// Parses a patch metadata element. | ||
11093 | /// </summary> | ||
11094 | /// <param name="node">Element to parse.</param> | ||
11095 | private void ParsePatchMetadataElement(XElement node) | ||
11096 | { | ||
11097 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
11098 | YesNoType allowRemoval = YesNoType.NotSet; | ||
11099 | string classification = null; | ||
11100 | string creationTimeUtc = null; | ||
11101 | string description = null; | ||
11102 | string displayName = null; | ||
11103 | string manufacturerName = null; | ||
11104 | string minorUpdateTargetRTM = null; | ||
11105 | string moreInfoUrl = null; | ||
11106 | int optimizeCA = CompilerConstants.IntegerNotSet; | ||
11107 | YesNoType optimizedInstallMode = YesNoType.NotSet; | ||
11108 | string targetProductName = null; | ||
11109 | |||
11110 | foreach (XAttribute attrib in node.Attributes()) | ||
11111 | { | ||
11112 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
11113 | { | ||
11114 | switch (attrib.Name.LocalName) | ||
11115 | { | ||
11116 | case "AllowRemoval": | ||
11117 | allowRemoval = this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
11118 | break; | ||
11119 | case "Classification": | ||
11120 | classification = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
11121 | break; | ||
11122 | case "CreationTimeUTC": | ||
11123 | creationTimeUtc = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
11124 | break; | ||
11125 | case "Description": | ||
11126 | description = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
11127 | break; | ||
11128 | case "DisplayName": | ||
11129 | displayName = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
11130 | break; | ||
11131 | case "ManufacturerName": | ||
11132 | manufacturerName = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
11133 | break; | ||
11134 | case "MinorUpdateTargetRTM": | ||
11135 | minorUpdateTargetRTM = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
11136 | break; | ||
11137 | case "MoreInfoURL": | ||
11138 | moreInfoUrl = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
11139 | break; | ||
11140 | case "OptimizedInstallMode": | ||
11141 | optimizedInstallMode = this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
11142 | break; | ||
11143 | case "TargetProductName": | ||
11144 | targetProductName = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
11145 | break; | ||
11146 | default: | ||
11147 | this.core.UnexpectedAttribute(node, attrib); | ||
11148 | break; | ||
11149 | } | ||
11150 | } | ||
11151 | else | ||
11152 | { | ||
11153 | this.core.ParseExtensionAttribute(node, attrib); | ||
11154 | } | ||
11155 | } | ||
11156 | |||
11157 | if (YesNoType.NotSet == allowRemoval) | ||
11158 | { | ||
11159 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "AllowRemoval")); | ||
11160 | } | ||
11161 | |||
11162 | if (null == classification) | ||
11163 | { | ||
11164 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Classification")); | ||
11165 | } | ||
11166 | |||
11167 | if (null == description) | ||
11168 | { | ||
11169 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Description")); | ||
11170 | } | ||
11171 | |||
11172 | if (null == displayName) | ||
11173 | { | ||
11174 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "DisplayName")); | ||
11175 | } | ||
11176 | |||
11177 | if (null == manufacturerName) | ||
11178 | { | ||
11179 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "ManufacturerName")); | ||
11180 | } | ||
11181 | |||
11182 | if (null == moreInfoUrl) | ||
11183 | { | ||
11184 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "MoreInfoURL")); | ||
11185 | } | ||
11186 | |||
11187 | if (null == targetProductName) | ||
11188 | { | ||
11189 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "TargetProductName")); | ||
11190 | } | ||
11191 | |||
11192 | foreach (XElement child in node.Elements()) | ||
11193 | { | ||
11194 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
11195 | { | ||
11196 | switch (child.Name.LocalName) | ||
11197 | { | ||
11198 | case "CustomProperty": | ||
11199 | this.ParseCustomPropertyElement(child); | ||
11200 | break; | ||
11201 | case "OptimizeCustomActions": | ||
11202 | optimizeCA = this.ParseOptimizeCustomActionsElement(child); | ||
11203 | break; | ||
11204 | default: | ||
11205 | this.core.UnexpectedElement(node, child); | ||
11206 | break; | ||
11207 | } | ||
11208 | } | ||
11209 | else | ||
11210 | { | ||
11211 | this.core.ParseExtensionElement(node, child); | ||
11212 | } | ||
11213 | } | ||
11214 | |||
11215 | if (!this.core.EncounteredError) | ||
11216 | { | ||
11217 | if (YesNoType.NotSet != allowRemoval) | ||
11218 | { | ||
11219 | Row row = this.core.CreateRow(sourceLineNumbers, "PatchMetadata"); | ||
11220 | row[0] = null; | ||
11221 | row[1] = "AllowRemoval"; | ||
11222 | row[2] = YesNoType.Yes == allowRemoval ? "1" : "0"; | ||
11223 | } | ||
11224 | |||
11225 | if (null != classification) | ||
11226 | { | ||
11227 | Row row = this.core.CreateRow(sourceLineNumbers, "PatchMetadata"); | ||
11228 | row[0] = null; | ||
11229 | row[1] = "Classification"; | ||
11230 | row[2] = classification; | ||
11231 | } | ||
11232 | |||
11233 | if (null != creationTimeUtc) | ||
11234 | { | ||
11235 | Row row = this.core.CreateRow(sourceLineNumbers, "PatchMetadata"); | ||
11236 | row[0] = null; | ||
11237 | row[1] = "CreationTimeUTC"; | ||
11238 | row[2] = creationTimeUtc; | ||
11239 | } | ||
11240 | |||
11241 | if (null != description) | ||
11242 | { | ||
11243 | Row row = this.core.CreateRow(sourceLineNumbers, "PatchMetadata"); | ||
11244 | row[0] = null; | ||
11245 | row[1] = "Description"; | ||
11246 | row[2] = description; | ||
11247 | } | ||
11248 | |||
11249 | if (null != displayName) | ||
11250 | { | ||
11251 | Row row = this.core.CreateRow(sourceLineNumbers, "PatchMetadata"); | ||
11252 | row[0] = null; | ||
11253 | row[1] = "DisplayName"; | ||
11254 | row[2] = displayName; | ||
11255 | } | ||
11256 | |||
11257 | if (null != manufacturerName) | ||
11258 | { | ||
11259 | Row row = this.core.CreateRow(sourceLineNumbers, "PatchMetadata"); | ||
11260 | row[0] = null; | ||
11261 | row[1] = "ManufacturerName"; | ||
11262 | row[2] = manufacturerName; | ||
11263 | } | ||
11264 | |||
11265 | if (null != minorUpdateTargetRTM) | ||
11266 | { | ||
11267 | Row row = this.core.CreateRow(sourceLineNumbers, "PatchMetadata"); | ||
11268 | row[0] = null; | ||
11269 | row[1] = "MinorUpdateTargetRTM"; | ||
11270 | row[2] = minorUpdateTargetRTM; | ||
11271 | } | ||
11272 | |||
11273 | if (null != moreInfoUrl) | ||
11274 | { | ||
11275 | Row row = this.core.CreateRow(sourceLineNumbers, "PatchMetadata"); | ||
11276 | row[0] = null; | ||
11277 | row[1] = "MoreInfoURL"; | ||
11278 | row[2] = moreInfoUrl; | ||
11279 | } | ||
11280 | |||
11281 | if (CompilerConstants.IntegerNotSet != optimizeCA) | ||
11282 | { | ||
11283 | Row row = this.core.CreateRow(sourceLineNumbers, "PatchMetadata"); | ||
11284 | row[0] = null; | ||
11285 | row[1] = "OptimizeCA"; | ||
11286 | row[2] = optimizeCA.ToString(CultureInfo.InvariantCulture); | ||
11287 | } | ||
11288 | |||
11289 | if (YesNoType.NotSet != optimizedInstallMode) | ||
11290 | { | ||
11291 | Row row = this.core.CreateRow(sourceLineNumbers, "PatchMetadata"); | ||
11292 | row[0] = null; | ||
11293 | row[1] = "OptimizedInstallMode"; | ||
11294 | row[2] = YesNoType.Yes == optimizedInstallMode ? "1" : "0"; | ||
11295 | } | ||
11296 | |||
11297 | if (null != targetProductName) | ||
11298 | { | ||
11299 | Row row = this.core.CreateRow(sourceLineNumbers, "PatchMetadata"); | ||
11300 | row[0] = null; | ||
11301 | row[1] = "TargetProductName"; | ||
11302 | row[2] = targetProductName; | ||
11303 | } | ||
11304 | } | ||
11305 | } | ||
11306 | |||
11307 | /// <summary> | ||
11308 | /// Parses a custom property element for the PatchMetadata table. | ||
11309 | /// </summary> | ||
11310 | /// <param name="node">Element to parse.</param> | ||
11311 | private void ParseCustomPropertyElement(XElement node) | ||
11312 | { | ||
11313 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
11314 | string company = null; | ||
11315 | string property = null; | ||
11316 | string value = null; | ||
11317 | |||
11318 | foreach (XAttribute attrib in node.Attributes()) | ||
11319 | { | ||
11320 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
11321 | { | ||
11322 | switch (attrib.Name.LocalName) | ||
11323 | { | ||
11324 | case "Company": | ||
11325 | company = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
11326 | break; | ||
11327 | case "Property": | ||
11328 | property = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
11329 | break; | ||
11330 | case "Value": | ||
11331 | value = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
11332 | break; | ||
11333 | default: | ||
11334 | this.core.UnexpectedAttribute(node, attrib); | ||
11335 | break; | ||
11336 | } | ||
11337 | } | ||
11338 | else | ||
11339 | { | ||
11340 | this.core.ParseExtensionAttribute(node, attrib); | ||
11341 | } | ||
11342 | } | ||
11343 | |||
11344 | if (null == company) | ||
11345 | { | ||
11346 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Company")); | ||
11347 | } | ||
11348 | |||
11349 | if (null == property) | ||
11350 | { | ||
11351 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Property")); | ||
11352 | } | ||
11353 | |||
11354 | if (null == value) | ||
11355 | { | ||
11356 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Value")); | ||
11357 | } | ||
11358 | |||
11359 | this.core.ParseForExtensionElements(node); | ||
11360 | |||
11361 | if (!this.core.EncounteredError) | ||
11362 | { | ||
11363 | Row row = this.core.CreateRow(sourceLineNumbers, "PatchMetadata"); | ||
11364 | row[0] = company; | ||
11365 | row[1] = property; | ||
11366 | row[2] = value; | ||
11367 | } | ||
11368 | } | ||
11369 | |||
11370 | /// <summary> | ||
11371 | /// Parses the OptimizeCustomActions element. | ||
11372 | /// </summary> | ||
11373 | /// <param name="node">Element to parse.</param> | ||
11374 | /// <returns>The combined integer value for callers to store as appropriate.</returns> | ||
11375 | private int ParseOptimizeCustomActionsElement(XElement node) | ||
11376 | { | ||
11377 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
11378 | OptimizeCA optimizeCA = OptimizeCA.None; | ||
11379 | |||
11380 | foreach (XAttribute attrib in node.Attributes()) | ||
11381 | { | ||
11382 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
11383 | { | ||
11384 | switch (attrib.Name.LocalName) | ||
11385 | { | ||
11386 | case "SkipAssignment": | ||
11387 | if (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
11388 | { | ||
11389 | optimizeCA |= OptimizeCA.SkipAssignment; | ||
11390 | } | ||
11391 | break; | ||
11392 | case "SkipImmediate": | ||
11393 | if (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
11394 | { | ||
11395 | optimizeCA |= OptimizeCA.SkipImmediate; | ||
11396 | } | ||
11397 | break; | ||
11398 | case "SkipDeferred": | ||
11399 | if (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
11400 | { | ||
11401 | optimizeCA |= OptimizeCA.SkipDeferred; | ||
11402 | } | ||
11403 | break; | ||
11404 | default: | ||
11405 | this.core.UnexpectedAttribute(node, attrib); | ||
11406 | break; | ||
11407 | } | ||
11408 | } | ||
11409 | else | ||
11410 | { | ||
11411 | this.core.ParseExtensionAttribute(node, attrib); | ||
11412 | } | ||
11413 | } | ||
11414 | |||
11415 | return (int)optimizeCA; | ||
11416 | } | ||
11417 | |||
11418 | /// <summary> | ||
11419 | /// Parses a patch information element. | ||
11420 | /// </summary> | ||
11421 | /// <param name="node">Element to parse.</param> | ||
11422 | private void ParsePatchInformationElement(XElement node) | ||
11423 | { | ||
11424 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
11425 | string codepage = "65001"; | ||
11426 | string comments = null; | ||
11427 | string keywords = "Installer,Patching,PCP,Database"; | ||
11428 | int msiVersion = 1; // Should always be 1 for patches | ||
11429 | string packageAuthor = null; | ||
11430 | string packageName = this.activeName; | ||
11431 | YesNoDefaultType security = YesNoDefaultType.Default; | ||
11432 | |||
11433 | foreach (XAttribute attrib in node.Attributes()) | ||
11434 | { | ||
11435 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
11436 | { | ||
11437 | switch (attrib.Name.LocalName) | ||
11438 | { | ||
11439 | case "AdminImage": | ||
11440 | this.core.OnMessage(WixWarnings.DeprecatedAttribute(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); | ||
11441 | break; | ||
11442 | case "Comments": | ||
11443 | comments = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
11444 | break; | ||
11445 | case "Compressed": | ||
11446 | this.core.OnMessage(WixWarnings.DeprecatedAttribute(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); | ||
11447 | break; | ||
11448 | case "Description": | ||
11449 | packageName = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
11450 | break; | ||
11451 | case "Keywords": | ||
11452 | keywords = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
11453 | break; | ||
11454 | case "Languages": | ||
11455 | this.core.OnMessage(WixWarnings.DeprecatedAttribute(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); | ||
11456 | break; | ||
11457 | case "Manufacturer": | ||
11458 | packageAuthor = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
11459 | break; | ||
11460 | case "Platforms": | ||
11461 | this.core.OnMessage(WixWarnings.DeprecatedAttribute(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); | ||
11462 | break; | ||
11463 | case "ReadOnly": | ||
11464 | security = this.core.GetAttributeYesNoDefaultValue(sourceLineNumbers, attrib); | ||
11465 | break; | ||
11466 | case "ShortNames": | ||
11467 | this.core.OnMessage(WixWarnings.DeprecatedAttribute(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); | ||
11468 | break; | ||
11469 | case "SummaryCodepage": | ||
11470 | codepage = this.core.GetAttributeLocalizableCodePageValue(sourceLineNumbers, attrib); | ||
11471 | break; | ||
11472 | default: | ||
11473 | this.core.UnexpectedAttribute(node, attrib); | ||
11474 | break; | ||
11475 | } | ||
11476 | } | ||
11477 | else | ||
11478 | { | ||
11479 | this.core.ParseExtensionAttribute(node, attrib); | ||
11480 | } | ||
11481 | } | ||
11482 | |||
11483 | this.core.ParseForExtensionElements(node); | ||
11484 | |||
11485 | if (!this.core.EncounteredError) | ||
11486 | { | ||
11487 | // PID_CODEPAGE | ||
11488 | Row row = this.core.CreateRow(sourceLineNumbers, "_SummaryInformation"); | ||
11489 | row[0] = 1; | ||
11490 | row[1] = codepage; | ||
11491 | |||
11492 | // PID_TITLE | ||
11493 | row = this.core.CreateRow(sourceLineNumbers, "_SummaryInformation"); | ||
11494 | row[0] = 2; | ||
11495 | row[1] = "Patch"; | ||
11496 | |||
11497 | // PID_SUBJECT | ||
11498 | if (null != packageName) | ||
11499 | { | ||
11500 | row = this.core.CreateRow(sourceLineNumbers, "_SummaryInformation"); | ||
11501 | row[0] = 3; | ||
11502 | row[1] = packageName; | ||
11503 | } | ||
11504 | |||
11505 | // PID_AUTHOR | ||
11506 | if (null != packageAuthor) | ||
11507 | { | ||
11508 | row = this.core.CreateRow(sourceLineNumbers, "_SummaryInformation"); | ||
11509 | row[0] = 4; | ||
11510 | row[1] = packageAuthor; | ||
11511 | } | ||
11512 | |||
11513 | // PID_KEYWORDS | ||
11514 | if (null != keywords) | ||
11515 | { | ||
11516 | row = this.core.CreateRow(sourceLineNumbers, "_SummaryInformation"); | ||
11517 | row[0] = 5; | ||
11518 | row[1] = keywords; | ||
11519 | } | ||
11520 | |||
11521 | // PID_COMMENTS | ||
11522 | if (null != comments) | ||
11523 | { | ||
11524 | row = this.core.CreateRow(sourceLineNumbers, "_SummaryInformation"); | ||
11525 | row[0] = 6; | ||
11526 | row[1] = comments; | ||
11527 | } | ||
11528 | |||
11529 | // PID_PAGECOUNT | ||
11530 | row = this.core.CreateRow(sourceLineNumbers, "_SummaryInformation"); | ||
11531 | row[0] = 14; | ||
11532 | row[1] = msiVersion.ToString(CultureInfo.InvariantCulture); | ||
11533 | |||
11534 | // PID_WORDCOUNT | ||
11535 | row = this.core.CreateRow(sourceLineNumbers, "_SummaryInformation"); | ||
11536 | row[0] = 15; | ||
11537 | row[1] = "0"; | ||
11538 | |||
11539 | // PID_SECURITY | ||
11540 | row = this.core.CreateRow(sourceLineNumbers, "_SummaryInformation"); | ||
11541 | row[0] = 19; | ||
11542 | switch (security) | ||
11543 | { | ||
11544 | case YesNoDefaultType.No: // no restriction | ||
11545 | row[1] = "0"; | ||
11546 | break; | ||
11547 | case YesNoDefaultType.Default: // read-only recommended | ||
11548 | row[1] = "2"; | ||
11549 | break; | ||
11550 | case YesNoDefaultType.Yes: // read-only enforced | ||
11551 | row[1] = "4"; | ||
11552 | break; | ||
11553 | } | ||
11554 | } | ||
11555 | } | ||
11556 | |||
11557 | /// <summary> | ||
11558 | /// Parses an ignore modularization element. | ||
11559 | /// </summary> | ||
11560 | /// <param name="node">XmlNode on an IgnoreModulatization element.</param> | ||
11561 | private void ParseIgnoreModularizationElement(XElement node) | ||
11562 | { | ||
11563 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
11564 | string name = null; | ||
11565 | |||
11566 | this.core.OnMessage(WixWarnings.DeprecatedIgnoreModularizationElement(sourceLineNumbers)); | ||
11567 | |||
11568 | foreach (XAttribute attrib in node.Attributes()) | ||
11569 | { | ||
11570 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
11571 | { | ||
11572 | switch (attrib.Name.LocalName) | ||
11573 | { | ||
11574 | case "Name": | ||
11575 | name = this.core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
11576 | break; | ||
11577 | case "Type": | ||
11578 | // this is actually not used | ||
11579 | break; | ||
11580 | default: | ||
11581 | this.core.UnexpectedAttribute(node, attrib); | ||
11582 | break; | ||
11583 | } | ||
11584 | } | ||
11585 | else | ||
11586 | { | ||
11587 | this.core.ParseExtensionAttribute(node, attrib); | ||
11588 | } | ||
11589 | } | ||
11590 | |||
11591 | if (null == name) | ||
11592 | { | ||
11593 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Name")); | ||
11594 | } | ||
11595 | |||
11596 | this.core.ParseForExtensionElements(node); | ||
11597 | |||
11598 | if (!this.core.EncounteredError) | ||
11599 | { | ||
11600 | Row row = this.core.CreateRow(sourceLineNumbers, "WixSuppressModularization"); | ||
11601 | row[0] = name; | ||
11602 | } | ||
11603 | } | ||
11604 | |||
11605 | /// <summary> | ||
11606 | /// Parses a permission element. | ||
11607 | /// </summary> | ||
11608 | /// <param name="node">Element to parse.</param> | ||
11609 | /// <param name="objectId">Identifier of object to be secured.</param> | ||
11610 | /// <param name="tableName">Name of table that contains objectId.</param> | ||
11611 | private void ParsePermissionElement(XElement node, string objectId, string tableName) | ||
11612 | { | ||
11613 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
11614 | BitArray bits = new BitArray(32); | ||
11615 | string domain = null; | ||
11616 | int permission = 0; | ||
11617 | string[] specialPermissions = null; | ||
11618 | string user = null; | ||
11619 | |||
11620 | switch (tableName) | ||
11621 | { | ||
11622 | case "CreateFolder": | ||
11623 | specialPermissions = Common.FolderPermissions; | ||
11624 | break; | ||
11625 | case "File": | ||
11626 | specialPermissions = Common.FilePermissions; | ||
11627 | break; | ||
11628 | case "Registry": | ||
11629 | specialPermissions = Common.RegistryPermissions; | ||
11630 | break; | ||
11631 | default: | ||
11632 | this.core.UnexpectedElement(node.Parent, node); | ||
11633 | return; // stop processing this element since no valid permissions are available | ||
11634 | } | ||
11635 | |||
11636 | foreach (XAttribute attrib in node.Attributes()) | ||
11637 | { | ||
11638 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
11639 | { | ||
11640 | switch (attrib.Name.LocalName) | ||
11641 | { | ||
11642 | case "Domain": | ||
11643 | domain = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
11644 | break; | ||
11645 | case "User": | ||
11646 | user = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
11647 | break; | ||
11648 | case "FileAllRights": | ||
11649 | // match the WinNT.h mask FILE_ALL_ACCESS for value 0x001F01FF (aka 1 1111 0000 0001 1111 1111 or 2032127) | ||
11650 | bits[0] = bits[1] = bits[2] = bits[3] = bits[4] = bits[5] = bits[6] = bits[7] = bits[8] = bits[16] = bits[17] = bits[18] = bits[19] = bits[20] = true; | ||
11651 | break; | ||
11652 | case "SpecificRightsAll": | ||
11653 | // match the WinNT.h mask SPECIFIC_RIGHTS_ALL for value 0x0000FFFF (aka 1111 1111 1111 1111) | ||
11654 | bits[0] = bits[1] = bits[2] = bits[3] = bits[4] = bits[5] = bits[6] = bits[7] = bits[8] = bits[9] = bits[10] = bits[11] = bits[12] = bits[13] = bits[14] = bits[15] = true; | ||
11655 | break; | ||
11656 | default: | ||
11657 | YesNoType attribValue = this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
11658 | if (!this.core.TrySetBitFromName(Common.StandardPermissions, attrib.Name.LocalName, attribValue, bits, 16)) | ||
11659 | { | ||
11660 | if (!this.core.TrySetBitFromName(Common.GenericPermissions, attrib.Name.LocalName, attribValue, bits, 28)) | ||
11661 | { | ||
11662 | if (!this.core.TrySetBitFromName(specialPermissions, attrib.Name.LocalName, attribValue, bits, 0)) | ||
11663 | { | ||
11664 | this.core.UnexpectedAttribute(node, attrib); | ||
11665 | break; | ||
11666 | } | ||
11667 | } | ||
11668 | } | ||
11669 | break; | ||
11670 | } | ||
11671 | } | ||
11672 | else | ||
11673 | { | ||
11674 | this.core.ParseExtensionAttribute(node, attrib); | ||
11675 | } | ||
11676 | } | ||
11677 | |||
11678 | permission = this.core.CreateIntegerFromBitArray(bits); | ||
11679 | |||
11680 | if (null == user) | ||
11681 | { | ||
11682 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "User")); | ||
11683 | } | ||
11684 | |||
11685 | if (int.MinValue == permission) // just GENERIC_READ, which is MSI_NULL | ||
11686 | { | ||
11687 | this.core.OnMessage(WixErrors.GenericReadNotAllowed(sourceLineNumbers)); | ||
11688 | } | ||
11689 | |||
11690 | this.core.ParseForExtensionElements(node); | ||
11691 | |||
11692 | if (!this.core.EncounteredError) | ||
11693 | { | ||
11694 | Row row = this.core.CreateRow(sourceLineNumbers, "LockPermissions"); | ||
11695 | row[0] = objectId; | ||
11696 | row[1] = tableName; | ||
11697 | row[2] = domain; | ||
11698 | row[3] = user; | ||
11699 | row[4] = permission; | ||
11700 | } | ||
11701 | } | ||
11702 | |||
11703 | /// <summary> | ||
11704 | /// Parses an extended permission element. | ||
11705 | /// </summary> | ||
11706 | /// <param name="node">Element to parse.</param> | ||
11707 | /// <param name="objectId">Identifier of object to be secured.</param> | ||
11708 | /// <param name="tableName">Name of table that contains objectId.</param> | ||
11709 | private void ParsePermissionExElement(XElement node, string objectId, string tableName) | ||
11710 | { | ||
11711 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
11712 | string condition = null; | ||
11713 | Identifier id = null; | ||
11714 | string sddl = null; | ||
11715 | |||
11716 | switch (tableName) | ||
11717 | { | ||
11718 | case "CreateFolder": | ||
11719 | case "File": | ||
11720 | case "Registry": | ||
11721 | case "ServiceInstall": | ||
11722 | break; | ||
11723 | default: | ||
11724 | this.core.UnexpectedElement(node.Parent, node); | ||
11725 | return; // stop processing this element since nothing will be valid. | ||
11726 | } | ||
11727 | |||
11728 | foreach (XAttribute attrib in node.Attributes()) | ||
11729 | { | ||
11730 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
11731 | { | ||
11732 | switch (attrib.Name.LocalName) | ||
11733 | { | ||
11734 | case "Id": | ||
11735 | id = this.core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
11736 | break; | ||
11737 | case "Sddl": | ||
11738 | sddl = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
11739 | break; | ||
11740 | default: | ||
11741 | this.core.UnexpectedAttribute(node, attrib); | ||
11742 | break; | ||
11743 | } | ||
11744 | } | ||
11745 | else | ||
11746 | { | ||
11747 | this.core.ParseExtensionAttribute(node, attrib); | ||
11748 | } | ||
11749 | } | ||
11750 | |||
11751 | if (null == sddl) | ||
11752 | { | ||
11753 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Sddl")); | ||
11754 | } | ||
11755 | |||
11756 | if (null == id) | ||
11757 | { | ||
11758 | id = this.core.CreateIdentifier("pme", objectId, tableName, sddl); | ||
11759 | } | ||
11760 | |||
11761 | foreach (XElement child in node.Elements()) | ||
11762 | { | ||
11763 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
11764 | { | ||
11765 | switch (child.Name.LocalName) | ||
11766 | { | ||
11767 | case "Condition": | ||
11768 | if (null != condition) | ||
11769 | { | ||
11770 | SourceLineNumber childSourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
11771 | this.core.OnMessage(WixErrors.TooManyChildren(childSourceLineNumbers, node.Name.LocalName, child.Name.LocalName)); | ||
11772 | } | ||
11773 | |||
11774 | condition = this.ParseConditionElement(child, node.Name.LocalName, null, null); | ||
11775 | break; | ||
11776 | default: | ||
11777 | this.core.UnexpectedElement(node, child); | ||
11778 | break; | ||
11779 | } | ||
11780 | } | ||
11781 | else | ||
11782 | { | ||
11783 | this.core.ParseExtensionElement(node, child); | ||
11784 | } | ||
11785 | } | ||
11786 | |||
11787 | if (!this.core.EncounteredError) | ||
11788 | { | ||
11789 | Row row = this.core.CreateRow(sourceLineNumbers, "MsiLockPermissionsEx", id); | ||
11790 | row[1] = objectId; | ||
11791 | row[2] = tableName; | ||
11792 | row[3] = sddl; | ||
11793 | row[4] = condition; | ||
11794 | } | ||
11795 | } | ||
11796 | |||
11797 | /// <summary> | ||
11798 | /// Parses a product element. | ||
11799 | /// </summary> | ||
11800 | /// <param name="node">Element to parse.</param> | ||
11801 | [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1800:DoNotCastUnnecessarily")] | ||
11802 | private void ParseProductElement(XElement node) | ||
11803 | { | ||
11804 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
11805 | int codepage = 0; | ||
11806 | string productCode = null; | ||
11807 | string upgradeCode = null; | ||
11808 | string manufacturer = null; | ||
11809 | string version = null; | ||
11810 | string symbols = null; | ||
11811 | |||
11812 | this.activeName = null; | ||
11813 | this.activeLanguage = null; | ||
11814 | |||
11815 | foreach (XAttribute attrib in node.Attributes()) | ||
11816 | { | ||
11817 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
11818 | { | ||
11819 | switch (attrib.Name.LocalName) | ||
11820 | { | ||
11821 | case "Id": | ||
11822 | productCode = this.core.GetAttributeGuidValue(sourceLineNumbers, attrib, true); | ||
11823 | break; | ||
11824 | case "Codepage": | ||
11825 | codepage = this.core.GetAttributeCodePageValue(sourceLineNumbers, attrib); | ||
11826 | break; | ||
11827 | case "Language": | ||
11828 | this.activeLanguage = this.core.GetAttributeLocalizableIntegerValue(sourceLineNumbers, attrib, 0, short.MaxValue); | ||
11829 | break; | ||
11830 | case "Manufacturer": | ||
11831 | manufacturer = this.core.GetAttributeValue(sourceLineNumbers, attrib, EmptyRule.MustHaveNonWhitespaceCharacters); | ||
11832 | if ("PUT-COMPANY-NAME-HERE" == manufacturer) | ||
11833 | { | ||
11834 | this.core.OnMessage(WixWarnings.PlaceholderValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, manufacturer)); | ||
11835 | } | ||
11836 | break; | ||
11837 | case "Name": | ||
11838 | this.activeName = this.core.GetAttributeValue(sourceLineNumbers, attrib, EmptyRule.MustHaveNonWhitespaceCharacters); | ||
11839 | if ("PUT-PRODUCT-NAME-HERE" == this.activeName) | ||
11840 | { | ||
11841 | this.core.OnMessage(WixWarnings.PlaceholderValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, this.activeName)); | ||
11842 | } | ||
11843 | break; | ||
11844 | case "UpgradeCode": | ||
11845 | upgradeCode = this.core.GetAttributeGuidValue(sourceLineNumbers, attrib, false); | ||
11846 | break; | ||
11847 | case "Version": // if the attribute is valid version, use the attribute value as is (so "1.0000.01.01" would *not* get translated to "1.0.1.1"). | ||
11848 | string verifiedVersion = this.core.GetAttributeVersionValue(sourceLineNumbers, attrib); | ||
11849 | if (!String.IsNullOrEmpty(verifiedVersion)) | ||
11850 | { | ||
11851 | version = attrib.Value; | ||
11852 | } | ||
11853 | break; | ||
11854 | default: | ||
11855 | this.core.UnexpectedAttribute(node, attrib); | ||
11856 | break; | ||
11857 | } | ||
11858 | } | ||
11859 | else | ||
11860 | { | ||
11861 | this.core.ParseExtensionAttribute(node, attrib); | ||
11862 | } | ||
11863 | } | ||
11864 | |||
11865 | if (null == productCode) | ||
11866 | { | ||
11867 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
11868 | } | ||
11869 | |||
11870 | if (null == this.activeLanguage) | ||
11871 | { | ||
11872 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Language")); | ||
11873 | } | ||
11874 | |||
11875 | if (null == manufacturer) | ||
11876 | { | ||
11877 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Manufacturer")); | ||
11878 | } | ||
11879 | |||
11880 | if (null == this.activeName) | ||
11881 | { | ||
11882 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Name")); | ||
11883 | } | ||
11884 | |||
11885 | if (null == upgradeCode) | ||
11886 | { | ||
11887 | this.core.OnMessage(WixWarnings.MissingUpgradeCode(sourceLineNumbers)); | ||
11888 | } | ||
11889 | |||
11890 | if (null == version) | ||
11891 | { | ||
11892 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Version")); | ||
11893 | } | ||
11894 | else if (!CompilerCore.IsValidProductVersion(version)) | ||
11895 | { | ||
11896 | this.core.OnMessage(WixErrors.InvalidProductVersion(sourceLineNumbers, version)); | ||
11897 | } | ||
11898 | |||
11899 | if (this.core.EncounteredError) | ||
11900 | { | ||
11901 | return; | ||
11902 | } | ||
11903 | |||
11904 | try | ||
11905 | { | ||
11906 | this.compilingProduct = true; | ||
11907 | this.core.CreateActiveSection(productCode, SectionType.Product, codepage); | ||
11908 | |||
11909 | this.AddProperty(sourceLineNumbers, new Identifier("Manufacturer", AccessModifier.Public), manufacturer, false, false, false, true); | ||
11910 | this.AddProperty(sourceLineNumbers, new Identifier("ProductCode", AccessModifier.Public), productCode, false, false, false, true); | ||
11911 | this.AddProperty(sourceLineNumbers, new Identifier("ProductLanguage", AccessModifier.Public), this.activeLanguage, false, false, false, true); | ||
11912 | this.AddProperty(sourceLineNumbers, new Identifier("ProductName", AccessModifier.Public), this.activeName, false, false, false, true); | ||
11913 | this.AddProperty(sourceLineNumbers, new Identifier("ProductVersion", AccessModifier.Public), version, false, false, false, true); | ||
11914 | if (null != upgradeCode) | ||
11915 | { | ||
11916 | this.AddProperty(sourceLineNumbers, new Identifier("UpgradeCode", AccessModifier.Public), upgradeCode, false, false, false, true); | ||
11917 | } | ||
11918 | |||
11919 | Dictionary<string, string> contextValues = new Dictionary<string, string>(); | ||
11920 | contextValues["ProductLanguage"] = this.activeLanguage; | ||
11921 | contextValues["ProductVersion"] = version; | ||
11922 | contextValues["UpgradeCode"] = upgradeCode; | ||
11923 | |||
11924 | int featureDisplay = 0; | ||
11925 | foreach (XElement child in node.Elements()) | ||
11926 | { | ||
11927 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
11928 | { | ||
11929 | switch (child.Name.LocalName) | ||
11930 | { | ||
11931 | case "_locDefinition": | ||
11932 | break; | ||
11933 | case "AdminExecuteSequence": | ||
11934 | case "AdminUISequence": | ||
11935 | case "AdvertiseExecuteSequence": | ||
11936 | case "InstallExecuteSequence": | ||
11937 | case "InstallUISequence": | ||
11938 | this.ParseSequenceElement(child, child.Name.LocalName); | ||
11939 | break; | ||
11940 | case "AppId": | ||
11941 | this.ParseAppIdElement(child, null, YesNoType.Yes, null, null, null); | ||
11942 | break; | ||
11943 | case "Binary": | ||
11944 | this.ParseBinaryElement(child); | ||
11945 | break; | ||
11946 | case "ComplianceCheck": | ||
11947 | this.ParseComplianceCheckElement(child); | ||
11948 | break; | ||
11949 | case "Component": | ||
11950 | this.ParseComponentElement(child, ComplexReferenceParentType.Unknown, null, null, CompilerConstants.IntegerNotSet, null, null); | ||
11951 | break; | ||
11952 | case "ComponentGroup": | ||
11953 | this.ParseComponentGroupElement(child, ComplexReferenceParentType.Unknown, null); | ||
11954 | break; | ||
11955 | case "Condition": | ||
11956 | this.ParseConditionElement(child, node.Name.LocalName, null, null); | ||
11957 | break; | ||
11958 | case "CustomAction": | ||
11959 | this.ParseCustomActionElement(child); | ||
11960 | break; | ||
11961 | case "CustomActionRef": | ||
11962 | this.ParseSimpleRefElement(child, "CustomAction"); | ||
11963 | break; | ||
11964 | case "CustomTable": | ||
11965 | this.ParseCustomTableElement(child); | ||
11966 | break; | ||
11967 | case "Directory": | ||
11968 | this.ParseDirectoryElement(child, null, CompilerConstants.IntegerNotSet, String.Empty); | ||
11969 | break; | ||
11970 | case "DirectoryRef": | ||
11971 | this.ParseDirectoryRefElement(child); | ||
11972 | break; | ||
11973 | case "EmbeddedChainer": | ||
11974 | this.ParseEmbeddedChainerElement(child); | ||
11975 | break; | ||
11976 | case "EmbeddedChainerRef": | ||
11977 | this.ParseSimpleRefElement(child, "MsiEmbeddedChainer"); | ||
11978 | break; | ||
11979 | case "EnsureTable": | ||
11980 | this.ParseEnsureTableElement(child); | ||
11981 | break; | ||
11982 | case "Feature": | ||
11983 | this.ParseFeatureElement(child, ComplexReferenceParentType.Product, productCode, ref featureDisplay); | ||
11984 | break; | ||
11985 | case "FeatureRef": | ||
11986 | this.ParseFeatureRefElement(child, ComplexReferenceParentType.Product, productCode); | ||
11987 | break; | ||
11988 | case "FeatureGroupRef": | ||
11989 | this.ParseFeatureGroupRefElement(child, ComplexReferenceParentType.Product, productCode); | ||
11990 | break; | ||
11991 | case "Icon": | ||
11992 | this.ParseIconElement(child); | ||
11993 | break; | ||
11994 | case "InstanceTransforms": | ||
11995 | this.ParseInstanceTransformsElement(child); | ||
11996 | break; | ||
11997 | case "MajorUpgrade": | ||
11998 | this.ParseMajorUpgradeElement(child, contextValues); | ||
11999 | break; | ||
12000 | case "Media": | ||
12001 | this.ParseMediaElement(child, null); | ||
12002 | break; | ||
12003 | case "MediaTemplate": | ||
12004 | this.ParseMediaTemplateElement(child, null); | ||
12005 | break; | ||
12006 | case "Package": | ||
12007 | this.ParsePackageElement(child, manufacturer, null); | ||
12008 | break; | ||
12009 | case "PackageCertificates": | ||
12010 | case "PatchCertificates": | ||
12011 | this.ParseCertificatesElement(child); | ||
12012 | break; | ||
12013 | case "Property": | ||
12014 | this.ParsePropertyElement(child); | ||
12015 | break; | ||
12016 | case "PropertyRef": | ||
12017 | this.ParseSimpleRefElement(child, "Property"); | ||
12018 | break; | ||
12019 | case "SetDirectory": | ||
12020 | this.ParseSetDirectoryElement(child); | ||
12021 | break; | ||
12022 | case "SetProperty": | ||
12023 | this.ParseSetPropertyElement(child); | ||
12024 | break; | ||
12025 | case "SFPCatalog": | ||
12026 | string parentName = null; | ||
12027 | this.ParseSFPCatalogElement(child, ref parentName); | ||
12028 | break; | ||
12029 | case "SymbolPath": | ||
12030 | if (null != symbols) | ||
12031 | { | ||
12032 | symbols += ";" + this.ParseSymbolPathElement(child); | ||
12033 | } | ||
12034 | else | ||
12035 | { | ||
12036 | symbols = this.ParseSymbolPathElement(child); | ||
12037 | } | ||
12038 | break; | ||
12039 | case "UI": | ||
12040 | this.ParseUIElement(child); | ||
12041 | break; | ||
12042 | case "UIRef": | ||
12043 | this.ParseSimpleRefElement(child, "WixUI"); | ||
12044 | break; | ||
12045 | case "Upgrade": | ||
12046 | this.ParseUpgradeElement(child); | ||
12047 | break; | ||
12048 | case "WixVariable": | ||
12049 | this.ParseWixVariableElement(child); | ||
12050 | break; | ||
12051 | default: | ||
12052 | this.core.UnexpectedElement(node, child); | ||
12053 | break; | ||
12054 | } | ||
12055 | } | ||
12056 | else | ||
12057 | { | ||
12058 | this.core.ParseExtensionElement(node, child); | ||
12059 | } | ||
12060 | } | ||
12061 | |||
12062 | if (!this.core.EncounteredError) | ||
12063 | { | ||
12064 | if (null != symbols) | ||
12065 | { | ||
12066 | WixDeltaPatchSymbolPathsRow symbolRow = (WixDeltaPatchSymbolPathsRow)this.core.CreateRow(sourceLineNumbers, "WixDeltaPatchSymbolPaths"); | ||
12067 | symbolRow.Id = productCode; | ||
12068 | symbolRow.Type = SymbolPathType.Product; | ||
12069 | symbolRow.SymbolPaths = symbols; | ||
12070 | } | ||
12071 | } | ||
12072 | } | ||
12073 | finally | ||
12074 | { | ||
12075 | this.compilingProduct = false; | ||
12076 | } | ||
12077 | } | ||
12078 | |||
12079 | /// <summary> | ||
12080 | /// Parses a progid element | ||
12081 | /// </summary> | ||
12082 | /// <param name="node">Element to parse.</param> | ||
12083 | /// <param name="componentId">Identifier of parent component.</param> | ||
12084 | /// <param name="advertise">Flag if progid is advertised.</param> | ||
12085 | /// <param name="classId">CLSID related to ProgId.</param> | ||
12086 | /// <param name="description">Default description of ProgId</param> | ||
12087 | /// <param name="parent">Optional parent ProgId</param> | ||
12088 | /// <param name="foundExtension">Set to true if an extension is found; used for error-checking.</param> | ||
12089 | /// <param name="firstProgIdForClass">Whether or not this ProgId is the first one found in the parent class.</param> | ||
12090 | /// <returns>This element's Id.</returns> | ||
12091 | private string ParseProgIdElement(XElement node, string componentId, YesNoType advertise, string classId, string description, string parent, ref bool foundExtension, YesNoType firstProgIdForClass) | ||
12092 | { | ||
12093 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
12094 | string icon = null; | ||
12095 | int iconIndex = CompilerConstants.IntegerNotSet; | ||
12096 | string noOpen = null; | ||
12097 | string progId = null; | ||
12098 | YesNoType progIdAdvertise = YesNoType.NotSet; | ||
12099 | |||
12100 | foreach (XAttribute attrib in node.Attributes()) | ||
12101 | { | ||
12102 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
12103 | { | ||
12104 | switch (attrib.Name.LocalName) | ||
12105 | { | ||
12106 | case "Id": | ||
12107 | progId = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
12108 | break; | ||
12109 | case "Advertise": | ||
12110 | progIdAdvertise = this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
12111 | break; | ||
12112 | case "Description": | ||
12113 | description = this.core.GetAttributeValue(sourceLineNumbers, attrib, EmptyRule.CanBeEmpty); | ||
12114 | break; | ||
12115 | case "Icon": | ||
12116 | icon = this.core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
12117 | break; | ||
12118 | case "IconIndex": | ||
12119 | iconIndex = this.core.GetAttributeIntegerValue(sourceLineNumbers, attrib, short.MinValue + 1, short.MaxValue); | ||
12120 | break; | ||
12121 | case "NoOpen": | ||
12122 | noOpen = this.core.GetAttributeValue(sourceLineNumbers, attrib, EmptyRule.CanBeEmpty); | ||
12123 | break; | ||
12124 | default: | ||
12125 | this.core.UnexpectedAttribute(node, attrib); | ||
12126 | break; | ||
12127 | } | ||
12128 | } | ||
12129 | else | ||
12130 | { | ||
12131 | this.core.ParseExtensionAttribute(node, attrib); | ||
12132 | } | ||
12133 | } | ||
12134 | |||
12135 | if ((YesNoType.No == advertise && YesNoType.Yes == progIdAdvertise) || (YesNoType.Yes == advertise && YesNoType.No == progIdAdvertise)) | ||
12136 | { | ||
12137 | this.core.OnMessage(WixErrors.AdvertiseStateMustMatch(sourceLineNumbers, advertise.ToString(), progIdAdvertise.ToString())); | ||
12138 | } | ||
12139 | else | ||
12140 | { | ||
12141 | advertise = progIdAdvertise; | ||
12142 | } | ||
12143 | |||
12144 | if (YesNoType.NotSet == advertise) | ||
12145 | { | ||
12146 | advertise = YesNoType.No; | ||
12147 | } | ||
12148 | |||
12149 | if (null != parent && (null != icon || CompilerConstants.IntegerNotSet != iconIndex)) | ||
12150 | { | ||
12151 | this.core.OnMessage(WixErrors.VersionIndependentProgIdsCannotHaveIcons(sourceLineNumbers)); | ||
12152 | } | ||
12153 | |||
12154 | YesNoType firstProgIdForNestedClass = YesNoType.Yes; | ||
12155 | foreach (XElement child in node.Elements()) | ||
12156 | { | ||
12157 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
12158 | { | ||
12159 | switch (child.Name.LocalName) | ||
12160 | { | ||
12161 | case "Extension": | ||
12162 | this.ParseExtensionElement(child, componentId, advertise, progId); | ||
12163 | foundExtension = true; | ||
12164 | break; | ||
12165 | case "ProgId": | ||
12166 | // Only allow one nested ProgId. If we have a child, we should not have a parent. | ||
12167 | if (null == parent) | ||
12168 | { | ||
12169 | if (YesNoType.Yes == advertise) | ||
12170 | { | ||
12171 | this.ParseProgIdElement(child, componentId, advertise, null, description, progId, ref foundExtension, firstProgIdForNestedClass); | ||
12172 | } | ||
12173 | else if (YesNoType.No == advertise) | ||
12174 | { | ||
12175 | this.ParseProgIdElement(child, componentId, advertise, classId, description, progId, ref foundExtension, firstProgIdForNestedClass); | ||
12176 | } | ||
12177 | |||
12178 | firstProgIdForNestedClass = YesNoType.No; // any ProgId after this one is definitely not the first. | ||
12179 | } | ||
12180 | else | ||
12181 | { | ||
12182 | SourceLineNumber childSourceLineNumbers = Preprocessor.GetSourceLineNumbers(child); | ||
12183 | this.core.OnMessage(WixErrors.ProgIdNestedTooDeep(childSourceLineNumbers)); | ||
12184 | } | ||
12185 | break; | ||
12186 | default: | ||
12187 | this.core.UnexpectedElement(node, child); | ||
12188 | break; | ||
12189 | } | ||
12190 | } | ||
12191 | else | ||
12192 | { | ||
12193 | this.core.ParseExtensionElement(node, child); | ||
12194 | } | ||
12195 | } | ||
12196 | |||
12197 | if (YesNoType.Yes == advertise) | ||
12198 | { | ||
12199 | if (!this.core.EncounteredError) | ||
12200 | { | ||
12201 | Row row = this.core.CreateRow(sourceLineNumbers, "ProgId"); | ||
12202 | row[0] = progId; | ||
12203 | row[1] = parent; | ||
12204 | row[2] = classId; | ||
12205 | row[3] = description; | ||
12206 | if (null != icon) | ||
12207 | { | ||
12208 | row[4] = icon; | ||
12209 | this.core.CreateSimpleReference(sourceLineNumbers, "Icon", icon); | ||
12210 | } | ||
12211 | |||
12212 | if (CompilerConstants.IntegerNotSet != iconIndex) | ||
12213 | { | ||
12214 | row[5] = iconIndex; | ||
12215 | } | ||
12216 | |||
12217 | this.core.EnsureTable(sourceLineNumbers, "Class"); | ||
12218 | } | ||
12219 | } | ||
12220 | else if (YesNoType.No == advertise) | ||
12221 | { | ||
12222 | this.core.CreateRegistryRow(sourceLineNumbers, MsiInterop.MsidbRegistryRootClassesRoot, progId, String.Empty, description, componentId); | ||
12223 | if (null != classId) | ||
12224 | { | ||
12225 | this.core.CreateRegistryRow(sourceLineNumbers, MsiInterop.MsidbRegistryRootClassesRoot, String.Concat(progId, "\\CLSID"), String.Empty, classId, componentId); | ||
12226 | if (null != parent) // if this is a version independent ProgId | ||
12227 | { | ||
12228 | if (YesNoType.Yes == firstProgIdForClass) | ||
12229 | { | ||
12230 | this.core.CreateRegistryRow(sourceLineNumbers, MsiInterop.MsidbRegistryRootClassesRoot, String.Concat("CLSID\\", classId, "\\VersionIndependentProgID"), String.Empty, progId, componentId); | ||
12231 | } | ||
12232 | |||
12233 | this.core.CreateRegistryRow(sourceLineNumbers, MsiInterop.MsidbRegistryRootClassesRoot, String.Concat(progId, "\\CurVer"), String.Empty, parent, componentId); | ||
12234 | } | ||
12235 | else | ||
12236 | { | ||
12237 | if (YesNoType.Yes == firstProgIdForClass) | ||
12238 | { | ||
12239 | this.core.CreateRegistryRow(sourceLineNumbers, MsiInterop.MsidbRegistryRootClassesRoot, String.Concat("CLSID\\", classId, "\\ProgID"), String.Empty, progId, componentId); | ||
12240 | } | ||
12241 | } | ||
12242 | } | ||
12243 | |||
12244 | if (null != icon) // ProgId's Default Icon | ||
12245 | { | ||
12246 | this.core.CreateSimpleReference(sourceLineNumbers, "File", icon); | ||
12247 | |||
12248 | icon = String.Format(CultureInfo.InvariantCulture, "\"[#{0}]\"", icon); | ||
12249 | |||
12250 | if (CompilerConstants.IntegerNotSet != iconIndex) | ||
12251 | { | ||
12252 | icon = String.Concat(icon, ",", iconIndex); | ||
12253 | } | ||
12254 | |||
12255 | this.core.CreateRegistryRow(sourceLineNumbers, MsiInterop.MsidbRegistryRootClassesRoot, String.Concat(progId, "\\DefaultIcon"), String.Empty, icon, componentId); | ||
12256 | } | ||
12257 | } | ||
12258 | |||
12259 | if (null != noOpen) | ||
12260 | { | ||
12261 | this.core.CreateRegistryRow(sourceLineNumbers, MsiInterop.MsidbRegistryRootClassesRoot, progId, "NoOpen", noOpen, componentId); // ProgId NoOpen name | ||
12262 | } | ||
12263 | |||
12264 | // raise an error for an orphaned ProgId | ||
12265 | if (YesNoType.Yes == advertise && !foundExtension && null == parent && null == classId) | ||
12266 | { | ||
12267 | this.core.OnMessage(WixWarnings.OrphanedProgId(sourceLineNumbers, progId)); | ||
12268 | } | ||
12269 | |||
12270 | return progId; | ||
12271 | } | ||
12272 | |||
12273 | /// <summary> | ||
12274 | /// Parses a property element. | ||
12275 | /// </summary> | ||
12276 | /// <param name="node">Element to parse.</param> | ||
12277 | private void ParsePropertyElement(XElement node) | ||
12278 | { | ||
12279 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
12280 | Identifier id = null; | ||
12281 | bool admin = false; | ||
12282 | bool complianceCheck = false; | ||
12283 | bool hidden = false; | ||
12284 | bool secure = false; | ||
12285 | YesNoType suppressModularization = YesNoType.NotSet; | ||
12286 | string value = null; | ||
12287 | |||
12288 | foreach (XAttribute attrib in node.Attributes()) | ||
12289 | { | ||
12290 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
12291 | { | ||
12292 | switch (attrib.Name.LocalName) | ||
12293 | { | ||
12294 | case "Id": | ||
12295 | id = this.core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
12296 | break; | ||
12297 | case "Admin": | ||
12298 | admin = YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
12299 | break; | ||
12300 | case "ComplianceCheck": | ||
12301 | complianceCheck = YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
12302 | break; | ||
12303 | case "Hidden": | ||
12304 | hidden = YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
12305 | break; | ||
12306 | case "Secure": | ||
12307 | secure = YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
12308 | break; | ||
12309 | case "SuppressModularization": | ||
12310 | suppressModularization = this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
12311 | break; | ||
12312 | case "Value": | ||
12313 | value = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
12314 | break; | ||
12315 | default: | ||
12316 | this.core.UnexpectedAttribute(node, attrib); | ||
12317 | break; | ||
12318 | } | ||
12319 | } | ||
12320 | else | ||
12321 | { | ||
12322 | this.core.ParseExtensionAttribute(node, attrib); | ||
12323 | } | ||
12324 | } | ||
12325 | |||
12326 | if (null == id) | ||
12327 | { | ||
12328 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
12329 | id = Identifier.Invalid; | ||
12330 | } | ||
12331 | else if ("ProductID" == id.Id) | ||
12332 | { | ||
12333 | this.core.OnMessage(WixWarnings.ProductIdAuthored(sourceLineNumbers)); | ||
12334 | } | ||
12335 | else if ("SecureCustomProperties" == id.Id || "AdminProperties" == id.Id || "MsiHiddenProperties" == id.Id) | ||
12336 | { | ||
12337 | this.core.OnMessage(WixErrors.CannotAuthorSpecialProperties(sourceLineNumbers, id.Id)); | ||
12338 | } | ||
12339 | |||
12340 | string innerText = this.core.GetTrimmedInnerText(node); | ||
12341 | if (null != value) | ||
12342 | { | ||
12343 | // cannot specify both the value attribute and inner text | ||
12344 | if (!String.IsNullOrEmpty(innerText)) | ||
12345 | { | ||
12346 | this.core.OnMessage(WixErrors.IllegalAttributeWithInnerText(sourceLineNumbers, node.Name.LocalName, "Value")); | ||
12347 | } | ||
12348 | } | ||
12349 | else // value attribute not specified, use inner text if any. | ||
12350 | { | ||
12351 | value = innerText; | ||
12352 | } | ||
12353 | |||
12354 | if ("ErrorDialog" == id.Id) | ||
12355 | { | ||
12356 | this.core.CreateSimpleReference(sourceLineNumbers, "Dialog", value); | ||
12357 | } | ||
12358 | |||
12359 | foreach (XElement child in node.Elements()) | ||
12360 | { | ||
12361 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
12362 | { | ||
12363 | { | ||
12364 | switch (child.Name.LocalName) | ||
12365 | { | ||
12366 | case "ProductSearch": | ||
12367 | this.ParseProductSearchElement(child, id.Id); | ||
12368 | secure = true; | ||
12369 | break; | ||
12370 | default: | ||
12371 | // let ParseSearchSignatures handle standard AppSearch children and unknown elements | ||
12372 | break; | ||
12373 | } | ||
12374 | } | ||
12375 | } | ||
12376 | } | ||
12377 | |||
12378 | // see if this property is used for appSearch | ||
12379 | List<string> signatures = this.ParseSearchSignatures(node); | ||
12380 | |||
12381 | // If we're doing CCP then there must be a signature. | ||
12382 | if (complianceCheck && 0 == signatures.Count) | ||
12383 | { | ||
12384 | this.core.OnMessage(WixErrors.SearchElementRequiredWithAttribute(sourceLineNumbers, node.Name.LocalName, "ComplianceCheck", "yes")); | ||
12385 | } | ||
12386 | |||
12387 | foreach (string sig in signatures) | ||
12388 | { | ||
12389 | if (complianceCheck && !this.core.EncounteredError) | ||
12390 | { | ||
12391 | this.core.CreateRow(sourceLineNumbers, "CCPSearch", new Identifier(sig, AccessModifier.Private)); | ||
12392 | } | ||
12393 | |||
12394 | this.AddAppSearch(sourceLineNumbers, id, sig); | ||
12395 | } | ||
12396 | |||
12397 | // If we're doing AppSearch get that setup. | ||
12398 | if (0 < signatures.Count) | ||
12399 | { | ||
12400 | this.AddProperty(sourceLineNumbers, id, value, admin, secure, hidden, false); | ||
12401 | } | ||
12402 | else // just a normal old property. | ||
12403 | { | ||
12404 | // If the property value is empty and none of the flags are set, print out a warning that we're ignoring | ||
12405 | // the element. | ||
12406 | if (String.IsNullOrEmpty(value) && !admin && !secure && !hidden) | ||
12407 | { | ||
12408 | this.core.OnMessage(WixWarnings.PropertyUseless(sourceLineNumbers, id.Id)); | ||
12409 | } | ||
12410 | else // there is a value and/or a flag set, do that. | ||
12411 | { | ||
12412 | this.AddProperty(sourceLineNumbers, id, value, admin, secure, hidden, false); | ||
12413 | } | ||
12414 | } | ||
12415 | |||
12416 | if (!this.core.EncounteredError && YesNoType.Yes == suppressModularization) | ||
12417 | { | ||
12418 | this.core.OnMessage(WixWarnings.PropertyModularizationSuppressed(sourceLineNumbers)); | ||
12419 | |||
12420 | this.core.CreateRow(sourceLineNumbers, "WixSuppressModularization", id); | ||
12421 | } | ||
12422 | } | ||
12423 | |||
12424 | /// <summary> | ||
12425 | /// Parses a RegistryKey element. | ||
12426 | /// </summary> | ||
12427 | /// <param name="node">Element to parse.</param> | ||
12428 | /// <param name="componentId">Identifier for parent component.</param> | ||
12429 | /// <param name="root">Root specified when element is nested under another Registry element, otherwise CompilerConstants.IntegerNotSet.</param> | ||
12430 | /// <param name="parentKey">Parent key for this Registry element when nested.</param> | ||
12431 | /// <param name="win64Component">true if the component is 64-bit.</param> | ||
12432 | /// <param name="possibleKeyPath">Identifier of this registry key since it could be the component's keypath.</param> | ||
12433 | /// <returns>Yes if this element was marked as the parent component's key path, No if explicitly marked as not being a key path, or NotSet otherwise.</returns> | ||
12434 | [SuppressMessage("Microsoft.Globalization", "CA1308:NormalizeStringsToUppercase", Justification = "Changing the way this string normalizes would result " + | ||
12435 | "in a change to the way the Registry table is generated, potentially causing extra churn in patches on an MSI built from an older version of WiX. " + | ||
12436 | "Furthermore, there is no security hole here, as the strings won't need to make a round trip")] | ||
12437 | private YesNoType ParseRegistryKeyElement(XElement node, string componentId, int root, string parentKey, bool win64Component, out string possibleKeyPath) | ||
12438 | { | ||
12439 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
12440 | Identifier id = null; | ||
12441 | string key = parentKey; // default to parent key path | ||
12442 | string action = null; | ||
12443 | bool forceCreateOnInstall = false; | ||
12444 | bool forceDeleteOnUninstall = false; | ||
12445 | Wix.RegistryKey.ActionType actionType = Wix.RegistryKey.ActionType.NotSet; | ||
12446 | YesNoType keyPath = YesNoType.NotSet; | ||
12447 | |||
12448 | possibleKeyPath = null; | ||
12449 | |||
12450 | foreach (XAttribute attrib in node.Attributes()) | ||
12451 | { | ||
12452 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
12453 | { | ||
12454 | switch (attrib.Name.LocalName) | ||
12455 | { | ||
12456 | case "Id": | ||
12457 | id = this.core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
12458 | break; | ||
12459 | case "Action": | ||
12460 | this.core.OnMessage(WixWarnings.DeprecatedRegistryKeyActionAttribute(sourceLineNumbers)); | ||
12461 | action = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
12462 | if (0 < action.Length) | ||
12463 | { | ||
12464 | actionType = Wix.RegistryKey.ParseActionType(action); | ||
12465 | switch (actionType) | ||
12466 | { | ||
12467 | case Wix.RegistryKey.ActionType.create: | ||
12468 | forceCreateOnInstall = true; | ||
12469 | break; | ||
12470 | case Wix.RegistryKey.ActionType.createAndRemoveOnUninstall: | ||
12471 | forceCreateOnInstall = true; | ||
12472 | forceDeleteOnUninstall = true; | ||
12473 | break; | ||
12474 | case Wix.RegistryKey.ActionType.none: | ||
12475 | break; | ||
12476 | default: | ||
12477 | this.core.OnMessage(WixErrors.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, action, "create", "createAndRemoveOnUninstall", "none")); | ||
12478 | break; | ||
12479 | } | ||
12480 | } | ||
12481 | break; | ||
12482 | case "ForceCreateOnInstall": | ||
12483 | forceCreateOnInstall = YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
12484 | break; | ||
12485 | case "ForceDeleteOnUninstall": | ||
12486 | forceDeleteOnUninstall = YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
12487 | break; | ||
12488 | case "Key": | ||
12489 | key = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
12490 | if (null != parentKey) | ||
12491 | { | ||
12492 | key = Path.Combine(parentKey, key); | ||
12493 | } | ||
12494 | break; | ||
12495 | case "Root": | ||
12496 | if (CompilerConstants.IntegerNotSet != root) | ||
12497 | { | ||
12498 | this.core.OnMessage(WixErrors.RegistryRootInvalid(sourceLineNumbers)); | ||
12499 | } | ||
12500 | |||
12501 | root = this.core.GetAttributeMsidbRegistryRootValue(sourceLineNumbers, attrib, true); | ||
12502 | break; | ||
12503 | default: | ||
12504 | this.core.UnexpectedAttribute(node, attrib); | ||
12505 | break; | ||
12506 | } | ||
12507 | } | ||
12508 | else | ||
12509 | { | ||
12510 | this.core.ParseExtensionAttribute(node, attrib); | ||
12511 | } | ||
12512 | } | ||
12513 | |||
12514 | string name = forceCreateOnInstall ? (forceDeleteOnUninstall ? "*" : "+") : (forceDeleteOnUninstall ? "-" : null); | ||
12515 | |||
12516 | if (forceCreateOnInstall || forceDeleteOnUninstall) // generates a Registry row, so an Id must be present | ||
12517 | { | ||
12518 | // generate the identifier if it wasn't provided | ||
12519 | if (null == id) | ||
12520 | { | ||
12521 | id = this.core.CreateIdentifier("reg", componentId, root.ToString(CultureInfo.InvariantCulture.NumberFormat), LowercaseOrNull(key), LowercaseOrNull(name)); | ||
12522 | } | ||
12523 | } | ||
12524 | else // does not generate a Registry row, so no Id should be present | ||
12525 | { | ||
12526 | if (null != id) | ||
12527 | { | ||
12528 | this.core.OnMessage(WixErrors.IllegalAttributeWithoutOtherAttributes(sourceLineNumbers, node.Name.LocalName, "Id", "ForceCreateOnInstall", "ForceDeleteOnUninstall", "yes", true)); | ||
12529 | } | ||
12530 | } | ||
12531 | |||
12532 | if (CompilerConstants.IntegerNotSet == root) | ||
12533 | { | ||
12534 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Root")); | ||
12535 | root = CompilerConstants.IllegalInteger; | ||
12536 | } | ||
12537 | |||
12538 | if (null == key) | ||
12539 | { | ||
12540 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Key")); | ||
12541 | key = String.Empty; // set the key to something to prevent null reference exceptions | ||
12542 | } | ||
12543 | |||
12544 | foreach (XElement child in node.Elements()) | ||
12545 | { | ||
12546 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
12547 | { | ||
12548 | string possibleChildKeyPath = null; | ||
12549 | |||
12550 | switch (child.Name.LocalName) | ||
12551 | { | ||
12552 | case "RegistryKey": | ||
12553 | if (YesNoType.Yes == this.ParseRegistryKeyElement(child, componentId, root, key, win64Component, out possibleChildKeyPath)) | ||
12554 | { | ||
12555 | if (YesNoType.Yes == keyPath) | ||
12556 | { | ||
12557 | this.core.OnMessage(WixErrors.ComponentMultipleKeyPaths(sourceLineNumbers, child.Name.LocalName, "KeyPath", "yes", "File", "RegistryValue", "ODBCDataSource")); | ||
12558 | } | ||
12559 | |||
12560 | possibleKeyPath = possibleChildKeyPath; // the child is the key path | ||
12561 | keyPath = YesNoType.Yes; | ||
12562 | } | ||
12563 | else if (null == possibleKeyPath && null != possibleChildKeyPath) | ||
12564 | { | ||
12565 | possibleKeyPath = possibleChildKeyPath; | ||
12566 | } | ||
12567 | break; | ||
12568 | case "RegistryValue": | ||
12569 | if (YesNoType.Yes == this.ParseRegistryValueElement(child, componentId, root, key, win64Component, out possibleChildKeyPath)) | ||
12570 | { | ||
12571 | if (YesNoType.Yes == keyPath) | ||
12572 | { | ||
12573 | this.core.OnMessage(WixErrors.ComponentMultipleKeyPaths(sourceLineNumbers, child.Name.LocalName, "KeyPath", "yes", "File", "RegistryValue", "ODBCDataSource")); | ||
12574 | } | ||
12575 | |||
12576 | possibleKeyPath = possibleChildKeyPath; // the child is the key path | ||
12577 | keyPath = YesNoType.Yes; | ||
12578 | } | ||
12579 | else if (null == possibleKeyPath && null != possibleChildKeyPath) | ||
12580 | { | ||
12581 | possibleKeyPath = possibleChildKeyPath; | ||
12582 | } | ||
12583 | break; | ||
12584 | case "Permission": | ||
12585 | if (!forceCreateOnInstall) | ||
12586 | { | ||
12587 | this.core.OnMessage(WixErrors.UnexpectedElementWithAttributeValue(sourceLineNumbers, node.Name.LocalName, child.Name.LocalName, "ForceCreateOnInstall", "yes")); | ||
12588 | } | ||
12589 | this.ParsePermissionElement(child, id.Id, "Registry"); | ||
12590 | break; | ||
12591 | case "PermissionEx": | ||
12592 | if (!forceCreateOnInstall) | ||
12593 | { | ||
12594 | this.core.OnMessage(WixErrors.UnexpectedElementWithAttributeValue(sourceLineNumbers, node.Name.LocalName, child.Name.LocalName, "ForceCreateOnInstall", "yes")); | ||
12595 | } | ||
12596 | this.ParsePermissionExElement(child, id.Id, "Registry"); | ||
12597 | break; | ||
12598 | default: | ||
12599 | this.core.UnexpectedElement(node, child); | ||
12600 | break; | ||
12601 | } | ||
12602 | } | ||
12603 | else | ||
12604 | { | ||
12605 | Dictionary<string, string> context = new Dictionary<string, string>() { { "RegistryId", id.Id }, { "ComponentId", componentId }, { "Win64", win64Component.ToString() } }; | ||
12606 | this.core.ParseExtensionElement(node, child, context); | ||
12607 | } | ||
12608 | } | ||
12609 | |||
12610 | |||
12611 | if (!this.core.EncounteredError && null != name) | ||
12612 | { | ||
12613 | Row row = this.core.CreateRow(sourceLineNumbers, "Registry", id); | ||
12614 | row[1] = root; | ||
12615 | row[2] = key; | ||
12616 | row[3] = name; | ||
12617 | row[4] = null; | ||
12618 | row[5] = componentId; | ||
12619 | } | ||
12620 | |||
12621 | return keyPath; | ||
12622 | } | ||
12623 | |||
12624 | /// <summary> | ||
12625 | /// Parses a RegistryValue element. | ||
12626 | /// </summary> | ||
12627 | /// <param name="node">Element to parse.</param> | ||
12628 | /// <param name="componentId">Identifier for parent component.</param> | ||
12629 | /// <param name="root">Root specified when element is nested under a RegistryKey element, otherwise CompilerConstants.IntegerNotSet.</param> | ||
12630 | /// <param name="parentKey">Root specified when element is nested under a RegistryKey element, otherwise CompilerConstants.IntegerNotSet.</param> | ||
12631 | /// <param name="win64Component">true if the component is 64-bit.</param> | ||
12632 | /// <param name="possibleKeyPath">Identifier of this registry key since it could be the component's keypath.</param> | ||
12633 | /// <returns>Yes if this element was marked as the parent component's key path, No if explicitly marked as not being a key path, or NotSet otherwise.</returns> | ||
12634 | [SuppressMessage("Microsoft.Globalization", "CA1308:NormalizeStringsToUppercase", Justification = "Changing the way this string normalizes would result " + | ||
12635 | "in a change to the way the Registry table is generated, potentially causing extra churn in patches on an MSI built from an older version of WiX. " + | ||
12636 | "Furthermore, there is no security hole here, as the strings won't need to make a round trip")] | ||
12637 | private YesNoType ParseRegistryValueElement(XElement node, string componentId, int root, string parentKey, bool win64Component, out string possibleKeyPath) | ||
12638 | { | ||
12639 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
12640 | Identifier id = null; | ||
12641 | string key = parentKey; // default to parent key path | ||
12642 | string name = null; | ||
12643 | string value = null; | ||
12644 | string type = null; | ||
12645 | Wix.RegistryValue.TypeType typeType = Wix.RegistryValue.TypeType.NotSet; | ||
12646 | string action = null; | ||
12647 | Wix.RegistryValue.ActionType actionType = Wix.RegistryValue.ActionType.NotSet; | ||
12648 | YesNoType keyPath = YesNoType.NotSet; | ||
12649 | bool couldBeKeyPath = true; // assume that this is a regular registry key that could become the key path | ||
12650 | |||
12651 | possibleKeyPath = null; | ||
12652 | |||
12653 | foreach (XAttribute attrib in node.Attributes()) | ||
12654 | { | ||
12655 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
12656 | { | ||
12657 | switch (attrib.Name.LocalName) | ||
12658 | { | ||
12659 | case "Id": | ||
12660 | id = this.core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
12661 | break; | ||
12662 | case "Action": | ||
12663 | action = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
12664 | if (0 < action.Length) | ||
12665 | { | ||
12666 | if (!Wix.RegistryValue.TryParseActionType(action, out actionType)) | ||
12667 | { | ||
12668 | this.core.OnMessage(WixErrors.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, action, "append", "prepend", "write")); | ||
12669 | } | ||
12670 | } | ||
12671 | break; | ||
12672 | case "Key": | ||
12673 | key = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
12674 | if (null != parentKey) | ||
12675 | { | ||
12676 | if (parentKey.EndsWith("\\", StringComparison.Ordinal)) | ||
12677 | { | ||
12678 | key = String.Concat(parentKey, key); | ||
12679 | } | ||
12680 | else | ||
12681 | { | ||
12682 | key = String.Concat(parentKey, "\\", key); | ||
12683 | } | ||
12684 | } | ||
12685 | break; | ||
12686 | case "KeyPath": | ||
12687 | keyPath = this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
12688 | break; | ||
12689 | case "Name": | ||
12690 | name = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
12691 | break; | ||
12692 | case "Root": | ||
12693 | if (CompilerConstants.IntegerNotSet != root) | ||
12694 | { | ||
12695 | this.core.OnMessage(WixErrors.RegistryRootInvalid(sourceLineNumbers)); | ||
12696 | } | ||
12697 | |||
12698 | root = this.core.GetAttributeMsidbRegistryRootValue(sourceLineNumbers, attrib, true); | ||
12699 | break; | ||
12700 | case "Type": | ||
12701 | type = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
12702 | if (0 < type.Length) | ||
12703 | { | ||
12704 | if (!Wix.RegistryValue.TryParseTypeType(type, out typeType)) | ||
12705 | { | ||
12706 | this.core.OnMessage(WixErrors.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, type, "binary", "expandable", "integer", "multiString", "string")); | ||
12707 | } | ||
12708 | } | ||
12709 | break; | ||
12710 | case "Value": | ||
12711 | value = this.core.GetAttributeValue(sourceLineNumbers, attrib, EmptyRule.CanBeEmpty); | ||
12712 | break; | ||
12713 | default: | ||
12714 | this.core.UnexpectedAttribute(node, attrib); | ||
12715 | break; | ||
12716 | } | ||
12717 | } | ||
12718 | else | ||
12719 | { | ||
12720 | this.core.ParseExtensionAttribute(node, attrib); | ||
12721 | } | ||
12722 | } | ||
12723 | |||
12724 | // generate the identifier if it wasn't provided | ||
12725 | if (null == id) | ||
12726 | { | ||
12727 | id = this.core.CreateIdentifier("reg", componentId, root.ToString(CultureInfo.InvariantCulture.NumberFormat), LowercaseOrNull(key), LowercaseOrNull(name)); | ||
12728 | } | ||
12729 | |||
12730 | if ((Wix.RegistryValue.ActionType.append == actionType || Wix.RegistryValue.ActionType.prepend == actionType) && | ||
12731 | Wix.RegistryValue.TypeType.multiString != typeType) | ||
12732 | { | ||
12733 | this.core.OnMessage(WixErrors.IllegalAttributeValueWithoutOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Action", action, "Type", "multiString")); | ||
12734 | } | ||
12735 | |||
12736 | if (null == key) | ||
12737 | { | ||
12738 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Key")); | ||
12739 | } | ||
12740 | |||
12741 | if (CompilerConstants.IntegerNotSet == root) | ||
12742 | { | ||
12743 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Root")); | ||
12744 | } | ||
12745 | |||
12746 | if (null == type) | ||
12747 | { | ||
12748 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Type")); | ||
12749 | } | ||
12750 | |||
12751 | foreach (XElement child in node.Elements()) | ||
12752 | { | ||
12753 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
12754 | { | ||
12755 | switch (child.Name.LocalName) | ||
12756 | { | ||
12757 | case "MultiStringValue": | ||
12758 | if (Wix.RegistryValue.TypeType.multiString != typeType && null != value) | ||
12759 | { | ||
12760 | this.core.OnMessage(WixErrors.RegistryMultipleValuesWithoutMultiString(sourceLineNumbers, node.Name.LocalName, "Value", child.Name.LocalName, "Type")); | ||
12761 | } | ||
12762 | else if (null == value) | ||
12763 | { | ||
12764 | value = Common.GetInnerText(child); | ||
12765 | } | ||
12766 | else | ||
12767 | { | ||
12768 | value = String.Concat(value, "[~]", Common.GetInnerText(child)); | ||
12769 | } | ||
12770 | break; | ||
12771 | case "Permission": | ||
12772 | this.ParsePermissionElement(child, id.Id, "Registry"); | ||
12773 | break; | ||
12774 | case "PermissionEx": | ||
12775 | this.ParsePermissionExElement(child, id.Id, "Registry"); | ||
12776 | break; | ||
12777 | default: | ||
12778 | this.core.UnexpectedElement(node, child); | ||
12779 | break; | ||
12780 | } | ||
12781 | } | ||
12782 | else | ||
12783 | { | ||
12784 | Dictionary<string, string> context = new Dictionary<string, string>() { { "RegistryId", id.Id }, { "ComponentId", componentId }, { "Win64", win64Component.ToString() } }; | ||
12785 | this.core.ParseExtensionElement(node, child, context); | ||
12786 | } | ||
12787 | } | ||
12788 | |||
12789 | |||
12790 | switch (typeType) | ||
12791 | { | ||
12792 | case Wix.RegistryValue.TypeType.binary: | ||
12793 | value = String.Concat("#x", value); | ||
12794 | break; | ||
12795 | case Wix.RegistryValue.TypeType.expandable: | ||
12796 | value = String.Concat("#%", value); | ||
12797 | break; | ||
12798 | case Wix.RegistryValue.TypeType.integer: | ||
12799 | value = String.Concat("#", value); | ||
12800 | break; | ||
12801 | case Wix.RegistryValue.TypeType.multiString: | ||
12802 | switch (actionType) | ||
12803 | { | ||
12804 | case Wix.RegistryValue.ActionType.append: | ||
12805 | value = String.Concat("[~]", value); | ||
12806 | break; | ||
12807 | case Wix.RegistryValue.ActionType.prepend: | ||
12808 | value = String.Concat(value, "[~]"); | ||
12809 | break; | ||
12810 | case Wix.RegistryValue.ActionType.write: | ||
12811 | default: | ||
12812 | if (null != value && -1 == value.IndexOf("[~]", StringComparison.Ordinal)) | ||
12813 | { | ||
12814 | value = String.Format(CultureInfo.InvariantCulture, "[~]{0}[~]", value); | ||
12815 | } | ||
12816 | break; | ||
12817 | } | ||
12818 | break; | ||
12819 | case Wix.RegistryValue.TypeType.@string: | ||
12820 | // escape the leading '#' character for string registry keys | ||
12821 | if (null != value && value.StartsWith("#", StringComparison.Ordinal)) | ||
12822 | { | ||
12823 | value = String.Concat("#", value); | ||
12824 | } | ||
12825 | break; | ||
12826 | } | ||
12827 | |||
12828 | // value may be set by child MultiStringValue elements, so it must be checked here | ||
12829 | if (null == value) | ||
12830 | { | ||
12831 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Value")); | ||
12832 | } | ||
12833 | else if (0 == value.Length && ("+" == name || "-" == name || "*" == name)) // prevent accidental authoring of special name values | ||
12834 | { | ||
12835 | this.core.OnMessage(WixErrors.RegistryNameValueIncorrect(sourceLineNumbers, node.Name.LocalName, "Name", name)); | ||
12836 | } | ||
12837 | |||
12838 | if (!this.core.EncounteredError) | ||
12839 | { | ||
12840 | Row row = this.core.CreateRow(sourceLineNumbers, "Registry", id); | ||
12841 | row[1] = root; | ||
12842 | row[2] = key; | ||
12843 | row[3] = name; | ||
12844 | row[4] = value; | ||
12845 | row[5] = componentId; | ||
12846 | } | ||
12847 | |||
12848 | // If this was just a regular registry key (that could be the key path) | ||
12849 | // and no child registry key set the possible key path, let's make this | ||
12850 | // Registry/@Id a possible key path. | ||
12851 | if (couldBeKeyPath && null == possibleKeyPath) | ||
12852 | { | ||
12853 | possibleKeyPath = id.Id; | ||
12854 | } | ||
12855 | |||
12856 | return keyPath; | ||
12857 | } | ||
12858 | |||
12859 | /// <summary> | ||
12860 | /// Parses a RemoveRegistryKey element. | ||
12861 | /// </summary> | ||
12862 | /// <param name="node">The element to parse.</param> | ||
12863 | /// <param name="componentId">The component identifier of the parent element.</param> | ||
12864 | [SuppressMessage("Microsoft.Globalization", "CA1308:NormalizeStringsToUppercase", Justification = "Changing the way this string normalizes would result " + | ||
12865 | "in a change to the way the Registry table is generated, potentially causing extra churn in patches on an MSI built from an older version of WiX. " + | ||
12866 | "Furthermore, there is no security hole here, as the strings won't need to make a round trip")] | ||
12867 | private void ParseRemoveRegistryKeyElement(XElement node, string componentId) | ||
12868 | { | ||
12869 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
12870 | Identifier id = null; | ||
12871 | string action = null; | ||
12872 | Wix.RemoveRegistryKey.ActionType actionType = Wix.RemoveRegistryKey.ActionType.NotSet; | ||
12873 | string key = null; | ||
12874 | string name = "-"; | ||
12875 | int root = CompilerConstants.IntegerNotSet; | ||
12876 | |||
12877 | foreach (XAttribute attrib in node.Attributes()) | ||
12878 | { | ||
12879 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
12880 | { | ||
12881 | switch (attrib.Name.LocalName) | ||
12882 | { | ||
12883 | case "Id": | ||
12884 | id = this.core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
12885 | break; | ||
12886 | case "Action": | ||
12887 | action = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
12888 | if (0 < action.Length) | ||
12889 | { | ||
12890 | if (!Wix.RemoveRegistryKey.TryParseActionType(action, out actionType)) | ||
12891 | { | ||
12892 | this.core.OnMessage(WixErrors.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, action, "removeOnInstall", "removeOnUninstall")); | ||
12893 | } | ||
12894 | } | ||
12895 | break; | ||
12896 | case "Key": | ||
12897 | key = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
12898 | break; | ||
12899 | case "Root": | ||
12900 | root = this.core.GetAttributeMsidbRegistryRootValue(sourceLineNumbers, attrib, true); | ||
12901 | break; | ||
12902 | default: | ||
12903 | this.core.UnexpectedAttribute(node, attrib); | ||
12904 | break; | ||
12905 | } | ||
12906 | } | ||
12907 | else | ||
12908 | { | ||
12909 | this.core.ParseExtensionAttribute(node, attrib); | ||
12910 | } | ||
12911 | } | ||
12912 | |||
12913 | // generate the identifier if it wasn't provided | ||
12914 | if (null == id) | ||
12915 | { | ||
12916 | id = this.core.CreateIdentifier("reg", componentId, root.ToString(CultureInfo.InvariantCulture.NumberFormat), LowercaseOrNull(key), LowercaseOrNull(name)); | ||
12917 | } | ||
12918 | |||
12919 | if (null == action) | ||
12920 | { | ||
12921 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Action")); | ||
12922 | } | ||
12923 | |||
12924 | if (null == key) | ||
12925 | { | ||
12926 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Key")); | ||
12927 | } | ||
12928 | |||
12929 | if (CompilerConstants.IntegerNotSet == root) | ||
12930 | { | ||
12931 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Root")); | ||
12932 | } | ||
12933 | |||
12934 | this.core.ParseForExtensionElements(node); | ||
12935 | |||
12936 | if (!this.core.EncounteredError) | ||
12937 | { | ||
12938 | Row row = this.core.CreateRow(sourceLineNumbers, (Wix.RemoveRegistryKey.ActionType.removeOnUninstall == actionType ? "Registry" : "RemoveRegistry"), id); | ||
12939 | row[1] = root; | ||
12940 | row[2] = key; | ||
12941 | row[3] = name; | ||
12942 | if (Wix.RemoveRegistryKey.ActionType.removeOnUninstall == actionType) // Registry table | ||
12943 | { | ||
12944 | row[4] = null; | ||
12945 | row[5] = componentId; | ||
12946 | } | ||
12947 | else // RemoveRegistry table | ||
12948 | { | ||
12949 | row[4] = componentId; | ||
12950 | } | ||
12951 | } | ||
12952 | } | ||
12953 | |||
12954 | /// <summary> | ||
12955 | /// Parses a RemoveRegistryValue element. | ||
12956 | /// </summary> | ||
12957 | /// <param name="node">The element to parse.</param> | ||
12958 | /// <param name="componentId">The component identifier of the parent element.</param> | ||
12959 | [SuppressMessage("Microsoft.Globalization", "CA1308:NormalizeStringsToUppercase", Justification = "Changing the way this string normalizes would result " + | ||
12960 | "in a change to the way the Registry table is generated, potentially causing extra churn in patches on an MSI built from an older version of WiX. " + | ||
12961 | "Furthermore, there is no security hole here, as the strings won't need to make a round trip")] | ||
12962 | private void ParseRemoveRegistryValueElement(XElement node, string componentId) | ||
12963 | { | ||
12964 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
12965 | Identifier id = null; | ||
12966 | string key = null; | ||
12967 | string name = null; | ||
12968 | int root = CompilerConstants.IntegerNotSet; | ||
12969 | |||
12970 | foreach (XAttribute attrib in node.Attributes()) | ||
12971 | { | ||
12972 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
12973 | { | ||
12974 | switch (attrib.Name.LocalName) | ||
12975 | { | ||
12976 | case "Id": | ||
12977 | id = this.core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
12978 | break; | ||
12979 | case "Key": | ||
12980 | key = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
12981 | break; | ||
12982 | case "Name": | ||
12983 | name = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
12984 | break; | ||
12985 | case "Root": | ||
12986 | root = this.core.GetAttributeMsidbRegistryRootValue(sourceLineNumbers, attrib, true); | ||
12987 | break; | ||
12988 | default: | ||
12989 | this.core.UnexpectedAttribute(node, attrib); | ||
12990 | break; | ||
12991 | } | ||
12992 | } | ||
12993 | else | ||
12994 | { | ||
12995 | this.core.ParseExtensionAttribute(node, attrib); | ||
12996 | } | ||
12997 | } | ||
12998 | |||
12999 | // generate the identifier if it wasn't provided | ||
13000 | if (null == id) | ||
13001 | { | ||
13002 | id = this.core.CreateIdentifier("reg", componentId, root.ToString(CultureInfo.InvariantCulture.NumberFormat), LowercaseOrNull(key), LowercaseOrNull(name)); | ||
13003 | } | ||
13004 | |||
13005 | if (null == key) | ||
13006 | { | ||
13007 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Key")); | ||
13008 | } | ||
13009 | |||
13010 | if (CompilerConstants.IntegerNotSet == root) | ||
13011 | { | ||
13012 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Root")); | ||
13013 | } | ||
13014 | |||
13015 | this.core.ParseForExtensionElements(node); | ||
13016 | |||
13017 | if (!this.core.EncounteredError) | ||
13018 | { | ||
13019 | Row row = this.core.CreateRow(sourceLineNumbers, "RemoveRegistry", id); | ||
13020 | row[1] = root; | ||
13021 | row[2] = key; | ||
13022 | row[3] = name; | ||
13023 | row[4] = componentId; | ||
13024 | } | ||
13025 | } | ||
13026 | |||
13027 | /// <summary> | ||
13028 | /// Parses a remove file element. | ||
13029 | /// </summary> | ||
13030 | /// <param name="node">Element to parse.</param> | ||
13031 | /// <param name="componentId">Identifier of parent component.</param> | ||
13032 | /// <param name="parentDirectory">Identifier of the parent component's directory.</param> | ||
13033 | private void ParseRemoveFileElement(XElement node, string componentId, string parentDirectory) | ||
13034 | { | ||
13035 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
13036 | Identifier id = null; | ||
13037 | string directory = null; | ||
13038 | string name = null; | ||
13039 | int on = CompilerConstants.IntegerNotSet; | ||
13040 | string property = null; | ||
13041 | string shortName = null; | ||
13042 | |||
13043 | foreach (XAttribute attrib in node.Attributes()) | ||
13044 | { | ||
13045 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
13046 | { | ||
13047 | switch (attrib.Name.LocalName) | ||
13048 | { | ||
13049 | case "Id": | ||
13050 | id = this.core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
13051 | break; | ||
13052 | case "Directory": | ||
13053 | directory = this.core.CreateDirectoryReferenceFromInlineSyntax(sourceLineNumbers, attrib, parentDirectory); | ||
13054 | break; | ||
13055 | case "Name": | ||
13056 | name = this.core.GetAttributeLongFilename(sourceLineNumbers, attrib, true); | ||
13057 | break; | ||
13058 | case "On": | ||
13059 | Wix.InstallUninstallType onValue = this.core.GetAttributeInstallUninstallValue(sourceLineNumbers, attrib); | ||
13060 | switch (onValue) | ||
13061 | { | ||
13062 | case Wix.InstallUninstallType.install: | ||
13063 | on = 1; | ||
13064 | break; | ||
13065 | case Wix.InstallUninstallType.uninstall: | ||
13066 | on = 2; | ||
13067 | break; | ||
13068 | case Wix.InstallUninstallType.both: | ||
13069 | on = 3; | ||
13070 | break; | ||
13071 | default: | ||
13072 | on = CompilerConstants.IllegalInteger; | ||
13073 | break; | ||
13074 | } | ||
13075 | break; | ||
13076 | case "Property": | ||
13077 | property = this.core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
13078 | break; | ||
13079 | case "ShortName": | ||
13080 | shortName = this.core.GetAttributeShortFilename(sourceLineNumbers, attrib, true); | ||
13081 | break; | ||
13082 | default: | ||
13083 | this.core.UnexpectedAttribute(node, attrib); | ||
13084 | break; | ||
13085 | } | ||
13086 | } | ||
13087 | else | ||
13088 | { | ||
13089 | this.core.ParseExtensionAttribute(node, attrib); | ||
13090 | } | ||
13091 | } | ||
13092 | |||
13093 | if (null == name) | ||
13094 | { | ||
13095 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Name")); | ||
13096 | } | ||
13097 | else if (0 < name.Length) | ||
13098 | { | ||
13099 | if (this.core.IsValidShortFilename(name, true)) | ||
13100 | { | ||
13101 | if (null == shortName) | ||
13102 | { | ||
13103 | shortName = name; | ||
13104 | name = null; | ||
13105 | } | ||
13106 | else | ||
13107 | { | ||
13108 | this.core.OnMessage(WixErrors.IllegalAttributeValueWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Name", name, "ShortName")); | ||
13109 | } | ||
13110 | } | ||
13111 | else if (null == shortName) // generate a short file name. | ||
13112 | { | ||
13113 | shortName = this.core.CreateShortName(name, true, true, node.Name.LocalName, componentId); | ||
13114 | } | ||
13115 | } | ||
13116 | |||
13117 | if (CompilerConstants.IntegerNotSet == on) | ||
13118 | { | ||
13119 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "On")); | ||
13120 | on = CompilerConstants.IllegalInteger; | ||
13121 | } | ||
13122 | |||
13123 | if (null != directory && null != property) | ||
13124 | { | ||
13125 | this.core.OnMessage(WixErrors.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Property", "Directory", directory)); | ||
13126 | } | ||
13127 | |||
13128 | if (null == id) | ||
13129 | { | ||
13130 | id = this.core.CreateIdentifier("rmf", directory ?? property ?? parentDirectory, LowercaseOrNull(shortName), LowercaseOrNull(name), on.ToString()); | ||
13131 | } | ||
13132 | |||
13133 | this.core.ParseForExtensionElements(node); | ||
13134 | |||
13135 | if (!this.core.EncounteredError) | ||
13136 | { | ||
13137 | Row row = this.core.CreateRow(sourceLineNumbers, "RemoveFile", id); | ||
13138 | row[1] = componentId; | ||
13139 | row[2] = GetMsiFilenameValue(shortName, name); | ||
13140 | if (null != directory) | ||
13141 | { | ||
13142 | row[3] = directory; | ||
13143 | } | ||
13144 | else if (null != property) | ||
13145 | { | ||
13146 | row[3] = property; | ||
13147 | } | ||
13148 | else | ||
13149 | { | ||
13150 | row[3] = parentDirectory; | ||
13151 | } | ||
13152 | row[4] = on; | ||
13153 | } | ||
13154 | } | ||
13155 | |||
13156 | /// <summary> | ||
13157 | /// Parses a RemoveFolder element. | ||
13158 | /// </summary> | ||
13159 | /// <param name="node">Element to parse.</param> | ||
13160 | /// <param name="componentId">Identifier of parent component.</param> | ||
13161 | /// <param name="parentDirectory">Identifier of parent component's directory.</param> | ||
13162 | private void ParseRemoveFolderElement(XElement node, string componentId, string parentDirectory) | ||
13163 | { | ||
13164 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
13165 | Identifier id = null; | ||
13166 | string directory = null; | ||
13167 | int on = CompilerConstants.IntegerNotSet; | ||
13168 | string property = null; | ||
13169 | |||
13170 | foreach (XAttribute attrib in node.Attributes()) | ||
13171 | { | ||
13172 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
13173 | { | ||
13174 | switch (attrib.Name.LocalName) | ||
13175 | { | ||
13176 | case "Id": | ||
13177 | id = this.core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
13178 | break; | ||
13179 | case "Directory": | ||
13180 | directory = this.core.CreateDirectoryReferenceFromInlineSyntax(sourceLineNumbers, attrib, parentDirectory); | ||
13181 | break; | ||
13182 | case "On": | ||
13183 | Wix.InstallUninstallType onValue = this.core.GetAttributeInstallUninstallValue(sourceLineNumbers, attrib); | ||
13184 | switch (onValue) | ||
13185 | { | ||
13186 | case Wix.InstallUninstallType.install: | ||
13187 | on = 1; | ||
13188 | break; | ||
13189 | case Wix.InstallUninstallType.uninstall: | ||
13190 | on = 2; | ||
13191 | break; | ||
13192 | case Wix.InstallUninstallType.both: | ||
13193 | on = 3; | ||
13194 | break; | ||
13195 | default: | ||
13196 | on = CompilerConstants.IllegalInteger; | ||
13197 | break; | ||
13198 | } | ||
13199 | break; | ||
13200 | case "Property": | ||
13201 | property = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
13202 | break; | ||
13203 | default: | ||
13204 | this.core.UnexpectedAttribute(node, attrib); | ||
13205 | break; | ||
13206 | } | ||
13207 | } | ||
13208 | else | ||
13209 | { | ||
13210 | this.core.ParseExtensionAttribute(node, attrib); | ||
13211 | } | ||
13212 | } | ||
13213 | |||
13214 | if (CompilerConstants.IntegerNotSet == on) | ||
13215 | { | ||
13216 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "On")); | ||
13217 | on = CompilerConstants.IllegalInteger; | ||
13218 | } | ||
13219 | |||
13220 | if (null != directory && null != property) | ||
13221 | { | ||
13222 | this.core.OnMessage(WixErrors.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Property", "Directory", directory)); | ||
13223 | } | ||
13224 | |||
13225 | if (null == id) | ||
13226 | { | ||
13227 | id = this.core.CreateIdentifier("rmf", directory ?? property ?? parentDirectory, on.ToString()); | ||
13228 | } | ||
13229 | |||
13230 | this.core.ParseForExtensionElements(node); | ||
13231 | |||
13232 | if (!this.core.EncounteredError) | ||
13233 | { | ||
13234 | Row row = this.core.CreateRow(sourceLineNumbers, "RemoveFile", id); | ||
13235 | row[1] = componentId; | ||
13236 | row[2] = null; | ||
13237 | if (null != directory) | ||
13238 | { | ||
13239 | row[3] = directory; | ||
13240 | } | ||
13241 | else if (null != property) | ||
13242 | { | ||
13243 | row[3] = property; | ||
13244 | } | ||
13245 | else | ||
13246 | { | ||
13247 | row[3] = parentDirectory; | ||
13248 | } | ||
13249 | row[4] = on; | ||
13250 | } | ||
13251 | } | ||
13252 | |||
13253 | /// <summary> | ||
13254 | /// Parses a reserve cost element. | ||
13255 | /// </summary> | ||
13256 | /// <param name="node">Element to parse.</param> | ||
13257 | /// <param name="componentId">Identifier of parent component.</param> | ||
13258 | /// <param name="directoryId">Optional and default identifier of referenced directory.</param> | ||
13259 | private void ParseReserveCostElement(XElement node, string componentId, string directoryId) | ||
13260 | { | ||
13261 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
13262 | Identifier id = null; | ||
13263 | int runFromSource = CompilerConstants.IntegerNotSet; | ||
13264 | int runLocal = CompilerConstants.IntegerNotSet; | ||
13265 | |||
13266 | foreach (XAttribute attrib in node.Attributes()) | ||
13267 | { | ||
13268 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
13269 | { | ||
13270 | switch (attrib.Name.LocalName) | ||
13271 | { | ||
13272 | case "Id": | ||
13273 | id = this.core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
13274 | break; | ||
13275 | case "Directory": | ||
13276 | directoryId = this.core.CreateDirectoryReferenceFromInlineSyntax(sourceLineNumbers, attrib, directoryId); | ||
13277 | break; | ||
13278 | case "RunFromSource": | ||
13279 | runFromSource = this.core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, int.MaxValue); | ||
13280 | break; | ||
13281 | case "RunLocal": | ||
13282 | runLocal = this.core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, int.MaxValue); | ||
13283 | break; | ||
13284 | default: | ||
13285 | this.core.UnexpectedAttribute(node, attrib); | ||
13286 | break; | ||
13287 | } | ||
13288 | } | ||
13289 | else | ||
13290 | { | ||
13291 | this.core.ParseExtensionAttribute(node, attrib); | ||
13292 | } | ||
13293 | } | ||
13294 | |||
13295 | if (null == id) | ||
13296 | { | ||
13297 | id = this.core.CreateIdentifier("rc", componentId, directoryId); | ||
13298 | } | ||
13299 | |||
13300 | if (CompilerConstants.IntegerNotSet == runFromSource) | ||
13301 | { | ||
13302 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "RunFromSource")); | ||
13303 | } | ||
13304 | |||
13305 | if (CompilerConstants.IntegerNotSet == runLocal) | ||
13306 | { | ||
13307 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "RunLocal")); | ||
13308 | } | ||
13309 | |||
13310 | this.core.ParseForExtensionElements(node); | ||
13311 | |||
13312 | if (!this.core.EncounteredError) | ||
13313 | { | ||
13314 | Row row = this.core.CreateRow(sourceLineNumbers, "ReserveCost", id); | ||
13315 | row[1] = componentId; | ||
13316 | row[2] = directoryId; | ||
13317 | row[3] = runLocal; | ||
13318 | row[4] = runFromSource; | ||
13319 | } | ||
13320 | } | ||
13321 | |||
13322 | /// <summary> | ||
13323 | /// Parses a sequence element. | ||
13324 | /// </summary> | ||
13325 | /// <param name="node">Element to parse.</param> | ||
13326 | /// <param name="sequenceTable">Name of sequence table.</param> | ||
13327 | private void ParseSequenceElement(XElement node, string sequenceTable) | ||
13328 | { | ||
13329 | // use the proper table name internally | ||
13330 | if ("AdvertiseExecuteSequence" == sequenceTable) | ||
13331 | { | ||
13332 | sequenceTable = "AdvtExecuteSequence"; | ||
13333 | } | ||
13334 | |||
13335 | // Parse each action in the sequence. | ||
13336 | foreach (XElement child in node.Elements()) | ||
13337 | { | ||
13338 | SourceLineNumber childSourceLineNumbers = Preprocessor.GetSourceLineNumbers(child); | ||
13339 | string actionName = child.Name.LocalName; | ||
13340 | string afterAction = null; | ||
13341 | string beforeAction = null; | ||
13342 | string condition = null; | ||
13343 | bool customAction = "Custom" == actionName; | ||
13344 | bool overridable = false; | ||
13345 | int exitSequence = CompilerConstants.IntegerNotSet; | ||
13346 | int sequence = CompilerConstants.IntegerNotSet; | ||
13347 | bool showDialog = "Show" == actionName; | ||
13348 | bool specialAction = "InstallExecute" == actionName || "InstallExecuteAgain" == actionName || "RemoveExistingProducts" == actionName || "DisableRollback" == actionName || "ScheduleReboot" == actionName || "ForceReboot" == actionName || "ResolveSource" == actionName; | ||
13349 | bool specialStandardAction = "AppSearch" == actionName || "CCPSearch" == actionName || "RMCCPSearch" == actionName || "LaunchConditions" == actionName || "FindRelatedProducts" == actionName; | ||
13350 | bool suppress = false; | ||
13351 | |||
13352 | foreach (XAttribute attrib in child.Attributes()) | ||
13353 | { | ||
13354 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
13355 | { | ||
13356 | switch (attrib.Name.LocalName) | ||
13357 | { | ||
13358 | case "Action": | ||
13359 | if (customAction) | ||
13360 | { | ||
13361 | actionName = this.core.GetAttributeIdentifierValue(childSourceLineNumbers, attrib); | ||
13362 | this.core.CreateSimpleReference(childSourceLineNumbers, "CustomAction", actionName); | ||
13363 | } | ||
13364 | else | ||
13365 | { | ||
13366 | this.core.UnexpectedAttribute(child, attrib); | ||
13367 | } | ||
13368 | break; | ||
13369 | case "After": | ||
13370 | if (customAction || showDialog || specialAction || specialStandardAction) | ||
13371 | { | ||
13372 | afterAction = this.core.GetAttributeIdentifierValue(childSourceLineNumbers, attrib); | ||
13373 | this.core.CreateSimpleReference(childSourceLineNumbers, "WixAction", sequenceTable, afterAction); | ||
13374 | } | ||
13375 | else | ||
13376 | { | ||
13377 | this.core.UnexpectedAttribute(child, attrib); | ||
13378 | } | ||
13379 | break; | ||
13380 | case "Before": | ||
13381 | if (customAction || showDialog || specialAction || specialStandardAction) | ||
13382 | { | ||
13383 | beforeAction = this.core.GetAttributeIdentifierValue(childSourceLineNumbers, attrib); | ||
13384 | this.core.CreateSimpleReference(childSourceLineNumbers, "WixAction", sequenceTable, beforeAction); | ||
13385 | } | ||
13386 | else | ||
13387 | { | ||
13388 | this.core.UnexpectedAttribute(child, attrib); | ||
13389 | } | ||
13390 | break; | ||
13391 | case "Dialog": | ||
13392 | if (showDialog) | ||
13393 | { | ||
13394 | actionName = this.core.GetAttributeIdentifierValue(childSourceLineNumbers, attrib); | ||
13395 | this.core.CreateSimpleReference(childSourceLineNumbers, "Dialog", actionName); | ||
13396 | } | ||
13397 | else | ||
13398 | { | ||
13399 | this.core.UnexpectedAttribute(child, attrib); | ||
13400 | } | ||
13401 | break; | ||
13402 | case "OnExit": | ||
13403 | if (customAction || showDialog || specialAction) | ||
13404 | { | ||
13405 | Wix.ExitType exitValue = this.core.GetAttributeExitValue(childSourceLineNumbers, attrib); | ||
13406 | switch (exitValue) | ||
13407 | { | ||
13408 | case Wix.ExitType.success: | ||
13409 | exitSequence = -1; | ||
13410 | break; | ||
13411 | case Wix.ExitType.cancel: | ||
13412 | exitSequence = -2; | ||
13413 | break; | ||
13414 | case Wix.ExitType.error: | ||
13415 | exitSequence = -3; | ||
13416 | break; | ||
13417 | case Wix.ExitType.suspend: | ||
13418 | exitSequence = -4; | ||
13419 | break; | ||
13420 | } | ||
13421 | } | ||
13422 | else | ||
13423 | { | ||
13424 | this.core.UnexpectedAttribute(child, attrib); | ||
13425 | } | ||
13426 | break; | ||
13427 | case "Overridable": | ||
13428 | overridable = YesNoType.Yes == this.core.GetAttributeYesNoValue(childSourceLineNumbers, attrib); | ||
13429 | break; | ||
13430 | case "Sequence": | ||
13431 | sequence = this.core.GetAttributeIntegerValue(childSourceLineNumbers, attrib, 1, short.MaxValue); | ||
13432 | break; | ||
13433 | case "Suppress": | ||
13434 | suppress = YesNoType.Yes == this.core.GetAttributeYesNoValue(childSourceLineNumbers, attrib); | ||
13435 | break; | ||
13436 | default: | ||
13437 | this.core.UnexpectedAttribute(node, attrib); | ||
13438 | break; | ||
13439 | } | ||
13440 | } | ||
13441 | else | ||
13442 | { | ||
13443 | this.core.ParseExtensionAttribute(node, attrib); | ||
13444 | } | ||
13445 | } | ||
13446 | |||
13447 | |||
13448 | // Get the condition from the inner text of the element. | ||
13449 | condition = this.core.GetConditionInnerText(child); | ||
13450 | |||
13451 | if (customAction && "Custom" == actionName) | ||
13452 | { | ||
13453 | this.core.OnMessage(WixErrors.ExpectedAttribute(childSourceLineNumbers, child.Name.LocalName, "Action")); | ||
13454 | } | ||
13455 | else if (showDialog && "Show" == actionName) | ||
13456 | { | ||
13457 | this.core.OnMessage(WixErrors.ExpectedAttribute(childSourceLineNumbers, child.Name.LocalName, "Dialog")); | ||
13458 | } | ||
13459 | |||
13460 | if (CompilerConstants.IntegerNotSet != sequence) | ||
13461 | { | ||
13462 | if (CompilerConstants.IntegerNotSet != exitSequence) | ||
13463 | { | ||
13464 | this.core.OnMessage(WixErrors.IllegalAttributeWithOtherAttribute(childSourceLineNumbers, child.Name.LocalName, "Sequence", "OnExit")); | ||
13465 | } | ||
13466 | else if (null != beforeAction || null != afterAction) | ||
13467 | { | ||
13468 | this.core.OnMessage(WixErrors.IllegalAttributeWithOtherAttribute(childSourceLineNumbers, child.Name.LocalName, "Sequence", "Before", "After")); | ||
13469 | } | ||
13470 | } | ||
13471 | else // sequence not specified use OnExit (which may also be not set). | ||
13472 | { | ||
13473 | sequence = exitSequence; | ||
13474 | } | ||
13475 | |||
13476 | if (null != beforeAction && null != afterAction) | ||
13477 | { | ||
13478 | this.core.OnMessage(WixErrors.IllegalAttributeWithOtherAttribute(childSourceLineNumbers, child.Name.LocalName, "After", "Before")); | ||
13479 | } | ||
13480 | else if ((customAction || showDialog || specialAction) && !suppress && CompilerConstants.IntegerNotSet == sequence && null == beforeAction && null == afterAction) | ||
13481 | { | ||
13482 | this.core.OnMessage(WixErrors.NeedSequenceBeforeOrAfter(childSourceLineNumbers, child.Name.LocalName)); | ||
13483 | } | ||
13484 | |||
13485 | // action that is scheduled to occur before/after itself | ||
13486 | if (beforeAction == actionName) | ||
13487 | { | ||
13488 | this.core.OnMessage(WixErrors.ActionScheduledRelativeToItself(childSourceLineNumbers, child.Name.LocalName, "Before", beforeAction)); | ||
13489 | } | ||
13490 | else if (afterAction == actionName) | ||
13491 | { | ||
13492 | this.core.OnMessage(WixErrors.ActionScheduledRelativeToItself(childSourceLineNumbers, child.Name.LocalName, "After", afterAction)); | ||
13493 | } | ||
13494 | |||
13495 | // normal standard actions cannot be set overridable by the user (since they are overridable by default) | ||
13496 | if (overridable && WindowsInstallerStandard.IsStandardAction(actionName) && !specialAction) | ||
13497 | { | ||
13498 | this.core.OnMessage(WixErrors.UnexpectedAttribute(childSourceLineNumbers, child.Name.LocalName, "Overridable")); | ||
13499 | } | ||
13500 | |||
13501 | // suppress cannot be specified at the same time as Before, After, or Sequence | ||
13502 | if (suppress && (null != afterAction || null != beforeAction || CompilerConstants.IntegerNotSet != sequence || overridable)) | ||
13503 | { | ||
13504 | this.core.OnMessage(WixErrors.IllegalAttributeWithOtherAttributes(childSourceLineNumbers, child.Name.LocalName, "Suppress", "Before", "After", "Sequence", "Overridable")); | ||
13505 | } | ||
13506 | |||
13507 | this.core.ParseForExtensionElements(child); | ||
13508 | |||
13509 | // add the row and any references needed | ||
13510 | if (!this.core.EncounteredError) | ||
13511 | { | ||
13512 | if (suppress) | ||
13513 | { | ||
13514 | Row row = this.core.CreateRow(childSourceLineNumbers, "WixSuppressAction"); | ||
13515 | row[0] = sequenceTable; | ||
13516 | row[1] = actionName; | ||
13517 | } | ||
13518 | else | ||
13519 | { | ||
13520 | Row row = this.core.CreateRow(childSourceLineNumbers, "WixAction"); | ||
13521 | row[0] = sequenceTable; | ||
13522 | row[1] = actionName; | ||
13523 | row[2] = condition; | ||
13524 | if (CompilerConstants.IntegerNotSet != sequence) | ||
13525 | { | ||
13526 | row[3] = sequence; | ||
13527 | } | ||
13528 | row[4] = beforeAction; | ||
13529 | row[5] = afterAction; | ||
13530 | row[6] = overridable ? 1 : 0; | ||
13531 | } | ||
13532 | } | ||
13533 | } | ||
13534 | } | ||
13535 | |||
13536 | |||
13537 | /// <summary> | ||
13538 | /// Parses a service config element. | ||
13539 | /// </summary> | ||
13540 | /// <param name="node">Element to parse.</param> | ||
13541 | /// <param name="componentId">Identifier of parent component.</param> | ||
13542 | /// <param name="serviceName">Optional element containing parent's service name.</param> | ||
13543 | private void ParseServiceConfigElement(XElement node, string componentId, string serviceName) | ||
13544 | { | ||
13545 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
13546 | Identifier id = null; | ||
13547 | string delayedAutoStart = null; | ||
13548 | string failureActionsWhen = null; | ||
13549 | int events = 0; | ||
13550 | string name = serviceName; | ||
13551 | string preShutdownDelay = null; | ||
13552 | string requiredPrivileges = null; | ||
13553 | string sid = null; | ||
13554 | |||
13555 | this.core.OnMessage(WixWarnings.ServiceConfigFamilyNotSupported(sourceLineNumbers, node.Name.LocalName)); | ||
13556 | |||
13557 | foreach (XAttribute attrib in node.Attributes()) | ||
13558 | { | ||
13559 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
13560 | { | ||
13561 | switch (attrib.Name.LocalName) | ||
13562 | { | ||
13563 | case "Id": | ||
13564 | id = this.core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
13565 | break; | ||
13566 | case "DelayedAutoStart": | ||
13567 | delayedAutoStart = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
13568 | if (0 < delayedAutoStart.Length) | ||
13569 | { | ||
13570 | switch (delayedAutoStart) | ||
13571 | { | ||
13572 | case "no": | ||
13573 | delayedAutoStart = "0"; | ||
13574 | break; | ||
13575 | case "yes": | ||
13576 | delayedAutoStart = "1"; | ||
13577 | break; | ||
13578 | default: | ||
13579 | // allow everything else to pass through that are hopefully "formatted" Properties. | ||
13580 | break; | ||
13581 | } | ||
13582 | } | ||
13583 | break; | ||
13584 | case "FailureActionsWhen": | ||
13585 | failureActionsWhen = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
13586 | if (0 < failureActionsWhen.Length) | ||
13587 | { | ||
13588 | switch (failureActionsWhen) | ||
13589 | { | ||
13590 | case "failedToStop": | ||
13591 | failureActionsWhen = "0"; | ||
13592 | break; | ||
13593 | case "failedToStopOrReturnedError": | ||
13594 | failureActionsWhen = "1"; | ||
13595 | break; | ||
13596 | default: | ||
13597 | // allow everything else to pass through that are hopefully "formatted" Properties. | ||
13598 | break; | ||
13599 | } | ||
13600 | } | ||
13601 | break; | ||
13602 | case "OnInstall": | ||
13603 | YesNoType install = this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
13604 | if (YesNoType.Yes == install) | ||
13605 | { | ||
13606 | events |= MsiInterop.MsidbServiceConfigEventInstall; | ||
13607 | } | ||
13608 | break; | ||
13609 | case "OnReinstall": | ||
13610 | YesNoType reinstall = this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
13611 | if (YesNoType.Yes == reinstall) | ||
13612 | { | ||
13613 | events |= MsiInterop.MsidbServiceConfigEventReinstall; | ||
13614 | } | ||
13615 | break; | ||
13616 | case "OnUninstall": | ||
13617 | YesNoType uninstall = this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
13618 | if (YesNoType.Yes == uninstall) | ||
13619 | { | ||
13620 | events |= MsiInterop.MsidbServiceConfigEventUninstall; | ||
13621 | } | ||
13622 | break; | ||
13623 | default: | ||
13624 | this.core.UnexpectedAttribute(node, attrib); | ||
13625 | break; | ||
13626 | case "PreShutdownDelay": | ||
13627 | preShutdownDelay = this.core.GetAttributeValue(sourceLineNumbers, attrib, EmptyRule.CanBeEmpty); | ||
13628 | break; | ||
13629 | case "ServiceName": | ||
13630 | if (!String.IsNullOrEmpty(serviceName)) | ||
13631 | { | ||
13632 | this.core.OnMessage(WixErrors.IllegalAttributeWhenNested(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, "ServiceInstall")); | ||
13633 | } | ||
13634 | |||
13635 | name = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
13636 | break; | ||
13637 | case "ServiceSid": | ||
13638 | sid = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
13639 | if (0 < sid.Length) | ||
13640 | { | ||
13641 | switch (sid) | ||
13642 | { | ||
13643 | case "none": | ||
13644 | sid = "0"; | ||
13645 | break; | ||
13646 | case "restricted": | ||
13647 | sid = "3"; | ||
13648 | break; | ||
13649 | case "unrestricted": | ||
13650 | sid = "1"; | ||
13651 | break; | ||
13652 | default: | ||
13653 | // allow everything else to pass through that are hopefully "formatted" Properties. | ||
13654 | break; | ||
13655 | } | ||
13656 | } | ||
13657 | break; | ||
13658 | } | ||
13659 | } | ||
13660 | else | ||
13661 | { | ||
13662 | this.core.ParseExtensionAttribute(node, attrib); | ||
13663 | } | ||
13664 | } | ||
13665 | |||
13666 | // Get the ServiceConfig required privilegs. | ||
13667 | foreach (XElement child in node.Elements()) | ||
13668 | { | ||
13669 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
13670 | { | ||
13671 | switch (child.Name.LocalName) | ||
13672 | { | ||
13673 | case "RequiredPrivilege": | ||
13674 | string privilege = this.core.GetTrimmedInnerText(child); | ||
13675 | switch (privilege) | ||
13676 | { | ||
13677 | case "assignPrimaryToken": | ||
13678 | privilege = "SeAssignPrimaryTokenPrivilege"; | ||
13679 | break; | ||
13680 | case "audit": | ||
13681 | privilege = "SeAuditPrivilege"; | ||
13682 | break; | ||
13683 | case "backup": | ||
13684 | privilege = "SeBackupPrivilege"; | ||
13685 | break; | ||
13686 | case "changeNotify": | ||
13687 | privilege = "SeChangeNotifyPrivilege"; | ||
13688 | break; | ||
13689 | case "createGlobal": | ||
13690 | privilege = "SeCreateGlobalPrivilege"; | ||
13691 | break; | ||
13692 | case "createPagefile": | ||
13693 | privilege = "SeCreatePagefilePrivilege"; | ||
13694 | break; | ||
13695 | case "createPermanent": | ||
13696 | privilege = "SeCreatePermanentPrivilege"; | ||
13697 | break; | ||
13698 | case "createSymbolicLink": | ||
13699 | privilege = "SeCreateSymbolicLinkPrivilege"; | ||
13700 | break; | ||
13701 | case "createToken": | ||
13702 | privilege = "SeCreateTokenPrivilege"; | ||
13703 | break; | ||
13704 | case "debug": | ||
13705 | privilege = "SeDebugPrivilege"; | ||
13706 | break; | ||
13707 | case "enableDelegation": | ||
13708 | privilege = "SeEnableDelegationPrivilege"; | ||
13709 | break; | ||
13710 | case "impersonate": | ||
13711 | privilege = "SeImpersonatePrivilege"; | ||
13712 | break; | ||
13713 | case "increaseBasePriority": | ||
13714 | privilege = "SeIncreaseBasePriorityPrivilege"; | ||
13715 | break; | ||
13716 | case "increaseQuota": | ||
13717 | privilege = "SeIncreaseQuotaPrivilege"; | ||
13718 | break; | ||
13719 | case "increaseWorkingSet": | ||
13720 | privilege = "SeIncreaseWorkingSetPrivilege"; | ||
13721 | break; | ||
13722 | case "loadDriver": | ||
13723 | privilege = "SeLoadDriverPrivilege"; | ||
13724 | break; | ||
13725 | case "lockMemory": | ||
13726 | privilege = "SeLockMemoryPrivilege"; | ||
13727 | break; | ||
13728 | case "machineAccount": | ||
13729 | privilege = "SeMachineAccountPrivilege"; | ||
13730 | break; | ||
13731 | case "manageVolume": | ||
13732 | privilege = "SeManageVolumePrivilege"; | ||
13733 | break; | ||
13734 | case "profileSingleProcess": | ||
13735 | privilege = "SeProfileSingleProcessPrivilege"; | ||
13736 | break; | ||
13737 | case "relabel": | ||
13738 | privilege = "SeRelabelPrivilege"; | ||
13739 | break; | ||
13740 | case "remoteShutdown": | ||
13741 | privilege = "SeRemoteShutdownPrivilege"; | ||
13742 | break; | ||
13743 | case "restore": | ||
13744 | privilege = "SeRestorePrivilege"; | ||
13745 | break; | ||
13746 | case "security": | ||
13747 | privilege = "SeSecurityPrivilege"; | ||
13748 | break; | ||
13749 | case "shutdown": | ||
13750 | privilege = "SeShutdownPrivilege"; | ||
13751 | break; | ||
13752 | case "syncAgent": | ||
13753 | privilege = "SeSyncAgentPrivilege"; | ||
13754 | break; | ||
13755 | case "systemEnvironment": | ||
13756 | privilege = "SeSystemEnvironmentPrivilege"; | ||
13757 | break; | ||
13758 | case "systemProfile": | ||
13759 | privilege = "SeSystemProfilePrivilege"; | ||
13760 | break; | ||
13761 | case "systemTime": | ||
13762 | case "modifySystemTime": | ||
13763 | privilege = "SeSystemtimePrivilege"; | ||
13764 | break; | ||
13765 | case "takeOwnership": | ||
13766 | privilege = "SeTakeOwnershipPrivilege"; | ||
13767 | break; | ||
13768 | case "tcb": | ||
13769 | case "trustedComputerBase": | ||
13770 | privilege = "SeTcbPrivilege"; | ||
13771 | break; | ||
13772 | case "timeZone": | ||
13773 | case "modifyTimeZone": | ||
13774 | privilege = "SeTimeZonePrivilege"; | ||
13775 | break; | ||
13776 | case "trustedCredManAccess": | ||
13777 | case "trustedCredentialManagerAccess": | ||
13778 | privilege = "SeTrustedCredManAccessPrivilege"; | ||
13779 | break; | ||
13780 | case "undock": | ||
13781 | privilege = "SeUndockPrivilege"; | ||
13782 | break; | ||
13783 | case "unsolicitedInput": | ||
13784 | privilege = "SeUnsolicitedInputPrivilege"; | ||
13785 | break; | ||
13786 | default: | ||
13787 | // allow everything else to pass through that are hopefully "formatted" Properties. | ||
13788 | break; | ||
13789 | } | ||
13790 | |||
13791 | if (null != requiredPrivileges) | ||
13792 | { | ||
13793 | requiredPrivileges = String.Concat(requiredPrivileges, "[~]"); | ||
13794 | } | ||
13795 | requiredPrivileges = String.Concat(requiredPrivileges, privilege); | ||
13796 | break; | ||
13797 | default: | ||
13798 | this.core.UnexpectedElement(node, child); | ||
13799 | break; | ||
13800 | } | ||
13801 | } | ||
13802 | else | ||
13803 | { | ||
13804 | this.core.ParseExtensionElement(node, child); | ||
13805 | } | ||
13806 | } | ||
13807 | |||
13808 | if (String.IsNullOrEmpty(name)) | ||
13809 | { | ||
13810 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "ServiceName")); | ||
13811 | } | ||
13812 | else if (null == id) | ||
13813 | { | ||
13814 | id = this.core.CreateIdentifierFromFilename(name); | ||
13815 | } | ||
13816 | |||
13817 | if (0 == events) | ||
13818 | { | ||
13819 | this.core.OnMessage(WixErrors.ExpectedAttributes(sourceLineNumbers, node.Name.LocalName, "OnInstall", "OnReinstall", "OnUninstall")); | ||
13820 | } | ||
13821 | |||
13822 | if (String.IsNullOrEmpty(delayedAutoStart) && String.IsNullOrEmpty(failureActionsWhen) && String.IsNullOrEmpty(preShutdownDelay) && String.IsNullOrEmpty(requiredPrivileges) && String.IsNullOrEmpty(sid)) | ||
13823 | { | ||
13824 | this.core.OnMessage(WixErrors.ExpectedAttributes(sourceLineNumbers, node.Name.LocalName, "DelayedAutoStart", "FailureActionsWhen", "PreShutdownDelay", "ServiceSid", "RequiredPrivilege")); | ||
13825 | } | ||
13826 | |||
13827 | if (!this.core.EncounteredError) | ||
13828 | { | ||
13829 | if (!String.IsNullOrEmpty(delayedAutoStart)) | ||
13830 | { | ||
13831 | Row row = this.core.CreateRow(sourceLineNumbers, "MsiServiceConfig", new Identifier(String.Concat(id.Id, ".DS"), id.Access)); | ||
13832 | row[1] = name; | ||
13833 | row[2] = events; | ||
13834 | row[3] = 3; | ||
13835 | row[4] = delayedAutoStart; | ||
13836 | row[5] = componentId; | ||
13837 | } | ||
13838 | |||
13839 | if (!String.IsNullOrEmpty(failureActionsWhen)) | ||
13840 | { | ||
13841 | Row row = this.core.CreateRow(sourceLineNumbers, "MsiServiceConfig", new Identifier(String.Concat(id.Id, ".FA"), id.Access)); | ||
13842 | row[1] = name; | ||
13843 | row[2] = events; | ||
13844 | row[3] = 4; | ||
13845 | row[4] = failureActionsWhen; | ||
13846 | row[5] = componentId; | ||
13847 | } | ||
13848 | |||
13849 | if (!String.IsNullOrEmpty(sid)) | ||
13850 | { | ||
13851 | Row row = this.core.CreateRow(sourceLineNumbers, "MsiServiceConfig", new Identifier(String.Concat(id.Id, ".SS"), id.Access)); | ||
13852 | row[1] = name; | ||
13853 | row[2] = events; | ||
13854 | row[3] = 5; | ||
13855 | row[4] = sid; | ||
13856 | row[5] = componentId; | ||
13857 | } | ||
13858 | |||
13859 | if (!String.IsNullOrEmpty(requiredPrivileges)) | ||
13860 | { | ||
13861 | Row row = this.core.CreateRow(sourceLineNumbers, "MsiServiceConfig", new Identifier(String.Concat(id.Id, ".RP"), id.Access)); | ||
13862 | row[1] = name; | ||
13863 | row[2] = events; | ||
13864 | row[3] = 6; | ||
13865 | row[4] = requiredPrivileges; | ||
13866 | row[5] = componentId; | ||
13867 | } | ||
13868 | |||
13869 | if (!String.IsNullOrEmpty(preShutdownDelay)) | ||
13870 | { | ||
13871 | Row row = this.core.CreateRow(sourceLineNumbers, "MsiServiceConfig", new Identifier(String.Concat(id.Id, ".PD"), id.Access)); | ||
13872 | row[1] = name; | ||
13873 | row[2] = events; | ||
13874 | row[3] = 7; | ||
13875 | row[4] = preShutdownDelay; | ||
13876 | row[5] = componentId; | ||
13877 | } | ||
13878 | } | ||
13879 | } | ||
13880 | |||
13881 | /// <summary> | ||
13882 | /// Parses a service config failure actions element. | ||
13883 | /// </summary> | ||
13884 | /// <param name="node">Element to parse.</param> | ||
13885 | /// <param name="componentId">Identifier of parent component.</param> | ||
13886 | /// <param name="serviceName">Optional element containing parent's service name.</param> | ||
13887 | private void ParseServiceConfigFailureActionsElement(XElement node, string componentId, string serviceName) | ||
13888 | { | ||
13889 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
13890 | Identifier id = null; | ||
13891 | int events = 0; | ||
13892 | string name = serviceName; | ||
13893 | int resetPeriod = CompilerConstants.IntegerNotSet; | ||
13894 | string rebootMessage = null; | ||
13895 | string command = null; | ||
13896 | string actions = null; | ||
13897 | string actionsDelays = null; | ||
13898 | |||
13899 | this.core.OnMessage(WixWarnings.ServiceConfigFamilyNotSupported(sourceLineNumbers, node.Name.LocalName)); | ||
13900 | |||
13901 | foreach (XAttribute attrib in node.Attributes()) | ||
13902 | { | ||
13903 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
13904 | { | ||
13905 | switch (attrib.Name.LocalName) | ||
13906 | { | ||
13907 | case "Id": | ||
13908 | id = this.core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
13909 | break; | ||
13910 | case "Command": | ||
13911 | command = this.core.GetAttributeValue(sourceLineNumbers, attrib, EmptyRule.CanBeEmpty); | ||
13912 | break; | ||
13913 | case "OnInstall": | ||
13914 | YesNoType install = this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
13915 | if (YesNoType.Yes == install) | ||
13916 | { | ||
13917 | events |= MsiInterop.MsidbServiceConfigEventInstall; | ||
13918 | } | ||
13919 | break; | ||
13920 | case "OnReinstall": | ||
13921 | YesNoType reinstall = this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
13922 | if (YesNoType.Yes == reinstall) | ||
13923 | { | ||
13924 | events |= MsiInterop.MsidbServiceConfigEventReinstall; | ||
13925 | } | ||
13926 | break; | ||
13927 | case "OnUninstall": | ||
13928 | YesNoType uninstall = this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
13929 | if (YesNoType.Yes == uninstall) | ||
13930 | { | ||
13931 | events |= MsiInterop.MsidbServiceConfigEventUninstall; | ||
13932 | } | ||
13933 | break; | ||
13934 | case "RebootMessage": | ||
13935 | rebootMessage = this.core.GetAttributeValue(sourceLineNumbers, attrib, EmptyRule.CanBeEmpty); | ||
13936 | break; | ||
13937 | case "ResetPeriod": | ||
13938 | resetPeriod = this.core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, int.MaxValue); | ||
13939 | break; | ||
13940 | case "ServiceName": | ||
13941 | if (!String.IsNullOrEmpty(serviceName)) | ||
13942 | { | ||
13943 | this.core.OnMessage(WixErrors.IllegalAttributeWhenNested(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, "ServiceInstall")); | ||
13944 | } | ||
13945 | |||
13946 | name = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
13947 | break; | ||
13948 | default: | ||
13949 | this.core.UnexpectedAttribute(node, attrib); | ||
13950 | break; | ||
13951 | } | ||
13952 | } | ||
13953 | else | ||
13954 | { | ||
13955 | this.core.ParseExtensionAttribute(node, attrib); | ||
13956 | } | ||
13957 | } | ||
13958 | |||
13959 | // Get the ServiceConfigFailureActions actions. | ||
13960 | foreach (XElement child in node.Elements()) | ||
13961 | { | ||
13962 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
13963 | { | ||
13964 | switch (child.Name.LocalName) | ||
13965 | { | ||
13966 | case "Failure": | ||
13967 | string action = null; | ||
13968 | string delay = null; | ||
13969 | SourceLineNumber childSourceLineNumbers = Preprocessor.GetSourceLineNumbers(child); | ||
13970 | |||
13971 | foreach (XAttribute childAttrib in child.Attributes()) | ||
13972 | { | ||
13973 | if (String.IsNullOrEmpty(childAttrib.Name.NamespaceName) || CompilerCore.WixNamespace == childAttrib.Name.Namespace) | ||
13974 | { | ||
13975 | switch (childAttrib.Name.LocalName) | ||
13976 | { | ||
13977 | case "Action": | ||
13978 | action = this.core.GetAttributeValue(childSourceLineNumbers, childAttrib); | ||
13979 | switch (action) | ||
13980 | { | ||
13981 | case "none": | ||
13982 | action = "0"; | ||
13983 | break; | ||
13984 | case "restartComputer": | ||
13985 | action = "2"; | ||
13986 | break; | ||
13987 | case "restartService": | ||
13988 | action = "1"; | ||
13989 | break; | ||
13990 | case "runCommand": | ||
13991 | action = "3"; | ||
13992 | break; | ||
13993 | default: | ||
13994 | // allow everything else to pass through that are hopefully "formatted" Properties. | ||
13995 | break; | ||
13996 | } | ||
13997 | break; | ||
13998 | case "Delay": | ||
13999 | delay = this.core.GetAttributeValue(childSourceLineNumbers, childAttrib); | ||
14000 | break; | ||
14001 | default: | ||
14002 | this.core.UnexpectedAttribute(child, childAttrib); | ||
14003 | break; | ||
14004 | } | ||
14005 | } | ||
14006 | } | ||
14007 | |||
14008 | if (String.IsNullOrEmpty(action)) | ||
14009 | { | ||
14010 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, child.Name.LocalName, "Action")); | ||
14011 | } | ||
14012 | |||
14013 | if (String.IsNullOrEmpty(delay)) | ||
14014 | { | ||
14015 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, child.Name.LocalName, "Delay")); | ||
14016 | } | ||
14017 | |||
14018 | if (!String.IsNullOrEmpty(actions)) | ||
14019 | { | ||
14020 | actions = String.Concat(actions, "[~]"); | ||
14021 | } | ||
14022 | actions = String.Concat(actions, action); | ||
14023 | |||
14024 | if (!String.IsNullOrEmpty(actionsDelays)) | ||
14025 | { | ||
14026 | actionsDelays = String.Concat(actionsDelays, "[~]"); | ||
14027 | } | ||
14028 | actionsDelays = String.Concat(actionsDelays, delay); | ||
14029 | break; | ||
14030 | default: | ||
14031 | this.core.UnexpectedElement(node, child); | ||
14032 | break; | ||
14033 | } | ||
14034 | } | ||
14035 | else | ||
14036 | { | ||
14037 | this.core.ParseExtensionElement(node, child); | ||
14038 | } | ||
14039 | } | ||
14040 | |||
14041 | if (String.IsNullOrEmpty(name)) | ||
14042 | { | ||
14043 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "ServiceName")); | ||
14044 | } | ||
14045 | else if (null == id) | ||
14046 | { | ||
14047 | id = this.core.CreateIdentifierFromFilename(name); | ||
14048 | } | ||
14049 | |||
14050 | if (0 == events) | ||
14051 | { | ||
14052 | this.core.OnMessage(WixErrors.ExpectedAttributes(sourceLineNumbers, node.Name.LocalName, "OnInstall", "OnReinstall", "OnUninstall")); | ||
14053 | } | ||
14054 | |||
14055 | if (!this.core.EncounteredError) | ||
14056 | { | ||
14057 | Row row = this.core.CreateRow(sourceLineNumbers, "MsiServiceConfigFailureActions", id); | ||
14058 | row[1] = name; | ||
14059 | row[2] = events; | ||
14060 | if (CompilerConstants.IntegerNotSet != resetPeriod) | ||
14061 | { | ||
14062 | row[3] = resetPeriod; | ||
14063 | } | ||
14064 | row[4] = rebootMessage ?? "[~]"; | ||
14065 | row[5] = command ?? "[~]"; | ||
14066 | row[6] = actions; | ||
14067 | row[7] = actionsDelays; | ||
14068 | row[8] = componentId; | ||
14069 | } | ||
14070 | } | ||
14071 | |||
14072 | /// <summary> | ||
14073 | /// Parses a service control element. | ||
14074 | /// </summary> | ||
14075 | /// <param name="node">Element to parse.</param> | ||
14076 | /// <param name="componentId">Identifier of parent component.</param> | ||
14077 | private void ParseServiceControlElement(XElement node, string componentId) | ||
14078 | { | ||
14079 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
14080 | string arguments = null; | ||
14081 | int events = 0; // default is to do nothing | ||
14082 | Identifier id = null; | ||
14083 | string name = null; | ||
14084 | YesNoType wait = YesNoType.NotSet; | ||
14085 | |||
14086 | foreach (XAttribute attrib in node.Attributes()) | ||
14087 | { | ||
14088 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
14089 | { | ||
14090 | switch (attrib.Name.LocalName) | ||
14091 | { | ||
14092 | case "Id": | ||
14093 | id = this.core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
14094 | break; | ||
14095 | case "Name": | ||
14096 | name = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
14097 | break; | ||
14098 | case "Remove": | ||
14099 | Wix.InstallUninstallType removeValue = this.core.GetAttributeInstallUninstallValue(sourceLineNumbers, attrib); | ||
14100 | switch (removeValue) | ||
14101 | { | ||
14102 | case Wix.InstallUninstallType.install: | ||
14103 | events |= MsiInterop.MsidbServiceControlEventDelete; | ||
14104 | break; | ||
14105 | case Wix.InstallUninstallType.uninstall: | ||
14106 | events |= MsiInterop.MsidbServiceControlEventUninstallDelete; | ||
14107 | break; | ||
14108 | case Wix.InstallUninstallType.both: | ||
14109 | events |= MsiInterop.MsidbServiceControlEventDelete | MsiInterop.MsidbServiceControlEventUninstallDelete; | ||
14110 | break; | ||
14111 | } | ||
14112 | break; | ||
14113 | case "Start": | ||
14114 | Wix.InstallUninstallType startValue = this.core.GetAttributeInstallUninstallValue(sourceLineNumbers, attrib); | ||
14115 | switch (startValue) | ||
14116 | { | ||
14117 | case Wix.InstallUninstallType.install: | ||
14118 | events |= MsiInterop.MsidbServiceControlEventStart; | ||
14119 | break; | ||
14120 | case Wix.InstallUninstallType.uninstall: | ||
14121 | events |= MsiInterop.MsidbServiceControlEventUninstallStart; | ||
14122 | break; | ||
14123 | case Wix.InstallUninstallType.both: | ||
14124 | events |= MsiInterop.MsidbServiceControlEventStart | MsiInterop.MsidbServiceControlEventUninstallStart; | ||
14125 | break; | ||
14126 | } | ||
14127 | break; | ||
14128 | case "Stop": | ||
14129 | Wix.InstallUninstallType stopValue = this.core.GetAttributeInstallUninstallValue(sourceLineNumbers, attrib); | ||
14130 | switch (stopValue) | ||
14131 | { | ||
14132 | case Wix.InstallUninstallType.install: | ||
14133 | events |= MsiInterop.MsidbServiceControlEventStop; | ||
14134 | break; | ||
14135 | case Wix.InstallUninstallType.uninstall: | ||
14136 | events |= MsiInterop.MsidbServiceControlEventUninstallStop; | ||
14137 | break; | ||
14138 | case Wix.InstallUninstallType.both: | ||
14139 | events |= MsiInterop.MsidbServiceControlEventStop | MsiInterop.MsidbServiceControlEventUninstallStop; | ||
14140 | break; | ||
14141 | } | ||
14142 | break; | ||
14143 | case "Wait": | ||
14144 | wait = this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
14145 | break; | ||
14146 | default: | ||
14147 | this.core.UnexpectedAttribute(node, attrib); | ||
14148 | break; | ||
14149 | } | ||
14150 | } | ||
14151 | else | ||
14152 | { | ||
14153 | this.core.ParseExtensionAttribute(node, attrib); | ||
14154 | } | ||
14155 | } | ||
14156 | |||
14157 | if (null == id) | ||
14158 | { | ||
14159 | id = this.core.CreateIdentifierFromFilename(name); | ||
14160 | } | ||
14161 | |||
14162 | if (null == name) | ||
14163 | { | ||
14164 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Name")); | ||
14165 | } | ||
14166 | |||
14167 | // get the ServiceControl arguments | ||
14168 | foreach (XElement child in node.Elements()) | ||
14169 | { | ||
14170 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
14171 | { | ||
14172 | switch (child.Name.LocalName) | ||
14173 | { | ||
14174 | case "ServiceArgument": | ||
14175 | if (null != arguments) | ||
14176 | { | ||
14177 | arguments = String.Concat(arguments, "[~]"); | ||
14178 | } | ||
14179 | arguments = String.Concat(arguments, this.core.GetTrimmedInnerText(child)); | ||
14180 | break; | ||
14181 | default: | ||
14182 | this.core.UnexpectedElement(node, child); | ||
14183 | break; | ||
14184 | } | ||
14185 | } | ||
14186 | else | ||
14187 | { | ||
14188 | this.core.ParseExtensionElement(node, child); | ||
14189 | } | ||
14190 | } | ||
14191 | |||
14192 | if (!this.core.EncounteredError) | ||
14193 | { | ||
14194 | Row row = this.core.CreateRow(sourceLineNumbers, "ServiceControl", id); | ||
14195 | row[1] = name; | ||
14196 | row[2] = events; | ||
14197 | row[3] = arguments; | ||
14198 | if (YesNoType.NotSet != wait) | ||
14199 | { | ||
14200 | row[4] = YesNoType.Yes == wait ? 1 : 0; | ||
14201 | } | ||
14202 | row[5] = componentId; | ||
14203 | } | ||
14204 | } | ||
14205 | |||
14206 | /// <summary> | ||
14207 | /// Parses a service dependency element. | ||
14208 | /// </summary> | ||
14209 | /// <param name="node">Element to parse.</param> | ||
14210 | /// <returns>Parsed sevice dependency name.</returns> | ||
14211 | private string ParseServiceDependencyElement(XElement node) | ||
14212 | { | ||
14213 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
14214 | string dependency = null; | ||
14215 | bool group = false; | ||
14216 | |||
14217 | foreach (XAttribute attrib in node.Attributes()) | ||
14218 | { | ||
14219 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
14220 | { | ||
14221 | switch (attrib.Name.LocalName) | ||
14222 | { | ||
14223 | case "Id": | ||
14224 | dependency = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
14225 | break; | ||
14226 | case "Group": | ||
14227 | group = YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
14228 | break; | ||
14229 | default: | ||
14230 | this.core.UnexpectedAttribute(node, attrib); | ||
14231 | break; | ||
14232 | } | ||
14233 | } | ||
14234 | else | ||
14235 | { | ||
14236 | this.core.ParseExtensionAttribute(node, attrib); | ||
14237 | } | ||
14238 | } | ||
14239 | |||
14240 | if (null == dependency) | ||
14241 | { | ||
14242 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
14243 | } | ||
14244 | |||
14245 | this.core.ParseForExtensionElements(node); | ||
14246 | |||
14247 | return group ? String.Concat("+", dependency) : dependency; | ||
14248 | } | ||
14249 | |||
14250 | /// <summary> | ||
14251 | /// Parses a service install element. | ||
14252 | /// </summary> | ||
14253 | /// <param name="node">Element to parse.</param> | ||
14254 | /// <param name="componentId">Identifier of parent component.</param> | ||
14255 | private void ParseServiceInstallElement(XElement node, string componentId, bool win64Component) | ||
14256 | { | ||
14257 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
14258 | Identifier id = null; | ||
14259 | string account = null; | ||
14260 | string arguments = null; | ||
14261 | string dependencies = null; | ||
14262 | string description = null; | ||
14263 | string displayName = null; | ||
14264 | bool eraseDescription = false; | ||
14265 | int errorbits = 0; | ||
14266 | string loadOrderGroup = null; | ||
14267 | string name = null; | ||
14268 | string password = null; | ||
14269 | int startType = 0; | ||
14270 | int typebits = 0; | ||
14271 | |||
14272 | foreach (XAttribute attrib in node.Attributes()) | ||
14273 | { | ||
14274 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
14275 | { | ||
14276 | switch (attrib.Name.LocalName) | ||
14277 | { | ||
14278 | case "Id": | ||
14279 | id = this.core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
14280 | break; | ||
14281 | case "Account": | ||
14282 | account = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
14283 | break; | ||
14284 | case "Arguments": | ||
14285 | arguments = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
14286 | break; | ||
14287 | case "Description": | ||
14288 | description = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
14289 | break; | ||
14290 | case "DisplayName": | ||
14291 | displayName = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
14292 | break; | ||
14293 | case "EraseDescription": | ||
14294 | eraseDescription = YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
14295 | break; | ||
14296 | case "ErrorControl": | ||
14297 | string errorControlValue = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
14298 | if (0 < errorControlValue.Length) | ||
14299 | { | ||
14300 | Wix.ServiceInstall.ErrorControlType errorControlType = Wix.ServiceInstall.ParseErrorControlType(errorControlValue); | ||
14301 | switch (errorControlType) | ||
14302 | { | ||
14303 | case Wix.ServiceInstall.ErrorControlType.ignore: | ||
14304 | errorbits |= MsiInterop.MsidbServiceInstallErrorIgnore; | ||
14305 | break; | ||
14306 | case Wix.ServiceInstall.ErrorControlType.normal: | ||
14307 | errorbits |= MsiInterop.MsidbServiceInstallErrorNormal; | ||
14308 | break; | ||
14309 | case Wix.ServiceInstall.ErrorControlType.critical: | ||
14310 | errorbits |= MsiInterop.MsidbServiceInstallErrorCritical; | ||
14311 | break; | ||
14312 | default: | ||
14313 | this.core.OnMessage(WixErrors.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, errorControlValue, "ignore", "normal", "critical")); | ||
14314 | break; | ||
14315 | } | ||
14316 | } | ||
14317 | break; | ||
14318 | case "Interactive": | ||
14319 | if (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
14320 | { | ||
14321 | typebits |= MsiInterop.MsidbServiceInstallInteractive; | ||
14322 | } | ||
14323 | break; | ||
14324 | case "LoadOrderGroup": | ||
14325 | loadOrderGroup = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
14326 | break; | ||
14327 | case "Name": | ||
14328 | name = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
14329 | break; | ||
14330 | case "Password": | ||
14331 | password = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
14332 | break; | ||
14333 | case "Start": | ||
14334 | string startValue = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
14335 | if (0 < startValue.Length) | ||
14336 | { | ||
14337 | Wix.ServiceInstall.StartType start = Wix.ServiceInstall.ParseStartType(startValue); | ||
14338 | switch (start) | ||
14339 | { | ||
14340 | case Wix.ServiceInstall.StartType.auto: | ||
14341 | startType = MsiInterop.MsidbServiceInstallAutoStart; | ||
14342 | break; | ||
14343 | case Wix.ServiceInstall.StartType.demand: | ||
14344 | startType = MsiInterop.MsidbServiceInstallDemandStart; | ||
14345 | break; | ||
14346 | case Wix.ServiceInstall.StartType.disabled: | ||
14347 | startType = MsiInterop.MsidbServiceInstallDisabled; | ||
14348 | break; | ||
14349 | case Wix.ServiceInstall.StartType.boot: | ||
14350 | case Wix.ServiceInstall.StartType.system: | ||
14351 | this.core.OnMessage(WixErrors.ValueNotSupported(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, startValue)); | ||
14352 | break; | ||
14353 | default: | ||
14354 | this.core.OnMessage(WixErrors.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, startValue, "auto", "demand", "disabled")); | ||
14355 | break; | ||
14356 | } | ||
14357 | } | ||
14358 | break; | ||
14359 | case "Type": | ||
14360 | string typeValue = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
14361 | if (0 < typeValue.Length) | ||
14362 | { | ||
14363 | Wix.ServiceInstall.TypeType typeType = Wix.ServiceInstall.ParseTypeType(typeValue); | ||
14364 | switch (typeType) | ||
14365 | { | ||
14366 | case Wix.ServiceInstall.TypeType.ownProcess: | ||
14367 | typebits |= MsiInterop.MsidbServiceInstallOwnProcess; | ||
14368 | break; | ||
14369 | case Wix.ServiceInstall.TypeType.shareProcess: | ||
14370 | typebits |= MsiInterop.MsidbServiceInstallShareProcess; | ||
14371 | break; | ||
14372 | case Wix.ServiceInstall.TypeType.kernelDriver: | ||
14373 | case Wix.ServiceInstall.TypeType.systemDriver: | ||
14374 | this.core.OnMessage(WixErrors.ValueNotSupported(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, typeValue)); | ||
14375 | break; | ||
14376 | default: | ||
14377 | this.core.OnMessage(WixErrors.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, node.Name.LocalName, typeValue, "ownProcess", "shareProcess")); | ||
14378 | break; | ||
14379 | } | ||
14380 | } | ||
14381 | break; | ||
14382 | case "Vital": | ||
14383 | if (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
14384 | { | ||
14385 | errorbits |= MsiInterop.MsidbServiceInstallErrorControlVital; | ||
14386 | } | ||
14387 | break; | ||
14388 | default: | ||
14389 | this.core.UnexpectedAttribute(node, attrib); | ||
14390 | break; | ||
14391 | } | ||
14392 | } | ||
14393 | else | ||
14394 | { | ||
14395 | this.core.ParseExtensionAttribute(node, attrib); | ||
14396 | } | ||
14397 | } | ||
14398 | |||
14399 | if (String.IsNullOrEmpty(name)) | ||
14400 | { | ||
14401 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Name")); | ||
14402 | } | ||
14403 | else if (null == id) | ||
14404 | { | ||
14405 | id = this.core.CreateIdentifierFromFilename(name); | ||
14406 | } | ||
14407 | |||
14408 | if (0 == startType) | ||
14409 | { | ||
14410 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Start")); | ||
14411 | } | ||
14412 | |||
14413 | if (eraseDescription) | ||
14414 | { | ||
14415 | description = "[~]"; | ||
14416 | } | ||
14417 | |||
14418 | // get the ServiceInstall dependencies and config | ||
14419 | foreach (XElement child in node.Elements()) | ||
14420 | { | ||
14421 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
14422 | { | ||
14423 | switch (child.Name.LocalName) | ||
14424 | { | ||
14425 | case "PermissionEx": | ||
14426 | this.ParsePermissionExElement(child, id.Id, "ServiceInstall"); | ||
14427 | break; | ||
14428 | case "ServiceConfig": | ||
14429 | this.ParseServiceConfigElement(child, componentId, name); | ||
14430 | break; | ||
14431 | case "ServiceConfigFailureActions": | ||
14432 | this.ParseServiceConfigFailureActionsElement(child, componentId, name); | ||
14433 | break; | ||
14434 | case "ServiceDependency": | ||
14435 | dependencies = String.Concat(dependencies, this.ParseServiceDependencyElement(child), "[~]"); | ||
14436 | break; | ||
14437 | default: | ||
14438 | this.core.UnexpectedElement(node, child); | ||
14439 | break; | ||
14440 | } | ||
14441 | } | ||
14442 | else | ||
14443 | { | ||
14444 | Dictionary<string, string> context = new Dictionary<string, string>() { { "ServiceInstallId", id.Id }, { "ServiceInstallName", name }, { "ServiceInstallComponentId", componentId }, { "Win64", win64Component.ToString() } }; | ||
14445 | this.core.ParseExtensionElement(node, child, context); | ||
14446 | } | ||
14447 | } | ||
14448 | |||
14449 | if (null != dependencies) | ||
14450 | { | ||
14451 | dependencies = String.Concat(dependencies, "[~]"); | ||
14452 | } | ||
14453 | |||
14454 | if (!this.core.EncounteredError) | ||
14455 | { | ||
14456 | Row row = this.core.CreateRow(sourceLineNumbers, "ServiceInstall", id); | ||
14457 | row[1] = name; | ||
14458 | row[2] = displayName; | ||
14459 | row[3] = typebits; | ||
14460 | row[4] = startType; | ||
14461 | row[5] = errorbits; | ||
14462 | row[6] = loadOrderGroup; | ||
14463 | row[7] = dependencies; | ||
14464 | row[8] = account; | ||
14465 | row[9] = password; | ||
14466 | row[10] = arguments; | ||
14467 | row[11] = componentId; | ||
14468 | row[12] = description; | ||
14469 | } | ||
14470 | } | ||
14471 | |||
14472 | /// <summary> | ||
14473 | /// Parses a SetDirectory element. | ||
14474 | /// </summary> | ||
14475 | /// <param name="node">Element to parse.</param> | ||
14476 | private void ParseSetDirectoryElement(XElement node) | ||
14477 | { | ||
14478 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
14479 | string actionName = null; | ||
14480 | string id = null; | ||
14481 | string condition = null; | ||
14482 | string[] sequences = new string[] { "InstallUISequence", "InstallExecuteSequence" }; // default to "both" | ||
14483 | int extraBits = 0; | ||
14484 | string value = null; | ||
14485 | |||
14486 | foreach (XAttribute attrib in node.Attributes()) | ||
14487 | { | ||
14488 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
14489 | { | ||
14490 | switch (attrib.Name.LocalName) | ||
14491 | { | ||
14492 | case "Action": | ||
14493 | actionName = this.core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
14494 | break; | ||
14495 | case "Id": | ||
14496 | id = this.core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
14497 | this.core.CreateSimpleReference(sourceLineNumbers, "Directory", id); | ||
14498 | break; | ||
14499 | case "Sequence": | ||
14500 | string sequenceValue = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
14501 | if (0 < sequenceValue.Length) | ||
14502 | { | ||
14503 | Wix.SequenceType sequenceType = Wix.Enums.ParseSequenceType(sequenceValue); | ||
14504 | switch (sequenceType) | ||
14505 | { | ||
14506 | case Wix.SequenceType.execute: | ||
14507 | sequences = new string[] { "InstallExecuteSequence" }; | ||
14508 | break; | ||
14509 | case Wix.SequenceType.ui: | ||
14510 | sequences = new string[] { "InstallUISequence" }; | ||
14511 | break; | ||
14512 | case Wix.SequenceType.first: | ||
14513 | extraBits = MsiInterop.MsidbCustomActionTypeFirstSequence; | ||
14514 | // default puts it in both sequence which is what we want | ||
14515 | break; | ||
14516 | case Wix.SequenceType.both: | ||
14517 | // default so no work necessary. | ||
14518 | break; | ||
14519 | default: | ||
14520 | this.core.OnMessage(WixErrors.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, sequenceValue, "execute", "ui", "both")); | ||
14521 | break; | ||
14522 | } | ||
14523 | } | ||
14524 | break; | ||
14525 | case "Value": | ||
14526 | value = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
14527 | break; | ||
14528 | default: | ||
14529 | this.core.UnexpectedAttribute(node, attrib); | ||
14530 | break; | ||
14531 | } | ||
14532 | } | ||
14533 | else | ||
14534 | { | ||
14535 | this.core.ParseExtensionAttribute(node, attrib); | ||
14536 | } | ||
14537 | } | ||
14538 | |||
14539 | condition = this.core.GetConditionInnerText(node); | ||
14540 | |||
14541 | if (null == id) | ||
14542 | { | ||
14543 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
14544 | } | ||
14545 | else if (String.IsNullOrEmpty(actionName)) | ||
14546 | { | ||
14547 | actionName = String.Concat("Set", id); | ||
14548 | } | ||
14549 | |||
14550 | if (null == value) | ||
14551 | { | ||
14552 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Value")); | ||
14553 | } | ||
14554 | |||
14555 | this.core.ParseForExtensionElements(node); | ||
14556 | |||
14557 | // add the row and any references needed | ||
14558 | if (!this.core.EncounteredError) | ||
14559 | { | ||
14560 | Row row = this.core.CreateRow(sourceLineNumbers, "CustomAction"); | ||
14561 | row[0] = actionName; | ||
14562 | row[1] = MsiInterop.MsidbCustomActionTypeProperty | MsiInterop.MsidbCustomActionTypeTextData | extraBits; | ||
14563 | row[2] = id; | ||
14564 | row[3] = value; | ||
14565 | |||
14566 | foreach (string sequence in sequences) | ||
14567 | { | ||
14568 | Row sequenceRow = this.core.CreateRow(sourceLineNumbers, "WixAction"); | ||
14569 | sequenceRow[0] = sequence; | ||
14570 | sequenceRow[1] = actionName; | ||
14571 | sequenceRow[2] = condition; | ||
14572 | // no explicit sequence | ||
14573 | // no before action | ||
14574 | sequenceRow[5] = "CostInitialize"; | ||
14575 | sequenceRow[6] = 0; // not overridable | ||
14576 | } | ||
14577 | } | ||
14578 | } | ||
14579 | |||
14580 | /// <summary> | ||
14581 | /// Parses a SetProperty element. | ||
14582 | /// </summary> | ||
14583 | /// <param name="node">Element to parse.</param> | ||
14584 | private void ParseSetPropertyElement(XElement node) | ||
14585 | { | ||
14586 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
14587 | string actionName = null; | ||
14588 | string id = null; | ||
14589 | string afterAction = null; | ||
14590 | string beforeAction = null; | ||
14591 | string condition = null; | ||
14592 | string[] sequences = new string[] { "InstallUISequence", "InstallExecuteSequence" }; // default to "both" | ||
14593 | int extraBits = 0; | ||
14594 | string value = null; | ||
14595 | |||
14596 | foreach (XAttribute attrib in node.Attributes()) | ||
14597 | { | ||
14598 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
14599 | { | ||
14600 | switch (attrib.Name.LocalName) | ||
14601 | { | ||
14602 | case "Action": | ||
14603 | actionName = this.core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
14604 | break; | ||
14605 | case "Id": | ||
14606 | id = this.core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
14607 | break; | ||
14608 | case "After": | ||
14609 | afterAction = this.core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
14610 | break; | ||
14611 | case "Before": | ||
14612 | beforeAction = this.core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
14613 | break; | ||
14614 | case "Sequence": | ||
14615 | string sequenceValue = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
14616 | if (0 < sequenceValue.Length) | ||
14617 | { | ||
14618 | Wix.SequenceType sequenceType = Wix.Enums.ParseSequenceType(sequenceValue); | ||
14619 | switch (sequenceType) | ||
14620 | { | ||
14621 | case Wix.SequenceType.execute: | ||
14622 | sequences = new string[] { "InstallExecuteSequence" }; | ||
14623 | break; | ||
14624 | case Wix.SequenceType.ui: | ||
14625 | sequences = new string[] { "InstallUISequence" }; | ||
14626 | break; | ||
14627 | case Wix.SequenceType.first: | ||
14628 | extraBits = MsiInterop.MsidbCustomActionTypeFirstSequence; | ||
14629 | // default puts it in both sequence which is what we want | ||
14630 | break; | ||
14631 | case Wix.SequenceType.both: | ||
14632 | // default so no work necessary. | ||
14633 | break; | ||
14634 | default: | ||
14635 | this.core.OnMessage(WixErrors.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, sequenceValue, "execute", "ui", "both")); | ||
14636 | break; | ||
14637 | } | ||
14638 | } | ||
14639 | break; | ||
14640 | case "Value": | ||
14641 | value = this.core.GetAttributeValue(sourceLineNumbers, attrib, EmptyRule.CanBeEmpty); | ||
14642 | break; | ||
14643 | default: | ||
14644 | this.core.UnexpectedAttribute(node, attrib); | ||
14645 | break; | ||
14646 | } | ||
14647 | } | ||
14648 | else | ||
14649 | { | ||
14650 | this.core.ParseExtensionAttribute(node, attrib); | ||
14651 | } | ||
14652 | } | ||
14653 | |||
14654 | condition = this.core.GetConditionInnerText(node); | ||
14655 | |||
14656 | if (null == id) | ||
14657 | { | ||
14658 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
14659 | } | ||
14660 | else if (String.IsNullOrEmpty(actionName)) | ||
14661 | { | ||
14662 | actionName = String.Concat("Set", id); | ||
14663 | } | ||
14664 | |||
14665 | if (null == value) | ||
14666 | { | ||
14667 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Value")); | ||
14668 | } | ||
14669 | |||
14670 | if (null != beforeAction && null != afterAction) | ||
14671 | { | ||
14672 | this.core.OnMessage(WixErrors.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "After", "Before")); | ||
14673 | } | ||
14674 | else if (null == beforeAction && null == afterAction) | ||
14675 | { | ||
14676 | this.core.OnMessage(WixErrors.ExpectedAttributesWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "After", "Before", "Id")); | ||
14677 | } | ||
14678 | |||
14679 | this.core.ParseForExtensionElements(node); | ||
14680 | |||
14681 | // add the row and any references needed | ||
14682 | if (!this.core.EncounteredError) | ||
14683 | { | ||
14684 | // action that is scheduled to occur before/after itself | ||
14685 | if (beforeAction == actionName) | ||
14686 | { | ||
14687 | this.core.OnMessage(WixErrors.ActionScheduledRelativeToItself(sourceLineNumbers, node.Name.LocalName, "Before", beforeAction)); | ||
14688 | } | ||
14689 | else if (afterAction == actionName) | ||
14690 | { | ||
14691 | this.core.OnMessage(WixErrors.ActionScheduledRelativeToItself(sourceLineNumbers, node.Name.LocalName, "After", afterAction)); | ||
14692 | } | ||
14693 | |||
14694 | Row row = this.core.CreateRow(sourceLineNumbers, "CustomAction"); | ||
14695 | row[0] = actionName; | ||
14696 | row[1] = MsiInterop.MsidbCustomActionTypeProperty | MsiInterop.MsidbCustomActionTypeTextData | extraBits; | ||
14697 | row[2] = id; | ||
14698 | row[3] = value; | ||
14699 | |||
14700 | foreach (string sequence in sequences) | ||
14701 | { | ||
14702 | Row sequenceRow = this.core.CreateRow(sourceLineNumbers, "WixAction"); | ||
14703 | sequenceRow[0] = sequence; | ||
14704 | sequenceRow[1] = actionName; | ||
14705 | sequenceRow[2] = condition; | ||
14706 | // no explicit sequence | ||
14707 | sequenceRow[4] = beforeAction; | ||
14708 | sequenceRow[5] = afterAction; | ||
14709 | sequenceRow[6] = 0; // not overridable | ||
14710 | |||
14711 | if (null != beforeAction) | ||
14712 | { | ||
14713 | if (WindowsInstallerStandard.IsStandardAction(beforeAction)) | ||
14714 | { | ||
14715 | this.core.CreateSimpleReference(sourceLineNumbers, "WixAction", sequence, beforeAction); | ||
14716 | } | ||
14717 | else | ||
14718 | { | ||
14719 | this.core.CreateSimpleReference(sourceLineNumbers, "CustomAction", beforeAction); | ||
14720 | } | ||
14721 | } | ||
14722 | |||
14723 | if (null != afterAction) | ||
14724 | { | ||
14725 | if (WindowsInstallerStandard.IsStandardAction(afterAction)) | ||
14726 | { | ||
14727 | this.core.CreateSimpleReference(sourceLineNumbers, "WixAction", sequence, afterAction); | ||
14728 | } | ||
14729 | else | ||
14730 | { | ||
14731 | this.core.CreateSimpleReference(sourceLineNumbers, "CustomAction", afterAction); | ||
14732 | } | ||
14733 | } | ||
14734 | } | ||
14735 | } | ||
14736 | } | ||
14737 | |||
14738 | /// <summary> | ||
14739 | /// Parses a SFP catalog element. | ||
14740 | /// </summary> | ||
14741 | /// <param name="node">Element to parse.</param> | ||
14742 | /// <param name="parentSFPCatalog">Parent SFPCatalog.</param> | ||
14743 | private void ParseSFPFileElement(XElement node, string parentSFPCatalog) | ||
14744 | { | ||
14745 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
14746 | string id = null; | ||
14747 | |||
14748 | foreach (XAttribute attrib in node.Attributes()) | ||
14749 | { | ||
14750 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
14751 | { | ||
14752 | switch (attrib.Name.LocalName) | ||
14753 | { | ||
14754 | case "Id": | ||
14755 | id = this.core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
14756 | break; | ||
14757 | default: | ||
14758 | this.core.UnexpectedAttribute(node, attrib); | ||
14759 | break; | ||
14760 | } | ||
14761 | } | ||
14762 | else | ||
14763 | { | ||
14764 | this.core.ParseExtensionAttribute(node, attrib); | ||
14765 | } | ||
14766 | } | ||
14767 | |||
14768 | if (null == id) | ||
14769 | { | ||
14770 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
14771 | } | ||
14772 | |||
14773 | this.core.ParseForExtensionElements(node); | ||
14774 | |||
14775 | if (!this.core.EncounteredError) | ||
14776 | { | ||
14777 | Row row = this.core.CreateRow(sourceLineNumbers, "FileSFPCatalog"); | ||
14778 | row[0] = id; | ||
14779 | row[1] = parentSFPCatalog; | ||
14780 | } | ||
14781 | } | ||
14782 | |||
14783 | /// <summary> | ||
14784 | /// Parses a SFP catalog element. | ||
14785 | /// </summary> | ||
14786 | /// <param name="node">Element to parse.</param> | ||
14787 | /// <param name="parentSFPCatalog">Parent SFPCatalog.</param> | ||
14788 | private void ParseSFPCatalogElement(XElement node, ref string parentSFPCatalog) | ||
14789 | { | ||
14790 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
14791 | string parentName = null; | ||
14792 | string dependency = null; | ||
14793 | string name = null; | ||
14794 | string sourceFile = null; | ||
14795 | |||
14796 | foreach (XAttribute attrib in node.Attributes()) | ||
14797 | { | ||
14798 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
14799 | { | ||
14800 | switch (attrib.Name.LocalName) | ||
14801 | { | ||
14802 | case "Dependency": | ||
14803 | dependency = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
14804 | break; | ||
14805 | case "Name": | ||
14806 | name = this.core.GetAttributeShortFilename(sourceLineNumbers, attrib, false); | ||
14807 | parentSFPCatalog = name; | ||
14808 | break; | ||
14809 | case "SourceFile": | ||
14810 | sourceFile = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
14811 | break; | ||
14812 | default: | ||
14813 | this.core.UnexpectedAttribute(node, attrib); | ||
14814 | break; | ||
14815 | } | ||
14816 | } | ||
14817 | else | ||
14818 | { | ||
14819 | this.core.ParseExtensionAttribute(node, attrib); | ||
14820 | } | ||
14821 | } | ||
14822 | |||
14823 | if (null == name) | ||
14824 | { | ||
14825 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Name")); | ||
14826 | } | ||
14827 | |||
14828 | if (null == sourceFile) | ||
14829 | { | ||
14830 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "SourceFile")); | ||
14831 | } | ||
14832 | |||
14833 | foreach (XElement child in node.Elements()) | ||
14834 | { | ||
14835 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
14836 | { | ||
14837 | switch (child.Name.LocalName) | ||
14838 | { | ||
14839 | case "SFPCatalog": | ||
14840 | this.ParseSFPCatalogElement(child, ref parentName); | ||
14841 | if (null != dependency && parentName == dependency) | ||
14842 | { | ||
14843 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Dependency")); | ||
14844 | } | ||
14845 | dependency = parentName; | ||
14846 | break; | ||
14847 | case "SFPFile": | ||
14848 | this.ParseSFPFileElement(child, name); | ||
14849 | break; | ||
14850 | default: | ||
14851 | this.core.UnexpectedElement(node, child); | ||
14852 | break; | ||
14853 | } | ||
14854 | } | ||
14855 | else | ||
14856 | { | ||
14857 | this.core.ParseExtensionElement(node, child); | ||
14858 | } | ||
14859 | } | ||
14860 | |||
14861 | if (null == dependency) | ||
14862 | { | ||
14863 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Dependency")); | ||
14864 | } | ||
14865 | |||
14866 | if (!this.core.EncounteredError) | ||
14867 | { | ||
14868 | Row row = this.core.CreateRow(sourceLineNumbers, "SFPCatalog"); | ||
14869 | row[0] = name; | ||
14870 | row[1] = sourceFile; | ||
14871 | row[2] = dependency; | ||
14872 | } | ||
14873 | } | ||
14874 | |||
14875 | /// <summary> | ||
14876 | /// Parses a shortcut element. | ||
14877 | /// </summary> | ||
14878 | /// <param name="node">Element to parse.</param> | ||
14879 | /// <param name="componentId">Identifer for parent component.</param> | ||
14880 | /// <param name="parentElementLocalName">Local name of parent element.</param> | ||
14881 | /// <param name="defaultTarget">Default identifier of parent (which is usually the target).</param> | ||
14882 | /// <param name="parentKeyPath">Flag to indicate whether the parent element is the keypath of a component or not (will only be true for file parent elements).</param> | ||
14883 | private void ParseShortcutElement(XElement node, string componentId, string parentElementLocalName, string defaultTarget, YesNoType parentKeyPath) | ||
14884 | { | ||
14885 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
14886 | Identifier id = null; | ||
14887 | bool advertise = false; | ||
14888 | string arguments = null; | ||
14889 | string description = null; | ||
14890 | string descriptionResourceDll = null; | ||
14891 | int descriptionResourceId = CompilerConstants.IntegerNotSet; | ||
14892 | string directory = null; | ||
14893 | string displayResourceDll = null; | ||
14894 | int displayResourceId = CompilerConstants.IntegerNotSet; | ||
14895 | int hotkey = CompilerConstants.IntegerNotSet; | ||
14896 | string icon = null; | ||
14897 | int iconIndex = CompilerConstants.IntegerNotSet; | ||
14898 | string name = null; | ||
14899 | string shortName = null; | ||
14900 | int show = CompilerConstants.IntegerNotSet; | ||
14901 | string target = null; | ||
14902 | string workingDirectory = null; | ||
14903 | |||
14904 | foreach (XAttribute attrib in node.Attributes()) | ||
14905 | { | ||
14906 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
14907 | { | ||
14908 | switch (attrib.Name.LocalName) | ||
14909 | { | ||
14910 | case "Id": | ||
14911 | id = this.core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
14912 | break; | ||
14913 | case "Advertise": | ||
14914 | advertise = YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
14915 | break; | ||
14916 | case "Arguments": | ||
14917 | arguments = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
14918 | break; | ||
14919 | case "Description": | ||
14920 | description = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
14921 | break; | ||
14922 | case "DescriptionResourceDll": | ||
14923 | descriptionResourceDll = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
14924 | break; | ||
14925 | case "DescriptionResourceId": | ||
14926 | descriptionResourceId = this.core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, short.MaxValue); | ||
14927 | break; | ||
14928 | case "Directory": | ||
14929 | directory = this.core.CreateDirectoryReferenceFromInlineSyntax(sourceLineNumbers, attrib, null); | ||
14930 | break; | ||
14931 | case "DisplayResourceDll": | ||
14932 | displayResourceDll = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
14933 | break; | ||
14934 | case "DisplayResourceId": | ||
14935 | displayResourceId = this.core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, short.MaxValue); | ||
14936 | break; | ||
14937 | case "Hotkey": | ||
14938 | hotkey = this.core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, short.MaxValue); | ||
14939 | break; | ||
14940 | case "Icon": | ||
14941 | icon = this.core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
14942 | this.core.CreateSimpleReference(sourceLineNumbers, "Icon", icon); | ||
14943 | break; | ||
14944 | case "IconIndex": | ||
14945 | iconIndex = this.core.GetAttributeIntegerValue(sourceLineNumbers, attrib, short.MinValue + 1, short.MaxValue); | ||
14946 | break; | ||
14947 | case "Name": | ||
14948 | name = this.core.GetAttributeLongFilename(sourceLineNumbers, attrib, false); | ||
14949 | break; | ||
14950 | case "ShortName": | ||
14951 | shortName = this.core.GetAttributeShortFilename(sourceLineNumbers, attrib, false); | ||
14952 | break; | ||
14953 | case "Show": | ||
14954 | string showValue = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
14955 | if (showValue.Length == 0) | ||
14956 | { | ||
14957 | show = CompilerConstants.IllegalInteger; | ||
14958 | } | ||
14959 | else | ||
14960 | { | ||
14961 | Wix.Shortcut.ShowType showType = Wix.Shortcut.ParseShowType(showValue); | ||
14962 | switch (showType) | ||
14963 | { | ||
14964 | case Wix.Shortcut.ShowType.normal: | ||
14965 | show = 1; | ||
14966 | break; | ||
14967 | case Wix.Shortcut.ShowType.maximized: | ||
14968 | show = 3; | ||
14969 | break; | ||
14970 | case Wix.Shortcut.ShowType.minimized: | ||
14971 | show = 7; | ||
14972 | break; | ||
14973 | default: | ||
14974 | this.core.OnMessage(WixErrors.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, "Show", showValue, "normal", "maximized", "minimized")); | ||
14975 | show = CompilerConstants.IllegalInteger; | ||
14976 | break; | ||
14977 | } | ||
14978 | } | ||
14979 | break; | ||
14980 | case "Target": | ||
14981 | target = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
14982 | break; | ||
14983 | case "WorkingDirectory": | ||
14984 | workingDirectory = this.core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
14985 | break; | ||
14986 | default: | ||
14987 | this.core.UnexpectedAttribute(node, attrib); | ||
14988 | break; | ||
14989 | } | ||
14990 | } | ||
14991 | else | ||
14992 | { | ||
14993 | this.core.ParseExtensionAttribute(node, attrib); | ||
14994 | } | ||
14995 | } | ||
14996 | |||
14997 | if (advertise && null != target) | ||
14998 | { | ||
14999 | this.core.OnMessage(WixErrors.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Target", "Advertise", "yes")); | ||
15000 | } | ||
15001 | |||
15002 | if (null == directory) | ||
15003 | { | ||
15004 | if ("Component" == parentElementLocalName) | ||
15005 | { | ||
15006 | directory = defaultTarget; | ||
15007 | } | ||
15008 | else | ||
15009 | { | ||
15010 | this.core.OnMessage(WixErrors.ExpectedAttributeWhenElementNotUnderElement(sourceLineNumbers, node.Name.LocalName, "Directory", "Component")); | ||
15011 | } | ||
15012 | } | ||
15013 | |||
15014 | if (null != descriptionResourceDll) | ||
15015 | { | ||
15016 | if (CompilerConstants.IntegerNotSet == descriptionResourceId) | ||
15017 | { | ||
15018 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "DescriptionResourceDll", "DescriptionResourceId")); | ||
15019 | } | ||
15020 | } | ||
15021 | else | ||
15022 | { | ||
15023 | if (CompilerConstants.IntegerNotSet != descriptionResourceId) | ||
15024 | { | ||
15025 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "DescriptionResourceId", "DescriptionResourceDll")); | ||
15026 | } | ||
15027 | } | ||
15028 | |||
15029 | if (null != displayResourceDll) | ||
15030 | { | ||
15031 | if (CompilerConstants.IntegerNotSet == displayResourceId) | ||
15032 | { | ||
15033 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "DisplayResourceDll", "DisplayResourceId")); | ||
15034 | } | ||
15035 | } | ||
15036 | else | ||
15037 | { | ||
15038 | if (CompilerConstants.IntegerNotSet != displayResourceId) | ||
15039 | { | ||
15040 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "DisplayResourceId", "DisplayResourceDll")); | ||
15041 | } | ||
15042 | } | ||
15043 | |||
15044 | if (null == name) | ||
15045 | { | ||
15046 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Name")); | ||
15047 | } | ||
15048 | else if (0 < name.Length) | ||
15049 | { | ||
15050 | if (this.core.IsValidShortFilename(name, false)) | ||
15051 | { | ||
15052 | if (null == shortName) | ||
15053 | { | ||
15054 | shortName = name; | ||
15055 | name = null; | ||
15056 | } | ||
15057 | else | ||
15058 | { | ||
15059 | this.core.OnMessage(WixErrors.IllegalAttributeValueWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Name", name, "ShortName")); | ||
15060 | } | ||
15061 | } | ||
15062 | else if (null == shortName) // generate a short file name. | ||
15063 | { | ||
15064 | shortName = this.core.CreateShortName(name, true, false, node.Name.LocalName, componentId, directory); | ||
15065 | } | ||
15066 | } | ||
15067 | |||
15068 | if ("Component" != parentElementLocalName && null != target) | ||
15069 | { | ||
15070 | this.core.OnMessage(WixErrors.IllegalAttributeWhenNested(sourceLineNumbers, node.Name.LocalName, "Target", parentElementLocalName)); | ||
15071 | } | ||
15072 | |||
15073 | if (null == id) | ||
15074 | { | ||
15075 | id = this.core.CreateIdentifier("sct", directory, LowercaseOrNull(name) ?? LowercaseOrNull(shortName)); | ||
15076 | } | ||
15077 | |||
15078 | foreach (XElement child in node.Elements()) | ||
15079 | { | ||
15080 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
15081 | { | ||
15082 | switch (child.Name.LocalName) | ||
15083 | { | ||
15084 | case "Icon": | ||
15085 | icon = this.ParseIconElement(child); | ||
15086 | break; | ||
15087 | case "ShortcutProperty": | ||
15088 | this.ParseShortcutPropertyElement(child, id.Id); | ||
15089 | break; | ||
15090 | default: | ||
15091 | this.core.UnexpectedElement(node, child); | ||
15092 | break; | ||
15093 | } | ||
15094 | } | ||
15095 | else | ||
15096 | { | ||
15097 | this.core.ParseExtensionElement(node, child); | ||
15098 | } | ||
15099 | } | ||
15100 | |||
15101 | if (!this.core.EncounteredError) | ||
15102 | { | ||
15103 | Row row = this.core.CreateRow(sourceLineNumbers, "Shortcut", id); | ||
15104 | row[1] = directory; | ||
15105 | row[2] = GetMsiFilenameValue(shortName, name); | ||
15106 | row[3] = componentId; | ||
15107 | if (advertise) | ||
15108 | { | ||
15109 | if (YesNoType.Yes != parentKeyPath && "Component" != parentElementLocalName) | ||
15110 | { | ||
15111 | this.core.OnMessage(WixWarnings.UnclearShortcut(sourceLineNumbers, id.Id, componentId, defaultTarget)); | ||
15112 | } | ||
15113 | row[4] = Guid.Empty.ToString("B"); | ||
15114 | } | ||
15115 | else if (null != target) | ||
15116 | { | ||
15117 | row[4] = target; | ||
15118 | } | ||
15119 | else if ("Component" == parentElementLocalName || "CreateFolder" == parentElementLocalName) | ||
15120 | { | ||
15121 | row[4] = String.Format(CultureInfo.InvariantCulture, "[{0}]", defaultTarget); | ||
15122 | } | ||
15123 | else if ("File" == parentElementLocalName) | ||
15124 | { | ||
15125 | row[4] = String.Format(CultureInfo.InvariantCulture, "[#{0}]", defaultTarget); | ||
15126 | } | ||
15127 | row[5] = arguments; | ||
15128 | row[6] = description; | ||
15129 | if (CompilerConstants.IntegerNotSet != hotkey) | ||
15130 | { | ||
15131 | row[7] = hotkey; | ||
15132 | } | ||
15133 | row[8] = icon; | ||
15134 | if (CompilerConstants.IntegerNotSet != iconIndex) | ||
15135 | { | ||
15136 | row[9] = iconIndex; | ||
15137 | } | ||
15138 | |||
15139 | if (CompilerConstants.IntegerNotSet != show) | ||
15140 | { | ||
15141 | row[10] = show; | ||
15142 | } | ||
15143 | row[11] = workingDirectory; | ||
15144 | row[12] = displayResourceDll; | ||
15145 | if (CompilerConstants.IntegerNotSet != displayResourceId) | ||
15146 | { | ||
15147 | row[13] = displayResourceId; | ||
15148 | } | ||
15149 | row[14] = descriptionResourceDll; | ||
15150 | if (CompilerConstants.IntegerNotSet != descriptionResourceId) | ||
15151 | { | ||
15152 | row[15] = descriptionResourceId; | ||
15153 | } | ||
15154 | } | ||
15155 | } | ||
15156 | |||
15157 | /// <summary> | ||
15158 | /// Parses a shortcut property element. | ||
15159 | /// </summary> | ||
15160 | /// <param name="node">Element to parse.</param> | ||
15161 | private void ParseShortcutPropertyElement(XElement node, string shortcutId) | ||
15162 | { | ||
15163 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
15164 | Identifier id = null; | ||
15165 | string key = null; | ||
15166 | string value = null; | ||
15167 | |||
15168 | foreach (XAttribute attrib in node.Attributes()) | ||
15169 | { | ||
15170 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
15171 | { | ||
15172 | switch (attrib.Name.LocalName) | ||
15173 | { | ||
15174 | case "Id": | ||
15175 | id = this.core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
15176 | break; | ||
15177 | case "Key": | ||
15178 | key = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
15179 | break; | ||
15180 | case "Value": | ||
15181 | value = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
15182 | break; | ||
15183 | default: | ||
15184 | this.core.UnexpectedAttribute(node, attrib); | ||
15185 | break; | ||
15186 | } | ||
15187 | } | ||
15188 | else | ||
15189 | { | ||
15190 | this.core.ParseExtensionAttribute(node, attrib); | ||
15191 | } | ||
15192 | } | ||
15193 | |||
15194 | if (String.IsNullOrEmpty(key)) | ||
15195 | { | ||
15196 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Key")); | ||
15197 | } | ||
15198 | else if (null == id) | ||
15199 | { | ||
15200 | id = this.core.CreateIdentifier("scp", shortcutId, key.ToUpperInvariant()); | ||
15201 | } | ||
15202 | |||
15203 | string innerText = this.core.GetTrimmedInnerText(node); | ||
15204 | if (!String.IsNullOrEmpty(innerText)) | ||
15205 | { | ||
15206 | if (String.IsNullOrEmpty(value)) | ||
15207 | { | ||
15208 | value = innerText; | ||
15209 | } | ||
15210 | else // cannot specify both the value attribute and inner text | ||
15211 | { | ||
15212 | this.core.OnMessage(WixErrors.IllegalAttributeWithInnerText(sourceLineNumbers, node.Name.LocalName, "Value")); | ||
15213 | } | ||
15214 | } | ||
15215 | |||
15216 | if (String.IsNullOrEmpty(value)) | ||
15217 | { | ||
15218 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Value")); | ||
15219 | } | ||
15220 | |||
15221 | this.core.ParseForExtensionElements(node); | ||
15222 | |||
15223 | if (!this.core.EncounteredError) | ||
15224 | { | ||
15225 | Row row = this.core.CreateRow(sourceLineNumbers, "MsiShortcutProperty", id); | ||
15226 | row[1] = shortcutId; | ||
15227 | row[2] = key; | ||
15228 | row[3] = value; | ||
15229 | } | ||
15230 | } | ||
15231 | |||
15232 | /// <summary> | ||
15233 | /// Parses a typelib element. | ||
15234 | /// </summary> | ||
15235 | /// <param name="node">Element to parse.</param> | ||
15236 | /// <param name="componentId">Identifier of parent component.</param> | ||
15237 | /// <param name="fileServer">Identifier of file that acts as typelib server.</param> | ||
15238 | /// <param name="win64Component">true if the component is 64-bit.</param> | ||
15239 | private void ParseTypeLibElement(XElement node, string componentId, string fileServer, bool win64Component) | ||
15240 | { | ||
15241 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
15242 | string id = null; | ||
15243 | YesNoType advertise = YesNoType.NotSet; | ||
15244 | int cost = CompilerConstants.IntegerNotSet; | ||
15245 | string description = null; | ||
15246 | int flags = 0; | ||
15247 | string helpDirectory = null; | ||
15248 | int language = CompilerConstants.IntegerNotSet; | ||
15249 | int majorVersion = CompilerConstants.IntegerNotSet; | ||
15250 | int minorVersion = CompilerConstants.IntegerNotSet; | ||
15251 | long resourceId = CompilerConstants.LongNotSet; | ||
15252 | |||
15253 | foreach (XAttribute attrib in node.Attributes()) | ||
15254 | { | ||
15255 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
15256 | { | ||
15257 | switch (attrib.Name.LocalName) | ||
15258 | { | ||
15259 | case "Id": | ||
15260 | id = this.core.GetAttributeGuidValue(sourceLineNumbers, attrib, false); | ||
15261 | break; | ||
15262 | case "Advertise": | ||
15263 | advertise = this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
15264 | break; | ||
15265 | case "Control": | ||
15266 | if (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
15267 | { | ||
15268 | flags |= 2; | ||
15269 | } | ||
15270 | break; | ||
15271 | case "Cost": | ||
15272 | cost = this.core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, int.MaxValue); | ||
15273 | break; | ||
15274 | case "Description": | ||
15275 | description = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
15276 | break; | ||
15277 | case "HasDiskImage": | ||
15278 | if (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
15279 | { | ||
15280 | flags |= 8; | ||
15281 | } | ||
15282 | break; | ||
15283 | case "HelpDirectory": | ||
15284 | helpDirectory = this.core.CreateDirectoryReferenceFromInlineSyntax(sourceLineNumbers, attrib, null); | ||
15285 | break; | ||
15286 | case "Hidden": | ||
15287 | if (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
15288 | { | ||
15289 | flags |= 4; | ||
15290 | } | ||
15291 | break; | ||
15292 | case "Language": | ||
15293 | language = this.core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, short.MaxValue); | ||
15294 | break; | ||
15295 | case "MajorVersion": | ||
15296 | majorVersion = this.core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, ushort.MaxValue); | ||
15297 | break; | ||
15298 | case "MinorVersion": | ||
15299 | minorVersion = this.core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, byte.MaxValue); | ||
15300 | break; | ||
15301 | case "ResourceId": | ||
15302 | resourceId = this.core.GetAttributeLongValue(sourceLineNumbers, attrib, int.MinValue, int.MaxValue); | ||
15303 | break; | ||
15304 | case "Restricted": | ||
15305 | if (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
15306 | { | ||
15307 | flags |= 1; | ||
15308 | } | ||
15309 | break; | ||
15310 | default: | ||
15311 | this.core.UnexpectedAttribute(node, attrib); | ||
15312 | break; | ||
15313 | } | ||
15314 | } | ||
15315 | else | ||
15316 | { | ||
15317 | this.core.ParseExtensionAttribute(node, attrib); | ||
15318 | } | ||
15319 | } | ||
15320 | |||
15321 | if (null == id) | ||
15322 | { | ||
15323 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
15324 | } | ||
15325 | |||
15326 | if (CompilerConstants.IntegerNotSet == language) | ||
15327 | { | ||
15328 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Language")); | ||
15329 | language = CompilerConstants.IllegalInteger; | ||
15330 | } | ||
15331 | |||
15332 | // build up the typelib version string for the registry if the major or minor version was specified | ||
15333 | string registryVersion = null; | ||
15334 | if (CompilerConstants.IntegerNotSet != majorVersion || CompilerConstants.IntegerNotSet != minorVersion) | ||
15335 | { | ||
15336 | if (CompilerConstants.IntegerNotSet != majorVersion) | ||
15337 | { | ||
15338 | registryVersion = majorVersion.ToString("x", CultureInfo.InvariantCulture.NumberFormat); | ||
15339 | } | ||
15340 | else | ||
15341 | { | ||
15342 | registryVersion = "0"; | ||
15343 | } | ||
15344 | |||
15345 | if (CompilerConstants.IntegerNotSet != minorVersion) | ||
15346 | { | ||
15347 | registryVersion = String.Concat(registryVersion, ".", minorVersion.ToString("x", CultureInfo.InvariantCulture.NumberFormat)); | ||
15348 | } | ||
15349 | else | ||
15350 | { | ||
15351 | registryVersion = String.Concat(registryVersion, ".0"); | ||
15352 | } | ||
15353 | } | ||
15354 | |||
15355 | // if the advertise state has not been set, default to non-advertised | ||
15356 | if (YesNoType.NotSet == advertise) | ||
15357 | { | ||
15358 | advertise = YesNoType.No; | ||
15359 | } | ||
15360 | |||
15361 | foreach (XElement child in node.Elements()) | ||
15362 | { | ||
15363 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
15364 | { | ||
15365 | switch (child.Name.LocalName) | ||
15366 | { | ||
15367 | case "AppId": | ||
15368 | this.ParseAppIdElement(child, componentId, YesNoType.NotSet, fileServer, id, registryVersion); | ||
15369 | break; | ||
15370 | case "Class": | ||
15371 | this.ParseClassElement(child, componentId, YesNoType.NotSet, fileServer, id, registryVersion, null); | ||
15372 | break; | ||
15373 | case "Interface": | ||
15374 | this.ParseInterfaceElement(child, componentId, null, null, id, registryVersion); | ||
15375 | break; | ||
15376 | default: | ||
15377 | this.core.UnexpectedElement(node, child); | ||
15378 | break; | ||
15379 | } | ||
15380 | } | ||
15381 | else | ||
15382 | { | ||
15383 | this.core.ParseExtensionElement(node, child); | ||
15384 | } | ||
15385 | } | ||
15386 | |||
15387 | |||
15388 | if (YesNoType.Yes == advertise) | ||
15389 | { | ||
15390 | if (CompilerConstants.LongNotSet != resourceId) | ||
15391 | { | ||
15392 | this.core.OnMessage(WixErrors.IllegalAttributeWhenAdvertised(sourceLineNumbers, node.Name.LocalName, "ResourceId")); | ||
15393 | } | ||
15394 | |||
15395 | if (0 != flags) | ||
15396 | { | ||
15397 | if (0x1 == (flags & 0x1)) | ||
15398 | { | ||
15399 | this.core.OnMessage(WixErrors.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Restricted", "Advertise", "yes")); | ||
15400 | } | ||
15401 | |||
15402 | if (0x2 == (flags & 0x2)) | ||
15403 | { | ||
15404 | this.core.OnMessage(WixErrors.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Control", "Advertise", "yes")); | ||
15405 | } | ||
15406 | |||
15407 | if (0x4 == (flags & 0x4)) | ||
15408 | { | ||
15409 | this.core.OnMessage(WixErrors.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Hidden", "Advertise", "yes")); | ||
15410 | } | ||
15411 | |||
15412 | if (0x8 == (flags & 0x8)) | ||
15413 | { | ||
15414 | this.core.OnMessage(WixErrors.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "HasDiskImage", "Advertise", "yes")); | ||
15415 | } | ||
15416 | } | ||
15417 | |||
15418 | if (!this.core.EncounteredError) | ||
15419 | { | ||
15420 | Row row = this.core.CreateRow(sourceLineNumbers, "TypeLib"); | ||
15421 | row[0] = id; | ||
15422 | row[1] = language; | ||
15423 | row[2] = componentId; | ||
15424 | if (CompilerConstants.IntegerNotSet != majorVersion || CompilerConstants.IntegerNotSet != minorVersion) | ||
15425 | { | ||
15426 | row[3] = (CompilerConstants.IntegerNotSet != majorVersion ? majorVersion * 256 : 0) + (CompilerConstants.IntegerNotSet != minorVersion ? minorVersion : 0); | ||
15427 | } | ||
15428 | row[4] = description; | ||
15429 | row[5] = helpDirectory; | ||
15430 | row[6] = Guid.Empty.ToString("B"); | ||
15431 | if (CompilerConstants.IntegerNotSet != cost) | ||
15432 | { | ||
15433 | row[7] = cost; | ||
15434 | } | ||
15435 | } | ||
15436 | } | ||
15437 | else if (YesNoType.No == advertise) | ||
15438 | { | ||
15439 | if (CompilerConstants.IntegerNotSet != cost && CompilerConstants.IllegalInteger != cost) | ||
15440 | { | ||
15441 | this.core.OnMessage(WixErrors.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Cost", "Advertise", "no")); | ||
15442 | } | ||
15443 | |||
15444 | if (null == fileServer) | ||
15445 | { | ||
15446 | this.core.OnMessage(WixErrors.MissingTypeLibFile(sourceLineNumbers, node.Name.LocalName, "File")); | ||
15447 | } | ||
15448 | |||
15449 | if (null == registryVersion) | ||
15450 | { | ||
15451 | this.core.OnMessage(WixErrors.ExpectedAttributesWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "MajorVersion", "MinorVersion", "Advertise", "no")); | ||
15452 | } | ||
15453 | |||
15454 | // HKCR\TypeLib\[ID]\[MajorVersion].[MinorVersion], (Default) = [Description] | ||
15455 | this.core.CreateRegistryRow(sourceLineNumbers, MsiInterop.MsidbRegistryRootClassesRoot, String.Format(CultureInfo.InvariantCulture, @"TypeLib\{0}\{1}", id, registryVersion), null, description, componentId); | ||
15456 | |||
15457 | // HKCR\TypeLib\[ID]\[MajorVersion].[MinorVersion]\[Language]\[win16|win32|win64], (Default) = [TypeLibPath]\[ResourceId] | ||
15458 | string path = String.Concat("[#", fileServer, "]"); | ||
15459 | if (CompilerConstants.LongNotSet != resourceId) | ||
15460 | { | ||
15461 | path = String.Concat(path, Path.DirectorySeparatorChar, resourceId.ToString(CultureInfo.InvariantCulture.NumberFormat)); | ||
15462 | } | ||
15463 | this.core.CreateRegistryRow(sourceLineNumbers, MsiInterop.MsidbRegistryRootClassesRoot, String.Format(CultureInfo.InvariantCulture, @"TypeLib\{0}\{1}\{2}\{3}", id, registryVersion, language, (win64Component ? "win64" : "win32")), null, path, componentId); | ||
15464 | |||
15465 | // HKCR\TypeLib\[ID]\[MajorVersion].[MinorVersion]\FLAGS, (Default) = [TypeLibFlags] | ||
15466 | this.core.CreateRegistryRow(sourceLineNumbers, MsiInterop.MsidbRegistryRootClassesRoot, String.Format(CultureInfo.InvariantCulture, @"TypeLib\{0}\{1}\FLAGS", id, registryVersion), null, flags.ToString(CultureInfo.InvariantCulture.NumberFormat), componentId); | ||
15467 | |||
15468 | if (null != helpDirectory) | ||
15469 | { | ||
15470 | // HKCR\TypeLib\[ID]\[MajorVersion].[MinorVersion]\HELPDIR, (Default) = [HelpDirectory] | ||
15471 | this.core.CreateRegistryRow(sourceLineNumbers, MsiInterop.MsidbRegistryRootClassesRoot, String.Format(CultureInfo.InvariantCulture, @"TypeLib\{0}\{1}\HELPDIR", id, registryVersion), null, String.Concat("[", helpDirectory, "]"), componentId); | ||
15472 | } | ||
15473 | } | ||
15474 | } | ||
15475 | |||
15476 | /// <summary> | ||
15477 | /// Parses an EmbeddedChaniner element. | ||
15478 | /// </summary> | ||
15479 | /// <param name="node">Element to parse.</param> | ||
15480 | private void ParseEmbeddedChainerElement(XElement node) | ||
15481 | { | ||
15482 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
15483 | Identifier id = null; | ||
15484 | string commandLine = null; | ||
15485 | string condition = null; | ||
15486 | string source = null; | ||
15487 | int type = 0; | ||
15488 | |||
15489 | foreach (XAttribute attrib in node.Attributes()) | ||
15490 | { | ||
15491 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
15492 | { | ||
15493 | switch (attrib.Name.LocalName) | ||
15494 | { | ||
15495 | case "Id": | ||
15496 | id = this.core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
15497 | break; | ||
15498 | case "BinarySource": | ||
15499 | if (null != source) | ||
15500 | { | ||
15501 | this.core.OnMessage(WixErrors.IllegalAttributeWithOtherAttributes(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, "FileSource", "PropertySource")); | ||
15502 | } | ||
15503 | source = this.core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
15504 | type = MsiInterop.MsidbCustomActionTypeExe + MsiInterop.MsidbCustomActionTypeBinaryData; | ||
15505 | this.core.CreateSimpleReference(sourceLineNumbers, "Binary", source); // add a reference to the appropriate Binary | ||
15506 | break; | ||
15507 | case "CommandLine": | ||
15508 | commandLine = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
15509 | break; | ||
15510 | case "FileSource": | ||
15511 | if (null != source) | ||
15512 | { | ||
15513 | this.core.OnMessage(WixErrors.IllegalAttributeWithOtherAttributes(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, "BinarySource", "PropertySource")); | ||
15514 | } | ||
15515 | source = this.core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
15516 | type = MsiInterop.MsidbCustomActionTypeExe + MsiInterop.MsidbCustomActionTypeSourceFile; | ||
15517 | this.core.CreateSimpleReference(sourceLineNumbers, "File", source); // add a reference to the appropriate File | ||
15518 | break; | ||
15519 | case "PropertySource": | ||
15520 | if (null != source) | ||
15521 | { | ||
15522 | this.core.OnMessage(WixErrors.IllegalAttributeWithOtherAttributes(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, "BinarySource", "FileSource")); | ||
15523 | } | ||
15524 | source = this.core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
15525 | type = MsiInterop.MsidbCustomActionTypeExe + MsiInterop.MsidbCustomActionTypeProperty; | ||
15526 | // cannot add a reference to a Property because it may be created at runtime. | ||
15527 | break; | ||
15528 | default: | ||
15529 | this.core.UnexpectedAttribute(node, attrib); | ||
15530 | break; | ||
15531 | } | ||
15532 | } | ||
15533 | else | ||
15534 | { | ||
15535 | this.core.ParseExtensionAttribute(node, attrib); | ||
15536 | } | ||
15537 | } | ||
15538 | |||
15539 | // Get the condition from the inner text of the element. | ||
15540 | condition = this.core.GetConditionInnerText(node); | ||
15541 | |||
15542 | if (null == id) | ||
15543 | { | ||
15544 | id = this.core.CreateIdentifier("mec", source, type.ToString()); | ||
15545 | } | ||
15546 | |||
15547 | if (null == source) | ||
15548 | { | ||
15549 | this.core.OnMessage(WixErrors.ExpectedAttributes(sourceLineNumbers, node.Name.LocalName, "BinarySource", "FileSource", "PropertySource")); | ||
15550 | } | ||
15551 | |||
15552 | if (!this.core.EncounteredError) | ||
15553 | { | ||
15554 | Row row = this.core.CreateRow(sourceLineNumbers, "MsiEmbeddedChainer", id); | ||
15555 | row[1] = condition; | ||
15556 | row[2] = commandLine; | ||
15557 | row[3] = source; | ||
15558 | row[4] = type; | ||
15559 | } | ||
15560 | } | ||
15561 | |||
15562 | /// <summary> | ||
15563 | /// Parses UI elements. | ||
15564 | /// </summary> | ||
15565 | /// <param name="node">Element to parse.</param> | ||
15566 | private void ParseUIElement(XElement node) | ||
15567 | { | ||
15568 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
15569 | Identifier id = null; | ||
15570 | int embeddedUICount = 0; | ||
15571 | |||
15572 | foreach (XAttribute attrib in node.Attributes()) | ||
15573 | { | ||
15574 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
15575 | { | ||
15576 | switch (attrib.Name.LocalName) | ||
15577 | { | ||
15578 | case "Id": | ||
15579 | id = this.core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
15580 | break; | ||
15581 | default: | ||
15582 | this.core.UnexpectedAttribute(node, attrib); | ||
15583 | break; | ||
15584 | } | ||
15585 | } | ||
15586 | else | ||
15587 | { | ||
15588 | this.core.ParseExtensionAttribute(node, attrib); | ||
15589 | } | ||
15590 | } | ||
15591 | |||
15592 | foreach (XElement child in node.Elements()) | ||
15593 | { | ||
15594 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
15595 | { | ||
15596 | switch (child.Name.LocalName) | ||
15597 | { | ||
15598 | case "BillboardAction": | ||
15599 | this.ParseBillboardActionElement(child); | ||
15600 | break; | ||
15601 | case "ComboBox": | ||
15602 | this.ParseControlGroupElement(child, this.tableDefinitions["ComboBox"], "ListItem"); | ||
15603 | break; | ||
15604 | case "Dialog": | ||
15605 | this.ParseDialogElement(child); | ||
15606 | break; | ||
15607 | case "DialogRef": | ||
15608 | this.ParseSimpleRefElement(child, "Dialog"); | ||
15609 | break; | ||
15610 | case "EmbeddedUI": | ||
15611 | if (0 < embeddedUICount) // there can be only one embedded UI | ||
15612 | { | ||
15613 | SourceLineNumber childSourceLineNumbers = Preprocessor.GetSourceLineNumbers(child); | ||
15614 | this.core.OnMessage(WixErrors.TooManyChildren(childSourceLineNumbers, node.Name.LocalName, child.Name.LocalName)); | ||
15615 | } | ||
15616 | this.ParseEmbeddedUIElement(child); | ||
15617 | ++embeddedUICount; | ||
15618 | break; | ||
15619 | case "Error": | ||
15620 | this.ParseErrorElement(child); | ||
15621 | break; | ||
15622 | case "ListBox": | ||
15623 | this.ParseControlGroupElement(child, this.tableDefinitions["ListBox"], "ListItem"); | ||
15624 | break; | ||
15625 | case "ListView": | ||
15626 | this.ParseControlGroupElement(child, this.tableDefinitions["ListView"], "ListItem"); | ||
15627 | break; | ||
15628 | case "ProgressText": | ||
15629 | this.ParseActionTextElement(child); | ||
15630 | break; | ||
15631 | case "Publish": | ||
15632 | int order = 0; | ||
15633 | this.ParsePublishElement(child, null, null, ref order); | ||
15634 | break; | ||
15635 | case "RadioButtonGroup": | ||
15636 | RadioButtonType radioButtonType = this.ParseRadioButtonGroupElement(child, null, RadioButtonType.NotSet); | ||
15637 | if (RadioButtonType.Bitmap == radioButtonType || RadioButtonType.Icon == radioButtonType) | ||
15638 | { | ||
15639 | SourceLineNumber childSourceLineNumbers = Preprocessor.GetSourceLineNumbers(child); | ||
15640 | this.core.OnMessage(WixErrors.RadioButtonBitmapAndIconDisallowed(childSourceLineNumbers)); | ||
15641 | } | ||
15642 | break; | ||
15643 | case "TextStyle": | ||
15644 | this.ParseTextStyleElement(child); | ||
15645 | break; | ||
15646 | case "UIText": | ||
15647 | this.ParseUITextElement(child); | ||
15648 | break; | ||
15649 | |||
15650 | // the following are available indentically under the UI and Product elements for document organization use only | ||
15651 | case "AdminUISequence": | ||
15652 | case "InstallUISequence": | ||
15653 | this.ParseSequenceElement(child, child.Name.LocalName); | ||
15654 | break; | ||
15655 | case "Binary": | ||
15656 | this.ParseBinaryElement(child); | ||
15657 | break; | ||
15658 | case "Property": | ||
15659 | this.ParsePropertyElement(child); | ||
15660 | break; | ||
15661 | case "PropertyRef": | ||
15662 | this.ParseSimpleRefElement(child, "Property"); | ||
15663 | break; | ||
15664 | case "UIRef": | ||
15665 | this.ParseSimpleRefElement(child, "WixUI"); | ||
15666 | break; | ||
15667 | |||
15668 | default: | ||
15669 | this.core.UnexpectedElement(node, child); | ||
15670 | break; | ||
15671 | } | ||
15672 | } | ||
15673 | else | ||
15674 | { | ||
15675 | this.core.ParseExtensionElement(node, child); | ||
15676 | } | ||
15677 | } | ||
15678 | |||
15679 | if (null != id && !this.core.EncounteredError) | ||
15680 | { | ||
15681 | this.core.CreateRow(sourceLineNumbers, "WixUI", id); | ||
15682 | } | ||
15683 | } | ||
15684 | |||
15685 | /// <summary> | ||
15686 | /// Parses a list item element. | ||
15687 | /// </summary> | ||
15688 | /// <param name="node">Element to parse.</param> | ||
15689 | /// <param name="table">Table to add row to.</param> | ||
15690 | /// <param name="property">Identifier of property referred to by list item.</param> | ||
15691 | /// <param name="order">Relative order of list items.</param> | ||
15692 | private void ParseListItemElement(XElement node, TableDefinition table, string property, ref int order) | ||
15693 | { | ||
15694 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
15695 | string icon = null; | ||
15696 | string text = null; | ||
15697 | string value = null; | ||
15698 | |||
15699 | foreach (XAttribute attrib in node.Attributes()) | ||
15700 | { | ||
15701 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
15702 | { | ||
15703 | switch (attrib.Name.LocalName) | ||
15704 | { | ||
15705 | case "Icon": | ||
15706 | if ("ListView" == table.Name) | ||
15707 | { | ||
15708 | icon = this.core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
15709 | this.core.CreateSimpleReference(sourceLineNumbers, "Binary", icon); | ||
15710 | } | ||
15711 | else | ||
15712 | { | ||
15713 | this.core.OnMessage(WixErrors.IllegalAttributeExceptOnElement(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, "ListView")); | ||
15714 | } | ||
15715 | break; | ||
15716 | case "Text": | ||
15717 | text = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
15718 | break; | ||
15719 | case "Value": | ||
15720 | value = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
15721 | break; | ||
15722 | default: | ||
15723 | this.core.UnexpectedAttribute(node, attrib); | ||
15724 | break; | ||
15725 | } | ||
15726 | } | ||
15727 | else | ||
15728 | { | ||
15729 | this.core.ParseExtensionAttribute(node, attrib); | ||
15730 | } | ||
15731 | } | ||
15732 | |||
15733 | if (null == value) | ||
15734 | { | ||
15735 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Value")); | ||
15736 | } | ||
15737 | |||
15738 | this.core.ParseForExtensionElements(node); | ||
15739 | |||
15740 | if (!this.core.EncounteredError) | ||
15741 | { | ||
15742 | Row row = this.core.CreateRow(sourceLineNumbers, table.Name); | ||
15743 | row[0] = property; | ||
15744 | row[1] = ++order; | ||
15745 | row[2] = value; | ||
15746 | row[3] = text; | ||
15747 | if (null != icon) | ||
15748 | { | ||
15749 | row[4] = icon; | ||
15750 | } | ||
15751 | } | ||
15752 | } | ||
15753 | |||
15754 | /// <summary> | ||
15755 | /// Parses a radio button element. | ||
15756 | /// </summary> | ||
15757 | /// <param name="node">Element to parse.</param> | ||
15758 | /// <param name="property">Identifier of property referred to by radio button.</param> | ||
15759 | /// <param name="order">Relative order of radio buttons.</param> | ||
15760 | /// <returns>Type of this radio button.</returns> | ||
15761 | private RadioButtonType ParseRadioButtonElement(XElement node, string property, ref int order) | ||
15762 | { | ||
15763 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
15764 | RadioButtonType type = RadioButtonType.NotSet; | ||
15765 | string value = null; | ||
15766 | string x = null; | ||
15767 | string y = null; | ||
15768 | string width = null; | ||
15769 | string height = null; | ||
15770 | string text = null; | ||
15771 | string tooltip = null; | ||
15772 | string help = null; | ||
15773 | |||
15774 | foreach (XAttribute attrib in node.Attributes()) | ||
15775 | { | ||
15776 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
15777 | { | ||
15778 | switch (attrib.Name.LocalName) | ||
15779 | { | ||
15780 | case "Bitmap": | ||
15781 | if (RadioButtonType.NotSet != type) | ||
15782 | { | ||
15783 | this.core.OnMessage(WixErrors.IllegalAttributeWithOtherAttributes(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, "Icon", "Text")); | ||
15784 | } | ||
15785 | text = this.core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
15786 | this.core.CreateSimpleReference(sourceLineNumbers, "Binary", text); | ||
15787 | type = RadioButtonType.Bitmap; | ||
15788 | break; | ||
15789 | case "Height": | ||
15790 | height = this.core.GetAttributeLocalizableIntegerValue(sourceLineNumbers, attrib, 0, short.MaxValue); | ||
15791 | break; | ||
15792 | case "Help": | ||
15793 | help = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
15794 | break; | ||
15795 | case "Icon": | ||
15796 | if (RadioButtonType.NotSet != type) | ||
15797 | { | ||
15798 | this.core.OnMessage(WixErrors.IllegalAttributeWithOtherAttributes(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, "Bitmap", "Text")); | ||
15799 | } | ||
15800 | text = this.core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
15801 | this.core.CreateSimpleReference(sourceLineNumbers, "Binary", text); | ||
15802 | type = RadioButtonType.Icon; | ||
15803 | break; | ||
15804 | case "Text": | ||
15805 | if (RadioButtonType.NotSet != type) | ||
15806 | { | ||
15807 | this.core.OnMessage(WixErrors.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, "Bitmap", "Icon")); | ||
15808 | } | ||
15809 | text = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
15810 | type = RadioButtonType.Text; | ||
15811 | break; | ||
15812 | case "ToolTip": | ||
15813 | tooltip = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
15814 | break; | ||
15815 | case "Value": | ||
15816 | value = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
15817 | break; | ||
15818 | case "Width": | ||
15819 | width = this.core.GetAttributeLocalizableIntegerValue(sourceLineNumbers, attrib, 0, short.MaxValue); | ||
15820 | break; | ||
15821 | case "X": | ||
15822 | x = this.core.GetAttributeLocalizableIntegerValue(sourceLineNumbers, attrib, 0, short.MaxValue); | ||
15823 | break; | ||
15824 | case "Y": | ||
15825 | y = this.core.GetAttributeLocalizableIntegerValue(sourceLineNumbers, attrib, 0, short.MaxValue); | ||
15826 | break; | ||
15827 | default: | ||
15828 | this.core.UnexpectedAttribute(node, attrib); | ||
15829 | break; | ||
15830 | } | ||
15831 | } | ||
15832 | else | ||
15833 | { | ||
15834 | this.core.ParseExtensionAttribute(node, attrib); | ||
15835 | } | ||
15836 | } | ||
15837 | |||
15838 | if (null == value) | ||
15839 | { | ||
15840 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Value")); | ||
15841 | } | ||
15842 | |||
15843 | if (null == x) | ||
15844 | { | ||
15845 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "X")); | ||
15846 | } | ||
15847 | |||
15848 | if (null == y) | ||
15849 | { | ||
15850 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Y")); | ||
15851 | } | ||
15852 | |||
15853 | if (null == width) | ||
15854 | { | ||
15855 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Width")); | ||
15856 | } | ||
15857 | |||
15858 | if (null == height) | ||
15859 | { | ||
15860 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Height")); | ||
15861 | } | ||
15862 | |||
15863 | this.core.ParseForExtensionElements(node); | ||
15864 | |||
15865 | if (!this.core.EncounteredError) | ||
15866 | { | ||
15867 | Row row = this.core.CreateRow(sourceLineNumbers, "RadioButton"); | ||
15868 | row[0] = property; | ||
15869 | row[1] = ++order; | ||
15870 | row[2] = value; | ||
15871 | row[3] = x; | ||
15872 | row[4] = y; | ||
15873 | row[5] = width; | ||
15874 | row[6] = height; | ||
15875 | row[7] = text; | ||
15876 | if (null != tooltip || null != help) | ||
15877 | { | ||
15878 | row[8] = String.Concat(tooltip, "|", help); | ||
15879 | } | ||
15880 | } | ||
15881 | |||
15882 | return type; | ||
15883 | } | ||
15884 | |||
15885 | /// <summary> | ||
15886 | /// Parses a billboard element. | ||
15887 | /// </summary> | ||
15888 | /// <param name="node">Element to parse.</param> | ||
15889 | private void ParseBillboardActionElement(XElement node) | ||
15890 | { | ||
15891 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
15892 | string action = null; | ||
15893 | int order = 0; | ||
15894 | |||
15895 | foreach (XAttribute attrib in node.Attributes()) | ||
15896 | { | ||
15897 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
15898 | { | ||
15899 | switch (attrib.Name.LocalName) | ||
15900 | { | ||
15901 | case "Id": | ||
15902 | action = this.core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
15903 | this.core.CreateSimpleReference(sourceLineNumbers, "WixAction", "InstallExecuteSequence", action); | ||
15904 | break; | ||
15905 | default: | ||
15906 | this.core.UnexpectedAttribute(node, attrib); | ||
15907 | break; | ||
15908 | } | ||
15909 | } | ||
15910 | else | ||
15911 | { | ||
15912 | this.core.ParseExtensionAttribute(node, attrib); | ||
15913 | } | ||
15914 | } | ||
15915 | |||
15916 | if (null == action) | ||
15917 | { | ||
15918 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
15919 | } | ||
15920 | |||
15921 | foreach (XElement child in node.Elements()) | ||
15922 | { | ||
15923 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
15924 | { | ||
15925 | switch (child.Name.LocalName) | ||
15926 | { | ||
15927 | case "Billboard": | ||
15928 | order = order + 1; | ||
15929 | this.ParseBillboardElement(child, action, order); | ||
15930 | break; | ||
15931 | default: | ||
15932 | this.core.UnexpectedElement(node, child); | ||
15933 | break; | ||
15934 | } | ||
15935 | } | ||
15936 | else | ||
15937 | { | ||
15938 | this.core.ParseExtensionElement(node, child); | ||
15939 | } | ||
15940 | } | ||
15941 | } | ||
15942 | |||
15943 | /// <summary> | ||
15944 | /// Parses a billboard element. | ||
15945 | /// </summary> | ||
15946 | /// <param name="node">Element to parse.</param> | ||
15947 | /// <param name="action">Action for the billboard.</param> | ||
15948 | /// <param name="order">Order of the billboard.</param> | ||
15949 | private void ParseBillboardElement(XElement node, string action, int order) | ||
15950 | { | ||
15951 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
15952 | Identifier id = null; | ||
15953 | string feature = null; | ||
15954 | |||
15955 | foreach (XAttribute attrib in node.Attributes()) | ||
15956 | { | ||
15957 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
15958 | { | ||
15959 | switch (attrib.Name.LocalName) | ||
15960 | { | ||
15961 | case "Id": | ||
15962 | id = this.core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
15963 | break; | ||
15964 | case "Feature": | ||
15965 | feature = this.core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
15966 | this.core.CreateSimpleReference(sourceLineNumbers, "Feature", feature); | ||
15967 | break; | ||
15968 | default: | ||
15969 | this.core.UnexpectedAttribute(node, attrib); | ||
15970 | break; | ||
15971 | } | ||
15972 | } | ||
15973 | else | ||
15974 | { | ||
15975 | this.core.ParseExtensionAttribute(node, attrib); | ||
15976 | } | ||
15977 | } | ||
15978 | |||
15979 | if (null == id) | ||
15980 | { | ||
15981 | id = this.core.CreateIdentifier("bil", action, order.ToString(), feature); | ||
15982 | } | ||
15983 | |||
15984 | foreach (XElement child in node.Elements()) | ||
15985 | { | ||
15986 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
15987 | { | ||
15988 | switch (child.Name.LocalName) | ||
15989 | { | ||
15990 | case "Control": | ||
15991 | // These are all thrown away. | ||
15992 | Row lastTabRow = null; | ||
15993 | string firstControl = null; | ||
15994 | string defaultControl = null; | ||
15995 | string cancelControl = null; | ||
15996 | |||
15997 | this.ParseControlElement(child, id.Id, this.tableDefinitions["BBControl"], ref lastTabRow, ref firstControl, ref defaultControl, ref cancelControl, false); | ||
15998 | break; | ||
15999 | default: | ||
16000 | this.core.UnexpectedElement(node, child); | ||
16001 | break; | ||
16002 | } | ||
16003 | } | ||
16004 | else | ||
16005 | { | ||
16006 | this.core.ParseExtensionElement(node, child); | ||
16007 | } | ||
16008 | } | ||
16009 | |||
16010 | |||
16011 | if (!this.core.EncounteredError) | ||
16012 | { | ||
16013 | Row row = this.core.CreateRow(sourceLineNumbers, "Billboard", id); | ||
16014 | row[1] = feature; | ||
16015 | row[2] = action; | ||
16016 | row[3] = order; | ||
16017 | } | ||
16018 | } | ||
16019 | |||
16020 | /// <summary> | ||
16021 | /// Parses a control group element. | ||
16022 | /// </summary> | ||
16023 | /// <param name="node">Element to parse.</param> | ||
16024 | /// <param name="table">Table referred to by control group.</param> | ||
16025 | /// <param name="childTag">Expected child elements.</param> | ||
16026 | private void ParseControlGroupElement(XElement node, TableDefinition table, string childTag) | ||
16027 | { | ||
16028 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
16029 | int order = 0; | ||
16030 | string property = null; | ||
16031 | |||
16032 | foreach (XAttribute attrib in node.Attributes()) | ||
16033 | { | ||
16034 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
16035 | { | ||
16036 | switch (attrib.Name.LocalName) | ||
16037 | { | ||
16038 | case "Property": | ||
16039 | property = this.core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
16040 | break; | ||
16041 | default: | ||
16042 | this.core.UnexpectedAttribute(node, attrib); | ||
16043 | break; | ||
16044 | } | ||
16045 | } | ||
16046 | else | ||
16047 | { | ||
16048 | this.core.ParseExtensionAttribute(node, attrib); | ||
16049 | } | ||
16050 | } | ||
16051 | |||
16052 | if (null == property) | ||
16053 | { | ||
16054 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Property")); | ||
16055 | } | ||
16056 | |||
16057 | foreach (XElement child in node.Elements()) | ||
16058 | { | ||
16059 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
16060 | { | ||
16061 | if (childTag != child.Name.LocalName) | ||
16062 | { | ||
16063 | this.core.UnexpectedElement(node, child); | ||
16064 | } | ||
16065 | |||
16066 | switch (child.Name.LocalName) | ||
16067 | { | ||
16068 | case "ListItem": | ||
16069 | this.ParseListItemElement(child, table, property, ref order); | ||
16070 | break; | ||
16071 | case "Property": | ||
16072 | this.ParsePropertyElement(child); | ||
16073 | break; | ||
16074 | default: | ||
16075 | this.core.UnexpectedElement(node, child); | ||
16076 | break; | ||
16077 | } | ||
16078 | } | ||
16079 | else | ||
16080 | { | ||
16081 | this.core.ParseExtensionElement(node, child); | ||
16082 | } | ||
16083 | } | ||
16084 | |||
16085 | } | ||
16086 | |||
16087 | /// <summary> | ||
16088 | /// Parses a radio button control group element. | ||
16089 | /// </summary> | ||
16090 | /// <param name="node">Element to parse.</param> | ||
16091 | /// <param name="property">Property associated with this radio button group.</param> | ||
16092 | /// <param name="groupType">Specifies the current type of radio buttons in the group.</param> | ||
16093 | /// <returns>The current type of radio buttons in the group.</returns> | ||
16094 | private RadioButtonType ParseRadioButtonGroupElement(XElement node, string property, RadioButtonType groupType) | ||
16095 | { | ||
16096 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
16097 | int order = 0; | ||
16098 | |||
16099 | foreach (XAttribute attrib in node.Attributes()) | ||
16100 | { | ||
16101 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
16102 | { | ||
16103 | switch (attrib.Name.LocalName) | ||
16104 | { | ||
16105 | case "Property": | ||
16106 | property = this.core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
16107 | this.core.CreateSimpleReference(sourceLineNumbers, "Property", property); | ||
16108 | break; | ||
16109 | default: | ||
16110 | this.core.UnexpectedAttribute(node, attrib); | ||
16111 | break; | ||
16112 | } | ||
16113 | } | ||
16114 | else | ||
16115 | { | ||
16116 | this.core.ParseExtensionAttribute(node, attrib); | ||
16117 | } | ||
16118 | } | ||
16119 | |||
16120 | if (null == property) | ||
16121 | { | ||
16122 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Property")); | ||
16123 | } | ||
16124 | |||
16125 | foreach (XElement child in node.Elements()) | ||
16126 | { | ||
16127 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
16128 | { | ||
16129 | switch (child.Name.LocalName) | ||
16130 | { | ||
16131 | case "RadioButton": | ||
16132 | RadioButtonType type = this.ParseRadioButtonElement(child, property, ref order); | ||
16133 | if (RadioButtonType.NotSet == groupType) | ||
16134 | { | ||
16135 | groupType = type; | ||
16136 | } | ||
16137 | else if (groupType != type) | ||
16138 | { | ||
16139 | SourceLineNumber childSourceLineNumbers = Preprocessor.GetSourceLineNumbers(child); | ||
16140 | this.core.OnMessage(WixErrors.RadioButtonTypeInconsistent(childSourceLineNumbers)); | ||
16141 | } | ||
16142 | break; | ||
16143 | default: | ||
16144 | this.core.UnexpectedElement(node, child); | ||
16145 | break; | ||
16146 | } | ||
16147 | } | ||
16148 | else | ||
16149 | { | ||
16150 | this.core.ParseExtensionElement(node, child); | ||
16151 | } | ||
16152 | } | ||
16153 | |||
16154 | |||
16155 | return groupType; | ||
16156 | } | ||
16157 | |||
16158 | /// <summary> | ||
16159 | /// Parses an action text element. | ||
16160 | /// </summary> | ||
16161 | /// <param name="node">Element to parse.</param> | ||
16162 | private void ParseActionTextElement(XElement node) | ||
16163 | { | ||
16164 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
16165 | string action = null; | ||
16166 | string template = null; | ||
16167 | |||
16168 | foreach (XAttribute attrib in node.Attributes()) | ||
16169 | { | ||
16170 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
16171 | { | ||
16172 | switch (attrib.Name.LocalName) | ||
16173 | { | ||
16174 | case "Action": | ||
16175 | action = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
16176 | break; | ||
16177 | case "Template": | ||
16178 | template = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
16179 | break; | ||
16180 | default: | ||
16181 | this.core.UnexpectedAttribute(node, attrib); | ||
16182 | break; | ||
16183 | } | ||
16184 | } | ||
16185 | else | ||
16186 | { | ||
16187 | this.core.ParseExtensionAttribute(node, attrib); | ||
16188 | } | ||
16189 | } | ||
16190 | |||
16191 | if (null == action) | ||
16192 | { | ||
16193 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Action")); | ||
16194 | } | ||
16195 | |||
16196 | this.core.ParseForExtensionElements(node); | ||
16197 | |||
16198 | if (!this.core.EncounteredError) | ||
16199 | { | ||
16200 | Row row = this.core.CreateRow(sourceLineNumbers, "ActionText"); | ||
16201 | row[0] = action; | ||
16202 | row[1] = Common.GetInnerText(node); | ||
16203 | row[2] = template; | ||
16204 | } | ||
16205 | } | ||
16206 | |||
16207 | /// <summary> | ||
16208 | /// Parses an ui text element. | ||
16209 | /// </summary> | ||
16210 | /// <param name="node">Element to parse.</param> | ||
16211 | private void ParseUITextElement(XElement node) | ||
16212 | { | ||
16213 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
16214 | Identifier id = null; | ||
16215 | string text = null; | ||
16216 | |||
16217 | foreach (XAttribute attrib in node.Attributes()) | ||
16218 | { | ||
16219 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
16220 | { | ||
16221 | switch (attrib.Name.LocalName) | ||
16222 | { | ||
16223 | case "Id": | ||
16224 | id = this.core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
16225 | break; | ||
16226 | default: | ||
16227 | this.core.UnexpectedAttribute(node, attrib); | ||
16228 | break; | ||
16229 | } | ||
16230 | } | ||
16231 | else | ||
16232 | { | ||
16233 | this.core.ParseExtensionAttribute(node, attrib); | ||
16234 | } | ||
16235 | } | ||
16236 | |||
16237 | text = Common.GetInnerText(node); | ||
16238 | |||
16239 | if (null == id) | ||
16240 | { | ||
16241 | id = this.core.CreateIdentifier("txt", text); | ||
16242 | } | ||
16243 | |||
16244 | this.core.ParseForExtensionElements(node); | ||
16245 | |||
16246 | if (!this.core.EncounteredError) | ||
16247 | { | ||
16248 | Row row = this.core.CreateRow(sourceLineNumbers, "UIText", id); | ||
16249 | row[1] = text; | ||
16250 | } | ||
16251 | } | ||
16252 | |||
16253 | /// <summary> | ||
16254 | /// Parses a text style element. | ||
16255 | /// </summary> | ||
16256 | /// <param name="node">Element to parse.</param> | ||
16257 | private void ParseTextStyleElement(XElement node) | ||
16258 | { | ||
16259 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
16260 | Identifier id = null; | ||
16261 | int bits = 0; | ||
16262 | int color = CompilerConstants.IntegerNotSet; | ||
16263 | string faceName = null; | ||
16264 | string size = "0"; | ||
16265 | |||
16266 | foreach (XAttribute attrib in node.Attributes()) | ||
16267 | { | ||
16268 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
16269 | { | ||
16270 | switch (attrib.Name.LocalName) | ||
16271 | { | ||
16272 | case "Id": | ||
16273 | id = this.core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
16274 | break; | ||
16275 | |||
16276 | // RGB Values | ||
16277 | case "Red": | ||
16278 | int redColor = this.core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, byte.MaxValue); | ||
16279 | if (CompilerConstants.IllegalInteger != redColor) | ||
16280 | { | ||
16281 | if (CompilerConstants.IntegerNotSet == color) | ||
16282 | { | ||
16283 | color = redColor; | ||
16284 | } | ||
16285 | else | ||
16286 | { | ||
16287 | color += redColor; | ||
16288 | } | ||
16289 | } | ||
16290 | break; | ||
16291 | case "Green": | ||
16292 | int greenColor = this.core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, byte.MaxValue); | ||
16293 | if (CompilerConstants.IllegalInteger != greenColor) | ||
16294 | { | ||
16295 | if (CompilerConstants.IntegerNotSet == color) | ||
16296 | { | ||
16297 | color = greenColor * 256; | ||
16298 | } | ||
16299 | else | ||
16300 | { | ||
16301 | color += greenColor * 256; | ||
16302 | } | ||
16303 | } | ||
16304 | break; | ||
16305 | case "Blue": | ||
16306 | int blueColor = this.core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, byte.MaxValue); | ||
16307 | if (CompilerConstants.IllegalInteger != blueColor) | ||
16308 | { | ||
16309 | if (CompilerConstants.IntegerNotSet == color) | ||
16310 | { | ||
16311 | color = blueColor * 65536; | ||
16312 | } | ||
16313 | else | ||
16314 | { | ||
16315 | color += blueColor * 65536; | ||
16316 | } | ||
16317 | } | ||
16318 | break; | ||
16319 | |||
16320 | // Style values | ||
16321 | case "Bold": | ||
16322 | if (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
16323 | { | ||
16324 | bits |= MsiInterop.MsidbTextStyleStyleBitsBold; | ||
16325 | } | ||
16326 | break; | ||
16327 | case "Italic": | ||
16328 | if (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
16329 | { | ||
16330 | bits |= MsiInterop.MsidbTextStyleStyleBitsItalic; | ||
16331 | } | ||
16332 | break; | ||
16333 | case "Strike": | ||
16334 | if (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
16335 | { | ||
16336 | bits |= MsiInterop.MsidbTextStyleStyleBitsStrike; | ||
16337 | } | ||
16338 | break; | ||
16339 | case "Underline": | ||
16340 | if (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
16341 | { | ||
16342 | bits |= MsiInterop.MsidbTextStyleStyleBitsUnderline; | ||
16343 | } | ||
16344 | break; | ||
16345 | |||
16346 | // Font values | ||
16347 | case "FaceName": | ||
16348 | faceName = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
16349 | break; | ||
16350 | case "Size": | ||
16351 | size = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
16352 | break; | ||
16353 | |||
16354 | default: | ||
16355 | this.core.UnexpectedAttribute(node, attrib); | ||
16356 | break; | ||
16357 | } | ||
16358 | } | ||
16359 | else | ||
16360 | { | ||
16361 | this.core.ParseExtensionAttribute(node, attrib); | ||
16362 | } | ||
16363 | } | ||
16364 | |||
16365 | if (null == id) | ||
16366 | { | ||
16367 | this.core.CreateIdentifier("txs", faceName, size.ToString(), color.ToString(), bits.ToString()); | ||
16368 | } | ||
16369 | |||
16370 | if (null == faceName) | ||
16371 | { | ||
16372 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "FaceName")); | ||
16373 | } | ||
16374 | |||
16375 | this.core.ParseForExtensionElements(node); | ||
16376 | |||
16377 | if (!this.core.EncounteredError) | ||
16378 | { | ||
16379 | Row row = this.core.CreateRow(sourceLineNumbers, "TextStyle", id); | ||
16380 | row[1] = faceName; | ||
16381 | row[2] = size; | ||
16382 | if (0 <= color) | ||
16383 | { | ||
16384 | row[3] = color; | ||
16385 | } | ||
16386 | |||
16387 | if (0 < bits) | ||
16388 | { | ||
16389 | row[4] = bits; | ||
16390 | } | ||
16391 | } | ||
16392 | } | ||
16393 | |||
16394 | /// <summary> | ||
16395 | /// Parses a dialog element. | ||
16396 | /// </summary> | ||
16397 | /// <param name="node">Element to parse.</param> | ||
16398 | private void ParseDialogElement(XElement node) | ||
16399 | { | ||
16400 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
16401 | Identifier id = null; | ||
16402 | int bits = MsiInterop.MsidbDialogAttributesVisible | MsiInterop.MsidbDialogAttributesModal | MsiInterop.MsidbDialogAttributesMinimize; | ||
16403 | int height = 0; | ||
16404 | string title = null; | ||
16405 | bool trackDiskSpace = false; | ||
16406 | int width = 0; | ||
16407 | int x = 50; | ||
16408 | int y = 50; | ||
16409 | |||
16410 | foreach (XAttribute attrib in node.Attributes()) | ||
16411 | { | ||
16412 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
16413 | { | ||
16414 | switch (attrib.Name.LocalName) | ||
16415 | { | ||
16416 | case "Id": | ||
16417 | id = this.core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
16418 | break; | ||
16419 | case "Height": | ||
16420 | height = this.core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, short.MaxValue); | ||
16421 | break; | ||
16422 | case "Title": | ||
16423 | title = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
16424 | break; | ||
16425 | case "Width": | ||
16426 | width = this.core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, short.MaxValue); | ||
16427 | break; | ||
16428 | case "X": | ||
16429 | x = this.core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, 100); | ||
16430 | break; | ||
16431 | case "Y": | ||
16432 | y = this.core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, 100); | ||
16433 | break; | ||
16434 | |||
16435 | case "CustomPalette": | ||
16436 | if (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
16437 | { | ||
16438 | bits ^= MsiInterop.MsidbDialogAttributesUseCustomPalette; | ||
16439 | } | ||
16440 | break; | ||
16441 | case "ErrorDialog": | ||
16442 | if (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
16443 | { | ||
16444 | bits ^= MsiInterop.MsidbDialogAttributesError; | ||
16445 | } | ||
16446 | break; | ||
16447 | case "Hidden": | ||
16448 | if (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
16449 | { | ||
16450 | bits ^= MsiInterop.MsidbDialogAttributesVisible; | ||
16451 | } | ||
16452 | break; | ||
16453 | case "KeepModeless": | ||
16454 | if (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
16455 | { | ||
16456 | bits ^= MsiInterop.MsidbDialogAttributesKeepModeless; | ||
16457 | } | ||
16458 | break; | ||
16459 | case "LeftScroll": | ||
16460 | if (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
16461 | { | ||
16462 | bits ^= MsiInterop.MsidbDialogAttributesLeftScroll; | ||
16463 | } | ||
16464 | break; | ||
16465 | case "Modeless": | ||
16466 | if (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
16467 | { | ||
16468 | bits ^= MsiInterop.MsidbDialogAttributesModal; | ||
16469 | } | ||
16470 | break; | ||
16471 | case "NoMinimize": | ||
16472 | if (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
16473 | { | ||
16474 | bits ^= MsiInterop.MsidbDialogAttributesMinimize; | ||
16475 | } | ||
16476 | break; | ||
16477 | case "RightAligned": | ||
16478 | if (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
16479 | { | ||
16480 | bits ^= MsiInterop.MsidbDialogAttributesRightAligned; | ||
16481 | } | ||
16482 | break; | ||
16483 | case "RightToLeft": | ||
16484 | if (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
16485 | { | ||
16486 | bits ^= MsiInterop.MsidbDialogAttributesRTLRO; | ||
16487 | } | ||
16488 | break; | ||
16489 | case "SystemModal": | ||
16490 | if (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
16491 | { | ||
16492 | bits ^= MsiInterop.MsidbDialogAttributesSysModal; | ||
16493 | } | ||
16494 | break; | ||
16495 | case "TrackDiskSpace": | ||
16496 | if (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
16497 | { | ||
16498 | bits ^= MsiInterop.MsidbDialogAttributesTrackDiskSpace; | ||
16499 | trackDiskSpace = true; | ||
16500 | } | ||
16501 | break; | ||
16502 | |||
16503 | default: | ||
16504 | this.core.UnexpectedAttribute(node, attrib); | ||
16505 | break; | ||
16506 | } | ||
16507 | } | ||
16508 | else | ||
16509 | { | ||
16510 | this.core.ParseExtensionAttribute(node, attrib); | ||
16511 | } | ||
16512 | } | ||
16513 | |||
16514 | if (null == id) | ||
16515 | { | ||
16516 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
16517 | id = Identifier.Invalid; | ||
16518 | } | ||
16519 | |||
16520 | Row lastTabRow = null; | ||
16521 | string cancelControl = null; | ||
16522 | string defaultControl = null; | ||
16523 | string firstControl = null; | ||
16524 | |||
16525 | foreach (XElement child in node.Elements()) | ||
16526 | { | ||
16527 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
16528 | { | ||
16529 | switch (child.Name.LocalName) | ||
16530 | { | ||
16531 | case "Control": | ||
16532 | this.ParseControlElement(child, id.Id, this.tableDefinitions["Control"], ref lastTabRow, ref firstControl, ref defaultControl, ref cancelControl, trackDiskSpace); | ||
16533 | break; | ||
16534 | default: | ||
16535 | this.core.UnexpectedElement(node, child); | ||
16536 | break; | ||
16537 | } | ||
16538 | } | ||
16539 | else | ||
16540 | { | ||
16541 | this.core.ParseExtensionElement(node, child); | ||
16542 | } | ||
16543 | } | ||
16544 | |||
16545 | |||
16546 | if (null != lastTabRow && null != lastTabRow[1]) | ||
16547 | { | ||
16548 | if (firstControl != lastTabRow[1].ToString()) | ||
16549 | { | ||
16550 | lastTabRow[10] = firstControl; | ||
16551 | } | ||
16552 | } | ||
16553 | |||
16554 | if (null == firstControl) | ||
16555 | { | ||
16556 | this.core.OnMessage(WixErrors.NoFirstControlSpecified(sourceLineNumbers, id.Id)); | ||
16557 | } | ||
16558 | |||
16559 | if (!this.core.EncounteredError) | ||
16560 | { | ||
16561 | Row row = this.core.CreateRow(sourceLineNumbers, "Dialog", id); | ||
16562 | row[1] = x; | ||
16563 | row[2] = y; | ||
16564 | row[3] = width; | ||
16565 | row[4] = height; | ||
16566 | row[5] = bits; | ||
16567 | row[6] = title; | ||
16568 | row[7] = firstControl; | ||
16569 | row[8] = defaultControl; | ||
16570 | row[9] = cancelControl; | ||
16571 | } | ||
16572 | } | ||
16573 | |||
16574 | /// <summary> | ||
16575 | /// Parses an EmbeddedUI element. | ||
16576 | /// </summary> | ||
16577 | /// <param name="node">Element to parse.</param> | ||
16578 | private void ParseEmbeddedUIElement(XElement node) | ||
16579 | { | ||
16580 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
16581 | Identifier id = null; | ||
16582 | string name = null; | ||
16583 | int attributes = MsiInterop.MsidbEmbeddedUI; // by default this is the primary DLL that does not support basic UI. | ||
16584 | int messageFilter = MsiInterop.INSTALLLOGMODE_FATALEXIT | MsiInterop.INSTALLLOGMODE_ERROR | MsiInterop.INSTALLLOGMODE_WARNING | MsiInterop.INSTALLLOGMODE_USER | ||
16585 | | MsiInterop.INSTALLLOGMODE_INFO | MsiInterop.INSTALLLOGMODE_FILESINUSE | MsiInterop.INSTALLLOGMODE_RESOLVESOURCE | ||
16586 | | MsiInterop.INSTALLLOGMODE_OUTOFDISKSPACE | MsiInterop.INSTALLLOGMODE_ACTIONSTART | MsiInterop.INSTALLLOGMODE_ACTIONDATA | ||
16587 | | MsiInterop.INSTALLLOGMODE_PROGRESS | MsiInterop.INSTALLLOGMODE_COMMONDATA | MsiInterop.INSTALLLOGMODE_INITIALIZE | ||
16588 | | MsiInterop.INSTALLLOGMODE_TERMINATE | MsiInterop.INSTALLLOGMODE_SHOWDIALOG | MsiInterop.INSTALLLOGMODE_RMFILESINUSE | ||
16589 | | MsiInterop.INSTALLLOGMODE_INSTALLSTART | MsiInterop.INSTALLLOGMODE_INSTALLEND; | ||
16590 | string sourceFile = null; | ||
16591 | |||
16592 | foreach (XAttribute attrib in node.Attributes()) | ||
16593 | { | ||
16594 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
16595 | { | ||
16596 | switch (attrib.Name.LocalName) | ||
16597 | { | ||
16598 | case "Id": | ||
16599 | id = this.core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
16600 | break; | ||
16601 | case "Name": | ||
16602 | name = this.core.GetAttributeLongFilename(sourceLineNumbers, attrib, false); | ||
16603 | break; | ||
16604 | case "IgnoreFatalExit": | ||
16605 | if (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
16606 | { | ||
16607 | messageFilter ^= MsiInterop.INSTALLLOGMODE_FATALEXIT; | ||
16608 | } | ||
16609 | break; | ||
16610 | case "IgnoreError": | ||
16611 | if (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
16612 | { | ||
16613 | messageFilter ^= MsiInterop.INSTALLLOGMODE_ERROR; | ||
16614 | } | ||
16615 | break; | ||
16616 | case "IgnoreWarning": | ||
16617 | if (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
16618 | { | ||
16619 | messageFilter ^= MsiInterop.INSTALLLOGMODE_WARNING; | ||
16620 | } | ||
16621 | break; | ||
16622 | case "IgnoreUser": | ||
16623 | if (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
16624 | { | ||
16625 | messageFilter ^= MsiInterop.INSTALLLOGMODE_USER; | ||
16626 | } | ||
16627 | break; | ||
16628 | case "IgnoreInfo": | ||
16629 | if (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
16630 | { | ||
16631 | messageFilter ^= MsiInterop.INSTALLLOGMODE_INFO; | ||
16632 | } | ||
16633 | break; | ||
16634 | case "IgnoreFilesInUse": | ||
16635 | if (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
16636 | { | ||
16637 | messageFilter ^= MsiInterop.INSTALLLOGMODE_FILESINUSE; | ||
16638 | } | ||
16639 | break; | ||
16640 | case "IgnoreResolveSource": | ||
16641 | if (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
16642 | { | ||
16643 | messageFilter ^= MsiInterop.INSTALLLOGMODE_RESOLVESOURCE; | ||
16644 | } | ||
16645 | break; | ||
16646 | case "IgnoreOutOfDiskSpace": | ||
16647 | if (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
16648 | { | ||
16649 | messageFilter ^= MsiInterop.INSTALLLOGMODE_OUTOFDISKSPACE; | ||
16650 | } | ||
16651 | break; | ||
16652 | case "IgnoreActionStart": | ||
16653 | if (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
16654 | { | ||
16655 | messageFilter ^= MsiInterop.INSTALLLOGMODE_ACTIONSTART; | ||
16656 | } | ||
16657 | break; | ||
16658 | case "IgnoreActionData": | ||
16659 | if (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
16660 | { | ||
16661 | messageFilter ^= MsiInterop.INSTALLLOGMODE_ACTIONDATA; | ||
16662 | } | ||
16663 | break; | ||
16664 | case "IgnoreProgress": | ||
16665 | if (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
16666 | { | ||
16667 | messageFilter ^= MsiInterop.INSTALLLOGMODE_PROGRESS; | ||
16668 | } | ||
16669 | break; | ||
16670 | case "IgnoreCommonData": | ||
16671 | if (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
16672 | { | ||
16673 | messageFilter ^= MsiInterop.INSTALLLOGMODE_COMMONDATA; | ||
16674 | } | ||
16675 | break; | ||
16676 | case "IgnoreInitialize": | ||
16677 | if (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
16678 | { | ||
16679 | messageFilter ^= MsiInterop.INSTALLLOGMODE_INITIALIZE; | ||
16680 | } | ||
16681 | break; | ||
16682 | case "IgnoreTerminate": | ||
16683 | if (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
16684 | { | ||
16685 | messageFilter ^= MsiInterop.INSTALLLOGMODE_TERMINATE; | ||
16686 | } | ||
16687 | break; | ||
16688 | case "IgnoreShowDialog": | ||
16689 | if (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
16690 | { | ||
16691 | messageFilter ^= MsiInterop.INSTALLLOGMODE_SHOWDIALOG; | ||
16692 | } | ||
16693 | break; | ||
16694 | case "IgnoreRMFilesInUse": | ||
16695 | if (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
16696 | { | ||
16697 | messageFilter ^= MsiInterop.INSTALLLOGMODE_RMFILESINUSE; | ||
16698 | } | ||
16699 | break; | ||
16700 | case "IgnoreInstallStart": | ||
16701 | if (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
16702 | { | ||
16703 | messageFilter ^= MsiInterop.INSTALLLOGMODE_INSTALLSTART; | ||
16704 | } | ||
16705 | break; | ||
16706 | case "IgnoreInstallEnd": | ||
16707 | if (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
16708 | { | ||
16709 | messageFilter ^= MsiInterop.INSTALLLOGMODE_INSTALLEND; | ||
16710 | } | ||
16711 | break; | ||
16712 | case "SourceFile": | ||
16713 | sourceFile = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
16714 | break; | ||
16715 | case "SupportBasicUI": | ||
16716 | if (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
16717 | { | ||
16718 | attributes |= MsiInterop.MsidbEmbeddedHandlesBasic; | ||
16719 | } | ||
16720 | break; | ||
16721 | default: | ||
16722 | this.core.UnexpectedAttribute(node, attrib); | ||
16723 | break; | ||
16724 | } | ||
16725 | } | ||
16726 | else | ||
16727 | { | ||
16728 | this.core.ParseExtensionAttribute(node, attrib); | ||
16729 | } | ||
16730 | } | ||
16731 | |||
16732 | if (String.IsNullOrEmpty(sourceFile)) | ||
16733 | { | ||
16734 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "SourceFile")); | ||
16735 | } | ||
16736 | else if (String.IsNullOrEmpty(name)) | ||
16737 | { | ||
16738 | name = Path.GetFileName(sourceFile); | ||
16739 | if (!this.core.IsValidLongFilename(name, false)) | ||
16740 | { | ||
16741 | this.core.OnMessage(WixErrors.IllegalLongFilename(sourceLineNumbers, node.Name.LocalName, "Source", name)); | ||
16742 | } | ||
16743 | } | ||
16744 | |||
16745 | if (null == id) | ||
16746 | { | ||
16747 | if (!String.IsNullOrEmpty(name)) | ||
16748 | { | ||
16749 | id = this.core.CreateIdentifierFromFilename(name); | ||
16750 | } | ||
16751 | |||
16752 | if (null == id) | ||
16753 | { | ||
16754 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
16755 | } | ||
16756 | else if (!Common.IsIdentifier(id.Id)) | ||
16757 | { | ||
16758 | this.core.OnMessage(WixErrors.IllegalIdentifier(sourceLineNumbers, node.Name.LocalName, "Id", id.Id)); | ||
16759 | } | ||
16760 | } | ||
16761 | else if (String.IsNullOrEmpty(name)) | ||
16762 | { | ||
16763 | name = id.Id; | ||
16764 | } | ||
16765 | |||
16766 | if (!name.Contains(".")) | ||
16767 | { | ||
16768 | this.core.OnMessage(WixErrors.InvalidEmbeddedUIFileName(sourceLineNumbers, name)); | ||
16769 | } | ||
16770 | |||
16771 | foreach (XElement child in node.Elements()) | ||
16772 | { | ||
16773 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
16774 | { | ||
16775 | switch (child.Name.LocalName) | ||
16776 | { | ||
16777 | case "EmbeddedUIResource": | ||
16778 | this.ParseEmbeddedUIResourceElement(child); | ||
16779 | break; | ||
16780 | default: | ||
16781 | this.core.UnexpectedElement(node, child); | ||
16782 | break; | ||
16783 | } | ||
16784 | } | ||
16785 | else | ||
16786 | { | ||
16787 | this.core.ParseExtensionElement(node, child); | ||
16788 | } | ||
16789 | } | ||
16790 | |||
16791 | if (!this.core.EncounteredError) | ||
16792 | { | ||
16793 | Row row = this.core.CreateRow(sourceLineNumbers, "MsiEmbeddedUI", id); | ||
16794 | row[1] = name; | ||
16795 | row[2] = attributes; | ||
16796 | row[3] = messageFilter; | ||
16797 | row[4] = sourceFile; | ||
16798 | } | ||
16799 | } | ||
16800 | |||
16801 | /// <summary> | ||
16802 | /// Parses a embedded UI resource element. | ||
16803 | /// </summary> | ||
16804 | /// <param name="node">Element to parse.</param> | ||
16805 | /// <param name="parentId">Identifier of parent EmbeddedUI element.</param> | ||
16806 | private void ParseEmbeddedUIResourceElement(XElement node) | ||
16807 | { | ||
16808 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
16809 | Identifier id = null; | ||
16810 | string name = null; | ||
16811 | string sourceFile = null; | ||
16812 | |||
16813 | foreach (XAttribute attrib in node.Attributes()) | ||
16814 | { | ||
16815 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
16816 | { | ||
16817 | switch (attrib.Name.LocalName) | ||
16818 | { | ||
16819 | case "Id": | ||
16820 | id = this.core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
16821 | break; | ||
16822 | case "Name": | ||
16823 | name = this.core.GetAttributeLongFilename(sourceLineNumbers, attrib, false); | ||
16824 | break; | ||
16825 | case "SourceFile": | ||
16826 | sourceFile = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
16827 | break; | ||
16828 | default: | ||
16829 | this.core.UnexpectedAttribute(node, attrib); | ||
16830 | break; | ||
16831 | } | ||
16832 | } | ||
16833 | else | ||
16834 | { | ||
16835 | this.core.ParseExtensionAttribute(node, attrib); | ||
16836 | } | ||
16837 | } | ||
16838 | |||
16839 | if (String.IsNullOrEmpty(sourceFile)) | ||
16840 | { | ||
16841 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "SourceFile")); | ||
16842 | } | ||
16843 | else if (String.IsNullOrEmpty(name)) | ||
16844 | { | ||
16845 | name = Path.GetFileName(sourceFile); | ||
16846 | if (!this.core.IsValidLongFilename(name, false)) | ||
16847 | { | ||
16848 | this.core.OnMessage(WixErrors.IllegalLongFilename(sourceLineNumbers, node.Name.LocalName, "Source", name)); | ||
16849 | } | ||
16850 | } | ||
16851 | |||
16852 | if (null == id) | ||
16853 | { | ||
16854 | if (!String.IsNullOrEmpty(name)) | ||
16855 | { | ||
16856 | id = this.core.CreateIdentifierFromFilename(name); | ||
16857 | } | ||
16858 | |||
16859 | if (null == id) | ||
16860 | { | ||
16861 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
16862 | } | ||
16863 | else if (!Common.IsIdentifier(id.Id)) | ||
16864 | { | ||
16865 | this.core.OnMessage(WixErrors.IllegalIdentifier(sourceLineNumbers, node.Name.LocalName, "Id", id.Id)); | ||
16866 | } | ||
16867 | } | ||
16868 | else if (String.IsNullOrEmpty(name)) | ||
16869 | { | ||
16870 | name = id.Id; | ||
16871 | } | ||
16872 | |||
16873 | this.core.ParseForExtensionElements(node); | ||
16874 | |||
16875 | if (!this.core.EncounteredError) | ||
16876 | { | ||
16877 | Row row = this.core.CreateRow(sourceLineNumbers, "MsiEmbeddedUI", id); | ||
16878 | row[1] = name; | ||
16879 | row[2] = 0; // embedded UI resources always set this to 0 | ||
16880 | row[3] = null; | ||
16881 | row[4] = sourceFile; | ||
16882 | } | ||
16883 | } | ||
16884 | |||
16885 | /// <summary> | ||
16886 | /// Parses a control element. | ||
16887 | /// </summary> | ||
16888 | /// <param name="node">Element to parse.</param> | ||
16889 | /// <param name="dialog">Identifier for parent dialog.</param> | ||
16890 | /// <param name="table">Table control belongs in.</param> | ||
16891 | /// <param name="lastTabRow">Last row in the tab order.</param> | ||
16892 | /// <param name="firstControl">Name of the first control in the tab order.</param> | ||
16893 | /// <param name="defaultControl">Name of the default control.</param> | ||
16894 | /// <param name="cancelControl">Name of the candle control.</param> | ||
16895 | /// <param name="trackDiskSpace">True if the containing dialog tracks disk space.</param> | ||
16896 | private void ParseControlElement(XElement node, string dialog, TableDefinition table, ref Row lastTabRow, ref string firstControl, ref string defaultControl, ref string cancelControl, bool trackDiskSpace) | ||
16897 | { | ||
16898 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
16899 | Identifier id = null; | ||
16900 | BitArray bits = new BitArray(32); | ||
16901 | int attributes = 0; | ||
16902 | string checkBoxPropertyRef = null; | ||
16903 | string checkboxValue = null; | ||
16904 | string controlType = null; | ||
16905 | bool disabled = false; | ||
16906 | string height = null; | ||
16907 | string help = null; | ||
16908 | bool isCancel = false; | ||
16909 | bool isDefault = false; | ||
16910 | bool notTabbable = false; | ||
16911 | string property = null; | ||
16912 | int publishOrder = 0; | ||
16913 | string[] specialAttributes = null; | ||
16914 | string sourceFile = null; | ||
16915 | string text = null; | ||
16916 | string tooltip = null; | ||
16917 | RadioButtonType radioButtonsType = RadioButtonType.NotSet; | ||
16918 | string width = null; | ||
16919 | string x = null; | ||
16920 | string y = null; | ||
16921 | |||
16922 | // The rest of the method relies on the control's Type, so we have to get that first. | ||
16923 | XAttribute typeAttribute = node.Attribute("Type"); | ||
16924 | if (null == typeAttribute) | ||
16925 | { | ||
16926 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Type")); | ||
16927 | } | ||
16928 | else | ||
16929 | { | ||
16930 | controlType = this.core.GetAttributeValue(sourceLineNumbers, typeAttribute); | ||
16931 | } | ||
16932 | |||
16933 | switch (controlType) | ||
16934 | { | ||
16935 | case "Billboard": | ||
16936 | specialAttributes = null; | ||
16937 | notTabbable = true; | ||
16938 | disabled = true; | ||
16939 | |||
16940 | this.core.EnsureTable(sourceLineNumbers, "Billboard"); | ||
16941 | break; | ||
16942 | case "Bitmap": | ||
16943 | specialAttributes = MsiInterop.BitmapControlAttributes; | ||
16944 | notTabbable = true; | ||
16945 | disabled = true; | ||
16946 | break; | ||
16947 | case "CheckBox": | ||
16948 | specialAttributes = MsiInterop.CheckboxControlAttributes; | ||
16949 | break; | ||
16950 | case "ComboBox": | ||
16951 | specialAttributes = MsiInterop.ComboboxControlAttributes; | ||
16952 | break; | ||
16953 | case "DirectoryCombo": | ||
16954 | specialAttributes = MsiInterop.VolumeControlAttributes; | ||
16955 | break; | ||
16956 | case "DirectoryList": | ||
16957 | specialAttributes = null; | ||
16958 | break; | ||
16959 | case "Edit": | ||
16960 | specialAttributes = MsiInterop.EditControlAttributes; | ||
16961 | break; | ||
16962 | case "GroupBox": | ||
16963 | specialAttributes = null; | ||
16964 | notTabbable = true; | ||
16965 | break; | ||
16966 | case "Hyperlink": | ||
16967 | specialAttributes = MsiInterop.HyperlinkControlAttributes; | ||
16968 | break; | ||
16969 | case "Icon": | ||
16970 | specialAttributes = MsiInterop.IconControlAttributes; | ||
16971 | notTabbable = true; | ||
16972 | disabled = true; | ||
16973 | break; | ||
16974 | case "Line": | ||
16975 | specialAttributes = null; | ||
16976 | notTabbable = true; | ||
16977 | disabled = true; | ||
16978 | break; | ||
16979 | case "ListBox": | ||
16980 | specialAttributes = MsiInterop.ListboxControlAttributes; | ||
16981 | break; | ||
16982 | case "ListView": | ||
16983 | specialAttributes = MsiInterop.ListviewControlAttributes; | ||
16984 | break; | ||
16985 | case "MaskedEdit": | ||
16986 | specialAttributes = MsiInterop.EditControlAttributes; | ||
16987 | break; | ||
16988 | case "PathEdit": | ||
16989 | specialAttributes = MsiInterop.EditControlAttributes; | ||
16990 | break; | ||
16991 | case "ProgressBar": | ||
16992 | specialAttributes = MsiInterop.ProgressControlAttributes; | ||
16993 | notTabbable = true; | ||
16994 | disabled = true; | ||
16995 | break; | ||
16996 | case "PushButton": | ||
16997 | specialAttributes = MsiInterop.ButtonControlAttributes; | ||
16998 | break; | ||
16999 | case "RadioButtonGroup": | ||
17000 | specialAttributes = MsiInterop.RadioControlAttributes; | ||
17001 | break; | ||
17002 | case "ScrollableText": | ||
17003 | specialAttributes = null; | ||
17004 | break; | ||
17005 | case "SelectionTree": | ||
17006 | specialAttributes = null; | ||
17007 | break; | ||
17008 | case "Text": | ||
17009 | specialAttributes = MsiInterop.TextControlAttributes; | ||
17010 | notTabbable = true; | ||
17011 | break; | ||
17012 | case "VolumeCostList": | ||
17013 | specialAttributes = MsiInterop.VolumeControlAttributes; | ||
17014 | notTabbable = true; | ||
17015 | break; | ||
17016 | case "VolumeSelectCombo": | ||
17017 | specialAttributes = MsiInterop.VolumeControlAttributes; | ||
17018 | break; | ||
17019 | default: | ||
17020 | specialAttributes = null; | ||
17021 | notTabbable = true; | ||
17022 | break; | ||
17023 | } | ||
17024 | |||
17025 | foreach (XAttribute attrib in node.Attributes()) | ||
17026 | { | ||
17027 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
17028 | { | ||
17029 | switch (attrib.Name.LocalName) | ||
17030 | { | ||
17031 | case "Id": | ||
17032 | id = this.core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
17033 | break; | ||
17034 | case "Type": // already processed | ||
17035 | break; | ||
17036 | case "Cancel": | ||
17037 | isCancel = YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
17038 | break; | ||
17039 | case "CheckBoxPropertyRef": | ||
17040 | checkBoxPropertyRef = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
17041 | break; | ||
17042 | case "CheckBoxValue": | ||
17043 | checkboxValue = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
17044 | break; | ||
17045 | case "Default": | ||
17046 | isDefault = YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
17047 | break; | ||
17048 | case "Height": | ||
17049 | height = this.core.GetAttributeLocalizableIntegerValue(sourceLineNumbers, attrib, 0, short.MaxValue); | ||
17050 | break; | ||
17051 | case "Help": | ||
17052 | help = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
17053 | break; | ||
17054 | case "IconSize": | ||
17055 | string iconSizeValue = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
17056 | if (null != specialAttributes) | ||
17057 | { | ||
17058 | if (0 < iconSizeValue.Length) | ||
17059 | { | ||
17060 | Wix.Control.IconSizeType iconsSizeType = Wix.Control.ParseIconSizeType(iconSizeValue); | ||
17061 | switch (iconsSizeType) | ||
17062 | { | ||
17063 | case Wix.Control.IconSizeType.Item16: | ||
17064 | this.core.TrySetBitFromName(specialAttributes, "Icon16", YesNoType.Yes, bits, 16); | ||
17065 | break; | ||
17066 | case Wix.Control.IconSizeType.Item32: | ||
17067 | this.core.TrySetBitFromName(specialAttributes, "Icon32", YesNoType.Yes, bits, 16); | ||
17068 | break; | ||
17069 | case Wix.Control.IconSizeType.Item48: | ||
17070 | this.core.TrySetBitFromName(specialAttributes, "Icon16", YesNoType.Yes, bits, 16); | ||
17071 | this.core.TrySetBitFromName(specialAttributes, "Icon32", YesNoType.Yes, bits, 16); | ||
17072 | break; | ||
17073 | default: | ||
17074 | this.core.OnMessage(WixErrors.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, iconSizeValue, "16", "32", "48")); | ||
17075 | break; | ||
17076 | } | ||
17077 | } | ||
17078 | } | ||
17079 | else | ||
17080 | { | ||
17081 | this.core.OnMessage(WixErrors.IllegalAttributeValueWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, iconSizeValue, "Type")); | ||
17082 | } | ||
17083 | break; | ||
17084 | case "Property": | ||
17085 | property = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
17086 | break; | ||
17087 | case "TabSkip": | ||
17088 | notTabbable = YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
17089 | break; | ||
17090 | case "Text": | ||
17091 | text = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
17092 | break; | ||
17093 | case "ToolTip": | ||
17094 | tooltip = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
17095 | break; | ||
17096 | case "Width": | ||
17097 | width = this.core.GetAttributeLocalizableIntegerValue(sourceLineNumbers, attrib, 0, short.MaxValue); | ||
17098 | break; | ||
17099 | case "X": | ||
17100 | x = this.core.GetAttributeLocalizableIntegerValue(sourceLineNumbers, attrib, 0, short.MaxValue); | ||
17101 | break; | ||
17102 | case "Y": | ||
17103 | y = this.core.GetAttributeLocalizableIntegerValue(sourceLineNumbers, attrib, 0, short.MaxValue); | ||
17104 | break; | ||
17105 | default: | ||
17106 | YesNoType attribValue = this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
17107 | if (!this.core.TrySetBitFromName(MsiInterop.CommonControlAttributes, attrib.Name.LocalName, attribValue, bits, 0)) | ||
17108 | { | ||
17109 | if (null == specialAttributes || !this.core.TrySetBitFromName(specialAttributes, attrib.Name.LocalName, attribValue, bits, 16)) | ||
17110 | { | ||
17111 | this.core.UnexpectedAttribute(node, attrib); | ||
17112 | } | ||
17113 | } | ||
17114 | break; | ||
17115 | } | ||
17116 | } | ||
17117 | else | ||
17118 | { | ||
17119 | this.core.ParseExtensionAttribute(node, attrib); | ||
17120 | } | ||
17121 | } | ||
17122 | |||
17123 | attributes = this.core.CreateIntegerFromBitArray(bits); | ||
17124 | |||
17125 | if (disabled) | ||
17126 | { | ||
17127 | attributes |= MsiInterop.MsidbControlAttributesEnabled; // bit will be inverted when stored | ||
17128 | } | ||
17129 | |||
17130 | if (null == height) | ||
17131 | { | ||
17132 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Height")); | ||
17133 | } | ||
17134 | |||
17135 | if (null == width) | ||
17136 | { | ||
17137 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Width")); | ||
17138 | } | ||
17139 | |||
17140 | if (null == x) | ||
17141 | { | ||
17142 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "X")); | ||
17143 | } | ||
17144 | |||
17145 | if (null == y) | ||
17146 | { | ||
17147 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Y")); | ||
17148 | } | ||
17149 | |||
17150 | if (null == id) | ||
17151 | { | ||
17152 | id = this.core.CreateIdentifier("ctl", dialog, x, y, height, width); | ||
17153 | } | ||
17154 | |||
17155 | if (isCancel) | ||
17156 | { | ||
17157 | cancelControl = id.Id; | ||
17158 | } | ||
17159 | |||
17160 | if (isDefault) | ||
17161 | { | ||
17162 | defaultControl = id.Id; | ||
17163 | } | ||
17164 | |||
17165 | foreach (XElement child in node.Elements()) | ||
17166 | { | ||
17167 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
17168 | { | ||
17169 | SourceLineNumber childSourceLineNumbers = Preprocessor.GetSourceLineNumbers(child); | ||
17170 | switch (child.Name.LocalName) | ||
17171 | { | ||
17172 | case "Binary": | ||
17173 | this.ParseBinaryElement(child); | ||
17174 | break; | ||
17175 | case "ComboBox": | ||
17176 | this.ParseControlGroupElement(child, this.tableDefinitions["ComboBox"], "ListItem"); | ||
17177 | break; | ||
17178 | case "Condition": | ||
17179 | this.ParseConditionElement(child, node.Name.LocalName, id.Id, dialog); | ||
17180 | break; | ||
17181 | case "ListBox": | ||
17182 | this.ParseControlGroupElement(child, this.tableDefinitions["ListBox"], "ListItem"); | ||
17183 | break; | ||
17184 | case "ListView": | ||
17185 | this.ParseControlGroupElement(child, this.tableDefinitions["ListView"], "ListItem"); | ||
17186 | break; | ||
17187 | case "Property": | ||
17188 | this.ParsePropertyElement(child); | ||
17189 | break; | ||
17190 | case "Publish": | ||
17191 | this.ParsePublishElement(child, dialog ?? String.Empty, id.Id, ref publishOrder); | ||
17192 | break; | ||
17193 | case "RadioButtonGroup": | ||
17194 | radioButtonsType = this.ParseRadioButtonGroupElement(child, property, radioButtonsType); | ||
17195 | break; | ||
17196 | case "Subscribe": | ||
17197 | this.ParseSubscribeElement(child, dialog, id.Id); | ||
17198 | break; | ||
17199 | case "Text": | ||
17200 | foreach (XAttribute attrib in child.Attributes()) | ||
17201 | { | ||
17202 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
17203 | { | ||
17204 | switch (attrib.Name.LocalName) | ||
17205 | { | ||
17206 | case "SourceFile": | ||
17207 | sourceFile = this.core.GetAttributeValue(childSourceLineNumbers, attrib); | ||
17208 | break; | ||
17209 | default: | ||
17210 | this.core.UnexpectedAttribute(child, attrib); | ||
17211 | break; | ||
17212 | } | ||
17213 | } | ||
17214 | else | ||
17215 | { | ||
17216 | this.core.ParseExtensionAttribute(child, attrib); | ||
17217 | } | ||
17218 | } | ||
17219 | |||
17220 | text = Common.GetInnerText(child); | ||
17221 | if (!String.IsNullOrEmpty(text) && null != sourceFile) | ||
17222 | { | ||
17223 | this.core.OnMessage(WixErrors.IllegalAttributeWithInnerText(childSourceLineNumbers, child.Name.LocalName, "SourceFile")); | ||
17224 | } | ||
17225 | break; | ||
17226 | default: | ||
17227 | this.core.UnexpectedElement(node, child); | ||
17228 | break; | ||
17229 | } | ||
17230 | } | ||
17231 | else | ||
17232 | { | ||
17233 | this.core.ParseExtensionElement(node, child); | ||
17234 | } | ||
17235 | } | ||
17236 | |||
17237 | // If the radio buttons have icons, then we need to add the icon attribute. | ||
17238 | switch (radioButtonsType) | ||
17239 | { | ||
17240 | case RadioButtonType.Bitmap: | ||
17241 | attributes |= MsiInterop.MsidbControlAttributesBitmap; | ||
17242 | break; | ||
17243 | case RadioButtonType.Icon: | ||
17244 | attributes |= MsiInterop.MsidbControlAttributesIcon; | ||
17245 | break; | ||
17246 | case RadioButtonType.Text: | ||
17247 | // Text is the default so nothing needs to be added bits | ||
17248 | break; | ||
17249 | } | ||
17250 | |||
17251 | // If we're tracking disk space, and this is a non-FormatSize Text control, and the text attribute starts with | ||
17252 | // '[' and ends with ']', add a space. It is not necessary for the whole string to be a property, just | ||
17253 | // those two characters matter. | ||
17254 | if (trackDiskSpace && "Text" == controlType && | ||
17255 | MsiInterop.MsidbControlAttributesFormatSize != (attributes & MsiInterop.MsidbControlAttributesFormatSize) && | ||
17256 | null != text && text.StartsWith("[", StringComparison.Ordinal) && text.EndsWith("]", StringComparison.Ordinal)) | ||
17257 | { | ||
17258 | text = String.Concat(text, " "); | ||
17259 | } | ||
17260 | |||
17261 | // the logic for creating control rows is a little tricky because of the way tabable controls are set | ||
17262 | Row row = null; | ||
17263 | if (!this.core.EncounteredError) | ||
17264 | { | ||
17265 | if ("CheckBox" == controlType) | ||
17266 | { | ||
17267 | if (String.IsNullOrEmpty(property) && String.IsNullOrEmpty(checkBoxPropertyRef)) | ||
17268 | { | ||
17269 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Property", "CheckBoxPropertyRef", true)); | ||
17270 | } | ||
17271 | else if (!String.IsNullOrEmpty(property) && !String.IsNullOrEmpty(checkBoxPropertyRef)) | ||
17272 | { | ||
17273 | this.core.OnMessage(WixErrors.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Property", "CheckBoxPropertyRef")); | ||
17274 | } | ||
17275 | else if (!String.IsNullOrEmpty(property)) | ||
17276 | { | ||
17277 | row = this.core.CreateRow(sourceLineNumbers, "CheckBox"); | ||
17278 | row[0] = property; | ||
17279 | row[1] = checkboxValue; | ||
17280 | } | ||
17281 | else | ||
17282 | { | ||
17283 | this.core.CreateSimpleReference(sourceLineNumbers, "CheckBox", checkBoxPropertyRef); | ||
17284 | } | ||
17285 | } | ||
17286 | |||
17287 | row = this.core.CreateRow(sourceLineNumbers, table.Name); | ||
17288 | row.Access = id.Access; | ||
17289 | row[0] = dialog; | ||
17290 | row[1] = id.Id; | ||
17291 | row[2] = controlType; | ||
17292 | row[3] = x; | ||
17293 | row[4] = y; | ||
17294 | row[5] = width; | ||
17295 | row[6] = height; | ||
17296 | row[7] = attributes ^ (MsiInterop.MsidbControlAttributesVisible | MsiInterop.MsidbControlAttributesEnabled); | ||
17297 | if ("BBControl" == table.Name) | ||
17298 | { | ||
17299 | row[8] = text; // BBControl.Text | ||
17300 | |||
17301 | if (null != sourceFile) | ||
17302 | { | ||
17303 | Row wixBBControlRow = this.core.CreateRow(sourceLineNumbers, "WixBBControl"); | ||
17304 | wixBBControlRow.Access = id.Access; | ||
17305 | wixBBControlRow[0] = dialog; | ||
17306 | wixBBControlRow[1] = id.Id; | ||
17307 | wixBBControlRow[2] = sourceFile; | ||
17308 | } | ||
17309 | } | ||
17310 | else | ||
17311 | { | ||
17312 | row[8] = !String.IsNullOrEmpty(property) ? property : checkBoxPropertyRef; | ||
17313 | row[9] = text; | ||
17314 | if (null != tooltip || null != help) | ||
17315 | { | ||
17316 | row[11] = String.Concat(tooltip, "|", help); // Separator is required, even if only one is non-null. | ||
17317 | } | ||
17318 | |||
17319 | if (null != sourceFile) | ||
17320 | { | ||
17321 | Row wixControlRow = this.core.CreateRow(sourceLineNumbers, "WixControl"); | ||
17322 | wixControlRow.Access = id.Access; | ||
17323 | wixControlRow[0] = dialog; | ||
17324 | wixControlRow[1] = id.Id; | ||
17325 | wixControlRow[2] = sourceFile; | ||
17326 | } | ||
17327 | } | ||
17328 | } | ||
17329 | |||
17330 | if (!notTabbable) | ||
17331 | { | ||
17332 | if ("BBControl" == table.Name) | ||
17333 | { | ||
17334 | this.core.OnMessage(WixErrors.TabbableControlNotAllowedInBillboard(sourceLineNumbers, node.Name.LocalName, controlType)); | ||
17335 | } | ||
17336 | |||
17337 | if (null == firstControl) | ||
17338 | { | ||
17339 | firstControl = id.Id; | ||
17340 | } | ||
17341 | |||
17342 | if (null != lastTabRow) | ||
17343 | { | ||
17344 | lastTabRow[10] = id.Id; | ||
17345 | } | ||
17346 | lastTabRow = row; | ||
17347 | } | ||
17348 | |||
17349 | // bitmap and icon controls contain a foreign key into the binary table in the text column; | ||
17350 | // add a reference if the identifier of the binary entry is known during compilation | ||
17351 | if (("Bitmap" == controlType || "Icon" == controlType) && Common.IsIdentifier(text)) | ||
17352 | { | ||
17353 | this.core.CreateSimpleReference(sourceLineNumbers, "Binary", text); | ||
17354 | } | ||
17355 | } | ||
17356 | |||
17357 | /// <summary> | ||
17358 | /// Parses a publish control event element. | ||
17359 | /// </summary> | ||
17360 | /// <param name="node">Element to parse.</param> | ||
17361 | /// <param name="dialog">Identifier of parent dialog.</param> | ||
17362 | /// <param name="control">Identifier of parent control.</param> | ||
17363 | /// <param name="order">Relative order of controls.</param> | ||
17364 | private void ParsePublishElement(XElement node, string dialog, string control, ref int order) | ||
17365 | { | ||
17366 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
17367 | string argument = null; | ||
17368 | string condition = null; | ||
17369 | string controlEvent = null; | ||
17370 | string property = null; | ||
17371 | |||
17372 | // give this control event a unique ordering | ||
17373 | order++; | ||
17374 | |||
17375 | foreach (XAttribute attrib in node.Attributes()) | ||
17376 | { | ||
17377 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
17378 | { | ||
17379 | switch (attrib.Name.LocalName) | ||
17380 | { | ||
17381 | case "Control": | ||
17382 | if (null != control) | ||
17383 | { | ||
17384 | this.core.OnMessage(WixErrors.IllegalAttributeWhenNested(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, node.Parent.Name.LocalName)); | ||
17385 | } | ||
17386 | control = this.core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
17387 | break; | ||
17388 | case "Dialog": | ||
17389 | if (null != dialog) | ||
17390 | { | ||
17391 | this.core.OnMessage(WixErrors.IllegalAttributeWhenNested(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, node.Parent.Name.LocalName)); | ||
17392 | } | ||
17393 | dialog = this.core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
17394 | this.core.CreateSimpleReference(sourceLineNumbers, "Dialog", dialog); | ||
17395 | break; | ||
17396 | case "Event": | ||
17397 | controlEvent = Compiler.UppercaseFirstChar(this.core.GetAttributeValue(sourceLineNumbers, attrib)); | ||
17398 | break; | ||
17399 | case "Order": | ||
17400 | order = this.core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, 2147483647); | ||
17401 | break; | ||
17402 | case "Property": | ||
17403 | property = String.Concat("[", this.core.GetAttributeValue(sourceLineNumbers, attrib), "]"); | ||
17404 | break; | ||
17405 | case "Value": | ||
17406 | argument = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
17407 | break; | ||
17408 | default: | ||
17409 | this.core.UnexpectedAttribute(node, attrib); | ||
17410 | break; | ||
17411 | } | ||
17412 | } | ||
17413 | else | ||
17414 | { | ||
17415 | this.core.ParseExtensionAttribute(node, attrib); | ||
17416 | } | ||
17417 | } | ||
17418 | |||
17419 | condition = this.core.GetConditionInnerText(node); | ||
17420 | |||
17421 | if (null == control) | ||
17422 | { | ||
17423 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Control")); | ||
17424 | } | ||
17425 | |||
17426 | if (null == dialog) | ||
17427 | { | ||
17428 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Dialog")); | ||
17429 | } | ||
17430 | |||
17431 | if (null == controlEvent && null == property) // need to specify at least one | ||
17432 | { | ||
17433 | this.core.OnMessage(WixErrors.ExpectedAttributes(sourceLineNumbers, node.Name.LocalName, "Event", "Property")); | ||
17434 | } | ||
17435 | else if (null != controlEvent && null != property) // cannot specify both | ||
17436 | { | ||
17437 | this.core.OnMessage(WixErrors.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Event", "Property")); | ||
17438 | } | ||
17439 | |||
17440 | if (null == argument) | ||
17441 | { | ||
17442 | if (null != controlEvent) | ||
17443 | { | ||
17444 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Value", "Event")); | ||
17445 | } | ||
17446 | else if (null != property) | ||
17447 | { | ||
17448 | // if this is setting a property to null, put a special value in the argument column | ||
17449 | argument = "{}"; | ||
17450 | } | ||
17451 | } | ||
17452 | |||
17453 | this.core.ParseForExtensionElements(node); | ||
17454 | |||
17455 | if (!this.core.EncounteredError) | ||
17456 | { | ||
17457 | Row row = this.core.CreateRow(sourceLineNumbers, "ControlEvent"); | ||
17458 | row[0] = dialog; | ||
17459 | row[1] = control; | ||
17460 | row[2] = (null != controlEvent ? controlEvent : property); | ||
17461 | row[3] = argument; | ||
17462 | row[4] = condition; | ||
17463 | row[5] = order; | ||
17464 | } | ||
17465 | |||
17466 | if ("DoAction" == controlEvent && null != argument) | ||
17467 | { | ||
17468 | // if we're not looking at a standard action or a formatted string then create a reference | ||
17469 | // to the custom action. | ||
17470 | if (!WindowsInstallerStandard.IsStandardAction(argument) && !Common.ContainsProperty(argument)) | ||
17471 | { | ||
17472 | this.core.CreateSimpleReference(sourceLineNumbers, "CustomAction", argument); | ||
17473 | } | ||
17474 | } | ||
17475 | |||
17476 | // if we're referring to a dialog but not through a property, add it to the references | ||
17477 | if (("NewDialog" == controlEvent || "SpawnDialog" == controlEvent || "SpawnWaitDialog" == controlEvent || "SelectionBrowse" == controlEvent) && Common.IsIdentifier(argument)) | ||
17478 | { | ||
17479 | this.core.CreateSimpleReference(sourceLineNumbers, "Dialog", argument); | ||
17480 | } | ||
17481 | } | ||
17482 | |||
17483 | /// <summary> | ||
17484 | /// Parses a control subscription element. | ||
17485 | /// </summary> | ||
17486 | /// <param name="node">Element to parse.</param> | ||
17487 | /// <param name="dialog">Identifier of dialog.</param> | ||
17488 | /// <param name="control">Identifier of control.</param> | ||
17489 | private void ParseSubscribeElement(XElement node, string dialog, string control) | ||
17490 | { | ||
17491 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
17492 | string controlAttribute = null; | ||
17493 | string eventMapping = null; | ||
17494 | |||
17495 | foreach (XAttribute attrib in node.Attributes()) | ||
17496 | { | ||
17497 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
17498 | { | ||
17499 | switch (attrib.Name.LocalName) | ||
17500 | { | ||
17501 | case "Attribute": | ||
17502 | controlAttribute = Compiler.UppercaseFirstChar(this.core.GetAttributeIdentifierValue(sourceLineNumbers, attrib)); | ||
17503 | break; | ||
17504 | case "Event": | ||
17505 | eventMapping = Compiler.UppercaseFirstChar(this.core.GetAttributeIdentifierValue(sourceLineNumbers, attrib)); | ||
17506 | break; | ||
17507 | default: | ||
17508 | this.core.UnexpectedAttribute(node, attrib); | ||
17509 | break; | ||
17510 | } | ||
17511 | } | ||
17512 | else | ||
17513 | { | ||
17514 | this.core.ParseExtensionAttribute(node, attrib); | ||
17515 | } | ||
17516 | } | ||
17517 | |||
17518 | this.core.ParseForExtensionElements(node); | ||
17519 | |||
17520 | if (!this.core.EncounteredError) | ||
17521 | { | ||
17522 | Row row = this.core.CreateRow(sourceLineNumbers, "EventMapping"); | ||
17523 | row[0] = dialog; | ||
17524 | row[1] = control; | ||
17525 | row[2] = eventMapping; | ||
17526 | row[3] = controlAttribute; | ||
17527 | } | ||
17528 | } | ||
17529 | |||
17530 | /// <summary> | ||
17531 | /// Parses an upgrade element. | ||
17532 | /// </summary> | ||
17533 | /// <param name="node">Element to parse.</param> | ||
17534 | private void ParseUpgradeElement(XElement node) | ||
17535 | { | ||
17536 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
17537 | string id = null; | ||
17538 | |||
17539 | foreach (XAttribute attrib in node.Attributes()) | ||
17540 | { | ||
17541 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
17542 | { | ||
17543 | switch (attrib.Name.LocalName) | ||
17544 | { | ||
17545 | case "Id": | ||
17546 | id = this.core.GetAttributeGuidValue(sourceLineNumbers, attrib, false); | ||
17547 | break; | ||
17548 | default: | ||
17549 | this.core.UnexpectedAttribute(node, attrib); | ||
17550 | break; | ||
17551 | } | ||
17552 | } | ||
17553 | else | ||
17554 | { | ||
17555 | this.core.ParseExtensionAttribute(node, attrib); | ||
17556 | } | ||
17557 | } | ||
17558 | |||
17559 | if (null == id) | ||
17560 | { | ||
17561 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
17562 | } | ||
17563 | |||
17564 | // process the UpgradeVersion children here | ||
17565 | foreach (XElement child in node.Elements()) | ||
17566 | { | ||
17567 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
17568 | { | ||
17569 | SourceLineNumber childSourceLineNumbers = Preprocessor.GetSourceLineNumbers(child); | ||
17570 | |||
17571 | switch (child.Name.LocalName) | ||
17572 | { | ||
17573 | case "Property": | ||
17574 | this.ParsePropertyElement(child); | ||
17575 | this.core.OnMessage(WixWarnings.DeprecatedUpgradeProperty(childSourceLineNumbers)); | ||
17576 | break; | ||
17577 | case "UpgradeVersion": | ||
17578 | this.ParseUpgradeVersionElement(child, id); | ||
17579 | break; | ||
17580 | default: | ||
17581 | this.core.UnexpectedElement(node, child); | ||
17582 | break; | ||
17583 | } | ||
17584 | } | ||
17585 | else | ||
17586 | { | ||
17587 | this.core.ParseExtensionElement(node, child); | ||
17588 | } | ||
17589 | } | ||
17590 | |||
17591 | |||
17592 | // No rows created here. All row creation is done in ParseUpgradeVersionElement. | ||
17593 | } | ||
17594 | |||
17595 | /// <summary> | ||
17596 | /// Parse upgrade version element. | ||
17597 | /// </summary> | ||
17598 | /// <param name="node">Element to parse.</param> | ||
17599 | /// <param name="upgradeId">Upgrade code.</param> | ||
17600 | private void ParseUpgradeVersionElement(XElement node, string upgradeId) | ||
17601 | { | ||
17602 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
17603 | |||
17604 | string actionProperty = null; | ||
17605 | string language = null; | ||
17606 | string maximum = null; | ||
17607 | string minimum = null; | ||
17608 | int options = 256; | ||
17609 | string removeFeatures = null; | ||
17610 | |||
17611 | foreach (XAttribute attrib in node.Attributes()) | ||
17612 | { | ||
17613 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
17614 | { | ||
17615 | switch (attrib.Name.LocalName) | ||
17616 | { | ||
17617 | case "ExcludeLanguages": | ||
17618 | if (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
17619 | { | ||
17620 | options |= MsiInterop.MsidbUpgradeAttributesLanguagesExclusive; | ||
17621 | } | ||
17622 | break; | ||
17623 | case "IgnoreRemoveFailure": | ||
17624 | if (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
17625 | { | ||
17626 | options |= MsiInterop.MsidbUpgradeAttributesIgnoreRemoveFailure; | ||
17627 | } | ||
17628 | break; | ||
17629 | case "IncludeMaximum": | ||
17630 | if (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
17631 | { | ||
17632 | options |= MsiInterop.MsidbUpgradeAttributesVersionMaxInclusive; | ||
17633 | } | ||
17634 | break; | ||
17635 | case "IncludeMinimum": // this is "yes" by default | ||
17636 | if (YesNoType.No == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
17637 | { | ||
17638 | options &= ~MsiInterop.MsidbUpgradeAttributesVersionMinInclusive; | ||
17639 | } | ||
17640 | break; | ||
17641 | case "Language": | ||
17642 | language = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
17643 | break; | ||
17644 | case "Minimum": | ||
17645 | minimum = this.core.GetAttributeVersionValue(sourceLineNumbers, attrib); | ||
17646 | break; | ||
17647 | case "Maximum": | ||
17648 | maximum = this.core.GetAttributeVersionValue(sourceLineNumbers, attrib); | ||
17649 | break; | ||
17650 | case "MigrateFeatures": | ||
17651 | if (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
17652 | { | ||
17653 | options |= MsiInterop.MsidbUpgradeAttributesMigrateFeatures; | ||
17654 | } | ||
17655 | break; | ||
17656 | case "OnlyDetect": | ||
17657 | if (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
17658 | { | ||
17659 | options |= MsiInterop.MsidbUpgradeAttributesOnlyDetect; | ||
17660 | } | ||
17661 | break; | ||
17662 | case "Property": | ||
17663 | actionProperty = this.core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
17664 | break; | ||
17665 | case "RemoveFeatures": | ||
17666 | removeFeatures = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
17667 | break; | ||
17668 | default: | ||
17669 | this.core.UnexpectedAttribute(node, attrib); | ||
17670 | break; | ||
17671 | } | ||
17672 | } | ||
17673 | else | ||
17674 | { | ||
17675 | this.core.ParseExtensionAttribute(node, attrib); | ||
17676 | } | ||
17677 | } | ||
17678 | |||
17679 | if (null == actionProperty) | ||
17680 | { | ||
17681 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Property")); | ||
17682 | } | ||
17683 | else if (actionProperty.ToUpper(CultureInfo.InvariantCulture) != actionProperty) | ||
17684 | { | ||
17685 | this.core.OnMessage(WixErrors.SecurePropertyNotUppercase(sourceLineNumbers, node.Name.LocalName, "Property", actionProperty)); | ||
17686 | } | ||
17687 | |||
17688 | if (null == minimum && null == maximum) | ||
17689 | { | ||
17690 | this.core.OnMessage(WixErrors.ExpectedAttributes(sourceLineNumbers, node.Name.LocalName, "Minimum", "Maximum")); | ||
17691 | } | ||
17692 | |||
17693 | this.core.ParseForExtensionElements(node); | ||
17694 | |||
17695 | if (!this.core.EncounteredError) | ||
17696 | { | ||
17697 | Row row = this.core.CreateRow(sourceLineNumbers, "Upgrade"); | ||
17698 | row[0] = upgradeId; | ||
17699 | row[1] = minimum; | ||
17700 | row[2] = maximum; | ||
17701 | row[3] = language; | ||
17702 | row[4] = options; | ||
17703 | row[5] = removeFeatures; | ||
17704 | row[6] = actionProperty; | ||
17705 | |||
17706 | // Ensure the action property is secure. | ||
17707 | this.AddWixPropertyRow(sourceLineNumbers, new Identifier(actionProperty, AccessModifier.Private), false, true, false); | ||
17708 | |||
17709 | // Ensure that RemoveExistingProducts is authored in InstallExecuteSequence | ||
17710 | // if at least one row in Upgrade table lacks the OnlyDetect attribute. | ||
17711 | if (0 == (options & MsiInterop.MsidbUpgradeAttributesOnlyDetect)) | ||
17712 | { | ||
17713 | this.core.CreateSimpleReference(sourceLineNumbers, "WixAction", "InstallExecuteSequence", "RemoveExistingProducts"); | ||
17714 | } | ||
17715 | } | ||
17716 | } | ||
17717 | |||
17718 | /// <summary> | ||
17719 | /// Parses a verb element. | ||
17720 | /// </summary> | ||
17721 | /// <param name="node">Element to parse.</param> | ||
17722 | /// <param name="extension">Extension verb is releated to.</param> | ||
17723 | /// <param name="progId">Optional progId for extension.</param> | ||
17724 | /// <param name="componentId">Identifier for parent component.</param> | ||
17725 | /// <param name="advertise">Flag if verb is advertised.</param> | ||
17726 | private void ParseVerbElement(XElement node, string extension, string progId, string componentId, YesNoType advertise) | ||
17727 | { | ||
17728 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
17729 | string id = null; | ||
17730 | string argument = null; | ||
17731 | string command = null; | ||
17732 | int sequence = CompilerConstants.IntegerNotSet; | ||
17733 | string target = null; | ||
17734 | string targetFile = null; | ||
17735 | string targetProperty = null; | ||
17736 | |||
17737 | foreach (XAttribute attrib in node.Attributes()) | ||
17738 | { | ||
17739 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
17740 | { | ||
17741 | switch (attrib.Name.LocalName) | ||
17742 | { | ||
17743 | case "Id": | ||
17744 | id = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
17745 | break; | ||
17746 | case "Argument": | ||
17747 | argument = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
17748 | break; | ||
17749 | case "Command": | ||
17750 | command = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
17751 | break; | ||
17752 | case "Sequence": | ||
17753 | sequence = this.core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 1, short.MaxValue); | ||
17754 | break; | ||
17755 | case "Target": | ||
17756 | target = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
17757 | this.core.OnMessage(WixWarnings.DeprecatedAttribute(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, "TargetFile", "TargetProperty")); | ||
17758 | break; | ||
17759 | case "TargetFile": | ||
17760 | targetFile = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
17761 | this.core.CreateSimpleReference(sourceLineNumbers, "File", targetFile); | ||
17762 | break; | ||
17763 | case "TargetProperty": | ||
17764 | targetProperty = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
17765 | break; | ||
17766 | default: | ||
17767 | this.core.UnexpectedAttribute(node, attrib); | ||
17768 | break; | ||
17769 | } | ||
17770 | } | ||
17771 | else | ||
17772 | { | ||
17773 | this.core.ParseExtensionAttribute(node, attrib); | ||
17774 | } | ||
17775 | } | ||
17776 | |||
17777 | if (null == id) | ||
17778 | { | ||
17779 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
17780 | } | ||
17781 | |||
17782 | if (null != target && null != targetFile) | ||
17783 | { | ||
17784 | this.core.OnMessage(WixErrors.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Target", "TargetFile")); | ||
17785 | } | ||
17786 | |||
17787 | if (null != target && null != targetProperty) | ||
17788 | { | ||
17789 | this.core.OnMessage(WixErrors.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Target", "TargetProperty")); | ||
17790 | } | ||
17791 | |||
17792 | if (null != targetFile && null != targetProperty) | ||
17793 | { | ||
17794 | this.core.OnMessage(WixErrors.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "TargetFile", "TargetProperty")); | ||
17795 | } | ||
17796 | |||
17797 | this.core.ParseForExtensionElements(node); | ||
17798 | |||
17799 | if (YesNoType.Yes == advertise) | ||
17800 | { | ||
17801 | if (null != target) | ||
17802 | { | ||
17803 | this.core.OnMessage(WixErrors.IllegalAttributeWhenAdvertised(sourceLineNumbers, node.Name.LocalName, "Target")); | ||
17804 | } | ||
17805 | |||
17806 | if (null != targetFile) | ||
17807 | { | ||
17808 | this.core.OnMessage(WixErrors.IllegalAttributeWhenAdvertised(sourceLineNumbers, node.Name.LocalName, "TargetFile")); | ||
17809 | } | ||
17810 | |||
17811 | if (null != targetProperty) | ||
17812 | { | ||
17813 | this.core.OnMessage(WixErrors.IllegalAttributeWhenAdvertised(sourceLineNumbers, node.Name.LocalName, "TargetProperty")); | ||
17814 | } | ||
17815 | |||
17816 | if (!this.core.EncounteredError) | ||
17817 | { | ||
17818 | Row row = this.core.CreateRow(sourceLineNumbers, "Verb"); | ||
17819 | row[0] = extension; | ||
17820 | row[1] = id; | ||
17821 | if (CompilerConstants.IntegerNotSet != sequence) | ||
17822 | { | ||
17823 | row[2] = sequence; | ||
17824 | } | ||
17825 | row[3] = command; | ||
17826 | row[4] = argument; | ||
17827 | } | ||
17828 | } | ||
17829 | else if (YesNoType.No == advertise) | ||
17830 | { | ||
17831 | if (CompilerConstants.IntegerNotSet != sequence) | ||
17832 | { | ||
17833 | this.core.OnMessage(WixErrors.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Sequence", "Advertise", "no")); | ||
17834 | } | ||
17835 | |||
17836 | if (null == target && null == targetFile && null == targetProperty) | ||
17837 | { | ||
17838 | this.core.OnMessage(WixErrors.ExpectedAttributesWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "TargetFile", "TargetProperty", "Advertise", "no")); | ||
17839 | } | ||
17840 | |||
17841 | if (null == target) | ||
17842 | { | ||
17843 | if (null != targetFile) | ||
17844 | { | ||
17845 | target = String.Concat("\"[#", targetFile, "]\""); | ||
17846 | } | ||
17847 | |||
17848 | if (null != targetProperty) | ||
17849 | { | ||
17850 | target = String.Concat("\"[", targetProperty, "]\""); | ||
17851 | } | ||
17852 | } | ||
17853 | |||
17854 | if (null != argument) | ||
17855 | { | ||
17856 | target = String.Concat(target, " ", argument); | ||
17857 | } | ||
17858 | |||
17859 | string prefix = (null != progId ? progId : String.Concat(".", extension)); | ||
17860 | |||
17861 | if (null != command) | ||
17862 | { | ||
17863 | this.core.CreateRegistryRow(sourceLineNumbers, MsiInterop.MsidbRegistryRootClassesRoot, String.Concat(prefix, "\\shell\\", id), String.Empty, command, componentId); | ||
17864 | } | ||
17865 | |||
17866 | this.core.CreateRegistryRow(sourceLineNumbers, MsiInterop.MsidbRegistryRootClassesRoot, String.Concat(prefix, "\\shell\\", id, "\\command"), String.Empty, target, componentId); | ||
17867 | } | ||
17868 | } | ||
17869 | |||
17870 | |||
17871 | /// <summary> | ||
17872 | /// Parses an ApprovedExeForElevation element. | ||
17873 | /// </summary> | ||
17874 | /// <param name="node">Element to parse</param> | ||
17875 | private void ParseApprovedExeForElevation(XElement node) | ||
17876 | { | ||
17877 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
17878 | Identifier id = null; | ||
17879 | string key = null; | ||
17880 | string valueName = null; | ||
17881 | YesNoType win64 = YesNoType.NotSet; | ||
17882 | |||
17883 | foreach (XAttribute attrib in node.Attributes()) | ||
17884 | { | ||
17885 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
17886 | { | ||
17887 | switch (attrib.Name.LocalName) | ||
17888 | { | ||
17889 | case "Id": | ||
17890 | id = this.core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
17891 | break; | ||
17892 | case "Key": | ||
17893 | key = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
17894 | break; | ||
17895 | case "Value": | ||
17896 | valueName = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
17897 | break; | ||
17898 | case "Win64": | ||
17899 | win64 = this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
17900 | break; | ||
17901 | default: | ||
17902 | this.core.UnexpectedAttribute(node, attrib); | ||
17903 | break; | ||
17904 | } | ||
17905 | } | ||
17906 | else | ||
17907 | { | ||
17908 | this.core.ParseExtensionAttribute(node, attrib); | ||
17909 | } | ||
17910 | } | ||
17911 | |||
17912 | if (null == id) | ||
17913 | { | ||
17914 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
17915 | } | ||
17916 | |||
17917 | if (null == key) | ||
17918 | { | ||
17919 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Key")); | ||
17920 | } | ||
17921 | |||
17922 | BundleApprovedExeForElevationAttributes attributes = BundleApprovedExeForElevationAttributes.None; | ||
17923 | |||
17924 | if (win64 == YesNoType.Yes) | ||
17925 | { | ||
17926 | attributes |= BundleApprovedExeForElevationAttributes.Win64; | ||
17927 | } | ||
17928 | |||
17929 | this.core.ParseForExtensionElements(node); | ||
17930 | |||
17931 | if (!this.core.EncounteredError) | ||
17932 | { | ||
17933 | WixApprovedExeForElevationRow wixApprovedExeForElevationRow = (WixApprovedExeForElevationRow)this.core.CreateRow(sourceLineNumbers, "WixApprovedExeForElevation", id); | ||
17934 | wixApprovedExeForElevationRow.Key = key; | ||
17935 | wixApprovedExeForElevationRow.ValueName = valueName; | ||
17936 | wixApprovedExeForElevationRow.Attributes = attributes; | ||
17937 | } | ||
17938 | } | ||
17939 | |||
17940 | /// <summary> | ||
17941 | /// Parses a Bundle element. | ||
17942 | /// </summary> | ||
17943 | /// <param name="node">Element to parse</param> | ||
17944 | private void ParseBundleElement(XElement node) | ||
17945 | { | ||
17946 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
17947 | string copyright = null; | ||
17948 | string aboutUrl = null; | ||
17949 | YesNoDefaultType compressed = YesNoDefaultType.Default; | ||
17950 | int disableModify = -1; | ||
17951 | YesNoType disableRemove = YesNoType.NotSet; | ||
17952 | string helpTelephone = null; | ||
17953 | string helpUrl = null; | ||
17954 | string manufacturer = null; | ||
17955 | string name = null; | ||
17956 | string tag = null; | ||
17957 | string updateUrl = null; | ||
17958 | string upgradeCode = null; | ||
17959 | string version = null; | ||
17960 | string condition = null; | ||
17961 | string parentName = null; | ||
17962 | |||
17963 | string fileSystemSafeBundleName = null; | ||
17964 | string logVariablePrefixAndExtension = null; | ||
17965 | string iconSourceFile = null; | ||
17966 | string splashScreenSourceFile = null; | ||
17967 | |||
17968 | // Process only standard attributes until the active section is initialized. | ||
17969 | foreach (XAttribute attrib in node.Attributes()) | ||
17970 | { | ||
17971 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
17972 | { | ||
17973 | switch (attrib.Name.LocalName) | ||
17974 | { | ||
17975 | case "AboutUrl": | ||
17976 | aboutUrl = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
17977 | break; | ||
17978 | case "Compressed": | ||
17979 | compressed = this.core.GetAttributeYesNoDefaultValue(sourceLineNumbers, attrib); | ||
17980 | break; | ||
17981 | case "Condition": | ||
17982 | condition = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
17983 | break; | ||
17984 | case "Copyright": | ||
17985 | copyright = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
17986 | break; | ||
17987 | case "DisableModify": | ||
17988 | string value = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
17989 | switch (value) | ||
17990 | { | ||
17991 | case "button": | ||
17992 | disableModify = 2; | ||
17993 | break; | ||
17994 | case "yes": | ||
17995 | disableModify = 1; | ||
17996 | break; | ||
17997 | case "no": | ||
17998 | disableModify = 0; | ||
17999 | break; | ||
18000 | default: | ||
18001 | this.core.OnMessage(WixErrors.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, value, "button", "yes", "no")); | ||
18002 | break; | ||
18003 | } | ||
18004 | break; | ||
18005 | case "DisableRemove": | ||
18006 | disableRemove = this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
18007 | break; | ||
18008 | case "DisableRepair": | ||
18009 | this.core.OnMessage(WixWarnings.DeprecatedAttribute(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); | ||
18010 | break; | ||
18011 | case "HelpTelephone": | ||
18012 | helpTelephone = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
18013 | break; | ||
18014 | case "HelpUrl": | ||
18015 | helpUrl = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
18016 | break; | ||
18017 | case "Manufacturer": | ||
18018 | manufacturer = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
18019 | break; | ||
18020 | case "IconSourceFile": | ||
18021 | iconSourceFile = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
18022 | break; | ||
18023 | case "Name": | ||
18024 | name = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
18025 | break; | ||
18026 | case "ParentName": | ||
18027 | parentName = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
18028 | break; | ||
18029 | case "SplashScreenSourceFile": | ||
18030 | splashScreenSourceFile = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
18031 | break; | ||
18032 | case "Tag": | ||
18033 | tag = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
18034 | break; | ||
18035 | case "UpdateUrl": | ||
18036 | updateUrl = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
18037 | break; | ||
18038 | case "UpgradeCode": | ||
18039 | upgradeCode = this.core.GetAttributeGuidValue(sourceLineNumbers, attrib, false); | ||
18040 | break; | ||
18041 | case "Version": | ||
18042 | version = this.core.GetAttributeVersionValue(sourceLineNumbers, attrib); | ||
18043 | break; | ||
18044 | default: | ||
18045 | this.core.UnexpectedAttribute(node, attrib); | ||
18046 | break; | ||
18047 | } | ||
18048 | } | ||
18049 | } | ||
18050 | |||
18051 | if (String.IsNullOrEmpty(version)) | ||
18052 | { | ||
18053 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Version")); | ||
18054 | } | ||
18055 | else if (!CompilerCore.IsValidModuleOrBundleVersion(version)) | ||
18056 | { | ||
18057 | this.core.OnMessage(WixWarnings.InvalidModuleOrBundleVersion(sourceLineNumbers, "Bundle", version)); | ||
18058 | } | ||
18059 | |||
18060 | if (String.IsNullOrEmpty(upgradeCode)) | ||
18061 | { | ||
18062 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "UpgradeCode")); | ||
18063 | } | ||
18064 | |||
18065 | if (String.IsNullOrEmpty(copyright)) | ||
18066 | { | ||
18067 | if (String.IsNullOrEmpty(manufacturer)) | ||
18068 | { | ||
18069 | copyright = "Copyright (c). All rights reserved."; | ||
18070 | } | ||
18071 | else | ||
18072 | { | ||
18073 | copyright = String.Format("Copyright (c) {0}. All rights reserved.", manufacturer); | ||
18074 | } | ||
18075 | } | ||
18076 | |||
18077 | if (String.IsNullOrEmpty(name)) | ||
18078 | { | ||
18079 | logVariablePrefixAndExtension = String.Concat("WixBundleLog:Setup.log"); | ||
18080 | } | ||
18081 | else | ||
18082 | { | ||
18083 | // Ensure only allowable path characters are in "name" (and change spaces to underscores). | ||
18084 | fileSystemSafeBundleName = CompilerCore.MakeValidLongFileName(name.Replace(' ', '_'), "_"); | ||
18085 | logVariablePrefixAndExtension = String.Concat("WixBundleLog:", fileSystemSafeBundleName, ".log"); | ||
18086 | } | ||
18087 | |||
18088 | this.activeName = String.IsNullOrEmpty(name) ? Common.GenerateGuid() : name; | ||
18089 | this.core.CreateActiveSection(this.activeName, SectionType.Bundle, 0); | ||
18090 | |||
18091 | // Now that the active section is initialized, process only extension attributes. | ||
18092 | foreach (XAttribute attrib in node.Attributes()) | ||
18093 | { | ||
18094 | if (!String.IsNullOrEmpty(attrib.Name.NamespaceName) && CompilerCore.WixNamespace != attrib.Name.Namespace) | ||
18095 | { | ||
18096 | this.core.ParseExtensionAttribute(node, attrib); | ||
18097 | } | ||
18098 | } | ||
18099 | |||
18100 | bool baSeen = false; | ||
18101 | bool chainSeen = false; | ||
18102 | bool logSeen = false; | ||
18103 | |||
18104 | foreach (XElement child in node.Elements()) | ||
18105 | { | ||
18106 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
18107 | { | ||
18108 | switch (child.Name.LocalName) | ||
18109 | { | ||
18110 | case "ApprovedExeForElevation": | ||
18111 | this.ParseApprovedExeForElevation(child); | ||
18112 | break; | ||
18113 | case "BootstrapperApplication": | ||
18114 | if (baSeen) | ||
18115 | { | ||
18116 | SourceLineNumber childSourceLineNumbers = Preprocessor.GetSourceLineNumbers(child); | ||
18117 | this.core.OnMessage(WixErrors.TooManyChildren(childSourceLineNumbers, node.Name.LocalName, "BootstrapperApplication")); | ||
18118 | } | ||
18119 | this.ParseBootstrapperApplicationElement(child); | ||
18120 | baSeen = true; | ||
18121 | break; | ||
18122 | case "BootstrapperApplicationRef": | ||
18123 | this.ParseBootstrapperApplicationRefElement(child); | ||
18124 | break; | ||
18125 | case "OptionalUpdateRegistration": | ||
18126 | this.ParseOptionalUpdateRegistrationElement(child, manufacturer, parentName, name); | ||
18127 | break; | ||
18128 | case "Catalog": | ||
18129 | this.ParseCatalogElement(child); | ||
18130 | break; | ||
18131 | case "Chain": | ||
18132 | if (chainSeen) | ||
18133 | { | ||
18134 | SourceLineNumber childSourceLineNumbers = Preprocessor.GetSourceLineNumbers(child); | ||
18135 | this.core.OnMessage(WixErrors.TooManyChildren(childSourceLineNumbers, node.Name.LocalName, "Chain")); | ||
18136 | } | ||
18137 | this.ParseChainElement(child); | ||
18138 | chainSeen = true; | ||
18139 | break; | ||
18140 | case "Container": | ||
18141 | this.ParseContainerElement(child); | ||
18142 | break; | ||
18143 | case "ContainerRef": | ||
18144 | this.ParseSimpleRefElement(child, "WixBundleContainer"); | ||
18145 | break; | ||
18146 | case "Log": | ||
18147 | if (logSeen) | ||
18148 | { | ||
18149 | SourceLineNumber childSourceLineNumbers = Preprocessor.GetSourceLineNumbers(child); | ||
18150 | this.core.OnMessage(WixErrors.TooManyChildren(childSourceLineNumbers, node.Name.LocalName, "Log")); | ||
18151 | } | ||
18152 | logVariablePrefixAndExtension = this.ParseLogElement(child, fileSystemSafeBundleName); | ||
18153 | logSeen = true; | ||
18154 | break; | ||
18155 | case "PayloadGroup": | ||
18156 | this.ParsePayloadGroupElement(child, ComplexReferenceParentType.Layout, "BundleLayoutOnlyPayloads"); | ||
18157 | break; | ||
18158 | case "PayloadGroupRef": | ||
18159 | this.ParsePayloadGroupRefElement(child, ComplexReferenceParentType.Layout, "BundleLayoutOnlyPayloads", ComplexReferenceChildType.Unknown, null); | ||
18160 | break; | ||
18161 | case "RelatedBundle": | ||
18162 | this.ParseRelatedBundleElement(child); | ||
18163 | break; | ||
18164 | case "Update": | ||
18165 | this.ParseUpdateElement(child); | ||
18166 | break; | ||
18167 | case "Variable": | ||
18168 | this.ParseVariableElement(child); | ||
18169 | break; | ||
18170 | case "WixVariable": | ||
18171 | this.ParseWixVariableElement(child); | ||
18172 | break; | ||
18173 | default: | ||
18174 | this.core.UnexpectedElement(node, child); | ||
18175 | break; | ||
18176 | } | ||
18177 | } | ||
18178 | else | ||
18179 | { | ||
18180 | this.core.ParseExtensionElement(node, child); | ||
18181 | } | ||
18182 | } | ||
18183 | |||
18184 | |||
18185 | if (!chainSeen) | ||
18186 | { | ||
18187 | this.core.OnMessage(WixErrors.ExpectedElement(sourceLineNumbers, node.Name.LocalName, "Chain")); | ||
18188 | } | ||
18189 | |||
18190 | if (!this.core.EncounteredError) | ||
18191 | { | ||
18192 | if (null != upgradeCode) | ||
18193 | { | ||
18194 | Row relatedBundleRow = this.core.CreateRow(sourceLineNumbers, "WixRelatedBundle"); | ||
18195 | relatedBundleRow[0] = upgradeCode; | ||
18196 | relatedBundleRow[1] = (int)Wix.RelatedBundle.ActionType.Upgrade; | ||
18197 | } | ||
18198 | |||
18199 | WixBundleContainerRow containerRow = (WixBundleContainerRow)this.core.CreateRow(sourceLineNumbers, "WixBundleContainer"); | ||
18200 | containerRow.Id = Compiler.BurnDefaultAttachedContainerId; | ||
18201 | containerRow.Name = "bundle-attached.cab"; | ||
18202 | containerRow.Type = ContainerType.Attached; | ||
18203 | |||
18204 | Row row = this.core.CreateRow(sourceLineNumbers, "WixBundle"); | ||
18205 | row[0] = version; | ||
18206 | row[1] = copyright; | ||
18207 | row[2] = name; | ||
18208 | row[3] = aboutUrl; | ||
18209 | if (-1 != disableModify) | ||
18210 | { | ||
18211 | row[4] = disableModify; | ||
18212 | } | ||
18213 | if (YesNoType.NotSet != disableRemove) | ||
18214 | { | ||
18215 | row[5] = (YesNoType.Yes == disableRemove) ? 1 : 0; | ||
18216 | } | ||
18217 | // row[6] - (deprecated) "disable repair" | ||
18218 | row[7] = helpTelephone; | ||
18219 | row[8] = helpUrl; | ||
18220 | row[9] = manufacturer; | ||
18221 | row[10] = updateUrl; | ||
18222 | if (YesNoDefaultType.Default != compressed) | ||
18223 | { | ||
18224 | row[11] = (YesNoDefaultType.Yes == compressed) ? 1 : 0; | ||
18225 | } | ||
18226 | |||
18227 | row[12] = logVariablePrefixAndExtension; | ||
18228 | row[13] = iconSourceFile; | ||
18229 | row[14] = splashScreenSourceFile; | ||
18230 | row[15] = condition; | ||
18231 | row[16] = tag; | ||
18232 | row[17] = this.CurrentPlatform.ToString(); | ||
18233 | row[18] = parentName; | ||
18234 | row[19] = upgradeCode; | ||
18235 | |||
18236 | // Ensure that the bundle stores the well-known persisted values. | ||
18237 | WixBundleVariableRow bundleNameWellKnownVariable = (WixBundleVariableRow)this.core.CreateRow(sourceLineNumbers, "WixBundleVariable"); | ||
18238 | bundleNameWellKnownVariable.Id = Compiler.BURN_BUNDLE_NAME; | ||
18239 | bundleNameWellKnownVariable.Hidden = false; | ||
18240 | bundleNameWellKnownVariable.Persisted = true; | ||
18241 | |||
18242 | WixBundleVariableRow bundleOriginalSourceWellKnownVariable = (WixBundleVariableRow)this.core.CreateRow(sourceLineNumbers, "WixBundleVariable"); | ||
18243 | bundleOriginalSourceWellKnownVariable.Id = Compiler.BURN_BUNDLE_ORIGINAL_SOURCE; | ||
18244 | bundleOriginalSourceWellKnownVariable.Hidden = false; | ||
18245 | bundleOriginalSourceWellKnownVariable.Persisted = true; | ||
18246 | |||
18247 | WixBundleVariableRow bundleOriginalSourceFolderWellKnownVariable = (WixBundleVariableRow)this.core.CreateRow(sourceLineNumbers, "WixBundleVariable"); | ||
18248 | bundleOriginalSourceFolderWellKnownVariable.Id = Compiler.BURN_BUNDLE_ORIGINAL_SOURCE_FOLDER; | ||
18249 | bundleOriginalSourceFolderWellKnownVariable.Hidden = false; | ||
18250 | bundleOriginalSourceFolderWellKnownVariable.Persisted = true; | ||
18251 | |||
18252 | WixBundleVariableRow bundleLastUsedSourceWellKnownVariable = (WixBundleVariableRow)this.core.CreateRow(sourceLineNumbers, "WixBundleVariable"); | ||
18253 | bundleLastUsedSourceWellKnownVariable.Id = Compiler.BURN_BUNDLE_LAST_USED_SOURCE; | ||
18254 | bundleLastUsedSourceWellKnownVariable.Hidden = false; | ||
18255 | bundleLastUsedSourceWellKnownVariable.Persisted = true; | ||
18256 | } | ||
18257 | } | ||
18258 | |||
18259 | /// <summary> | ||
18260 | /// Parse a Container element. | ||
18261 | /// </summary> | ||
18262 | /// <param name="node">Element to parse</param> | ||
18263 | private string ParseLogElement(XElement node, string fileSystemSafeBundleName) | ||
18264 | { | ||
18265 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
18266 | YesNoType disableLog = YesNoType.NotSet; | ||
18267 | string variable = "WixBundleLog"; | ||
18268 | string logPrefix = fileSystemSafeBundleName ?? "Setup"; | ||
18269 | string logExtension = ".log"; | ||
18270 | |||
18271 | foreach (XAttribute attrib in node.Attributes()) | ||
18272 | { | ||
18273 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
18274 | { | ||
18275 | switch (attrib.Name.LocalName) | ||
18276 | { | ||
18277 | case "Disable": | ||
18278 | disableLog = this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
18279 | break; | ||
18280 | case "PathVariable": | ||
18281 | variable = this.core.GetAttributeValue(sourceLineNumbers, attrib, EmptyRule.CanBeEmpty); | ||
18282 | break; | ||
18283 | case "Prefix": | ||
18284 | logPrefix = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
18285 | break; | ||
18286 | case "Extension": | ||
18287 | logExtension = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
18288 | break; | ||
18289 | default: | ||
18290 | this.core.UnexpectedAttribute(node, attrib); | ||
18291 | break; | ||
18292 | } | ||
18293 | } | ||
18294 | else | ||
18295 | { | ||
18296 | this.core.ParseExtensionAttribute(node, attrib); | ||
18297 | } | ||
18298 | } | ||
18299 | |||
18300 | if (!logExtension.StartsWith(".", StringComparison.Ordinal)) | ||
18301 | { | ||
18302 | logExtension = String.Concat(".", logExtension); | ||
18303 | } | ||
18304 | |||
18305 | this.core.ParseForExtensionElements(node); | ||
18306 | |||
18307 | return YesNoType.Yes == disableLog ? null : String.Concat(variable, ":", logPrefix, logExtension); | ||
18308 | } | ||
18309 | |||
18310 | /// <summary> | ||
18311 | /// Parse a Catalog element. | ||
18312 | /// </summary> | ||
18313 | /// <param name="node">Element to parse</param> | ||
18314 | private void ParseCatalogElement(XElement node) | ||
18315 | { | ||
18316 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
18317 | Identifier id = null; | ||
18318 | string sourceFile = null; | ||
18319 | |||
18320 | foreach (XAttribute attrib in node.Attributes()) | ||
18321 | { | ||
18322 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
18323 | { | ||
18324 | switch (attrib.Name.LocalName) | ||
18325 | { | ||
18326 | case "Id": | ||
18327 | id = this.core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
18328 | break; | ||
18329 | case "SourceFile": | ||
18330 | sourceFile = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
18331 | break; | ||
18332 | default: | ||
18333 | this.core.UnexpectedAttribute(node, attrib); | ||
18334 | break; | ||
18335 | } | ||
18336 | } | ||
18337 | } | ||
18338 | |||
18339 | if (null == id) | ||
18340 | { | ||
18341 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
18342 | } | ||
18343 | |||
18344 | if (null == sourceFile) | ||
18345 | { | ||
18346 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "SourceFile")); | ||
18347 | } | ||
18348 | |||
18349 | this.core.ParseForExtensionElements(node); | ||
18350 | |||
18351 | // Create catalog row | ||
18352 | if (!this.core.EncounteredError) | ||
18353 | { | ||
18354 | this.CreatePayloadRow(sourceLineNumbers, id, Path.GetFileName(sourceFile), sourceFile, null, ComplexReferenceParentType.Container, Compiler.BurnUXContainerId, ComplexReferenceChildType.Unknown, null, YesNoDefaultType.Yes, YesNoType.Yes, null, null, null); | ||
18355 | |||
18356 | WixBundleCatalogRow wixCatalogRow = (WixBundleCatalogRow)this.core.CreateRow(sourceLineNumbers, "WixBundleCatalog", id); | ||
18357 | wixCatalogRow.Payload = id.Id; | ||
18358 | } | ||
18359 | } | ||
18360 | |||
18361 | /// <summary> | ||
18362 | /// Parse a Container element. | ||
18363 | /// </summary> | ||
18364 | /// <param name="node">Element to parse</param> | ||
18365 | private void ParseContainerElement(XElement node) | ||
18366 | { | ||
18367 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
18368 | Identifier id = null; | ||
18369 | string downloadUrl = null; | ||
18370 | string name = null; | ||
18371 | ContainerType type = ContainerType.Detached; | ||
18372 | |||
18373 | foreach (XAttribute attrib in node.Attributes()) | ||
18374 | { | ||
18375 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
18376 | { | ||
18377 | switch (attrib.Name.LocalName) | ||
18378 | { | ||
18379 | case "Id": | ||
18380 | id = this.core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
18381 | break; | ||
18382 | case "DownloadUrl": | ||
18383 | downloadUrl = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
18384 | break; | ||
18385 | case "Name": | ||
18386 | name = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
18387 | break; | ||
18388 | case "Type": | ||
18389 | string typeString = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
18390 | if (!Enum.TryParse<ContainerType>(typeString, out type)) | ||
18391 | { | ||
18392 | this.core.OnMessage(WixErrors.IllegalAttributeValueWithLegalList(sourceLineNumbers, node.Name.LocalName, "Type", typeString, "attached, detached")); | ||
18393 | } | ||
18394 | break; | ||
18395 | default: | ||
18396 | this.core.UnexpectedAttribute(node, attrib); | ||
18397 | break; | ||
18398 | } | ||
18399 | } | ||
18400 | else | ||
18401 | { | ||
18402 | this.core.ParseExtensionAttribute(node, attrib); | ||
18403 | } | ||
18404 | } | ||
18405 | |||
18406 | if (null == id) | ||
18407 | { | ||
18408 | if (!String.IsNullOrEmpty(name)) | ||
18409 | { | ||
18410 | id = this.core.CreateIdentifierFromFilename(name); | ||
18411 | } | ||
18412 | |||
18413 | if (null == id) | ||
18414 | { | ||
18415 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
18416 | id = Identifier.Invalid; | ||
18417 | } | ||
18418 | else if (!Common.IsIdentifier(id.Id)) | ||
18419 | { | ||
18420 | this.core.OnMessage(WixErrors.IllegalIdentifier(sourceLineNumbers, node.Name.LocalName, "Id", id.Id)); | ||
18421 | } | ||
18422 | } | ||
18423 | else if (null == name) | ||
18424 | { | ||
18425 | name = id.Id; | ||
18426 | } | ||
18427 | |||
18428 | if (!String.IsNullOrEmpty(downloadUrl) && ContainerType.Detached != type) | ||
18429 | { | ||
18430 | this.core.OnMessage(WixErrors.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "DownloadUrl", "Type", "attached")); | ||
18431 | } | ||
18432 | |||
18433 | foreach (XElement child in node.Elements()) | ||
18434 | { | ||
18435 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
18436 | { | ||
18437 | switch (child.Name.LocalName) | ||
18438 | { | ||
18439 | case "PackageGroupRef": | ||
18440 | this.ParsePackageGroupRefElement(child, ComplexReferenceParentType.Container, id.Id); | ||
18441 | break; | ||
18442 | default: | ||
18443 | this.core.UnexpectedElement(node, child); | ||
18444 | break; | ||
18445 | } | ||
18446 | } | ||
18447 | else | ||
18448 | { | ||
18449 | this.core.ParseExtensionElement(node, child); | ||
18450 | } | ||
18451 | } | ||
18452 | |||
18453 | |||
18454 | if (!this.core.EncounteredError) | ||
18455 | { | ||
18456 | WixBundleContainerRow row = (WixBundleContainerRow)this.core.CreateRow(sourceLineNumbers, "WixBundleContainer", id); | ||
18457 | row.Name = name; | ||
18458 | row.Type = type; | ||
18459 | row.DownloadUrl = downloadUrl; | ||
18460 | } | ||
18461 | } | ||
18462 | |||
18463 | /// <summary> | ||
18464 | /// Parse the BoostrapperApplication element. | ||
18465 | /// </summary> | ||
18466 | /// <param name="node">Element to parse</param> | ||
18467 | private void ParseBootstrapperApplicationElement(XElement node) | ||
18468 | { | ||
18469 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
18470 | string id = null; | ||
18471 | string previousId = null; | ||
18472 | ComplexReferenceChildType previousType = ComplexReferenceChildType.Unknown; | ||
18473 | |||
18474 | // The BootstrapperApplication element acts like a Payload element so delegate to the "Payload" attribute parsing code to parse and create a Payload entry. | ||
18475 | id = this.ParsePayloadElementContent(node, ComplexReferenceParentType.Container, Compiler.BurnUXContainerId, previousType, previousId, false); | ||
18476 | if (null != id) | ||
18477 | { | ||
18478 | previousId = id; | ||
18479 | previousType = ComplexReferenceChildType.Payload; | ||
18480 | } | ||
18481 | |||
18482 | foreach (XElement child in node.Elements()) | ||
18483 | { | ||
18484 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
18485 | { | ||
18486 | switch (child.Name.LocalName) | ||
18487 | { | ||
18488 | case "Payload": | ||
18489 | previousId = this.ParsePayloadElement(child, ComplexReferenceParentType.Container, Compiler.BurnUXContainerId, previousType, previousId); | ||
18490 | previousType = ComplexReferenceChildType.Payload; | ||
18491 | break; | ||
18492 | case "PayloadGroupRef": | ||
18493 | previousId = this.ParsePayloadGroupRefElement(child, ComplexReferenceParentType.Container, Compiler.BurnUXContainerId, previousType, previousId); | ||
18494 | previousType = ComplexReferenceChildType.PayloadGroup; | ||
18495 | break; | ||
18496 | default: | ||
18497 | this.core.UnexpectedElement(node, child); | ||
18498 | break; | ||
18499 | } | ||
18500 | } | ||
18501 | else | ||
18502 | { | ||
18503 | this.core.ParseExtensionElement(node, child); | ||
18504 | } | ||
18505 | } | ||
18506 | |||
18507 | if (null == previousId) | ||
18508 | { | ||
18509 | // We need *either* <Payload> or <PayloadGroupRef> or even just @SourceFile on the BA... | ||
18510 | // but we just say there's a missing <Payload>. | ||
18511 | // TODO: Is there a better message for this? | ||
18512 | this.core.OnMessage(WixErrors.ExpectedElement(sourceLineNumbers, node.Name.LocalName, "Payload")); | ||
18513 | } | ||
18514 | |||
18515 | // Add the application as an attached container and if an Id was provided add that too. | ||
18516 | if (!this.core.EncounteredError) | ||
18517 | { | ||
18518 | WixBundleContainerRow containerRow = (WixBundleContainerRow)this.core.CreateRow(sourceLineNumbers, "WixBundleContainer"); | ||
18519 | containerRow.Id = Compiler.BurnUXContainerId; | ||
18520 | containerRow.Name = "bundle-ux.cab"; | ||
18521 | containerRow.Type = ContainerType.Attached; | ||
18522 | |||
18523 | if (!String.IsNullOrEmpty(id)) | ||
18524 | { | ||
18525 | Row row = this.core.CreateRow(sourceLineNumbers, "WixBootstrapperApplication"); | ||
18526 | row[0] = id; | ||
18527 | } | ||
18528 | } | ||
18529 | } | ||
18530 | |||
18531 | /// <summary> | ||
18532 | /// Parse the BoostrapperApplicationRef element. | ||
18533 | /// </summary> | ||
18534 | /// <param name="node">Element to parse</param> | ||
18535 | private void ParseBootstrapperApplicationRefElement(XElement node) | ||
18536 | { | ||
18537 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
18538 | string id = null; | ||
18539 | string previousId = null; | ||
18540 | ComplexReferenceChildType previousType = ComplexReferenceChildType.Unknown; | ||
18541 | |||
18542 | foreach (XAttribute attrib in node.Attributes()) | ||
18543 | { | ||
18544 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
18545 | { | ||
18546 | switch (attrib.Name.LocalName) | ||
18547 | { | ||
18548 | case "Id": | ||
18549 | id = this.core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
18550 | break; | ||
18551 | default: | ||
18552 | this.core.UnexpectedAttribute(node, attrib); | ||
18553 | break; | ||
18554 | } | ||
18555 | } | ||
18556 | else | ||
18557 | { | ||
18558 | this.core.ParseExtensionAttribute(node, attrib); | ||
18559 | } | ||
18560 | } | ||
18561 | |||
18562 | foreach (XElement child in node.Elements()) | ||
18563 | { | ||
18564 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
18565 | { | ||
18566 | switch (child.Name.LocalName) | ||
18567 | { | ||
18568 | case "Payload": | ||
18569 | previousId = this.ParsePayloadElement(child, ComplexReferenceParentType.Container, Compiler.BurnUXContainerId, previousType, previousId); | ||
18570 | previousType = ComplexReferenceChildType.Payload; | ||
18571 | break; | ||
18572 | case "PayloadGroupRef": | ||
18573 | previousId = this.ParsePayloadGroupRefElement(child, ComplexReferenceParentType.Container, Compiler.BurnUXContainerId, previousType, previousId); | ||
18574 | previousType = ComplexReferenceChildType.PayloadGroup; | ||
18575 | break; | ||
18576 | default: | ||
18577 | this.core.UnexpectedElement(node, child); | ||
18578 | break; | ||
18579 | } | ||
18580 | } | ||
18581 | else | ||
18582 | { | ||
18583 | this.core.ParseExtensionElement(node, child); | ||
18584 | } | ||
18585 | } | ||
18586 | |||
18587 | |||
18588 | if (String.IsNullOrEmpty(id)) | ||
18589 | { | ||
18590 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
18591 | } | ||
18592 | else | ||
18593 | { | ||
18594 | this.core.CreateSimpleReference(sourceLineNumbers, "WixBootstrapperApplication", id); | ||
18595 | } | ||
18596 | } | ||
18597 | |||
18598 | /// <summary> | ||
18599 | /// Parse the OptionalUpdateRegistration element. | ||
18600 | /// </summary> | ||
18601 | /// <param name="node">The element to parse.</param> | ||
18602 | /// <param name="defaultManufacturer">The manufacturer.</param> | ||
18603 | /// <param name="defaultProductFamily">The product family.</param> | ||
18604 | /// <param name="defaultName">The bundle name.</param> | ||
18605 | private void ParseOptionalUpdateRegistrationElement(XElement node, string defaultManufacturer, string defaultProductFamily, string defaultName) | ||
18606 | { | ||
18607 | const string defaultClassification = "Update"; | ||
18608 | |||
18609 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
18610 | string manufacturer = null; | ||
18611 | string department = null; | ||
18612 | string productFamily = null; | ||
18613 | string name = null; | ||
18614 | string classification = defaultClassification; | ||
18615 | |||
18616 | foreach (XAttribute attrib in node.Attributes()) | ||
18617 | { | ||
18618 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
18619 | { | ||
18620 | switch (attrib.Name.LocalName) | ||
18621 | { | ||
18622 | case "Manufacturer": | ||
18623 | manufacturer = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
18624 | break; | ||
18625 | case "Department": | ||
18626 | department = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
18627 | break; | ||
18628 | case "ProductFamily": | ||
18629 | productFamily = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
18630 | break; | ||
18631 | case "Name": | ||
18632 | name = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
18633 | break; | ||
18634 | case "Classification": | ||
18635 | classification = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
18636 | break; | ||
18637 | default: | ||
18638 | this.core.UnexpectedAttribute(node, attrib); | ||
18639 | break; | ||
18640 | } | ||
18641 | } | ||
18642 | else | ||
18643 | { | ||
18644 | this.core.ParseExtensionAttribute(node, attrib); | ||
18645 | } | ||
18646 | } | ||
18647 | |||
18648 | if (String.IsNullOrEmpty(manufacturer)) | ||
18649 | { | ||
18650 | if (!String.IsNullOrEmpty(defaultManufacturer)) | ||
18651 | { | ||
18652 | manufacturer = defaultManufacturer; | ||
18653 | } | ||
18654 | else | ||
18655 | { | ||
18656 | this.core.OnMessage(WixErrors.ExpectedAttributeInElementOrParent(sourceLineNumbers, node.Name.LocalName, "Manufacturer", node.Parent.Name.LocalName)); | ||
18657 | } | ||
18658 | } | ||
18659 | |||
18660 | if (String.IsNullOrEmpty(productFamily)) | ||
18661 | { | ||
18662 | if (!String.IsNullOrEmpty(defaultProductFamily)) | ||
18663 | { | ||
18664 | productFamily = defaultProductFamily; | ||
18665 | } | ||
18666 | } | ||
18667 | |||
18668 | if (String.IsNullOrEmpty(name)) | ||
18669 | { | ||
18670 | if (!String.IsNullOrEmpty(defaultName)) | ||
18671 | { | ||
18672 | name = defaultName; | ||
18673 | } | ||
18674 | else | ||
18675 | { | ||
18676 | this.core.OnMessage(WixErrors.ExpectedAttributeInElementOrParent(sourceLineNumbers, node.Name.LocalName, "Name", node.Parent.Name.LocalName)); | ||
18677 | } | ||
18678 | } | ||
18679 | |||
18680 | if (String.IsNullOrEmpty(classification)) | ||
18681 | { | ||
18682 | this.core.OnMessage(WixErrors.IllegalEmptyAttributeValue(sourceLineNumbers, node.Name.LocalName, "Classification", defaultClassification)); | ||
18683 | } | ||
18684 | |||
18685 | this.core.ParseForExtensionElements(node); | ||
18686 | |||
18687 | if (!this.core.EncounteredError) | ||
18688 | { | ||
18689 | Row row = this.core.CreateRow(sourceLineNumbers, "WixUpdateRegistration"); | ||
18690 | row[0] = manufacturer; | ||
18691 | row[1] = department; | ||
18692 | row[2] = productFamily; | ||
18693 | row[3] = name; | ||
18694 | row[4] = classification; | ||
18695 | } | ||
18696 | } | ||
18697 | |||
18698 | /// <summary> | ||
18699 | /// Parse Payload element. | ||
18700 | /// </summary> | ||
18701 | /// <param name="node">Element to parse</param> | ||
18702 | /// <param name="parentType">ComplexReferenceParentType of parent element. (BA or PayloadGroup)</param> | ||
18703 | /// <param name="parentId">Identifier of parent element.</param> | ||
18704 | private string ParsePayloadElement(XElement node, ComplexReferenceParentType parentType, string parentId, ComplexReferenceChildType previousType, string previousId) | ||
18705 | { | ||
18706 | Debug.Assert(ComplexReferenceParentType.PayloadGroup == parentType || ComplexReferenceParentType.Package == parentType || ComplexReferenceParentType.Container == parentType); | ||
18707 | Debug.Assert(ComplexReferenceChildType.Unknown == previousType || ComplexReferenceChildType.PayloadGroup == previousType || ComplexReferenceChildType.Payload == previousType); | ||
18708 | |||
18709 | string id = ParsePayloadElementContent(node, parentType, parentId, previousType, previousId, true); | ||
18710 | Dictionary<string, string> context = new Dictionary<string, string>(); | ||
18711 | context["Id"] = id; | ||
18712 | |||
18713 | foreach (XElement child in node.Elements()) | ||
18714 | { | ||
18715 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
18716 | { | ||
18717 | switch (child.Name.LocalName) | ||
18718 | { | ||
18719 | default: | ||
18720 | this.core.UnexpectedElement(node, child); | ||
18721 | break; | ||
18722 | } | ||
18723 | } | ||
18724 | else | ||
18725 | { | ||
18726 | this.core.ParseExtensionElement(node, child, context); | ||
18727 | } | ||
18728 | } | ||
18729 | |||
18730 | return id; | ||
18731 | } | ||
18732 | |||
18733 | /// <summary> | ||
18734 | /// Parse the attributes of the Payload element. | ||
18735 | /// </summary> | ||
18736 | /// <param name="node">Element to parse</param> | ||
18737 | /// <param name="parentType">ComplexReferenceParentType of parent element.</param> | ||
18738 | /// <param name="parentId">Identifier of parent element.</param> | ||
18739 | private string ParsePayloadElementContent(XElement node, ComplexReferenceParentType parentType, string parentId, ComplexReferenceChildType previousType, string previousId, bool required) | ||
18740 | { | ||
18741 | Debug.Assert(ComplexReferenceParentType.PayloadGroup == parentType || ComplexReferenceParentType.Package == parentType || ComplexReferenceParentType.Container == parentType); | ||
18742 | |||
18743 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
18744 | YesNoDefaultType compressed = YesNoDefaultType.Default; | ||
18745 | YesNoType enableSignatureVerification = YesNoType.No; | ||
18746 | Identifier id = null; | ||
18747 | string name = null; | ||
18748 | string sourceFile = null; | ||
18749 | string downloadUrl = null; | ||
18750 | Wix.RemotePayload remotePayload = null; | ||
18751 | |||
18752 | // This list lets us evaluate extension attributes *after* all core attributes | ||
18753 | // have been parsed and dealt with, regardless of authoring order. | ||
18754 | List<XAttribute> extensionAttributes = new List<XAttribute>(); | ||
18755 | |||
18756 | foreach (XAttribute attrib in node.Attributes()) | ||
18757 | { | ||
18758 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
18759 | { | ||
18760 | switch (attrib.Name.LocalName) | ||
18761 | { | ||
18762 | case "Id": | ||
18763 | id = this.core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
18764 | break; | ||
18765 | case "Compressed": | ||
18766 | compressed = this.core.GetAttributeYesNoDefaultValue(sourceLineNumbers, attrib); | ||
18767 | break; | ||
18768 | case "Name": | ||
18769 | name = this.core.GetAttributeLongFilename(sourceLineNumbers, attrib, false, true); | ||
18770 | break; | ||
18771 | case "SourceFile": | ||
18772 | sourceFile = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
18773 | break; | ||
18774 | case "DownloadUrl": | ||
18775 | downloadUrl = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
18776 | break; | ||
18777 | case "EnableSignatureVerification": | ||
18778 | enableSignatureVerification = this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
18779 | break; | ||
18780 | default: | ||
18781 | this.core.UnexpectedAttribute(node, attrib); | ||
18782 | break; | ||
18783 | } | ||
18784 | } | ||
18785 | else | ||
18786 | { | ||
18787 | extensionAttributes.Add(attrib); | ||
18788 | } | ||
18789 | } | ||
18790 | |||
18791 | if (!required && null == sourceFile) | ||
18792 | { | ||
18793 | // Nothing left to do! | ||
18794 | return null; | ||
18795 | } | ||
18796 | |||
18797 | if (null == id) | ||
18798 | { | ||
18799 | id = this.core.CreateIdentifier("pay", (null != sourceFile) ? sourceFile.ToUpperInvariant() : String.Empty); | ||
18800 | } | ||
18801 | |||
18802 | // Now that the PayloadId is known, we can parse the extension attributes. | ||
18803 | Dictionary<string, string> context = new Dictionary<string, string>(); | ||
18804 | context["Id"] = id.Id; | ||
18805 | |||
18806 | foreach (XAttribute extensionAttribute in extensionAttributes) | ||
18807 | { | ||
18808 | this.core.ParseExtensionAttribute(node, extensionAttribute, context); | ||
18809 | } | ||
18810 | |||
18811 | // We only handle the elements we care about. Let caller handle other children. | ||
18812 | foreach (XElement child in node.Elements(CompilerCore.WixNamespace + "RemotePayload")) | ||
18813 | { | ||
18814 | SourceLineNumber childSourceLineNumbers = Preprocessor.GetSourceLineNumbers(child); | ||
18815 | |||
18816 | if (CompilerCore.WixNamespace == node.Name.Namespace && node.Name.LocalName != "ExePackage") | ||
18817 | { | ||
18818 | this.core.OnMessage(WixErrors.RemotePayloadUnsupported(childSourceLineNumbers)); | ||
18819 | continue; | ||
18820 | } | ||
18821 | |||
18822 | if (null != remotePayload) | ||
18823 | { | ||
18824 | this.core.OnMessage(WixErrors.TooManyChildren(childSourceLineNumbers, node.Name.LocalName, child.Name.LocalName)); | ||
18825 | } | ||
18826 | |||
18827 | remotePayload = this.ParseRemotePayloadElement(child); | ||
18828 | } | ||
18829 | |||
18830 | if (null != sourceFile && null != remotePayload) | ||
18831 | { | ||
18832 | this.core.OnMessage(WixErrors.UnexpectedElementWithAttribute(sourceLineNumbers, node.Name.LocalName, "RemotePayload", "SourceFile")); | ||
18833 | } | ||
18834 | else if (null == sourceFile && null == remotePayload) | ||
18835 | { | ||
18836 | this.core.OnMessage(WixErrors.ExpectedAttributeOrElement(sourceLineNumbers, node.Name.LocalName, "SourceFile", "RemotePayload")); | ||
18837 | } | ||
18838 | else if (null == sourceFile) | ||
18839 | { | ||
18840 | sourceFile = String.Empty; | ||
18841 | } | ||
18842 | |||
18843 | if (null == downloadUrl && null != remotePayload) | ||
18844 | { | ||
18845 | this.core.OnMessage(WixErrors.ExpectedAttributeWithElement(sourceLineNumbers, node.Name.LocalName, "DownloadUrl", "RemotePayload")); | ||
18846 | } | ||
18847 | |||
18848 | if (Compiler.BurnUXContainerId == parentId) | ||
18849 | { | ||
18850 | if (compressed == YesNoDefaultType.No) | ||
18851 | { | ||
18852 | core.OnMessage(WixWarnings.UxPayloadsOnlySupportEmbedding(sourceLineNumbers, sourceFile)); | ||
18853 | } | ||
18854 | |||
18855 | compressed = YesNoDefaultType.Yes; | ||
18856 | } | ||
18857 | |||
18858 | this.CreatePayloadRow(sourceLineNumbers, id, name, sourceFile, downloadUrl, parentType, parentId, previousType, previousId, compressed, enableSignatureVerification, null, null, remotePayload); | ||
18859 | |||
18860 | return id.Id; | ||
18861 | } | ||
18862 | |||
18863 | private Wix.RemotePayload ParseRemotePayloadElement(XElement node) | ||
18864 | { | ||
18865 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
18866 | Wix.RemotePayload remotePayload = new Wix.RemotePayload(); | ||
18867 | |||
18868 | foreach (XAttribute attrib in node.Attributes()) | ||
18869 | { | ||
18870 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
18871 | { | ||
18872 | switch (attrib.Name.LocalName) | ||
18873 | { | ||
18874 | case "CertificatePublicKey": | ||
18875 | remotePayload.CertificatePublicKey = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
18876 | break; | ||
18877 | case "CertificateThumbprint": | ||
18878 | remotePayload.CertificateThumbprint = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
18879 | break; | ||
18880 | case "Description": | ||
18881 | remotePayload.Description = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
18882 | break; | ||
18883 | case "Hash": | ||
18884 | remotePayload.Hash = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
18885 | break; | ||
18886 | case "ProductName": | ||
18887 | remotePayload.ProductName = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
18888 | break; | ||
18889 | case "Size": | ||
18890 | remotePayload.Size = this.core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, int.MaxValue); | ||
18891 | break; | ||
18892 | case "Version": | ||
18893 | remotePayload.Version = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
18894 | break; | ||
18895 | default: | ||
18896 | this.core.UnexpectedAttribute(node, attrib); | ||
18897 | break; | ||
18898 | } | ||
18899 | } | ||
18900 | else | ||
18901 | { | ||
18902 | this.core.ParseExtensionAttribute(node, attrib); | ||
18903 | } | ||
18904 | } | ||
18905 | |||
18906 | if (String.IsNullOrEmpty(remotePayload.ProductName)) | ||
18907 | { | ||
18908 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "ProductName")); | ||
18909 | } | ||
18910 | |||
18911 | if (String.IsNullOrEmpty(remotePayload.Description)) | ||
18912 | { | ||
18913 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Description")); | ||
18914 | } | ||
18915 | |||
18916 | if (String.IsNullOrEmpty(remotePayload.Hash)) | ||
18917 | { | ||
18918 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Hash")); | ||
18919 | } | ||
18920 | |||
18921 | if (0 == remotePayload.Size) | ||
18922 | { | ||
18923 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Size")); | ||
18924 | } | ||
18925 | |||
18926 | if (String.IsNullOrEmpty(remotePayload.Version)) | ||
18927 | { | ||
18928 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Version")); | ||
18929 | } | ||
18930 | |||
18931 | return remotePayload; | ||
18932 | } | ||
18933 | |||
18934 | /// <summary> | ||
18935 | /// Creates the row for a Payload. | ||
18936 | /// </summary> | ||
18937 | /// <param name="node">Element to parse</param> | ||
18938 | /// <param name="parentType">ComplexReferenceParentType of parent element</param> | ||
18939 | /// <param name="parentId">Identifier of parent element.</param> | ||
18940 | private WixBundlePayloadRow CreatePayloadRow(SourceLineNumber sourceLineNumbers, Identifier id, string name, string sourceFile, string downloadUrl, ComplexReferenceParentType parentType, | ||
18941 | string parentId, ComplexReferenceChildType previousType, string previousId, YesNoDefaultType compressed, YesNoType enableSignatureVerification, string displayName, string description, | ||
18942 | Wix.RemotePayload remotePayload) | ||
18943 | { | ||
18944 | WixBundlePayloadRow row = null; | ||
18945 | |||
18946 | if (!this.core.EncounteredError) | ||
18947 | { | ||
18948 | row = (WixBundlePayloadRow)this.core.CreateRow(sourceLineNumbers, "WixBundlePayload", id); | ||
18949 | row.Name = String.IsNullOrEmpty(name) ? Path.GetFileName(sourceFile) : name; | ||
18950 | row.SourceFile = sourceFile; | ||
18951 | row.DownloadUrl = downloadUrl; | ||
18952 | row.Compressed = compressed; | ||
18953 | row.UnresolvedSourceFile = sourceFile; // duplicate of sourceFile but in a string column so it won't get resolved to a full path during binding. | ||
18954 | row.DisplayName = displayName; | ||
18955 | row.Description = description; | ||
18956 | row.EnableSignatureValidation = (YesNoType.Yes == enableSignatureVerification); | ||
18957 | |||
18958 | if (null != remotePayload) | ||
18959 | { | ||
18960 | row.Description = remotePayload.Description; | ||
18961 | row.DisplayName = remotePayload.ProductName; | ||
18962 | row.Hash = remotePayload.Hash; | ||
18963 | row.PublicKey = remotePayload.CertificatePublicKey; | ||
18964 | row.Thumbprint = remotePayload.CertificateThumbprint; | ||
18965 | row.FileSize = remotePayload.Size; | ||
18966 | row.Version = remotePayload.Version; | ||
18967 | } | ||
18968 | |||
18969 | this.CreateGroupAndOrderingRows(sourceLineNumbers, parentType, parentId, ComplexReferenceChildType.Payload, id.Id, previousType, previousId); | ||
18970 | } | ||
18971 | |||
18972 | return row; | ||
18973 | } | ||
18974 | |||
18975 | /// <summary> | ||
18976 | /// Parse PayloadGroup element. | ||
18977 | /// </summary> | ||
18978 | /// <param name="node">Element to parse</param> | ||
18979 | /// <param name="parentType">Optional ComplexReferenceParentType of parent element. (typically another PayloadGroup)</param> | ||
18980 | /// <param name="parentId">Identifier of parent element.</param> | ||
18981 | private void ParsePayloadGroupElement(XElement node, ComplexReferenceParentType parentType, string parentId) | ||
18982 | { | ||
18983 | Debug.Assert(ComplexReferenceParentType.Unknown == parentType || ComplexReferenceParentType.Layout == parentType || ComplexReferenceParentType.PayloadGroup == parentType); | ||
18984 | |||
18985 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
18986 | Identifier id = null; | ||
18987 | |||
18988 | foreach (XAttribute attrib in node.Attributes()) | ||
18989 | { | ||
18990 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
18991 | { | ||
18992 | switch (attrib.Name.LocalName) | ||
18993 | { | ||
18994 | case "Id": | ||
18995 | id = this.core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
18996 | break; | ||
18997 | default: | ||
18998 | this.core.UnexpectedAttribute(node, attrib); | ||
18999 | break; | ||
19000 | } | ||
19001 | } | ||
19002 | else | ||
19003 | { | ||
19004 | this.core.ParseExtensionAttribute(node, attrib); | ||
19005 | } | ||
19006 | } | ||
19007 | |||
19008 | if (null == id) | ||
19009 | { | ||
19010 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
19011 | id = Identifier.Invalid; | ||
19012 | } | ||
19013 | |||
19014 | ComplexReferenceChildType previousType = ComplexReferenceChildType.Unknown; | ||
19015 | string previousId = null; | ||
19016 | foreach (XElement child in node.Elements()) | ||
19017 | { | ||
19018 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
19019 | { | ||
19020 | switch (child.Name.LocalName) | ||
19021 | { | ||
19022 | case "Payload": | ||
19023 | previousId = this.ParsePayloadElement(child, ComplexReferenceParentType.PayloadGroup, id.Id, previousType, previousId); | ||
19024 | previousType = ComplexReferenceChildType.Payload; | ||
19025 | break; | ||
19026 | case "PayloadGroupRef": | ||
19027 | previousId = this.ParsePayloadGroupRefElement(child, ComplexReferenceParentType.PayloadGroup, id.Id, previousType, previousId); | ||
19028 | previousType = ComplexReferenceChildType.PayloadGroup; | ||
19029 | break; | ||
19030 | default: | ||
19031 | this.core.UnexpectedElement(node, child); | ||
19032 | break; | ||
19033 | } | ||
19034 | } | ||
19035 | else | ||
19036 | { | ||
19037 | this.core.ParseExtensionElement(node, child); | ||
19038 | } | ||
19039 | } | ||
19040 | |||
19041 | |||
19042 | if (!this.core.EncounteredError) | ||
19043 | { | ||
19044 | this.core.CreateRow(sourceLineNumbers, "WixBundlePayloadGroup", id); | ||
19045 | |||
19046 | this.CreateGroupAndOrderingRows(sourceLineNumbers, parentType, parentId, ComplexReferenceChildType.PayloadGroup, id.Id, ComplexReferenceChildType.Unknown, null); | ||
19047 | } | ||
19048 | } | ||
19049 | |||
19050 | /// <summary> | ||
19051 | /// Parses a payload group reference element. | ||
19052 | /// </summary> | ||
19053 | /// <param name="node">Element to parse.</param> | ||
19054 | /// <param name="parentType">ComplexReferenceParentType of parent element (BA or PayloadGroup).</param> | ||
19055 | /// <param name="parentId">Identifier of parent element.</param> | ||
19056 | private string ParsePayloadGroupRefElement(XElement node, ComplexReferenceParentType parentType, string parentId, ComplexReferenceChildType previousType, string previousId) | ||
19057 | { | ||
19058 | Debug.Assert(ComplexReferenceParentType.Layout == parentType || ComplexReferenceParentType.PayloadGroup == parentType || ComplexReferenceParentType.Package == parentType || ComplexReferenceParentType.Container == parentType); | ||
19059 | Debug.Assert(ComplexReferenceChildType.Unknown == previousType || ComplexReferenceChildType.PayloadGroup == previousType || ComplexReferenceChildType.Payload == previousType); | ||
19060 | |||
19061 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
19062 | string id = null; | ||
19063 | |||
19064 | foreach (XAttribute attrib in node.Attributes()) | ||
19065 | { | ||
19066 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
19067 | { | ||
19068 | switch (attrib.Name.LocalName) | ||
19069 | { | ||
19070 | case "Id": | ||
19071 | id = this.core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
19072 | this.core.CreateSimpleReference(sourceLineNumbers, "WixBundlePayloadGroup", id); | ||
19073 | break; | ||
19074 | default: | ||
19075 | this.core.UnexpectedAttribute(node, attrib); | ||
19076 | break; | ||
19077 | } | ||
19078 | } | ||
19079 | else | ||
19080 | { | ||
19081 | this.core.ParseExtensionAttribute(node, attrib); | ||
19082 | } | ||
19083 | } | ||
19084 | |||
19085 | if (null == id) | ||
19086 | { | ||
19087 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
19088 | } | ||
19089 | |||
19090 | this.core.ParseForExtensionElements(node); | ||
19091 | |||
19092 | this.CreateGroupAndOrderingRows(sourceLineNumbers, parentType, parentId, ComplexReferenceChildType.PayloadGroup, id, previousType, previousId); | ||
19093 | |||
19094 | return id; | ||
19095 | } | ||
19096 | |||
19097 | /// <summary> | ||
19098 | /// Creates group and ordering information. | ||
19099 | /// </summary> | ||
19100 | /// <param name="sourceLineNumbers">Source line numbers.</param> | ||
19101 | /// <param name="parentType">Type of parent group, if known.</param> | ||
19102 | /// <param name="parentId">Identifier of parent group, if known.</param> | ||
19103 | /// <param name="type">Type of this item.</param> | ||
19104 | /// <param name="id">Identifier for this item.</param> | ||
19105 | /// <param name="previousType">Type of previous item, if known.</param> | ||
19106 | /// <param name="previousId">Identifier of previous item, if known</param> | ||
19107 | private void CreateGroupAndOrderingRows(SourceLineNumber sourceLineNumbers, | ||
19108 | ComplexReferenceParentType parentType, string parentId, | ||
19109 | ComplexReferenceChildType type, string id, | ||
19110 | ComplexReferenceChildType previousType, string previousId) | ||
19111 | { | ||
19112 | if (ComplexReferenceParentType.Unknown != parentType && null != parentId) | ||
19113 | { | ||
19114 | this.core.CreateWixGroupRow(sourceLineNumbers, parentType, parentId, type, id); | ||
19115 | } | ||
19116 | |||
19117 | if (ComplexReferenceChildType.Unknown != previousType && null != previousId) | ||
19118 | { | ||
19119 | this.CreateWixOrderingRow(sourceLineNumbers, type, id, previousType, previousId); | ||
19120 | } | ||
19121 | } | ||
19122 | |||
19123 | /// <summary> | ||
19124 | /// Parse ExitCode element. | ||
19125 | /// </summary> | ||
19126 | /// <param name="node">Element to parse</param> | ||
19127 | /// <param name="packageId">Id of parent element</param> | ||
19128 | private void ParseExitCodeElement(XElement node, string packageId) | ||
19129 | { | ||
19130 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
19131 | int value = CompilerConstants.IntegerNotSet; | ||
19132 | ExitCodeBehaviorType behavior = ExitCodeBehaviorType.NotSet; | ||
19133 | |||
19134 | foreach (XAttribute attrib in node.Attributes()) | ||
19135 | { | ||
19136 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
19137 | { | ||
19138 | switch (attrib.Name.LocalName) | ||
19139 | { | ||
19140 | case "Value": | ||
19141 | value = this.core.GetAttributeIntegerValue(sourceLineNumbers, attrib, int.MinValue + 2, int.MaxValue); | ||
19142 | break; | ||
19143 | case "Behavior": | ||
19144 | string behaviorString = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
19145 | if (!Enum.TryParse<ExitCodeBehaviorType>(behaviorString, true, out behavior)) | ||
19146 | { | ||
19147 | this.core.OnMessage(WixErrors.IllegalAttributeValueWithLegalList(sourceLineNumbers, node.Name.LocalName, "Behavior", behaviorString, "success, error, scheduleReboot, forceReboot")); | ||
19148 | } | ||
19149 | break; | ||
19150 | default: | ||
19151 | this.core.UnexpectedAttribute(node, attrib); | ||
19152 | break; | ||
19153 | } | ||
19154 | } | ||
19155 | else | ||
19156 | { | ||
19157 | this.core.ParseExtensionAttribute(node, attrib); | ||
19158 | } | ||
19159 | } | ||
19160 | |||
19161 | if (ExitCodeBehaviorType.NotSet == behavior) | ||
19162 | { | ||
19163 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Behavior")); | ||
19164 | } | ||
19165 | |||
19166 | this.core.ParseForExtensionElements(node); | ||
19167 | |||
19168 | if (!this.core.EncounteredError) | ||
19169 | { | ||
19170 | WixBundlePackageExitCodeRow row = (WixBundlePackageExitCodeRow)this.core.CreateRow(sourceLineNumbers, "WixBundlePackageExitCode"); | ||
19171 | row.ChainPackageId = packageId; | ||
19172 | row.Code = value; | ||
19173 | row.Behavior = behavior; | ||
19174 | } | ||
19175 | } | ||
19176 | |||
19177 | /// <summary> | ||
19178 | /// Parse Chain element. | ||
19179 | /// </summary> | ||
19180 | /// <param name="node">Element to parse</param> | ||
19181 | private void ParseChainElement(XElement node) | ||
19182 | { | ||
19183 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
19184 | WixChainAttributes attributes = WixChainAttributes.None; | ||
19185 | |||
19186 | foreach (XAttribute attrib in node.Attributes()) | ||
19187 | { | ||
19188 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
19189 | { | ||
19190 | switch (attrib.Name.LocalName) | ||
19191 | { | ||
19192 | case "DisableRollback": | ||
19193 | if (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
19194 | { | ||
19195 | attributes |= WixChainAttributes.DisableRollback; | ||
19196 | } | ||
19197 | break; | ||
19198 | case "DisableSystemRestore": | ||
19199 | if (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
19200 | { | ||
19201 | attributes |= WixChainAttributes.DisableSystemRestore; | ||
19202 | } | ||
19203 | break; | ||
19204 | case "ParallelCache": | ||
19205 | if (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
19206 | { | ||
19207 | attributes |= WixChainAttributes.ParallelCache; | ||
19208 | } | ||
19209 | break; | ||
19210 | default: | ||
19211 | this.core.UnexpectedAttribute(node, attrib); | ||
19212 | break; | ||
19213 | } | ||
19214 | } | ||
19215 | else | ||
19216 | { | ||
19217 | this.core.ParseExtensionAttribute(node, attrib); | ||
19218 | } | ||
19219 | } | ||
19220 | |||
19221 | // Ensure there is always a rollback boundary at the beginning of the chain. | ||
19222 | this.CreateRollbackBoundary(sourceLineNumbers, new Identifier("WixDefaultBoundary", AccessModifier.Public), YesNoType.Yes, YesNoType.No, ComplexReferenceParentType.PackageGroup, "WixChain", ComplexReferenceChildType.Unknown, null); | ||
19223 | |||
19224 | string previousId = "WixDefaultBoundary"; | ||
19225 | ComplexReferenceChildType previousType = ComplexReferenceChildType.Package; | ||
19226 | |||
19227 | foreach (XElement child in node.Elements()) | ||
19228 | { | ||
19229 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
19230 | { | ||
19231 | switch (child.Name.LocalName) | ||
19232 | { | ||
19233 | case "MsiPackage": | ||
19234 | previousId = this.ParseMsiPackageElement(child, ComplexReferenceParentType.PackageGroup, "WixChain", previousType, previousId); | ||
19235 | previousType = ComplexReferenceChildType.Package; | ||
19236 | break; | ||
19237 | case "MspPackage": | ||
19238 | previousId = this.ParseMspPackageElement(child, ComplexReferenceParentType.PackageGroup, "WixChain", previousType, previousId); | ||
19239 | previousType = ComplexReferenceChildType.Package; | ||
19240 | break; | ||
19241 | case "MsuPackage": | ||
19242 | previousId = this.ParseMsuPackageElement(child, ComplexReferenceParentType.PackageGroup, "WixChain", previousType, previousId); | ||
19243 | previousType = ComplexReferenceChildType.Package; | ||
19244 | break; | ||
19245 | case "ExePackage": | ||
19246 | previousId = this.ParseExePackageElement(child, ComplexReferenceParentType.PackageGroup, "WixChain", previousType, previousId); | ||
19247 | previousType = ComplexReferenceChildType.Package; | ||
19248 | break; | ||
19249 | case "RollbackBoundary": | ||
19250 | previousId = this.ParseRollbackBoundaryElement(child, ComplexReferenceParentType.PackageGroup, "WixChain", previousType, previousId); | ||
19251 | previousType = ComplexReferenceChildType.Package; | ||
19252 | break; | ||
19253 | case "PackageGroupRef": | ||
19254 | previousId = this.ParsePackageGroupRefElement(child, ComplexReferenceParentType.PackageGroup, "WixChain", previousType, previousId); | ||
19255 | previousType = ComplexReferenceChildType.PackageGroup; | ||
19256 | break; | ||
19257 | default: | ||
19258 | this.core.UnexpectedElement(node, child); | ||
19259 | break; | ||
19260 | } | ||
19261 | } | ||
19262 | else | ||
19263 | { | ||
19264 | this.core.ParseExtensionElement(node, child); | ||
19265 | } | ||
19266 | } | ||
19267 | |||
19268 | |||
19269 | if (null == previousId) | ||
19270 | { | ||
19271 | this.core.OnMessage(WixErrors.ExpectedElement(sourceLineNumbers, node.Name.LocalName, "MsiPackage", "ExePackage", "PackageGroupRef")); | ||
19272 | } | ||
19273 | |||
19274 | if (!this.core.EncounteredError) | ||
19275 | { | ||
19276 | WixChainRow row = (WixChainRow)this.core.CreateRow(sourceLineNumbers, "WixChain"); | ||
19277 | row.Attributes = attributes; | ||
19278 | } | ||
19279 | } | ||
19280 | |||
19281 | /// <summary> | ||
19282 | /// Parse MsiPackage element | ||
19283 | /// </summary> | ||
19284 | /// <param name="node">Element to parse</param> | ||
19285 | /// <param name="parentType">Type of parent group, if known.</param> | ||
19286 | /// <param name="parentId">Identifier of parent group, if known.</param> | ||
19287 | /// <param name="previousType">Type of previous item, if known.</param> | ||
19288 | /// <param name="previousId">Identifier of previous item, if known</param> | ||
19289 | /// <returns>Identifier for package element.</returns> | ||
19290 | private string ParseMsiPackageElement(XElement node, ComplexReferenceParentType parentType, string parentId, ComplexReferenceChildType previousType, string previousId) | ||
19291 | { | ||
19292 | return ParseChainPackage(node, WixBundlePackageType.Msi, parentType, parentId, previousType, previousId); | ||
19293 | } | ||
19294 | |||
19295 | /// <summary> | ||
19296 | /// Parse MspPackage element | ||
19297 | /// </summary> | ||
19298 | /// <param name="node">Element to parse</param> | ||
19299 | /// <param name="parentType">Type of parent group, if known.</param> | ||
19300 | /// <param name="parentId">Identifier of parent group, if known.</param> | ||
19301 | /// <param name="previousType">Type of previous item, if known.</param> | ||
19302 | /// <param name="previousId">Identifier of previous item, if known</param> | ||
19303 | /// <returns>Identifier for package element.</returns> | ||
19304 | private string ParseMspPackageElement(XElement node, ComplexReferenceParentType parentType, string parentId, ComplexReferenceChildType previousType, string previousId) | ||
19305 | { | ||
19306 | return ParseChainPackage(node, WixBundlePackageType.Msp, parentType, parentId, previousType, previousId); | ||
19307 | } | ||
19308 | |||
19309 | /// <summary> | ||
19310 | /// Parse MsuPackage element | ||
19311 | /// </summary> | ||
19312 | /// <param name="node">Element to parse</param> | ||
19313 | /// <param name="parentType">Type of parent group, if known.</param> | ||
19314 | /// <param name="parentId">Identifier of parent group, if known.</param> | ||
19315 | /// <param name="previousType">Type of previous item, if known.</param> | ||
19316 | /// <param name="previousId">Identifier of previous item, if known</param> | ||
19317 | /// <returns>Identifier for package element.</returns> | ||
19318 | private string ParseMsuPackageElement(XElement node, ComplexReferenceParentType parentType, string parentId, ComplexReferenceChildType previousType, string previousId) | ||
19319 | { | ||
19320 | return ParseChainPackage(node, WixBundlePackageType.Msu, parentType, parentId, previousType, previousId); | ||
19321 | } | ||
19322 | |||
19323 | /// <summary> | ||
19324 | /// Parse ExePackage element | ||
19325 | /// </summary> | ||
19326 | /// <param name="node">Element to parse</param> | ||
19327 | /// <param name="parentType">Type of parent group, if known.</param> | ||
19328 | /// <param name="parentId">Identifier of parent group, if known.</param> | ||
19329 | /// <param name="previousType">Type of previous item, if known.</param> | ||
19330 | /// <param name="previousId">Identifier of previous item, if known</param> | ||
19331 | /// <returns>Identifier for package element.</returns> | ||
19332 | private string ParseExePackageElement(XElement node, ComplexReferenceParentType parentType, string parentId, ComplexReferenceChildType previousType, string previousId) | ||
19333 | { | ||
19334 | return ParseChainPackage(node, WixBundlePackageType.Exe, parentType, parentId, previousType, previousId); | ||
19335 | } | ||
19336 | |||
19337 | /// <summary> | ||
19338 | /// Parse RollbackBoundary element | ||
19339 | /// </summary> | ||
19340 | /// <param name="node">Element to parse</param> | ||
19341 | /// <param name="parentType">Type of parent group, if known.</param> | ||
19342 | /// <param name="parentId">Identifier of parent group, if known.</param> | ||
19343 | /// <param name="previousType">Type of previous item, if known.</param> | ||
19344 | /// <param name="previousId">Identifier of previous item, if known</param> | ||
19345 | /// <returns>Identifier for package element.</returns> | ||
19346 | private string ParseRollbackBoundaryElement(XElement node, ComplexReferenceParentType parentType, string parentId, ComplexReferenceChildType previousType, string previousId) | ||
19347 | { | ||
19348 | Debug.Assert(ComplexReferenceParentType.PackageGroup == parentType); | ||
19349 | Debug.Assert(ComplexReferenceChildType.Unknown == previousType || ComplexReferenceChildType.PackageGroup == previousType || ComplexReferenceChildType.Package == previousType); | ||
19350 | |||
19351 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
19352 | Identifier id = null; | ||
19353 | YesNoType vital = YesNoType.Yes; | ||
19354 | YesNoType transaction = YesNoType.No; | ||
19355 | |||
19356 | // This list lets us evaluate extension attributes *after* all core attributes | ||
19357 | // have been parsed and dealt with, regardless of authoring order. | ||
19358 | List<XAttribute> extensionAttributes = new List<XAttribute>(); | ||
19359 | |||
19360 | foreach (XAttribute attrib in node.Attributes()) | ||
19361 | { | ||
19362 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
19363 | { | ||
19364 | bool allowed = true; | ||
19365 | switch (attrib.Name.LocalName) | ||
19366 | { | ||
19367 | case "Id": | ||
19368 | id = this.core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
19369 | break; | ||
19370 | case "Vital": | ||
19371 | vital = this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
19372 | break; | ||
19373 | case "Transaction": | ||
19374 | transaction = this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
19375 | break; | ||
19376 | default: | ||
19377 | allowed = false; | ||
19378 | break; | ||
19379 | } | ||
19380 | |||
19381 | if (!allowed) | ||
19382 | { | ||
19383 | this.core.UnexpectedAttribute(node, attrib); | ||
19384 | } | ||
19385 | } | ||
19386 | else | ||
19387 | { | ||
19388 | // Save the extension attributes for later... | ||
19389 | extensionAttributes.Add(attrib); | ||
19390 | } | ||
19391 | } | ||
19392 | |||
19393 | if (null == id) | ||
19394 | { | ||
19395 | if (!String.IsNullOrEmpty(previousId)) | ||
19396 | { | ||
19397 | id = this.core.CreateIdentifier("rba", previousId); | ||
19398 | } | ||
19399 | |||
19400 | if (null == id) | ||
19401 | { | ||
19402 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
19403 | id = Identifier.Invalid; | ||
19404 | } | ||
19405 | else if (!Common.IsIdentifier(id.Id)) | ||
19406 | { | ||
19407 | this.core.OnMessage(WixErrors.IllegalIdentifier(sourceLineNumbers, node.Name.LocalName, "Id", id.Id)); | ||
19408 | } | ||
19409 | } | ||
19410 | |||
19411 | // Now that the rollback identifier is known, we can parse the extension attributes... | ||
19412 | Dictionary<string, string> contextValues = new Dictionary<string, string>(); | ||
19413 | contextValues["RollbackBoundaryId"] = id.Id; | ||
19414 | foreach (XAttribute attribute in extensionAttributes) | ||
19415 | { | ||
19416 | this.core.ParseExtensionAttribute(node, attribute, contextValues); | ||
19417 | } | ||
19418 | |||
19419 | this.core.ParseForExtensionElements(node); | ||
19420 | |||
19421 | if (!this.core.EncounteredError) | ||
19422 | { | ||
19423 | this.CreateRollbackBoundary(sourceLineNumbers, id, vital, transaction, parentType, parentId, previousType, previousId); | ||
19424 | } | ||
19425 | |||
19426 | return id.Id; | ||
19427 | } | ||
19428 | |||
19429 | /// <summary> | ||
19430 | /// Parses one of the ChainPackage elements | ||
19431 | /// </summary> | ||
19432 | /// <param name="node">Element to parse</param> | ||
19433 | /// <param name="packageType">Type of package to parse</param> | ||
19434 | /// <param name="parentType">Type of parent group, if known.</param> | ||
19435 | /// <param name="parentId">Identifier of parent group, if known.</param> | ||
19436 | /// <param name="previousType">Type of previous item, if known.</param> | ||
19437 | /// <param name="previousId">Identifier of previous item, if known</param> | ||
19438 | /// <returns>Identifier for package element.</returns> | ||
19439 | /// <remarks>This method contains the shared logic for parsing all of the ChainPackage | ||
19440 | /// types, as there is more in common between them than different.</remarks> | ||
19441 | private string ParseChainPackage(XElement node, WixBundlePackageType packageType, ComplexReferenceParentType parentType, string parentId, ComplexReferenceChildType previousType, string previousId) | ||
19442 | { | ||
19443 | Debug.Assert(ComplexReferenceParentType.PackageGroup == parentType); | ||
19444 | Debug.Assert(ComplexReferenceChildType.Unknown == previousType || ComplexReferenceChildType.PackageGroup == previousType || ComplexReferenceChildType.Package == previousType); | ||
19445 | |||
19446 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
19447 | Identifier id = null; | ||
19448 | string name = null; | ||
19449 | string sourceFile = null; | ||
19450 | string downloadUrl = null; | ||
19451 | string after = null; | ||
19452 | string installCondition = null; | ||
19453 | YesNoAlwaysType cache = YesNoAlwaysType.Yes; // the default is to cache everything in tradeoff for stability over disk space. | ||
19454 | string cacheId = null; | ||
19455 | string description = null; | ||
19456 | string displayName = null; | ||
19457 | string logPathVariable = (packageType == WixBundlePackageType.Msu) ? String.Empty : null; | ||
19458 | string rollbackPathVariable = (packageType == WixBundlePackageType.Msu) ? String.Empty : null; | ||
19459 | YesNoType permanent = YesNoType.NotSet; | ||
19460 | YesNoType visible = YesNoType.NotSet; | ||
19461 | YesNoType vital = YesNoType.Yes; | ||
19462 | string installCommand = null; | ||
19463 | string repairCommand = null; | ||
19464 | YesNoType repairable = YesNoType.NotSet; | ||
19465 | string uninstallCommand = null; | ||
19466 | YesNoDefaultType perMachine = YesNoDefaultType.NotSet; | ||
19467 | string detectCondition = null; | ||
19468 | string protocol = null; | ||
19469 | int installSize = CompilerConstants.IntegerNotSet; | ||
19470 | string msuKB = null; | ||
19471 | YesNoType suppressLooseFilePayloadGeneration = YesNoType.NotSet; | ||
19472 | YesNoType enableSignatureVerification = YesNoType.No; | ||
19473 | YesNoDefaultType compressed = YesNoDefaultType.Default; | ||
19474 | YesNoType displayInternalUI = YesNoType.NotSet; | ||
19475 | YesNoType enableFeatureSelection = YesNoType.NotSet; | ||
19476 | YesNoType forcePerMachine = YesNoType.NotSet; | ||
19477 | Wix.RemotePayload remotePayload = null; | ||
19478 | YesNoType slipstream = YesNoType.NotSet; | ||
19479 | |||
19480 | string[] expectedNetFx4Args = new string[] { "/q", "/norestart", "/chainingpackage" }; | ||
19481 | |||
19482 | // This list lets us evaluate extension attributes *after* all core attributes | ||
19483 | // have been parsed and dealt with, regardless of authoring order. | ||
19484 | List<XAttribute> extensionAttributes = new List<XAttribute>(); | ||
19485 | |||
19486 | foreach (XAttribute attrib in node.Attributes()) | ||
19487 | { | ||
19488 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
19489 | { | ||
19490 | bool allowed = true; | ||
19491 | switch (attrib.Name.LocalName) | ||
19492 | { | ||
19493 | case "Id": | ||
19494 | id = this.core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
19495 | break; | ||
19496 | case "Name": | ||
19497 | name = this.core.GetAttributeLongFilename(sourceLineNumbers, attrib, false, true); | ||
19498 | if (!this.core.IsValidLongFilename(name, false, true)) | ||
19499 | { | ||
19500 | this.core.OnMessage(WixErrors.IllegalLongFilename(sourceLineNumbers, node.Name.LocalName, "Name", name)); | ||
19501 | } | ||
19502 | break; | ||
19503 | case "SourceFile": | ||
19504 | sourceFile = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
19505 | break; | ||
19506 | case "DownloadUrl": | ||
19507 | downloadUrl = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
19508 | break; | ||
19509 | case "After": | ||
19510 | after = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
19511 | break; | ||
19512 | case "InstallCondition": | ||
19513 | installCondition = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
19514 | break; | ||
19515 | case "Cache": | ||
19516 | cache = this.core.GetAttributeYesNoAlwaysValue(sourceLineNumbers, attrib); | ||
19517 | break; | ||
19518 | case "CacheId": | ||
19519 | cacheId = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
19520 | break; | ||
19521 | case "Description": | ||
19522 | description = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
19523 | break; | ||
19524 | case "DisplayName": | ||
19525 | displayName = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
19526 | break; | ||
19527 | case "DisplayInternalUI": | ||
19528 | displayInternalUI = this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
19529 | allowed = (packageType == WixBundlePackageType.Msi || packageType == WixBundlePackageType.Msp); | ||
19530 | break; | ||
19531 | case "EnableFeatureSelection": | ||
19532 | enableFeatureSelection = this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
19533 | allowed = (packageType == WixBundlePackageType.Msi); | ||
19534 | break; | ||
19535 | case "ForcePerMachine": | ||
19536 | forcePerMachine = this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
19537 | allowed = (packageType == WixBundlePackageType.Msi); | ||
19538 | break; | ||
19539 | case "LogPathVariable": | ||
19540 | logPathVariable = this.core.GetAttributeValue(sourceLineNumbers, attrib, EmptyRule.CanBeEmpty); | ||
19541 | break; | ||
19542 | case "RollbackLogPathVariable": | ||
19543 | rollbackPathVariable = this.core.GetAttributeValue(sourceLineNumbers, attrib, EmptyRule.CanBeEmpty); | ||
19544 | break; | ||
19545 | case "Permanent": | ||
19546 | permanent = this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
19547 | break; | ||
19548 | case "Visible": | ||
19549 | visible = this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
19550 | allowed = (packageType == WixBundlePackageType.Msi); | ||
19551 | break; | ||
19552 | case "Vital": | ||
19553 | vital = this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
19554 | break; | ||
19555 | case "InstallCommand": | ||
19556 | installCommand = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
19557 | allowed = (packageType == WixBundlePackageType.Exe); | ||
19558 | break; | ||
19559 | case "RepairCommand": | ||
19560 | repairCommand = this.core.GetAttributeValue(sourceLineNumbers, attrib, EmptyRule.CanBeEmpty); | ||
19561 | repairable = YesNoType.Yes; | ||
19562 | allowed = (packageType == WixBundlePackageType.Exe); | ||
19563 | break; | ||
19564 | case "UninstallCommand": | ||
19565 | uninstallCommand = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
19566 | allowed = (packageType == WixBundlePackageType.Exe); | ||
19567 | break; | ||
19568 | case "PerMachine": | ||
19569 | perMachine = this.core.GetAttributeYesNoDefaultValue(sourceLineNumbers, attrib); | ||
19570 | allowed = (packageType == WixBundlePackageType.Exe || packageType == WixBundlePackageType.Msp); | ||
19571 | break; | ||
19572 | case "DetectCondition": | ||
19573 | detectCondition = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
19574 | allowed = (packageType == WixBundlePackageType.Exe || packageType == WixBundlePackageType.Msu); | ||
19575 | break; | ||
19576 | case "Protocol": | ||
19577 | protocol = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
19578 | allowed = (packageType == WixBundlePackageType.Exe); | ||
19579 | break; | ||
19580 | case "InstallSize": | ||
19581 | installSize = this.core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, int.MaxValue); | ||
19582 | break; | ||
19583 | case "KB": | ||
19584 | msuKB = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
19585 | allowed = (packageType == WixBundlePackageType.Msu); | ||
19586 | break; | ||
19587 | case "Compressed": | ||
19588 | compressed = this.core.GetAttributeYesNoDefaultValue(sourceLineNumbers, attrib); | ||
19589 | break; | ||
19590 | case "SuppressLooseFilePayloadGeneration": | ||
19591 | this.core.OnMessage(WixWarnings.DeprecatedAttribute(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); | ||
19592 | suppressLooseFilePayloadGeneration = this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
19593 | allowed = (packageType == WixBundlePackageType.Msi); | ||
19594 | break; | ||
19595 | case "EnableSignatureVerification": | ||
19596 | enableSignatureVerification = this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
19597 | break; | ||
19598 | case "Slipstream": | ||
19599 | slipstream = this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
19600 | allowed = (packageType == WixBundlePackageType.Msp); | ||
19601 | break; | ||
19602 | default: | ||
19603 | allowed = false; | ||
19604 | break; | ||
19605 | } | ||
19606 | |||
19607 | if (!allowed) | ||
19608 | { | ||
19609 | this.core.UnexpectedAttribute(node, attrib); | ||
19610 | } | ||
19611 | } | ||
19612 | else | ||
19613 | { | ||
19614 | // Save the extension attributes for later... | ||
19615 | extensionAttributes.Add(attrib); | ||
19616 | } | ||
19617 | } | ||
19618 | |||
19619 | // We need to handle RemotePayload up front because it effects value of sourceFile which is used in Id generation. Id is needed by other child elements. | ||
19620 | foreach (XElement child in node.Elements(CompilerCore.WixNamespace + "RemotePayload")) | ||
19621 | { | ||
19622 | SourceLineNumber childSourceLineNumbers = Preprocessor.GetSourceLineNumbers(child); | ||
19623 | |||
19624 | if (CompilerCore.WixNamespace == node.Name.Namespace && node.Name.LocalName != "ExePackage" && node.Name.LocalName != "MsuPackage") | ||
19625 | { | ||
19626 | this.core.OnMessage(WixErrors.RemotePayloadUnsupported(childSourceLineNumbers)); | ||
19627 | continue; | ||
19628 | } | ||
19629 | |||
19630 | if (null != remotePayload) | ||
19631 | { | ||
19632 | this.core.OnMessage(WixErrors.TooManyChildren(childSourceLineNumbers, node.Name.LocalName, child.Name.LocalName)); | ||
19633 | } | ||
19634 | |||
19635 | remotePayload = this.ParseRemotePayloadElement(child); | ||
19636 | } | ||
19637 | |||
19638 | if (String.IsNullOrEmpty(sourceFile)) | ||
19639 | { | ||
19640 | if (String.IsNullOrEmpty(name)) | ||
19641 | { | ||
19642 | this.core.OnMessage(WixErrors.ExpectedAttributesWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Name", "SourceFile")); | ||
19643 | } | ||
19644 | else if (null == remotePayload) | ||
19645 | { | ||
19646 | sourceFile = Path.Combine("SourceDir", name); | ||
19647 | } | ||
19648 | else | ||
19649 | { | ||
19650 | sourceFile = String.Empty; // SourceFile is required it cannot be null. | ||
19651 | } | ||
19652 | } | ||
19653 | else if (null != remotePayload) | ||
19654 | { | ||
19655 | this.core.OnMessage(WixErrors.UnexpectedElementWithAttribute(sourceLineNumbers, node.Name.LocalName, "RemotePayload", "SourceFile")); | ||
19656 | } | ||
19657 | else if (sourceFile.EndsWith(Path.DirectorySeparatorChar.ToString(), StringComparison.Ordinal)) | ||
19658 | { | ||
19659 | if (String.IsNullOrEmpty(name)) | ||
19660 | { | ||
19661 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Name", "SourceFile", sourceFile)); | ||
19662 | } | ||
19663 | else | ||
19664 | { | ||
19665 | sourceFile = Path.Combine(sourceFile, Path.GetFileName(name)); | ||
19666 | } | ||
19667 | } | ||
19668 | |||
19669 | if (null == downloadUrl && null != remotePayload) | ||
19670 | { | ||
19671 | this.core.OnMessage(WixErrors.ExpectedAttributeWithElement(sourceLineNumbers, node.Name.LocalName, "DownloadUrl", "RemotePayload")); | ||
19672 | } | ||
19673 | |||
19674 | if (YesNoDefaultType.No != compressed && null != remotePayload) | ||
19675 | { | ||
19676 | compressed = YesNoDefaultType.No; | ||
19677 | this.core.OnMessage(WixWarnings.RemotePayloadsMustNotAlsoBeCompressed(sourceLineNumbers, node.Name.LocalName)); | ||
19678 | } | ||
19679 | |||
19680 | if (null == id) | ||
19681 | { | ||
19682 | if (!String.IsNullOrEmpty(name)) | ||
19683 | { | ||
19684 | id = this.core.CreateIdentifierFromFilename(Path.GetFileName(name)); | ||
19685 | } | ||
19686 | else if (!String.IsNullOrEmpty(sourceFile)) | ||
19687 | { | ||
19688 | id = this.core.CreateIdentifierFromFilename(Path.GetFileName(sourceFile)); | ||
19689 | } | ||
19690 | |||
19691 | if (null == id) | ||
19692 | { | ||
19693 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
19694 | id = Identifier.Invalid; | ||
19695 | } | ||
19696 | else if (!Common.IsIdentifier(id.Id)) | ||
19697 | { | ||
19698 | this.core.OnMessage(WixErrors.IllegalIdentifier(sourceLineNumbers, node.Name.LocalName, "Id", id.Id)); | ||
19699 | } | ||
19700 | } | ||
19701 | |||
19702 | if (null == logPathVariable) | ||
19703 | { | ||
19704 | logPathVariable = String.Concat("WixBundleLog_", id.Id); | ||
19705 | } | ||
19706 | |||
19707 | if (null == rollbackPathVariable) | ||
19708 | { | ||
19709 | rollbackPathVariable = String.Concat("WixBundleRollbackLog_", id.Id); | ||
19710 | } | ||
19711 | |||
19712 | if (!String.IsNullOrEmpty(protocol) && !protocol.Equals("burn", StringComparison.Ordinal) && !protocol.Equals("netfx4", StringComparison.Ordinal) && !protocol.Equals("none", StringComparison.Ordinal)) | ||
19713 | { | ||
19714 | this.core.OnMessage(WixErrors.IllegalAttributeValueWithLegalList(sourceLineNumbers, node.Name.LocalName, "Protocol", protocol, "none, burn, netfx4")); | ||
19715 | } | ||
19716 | |||
19717 | if (!String.IsNullOrEmpty(protocol) && protocol.Equals("netfx4", StringComparison.Ordinal)) | ||
19718 | { | ||
19719 | foreach (string expectedArgument in expectedNetFx4Args) | ||
19720 | { | ||
19721 | if (null == installCommand || -1 == installCommand.IndexOf(expectedArgument, StringComparison.OrdinalIgnoreCase)) | ||
19722 | { | ||
19723 | this.core.OnMessage(WixWarnings.AttributeShouldContain(sourceLineNumbers, node.Name.LocalName, "InstallCommand", installCommand, expectedArgument, "Protocol", "netfx4")); | ||
19724 | } | ||
19725 | |||
19726 | if (null == repairCommand || -1 == repairCommand.IndexOf(expectedArgument, StringComparison.OrdinalIgnoreCase)) | ||
19727 | { | ||
19728 | this.core.OnMessage(WixWarnings.AttributeShouldContain(sourceLineNumbers, node.Name.LocalName, "RepairCommand", repairCommand, expectedArgument, "Protocol", "netfx4")); | ||
19729 | } | ||
19730 | |||
19731 | if (null == uninstallCommand || -1 == uninstallCommand.IndexOf(expectedArgument, StringComparison.OrdinalIgnoreCase)) | ||
19732 | { | ||
19733 | this.core.OnMessage(WixWarnings.AttributeShouldContain(sourceLineNumbers, node.Name.LocalName, "UninstallCommand", uninstallCommand, expectedArgument, "Protocol", "netfx4")); | ||
19734 | } | ||
19735 | } | ||
19736 | } | ||
19737 | |||
19738 | // Only set default scope for EXEs and MSPs if not already set. | ||
19739 | if ((WixBundlePackageType.Exe == packageType || WixBundlePackageType.Msp == packageType) && YesNoDefaultType.NotSet == perMachine) | ||
19740 | { | ||
19741 | perMachine = YesNoDefaultType.Default; | ||
19742 | } | ||
19743 | |||
19744 | // Now that the package ID is known, we can parse the extension attributes... | ||
19745 | Dictionary<string, string> contextValues = new Dictionary<string, string>() { { "PackageId", id.Id } }; | ||
19746 | foreach (XAttribute attribute in extensionAttributes) | ||
19747 | { | ||
19748 | this.core.ParseExtensionAttribute(node, attribute, contextValues); | ||
19749 | } | ||
19750 | |||
19751 | foreach (XElement child in node.Elements()) | ||
19752 | { | ||
19753 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
19754 | { | ||
19755 | bool allowed = true; | ||
19756 | switch (child.Name.LocalName) | ||
19757 | { | ||
19758 | case "SlipstreamMsp": | ||
19759 | allowed = (packageType == WixBundlePackageType.Msi); | ||
19760 | if (allowed) | ||
19761 | { | ||
19762 | this.ParseSlipstreamMspElement(child, id.Id); | ||
19763 | } | ||
19764 | break; | ||
19765 | case "MsiProperty": | ||
19766 | allowed = (packageType == WixBundlePackageType.Msi || packageType == WixBundlePackageType.Msp); | ||
19767 | if (allowed) | ||
19768 | { | ||
19769 | this.ParseMsiPropertyElement(child, id.Id); | ||
19770 | } | ||
19771 | break; | ||
19772 | case "Payload": | ||
19773 | this.ParsePayloadElement(child, ComplexReferenceParentType.Package, id.Id, ComplexReferenceChildType.Unknown, null); | ||
19774 | break; | ||
19775 | case "PayloadGroupRef": | ||
19776 | this.ParsePayloadGroupRefElement(child, ComplexReferenceParentType.Package, id.Id, ComplexReferenceChildType.Unknown, null); | ||
19777 | break; | ||
19778 | case "ExitCode": | ||
19779 | allowed = (packageType == WixBundlePackageType.Exe); | ||
19780 | if (allowed) | ||
19781 | { | ||
19782 | this.ParseExitCodeElement(child, id.Id); | ||
19783 | } | ||
19784 | break; | ||
19785 | case "CommandLine": | ||
19786 | allowed = (packageType == WixBundlePackageType.Exe); | ||
19787 | if (allowed) | ||
19788 | { | ||
19789 | this.ParseCommandLineElement(child, id.Id); | ||
19790 | } | ||
19791 | break; | ||
19792 | case "RemotePayload": | ||
19793 | // Handled previously | ||
19794 | break; | ||
19795 | default: | ||
19796 | allowed = false; | ||
19797 | break; | ||
19798 | } | ||
19799 | |||
19800 | if (!allowed) | ||
19801 | { | ||
19802 | this.core.UnexpectedElement(node, child); | ||
19803 | } | ||
19804 | } | ||
19805 | else | ||
19806 | { | ||
19807 | Dictionary<string, string> context = new Dictionary<string, string>() { { "Id", id.Id } }; | ||
19808 | this.core.ParseExtensionElement(node, child, context); | ||
19809 | } | ||
19810 | } | ||
19811 | |||
19812 | if (!this.core.EncounteredError) | ||
19813 | { | ||
19814 | // We create the package contents as a payload with this package as the parent | ||
19815 | this.CreatePayloadRow(sourceLineNumbers, id, name, sourceFile, downloadUrl, ComplexReferenceParentType.Package, id.Id, | ||
19816 | ComplexReferenceChildType.Unknown, null, compressed, enableSignatureVerification, displayName, description, remotePayload); | ||
19817 | |||
19818 | WixChainItemRow chainItemRow = (WixChainItemRow)this.core.CreateRow(sourceLineNumbers, "WixChainItem", id); | ||
19819 | |||
19820 | WixBundlePackageAttributes attributes = 0; | ||
19821 | attributes |= (YesNoType.Yes == permanent) ? WixBundlePackageAttributes.Permanent : 0; | ||
19822 | attributes |= (YesNoType.Yes == visible) ? WixBundlePackageAttributes.Visible : 0; | ||
19823 | |||
19824 | WixBundlePackageRow chainPackageRow = (WixBundlePackageRow)this.core.CreateRow(sourceLineNumbers, "WixBundlePackage", id); | ||
19825 | chainPackageRow.Type = packageType; | ||
19826 | chainPackageRow.PackagePayload = id.Id; | ||
19827 | chainPackageRow.Attributes = attributes; | ||
19828 | |||
19829 | chainPackageRow.InstallCondition = installCondition; | ||
19830 | |||
19831 | if (YesNoAlwaysType.NotSet != cache) | ||
19832 | { | ||
19833 | chainPackageRow.Cache = cache; | ||
19834 | } | ||
19835 | |||
19836 | chainPackageRow.CacheId = cacheId; | ||
19837 | |||
19838 | if (YesNoType.NotSet != vital) | ||
19839 | { | ||
19840 | chainPackageRow.Vital = vital; | ||
19841 | } | ||
19842 | |||
19843 | if (YesNoDefaultType.NotSet != perMachine) | ||
19844 | { | ||
19845 | chainPackageRow.PerMachine = perMachine; | ||
19846 | } | ||
19847 | |||
19848 | chainPackageRow.LogPathVariable = logPathVariable; | ||
19849 | chainPackageRow.RollbackLogPathVariable = rollbackPathVariable; | ||
19850 | |||
19851 | if (CompilerConstants.IntegerNotSet != installSize) | ||
19852 | { | ||
19853 | chainPackageRow.InstallSize = installSize; | ||
19854 | } | ||
19855 | |||
19856 | switch (packageType) | ||
19857 | { | ||
19858 | case WixBundlePackageType.Exe: | ||
19859 | WixBundleExePackageAttributes exeAttributes = 0; | ||
19860 | exeAttributes |= (YesNoType.Yes == repairable) ? WixBundleExePackageAttributes.Repairable : 0; | ||
19861 | |||
19862 | WixBundleExePackageRow exeRow = (WixBundleExePackageRow)this.core.CreateRow(sourceLineNumbers, "WixBundleExePackage", id); | ||
19863 | exeRow.Attributes = exeAttributes; | ||
19864 | exeRow.DetectCondition = detectCondition; | ||
19865 | exeRow.InstallCommand = installCommand; | ||
19866 | exeRow.RepairCommand = repairCommand; | ||
19867 | exeRow.UninstallCommand = uninstallCommand; | ||
19868 | exeRow.ExeProtocol = protocol; | ||
19869 | break; | ||
19870 | |||
19871 | case WixBundlePackageType.Msi: | ||
19872 | WixBundleMsiPackageAttributes msiAttributes = 0; | ||
19873 | msiAttributes |= (YesNoType.Yes == displayInternalUI) ? WixBundleMsiPackageAttributes.DisplayInternalUI : 0; | ||
19874 | msiAttributes |= (YesNoType.Yes == enableFeatureSelection) ? WixBundleMsiPackageAttributes.EnableFeatureSelection : 0; | ||
19875 | msiAttributes |= (YesNoType.Yes == forcePerMachine) ? WixBundleMsiPackageAttributes.ForcePerMachine : 0; | ||
19876 | msiAttributes |= (YesNoType.Yes == suppressLooseFilePayloadGeneration) ? WixBundleMsiPackageAttributes.SuppressLooseFilePayloadGeneration : 0; | ||
19877 | |||
19878 | WixBundleMsiPackageRow msiRow = (WixBundleMsiPackageRow)this.core.CreateRow(sourceLineNumbers, "WixBundleMsiPackage", id); | ||
19879 | msiRow.Attributes = msiAttributes; | ||
19880 | break; | ||
19881 | |||
19882 | case WixBundlePackageType.Msp: | ||
19883 | WixBundleMspPackageAttributes mspAttributes = 0; | ||
19884 | mspAttributes |= (YesNoType.Yes == displayInternalUI) ? WixBundleMspPackageAttributes.DisplayInternalUI : 0; | ||
19885 | mspAttributes |= (YesNoType.Yes == slipstream) ? WixBundleMspPackageAttributes.Slipstream : 0; | ||
19886 | |||
19887 | WixBundleMspPackageRow mspRow = (WixBundleMspPackageRow)this.core.CreateRow(sourceLineNumbers, "WixBundleMspPackage", id); | ||
19888 | mspRow.Attributes = mspAttributes; | ||
19889 | break; | ||
19890 | |||
19891 | case WixBundlePackageType.Msu: | ||
19892 | WixBundleMsuPackageRow msuRow = (WixBundleMsuPackageRow)this.core.CreateRow(sourceLineNumbers, "WixBundleMsuPackage", id); | ||
19893 | msuRow.DetectCondition = detectCondition; | ||
19894 | msuRow.MsuKB = msuKB; | ||
19895 | break; | ||
19896 | } | ||
19897 | |||
19898 | this.CreateChainPackageMetaRows(sourceLineNumbers, parentType, parentId, ComplexReferenceChildType.Package, id.Id, previousType, previousId, after); | ||
19899 | } | ||
19900 | |||
19901 | return id.Id; | ||
19902 | } | ||
19903 | |||
19904 | /// <summary> | ||
19905 | /// Parse CommandLine element. | ||
19906 | /// </summary> | ||
19907 | /// <param name="node">Element to parse</param> | ||
19908 | private void ParseCommandLineElement(XElement node, string packageId) | ||
19909 | { | ||
19910 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
19911 | string installArgument = null; | ||
19912 | string uninstallArgument = null; | ||
19913 | string repairArgument = null; | ||
19914 | string condition = null; | ||
19915 | |||
19916 | foreach (XAttribute attrib in node.Attributes()) | ||
19917 | { | ||
19918 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
19919 | { | ||
19920 | switch (attrib.Name.LocalName) | ||
19921 | { | ||
19922 | case "InstallArgument": | ||
19923 | installArgument = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
19924 | break; | ||
19925 | case "UninstallArgument": | ||
19926 | uninstallArgument = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
19927 | break; | ||
19928 | case "RepairArgument": | ||
19929 | repairArgument = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
19930 | break; | ||
19931 | case "Condition": | ||
19932 | condition = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
19933 | break; | ||
19934 | default: | ||
19935 | this.core.UnexpectedAttribute(node, attrib); | ||
19936 | break; | ||
19937 | } | ||
19938 | } | ||
19939 | else | ||
19940 | { | ||
19941 | this.core.ParseExtensionAttribute(node, attrib); | ||
19942 | } | ||
19943 | } | ||
19944 | |||
19945 | if (String.IsNullOrEmpty(condition)) | ||
19946 | { | ||
19947 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Condition")); | ||
19948 | } | ||
19949 | |||
19950 | this.core.ParseForExtensionElements(node); | ||
19951 | |||
19952 | if (!this.core.EncounteredError) | ||
19953 | { | ||
19954 | WixBundlePackageCommandLineRow row = (WixBundlePackageCommandLineRow)this.core.CreateRow(sourceLineNumbers, "WixBundlePackageCommandLine"); | ||
19955 | row.ChainPackageId = packageId; | ||
19956 | row.InstallArgument = installArgument; | ||
19957 | row.UninstallArgument = uninstallArgument; | ||
19958 | row.RepairArgument = repairArgument; | ||
19959 | row.Condition = condition; | ||
19960 | } | ||
19961 | } | ||
19962 | |||
19963 | /// <summary> | ||
19964 | /// Parse PackageGroup element. | ||
19965 | /// </summary> | ||
19966 | /// <param name="node">Element to parse</param> | ||
19967 | private void ParsePackageGroupElement(XElement node) | ||
19968 | { | ||
19969 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
19970 | Identifier id = null; | ||
19971 | |||
19972 | foreach (XAttribute attrib in node.Attributes()) | ||
19973 | { | ||
19974 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
19975 | { | ||
19976 | switch (attrib.Name.LocalName) | ||
19977 | { | ||
19978 | case "Id": | ||
19979 | id = this.core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
19980 | break; | ||
19981 | default: | ||
19982 | this.core.UnexpectedAttribute(node, attrib); | ||
19983 | break; | ||
19984 | } | ||
19985 | } | ||
19986 | else | ||
19987 | { | ||
19988 | this.core.ParseExtensionAttribute(node, attrib); | ||
19989 | } | ||
19990 | } | ||
19991 | |||
19992 | if (null == id) | ||
19993 | { | ||
19994 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
19995 | id = Identifier.Invalid; | ||
19996 | } | ||
19997 | |||
19998 | ComplexReferenceChildType previousType = ComplexReferenceChildType.Unknown; | ||
19999 | string previousId = null; | ||
20000 | foreach (XElement child in node.Elements()) | ||
20001 | { | ||
20002 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
20003 | { | ||
20004 | switch (child.Name.LocalName) | ||
20005 | { | ||
20006 | case "MsiPackage": | ||
20007 | previousId = this.ParseMsiPackageElement(child, ComplexReferenceParentType.PackageGroup, id.Id, previousType, previousId); | ||
20008 | previousType = ComplexReferenceChildType.Package; | ||
20009 | break; | ||
20010 | case "MspPackage": | ||
20011 | previousId = this.ParseMspPackageElement(child, ComplexReferenceParentType.PackageGroup, id.Id, previousType, previousId); | ||
20012 | previousType = ComplexReferenceChildType.Package; | ||
20013 | break; | ||
20014 | case "MsuPackage": | ||
20015 | previousId = this.ParseMsuPackageElement(child, ComplexReferenceParentType.PackageGroup, id.Id, previousType, previousId); | ||
20016 | previousType = ComplexReferenceChildType.Package; | ||
20017 | break; | ||
20018 | case "ExePackage": | ||
20019 | previousId = this.ParseExePackageElement(child, ComplexReferenceParentType.PackageGroup, id.Id, previousType, previousId); | ||
20020 | previousType = ComplexReferenceChildType.Package; | ||
20021 | break; | ||
20022 | case "RollbackBoundary": | ||
20023 | previousId = this.ParseRollbackBoundaryElement(child, ComplexReferenceParentType.PackageGroup, id.Id, previousType, previousId); | ||
20024 | previousType = ComplexReferenceChildType.Package; | ||
20025 | break; | ||
20026 | case "PackageGroupRef": | ||
20027 | previousId = this.ParsePackageGroupRefElement(child, ComplexReferenceParentType.PackageGroup, id.Id, previousType, previousId); | ||
20028 | previousType = ComplexReferenceChildType.PackageGroup; | ||
20029 | break; | ||
20030 | default: | ||
20031 | this.core.UnexpectedElement(node, child); | ||
20032 | break; | ||
20033 | } | ||
20034 | } | ||
20035 | else | ||
20036 | { | ||
20037 | this.core.ParseExtensionElement(node, child); | ||
20038 | } | ||
20039 | } | ||
20040 | |||
20041 | |||
20042 | if (!this.core.EncounteredError) | ||
20043 | { | ||
20044 | this.core.CreateRow(sourceLineNumbers, "WixBundlePackageGroup", id); | ||
20045 | } | ||
20046 | } | ||
20047 | |||
20048 | /// <summary> | ||
20049 | /// Parses a package group reference element. | ||
20050 | /// </summary> | ||
20051 | /// <param name="node">Element to parse.</param> | ||
20052 | /// <param name="parentType">ComplexReferenceParentType of parent element (Unknown or PackageGroup).</param> | ||
20053 | /// <param name="parentId">Identifier of parent element.</param> | ||
20054 | /// <returns>Identifier for package group element.</rereturns> | ||
20055 | private string ParsePackageGroupRefElement(XElement node, ComplexReferenceParentType parentType, string parentId) | ||
20056 | { | ||
20057 | return this.ParsePackageGroupRefElement(node, parentType, parentId, ComplexReferenceChildType.Unknown, null); | ||
20058 | } | ||
20059 | |||
20060 | /// <summary> | ||
20061 | /// Parses a package group reference element. | ||
20062 | /// </summary> | ||
20063 | /// <param name="node">Element to parse.</param> | ||
20064 | /// <param name="parentType">ComplexReferenceParentType of parent element (Unknown or PackageGroup).</param> | ||
20065 | /// <param name="parentId">Identifier of parent element.</param> | ||
20066 | /// <param name="parentType">ComplexReferenceParentType of previous element (Unknown, Package, or PackageGroup).</param> | ||
20067 | /// <param name="parentId">Identifier of parent element.</param> | ||
20068 | /// <returns>Identifier for package group element.</rereturns> | ||
20069 | private string ParsePackageGroupRefElement(XElement node, ComplexReferenceParentType parentType, string parentId, ComplexReferenceChildType previousType, string previousId) | ||
20070 | { | ||
20071 | Debug.Assert(ComplexReferenceParentType.Unknown == parentType || ComplexReferenceParentType.PackageGroup == parentType || ComplexReferenceParentType.Container == parentType); | ||
20072 | Debug.Assert(ComplexReferenceChildType.Unknown == previousType || ComplexReferenceChildType.PackageGroup == previousType || ComplexReferenceChildType.Package == previousType); | ||
20073 | |||
20074 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
20075 | string id = null; | ||
20076 | string after = null; | ||
20077 | |||
20078 | foreach (XAttribute attrib in node.Attributes()) | ||
20079 | { | ||
20080 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
20081 | { | ||
20082 | switch (attrib.Name.LocalName) | ||
20083 | { | ||
20084 | case "Id": | ||
20085 | id = this.core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
20086 | this.core.CreateSimpleReference(sourceLineNumbers, "WixBundlePackageGroup", id); | ||
20087 | break; | ||
20088 | case "After": | ||
20089 | after = this.core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
20090 | break; | ||
20091 | default: | ||
20092 | this.core.UnexpectedAttribute(node, attrib); | ||
20093 | break; | ||
20094 | } | ||
20095 | } | ||
20096 | else | ||
20097 | { | ||
20098 | this.core.ParseExtensionAttribute(node, attrib); | ||
20099 | |||
20100 | } | ||
20101 | } | ||
20102 | |||
20103 | if (null == id) | ||
20104 | { | ||
20105 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
20106 | } | ||
20107 | |||
20108 | if (null != after && ComplexReferenceParentType.Container == parentType) | ||
20109 | { | ||
20110 | this.core.OnMessage(WixErrors.IllegalAttributeWhenNested(sourceLineNumbers, node.Name.LocalName, "After", parentId)); | ||
20111 | } | ||
20112 | |||
20113 | this.core.ParseForExtensionElements(node); | ||
20114 | |||
20115 | if (ComplexReferenceParentType.Container == parentType) | ||
20116 | { | ||
20117 | this.core.CreateWixGroupRow(sourceLineNumbers, ComplexReferenceParentType.Container, parentId, ComplexReferenceChildType.PackageGroup, id); | ||
20118 | } | ||
20119 | else | ||
20120 | { | ||
20121 | this.CreateChainPackageMetaRows(sourceLineNumbers, parentType, parentId, ComplexReferenceChildType.PackageGroup, id, previousType, previousId, after); | ||
20122 | } | ||
20123 | |||
20124 | return id; | ||
20125 | } | ||
20126 | |||
20127 | /// <summary> | ||
20128 | /// Creates rollback boundary. | ||
20129 | /// </summary> | ||
20130 | /// <param name="sourceLineNumbers">Source line numbers.</param> | ||
20131 | /// <param name="id">Identifier for the rollback boundary.</param> | ||
20132 | /// <param name="vital">Indicates whether the rollback boundary is vital or not.</param> | ||
20133 | /// <param name="parentType">Type of parent group.</param> | ||
20134 | /// <param name="parentId">Identifier of parent group.</param> | ||
20135 | /// <param name="previousType">Type of previous item, if any.</param> | ||
20136 | /// <param name="previousId">Identifier of previous item, if any.</param> | ||
20137 | private void CreateRollbackBoundary(SourceLineNumber sourceLineNumbers, Identifier id, YesNoType vital, YesNoType transaction, ComplexReferenceParentType parentType, string parentId, ComplexReferenceChildType previousType, string previousId) | ||
20138 | { | ||
20139 | WixChainItemRow row = (WixChainItemRow)this.core.CreateRow(sourceLineNumbers, "WixChainItem", id); | ||
20140 | |||
20141 | WixBundleRollbackBoundaryRow rollbackBoundary = (WixBundleRollbackBoundaryRow)this.core.CreateRow(sourceLineNumbers, "WixBundleRollbackBoundary", id); | ||
20142 | |||
20143 | if (YesNoType.NotSet != vital) | ||
20144 | { | ||
20145 | rollbackBoundary.Vital = vital; | ||
20146 | } | ||
20147 | if (YesNoType.NotSet != transaction) | ||
20148 | { | ||
20149 | rollbackBoundary.Transaction = transaction; | ||
20150 | } | ||
20151 | |||
20152 | this.CreateChainPackageMetaRows(sourceLineNumbers, parentType, parentId, ComplexReferenceChildType.Package, id.Id, previousType, previousId, null); | ||
20153 | } | ||
20154 | |||
20155 | /// <summary> | ||
20156 | /// Creates group and ordering information for packages | ||
20157 | /// </summary> | ||
20158 | /// <param name="sourceLineNumbers">Source line numbers.</param> | ||
20159 | /// <param name="parentType">Type of parent group, if known.</param> | ||
20160 | /// <param name="parentId">Identifier of parent group, if known.</param> | ||
20161 | /// <param name="type">Type of this item.</param> | ||
20162 | /// <param name="id">Identifier for this item.</param> | ||
20163 | /// <param name="previousType">Type of previous item, if known.</param> | ||
20164 | /// <param name="previousId">Identifier of previous item, if known</param> | ||
20165 | /// <param name="afterId">Identifier of explicit 'After' attribute, if given.</param> | ||
20166 | private void CreateChainPackageMetaRows(SourceLineNumber sourceLineNumbers, | ||
20167 | ComplexReferenceParentType parentType, string parentId, | ||
20168 | ComplexReferenceChildType type, string id, | ||
20169 | ComplexReferenceChildType previousType, string previousId, string afterId) | ||
20170 | { | ||
20171 | // If there's an explicit 'After' attribute, it overrides the inferred previous item. | ||
20172 | if (null != afterId) | ||
20173 | { | ||
20174 | previousType = ComplexReferenceChildType.Package; | ||
20175 | previousId = afterId; | ||
20176 | } | ||
20177 | |||
20178 | this.CreateGroupAndOrderingRows(sourceLineNumbers, parentType, parentId, type, id, previousType, previousId); | ||
20179 | } | ||
20180 | |||
20181 | // TODO: Should we define our own enum for this, just to ensure there's no "cross-contamination"? | ||
20182 | // TODO: Also, we could potentially include an 'Attributes' field to track things like | ||
20183 | // 'before' vs. 'after', and explicit vs. inferred dependencies. | ||
20184 | private void CreateWixOrderingRow(SourceLineNumber sourceLineNumbers, | ||
20185 | ComplexReferenceChildType itemType, string itemId, | ||
20186 | ComplexReferenceChildType dependsOnType, string dependsOnId) | ||
20187 | { | ||
20188 | if (!this.core.EncounteredError) | ||
20189 | { | ||
20190 | Row row = this.core.CreateRow(sourceLineNumbers, "WixOrdering"); | ||
20191 | row[0] = itemType.ToString(); | ||
20192 | row[1] = itemId; | ||
20193 | row[2] = dependsOnType.ToString(); | ||
20194 | row[3] = dependsOnId; | ||
20195 | } | ||
20196 | } | ||
20197 | |||
20198 | /// <summary> | ||
20199 | /// Parse MsiProperty element | ||
20200 | /// </summary> | ||
20201 | /// <param name="node">Element to parse</param> | ||
20202 | /// <param name="packageId">Id of parent element</param> | ||
20203 | private void ParseMsiPropertyElement(XElement node, string packageId) | ||
20204 | { | ||
20205 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
20206 | string name = null; | ||
20207 | string value = null; | ||
20208 | string condition = null; | ||
20209 | |||
20210 | foreach (XAttribute attrib in node.Attributes()) | ||
20211 | { | ||
20212 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
20213 | { | ||
20214 | switch (attrib.Name.LocalName) | ||
20215 | { | ||
20216 | case "Name": | ||
20217 | name = this.core.GetAttributeMsiPropertyNameValue(sourceLineNumbers, attrib); | ||
20218 | break; | ||
20219 | case "Value": | ||
20220 | value = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
20221 | break; | ||
20222 | case "Condition": | ||
20223 | condition = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
20224 | break; | ||
20225 | default: | ||
20226 | this.core.UnexpectedAttribute(node, attrib); | ||
20227 | break; | ||
20228 | } | ||
20229 | } | ||
20230 | else | ||
20231 | { | ||
20232 | this.core.ParseExtensionAttribute(node, attrib); | ||
20233 | } | ||
20234 | } | ||
20235 | |||
20236 | if (null == name) | ||
20237 | { | ||
20238 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Name")); | ||
20239 | } | ||
20240 | |||
20241 | if (null == value) | ||
20242 | { | ||
20243 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Value")); | ||
20244 | } | ||
20245 | |||
20246 | this.core.ParseForExtensionElements(node); | ||
20247 | |||
20248 | if (!this.core.EncounteredError) | ||
20249 | { | ||
20250 | WixBundleMsiPropertyRow row = (WixBundleMsiPropertyRow)this.core.CreateRow(sourceLineNumbers, "WixBundleMsiProperty"); | ||
20251 | row.ChainPackageId = packageId; | ||
20252 | row.Name = name; | ||
20253 | row.Value = value; | ||
20254 | |||
20255 | if (!String.IsNullOrEmpty(condition)) | ||
20256 | { | ||
20257 | row.Condition = condition; | ||
20258 | } | ||
20259 | } | ||
20260 | } | ||
20261 | |||
20262 | /// <summary> | ||
20263 | /// Parse SlipstreamMsp element | ||
20264 | /// </summary> | ||
20265 | /// <param name="node">Element to parse</param> | ||
20266 | /// <param name="packageId">Id of parent element</param> | ||
20267 | private void ParseSlipstreamMspElement(XElement node, string packageId) | ||
20268 | { | ||
20269 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
20270 | string id = null; | ||
20271 | |||
20272 | foreach (XAttribute attrib in node.Attributes()) | ||
20273 | { | ||
20274 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
20275 | { | ||
20276 | switch (attrib.Name.LocalName) | ||
20277 | { | ||
20278 | case "Id": | ||
20279 | id = this.core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
20280 | this.core.CreateSimpleReference(sourceLineNumbers, "WixBundlePackage", id); | ||
20281 | break; | ||
20282 | default: | ||
20283 | this.core.UnexpectedAttribute(node, attrib); | ||
20284 | break; | ||
20285 | } | ||
20286 | } | ||
20287 | else | ||
20288 | { | ||
20289 | this.core.ParseExtensionAttribute(node, attrib); | ||
20290 | } | ||
20291 | } | ||
20292 | |||
20293 | if (null == id) | ||
20294 | { | ||
20295 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
20296 | } | ||
20297 | |||
20298 | this.core.ParseForExtensionElements(node); | ||
20299 | |||
20300 | if (!this.core.EncounteredError) | ||
20301 | { | ||
20302 | WixBundleSlipstreamMspRow row = (WixBundleSlipstreamMspRow)this.core.CreateRow(sourceLineNumbers, "WixBundleSlipstreamMsp"); | ||
20303 | row.ChainPackageId = packageId; | ||
20304 | row.MspPackageId = id; | ||
20305 | } | ||
20306 | } | ||
20307 | |||
20308 | /// <summary> | ||
20309 | /// Parse RelatedBundle element | ||
20310 | /// </summary> | ||
20311 | /// <param name="node">Element to parse</param> | ||
20312 | private void ParseRelatedBundleElement(XElement node) | ||
20313 | { | ||
20314 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
20315 | string id = null; | ||
20316 | string action = null; | ||
20317 | Wix.RelatedBundle.ActionType actionType = Wix.RelatedBundle.ActionType.Detect; | ||
20318 | |||
20319 | foreach (XAttribute attrib in node.Attributes()) | ||
20320 | { | ||
20321 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
20322 | { | ||
20323 | switch (attrib.Name.LocalName) | ||
20324 | { | ||
20325 | case "Id": | ||
20326 | id = this.core.GetAttributeGuidValue(sourceLineNumbers, attrib, false); | ||
20327 | break; | ||
20328 | case "Action": | ||
20329 | action = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
20330 | break; | ||
20331 | default: | ||
20332 | this.core.UnexpectedAttribute(node, attrib); | ||
20333 | break; | ||
20334 | } | ||
20335 | } | ||
20336 | else | ||
20337 | { | ||
20338 | this.core.ParseExtensionAttribute(node, attrib); | ||
20339 | } | ||
20340 | } | ||
20341 | |||
20342 | if (null == id) | ||
20343 | { | ||
20344 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
20345 | } | ||
20346 | |||
20347 | if (!String.IsNullOrEmpty(action)) | ||
20348 | { | ||
20349 | actionType = Wix.RelatedBundle.ParseActionType(action); | ||
20350 | switch (actionType) | ||
20351 | { | ||
20352 | case Wix.RelatedBundle.ActionType.Detect: | ||
20353 | break; | ||
20354 | case Wix.RelatedBundle.ActionType.Upgrade: | ||
20355 | break; | ||
20356 | case Wix.RelatedBundle.ActionType.Addon: | ||
20357 | break; | ||
20358 | case Wix.RelatedBundle.ActionType.Patch: | ||
20359 | break; | ||
20360 | default: | ||
20361 | this.core.OnMessage(WixErrors.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, "Action", action, "Detect", "Upgrade", "Addon", "Patch")); | ||
20362 | break; | ||
20363 | } | ||
20364 | } | ||
20365 | |||
20366 | this.core.ParseForExtensionElements(node); | ||
20367 | |||
20368 | if (!this.core.EncounteredError) | ||
20369 | { | ||
20370 | Row row = this.core.CreateRow(sourceLineNumbers, "WixRelatedBundle"); | ||
20371 | row[0] = id; | ||
20372 | row[1] = (int)actionType; | ||
20373 | } | ||
20374 | } | ||
20375 | |||
20376 | /// <summary> | ||
20377 | /// Parse Update element | ||
20378 | /// </summary> | ||
20379 | /// <param name="node">Element to parse</param> | ||
20380 | private void ParseUpdateElement(XElement node) | ||
20381 | { | ||
20382 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
20383 | string location = null; | ||
20384 | |||
20385 | foreach (XAttribute attrib in node.Attributes()) | ||
20386 | { | ||
20387 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
20388 | { | ||
20389 | switch (attrib.Name.LocalName) | ||
20390 | { | ||
20391 | case "Location": | ||
20392 | location = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
20393 | break; | ||
20394 | default: | ||
20395 | this.core.UnexpectedAttribute(node, attrib); | ||
20396 | break; | ||
20397 | } | ||
20398 | } | ||
20399 | else | ||
20400 | { | ||
20401 | this.core.ParseExtensionAttribute(node, attrib); | ||
20402 | } | ||
20403 | } | ||
20404 | |||
20405 | if (null == location) | ||
20406 | { | ||
20407 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Location")); | ||
20408 | } | ||
20409 | |||
20410 | this.core.ParseForExtensionElements(node); | ||
20411 | |||
20412 | if (!this.core.EncounteredError) | ||
20413 | { | ||
20414 | Row row = this.core.CreateRow(sourceLineNumbers, "WixBundleUpdate"); | ||
20415 | row[0] = location; | ||
20416 | } | ||
20417 | } | ||
20418 | |||
20419 | /// <summary> | ||
20420 | /// Parse Variable element | ||
20421 | /// </summary> | ||
20422 | /// <param name="node">Element to parse</param> | ||
20423 | private void ParseVariableElement(XElement node) | ||
20424 | { | ||
20425 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
20426 | bool hidden = false; | ||
20427 | string name = null; | ||
20428 | bool persisted = false; | ||
20429 | string value = null; | ||
20430 | string type = null; | ||
20431 | |||
20432 | foreach (XAttribute attrib in node.Attributes()) | ||
20433 | { | ||
20434 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
20435 | { | ||
20436 | switch (attrib.Name.LocalName) | ||
20437 | { | ||
20438 | case "Hidden": | ||
20439 | if (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
20440 | { | ||
20441 | hidden = true; | ||
20442 | } | ||
20443 | break; | ||
20444 | case "Name": | ||
20445 | name = this.core.GetAttributeBundleVariableValue(sourceLineNumbers, attrib); | ||
20446 | break; | ||
20447 | case "Persisted": | ||
20448 | if (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
20449 | { | ||
20450 | persisted = true; | ||
20451 | } | ||
20452 | break; | ||
20453 | case "Value": | ||
20454 | value = this.core.GetAttributeValue(sourceLineNumbers, attrib, EmptyRule.CanBeEmpty); | ||
20455 | break; | ||
20456 | case "Type": | ||
20457 | type = this.core.GetAttributeValue(sourceLineNumbers, attrib); | ||
20458 | break; | ||
20459 | default: | ||
20460 | this.core.UnexpectedAttribute(node, attrib); | ||
20461 | break; | ||
20462 | } | ||
20463 | } | ||
20464 | else | ||
20465 | { | ||
20466 | this.core.ParseExtensionAttribute(node, attrib); | ||
20467 | } | ||
20468 | } | ||
20469 | |||
20470 | if (null == name) | ||
20471 | { | ||
20472 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Name")); | ||
20473 | } | ||
20474 | else if (name.StartsWith("Wix", StringComparison.OrdinalIgnoreCase)) | ||
20475 | { | ||
20476 | this.core.OnMessage(WixErrors.ReservedNamespaceViolation(sourceLineNumbers, node.Name.LocalName, "Name", "Wix")); | ||
20477 | } | ||
20478 | |||
20479 | if (null == type && null != value) | ||
20480 | { | ||
20481 | // Infer the type from the current value... | ||
20482 | if (value.StartsWith("v", StringComparison.OrdinalIgnoreCase)) | ||
20483 | { | ||
20484 | // Version constructor does not support simple "v#" syntax so check to see if the value is | ||
20485 | // non-negative real quick. | ||
20486 | Int32 number; | ||
20487 | if (Int32.TryParse(value.Substring(1), NumberStyles.None, CultureInfo.InvariantCulture.NumberFormat, out number)) | ||
20488 | { | ||
20489 | type = "version"; | ||
20490 | } | ||
20491 | else | ||
20492 | { | ||
20493 | // Sadly, Version doesn't have a TryParse() method until .NET 4, so we have to try/catch to see if it parses. | ||
20494 | try | ||
20495 | { | ||
20496 | Version version = new Version(value.Substring(1)); | ||
20497 | type = "version"; | ||
20498 | } | ||
20499 | catch (Exception) | ||
20500 | { | ||
20501 | } | ||
20502 | } | ||
20503 | } | ||
20504 | |||
20505 | // Not a version, check for numeric. | ||
20506 | if (null == type) | ||
20507 | { | ||
20508 | Int64 number; | ||
20509 | if (Int64.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture.NumberFormat, out number)) | ||
20510 | { | ||
20511 | type = "numeric"; | ||
20512 | } | ||
20513 | else | ||
20514 | { | ||
20515 | type = "string"; | ||
20516 | } | ||
20517 | } | ||
20518 | } | ||
20519 | |||
20520 | if (null == value && null != type) | ||
20521 | { | ||
20522 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, "Variable", "Value", "Type")); | ||
20523 | } | ||
20524 | |||
20525 | this.core.ParseForExtensionElements(node); | ||
20526 | |||
20527 | if (!this.core.EncounteredError) | ||
20528 | { | ||
20529 | WixBundleVariableRow row = (WixBundleVariableRow)this.core.CreateRow(sourceLineNumbers, "WixBundleVariable"); | ||
20530 | row.Id = name; | ||
20531 | row.Value = value; | ||
20532 | row.Type = type; | ||
20533 | row.Hidden = hidden; | ||
20534 | row.Persisted = persisted; | ||
20535 | } | ||
20536 | } | ||
20537 | |||
20538 | |||
20539 | |||
20540 | /// <summary> | ||
20541 | /// Parses a Wix element. | ||
20542 | /// </summary> | ||
20543 | /// <param name="node">Element to parse.</param> | ||
20544 | private void ParseWixElement(XElement node) | ||
20545 | { | ||
20546 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
20547 | string requiredVersion = null; | ||
20548 | |||
20549 | foreach (XAttribute attrib in node.Attributes()) | ||
20550 | { | ||
20551 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
20552 | { | ||
20553 | switch (attrib.Name.LocalName) | ||
20554 | { | ||
20555 | case "RequiredVersion": | ||
20556 | requiredVersion = this.core.GetAttributeVersionValue(sourceLineNumbers, attrib); | ||
20557 | break; | ||
20558 | default: | ||
20559 | this.core.UnexpectedAttribute(node, attrib); | ||
20560 | break; | ||
20561 | } | ||
20562 | } | ||
20563 | else | ||
20564 | { | ||
20565 | this.core.ParseExtensionAttribute(node, attrib); | ||
20566 | } | ||
20567 | } | ||
20568 | |||
20569 | if (null != requiredVersion) | ||
20570 | { | ||
20571 | this.core.VerifyRequiredVersion(sourceLineNumbers, requiredVersion); | ||
20572 | } | ||
20573 | |||
20574 | foreach (XElement child in node.Elements()) | ||
20575 | { | ||
20576 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
20577 | { | ||
20578 | switch (child.Name.LocalName) | ||
20579 | { | ||
20580 | case "Bundle": | ||
20581 | this.ParseBundleElement(child); | ||
20582 | break; | ||
20583 | case "Fragment": | ||
20584 | this.ParseFragmentElement(child); | ||
20585 | break; | ||
20586 | case "Module": | ||
20587 | this.ParseModuleElement(child); | ||
20588 | break; | ||
20589 | case "PatchCreation": | ||
20590 | this.ParsePatchCreationElement(child); | ||
20591 | break; | ||
20592 | case "Product": | ||
20593 | this.ParseProductElement(child); | ||
20594 | break; | ||
20595 | case "Patch": | ||
20596 | this.ParsePatchElement(child); | ||
20597 | break; | ||
20598 | default: | ||
20599 | this.core.UnexpectedElement(node, child); | ||
20600 | break; | ||
20601 | } | ||
20602 | } | ||
20603 | else | ||
20604 | { | ||
20605 | this.core.ParseExtensionElement(node, child); | ||
20606 | } | ||
20607 | } | ||
20608 | } | ||
20609 | |||
20610 | /// <summary> | ||
20611 | /// Parses a WixVariable element. | ||
20612 | /// </summary> | ||
20613 | /// <param name="node">Element to parse.</param> | ||
20614 | private void ParseWixVariableElement(XElement node) | ||
20615 | { | ||
20616 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
20617 | Identifier id = null; | ||
20618 | bool overridable = false; | ||
20619 | string value = null; | ||
20620 | |||
20621 | foreach (XAttribute attrib in node.Attributes()) | ||
20622 | { | ||
20623 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
20624 | { | ||
20625 | switch (attrib.Name.LocalName) | ||
20626 | { | ||
20627 | case "Id": | ||
20628 | id = this.core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
20629 | break; | ||
20630 | case "Overridable": | ||
20631 | overridable = (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)); | ||
20632 | break; | ||
20633 | case "Value": | ||
20634 | value = this.core.GetAttributeValue(sourceLineNumbers, attrib, EmptyRule.CanBeEmpty); | ||
20635 | break; | ||
20636 | default: | ||
20637 | this.core.UnexpectedAttribute(node, attrib); | ||
20638 | break; | ||
20639 | } | ||
20640 | } | ||
20641 | else | ||
20642 | { | ||
20643 | this.core.ParseExtensionAttribute(node, attrib); | ||
20644 | } | ||
20645 | } | ||
20646 | |||
20647 | if (null == id) | ||
20648 | { | ||
20649 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
20650 | } | ||
20651 | |||
20652 | if (null == value) | ||
20653 | { | ||
20654 | this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Value")); | ||
20655 | } | ||
20656 | |||
20657 | this.core.ParseForExtensionElements(node); | ||
20658 | |||
20659 | if (!this.core.EncounteredError) | ||
20660 | { | ||
20661 | WixVariableRow wixVariableRow = (WixVariableRow)this.core.CreateRow(sourceLineNumbers, "WixVariable", id); | ||
20662 | wixVariableRow.Value = value; | ||
20663 | wixVariableRow.Overridable = overridable; | ||
20664 | } | ||
20665 | } | ||
20666 | } | ||
20667 | } | ||