From d3d3649a68cb1fa589fdd987a6690dbd5d671f0d Mon Sep 17 00:00:00 2001 From: Rob Mensching Date: Sun, 17 Sep 2017 15:35:20 -0700 Subject: Initial code commit --- src/WixToolset.BuildTasks/GetLooseFileList.cs | 230 ++++++++++++++++++++++++++ 1 file changed, 230 insertions(+) create mode 100644 src/WixToolset.BuildTasks/GetLooseFileList.cs (limited to 'src/WixToolset.BuildTasks/GetLooseFileList.cs') diff --git a/src/WixToolset.BuildTasks/GetLooseFileList.cs b/src/WixToolset.BuildTasks/GetLooseFileList.cs new file mode 100644 index 00000000..bd403426 --- /dev/null +++ b/src/WixToolset.BuildTasks/GetLooseFileList.cs @@ -0,0 +1,230 @@ +// 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.BuildTasks +{ + using System; + using System.Collections; + using System.Collections.Generic; + using System.Diagnostics; + using System.IO; + using System.Reflection; + using System.Xml; + using Microsoft.Build.Framework; + using Microsoft.Build.Utilities; + using WixToolset.Dtf.WindowsInstaller; + using Microsoft.Win32; + + /// + /// This task assigns Culture metadata to files based on the value of the Culture attribute on the + /// WixLocalization element inside the file. + /// + public class GetLooseFileList : Task + { + private ITaskItem database; + private ITaskItem[] looseFileList; + + internal const int MsidbFileAttributesNoncompressed = 8192; + internal const int MsidbFileAttributesCompressed = 16384; + + /// + /// The list of database files to find Loose Files in + /// + [Required] + public ITaskItem Database + { + get { return this.database; } + set { this.database = value; } + } + + /// + /// The total list of Loose Files in this database + /// + [Output] + public ITaskItem[] LooseFileList + { + get { return this.looseFileList; } + } + + /// + /// Takes the "defaultDir" column + /// + /// Returns the corresponding sourceDir. + public string SourceDirFromDefaultDir(string defaultDir) + { + string sourceDir; + + string[] splitted = defaultDir.Split(':'); + + if (1 == splitted.Length) + { + sourceDir = splitted[0]; + } + else + { + sourceDir = splitted[1]; + } + + splitted = sourceDir.Split('|'); + + if (1 == splitted.Length) + { + sourceDir = splitted[0]; + } + else + { + sourceDir = splitted[1]; + } + + return sourceDir; + } + + /// + /// Takes the "FileName" column + /// + /// Returns the corresponding source file name. + public string SourceFileFromFileName(string fileName) + { + string sourceFile; + + string[] splitted = fileName.Split('|'); + + if (1 == splitted.Length) + { + sourceFile = splitted[0]; + } + else + { + sourceFile = splitted[1]; + } + + return sourceFile; + } + + /// + /// Gets a complete list of external Loose Files referenced by the given installer database file. + /// + /// True upon completion of the task execution. + public override bool Execute() + { + string databaseFile = this.database.ItemSpec; + Object []emptyArgs = { }; + System.Collections.Generic.List looseFileNames = new System.Collections.Generic.List(); + Dictionary ComponentFullDirectory = new Dictionary(); + Dictionary DirectoryIdDefaultDir = new Dictionary(); + Dictionary DirectoryIdParent = new Dictionary(); + Dictionary DirectoryIdFullSource = new Dictionary(); + int i; + string databaseDir = Path.GetDirectoryName(databaseFile); + + // If the file doesn't exist, no Loose Files to return, so exit now + if (!File.Exists(databaseFile)) + { + return true; + } + + using (Database database = new Database(databaseFile)) + { + bool compressed = false; + if (2 == (database.SummaryInfo.WordCount & 2)) + { + compressed = true; + } + + // If the media table doesn't exist, no Loose Files to return, so exit now + if (null == database.Tables["File"]) + { + return true; + } + + // Only setup all these helpful indexes if the database is marked as uncompressed. If it's marked as compressed, files are stored at the root, + // so none of these indexes will be used + if (!compressed) + { + if (null == database.Tables["Directory"] || null == database.Tables["Component"]) + { + return true; + } + + System.Collections.IList directoryRecords = database.ExecuteQuery("SELECT `Directory`,`Directory_Parent`,`DefaultDir` FROM `Directory`", emptyArgs); + + // First setup a simple index from DirectoryId to DefaultDir + for (i = 0; i < directoryRecords.Count; i += 3) + { + string directoryId = (string)(directoryRecords[i]); + string directoryParent = (string)(directoryRecords[i + 1]); + string defaultDir = (string)(directoryRecords[i + 2]); + + string sourceDir = SourceDirFromDefaultDir(defaultDir); + + DirectoryIdDefaultDir[directoryId] = sourceDir; + DirectoryIdParent[directoryId] = directoryParent; + } + + // Setup an index from directory Id to the full source path + for (i = 0; i < directoryRecords.Count; i += 3) + { + string directoryId = (string)(directoryRecords[i]); + string directoryParent = (string)(directoryRecords[i + 1]); + string defaultDir = (string)(directoryRecords[i + 2]); + + string sourceDir = DirectoryIdDefaultDir[directoryId]; + + // The TARGETDIR case + if (String.IsNullOrEmpty(directoryParent)) + { + DirectoryIdFullSource[directoryId] = databaseDir; + } + else + { + string tempDirectoryParent = directoryParent; + + while (!String.IsNullOrEmpty(tempDirectoryParent) && !String.IsNullOrEmpty(DirectoryIdParent[tempDirectoryParent])) + { + sourceDir = Path.Combine(DirectoryIdDefaultDir[tempDirectoryParent], sourceDir); + + tempDirectoryParent = DirectoryIdParent[tempDirectoryParent]; + } + + DirectoryIdFullSource[directoryId] = Path.Combine(databaseDir, sourceDir); + } + } + + // Setup an index from component Id to full directory path + System.Collections.IList componentRecords = database.ExecuteQuery("SELECT `Component`,`Directory_` FROM `Component`", emptyArgs); + + for (i = 0; i < componentRecords.Count; i += 2) + { + string componentId = (string)(componentRecords[i]); + string componentDir = (string)(componentRecords[i + 1]); + + ComponentFullDirectory[componentId] = DirectoryIdFullSource[componentDir]; + } + } + + System.Collections.IList fileRecords = database.ExecuteQuery("SELECT `Component_`,`FileName`,`Attributes` FROM `File`", emptyArgs); + + for (i = 0; i < fileRecords.Count; i += 3) + { + string componentId = (string)(fileRecords[i]); + string fileName = SourceFileFromFileName((string)(fileRecords[i + 1])); + int attributes = (int)(fileRecords[i + 2]); + + // If the whole database is marked uncompressed, use the directory layout made above + if ((!compressed && MsidbFileAttributesCompressed != (attributes & MsidbFileAttributesCompressed))) + { + looseFileNames.Add(new TaskItem(Path.GetFullPath(Path.Combine(ComponentFullDirectory[componentId], fileName)))); + } + // If the database is marked as compressed, put files at the root + else if (compressed && (MsidbFileAttributesNoncompressed == (attributes & MsidbFileAttributesNoncompressed))) + { + looseFileNames.Add(new TaskItem(Path.GetFullPath(Path.Combine(databaseDir, fileName)))); + } + } + } + + this.looseFileList = looseFileNames.ToArray(); + + return true; + } + } +} -- cgit v1.2.3-55-g6feb