aboutsummaryrefslogtreecommitdiff
path: root/src/burn/engine/package.cpp
diff options
context:
space:
mode:
authorRob Mensching <rob@firegiant.com>2021-04-22 17:06:54 -0700
committerRob Mensching <rob@firegiant.com>2021-04-29 16:36:06 -0700
commitaf10c45d7b3a44af0b461a557847fe03263dcc10 (patch)
tree6a5c1532304782c36ffe4200b38f3afb76789a43 /src/burn/engine/package.cpp
parent9c2aed97299fb96aeee3f1471ce40225437aaecf (diff)
downloadwix-af10c45d7b3a44af0b461a557847fe03263dcc10.tar.gz
wix-af10c45d7b3a44af0b461a557847fe03263dcc10.tar.bz2
wix-af10c45d7b3a44af0b461a557847fe03263dcc10.zip
Move burn into burn
Diffstat (limited to 'src/burn/engine/package.cpp')
-rw-r--r--src/burn/engine/package.cpp692
1 files changed, 692 insertions, 0 deletions
diff --git a/src/burn/engine/package.cpp b/src/burn/engine/package.cpp
new file mode 100644
index 00000000..3f8c8b0f
--- /dev/null
+++ b/src/burn/engine/package.cpp
@@ -0,0 +1,692 @@
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#include "precomp.h"
4
5
6// internal function declarations
7
8static HRESULT ParsePayloadRefsFromXml(
9 __in BURN_PACKAGE* pPackage,
10 __in BURN_PAYLOADS* pPayloads,
11 __in IXMLDOMNode* pixnPackage
12 );
13static HRESULT ParsePatchTargetCode(
14 __in BURN_PACKAGES* pPackages,
15 __in IXMLDOMNode* pixnBundle
16 );
17static HRESULT FindRollbackBoundaryById(
18 __in BURN_PACKAGES* pPackages,
19 __in_z LPCWSTR wzId,
20 __out BURN_ROLLBACK_BOUNDARY** ppRollbackBoundary
21 );
22
23
24// function definitions
25
26extern "C" HRESULT PackagesParseFromXml(
27 __in BURN_PACKAGES* pPackages,
28 __in BURN_PAYLOADS* pPayloads,
29 __in IXMLDOMNode* pixnBundle
30 )
31{
32 HRESULT hr = S_OK;
33 IXMLDOMNodeList* pixnNodes = NULL;
34 IXMLDOMNode* pixnNode = NULL;
35 DWORD cNodes = 0;
36 BSTR bstrNodeName = NULL;
37 DWORD cMspPackages = 0;
38 LPWSTR scz = NULL;
39
40 // select rollback boundary nodes
41 hr = XmlSelectNodes(pixnBundle, L"RollbackBoundary", &pixnNodes);
42 ExitOnFailure(hr, "Failed to select rollback boundary nodes.");
43
44 // get rollback boundary node count
45 hr = pixnNodes->get_length((long*)&cNodes);
46 ExitOnFailure(hr, "Failed to get rollback bundary node count.");
47
48 if (cNodes)
49 {
50 // allocate memory for rollback boundaries
51 pPackages->rgRollbackBoundaries = (BURN_ROLLBACK_BOUNDARY*)MemAlloc(sizeof(BURN_ROLLBACK_BOUNDARY) * cNodes, TRUE);
52 ExitOnNull(pPackages->rgRollbackBoundaries, hr, E_OUTOFMEMORY, "Failed to allocate memory for rollback boundary structs.");
53
54 pPackages->cRollbackBoundaries = cNodes;
55
56 // parse rollback boundary elements
57 for (DWORD i = 0; i < cNodes; ++i)
58 {
59 BURN_ROLLBACK_BOUNDARY* pRollbackBoundary = &pPackages->rgRollbackBoundaries[i];
60
61 hr = XmlNextElement(pixnNodes, &pixnNode, &bstrNodeName);
62 ExitOnFailure(hr, "Failed to get next node.");
63
64 // @Id
65 hr = XmlGetAttributeEx(pixnNode, L"Id", &pRollbackBoundary->sczId);
66 ExitOnFailure(hr, "Failed to get @Id.");
67
68 // @Vital
69 hr = XmlGetYesNoAttribute(pixnNode, L"Vital", &pRollbackBoundary->fVital);
70 ExitOnFailure(hr, "Failed to get @Vital.");
71
72 // @Transaction
73 hr = XmlGetYesNoAttribute(pixnNode, L"Transaction", &pRollbackBoundary->fTransaction);
74 ExitOnFailure(hr, "Failed to get @Transaction.");
75
76 // prepare next iteration
77 ReleaseNullObject(pixnNode);
78 ReleaseNullBSTR(bstrNodeName);
79 }
80 }
81
82 ReleaseNullObject(pixnNodes); // done with the RollbackBoundary elements.
83
84 // select package nodes
85 hr = XmlSelectNodes(pixnBundle, L"Chain/ExePackage|Chain/MsiPackage|Chain/MspPackage|Chain/MsuPackage", &pixnNodes);
86 ExitOnFailure(hr, "Failed to select package nodes.");
87
88 // get package node count
89 hr = pixnNodes->get_length((long*)&cNodes);
90 ExitOnFailure(hr, "Failed to get package node count.");
91
92 if (!cNodes)
93 {
94 ExitFunction1(hr = S_OK);
95 }
96
97 // allocate memory for packages
98 pPackages->rgPackages = (BURN_PACKAGE*)MemAlloc(sizeof(BURN_PACKAGE) * cNodes, TRUE);
99 ExitOnNull(pPackages->rgPackages, hr, E_OUTOFMEMORY, "Failed to allocate memory for package structs.");
100
101 pPackages->cPackages = cNodes;
102
103 // parse package elements
104 for (DWORD i = 0; i < cNodes; ++i)
105 {
106 BURN_PACKAGE* pPackage = &pPackages->rgPackages[i];
107
108 hr = XmlNextElement(pixnNodes, &pixnNode, &bstrNodeName);
109 ExitOnFailure(hr, "Failed to get next node.");
110
111 // @Id
112 hr = XmlGetAttributeEx(pixnNode, L"Id", &pPackage->sczId);
113 ExitOnFailure(hr, "Failed to get @Id.");
114
115 // @Cache
116 hr = XmlGetAttributeEx(pixnNode, L"Cache", &scz);
117 if (SUCCEEDED(hr))
118 {
119 if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, scz, -1, L"remove", -1))
120 {
121 pPackage->authoredCacheType = BOOTSTRAPPER_CACHE_TYPE_REMOVE;
122 }
123 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, scz, -1, L"keep", -1))
124 {
125 pPackage->authoredCacheType = BOOTSTRAPPER_CACHE_TYPE_KEEP;
126 }
127 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, scz, -1, L"force", -1))
128 {
129 pPackage->authoredCacheType = BOOTSTRAPPER_CACHE_TYPE_FORCE;
130 }
131 else
132 {
133 hr = E_UNEXPECTED;
134 ExitOnRootFailure(hr, "Invalid cache type: %ls", scz);
135 }
136 }
137 ExitOnFailure(hr, "Failed to get @Cache.");
138
139 // @CacheId
140 hr = XmlGetAttributeEx(pixnNode, L"CacheId", &pPackage->sczCacheId);
141 ExitOnFailure(hr, "Failed to get @CacheId.");
142
143 // @Size
144 hr = XmlGetAttributeLargeNumber(pixnNode, L"Size", &pPackage->qwSize);
145 ExitOnFailure(hr, "Failed to get @Size.");
146
147 // @InstallSize
148 hr = XmlGetAttributeLargeNumber(pixnNode, L"InstallSize", &pPackage->qwInstallSize);
149 ExitOnFailure(hr, "Failed to get @InstallSize.");
150
151 // @PerMachine
152 hr = XmlGetYesNoAttribute(pixnNode, L"PerMachine", &pPackage->fPerMachine);
153 ExitOnFailure(hr, "Failed to get @PerMachine.");
154
155 // @Permanent
156 hr = XmlGetYesNoAttribute(pixnNode, L"Permanent", &pPackage->fUninstallable);
157 ExitOnFailure(hr, "Failed to get @Permanent.");
158 pPackage->fUninstallable = !pPackage->fUninstallable; // TODO: change "Uninstallable" variable name to permanent, until then Uninstallable is the opposite of Permanent so fix the variable.
159 pPackage->fCanAffectRegistration = pPackage->fUninstallable;
160
161 // @Vital
162 hr = XmlGetYesNoAttribute(pixnNode, L"Vital", &pPackage->fVital);
163 ExitOnFailure(hr, "Failed to get @Vital.");
164
165 // @LogPathVariable
166 hr = XmlGetAttributeEx(pixnNode, L"LogPathVariable", &pPackage->sczLogPathVariable);
167 if (E_NOTFOUND != hr)
168 {
169 ExitOnFailure(hr, "Failed to get @LogPathVariable.");
170 }
171
172 // @RollbackLogPathVariable
173 hr = XmlGetAttributeEx(pixnNode, L"RollbackLogPathVariable", &pPackage->sczRollbackLogPathVariable);
174 if (E_NOTFOUND != hr)
175 {
176 ExitOnFailure(hr, "Failed to get @RollbackLogPathVariable.");
177 }
178
179 // @InstallCondition
180 hr = XmlGetAttributeEx(pixnNode, L"InstallCondition", &pPackage->sczInstallCondition);
181 if (E_NOTFOUND != hr)
182 {
183 ExitOnFailure(hr, "Failed to get @InstallCondition.");
184 }
185
186 // @RollbackBoundaryForward
187 hr = XmlGetAttributeEx(pixnNode, L"RollbackBoundaryForward", &scz);
188 if (E_NOTFOUND != hr)
189 {
190 ExitOnFailure(hr, "Failed to get @RollbackBoundaryForward.");
191
192 hr = FindRollbackBoundaryById(pPackages, scz, &pPackage->pRollbackBoundaryForward);
193 ExitOnFailure(hr, "Failed to find forward transaction boundary: %ls", scz);
194 }
195
196 // @RollbackBoundaryBackward
197 hr = XmlGetAttributeEx(pixnNode, L"RollbackBoundaryBackward", &scz);
198 if (E_NOTFOUND != hr)
199 {
200 ExitOnFailure(hr, "Failed to get @RollbackBoundaryBackward.");
201
202 hr = FindRollbackBoundaryById(pPackages, scz, &pPackage->pRollbackBoundaryBackward);
203 ExitOnFailure(hr, "Failed to find backward transaction boundary: %ls", scz);
204 }
205
206 // read type specific attributes
207 if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, bstrNodeName, -1, L"ExePackage", -1))
208 {
209 pPackage->type = BURN_PACKAGE_TYPE_EXE;
210
211 hr = ExeEngineParsePackageFromXml(pixnNode, pPackage); // TODO: Modularization
212 ExitOnFailure(hr, "Failed to parse EXE package.");
213 }
214 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, bstrNodeName, -1, L"MsiPackage", -1))
215 {
216 pPackage->type = BURN_PACKAGE_TYPE_MSI;
217
218 hr = MsiEngineParsePackageFromXml(pixnNode, pPackage); // TODO: Modularization
219 ExitOnFailure(hr, "Failed to parse MSI package.");
220 }
221 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, bstrNodeName, -1, L"MspPackage", -1))
222 {
223 pPackage->type = BURN_PACKAGE_TYPE_MSP;
224
225 hr = MspEngineParsePackageFromXml(pixnNode, pPackage); // TODO: Modularization
226 ExitOnFailure(hr, "Failed to parse MSP package.");
227
228 ++cMspPackages;
229 }
230 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, bstrNodeName, -1, L"MsuPackage", -1))
231 {
232 pPackage->type = BURN_PACKAGE_TYPE_MSU;
233
234 hr = MsuEngineParsePackageFromXml(pixnNode, pPackage); // TODO: Modularization
235 ExitOnFailure(hr, "Failed to parse MSU package.");
236 }
237 else
238 {
239 // ignore other package types for now
240 }
241
242 // parse payload references
243 hr = ParsePayloadRefsFromXml(pPackage, pPayloads, pixnNode);
244 ExitOnFailure(hr, "Failed to parse payload references.");
245
246 // parse dependency providers
247 hr = DependencyParseProvidersFromXml(pPackage, pixnNode);
248 ExitOnFailure(hr, "Failed to parse dependency providers.");
249
250 // prepare next iteration
251 ReleaseNullObject(pixnNode);
252 ReleaseNullBSTR(bstrNodeName);
253 }
254
255 if (cMspPackages)
256 {
257 pPackages->rgPatchInfo = static_cast<MSIPATCHSEQUENCEINFOW*>(MemAlloc(sizeof(MSIPATCHSEQUENCEINFOW) * cMspPackages, TRUE));
258 ExitOnNull(pPackages->rgPatchInfo, hr, E_OUTOFMEMORY, "Failed to allocate memory for MSP patch sequence information.");
259
260 pPackages->rgPatchInfoToPackage = static_cast<BURN_PACKAGE**>(MemAlloc(sizeof(BURN_PACKAGE*) * cMspPackages, TRUE));
261 ExitOnNull(pPackages->rgPatchInfoToPackage, hr, E_OUTOFMEMORY, "Failed to allocate memory for patch sequence information to package lookup.");
262
263 for (DWORD i = 0; i < pPackages->cPackages; ++i)
264 {
265 BURN_PACKAGE* pPackage = &pPackages->rgPackages[i];
266
267 if (BURN_PACKAGE_TYPE_MSP == pPackage->type)
268 {
269 pPackages->rgPatchInfo[pPackages->cPatchInfo].szPatchData = pPackage->Msp.sczApplicabilityXml;
270 pPackages->rgPatchInfo[pPackages->cPatchInfo].ePatchDataType = MSIPATCH_DATATYPE_XMLBLOB;
271 pPackages->rgPatchInfoToPackage[pPackages->cPatchInfo] = pPackage;
272 ++pPackages->cPatchInfo;
273
274 // Loop through all MSI packages seeing if any of them slipstream this MSP.
275 for (DWORD j = 0; j < pPackages->cPackages; ++j)
276 {
277 BURN_PACKAGE* pMsiPackage = &pPackages->rgPackages[j];
278
279 if (BURN_PACKAGE_TYPE_MSI == pMsiPackage->type)
280 {
281 for (DWORD k = 0; k < pMsiPackage->Msi.cSlipstreamMspPackages; ++k)
282 {
283 if (pMsiPackage->Msi.rgsczSlipstreamMspPackageIds[k] && CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, pPackage->sczId, -1, pMsiPackage->Msi.rgsczSlipstreamMspPackageIds[k], -1))
284 {
285 BURN_SLIPSTREAM_MSP* pSlipstreamMsp = pMsiPackage->Msi.rgSlipstreamMsps + k;
286 pSlipstreamMsp->pMspPackage = pPackage;
287 pSlipstreamMsp->dwMsiChainedPatchIndex = BURN_PACKAGE_INVALID_PATCH_INDEX;
288
289 ReleaseNullStr(pMsiPackage->Msi.rgsczSlipstreamMspPackageIds[k]); // we don't need the slipstream package id any longer so free it.
290 }
291 }
292 }
293 }
294 }
295 }
296 }
297
298 AssertSz(pPackages->cPatchInfo == cMspPackages, "Count of packages patch info should be equal to the number of MSP packages.");
299
300#if DEBUG
301 // Loop through all MSI packages seeing if any of them are missing their slipstream MSP.
302 for (DWORD i = 0; i < pPackages->cPackages; ++i)
303 {
304 BURN_PACKAGE* pPackage = &pPackages->rgPackages[i];
305
306 if (BURN_PACKAGE_TYPE_MSI == pPackage->type)
307 {
308 for (DWORD k = 0; k < pPackage->Msi.cSlipstreamMspPackages; ++k)
309 {
310 if (pPackage->Msi.rgsczSlipstreamMspPackageIds[k])
311 {
312 AssertSz(FALSE, "MSI slipstream MSP package doesn't exist.");
313 }
314 }
315 }
316 }
317#endif
318
319 hr = ParsePatchTargetCode(pPackages, pixnBundle);
320 ExitOnFailure(hr, "Failed to parse target product codes.");
321
322 hr = S_OK;
323
324LExit:
325 ReleaseObject(pixnNodes);
326 ReleaseObject(pixnNode);
327 ReleaseBSTR(bstrNodeName);
328 ReleaseStr(scz);
329
330 return hr;
331}
332
333extern "C" void PackageUninitialize(
334 __in BURN_PACKAGE* pPackage
335 )
336{
337 ReleaseStr(pPackage->sczId);
338 ReleaseStr(pPackage->sczLogPathVariable);
339 ReleaseStr(pPackage->sczRollbackLogPathVariable);
340 ReleaseStr(pPackage->sczInstallCondition);
341 ReleaseStr(pPackage->sczCacheId);
342
343 if (pPackage->rgDependencyProviders)
344 {
345 for (DWORD i = 0; i < pPackage->cDependencyProviders; ++i)
346 {
347 DependencyUninitializeProvider(pPackage->rgDependencyProviders + i);
348 }
349 MemFree(pPackage->rgDependencyProviders);
350 }
351
352 ReleaseMem(pPackage->payloads.rgItems);
353
354 switch (pPackage->type)
355 {
356 case BURN_PACKAGE_TYPE_EXE:
357 ExeEnginePackageUninitialize(pPackage); // TODO: Modularization
358 break;
359 case BURN_PACKAGE_TYPE_MSI:
360 MsiEnginePackageUninitialize(pPackage); // TODO: Modularization
361 break;
362 case BURN_PACKAGE_TYPE_MSP:
363 MspEnginePackageUninitialize(pPackage); // TODO: Modularization
364 break;
365 case BURN_PACKAGE_TYPE_MSU:
366 MsuEnginePackageUninitialize(pPackage); // TODO: Modularization
367 break;
368 }
369}
370
371extern "C" void PackagesUninitialize(
372 __in BURN_PACKAGES* pPackages
373 )
374{
375 if (pPackages->rgRollbackBoundaries)
376 {
377 for (DWORD i = 0; i < pPackages->cRollbackBoundaries; ++i)
378 {
379 ReleaseStr(pPackages->rgRollbackBoundaries[i].sczId);
380 ReleaseStr(pPackages->rgRollbackBoundaries[i].sczLogPath);
381 }
382 MemFree(pPackages->rgRollbackBoundaries);
383 }
384
385 if (pPackages->rgPackages)
386 {
387 for (DWORD i = 0; i < pPackages->cPackages; ++i)
388 {
389 PackageUninitialize(pPackages->rgPackages + i);
390 }
391 MemFree(pPackages->rgPackages);
392 }
393
394 if (pPackages->rgPatchTargetCodes)
395 {
396 for (DWORD i = 0; i < pPackages->cPatchTargetCodes; ++i)
397 {
398 ReleaseStr(pPackages->rgPatchTargetCodes[i].sczTargetCode);
399 }
400 MemFree(pPackages->rgPatchTargetCodes);
401 }
402
403 ReleaseMem(pPackages->rgPatchInfo);
404 ReleaseMem(pPackages->rgPatchInfoToPackage);
405
406 // clear struct
407 memset(pPackages, 0, sizeof(BURN_PACKAGES));
408}
409
410extern "C" HRESULT PackageFindById(
411 __in BURN_PACKAGES* pPackages,
412 __in_z LPCWSTR wzId,
413 __out BURN_PACKAGE** ppPackage
414 )
415{
416 HRESULT hr = S_OK;
417 BURN_PACKAGE* pPackage = NULL;
418
419 for (DWORD i = 0; i < pPackages->cPackages; ++i)
420 {
421 pPackage = &pPackages->rgPackages[i];
422
423 if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, pPackage->sczId, -1, wzId, -1))
424 {
425 *ppPackage = pPackage;
426 ExitFunction1(hr = S_OK);
427 }
428 }
429
430 hr = E_NOTFOUND;
431
432LExit:
433 return hr;
434}
435
436
437extern "C" HRESULT PackageFindRelatedById(
438 __in BURN_RELATED_BUNDLES* pRelatedBundles,
439 __in_z LPCWSTR wzId,
440 __out BURN_PACKAGE** ppPackage
441 )
442{
443 HRESULT hr = S_OK;
444 BURN_PACKAGE* pPackage = NULL;
445
446 for (DWORD i = 0; i < pRelatedBundles->cRelatedBundles; ++i)
447 {
448 pPackage = &pRelatedBundles->rgRelatedBundles[i].package;
449
450 if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, pPackage->sczId, -1, wzId, -1))
451 {
452 *ppPackage = pPackage;
453 ExitFunction1(hr = S_OK);
454 }
455 }
456
457 hr = E_NOTFOUND;
458
459LExit:
460 return hr;
461}
462
463/********************************************************************
464 PackageGetProperty - Determines if the property is defined
465 and optionally copies the property value.
466
467 Note: The caller must free psczValue if requested.
468
469 Note: Returns E_NOTFOUND if the property was not defined or if the
470 package does not support properties.
471
472*********************************************************************/
473extern "C" HRESULT PackageGetProperty(
474 __in const BURN_PACKAGE* pPackage,
475 __in_z LPCWSTR wzProperty,
476 __out_z_opt LPWSTR* psczValue
477 )
478{
479 HRESULT hr = E_NOTFOUND;
480 BURN_MSIPROPERTY* rgProperties = NULL;
481 DWORD cProperties = 0;
482
483 // For MSIs and MSPs, enumerate the properties looking for wzProperty.
484 if (BURN_PACKAGE_TYPE_MSI == pPackage->type)
485 {
486 rgProperties = pPackage->Msi.rgProperties;
487 cProperties = pPackage->Msi.cProperties;
488 }
489 else if (BURN_PACKAGE_TYPE_MSP == pPackage->type)
490 {
491 rgProperties = pPackage->Msp.rgProperties;
492 cProperties = pPackage->Msp.cProperties;
493 }
494
495 for (DWORD i = 0; i < cProperties; ++i)
496 {
497 const BURN_MSIPROPERTY* pProperty = &rgProperties[i];
498
499 if (CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, 0, pProperty->sczId, -1, wzProperty, -1))
500 {
501 if (psczValue)
502 {
503 hr = StrAllocString(psczValue, pProperty->sczValue, 0);
504 ExitOnFailure(hr, "Failed to copy the property value.");
505 }
506
507 ExitFunction1(hr = S_OK);
508 }
509 }
510
511LExit:
512 return hr;
513}
514
515extern "C" HRESULT PackageFindRollbackBoundaryById(
516 __in BURN_PACKAGES* pPackages,
517 __in_z LPCWSTR wzId,
518 __out BURN_ROLLBACK_BOUNDARY** ppRollbackBoundary
519 )
520{
521 HRESULT hr = S_OK;
522 BURN_ROLLBACK_BOUNDARY* pRollbackBoundary = NULL;
523
524 for (DWORD i = 0; i < pPackages->cRollbackBoundaries; ++i)
525 {
526 pRollbackBoundary = &pPackages->rgRollbackBoundaries[i];
527
528 if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, pRollbackBoundary->sczId, -1, wzId, -1))
529 {
530 *ppRollbackBoundary = pRollbackBoundary;
531 ExitFunction1(hr = S_OK);
532 }
533 }
534
535 hr = E_NOTFOUND;
536
537LExit:
538 return hr;
539}
540
541
542// internal function declarations
543
544static HRESULT ParsePayloadRefsFromXml(
545 __in BURN_PACKAGE* pPackage,
546 __in BURN_PAYLOADS* pPayloads,
547 __in IXMLDOMNode* pixnPackage
548 )
549{
550 HRESULT hr = S_OK;
551 IXMLDOMNodeList* pixnNodes = NULL;
552 IXMLDOMNode* pixnNode = NULL;
553 DWORD cNodes = 0;
554 LPWSTR sczId = NULL;
555
556 // select package nodes
557 hr = XmlSelectNodes(pixnPackage, L"PayloadRef", &pixnNodes);
558 ExitOnFailure(hr, "Failed to select package nodes.");
559
560 // get package node count
561 hr = pixnNodes->get_length((long*)&cNodes);
562 ExitOnFailure(hr, "Failed to get package node count.");
563
564 if (!cNodes)
565 {
566 ExitFunction1(hr = S_OK);
567 }
568
569 // allocate memory for payload pointers
570 pPackage->payloads.rgItems = (BURN_PAYLOAD_GROUP_ITEM*)MemAlloc(sizeof(BURN_PAYLOAD_GROUP_ITEM) * cNodes, TRUE);
571 ExitOnNull(pPackage->payloads.rgItems, hr, E_OUTOFMEMORY, "Failed to allocate memory for package payloads.");
572
573 pPackage->payloads.cItems = cNodes;
574
575 // parse package elements
576 for (DWORD i = 0; i < cNodes; ++i)
577 {
578 BURN_PAYLOAD_GROUP_ITEM* pPackagePayload = pPackage->payloads.rgItems + i;
579
580 hr = XmlNextElement(pixnNodes, &pixnNode, NULL);
581 ExitOnFailure(hr, "Failed to get next node.");
582
583 // @Id
584 hr = XmlGetAttributeEx(pixnNode, L"Id", &sczId);
585 ExitOnFailure(hr, "Failed to get Id attribute.");
586
587 // find payload
588 hr = PayloadFindById(pPayloads, sczId, &pPackagePayload->pPayload);
589 ExitOnFailure(hr, "Failed to find payload.");
590
591 pPackage->payloads.qwTotalSize += pPackagePayload->pPayload->qwFileSize;
592
593 // prepare next iteration
594 ReleaseNullObject(pixnNode);
595 }
596
597 hr = S_OK;
598
599LExit:
600 ReleaseObject(pixnNodes);
601 ReleaseObject(pixnNode);
602 ReleaseStr(sczId);
603
604 return hr;
605}
606
607static HRESULT ParsePatchTargetCode(
608 __in BURN_PACKAGES* pPackages,
609 __in IXMLDOMNode* pixnBundle
610 )
611{
612 HRESULT hr = S_OK;
613 IXMLDOMNodeList* pixnNodes = NULL;
614 IXMLDOMNode* pixnNode = NULL;
615 DWORD cNodes = 0;
616 BSTR bstrNodeText = NULL;
617 BOOL fProduct;
618
619 hr = XmlSelectNodes(pixnBundle, L"PatchTargetCode", &pixnNodes);
620 ExitOnFailure(hr, "Failed to select PatchTargetCode nodes.");
621
622 hr = pixnNodes->get_length((long*)&cNodes);
623 ExitOnFailure(hr, "Failed to get PatchTargetCode node count.");
624
625 if (!cNodes)
626 {
627 ExitFunction1(hr = S_OK);
628 }
629
630 pPackages->rgPatchTargetCodes = (BURN_PATCH_TARGETCODE*)MemAlloc(sizeof(BURN_PATCH_TARGETCODE) * cNodes, TRUE);
631 ExitOnNull(pPackages->rgPatchTargetCodes, hr, E_OUTOFMEMORY, "Failed to allocate memory for patch targetcodes.");
632
633 pPackages->cPatchTargetCodes = cNodes;
634
635 for (DWORD i = 0; i < cNodes; ++i)
636 {
637 BURN_PATCH_TARGETCODE* pTargetCode = pPackages->rgPatchTargetCodes + i;
638
639 hr = XmlNextElement(pixnNodes, &pixnNode, NULL);
640 ExitOnFailure(hr, "Failed to get next node.");
641
642 hr = XmlGetAttributeEx(pixnNode, L"TargetCode", &pTargetCode->sczTargetCode);
643 ExitOnFailure(hr, "Failed to get @TargetCode attribute.");
644
645 hr = XmlGetYesNoAttribute(pixnNode, L"Product", &fProduct);
646 if (E_NOTFOUND == hr)
647 {
648 fProduct = FALSE;
649 hr = S_OK;
650 }
651 ExitOnFailure(hr, "Failed to get @Product.");
652
653 pTargetCode->type = fProduct ? BURN_PATCH_TARGETCODE_TYPE_PRODUCT : BURN_PATCH_TARGETCODE_TYPE_UPGRADE;
654
655 // prepare next iteration
656 ReleaseNullBSTR(bstrNodeText);
657 ReleaseNullObject(pixnNode);
658 }
659
660LExit:
661 ReleaseBSTR(bstrNodeText);
662 ReleaseObject(pixnNode);
663 ReleaseObject(pixnNodes);
664
665 return hr;
666}
667
668static HRESULT FindRollbackBoundaryById(
669 __in BURN_PACKAGES* pPackages,
670 __in_z LPCWSTR wzId,
671 __out BURN_ROLLBACK_BOUNDARY** ppRollbackBoundary
672 )
673{
674 HRESULT hr = S_OK;
675 BURN_ROLLBACK_BOUNDARY* pRollbackBoundary = NULL;
676
677 for (DWORD i = 0; i < pPackages->cRollbackBoundaries; ++i)
678 {
679 pRollbackBoundary = &pPackages->rgRollbackBoundaries[i];
680
681 if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, pRollbackBoundary->sczId, -1, wzId, -1))
682 {
683 *ppRollbackBoundary = pRollbackBoundary;
684 ExitFunction1(hr = S_OK);
685 }
686 }
687
688 hr = E_NOTFOUND;
689
690LExit:
691 return hr;
692}