From dbde9e7104b907bbbaea17e21247d8cafc8b3a4c Mon Sep 17 00:00:00 2001 From: Rob Mensching Date: Sat, 14 Oct 2017 16:12:07 -0700 Subject: Massive refactoring to introduce the concept of IBackend --- src/WixToolset.Core.Burn/Bundles/BurnReader.cs | 220 +++++++++++++++++++++++++ 1 file changed, 220 insertions(+) create mode 100644 src/WixToolset.Core.Burn/Bundles/BurnReader.cs (limited to 'src/WixToolset.Core.Burn/Bundles/BurnReader.cs') 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 @@ +// 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. + +namespace WixToolset.Core.Burn.Bundles +{ + using System; + using System.Collections; + using System.Collections.Generic; + using System.IO; + using System.Xml; + using WixToolset.Core.Cab; + + /// + /// Burn PE reader for the WiX toolset. + /// + /// This class encapsulates reading from a stub EXE with containers attached + /// for dissecting bundled/chained setup packages. + /// + /// using (BurnReader reader = BurnReader.Open(fileExe, this.core, guid)) + /// { + /// reader.ExtractUXContainer(file1, tempFolder); + /// } + /// + internal class BurnReader : BurnCommon + { + private bool disposed; + + private bool invalidBundle; + private BinaryReader binaryReader; + private List attachedContainerPayloadNames; + + /// + /// Creates a BurnReader for reading a PE file. + /// + /// File to read. + private BurnReader(string fileExe) + : base(fileExe) + { + this.attachedContainerPayloadNames = new List(); + } + + /// + /// Gets the underlying stream. + /// + public Stream Stream + { + get + { + return (null != this.binaryReader) ? this.binaryReader.BaseStream : null; + } + } + + internal static BurnReader Open(object inputFilePath) + { + throw new NotImplementedException(); + } + + /// + /// Opens a Burn reader. + /// + /// Path to file. + /// Burn reader. + public static BurnReader Open(string fileExe) + { + BurnReader reader = new BurnReader(fileExe); + + reader.binaryReader = new BinaryReader(File.Open(fileExe, FileMode.Open, FileAccess.Read, FileShare.Read | FileShare.Delete)); + if (!reader.Initialize(reader.binaryReader)) + { + reader.invalidBundle = true; + } + + return reader; + } + + /// + /// Gets the UX container from the exe and extracts its contents to the output directory. + /// + /// Directory to write extracted files to. + /// True if successful, false otherwise + public bool ExtractUXContainer(string outputDirectory, string tempDirectory) + { + // No UX container to extract + if (this.UXAddress == 0 || this.UXSize == 0) + { + return false; + } + + if (this.invalidBundle) + { + return false; + } + + Directory.CreateDirectory(outputDirectory); + string tempCabPath = Path.Combine(tempDirectory, "ux.cab"); + string manifestOriginalPath = Path.Combine(outputDirectory, "0"); + string manifestPath = Path.Combine(outputDirectory, "manifest.xml"); + + this.binaryReader.BaseStream.Seek(this.UXAddress, SeekOrigin.Begin); + using (Stream tempCab = File.Open(tempCabPath, FileMode.Create, FileAccess.Write)) + { + BurnCommon.CopyStream(this.binaryReader.BaseStream, tempCab, (int)this.UXSize); + } + + using (var extract = new WixExtractCab()) + { + extract.Extract(tempCabPath, outputDirectory); + } + + Directory.CreateDirectory(Path.GetDirectoryName(manifestPath)); + File.Delete(manifestPath); + File.Move(manifestOriginalPath, manifestPath); + + XmlDocument document = new XmlDocument(); + document.Load(manifestPath); + XmlNamespaceManager namespaceManager = new XmlNamespaceManager(document.NameTable); + namespaceManager.AddNamespace("burn", BurnCommon.BurnNamespace); + XmlNodeList uxPayloads = document.SelectNodes("/burn:BurnManifest/burn:UX/burn:Payload", namespaceManager); + XmlNodeList payloads = document.SelectNodes("/burn:BurnManifest/burn:Payload", namespaceManager); + + foreach (XmlNode uxPayload in uxPayloads) + { + XmlNode sourcePathNode = uxPayload.Attributes.GetNamedItem("SourcePath"); + XmlNode filePathNode = uxPayload.Attributes.GetNamedItem("FilePath"); + + string sourcePath = Path.Combine(outputDirectory, sourcePathNode.Value); + string destinationPath = Path.Combine(outputDirectory, filePathNode.Value); + + Directory.CreateDirectory(Path.GetDirectoryName(destinationPath)); + File.Delete(destinationPath); + File.Move(sourcePath, destinationPath); + } + + foreach (XmlNode payload in payloads) + { + XmlNode sourcePathNode = payload.Attributes.GetNamedItem("SourcePath"); + XmlNode filePathNode = payload.Attributes.GetNamedItem("FilePath"); + XmlNode packagingNode = payload.Attributes.GetNamedItem("Packaging"); + + string sourcePath = sourcePathNode.Value; + string destinationPath = filePathNode.Value; + string packaging = packagingNode.Value; + + if (packaging.Equals("embedded", StringComparison.OrdinalIgnoreCase)) + { + this.attachedContainerPayloadNames.Add(new DictionaryEntry(sourcePath, destinationPath)); + } + } + + return true; + } + + internal void ExtractUXContainer(string uxExtractPath, object intermediateFolder) + { + throw new NotImplementedException(); + } + + /// + /// Gets the attached container from the exe and extracts its contents to the output directory. + /// + /// Directory to write extracted files to. + /// True if successful, false otherwise + public bool ExtractAttachedContainer(string outputDirectory, string tempDirectory) + { + // No attached container to extract + if (this.AttachedContainerAddress == 0 || this.AttachedContainerSize == 0) + { + return false; + } + + if (this.invalidBundle) + { + return false; + } + + Directory.CreateDirectory(outputDirectory); + string tempCabPath = Path.Combine(tempDirectory, "attached.cab"); + + this.binaryReader.BaseStream.Seek(this.AttachedContainerAddress, SeekOrigin.Begin); + using (Stream tempCab = File.Open(tempCabPath, FileMode.Create, FileAccess.Write)) + { + BurnCommon.CopyStream(this.binaryReader.BaseStream, tempCab, (int)this.AttachedContainerSize); + } + + using (WixExtractCab extract = new WixExtractCab()) + { + extract.Extract(tempCabPath, outputDirectory); + } + + foreach (DictionaryEntry entry in this.attachedContainerPayloadNames) + { + string sourcePath = Path.Combine(outputDirectory, (string)entry.Key); + string destinationPath = Path.Combine(outputDirectory, (string)entry.Value); + + Directory.CreateDirectory(Path.GetDirectoryName(destinationPath)); + File.Delete(destinationPath); + File.Move(sourcePath, destinationPath); + } + + return true; + } + + /// + /// Dispose object. + /// + /// True when releasing managed objects. + protected override void Dispose(bool disposing) + { + if (!this.disposed) + { + if (disposing && this.binaryReader != null) + { + this.binaryReader.Close(); + this.binaryReader = null; + } + + this.disposed = true; + } + } + } +} -- cgit v1.2.3-55-g6feb