diff options
Diffstat (limited to 'src/WixToolset.Core.Burn/Bundles/BurnReader.cs')
-rw-r--r-- | src/WixToolset.Core.Burn/Bundles/BurnReader.cs | 220 |
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 | |||
3 | namespace 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 | } | ||