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 | } | ||
