diff options
Diffstat (limited to 'src/WixToolset.Core.WindowsInstaller/Bind/CreateCabinetsCommand.cs')
-rw-r--r-- | src/WixToolset.Core.WindowsInstaller/Bind/CreateCabinetsCommand.cs | 499 |
1 files changed, 499 insertions, 0 deletions
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/CreateCabinetsCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/CreateCabinetsCommand.cs new file mode 100644 index 00000000..02015744 --- /dev/null +++ b/src/WixToolset.Core.WindowsInstaller/Bind/CreateCabinetsCommand.cs | |||
@@ -0,0 +1,499 @@ | |||
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.Databases | ||
4 | { | ||
5 | using System; | ||
6 | using System.Collections.Generic; | ||
7 | using System.Globalization; | ||
8 | using System.IO; | ||
9 | using System.Linq; | ||
10 | using System.Runtime.InteropServices; | ||
11 | using System.Threading; | ||
12 | using WixToolset.Core.Bind; | ||
13 | using WixToolset.Core.WindowsInstaller.Bind; | ||
14 | using WixToolset.Data; | ||
15 | using WixToolset.Data.Bind; | ||
16 | using WixToolset.Data.Rows; | ||
17 | using WixToolset.Extensibility; | ||
18 | |||
19 | /// <summary> | ||
20 | /// Creates cabinet files. | ||
21 | /// </summary> | ||
22 | internal class CreateCabinetsCommand | ||
23 | { | ||
24 | public const int DefaultMaximumUncompressedMediaSize = 200; // Default value is 200 MB | ||
25 | public const int MaxValueOfMaxCabSizeForLargeFileSplitting = 2 * 1024; // 2048 MB (i.e. 2 GB) | ||
26 | |||
27 | private List<FileTransfer> fileTransfers; | ||
28 | |||
29 | private FileSplitCabNamesCallback newCabNamesCallBack; | ||
30 | |||
31 | private Dictionary<string, string> lastCabinetAddedToMediaTable; // Key is First Cabinet Name, Value is Last Cabinet Added in the Split Sequence | ||
32 | |||
33 | public CreateCabinetsCommand() | ||
34 | { | ||
35 | this.fileTransfers = new List<FileTransfer>(); | ||
36 | |||
37 | this.newCabNamesCallBack = this.NewCabNamesCallBack; | ||
38 | } | ||
39 | |||
40 | /// <summary> | ||
41 | /// Sets the number of threads to use for cabinet creation. | ||
42 | /// </summary> | ||
43 | public int CabbingThreadCount { private get; set; } | ||
44 | |||
45 | public string CabCachePath { private get; set; } | ||
46 | |||
47 | public string TempFilesLocation { private get; set; } | ||
48 | |||
49 | /// <summary> | ||
50 | /// Sets the default compression level to use for cabinets | ||
51 | /// that don't have their compression level explicitly set. | ||
52 | /// </summary> | ||
53 | public CompressionLevel DefaultCompressionLevel { private get; set; } | ||
54 | |||
55 | public IEnumerable<IWindowsInstallerBackendExtension> BackendExtensions { private get; set; } | ||
56 | |||
57 | public Output Output { private get; set; } | ||
58 | |||
59 | public string LayoutDirectory { private get; set; } | ||
60 | |||
61 | public bool Compressed { private get; set; } | ||
62 | |||
63 | public Dictionary<MediaRow, IEnumerable<FileFacade>> FileRowsByCabinet { private get; set; } | ||
64 | |||
65 | public Func<MediaRow, string, string, string> ResolveMedia { private get; set; } | ||
66 | |||
67 | public TableDefinitionCollection TableDefinitions { private get; set; } | ||
68 | |||
69 | public Table WixMediaTable { private get; set; } | ||
70 | |||
71 | public IEnumerable<FileTransfer> FileTransfers => this.fileTransfers; | ||
72 | |||
73 | /// <param name="output">Output to generate image for.</param> | ||
74 | /// <param name="fileTransfers">Array of files to be transfered.</param> | ||
75 | /// <param name="layoutDirectory">The directory in which the image should be layed out.</param> | ||
76 | /// <param name="compressed">Flag if source image should be compressed.</param> | ||
77 | /// <returns>The uncompressed file rows.</returns> | ||
78 | public void Execute() | ||
79 | { | ||
80 | RowDictionary<WixMediaRow> wixMediaRows = new RowDictionary<WixMediaRow>(this.WixMediaTable); | ||
81 | |||
82 | this.lastCabinetAddedToMediaTable = new Dictionary<string, string>(); | ||
83 | |||
84 | this.SetCabbingThreadCount(); | ||
85 | |||
86 | // Send Binder object to Facilitate NewCabNamesCallBack Callback | ||
87 | CabinetBuilder cabinetBuilder = new CabinetBuilder(this.CabbingThreadCount, Marshal.GetFunctionPointerForDelegate(this.newCabNamesCallBack)); | ||
88 | |||
89 | // Supply Compile MediaTemplate Attributes to Cabinet Builder | ||
90 | int MaximumCabinetSizeForLargeFileSplitting; | ||
91 | int MaximumUncompressedMediaSize; | ||
92 | this.GetMediaTemplateAttributes(out MaximumCabinetSizeForLargeFileSplitting, out MaximumUncompressedMediaSize); | ||
93 | cabinetBuilder.MaximumCabinetSizeForLargeFileSplitting = MaximumCabinetSizeForLargeFileSplitting; | ||
94 | cabinetBuilder.MaximumUncompressedMediaSize = MaximumUncompressedMediaSize; | ||
95 | |||
96 | foreach (var entry in this.FileRowsByCabinet) | ||
97 | { | ||
98 | MediaRow mediaRow = entry.Key; | ||
99 | IEnumerable<FileFacade> files = entry.Value; | ||
100 | CompressionLevel compressionLevel = this.DefaultCompressionLevel; | ||
101 | |||
102 | WixMediaRow wixMediaRow = null; | ||
103 | string mediaLayoutFolder = null; | ||
104 | |||
105 | if (wixMediaRows.TryGetValue(mediaRow.GetKey(), out wixMediaRow)) | ||
106 | { | ||
107 | mediaLayoutFolder = wixMediaRow.Layout; | ||
108 | |||
109 | if (wixMediaRow.CompressionLevel.HasValue) | ||
110 | { | ||
111 | compressionLevel = wixMediaRow.CompressionLevel.Value; | ||
112 | } | ||
113 | } | ||
114 | |||
115 | string cabinetDir = this.ResolveMedia(mediaRow, mediaLayoutFolder, this.LayoutDirectory); | ||
116 | |||
117 | CabinetWorkItem cabinetWorkItem = this.CreateCabinetWorkItem(this.Output, cabinetDir, mediaRow, compressionLevel, files, this.fileTransfers); | ||
118 | if (null != cabinetWorkItem) | ||
119 | { | ||
120 | cabinetBuilder.Enqueue(cabinetWorkItem); | ||
121 | } | ||
122 | } | ||
123 | |||
124 | // stop processing if an error previously occurred | ||
125 | if (Messaging.Instance.EncounteredError) | ||
126 | { | ||
127 | return; | ||
128 | } | ||
129 | |||
130 | // create queued cabinets with multiple threads | ||
131 | cabinetBuilder.CreateQueuedCabinets(); | ||
132 | if (Messaging.Instance.EncounteredError) | ||
133 | { | ||
134 | return; | ||
135 | } | ||
136 | } | ||
137 | |||
138 | /// <summary> | ||
139 | /// Sets the thead count to the number of processors if the current thread count is set to 0. | ||
140 | /// </summary> | ||
141 | /// <remarks>The thread count value must be greater than 0 otherwise and exception will be thrown.</remarks> | ||
142 | private void SetCabbingThreadCount() | ||
143 | { | ||
144 | // default the number of cabbing threads to the number of processors if it wasn't specified | ||
145 | if (0 == this.CabbingThreadCount) | ||
146 | { | ||
147 | string numberOfProcessors = System.Environment.GetEnvironmentVariable("NUMBER_OF_PROCESSORS"); | ||
148 | |||
149 | try | ||
150 | { | ||
151 | if (null != numberOfProcessors) | ||
152 | { | ||
153 | this.CabbingThreadCount = Convert.ToInt32(numberOfProcessors, CultureInfo.InvariantCulture.NumberFormat); | ||
154 | |||
155 | if (0 >= this.CabbingThreadCount) | ||
156 | { | ||
157 | throw new WixException(WixErrors.IllegalEnvironmentVariable("NUMBER_OF_PROCESSORS", numberOfProcessors)); | ||
158 | } | ||
159 | } | ||
160 | else // default to 1 if the environment variable is not set | ||
161 | { | ||
162 | this.CabbingThreadCount = 1; | ||
163 | } | ||
164 | |||
165 | Messaging.Instance.OnMessage(WixVerboses.SetCabbingThreadCount(this.CabbingThreadCount.ToString())); | ||
166 | } | ||
167 | catch (ArgumentException) | ||
168 | { | ||
169 | throw new WixException(WixErrors.IllegalEnvironmentVariable("NUMBER_OF_PROCESSORS", numberOfProcessors)); | ||
170 | } | ||
171 | catch (FormatException) | ||
172 | { | ||
173 | throw new WixException(WixErrors.IllegalEnvironmentVariable("NUMBER_OF_PROCESSORS", numberOfProcessors)); | ||
174 | } | ||
175 | } | ||
176 | } | ||
177 | |||
178 | |||
179 | /// <summary> | ||
180 | /// Creates a work item to create a cabinet. | ||
181 | /// </summary> | ||
182 | /// <param name="output">Output for the current database.</param> | ||
183 | /// <param name="cabinetDir">Directory to create cabinet in.</param> | ||
184 | /// <param name="mediaRow">MediaRow containing information about the cabinet.</param> | ||
185 | /// <param name="fileFacades">Collection of files in this cabinet.</param> | ||
186 | /// <param name="fileTransfers">Array of files to be transfered.</param> | ||
187 | /// <returns>created CabinetWorkItem object</returns> | ||
188 | private CabinetWorkItem CreateCabinetWorkItem(Output output, string cabinetDir, MediaRow mediaRow, CompressionLevel compressionLevel, IEnumerable<FileFacade> fileFacades, List<FileTransfer> fileTransfers) | ||
189 | { | ||
190 | CabinetWorkItem cabinetWorkItem = null; | ||
191 | string tempCabinetFileX = Path.Combine(this.TempFilesLocation, mediaRow.Cabinet); | ||
192 | |||
193 | // check for an empty cabinet | ||
194 | if (!fileFacades.Any()) | ||
195 | { | ||
196 | string cabinetName = mediaRow.Cabinet; | ||
197 | |||
198 | // remove the leading '#' from the embedded cabinet name to make the warning easier to understand | ||
199 | if (cabinetName.StartsWith("#", StringComparison.Ordinal)) | ||
200 | { | ||
201 | cabinetName = cabinetName.Substring(1); | ||
202 | } | ||
203 | |||
204 | // If building a patch, remind them to run -p for torch. | ||
205 | if (OutputType.Patch == output.Type) | ||
206 | { | ||
207 | Messaging.Instance.OnMessage(WixWarnings.EmptyCabinet(mediaRow.SourceLineNumbers, cabinetName, true)); | ||
208 | } | ||
209 | else | ||
210 | { | ||
211 | Messaging.Instance.OnMessage(WixWarnings.EmptyCabinet(mediaRow.SourceLineNumbers, cabinetName)); | ||
212 | } | ||
213 | } | ||
214 | |||
215 | var cabinetResolver = new CabinetResolver(this.CabCachePath, this.BackendExtensions); | ||
216 | |||
217 | ResolvedCabinet resolvedCabinet = cabinetResolver.ResolveCabinet(tempCabinetFileX, fileFacades); | ||
218 | |||
219 | // create a cabinet work item if it's not being skipped | ||
220 | if (CabinetBuildOption.BuildAndCopy == resolvedCabinet.BuildOption || CabinetBuildOption.BuildAndMove == resolvedCabinet.BuildOption) | ||
221 | { | ||
222 | int maxThreshold = 0; // default to the threshold for best smartcabbing (makes smallest cabinet). | ||
223 | |||
224 | cabinetWorkItem = new CabinetWorkItem(fileFacades, resolvedCabinet.Path, maxThreshold, compressionLevel/*, this.FileManager*/); | ||
225 | } | ||
226 | else // reuse the cabinet from the cabinet cache. | ||
227 | { | ||
228 | Messaging.Instance.OnMessage(WixVerboses.ReusingCabCache(mediaRow.SourceLineNumbers, mediaRow.Cabinet, resolvedCabinet.Path)); | ||
229 | |||
230 | try | ||
231 | { | ||
232 | // Ensure the cached cabinet timestamp is current to prevent perpetual incremental builds. The | ||
233 | // problematic scenario goes like this. Imagine two cabinets in the cache. Update a file that | ||
234 | // goes into one of the cabinets. One cabinet will get rebuilt, the other will be copied from | ||
235 | // the cache. Now the file (an input) has a newer timestamp than the reused cabient (an output) | ||
236 | // causing the project to look like it perpetually needs a rebuild until all of the reused | ||
237 | // cabinets get newer timestamps. | ||
238 | File.SetLastWriteTime(resolvedCabinet.Path, DateTime.Now); | ||
239 | } | ||
240 | catch (Exception e) | ||
241 | { | ||
242 | Messaging.Instance.OnMessage(WixWarnings.CannotUpdateCabCache(mediaRow.SourceLineNumbers, resolvedCabinet.Path, e.Message)); | ||
243 | } | ||
244 | } | ||
245 | |||
246 | if (mediaRow.Cabinet.StartsWith("#", StringComparison.Ordinal)) | ||
247 | { | ||
248 | Table streamsTable = output.EnsureTable(this.TableDefinitions["_Streams"]); | ||
249 | |||
250 | Row streamRow = streamsTable.CreateRow(mediaRow.SourceLineNumbers); | ||
251 | streamRow[0] = mediaRow.Cabinet.Substring(1); | ||
252 | streamRow[1] = resolvedCabinet.Path; | ||
253 | } | ||
254 | else | ||
255 | { | ||
256 | string destinationPath = Path.Combine(cabinetDir, mediaRow.Cabinet); | ||
257 | FileTransfer transfer; | ||
258 | if (FileTransfer.TryCreate(resolvedCabinet.Path, destinationPath, CabinetBuildOption.BuildAndMove == resolvedCabinet.BuildOption, "Cabinet", mediaRow.SourceLineNumbers, out transfer)) | ||
259 | { | ||
260 | transfer.Built = true; | ||
261 | fileTransfers.Add(transfer); | ||
262 | } | ||
263 | } | ||
264 | |||
265 | return cabinetWorkItem; | ||
266 | } | ||
267 | |||
268 | //private ResolvedCabinet ResolveCabinet(string cabinetPath, IEnumerable<FileFacade> fileFacades) | ||
269 | //{ | ||
270 | // ResolvedCabinet resolved = null; | ||
271 | |||
272 | // List<BindFileWithPath> filesWithPath = fileFacades.Select(f => new BindFileWithPath() { Id = f.File.File, Path = f.WixFile.Source }).ToList(); | ||
273 | |||
274 | // foreach (var extension in this.BackendExtensions) | ||
275 | // { | ||
276 | // resolved = extension.ResolveCabinet(cabinetPath, filesWithPath); | ||
277 | // if (null != resolved) | ||
278 | // { | ||
279 | // break; | ||
280 | // } | ||
281 | // } | ||
282 | |||
283 | // return resolved; | ||
284 | //} | ||
285 | |||
286 | /// <summary> | ||
287 | /// Delegate for Cabinet Split Callback | ||
288 | /// </summary> | ||
289 | [UnmanagedFunctionPointer(CallingConvention.StdCall)] | ||
290 | internal delegate void FileSplitCabNamesCallback([MarshalAs(UnmanagedType.LPWStr)]string firstCabName, [MarshalAs(UnmanagedType.LPWStr)]string newCabName, [MarshalAs(UnmanagedType.LPWStr)]string fileToken); | ||
291 | |||
292 | /// <summary> | ||
293 | /// Call back to Add File Transfer for new Cab and add new Cab to Media table | ||
294 | /// This callback can come from Multiple Cabinet Builder Threads and so should be thread safe | ||
295 | /// This callback will not be called in case there is no File splitting. i.e. MaximumCabinetSizeForLargeFileSplitting was not authored | ||
296 | /// </summary> | ||
297 | /// <param name="firstCabName">The name of splitting cabinet without extention e.g. "cab1".</param> | ||
298 | /// <param name="newCabName">The name of the new cabinet that would be formed by splitting e.g. "cab1b.cab"</param> | ||
299 | /// <param name="fileToken">The file token of the first file present in the splitting cabinet</param> | ||
300 | internal void NewCabNamesCallBack([MarshalAs(UnmanagedType.LPWStr)]string firstCabName, [MarshalAs(UnmanagedType.LPWStr)]string newCabName, [MarshalAs(UnmanagedType.LPWStr)]string fileToken) | ||
301 | { | ||
302 | // Locking Mutex here as this callback can come from Multiple Cabinet Builder Threads | ||
303 | Mutex mutex = new Mutex(false, "WixCabinetSplitBinderCallback"); | ||
304 | try | ||
305 | { | ||
306 | if (!mutex.WaitOne(0, false)) // Check if you can get the lock | ||
307 | { | ||
308 | // Cound not get the Lock | ||
309 | Messaging.Instance.OnMessage(WixVerboses.CabinetsSplitInParallel()); | ||
310 | mutex.WaitOne(); // Wait on other thread | ||
311 | } | ||
312 | |||
313 | string firstCabinetName = firstCabName + ".cab"; | ||
314 | string newCabinetName = newCabName; | ||
315 | bool transferAdded = false; // Used for Error Handling | ||
316 | |||
317 | // Create File Transfer for new Cabinet using transfer of Base Cabinet | ||
318 | foreach (FileTransfer transfer in this.FileTransfers) | ||
319 | { | ||
320 | if (firstCabinetName.Equals(Path.GetFileName(transfer.Source), StringComparison.InvariantCultureIgnoreCase)) | ||
321 | { | ||
322 | string newCabSourcePath = Path.Combine(Path.GetDirectoryName(transfer.Source), newCabinetName); | ||
323 | string newCabTargetPath = Path.Combine(Path.GetDirectoryName(transfer.Destination), newCabinetName); | ||
324 | |||
325 | FileTransfer newTransfer; | ||
326 | if (FileTransfer.TryCreate(newCabSourcePath, newCabTargetPath, transfer.Move, "Cabinet", transfer.SourceLineNumbers, out newTransfer)) | ||
327 | { | ||
328 | newTransfer.Built = true; | ||
329 | this.fileTransfers.Add(newTransfer); | ||
330 | transferAdded = true; | ||
331 | break; | ||
332 | } | ||
333 | } | ||
334 | } | ||
335 | |||
336 | // Check if File Transfer was added | ||
337 | if (!transferAdded) | ||
338 | { | ||
339 | throw new WixException(WixErrors.SplitCabinetCopyRegistrationFailed(newCabinetName, firstCabinetName)); | ||
340 | } | ||
341 | |||
342 | // Add the new Cabinets to media table using LastSequence of Base Cabinet | ||
343 | Table mediaTable = this.Output.Tables["Media"]; | ||
344 | Table wixFileTable = this.Output.Tables["WixFile"]; | ||
345 | int diskIDForLastSplitCabAdded = 0; // The DiskID value for the first cab in this cabinet split chain | ||
346 | int lastSequenceForLastSplitCabAdded = 0; // The LastSequence value for the first cab in this cabinet split chain | ||
347 | bool lastSplitCabinetFound = false; // Used for Error Handling | ||
348 | |||
349 | string lastCabinetOfThisSequence = String.Empty; | ||
350 | // Get the Value of Last Cabinet Added in this split Sequence from Dictionary | ||
351 | if (!this.lastCabinetAddedToMediaTable.TryGetValue(firstCabinetName, out lastCabinetOfThisSequence)) | ||
352 | { | ||
353 | // If there is no value for this sequence, then use first Cabinet is the last one of this split sequence | ||
354 | lastCabinetOfThisSequence = firstCabinetName; | ||
355 | } | ||
356 | |||
357 | foreach (MediaRow mediaRow in mediaTable.Rows) | ||
358 | { | ||
359 | // Get details for the Last Cabinet Added in this Split Sequence | ||
360 | if ((lastSequenceForLastSplitCabAdded == 0) && lastCabinetOfThisSequence.Equals(mediaRow.Cabinet, StringComparison.InvariantCultureIgnoreCase)) | ||
361 | { | ||
362 | lastSequenceForLastSplitCabAdded = mediaRow.LastSequence; | ||
363 | diskIDForLastSplitCabAdded = mediaRow.DiskId; | ||
364 | lastSplitCabinetFound = true; | ||
365 | } | ||
366 | |||
367 | // Check for Name Collision for the new Cabinet added | ||
368 | if (newCabinetName.Equals(mediaRow.Cabinet, StringComparison.InvariantCultureIgnoreCase)) | ||
369 | { | ||
370 | // Name Collision of generated Split Cabinet Name and user Specified Cab name for current row | ||
371 | throw new WixException(WixErrors.SplitCabinetNameCollision(newCabinetName, firstCabinetName)); | ||
372 | } | ||
373 | } | ||
374 | |||
375 | // Check if the last Split Cabinet was found in the Media Table | ||
376 | if (!lastSplitCabinetFound) | ||
377 | { | ||
378 | throw new WixException(WixErrors.SplitCabinetInsertionFailed(newCabinetName, firstCabinetName, lastCabinetOfThisSequence)); | ||
379 | } | ||
380 | |||
381 | // The new Row has to be inserted just after the last cab in this cabinet split chain according to DiskID Sort | ||
382 | // This is because the FDI Extract requires DiskID of Split Cabinets to be continuous. It Fails otherwise with | ||
383 | // Error 2350 (FDI Server Error) as next DiskID did not have the right split cabinet during extraction | ||
384 | MediaRow newMediaRow = (MediaRow)mediaTable.CreateRow(null); | ||
385 | newMediaRow.Cabinet = newCabinetName; | ||
386 | newMediaRow.DiskId = diskIDForLastSplitCabAdded + 1; // When Sorted with DiskID, this new Cabinet Row is an Insertion | ||
387 | newMediaRow.LastSequence = lastSequenceForLastSplitCabAdded; | ||
388 | |||
389 | // Now increment the DiskID for all rows that come after the newly inserted row to Ensure that DiskId is unique | ||
390 | foreach (MediaRow mediaRow in mediaTable.Rows) | ||
391 | { | ||
392 | // Check if this row comes after inserted row and it is not the new cabinet inserted row | ||
393 | if (mediaRow.DiskId >= newMediaRow.DiskId && !newCabinetName.Equals(mediaRow.Cabinet, StringComparison.InvariantCultureIgnoreCase)) | ||
394 | { | ||
395 | mediaRow.DiskId++; // Increment DiskID | ||
396 | } | ||
397 | } | ||
398 | |||
399 | // Now Increment DiskID for All files Rows so that they refer to the right Media Row | ||
400 | foreach (WixFileRow wixFileRow in wixFileTable.Rows) | ||
401 | { | ||
402 | // Check if this row comes after inserted row and if this row is not the file that has to go into the current cabinet | ||
403 | // This check will work as we have only one large file in every splitting cabinet | ||
404 | // If we want to support splitting cabinet with more large files we need to update this code | ||
405 | if (wixFileRow.DiskId >= newMediaRow.DiskId && !wixFileRow.File.Equals(fileToken, StringComparison.InvariantCultureIgnoreCase)) | ||
406 | { | ||
407 | wixFileRow.DiskId++; // Increment DiskID | ||
408 | } | ||
409 | } | ||
410 | |||
411 | // Update the Last Cabinet Added in the Split Sequence in Dictionary for future callback | ||
412 | this.lastCabinetAddedToMediaTable[firstCabinetName] = newCabinetName; | ||
413 | |||
414 | mediaTable.ValidateRows(); // Valdiates DiskDIs, throws Exception as Wix Error if validation fails | ||
415 | } | ||
416 | finally | ||
417 | { | ||
418 | // Releasing the Mutex here | ||
419 | mutex.ReleaseMutex(); | ||
420 | } | ||
421 | } | ||
422 | |||
423 | |||
424 | /// <summary> | ||
425 | /// Gets Compiler Values of MediaTemplate Attributes governing Maximum Cabinet Size after applying Environment Variable Overrides | ||
426 | /// </summary> | ||
427 | /// <param name="output">Output to generate image for.</param> | ||
428 | /// <param name="fileRows">The indexed file rows.</param> | ||
429 | private void GetMediaTemplateAttributes(out int maxCabSizeForLargeFileSplitting, out int maxUncompressedMediaSize) | ||
430 | { | ||
431 | // Get Environment Variable Overrides for MediaTemplate Attributes governing Maximum Cabinet Size | ||
432 | string mcslfsString = Environment.GetEnvironmentVariable("WIX_MCSLFS"); | ||
433 | string mumsString = Environment.GetEnvironmentVariable("WIX_MUMS"); | ||
434 | int maxCabSizeForLargeFileInMB = 0; | ||
435 | int maxPreCompressedSizeInMB = 0; | ||
436 | ulong testOverFlow = 0; | ||
437 | |||
438 | // Supply Compile MediaTemplate Attributes to Cabinet Builder | ||
439 | Table mediaTemplateTable = this.Output.Tables["WixMediaTemplate"]; | ||
440 | if (mediaTemplateTable != null) | ||
441 | { | ||
442 | WixMediaTemplateRow mediaTemplateRow = (WixMediaTemplateRow)mediaTemplateTable.Rows[0]; | ||
443 | |||
444 | // Get the Value for Max Cab Size for File Splitting | ||
445 | try | ||
446 | { | ||
447 | // Override authored mcslfs value if environment variable is authored. | ||
448 | if (!String.IsNullOrEmpty(mcslfsString)) | ||
449 | { | ||
450 | maxCabSizeForLargeFileInMB = Int32.Parse(mcslfsString); | ||
451 | } | ||
452 | else | ||
453 | { | ||
454 | maxCabSizeForLargeFileInMB = mediaTemplateRow.MaximumCabinetSizeForLargeFileSplitting; | ||
455 | } | ||
456 | testOverFlow = (ulong)maxCabSizeForLargeFileInMB * 1024 * 1024; | ||
457 | } | ||
458 | catch (FormatException) | ||
459 | { | ||
460 | throw new WixException(WixErrors.IllegalEnvironmentVariable("WIX_MCSLFS", mcslfsString)); | ||
461 | } | ||
462 | catch (OverflowException) | ||
463 | { | ||
464 | throw new WixException(WixErrors.MaximumCabinetSizeForLargeFileSplittingTooLarge(null, maxCabSizeForLargeFileInMB, MaxValueOfMaxCabSizeForLargeFileSplitting)); | ||
465 | } | ||
466 | |||
467 | try | ||
468 | { | ||
469 | // Override authored mums value if environment variable is authored. | ||
470 | if (!String.IsNullOrEmpty(mumsString)) | ||
471 | { | ||
472 | maxPreCompressedSizeInMB = Int32.Parse(mumsString); | ||
473 | } | ||
474 | else | ||
475 | { | ||
476 | maxPreCompressedSizeInMB = mediaTemplateRow.MaximumUncompressedMediaSize; | ||
477 | } | ||
478 | testOverFlow = (ulong)maxPreCompressedSizeInMB * 1024 * 1024; | ||
479 | } | ||
480 | catch (FormatException) | ||
481 | { | ||
482 | throw new WixException(WixErrors.IllegalEnvironmentVariable("WIX_MUMS", mumsString)); | ||
483 | } | ||
484 | catch (OverflowException) | ||
485 | { | ||
486 | throw new WixException(WixErrors.MaximumUncompressedMediaSizeTooLarge(null, maxPreCompressedSizeInMB)); | ||
487 | } | ||
488 | |||
489 | maxCabSizeForLargeFileSplitting = maxCabSizeForLargeFileInMB; | ||
490 | maxUncompressedMediaSize = maxPreCompressedSizeInMB; | ||
491 | } | ||
492 | else | ||
493 | { | ||
494 | maxCabSizeForLargeFileSplitting = 0; | ||
495 | maxUncompressedMediaSize = DefaultMaximumUncompressedMediaSize; | ||
496 | } | ||
497 | } | ||
498 | } | ||
499 | } | ||