This commit is contained in:
Sean Hall 2019-01-18 18:49:46 -06:00
Родитель ba9ba99769
Коммит 0a5c0aafba
11 изменённых файлов: 1185 добавлений и 0 удалений

417
src/wixext/TagBinder.cs Normal file
Просмотреть файл

@ -0,0 +1,417 @@
// 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.
namespace WixToolset.Extensions
{
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Xml;
using WixToolset.Data;
using WixToolset.Data.Rows;
using WixToolset.Dtf.WindowsInstaller;
using WixToolset.Extensibility;
/// <summary>
/// The Binder for the WiX Toolset Software Id Tag Extension.
/// </summary>
public sealed class TagBinder : BinderExtension
{
private string overallRegid;
private RowDictionary<Row> swidRows = new RowDictionary<Row>();
/// <summary>
/// Called before database binding occurs.
/// </summary>
public override void Initialize(Output output)
{
// Only process MSI packages.
if (OutputType.Product != output.Type)
{
return;
}
this.overallRegid = null; // always reset overall regid on initialize.
// Ensure the tag files are generated to be imported by the MSI.
this.CreateProductTagFiles(output);
}
/// <summary>
/// Called after database variable resolution occurs.
/// </summary>
public override void AfterResolvedFields(Output output)
{
// Only process MSI packages.
if (OutputType.Product != output.Type)
{
return;
}
Table wixBindUpdateFilesTable = output.Tables["WixBindUpdatedFiles"];
// We'll end up re-writing the tag files but this time we may have the ProductCode
// now to use as the unique id.
List<WixFileRow> updatedFileRows = this.CreateProductTagFiles(output);
foreach (WixFileRow updateFileRow in updatedFileRows)
{
Row row = wixBindUpdateFilesTable.CreateRow(updateFileRow.SourceLineNumbers);
row[0] = updateFileRow.File;
}
}
/// <summary>
/// Called after all output changes occur and right before the output is bound into its final format.
/// </summary>
public override void Finish(Output output)
{
// Only finish bundles.
if (OutputType.Bundle != output.Type)
{
return;
}
this.overallRegid = null; // always reset overall regid on initialize.
Table tagTable = output.Tables["WixBundleTag"];
if (null != tagTable)
{
Table table = output.Tables["WixBundle"];
WixBundleRow bundleInfo = (WixBundleRow)table.Rows[0];
Version bundleVersion = TagBinder.CreateFourPartVersion(bundleInfo.Version);
// Try to collect all the software id tags from all the child packages.
IList<SoftwareTag> allTags = TagBinder.CollectPackageTags(output);
foreach (Row tagRow in tagTable.Rows)
{
string regid = (string)tagRow[1];
string name = (string)tagRow[2];
bool licensed = (null != tagRow[3] && 0 != (int)tagRow[3]);
string typeString = (string)tagRow[5];
TagType type = String.IsNullOrEmpty(typeString) ? TagType.Unknown : (TagType)Enum.Parse(typeof(TagType), typeString);
IList<SoftwareTag> containedTags = TagBinder.CalculateContainedTagsAndType(allTags, ref type);
using (MemoryStream ms = new MemoryStream())
{
TagBinder.CreateTagFile(ms, regid, bundleInfo.BundleId.ToString("D").ToUpperInvariant(), bundleInfo.Name, bundleVersion, bundleInfo.Publisher, licensed, type, containedTags);
tagRow[4] = Encoding.UTF8.GetString(ms.ToArray());
}
}
}
}
private List<WixFileRow> CreateProductTagFiles(Output output)
{
List<WixFileRow> updatedFileRows = new List<WixFileRow>();
SourceLineNumber sourceLineNumbers = null;
Table tagTable = output.Tables["WixProductTag"];
if (null != tagTable)
{
string productCode = null;
string productName = null;
Version productVersion = null;
string manufacturer = null;
Table properties = output.Tables["Property"];
foreach (Row property in properties.Rows)
{
switch ((string)property[0])
{
case "ProductCode":
productCode = (string)property[1];
break;
case "ProductName":
productName = (string)property[1];
break;
case "ProductVersion":
productVersion = TagBinder.CreateFourPartVersion((string)property[1]);
break;
case "Manufacturer":
manufacturer = (string)property[1];
break;
}
}
// If the ProductCode is available, only keep it if it is a GUID.
if (!String.IsNullOrEmpty(productCode))
{
if (productCode.Equals("*"))
{
productCode = null;
}
else
{
try
{
Guid guid = new Guid(productCode);
productCode = guid.ToString("D").ToUpperInvariant();
}
catch // not a GUID, erase it.
{
productCode = null;
}
}
}
Table wixFileTable = output.Tables["WixFile"];
foreach (Row tagRow in tagTable.Rows)
{
string fileId = (string)tagRow[0];
string regid = (string)tagRow[1];
string name = (string)tagRow[2];
bool licensed = (null != tagRow[3] && 1 == (int)tagRow[3]);
string typeString = (string)tagRow[4];
TagType type = String.IsNullOrEmpty(typeString) ? TagType.Application : (TagType)Enum.Parse(typeof(TagType), typeString);
string uniqueId = String.IsNullOrEmpty(productCode) ? name.Replace(" ", "-") : productCode;
if (String.IsNullOrEmpty(this.overallRegid))
{
this.overallRegid = regid;
sourceLineNumbers = tagRow.SourceLineNumbers;
}
else if (!this.overallRegid.Equals(regid, StringComparison.Ordinal))
{
// TODO: display error that only one regid supported.
}
// Find the WixFileRow that matches for this WixProductTag.
foreach (WixFileRow wixFileRow in wixFileTable.Rows)
{
if (fileId == wixFileRow.File)
{
// Write the tag file.
wixFileRow.Source = Path.GetTempFileName();
using (FileStream fs = new FileStream(wixFileRow.Source, FileMode.Create))
{
TagBinder.CreateTagFile(fs, regid, uniqueId, productName, productVersion, manufacturer, licensed, type, null);
}
updatedFileRows.Add(wixFileRow); // remember that we modified this file.
// Ensure the matching "SoftwareIdentificationTag" row exists and
// is populated correctly.
Row swidRow;
if (!this.swidRows.TryGetValue(fileId, out swidRow))
{
Table swid = output.Tables["SoftwareIdentificationTag"];
swidRow = swid.CreateRow(wixFileRow.SourceLineNumbers);
swidRow[0] = fileId;
swidRow[1] = this.overallRegid;
this.swidRows.Add(swidRow);
}
// Always rewrite.
swidRow[2] = uniqueId;
swidRow[3] = type.ToString();
break;
}
}
}
}
// If we remembered the source line number for the regid, then add
// a WixVariable to map to the regid.
if (null != sourceLineNumbers)
{
Table wixVariableTable = output.EnsureTable(this.Core.TableDefinitions["WixVariable"]);
WixVariableRow wixVariableRow = (WixVariableRow)wixVariableTable.CreateRow(sourceLineNumbers);
wixVariableRow.Id = "WixTagRegid";
wixVariableRow.Value = this.overallRegid;
wixVariableRow.Overridable = false;
}
return updatedFileRows;
}
private static Version CreateFourPartVersion(string versionString)
{
Version version = new Version(versionString);
return new Version(version.Major,
-1 < version.Minor ? version.Minor : 0,
-1 < version.Build ? version.Build : 0,
-1 < version.Revision ? version.Revision : 0);
}
private static IList<SoftwareTag> CollectPackageTags(Output bundle)
{
List<SoftwareTag> tags = new List<SoftwareTag>();
Table packageTable = bundle.Tables["WixBundlePackage"];
if (null != packageTable)
{
Table payloadTable = bundle.Tables["WixBundlePayload"];
RowDictionary<WixBundlePayloadRow> payloads = new RowDictionary<WixBundlePayloadRow>(payloadTable);
foreach (WixBundlePackageRow row in packageTable.RowsAs<WixBundlePackageRow>())
{
if (WixBundlePackageType.Msi == row.Type)
{
string packagePayloadId = row.PackagePayload;
WixBundlePayloadRow payload = payloads.Get(packagePayloadId);
using (Database db = new Database(payload.FullFileName))
{
if (db.Tables.Contains("SoftwareIdentificationTag"))
{
using (View view = db.OpenView("SELECT `Regid`, `UniqueId`, `Type` FROM `SoftwareIdentificationTag`"))
{
view.Execute();
while (true)
{
using (Record record = view.Fetch())
{
if (null == record)
{
break;
}
TagType type = String.IsNullOrEmpty(record.GetString(3)) ? TagType.Unknown : (TagType)Enum.Parse(typeof(TagType), record.GetString(3));
tags.Add(new SoftwareTag() { Regid = record.GetString(1), Id = record.GetString(2), Type = type });
}
}
}
}
}
}
}
}
return tags;
}
private static IList<SoftwareTag> CalculateContainedTagsAndType(IEnumerable<SoftwareTag> allTags, ref TagType type)
{
List<SoftwareTag> containedTags = new List<SoftwareTag>();
foreach (SoftwareTag tag in allTags)
{
// If this tag type is an Application or Group then try to coerce our type to a Group.
if (TagType.Application == tag.Type || TagType.Group == tag.Type)
{
// If the type is still unknown, change our tag type and clear any contained tags that might have already
// been colllected.
if (TagType.Unknown == type)
{
type = TagType.Group;
containedTags = new List<SoftwareTag>();
}
// If we are a Group then we can add this as a contained tag, otherwise skip it.
if (TagType.Group == type)
{
containedTags.Add(tag);
}
// TODO: should we warn if this bundle is typed as a non-Group software id tag but is actually
// carrying Application or Group software tags?
}
else if (TagType.Component == tag.Type || TagType.Feature == tag.Type)
{
// We collect Component and Feature tags only if the our tag is an Application or might still default to an Application.
if (TagType.Application == type || TagType.Unknown == type)
{
containedTags.Add(tag);
}
}
}
// If our type was not set by now, we'll default to an Application.
if (TagType.Unknown == type)
{
type = TagType.Application;
}
return containedTags;
}
private static void CreateTagFile(Stream stream, string regid, string uniqueId, string name, Version version, string manufacturer, bool licensed, TagType tagType, IList<SoftwareTag> containedTags)
{
using (XmlTextWriter writer = new XmlTextWriter(stream, Encoding.UTF8))
{
writer.WriteStartDocument();
writer.WriteStartElement("software_identification_tag", "http://standards.iso.org/iso/19770/-2/2009/schema.xsd");
writer.WriteElementString("entitlement_required_indicator", licensed ? "true" : "false");
writer.WriteElementString("product_title", name);
writer.WriteStartElement("product_version");
writer.WriteElementString("name", version.ToString());
writer.WriteStartElement("numeric");
writer.WriteElementString("major", version.Major.ToString());
writer.WriteElementString("minor", version.Minor.ToString());
writer.WriteElementString("build", version.Build.ToString());
writer.WriteElementString("review", version.Revision.ToString());
writer.WriteEndElement();
writer.WriteEndElement();
writer.WriteStartElement("software_creator");
writer.WriteElementString("name", manufacturer);
writer.WriteElementString("regid", regid);
writer.WriteEndElement();
if (licensed)
{
writer.WriteStartElement("software_licensor");
writer.WriteElementString("name", manufacturer);
writer.WriteElementString("regid", regid);
writer.WriteEndElement();
}
writer.WriteStartElement("software_id");
writer.WriteElementString("unique_id", uniqueId);
writer.WriteElementString("tag_creator_regid", regid);
writer.WriteEndElement();
writer.WriteStartElement("tag_creator");
writer.WriteElementString("name", manufacturer);
writer.WriteElementString("regid", regid);
writer.WriteEndElement();
if (null != containedTags && 0 < containedTags.Count)
{
writer.WriteStartElement("complex_of");
foreach (SoftwareTag tag in containedTags)
{
writer.WriteStartElement("software_id");
writer.WriteElementString("unique_id", tag.Id);
writer.WriteElementString("tag_creator_regid", tag.Regid);
writer.WriteEndElement(); // </software_id>
}
writer.WriteEndElement(); // </complex_of>
}
if (TagType.Unknown != tagType)
{
writer.WriteStartElement("extended_information");
writer.WriteStartElement("tag_type", "http://www.tagvault.org/tv_extensions.xsd");
writer.WriteValue(tagType.ToString());
writer.WriteEndElement(); // </tag_type>
writer.WriteEndElement(); // </extended_information>
}
writer.WriteEndElement(); // </software_identification_tag>
}
}
private enum TagType
{
Unknown,
Application,
Component,
Feature,
Group,
Patch,
}
private class SoftwareTag
{
public string Regid { get; set; }
public string Id { get; set; }
public TagType Type { get; set; }
}
}
}

344
src/wixext/TagCompiler.cs Normal file
Просмотреть файл

@ -0,0 +1,344 @@
// 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.
namespace WixToolset.Extensions
{
using System;
using System.Collections.Generic;
using System.Xml.Linq;
using WixToolset.Data;
using WixToolset.Data.Rows;
using WixToolset.Extensibility;
/// <summary>
/// The compiler for the WiX Toolset Software Id Tag Extension.
/// </summary>
public sealed class TagCompiler : CompilerExtension
{
/// <summary>
/// Instantiate a new GamingCompiler.
/// </summary>
public TagCompiler()
{
this.Namespace = "http://wixtoolset.org/schemas/v4/wxs/tag";
}
/// <summary>
/// Processes an element for the Compiler.
/// </summary>
/// <param name="sourceLineNumbers">Source line number for the parent element.</param>
/// <param name="parentElement">Parent element of element to process.</param>
/// <param name="element">Element to process.</param>
/// <param name="contextValues">Extra information about the context in which this element is being parsed.</param>
public override void ParseElement(XElement parentElement, XElement element, IDictionary<string, string> context)
{
switch (parentElement.Name.LocalName)
{
case "Bundle":
switch (element.Name.LocalName)
{
case "Tag":
this.ParseBundleTagElement(element);
break;
default:
this.Core.UnexpectedElement(parentElement, element);
break;
}
break;
case "Product":
switch (element.Name.LocalName)
{
case "Tag":
this.ParseProductTagElement(element);
break;
default:
this.Core.UnexpectedElement(parentElement, element);
break;
}
break;
case "PatchFamily":
switch (element.Name.LocalName)
{
case "TagRef":
this.ParseTagRefElement(element);
break;
default:
this.Core.UnexpectedElement(parentElement, element);
break;
}
break;
default:
this.Core.UnexpectedElement(parentElement, element);
break;
}
}
/// <summary>
/// Parses a Tag element for Software Id Tag registration under a Bundle element.
/// </summary>
/// <param name="node">The element to parse.</param>
private void ParseBundleTagElement(XElement node)
{
SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node);
string name = null;
string regid = null;
YesNoType licensed = YesNoType.NotSet;
string type = null;
foreach (XAttribute attrib in node.Attributes())
{
if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
{
switch (attrib.Name.LocalName)
{
case "Name":
name = this.Core.GetAttributeLongFilename(sourceLineNumbers, attrib, false);
break;
case "Regid":
regid = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
break;
case "Licensed":
licensed = this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib);
break;
case "Type":
type = this.ParseTagTypeAttribute(sourceLineNumbers, node, attrib);
break;
default:
this.Core.UnexpectedAttribute(node, attrib);
break;
}
}
else
{
this.Core.ParseExtensionAttribute(node, attrib);
}
}
this.Core.ParseForExtensionElements(node);
if (String.IsNullOrEmpty(name))
{
XAttribute productNameAttribute = node.Parent.Attribute("Name");
if (null != productNameAttribute)
{
name = productNameAttribute.Value;
}
else
{
this.Core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Name"));
}
}
if (!String.IsNullOrEmpty(name) && !this.Core.IsValidLongFilename(name, false))
{
this.Core.OnMessage(TagErrors.IllegalName(sourceLineNumbers, node.Parent.Name.LocalName, name));
}
if (String.IsNullOrEmpty(regid))
{
this.Core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Regid"));
}
if (!this.Core.EncounteredError)
{
string fileName = String.Concat(regid, " ", name, ".swidtag");
Row tagRow = this.Core.CreateRow(sourceLineNumbers, "WixBundleTag");
tagRow[0] = fileName;
tagRow[1] = regid;
tagRow[2] = name;
if (YesNoType.Yes == licensed)
{
tagRow[3] = 1;
}
// field 4 is the TagXml set by the binder.
tagRow[5] = type;
}
}
/// <summary>
/// Parses a Tag element for Software Id Tag registration under a Product element.
/// </summary>
/// <param name="node">The element to parse.</param>
private void ParseProductTagElement(XElement node)
{
SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node);
string name = null;
string regid = null;
string feature = "WixSwidTag";
YesNoType licensed = YesNoType.NotSet;
string type = null;
foreach (XAttribute attrib in node.Attributes())
{
if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
{
switch (attrib.Name.LocalName)
{
case "Name":
name = this.Core.GetAttributeLongFilename(sourceLineNumbers, attrib, false);
break;
case "Regid":
regid = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
break;
case "Feature":
feature = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
break;
case "Licensed":
licensed = this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib);
break;
case "Type":
type = this.ParseTagTypeAttribute(sourceLineNumbers, node, attrib);
break;
default:
this.Core.UnexpectedAttribute(node, attrib);
break;
}
}
else
{
this.Core.ParseExtensionAttribute(node, attrib);
}
}
this.Core.ParseForExtensionElements(node);
if (String.IsNullOrEmpty(name))
{
XAttribute productNameAttribute = node.Parent.Attribute("Name");
if (null != productNameAttribute)
{
name = productNameAttribute.Value;
}
else
{
this.Core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Name"));
}
}
if (!String.IsNullOrEmpty(name) && !this.Core.IsValidLongFilename(name, false))
{
this.Core.OnMessage(TagErrors.IllegalName(sourceLineNumbers, node.Parent.Name.LocalName, name));
}
if (String.IsNullOrEmpty(regid))
{
this.Core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Regid"));
}
if (!this.Core.EncounteredError)
{
string directoryId = "WixTagRegidFolder";
Identifier fileId = this.Core.CreateIdentifier("tag", regid, ".product.tag");
string fileName = String.Concat(regid, " ", name, ".swidtag");
string shortName = this.Core.CreateShortName(fileName, false, false);
this.Core.CreateSimpleReference(sourceLineNumbers, "Directory", directoryId);
ComponentRow componentRow = (ComponentRow)this.Core.CreateRow(sourceLineNumbers, "Component", fileId);
componentRow.Guid = "*";
componentRow[3] = 0;
componentRow.Directory = directoryId;
componentRow.IsLocalOnly = true;
componentRow.KeyPath = fileId.Id;
this.Core.CreateSimpleReference(sourceLineNumbers, "Feature", feature);
this.Core.CreateComplexReference(sourceLineNumbers, ComplexReferenceParentType.Feature, feature, null, ComplexReferenceChildType.Component, fileId.Id, true);
FileRow fileRow = (FileRow)this.Core.CreateRow(sourceLineNumbers, "File", fileId);
fileRow.Component = fileId.Id;
fileRow.FileName = String.Concat(shortName, "|", fileName);
WixFileRow wixFileRow = (WixFileRow)this.Core.CreateRow(sourceLineNumbers, "WixFile");
wixFileRow.Directory = directoryId;
wixFileRow.File = fileId.Id;
wixFileRow.DiskId = 1;
wixFileRow.Attributes = 1;
wixFileRow.Source = String.Concat("%TEMP%\\", fileName);
this.Core.EnsureTable(sourceLineNumbers, "SoftwareIdentificationTag");
Row row = this.Core.CreateRow(sourceLineNumbers, "WixProductTag");
row[0] = fileId.Id;
row[1] = regid;
row[2] = name;
if (YesNoType.Yes == licensed)
{
row[3] = 1;
}
row[4] = type;
this.Core.CreateSimpleReference(sourceLineNumbers, "File", fileId.Id);
}
}
/// <summary>
/// Parses a TagRef element for Software Id Tag registration under a PatchFamily element.
/// </summary>
/// <param name="node">The element to parse.</param>
private void ParseTagRefElement(XElement node)
{
SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node);
string regid = null;
foreach (XAttribute attrib in node.Attributes())
{
if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
{
switch (attrib.Name.LocalName)
{
case "Regid":
regid = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
break;
default:
this.Core.UnexpectedAttribute(node, attrib);
break;
}
}
else
{
this.Core.ParseExtensionAttribute(node, attrib);
}
}
this.Core.ParseForExtensionElements(node);
if (String.IsNullOrEmpty(regid))
{
this.Core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Regid"));
}
if (!this.Core.EncounteredError)
{
Identifier id = this.Core.CreateIdentifier("tag", regid, ".product.tag");
this.Core.CreatePatchFamilyChildReference(sourceLineNumbers, "Component", id.Id);
}
}
private string ParseTagTypeAttribute(SourceLineNumber sourceLineNumbers, XElement node, XAttribute attrib)
{
string typeValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
switch (typeValue)
{
case "application":
typeValue = "Application";
break;
case "component":
typeValue = "Component";
break;
case "feature":
typeValue = "Feature";
break;
case "group":
typeValue = "Group";
break;
case "patch":
typeValue = "Patch";
break;
default:
this.Core.OnMessage(WixErrors.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, typeValue, "application", "component", "feature", "group", "patch"));
break;
}
return typeValue;
}
}
}

Просмотреть файл

@ -0,0 +1,69 @@
// 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.
namespace WixToolset.Extensions
{
using System;
using WixToolset;
using WixToolset.Data;
using WixToolset.Extensibility;
using Tag = WixToolset.Extensions.Serialize.Tag;
/// <summary>
/// The Binder for the WiX Toolset Software Id Tag Extension.
/// </summary>
public sealed class TagDecompiler : DecompilerExtension
{
/// <summary>
/// Creates a decompiler for Tag Extension.
/// </summary>
public TagDecompiler()
{
this.TableDefinitions = TagExtensionData.GetExtensionTableDefinitions();
}
/// <summary>
/// Get the extensions library to be removed.
/// </summary>
/// <param name="tableDefinitions">Table definitions for library.</param>
/// <returns>Library to remove from decompiled output.</returns>
public override Library GetLibraryToRemove(TableDefinitionCollection tableDefinitions)
{
return TagExtensionData.GetExtensionLibrary(tableDefinitions);
}
/// <summary>
/// Decompiles an extension table.
/// </summary>
/// <param name="table">The table to decompile.</param>
public override void DecompileTable(Table table)
{
switch (table.Name)
{
case "SoftwareIdentificationTag":
this.DecompileSoftwareIdentificationTag(table);
break;
default:
base.DecompileTable(table);
break;
}
}
/// <summary>
/// Decompile the SoftwareIdentificationTag table.
/// </summary>
/// <param name="table">The table to decompile.</param>
private void DecompileSoftwareIdentificationTag(Table table)
{
foreach (Row row in table.Rows)
{
Tag.Tag tag= new Tag.Tag();
tag.Regid = (string)row[1];
tag.Name = (string)row[2];
tag.Licensed = null == row[3] ? Tag.YesNoType.NotSet : 1 == (int)row[3] ? Tag.YesNoType.yes : Tag.YesNoType.no;
this.Core.RootElement.AddChild(tag);
}
}
}
}

Просмотреть файл

@ -0,0 +1,55 @@
// 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.
namespace WixToolset.Extensions
{
using System;
using System.Reflection;
using WixToolset.Data;
using WixToolset.Extensibility;
/// <summary>
/// The WiX Toolset Software Id Tag Extension.
/// </summary>
public sealed class TagExtensionData : ExtensionData
{
/// <summary>
/// Gets the optional table definitions for this extension.
/// </summary>
/// <value>The optional table definitions for this extension.</value>
public override TableDefinitionCollection TableDefinitions
{
get
{
return TagExtensionData.GetExtensionTableDefinitions();
}
}
/// <summary>
/// Gets the library associated with this extension.
/// </summary>
/// <param name="tableDefinitions">The table definitions to use while loading the library.</param>
/// <returns>The loaded library.</returns>
public override Library GetLibrary(TableDefinitionCollection tableDefinitions)
{
return TagExtensionData.GetExtensionLibrary(tableDefinitions);
}
/// <summary>
/// Internal mechanism to access the extension's table definitions.
/// </summary>
/// <returns>Extension's table definitions.</returns>
internal static TableDefinitionCollection GetExtensionTableDefinitions()
{
return ExtensionData.LoadTableDefinitionHelper(Assembly.GetExecutingAssembly(), "WixToolset.Extensions.Data.tables.xml");
}
/// <summary>
/// Internal mechanism to access the extension's library.
/// </summary>
/// <returns>Extension's library.</returns>
internal static Library GetExtensionLibrary(TableDefinitionCollection tableDefinitions)
{
return ExtensionData.LoadLibraryHelper(Assembly.GetExecutingAssembly(), "WixToolset.Extensions.Data.tag.wixlib", tableDefinitions);
}
}
}

Просмотреть файл

@ -0,0 +1,51 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 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. -->
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0">
<PropertyGroup>
<ProjectGuid>{696EB455-0EF3-47C0-8A02-86FF5D8CC791}</ProjectGuid>
<AssemblyName>WixTagExtension</AssemblyName>
<OutputType>Library</OutputType>
<RootNamespace>WixToolset.Extensions</RootNamespace>
</PropertyGroup>
<ItemGroup>
<Compile Include="AssemblyInfo.cs" />
<Compile Include="TagBinder.cs" />
<Compile Include="TagCompiler.cs" />
<Compile Include="TagDecompiler.cs" />
<Compile Include="TagExtensionData.cs" />
<MsgGenSource Include="Data\messages.xml">
<ResourcesLogicalName>$(RootNamespace).Data.Messages.resources</ResourcesLogicalName>
</MsgGenSource>
<EmbeddedFlattenedResource Include="Data\tables.xml">
<LogicalName>$(RootNamespace).Data.tables.xml</LogicalName>
</EmbeddedFlattenedResource>
<EmbeddedFlattenedResource Include="Xsd\tag.xsd">
<LogicalName>$(RootNamespace).Xsd.tag.xsd</LogicalName>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</EmbeddedFlattenedResource>
<XsdGenSource Include="Xsd\tag.xsd">
<CommonNamespace>WixToolset.Data.Serialize</CommonNamespace>
<Namespace>WixToolset.Extensions.Serialize.Tag</Namespace>
</XsdGenSource>
<EmbeddedResource Include="$(OutputPath)\tag.wixlib">
<Link>Data\tag.wixlib</Link>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Xml" />
<Reference Include="System.Xml.Linq" />
<ProjectReference Include="..\..\..\DTF\Libraries\WindowsInstaller\WindowsInstaller.csproj" />
<ProjectReference Include="..\..\..\libs\WixToolset.Data\WixToolset.Data.csproj" />
<ProjectReference Include="..\..\..\libs\WixToolset.Extensibility\WixToolset.Extensibility.csproj" />
<ProjectReference Include="..\..\..\tools\wix\Wix.csproj" />
<ProjectReference Include="..\wixlib\TagExtension.wixproj">
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
</ProjectReference>
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildProjectDirectory), wix.proj))\tools\WixBuild.targets" />
</Project>

15
src/wixext/messages.xml Normal file
Просмотреть файл

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 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. -->
<Messages Namespace="WixToolset.Extensions" Resources="Data.Messages" xmlns="http://schemas.microsoft.com/genmsgs/2004/07/messages">
<Class Name="TagErrors" ContainerName="TagErrorEventArgs" BaseContainerName="WixErrorEventArgs">
<Message Id="IllegalName" Number="6601">
<Instance>
The Tag/@Name attribute value, '{1}', contains invalid filename identifiers. The Tag/@Name may have defaulted from the {0}/@Name attrbute. If so, use the Tag/@Name attribute to provide a valid filename. Any character except for the follow may be used: \ ? | > &lt; : / * ".
<Parameter Type="System.String" Name="parentElement" />
<Parameter Type="System.String" Name="name" />
</Instance>
</Message>
</Class>
</Messages>

42
src/wixext/tables.xml Normal file
Просмотреть файл

@ -0,0 +1,42 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 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. -->
<tableDefinitions xmlns="http://wixtoolset.org/schemas/v4/wi/tables">
<tableDefinition name="WixBundleTag" unreal="yes">
<columnDefinition name="Filename" type="string" length="255" primaryKey="yes"
category="filename" description="The file name for the software id tag."/>
<columnDefinition name="Regid" type="string" length="0" primaryKey="yes"
category="text" description="The regid for the software id tag."/>
<columnDefinition name="Name" type="string" length="255" nullable="yes"
category="text" description="The name for the software id tag."/>
<columnDefinition name="Attributes" type="number" length="4" nullable="yes"
minValue="0" maxValue="2147483647" description="A 32-bit word that specifies bits of software id tag."/>
<columnDefinition name="Xml" type="string" length="0" nullable="yes"
category="text" description="The software id tag as XML. Only valid after binding"/>
<columnDefinition name="Type" type="string" length="0" nullable="yes"
category="text" description="The type of the software id tag."/>
</tableDefinition>
<tableDefinition name="WixProductTag" unreal="yes">
<columnDefinition name="File_" type="string" length="72" modularize="column" primaryKey="yes"
keyTable="File" keyColumn="1" category="identifier" description="The file representing the software id tag."/>
<columnDefinition name="Regid" type="string" length="0"
category="text" description="The regid for the software id tag."/>
<columnDefinition name="Name" type="string" length="0" nullable="yes"
category="text" description="The name for the software id tag."/>
<columnDefinition name="Attributes" type="number" length="4" nullable="yes"
minValue="0" maxValue="2147483647" description="A 32-bit word that specifies bits of software id tag."/>
<columnDefinition name="Type" type="string" length="0" nullable="yes"
category="text" description="The type of the software id tag."/>
</tableDefinition>
<tableDefinition name="SoftwareIdentificationTag">
<columnDefinition name="File_" type="string" length="72" modularize="column" primaryKey="yes"
keyTable="File" keyColumn="1" category="identifier" description="The file that installs the software id tag."/>
<columnDefinition name="Regid" type="string" length="0"
category="text" description="The regid for the software id tag."/>
<columnDefinition name="UniqueId" type="string" length="0"
category="text" description="The unique id for the software id tag."/>
<columnDefinition name="Type" type="string" length="0"
category="text" description="The type of the software id tag."/>
</tableDefinition>
</tableDefinitions>

143
src/wixext/tag.xsd Normal file
Просмотреть файл

@ -0,0 +1,143 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 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. -->
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xse=" http://wixtoolset.org/schemas/XmlSchemaExtension"
xmlns:html="http://www.w3.org/1999/xhtml"
targetNamespace="http://wixtoolset.org/schemas/v4/wxs/tag"
xmlns="http://wixtoolset.org/schemas/v4/wxs/tag">
<xs:annotation>
<xs:documentation>
The source code schema for the WiX Toolset Software Id Tag Extension.
</xs:documentation>
</xs:annotation>
<xs:import namespace="http://wixtoolset.org/schemas/v4/wxs" />
<xs:element name="Tag">
<xs:annotation>
<xs:documentation>
This extension implements the ISO/IEC 19770-2 specification. A SWID tag file
will be generated an inserted into the Product or Bundle.
</xs:documentation>
<xs:appinfo>
<xse:parent namespace="http://wixtoolset.org/schemas/v4/wxs" ref="Bundle" />
<xse:parent namespace="http://wixtoolset.org/schemas/v4/wxs" ref="Product" />
</xs:appinfo>
</xs:annotation>
<xs:complexType>
<xs:attribute name="Name" type="xs:string">
<xs:annotation>
<xs:documentation>
Name to use in the filename for the software id tag. By default the filename
uses the Bundle/@Name or Product/@Name. If the bundle name or product name contains
invalid filename characters such as ":" or "?", use this attribute to provide
a valid filename.
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="Regid" type="xs:string" use="required">
<xs:annotation>
<xs:documentation>
The regid for the software id tag. A regid follows the format: "regid" + "."
+ YYYY-MM + "." + reverse domain order. The YYYY-MM is the year and month the
domain was first owned. For example: "regid.1995-08.com.example".
</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="Feature" type="xs:string">
<xs:annotation>
<xs:documentation>Optional attribute to explicitly set the Feature when defining the software id tag
in a Product. By default the software id tag will always be installed by a top-level hidden feature.
It is recommended to <html:strong>not</html:strong> set this attribute.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="Licensed" type="YesNoTypeUnion">
<xs:annotation>
<xs:documentation>Indicates whether the software requires a license. The default is
"no". </xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="Type" type="TagTypeUnion">
<xs:annotation>
<xs:documentation>
Defines the type of software tag being defined. One of the following values may be used: "group",
"application", "patch", or "component". The default is "application" when the Tag element is a child of
the Product element. The default is "group" or "application" when the Tag element is under a Bundle element
based on the contents of the bundle's chain. The Bundle/Tag@Type will be "application" unless there are one
or more packages that define a software Tag@Type of "application" or "group".
</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
</xs:element>
<xs:element name="TagRef">
<xs:annotation>
<xs:documentation>
Allows an ISO/IEC 19770-2 SWID tag file to be referenced in a Patch.
</xs:documentation>
<xs:appinfo>
<xse:parent namespace="http://wixtoolset.org/schemas/v4/wxs" ref="PatchFamily" />
</xs:appinfo>
</xs:annotation>
<xs:complexType>
<xs:attribute name="Regid" type="xs:string" use="required">
<xs:annotation>
<xs:documentation>
The regid for the software id tag. A regid follows the format: "regid" + "."
+ YYYY-MM + "." + reverse domain order. The YYYY-MM is the year and month the
domain was first owned. For example: "regid.1995-08.com.example".
</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
</xs:element>
<xs:simpleType name="TagTypeUnion">
<xs:annotation>
<xs:documentation>Values of this type will be "application", "component", "feature", "group", or "patch".</xs:documentation>
</xs:annotation>
<xs:union memberTypes="TagType PreprocessorVariables"/>
</xs:simpleType>
<xs:simpleType name="TagType">
<xs:annotation>
<xs:documentation>Values of this type will be "application", "component", "feature", "group", or "patch".</xs:documentation>
</xs:annotation>
<xs:restriction base="xs:NMTOKEN">
<xs:enumeration value="application" />
<xs:enumeration value="component" />
<xs:enumeration value="feature" />
<xs:enumeration value="group" />
<xs:enumeration value="patch" />
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="YesNoTypeUnion">
<xs:annotation>
<xs:documentation>Values of this type will either be "yes" or "no".</xs:documentation>
</xs:annotation>
<xs:union memberTypes="YesNoType PreprocessorVariables"/>
</xs:simpleType>
<xs:simpleType name="YesNoType">
<xs:annotation>
<xs:documentation>Values of this type will either be "yes" or "no".</xs:documentation>
</xs:annotation>
<xs:restriction base="xs:NMTOKEN">
<xs:enumeration value="no" />
<xs:enumeration value="yes" />
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="PreprocessorVariables">
<xs:annotation>
<xs:documentation>A type that represents that 1 or more preprocessor variables (as they appear in sources on disk, before preprocessor has run).</xs:documentation>
</xs:annotation>
<xs:restriction base="xs:string">
<xs:pattern value="(\$\(\w+\.(\w|[.])+\))+" />
</xs:restriction>
</xs:simpleType>
</xs:schema>

Просмотреть файл

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8" ?>
<!-- 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. -->
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0">
<PropertyGroup>
<ProjectGuid>{47BD326B-88F2-428F-9145-3397DD404E64}</ProjectGuid>
<OutputName>tag</OutputName>
<OutputType>Library</OutputType>
<BindFiles>True</BindFiles>
<Pedantic>True</Pedantic>
<Cultures>en-us</Cultures>
</PropertyGroup>
<ItemGroup>
<Compile Include="TagFeature.wxs" />
<Compile Include="TagFolder.wxs" />
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildProjectDirectory), wix.proj))\tools\WixBuild.targets" />
</Project>

10
src/wixlib/TagFeature.wxs Normal file
Просмотреть файл

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- 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. -->
<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
<Fragment>
<Feature Id="WixSwidTag" Title="ISO/IEC 19770-2" Level="1" InstallDefault="local"
Display="hidden" AllowAdvertise="no" Absent="disallow" />
</Fragment>
</Wix>

18
src/wixlib/TagFolder.wxs Normal file
Просмотреть файл

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- 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. -->
<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
<Fragment>
<Property Id="ProductRegid" Value="!(wix.WixTagRegid=InvalidRegid)" />
<DirectoryRef Id="TARGETDIR">
<Directory Id="WixTagFolder" Name="swidtags" ComponentGuidGenerationSeed="0F673797-85FC-49D8-A0D8-B5C81C7C9CDC">
<Directory Id="WixTagRegidFolder" Name="!(wix.WixTagRegid=InvalidRegid)" />
</Directory>
</DirectoryRef>
<SetProperty Action="SetWixTagFolderPerUser" Id="WixTagFolder" Value="[LocalAppDataFolder]" Sequence="both" Before="CostFinalize">NOT ALLUSERS</SetProperty>
<SetProperty Action="SetWixTagFolderPerMachine" Id="WixTagFolder" Value="[CommonAppDataFolder]" Sequence="both" Before="CostFinalize">ALLUSERS</SetProperty>
</Fragment>
</Wix>