aboutsummaryrefslogtreecommitdiff
path: root/src/WixToolset.Core.WindowsInstaller/Bind/AssignMediaCommand.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/WixToolset.Core.WindowsInstaller/Bind/AssignMediaCommand.cs')
-rw-r--r--src/WixToolset.Core.WindowsInstaller/Bind/AssignMediaCommand.cs187
1 files changed, 92 insertions, 95 deletions
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/AssignMediaCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/AssignMediaCommand.cs
index 74e2cdb5..f426b96d 100644
--- a/src/WixToolset.Core.WindowsInstaller/Bind/AssignMediaCommand.cs
+++ b/src/WixToolset.Core.WindowsInstaller/Bind/AssignMediaCommand.cs
@@ -1,43 +1,44 @@
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. 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 2
3namespace WixToolset.Core.WindowsInstaller.Databases 3namespace WixToolset.Core.WindowsInstaller.Bind
4{ 4{
5 using System; 5 using System;
6 using System.Collections.Generic; 6 using System.Collections.Generic;
7 using System.Globalization; 7 using System.Globalization;
8 using System.Linq;
8 using WixToolset.Core.Bind; 9 using WixToolset.Core.Bind;
9 using WixToolset.Data; 10 using WixToolset.Data;
10 using WixToolset.Data.Rows; 11 using WixToolset.Data.Rows;
12 using WixToolset.Data.Tuples;
11 13
12 /// <summary> 14 /// <summary>
13 /// AssignMediaCommand assigns files to cabs based on Media or MediaTemplate rows. 15 /// AssignMediaCommand assigns files to cabs based on Media or MediaTemplate rows.
14 /// </summary> 16 /// </summary>
15 public class AssignMediaCommand 17 internal class AssignMediaCommand
16 { 18 {
17 public AssignMediaCommand() 19 public AssignMediaCommand(IntermediateSection section)
18 { 20 {
19 this.CabinetNameTemplate = "Cab{0}.cab"; 21 this.CabinetNameTemplate = "Cab{0}.cab";
22 this.Section = section;
20 } 23 }
21 24
22 public Output Output { private get; set; } 25 private IntermediateSection Section { get; }
26
27 public IEnumerable<FileFacade> FileFacades { private get; set; }
23 28
24 public bool FilesCompressed { private get; set; } 29 public bool FilesCompressed { private get; set; }
25 30
26 public string CabinetNameTemplate { private get; set; } 31 public string CabinetNameTemplate { private get; set; }
27 32
28 public IEnumerable<FileFacade> FileFacades { private get; set; }
29
30 public TableDefinitionCollection TableDefinitions { private get; set; }
31
32 /// <summary> 33 /// <summary>
33 /// Gets cabinets with their file rows. 34 /// Gets cabinets with their file rows.
34 /// </summary> 35 /// </summary>
35 public Dictionary<MediaRow, IEnumerable<FileFacade>> FileFacadesByCabinetMedia { get; private set; } 36 public Dictionary<MediaTuple, IEnumerable<FileFacade>> FileFacadesByCabinetMedia { get; private set; }
36 37
37 /// <summary> 38 /// <summary>
38 /// Get media rows. 39 /// Get media rows.
39 /// </summary> 40 /// </summary>
40 public RowDictionary<MediaRow> MediaRows { get; private set; } 41 public Dictionary<int, MediaTuple> MediaRows { get; private set; }
41 42
42 /// <summary> 43 /// <summary>
43 /// Get uncompressed file rows. This will contain file rows of File elements that are marked with compression=no. 44 /// Get uncompressed file rows. This will contain file rows of File elements that are marked with compression=no.
@@ -47,42 +48,41 @@ namespace WixToolset.Core.WindowsInstaller.Databases
47 48
48 public void Execute() 49 public void Execute()
49 { 50 {
50 Dictionary<MediaRow, List<FileFacade>> filesByCabinetMedia = new Dictionary<MediaRow, List<FileFacade>>(); 51 var filesByCabinetMedia = new Dictionary<MediaTuple, List<FileFacade>>();
51 52
52 RowDictionary<MediaRow> mediaRows = new RowDictionary<MediaRow>(); 53 var mediaRows = new Dictionary<int, MediaTuple>();
53 54
54 List<FileFacade> uncompressedFiles = new List<FileFacade>(); 55 List<FileFacade> uncompressedFiles = new List<FileFacade>();
55 56
56 MediaRow mergeModuleMediaRow = null; 57 var mediaTable = this.Section.Tuples.OfType<MediaTuple>().ToList();
57 Table mediaTable = this.Output.Tables["Media"]; 58 var mediaTemplateTable = this.Section.Tuples.OfType<WixMediaTemplateTuple>().ToList();
58 Table mediaTemplateTable = this.Output.Tables["WixMediaTemplate"];
59 59
60 // If both tables are authored, it is an error. 60 // If both tables are authored, it is an error.
61 if ((mediaTemplateTable != null && mediaTemplateTable.Rows.Count > 0) && (mediaTable != null && mediaTable.Rows.Count > 1)) 61 if ((mediaTemplateTable != null && mediaTemplateTable.Count > 0) && (mediaTable != null && mediaTable.Count > 1))
62 { 62 {
63 throw new WixException(WixErrors.MediaTableCollision(null)); 63 throw new WixException(WixErrors.MediaTableCollision(null));
64 } 64 }
65 65
66 // When building merge module, all the files go to "#MergeModule.CABinet". 66 // When building merge module, all the files go to "#MergeModule.CABinet".
67 if (OutputType.Module == this.Output.Type) 67 if (SectionType.Module == this.Section.Type)
68 { 68 {
69 Table mergeModuleMediaTable = new Table(this.TableDefinitions["Media"]); 69 var mergeModuleMediaRow = new MediaTuple();
70 mergeModuleMediaRow = (MediaRow)mergeModuleMediaTable.CreateRow(null);
71 mergeModuleMediaRow.Cabinet = "#MergeModule.CABinet"; 70 mergeModuleMediaRow.Cabinet = "#MergeModule.CABinet";
72 71
73 filesByCabinetMedia.Add(mergeModuleMediaRow, new List<FileFacade>()); 72 this.Section.Tuples.Add(mergeModuleMediaRow);
74 }
75 73
76 if (OutputType.Module == this.Output.Type || null == mediaTemplateTable) 74 filesByCabinetMedia.Add(mergeModuleMediaRow, new List<FileFacade>(this.FileFacades));
75 }
76 else if (null == mediaTemplateTable)
77 { 77 {
78 this.ManuallyAssignFiles(mediaTable, mergeModuleMediaRow, this.FileFacades, filesByCabinetMedia, mediaRows, uncompressedFiles); 78 this.ManuallyAssignFiles(mediaTable, this.FileFacades, filesByCabinetMedia, mediaRows, uncompressedFiles);
79 } 79 }
80 else 80 else
81 { 81 {
82 this.AutoAssignFiles(mediaTable, this.FileFacades, filesByCabinetMedia, mediaRows, uncompressedFiles); 82 this.AutoAssignFiles(mediaTable, this.FileFacades, filesByCabinetMedia, mediaRows, uncompressedFiles);
83 } 83 }
84 84
85 this.FileFacadesByCabinetMedia = new Dictionary<MediaRow, IEnumerable<FileFacade>>(); 85 this.FileFacadesByCabinetMedia = new Dictionary<MediaTuple, IEnumerable<FileFacade>>();
86 86
87 foreach (var mediaRowWithFiles in filesByCabinetMedia) 87 foreach (var mediaRowWithFiles in filesByCabinetMedia)
88 { 88 {
@@ -98,7 +98,7 @@ namespace WixToolset.Core.WindowsInstaller.Databases
98 /// Assign files to cabinets based on MediaTemplate authoring. 98 /// Assign files to cabinets based on MediaTemplate authoring.
99 /// </summary> 99 /// </summary>
100 /// <param name="fileFacades">FileRowCollection</param> 100 /// <param name="fileFacades">FileRowCollection</param>
101 private void AutoAssignFiles(Table mediaTable, IEnumerable<FileFacade> fileFacades, Dictionary<MediaRow, List<FileFacade>> filesByCabinetMedia, RowDictionary<MediaRow> mediaRows, List<FileFacade> uncompressedFiles) 101 private void AutoAssignFiles(List<MediaTuple> mediaTable, IEnumerable<FileFacade> fileFacades, Dictionary<MediaTuple, List<FileFacade>> filesByCabinetMedia, Dictionary<int, MediaTuple> mediaRows, List<FileFacade> uncompressedFiles)
102 { 102 {
103 const int MaxCabIndex = 999; 103 const int MaxCabIndex = 999;
104 104
@@ -107,13 +107,19 @@ namespace WixToolset.Core.WindowsInstaller.Databases
107 int maxPreCabSizeInMB = 0; 107 int maxPreCabSizeInMB = 0;
108 int currentCabIndex = 0; 108 int currentCabIndex = 0;
109 109
110 MediaRow currentMediaRow = null; 110 MediaTuple currentMediaRow = null;
111 111
112 Table mediaTemplateTable = this.Output.Tables["WixMediaTemplate"]; 112 var mediaTemplateTable = this.Section.Tuples.OfType<WixMediaTemplateTuple>();
113
114 // Remove all previous media tuples since they will be replaced with
115 // media template.
116 foreach (var mediaTuple in mediaTable)
117 {
118 this.Section.Tuples.Remove(mediaTuple);
119 }
113 120
114 // Auto assign files to cabinets based on maximum uncompressed media size 121 // Auto assign files to cabinets based on maximum uncompressed media size
115 mediaTable.Rows.Clear(); 122 var mediaTemplateRow = mediaTemplateTable.Single();
116 WixMediaTemplateRow mediaTemplateRow = (WixMediaTemplateRow)mediaTemplateTable.Rows[0];
117 123
118 if (!String.IsNullOrEmpty(mediaTemplateRow.CabinetTemplate)) 124 if (!String.IsNullOrEmpty(mediaTemplateRow.CabinetTemplate))
119 { 125 {
@@ -149,9 +155,9 @@ namespace WixToolset.Core.WindowsInstaller.Databases
149 { 155 {
150 // When building a product, if the current file is not to be compressed or if 156 // When building a product, if the current file is not to be compressed or if
151 // the package set not to be compressed, don't cab it. 157 // the package set not to be compressed, don't cab it.
152 if (OutputType.Product == this.Output.Type && 158 if (SectionType.Product == this.Section.Type &&
153 (!facade.File.Compressed.Value || 159 ((facade.File.Compressed.HasValue && !facade.File.Compressed.Value) ||
154 (!facade.File.Compressed.HasValue && !this.FilesCompressed))) 160 (!facade.File.Compressed.HasValue && !this.FilesCompressed)))
155 { 161 {
156 uncompressedFiles.Add(facade); 162 uncompressedFiles.Add(facade);
157 continue; 163 continue;
@@ -172,8 +178,8 @@ namespace WixToolset.Core.WindowsInstaller.Databases
172 if (currentPreCabSize > maxPreCabSizeInBytes) 178 if (currentPreCabSize > maxPreCabSizeInBytes)
173 { 179 {
174 // Overflow due to current file 180 // Overflow due to current file
175 currentMediaRow = this.AddMediaRow(mediaTemplateRow, mediaTable, ++currentCabIndex); 181 currentMediaRow = this.AddMediaRow(mediaTemplateRow, ++currentCabIndex);
176 mediaRows.Add(currentMediaRow); 182 mediaRows.Add(currentMediaRow.DiskId, currentMediaRow);
177 filesByCabinetMedia.Add(currentMediaRow, new List<FileFacade>()); 183 filesByCabinetMedia.Add(currentMediaRow, new List<FileFacade>());
178 184
179 List<FileFacade> cabinetFileRows = filesByCabinetMedia[currentMediaRow]; 185 List<FileFacade> cabinetFileRows = filesByCabinetMedia[currentMediaRow];
@@ -188,8 +194,8 @@ namespace WixToolset.Core.WindowsInstaller.Databases
188 if (currentMediaRow == null) 194 if (currentMediaRow == null)
189 { 195 {
190 // Create new cab and MediaRow 196 // Create new cab and MediaRow
191 currentMediaRow = this.AddMediaRow(mediaTemplateRow, mediaTable, ++currentCabIndex); 197 currentMediaRow = this.AddMediaRow(mediaTemplateRow, ++currentCabIndex);
192 mediaRows.Add(currentMediaRow); 198 mediaRows.Add(currentMediaRow.DiskId, currentMediaRow);
193 filesByCabinetMedia.Add(currentMediaRow, new List<FileFacade>()); 199 filesByCabinetMedia.Add(currentMediaRow, new List<FileFacade>());
194 } 200 }
195 201
@@ -201,11 +207,13 @@ namespace WixToolset.Core.WindowsInstaller.Databases
201 } 207 }
202 208
203 // If there are uncompressed files and no MediaRow, create a default one. 209 // If there are uncompressed files and no MediaRow, create a default one.
204 if (uncompressedFiles.Count > 0 && mediaTable.Rows.Count == 0) 210 if (uncompressedFiles.Count > 0 && !this.Section.Tuples.OfType<MediaTuple>().Any())
205 { 211 {
206 MediaRow defaultMediaRow = (MediaRow)mediaTable.CreateRow(null); 212 var defaultMediaRow = new MediaTuple(null, new Identifier(1, AccessModifier.Private));
207 defaultMediaRow.DiskId = 1; 213 defaultMediaRow.DiskId = 1;
208 mediaRows.Add(defaultMediaRow); 214
215 mediaRows.Add(1, defaultMediaRow);
216 this.Section.Tuples.Add(defaultMediaRow);
209 } 217 }
210 } 218 }
211 219
@@ -213,79 +221,65 @@ namespace WixToolset.Core.WindowsInstaller.Databases
213 /// Assign files to cabinets based on Media authoring. 221 /// Assign files to cabinets based on Media authoring.
214 /// </summary> 222 /// </summary>
215 /// <param name="mediaTable"></param> 223 /// <param name="mediaTable"></param>
216 /// <param name="mergeModuleMediaRow"></param>
217 /// <param name="fileFacades"></param> 224 /// <param name="fileFacades"></param>
218 private void ManuallyAssignFiles(Table mediaTable, MediaRow mergeModuleMediaRow, IEnumerable<FileFacade> fileFacades, Dictionary<MediaRow, List<FileFacade>> filesByCabinetMedia, RowDictionary<MediaRow> mediaRows, List<FileFacade> uncompressedFiles) 225 private void ManuallyAssignFiles(List<MediaTuple> mediaTable, IEnumerable<FileFacade> fileFacades, Dictionary<MediaTuple, List<FileFacade>> filesByCabinetMedia, Dictionary<int, MediaTuple> mediaRows, List<FileFacade> uncompressedFiles)
219 { 226 {
220 if (OutputType.Module != this.Output.Type) 227 if (mediaTable.Any())
221 { 228 {
222 if (null != mediaTable) 229 var cabinetMediaRows = new Dictionary<string, MediaTuple>(StringComparer.OrdinalIgnoreCase);
230 foreach (var mediaRow in mediaTable)
223 { 231 {
224 Dictionary<string, MediaRow> cabinetMediaRows = new Dictionary<string, MediaRow>(StringComparer.InvariantCultureIgnoreCase); 232 // If the Media row has a cabinet, make sure it is unique across all Media rows.
225 foreach (MediaRow mediaRow in mediaTable.Rows) 233 if (!String.IsNullOrEmpty(mediaRow.Cabinet))
226 { 234 {
227 // If the Media row has a cabinet, make sure it is unique across all Media rows. 235 if (cabinetMediaRows.TryGetValue(mediaRow.Cabinet, out var existingRow))
228 if (!String.IsNullOrEmpty(mediaRow.Cabinet))
229 { 236 {
230 MediaRow existingRow; 237 Messaging.Instance.OnMessage(WixErrors.DuplicateCabinetName(mediaRow.SourceLineNumbers, mediaRow.Cabinet));
231 if (cabinetMediaRows.TryGetValue(mediaRow.Cabinet, out existingRow)) 238 Messaging.Instance.OnMessage(WixErrors.DuplicateCabinetName2(existingRow.SourceLineNumbers, existingRow.Cabinet));
232 { 239 }
233 Messaging.Instance.OnMessage(WixErrors.DuplicateCabinetName(mediaRow.SourceLineNumbers, mediaRow.Cabinet)); 240 else
234 Messaging.Instance.OnMessage(WixErrors.DuplicateCabinetName2(existingRow.SourceLineNumbers, existingRow.Cabinet)); 241 {
235 } 242 cabinetMediaRows.Add(mediaRow.Cabinet, mediaRow);
236 else
237 {
238 cabinetMediaRows.Add(mediaRow.Cabinet, mediaRow);
239 }
240 } 243 }
241
242 mediaRows.Add(mediaRow);
243 } 244 }
245
246 mediaRows.Add(mediaRow.DiskId, mediaRow);
244 } 247 }
248 }
245 249
246 foreach (MediaRow mediaRow in mediaRows.Values) 250 foreach (var mediaRow in mediaRows.Values)
251 {
252 if (null != mediaRow.Cabinet)
247 { 253 {
248 if (null != mediaRow.Cabinet) 254 filesByCabinetMedia.Add(mediaRow, new List<FileFacade>());
249 {
250 filesByCabinetMedia.Add(mediaRow, new List<FileFacade>());
251 }
252 } 255 }
253 } 256 }
254 257
255 foreach (FileFacade facade in fileFacades) 258 foreach (FileFacade facade in fileFacades)
256 { 259 {
257 if (OutputType.Module == this.Output.Type) 260 if (!mediaRows.TryGetValue(facade.WixFile.DiskId, out var mediaRow))
258 { 261 {
259 filesByCabinetMedia[mergeModuleMediaRow].Add(facade); 262 Messaging.Instance.OnMessage(WixErrors.MissingMedia(facade.File.SourceLineNumbers, facade.WixFile.DiskId));
263 continue;
260 } 264 }
261 else
262 {
263 MediaRow mediaRow;
264 if (!mediaRows.TryGetValue(facade.WixFile.DiskId.ToString(CultureInfo.InvariantCulture), out mediaRow))
265 {
266 Messaging.Instance.OnMessage(WixErrors.MissingMedia(facade.File.SourceLineNumbers, facade.WixFile.DiskId));
267 continue;
268 }
269 265
270 // When building a product, if the current file is not to be compressed or if 266 // When building a product, if the current file is not to be compressed or if
271 // the package set not to be compressed, don't cab it. 267 // the package set not to be compressed, don't cab it.
272 if (OutputType.Product == this.Output.Type && 268 if (SectionType.Product == this.Section.Type &&
273 (!facade.File.Compressed.Value || 269 (!facade.File.Compressed.Value ||
274 (!facade.File.Compressed.HasValue && !this.FilesCompressed))) 270 (!facade.File.Compressed.HasValue && !this.FilesCompressed)))
271 {
272 uncompressedFiles.Add(facade);
273 }
274 else // file is marked compressed.
275 {
276 if (filesByCabinetMedia.TryGetValue(mediaRow, out var cabinetFiles))
275 { 277 {
276 uncompressedFiles.Add(facade); 278 cabinetFiles.Add(facade);
277 } 279 }
278 else // file is marked compressed. 280 else
279 { 281 {
280 List<FileFacade> cabinetFiles; 282 Messaging.Instance.OnMessage(WixErrors.ExpectedMediaCabinet(facade.File.SourceLineNumbers, facade.File.File, facade.WixFile.DiskId));
281 if (filesByCabinetMedia.TryGetValue(mediaRow, out cabinetFiles))
282 {
283 cabinetFiles.Add(facade);
284 }
285 else
286 {
287 Messaging.Instance.OnMessage(WixErrors.ExpectedMediaCabinet(facade.File.SourceLineNumbers, facade.File.File, facade.WixFile.DiskId));
288 }
289 } 283 }
290 } 284 }
291 } 285 }
@@ -297,17 +291,20 @@ namespace WixToolset.Core.WindowsInstaller.Databases
297 /// <param name="mediaTable"></param> 291 /// <param name="mediaTable"></param>
298 /// <param name="cabIndex"></param> 292 /// <param name="cabIndex"></param>
299 /// <returns></returns> 293 /// <returns></returns>
300 private MediaRow AddMediaRow(WixMediaTemplateRow mediaTemplateRow, Table mediaTable, int cabIndex) 294 private MediaTuple AddMediaRow(WixMediaTemplateTuple mediaTemplateRow, int cabIndex)
301 { 295 {
302 MediaRow currentMediaRow = (MediaRow)mediaTable.CreateRow(mediaTemplateRow.SourceLineNumbers); 296 var currentMediaRow = new MediaTuple(mediaTemplateRow.SourceLineNumbers, new Identifier(cabIndex, AccessModifier.Private));
303 currentMediaRow.DiskId = cabIndex; 297 currentMediaRow.DiskId = cabIndex;
304 currentMediaRow.Cabinet = String.Format(CultureInfo.InvariantCulture, this.CabinetNameTemplate, cabIndex); 298 currentMediaRow.Cabinet = String.Format(CultureInfo.InvariantCulture, this.CabinetNameTemplate, cabIndex);
305 299
306 Table wixMediaTable = this.Output.EnsureTable(this.TableDefinitions["WixMedia"]); 300 this.Section.Tuples.Add(currentMediaRow);
307 WixMediaRow row = (WixMediaRow)wixMediaTable.CreateRow(mediaTemplateRow.SourceLineNumbers); 301
308 row.DiskId = cabIndex; 302 var row = new WixMediaTuple(mediaTemplateRow.SourceLineNumbers, new Identifier(cabIndex, AccessModifier.Private));
303 row.DiskId_ = cabIndex;
309 row.CompressionLevel = mediaTemplateRow.CompressionLevel; 304 row.CompressionLevel = mediaTemplateRow.CompressionLevel;
310 305
306 this.Section.Tuples.Add(row);
307
311 return currentMediaRow; 308 return currentMediaRow;
312 } 309 }
313 } 310 }