aboutsummaryrefslogtreecommitdiff
path: root/src/WixToolset.Core/Bind/Databases/ExtractMergeModuleFilesCommand.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/WixToolset.Core/Bind/Databases/ExtractMergeModuleFilesCommand.cs')
-rw-r--r--src/WixToolset.Core/Bind/Databases/ExtractMergeModuleFilesCommand.cs225
1 files changed, 0 insertions, 225 deletions
diff --git a/src/WixToolset.Core/Bind/Databases/ExtractMergeModuleFilesCommand.cs b/src/WixToolset.Core/Bind/Databases/ExtractMergeModuleFilesCommand.cs
deleted file mode 100644
index bee1488b..00000000
--- a/src/WixToolset.Core/Bind/Databases/ExtractMergeModuleFilesCommand.cs
+++ /dev/null
@@ -1,225 +0,0 @@
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
3namespace WixToolset.Bind.Databases
4{
5 using System;
6 using System.Collections.Generic;
7 using System.ComponentModel;
8 using System.Globalization;
9 using System.IO;
10 using System.Linq;
11 using System.Runtime.InteropServices;
12 using WixToolset.Cab;
13 using WixToolset.Data;
14 using WixToolset.Data.Rows;
15 using WixToolset.MergeMod;
16 using WixToolset.Msi;
17 using WixToolset.Core.Native;
18
19 /// <summary>
20 /// Retrieve files information and extract them from merge modules.
21 /// </summary>
22 internal class ExtractMergeModuleFilesCommand : ICommand
23 {
24 public IEnumerable<FileFacade> FileFacades { private get; set; }
25
26 public Table FileTable { private get; set; }
27
28 public Table WixFileTable { private get; set; }
29
30 public Table WixMergeTable { private get; set; }
31
32 public int OutputInstallerVersion { private get; set; }
33
34 public bool SuppressLayout { private get; set; }
35
36 public string TempFilesLocation { private get; set; }
37
38 public IEnumerable<FileFacade> MergeModulesFileFacades { get; private set; }
39
40 public void Execute()
41 {
42 List<FileFacade> mergeModulesFileFacades = new List<FileFacade>();
43
44 IMsmMerge2 merge = MsmInterop.GetMsmMerge();
45
46 // Index all of the file rows to be able to detect collisions with files in the Merge Modules.
47 // It may seem a bit expensive to build up this index solely for the purpose of checking collisions
48 // and you may be thinking, "Surely, we must need the file rows indexed elsewhere." It turns out
49 // there are other cases where we need all the file rows indexed, however they are not common cases.
50 // Now since Merge Modules are already slow and generally less desirable than .wixlibs we'll let
51 // this case be slightly more expensive because the cost of maintaining an indexed file row collection
52 // is a lot more costly for the common cases.
53 Dictionary<string, FileFacade> indexedFileFacades = this.FileFacades.ToDictionary(f => f.File.File, StringComparer.Ordinal);
54
55 foreach (WixMergeRow wixMergeRow in this.WixMergeTable.Rows)
56 {
57 bool containsFiles = this.CreateFacadesForMergeModuleFiles(wixMergeRow, mergeModulesFileFacades, indexedFileFacades);
58
59 // If the module has files and creating layout
60 if (containsFiles && !this.SuppressLayout)
61 {
62 this.ExtractFilesFromMergeModule(merge, wixMergeRow);
63 }
64 }
65
66 this.MergeModulesFileFacades = mergeModulesFileFacades;
67 }
68
69 private bool CreateFacadesForMergeModuleFiles(WixMergeRow wixMergeRow, List<FileFacade> mergeModulesFileFacades, Dictionary<string, FileFacade> indexedFileFacades)
70 {
71 bool containsFiles = false;
72
73 try
74 {
75 // read the module's File table to get its FileMediaInformation entries and gather any other information needed from the module.
76 using (Database db = new Database(wixMergeRow.SourceFile, OpenDatabase.ReadOnly))
77 {
78 if (db.TableExists("File") && db.TableExists("Component"))
79 {
80 Dictionary<string, FileFacade> uniqueModuleFileIdentifiers = new Dictionary<string, FileFacade>(StringComparer.OrdinalIgnoreCase);
81
82 using (View view = db.OpenExecuteView("SELECT `File`, `Directory_` FROM `File`, `Component` WHERE `Component_`=`Component`"))
83 {
84 // add each file row from the merge module into the file row collection (check for errors along the way)
85 while (true)
86 {
87 using (Record record = view.Fetch())
88 {
89 if (null == record)
90 {
91 break;
92 }
93
94 // NOTE: this is very tricky - the merge module file rows are not added to the
95 // file table because they should not be created via idt import. Instead, these
96 // rows are created by merging in the actual modules.
97 FileRow fileRow = (FileRow)this.FileTable.CreateRow(wixMergeRow.SourceLineNumbers, false);
98 fileRow.File = record[1];
99 fileRow.Compressed = wixMergeRow.FileCompression;
100
101 WixFileRow wixFileRow = (WixFileRow)this.WixFileTable.CreateRow(wixMergeRow.SourceLineNumbers, false);
102 wixFileRow.Directory = record[2];
103 wixFileRow.DiskId = wixMergeRow.DiskId;
104 wixFileRow.PatchGroup = -1;
105 wixFileRow.Source = String.Concat(this.TempFilesLocation, Path.DirectorySeparatorChar, "MergeId.", wixMergeRow.Number.ToString(CultureInfo.InvariantCulture), Path.DirectorySeparatorChar, record[1]);
106
107 FileFacade mergeModuleFileFacade = new FileFacade(true, fileRow, wixFileRow);
108
109 FileFacade collidingFacade;
110
111 // If case-sensitive collision with another merge module or a user-authored file identifier.
112 if (indexedFileFacades.TryGetValue(mergeModuleFileFacade.File.File, out collidingFacade))
113 {
114 Messaging.Instance.OnMessage(WixErrors.DuplicateModuleFileIdentifier(wixMergeRow.SourceLineNumbers, wixMergeRow.Id, collidingFacade.File.File));
115 }
116 else if (uniqueModuleFileIdentifiers.TryGetValue(mergeModuleFileFacade.File.File, out collidingFacade)) // case-insensitive collision with another file identifier in the same merge module
117 {
118 Messaging.Instance.OnMessage(WixErrors.DuplicateModuleCaseInsensitiveFileIdentifier(wixMergeRow.SourceLineNumbers, wixMergeRow.Id, mergeModuleFileFacade.File.File, collidingFacade.File.File));
119 }
120 else // no collision
121 {
122 mergeModulesFileFacades.Add(mergeModuleFileFacade);
123
124 // Keep updating the indexes as new rows are added.
125 indexedFileFacades.Add(mergeModuleFileFacade.File.File, mergeModuleFileFacade);
126 uniqueModuleFileIdentifiers.Add(mergeModuleFileFacade.File.File, mergeModuleFileFacade);
127 }
128
129 containsFiles = true;
130 }
131 }
132 }
133 }
134
135 // Get the summary information to detect the Schema
136 using (SummaryInformation summaryInformation = new SummaryInformation(db))
137 {
138 string moduleInstallerVersionString = summaryInformation.GetProperty(14);
139
140 try
141 {
142 int moduleInstallerVersion = Convert.ToInt32(moduleInstallerVersionString, CultureInfo.InvariantCulture);
143 if (moduleInstallerVersion > this.OutputInstallerVersion)
144 {
145 Messaging.Instance.OnMessage(WixWarnings.InvalidHigherInstallerVersionInModule(wixMergeRow.SourceLineNumbers, wixMergeRow.Id, moduleInstallerVersion, this.OutputInstallerVersion));
146 }
147 }
148 catch (FormatException)
149 {
150 throw new WixException(WixErrors.MissingOrInvalidModuleInstallerVersion(wixMergeRow.SourceLineNumbers, wixMergeRow.Id, wixMergeRow.SourceFile, moduleInstallerVersionString));
151 }
152 }
153 }
154 }
155 catch (FileNotFoundException)
156 {
157 throw new WixException(WixErrors.FileNotFound(wixMergeRow.SourceLineNumbers, wixMergeRow.SourceFile));
158 }
159 catch (Win32Exception)
160 {
161 throw new WixException(WixErrors.CannotOpenMergeModule(wixMergeRow.SourceLineNumbers, wixMergeRow.Id, wixMergeRow.SourceFile));
162 }
163
164 return containsFiles;
165 }
166
167 private void ExtractFilesFromMergeModule(IMsmMerge2 merge, WixMergeRow wixMergeRow)
168 {
169 bool moduleOpen = false;
170 short mergeLanguage;
171
172 try
173 {
174 mergeLanguage = Convert.ToInt16(wixMergeRow.Language, CultureInfo.InvariantCulture);
175 }
176 catch (System.FormatException)
177 {
178 Messaging.Instance.OnMessage(WixErrors.InvalidMergeLanguage(wixMergeRow.SourceLineNumbers, wixMergeRow.Id, wixMergeRow.Language));
179 return;
180 }
181
182 try
183 {
184 merge.OpenModule(wixMergeRow.SourceFile, mergeLanguage);
185 moduleOpen = true;
186
187 string safeMergeId = wixMergeRow.Number.ToString(CultureInfo.InvariantCulture.NumberFormat);
188
189 // extract the module cabinet, then explode all of the files to a temp directory
190 string moduleCabPath = String.Concat(this.TempFilesLocation, Path.DirectorySeparatorChar, safeMergeId, ".module.cab");
191 merge.ExtractCAB(moduleCabPath);
192
193 string mergeIdPath = String.Concat(this.TempFilesLocation, Path.DirectorySeparatorChar, "MergeId.", safeMergeId);
194 Directory.CreateDirectory(mergeIdPath);
195
196 using (WixExtractCab extractCab = new WixExtractCab())
197 {
198 try
199 {
200 extractCab.Extract(moduleCabPath, mergeIdPath);
201 }
202 catch (FileNotFoundException)
203 {
204 throw new WixException(WixErrors.CabFileDoesNotExist(moduleCabPath, wixMergeRow.SourceFile, mergeIdPath));
205 }
206 catch
207 {
208 throw new WixException(WixErrors.CabExtractionFailed(moduleCabPath, wixMergeRow.SourceFile, mergeIdPath));
209 }
210 }
211 }
212 catch (COMException ce)
213 {
214 throw new WixException(WixErrors.UnableToOpenModule(wixMergeRow.SourceLineNumbers, wixMergeRow.SourceFile, ce.Message));
215 }
216 finally
217 {
218 if (moduleOpen)
219 {
220 merge.CloseModule();
221 }
222 }
223 }
224 }
225}