aboutsummaryrefslogtreecommitdiff
path: root/src/WixToolset.Core.Burn/Bundles/BurnReader.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/WixToolset.Core.Burn/Bundles/BurnReader.cs')
-rw-r--r--src/WixToolset.Core.Burn/Bundles/BurnReader.cs220
1 files changed, 220 insertions, 0 deletions
diff --git a/src/WixToolset.Core.Burn/Bundles/BurnReader.cs b/src/WixToolset.Core.Burn/Bundles/BurnReader.cs
new file mode 100644
index 00000000..261ef7b4
--- /dev/null
+++ b/src/WixToolset.Core.Burn/Bundles/BurnReader.cs
@@ -0,0 +1,220 @@
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.Core.Burn.Bundles
4{
5 using System;
6 using System.Collections;
7 using System.Collections.Generic;
8 using System.IO;
9 using System.Xml;
10 using WixToolset.Core.Cab;
11
12 /// <summary>
13 /// Burn PE reader for the WiX toolset.
14 /// </summary>
15 /// <remarks>This class encapsulates reading from a stub EXE with containers attached
16 /// for dissecting bundled/chained setup packages.</remarks>
17 /// <example>
18 /// using (BurnReader reader = BurnReader.Open(fileExe, this.core, guid))
19 /// {
20 /// reader.ExtractUXContainer(file1, tempFolder);
21 /// }
22 /// </example>
23 internal class BurnReader : BurnCommon
24 {
25 private bool disposed;
26
27 private bool invalidBundle;
28 private BinaryReader binaryReader;
29 private List<DictionaryEntry> attachedContainerPayloadNames;
30
31 /// <summary>
32 /// Creates a BurnReader for reading a PE file.
33 /// </summary>
34 /// <param name="fileExe">File to read.</param>
35 private BurnReader(string fileExe)
36 : base(fileExe)
37 {
38 this.attachedContainerPayloadNames = new List<DictionaryEntry>();
39 }
40
41 /// <summary>
42 /// Gets the underlying stream.
43 /// </summary>
44 public Stream Stream
45 {
46 get
47 {
48 return (null != this.binaryReader) ? this.binaryReader.BaseStream : null;
49 }
50 }
51
52 internal static BurnReader Open(object inputFilePath)
53 {
54 throw new NotImplementedException();
55 }
56
57 /// <summary>
58 /// Opens a Burn reader.
59 /// </summary>
60 /// <param name="fileExe">Path to file.</param>
61 /// <returns>Burn reader.</returns>
62 public static BurnReader Open(string fileExe)
63 {
64 BurnReader reader = new BurnReader(fileExe);
65
66 reader.binaryReader = new BinaryReader(File.Open(fileExe, FileMode.Open, FileAccess.Read, FileShare.Read | FileShare.Delete));
67 if (!reader.Initialize(reader.binaryReader))
68 {
69 reader.invalidBundle = true;
70 }
71
72 return reader;
73 }
74
75 /// <summary>
76 /// Gets the UX container from the exe and extracts its contents to the output directory.
77 /// </summary>
78 /// <param name="outputDirectory">Directory to write extracted files to.</param>
79 /// <returns>True if successful, false otherwise</returns>
80 public bool ExtractUXContainer(string outputDirectory, string tempDirectory)
81 {
82 // No UX container to extract
83 if (this.UXAddress == 0 || this.UXSize == 0)
84 {
85 return false;
86 }
87
88 if (this.invalidBundle)
89 {
90 return false;
91 }
92
93 Directory.CreateDirectory(outputDirectory);
94 string tempCabPath = Path.Combine(tempDirectory, "ux.cab");
95 string manifestOriginalPath = Path.Combine(outputDirectory, "0");
96 string manifestPath = Path.Combine(outputDirectory, "manifest.xml");
97
98 this.binaryReader.BaseStream.Seek(this.UXAddress, SeekOrigin.Begin);
99 using (Stream tempCab = File.Open(tempCabPath, FileMode.Create, FileAccess.Write))
100 {
101 BurnCommon.CopyStream(this.binaryReader.BaseStream, tempCab, (int)this.UXSize);
102 }
103
104 using (var extract = new WixExtractCab())
105 {
106 extract.Extract(tempCabPath, outputDirectory);
107 }
108
109 Directory.CreateDirectory(Path.GetDirectoryName(manifestPath));
110 File.Delete(manifestPath);
111 File.Move(manifestOriginalPath, manifestPath);
112
113 XmlDocument document = new XmlDocument();
114 document.Load(manifestPath);
115 XmlNamespaceManager namespaceManager = new XmlNamespaceManager(document.NameTable);
116 namespaceManager.AddNamespace("burn", BurnCommon.BurnNamespace);
117 XmlNodeList uxPayloads = document.SelectNodes("/burn:BurnManifest/burn:UX/burn:Payload", namespaceManager);
118 XmlNodeList payloads = document.SelectNodes("/burn:BurnManifest/burn:Payload", namespaceManager);
119
120 foreach (XmlNode uxPayload in uxPayloads)
121 {
122 XmlNode sourcePathNode = uxPayload.Attributes.GetNamedItem("SourcePath");
123 XmlNode filePathNode = uxPayload.Attributes.GetNamedItem("FilePath");
124
125 string sourcePath = Path.Combine(outputDirectory, sourcePathNode.Value);
126 string destinationPath = Path.Combine(outputDirectory, filePathNode.Value);
127
128 Directory.CreateDirectory(Path.GetDirectoryName(destinationPath));
129 File.Delete(destinationPath);
130 File.Move(sourcePath, destinationPath);
131 }
132
133 foreach (XmlNode payload in payloads)
134 {
135 XmlNode sourcePathNode = payload.Attributes.GetNamedItem("SourcePath");
136 XmlNode filePathNode = payload.Attributes.GetNamedItem("FilePath");
137 XmlNode packagingNode = payload.Attributes.GetNamedItem("Packaging");
138
139 string sourcePath = sourcePathNode.Value;
140 string destinationPath = filePathNode.Value;
141 string packaging = packagingNode.Value;
142
143 if (packaging.Equals("embedded", StringComparison.OrdinalIgnoreCase))
144 {
145 this.attachedContainerPayloadNames.Add(new DictionaryEntry(sourcePath, destinationPath));
146 }
147 }
148
149 return true;
150 }
151
152 internal void ExtractUXContainer(string uxExtractPath, object intermediateFolder)
153 {
154 throw new NotImplementedException();
155 }
156
157 /// <summary>
158 /// Gets the attached container from the exe and extracts its contents to the output directory.
159 /// </summary>
160 /// <param name="outputDirectory">Directory to write extracted files to.</param>
161 /// <returns>True if successful, false otherwise</returns>
162 public bool ExtractAttachedContainer(string outputDirectory, string tempDirectory)
163 {
164 // No attached container to extract
165 if (this.AttachedContainerAddress == 0 || this.AttachedContainerSize == 0)
166 {
167 return false;
168 }
169
170 if (this.invalidBundle)
171 {
172 return false;
173 }
174
175 Directory.CreateDirectory(outputDirectory);
176 string tempCabPath = Path.Combine(tempDirectory, "attached.cab");
177
178 this.binaryReader.BaseStream.Seek(this.AttachedContainerAddress, SeekOrigin.Begin);
179 using (Stream tempCab = File.Open(tempCabPath, FileMode.Create, FileAccess.Write))
180 {
181 BurnCommon.CopyStream(this.binaryReader.BaseStream, tempCab, (int)this.AttachedContainerSize);
182 }
183
184 using (WixExtractCab extract = new WixExtractCab())
185 {
186 extract.Extract(tempCabPath, outputDirectory);
187 }
188
189 foreach (DictionaryEntry entry in this.attachedContainerPayloadNames)
190 {
191 string sourcePath = Path.Combine(outputDirectory, (string)entry.Key);
192 string destinationPath = Path.Combine(outputDirectory, (string)entry.Value);
193
194 Directory.CreateDirectory(Path.GetDirectoryName(destinationPath));
195 File.Delete(destinationPath);
196 File.Move(sourcePath, destinationPath);
197 }
198
199 return true;
200 }
201
202 /// <summary>
203 /// Dispose object.
204 /// </summary>
205 /// <param name="disposing">True when releasing managed objects.</param>
206 protected override void Dispose(bool disposing)
207 {
208 if (!this.disposed)
209 {
210 if (disposing && this.binaryReader != null)
211 {
212 this.binaryReader.Close();
213 this.binaryReader = null;
214 }
215
216 this.disposed = true;
217 }
218 }
219 }
220}