diff options
Diffstat (limited to 'src/burn/engine/package.cpp')
-rw-r--r-- | src/burn/engine/package.cpp | 692 |
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 | |||
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 | |||
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 | |||
324 | LExit: | ||
325 | ReleaseObject(pixnNodes); | ||
326 | ReleaseObject(pixnNode); | ||
327 | ReleaseBSTR(bstrNodeName); | ||
328 | ReleaseStr(scz); | ||
329 | |||
330 | return hr; | ||
331 | } | ||
332 | |||
333 | extern "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 | |||
371 | extern "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 | |||
410 | extern "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 | |||
432 | LExit: | ||
433 | return hr; | ||
434 | } | ||
435 | |||
436 | |||
437 | extern "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 | |||
459 | LExit: | ||
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 | *********************************************************************/ | ||
473 | extern "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 | |||
511 | LExit: | ||
512 | return hr; | ||
513 | } | ||
514 | |||
515 | extern "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 | |||
537 | LExit: | ||
538 | return hr; | ||
539 | } | ||
540 | |||
541 | |||
542 | // internal function declarations | ||
543 | |||
544 | static 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 | |||
599 | LExit: | ||
600 | ReleaseObject(pixnNodes); | ||
601 | ReleaseObject(pixnNode); | ||
602 | ReleaseStr(sczId); | ||
603 | |||
604 | return hr; | ||
605 | } | ||
606 | |||
607 | static 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 | |||
660 | LExit: | ||
661 | ReleaseBSTR(bstrNodeText); | ||
662 | ReleaseObject(pixnNode); | ||
663 | ReleaseObject(pixnNodes); | ||
664 | |||
665 | return hr; | ||
666 | } | ||
667 | |||
668 | static 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 | |||
690 | LExit: | ||
691 | return hr; | ||
692 | } | ||