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 --- src/WixToolset.Data/WindowsInstaller/Table.cs | 333 ++++++++++++++++++++++++++ 1 file changed, 333 insertions(+) create mode 100644 src/WixToolset.Data/WindowsInstaller/Table.cs (limited to 'src/WixToolset.Data/WindowsInstaller/Table.cs') diff --git a/src/WixToolset.Data/WindowsInstaller/Table.cs b/src/WixToolset.Data/WindowsInstaller/Table.cs new file mode 100644 index 00000000..7fcc1b31 --- /dev/null +++ b/src/WixToolset.Data/WindowsInstaller/Table.cs @@ -0,0 +1,333 @@ +// 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.Diagnostics; + using System.Xml; + using WixToolset.Data.WindowsInstaller.Rows; + + /// + /// Object that represents a table in a database. + /// + public class Table + { + /// + /// Creates a table. + /// + /// Definition of the table. + public Table(TableDefinition tableDefinition) + { + this.Definition = tableDefinition; + this.Rows = new List(); + } + + /// + /// Gets the table definition. + /// + /// Definition of the table. + public TableDefinition Definition { get; } + + /// + /// Gets the name of the table. + /// + /// Name of the table. + public string Name => this.Definition.Name; + + /// + /// Gets or sets the table transform operation. + /// + /// The table transform operation. + public TableOperation Operation { get; set; } + + /// + /// Gets the rows contained in the table. + /// + /// Rows contained in the table. + public IList Rows { get; } + + /// + /// Creates a new row in the table. + /// + /// Original source lines for this row. + /// Specifies whether to only create the row or add it to the table automatically. + /// Row created in table. + public Row CreateRow(SourceLineNumber sourceLineNumbers, bool add = true) + { + Row row; + + switch (this.Name) + { + case "BBControl": + row = new BBControlRow(sourceLineNumbers, this); + break; + case "WixBundlePackage": + row = new WixBundlePackageRow(sourceLineNumbers, this); + break; + case "WixBundleExePackage": + row = new WixBundleExePackageRow(sourceLineNumbers, this); + break; + case "WixBundleMsiPackage": + row = new WixBundleMsiPackageRow(sourceLineNumbers, this); + break; + case "WixBundleMspPackage": + row = new WixBundleMspPackageRow(sourceLineNumbers, this); + break; + case "WixBundleMsuPackage": + row = new WixBundleMsuPackageRow(sourceLineNumbers, this); + break; + case "Component": + row = new ComponentRow(sourceLineNumbers, this); + break; + case "WixBundleContainer": + row = new WixBundleContainerRow(sourceLineNumbers, this); + break; + case "Control": + row = new ControlRow(sourceLineNumbers, this); + break; + case "File": + row = new FileRow(sourceLineNumbers, this); + break; + case "WixBundleMsiFeature": + row = new WixBundleMsiFeatureRow(sourceLineNumbers, this); + break; + case "WixBundleMsiProperty": + row = new WixBundleMsiPropertyRow(sourceLineNumbers, this); + break; + case "Media": + row = new MediaRow(sourceLineNumbers, this); + break; + case "WixBundlePayload": + row = new WixBundlePayloadRow(sourceLineNumbers, this); + break; + case "Property": + row = new PropertyRow(sourceLineNumbers, this); + break; + case "WixRelatedBundle": + row = new WixRelatedBundleRow(sourceLineNumbers, this); + break; + case "WixBundleRelatedPackage": + row = new WixBundleRelatedPackageRow(sourceLineNumbers, this); + break; + case "WixBundleRollbackBoundary": + row = new WixBundleRollbackBoundaryRow(sourceLineNumbers, this); + break; + case "Upgrade": + row = new UpgradeRow(sourceLineNumbers, this); + break; + case "WixBundleVariable": + row = new WixBundleVariableRow(sourceLineNumbers, this); + break; + case "WixAction": + row = new WixActionRow(sourceLineNumbers, this); + break; + case "WixApprovedExeForElevation": + row = new WixApprovedExeForElevationRow(sourceLineNumbers, this); + break; + case "WixBundle": + row = new WixBundleRow(sourceLineNumbers, this); + break; + case "WixBundlePackageExitCode": + row = new WixBundlePackageExitCodeRow(sourceLineNumbers, this); + break; + case "WixBundlePatchTargetCode": + row = new WixBundlePatchTargetCodeRow(sourceLineNumbers, this); + break; + case "WixBundleSlipstreamMsp": + row = new WixBundleSlipstreamMspRow(sourceLineNumbers, this); + break; + case "WixBundleUpdate": + row = new WixBundleUpdateRow(sourceLineNumbers, this); + break; + case "WixBundleCatalog": + row = new WixBundleCatalogRow(sourceLineNumbers, this); + break; + case "WixChain": + row = new WixChainRow(sourceLineNumbers, this); + break; + case "WixChainItem": + row = new WixChainItemRow(sourceLineNumbers, this); + break; + case "WixBundlePackageCommandLine": + row = new WixBundlePackageCommandLineRow(sourceLineNumbers, this); + break; + case "WixComplexReference": + row = new WixComplexReferenceRow(sourceLineNumbers, this); + break; + case "WixDeltaPatchFile": + row = new WixDeltaPatchFileRow(sourceLineNumbers, this); + break; + case "WixDeltaPatchSymbolPaths": + row = new WixDeltaPatchSymbolPathsRow(sourceLineNumbers, this); + break; + case "WixFile": + row = new WixFileRow(sourceLineNumbers, this); + break; + case "WixGroup": + row = new WixGroupRow(sourceLineNumbers, this); + break; + case "WixMedia": + row = new WixMediaRow(sourceLineNumbers, this); + break; + case "WixMediaTemplate": + row = new WixMediaTemplateRow(sourceLineNumbers, this); + break; + case "WixMerge": + row = new WixMergeRow(sourceLineNumbers, this); + break; + case "WixPayloadProperties": + row = new WixPayloadPropertiesRow(sourceLineNumbers, this); + break; + case "WixProperty": + row = new WixPropertyRow(sourceLineNumbers, this); + break; + case "WixSimpleReference": + row = new WixSimpleReferenceRow(sourceLineNumbers, this); + break; + case "WixUpdateRegistration": + row = new WixUpdateRegistrationRow(sourceLineNumbers, this); + break; + + default: + row = new Row(sourceLineNumbers, this); + break; + } + + if (add) + { + this.Rows.Add(row); + } + + return row; + } + + /// + /// Parse a table from the xml. + /// + /// XmlReader where the intermediate is persisted. + /// TableDefinitions to use in the intermediate. + /// The parsed table. + internal static Table Read(XmlReader reader, TableDefinitionCollection tableDefinitions) + { + Debug.Assert("table" == reader.LocalName); + + bool empty = reader.IsEmptyElement; + TableOperation operation = TableOperation.None; + string name = null; + + while (reader.MoveToNextAttribute()) + { + switch (reader.LocalName) + { + case "name": + name = reader.Value; + break; + case "op": + switch (reader.Value) + { + case "add": + operation = TableOperation.Add; + break; + case "drop": + operation = TableOperation.Drop; + break; + default: + throw new XmlException(); + } + break; + } + } + + if (null == name) + { + throw new XmlException(); + } + + TableDefinition tableDefinition = tableDefinitions[name]; + Table table = new Table(tableDefinition); + table.Operation = operation; + + if (!empty) + { + bool done = false; + + // loop through all the rows in a table + while (!done && reader.Read()) + { + switch (reader.NodeType) + { + case XmlNodeType.Element: + switch (reader.LocalName) + { + case "row": + Row.Read(reader, table); + break; + default: + throw new XmlException(); + } + break; + case XmlNodeType.EndElement: + done = true; + break; + } + } + + if (!done) + { + throw new XmlException(); + } + } + + return table; + } + + /// + /// Persists a row in an XML format. + /// + /// XmlWriter where the Row should persist itself as XML. + internal void Write(XmlWriter writer) + { + if (null == writer) + { + throw new ArgumentNullException("writer"); + } + + writer.WriteStartElement("table", Intermediate.XmlNamespaceUri); + writer.WriteAttributeString("name", this.Name); + + if (TableOperation.None != this.Operation) + { + writer.WriteAttributeString("op", this.Operation.ToString().ToLowerInvariant()); + } + + foreach (var row in this.Rows) + { + row.Write(writer); + } + + writer.WriteEndElement(); + } + + /// + /// Validates the rows of this OutputTable and throws if it collides on + /// primary keys. + /// + public void ValidateRows() + { + var primaryKeys = new Dictionary(); + + foreach (var row in this.Rows) + { + var primaryKey = row.GetPrimaryKey(); + + if (primaryKeys.TryGetValue(primaryKey, out var collisionSourceLineNumber)) + { + throw new WixException(WixDataErrors.DuplicatePrimaryKey(collisionSourceLineNumber, primaryKey, this.Definition.Name)); + } + + primaryKeys.Add(primaryKey, row.SourceLineNumbers); + } + } + } +} -- cgit v1.2.3-55-g6feb