aboutsummaryrefslogtreecommitdiff
path: root/src/WixToolset.Core.Burn/Bundles/BurnWriter.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/WixToolset.Core.Burn/Bundles/BurnWriter.cs')
-rw-r--r--src/WixToolset.Core.Burn/Bundles/BurnWriter.cs239
1 files changed, 239 insertions, 0 deletions
diff --git a/src/WixToolset.Core.Burn/Bundles/BurnWriter.cs b/src/WixToolset.Core.Burn/Bundles/BurnWriter.cs
new file mode 100644
index 00000000..e7365212
--- /dev/null
+++ b/src/WixToolset.Core.Burn/Bundles/BurnWriter.cs
@@ -0,0 +1,239 @@
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.Diagnostics;
7 using System.IO;
8 using WixToolset.Data;
9
10 /// <summary>
11 /// Burn PE writer for the WiX toolset.
12 /// </summary>
13 /// <remarks>This class encapsulates reading/writing to a stub EXE for
14 /// creating bundled/chained setup packages.</remarks>
15 /// <example>
16 /// using (BurnWriter writer = new BurnWriter(fileExe, this.core, guid))
17 /// {
18 /// writer.AppendContainer(file1, BurnWriter.Container.UX);
19 /// writer.AppendContainer(file2, BurnWriter.Container.Attached);
20 /// }
21 /// </example>
22 internal class BurnWriter : BurnCommon
23 {
24 private bool disposed;
25 private bool invalidBundle;
26 private BinaryWriter binaryWriter;
27
28 /// <summary>
29 /// Creates a BurnWriter for re-writing a PE file.
30 /// </summary>
31 /// <param name="fileExe">File to modify in-place.</param>
32 /// <param name="bundleGuid">GUID for the bundle.</param>
33 private BurnWriter(string fileExe)
34 : base(fileExe)
35 {
36 }
37
38 /// <summary>
39 /// Opens a Burn writer.
40 /// </summary>
41 /// <param name="fileExe">Path to file.</param>
42 /// <returns>Burn writer.</returns>
43 public static BurnWriter Open(string fileExe)
44 {
45 BurnWriter writer = new BurnWriter(fileExe);
46
47 using (BinaryReader binaryReader = new BinaryReader(File.Open(fileExe, FileMode.Open, FileAccess.Read, FileShare.Read | FileShare.Delete)))
48 {
49 if (!writer.Initialize(binaryReader))
50 {
51 writer.invalidBundle = true;
52 }
53 }
54
55 if (!writer.invalidBundle)
56 {
57 writer.binaryWriter = new BinaryWriter(File.Open(fileExe, FileMode.Open, FileAccess.ReadWrite, FileShare.Read | FileShare.Delete));
58 }
59
60 return writer;
61 }
62
63 /// <summary>
64 /// Update the ".wixburn" section data.
65 /// </summary>
66 /// <param name="stubSize">Size of the stub engine "burn.exe".</param>
67 /// <param name="bundleId">Unique identifier for this bundle.</param>
68 /// <returns></returns>
69 public bool InitializeBundleSectionData(long stubSize, Guid bundleId)
70 {
71 if (this.invalidBundle)
72 {
73 return false;
74 }
75
76 this.WriteToBurnSectionOffset(BURN_SECTION_OFFSET_MAGIC, BURN_SECTION_MAGIC);
77 this.WriteToBurnSectionOffset(BURN_SECTION_OFFSET_VERSION, BURN_SECTION_VERSION);
78
79 Messaging.Instance.OnMessage(WixVerboses.BundleGuid(bundleId.ToString("B")));
80 this.binaryWriter.BaseStream.Seek(this.wixburnDataOffset + BURN_SECTION_OFFSET_BUNDLEGUID, SeekOrigin.Begin);
81 this.binaryWriter.Write(bundleId.ToByteArray());
82
83 this.StubSize = (uint)stubSize;
84
85 this.WriteToBurnSectionOffset(BURN_SECTION_OFFSET_STUBSIZE, this.StubSize);
86 this.WriteToBurnSectionOffset(BURN_SECTION_OFFSET_ORIGINALCHECKSUM, 0);
87 this.WriteToBurnSectionOffset(BURN_SECTION_OFFSET_ORIGINALSIGNATUREOFFSET, 0);
88 this.WriteToBurnSectionOffset(BURN_SECTION_OFFSET_ORIGINALSIGNATURESIZE, 0);
89 this.WriteToBurnSectionOffset(BURN_SECTION_OFFSET_FORMAT, 1); // Hard-coded to CAB for now.
90 this.WriteToBurnSectionOffset(BURN_SECTION_OFFSET_COUNT, 0);
91 this.WriteToBurnSectionOffset(BURN_SECTION_OFFSET_UXSIZE, 0);
92 this.WriteToBurnSectionOffset(BURN_SECTION_OFFSET_ATTACHEDCONTAINERSIZE, 0);
93 this.binaryWriter.BaseStream.Flush();
94
95 this.EngineSize = this.StubSize;
96
97 return true;
98 }
99
100 /// <summary>
101 /// Appends a UX or Attached container to the exe and updates the ".wixburn" section data to point to it.
102 /// </summary>
103 /// <param name="fileContainer">File path to append to the current exe.</param>
104 /// <param name="container">Container section represented by the fileContainer.</param>
105 /// <returns>true if the container data is successfully appended; false otherwise</returns>
106 public bool AppendContainer(string fileContainer, BurnCommon.Container container)
107 {
108 using (FileStream reader = File.OpenRead(fileContainer))
109 {
110 return this.AppendContainer(reader, reader.Length, container);
111 }
112 }
113
114 /// <summary>
115 /// Appends a UX or Attached container to the exe and updates the ".wixburn" section data to point to it.
116 /// </summary>
117 /// <param name="containerStream">File stream to append to the current exe.</param>
118 /// <param name="containerSize">Size of container to append.</param>
119 /// <param name="container">Container section represented by the fileContainer.</param>
120 /// <returns>true if the container data is successfully appended; false otherwise</returns>
121 public bool AppendContainer(Stream containerStream, long containerSize, BurnCommon.Container container)
122 {
123 UInt32 burnSectionCount = 0;
124 UInt32 burnSectionOffsetSize = 0;
125
126 switch (container)
127 {
128 case Container.UX:
129 burnSectionCount = 1;
130 burnSectionOffsetSize = BURN_SECTION_OFFSET_UXSIZE;
131 // TODO: verify that the size in the section data is 0 or the same size.
132 this.EngineSize += (uint)containerSize;
133 this.UXSize = (uint)containerSize;
134 break;
135
136 case Container.Attached:
137 burnSectionCount = 2;
138 burnSectionOffsetSize = BURN_SECTION_OFFSET_ATTACHEDCONTAINERSIZE;
139 // TODO: verify that the size in the section data is 0 or the same size.
140 this.AttachedContainerSize = (uint)containerSize;
141 break;
142
143 default:
144 Debug.Assert(false);
145 return false;
146 }
147
148 return AppendContainer(containerStream, (UInt32)containerSize, burnSectionOffsetSize, burnSectionCount);
149 }
150
151 public void RememberThenResetSignature()
152 {
153 if (this.invalidBundle)
154 {
155 return;
156 }
157
158 this.OriginalChecksum = this.Checksum;
159 this.OriginalSignatureOffset = this.SignatureOffset;
160 this.OriginalSignatureSize = this.SignatureSize;
161
162 this.WriteToBurnSectionOffset(BURN_SECTION_OFFSET_ORIGINALCHECKSUM, this.OriginalChecksum);
163 this.WriteToBurnSectionOffset(BURN_SECTION_OFFSET_ORIGINALSIGNATUREOFFSET, this.OriginalSignatureOffset);
164 this.WriteToBurnSectionOffset(BURN_SECTION_OFFSET_ORIGINALSIGNATURESIZE, this.OriginalSignatureSize);
165
166 this.Checksum = 0;
167 this.SignatureOffset = 0;
168 this.SignatureSize = 0;
169
170 this.WriteToOffset(this.checksumOffset, this.Checksum);
171 this.WriteToOffset(this.certificateTableSignatureOffset, this.SignatureOffset);
172 this.WriteToOffset(this.certificateTableSignatureSize, this.SignatureSize);
173 }
174
175 /// <summary>
176 /// Dispose object.
177 /// </summary>
178 /// <param name="disposing">True when releasing managed objects.</param>
179 protected override void Dispose(bool disposing)
180 {
181 if (!this.disposed)
182 {
183 if (disposing && this.binaryWriter != null)
184 {
185 this.binaryWriter.Close();
186 this.binaryWriter = null;
187 }
188
189 this.disposed = true;
190 }
191 }
192
193 /// <summary>
194 /// Appends a container to the exe and updates the ".wixburn" section data to point to it.
195 /// </summary>
196 /// <param name="containerStream">File stream to append to the current exe.</param>
197 /// <param name="burnSectionOffsetSize">Offset of size field for this container in ".wixburn" section data.</param>
198 /// <returns>true if the container data is successfully appended; false otherwise</returns>
199 private bool AppendContainer(Stream containerStream, UInt32 containerSize, UInt32 burnSectionOffsetSize, UInt32 burnSectionCount)
200 {
201 if (this.invalidBundle)
202 {
203 return false;
204 }
205
206 // Update the ".wixburn" section data
207 this.WriteToBurnSectionOffset(BURN_SECTION_OFFSET_COUNT, burnSectionCount);
208 this.WriteToBurnSectionOffset(burnSectionOffsetSize, containerSize);
209
210 // Append the container to the end of the existing bits.
211 this.binaryWriter.BaseStream.Seek(0, SeekOrigin.End);
212 BurnCommon.CopyStream(containerStream, this.binaryWriter.BaseStream, (int)containerSize);
213 this.binaryWriter.BaseStream.Flush();
214
215 return true;
216 }
217
218 /// <summary>
219 /// Writes the value to an offset in the Burn section data.
220 /// </summary>
221 /// <param name="offset">Offset in to the Burn section data.</param>
222 /// <param name="value">Value to write.</param>
223 private void WriteToBurnSectionOffset(uint offset, uint value)
224 {
225 this.WriteToOffset(this.wixburnDataOffset + offset, value);
226 }
227
228 /// <summary>
229 /// Writes the value to an offset in the Burn stub.
230 /// </summary>
231 /// <param name="offset">Offset in to the Burn stub.</param>
232 /// <param name="value">Value to write.</param>
233 private void WriteToOffset(uint offset, uint value)
234 {
235 this.binaryWriter.BaseStream.Seek((int)offset, SeekOrigin.Begin);
236 this.binaryWriter.Write(value);
237 }
238 }
239}