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