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 | } | ||
