@joebigelow / wix-1 / commits / 323f62d3

Follow up for multiple attached container support

* validate cContainers * use previous embeddedid format and use intermediate folder when extracting attached containers * remove special cases for 0 byte containers in BurnCommon classes and Insignia * don't hardcode max containers * reduce properties in BurnCommon * add e2e test #6144

Sean Hall committed Nov 2, 2021 at 17:47 UTC 323f62d3d0f4b73db5fde8977e2540194c6de006
19 files changed +276 -158
src/burn/engine/section.cpp
+13 -11
@@ -26,7 +26,7 @@ typedef struct _BURN_SECTION_HEADER
26
27 DWORD dwFormat;
28 DWORD cContainers;
29 - DWORD rgcbContainers[116];
29 + DWORD rgcbContainers[1];
30 } BURN_SECTION_HEADER;
31
32 static HRESULT VerifySectionMatchesMemoryPEHeader(
@@ -53,6 +53,7 @@ extern "C" HRESULT SectionInitialize(
53 IMAGE_SECTION_HEADER sectionHeader = { };
54 DWORD_PTR dwOriginalChecksumAndSignatureOffset = 0;
55 BURN_SECTION_HEADER* pBurnSectionHeader = NULL;
56 + DWORD cMaxContainers = 0;
57
58 pSection->hEngineFile = hEngineFile;
59 ExitOnInvalidHandleWithLastError(pSection->hEngineFile, hr, "Failed to open handle to engine process path.");
@@ -142,8 +143,7 @@ extern "C" HRESULT SectionInitialize(
143 }
144 if (sizeof(IMAGE_SECTION_HEADER) > cbRead)
145 {
145 - hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
146 - ExitOnRootFailure(hr, "Failed to read complete image section header, index: %u", i);
146 + ExitWithRootFailure(hr, E_INVALIDDATA, "Failed to read complete image section header, index: %u", i);
147 }
148
149 // compare header name
@@ -156,8 +156,7 @@ extern "C" HRESULT SectionInitialize(
156 // fail if we hit the end
157 if (i + 1 >= ntHeader.FileHeader.NumberOfSections)
158 {
159 - hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
160 - ExitOnRootFailure(hr, "Failed to find Burn section.");
159 + ExitWithRootFailure(hr, E_INVALIDDATA, "Failed to find Burn section.");
160 }
161 }
162
@@ -168,8 +167,7 @@ extern "C" HRESULT SectionInitialize(
167 // check size of section
168 if (sizeof(BURN_SECTION_HEADER) > sectionHeader.SizeOfRawData)
169 {
171 - hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
172 - ExitOnRootFailure(hr, "Failed to read section info, data to short: %u", sectionHeader.SizeOfRawData);
170 + ExitWithRootFailure(hr, E_INVALIDDATA, "Failed to read section info, data too short: %u", sectionHeader.SizeOfRawData);
171 }
172
173 // allocate buffer for section info
@@ -193,15 +191,19 @@ extern "C" HRESULT SectionInitialize(
191 }
192 else if (sectionHeader.SizeOfRawData > cbRead)
193 {
196 - hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
197 - ExitOnRootFailure(hr, "Failed to read complete section info.");
194 + ExitWithRootFailure(hr, E_INVALIDDATA, "Failed to read complete section info.");
195 }
196
197 // validate version of section info
198 if (BURN_SECTION_VERSION != pBurnSectionHeader->dwVersion)
199 {
203 - hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
204 - ExitOnRootFailure(hr, "Failed to read section info, unsupported version: %08x", pBurnSectionHeader->dwVersion);
200 + ExitWithRootFailure(hr, E_INVALIDDATA, "Failed to read section info, unsupported version: %08x", pBurnSectionHeader->dwVersion);
201 + }
202 +
203 + cMaxContainers = (sectionHeader.SizeOfRawData - offsetof(BURN_SECTION_HEADER, rgcbContainers)) / sizeof(DWORD);
204 + if (cMaxContainers < pBurnSectionHeader->cContainers)
205 + {
206 + ExitWithRootFailure(hr, E_INVALIDDATA, "Invalid section info, cContainers too large: %u", pBurnSectionHeader->cContainers);
207 }
208
209 hr = FileSizeByHandle(pSection->hSourceEngineFile, &llSize);
src/burn/stub/StubSection.cpp
+2 -1
@@ -18,5 +18,6 @@ static DWORD dwOriginalSignatureSize = 0;
18
19 static DWORD dwContainerFormat = 1;
20 static DWORD dwContainerCount = 0;
21 -static DWORD qwAttachedContainerSizes[116]; // Including UX container
21 +// (512 (minimum section size) - 48 (size of above data)) / 4 (size of DWORD)
22 +static DWORD qwAttachedContainerSizes[116];
23 #pragma data_seg(pop)
src/test/burn/TestData/ContainerTests/BundleA/BundleA.wixproj new
+19
@@ -0,0 +1,19 @@
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 +<Project Sdk="WixToolset.Sdk">
3 + <PropertyGroup>
4 + <OutputType>Bundle</OutputType>
5 + <UpgradeCode>{16798DF3-C365-410D-B376-E63A961E4822}</UpgradeCode>
6 + </PropertyGroup>
7 + <ItemGroup>
8 + <Compile Include="..\..\Templates\Bundle.wxs" Link="Bundle.wxs" />
9 + </ItemGroup>
10 + <ItemGroup>
11 + <ProjectReference Include="..\PackageA\PackageA.wixproj" />
12 + <ProjectReference Include="..\PackageB\PackageB.wixproj" />
13 + <ProjectReference Include="..\..\TestBA\TestBAWixlib\testbawixlib.wixproj" />
14 + </ItemGroup>
15 + <ItemGroup>
16 + <PackageReference Include="WixToolset.Bal.wixext" />
17 + <PackageReference Include="WixToolset.NetFx.wixext" />
18 + </ItemGroup>
19 +</Project>
\ No newline at end of file
src/test/burn/TestData/ContainerTests/BundleA/BundleA.wxs new
+17
@@ -0,0 +1,17 @@
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 +
4 +<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
5 + <Fragment>
6 + <PackageGroup Id="BundlePackages">
7 + <MsiPackage Id="PackageA" SourceFile="$(var.PackageA.TargetPath)" />
8 + <PackageGroupRef Id="PackageB" />
9 + </PackageGroup>
10 + <PackageGroup Id="PackageB">
11 + <MsiPackage Id="PackageB" SourceFile="$(var.PackageB.TargetPath)" />
12 + </PackageGroup>
13 + <Container Id="CustomAttachedContainer" Name="CustomAttachedContainer" Type="attached">
14 + <PackageGroupRef Id="PackageB" />
15 + </Container>
16 + </Fragment>
17 +</Wix>
src/test/burn/TestData/ContainerTests/PackageA/PackageA.wixproj new
+10
@@ -0,0 +1,10 @@
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 +<Project Sdk="WixToolset.Sdk">
3 + <PropertyGroup>
4 + <CabPrefix>a</CabPrefix>
5 + <UpgradeCode>{D452A40D-27B2-41A1-A103-4FD5744B548E}</UpgradeCode>
6 + </PropertyGroup>
7 + <ItemGroup>
8 + <Compile Include="..\..\Templates\Package.wxs" Link="Package.wxs" />
9 + </ItemGroup>
10 +</Project>
\ No newline at end of file
src/test/burn/TestData/ContainerTests/PackageB/PackageB.wixproj new
+10
@@ -0,0 +1,10 @@
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 +<Project Sdk="WixToolset.Sdk">
3 + <PropertyGroup>
4 + <CabPrefix>b</CabPrefix>
5 + <UpgradeCode>{EB8E7A16-9855-4019-90D6-F5A242A75250}</UpgradeCode>
6 + </PropertyGroup>
7 + <ItemGroup>
8 + <Compile Include="..\..\Templates\Package.wxs" Link="Package.wxs" />
9 + </ItemGroup>
10 +</Project>
\ No newline at end of file
src/test/burn/WixToolsetTest.BurnE2E/ContainerTests.cs new
+29
@@ -0,0 +1,29 @@
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 WixToolsetTest.BurnE2E
4 +{
5 + using Xunit;
6 + using Xunit.Abstractions;
7 +
8 + public class ContainerTests : BurnE2ETests
9 + {
10 + public ContainerTests(ITestOutputHelper testOutputHelper) : base(testOutputHelper) { }
11 +
12 + [Fact]
13 + public void CanSupportMultipleAttachedContainers()
14 + {
15 + var packageA = this.CreatePackageInstaller("PackageA");
16 + var packageB = this.CreatePackageInstaller("PackageB");
17 + var bundleA = this.CreateBundleInstaller("BundleA");
18 +
19 + packageA.VerifyInstalled(false);
20 + packageB.VerifyInstalled(false);
21 +
22 + bundleA.Install();
23 + bundleA.VerifyRegisteredAndInPackageCache();
24 +
25 + packageA.VerifyInstalled(true);
26 + packageB.VerifyInstalled(true);
27 + }
28 + }
29 +}
src/wix/WixToolset.Core.Burn/Bind/BindBundleCommand.cs
+3 -1
@@ -296,13 +296,15 @@ namespace WixToolset.Core.Burn
296 }
297
298 // Give the embedded payloads without an embedded id yet an embedded id.
299 + var payloadIndex = 0;
300 foreach (var payload in payloadSymbols.Values)
301 {
302 Debug.Assert(PackagingType.Unknown != payload.Packaging);
303
304 if (PackagingType.Embedded == payload.Packaging && String.IsNullOrEmpty(payload.EmbeddedId))
305 {
305 - payload.EmbeddedId = Guid.NewGuid().ToString("N");
306 + payload.EmbeddedId = String.Format(CultureInfo.InvariantCulture, BurnCommon.BurnAuthoredContainerEmbeddedIdFormat, payloadIndex);
307 + ++payloadIndex;
308 }
309 }
310 }
src/wix/WixToolset.Core.Burn/BundleBackend.cs
+1 -1
@@ -67,7 +67,7 @@ namespace WixToolset.Core.Burn
67 using (var reader = BurnReader.Open(messaging, context.InputFilePath))
68 {
69 reader.ExtractUXContainer(uxExtractPath, context.IntermediateFolder);
70 - reader.ExtractAttachedContainers(context.ExportBasePath);
70 + reader.ExtractAttachedContainers(context.ExportBasePath, context.IntermediateFolder);
71 }
72
73 return null;
src/wix/WixToolset.Core.Burn/Bundles/BurnCommon.cs
+29 -32
@@ -20,6 +20,7 @@ namespace WixToolset.Core.Burn.Bundles
20 {
21 public const string BurnNamespace = "http://wixtoolset.org/schemas/v4/2008/Burn";
22 public const string BurnUXContainerEmbeddedIdFormat = "u{0}";
23 + public const string BurnAuthoredContainerEmbeddedIdFormat = "a{0}";
24
25 public const string BADataFileName = "BootstrapperApplicationData.xml";
26 public const string BADataNamespace = "http://wixtoolset.org/schemas/v4/BootstrapperApplicationData";
@@ -79,12 +80,11 @@ namespace WixToolset.Core.Burn.Bundles
80 protected const UInt32 BURN_SECTION_OFFSET_COUNT = 44;
81 protected const UInt32 BURN_SECTION_OFFSET_UXSIZE = 48;
82 protected const UInt32 BURN_SECTION_OFFSET_ATTACHEDCONTAINERSIZE0 = 52;
83 + protected const UInt32 BURN_SECTION_MIN_SIZE = BURN_SECTION_OFFSET_ATTACHEDCONTAINERSIZE0;
84
85 protected const UInt32 BURN_SECTION_MAGIC = 0x00f14300;
86 protected const UInt32 BURN_SECTION_VERSION = 0x00000003;
87 protected const UInt32 BURN_SECTION_COMPATIBLE_VERSION = 0x00000002;
86 - protected const UInt32 BURN_SECTION_SIZE = 512;
87 - protected const UInt32 BURN_SECTION_MAX_ATTACHEDCONTAINER_COUNT = (BURN_SECTION_SIZE - BURN_SECTION_OFFSET_ATTACHEDCONTAINERSIZE0) / sizeof(UInt32);
88
89 protected string fileExe;
90 protected UInt32 peOffset = UInt32.MaxValue;
@@ -94,6 +94,8 @@ namespace WixToolset.Core.Burn.Bundles
94 protected UInt32 certificateTableSignatureOffset;
95 protected UInt32 certificateTableSignatureSize;
96 protected UInt32 wixburnDataOffset = UInt32.MaxValue;
97 + protected UInt32 wixburnRawDataSize;
98 + protected UInt32 wixburnMaxContainers;
99
100 // TODO: does this enum exist in another form somewhere?
101 /// <summary>
@@ -127,9 +129,7 @@ namespace WixToolset.Core.Burn.Bundles
129 public UInt32 OriginalSignatureOffset { get; protected set; }
130 public UInt32 OriginalSignatureSize { get; protected set; }
131 public UInt32 EngineSize { get; protected set; }
130 - public UInt32 ContainerCount { get; protected set; }
131 - public UInt32 UXAddress { get; protected set; }
132 - public UInt32 UXSize { get; protected set; }
132 + public UInt32 UXAddress { get { return this.StubSize; } }
133 public List<ContainerSlot> AttachedContainers { get; protected set; }
134
135 protected IMessaging Messaging { get; }
@@ -180,9 +180,7 @@ namespace WixToolset.Core.Burn.Bundles
180 }
181
182 reader.BaseStream.Seek(this.wixburnDataOffset, SeekOrigin.Begin);
183 - List<byte> manifest = new List<byte>();
184 - manifest.AddRange(reader.ReadBytes((int)BURN_SECTION_SIZE));
185 - byte[] bytes = manifest.ToArray();
183 + byte[] bytes = reader.ReadBytes((int)this.wixburnRawDataSize);
184 UInt32 uint32 = 0;
185
186 uint32 = BurnCommon.ReadUInt32(bytes, BURN_SECTION_OFFSET_MAGIC);
@@ -211,40 +209,37 @@ namespace WixToolset.Core.Burn.Bundles
209 this.OriginalSignatureOffset = BurnCommon.ReadUInt32(bytes, BURN_SECTION_OFFSET_ORIGINALSIGNATUREOFFSET);
210 this.OriginalSignatureSize = BurnCommon.ReadUInt32(bytes, BURN_SECTION_OFFSET_ORIGINALSIGNATURESIZE);
211
214 - this.ContainerCount = BurnCommon.ReadUInt32(bytes, BURN_SECTION_OFFSET_COUNT);
215 - if (BURN_SECTION_MAX_ATTACHEDCONTAINER_COUNT < this.ContainerCount)
212 + uint containerCount = BurnCommon.ReadUInt32(bytes, BURN_SECTION_OFFSET_COUNT);
213 + uint uxSize = 0;
214 + if (this.wixburnMaxContainers < containerCount)
215 {
216 this.Messaging.Write(ErrorMessages.InvalidBundle(this.fileExe));
217 return false;
218 }
220 - this.UXAddress = this.StubSize;
221 - this.UXSize = BurnCommon.ReadUInt32(bytes, BURN_SECTION_OFFSET_UXSIZE);
219 + else if (containerCount > 0)
220 + {
221 + this.AttachedContainers.Clear();
222 + for (uint i = 0; i < containerCount; ++i)
223 + {
224 + uint sizeOffset = BURN_SECTION_OFFSET_UXSIZE + (i * 4);
225 + uint size = BurnCommon.ReadUInt32(bytes, sizeOffset);
226 + this.AttachedContainers.Add(new ContainerSlot(size));
227 + }
228 + uxSize = this.AttachedContainers[0].Size;
229 + }
230
231 // If there is an original signature use that to determine the engine size.
232 if (0 < this.OriginalSignatureOffset)
233 {
234 this.EngineSize = this.OriginalSignatureOffset + this.OriginalSignatureSize;
235 }
228 - else if (0 < this.SignatureOffset && 2 > this.ContainerCount) // if there is a signature and no attached containers, use the current signature.
236 + else if (0 < this.SignatureOffset && 2 > containerCount) // if there is a signature and no attached containers, use the current signature.
237 {
238 this.EngineSize = this.SignatureOffset + this.SignatureSize;
239 }
240 else // just use the stub and UX container as the size of the engine.
241 {
234 - this.EngineSize = this.StubSize + this.UXSize;
235 - }
236 -
237 - this.AttachedContainers.Clear();
238 - uint nextAddress = this.EngineSize;
239 - if (this.ContainerCount > 1)
240 - {
241 - for (uint i = 0; i < (this.ContainerCount - 1 /* Excluding UX */); ++i)
242 - {
243 - uint sizeOffset = BURN_SECTION_OFFSET_ATTACHEDCONTAINERSIZE0 + (i * 4);
244 - uint size = BurnCommon.ReadUInt32(bytes, sizeOffset);
245 - this.AttachedContainers.Add(new ContainerSlot(nextAddress, size));
246 - nextAddress += size;
247 - }
242 + this.EngineSize = this.UXAddress + uxSize;
243 }
244
245 return true;
@@ -288,13 +283,17 @@ namespace WixToolset.Core.Burn.Bundles
283 return false;
284 }
285
291 - // We need 512 bytes for the manifest header
292 - if (BURN_SECTION_SIZE > BurnCommon.ReadUInt32(bytes, IMAGE_SECTION_HEADER_OFFSET_SIZEOFRAWDATA))
286 + this.wixburnRawDataSize = BurnCommon.ReadUInt32(bytes, IMAGE_SECTION_HEADER_OFFSET_SIZEOFRAWDATA);
287 +
288 + // we need 52 bytes for the manifest header, which is always going to fit in
289 + // the smallest alignment (512 bytes), but just to be paranoid...
290 + if (BURN_SECTION_MIN_SIZE > this.wixburnRawDataSize)
291 {
292 this.Messaging.Write(ErrorMessages.StubWixburnSectionTooSmall(this.fileExe));
293 return false;
294 }
295
296 + this.wixburnMaxContainers = (this.wixburnRawDataSize - BURN_SECTION_OFFSET_UXSIZE) / sizeof(UInt32);
297 this.wixburnDataOffset = BurnCommon.ReadUInt32(bytes, IMAGE_SECTION_HEADER_OFFSET_POINTERTORAWDATA);
298 }
299
@@ -404,13 +403,11 @@ namespace WixToolset.Core.Burn.Bundles
403
404 internal struct ContainerSlot
405 {
407 - public ContainerSlot(uint address, uint size) : this()
406 + public ContainerSlot(uint size) : this()
407 {
409 - this.Address = address;
408 this.Size = size;
409 }
410
413 - public uint Address { get; set; }
411 public uint Size { get; set; }
412 }
413 }
src/wix/WixToolset.Core.Burn/Bundles/BurnReader.cs
+15 -9
@@ -78,7 +78,7 @@ namespace WixToolset.Core.Burn.Bundles
78 public bool ExtractUXContainer(string outputDirectory, string tempDirectory)
79 {
80 // No UX container to extract
81 - if (this.UXAddress == 0 || this.UXSize == 0)
81 + if (this.AttachedContainers.Count == 0)
82 {
83 return false;
84 }
@@ -92,11 +92,12 @@ namespace WixToolset.Core.Burn.Bundles
92 string tempCabPath = Path.Combine(tempDirectory, "ux.cab");
93 string manifestOriginalPath = Path.Combine(outputDirectory, "0");
94 string manifestPath = Path.Combine(outputDirectory, "manifest.xml");
95 + var uxContainerSlot = this.AttachedContainers[0];
96
97 this.binaryReader.BaseStream.Seek(this.UXAddress, SeekOrigin.Begin);
98 using (Stream tempCab = File.Open(tempCabPath, FileMode.Create, FileAccess.Write))
99 {
99 - BurnCommon.CopyStream(this.binaryReader.BaseStream, tempCab, (int)this.UXSize);
100 + BurnCommon.CopyStream(this.binaryReader.BaseStream, tempCab, (int)uxContainerSlot.Size);
101 }
102
103 var cabinet = new Cabinet(tempCabPath);
@@ -152,14 +153,15 @@ namespace WixToolset.Core.Burn.Bundles
153 }
154
155 /// <summary>
155 - /// Gets the attached container from the exe and extracts its contents to the output directory.
156 + /// Gets each non-UX attached container from the exe and extracts its contents to the output directory.
157 /// </summary>
158 /// <param name="outputDirectory">Directory to write extracted files to.</param>
159 + /// <param name="tempDirectory">Scratch directory.</param>
160 /// <returns>True if successful, false otherwise</returns>
159 - public bool ExtractAttachedContainers(string outputDirectory)
161 + public bool ExtractAttachedContainers(string outputDirectory, string tempDirectory)
162 {
161 - // No attached container to extract
162 - if (this.AttachedContainers.Count == 0)
163 + // No attached containers to extract
164 + if (this.AttachedContainers.Count < 2)
165 {
166 return false;
167 }
@@ -170,11 +172,13 @@ namespace WixToolset.Core.Burn.Bundles
172 }
173
174 Directory.CreateDirectory(outputDirectory);
173 - foreach (ContainerSlot cntnr in this.AttachedContainers)
175 + uint nextAddress = this.EngineSize;
176 + for (int i = 1; i < this.AttachedContainers.Count; i++)
177 {
175 - string tempCabPath = Path.GetTempFileName();
178 + ContainerSlot cntnr = this.AttachedContainers[i];
179 + string tempCabPath = Path.Combine(tempDirectory, $"a{i}.cab");
180
177 - this.binaryReader.BaseStream.Seek(cntnr.Address, SeekOrigin.Begin);
181 + this.binaryReader.BaseStream.Seek(nextAddress, SeekOrigin.Begin);
182 using (Stream tempCab = File.Open(tempCabPath, FileMode.Create, FileAccess.Write))
183 {
184 BurnCommon.CopyStream(this.binaryReader.BaseStream, tempCab, (int)cntnr.Size);
@@ -182,6 +186,8 @@ namespace WixToolset.Core.Burn.Bundles
186
187 var cabinet = new Cabinet(tempCabPath);
188 cabinet.Extract(outputDirectory);
189 +
190 + nextAddress += cntnr.Size;
191 }
192
193 foreach (DictionaryEntry entry in this.attachedContainerPayloadNames)
src/wix/WixToolset.Core.Burn/Bundles/BurnWriter.cs
+50 -30
@@ -91,9 +91,9 @@ namespace WixToolset.Core.Burn.Bundles
91 this.WriteToBurnSectionOffset(BURN_SECTION_OFFSET_ORIGINALSIGNATUREOFFSET, 0);
92 this.WriteToBurnSectionOffset(BURN_SECTION_OFFSET_ORIGINALSIGNATURESIZE, 0);
93 this.WriteToBurnSectionOffset(BURN_SECTION_OFFSET_FORMAT, 1); // Hard-coded to CAB for now.
94 + this.AttachedContainers.Clear();
95 this.WriteToBurnSectionOffset(BURN_SECTION_OFFSET_COUNT, 0);
95 - this.WriteToBurnSectionOffset(BURN_SECTION_OFFSET_UXSIZE, 0);
96 - for (uint i = BURN_SECTION_OFFSET_ATTACHEDCONTAINERSIZE0; i < BURN_SECTION_SIZE; i += sizeof(UInt32))
96 + for (uint i = BURN_SECTION_OFFSET_UXSIZE; i < this.wixburnMaxContainers; i += sizeof(UInt32))
97 {
98 this.WriteToBurnSectionOffset(i, 0);
99 }
@@ -118,6 +118,39 @@ namespace WixToolset.Core.Burn.Bundles
118 }
119 }
120
121 + /// <summary>
122 + /// Appends the non-UX attached containers from the reader to this bundle.
123 + /// </summary>
124 + /// <param name="reader">The source bundle.</param>
125 + /// <returns>true if the container data is successfully appended; false otherwise.</returns>
126 + public bool ReattachContainers(BurnReader reader)
127 + {
128 + if (this.AttachedContainers.Count == 0 || reader.AttachedContainers.Count < 2)
129 + {
130 + return false;
131 + }
132 +
133 + this.RememberThenResetSignature();
134 +
135 + var uxContainerSlot = this.AttachedContainers[0];
136 + this.AttachedContainers.Clear();
137 + this.AttachedContainers.Add(uxContainerSlot);
138 +
139 + uint nextAddress = this.EngineSize;
140 + for (int i = 1; i < reader.AttachedContainers.Count; i++)
141 + {
142 + ContainerSlot cntnr = reader.AttachedContainers[i];
143 +
144 + reader.Stream.Seek(nextAddress, SeekOrigin.Begin);
145 + // TODO: verify that the size in the section data is 0 or the same size.
146 + this.AppendContainer(reader.Stream, cntnr.Size, BurnCommon.Container.Attached);
147 +
148 + nextAddress += cntnr.Size;
149 + }
150 +
151 + return true;
152 + }
153 +
154 /// <summary>
155 /// Appends a UX or Attached container to the exe and updates the ".wixburn" section data to point to it.
156 /// </summary>
@@ -127,38 +160,23 @@ namespace WixToolset.Core.Burn.Bundles
160 /// <returns>true if the container data is successfully appended; false otherwise</returns>
161 public bool AppendContainer(Stream containerStream, long containerSize, BurnCommon.Container container)
162 {
130 - UInt32 burnSectionCount = 0;
131 - UInt32 burnSectionOffsetSize = 0;
132 -
133 - if (containerSize == 0)
134 - {
135 - return false;
136 - }
163 + uint containerCount = (uint)this.AttachedContainers.Count;
164 + uint burnSectionOffsetSize = BURN_SECTION_OFFSET_UXSIZE + (containerCount * sizeof(UInt32));
165 + var containerSlot = new ContainerSlot((uint)containerSize);
166
167 switch (container)
168 {
169 case Container.UX:
141 - burnSectionCount = 1;
142 - burnSectionOffsetSize = BURN_SECTION_OFFSET_UXSIZE;
143 - // TODO: verify that the size in the section data is 0 or the same size.
144 - this.EngineSize += (uint)containerSize;
145 - this.UXSize = (uint)containerSize;
146 - break;
147 -
148 - case Container.Attached:
149 - // TODO: verify that the size in the section data is 0 or the same size.
150 - uint nextAddress = this.EngineSize;
151 - foreach (ContainerSlot cntnr in this.AttachedContainers)
170 + if (containerCount != 0)
171 {
153 - if (cntnr.Address >= nextAddress)
154 - {
155 - nextAddress = cntnr.Address + cntnr.Size;
156 - }
172 + Debug.Assert(false);
173 + return false;
174 }
175
159 - this.AttachedContainers.Add(new ContainerSlot(nextAddress, (uint)containerSize));
160 - burnSectionCount = 1 + (uint)this.AttachedContainers.Count;
161 - burnSectionOffsetSize = BURN_SECTION_OFFSET_UXSIZE + ((uint)this.AttachedContainers.Count * 4);
176 + this.EngineSize += containerSlot.Size;
177 + break;
178 +
179 + case Container.Attached:
180 break;
181
182 default:
@@ -166,7 +184,9 @@ namespace WixToolset.Core.Burn.Bundles
184 return false;
185 }
186
169 - return this.AppendContainer(containerStream, (UInt32)containerSize, burnSectionOffsetSize, burnSectionCount);
187 + this.AttachedContainers.Add(containerSlot);
188 + ++containerCount;
189 + return this.AppendContainer(containerStream, containerSlot.Size, burnSectionOffsetSize, containerCount);
190 }
191
192 public void RememberThenResetSignature()
@@ -225,10 +245,10 @@ namespace WixToolset.Core.Burn.Bundles
245 {
246 return false;
247 }
228 - if (burnSectionOffsetSize > (BURN_SECTION_SIZE - sizeof(UInt32)))
248 + if (burnSectionOffsetSize > (this.wixburnRawDataSize - sizeof(UInt32)))
249 {
250 this.invalidBundle = true;
231 - this.Messaging.Write(BurnBackendErrors.TooManyAttachedContainers(BURN_SECTION_MAX_ATTACHEDCONTAINER_COUNT));
251 + this.Messaging.Write(BurnBackendErrors.TooManyAttachedContainers(this.wixburnMaxContainers));
252 return false;
253 }
254
src/wix/WixToolset.Core.Burn/Inscribe/InscribeBundleCommand.cs
+1 -16
@@ -31,22 +31,7 @@ namespace WixToolset.Core.Burn.Inscribe
31 FileSystem.CopyFile(this.Context.SignedEngineFile, tempFile, allowHardlink: false);
32 using (BurnWriter writer = BurnWriter.Open(this.Messaging, tempFile))
33 {
34 - if (reader.Version != writer.Version)
35 - {
36 - this.Messaging.Write(BurnBackendErrors.IncompatibleWixBurnSection(this.Context.InputFilePath, reader.Version));
37 - }
38 -
39 - writer.AttachedContainers.Clear();
40 - writer.RememberThenResetSignature();
41 - foreach (ContainerSlot cntnr in reader.AttachedContainers)
42 - {
43 - if (cntnr.Size > 0)
44 - {
45 - reader.Stream.Seek(cntnr.Address, SeekOrigin.Begin);
46 - writer.AppendContainer(reader.Stream, cntnr.Size, BurnCommon.Container.Attached);
47 - inscribed = true;
48 - }
49 - }
34 + inscribed = writer.ReattachContainers(reader);
35 }
36 }
37
src/wix/WixToolset.Core.TestPackage/BundleExtractor.cs
+23 -19
@@ -21,44 +21,48 @@ namespace WixToolset.Core.TestPackage
21 /// <param name="tempFolderPath">Temp path for extraction.</param>
22 /// <returns></returns>
23 public static ExtractBAContainerResult ExtractBAContainer(IMessaging messaging, string bundleFilePath, string destinationFolderPath, string tempFolderPath)
24 + {
25 + return ExtractAllContainers(messaging, bundleFilePath, destinationFolderPath, null, tempFolderPath);
26 + }
27 +
28 + /// <summary>
29 + /// Extracts the BA container.
30 + /// </summary>
31 + /// <param name="messaging"></param>
32 + /// <param name="bundleFilePath">Path to the bundle.</param>
33 + /// <param name="baFolderPath">Path to extract BA to.</param>
34 + /// <param name="otherContainersFolderPath">Path to extract other attached containers to.</param>
35 + /// <param name="tempFolderPath">Temp path for extraction.</param>
36 + /// <returns></returns>
37 + public static ExtractBAContainerResult ExtractAllContainers(IMessaging messaging, string bundleFilePath, string baFolderPath, string otherContainersFolderPath, string tempFolderPath)
38 {
39 var result = new ExtractBAContainerResult();
40 Directory.CreateDirectory(tempFolderPath);
41 using (var burnReader = BurnReader.Open(messaging, bundleFilePath))
42 {
29 - result.Success = burnReader.ExtractUXContainer(destinationFolderPath, tempFolderPath);
43 + result.Success = burnReader.ExtractUXContainer(baFolderPath, tempFolderPath);
44 +
45 + if (otherContainersFolderPath != null)
46 + {
47 + result.AttachedContainersSuccess = burnReader.ExtractAttachedContainers(otherContainersFolderPath, tempFolderPath);
48 + }
49 }
50
51 if (result.Success)
52 {
34 - result.ManifestDocument = LoadBurnManifest(destinationFolderPath);
53 + result.ManifestDocument = LoadBurnManifest(baFolderPath);
54 result.ManifestNamespaceManager = GetBurnNamespaceManager(result.ManifestDocument, "burn");
55
37 - result.BADataDocument = LoadBAData(destinationFolderPath);
56 + result.BADataDocument = LoadBAData(baFolderPath);
57 result.BADataNamespaceManager = GetBADataNamespaceManager(result.BADataDocument, "ba");
58
40 - result.BundleExtensionDataDocument = LoadBundleExtensionData(destinationFolderPath);
59 + result.BundleExtensionDataDocument = LoadBundleExtensionData(baFolderPath);
60 result.BundleExtensionDataNamespaceManager = GetBundleExtensionDataNamespaceManager(result.BundleExtensionDataDocument, "be");
61 }
62
63 return result;
64 }
65
47 - /// <summary>
48 - /// Extracts the attached container.
49 - /// </summary>
50 - /// <param name="messaging"></param>
51 - /// <param name="bundleFilePath">Path to the bundle.</param>
52 - /// <param name="destinationFolderPath">Path to extract to.</param>
53 - /// <returns>True if there was an attached container.</returns>
54 - public static bool ExtractAttachedContainers(IMessaging messaging, string bundleFilePath, string destinationFolderPath)
55 - {
56 - using (var burnReader = BurnReader.Open(messaging, bundleFilePath))
57 - {
58 - return burnReader.ExtractAttachedContainers(destinationFolderPath);
59 - }
60 - }
61 -
66 /// <summary>
67 /// Gets an <see cref="XmlNamespaceManager"/> for BootstrapperApplicationData.xml with the given prefix assigned to the root namespace.
68 /// </summary>
src/wix/WixToolset.Core.TestPackage/ExtractBAContainerResult.cs
+6
@@ -46,6 +46,11 @@ namespace WixToolset.Core.TestPackage
46 /// </summary>
47 public bool Success { get; set; }
48
49 + /// <summary>
50 + /// Whether attached containers extraction succeeded.
51 + /// </summary>
52 + public bool? AttachedContainersSuccess { get; set; }
53 +
54 /// <summary>
55 ///
56 /// </summary>
@@ -53,6 +58,7 @@ namespace WixToolset.Core.TestPackage
58 public ExtractBAContainerResult AssertSuccess()
59 {
60 Assert.True(this.Success);
61 + Assert.True(!this.AttachedContainersSuccess.HasValue || this.AttachedContainersSuccess.Value);
62 return this;
63 }
64
src/wix/test/WixToolsetTest.CoreIntegration/BundleFixture.cs
+6 -2
@@ -125,8 +125,8 @@ namespace WixToolsetTest.CoreIntegration
125
126 var msiPayloads = extractResult.SelectManifestNodes("/burn:BurnManifest/burn:Payload[@Id='test.msi']");
127 var msiPayload = (XmlNode)Assert.Single(msiPayloads);
128 - Assert.Equal("<Payload Id='test.msi' FilePath='test.msi' FileSize='*' Hash='*' Packaging='embedded' SourcePath='*' Container='WixAttachedContainer' />",
129 - msiPayload.GetTestXml(new Dictionary<string, List<string>>() { { "Payload", new List<string> { "FileSize", "Hash", "SourcePath" } } }));
128 + Assert.Equal("<Payload Id='test.msi' FilePath='test.msi' FileSize='*' Hash='*' Packaging='embedded' SourcePath='a0' Container='WixAttachedContainer' />",
129 + msiPayload.GetTestXml(new Dictionary<string, List<string>>() { { "Payload", new List<string> { "FileSize", "Hash" } } }));
130 }
131
132 var manifestResource = new Resource(ResourceType.Manifest, "#1", 1033);
@@ -156,6 +156,7 @@ namespace WixToolsetTest.CoreIntegration
156 var exePath = Path.Combine(baseFolder, @"bin\test.exe");
157 var pdbPath = Path.Combine(baseFolder, @"bin\test.wixpdb");
158 var baFolderPath = Path.Combine(baseFolder, "ba");
159 + var attachedFolderPath = Path.Combine(baseFolder, "attached");
160 var extractFolderPath = Path.Combine(baseFolder, "extract");
161
162 var result = WixRunner.Execute(false, new[] // TODO: go back to elevating warnings as errors.
@@ -186,6 +187,9 @@ namespace WixToolsetTest.CoreIntegration
187 "<trustInfo xmlns=\"urn:schemas-microsoft-com:asm.v3\"><security><requestedPrivileges><requestedExecutionLevel level=\"asInvoker\" uiAccess=\"false\" /></requestedPrivileges></security></trustInfo>" +
188 "<application xmlns=\"urn:schemas-microsoft-com:asm.v3\"><windowsSettings><dpiAware xmlns=\"http://schemas.microsoft.com/SMI/2005/WindowsSettings\">true/pm</dpiAware><dpiAwareness xmlns=\"http://schemas.microsoft.com/SMI/2016/WindowsSettings\">PerMonitorV2, PerMonitor</dpiAwareness></windowsSettings></application>" +
189 "</assembly>", actualManifestData);
190 +
191 + var extractResult = BundleExtractor.ExtractAllContainers(null, exePath, baFolderPath, attachedFolderPath, extractFolderPath);
192 + extractResult.AssertSuccess();
193 }
194 }
195
src/wix/test/WixToolsetTest.CoreIntegration/ContainerFixture.cs
+33 -25
@@ -49,11 +49,11 @@ namespace WixToolsetTest.CoreIntegration
49
50 var payloads = extractResult.SelectManifestNodes("/burn:BurnManifest/burn:Payload");
51 Assert.Equal(4, payloads.Count);
52 - var ignoreAttributes = new Dictionary<string, List<string>> { { "Payload", new List<string> { "FileSize", "Hash", "SourcePath" } } };
53 - Assert.Equal(@"<Payload Id='FirstX64' FilePath='FirstX64\FirstX64.msi' FileSize='*' Hash='*' DownloadUrl='http://example.com//FirstX64/FirstX64/FirstX64.msi' Packaging='embedded' SourcePath='*' Container='BundlePackages' />", payloads[0].GetTestXml(ignoreAttributes));
54 - Assert.Equal(@"<Payload Id='FirstX86.msi' FilePath='FirstX86\FirstX86.msi' FileSize='*' Hash='*' DownloadUrl='http://example.com//FirstX86.msi/FirstX86/FirstX86.msi' Packaging='embedded' SourcePath='*' Container='BundlePackages' />", payloads[1].GetTestXml(ignoreAttributes));
55 - Assert.Equal(@"<Payload Id='fk1m38Cf9RZ2Bx_ipinRY6BftelU' FilePath='FirstX86\PFiles\MsiPackage\test.txt' FileSize='*' Hash='*' DownloadUrl='http://example.com/FirstX86.msi/fk1m38Cf9RZ2Bx_ipinRY6BftelU/FirstX86/PFiles/MsiPackage/test.txt' Packaging='embedded' SourcePath='*' Container='BundlePackages' />", payloads[2].GetTestXml(ignoreAttributes));
56 - Assert.Equal(@"<Payload Id='ff2L_N_DLQ.nSUi.l8LxG14gd2V4' FilePath='FirstX64\PFiles\MsiPackage\test.txt' FileSize='*' Hash='*' DownloadUrl='http://example.com/FirstX64/ff2L_N_DLQ.nSUi.l8LxG14gd2V4/FirstX64/PFiles/MsiPackage/test.txt' Packaging='embedded' SourcePath='*' Container='BundlePackages' />", payloads[3].GetTestXml(ignoreAttributes));
52 + var ignoreAttributes = new Dictionary<string, List<string>> { { "Payload", new List<string> { "FileSize", "Hash" } } };
53 + Assert.Equal(@"<Payload Id='FirstX64' FilePath='FirstX64\FirstX64.msi' FileSize='*' Hash='*' DownloadUrl='http://example.com//FirstX64/FirstX64/FirstX64.msi' Packaging='embedded' SourcePath='a0' Container='BundlePackages' />", payloads[0].GetTestXml(ignoreAttributes));
54 + Assert.Equal(@"<Payload Id='FirstX86.msi' FilePath='FirstX86\FirstX86.msi' FileSize='*' Hash='*' DownloadUrl='http://example.com//FirstX86.msi/FirstX86/FirstX86.msi' Packaging='embedded' SourcePath='a1' Container='BundlePackages' />", payloads[1].GetTestXml(ignoreAttributes));
55 + Assert.Equal(@"<Payload Id='fk1m38Cf9RZ2Bx_ipinRY6BftelU' FilePath='FirstX86\PFiles\MsiPackage\test.txt' FileSize='*' Hash='*' DownloadUrl='http://example.com/FirstX86.msi/fk1m38Cf9RZ2Bx_ipinRY6BftelU/FirstX86/PFiles/MsiPackage/test.txt' Packaging='embedded' SourcePath='a2' Container='BundlePackages' />", payloads[2].GetTestXml(ignoreAttributes));
56 + Assert.Equal(@"<Payload Id='ff2L_N_DLQ.nSUi.l8LxG14gd2V4' FilePath='FirstX64\PFiles\MsiPackage\test.txt' FileSize='*' Hash='*' DownloadUrl='http://example.com/FirstX64/ff2L_N_DLQ.nSUi.l8LxG14gd2V4/FirstX64/PFiles/MsiPackage/test.txt' Packaging='embedded' SourcePath='a3' Container='BundlePackages' />", payloads[3].GetTestXml(ignoreAttributes));
57 }
58 }
59
@@ -93,11 +93,11 @@ namespace WixToolsetTest.CoreIntegration
93
94 var payloads = extractResult.SelectManifestNodes("/burn:BurnManifest/burn:Payload");
95 Assert.Equal(4, payloads.Count);
96 - var ignoreAttributes = new Dictionary<string, List<string>> { { "Payload", new List<string> { "FileSize", "Hash", "SourcePath" } } };
97 - Assert.Equal(@"<Payload Id='FirstX86.msi' FilePath='FirstX86.msi' FileSize='*' Hash='*' Packaging='embedded' SourcePath='*' Container='WixAttachedContainer' />", payloads[0].GetTestXml(ignoreAttributes));
98 - Assert.Equal(@"<Payload Id='FirstX64.msi' FilePath='FirstX64.msi' FileSize='*' Hash='*' Packaging='embedded' SourcePath='*' Container='FirstX64' />", payloads[1].GetTestXml(ignoreAttributes));
99 - Assert.Equal(@"<Payload Id='fk1m38Cf9RZ2Bx_ipinRY6BftelU' FilePath='PFiles\MsiPackage\test.txt' FileSize='*' Hash='*' Packaging='embedded' SourcePath='*' Container='WixAttachedContainer' />", payloads[2].GetTestXml(ignoreAttributes));
100 - Assert.Equal(@"<Payload Id='fC0n41rZK8oW3JK8LzHu6AT3CjdQ' FilePath='PFiles\MsiPackage\test.txt' FileSize='*' Hash='*' Packaging='embedded' SourcePath='*' Container='FirstX64' />", payloads[3].GetTestXml(ignoreAttributes));
96 + var ignoreAttributes = new Dictionary<string, List<string>> { { "Payload", new List<string> { "FileSize", "Hash" } } };
97 + Assert.Equal(@"<Payload Id='FirstX86.msi' FilePath='FirstX86.msi' FileSize='*' Hash='*' Packaging='embedded' SourcePath='a0' Container='WixAttachedContainer' />", payloads[0].GetTestXml(ignoreAttributes));
98 + Assert.Equal(@"<Payload Id='FirstX64.msi' FilePath='FirstX64.msi' FileSize='*' Hash='*' Packaging='embedded' SourcePath='a1' Container='FirstX64' />", payloads[1].GetTestXml(ignoreAttributes));
99 + Assert.Equal(@"<Payload Id='fk1m38Cf9RZ2Bx_ipinRY6BftelU' FilePath='PFiles\MsiPackage\test.txt' FileSize='*' Hash='*' Packaging='embedded' SourcePath='a2' Container='WixAttachedContainer' />", payloads[2].GetTestXml(ignoreAttributes));
100 + Assert.Equal(@"<Payload Id='fC0n41rZK8oW3JK8LzHu6AT3CjdQ' FilePath='PFiles\MsiPackage\test.txt' FileSize='*' Hash='*' Packaging='embedded' SourcePath='a3' Container='FirstX64' />", payloads[3].GetTestXml(ignoreAttributes));
101 }
102 }
103
@@ -203,14 +203,14 @@ namespace WixToolsetTest.CoreIntegration
203 var extractResult = BundleExtractor.ExtractBAContainer(null, bundlePath, baFolderPath, extractFolderPath);
204 extractResult.AssertSuccess();
205
206 - var ignoreAttributes = new Dictionary<string, List<string>> { { "Payload", new List<string> { "FileSize", "Hash", "SourcePath" } } };
206 + var ignoreAttributes = new Dictionary<string, List<string>> { { "Payload", new List<string> { "FileSize", "Hash" } } };
207 var payloads = extractResult.SelectManifestNodes("/burn:BurnManifest/burn:Payload[@Id='SharedPayload']")
208 .Cast<XmlElement>()
209 .Select(e => e.GetTestXml(ignoreAttributes))
210 .ToArray();
211 WixAssert.CompareLineByLine(new string[]
212 {
213 - "<Payload Id='SharedPayload' FilePath='LayoutPayloadInContainer.wxs' FileSize='*' Hash='*' LayoutOnly='yes' Packaging='embedded' SourcePath='*' Container='FirstX64' />",
213 + "<Payload Id='SharedPayload' FilePath='LayoutPayloadInContainer.wxs' FileSize='*' Hash='*' LayoutOnly='yes' Packaging='embedded' SourcePath='a1' Container='FirstX64' />",
214 }, payloads);
215 }
216 }
@@ -227,8 +227,8 @@ namespace WixToolsetTest.CoreIntegration
227 var binFolder = Path.Combine(baseFolder, "bin");
228 var bundlePath = Path.Combine(binFolder, "test.exe");
229 var baFolderPath = Path.Combine(baseFolder, "ba");
230 + var attachedFolderPath = Path.Combine(baseFolder, "attached");
231 var extractFolderPath = Path.Combine(baseFolder, "extract");
231 - var tempFolderPath = Path.Combine(baseFolder, "temp");
232
233 this.BuildMsis(folder, intermediateFolder, binFolder);
234
@@ -243,19 +243,27 @@ namespace WixToolsetTest.CoreIntegration
243 "-o", bundlePath
244 });
245
246 - Assert.Equal(0, result.ExitCode);
246 + result.AssertSuccess();
247 Assert.True(File.Exists(bundlePath));
248
249 - Directory.CreateDirectory(tempFolderPath);
250 - using (var burnReader = BurnReader.Open(null, bundlePath))
251 - {
252 - // Extract the BA because that loads the payload target paths from the manifest
253 - Assert.True(burnReader.ExtractUXContainer(baFolderPath, tempFolderPath));
254 - Assert.True(burnReader.ExtractAttachedContainers(extractFolderPath));
255 - }
249 + var extractResult = BundleExtractor.ExtractAllContainers(null, bundlePath, baFolderPath, attachedFolderPath, extractFolderPath);
250 + extractResult.AssertSuccess();
251
257 - Assert.True(File.Exists(Path.Combine(extractFolderPath, "FirstX64", "FirstX64.msi")), "Expected extracted container to contain FirstX64.msi");
258 - Assert.True(File.Exists(Path.Combine(extractFolderPath, "WixAttachedContainer", "FirstX86.msi")), "Expected extracted container to contain FirstX86.msi");
252 + Assert.True(File.Exists(Path.Combine(attachedFolderPath, "FirstX64", "FirstX64.msi")), "Expected extracted container to contain FirstX64.msi");
253 + Assert.True(File.Exists(Path.Combine(attachedFolderPath, "WixAttachedContainer", "FirstX86.msi")), "Expected extracted container to contain FirstX86.msi");
254 +
255 + var ignoreAttributes = new Dictionary<string, List<string>> { { "Payload", new List<string> { "FileSize", "Hash" } } };
256 + var payloads = extractResult.SelectManifestNodes("/burn:BurnManifest/burn:Payload")
257 + .Cast<XmlElement>()
258 + .Select(e => e.GetTestXml(ignoreAttributes))
259 + .ToArray();
260 + WixAssert.CompareLineByLine(new string[]
261 + {
262 + "<Payload Id='FirstX86.msi' FilePath='FirstX86.msi' FileSize='*' Hash='*' Packaging='embedded' SourcePath='a0' Container='WixAttachedContainer' />",
263 + "<Payload Id='FirstX64.msi' FilePath='FirstX64.msi' FileSize='*' Hash='*' Packaging='embedded' SourcePath='a1' Container='FirstX64' />",
264 + "<Payload Id='fk1m38Cf9RZ2Bx_ipinRY6BftelU' FilePath='PFiles\\MsiPackage\\test.txt' FileSize='*' Hash='*' Packaging='embedded' SourcePath='a2' Container='WixAttachedContainer' />",
265 + "<Payload Id='fC0n41rZK8oW3JK8LzHu6AT3CjdQ' FilePath='PFiles\\MsiPackage\\test.txt' FileSize='*' Hash='*' Packaging='embedded' SourcePath='a3' Container='FirstX64' />",
266 + }, payloads);
267 }
268 }
269
@@ -297,14 +305,14 @@ namespace WixToolsetTest.CoreIntegration
305 var extractResult = BundleExtractor.ExtractBAContainer(null, bundlePath, baFolderPath, extractFolderPath);
306 extractResult.AssertSuccess();
307
300 - var ignoreAttributes = new Dictionary<string, List<string>> { { "Payload", new List<string> { "FileSize", "Hash", "SourcePath" } } };
308 + var ignoreAttributes = new Dictionary<string, List<string>> { { "Payload", new List<string> { "FileSize", "Hash" } } };
309 var payloads = extractResult.SelectManifestNodes("/burn:BurnManifest/burn:Payload[@Id='SharedPayload']")
310 .Cast<XmlElement>()
311 .Select(e => e.GetTestXml(ignoreAttributes))
312 .ToArray();
313 WixAssert.CompareLineByLine(new string[]
314 {
307 - "<Payload Id='SharedPayload' FilePath='PayloadInMultipleContainers.wxs' FileSize='*' Hash='*' Packaging='embedded' SourcePath='*' Container='FirstX86' />",
315 + "<Payload Id='SharedPayload' FilePath='PayloadInMultipleContainers.wxs' FileSize='*' Hash='*' Packaging='embedded' SourcePath='a2' Container='FirstX86' />",
316 }, payloads);
317 }
318 }
src/wix/test/WixToolsetTest.CoreIntegration/PackagePayloadFixture.cs
+1 -2
@@ -46,14 +46,13 @@ namespace WixToolsetTest.CoreIntegration
46 var ignoreAttributesByElementName = new Dictionary<string, List<string>>
47 {
48 { "ExePackage", new List<string> { "CacheId", "InstallSize", "Size" } },
49 - { "Payload", new List<string> { "SourcePath" } },
49 };
50 Assert.Equal(1, exePackageElements.Count);
51 Assert.Equal("<ExePackage Id='PackagePayloadInPayloadGroup' Cache='keep' CacheId='*' InstallSize='*' Size='*' PerMachine='yes' Permanent='yes' Vital='yes' RollbackBoundaryForward='WixDefaultBoundary' RollbackBoundaryBackward='WixDefaultBoundary' LogPathVariable='WixBundleLog_PackagePayloadInPayloadGroup' RollbackLogPathVariable='WixBundleRollbackLog_PackagePayloadInPayloadGroup' DetectCondition='none' InstallArguments='' UninstallArguments='' RepairArguments='' Repairable='no'><PayloadRef Id='burn.exe' /></ExePackage>", exePackageElements[0].GetTestXml(ignoreAttributesByElementName));
52
53 var payloadElements = extractResult.SelectManifestNodes("/burn:BurnManifest/burn:Payload[@Id='burn.exe']");
54 Assert.Equal(1, payloadElements.Count);
56 - Assert.Equal("<Payload Id='burn.exe' FilePath='burn.exe' FileSize='463360' Hash='F6E722518AC3AB7E31C70099368D5770788C179AA23226110DCF07319B1E1964E246A1E8AE72E2CF23E0138AFC281BAFDE45969204405E114EB20C8195DA7E5E' Packaging='embedded' SourcePath='*' Container='WixAttachedContainer' />", payloadElements[0].GetTestXml(ignoreAttributesByElementName));
55 + Assert.Equal("<Payload Id='burn.exe' FilePath='burn.exe' FileSize='463360' Hash='F6E722518AC3AB7E31C70099368D5770788C179AA23226110DCF07319B1E1964E246A1E8AE72E2CF23E0138AFC281BAFDE45969204405E114EB20C8195DA7E5E' Packaging='embedded' SourcePath='a0' Container='WixAttachedContainer' />", payloadElements[0].GetTestXml());
56 }
57 }
58
src/wix/test/WixToolsetTest.CoreIntegration/PayloadFixture.cs
+8 -9
@@ -189,15 +189,14 @@ namespace WixToolsetTest.CoreIntegration
189 .Cast<XmlElement>()
190 .Select(e => e.GetTestXml(ignoreAttributesByElementName))
191 .ToArray();
192 -
193 - var ignoreAttributes = new Dictionary<string, List<string>> { { "Payload", new List<string> { "FileSize", "Hash"} } };
194 - var ignoreAttributesWithSrc = new Dictionary<string, List<string>> { { "Payload", new List<string> { "FileSize", "Hash", "SourcePath" } } };
195 - Assert.Equal(5, payloads.Length);
196 - Assert.Equal(@"<Payload Id='burn.exe' FilePath='burn.exe' FileSize='*' Hash='*' Packaging='embedded' SourcePath='*' Container='PackagesContainer' />", payloads[0].GetTestXml(ignoreAttributesWithSrc));
197 - Assert.Equal(@"<Payload Id='test.msi' FilePath='test.msi' FileSize='*' Hash='*' DownloadUrl='http://example.com/id/test.msi/test.msi' Packaging='external' SourcePath='test.msi' />", payloads[1].GetTestXml(ignoreAttributes));
198 - Assert.Equal(@"<Payload Id='LayoutOnlyPayload' FilePath='DownloadUrlPlaceholdersBundle.wxs' FileSize='*' Hash='*' LayoutOnly='yes' DownloadUrl='http://example.com/id/LayoutOnlyPayload/DownloadUrlPlaceholdersBundle.wxs' Packaging='external' SourcePath='DownloadUrlPlaceholdersBundle.wxs' />", payloads[2].GetTestXml(ignoreAttributes));
199 - Assert.Equal(@"<Payload Id='fhuZsOcBDTuIX8rF96kswqI6SnuI' FilePath='MsiPackage\test.txt' FileSize='*' Hash='*' DownloadUrl='http://example.com/test.msiid/fhuZsOcBDTuIX8rF96kswqI6SnuI/MsiPackage/test.txt' Packaging='external' SourcePath='MsiPackage\test.txt' />", payloads[3].GetTestXml(ignoreAttributes));
200 - Assert.Equal(@"<Payload Id='faf_OZ741BG7SJ6ZkcIvivZ2Yzo8' FilePath='MsiPackage\Shared.dll' FileSize='*' Hash='*' DownloadUrl='http://example.com/test.msiid/faf_OZ741BG7SJ6ZkcIvivZ2Yzo8/MsiPackage/Shared.dll' Packaging='external' SourcePath='MsiPackage\Shared.dll' />", payloads[4].GetTestXml(ignoreAttributes));
192 + WixAssert.CompareLineByLine(new string[]
193 + {
194 + "<Payload Id='burn.exe' FilePath='burn.exe' FileSize='*' Hash='*' Packaging='embedded' SourcePath='a0' Container='PackagesContainer' />",
195 + "<Payload Id='test.msi' FilePath='test.msi' FileSize='*' Hash='*' DownloadUrl='http://example.com/id/test.msi/test.msi' Packaging='external' SourcePath='test.msi' />",
196 + "<Payload Id='LayoutOnlyPayload' FilePath='DownloadUrlPlaceholdersBundle.wxs' FileSize='*' Hash='*' LayoutOnly='yes' DownloadUrl='http://example.com/id/LayoutOnlyPayload/DownloadUrlPlaceholdersBundle.wxs' Packaging='external' SourcePath='DownloadUrlPlaceholdersBundle.wxs' />",
197 + @"<Payload Id='fhuZsOcBDTuIX8rF96kswqI6SnuI' FilePath='MsiPackage\test.txt' FileSize='*' Hash='*' DownloadUrl='http://example.com/test.msiid/fhuZsOcBDTuIX8rF96kswqI6SnuI/MsiPackage/test.txt' Packaging='external' SourcePath='MsiPackage\test.txt' />",
198 + @"<Payload Id='faf_OZ741BG7SJ6ZkcIvivZ2Yzo8' FilePath='MsiPackage\Shared.dll' FileSize='*' Hash='*' DownloadUrl='http://example.com/test.msiid/faf_OZ741BG7SJ6ZkcIvivZ2Yzo8/MsiPackage/Shared.dll' Packaging='external' SourcePath='MsiPackage\Shared.dll' />",
199 + }, payloads);
200
201 var containers = extractResult.SelectManifestNodes("/burn:BurnManifest/burn:Container")
202 .Cast<XmlElement>()