From 221da62c05ef2b515eb507c77655514cd0ec32a4 Mon Sep 17 00:00:00 2001 From: Rob Mensching Date: Thu, 7 Dec 2017 14:17:39 -0800 Subject: Reintegrate MSI constructs into WxToolset.Data.WindowsInstaller namespace --- .../WindowsInstaller/TableDefinition.cs | 218 +++++++++++++++++++++ 1 file changed, 218 insertions(+) create mode 100644 src/WixToolset.Data/WindowsInstaller/TableDefinition.cs (limited to 'src/WixToolset.Data/WindowsInstaller/TableDefinition.cs') diff --git a/src/WixToolset.Data/WindowsInstaller/TableDefinition.cs b/src/WixToolset.Data/WindowsInstaller/TableDefinition.cs new file mode 100644 index 00000000..518f0926 --- /dev/null +++ b/src/WixToolset.Data/WindowsInstaller/TableDefinition.cs @@ -0,0 +1,218 @@ +// 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.Data.WindowsInstaller +{ + using System; + using System.Collections.Generic; + using System.Collections.ObjectModel; + using System.Xml; + + /// + /// Definition of a table in a database. + /// + public sealed class TableDefinition : IComparable + { + /// + /// Tracks the maximum number of columns supported in a real table. + /// This is a Windows Installer limitation. + /// + public const int MaxColumnsInRealTable = 32; + + /// + /// Creates a table definition. + /// + /// Name of table to create. + /// Column definitions for the table. + /// Flag if table is unreal. + /// Flag if table is part of UX Manifest. + public TableDefinition(string name, IList columns, bool unreal = false, bool bootstrapperApplicationData = false) + { + this.Name = name; + this.Unreal = unreal; + this.BootstrapperApplicationData = bootstrapperApplicationData; + + this.Columns = new ReadOnlyCollection(columns); + } + + /// + /// Gets the name of the table. + /// + /// Name of the table. + public string Name { get; private set; } + + /// + /// Gets if the table is unreal. + /// + /// Flag if table is unreal. + public bool Unreal { get; private set; } + + /// + /// Gets if the table is a part of the bootstrapper application data manifest. + /// + /// Flag if table is a part of the bootstrapper application data manifest. + public bool BootstrapperApplicationData { get; private set; } + + /// + /// Gets the collection of column definitions for this table. + /// + /// Collection of column definitions for this table. + public IList Columns { get; private set; } + + /// + /// Gets the column definition in the table by index. + /// + /// Index of column to locate. + /// Column definition in the table by index. + public ColumnDefinition this[int columnIndex] + { + get { return this.Columns[columnIndex]; } + } + + /// + /// Compares this table definition to another table definition. + /// + /// + /// Only Windows Installer traits are compared, allowing for updates to WiX-specific table definitions. + /// + /// The updated to compare with this target definition. + /// 0 if the tables' core properties are the same; otherwise, non-0. + public int CompareTo(TableDefinition updated) + { + // by definition, this object is greater than null + if (null == updated) + { + return 1; + } + + // compare the table names + int ret = String.Compare(this.Name, updated.Name, StringComparison.Ordinal); + + // compare the column count + if (0 == ret) + { + // transforms can only add columns + ret = Math.Min(0, updated.Columns.Count - this.Columns.Count); + + // compare name, type, and length of each column + for (int i = 0; 0 == ret && this.Columns.Count > i; i++) + { + ColumnDefinition thisColumnDef = this.Columns[i]; + ColumnDefinition updatedColumnDef = updated.Columns[i]; + + ret = thisColumnDef.CompareTo(updatedColumnDef); + } + } + + return ret; + } + + /// + /// Parses table definition from xml reader. + /// + /// Reader to get data from. + /// The TableDefintion represented by the Xml. + internal static TableDefinition Read(XmlReader reader) + { + bool empty = reader.IsEmptyElement; + string name = null; + bool unreal = false; + bool bootstrapperApplicationData = false; + + while (reader.MoveToNextAttribute()) + { + switch (reader.LocalName) + { + case "name": + name = reader.Value; + break; + case "unreal": + unreal = reader.Value.Equals("yes"); + break; + case "bootstrapperApplicationData": + bootstrapperApplicationData = reader.Value.Equals("yes"); + break; + } + } + + if (null == name) + { + throw new XmlException(); + } + + List columns = new List(); + bool hasPrimaryKeyColumn = false; + + // parse the child elements + if (!empty) + { + bool done = false; + + while (!done && reader.Read()) + { + switch (reader.NodeType) + { + case XmlNodeType.Element: + switch (reader.LocalName) + { + case "columnDefinition": + ColumnDefinition columnDefinition = ColumnDefinition.Read(reader); + columns.Add(columnDefinition); + + if (columnDefinition.PrimaryKey) + { + hasPrimaryKeyColumn = true; + } + break; + default: + throw new XmlException(); + } + break; + case XmlNodeType.EndElement: + done = true; + break; + } + } + + if (!unreal && !bootstrapperApplicationData && !hasPrimaryKeyColumn) + { + throw new WixException(WixDataErrors.RealTableMissingPrimaryKeyColumn(SourceLineNumber.CreateFromUri(reader.BaseURI), name)); + } + + if (!done) + { + throw new XmlException(); + } + } + + return new TableDefinition(name, columns, unreal, bootstrapperApplicationData); + } + + /// + /// Persists an output in an XML format. + /// + /// XmlWriter where the Output should persist itself as XML. + internal void Write(XmlWriter writer) + { + writer.WriteStartElement("tableDefinition", TableDefinitionCollection.XmlNamespaceUri); + + writer.WriteAttributeString("name", this.Name); + + if (this.Unreal) + { + writer.WriteAttributeString("unreal", "yes"); + } + + if (this.BootstrapperApplicationData) + { + writer.WriteAttributeString("bootstrapperApplicationData", "yes"); + } + + foreach (ColumnDefinition columnDefinition in this.Columns) + { + columnDefinition.Write(writer); + } + + writer.WriteEndElement(); + } + } +} -- cgit v1.2.3-55-g6feb