diff options
Diffstat (limited to 'src/WixToolset.Core/Compiler_Patch.cs')
-rw-r--r-- | src/WixToolset.Core/Compiler_Patch.cs | 655 |
1 files changed, 655 insertions, 0 deletions
diff --git a/src/WixToolset.Core/Compiler_Patch.cs b/src/WixToolset.Core/Compiler_Patch.cs new file mode 100644 index 00000000..42951543 --- /dev/null +++ b/src/WixToolset.Core/Compiler_Patch.cs | |||
@@ -0,0 +1,655 @@ | |||
1 | // Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. | ||
2 | |||
3 | namespace WixToolset.Core | ||
4 | { | ||
5 | using System; | ||
6 | using System.Collections.Generic; | ||
7 | using System.Diagnostics; | ||
8 | using System.Globalization; | ||
9 | using System.Xml.Linq; | ||
10 | using WixToolset.Data; | ||
11 | using WixToolset.Data.Tuples; | ||
12 | using WixToolset.Extensibility; | ||
13 | |||
14 | /// <summary> | ||
15 | /// Compiler of the WiX toolset. | ||
16 | /// </summary> | ||
17 | internal partial class Compiler : ICompiler | ||
18 | { | ||
19 | /// <summary> | ||
20 | /// Parses an patch element. | ||
21 | /// </summary> | ||
22 | /// <param name="node">The element to parse.</param> | ||
23 | private void ParsePatchElement(XElement node) | ||
24 | { | ||
25 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
26 | string patchId = null; | ||
27 | var codepage = 0; | ||
28 | ////bool versionMismatches = false; | ||
29 | ////bool productMismatches = false; | ||
30 | var allowRemoval = false; | ||
31 | string classification = null; | ||
32 | string clientPatchId = null; | ||
33 | string description = null; | ||
34 | string displayName = null; | ||
35 | string comments = null; | ||
36 | string manufacturer = null; | ||
37 | var minorUpdateTargetRTM = YesNoType.NotSet; | ||
38 | string moreInfoUrl = null; | ||
39 | var optimizeCA = CompilerConstants.IntegerNotSet; | ||
40 | var optimizedInstallMode = YesNoType.NotSet; | ||
41 | string targetProductName = null; | ||
42 | // string replaceGuids = String.Empty; | ||
43 | var apiPatchingSymbolFlags = 0; | ||
44 | var optimizePatchSizeForLargeFiles = false; | ||
45 | |||
46 | foreach (var attrib in node.Attributes()) | ||
47 | { | ||
48 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
49 | { | ||
50 | switch (attrib.Name.LocalName) | ||
51 | { | ||
52 | case "Id": | ||
53 | patchId = this.Core.GetAttributeGuidValue(sourceLineNumbers, attrib, true); | ||
54 | break; | ||
55 | case "Codepage": | ||
56 | codepage = this.Core.GetAttributeCodePageValue(sourceLineNumbers, attrib); | ||
57 | break; | ||
58 | case "AllowMajorVersionMismatches": | ||
59 | ////versionMismatches = (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)); | ||
60 | break; | ||
61 | case "AllowProductCodeMismatches": | ||
62 | ////productMismatches = (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)); | ||
63 | break; | ||
64 | case "AllowRemoval": | ||
65 | allowRemoval = (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)); | ||
66 | break; | ||
67 | case "Classification": | ||
68 | classification = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
69 | break; | ||
70 | case "ClientPatchId": | ||
71 | clientPatchId = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
72 | break; | ||
73 | case "Description": | ||
74 | description = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
75 | break; | ||
76 | case "DisplayName": | ||
77 | displayName = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
78 | break; | ||
79 | case "Comments": | ||
80 | comments = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
81 | break; | ||
82 | case "Manufacturer": | ||
83 | manufacturer = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
84 | break; | ||
85 | case "MinorUpdateTargetRTM": | ||
86 | minorUpdateTargetRTM = this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
87 | break; | ||
88 | case "MoreInfoURL": | ||
89 | moreInfoUrl = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
90 | break; | ||
91 | case "OptimizedInstallMode": | ||
92 | optimizedInstallMode = this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
93 | break; | ||
94 | case "TargetProductName": | ||
95 | targetProductName = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
96 | break; | ||
97 | case "ApiPatchingSymbolNoImagehlpFlag": | ||
98 | apiPatchingSymbolFlags |= (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) ? (int)PatchSymbolFlagsType.PATCH_SYMBOL_NO_IMAGEHLP : 0; | ||
99 | break; | ||
100 | case "ApiPatchingSymbolNoFailuresFlag": | ||
101 | apiPatchingSymbolFlags |= (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) ? (int)PatchSymbolFlagsType.PATCH_SYMBOL_NO_FAILURES : 0; | ||
102 | break; | ||
103 | case "ApiPatchingSymbolUndecoratedTooFlag": | ||
104 | apiPatchingSymbolFlags |= (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) ? (int)PatchSymbolFlagsType.PATCH_SYMBOL_UNDECORATED_TOO : 0; | ||
105 | break; | ||
106 | case "OptimizePatchSizeForLargeFiles": | ||
107 | optimizePatchSizeForLargeFiles = (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)); | ||
108 | break; | ||
109 | default: | ||
110 | this.Core.UnexpectedAttribute(node, attrib); | ||
111 | break; | ||
112 | } | ||
113 | } | ||
114 | else | ||
115 | { | ||
116 | this.Core.ParseExtensionAttribute(node, attrib); | ||
117 | } | ||
118 | } | ||
119 | |||
120 | if (patchId == null || patchId == "*") | ||
121 | { | ||
122 | // auto-generate at compile time, since this value gets dispersed to several locations | ||
123 | patchId = Common.GenerateGuid(); | ||
124 | } | ||
125 | this.activeName = patchId; | ||
126 | |||
127 | if (null == this.activeName) | ||
128 | { | ||
129 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
130 | } | ||
131 | if (null == classification) | ||
132 | { | ||
133 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Classification")); | ||
134 | } | ||
135 | if (null == clientPatchId) | ||
136 | { | ||
137 | clientPatchId = String.Concat("_", new Guid(patchId).ToString("N", CultureInfo.InvariantCulture).ToUpper(CultureInfo.InvariantCulture)); | ||
138 | } | ||
139 | if (null == description) | ||
140 | { | ||
141 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Description")); | ||
142 | } | ||
143 | if (null == displayName) | ||
144 | { | ||
145 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "DisplayName")); | ||
146 | } | ||
147 | if (null == manufacturer) | ||
148 | { | ||
149 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Manufacturer")); | ||
150 | } | ||
151 | |||
152 | this.Core.CreateActiveSection(this.activeName, SectionType.Patch, codepage, this.Context.CompilationId); | ||
153 | |||
154 | foreach (var child in node.Elements()) | ||
155 | { | ||
156 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
157 | { | ||
158 | switch (child.Name.LocalName) | ||
159 | { | ||
160 | case "PatchInformation": | ||
161 | this.ParsePatchInformationElement(child); | ||
162 | break; | ||
163 | case "Media": | ||
164 | this.ParseMediaElement(child, patchId); | ||
165 | break; | ||
166 | case "OptimizeCustomActions": | ||
167 | optimizeCA = this.ParseOptimizeCustomActionsElement(child); | ||
168 | break; | ||
169 | case "PatchFamily": | ||
170 | this.ParsePatchFamilyElement(child, ComplexReferenceParentType.Patch, patchId); | ||
171 | break; | ||
172 | case "PatchFamilyRef": | ||
173 | this.ParsePatchFamilyRefElement(child, ComplexReferenceParentType.Patch, patchId); | ||
174 | break; | ||
175 | case "PatchFamilyGroup": | ||
176 | this.ParsePatchFamilyGroupElement(child, ComplexReferenceParentType.Patch, patchId); | ||
177 | break; | ||
178 | case "PatchFamilyGroupRef": | ||
179 | this.ParsePatchFamilyGroupRefElement(child, ComplexReferenceParentType.Patch, patchId); | ||
180 | break; | ||
181 | case "PatchProperty": | ||
182 | this.ParsePatchPropertyElement(child, true); | ||
183 | break; | ||
184 | case "TargetProductCodes": | ||
185 | this.ParseTargetProductCodesElement(child); | ||
186 | break; | ||
187 | default: | ||
188 | this.Core.UnexpectedElement(node, child); | ||
189 | break; | ||
190 | } | ||
191 | } | ||
192 | else | ||
193 | { | ||
194 | this.Core.ParseExtensionElement(node, child); | ||
195 | } | ||
196 | } | ||
197 | |||
198 | if (!this.Core.EncounteredError) | ||
199 | { | ||
200 | var tuple = new WixPatchIdTuple(sourceLineNumbers) | ||
201 | { | ||
202 | ProductCode = patchId, | ||
203 | ClientPatchId = clientPatchId, | ||
204 | OptimizePatchSizeForLargeFiles = optimizePatchSizeForLargeFiles, | ||
205 | ApiPatchingSymbolFlags = apiPatchingSymbolFlags | ||
206 | }; | ||
207 | |||
208 | this.Core.AddTuple(tuple); | ||
209 | |||
210 | if (allowRemoval) | ||
211 | { | ||
212 | this.AddMsiPatchMetadata(sourceLineNumbers, null, "AllowRemoval", allowRemoval ? "1" : "0"); | ||
213 | } | ||
214 | |||
215 | if (null != classification) | ||
216 | { | ||
217 | this.AddMsiPatchMetadata(sourceLineNumbers, null, "Classification", classification); | ||
218 | } | ||
219 | |||
220 | // always generate the CreationTimeUTC | ||
221 | { | ||
222 | this.AddMsiPatchMetadata(sourceLineNumbers, null, "CreationTimeUTC", DateTime.UtcNow.ToString("MM-dd-yy HH:mm", CultureInfo.InvariantCulture)); | ||
223 | } | ||
224 | |||
225 | if (null != description) | ||
226 | { | ||
227 | this.AddMsiPatchMetadata(sourceLineNumbers, null, "Description", description); | ||
228 | } | ||
229 | |||
230 | if (null != displayName) | ||
231 | { | ||
232 | this.AddMsiPatchMetadata(sourceLineNumbers, null, "DisplayName", displayName); | ||
233 | } | ||
234 | |||
235 | if (null != manufacturer) | ||
236 | { | ||
237 | this.AddMsiPatchMetadata(sourceLineNumbers, null, "ManufacturerName", manufacturer); | ||
238 | } | ||
239 | |||
240 | if (YesNoType.NotSet != minorUpdateTargetRTM) | ||
241 | { | ||
242 | this.AddMsiPatchMetadata(sourceLineNumbers, null, "MinorUpdateTargetRTM", YesNoType.Yes == minorUpdateTargetRTM ? "1" : "0"); | ||
243 | } | ||
244 | |||
245 | if (null != moreInfoUrl) | ||
246 | { | ||
247 | this.AddMsiPatchMetadata(sourceLineNumbers, null, "MoreInfoURL", moreInfoUrl); | ||
248 | } | ||
249 | |||
250 | if (CompilerConstants.IntegerNotSet != optimizeCA) | ||
251 | { | ||
252 | this.AddMsiPatchMetadata(sourceLineNumbers, null, "OptimizeCA", optimizeCA.ToString(CultureInfo.InvariantCulture)); | ||
253 | } | ||
254 | |||
255 | if (YesNoType.NotSet != optimizedInstallMode) | ||
256 | { | ||
257 | this.AddMsiPatchMetadata(sourceLineNumbers, null, "OptimizedInstallMode", YesNoType.Yes == optimizedInstallMode ? "1" : "0"); | ||
258 | } | ||
259 | |||
260 | if (null != targetProductName) | ||
261 | { | ||
262 | this.AddMsiPatchMetadata(sourceLineNumbers, null, "TargetProductName", targetProductName); | ||
263 | } | ||
264 | |||
265 | if (null != comments) | ||
266 | { | ||
267 | this.AddMsiPatchMetadata(sourceLineNumbers, null, "Comments", comments); | ||
268 | } | ||
269 | } | ||
270 | // TODO: do something with versionMismatches and productMismatches | ||
271 | } | ||
272 | |||
273 | /// <summary> | ||
274 | /// Parses the OptimizeCustomActions element. | ||
275 | /// </summary> | ||
276 | /// <param name="node">Element to parse.</param> | ||
277 | /// <returns>The combined integer value for callers to store as appropriate.</returns> | ||
278 | private int ParseOptimizeCustomActionsElement(XElement node) | ||
279 | { | ||
280 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
281 | var optimizeCA = OptimizeCA.None; | ||
282 | |||
283 | foreach (var attrib in node.Attributes()) | ||
284 | { | ||
285 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
286 | { | ||
287 | switch (attrib.Name.LocalName) | ||
288 | { | ||
289 | case "SkipAssignment": | ||
290 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
291 | { | ||
292 | optimizeCA |= OptimizeCA.SkipAssignment; | ||
293 | } | ||
294 | break; | ||
295 | case "SkipImmediate": | ||
296 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
297 | { | ||
298 | optimizeCA |= OptimizeCA.SkipImmediate; | ||
299 | } | ||
300 | break; | ||
301 | case "SkipDeferred": | ||
302 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
303 | { | ||
304 | optimizeCA |= OptimizeCA.SkipDeferred; | ||
305 | } | ||
306 | break; | ||
307 | default: | ||
308 | this.Core.UnexpectedAttribute(node, attrib); | ||
309 | break; | ||
310 | } | ||
311 | } | ||
312 | else | ||
313 | { | ||
314 | this.Core.ParseExtensionAttribute(node, attrib); | ||
315 | } | ||
316 | } | ||
317 | |||
318 | return (int)optimizeCA; | ||
319 | } | ||
320 | |||
321 | /// <summary> | ||
322 | /// Parses a PatchFamily element. | ||
323 | /// </summary> | ||
324 | /// <param name="node">The element to parse.</param> | ||
325 | private void ParsePatchFamilyElement(XElement node, ComplexReferenceParentType parentType, string parentId) | ||
326 | { | ||
327 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
328 | Identifier id = null; | ||
329 | string productCode = null; | ||
330 | string version = null; | ||
331 | var attributes = 0; | ||
332 | |||
333 | foreach (var attrib in node.Attributes()) | ||
334 | { | ||
335 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
336 | { | ||
337 | switch (attrib.Name.LocalName) | ||
338 | { | ||
339 | case "Id": | ||
340 | id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
341 | break; | ||
342 | case "ProductCode": | ||
343 | productCode = this.Core.GetAttributeGuidValue(sourceLineNumbers, attrib, false); | ||
344 | break; | ||
345 | case "Version": | ||
346 | version = this.Core.GetAttributeVersionValue(sourceLineNumbers, attrib); | ||
347 | break; | ||
348 | case "Supersede": | ||
349 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
350 | { | ||
351 | attributes |= 0x1; | ||
352 | } | ||
353 | break; | ||
354 | default: | ||
355 | this.Core.UnexpectedAttribute(node, attrib); | ||
356 | break; | ||
357 | } | ||
358 | } | ||
359 | else | ||
360 | { | ||
361 | this.Core.ParseExtensionAttribute(node, attrib); | ||
362 | } | ||
363 | } | ||
364 | |||
365 | if (null == id) | ||
366 | { | ||
367 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
368 | id = Identifier.Invalid; | ||
369 | } | ||
370 | |||
371 | if (String.IsNullOrEmpty(version)) | ||
372 | { | ||
373 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Version")); | ||
374 | } | ||
375 | else if (!CompilerCore.IsValidProductVersion(version)) | ||
376 | { | ||
377 | this.Core.Write(ErrorMessages.InvalidProductVersion(sourceLineNumbers, version)); | ||
378 | } | ||
379 | |||
380 | // find unexpected child elements | ||
381 | foreach (var child in node.Elements()) | ||
382 | { | ||
383 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
384 | { | ||
385 | switch (child.Name.LocalName) | ||
386 | { | ||
387 | case "All": | ||
388 | this.ParseAllElement(child); | ||
389 | break; | ||
390 | case "BinaryRef": | ||
391 | this.ParsePatchChildRefElement(child, "Binary"); | ||
392 | break; | ||
393 | case "ComponentRef": | ||
394 | this.ParsePatchChildRefElement(child, "Component"); | ||
395 | break; | ||
396 | case "CustomActionRef": | ||
397 | this.ParsePatchChildRefElement(child, "CustomAction"); | ||
398 | break; | ||
399 | case "DirectoryRef": | ||
400 | this.ParsePatchChildRefElement(child, "Directory"); | ||
401 | break; | ||
402 | case "DigitalCertificateRef": | ||
403 | this.ParsePatchChildRefElement(child, "MsiDigitalCertificate"); | ||
404 | break; | ||
405 | case "FeatureRef": | ||
406 | this.ParsePatchChildRefElement(child, "Feature"); | ||
407 | break; | ||
408 | case "IconRef": | ||
409 | this.ParsePatchChildRefElement(child, "Icon"); | ||
410 | break; | ||
411 | case "PropertyRef": | ||
412 | this.ParsePatchChildRefElement(child, "Property"); | ||
413 | break; | ||
414 | case "UIRef": | ||
415 | this.ParsePatchChildRefElement(child, "WixUI"); | ||
416 | break; | ||
417 | default: | ||
418 | this.Core.UnexpectedElement(node, child); | ||
419 | break; | ||
420 | } | ||
421 | } | ||
422 | else | ||
423 | { | ||
424 | this.Core.ParseExtensionElement(node, child); | ||
425 | } | ||
426 | } | ||
427 | |||
428 | |||
429 | if (!this.Core.EncounteredError) | ||
430 | { | ||
431 | var tuple = new MsiPatchSequenceTuple(sourceLineNumbers) | ||
432 | { | ||
433 | PatchFamily = id.Id, | ||
434 | ProductCode = productCode, | ||
435 | Sequence = version, | ||
436 | Attributes = attributes | ||
437 | }; | ||
438 | |||
439 | this.Core.AddTuple(tuple); | ||
440 | |||
441 | if (ComplexReferenceParentType.Unknown != parentType) | ||
442 | { | ||
443 | this.Core.CreateComplexReference(sourceLineNumbers, parentType, parentId, null, ComplexReferenceChildType.PatchFamily, id.Id, ComplexReferenceParentType.Patch == parentType); | ||
444 | } | ||
445 | } | ||
446 | } | ||
447 | |||
448 | /// <summary> | ||
449 | /// Parses a PatchFamilyGroup element. | ||
450 | /// </summary> | ||
451 | /// <param name="node">Element to parse.</param> | ||
452 | [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1800:DoNotCastUnnecessarily")] | ||
453 | private void ParsePatchFamilyGroupElement(XElement node, ComplexReferenceParentType parentType, string parentId) | ||
454 | { | ||
455 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
456 | Identifier id = null; | ||
457 | |||
458 | foreach (var 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 | id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
466 | break; | ||
467 | default: | ||
468 | this.Core.UnexpectedAttribute(node, attrib); | ||
469 | break; | ||
470 | } | ||
471 | } | ||
472 | else | ||
473 | { | ||
474 | this.Core.ParseExtensionAttribute(node, attrib); | ||
475 | } | ||
476 | } | ||
477 | |||
478 | if (null == id) | ||
479 | { | ||
480 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
481 | id = Identifier.Invalid; | ||
482 | } | ||
483 | |||
484 | foreach (var child in node.Elements()) | ||
485 | { | ||
486 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
487 | { | ||
488 | switch (child.Name.LocalName) | ||
489 | { | ||
490 | case "PatchFamily": | ||
491 | this.ParsePatchFamilyElement(child, ComplexReferenceParentType.PatchFamilyGroup, id.Id); | ||
492 | break; | ||
493 | case "PatchFamilyRef": | ||
494 | this.ParsePatchFamilyRefElement(child, ComplexReferenceParentType.PatchFamilyGroup, id.Id); | ||
495 | break; | ||
496 | case "PatchFamilyGroupRef": | ||
497 | this.ParsePatchFamilyGroupRefElement(child, ComplexReferenceParentType.PatchFamilyGroup, id.Id); | ||
498 | break; | ||
499 | default: | ||
500 | this.Core.UnexpectedElement(node, child); | ||
501 | break; | ||
502 | } | ||
503 | } | ||
504 | else | ||
505 | { | ||
506 | this.Core.ParseExtensionElement(node, child); | ||
507 | } | ||
508 | } | ||
509 | |||
510 | if (!this.Core.EncounteredError) | ||
511 | { | ||
512 | this.Core.AddTuple(new WixPatchFamilyGroupTuple(sourceLineNumbers, id)); | ||
513 | |||
514 | //Add this PatchFamilyGroup and its parent in WixGroup. | ||
515 | this.Core.CreateWixGroupRow(sourceLineNumbers, parentType, parentId, ComplexReferenceChildType.PatchFamilyGroup, id.Id); | ||
516 | } | ||
517 | } | ||
518 | |||
519 | /// <summary> | ||
520 | /// Parses a PatchFamilyGroup reference element. | ||
521 | /// </summary> | ||
522 | /// <param name="node">Element to parse.</param> | ||
523 | /// <param name="parentType">The type of parent.</param> | ||
524 | /// <param name="parentId">Identifier of parent element.</param> | ||
525 | private void ParsePatchFamilyGroupRefElement(XElement node, ComplexReferenceParentType parentType, string parentId) | ||
526 | { | ||
527 | Debug.Assert(ComplexReferenceParentType.PatchFamilyGroup == parentType || ComplexReferenceParentType.Patch == parentType); | ||
528 | |||
529 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
530 | string id = null; | ||
531 | |||
532 | foreach (var attrib in node.Attributes()) | ||
533 | { | ||
534 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
535 | { | ||
536 | switch (attrib.Name.LocalName) | ||
537 | { | ||
538 | case "Id": | ||
539 | id = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
540 | this.Core.CreateSimpleReference(sourceLineNumbers, "WixPatchFamilyGroup", id); | ||
541 | break; | ||
542 | default: | ||
543 | this.Core.UnexpectedAttribute(node, attrib); | ||
544 | break; | ||
545 | } | ||
546 | } | ||
547 | else | ||
548 | { | ||
549 | this.Core.ParseExtensionAttribute(node, attrib); | ||
550 | } | ||
551 | } | ||
552 | |||
553 | if (null == id) | ||
554 | { | ||
555 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
556 | } | ||
557 | |||
558 | this.Core.ParseForExtensionElements(node); | ||
559 | |||
560 | if (!this.Core.EncounteredError) | ||
561 | { | ||
562 | this.Core.CreateComplexReference(sourceLineNumbers, parentType, parentId, null, ComplexReferenceChildType.PatchFamilyGroup, id, true); | ||
563 | } | ||
564 | } | ||
565 | |||
566 | /// <summary> | ||
567 | /// Parses a TargetProductCodes element. | ||
568 | /// </summary> | ||
569 | /// <param name="node">The element to parse.</param> | ||
570 | private void ParseTargetProductCodesElement(XElement node) | ||
571 | { | ||
572 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
573 | var replace = false; | ||
574 | var targetProductCodes = new List<string>(); | ||
575 | |||
576 | foreach (var attrib in node.Attributes()) | ||
577 | { | ||
578 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
579 | { | ||
580 | switch (attrib.Name.LocalName) | ||
581 | { | ||
582 | case "Replace": | ||
583 | replace = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
584 | break; | ||
585 | default: | ||
586 | this.Core.UnexpectedAttribute(node, attrib); | ||
587 | break; | ||
588 | } | ||
589 | } | ||
590 | else | ||
591 | { | ||
592 | this.Core.ParseExtensionAttribute(node, attrib); | ||
593 | } | ||
594 | } | ||
595 | |||
596 | foreach (var child in node.Elements()) | ||
597 | { | ||
598 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
599 | { | ||
600 | switch (child.Name.LocalName) | ||
601 | { | ||
602 | case "TargetProductCode": | ||
603 | var id = this.ParseTargetProductCodeElement(child); | ||
604 | if (0 == String.CompareOrdinal("*", id)) | ||
605 | { | ||
606 | this.Core.Write(ErrorMessages.IllegalAttributeValueWhenNested(sourceLineNumbers, child.Name.LocalName, "Id", id, node.Name.LocalName)); | ||
607 | } | ||
608 | else | ||
609 | { | ||
610 | targetProductCodes.Add(id); | ||
611 | } | ||
612 | break; | ||
613 | default: | ||
614 | this.Core.UnexpectedElement(node, child); | ||
615 | break; | ||
616 | } | ||
617 | } | ||
618 | else | ||
619 | { | ||
620 | this.Core.ParseExtensionElement(node, child); | ||
621 | } | ||
622 | } | ||
623 | |||
624 | if (!this.Core.EncounteredError) | ||
625 | { | ||
626 | // By default, target ProductCodes should be added. | ||
627 | if (!replace) | ||
628 | { | ||
629 | this.Core.AddTuple(new WixPatchTargetTuple(sourceLineNumbers) | ||
630 | { | ||
631 | ProductCode = "*" | ||
632 | }); | ||
633 | } | ||
634 | |||
635 | foreach (var targetProductCode in targetProductCodes) | ||
636 | { | ||
637 | this.Core.AddTuple(new WixPatchTargetTuple(sourceLineNumbers) | ||
638 | { | ||
639 | ProductCode = targetProductCode | ||
640 | }); | ||
641 | } | ||
642 | } | ||
643 | } | ||
644 | |||
645 | private void AddMsiPatchMetadata(SourceLineNumber sourceLineNumbers, string company, string property, string value) | ||
646 | { | ||
647 | this.Core.AddTuple(new MsiPatchMetadataTuple(sourceLineNumbers, new Identifier(AccessModifier.Private, company, property)) | ||
648 | { | ||
649 | Company = company, | ||
650 | Property = property, | ||
651 | Value = value | ||
652 | }); | ||
653 | } | ||
654 | } | ||
655 | } | ||