diff options
Diffstat (limited to 'src/engine/package.cpp')
-rw-r--r-- | src/engine/package.cpp | 678 |
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 | |||
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"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 | |||
302 | LExit: | ||
303 | ReleaseObject(pixnNodes); | ||
304 | ReleaseObject(pixnNode); | ||
305 | ReleaseBSTR(bstrNodeName); | ||
306 | ReleaseStr(scz); | ||
307 | |||
308 | return hr; | ||
309 | } | ||
310 | |||
311 | extern "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 | |||
350 | extern "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 | |||
397 | extern "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 | |||
430 | LExit: | ||
431 | return hr; | ||
432 | } | ||
433 | |||
434 | |||
435 | extern "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 | |||
457 | LExit: | ||
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 | *********************************************************************/ | ||
471 | extern "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 | |||
509 | LExit: | ||
510 | return hr; | ||
511 | } | ||
512 | |||
513 | HRESULT 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 | |||
525 | LExit: | ||
526 | return hr; | ||
527 | } | ||
528 | |||
529 | |||
530 | // internal function declarations | ||
531 | |||
532 | static 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 | |||
585 | LExit: | ||
586 | ReleaseObject(pixnNodes); | ||
587 | ReleaseObject(pixnNode); | ||
588 | ReleaseStr(sczId); | ||
589 | |||
590 | return hr; | ||
591 | } | ||
592 | |||
593 | static 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 | |||
646 | LExit: | ||
647 | ReleaseBSTR(bstrNodeText); | ||
648 | ReleaseObject(pixnNode); | ||
649 | ReleaseObject(pixnNodes); | ||
650 | |||
651 | return hr; | ||
652 | } | ||
653 | |||
654 | static 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 | |||
676 | LExit: | ||
677 | return hr; | ||
678 | } | ||