1    	//  =========================================================================
2    	//  
3    	//                             INTEL CONFIDENTIAL
4    	//                            Copyright 2005 - 2015
5    	//                    Intel Corporation All Rights Reserved. 
6    	//  
7    	//  =========================================================================
8    	//  The source code contained or described herein and all documents 
9    	//  related to the source code ("Material") are owned by Intel Corporation 
10   	//  or its suppliers or licensors. Title to the Material remains with 
11   	//  Intel Corporation or its suppliers and licensors. The Material contains 
12   	//  trade secrets and proprietary and confidential information of Intel or 
13   	//  its suppliers and licensors. The Material is protected by worldwide 
14   	//  copyright and trade secret laws and treaty provisions. No part of the 
15   	//  Material may be used, copied, reproduced, modified, published, uploaded, 
16   	//  posted, transmitted, distributed, or disclosed in any way without Intel’s 
17   	//  prior express written permission.
18   	//  
19   	//  No license under any patent, copyright, trade secret or other intellectual 
20   	//  property right is granted to or conferred upon you by disclosure or 
21   	//  delivery of the Materials, either expressly, by implication, inducement, 
22   	//  estoppel or otherwise. Any license under such intellectual property rights 
23   	//  must be express and approved by Intel in writing.
24   	//  ==========================================================================
25   	
26   	using System;
27   	using System.Collections.Generic;
28   	using System.Diagnostics;
29   	using System.IO;
30   	using System.Linq;
31   	using System.Reflection;
32   	using System.Text;
33   	using System.Threading;
34   	using Microsoft.Deployment.Compression;
35   	using Microsoft.Deployment.Compression.Cab;
36   	using Microsoft.Tools.WindowsInstallerXml;
37   	using Microsoft.Tools.WindowsInstallerXml.Bootstrapper;
38   	using SysProcess = System.Diagnostics.Process;
39   	
40   	namespace Intel.Deployment.Bootstrapper.Models
41   	{
42   		internal class ExtractModel : BaseModel
43   		{
44   			#region Events
45   			public event EventHandler<ProgressEventArgs> Progress;
46   			public event EventHandler<SuccessEventArgs> ExtractComplete;
47   			#endregion
48   	
49   			#region Fields
50   			private string _BundleExe;
51   			private string _BAAssemblyLocation;
52   			private string _PayloadLocation;
53   			#endregion
54   	
55   			#region Properties
56   			private string BundleExe
57   			{
58   				get
59   				{
60   					if (this._BundleExe == null)
61   					{
62   						this._BundleExe = SysProcess.GetCurrentProcess().MainModule.FileName;
63   						Log.WriteLine("Retreived bundle exe file location: " + this._BundleExe);
64   					}
65   					return this._BundleExe;
66   				}
67   			}
68   	
69   			private string BAAssemblyLocation
70   			{
71   				get
72   				{
73   					if (this._BAAssemblyLocation == null)
74   					{
75   						this._BAAssemblyLocation = Assembly.GetExecutingAssembly().Location;
76   						Log.WriteLine("Retreived MBA assembly file location: " + this._BAAssemblyLocation);
77   					}
78   					return this._BAAssemblyLocation;
79   				}
80   			}
81   			private string PayloadLocation
82   			{
83   				get
84   				{
85   					if (this._PayloadLocation == null)
86   					{
(2) Event example_checked: Example 1: "System.IO.Directory.GetParent(this.BAAssemblyLocation)" has its value checked in "System.IO.Directory.GetParent(this.BAAssemblyLocation)".
Also see events: [returned_null][null_method_call]
87   						this._PayloadLocation = Directory.GetParent(this.BAAssemblyLocation)?.FullName;
88   						Log.WriteLine("Retreived payload location: " + this._PayloadLocation);
89   					}
90   					return this._PayloadLocation;
91   				}
92   			}
93   			#endregion
94   	
95   			#region Methods - Extract
96   			public void BeginExtract(string location)
97   			{
98   				var thread = new Thread(() =>
99   					{
100  						try { this.Extract(location); }
101  						catch (Exception ex) { Log.WriteException(ex); }
102  					});
103  				thread.Start();
104  			}
105  			public void Extract(string location)
106  			{
107  				int error = this.DoExtract(new Folder(location));
108  	
109  				this.OnExtractComplete(error);
110  			}
111  			private int DoExtract(Folder folder)
112  			{
113  				try
114  				{
115  					//Unbind the msi packages to a temporary folder.
116  					using (var unbindFolder = UnbindToTempFolder())
117  					{
118  						var msiFolder = unbindFolder.GetSubfolder("AttachedContainer");
119  	
120  						foreach (var mapping in GetExtractionMappings(msiFolder))
121  						{
122  							var destination = folder.GetSubfolder(mapping.Destination);
123  	
124  							string driversCabPath = Path.Combine(msiFolder.Path, mapping.CabFile);
125  	
126  							RunExtractionAndDeleteCab(driversCabPath, destination.Path);
127  						}
128  					}
129  	
130  					return Win32Error.Success;
131  				}
132  				catch (Exception exc)
133  				{
134  					Log.WriteException(exc);
135  					return Error.Extract;
136  				}
137  			}
138  			#endregion
139  	
140  			#region Methods - ExtractMup
141  			public void BeginExtractMup(string location)
142  			{
143  				var thread = new Thread(() =>
144  				{
145  					try { this.ExtractMup(location); }
146  					catch (Exception ex) { Log.WriteException(ex); }
147  				});
148  				thread.Start();
149  			}
150  			public void ExtractMup(string location)
151  			{
152  				int error = this.DoExtractMup(new Folder(location));
153  	
154  				this.OnExtractComplete(error);
155  			}
156  	        private int DoExtractMup(Folder folder)
157  	        {
158  	            try
159  	            {
160  	                using (var tempFolder = TempFolder.Create())
161  	                {
162  	                    DoExtract(tempFolder);
163  	
164  	                    var allInfs = Directory.GetFiles(tempFolder.Path, "*.inf", SearchOption.AllDirectories);
165  	                    var MupMapping = Intel.Tools.MSBuildTasks.CreateMup.MupHelper.GetMupMapping(allInfs);
166  	
167  	                    foreach(var mupEntry in MupMapping)
168  	                    {
169  	                        string destinationPath = Path.Combine(folder.Path, mupEntry.Value);
170  	                        Directory.CreateDirectory(Path.GetDirectoryName(destinationPath));
171  	                        File.Copy(mupEntry.Key, destinationPath, true);
172  	                    }
173  	                }
174  	
175  	                return Win32Error.Success;
176  	            }
177  	            catch (Exception exc)
178  	            {
179  	                Log.WriteException(exc);
180  	                return Error.Extract;
181  	            }
182  	        }
183  			#endregion
184  	
185  			#region Methods - Event Handlers
186  			private void OnProgress(object sender, ArchiveProgressEventArgs e)
187  			{
188  				lock (this)
189  				{
190  					try
191  					{
192  						this.OnProgress((int)(100 * ((double)e.FileBytesProcessed / (double)e.TotalFileBytes)));
193  					}
194  					//Catch any exceptions, progress bars can safely be ignored.
195  					catch { }
196  				}
197  			}
198  	
199  			private void OnProgress(int progress)
200  			{
201  				var handler = this.Progress;
202  				if (handler != null)
203  				{
204  					handler(this, new ProgressEventArgs(progress, progress));
205  				}
206  			}
207  	
208  			private void OnExtractComplete(int error)
209  			{
210  				Log.WriteLine("Extraction complete. error: '{0}'", error);
211  	
212  				var handler = this.ExtractComplete;
213  				if (handler != null)
214  				{
215  					handler(this, new SuccessEventArgs(error));
216  				}
217  			}
218  			#endregion
219  	
220  			#region Methods - Helpers
221  			private TempFolder UnbindToTempFolder()
222  			{
223  				//Get a temporary location.
224  				var tempFolder = TempFolder.Create();
225  				Log.WriteLine("Unbinding to temporary folder: " + tempFolder.Path);
226  				string attachedContainerSource = this.Engine.StringVariables["WixBundleOriginalSource"];
227  				Log.WriteLine("Unbinding from: " + attachedContainerSource);
228  	
229  				//Extract to the temporary location.
230  				var unbinder = new Unbinder();
231  				unbinder.Unbind(attachedContainerSource, OutputType.Bundle, tempFolder.Path);
232  				unbinder.DeleteTempFiles();
233  	
234  				Log.WriteLine("Completed unbinding.");
235  				return tempFolder;
236  			}
237  	
238  			private List<ExtractionMapping> GetExtractionMappings(Folder msiFolder)
239  			{
240  				string key, value,
241  					valueDest, valueCab, valueCondition;
242  				string[] valueSplit,
243  					msiFiles = msiFolder.GetFiles(false);
244  				var list = new List<ExtractionMapping>();
245  	
246  				foreach (var msiFile in msiFiles)
247  				{
248  					key = string.Format("IIF_ExtractionMapping_{0}", Path.GetFileName(msiFile));
249  	
250  					if (this.Engine.StringVariables.Contains(key))
251  					{
252  						value = this.Engine.StringVariables[key];
253  						valueSplit = value.Split(new[] { ';' });
254  	
255  						if (valueSplit.Length != 3 || string.IsNullOrEmpty(valueSplit[1]))
256  						{
257  							throw new Exception("Incorrectly formed extraction mapping: " + value);
258  						}
259  	
260  						valueDest      = valueSplit[0].Trim();
261  						valueCab       = valueSplit[1].Trim();
262  						valueCondition = valueSplit[2].Trim();
263  	
264  						if (string.IsNullOrEmpty(valueCondition)) valueCondition = "1"; //True
265  	
266  						if (this.Engine.EvaluateCondition(valueCondition))
267  						{
268  							list.Add(new ExtractionMapping(msiFile, valueDest, valueCab));
269  						}
270  					}
271  				}
272  	
273  				return list;
274  			}
275  	
276  			private void RunExtractionAndDeleteCab(string cabFile, string destination)
277  			{
278  				//If the driver cab file exists...
279  				if (File.Exists(cabFile))
280  				{
281  					Log.WriteLine("Unpacking cab: " + cabFile);
282  					var cabInfo = new CabInfo(cabFile);
283  					cabInfo.Unpack(destination, OnProgress);
284  	
285  					Log.WriteLine("Deleting file: " + cabFile);
286  					File.Delete(cabFile);
287  				}
288  				else
289  				{
290  					//...otherwise, extract the drivers from the msi database file as though it is the cab itself.
291  					throw new FileNotFoundException("Drivers cab file not found: " + cabFile);
292  				}
293  			}
294  	
295  			private struct ExtractionMapping
296  			{
297  				public string MsiFile;
298  				public string Destination;
299  				public string CabFile;
300  	
301  				public ExtractionMapping(string msiFile, string destination, string cabFile)
302  				{
303  					this.MsiFile = msiFile;
304  					this.Destination = destination;
305  					this.CabFile = cabFile;
306  				}
307  			}
308  			#endregion
309  		}
310  	}
311