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