//-------------------------------------------------------------------------------------------------
//
// Copyright (c) 2004, Outercurve Foundation.
// This software is released under Microsoft Reciprocal License (MS-RL).
// The license and further copyright text can be found in the file
// LICENSE.TXT at the root directory of the distribution.
//
//
//
// The compiler for the Windows Installer XML Toolset Bal Extension.
//
//-------------------------------------------------------------------------------------------------
namespace Microsoft.Tools.WindowsInstallerXml.Extensions
{
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Xml;
using System.Xml.Schema;
using Microsoft.Tools.WindowsInstallerXml;
///
/// The compiler for the Windows Installer XML Toolset Bal Extension.
///
public sealed class BalCompiler : CompilerExtension
{
private SourceLineNumberCollection addedConditionLineNumber;
private XmlSchema schema;
///
/// Instantiate a new BalCompiler.
///
public BalCompiler()
{
this.addedConditionLineNumber = null;
this.schema = LoadXmlSchemaHelper(Assembly.GetExecutingAssembly(), "Microsoft.Tools.WindowsInstallerXml.Extensions.Xsd.bal.xsd");
}
///
/// Gets the schema for this extension.
///
/// Schema for this extension.
public override XmlSchema Schema
{
get { return this.schema; }
}
///
/// Processes an element for the Compiler.
///
/// Source line number for the parent element.
/// Parent element of element to process.
/// Element to process.
/// Extra information about the context in which this element is being parsed.
public override void ParseElement(SourceLineNumberCollection sourceLineNumbers, XmlElement parentElement, XmlElement element, params string[] contextValues)
{
switch (parentElement.LocalName)
{
case "Bundle":
case "Fragment":
switch (element.LocalName)
{
case "Condition":
this.ParseConditionElement(element);
break;
default:
this.Core.UnexpectedElement(parentElement, element);
break;
}
break;
case "BootstrapperApplicationRef":
switch (element.LocalName)
{
case "WixExtendedBootstrapperApplication":
this.ParseWixExtendedBootstrapperApplicationElement(element);
break;
default:
this.Core.UnexpectedElement(parentElement, element);
break;
}
break;
default:
this.Core.UnexpectedElement(parentElement, element);
break;
}
}
///
/// Processes an attribute for the Compiler.
///
/// Source line number for the parent element.
/// Parent element of element to process.
/// Attribute to process.
/// Extra information about the context in which this element is being parsed.
public override void ParseAttribute(SourceLineNumberCollection sourceLineNumbers, XmlElement parentElement, XmlAttribute attribute, Dictionary contextValues)
{
switch (parentElement.LocalName)
{
case "Variable":
// at the time the extension attribute is parsed, the compiler might not yet have
// parsed the Name attribute, so we need to get it directly from the parent element.
string variableName = parentElement.GetAttribute("Name");
if (String.IsNullOrEmpty(variableName))
{
this.Core.OnMessage(WixErrors.ExpectedParentWithAttribute(sourceLineNumbers, "Variable", "Overridable", "Name"));
}
else
{
switch (attribute.LocalName)
{
case "Overridable":
if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attribute))
{
Row row = this.Core.CreateRow(sourceLineNumbers, "WixStdbaOverridableVariable");
row[0] = variableName;
}
break;
default:
this.Core.UnexpectedAttribute(sourceLineNumbers, attribute);
break;
}
}
break;
default:
this.Core.UnexpectedAttribute(sourceLineNumbers, attribute);
break;
}
}
///
/// Parses a Condition element for Bundles.
///
/// The element to parse.
private void ParseConditionElement(XmlNode node)
{
SourceLineNumberCollection sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node);
string condition = CompilerCore.GetConditionInnerText(node); // condition is the inner text of the element.
string message = null;
foreach (XmlAttribute attrib in node.Attributes)
{
if (0 == attrib.NamespaceURI.Length || attrib.NamespaceURI == this.schema.TargetNamespace)
{
switch (attrib.LocalName)
{
case "Message":
message = this.Core.GetAttributeValue(sourceLineNumbers, attrib, false);
break;
default:
this.Core.UnexpectedAttribute(sourceLineNumbers, attrib);
break;
}
}
else
{
this.Core.UnsupportedExtensionAttribute(sourceLineNumbers, attrib);
}
}
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);
}
}
}
// Error check the values.
if (String.IsNullOrEmpty(condition))
{
this.Core.OnMessage(WixErrors.ConditionExpected(sourceLineNumbers, node.Name));
}
if (null == message)
{
this.Core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name, "Message"));
}
if (!this.Core.EncounteredError)
{
Row row = this.Core.CreateRow(sourceLineNumbers, "WixBalCondition");
row[0] = condition;
row[1] = message;
if (null == this.addedConditionLineNumber)
{
this.addedConditionLineNumber = sourceLineNumbers;
}
}
}
///
/// Parses a WixExtendedBootstrapperApplication element for Bundles.
///
/// The element to parse.
private void ParseWixExtendedBootstrapperApplicationElement(XmlNode node)
{
SourceLineNumberCollection sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node);
string launchTarget = null;
string licenseFile = null;
string licenseUrl = null;
string logoFile = null;
string logoSideFile = null;
string themeFile = null;
string localizationFile = null;
YesNoType suppressOptionsUI = YesNoType.NotSet;
YesNoType suppressDowngradeFailure = YesNoType.NotSet;
YesNoType suppressRepair = YesNoType.NotSet;
YesNoType showVersion = YesNoType.NotSet;
YesNoType launchPassive = YesNoType.NotSet;
YesNoType launchQuiet = YesNoType.NotSet;
foreach (XmlAttribute attrib in node.Attributes)
{
if (0 == attrib.NamespaceURI.Length || attrib.NamespaceURI == this.schema.TargetNamespace)
{
switch (attrib.LocalName)
{
case "LaunchTarget":
launchTarget = this.Core.GetAttributeValue(sourceLineNumbers, attrib, false);
break;
case "LicenseFile":
licenseFile = this.Core.GetAttributeValue(sourceLineNumbers, attrib, false);
break;
case "LicenseUrl":
licenseUrl = this.Core.GetAttributeValue(sourceLineNumbers, attrib, true);
break;
case "LogoFile":
logoFile = this.Core.GetAttributeValue(sourceLineNumbers, attrib, false);
break;
case "LogoSideFile":
logoSideFile = this.Core.GetAttributeValue(sourceLineNumbers, attrib, false);
break;
case "ThemeFile":
themeFile = this.Core.GetAttributeValue(sourceLineNumbers, attrib, false);
break;
case "LocalizationFile":
localizationFile = this.Core.GetAttributeValue(sourceLineNumbers, attrib, false);
break;
case "SuppressOptionsUI":
suppressOptionsUI = this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib);
break;
case "LaunchPassive":
launchPassive = this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib);
break;
case "LaunchQuiet":
launchQuiet = this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib);
break;
case "SuppressDowngradeFailure":
suppressDowngradeFailure = this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib);
break;
case "SuppressRepair":
suppressRepair = this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib);
break;
case "ShowVersion":
showVersion = this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib);
break;
default:
this.Core.UnexpectedAttribute(sourceLineNumbers, attrib);
break;
}
}
else
{
this.Core.UnsupportedExtensionAttribute(sourceLineNumbers, attrib);
}
}
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 (String.IsNullOrEmpty(licenseFile) && null == licenseUrl)
{
this.Core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name, "LicenseFile", "LicenseUrl", true));
}
if (!this.Core.EncounteredError)
{
if (!String.IsNullOrEmpty(launchTarget))
{
this.Core.CreateVariableRow(sourceLineNumbers, "LaunchTarget", launchTarget, "string", false, false);
}
if (!String.IsNullOrEmpty(licenseFile))
{
this.Core.CreateWixVariableRow(sourceLineNumbers, "WixExtbaLicenseRtf", licenseFile, false);
}
if (null != licenseUrl)
{
this.Core.CreateWixVariableRow(sourceLineNumbers, "WixExtbaLicenseUrl", licenseUrl, false);
}
if (!String.IsNullOrEmpty(logoFile))
{
this.Core.CreateWixVariableRow(sourceLineNumbers, "WixExtbaLogo", logoFile, false);
}
if (!String.IsNullOrEmpty(logoSideFile))
{
this.Core.CreateWixVariableRow(sourceLineNumbers, "WixExtbaLogoSide", logoSideFile, false);
}
if (!String.IsNullOrEmpty(themeFile))
{
this.Core.CreateWixVariableRow(sourceLineNumbers, "WixExtbaThemeXml", themeFile, false);
}
if (!String.IsNullOrEmpty(localizationFile))
{
this.Core.CreateWixVariableRow(sourceLineNumbers, "WixExtbaThemeWxl", localizationFile, false);
}
if (YesNoType.Yes == suppressOptionsUI || YesNoType.Yes == suppressDowngradeFailure || YesNoType.Yes == suppressRepair)
{
Row row = this.Core.CreateRow(sourceLineNumbers, "WixExtbaOptions");
if (YesNoType.Yes == suppressOptionsUI)
{
row[0] = 1;
}
if (YesNoType.Yes == suppressDowngradeFailure)
{
row[1] = 1;
}
if (YesNoType.Yes == suppressRepair)
{
row[2] = 1;
}
if (YesNoType.Yes == showVersion)
{
row[3] = 1;
}
if (YesNoType.Yes == launchPassive)
{
row[4] = 1;
}
if (YesNoType.Yes == launchQuiet)
{
row[5] = 1;
}
}
}
}
}
}