From 3f583916719eeef598d10a5d4e14ef14f008243b Mon Sep 17 00:00:00 2001 From: Rob Mensching Date: Tue, 11 May 2021 07:36:37 -0700 Subject: Merge Dtf --- .../ColumnCollection.cs | 333 +++++++++++++++++++++ 1 file changed, 333 insertions(+) create mode 100644 src/dtf/WixToolset.Dtf.WindowsInstaller/ColumnCollection.cs (limited to 'src/dtf/WixToolset.Dtf.WindowsInstaller/ColumnCollection.cs') diff --git a/src/dtf/WixToolset.Dtf.WindowsInstaller/ColumnCollection.cs b/src/dtf/WixToolset.Dtf.WindowsInstaller/ColumnCollection.cs new file mode 100644 index 00000000..9a452da1 --- /dev/null +++ b/src/dtf/WixToolset.Dtf.WindowsInstaller/ColumnCollection.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.Dtf.WindowsInstaller +{ + using System; + using System.IO; + using System.Collections; + using System.Collections.Generic; + using System.Text; + using System.Diagnostics.CodeAnalysis; + + /// + /// Collection of column information related to a or + /// . + /// + public sealed class ColumnCollection : ICollection + { + private IList columns; + private string formatString; + + /// + /// Creates a new ColumnCollection based on a specified list of columns. + /// + /// columns to be added to the new collection + public ColumnCollection(ICollection columns) + { + if (columns == null) + { + throw new ArgumentNullException("columns"); + } + + this.columns = new List(columns); + } + + /// + /// Creates a new ColumnCollection that is associated with a database table. + /// + /// view that contains the columns + internal ColumnCollection(View view) + { + if (view == null) + { + throw new ArgumentNullException("view"); + } + + this.columns = ColumnCollection.GetViewColumns(view); + } + + /// + /// Gets the number of columns in the collection. + /// + /// number of columns in the collection + public int Count + { + get + { + return this.columns.Count; + } + } + + /// + /// Gets a boolean value indicating whether the collection is read-only. + /// A ColumnCollection is read-only if it is associated with a + /// or a read-only . + /// + /// read-only status of the collection + public bool IsReadOnly + { + get + { + return true; + } + } + + /// + /// Gets information about a specific column in the collection. + /// + /// 1-based index into the column collection + /// is less + /// than 1 or greater than the number of columns in the collection + public ColumnInfo this[int columnIndex] + { + get + { + if (columnIndex >= 0 && columnIndex < this.columns.Count) + { + return this.columns[columnIndex]; + } + else + { + throw new ArgumentOutOfRangeException("columnIndex"); + } + } + } + + /// + /// Gets information about a specific column in the collection. + /// + /// case-sensitive name of a column collection + /// does + /// not exist in the collection + public ColumnInfo this[string columnName] + { + get + { + if (String.IsNullOrEmpty(columnName)) + { + throw new ArgumentNullException("columnName"); + } + + foreach (ColumnInfo colInfo in this.columns) + { + if (colInfo.Name == columnName) + { + return colInfo; + } + } + + throw new ArgumentOutOfRangeException("columnName"); + } + } + + /// + /// Not supported because the collection is read-only. + /// + /// information about the column being added + /// the collection is read-only + public void Add(ColumnInfo item) + { + throw new InvalidOperationException(); + } + + /// + /// Not supported because the collection is read-only. + /// + /// the collection is read-only + public void Clear() + { + throw new InvalidOperationException(); + } + + /// + /// Checks if a column with a given name exists in the collection. + /// + /// case-sensitive name of the column to look for + /// true if the column exists in the collection, false otherwise + public bool Contains(string columnName) + { + return this.IndexOf(columnName) >= 0; + } + + /// + /// Checks if a column with a given name exists in the collection. + /// + /// column to look for, with case-sensitive name + /// true if the column exists in the collection, false otherwise + bool ICollection.Contains(ColumnInfo column) + { + return this.Contains(column.Name); + } + + /// + /// Gets the index of a column within the collection. + /// + /// case-sensitive name of the column to look for + /// 0-based index of the column, or -1 if not found + public int IndexOf(string columnName) + { + if (String.IsNullOrEmpty(columnName)) + { + throw new ArgumentNullException("columnName"); + } + + for (int index = 0; index < this.columns.Count; index++) + { + if (this.columns[index].Name == columnName) + { + return index; + } + } + return -1; + } + + /// + /// Copies the columns from this collection into an array. + /// + /// destination array to be filed + /// offset into the destination array where copying begins + public void CopyTo(ColumnInfo[] array, int arrayIndex) + { + if (array == null) + { + throw new ArgumentNullException("array"); + } + + this.columns.CopyTo(array, arrayIndex); + } + + /// + /// Not supported because the collection is read-only. + /// + /// column to remove + /// true if the column was removed, false if it was not found + /// the collection is read-only + [SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "column")] + [SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic")] + bool ICollection.Remove(ColumnInfo column) + { + throw new InvalidOperationException(); + } + + /// + /// Gets an enumerator over the columns in the collection. + /// + /// An enumerator of ColumnInfo objects. + public IEnumerator GetEnumerator() + { + return this.columns.GetEnumerator(); + } + + /// + /// Gets a string suitable for printing all the values of a record containing these columns. + /// + public string FormatString + { + get + { + if (this.formatString == null) + { + this.formatString = CreateFormatString(this.columns); + } + return this.formatString; + } + } + + private static string CreateFormatString(IList columns) + { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < columns.Count; i++) + { + if (columns[i].Type == typeof(Stream)) + { + sb.AppendFormat("{0} = [Binary Data]", columns[i].Name); + } + else + { + sb.AppendFormat("{0} = [{1}]", columns[i].Name, i + 1); + } + + if (i < columns.Count - 1) + { + sb.Append(", "); + } + } + return sb.ToString(); + } + + /// + /// Gets an enumerator over the columns in the collection. + /// + /// An enumerator of ColumnInfo objects. + IEnumerator IEnumerable.GetEnumerator() + { + return this.GetEnumerator(); + } + + /// + /// Creates ColumnInfo objects for the associated view. + /// + /// dynamically-generated list of columns + private static IList GetViewColumns(View view) + { + IList columnNames = ColumnCollection.GetViewColumns(view, false); + IList columnTypes = ColumnCollection.GetViewColumns(view, true); + + int count = columnNames.Count; + if (columnTypes[count - 1] == "O0") + { + // Weird.. the "_Tables" table returns a second column with type "O0" -- ignore it. + count--; + } + + IList columnsList = new List(count); + for (int i = 0; i < count; i++) + { + columnsList.Add(new ColumnInfo(columnNames[i], columnTypes[i])); + } + + return columnsList; + } + + /// + /// Gets a list of column names or column-definition-strings for the + /// associated view. + /// + /// the view to that defines the columns + /// true to return types (column definition strings), + /// false to return names + /// list of column names or types + private static IList GetViewColumns(View view, bool types) + { + int recordHandle; + int typesFlag = types ? 1 : 0; + uint ret = RemotableNativeMethods.MsiViewGetColumnInfo( + (int) view.Handle, (uint) typesFlag, out recordHandle); + if (ret != 0) + { + throw InstallerException.ExceptionFromReturnCode(ret); + } + + using (Record rec = new Record((IntPtr) recordHandle, true, null)) + { + int count = rec.FieldCount; + IList columnsList = new List(count); + + // Since we must be getting all strings of limited length, + // this code is faster than calling rec.GetString(field). + for (int field = 1; field <= count; field++) + { + uint bufSize = 256; + StringBuilder buf = new StringBuilder((int) bufSize); + ret = RemotableNativeMethods.MsiRecordGetString((int) rec.Handle, (uint) field, buf, ref bufSize); + if (ret != 0) + { + throw InstallerException.ExceptionFromReturnCode(ret); + } + columnsList.Add(buf.ToString()); + } + return columnsList; + } + } + } +} -- cgit v1.2.3-55-g6feb