diff options
Diffstat (limited to 'src/WixToolset.Core/Bind/Databases/ExtractMergeModuleFilesCommand.cs')
-rw-r--r-- | src/WixToolset.Core/Bind/Databases/ExtractMergeModuleFilesCommand.cs | 225 |
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 | |||
3 | namespace 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 | } | ||