// 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; /// /// Object that represents a table in a database. /// [DebuggerDisplay("{Name}")] 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 and adds it to the table. /// /// Original source lines for this row. /// Row created in table. public Row CreateRow(SourceLineNumber sourceLineNumbers) { var row = this.Definition.CreateRow(sourceLineNumbers, this); this.Rows.Add(row); return row; } /// /// 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(ErrorMessages.DuplicatePrimaryKey(collisionSourceLineNumber, primaryKey, this.Definition.Name)); } primaryKeys.Add(primaryKey, row.SourceLineNumbers); } } /// /// 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", WindowsInstallerData.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(); } } }