aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore2
-rw-r--r--src/burn/engine/apply.cpp2
-rw-r--r--src/burn/engine/burnextension.cpp11
-rw-r--r--src/burn/engine/burnextension.h1
-rw-r--r--src/burn/engine/container.cpp3
-rw-r--r--src/burn/engine/container.h3
-rw-r--r--src/burn/engine/manifest.h2
-rw-r--r--src/burn/engine/payload.cpp80
-rw-r--r--src/burn/engine/payload.h3
-rw-r--r--src/burn/engine/userexperience.h2
-rw-r--r--src/libs/dutil/WixToolset.DUtil/dictutil.cpp128
-rw-r--r--src/test/burn/TestData/Manual/BundleB/Bundle.wxs56
-rw-r--r--src/test/burn/TestData/Manual/BundleB/BundleB.wixproj32
-rw-r--r--src/test/burn/TestData/Manual/BundleB/BundleB.wxs15
-rw-r--r--src/test/burn/TestData/Manual/BundleB/ba.xslt21
-rw-r--r--src/test/burn/TestData/Manual/BundleB/package.xslt21
-rw-r--r--src/test/burn/TestExe/Task.cs22
-rw-r--r--src/wix/WixToolset.Core.Burn/Bind/BindBundleCommand.cs7
-rw-r--r--src/wix/WixToolset.Core.Burn/Bundles/CreateBurnManifestCommand.cs5
-rw-r--r--src/wix/WixToolset.Core/Compile/CompilerPayload.cs4
-rw-r--r--src/wix/WixToolset.Core/Compiler_Bundle.cs70
-rw-r--r--src/wix/WixToolset.Core/Link/WixGroupingOrdering.cs3
-rw-r--r--src/wix/test/WixToolsetTest.CoreIntegration/BundleManifestFixture.cs10
23 files changed, 317 insertions, 186 deletions
diff --git a/.gitignore b/.gitignore
index cb613709..3dc0e69a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -399,3 +399,5 @@ build/.tools/
399 399
400# Ignore generated test data 400# Ignore generated test data
401src/test/burn/TestData/CacheTests/BundleC/fivegb.file 401src/test/burn/TestData/CacheTests/BundleC/fivegb.file
402src/test/burn/TestData/Manual/BundleB/BAPayloads
403src/test/burn/TestData/Manual/BundleB/PackagePayloads
diff --git a/src/burn/engine/apply.cpp b/src/burn/engine/apply.cpp
index a99a3987..c126d63c 100644
--- a/src/burn/engine/apply.cpp
+++ b/src/burn/engine/apply.cpp
@@ -1175,7 +1175,7 @@ static HRESULT ExtractContainer(
1175 { 1175 {
1176 BOOL fExtracted = FALSE; 1176 BOOL fExtracted = FALSE;
1177 1177
1178 hr = PayloadFindEmbeddedBySourcePath(pContext->pPayloads, sczStreamName, &pExtract); 1178 hr = PayloadFindEmbeddedBySourcePath(pContainer->sdhPayloads, sczStreamName, &pExtract);
1179 if (E_NOTFOUND != hr) 1179 if (E_NOTFOUND != hr)
1180 { 1180 {
1181 ExitOnFailure(hr, "Failed to find embedded payload by source path: %ls container: %ls", sczStreamName, pContainer->sczId); 1181 ExitOnFailure(hr, "Failed to find embedded payload by source path: %ls container: %ls", sczStreamName, pContainer->sczId);
diff --git a/src/burn/engine/burnextension.cpp b/src/burn/engine/burnextension.cpp
index 475df1c5..ee4b1542 100644
--- a/src/burn/engine/burnextension.cpp
+++ b/src/burn/engine/burnextension.cpp
@@ -26,6 +26,7 @@ EXTERN_C HRESULT BurnExtensionParseFromXml(
26 IXMLDOMNodeList* pixnNodes = NULL; 26 IXMLDOMNodeList* pixnNodes = NULL;
27 IXMLDOMNode* pixnNode = NULL; 27 IXMLDOMNode* pixnNode = NULL;
28 DWORD cNodes = 0; 28 DWORD cNodes = 0;
29 LPWSTR scz = NULL;
29 30
30 // Select BundleExtension nodes. 31 // Select BundleExtension nodes.
31 hr = XmlSelectNodes(pixnBundle, L"BundleExtension", &pixnNodes); 32 hr = XmlSelectNodes(pixnBundle, L"BundleExtension", &pixnNodes);
@@ -59,11 +60,11 @@ EXTERN_C HRESULT BurnExtensionParseFromXml(
59 ExitOnFailure(hr, "Failed to get @Id."); 60 ExitOnFailure(hr, "Failed to get @Id.");
60 61
61 // @EntryPayloadId 62 // @EntryPayloadId
62 hr = XmlGetAttributeEx(pixnNode, L"EntryPayloadId", &pExtension->sczEntryPayloadId); 63 hr = XmlGetAttributeEx(pixnNode, L"EntryPayloadSourcePath", &scz);
63 ExitOnFailure(hr, "Failed to get @EntryPayloadId."); 64 ExitOnFailure(hr, "Failed to get @EntryPayloadSourcePath.");
64 65
65 hr = PayloadFindById(pBaPayloads, pExtension->sczEntryPayloadId, &pExtension->pEntryPayload); 66 hr = PayloadFindEmbeddedBySourcePath(pBaPayloads->sdhPayloads, scz, &pExtension->pEntryPayload);
66 ExitOnFailure(hr, "Failed to find BundleExtension EntryPayload '%ls'.", pExtension->sczEntryPayloadId); 67 ExitOnFailure(hr, "Failed to find BundleExtension EntryPayload '%ls'.", pExtension->sczId);
67 68
68 // prepare next iteration 69 // prepare next iteration
69 ReleaseNullObject(pixnNode); 70 ReleaseNullObject(pixnNode);
@@ -72,6 +73,7 @@ EXTERN_C HRESULT BurnExtensionParseFromXml(
72 hr = S_OK; 73 hr = S_OK;
73 74
74LExit: 75LExit:
76 ReleaseStr(scz);
75 ReleaseObject(pixnNode); 77 ReleaseObject(pixnNode);
76 ReleaseObject(pixnNodes); 78 ReleaseObject(pixnNodes);
77 79
@@ -92,7 +94,6 @@ EXTERN_C void BurnExtensionUninitialize(
92 { 94 {
93 BURN_EXTENSION* pExtension = &pBurnExtensions->rgExtensions[i]; 95 BURN_EXTENSION* pExtension = &pBurnExtensions->rgExtensions[i];
94 96
95 ReleaseStr(pExtension->sczEntryPayloadId);
96 ReleaseStr(pExtension->sczId); 97 ReleaseStr(pExtension->sczId);
97 } 98 }
98 MemFree(pBurnExtensions->rgExtensions); 99 MemFree(pBurnExtensions->rgExtensions);
diff --git a/src/burn/engine/burnextension.h b/src/burn/engine/burnextension.h
index 370ddd2d..3529ef38 100644
--- a/src/burn/engine/burnextension.h
+++ b/src/burn/engine/burnextension.h
@@ -13,7 +13,6 @@ typedef struct _BURN_EXTENSION_ENGINE_CONTEXT BURN_EXTENSION_ENGINE_CONTEXT;
13 13
14typedef struct _BURN_EXTENSION 14typedef struct _BURN_EXTENSION
15{ 15{
16 LPWSTR sczEntryPayloadId;
17 LPWSTR sczId; 16 LPWSTR sczId;
18 17
19 BURN_PAYLOAD* pEntryPayload; 18 BURN_PAYLOAD* pEntryPayload;
diff --git a/src/burn/engine/container.cpp b/src/burn/engine/container.cpp
index c6f2ada8..aa123927 100644
--- a/src/burn/engine/container.cpp
+++ b/src/burn/engine/container.cpp
@@ -35,7 +35,7 @@ extern "C" HRESULT ContainersParseFromXml(
35 35
36 pContainers->cContainers = cNodes; 36 pContainers->cContainers = cNodes;
37 37
38 // parse search elements 38 // parse container elements
39 for (DWORD i = 0; i < cNodes; ++i) 39 for (DWORD i = 0; i < cNodes; ++i)
40 { 40 {
41 BURN_CONTAINER* pContainer = &pContainers->rgContainers[i]; 41 BURN_CONTAINER* pContainer = &pContainers->rgContainers[i];
@@ -181,6 +181,7 @@ extern "C" void ContainersUninitialize(
181 ReleaseStr(pContainer->downloadSource.sczUser); 181 ReleaseStr(pContainer->downloadSource.sczUser);
182 ReleaseStr(pContainer->downloadSource.sczPassword); 182 ReleaseStr(pContainer->downloadSource.sczPassword);
183 ReleaseStr(pContainer->sczUnverifiedPath); 183 ReleaseStr(pContainer->sczUnverifiedPath);
184 ReleaseDict(pContainer->sdhPayloads);
184 } 185 }
185 MemFree(pContainers->rgContainers); 186 MemFree(pContainers->rgContainers);
186 } 187 }
diff --git a/src/burn/engine/container.h b/src/burn/engine/container.h
index d454a248..f35f1da5 100644
--- a/src/burn/engine/container.h
+++ b/src/burn/engine/container.h
@@ -72,6 +72,9 @@ typedef struct _BURN_CONTAINER
72 LPWSTR sczFilePath; // relative path to container. 72 LPWSTR sczFilePath; // relative path to container.
73 DOWNLOAD_SOURCE downloadSource; 73 DOWNLOAD_SOURCE downloadSource;
74 74
75 DWORD cParsedPayloads;
76 STRINGDICT_HANDLE sdhPayloads; // value is BURN_PAYLOAD*
77
75 BYTE* pbHash; 78 BYTE* pbHash;
76 DWORD cbHash; 79 DWORD cbHash;
77 BURN_CONTAINER_VERIFICATION verification; 80 BURN_CONTAINER_VERIFICATION verification;
diff --git a/src/burn/engine/manifest.h b/src/burn/engine/manifest.h
index 8c527279..40748c52 100644
--- a/src/burn/engine/manifest.h
+++ b/src/burn/engine/manifest.h
@@ -2,8 +2,6 @@
2// 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// 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.
3 3
4 4
5interface IBurnPayload; // forward declare.
6
7#if defined(__cplusplus) 5#if defined(__cplusplus)
8extern "C" { 6extern "C" {
9#endif 7#endif
diff --git a/src/burn/engine/payload.cpp b/src/burn/engine/payload.cpp
index 84c32eec..e0362a76 100644
--- a/src/burn/engine/payload.cpp
+++ b/src/burn/engine/payload.cpp
@@ -5,13 +5,6 @@
5 5
6// internal function declarations 6// internal function declarations
7 7
8static HRESULT FindEmbeddedBySourcePath(
9 __in BURN_PAYLOADS* pPayloads,
10 __in_opt BURN_CONTAINER* pContainer,
11 __in_z LPCWSTR wzStreamName,
12 __out BURN_PAYLOAD** ppPayload
13 );
14
15 8
16// function definitions 9// function definitions
17 10
@@ -29,6 +22,7 @@ extern "C" HRESULT PayloadsParseFromXml(
29 LPWSTR scz = NULL; 22 LPWSTR scz = NULL;
30 BOOL fChainPayload = pContainers && pLayoutPayloads; // These are required when parsing chain payloads. 23 BOOL fChainPayload = pContainers && pLayoutPayloads; // These are required when parsing chain payloads.
31 BOOL fValidFileSize = FALSE; 24 BOOL fValidFileSize = FALSE;
25 size_t cByteOffset = fChainPayload ? offsetof(BURN_PAYLOAD, sczKey) : offsetof(BURN_PAYLOAD, sczSourcePath);
32 26
33 // select payload nodes 27 // select payload nodes
34 hr = XmlSelectNodes(pixnBundle, L"Payload", &pixnNodes); 28 hr = XmlSelectNodes(pixnBundle, L"Payload", &pixnNodes);
@@ -49,7 +43,11 @@ extern "C" HRESULT PayloadsParseFromXml(
49 43
50 pPayloads->cPayloads = cNodes; 44 pPayloads->cPayloads = cNodes;
51 45
52 // parse search elements 46 // create dictionary for payloads
47 hr = DictCreateWithEmbeddedKey(&pPayloads->sdhPayloads, pPayloads->cPayloads, reinterpret_cast<void**>(&pPayloads->rgPayloads), cByteOffset, DICT_FLAG_NONE);
48 ExitOnFailure(hr, "Failed to create dictionary for payloads.");
49
50 // parse payload elements
53 for (DWORD i = 0; i < cNodes; ++i) 51 for (DWORD i = 0; i < cNodes; ++i)
54 { 52 {
55 BURN_PAYLOAD* pPayload = &pPayloads->rgPayloads[i]; 53 BURN_PAYLOAD* pPayload = &pPayloads->rgPayloads[i];
@@ -104,6 +102,8 @@ extern "C" HRESULT PayloadsParseFromXml(
104 // find container 102 // find container
105 hr = ContainerFindById(pContainers, scz, &pPayload->pContainer); 103 hr = ContainerFindById(pContainers, scz, &pPayload->pContainer);
106 ExitOnFailure(hr, "Failed to to find container: %ls", scz); 104 ExitOnFailure(hr, "Failed to to find container: %ls", scz);
105
106 pPayload->pContainer->cParsedPayloads += 1;
107 } 107 }
108 108
109 // @LayoutOnly 109 // @LayoutOnly
@@ -190,12 +190,37 @@ extern "C" HRESULT PayloadsParseFromXml(
190 } 190 }
191 } 191 }
192 192
193 hr = DictAddValue(pPayloads->sdhPayloads, pPayload);
194 ExitOnFailure(hr, "Failed to add payload to payloads dictionary.");
195
193 // prepare next iteration 196 // prepare next iteration
194 ReleaseNullObject(pixnNode); 197 ReleaseNullObject(pixnNode);
195 } 198 }
196 199
197 hr = S_OK; 200 hr = S_OK;
198 201
202 if (pContainers && pContainers->cContainers)
203 {
204 for (DWORD i = 0; i < pPayloads->cPayloads; ++i)
205 {
206 BURN_PAYLOAD* pPayload = &pPayloads->rgPayloads[i];
207 BURN_CONTAINER* pContainer = pPayload->pContainer;
208
209 if (!pContainer)
210 {
211 continue;
212 }
213 else if (!pContainer->sdhPayloads)
214 {
215 hr = DictCreateWithEmbeddedKey(&pContainer->sdhPayloads, pContainer->cParsedPayloads, NULL, offsetof(BURN_PAYLOAD, sczSourcePath), DICT_FLAG_NONE);
216 ExitOnFailure(hr, "Failed to create dictionary for container payloads.");
217 }
218
219 hr = DictAddValue(pContainer->sdhPayloads, pPayload);
220 ExitOnFailure(hr, "Failed to add payload to container dictionary.");
221 }
222 }
223
199LExit: 224LExit:
200 ReleaseObject(pixnNodes); 225 ReleaseObject(pixnNodes);
201 ReleaseObject(pixnNode); 226 ReleaseObject(pixnNode);
@@ -237,6 +262,8 @@ extern "C" void PayloadsUninitialize(
237 MemFree(pPayloads->rgPayloads); 262 MemFree(pPayloads->rgPayloads);
238 } 263 }
239 264
265 ReleaseDict(pPayloads->sdhPayloads);
266
240 // clear struct 267 // clear struct
241 memset(pPayloads, 0, sizeof(BURN_PAYLOADS)); 268 memset(pPayloads, 0, sizeof(BURN_PAYLOADS));
242} 269}
@@ -265,7 +292,7 @@ extern "C" HRESULT PayloadExtractUXContainer(
265 ExitOnFailure(hr, "Failed to get next stream."); 292 ExitOnFailure(hr, "Failed to get next stream.");
266 293
267 // find payload by stream name 294 // find payload by stream name
268 hr = PayloadFindEmbeddedBySourcePath(pPayloads, sczStreamName, &pPayload); 295 hr = PayloadFindEmbeddedBySourcePath(pPayloads->sdhPayloads, sczStreamName, &pPayload);
269 ExitOnFailure(hr, "Failed to find embedded payload: %ls", sczStreamName); 296 ExitOnFailure(hr, "Failed to find embedded payload: %ls", sczStreamName);
270 297
271 // make file path 298 // make file path
@@ -313,51 +340,22 @@ extern "C" HRESULT PayloadFindById(
313 ) 340 )
314{ 341{
315 HRESULT hr = S_OK; 342 HRESULT hr = S_OK;
316 BURN_PAYLOAD* pPayload = NULL;
317 343
318 for (DWORD i = 0; i < pPayloads->cPayloads; ++i) 344 hr = DictGetValue(pPayloads->sdhPayloads, wzId, reinterpret_cast<void**>(ppPayload));
319 {
320 pPayload = &pPayloads->rgPayloads[i];
321
322 if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, pPayload->sczKey, -1, wzId, -1))
323 {
324 *ppPayload = pPayload;
325 ExitFunction1(hr = S_OK);
326 }
327 }
328 345
329 hr = E_NOTFOUND;
330
331LExit:
332 return hr; 346 return hr;
333} 347}
334 348
335extern "C" HRESULT PayloadFindEmbeddedBySourcePath( 349extern "C" HRESULT PayloadFindEmbeddedBySourcePath(
336 __in BURN_PAYLOADS* pPayloads, 350 __in STRINGDICT_HANDLE sdhPayloads,
337 __in_z LPCWSTR wzStreamName, 351 __in_z LPCWSTR wzStreamName,
338 __out BURN_PAYLOAD** ppPayload 352 __out BURN_PAYLOAD** ppPayload
339 ) 353 )
340{ 354{
341 HRESULT hr = S_OK; 355 HRESULT hr = S_OK;
342 BURN_PAYLOAD* pPayload = NULL;
343 356
344 for (DWORD i = 0; i < pPayloads->cPayloads; ++i) 357 hr = DictGetValue(sdhPayloads, wzStreamName, reinterpret_cast<void**>(ppPayload));
345 {
346 pPayload = &pPayloads->rgPayloads[i];
347
348 if (BURN_PAYLOAD_PACKAGING_EMBEDDED == pPayload->packaging)
349 {
350 if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, pPayload->sczSourcePath, -1, wzStreamName, -1))
351 {
352 *ppPayload = pPayload;
353 ExitFunction1(hr = S_OK);
354 }
355 }
356 }
357 358
358 hr = E_NOTFOUND;
359
360LExit:
361 return hr; 359 return hr;
362} 360}
363 361
diff --git a/src/burn/engine/payload.h b/src/burn/engine/payload.h
index c12fbe66..14738506 100644
--- a/src/burn/engine/payload.h
+++ b/src/burn/engine/payload.h
@@ -66,6 +66,7 @@ typedef struct _BURN_PAYLOADS
66{ 66{
67 BURN_PAYLOAD* rgPayloads; 67 BURN_PAYLOAD* rgPayloads;
68 DWORD cPayloads; 68 DWORD cPayloads;
69 STRINGDICT_HANDLE sdhPayloads; // value is BURN_PAYLOAD*
69} BURN_PAYLOADS; 70} BURN_PAYLOADS;
70 71
71typedef struct _BURN_PAYLOAD_GROUP_ITEM 72typedef struct _BURN_PAYLOAD_GROUP_ITEM
@@ -109,7 +110,7 @@ HRESULT PayloadFindById(
109 __out BURN_PAYLOAD** ppPayload 110 __out BURN_PAYLOAD** ppPayload
110 ); 111 );
111HRESULT PayloadFindEmbeddedBySourcePath( 112HRESULT PayloadFindEmbeddedBySourcePath(
112 __in BURN_PAYLOADS* pPayloads, 113 __in STRINGDICT_HANDLE sdhPayloads,
113 __in_z LPCWSTR wzStreamName, 114 __in_z LPCWSTR wzStreamName,
114 __out BURN_PAYLOAD** ppPayload 115 __out BURN_PAYLOAD** ppPayload
115 ); 116 );
diff --git a/src/burn/engine/userexperience.h b/src/burn/engine/userexperience.h
index 6a5ae697..584bef14 100644
--- a/src/burn/engine/userexperience.h
+++ b/src/burn/engine/userexperience.h
@@ -15,7 +15,7 @@ const DWORD MB_RETRYTRYAGAIN = 0xF;
15 15
16// structs 16// structs
17 17
18typedef struct _BOOTSTRAPPER_ENGINE_CONTEXT BOOTSTRAPPER_ENGINE_CONTEXT; 18typedef struct _BOOTSTRAPPER_ENGINE_CONTEXT BOOTSTRAPPER_ENGINE_CONTEXT; // forward declare
19 19
20typedef struct _BURN_USER_EXPERIENCE 20typedef struct _BURN_USER_EXPERIENCE
21{ 21{
diff --git a/src/libs/dutil/WixToolset.DUtil/dictutil.cpp b/src/libs/dutil/WixToolset.DUtil/dictutil.cpp
index 0d0743eb..09b150df 100644
--- a/src/libs/dutil/WixToolset.DUtil/dictutil.cpp
+++ b/src/libs/dutil/WixToolset.DUtil/dictutil.cpp
@@ -72,6 +72,14 @@ struct STRINGDICT_STRUCT
72 72
73const int STRINGDICT_HANDLE_BYTES = sizeof(STRINGDICT_STRUCT); 73const int STRINGDICT_HANDLE_BYTES = sizeof(STRINGDICT_STRUCT);
74 74
75static HRESULT CreateDict(
76 __out_bcount(STRINGDICT_HANDLE_BYTES) STRINGDICT_HANDLE* psdHandle,
77 __in DICT_TYPE dtType,
78 __in DWORD dwNumExpectedItems,
79 __in_opt void** ppvArray,
80 __in size_t cByteOffset,
81 __in DICT_FLAG dfFlags
82 );
75static HRESULT StringHash( 83static HRESULT StringHash(
76 __in const STRINGDICT_STRUCT *psd, 84 __in const STRINGDICT_STRUCT *psd,
77 __in DWORD dwNumBuckets, 85 __in DWORD dwNumBuckets,
@@ -135,41 +143,7 @@ extern "C" HRESULT DAPI DictCreateWithEmbeddedKey(
135 __in DICT_FLAG dfFlags 143 __in DICT_FLAG dfFlags
136 ) 144 )
137{ 145{
138 HRESULT hr = S_OK; 146 return CreateDict(psdHandle, DICT_EMBEDDED_KEY, dwNumExpectedItems, ppvArray, cByteOffset, dfFlags);
139
140 DictExitOnNull(psdHandle, hr, E_INVALIDARG, "Handle not specified while creating dict");
141
142 // Allocate the handle
143 *psdHandle = static_cast<STRINGDICT_HANDLE>(MemAlloc(sizeof(STRINGDICT_STRUCT), FALSE));
144 DictExitOnNull(*psdHandle, hr, E_OUTOFMEMORY, "Failed to allocate dictionary object");
145
146 STRINGDICT_STRUCT *psd = static_cast<STRINGDICT_STRUCT *>(*psdHandle);
147
148 // Fill out the new handle's values
149 psd->dtType = DICT_EMBEDDED_KEY;
150 psd->dfFlags = dfFlags;
151 psd->cByteOffset = cByteOffset;
152 psd->dwBucketSizeIndex = 0;
153 psd->dwNumItems = 0;
154 psd->ppvItemList = NULL;
155 psd->ppvValueArray = ppvArray;
156
157 // Make psd->dwBucketSizeIndex point to the appropriate spot in the prime
158 // array based on expected number of items and items to buckets ratio
159 // Careful: the "-1" in "countof(MAX_BUCKET_SIZES)-1" ensures we don't end
160 // this loop past the end of the array!
161 while (psd->dwBucketSizeIndex < (countof(MAX_BUCKET_SIZES)-1) &&
162 MAX_BUCKET_SIZES[psd->dwBucketSizeIndex] < dwNumExpectedItems * MAX_BUCKETS_TO_ITEMS_RATIO)
163 {
164 ++psd->dwBucketSizeIndex;
165 }
166
167 // Finally, allocate our initial buckets
168 psd->ppvBuckets = static_cast<void**>(MemAlloc(sizeof(void *) * MAX_BUCKET_SIZES[psd->dwBucketSizeIndex], TRUE));
169 DictExitOnNull(psd->ppvBuckets, hr, E_OUTOFMEMORY, "Failed to allocate buckets for dictionary");
170
171LExit:
172 return hr;
173} 147}
174 148
175// The dict will store a set of keys, with no values associated with them. Use DictAddKey() and DictKeyExists() with this dictionary type. 149// The dict will store a set of keys, with no values associated with them. Use DictAddKey() and DictKeyExists() with this dictionary type.
@@ -179,41 +153,7 @@ extern "C" HRESULT DAPI DictCreateStringList(
179 __in DICT_FLAG dfFlags 153 __in DICT_FLAG dfFlags
180 ) 154 )
181{ 155{
182 HRESULT hr = S_OK; 156 return CreateDict(psdHandle, DICT_STRING_LIST, dwNumExpectedItems, NULL, 0, dfFlags);
183
184 DictExitOnNull(psdHandle, hr, E_INVALIDARG, "Handle not specified while creating dict");
185
186 // Allocate the handle
187 *psdHandle = static_cast<STRINGDICT_HANDLE>(MemAlloc(sizeof(STRINGDICT_STRUCT), FALSE));
188 DictExitOnNull(*psdHandle, hr, E_OUTOFMEMORY, "Failed to allocate dictionary object");
189
190 STRINGDICT_STRUCT *psd = static_cast<STRINGDICT_STRUCT *>(*psdHandle);
191
192 // Fill out the new handle's values
193 psd->dtType = DICT_STRING_LIST;
194 psd->dfFlags = dfFlags;
195 psd->cByteOffset = 0;
196 psd->dwBucketSizeIndex = 0;
197 psd->dwNumItems = 0;
198 psd->ppvItemList = NULL;
199 psd->ppvValueArray = NULL;
200
201 // Make psd->dwBucketSizeIndex point to the appropriate spot in the prime
202 // array based on expected number of items and items to buckets ratio
203 // Careful: the "-1" in "countof(MAX_BUCKET_SIZES)-1" ensures we don't end
204 // this loop past the end of the array!
205 while (psd->dwBucketSizeIndex < (countof(MAX_BUCKET_SIZES)-1) &&
206 MAX_BUCKET_SIZES[psd->dwBucketSizeIndex] < dwNumExpectedItems * MAX_BUCKETS_TO_ITEMS_RATIO)
207 {
208 ++psd->dwBucketSizeIndex;
209 }
210
211 // Finally, allocate our initial buckets
212 psd->ppvBuckets = static_cast<void**>(MemAlloc(sizeof(void *) * MAX_BUCKET_SIZES[psd->dwBucketSizeIndex], TRUE));
213 DictExitOnNull(psd->ppvBuckets, hr, E_OUTOFMEMORY, "Failed to allocate buckets for dictionary");
214
215LExit:
216 return hr;
217} 157}
218 158
219extern "C" HRESULT DAPI DictCreateStringListFromArray( 159extern "C" HRESULT DAPI DictCreateStringListFromArray(
@@ -467,6 +407,54 @@ extern "C" void DAPI DictDestroy(
467 ReleaseMem(psd); 407 ReleaseMem(psd);
468} 408}
469 409
410static HRESULT CreateDict(
411 __out_bcount(STRINGDICT_HANDLE_BYTES) STRINGDICT_HANDLE* psdHandle,
412 __in DICT_TYPE dtType,
413 __in DWORD dwNumExpectedItems,
414 __in_opt void** ppvArray,
415 __in size_t cByteOffset,
416 __in DICT_FLAG dfFlags
417 )
418{
419 HRESULT hr = S_OK;
420
421 DictExitOnNull(psdHandle, hr, E_INVALIDARG, "Handle not specified while creating dict.");
422
423 // Allocate the handle
424 *psdHandle = static_cast<STRINGDICT_HANDLE>(MemAlloc(sizeof(STRINGDICT_STRUCT), TRUE));
425 DictExitOnNull(*psdHandle, hr, E_OUTOFMEMORY, "Failed to allocate dictionary object.");
426
427 STRINGDICT_STRUCT* psd = static_cast<STRINGDICT_STRUCT*>(*psdHandle);
428
429 // Fill out the new handle's values
430 psd->dtType = dtType;
431 psd->dfFlags = dfFlags;
432 psd->cByteOffset = cByteOffset;
433 psd->ppvValueArray = ppvArray;
434
435 // Make psd->dwBucketSizeIndex point to the appropriate spot in the prime
436 // array based on expected number of items and items to buckets ratio
437 // Careful: the "-1" in "countof(MAX_BUCKET_SIZES)-1" ensures we don't end
438 // this loop past the end of the array!
439 while (psd->dwBucketSizeIndex < (countof(MAX_BUCKET_SIZES) - 1) &&
440 MAX_BUCKET_SIZES[psd->dwBucketSizeIndex] < dwNumExpectedItems * MAX_BUCKETS_TO_ITEMS_RATIO)
441 {
442 ++psd->dwBucketSizeIndex;
443 }
444
445 hr = MemAllocArray(reinterpret_cast<LPVOID*>(&psd->ppvBuckets), sizeof(void*), MAX_BUCKET_SIZES[psd->dwBucketSizeIndex]);
446 DictExitOnFailure(hr, "Failed to allocate buckets for dictionary.");
447
448 if (dwNumExpectedItems)
449 {
450 hr = MemAllocArray(reinterpret_cast<LPVOID*>(&psd->ppvItemList), sizeof(void*), dwNumExpectedItems);
451 DictExitOnFailure(hr, "Failed to pre-allocate item list for dictionary.");
452 }
453
454LExit:
455 return hr;
456}
457
470static HRESULT StringHash( 458static HRESULT StringHash(
471 __in const STRINGDICT_STRUCT *psd, 459 __in const STRINGDICT_STRUCT *psd,
472 __in DWORD dwNumBuckets, 460 __in DWORD dwNumBuckets,
diff --git a/src/test/burn/TestData/Manual/BundleB/Bundle.wxs b/src/test/burn/TestData/Manual/BundleB/Bundle.wxs
new file mode 100644
index 00000000..615d4b1d
--- /dev/null
+++ b/src/test/burn/TestData/Manual/BundleB/Bundle.wxs
@@ -0,0 +1,56 @@
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<?ifndef Version?>
4<?define Version = 1.0.0.0?>
5<?endif?>
6
7<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs" xmlns:bal="http://wixtoolset.org/schemas/v4/wxs/bal">
8 <!-- The only difference from the template should be the SplashScreen -->
9 <Bundle Name="~$(var.TestGroupName) - $(var.BundleName)" Version="$(var.Version)" UpgradeCode="$(var.UpgradeCode)" Compressed="yes" SplashScreenSourceFile="..\BafThmutilTesting\theme\star_transparent.bmp">
10 <Log Prefix="~$(var.TestGroupName)_$(var.BundleName)" />
11
12 <Variable Name="TestGroupName" Value="$(var.TestGroupName)" />
13
14 <?ifdef SoftwareTag?>
15 <SoftwareTag Regid="regid.1995-08.com.example" InstallPath="[CommonAppDataFolder]regid.1995-08.com.example" />
16 <?endif?>
17
18 <?ifndef BA?>
19 <!-- pulled in through the PackageGroupRef below -->
20 <?elseif $(var.BA) = "TestBAdnc"?>
21 <!-- pulled in through the PackageGroupRef below -->
22 <?elseif $(var.BA) = "TestBA_x64"?>
23 <!-- pulled in through the PackageGroupRef below -->
24 <?elseif $(var.BA) = "TestBAdnc_x64"?>
25 <!-- pulled in through the PackageGroupRef below -->
26 <?elseif $(var.BA) = "WixBA"?>
27 <!-- pulled in through the PackageGroupRef below -->
28 <?elseif $(var.BA) = "WixBAdnc_x64"?>
29 <!-- pulled in through the PackageGroupRef below -->
30 <?elseif $(var.BA) = "hyperlinkLicense"?>
31 <BootstrapperApplication>
32 <bal:WixStandardBootstrapperApplication LicenseUrl="" Theme="hyperlinkLicense" />
33 </BootstrapperApplication>
34 <?else?>
35 <BootstrapperApplicationRef Id="$(var.BA)" />
36 <?endif?>
37
38 <Chain>
39 <?ifndef BA?>
40 <PackageGroupRef Id="TestBA" />
41 <?elseif $(var.BA) = "TestBAdnc"?>
42 <PackageGroupRef Id="TestBAdnc" />
43 <?elseif $(var.BA) = "TestBA_x64"?>
44 <PackageGroupRef Id="TestBA_x64" />
45 <?elseif $(var.BA) = "TestBAdnc_x64"?>
46 <PackageGroupRef Id="TestBAdnc_x64" />
47 <?elseif $(var.BA) = "WixBA"?>
48 <PackageGroupRef Id="WixBA" />
49 <?elseif $(var.BA) = "WixBAdnc_x64"?>
50 <PackageGroupRef Id="WixBAdnc_x64" />
51 <?endif?>
52
53 <PackageGroupRef Id="BundlePackages" />
54 </Chain>
55 </Bundle>
56</Wix>
diff --git a/src/test/burn/TestData/Manual/BundleB/BundleB.wixproj b/src/test/burn/TestData/Manual/BundleB/BundleB.wixproj
new file mode 100644
index 00000000..35c92246
--- /dev/null
+++ b/src/test/burn/TestData/Manual/BundleB/BundleB.wixproj
@@ -0,0 +1,32 @@
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 <BA>hyperlinkLicense</BA>
6 <UpgradeCode>{5DE2F206-3C37-4265-81F7-095284E16B08}</UpgradeCode>
7 <HarvestDirectoryAdditionalOptions>-generate payloadgroup</HarvestDirectoryAdditionalOptions>
8 </PropertyGroup>
9 <ItemGroup>
10 <HarvestDirectory Include="BAPayloads">
11 <ComponentGroupName>BAPayloads</ComponentGroupName>
12 <DirectoryRefId>BAPayloads</DirectoryRefId>
13 <Transforms>ba.xslt</Transforms>
14 </HarvestDirectory>
15 <HarvestDirectory Include="PackagePayloads">
16 <ComponentGroupName>PackagePayloads</ComponentGroupName>
17 <DirectoryRefId>PackagePayloads</DirectoryRefId>
18 <Transforms>package.xslt</Transforms>
19 </HarvestDirectory>
20 </ItemGroup>
21 <ItemGroup>
22 <ProjectReference Include="..\PackageA\PackageA.wixproj" />
23 </ItemGroup>
24 <ItemGroup>
25 <PackageReference Include="WixToolset.Bal.wixext" />
26 </ItemGroup>
27 <!-- We do this dynamically to avoid committing so many files to source control. -->
28 <Target Name="CreateThousandsOfFiles" AfterTargets="BeforeBuild">
29 <Exec Command='"$(BaseOutputPath)$(Configuration)\netcoreapp3.1\win-x86\testexe.exe" /gf "BAPayloads|10000' WorkingDirectory="$(MSBuildProjectDirectory)" />
30 <Exec Command='"$(BaseOutputPath)$(Configuration)\netcoreapp3.1\win-x86\testexe.exe" /gf "PackagePayloads|10000' WorkingDirectory="$(MSBuildProjectDirectory)" />
31 </Target>
32</Project> \ No newline at end of file
diff --git a/src/test/burn/TestData/Manual/BundleB/BundleB.wxs b/src/test/burn/TestData/Manual/BundleB/BundleB.wxs
new file mode 100644
index 00000000..3b189b15
--- /dev/null
+++ b/src/test/burn/TestData/Manual/BundleB/BundleB.wxs
@@ -0,0 +1,15 @@
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" xmlns:bal="http://wixtoolset.org/schemas/v4/wxs/bal">
5 <Fragment>
6 <BootstrapperApplication>
7 <PayloadGroupRef Id="BAPayloads" />
8 </BootstrapperApplication>
9 <PackageGroup Id="BundlePackages">
10 <MsiPackage Id="PackageA" SourceFile="$(var.PackageA.TargetPath)">
11 <PayloadGroupRef Id="PackagePayloads" />
12 </MsiPackage>
13 </PackageGroup>
14 </Fragment>
15</Wix>
diff --git a/src/test/burn/TestData/Manual/BundleB/ba.xslt b/src/test/burn/TestData/Manual/BundleB/ba.xslt
new file mode 100644
index 00000000..54bc7fe6
--- /dev/null
+++ b/src/test/burn/TestData/Manual/BundleB/ba.xslt
@@ -0,0 +1,21 @@
1<?xml version="1.0" encoding="utf-8"?>
2<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
3 xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl"
4 xmlns:wix="http://wixtoolset.org/schemas/v4/wxs"
5>
6 <xsl:output method="xml" indent="yes"/>
7
8 <xsl:template match="@* | node()">
9 <xsl:copy>
10 <xsl:apply-templates select="@* | node()"/>
11 </xsl:copy>
12 </xsl:template>
13
14 <xsl:template match="wix:Payload" >
15 <xsl:copy>
16 <xsl:apply-templates select="@* | node()"/>
17 <xsl:attribute name="Id">ba_<xsl:value-of select="substring(@SourceFile, 11)" /></xsl:attribute>
18 <xsl:attribute name="SourceFile">BAPayloads<xsl:value-of select="substring(@SourceFile, 10)" /></xsl:attribute>
19 </xsl:copy>
20 </xsl:template>
21</xsl:stylesheet>
diff --git a/src/test/burn/TestData/Manual/BundleB/package.xslt b/src/test/burn/TestData/Manual/BundleB/package.xslt
new file mode 100644
index 00000000..304ff78b
--- /dev/null
+++ b/src/test/burn/TestData/Manual/BundleB/package.xslt
@@ -0,0 +1,21 @@
1<?xml version="1.0" encoding="utf-8"?>
2<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
3 xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl"
4 xmlns:wix="http://wixtoolset.org/schemas/v4/wxs"
5>
6 <xsl:output method="xml" indent="yes"/>
7
8 <xsl:template match="@* | node()">
9 <xsl:copy>
10 <xsl:apply-templates select="@* | node()"/>
11 </xsl:copy>
12 </xsl:template>
13
14 <xsl:template match="wix:Payload" >
15 <xsl:copy>
16 <xsl:apply-templates select="@* | node()"/>
17 <xsl:attribute name="Id">package_<xsl:value-of select="substring(@SourceFile, 11)" /></xsl:attribute>
18 <xsl:attribute name="SourceFile">PackagePayloads<xsl:value-of select="substring(@SourceFile, 10)" /></xsl:attribute>
19 </xsl:copy>
20 </xsl:template>
21</xsl:stylesheet>
diff --git a/src/test/burn/TestExe/Task.cs b/src/test/burn/TestExe/Task.cs
index 7d39bfd9..59f774fb 100644
--- a/src/test/burn/TestExe/Task.cs
+++ b/src/test/burn/TestExe/Task.cs
@@ -59,6 +59,24 @@ namespace TestExe
59 } 59 }
60 } 60 }
61 61
62 public class GenerateFilesTask : Task
63 {
64 public GenerateFilesTask(string Data) : base(Data) { }
65
66 public override void RunTask()
67 {
68 string[] tokens = this.data.Split(new char[] { '|' }, 2);
69 string folderPath = System.Environment.ExpandEnvironmentVariables(tokens[0]);
70 long size = long.Parse(tokens[1]);
71 Directory.CreateDirectory(folderPath);
72 var bytes = new byte[0];
73 for (long i = 1; i <= size; i++)
74 {
75 File.WriteAllBytes(Path.Combine(folderPath, $"{i}.txt"), bytes);
76 }
77 }
78 }
79
62 public class LargeFileTask : Task 80 public class LargeFileTask : Task
63 { 81 {
64 public LargeFileTask(string Data) : base(Data) { } 82 public LargeFileTask(string Data) : base(Data) { }
@@ -163,6 +181,10 @@ namespace TestExe
163 t = new SleepRandomTask(args[i + 1]); 181 t = new SleepRandomTask(args[i + 1]);
164 tasks.Add(t); 182 tasks.Add(t);
165 break; 183 break;
184 case "/gf":
185 t = new GenerateFilesTask(args[i + 1]);
186 tasks.Add(t);
187 break;
166 case "/lf": 188 case "/lf":
167 t = new LargeFileTask(args[i + 1]); 189 t = new LargeFileTask(args[i + 1]);
168 tasks.Add(t); 190 tasks.Add(t);
diff --git a/src/wix/WixToolset.Core.Burn/Bind/BindBundleCommand.cs b/src/wix/WixToolset.Core.Burn/Bind/BindBundleCommand.cs
index 4a4f06f3..97007022 100644
--- a/src/wix/WixToolset.Core.Burn/Bind/BindBundleCommand.cs
+++ b/src/wix/WixToolset.Core.Burn/Bind/BindBundleCommand.cs
@@ -239,15 +239,18 @@ namespace WixToolset.Core.Burn
239 { 239 {
240 foreach (var facade in facades.Values) 240 foreach (var facade in facades.Values)
241 { 241 {
242 facade.PackageSymbol.Size = 0; 242 // Use temporary variable to avoid excessive number of PreviousValues.
243 long packageSize = 0;
243 244
244 var packagePayloads = packagesPayloads[facade.PackageId]; 245 var packagePayloads = packagesPayloads[facade.PackageId];
245 246
246 foreach (var payload in packagePayloads.Values) 247 foreach (var payload in packagePayloads.Values)
247 { 248 {
248 facade.PackageSymbol.Size += payload.FileSize.Value; 249 packageSize += payload.FileSize.Value;
249 } 250 }
250 251
252 facade.PackageSymbol.Size = packageSize;
253
251 if (!facade.PackageSymbol.InstallSize.HasValue) 254 if (!facade.PackageSymbol.InstallSize.HasValue)
252 { 255 {
253 facade.PackageSymbol.InstallSize = facade.PackageSymbol.Size; 256 facade.PackageSymbol.InstallSize = facade.PackageSymbol.Size;
diff --git a/src/wix/WixToolset.Core.Burn/Bundles/CreateBurnManifestCommand.cs b/src/wix/WixToolset.Core.Burn/Bundles/CreateBurnManifestCommand.cs
index 429b3565..5a7241ab 100644
--- a/src/wix/WixToolset.Core.Burn/Bundles/CreateBurnManifestCommand.cs
+++ b/src/wix/WixToolset.Core.Burn/Bundles/CreateBurnManifestCommand.cs
@@ -604,12 +604,15 @@ namespace WixToolset.Core.Burn.Bundles
604 604
605 // Write the BundleExtension elements. 605 // Write the BundleExtension elements.
606 var bundleExtensions = this.Section.Symbols.OfType<WixBundleExtensionSymbol>(); 606 var bundleExtensions = this.Section.Symbols.OfType<WixBundleExtensionSymbol>();
607 var uxPayloadsById = this.UXContainerPayloads.ToDictionary(p => p.Id.Id);
607 608
608 foreach (var bundleExtension in bundleExtensions) 609 foreach (var bundleExtension in bundleExtensions)
609 { 610 {
611 var entryPayload = uxPayloadsById[bundleExtension.PayloadRef];
612
610 writer.WriteStartElement("BundleExtension"); 613 writer.WriteStartElement("BundleExtension");
611 writer.WriteAttributeString("Id", bundleExtension.Id.Id); 614 writer.WriteAttributeString("Id", bundleExtension.Id.Id);
612 writer.WriteAttributeString("EntryPayloadId", bundleExtension.PayloadRef); 615 writer.WriteAttributeString("EntryPayloadSourcePath", entryPayload.EmbeddedId);
613 616
614 writer.WriteEndElement(); 617 writer.WriteEndElement();
615 } 618 }
diff --git a/src/wix/WixToolset.Core/Compile/CompilerPayload.cs b/src/wix/WixToolset.Core/Compile/CompilerPayload.cs
index 3f423034..ea63ee8c 100644
--- a/src/wix/WixToolset.Core/Compile/CompilerPayload.cs
+++ b/src/wix/WixToolset.Core/Compile/CompilerPayload.cs
@@ -143,7 +143,7 @@ namespace WixToolset.Core
143 } 143 }
144 } 144 }
145 145
146 public WixBundlePayloadSymbol CreatePayloadSymbol(ComplexReferenceParentType parentType, string parentId, ComplexReferenceChildType previousType = ComplexReferenceChildType.Unknown, string previousId = null) 146 public WixBundlePayloadSymbol CreatePayloadSymbol(ComplexReferenceParentType parentType, string parentId)
147 { 147 {
148 WixBundlePayloadSymbol symbol = null; 148 WixBundlePayloadSymbol symbol = null;
149 149
@@ -179,7 +179,7 @@ namespace WixToolset.Core
179 Version = this.Version, 179 Version = this.Version,
180 }); 180 });
181 181
182 this.Core.CreateGroupAndOrderingRows(this.SourceLineNumbers, parentType, parentId, ComplexReferenceChildType.Payload, symbol.Id.Id, previousType, previousId); 182 this.Core.CreateGroupAndOrderingRows(this.SourceLineNumbers, parentType, parentId, ComplexReferenceChildType.Payload, symbol.Id.Id, ComplexReferenceChildType.Unknown, null);
183 } 183 }
184 184
185 return symbol; 185 return symbol;
diff --git a/src/wix/WixToolset.Core/Compiler_Bundle.cs b/src/wix/WixToolset.Core/Compiler_Bundle.cs
index 3e238b82..a72d434d 100644
--- a/src/wix/WixToolset.Core/Compiler_Bundle.cs
+++ b/src/wix/WixToolset.Core/Compiler_Bundle.cs
@@ -351,7 +351,7 @@ namespace WixToolset.Core
351 this.ParsePayloadGroupElement(child, ComplexReferenceParentType.Layout, Compiler.BundleLayoutOnlyPayloads); 351 this.ParsePayloadGroupElement(child, ComplexReferenceParentType.Layout, Compiler.BundleLayoutOnlyPayloads);
352 break; 352 break;
353 case "PayloadGroupRef": 353 case "PayloadGroupRef":
354 this.ParsePayloadGroupRefElement(child, ComplexReferenceParentType.Layout, Compiler.BundleLayoutOnlyPayloads, ComplexReferenceChildType.Unknown, null); 354 this.ParsePayloadGroupRefElement(child, ComplexReferenceParentType.Layout, Compiler.BundleLayoutOnlyPayloads);
355 break; 355 break;
356 case "RelatedBundle": 356 case "RelatedBundle":
357 this.ParseRelatedBundleElement(child); 357 this.ParseRelatedBundleElement(child);
@@ -649,8 +649,6 @@ namespace WixToolset.Core
649 { 649 {
650 var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); 650 var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node);
651 Identifier id = null; 651 Identifier id = null;
652 Identifier previousId = null;
653 var previousType = ComplexReferenceChildType.Unknown;
654 652
655 foreach (var attrib in node.Attributes()) 653 foreach (var attrib in node.Attributes())
656 { 654 {
@@ -675,16 +673,13 @@ namespace WixToolset.Core
675 switch (child.Name.LocalName) 673 switch (child.Name.LocalName)
676 { 674 {
677 case "BootstrapperApplicationDll": 675 case "BootstrapperApplicationDll":
678 previousId = this.ParseBootstrapperApplicationDllElement(child, id, previousType, previousId); 676 this.ParseBootstrapperApplicationDllElement(child, id);
679 previousType = ComplexReferenceChildType.Payload;
680 break; 677 break;
681 case "Payload": 678 case "Payload":
682 previousId = this.ParsePayloadElement(child, ComplexReferenceParentType.Container, Compiler.BurnUXContainerId, previousType, previousId); 679 this.ParsePayloadElement(child, ComplexReferenceParentType.Container, Compiler.BurnUXContainerId);
683 previousType = ComplexReferenceChildType.Payload;
684 break; 680 break;
685 case "PayloadGroupRef": 681 case "PayloadGroupRef":
686 previousId = this.ParsePayloadGroupRefElement(child, ComplexReferenceParentType.Container, Compiler.BurnUXContainerId, previousType, previousId); 682 this.ParsePayloadGroupRefElement(child, ComplexReferenceParentType.Container, Compiler.BurnUXContainerId);
687 previousType = ComplexReferenceChildType.PayloadGroup;
688 break; 683 break;
689 default: 684 default:
690 this.Core.UnexpectedElement(node, child); 685 this.Core.UnexpectedElement(node, child);
@@ -708,9 +703,7 @@ namespace WixToolset.Core
708 /// </summary> 703 /// </summary>
709 /// <param name="node">Element to parse</param> 704 /// <param name="node">Element to parse</param>
710 /// <param name="defaultId"></param> 705 /// <param name="defaultId"></param>
711 /// <param name="previousType"></param> 706 private Identifier ParseBootstrapperApplicationDllElement(XElement node, Identifier defaultId)
712 /// <param name="previousId"></param>
713 private Identifier ParseBootstrapperApplicationDllElement(XElement node, Identifier defaultId, ComplexReferenceChildType previousType, Identifier previousId)
714 { 707 {
715 var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); 708 var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node);
716 var compilerPayload = new CompilerPayload(this.Core, sourceLineNumbers, node) 709 var compilerPayload = new CompilerPayload(this.Core, sourceLineNumbers, node)
@@ -805,7 +798,7 @@ namespace WixToolset.Core
805 798
806 if (!this.Core.EncounteredError) 799 if (!this.Core.EncounteredError)
807 { 800 {
808 compilerPayload.CreatePayloadSymbol(ComplexReferenceParentType.Container, Compiler.BurnUXContainerId.Id, previousType, previousId?.Id); 801 compilerPayload.CreatePayloadSymbol(ComplexReferenceParentType.Container, Compiler.BurnUXContainerId.Id);
809 this.Core.AddSymbol(new WixBundleContainerSymbol(sourceLineNumbers, Compiler.BurnUXContainerId) 802 this.Core.AddSymbol(new WixBundleContainerSymbol(sourceLineNumbers, Compiler.BurnUXContainerId)
810 { 803 {
811 Name = "bundle-ux.cab", 804 Name = "bundle-ux.cab",
@@ -829,8 +822,6 @@ namespace WixToolset.Core
829 { 822 {
830 var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); 823 var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node);
831 string id = null; 824 string id = null;
832 Identifier previousId = null;
833 var previousType = ComplexReferenceChildType.Unknown;
834 825
835 foreach (var attrib in node.Attributes()) 826 foreach (var attrib in node.Attributes())
836 { 827 {
@@ -859,12 +850,10 @@ namespace WixToolset.Core
859 switch (child.Name.LocalName) 850 switch (child.Name.LocalName)
860 { 851 {
861 case "Payload": 852 case "Payload":
862 previousId = this.ParsePayloadElement(child, ComplexReferenceParentType.Container, Compiler.BurnUXContainerId, previousType, previousId); 853 this.ParsePayloadElement(child, ComplexReferenceParentType.Container, Compiler.BurnUXContainerId);
863 previousType = ComplexReferenceChildType.Payload;
864 break; 854 break;
865 case "PayloadGroupRef": 855 case "PayloadGroupRef":
866 previousId = this.ParsePayloadGroupRefElement(child, ComplexReferenceParentType.Container, Compiler.BurnUXContainerId, previousType, previousId); 856 this.ParsePayloadGroupRefElement(child, ComplexReferenceParentType.Container, Compiler.BurnUXContainerId);
867 previousType = ComplexReferenceChildType.PayloadGroup;
868 break; 857 break;
869 default: 858 default:
870 this.Core.UnexpectedElement(node, child); 859 this.Core.UnexpectedElement(node, child);
@@ -1195,8 +1184,6 @@ namespace WixToolset.Core
1195 { 1184 {
1196 var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); 1185 var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node);
1197 var compilerPayload = new CompilerPayload(this.Core, sourceLineNumbers, node); 1186 var compilerPayload = new CompilerPayload(this.Core, sourceLineNumbers, node);
1198 Identifier previousId = null;
1199 var previousType = ComplexReferenceChildType.Unknown;
1200 1187
1201 // This list lets us evaluate extension attributes *after* all core attributes 1188 // This list lets us evaluate extension attributes *after* all core attributes
1202 // have been parsed and dealt with, regardless of authoring order. 1189 // have been parsed and dealt with, regardless of authoring order.
@@ -1241,9 +1228,7 @@ namespace WixToolset.Core
1241 this.Core.ParseExtensionAttribute(node, extensionAttribute, context); 1228 this.Core.ParseExtensionAttribute(node, extensionAttribute, context);
1242 } 1229 }
1243 1230
1244 compilerPayload.CreatePayloadSymbol(ComplexReferenceParentType.Container, Compiler.BurnUXContainerId.Id, previousType, previousId?.Id); 1231 compilerPayload.CreatePayloadSymbol(ComplexReferenceParentType.Container, Compiler.BurnUXContainerId.Id);
1245 previousId = compilerPayload.Id;
1246 previousType = ComplexReferenceChildType.Payload;
1247 1232
1248 foreach (var child in node.Elements()) 1233 foreach (var child in node.Elements())
1249 { 1234 {
@@ -1252,12 +1237,10 @@ namespace WixToolset.Core
1252 switch (child.Name.LocalName) 1237 switch (child.Name.LocalName)
1253 { 1238 {
1254 case "Payload": 1239 case "Payload":
1255 previousId = this.ParsePayloadElement(child, ComplexReferenceParentType.Container, Compiler.BurnUXContainerId, previousType, previousId); 1240 this.ParsePayloadElement(child, ComplexReferenceParentType.Container, Compiler.BurnUXContainerId);
1256 previousType = ComplexReferenceChildType.Payload;
1257 break; 1241 break;
1258 case "PayloadGroupRef": 1242 case "PayloadGroupRef":
1259 previousId = this.ParsePayloadGroupRefElement(child, ComplexReferenceParentType.Container, Compiler.BurnUXContainerId, previousType, previousId); 1243 this.ParsePayloadGroupRefElement(child, ComplexReferenceParentType.Container, Compiler.BurnUXContainerId);
1260 previousType = ComplexReferenceChildType.PayloadGroup;
1261 break; 1244 break;
1262 default: 1245 default:
1263 this.Core.UnexpectedElement(node, child); 1246 this.Core.UnexpectedElement(node, child);
@@ -1388,12 +1371,9 @@ namespace WixToolset.Core
1388 /// <param name="node">Element to parse</param> 1371 /// <param name="node">Element to parse</param>
1389 /// <param name="parentType">ComplexReferenceParentType of parent element. (BA or PayloadGroup)</param> 1372 /// <param name="parentType">ComplexReferenceParentType of parent element. (BA or PayloadGroup)</param>
1390 /// <param name="parentId">Identifier of parent element.</param> 1373 /// <param name="parentId">Identifier of parent element.</param>
1391 /// <param name="previousType"></param> 1374 private Identifier ParsePayloadElement(XElement node, ComplexReferenceParentType parentType, Identifier parentId)
1392 /// <param name="previousId"></param>
1393 private Identifier ParsePayloadElement(XElement node, ComplexReferenceParentType parentType, Identifier parentId, ComplexReferenceChildType previousType, Identifier previousId)
1394 { 1375 {
1395 Debug.Assert(ComplexReferenceParentType.PayloadGroup == parentType || ComplexReferenceParentType.Package == parentType || ComplexReferenceParentType.Container == parentType); 1376 Debug.Assert(ComplexReferenceParentType.PayloadGroup == parentType || ComplexReferenceParentType.Package == parentType || ComplexReferenceParentType.Container == parentType);
1396 Debug.Assert(ComplexReferenceChildType.Unknown == previousType || ComplexReferenceChildType.PayloadGroup == previousType || ComplexReferenceChildType.Payload == previousType);
1397 1377
1398 var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); 1378 var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node);
1399 var compilerPayload = new CompilerPayload(this.Core, sourceLineNumbers, node); 1379 var compilerPayload = new CompilerPayload(this.Core, sourceLineNumbers, node);
@@ -1470,7 +1450,7 @@ namespace WixToolset.Core
1470 } 1450 }
1471 } 1451 }
1472 1452
1473 compilerPayload.CreatePayloadSymbol(parentType, parentId?.Id, previousType, previousId?.Id); 1453 compilerPayload.CreatePayloadSymbol(parentType, parentId?.Id);
1474 1454
1475 return compilerPayload.Id; 1455 return compilerPayload.Id;
1476 } 1456 }
@@ -1514,8 +1494,6 @@ namespace WixToolset.Core
1514 id = Identifier.Invalid; 1494 id = Identifier.Invalid;
1515 } 1495 }
1516 1496
1517 var previousType = ComplexReferenceChildType.Unknown;
1518 Identifier previousId = null;
1519 foreach (var child in node.Elements()) 1497 foreach (var child in node.Elements())
1520 { 1498 {
1521 if (CompilerCore.WixNamespace == child.Name.Namespace) 1499 if (CompilerCore.WixNamespace == child.Name.Namespace)
@@ -1536,12 +1514,10 @@ namespace WixToolset.Core
1536 packageType = WixBundlePackageType.Msu; 1514 packageType = WixBundlePackageType.Msu;
1537 break; 1515 break;
1538 case "Payload": 1516 case "Payload":
1539 previousId = this.ParsePayloadElement(child, ComplexReferenceParentType.PayloadGroup, id, previousType, previousId); 1517 this.ParsePayloadElement(child, ComplexReferenceParentType.PayloadGroup, id);
1540 previousType = ComplexReferenceChildType.Payload;
1541 break; 1518 break;
1542 case "PayloadGroupRef": 1519 case "PayloadGroupRef":
1543 previousId = this.ParsePayloadGroupRefElement(child, ComplexReferenceParentType.PayloadGroup, id, previousType, previousId); 1520 this.ParsePayloadGroupRefElement(child, ComplexReferenceParentType.PayloadGroup, id);
1544 previousType = ComplexReferenceChildType.PayloadGroup;
1545 break; 1521 break;
1546 default: 1522 default:
1547 this.Core.UnexpectedElement(node, child); 1523 this.Core.UnexpectedElement(node, child);
@@ -1551,12 +1527,9 @@ namespace WixToolset.Core
1551 if (packageType.HasValue) 1527 if (packageType.HasValue)
1552 { 1528 {
1553 var compilerPayload = this.ParsePackagePayloadElement(null, child, packageType.Value, null); 1529 var compilerPayload = this.ParsePackagePayloadElement(null, child, packageType.Value, null);
1554 var payloadSymbol = compilerPayload.CreatePayloadSymbol(ComplexReferenceParentType.PayloadGroup, id?.Id, previousType, previousId?.Id); 1530 var payloadSymbol = compilerPayload.CreatePayloadSymbol(ComplexReferenceParentType.PayloadGroup, id?.Id);
1555 if (payloadSymbol != null) 1531 if (payloadSymbol != null)
1556 { 1532 {
1557 previousId = payloadSymbol.Id;
1558 previousType = ComplexReferenceChildType.Payload;
1559
1560 this.CreatePackagePayloadSymbol(payloadSymbol.SourceLineNumbers, packageType.Value, payloadSymbol.Id, ComplexReferenceParentType.PayloadGroup, id); 1533 this.CreatePackagePayloadSymbol(payloadSymbol.SourceLineNumbers, packageType.Value, payloadSymbol.Id, ComplexReferenceParentType.PayloadGroup, id);
1561 } 1534 }
1562 } 1535 }
@@ -1582,12 +1555,9 @@ namespace WixToolset.Core
1582 /// <param name="node">Element to parse.</param> 1555 /// <param name="node">Element to parse.</param>
1583 /// <param name="parentType">ComplexReferenceParentType of parent element (BA or PayloadGroup).</param> 1556 /// <param name="parentType">ComplexReferenceParentType of parent element (BA or PayloadGroup).</param>
1584 /// <param name="parentId">Identifier of parent element.</param> 1557 /// <param name="parentId">Identifier of parent element.</param>
1585 /// <param name="previousType"></param> 1558 private Identifier ParsePayloadGroupRefElement(XElement node, ComplexReferenceParentType parentType, Identifier parentId)
1586 /// <param name="previousId"></param>
1587 private Identifier ParsePayloadGroupRefElement(XElement node, ComplexReferenceParentType parentType, Identifier parentId, ComplexReferenceChildType previousType, Identifier previousId)
1588 { 1559 {
1589 Debug.Assert(ComplexReferenceParentType.Layout == parentType || ComplexReferenceParentType.PayloadGroup == parentType || ComplexReferenceParentType.Package == parentType || ComplexReferenceParentType.Container == parentType); 1560 Debug.Assert(ComplexReferenceParentType.Layout == parentType || ComplexReferenceParentType.PayloadGroup == parentType || ComplexReferenceParentType.Package == parentType || ComplexReferenceParentType.Container == parentType);
1590 Debug.Assert(ComplexReferenceChildType.Unknown == previousType || ComplexReferenceChildType.PayloadGroup == previousType || ComplexReferenceChildType.Payload == previousType);
1591 1561
1592 var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); 1562 var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node);
1593 Identifier id = null; 1563 Identifier id = null;
@@ -1620,7 +1590,7 @@ namespace WixToolset.Core
1620 1590
1621 this.Core.ParseForExtensionElements(node); 1591 this.Core.ParseForExtensionElements(node);
1622 1592
1623 this.Core.CreateGroupAndOrderingRows(sourceLineNumbers, parentType, parentId?.Id, ComplexReferenceChildType.PayloadGroup, id?.Id, previousType, previousId?.Id); 1593 this.Core.CreateGroupAndOrderingRows(sourceLineNumbers, parentType, parentId?.Id, ComplexReferenceChildType.PayloadGroup, id?.Id, ComplexReferenceChildType.Unknown, null);
1624 1594
1625 return id; 1595 return id;
1626 } 1596 }
@@ -2259,10 +2229,10 @@ namespace WixToolset.Core
2259 } 2229 }
2260 break; 2230 break;
2261 case "Payload": 2231 case "Payload":
2262 this.ParsePayloadElement(child, ComplexReferenceParentType.Package, id, ComplexReferenceChildType.Unknown, null); 2232 this.ParsePayloadElement(child, ComplexReferenceParentType.Package, id);
2263 break; 2233 break;
2264 case "PayloadGroupRef": 2234 case "PayloadGroupRef":
2265 this.ParsePayloadGroupRefElement(child, ComplexReferenceParentType.Package, id, ComplexReferenceChildType.Unknown, null); 2235 this.ParsePayloadGroupRefElement(child, ComplexReferenceParentType.Package, id);
2266 break; 2236 break;
2267 case "Provides": 2237 case "Provides":
2268 this.ParseProvidesElement(child, packageType, id.Id, out _); 2238 this.ParseProvidesElement(child, packageType, id.Id, out _);
diff --git a/src/wix/WixToolset.Core/Link/WixGroupingOrdering.cs b/src/wix/WixToolset.Core/Link/WixGroupingOrdering.cs
index f9de82a9..152f897b 100644
--- a/src/wix/WixToolset.Core/Link/WixGroupingOrdering.cs
+++ b/src/wix/WixToolset.Core/Link/WixGroupingOrdering.cs
@@ -645,13 +645,14 @@ namespace WixToolset.Core.Link
645 this.AddAfter(nestedAfterItems, messageHandler); 645 this.AddAfter(nestedAfterItems, messageHandler);
646 } 646 }
647 647
648 // We *don't* propagate ordering information from Packages or 648 // We *don't* propagate ordering information from Packages, PayloadGroups, or
649 // Containers to their children, because ordering doesn't matter 649 // Containers to their children, because ordering doesn't matter
650 // for them, and a Payload in two Packages (or Containers) can 650 // for them, and a Payload in two Packages (or Containers) can
651 // cause a circular reference to occur. 651 // cause a circular reference to occur.
652 private bool ShouldItemPropagateChildOrdering() 652 private bool ShouldItemPropagateChildOrdering()
653 { 653 {
654 if (String.Equals(nameof(ComplexReferenceParentType.Package), this.Type, StringComparison.Ordinal) || 654 if (String.Equals(nameof(ComplexReferenceParentType.Package), this.Type, StringComparison.Ordinal) ||
655 String.Equals(nameof(ComplexReferenceParentType.PayloadGroup), this.Type, StringComparison.Ordinal) ||
655 String.Equals(nameof(ComplexReferenceParentType.Container), this.Type, StringComparison.Ordinal)) 656 String.Equals(nameof(ComplexReferenceParentType.Container), this.Type, StringComparison.Ordinal))
656 { 657 {
657 return false; 658 return false;
diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/BundleManifestFixture.cs b/src/wix/test/WixToolsetTest.CoreIntegration/BundleManifestFixture.cs
index 19d0a2fc..534086b6 100644
--- a/src/wix/test/WixToolsetTest.CoreIntegration/BundleManifestFixture.cs
+++ b/src/wix/test/WixToolsetTest.CoreIntegration/BundleManifestFixture.cs
@@ -211,15 +211,11 @@ namespace WixToolsetTest.CoreIntegration
211 211
212 var bundleExtensions = extractResult.SelectManifestNodes("/burn:BurnManifest/burn:BundleExtension"); 212 var bundleExtensions = extractResult.SelectManifestNodes("/burn:BurnManifest/burn:BundleExtension");
213 Assert.Equal(1, bundleExtensions.Count); 213 Assert.Equal(1, bundleExtensions.Count);
214 Assert.Equal("<BundleExtension Id='ExampleBext' EntryPayloadId='ExampleBext' />", bundleExtensions[0].GetTestXml()); 214 Assert.Equal("<BundleExtension Id='ExampleBext' EntryPayloadSourcePath='u1' />", bundleExtensions[0].GetTestXml());
215 215
216 var bundleExtensionPayloads = extractResult.SelectManifestNodes("/burn:BurnManifest/burn:UX/burn:Payload[@Id='ExampleBext']"); 216 var bundleExtensionPayloads = extractResult.SelectManifestNodes("/burn:BurnManifest/burn:UX/burn:Payload[@Id='ExampleBext']");
217 Assert.Equal(1, bundleExtensionPayloads.Count); 217 Assert.Equal(1, bundleExtensionPayloads.Count);
218 var ignored = new Dictionary<string, List<string>> 218 Assert.Equal("<Payload Id='ExampleBext' FilePath='fakebext.dll' SourcePath='u1' />", bundleExtensionPayloads[0].GetTestXml());
219 {
220 { "Payload", new List<string> { "FileSize", "Hash", "SourcePath" } },
221 };
222 Assert.Equal("<Payload Id='ExampleBext' FilePath='fakebext.dll' SourcePath='*' />", bundleExtensionPayloads[0].GetTestXml(ignored));
223 } 219 }
224 } 220 }
225 221
@@ -259,7 +255,7 @@ namespace WixToolsetTest.CoreIntegration
259 255
260 var bundleExtensions = extractResult.SelectManifestNodes("/burn:BurnManifest/burn:BundleExtension"); 256 var bundleExtensions = extractResult.SelectManifestNodes("/burn:BurnManifest/burn:BundleExtension");
261 Assert.Equal(1, bundleExtensions.Count); 257 Assert.Equal(1, bundleExtensions.Count);
262 Assert.Equal("<BundleExtension Id='ExampleBundleExtension' EntryPayloadId='ExampleBundleExtension' />", bundleExtensions[0].GetTestXml()); 258 Assert.Equal("<BundleExtension Id='ExampleBundleExtension' EntryPayloadSourcePath='u1' />", bundleExtensions[0].GetTestXml());
263 259
264 var extensionSearches = extractResult.SelectManifestNodes("/burn:BurnManifest/burn:ExtensionSearch"); 260 var extensionSearches = extractResult.SelectManifestNodes("/burn:BurnManifest/burn:ExtensionSearch");
265 Assert.Equal(2, extensionSearches.Count); 261 Assert.Equal(2, extensionSearches.Count);