/// <summary> /// Creates a new complex reference. /// </summary> /// <param name="parentType">Parent type of complex reference.</param> /// <param name="parentId">Identifier for parent of complex reference.</param> /// <param name="parentLanguage">Language for parent of complex reference (only valid when parent is Module).</param> /// <param name="childType">Child type of complex reference.</param> /// <param name="childId">Identifier for child of complex reference.</param> /// <param name="primary">Flag if complex reference is the primary for advertised goop.</param> public ComplexReference(ComplexReferenceParentType parentType, string parentId, string parentLanguage, ComplexReferenceChildType childType, string childId, bool primary) { if (ComplexReferenceParentType.Module != this.parentType && null != this.parentLanguage) { throw new ArgumentException("ParentLanguage cannot be specified unless the parent is a Module."); } this.parentType = parentType; this.parentId = parentId; this.parentLanguage = parentLanguage; this.childType = childType; this.childId = childId; this.primary = primary; this.section = null; }
/// <summary> /// Finds all nested items under a parent group and creates new WixGroup data for them. /// </summary> /// <param name="parentType">The group type for the parent group to flatten.</param> /// <param name="parentId">The identifier of the parent group to flatten.</param> /// <param name="removeUsedRows">Whether to remove used group rows before returning.</param> public void FlattenAndRewriteRows(ComplexReferenceChildType parentType, string parentId, bool removeUsedRows) { var parentTypeString = parentType.ToString(); Debug.Assert(this.groupTypes.Contains(parentTypeString)); this.CreateOrderedList(parentTypeString, parentId, out var orderedItems); if (this.Messaging.EncounteredError) { return; } this.CreateNewGroupRows(parentTypeString, parentId, orderedItems); if (removeUsedRows) { this.RemoveUsedGroupRows(); } }
/// <summary> /// Parse ExePackage element /// </summary> /// <param name="node">Element to parse</param> /// <param name="parentType">Type of parent group, if known.</param> /// <param name="parentId">Identifier of parent group, if known.</param> /// <param name="previousType">Type of previous item, if known.</param> /// <param name="previousId">Identifier of previous item, if known</param> /// <returns>Identifier for package element.</returns> private string ParseExePackageElement(XmlNode node, ComplexReferenceParentType parentType, string parentId, ComplexReferenceChildType previousType, string previousId) { return ParseChainPackage(node, ChainPackageType.Exe, parentType, parentId, previousType, previousId); }
/// <summary> /// Creates the row for a Payload. /// </summary> /// <param name="node">Element to parse</param> /// <param name="parentType">ComplexReferenceParentType of parent element</param> /// <param name="parentId">Identifier of parent element.</param> private void CreatePayloadRow(SourceLineNumberCollection sourceLineNumbers, string id, string name, string sourceFile, string downloadUrl, ComplexReferenceParentType parentType, string parentId, ComplexReferenceChildType previousType, string previousId, YesNoDefaultType compressed, YesNoType suppressSignatureVerification, string displayName, string description) { if (!this.core.EncounteredError) { Row row = this.core.CreateRow(sourceLineNumbers, "Payload"); row[0] = id; row[1] = String.IsNullOrEmpty(name) ? Path.GetFileName(sourceFile) : name; row[2] = sourceFile; row[3] = downloadUrl; if (YesNoDefaultType.Default != compressed) { row[4] = (YesNoDefaultType.Yes == compressed) ? 1 : 0; } row[5] = sourceFile; // duplicate of sourceFile but in a string column so it won't get resolved to a full path during binding. row[6] = (YesNoType.Yes == suppressSignatureVerification) ? 1 : 0; if (!String.IsNullOrEmpty(description) || !String.IsNullOrEmpty(displayName)) { Row rowDisplay = this.core.CreateRow(sourceLineNumbers, "PayloadDisplayInformation"); rowDisplay[0] = id; rowDisplay[1] = displayName; rowDisplay[2] = description; } this.CreateGroupAndOrderingRows(sourceLineNumbers, parentType, parentId, ComplexReferenceChildType.Payload, id, previousType, previousId); } }
/// <summary> /// Creates group and ordering information. /// </summary> /// <param name="sourceLineNumbers">Source line numbers.</param> /// <param name="parentType">Type of parent group, if known.</param> /// <param name="parentId">Identifier of parent group, if known.</param> /// <param name="type">Type of this item.</param> /// <param name="id">Identifier for this item.</param> /// <param name="previousType">Type of previous item, if known.</param> /// <param name="previousId">Identifier of previous item, if known</param> private void CreateGroupAndOrderingRows(SourceLineNumberCollection sourceLineNumbers, ComplexReferenceParentType parentType, string parentId, ComplexReferenceChildType type, string id, ComplexReferenceChildType previousType, string previousId) { if (ComplexReferenceParentType.Unknown != parentType && null != parentId) { this.core.CreateWixGroupRow(sourceLineNumbers, parentType, parentId, type, id); } if (ComplexReferenceChildType.Unknown != previousType && null != previousId) { this.CreateWixOrderingRow(sourceLineNumbers, type, id, previousType, previousId); } }
/// <summary> /// Parse Payload element. /// </summary> /// <param name="node">Element to parse</param> /// <param name="parentType">ComplexReferenceParentType of parent element. (BA or PayloadGroup)</param> /// <param name="parentId">Identifier of parent element.</param> private string ParsePayloadElement(XmlNode node, ComplexReferenceParentType parentType, string parentId, ComplexReferenceChildType previousType, string previousId) { Debug.Assert(ComplexReferenceParentType.PayloadGroup == parentType || ComplexReferenceParentType.Package == parentType || ComplexReferenceParentType.Container == parentType); Debug.Assert(ComplexReferenceChildType.Unknown == previousType || ComplexReferenceChildType.PayloadGroup == previousType || ComplexReferenceChildType.Payload == previousType); string id = ParsePayloadElementContent(node, parentType, parentId, previousType, previousId, true); foreach (XmlNode child in node.ChildNodes) { if (XmlNodeType.Element == child.NodeType) { if (child.NamespaceURI == this.schema.TargetNamespace) { switch (child.LocalName) { default: this.core.UnexpectedElement(node, child); break; } } else { this.core.UnsupportedExtensionElement(node, child); } } } return id; }
/// <summary> /// Parse the attributes of the Payload element. /// </summary> /// <param name="node">Element to parse</param> /// <param name="parentType">ComplexReferenceParentType of parent element.</param> /// <param name="parentId">Identifier of parent element.</param> private string ParsePayloadElementContent(XmlNode node, ComplexReferenceParentType parentType, string parentId, ComplexReferenceChildType previousType, string previousId, bool required) { Debug.Assert(ComplexReferenceParentType.PayloadGroup == parentType || ComplexReferenceParentType.Package == parentType || ComplexReferenceParentType.Container == parentType); SourceLineNumberCollection sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); YesNoDefaultType compressed = YesNoDefaultType.Default; YesNoType suppressSignatureVerification = YesNoType.NotSet; string id = null; string name = null; string sourceFile = null; string downloadUrl = null; PayloadInfoRow remotePayload = null; foreach (XmlAttribute attrib in node.Attributes) { if (0 == attrib.NamespaceURI.Length || attrib.NamespaceURI == this.schema.TargetNamespace) { switch (attrib.LocalName) { case "Id": id = this.core.GetAttributeValue(sourceLineNumbers, attrib); break; case "Compressed": compressed = this.core.GetAttributeYesNoDefaultValue(sourceLineNumbers, attrib); break; case "Name": name = this.core.GetAttributeLongFilename(sourceLineNumbers, attrib, false, true); break; case "SourceFile": sourceFile = this.core.GetAttributeValue(sourceLineNumbers, attrib); break; case "DownloadUrl": downloadUrl = this.core.GetAttributeValue(sourceLineNumbers, attrib); break; case "SuppressSignatureVerification": suppressSignatureVerification = this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); break; default: this.core.UnexpectedAttribute(sourceLineNumbers, attrib); break; } } else { this.core.UnsupportedExtensionAttribute(sourceLineNumbers, attrib); } } if (!required && null == sourceFile) { // Nothing left to do! return null; } foreach (XmlNode child in node.ChildNodes) { // We only handle the elements we care about. Let caller handle other children. if ((XmlNodeType.Element == child.NodeType) && (child.NamespaceURI == this.schema.TargetNamespace) && (child.LocalName == "RemotePayload")) { SourceLineNumberCollection childSourceLineNumbers = Preprocessor.GetSourceLineNumbers(child); if (node.NamespaceURI == this.schema.TargetNamespace && node.LocalName != "ExePackage") { this.core.OnMessage(WixErrors.RemotePayloadUnsupported(childSourceLineNumbers)); continue; } if (null != remotePayload) { this.core.OnMessage(WixErrors.TooManyChildren(childSourceLineNumbers, node.Name, child.LocalName)); } remotePayload = this.ParseRemotePayloadElement(child, id); } } if (null != sourceFile && null != remotePayload) { this.core.OnMessage(WixErrors.UnexpectedElementWithAttribute(sourceLineNumbers, node.Name, "RemotePayload", "SourceFile")); } else if (null == sourceFile && null == remotePayload) { this.core.OnMessage(WixErrors.ExpectedAttributeOrElement(sourceLineNumbers, node.Name, "SourceFile", "RemotePayload")); } else if (null == sourceFile) { sourceFile = String.Empty; } if (null == downloadUrl && null != remotePayload) { this.core.OnMessage(WixErrors.ExpectedAttributeWithElement(sourceLineNumbers, node.Name, "DownloadUrl", "RemotePayload")); } if (Compiler.BurnUXContainerId == parentId) { if (compressed == YesNoDefaultType.No) { core.OnMessage(WixWarnings.UxPayloadsOnlySupportEmbedding(sourceLineNumbers, sourceFile)); } compressed = YesNoDefaultType.Yes; } if (String.IsNullOrEmpty(id)) { id = this.core.GenerateIdentifier("pay", (null != sourceFile) ? sourceFile.ToUpperInvariant() : String.Empty); } if (null != remotePayload) { remotePayload.Id = id; } this.CreatePayloadRow(sourceLineNumbers, id, name, sourceFile, downloadUrl, parentType, parentId, previousType, previousId, compressed, suppressSignatureVerification, null, null); return id; }
// TODO: Should we define our own enum for this, just to ensure there's no "cross-contamination"? // TODO: Also, we could potentially include an 'Attributes' field to track things like // 'before' vs. 'after', and explicit vs. inferred dependencies. private void CreateWixOrderingRow(SourceLineNumberCollection sourceLineNumbers, ComplexReferenceChildType itemType, string itemId, ComplexReferenceChildType dependsOnType, string dependsOnId) { if (!this.core.EncounteredError) { Row row = this.core.CreateRow(sourceLineNumbers, "WixOrdering"); row[0] = itemType.ToString(); row[1] = itemId; row[2] = dependsOnType.ToString(); row[3] = dependsOnId; } }
/// <summary> /// Parse RollbackBoundary element /// </summary> /// <param name="node">Element to parse</param> /// <param name="parentType">Type of parent group, if known.</param> /// <param name="parentId">Identifier of parent group, if known.</param> /// <param name="previousType">Type of previous item, if known.</param> /// <param name="previousId">Identifier of previous item, if known</param> /// <returns>Identifier for package element.</returns> private string ParseRollbackBoundaryElement(XmlNode node, ComplexReferenceParentType parentType, string parentId, ComplexReferenceChildType previousType, string previousId) { Debug.Assert(ComplexReferenceParentType.PackageGroup == parentType); Debug.Assert(ComplexReferenceChildType.Unknown == previousType || ComplexReferenceChildType.PackageGroup == previousType || ComplexReferenceChildType.Package == previousType); SourceLineNumberCollection sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); string id = null; YesNoType vital = YesNoType.Yes; // This crazy list lets us evaluate extension attributes *after* all core attributes // have been parsed and dealt with, regardless of authoring order. List<KeyValuePair<SourceLineNumberCollection, XmlAttribute>> extensionAttributes = new List<KeyValuePair<SourceLineNumberCollection, XmlAttribute>>(); foreach (XmlAttribute attrib in node.Attributes) { if (0 == attrib.NamespaceURI.Length || attrib.NamespaceURI == this.schema.TargetNamespace) { bool allowed = true; switch (attrib.LocalName) { case "Id": id = this.core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); break; case "Vital": vital = this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); break; default: allowed = false; break; } if (!allowed) { this.core.UnexpectedAttribute(sourceLineNumbers, attrib); } } else { // Save the extension attributes for later... extensionAttributes.Add(new KeyValuePair<SourceLineNumberCollection, XmlAttribute>(sourceLineNumbers, attrib)); } } if (String.IsNullOrEmpty(id)) { if (!String.IsNullOrEmpty(previousId)) { id = this.core.GenerateIdentifier("rba", previousId); } if (null == id) { this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name, "Id")); } else if (!CompilerCore.IsIdentifier(id)) { this.core.OnMessage(WixErrors.IllegalIdentifier(sourceLineNumbers, node.Name, "Id", id)); } } // Now that the package ID is known, we can parse the extension attributes... Dictionary<string, string> contextValues = new Dictionary<string, string>(); contextValues["RollbackBoundaryId"] = id; foreach (KeyValuePair<SourceLineNumberCollection, XmlAttribute> pair in extensionAttributes) { this.core.ParseExtensionAttribute(pair.Key, (XmlElement)node, pair.Value, contextValues); } foreach (XmlNode child in node.ChildNodes) { if (XmlNodeType.Element == child.NodeType) { if (child.NamespaceURI == this.schema.TargetNamespace) { this.core.UnexpectedElement(node, child); } else { this.core.ParseExtensionElement(sourceLineNumbers, (XmlElement)node, (XmlElement)child, id); } } } if (!this.core.EncounteredError) { Row row = this.core.CreateRow(sourceLineNumbers, "ChainPackage"); row[0] = id; row[1] = ChainPackageType.RollbackBoundary.ToString(); if (YesNoType.NotSet != vital) { row[10] = (YesNoType.Yes == vital) ? 1 : 0; } this.CreateChainPackageMetaRows(sourceLineNumbers, parentType, parentId, ComplexReferenceChildType.Package, id, previousType, previousId, null); } return id; }
/// <summary> /// Parses a package group reference element. /// </summary> /// <param name="node">Element to parse.</param> /// <param name="parentType">ComplexReferenceParentType of parent element (Unknown or PackageGroup).</param> /// <param name="parentId">Identifier of parent element.</param> /// <param name="parentType">ComplexReferenceParentType of previous element (Unknown, Package, or PackageGroup).</param> /// <param name="parentId">Identifier of parent element.</param> /// <returns>Identifier for package group element.</rereturns> private string ParsePackageGroupRefElement(XmlNode node, ComplexReferenceParentType parentType, string parentId, ComplexReferenceChildType previousType, string previousId) { Debug.Assert(ComplexReferenceParentType.Unknown == parentType || ComplexReferenceParentType.PackageGroup == parentType || ComplexReferenceParentType.Container == parentType); Debug.Assert(ComplexReferenceChildType.Unknown == previousType || ComplexReferenceChildType.PackageGroup == previousType || ComplexReferenceChildType.Package == previousType); SourceLineNumberCollection sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); string id = null; string after = null; foreach (XmlAttribute attrib in node.Attributes) { if (0 == attrib.NamespaceURI.Length || attrib.NamespaceURI == this.schema.TargetNamespace) { switch (attrib.LocalName) { case "Id": id = this.core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); this.core.CreateWixSimpleReferenceRow(sourceLineNumbers, "ChainPackageGroup", id); break; case "After": after = this.core.GetAttributeValue(sourceLineNumbers, attrib); break; default: this.core.UnexpectedAttribute(sourceLineNumbers, attrib); break; } } else { this.core.UnsupportedExtensionAttribute(sourceLineNumbers, attrib); } } if (null == id) { this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name, "Id")); } if (null != after && ComplexReferenceParentType.Container == parentType) { this.core.OnMessage(WixErrors.IllegalAttributeWhenNested(sourceLineNumbers, node.Name, "After", parentId)); } foreach (XmlNode child in node.ChildNodes) { if (XmlNodeType.Element == child.NodeType) { if (child.NamespaceURI == this.schema.TargetNamespace) { this.core.UnexpectedElement(node, child); } else { this.core.UnsupportedExtensionElement(node, child); } } } if (ComplexReferenceParentType.Container == parentType) { this.core.CreateWixGroupRow(sourceLineNumbers, ComplexReferenceParentType.Container, parentId, ComplexReferenceChildType.PackageGroup, id); } else { this.CreateChainPackageMetaRows(sourceLineNumbers, parentType, parentId, ComplexReferenceChildType.PackageGroup, id, previousType, previousId, after); } return id; }
public void CreateWixGroupRow(IntermediateSection section, SourceLineNumber sourceLineNumbers, ComplexReferenceParentType parentType, string parentId, ComplexReferenceChildType childType, string childId) { if (null == parentId || ComplexReferenceParentType.Unknown == parentType) { return; } if (null == childId) { throw new ArgumentNullException("childId"); } var row = (WixGroupTuple)this.CreateRow(section, sourceLineNumbers, TupleDefinitionType.WixGroup); row.ParentId = parentId; row.ParentType = parentType; row.ChildId = childId; row.ChildType = childType; }
public void CreateComplexReference(IntermediateSection section, SourceLineNumber sourceLineNumbers, ComplexReferenceParentType parentType, string parentId, string parentLanguage, ComplexReferenceChildType childType, string childId, bool isPrimary) { var wixComplexReferenceRow = (WixComplexReferenceTuple)this.CreateRow(section, sourceLineNumbers, TupleDefinitionType.WixComplexReference); wixComplexReferenceRow.Parent = parentId; wixComplexReferenceRow.ParentType = parentType; wixComplexReferenceRow.ParentLanguage = parentLanguage; wixComplexReferenceRow.Child = childId; wixComplexReferenceRow.ChildType = childType; wixComplexReferenceRow.IsPrimary = isPrimary; this.CreateWixGroupRow(section, sourceLineNumbers, parentType, parentId, childType, childId); }
private string CombineTypeAndId(ComplexReferenceChildType type, string id) { return String.Format("{0}:{1}", type.ToString(), id); }
public WixBundlePayloadSymbol CreatePayloadSymbol(ComplexReferenceParentType parentType, string parentId, ComplexReferenceChildType previousType = ComplexReferenceChildType.Unknown, string previousId = null) { WixBundlePayloadSymbol symbol = null; if (parentType == ComplexReferenceParentType.Container && parentId == BurnConstants.BurnUXContainerName) { if (this.Compressed == YesNoDefaultType.No) { this.Core.Write(WarningMessages.UxPayloadsOnlySupportEmbedding(this.SourceLineNumbers, this.SourceFile)); } if (!String.IsNullOrEmpty(this.DownloadUrl)) { this.Core.Write(WarningMessages.DownloadUrlNotSupportedForBAPayloads(this.SourceLineNumbers, this.Id.Id)); } this.Compressed = YesNoDefaultType.Yes; this.DownloadUrl = null; } if (!this.Core.EncounteredError) { symbol = this.Core.AddSymbol(new WixBundlePayloadSymbol(this.SourceLineNumbers, this.Id) { Name = String.IsNullOrEmpty(this.Name) ? Path.GetFileName(this.SourceFile) : this.Name, SourceFile = new IntermediateFieldPathValue { Path = this.SourceFile }, DownloadUrl = this.DownloadUrl, Compressed = (this.Compressed == YesNoDefaultType.Yes) ? true : (this.Compressed == YesNoDefaultType.No) ? (bool?)false : null, UnresolvedSourceFile = this.SourceFile, // duplicate of sourceFile but in a string column so it won't get resolved to a full path during binding. DisplayName = this.ProductName, Description = this.Description, Hash = this.Hash, FileSize = this.Size, Version = this.Version, }); this.Core.CreateGroupAndOrderingRows(this.SourceLineNumbers, parentType, parentId, ComplexReferenceChildType.Payload, symbol.Id.Id, previousType, previousId); } return(symbol); }
/// <summary> /// A row in the WixGroup table is added for this child node and its parent node. /// </summary> /// <param name="sourceLineNumbers">Source line information for the row.</param> /// <param name="parentType">Type of child's complex reference parent.</param> /// <param name="parentId">Id of the parenet node.</param> /// <param name="childType">Complex reference type of child</param> /// <param name="childId">Id of the Child Node.</param> public void CreateWixGroupRow(SourceLineNumberCollection sourceLineNumbers, ComplexReferenceParentType parentType, string parentId, ComplexReferenceChildType childType, string childId) { if (!this.EncounteredError) { if (null == parentId || ComplexReferenceParentType.Unknown == parentType) { return; } if (null == childId) { throw new ArgumentNullException("childId"); } Row WixGroupRow = this.CreateRow(sourceLineNumbers, "WixGroup"); WixGroupRow[0] = parentId; WixGroupRow[1] = Enum.GetName(typeof(ComplexReferenceParentType), parentType); WixGroupRow[2] = childId; WixGroupRow[3] = Enum.GetName(typeof(ComplexReferenceChildType), childType); } }
/// <summary> /// Creates WixComplexReference and WixGroup rows in the active section. /// </summary> /// <param name="sourceLineNumbers">Source line information.</param> /// <param name="parentType">The parent type.</param> /// <param name="parentId">The parent id.</param> /// <param name="parentLanguage">The parent language.</param> /// <param name="childType">The child type.</param> /// <param name="childId">The child id.</param> /// <param name="isPrimary">Whether the child is primary.</param> public void CreateComplexReference(SourceLineNumberCollection sourceLineNumbers, ComplexReferenceParentType parentType, string parentId, string parentLanguage, ComplexReferenceChildType childType, string childId, bool isPrimary) { this.CreateWixComplexReferenceRow(sourceLineNumbers, parentType, parentId, parentLanguage, childType, childId, isPrimary); this.CreateWixGroupRow(sourceLineNumbers, parentType, parentId, childType, childId); }
/// <summary> /// Creates a WiX complex reference in the active section. /// </summary> /// <param name="sourceLineNumbers">Source line information.</param> /// <param name="parentType">The parent type.</param> /// <param name="parentId">The parent id.</param> /// <param name="parentLanguage">The parent language.</param> /// <param name="childType">The child type.</param> /// <param name="childId">The child id.</param> /// <param name="isPrimary">Whether the child is primary.</param> internal void CreateWixComplexReferenceRow(SourceLineNumberCollection sourceLineNumbers, ComplexReferenceParentType parentType, string parentId, string parentLanguage, ComplexReferenceChildType childType, string childId, bool isPrimary) { if (!this.EncounteredError) { WixComplexReferenceRow wixComplexReferenceRow = (WixComplexReferenceRow)this.CreateRow(sourceLineNumbers, "WixComplexReference"); wixComplexReferenceRow.ParentId = parentId; wixComplexReferenceRow.ParentType = parentType; wixComplexReferenceRow.ParentLanguage = parentLanguage; wixComplexReferenceRow.ChildId = childId; wixComplexReferenceRow.ChildType = childType; wixComplexReferenceRow.IsPrimary = isPrimary; } }
/// <summary> /// Parses one of the ChainPackage elements /// </summary> /// <param name="node">Element to parse</param> /// <param name="packageType">Type of package to parse</param> /// <param name="parentType">Type of parent group, if known.</param> /// <param name="parentId">Identifier of parent group, if known.</param> /// <param name="previousType">Type of previous item, if known.</param> /// <param name="previousId">Identifier of previous item, if known</param> /// <returns>Identifier for package element.</returns> /// <remarks>This method contains the shared logic for parsing all of the ChainPackage /// types, as there is more in common between them than different.</remarks> private string ParseChainPackage(XmlNode node, ChainPackageType packageType, ComplexReferenceParentType parentType, string parentId, ComplexReferenceChildType previousType, string previousId) { Debug.Assert(ComplexReferenceParentType.PackageGroup == parentType); Debug.Assert(ComplexReferenceChildType.Unknown == previousType || ComplexReferenceChildType.PackageGroup == previousType || ComplexReferenceChildType.Package == previousType); SourceLineNumberCollection sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); string name = null; string sourceFile = null; string downloadUrl = null; string id = null; string after = null; string installCondition = null; YesNoType cache = YesNoType.NotSet; string cacheId = null; string description = null; string displayName = null; string logPathVariable = (packageType == ChainPackageType.Msu) ? String.Empty : null; string rollbackPathVariable = (packageType == ChainPackageType.Msu) ? String.Empty : null; YesNoType permanent = YesNoType.NotSet; YesNoType visible = YesNoType.NotSet; YesNoType vital = YesNoType.Yes; string installCommand = null; string repairCommand = null; YesNoType repairable = YesNoType.NotSet; string uninstallCommand = null; YesNoDefaultType perMachine = YesNoDefaultType.NotSet; string detectCondition = null; string protocol = null; int installSize = CompilerCore.IntegerNotSet; string msuKB = null; YesNoType suppressLooseFilePayloadGeneration = YesNoType.NotSet; YesNoType suppressSignatureVerification = YesNoType.NotSet; YesNoDefaultType compressed = YesNoDefaultType.Default; YesNoType displayInternalUI = YesNoType.NotSet; YesNoType enableFeatureSelection = YesNoType.NotSet; YesNoType forcePerMachine = YesNoType.NotSet; BundlePackageAttributes attributes = BundlePackageAttributes.None; PayloadInfoRow remotePayload = null; YesNoType slipstream = YesNoType.NotSet; string[] expectedNetFx4Args = new string[] { "/q", "/norestart", "/chainingpackage" }; // This crazy list lets us evaluate extension attributes *after* all core attributes // have been parsed and dealt with, regardless of authoring order. List<KeyValuePair<SourceLineNumberCollection, XmlAttribute>> extensionAttributes = new List<KeyValuePair<SourceLineNumberCollection, XmlAttribute>>(); foreach (XmlAttribute attrib in node.Attributes) { if (0 == attrib.NamespaceURI.Length || attrib.NamespaceURI == this.schema.TargetNamespace) { bool allowed = true; switch (attrib.LocalName) { case "Name": name = this.core.GetAttributeLongFilename(sourceLineNumbers, attrib, false, true); if (!CompilerCore.IsValidLongFilename(name, false, true)) { this.core.OnMessage(WixErrors.IllegalLongFilename(sourceLineNumbers, node.Name, "Name", name)); } break; case "SourceFile": sourceFile = this.core.GetAttributeValue(sourceLineNumbers, attrib); break; case "DownloadUrl": downloadUrl = this.core.GetAttributeValue(sourceLineNumbers, attrib); break; case "Id": id = this.core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); break; case "After": after = this.core.GetAttributeValue(sourceLineNumbers, attrib); break; case "InstallCondition": installCondition = this.core.GetAttributeValue(sourceLineNumbers, attrib); break; case "Cache": cache = this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); break; case "CacheId": cacheId = this.core.GetAttributeValue(sourceLineNumbers, attrib); break; case "Description": description = this.core.GetAttributeValue(sourceLineNumbers, attrib); break; case "DisplayName": displayName = this.core.GetAttributeValue(sourceLineNumbers, attrib); break; case "DisplayInternalUI": displayInternalUI = this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); allowed = (packageType == ChainPackageType.Msi || packageType == ChainPackageType.Msp); break; case "EnableFeatureSelection": enableFeatureSelection = this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); allowed = (packageType == ChainPackageType.Msi); break; case "ForcePerMachine": forcePerMachine = this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); allowed = (packageType == ChainPackageType.Msi); break; case "LogPathVariable": logPathVariable = this.core.GetAttributeValue(sourceLineNumbers, attrib, true); break; case "RollbackLogPathVariable": rollbackPathVariable = this.core.GetAttributeValue(sourceLineNumbers, attrib, true); break; case "Permanent": permanent = this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); break; case "Visible": visible = this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); allowed = (packageType == ChainPackageType.Msi); break; case "Vital": vital = this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); break; case "InstallCommand": installCommand = this.core.GetAttributeValue(sourceLineNumbers, attrib); allowed = (packageType == ChainPackageType.Exe); break; case "RepairCommand": repairCommand = this.core.GetAttributeValue(sourceLineNumbers, attrib, true); repairable = YesNoType.Yes; allowed = (packageType == ChainPackageType.Exe); break; case "UninstallCommand": uninstallCommand = this.core.GetAttributeValue(sourceLineNumbers, attrib); allowed = (packageType == ChainPackageType.Exe); break; case "PerMachine": perMachine = this.core.GetAttributeYesNoDefaultValue(sourceLineNumbers, attrib); allowed = (packageType == ChainPackageType.Exe || packageType == ChainPackageType.Msp); break; case "DetectCondition": detectCondition = this.core.GetAttributeValue(sourceLineNumbers, attrib); allowed = (packageType == ChainPackageType.Exe || packageType == ChainPackageType.Msu); break; case "Protocol": protocol = this.core.GetAttributeValue(sourceLineNumbers, attrib); allowed = (packageType == ChainPackageType.Exe); break; case "InstallSize": installSize = this.core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, int.MaxValue); break; case "KB": msuKB = this.core.GetAttributeValue(sourceLineNumbers, attrib); allowed = (packageType == ChainPackageType.Msu); break; case "Compressed": compressed = this.core.GetAttributeYesNoDefaultValue(sourceLineNumbers, attrib); break; case "SuppressLooseFilePayloadGeneration": this.core.OnMessage(WixWarnings.DeprecatedAttribute(sourceLineNumbers, node.Name, attrib.Name)); suppressLooseFilePayloadGeneration = this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); allowed = (packageType == ChainPackageType.Msi); break; case "SuppressSignatureVerification": suppressSignatureVerification = this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); break; case "Slipstream": slipstream = this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); allowed = (packageType == ChainPackageType.Msp); break; default: allowed = false; break; } if (!allowed) { this.core.UnexpectedAttribute(sourceLineNumbers, attrib); } } else { // Save the extension attributes for later... extensionAttributes.Add(new KeyValuePair<SourceLineNumberCollection, XmlAttribute>(sourceLineNumbers, attrib)); } } foreach (XmlNode child in node.ChildNodes) { // 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. if ((XmlNodeType.Element == child.NodeType) && (child.NamespaceURI == this.schema.TargetNamespace) && (child.LocalName == "RemotePayload")) { SourceLineNumberCollection childSourceLineNumbers = Preprocessor.GetSourceLineNumbers(child); if (node.NamespaceURI == this.schema.TargetNamespace && node.LocalName != "ExePackage") { this.core.OnMessage(WixErrors.RemotePayloadUnsupported(childSourceLineNumbers)); continue; } if (null != remotePayload) { this.core.OnMessage(WixErrors.TooManyChildren(childSourceLineNumbers, node.Name, child.LocalName)); } remotePayload = this.ParseRemotePayloadElement(child, id); } } if (String.IsNullOrEmpty(sourceFile)) { if (String.IsNullOrEmpty(name)) { this.core.OnMessage(WixErrors.ExpectedAttributesWithOtherAttribute(sourceLineNumbers, node.Name, "Name", "SourceFile")); } else if (null == remotePayload) { sourceFile = Path.Combine("SourceDir", name); } else { sourceFile = String.Empty; // SourceFile is required it cannot be null. } } else if (null != remotePayload) { this.core.OnMessage(WixErrors.UnexpectedElementWithAttribute(sourceLineNumbers, node.Name, "RemotePayload", "SourceFile")); } else if (sourceFile.EndsWith(Path.DirectorySeparatorChar.ToString(), StringComparison.Ordinal)) { if (String.IsNullOrEmpty(name)) { this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name, "Name", "SourceFile", sourceFile)); } else { sourceFile = Path.Combine(sourceFile, Path.GetFileName(name)); } } if (null == downloadUrl && null != remotePayload) { this.core.OnMessage(WixErrors.ExpectedAttributeWithElement(sourceLineNumbers, node.Name, "DownloadUrl", "RemotePayload")); } if (String.IsNullOrEmpty(id)) { if (!String.IsNullOrEmpty(name)) { id = CompilerCore.GetIdentifierFromName(Path.GetFileName(name)); } else if (!String.IsNullOrEmpty(sourceFile)) { id = CompilerCore.GetIdentifierFromName(Path.GetFileName(sourceFile)); } if (null == id) { this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name, "Id")); } else if (!CompilerCore.IsIdentifier(id)) { this.core.OnMessage(WixErrors.IllegalIdentifier(sourceLineNumbers, node.Name, "Id", id)); } } if (null != remotePayload) { remotePayload.Id = id; } if (null == logPathVariable) { logPathVariable = String.Concat("WixBundleLog_", id); } if (null == rollbackPathVariable) { rollbackPathVariable = String.Concat("WixBundleRollbackLog_", id); } if (!String.IsNullOrEmpty(protocol) && !protocol.Equals("burn", StringComparison.Ordinal) && !protocol.Equals("netfx4", StringComparison.Ordinal) && !protocol.Equals("none", StringComparison.Ordinal)) { this.core.OnMessage(WixErrors.IllegalAttributeValueWithLegalList(sourceLineNumbers, node.Name, "Protocol", protocol, "none, burn, netfx4")); } if (!String.IsNullOrEmpty(protocol) && protocol.Equals("netfx4", StringComparison.Ordinal)) { foreach (string expectedArgument in expectedNetFx4Args) { if (null == installCommand || -1 == installCommand.IndexOf(expectedArgument, StringComparison.OrdinalIgnoreCase)) { this.core.OnMessage(WixWarnings.AttributeShouldContain(sourceLineNumbers, node.Name, "InstallCommand", installCommand, expectedArgument, "Protocol", "netfx4")); } if (null == repairCommand || -1 == repairCommand.IndexOf(expectedArgument, StringComparison.OrdinalIgnoreCase)) { this.core.OnMessage(WixWarnings.AttributeShouldContain(sourceLineNumbers, node.Name, "RepairCommand", repairCommand, expectedArgument, "Protocol", "netfx4")); } if (null == uninstallCommand || -1 == uninstallCommand.IndexOf(expectedArgument, StringComparison.OrdinalIgnoreCase)) { this.core.OnMessage(WixWarnings.AttributeShouldContain(sourceLineNumbers, node.Name, "UninstallCommand", uninstallCommand, expectedArgument, "Protocol", "netfx4")); } } } // Only set default scope for EXEs and MSPs if not already set. if ((ChainPackageType.Exe == packageType || ChainPackageType.Msp == packageType) && YesNoDefaultType.NotSet == perMachine) { perMachine = YesNoDefaultType.Default; } // Now that the package ID is known, we can parse the extension attributes... Dictionary<string, string> contextValues = new Dictionary<string, string>(); contextValues["PackageId"] = id; foreach (KeyValuePair<SourceLineNumberCollection, XmlAttribute> pair in extensionAttributes) { this.core.ParseExtensionAttribute(pair.Key, (XmlElement)node, pair.Value, contextValues); } foreach (XmlNode child in node.ChildNodes) { if (XmlNodeType.Element == child.NodeType) { if (child.NamespaceURI == this.schema.TargetNamespace) { bool allowed = true; switch (child.LocalName) { case "SlipstreamMsp": allowed = (packageType == ChainPackageType.Msi); if (allowed) { this.ParseSlipstreamMspElement(child, id); } break; case "MsiProperty": allowed = (packageType == ChainPackageType.Msi || packageType == ChainPackageType.Msp); if (allowed) { this.ParseMsiPropertyElement(child, id); } break; case "Payload": this.ParsePayloadElement(child, ComplexReferenceParentType.Package, id, ComplexReferenceChildType.Unknown, null); break; case "PayloadGroupRef": this.ParsePayloadGroupRefElement(child, ComplexReferenceParentType.Package, id, ComplexReferenceChildType.Unknown, null); break; case "ExitCode": allowed = (packageType == ChainPackageType.Exe); if (allowed) { this.ParseExitCodeElement(child, id); } break; case "RemotePayload": // Handled previously break; default: allowed = false; break; } if (!allowed) { this.core.UnexpectedElement(node, child); } } else { this.core.ParseExtensionElement(sourceLineNumbers, (XmlElement)node, (XmlElement)child, id); } } } if (!this.core.EncounteredError) { if (YesNoType.Yes == permanent) { attributes |= BundlePackageAttributes.Permanent; } if (YesNoType.Yes == visible) { attributes |= BundlePackageAttributes.Visible; } if (YesNoType.Yes == slipstream) { attributes |= BundlePackageAttributes.Slipstream; } // We create the package contents as a payload with this package as the parent this.CreatePayloadRow(sourceLineNumbers, id, name, sourceFile, downloadUrl, ComplexReferenceParentType.Package, id, ComplexReferenceChildType.Unknown, null, compressed, suppressSignatureVerification, displayName, description); Row row = this.core.CreateRow(sourceLineNumbers, "ChainPackage"); row[0] = id; row[1] = packageType.ToString(); row[2] = id; row[3] = installCondition; row[4] = installCommand; row[5] = repairCommand; row[6] = uninstallCommand; if (YesNoType.NotSet != cache) { row[7] = (YesNoType.Yes == cache) ? 1 : 0; } row[8] = cacheId; row[9] = (int)attributes; if (YesNoType.NotSet != vital) { row[10] = (YesNoType.Yes == vital) ? 1 : 0; } switch (perMachine) { case YesNoDefaultType.No: row[11] = 0; break; case YesNoDefaultType.Yes: row[11] = 1; break; case YesNoDefaultType.Default: row[11] = 2; break; } row[12] = detectCondition; row[13] = msuKB; if (YesNoType.NotSet != repairable) { row[14] = (YesNoType.Yes == repairable) ? 1 : 0; } row[15] = logPathVariable; row[16] = rollbackPathVariable; row[17] = protocol; row[18] = installSize; if (YesNoType.NotSet != suppressLooseFilePayloadGeneration) { row[19] = (YesNoType.Yes == suppressLooseFilePayloadGeneration) ? 1 : 0; } if (YesNoType.NotSet != enableFeatureSelection) { row[20] = (YesNoType.Yes == enableFeatureSelection) ? 1 : 0; } if (YesNoType.NotSet != forcePerMachine) { row[21] = (YesNoType.Yes == forcePerMachine) ? 1 : 0; } if (YesNoType.NotSet != displayInternalUI) { row[22] = (YesNoType.Yes == displayInternalUI) ? 1 : 0; } this.CreateChainPackageMetaRows(sourceLineNumbers, parentType, parentId, ComplexReferenceChildType.Package, id, previousType, previousId, after); } return id; }
/// <summary> /// Parse a complex reference from the xml. /// </summary> /// <param name="intermediate">Intermediate to populate with persisted data.</param> /// <param name="reader">XmlReader where the intermediate is persisted.</param> /// <param name="section">Section to populate with persisted data.</param> private static void ParseComplexReference(Intermediate intermediate, XmlReader reader, Section section) { bool empty = reader.IsEmptyElement; ComplexReferenceParentType parentType = ComplexReferenceParentType.Unknown; string parentId = null; string parentLanguage = null; ComplexReferenceChildType childType = ComplexReferenceChildType.Unknown; string childId = null; bool primary = false; while (reader.MoveToNextAttribute()) { switch (reader.LocalName) { case "parent": parentId = reader.Value; break; case "parentLanguage": parentLanguage = reader.Value; break; case "parentType": switch (reader.Value) { case "componentGroup": parentType = ComplexReferenceParentType.ComponentGroup; break; case "feature": parentType = ComplexReferenceParentType.Feature; break; case "module": parentType = ComplexReferenceParentType.Module; break; } break; case "child": childId = reader.Value; break; case "childType": switch (reader.Value) { case "component": childType = ComplexReferenceChildType.Component; break; case "componentGroup": childType = ComplexReferenceChildType.ComponentGroup; break; case "feature": childType = ComplexReferenceChildType.Feature; break; case "fragment": childType = ComplexReferenceChildType.Fragment; break; case "module": childType = ComplexReferenceChildType.Module; break; } break; case "primary": primary = Common.IsYes(reader.Value, SourceLineNumberCollection.FromFileName(intermediate.Path), "complexReference", "primary", parentId); break; } } if (ComplexReferenceParentType.Unknown == parentType) { throw new WixInvalidIntermediateException(SourceLineNumberCollection.FromFileName(intermediate.Path), "Unknown ComplexReferenceParentType type"); } if (null == parentId) { throw new WixInvalidIntermediateException(SourceLineNumberCollection.FromFileName(intermediate.Path), "ComplexReference missing required attribute: 'parentId'"); } if (ComplexReferenceChildType.Unknown == childType) { throw new WixInvalidIntermediateException(SourceLineNumberCollection.FromFileName(intermediate.Path), "Unknown ComplexReferenceChildType type"); } if (null == childId) { throw new WixInvalidIntermediateException(SourceLineNumberCollection.FromFileName(intermediate.Path), "ComplexReference missing required attribute: 'childId'"); } if (!empty && reader.Read() && XmlNodeType.EndElement != reader.MoveToContent()) { throw new WixInvalidIntermediateException(SourceLineNumberCollection.FromFileName(intermediate.Path), String.Format("Unexpected content while processing 'complexReference': {0}", reader.NodeType.ToString())); } section.ComplexReferences.Add(new ComplexReference(parentType, parentId, parentLanguage, childType, childId, primary)); }
/// <summary> /// Creates group and ordering information for packages /// </summary> /// <param name="sourceLineNumbers">Source line numbers.</param> /// <param name="parentType">Type of parent group, if known.</param> /// <param name="parentId">Identifier of parent group, if known.</param> /// <param name="type">Type of this item.</param> /// <param name="id">Identifier for this item.</param> /// <param name="previousType">Type of previous item, if known.</param> /// <param name="previousId">Identifier of previous item, if known</param> /// <param name="afterId">Identifier of explicit 'After' attribute, if given.</param> private void CreateChainPackageMetaRows(SourceLineNumberCollection sourceLineNumbers, ComplexReferenceParentType parentType, string parentId, ComplexReferenceChildType type, string id, ComplexReferenceChildType previousType, string previousId, string afterId) { // If there's an explicit 'After' attribute, it overrides the inferred previous item. if (null != afterId) { previousType = ComplexReferenceChildType.Package; previousId = afterId; } this.CreateGroupAndOrderingRows(sourceLineNumbers, parentType, parentId, type, id, previousType, previousId); }
public void CreateWixGroupSymbol(IntermediateSection section, SourceLineNumber sourceLineNumbers, ComplexReferenceParentType parentType, string parentId, ComplexReferenceChildType childType, string childId) { if (null == parentId || ComplexReferenceParentType.Unknown == parentType) { return; } if (null == childId) { throw new ArgumentNullException(nameof(childId)); } section.AddSymbol(new WixGroupSymbol(sourceLineNumbers) { ParentId = parentId, ParentType = parentType, ChildId = childId, ChildType = childType, }); }
public void CreateComplexReference(IntermediateSection section, SourceLineNumber sourceLineNumbers, ComplexReferenceParentType parentType, string parentId, string parentLanguage, ComplexReferenceChildType childType, string childId, bool isPrimary) { section.AddSymbol(new WixComplexReferenceSymbol(sourceLineNumbers) { Parent = parentId, ParentType = parentType, ParentLanguage = parentLanguage, Child = childId, ChildType = childType, IsPrimary = isPrimary }); this.CreateWixGroupSymbol(section, sourceLineNumbers, parentType, parentId, childType, childId); }
public void CreateWixGroupRow(IntermediateSection section, SourceLineNumber sourceLineNumbers, ComplexReferenceParentType parentType, string parentId, ComplexReferenceChildType childType, string childId) { this.CreateWixGroupSymbol(section, sourceLineNumbers, parentType, parentId, childType, childId); }