aboutsummaryrefslogtreecommitdiff
path: root/src/engine/package.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/engine/package.cpp')
-rw-r--r--src/engine/package.cpp678
1 files changed, 678 insertions, 0 deletions
diff --git a/src/engine/package.cpp b/src/engine/package.cpp
new file mode 100644
index 00000000..02958efd
--- /dev/null
+++ b/src/engine/package.cpp
@@ -0,0 +1,678 @@
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"no", -1))
120 {
121 pPackage->cacheType = BURN_CACHE_TYPE_NO;
122 }
123 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, scz, -1, L"yes", -1))
124 {
125 pPackage->cacheType = BURN_CACHE_TYPE_YES;
126 }
127 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, scz, -1, L"always", -1))
128 {
129 pPackage->cacheType = BURN_CACHE_TYPE_ALWAYS;
130 }
131 else
132 {
133 hr = E_UNEXPECTED;
134 ExitOnFailure(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
160 // @Vital
161 hr = XmlGetYesNoAttribute(pixnNode, L"Vital", &pPackage->fVital);
162 ExitOnFailure(hr, "Failed to get @Vital.");
163
164 // @LogPathVariable
165 hr = XmlGetAttributeEx(pixnNode, L"LogPathVariable", &pPackage->sczLogPathVariable);
166 if (E_NOTFOUND != hr)
167 {
168 ExitOnFailure(hr, "Failed to get @LogPathVariable.");
169 }
170
171 // @RollbackLogPathVariable
172 hr = XmlGetAttributeEx(pixnNode, L"RollbackLogPathVariable", &pPackage->sczRollbackLogPathVariable);
173 if (E_NOTFOUND != hr)
174 {
175 ExitOnFailure(hr, "Failed to get @RollbackLogPathVariable.");
176 }
177
178 // @InstallCondition
179 hr = XmlGetAttributeEx(pixnNode, L"InstallCondition", &pPackage->sczInstallCondition);
180 if (E_NOTFOUND != hr)
181 {
182 ExitOnFailure(hr, "Failed to get @InstallCondition.");
183 }
184
185 // @RollbackBoundaryForward
186 hr = XmlGetAttributeEx(pixnNode, L"RollbackBoundaryForward", &scz);
187 if (E_NOTFOUND != hr)
188 {
189 ExitOnFailure(hr, "Failed to get @RollbackBoundaryForward.");
190
191 hr = FindRollbackBoundaryById(pPackages, scz, &pPackage->pRollbackBoundaryForward);
192 ExitOnFailure(hr, "Failed to find forward transaction boundary: %ls", scz);
193 }
194
195 // @RollbackBoundaryBackward
196 hr = XmlGetAttributeEx(pixnNode, L"RollbackBoundaryBackward", &scz);
197 if (E_NOTFOUND != hr)
198 {
199 ExitOnFailure(hr, "Failed to get @RollbackBoundaryBackward.");
200
201 hr = FindRollbackBoundaryById(pPackages, scz, &pPackage->pRollbackBoundaryBackward);
202 ExitOnFailure(hr, "Failed to find backward transaction boundary: %ls", scz);
203 }
204
205 // read type specific attributes
206 if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, bstrNodeName, -1, L"ExePackage", -1))
207 {
208 pPackage->type = BURN_PACKAGE_TYPE_EXE;
209
210 hr = ExeEngineParsePackageFromXml(pixnNode, pPackage); // TODO: Modularization
211 ExitOnFailure(hr, "Failed to parse EXE package.");
212 }
213 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, bstrNodeName, -1, L"MsiPackage", -1))
214 {
215 pPackage->type = BURN_PACKAGE_TYPE_MSI;
216
217 hr = MsiEngineParsePackageFromXml(pixnNode, pPackage); // TODO: Modularization
218 ExitOnFailure(hr, "Failed to parse MSI package.");
219 }
220 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, bstrNodeName, -1, L"MspPackage", -1))
221 {
222 pPackage->type = BURN_PACKAGE_TYPE_MSP;
223
224 hr = MspEngineParsePackageFromXml(pixnNode, pPackage); // TODO: Modularization
225 ExitOnFailure(hr, "Failed to parse MSP package.");
226
227 ++cMspPackages;
228 }
229 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, bstrNodeName, -1, L"MsuPackage", -1))
230 {
231 pPackage->type = BURN_PACKAGE_TYPE_MSU;
232
233 hr = MsuEngineParsePackageFromXml(pixnNode, pPackage); // TODO: Modularization
234 ExitOnFailure(hr, "Failed to parse MSU package.");
235 }
236 else
237 {
238 // ignore other package types for now
239 }
240
241 // parse payload references
242 hr = ParsePayloadRefsFromXml(pPackage, pPayloads, pixnNode);
243 ExitOnFailure(hr, "Failed to parse payload references.");
244
245 // parse dependency providers
246 hr = DependencyParseProvidersFromXml(pPackage, pixnNode);
247 ExitOnFailure(hr, "Failed to parse dependency providers.");
248
249 // prepare next iteration
250 ReleaseNullObject(pixnNode);
251 ReleaseNullBSTR(bstrNodeName);
252 }
253
254 if (cMspPackages)
255 {
256 pPackages->rgPatchInfo = static_cast<MSIPATCHSEQUENCEINFOW*>(MemAlloc(sizeof(MSIPATCHSEQUENCEINFOW) * cMspPackages, TRUE));
257 ExitOnNull(pPackages->rgPatchInfo, hr, E_OUTOFMEMORY, "Failed to allocate memory for MSP patch sequence information.");
258
259 pPackages->rgPatchInfoToPackage = static_cast<BURN_PACKAGE**>(MemAlloc(sizeof(BURN_PACKAGE*) * cMspPackages, TRUE));
260 ExitOnNull(pPackages->rgPatchInfoToPackage, hr, E_OUTOFMEMORY, "Failed to allocate memory for patch sequence information to package lookup.");
261
262 for (DWORD i = 0; i < pPackages->cPackages; ++i)
263 {
264 BURN_PACKAGE* pPackage = &pPackages->rgPackages[i];
265
266 if (BURN_PACKAGE_TYPE_MSP == pPackage->type)
267 {
268 pPackages->rgPatchInfo[pPackages->cPatchInfo].szPatchData = pPackage->Msp.sczApplicabilityXml;
269 pPackages->rgPatchInfo[pPackages->cPatchInfo].ePatchDataType = MSIPATCH_DATATYPE_XMLBLOB;
270 pPackages->rgPatchInfoToPackage[pPackages->cPatchInfo] = pPackage;
271 ++pPackages->cPatchInfo;
272
273 // Loop through all MSI packages seeing if any of them slipstream this MSP.
274 for (DWORD j = 0; j < pPackages->cPackages; ++j)
275 {
276 BURN_PACKAGE* pMsiPackage = &pPackages->rgPackages[j];
277
278 if (BURN_PACKAGE_TYPE_MSI == pMsiPackage->type)
279 {
280 for (DWORD k = 0; k < pMsiPackage->Msi.cSlipstreamMspPackages; ++k)
281 {
282 if (pMsiPackage->Msi.rgsczSlipstreamMspPackageIds[k] && CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, pPackage->sczId, -1, pMsiPackage->Msi.rgsczSlipstreamMspPackageIds[k], -1))
283 {
284 pMsiPackage->Msi.rgpSlipstreamMspPackages[k] = pPackage;
285
286 ReleaseNullStr(pMsiPackage->Msi.rgsczSlipstreamMspPackageIds[k]); // we don't need the slipstream package id any longer so free it.
287 }
288 }
289 }
290 }
291 }
292 }
293 }
294
295 AssertSz(pPackages->cPatchInfo == cMspPackages, "Count of packages patch info should be equal to the number of MSP packages.");
296
297 hr = ParsePatchTargetCode(pPackages, pixnBundle);
298 ExitOnFailure(hr, "Failed to parse target product codes.");
299
300 hr = S_OK;
301
302LExit:
303 ReleaseObject(pixnNodes);
304 ReleaseObject(pixnNode);
305 ReleaseBSTR(bstrNodeName);
306 ReleaseStr(scz);
307
308 return hr;
309}
310
311extern "C" void PackageUninitialize(
312 __in BURN_PACKAGE* pPackage
313 )
314{
315 ReleaseStr(pPackage->sczId);
316 ReleaseStr(pPackage->sczLogPathVariable);
317 ReleaseStr(pPackage->sczRollbackLogPathVariable);
318 ReleaseStr(pPackage->sczInstallCondition);
319 ReleaseStr(pPackage->sczRollbackInstallCondition);
320 ReleaseStr(pPackage->sczCacheId);
321
322 if (pPackage->rgDependencyProviders)
323 {
324 for (DWORD i = 0; i < pPackage->cDependencyProviders; ++i)
325 {
326 DependencyUninitialize(pPackage->rgDependencyProviders + i);
327 }
328 MemFree(pPackage->rgDependencyProviders);
329 }
330
331 ReleaseMem(pPackage->rgPayloads);
332
333 switch (pPackage->type)
334 {
335 case BURN_PACKAGE_TYPE_EXE:
336 ExeEnginePackageUninitialize(pPackage); // TODO: Modularization
337 break;
338 case BURN_PACKAGE_TYPE_MSI:
339 MsiEnginePackageUninitialize(pPackage); // TODO: Modularization
340 break;
341 case BURN_PACKAGE_TYPE_MSP:
342 MspEnginePackageUninitialize(pPackage); // TODO: Modularization
343 break;
344 case BURN_PACKAGE_TYPE_MSU:
345 MsuEnginePackageUninitialize(pPackage); // TODO: Modularization
346 break;
347 }
348}
349
350extern "C" void PackagesUninitialize(
351 __in BURN_PACKAGES* pPackages
352 )
353{
354 if (pPackages->rgRollbackBoundaries)
355 {
356 for (DWORD i = 0; i < pPackages->cRollbackBoundaries; ++i)
357 {
358 ReleaseStr(pPackages->rgRollbackBoundaries[i].sczId);
359 }
360 MemFree(pPackages->rgRollbackBoundaries);
361 }
362
363 if (pPackages->rgPackages)
364 {
365 for (DWORD i = 0; i < pPackages->cPackages; ++i)
366 {
367 PackageUninitialize(pPackages->rgPackages + i);
368 }
369 MemFree(pPackages->rgPackages);
370 }
371
372 if (pPackages->rgCompatiblePackages)
373 {
374 for (DWORD i = 0; i < pPackages->cCompatiblePackages; ++i)
375 {
376 PackageUninitialize(pPackages->rgCompatiblePackages + i);
377 }
378 MemFree(pPackages->rgCompatiblePackages);
379 }
380
381 if (pPackages->rgPatchTargetCodes)
382 {
383 for (DWORD i = 0; i < pPackages->cPatchTargetCodes; ++i)
384 {
385 ReleaseStr(pPackages->rgPatchTargetCodes[i].sczTargetCode);
386 }
387 MemFree(pPackages->rgPatchTargetCodes);
388 }
389
390 ReleaseMem(pPackages->rgPatchInfo);
391 ReleaseMem(pPackages->rgPatchInfoToPackage);
392
393 // clear struct
394 memset(pPackages, 0, sizeof(BURN_PACKAGES));
395}
396
397extern "C" HRESULT PackageFindById(
398 __in BURN_PACKAGES* pPackages,
399 __in_z LPCWSTR wzId,
400 __out BURN_PACKAGE** ppPackage
401 )
402{
403 HRESULT hr = S_OK;
404 BURN_PACKAGE* pPackage = NULL;
405
406 for (DWORD i = 0; i < pPackages->cPackages; ++i)
407 {
408 pPackage = &pPackages->rgPackages[i];
409
410 if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, pPackage->sczId, -1, wzId, -1))
411 {
412 *ppPackage = pPackage;
413 ExitFunction1(hr = S_OK);
414 }
415 }
416
417 for (DWORD i = 0; i < pPackages->cCompatiblePackages; ++i)
418 {
419 pPackage = &pPackages->rgCompatiblePackages[i];
420
421 if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, pPackage->sczId, -1, wzId, -1))
422 {
423 *ppPackage = pPackage;
424 ExitFunction1(hr = S_OK);
425 }
426 }
427
428 hr = E_NOTFOUND;
429
430LExit:
431 return hr;
432}
433
434
435extern "C" HRESULT PackageFindRelatedById(
436 __in BURN_RELATED_BUNDLES* pRelatedBundles,
437 __in_z LPCWSTR wzId,
438 __out BURN_PACKAGE** ppPackage
439 )
440{
441 HRESULT hr = S_OK;
442 BURN_PACKAGE* pPackage = NULL;
443
444 for (DWORD i = 0; i < pRelatedBundles->cRelatedBundles; ++i)
445 {
446 pPackage = &pRelatedBundles->rgRelatedBundles[i].package;
447
448 if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, pPackage->sczId, -1, wzId, -1))
449 {
450 *ppPackage = pPackage;
451 ExitFunction1(hr = S_OK);
452 }
453 }
454
455 hr = E_NOTFOUND;
456
457LExit:
458 return hr;
459}
460
461/********************************************************************
462 PackageGetProperty - Determines if the property is defined
463 and optionally copies the property value.
464
465 Note: The caller must free psczValue if requested.
466
467 Note: Returns E_NOTFOUND if the property was not defined or if the
468 package does not support properties.
469
470*********************************************************************/
471extern "C" HRESULT PackageGetProperty(
472 __in const BURN_PACKAGE* pPackage,
473 __in_z LPCWSTR wzProperty,
474 __out_z_opt LPWSTR* psczValue
475 )
476{
477 HRESULT hr = E_NOTFOUND;
478 BURN_MSIPROPERTY* rgProperties = NULL;
479 DWORD cProperties = 0;
480
481 // For MSIs and MSPs, enumerate the properties looking for wzProperty.
482 if (BURN_PACKAGE_TYPE_MSI == pPackage->type)
483 {
484 rgProperties = pPackage->Msi.rgProperties;
485 cProperties = pPackage->Msi.cProperties;
486 }
487 else if (BURN_PACKAGE_TYPE_MSP == pPackage->type)
488 {
489 rgProperties = pPackage->Msp.rgProperties;
490 cProperties = pPackage->Msp.cProperties;
491 }
492
493 for (DWORD i = 0; i < cProperties; ++i)
494 {
495 const BURN_MSIPROPERTY* pProperty = &rgProperties[i];
496
497 if (CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, 0, pProperty->sczId, -1, wzProperty, -1))
498 {
499 if (psczValue)
500 {
501 hr = StrAllocString(psczValue, pProperty->sczValue, 0);
502 ExitOnFailure(hr, "Failed to copy the property value.");
503 }
504
505 ExitFunction1(hr = S_OK);
506 }
507 }
508
509LExit:
510 return hr;
511}
512
513HRESULT PackageEnsureCompatiblePackagesArray(
514 __in BURN_PACKAGES* pPackages
515 )
516{
517 HRESULT hr = S_OK;
518
519 if (!pPackages->rgCompatiblePackages)
520 {
521 pPackages->rgCompatiblePackages = (BURN_PACKAGE*)MemAlloc(sizeof(BURN_PACKAGE) * pPackages->cPackages, TRUE);
522 ExitOnNull(pPackages->rgCompatiblePackages, hr, E_OUTOFMEMORY, "Failed to allocate memory for compatible packages.");
523 }
524
525LExit:
526 return hr;
527}
528
529
530// internal function declarations
531
532static HRESULT ParsePayloadRefsFromXml(
533 __in BURN_PACKAGE* pPackage,
534 __in BURN_PAYLOADS* pPayloads,
535 __in IXMLDOMNode* pixnPackage
536 )
537{
538 HRESULT hr = S_OK;
539 IXMLDOMNodeList* pixnNodes = NULL;
540 IXMLDOMNode* pixnNode = NULL;
541 DWORD cNodes = 0;
542 LPWSTR sczId = NULL;
543
544 // select package nodes
545 hr = XmlSelectNodes(pixnPackage, L"PayloadRef", &pixnNodes);
546 ExitOnFailure(hr, "Failed to select package nodes.");
547
548 // get package node count
549 hr = pixnNodes->get_length((long*)&cNodes);
550 ExitOnFailure(hr, "Failed to get package node count.");
551
552 if (!cNodes)
553 {
554 ExitFunction1(hr = S_OK);
555 }
556
557 // allocate memory for payload pointers
558 pPackage->rgPayloads = (BURN_PACKAGE_PAYLOAD*)MemAlloc(sizeof(BURN_PACKAGE_PAYLOAD) * cNodes, TRUE);
559 ExitOnNull(pPackage->rgPayloads, hr, E_OUTOFMEMORY, "Failed to allocate memory for package payloads.");
560
561 pPackage->cPayloads = cNodes;
562
563 // parse package elements
564 for (DWORD i = 0; i < cNodes; ++i)
565 {
566 BURN_PACKAGE_PAYLOAD* pPackagePayload = &pPackage->rgPayloads[i];
567
568 hr = XmlNextElement(pixnNodes, &pixnNode, NULL);
569 ExitOnFailure(hr, "Failed to get next node.");
570
571 // @Id
572 hr = XmlGetAttributeEx(pixnNode, L"Id", &sczId);
573 ExitOnFailure(hr, "Failed to get Id attribute.");
574
575 // find payload
576 hr = PayloadFindById(pPayloads, sczId, &pPackagePayload->pPayload);
577 ExitOnFailure(hr, "Failed to find payload.");
578
579 // prepare next iteration
580 ReleaseNullObject(pixnNode);
581 }
582
583 hr = S_OK;
584
585LExit:
586 ReleaseObject(pixnNodes);
587 ReleaseObject(pixnNode);
588 ReleaseStr(sczId);
589
590 return hr;
591}
592
593static HRESULT ParsePatchTargetCode(
594 __in BURN_PACKAGES* pPackages,
595 __in IXMLDOMNode* pixnBundle
596 )
597{
598 HRESULT hr = S_OK;
599 IXMLDOMNodeList* pixnNodes = NULL;
600 IXMLDOMNode* pixnNode = NULL;
601 DWORD cNodes = 0;
602 BSTR bstrNodeText = NULL;
603 BOOL fProduct;
604
605 hr = XmlSelectNodes(pixnBundle, L"PatchTargetCode", &pixnNodes);
606 ExitOnFailure(hr, "Failed to select PatchTargetCode nodes.");
607
608 hr = pixnNodes->get_length((long*)&cNodes);
609 ExitOnFailure(hr, "Failed to get PatchTargetCode node count.");
610
611 if (!cNodes)
612 {
613 ExitFunction1(hr = S_OK);
614 }
615
616 pPackages->rgPatchTargetCodes = (BURN_PATCH_TARGETCODE*)MemAlloc(sizeof(BURN_PATCH_TARGETCODE) * cNodes, TRUE);
617 ExitOnNull(pPackages->rgPatchTargetCodes, hr, E_OUTOFMEMORY, "Failed to allocate memory for patch targetcodes.");
618
619 pPackages->cPatchTargetCodes = cNodes;
620
621 for (DWORD i = 0; i < cNodes; ++i)
622 {
623 BURN_PATCH_TARGETCODE* pTargetCode = pPackages->rgPatchTargetCodes + i;
624
625 hr = XmlNextElement(pixnNodes, &pixnNode, NULL);
626 ExitOnFailure(hr, "Failed to get next node.");
627
628 hr = XmlGetAttributeEx(pixnNode, L"TargetCode", &pTargetCode->sczTargetCode);
629 ExitOnFailure(hr, "Failed to get @TargetCode attribute.");
630
631 hr = XmlGetYesNoAttribute(pixnNode, L"Product", &fProduct);
632 if (E_NOTFOUND == hr)
633 {
634 fProduct = FALSE;
635 hr = S_OK;
636 }
637 ExitOnFailure(hr, "Failed to get @Product.");
638
639 pTargetCode->type = fProduct ? BURN_PATCH_TARGETCODE_TYPE_PRODUCT : BURN_PATCH_TARGETCODE_TYPE_UPGRADE;
640
641 // prepare next iteration
642 ReleaseNullBSTR(bstrNodeText);
643 ReleaseNullObject(pixnNode);
644 }
645
646LExit:
647 ReleaseBSTR(bstrNodeText);
648 ReleaseObject(pixnNode);
649 ReleaseObject(pixnNodes);
650
651 return hr;
652}
653
654static HRESULT FindRollbackBoundaryById(
655 __in BURN_PACKAGES* pPackages,
656 __in_z LPCWSTR wzId,
657 __out BURN_ROLLBACK_BOUNDARY** ppRollbackBoundary
658 )
659{
660 HRESULT hr = S_OK;
661 BURN_ROLLBACK_BOUNDARY* pRollbackBoundary = NULL;
662
663 for (DWORD i = 0; i < pPackages->cRollbackBoundaries; ++i)
664 {
665 pRollbackBoundary = &pPackages->rgRollbackBoundaries[i];
666
667 if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, pRollbackBoundary->sczId, -1, wzId, -1))
668 {
669 *ppRollbackBoundary = pRollbackBoundary;
670 ExitFunction1(hr = S_OK);
671 }
672 }
673
674 hr = E_NOTFOUND;
675
676LExit:
677 return hr;
678}