| 1 | // 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. |
| 2 | |
| 3 | namespace WixToolset.Core.WindowsInstaller.Bind |
| 4 | { |
| 5 | using System; |
| 6 | using System.Collections.Generic; |
| 7 | using System.IO; |
| 8 | using System.Linq; |
| 9 | using WixToolset.Core.Native.Msi; |
| 10 | using WixToolset.Data; |
| 11 | using WixToolset.Data.Symbols; |
| 12 | using WixToolset.Extensibility.Data; |
| 13 | using WixToolset.Extensibility.Services; |
| 14 | |
| 15 | /// <summary> |
| 16 | /// Defines the file transfers necessary to layout the uncompressed files. |
| 17 | /// </summary> |
| 18 | internal class ProcessUncompressedFilesCommand |
| 19 | { |
| 20 | public ProcessUncompressedFilesCommand(IntermediateSection section, IBackendHelper backendHelper, IPathResolver pathResolver, IEnumerable<IFileFacade> fileFacades, string outputPath, bool compressed, bool longNamesInImage, Func<MediaSymbol, string, string, string> resolveMedia) |
| 21 | { |
| 22 | this.Section = section; |
| 23 | this.BackendHelper = backendHelper; |
| 24 | this.PathResolver = pathResolver; |
| 25 | |
| 26 | this.DatabasePath = outputPath; |
| 27 | this.LayoutDirectory = Path.GetDirectoryName(outputPath); |
| 28 | this.Compressed = compressed; |
| 29 | this.LongNamesInImage = longNamesInImage; |
| 30 | |
| 31 | this.FileFacades = fileFacades; |
| 32 | this.ResolveMedia = resolveMedia; |
| 33 | } |
| 34 | |
| 35 | private IntermediateSection Section { get; } |
| 36 | |
| 37 | private IBackendHelper BackendHelper { get; } |
| 38 | |
| 39 | private IPathResolver PathResolver { get; } |
| 40 | |
| 41 | private string DatabasePath { get; } |
| 42 | |
| 43 | private string LayoutDirectory { get; } |
| 44 | |
| 45 | private bool Compressed { get; } |
| 46 | |
| 47 | private bool LongNamesInImage { get; } |
| 48 | |
| 49 | private IEnumerable<IFileFacade> FileFacades { get; } |
| 50 | |
| 51 | private Func<MediaSymbol, string, string, string> ResolveMedia { get; } |
| 52 | |
| 53 | public IEnumerable<IFileTransfer> FileTransfers { get; private set; } |
| 54 | |
| 55 | public IEnumerable<ITrackedFile> TrackedFiles { get; private set; } |
| 56 | |
| 57 | public void Execute() |
| 58 | { |
| 59 | var fileTransfers = new List<IFileTransfer>(); |
| 60 | |
| 61 | var trackedFiles = new List<ITrackedFile>(); |
| 62 | |
| 63 | var directories = new Dictionary<string, IResolvedDirectory>(); |
| 64 | |
| 65 | var mediaRows = this.Section.Symbols.OfType<MediaSymbol>().ToDictionary(t => t.DiskId); |
| 66 | |
| 67 | using (var db = new Database(this.DatabasePath, OpenDatabase.ReadOnly)) |
| 68 | { |
| 69 | using (var directoryView = db.OpenExecuteView("SELECT `Directory`, `Directory_Parent`, `DefaultDir` FROM `Directory`")) |
| 70 | { |
| 71 | foreach (var directoryRecord in directoryView.Records) |
| 72 | { |
| 73 | var sourceName = this.BackendHelper.GetMsiFileName(directoryRecord.GetString(3), true, this.LongNamesInImage); |
| 74 | |
| 75 | var resolvedDirectory = this.BackendHelper.CreateResolvedDirectory(directoryRecord.GetString(2), sourceName); |
| 76 | |
| 77 | directories.Add(directoryRecord.GetString(1), resolvedDirectory); |
| 78 | } |
| 79 | } |
| 80 | |
| 81 | using (var fileView = db.OpenView("SELECT `Directory_`, `FileName` FROM `Component`, `File` WHERE `Component`.`Component`=`File`.`Component_` AND `File`.`File`=?")) |
| 82 | { |
| 83 | using (var fileQueryRecord = new Record(1)) |
| 84 | { |
| 85 | // for each file in the array of uncompressed files |
| 86 | foreach (var facade in this.FileFacades) |
| 87 | { |
| 88 | var mediaSymbol = mediaRows[facade.DiskId]; |
| 89 | string relativeFileLayoutPath = null; |
| 90 | var mediaLayoutFolder = mediaSymbol.Layout; |
| 91 | |
| 92 | var mediaLayoutDirectory = this.ResolveMedia(mediaSymbol, mediaLayoutFolder, this.LayoutDirectory); |
| 93 | |
| 94 | // setup up the query record and find the appropriate file in the |
| 95 | // previously executed file view |
| 96 | fileQueryRecord[1] = facade.Id; |
| 97 | fileView.Execute(fileQueryRecord); |
| 98 | |
| 99 | using (var fileRecord = fileView.Fetch()) |
| 100 | { |
| 101 | if (null == fileRecord) |
| 102 | { |
| 103 | throw new WixException(ErrorMessages.FileIdentifierNotFound(facade.SourceLineNumber, facade.Id)); |
| 104 | } |
| 105 | |
| 106 | relativeFileLayoutPath = this.PathResolver.GetFileSourcePath(directories, fileRecord[1], fileRecord[2], this.Compressed, this.LongNamesInImage); |
| 107 | } |
| 108 | |
| 109 | // finally put together the base media layout path and the relative file layout path |
| 110 | var fileLayoutPath = Path.Combine(mediaLayoutDirectory, relativeFileLayoutPath); |
| 111 | |
| 112 | var transfer = this.BackendHelper.CreateFileTransfer(facade.SourcePath, fileLayoutPath, false, facade.SourceLineNumber); |
| 113 | fileTransfers.Add(transfer); |
| 114 | |
| 115 | var tracked = this.BackendHelper.TrackFile(transfer.Destination, TrackedFileType.CopiedOutput, facade.SourceLineNumber); |
| 116 | trackedFiles.Add(tracked); |
| 117 | } |
| 118 | } |
| 119 | } |
| 120 | } |
| 121 | |
| 122 | this.FileTransfers = fileTransfers; |
| 123 | this.TrackedFiles = trackedFiles; |
| 124 | } |
| 125 | } |
| 126 | } |