diff options
Diffstat (limited to 'src/api/burn/balutil/balinfo.cpp')
-rw-r--r-- | src/api/burn/balutil/balinfo.cpp | 373 |
1 files changed, 373 insertions, 0 deletions
diff --git a/src/api/burn/balutil/balinfo.cpp b/src/api/burn/balutil/balinfo.cpp new file mode 100644 index 00000000..3abb9286 --- /dev/null +++ b/src/api/burn/balutil/balinfo.cpp | |||
@@ -0,0 +1,373 @@ | |||
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 | // prototypes | ||
6 | static HRESULT ParsePackagesFromXml( | ||
7 | __in BAL_INFO_PACKAGES* pPackages, | ||
8 | __in IXMLDOMDocument* pixdManifest | ||
9 | ); | ||
10 | static HRESULT ParseBalPackageInfoFromXml( | ||
11 | __in BAL_INFO_PACKAGES* pPackages, | ||
12 | __in IXMLDOMDocument* pixdManifest | ||
13 | ); | ||
14 | |||
15 | |||
16 | DAPI_(HRESULT) BalInfoParseFromXml( | ||
17 | __in BAL_INFO_BUNDLE* pBundle, | ||
18 | __in IXMLDOMDocument* pixdManifest | ||
19 | ) | ||
20 | { | ||
21 | HRESULT hr = S_OK; | ||
22 | IXMLDOMNode* pNode = NULL; | ||
23 | |||
24 | hr = XmlSelectSingleNode(pixdManifest, L"/BootstrapperApplicationData/WixBundleProperties", &pNode); | ||
25 | ExitOnFailure(hr, "Failed to select bundle information."); | ||
26 | |||
27 | if (S_OK == hr) | ||
28 | { | ||
29 | hr = XmlGetYesNoAttribute(pNode, L"PerMachine", &pBundle->fPerMachine); | ||
30 | if (E_NOTFOUND != hr) | ||
31 | { | ||
32 | ExitOnFailure(hr, "Failed to read bundle information per-machine."); | ||
33 | } | ||
34 | |||
35 | hr = XmlGetAttributeEx(pNode, L"DisplayName", &pBundle->sczName); | ||
36 | if (E_NOTFOUND != hr) | ||
37 | { | ||
38 | ExitOnFailure(hr, "Failed to read bundle information display name."); | ||
39 | } | ||
40 | |||
41 | hr = XmlGetAttributeEx(pNode, L"LogPathVariable", &pBundle->sczLogVariable); | ||
42 | if (E_NOTFOUND != hr) | ||
43 | { | ||
44 | ExitOnFailure(hr, "Failed to read bundle information log path variable."); | ||
45 | } | ||
46 | } | ||
47 | |||
48 | hr = ParsePackagesFromXml(&pBundle->packages, pixdManifest); | ||
49 | BalExitOnFailure(hr, "Failed to parse package information from bootstrapper application data."); | ||
50 | |||
51 | hr = ParseBalPackageInfoFromXml(&pBundle->packages, pixdManifest); | ||
52 | BalExitOnFailure(hr, "Failed to parse bal package information from bootstrapper application data."); | ||
53 | |||
54 | LExit: | ||
55 | ReleaseObject(pNode); | ||
56 | |||
57 | return hr; | ||
58 | } | ||
59 | |||
60 | |||
61 | DAPI_(HRESULT) BalInfoAddRelatedBundleAsPackage( | ||
62 | __in BAL_INFO_PACKAGES* pPackages, | ||
63 | __in LPCWSTR wzId, | ||
64 | __in BOOTSTRAPPER_RELATION_TYPE relationType, | ||
65 | __in BOOL /*fPerMachine*/, | ||
66 | __out_opt BAL_INFO_PACKAGE** ppPackage | ||
67 | ) | ||
68 | { | ||
69 | HRESULT hr = S_OK; | ||
70 | BAL_INFO_PACKAGE_TYPE type = BAL_INFO_PACKAGE_TYPE_UNKNOWN; | ||
71 | BAL_INFO_PACKAGE* pPackage = NULL; | ||
72 | |||
73 | // Ensure we have a supported relation type. | ||
74 | switch (relationType) | ||
75 | { | ||
76 | case BOOTSTRAPPER_RELATION_ADDON: | ||
77 | type = BAL_INFO_PACKAGE_TYPE_BUNDLE_ADDON; | ||
78 | break; | ||
79 | |||
80 | case BOOTSTRAPPER_RELATION_PATCH: | ||
81 | type = BAL_INFO_PACKAGE_TYPE_BUNDLE_PATCH; | ||
82 | break; | ||
83 | |||
84 | case BOOTSTRAPPER_RELATION_UPGRADE: | ||
85 | type = BAL_INFO_PACKAGE_TYPE_BUNDLE_UPGRADE; | ||
86 | break; | ||
87 | |||
88 | default: | ||
89 | ExitOnFailure(hr = E_INVALIDARG, "Unknown related bundle type: %u", relationType); | ||
90 | } | ||
91 | |||
92 | // Check to see if the bundle is already in the list of packages. | ||
93 | for (DWORD i = 0; i < pPackages->cPackages; ++i) | ||
94 | { | ||
95 | if (CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, 0, wzId, -1, pPackages->rgPackages[i].sczId, -1)) | ||
96 | { | ||
97 | ExitFunction1(hr = HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS)); | ||
98 | } | ||
99 | } | ||
100 | |||
101 | // Add the related bundle as a package. | ||
102 | hr = MemEnsureArraySize(reinterpret_cast<LPVOID*>(&pPackages->rgPackages), pPackages->cPackages + 1, sizeof(BAL_INFO_PACKAGE), 2); | ||
103 | ExitOnFailure(hr, "Failed to allocate memory for related bundle package information."); | ||
104 | |||
105 | pPackage = pPackages->rgPackages + pPackages->cPackages; | ||
106 | ++pPackages->cPackages; | ||
107 | |||
108 | hr = StrAllocString(&pPackage->sczId, wzId, 0); | ||
109 | ExitOnFailure(hr, "Failed to copy related bundle package id."); | ||
110 | |||
111 | pPackage->type = type; | ||
112 | |||
113 | // TODO: try to look up the DisplayName and Description in Add/Remove Programs with the wzId. | ||
114 | |||
115 | if (ppPackage) | ||
116 | { | ||
117 | *ppPackage = pPackage; | ||
118 | } | ||
119 | |||
120 | LExit: | ||
121 | return hr; | ||
122 | } | ||
123 | |||
124 | |||
125 | DAPI_(HRESULT) BalInfoFindPackageById( | ||
126 | __in BAL_INFO_PACKAGES* pPackages, | ||
127 | __in LPCWSTR wzId, | ||
128 | __out BAL_INFO_PACKAGE** ppPackage | ||
129 | ) | ||
130 | { | ||
131 | *ppPackage = NULL; | ||
132 | |||
133 | for (DWORD i = 0; i < pPackages->cPackages; ++i) | ||
134 | { | ||
135 | if (CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, 0, wzId, -1, pPackages->rgPackages[i].sczId, -1)) | ||
136 | { | ||
137 | *ppPackage = pPackages->rgPackages + i; | ||
138 | break; | ||
139 | } | ||
140 | } | ||
141 | |||
142 | return *ppPackage ? S_OK : E_NOTFOUND; | ||
143 | } | ||
144 | |||
145 | |||
146 | DAPI_(void) BalInfoUninitialize( | ||
147 | __in BAL_INFO_BUNDLE* pBundle | ||
148 | ) | ||
149 | { | ||
150 | for (DWORD i = 0; i < pBundle->packages.cPackages; ++i) | ||
151 | { | ||
152 | ReleaseStr(pBundle->packages.rgPackages[i].sczDisplayName); | ||
153 | ReleaseStr(pBundle->packages.rgPackages[i].sczDescription); | ||
154 | ReleaseStr(pBundle->packages.rgPackages[i].sczId); | ||
155 | ReleaseStr(pBundle->packages.rgPackages[i].sczDisplayInternalUICondition); | ||
156 | ReleaseStr(pBundle->packages.rgPackages[i].sczProductCode); | ||
157 | ReleaseStr(pBundle->packages.rgPackages[i].sczUpgradeCode); | ||
158 | ReleaseStr(pBundle->packages.rgPackages[i].sczVersion); | ||
159 | ReleaseStr(pBundle->packages.rgPackages[i].sczInstallCondition); | ||
160 | ReleaseStr(pBundle->packages.rgPackages[i].sczPrereqLicenseFile); | ||
161 | ReleaseStr(pBundle->packages.rgPackages[i].sczPrereqLicenseUrl); | ||
162 | } | ||
163 | |||
164 | ReleaseMem(pBundle->packages.rgPackages); | ||
165 | |||
166 | ReleaseStr(pBundle->sczName); | ||
167 | ReleaseStr(pBundle->sczLogVariable); | ||
168 | memset(pBundle, 0, sizeof(BAL_INFO_BUNDLE)); | ||
169 | } | ||
170 | |||
171 | |||
172 | static HRESULT ParsePackagesFromXml( | ||
173 | __in BAL_INFO_PACKAGES* pPackages, | ||
174 | __in IXMLDOMDocument* pixdManifest | ||
175 | ) | ||
176 | { | ||
177 | HRESULT hr = S_OK; | ||
178 | IXMLDOMNodeList* pNodeList = NULL; | ||
179 | IXMLDOMNode* pNode = NULL; | ||
180 | BAL_INFO_PACKAGE* prgPackages = NULL; | ||
181 | DWORD cPackages = 0; | ||
182 | LPWSTR scz = NULL; | ||
183 | |||
184 | hr = XmlSelectNodes(pixdManifest, L"/BootstrapperApplicationData/WixPackageProperties", &pNodeList); | ||
185 | ExitOnFailure(hr, "Failed to select all packages."); | ||
186 | |||
187 | hr = pNodeList->get_length(reinterpret_cast<long*>(&cPackages)); | ||
188 | ExitOnFailure(hr, "Failed to get the package count."); | ||
189 | |||
190 | prgPackages = static_cast<BAL_INFO_PACKAGE*>(MemAlloc(sizeof(BAL_INFO_PACKAGE) * cPackages, TRUE)); | ||
191 | ExitOnNull(prgPackages, hr, E_OUTOFMEMORY, "Failed to allocate memory for packages."); | ||
192 | |||
193 | DWORD iPackage = 0; | ||
194 | while (S_OK == (hr = XmlNextElement(pNodeList, &pNode, NULL))) | ||
195 | { | ||
196 | hr = XmlGetAttributeEx(pNode, L"Package", &prgPackages[iPackage].sczId); | ||
197 | ExitOnFailure(hr, "Failed to get package identifier for package."); | ||
198 | |||
199 | hr = XmlGetAttributeEx(pNode, L"DisplayName", &prgPackages[iPackage].sczDisplayName); | ||
200 | if (E_NOTFOUND != hr) | ||
201 | { | ||
202 | ExitOnFailure(hr, "Failed to get display name for package."); | ||
203 | } | ||
204 | |||
205 | hr = XmlGetAttributeEx(pNode, L"Description", &prgPackages[iPackage].sczDescription); | ||
206 | if (E_NOTFOUND != hr) | ||
207 | { | ||
208 | ExitOnFailure(hr, "Failed to get description for package."); | ||
209 | } | ||
210 | |||
211 | hr = XmlGetAttributeEx(pNode, L"PackageType", &scz); | ||
212 | ExitOnFailure(hr, "Failed to get package type for package."); | ||
213 | |||
214 | if (CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, 0, L"Exe", -1, scz, -1)) | ||
215 | { | ||
216 | prgPackages[iPackage].type = BAL_INFO_PACKAGE_TYPE_EXE; | ||
217 | } | ||
218 | else if (CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, 0, L"Msi", -1, scz, -1)) | ||
219 | { | ||
220 | prgPackages[iPackage].type = BAL_INFO_PACKAGE_TYPE_MSI; | ||
221 | } | ||
222 | else if (CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, 0, L"Msp", -1, scz, -1)) | ||
223 | { | ||
224 | prgPackages[iPackage].type = BAL_INFO_PACKAGE_TYPE_MSP; | ||
225 | } | ||
226 | else if (CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, 0, L"Msu", -1, scz, -1)) | ||
227 | { | ||
228 | prgPackages[iPackage].type = BAL_INFO_PACKAGE_TYPE_MSU; | ||
229 | } | ||
230 | |||
231 | hr = XmlGetYesNoAttribute(pNode, L"Permanent", &prgPackages[iPackage].fPermanent); | ||
232 | ExitOnFailure(hr, "Failed to get permanent setting for package."); | ||
233 | |||
234 | hr = XmlGetYesNoAttribute(pNode, L"Vital", &prgPackages[iPackage].fVital); | ||
235 | ExitOnFailure(hr, "Failed to get vital setting for package."); | ||
236 | |||
237 | hr = XmlGetAttributeEx(pNode, L"ProductCode", &prgPackages[iPackage].sczProductCode); | ||
238 | if (E_NOTFOUND != hr) | ||
239 | { | ||
240 | ExitOnFailure(hr, "Failed to get product code for package."); | ||
241 | } | ||
242 | |||
243 | hr = XmlGetAttributeEx(pNode, L"UpgradeCode", &prgPackages[iPackage].sczUpgradeCode); | ||
244 | if (E_NOTFOUND != hr) | ||
245 | { | ||
246 | ExitOnFailure(hr, "Failed to get upgrade code for package."); | ||
247 | } | ||
248 | |||
249 | hr = XmlGetAttributeEx(pNode, L"Version", &prgPackages[iPackage].sczVersion); | ||
250 | if (E_NOTFOUND != hr) | ||
251 | { | ||
252 | ExitOnFailure(hr, "Failed to get version for package."); | ||
253 | } | ||
254 | |||
255 | hr = XmlGetAttributeEx(pNode, L"InstallCondition", &prgPackages[iPackage].sczInstallCondition); | ||
256 | if (E_NOTFOUND != hr) | ||
257 | { | ||
258 | ExitOnFailure(hr, "Failed to get install condition for package."); | ||
259 | } | ||
260 | |||
261 | hr = XmlGetAttributeEx(pNode, L"Cache", &scz); | ||
262 | ExitOnFailure(hr, "Failed to get cache type for package."); | ||
263 | |||
264 | if (CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, 0, scz, -1, L"remove", -1)) | ||
265 | { | ||
266 | prgPackages[iPackage].cacheType = BOOTSTRAPPER_CACHE_TYPE_REMOVE; | ||
267 | } | ||
268 | else if (CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, 0, scz, -1, L"keep", -1)) | ||
269 | { | ||
270 | prgPackages[iPackage].cacheType = BOOTSTRAPPER_CACHE_TYPE_KEEP; | ||
271 | } | ||
272 | else if (CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, 0, scz, -1, L"force", -1)) | ||
273 | { | ||
274 | prgPackages[iPackage].cacheType = BOOTSTRAPPER_CACHE_TYPE_FORCE; | ||
275 | } | ||
276 | |||
277 | ++iPackage; | ||
278 | ReleaseNullObject(pNode); | ||
279 | } | ||
280 | ExitOnFailure(hr, "Failed to parse all package property elements."); | ||
281 | |||
282 | if (S_FALSE == hr) | ||
283 | { | ||
284 | hr = S_OK; | ||
285 | } | ||
286 | |||
287 | pPackages->cPackages = cPackages; | ||
288 | pPackages->rgPackages = prgPackages; | ||
289 | prgPackages = NULL; | ||
290 | |||
291 | LExit: | ||
292 | ReleaseStr(scz); | ||
293 | ReleaseMem(prgPackages); | ||
294 | ReleaseObject(pNode); | ||
295 | ReleaseObject(pNodeList); | ||
296 | |||
297 | return hr; | ||
298 | } | ||
299 | |||
300 | |||
301 | static HRESULT ParseBalPackageInfoFromXml( | ||
302 | __in BAL_INFO_PACKAGES* pPackages, | ||
303 | __in IXMLDOMDocument* pixdManifest | ||
304 | ) | ||
305 | { | ||
306 | HRESULT hr = S_OK; | ||
307 | IXMLDOMNodeList* pNodeList = NULL; | ||
308 | IXMLDOMNode* pNode = NULL; | ||
309 | LPWSTR scz = NULL; | ||
310 | BAL_INFO_PACKAGE* pPackage = NULL; | ||
311 | |||
312 | hr = XmlSelectNodes(pixdManifest, L"/BootstrapperApplicationData/WixBalPackageInfo", &pNodeList); | ||
313 | ExitOnFailure(hr, "Failed to select all packages."); | ||
314 | |||
315 | while (S_OK == (hr = XmlNextElement(pNodeList, &pNode, NULL))) | ||
316 | { | ||
317 | hr = XmlGetAttributeEx(pNode, L"PackageId", &scz); | ||
318 | ExitOnFailure(hr, "Failed to get package identifier for WixBalPackageInfo."); | ||
319 | |||
320 | hr = BalInfoFindPackageById(pPackages, scz, &pPackage); | ||
321 | ExitOnFailure(hr, "Failed to find package specified in WixBalPackageInfo: %ls", scz); | ||
322 | |||
323 | hr = XmlGetAttributeEx(pNode, L"DisplayInternalUICondition", &pPackage->sczDisplayInternalUICondition); | ||
324 | if (E_NOTFOUND != hr) | ||
325 | { | ||
326 | ExitOnFailure(hr, "Failed to get DisplayInternalUICondition setting for package."); | ||
327 | } | ||
328 | |||
329 | ReleaseNullObject(pNode); | ||
330 | } | ||
331 | ExitOnFailure(hr, "Failed to parse all WixBalPackageInfo elements."); | ||
332 | |||
333 | hr = XmlSelectNodes(pixdManifest, L"/BootstrapperApplicationData/WixMbaPrereqInformation", &pNodeList); | ||
334 | ExitOnFailure(hr, "Failed to select all packages."); | ||
335 | |||
336 | while (S_OK == (hr = XmlNextElement(pNodeList, &pNode, NULL))) | ||
337 | { | ||
338 | hr = XmlGetAttributeEx(pNode, L"PackageId", &scz); | ||
339 | ExitOnFailure(hr, "Failed to get package identifier for WixMbaPrereqInformation."); | ||
340 | |||
341 | hr = BalInfoFindPackageById(pPackages, scz, &pPackage); | ||
342 | ExitOnFailure(hr, "Failed to find package specified in WixMbaPrereqInformation: %ls", scz); | ||
343 | |||
344 | pPackage->fPrereqPackage = TRUE; | ||
345 | |||
346 | hr = XmlGetAttributeEx(pNode, L"LicenseFile", &pPackage->sczPrereqLicenseFile); | ||
347 | if (E_NOTFOUND != hr) | ||
348 | { | ||
349 | ExitOnFailure(hr, "Failed to get LicenseFile setting for prereq package."); | ||
350 | } | ||
351 | |||
352 | hr = XmlGetAttributeEx(pNode, L"LicenseUrl", &pPackage->sczPrereqLicenseUrl); | ||
353 | if (E_NOTFOUND != hr) | ||
354 | { | ||
355 | ExitOnFailure(hr, "Failed to get LicenseUrl setting for prereq package."); | ||
356 | } | ||
357 | |||
358 | ReleaseNullObject(pNode); | ||
359 | } | ||
360 | ExitOnFailure(hr, "Failed to parse all WixMbaPrereqInformation elements."); | ||
361 | |||
362 | if (S_FALSE == hr) | ||
363 | { | ||
364 | hr = S_OK; | ||
365 | } | ||
366 | |||
367 | LExit: | ||
368 | ReleaseStr(scz); | ||
369 | ReleaseObject(pNode); | ||
370 | ReleaseObject(pNodeList); | ||
371 | |||
372 | return hr; | ||
373 | } | ||