aboutsummaryrefslogtreecommitdiff
path: root/src/libs/dutil/WixToolset.DUtil/apuputil.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/libs/dutil/WixToolset.DUtil/apuputil.cpp')
-rw-r--r--src/libs/dutil/WixToolset.DUtil/apuputil.cpp700
1 files changed, 700 insertions, 0 deletions
diff --git a/src/libs/dutil/WixToolset.DUtil/apuputil.cpp b/src/libs/dutil/WixToolset.DUtil/apuputil.cpp
new file mode 100644
index 00000000..eb96d515
--- /dev/null
+++ b/src/libs/dutil/WixToolset.DUtil/apuputil.cpp
@@ -0,0 +1,700 @@
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// Exit macros
6#define ApupExitOnLastError(x, s, ...) ExitOnLastErrorSource(DUTIL_SOURCE_APUPUTIL, x, s, __VA_ARGS__)
7#define ApupExitOnLastErrorDebugTrace(x, s, ...) ExitOnLastErrorDebugTraceSource(DUTIL_SOURCE_APUPUTIL, x, s, __VA_ARGS__)
8#define ApupExitWithLastError(x, s, ...) ExitWithLastErrorSource(DUTIL_SOURCE_APUPUTIL, x, s, __VA_ARGS__)
9#define ApupExitOnFailure(x, s, ...) ExitOnFailureSource(DUTIL_SOURCE_APUPUTIL, x, s, __VA_ARGS__)
10#define ApupExitOnRootFailure(x, s, ...) ExitOnRootFailureSource(DUTIL_SOURCE_APUPUTIL, x, s, __VA_ARGS__)
11#define ApupExitOnFailureDebugTrace(x, s, ...) ExitOnFailureDebugTraceSource(DUTIL_SOURCE_APUPUTIL, x, s, __VA_ARGS__)
12#define ApupExitOnNull(p, x, e, s, ...) ExitOnNullSource(DUTIL_SOURCE_APUPUTIL, p, x, e, s, __VA_ARGS__)
13#define ApupExitOnNullWithLastError(p, x, s, ...) ExitOnNullWithLastErrorSource(DUTIL_SOURCE_APUPUTIL, p, x, s, __VA_ARGS__)
14#define ApupExitOnNullDebugTrace(p, x, e, s, ...) ExitOnNullDebugTraceSource(DUTIL_SOURCE_APUPUTIL, p, x, e, s, __VA_ARGS__)
15#define ApupExitOnInvalidHandleWithLastError(p, x, s, ...) ExitOnInvalidHandleWithLastErrorSource(DUTIL_SOURCE_APUPUTIL, p, x, s, __VA_ARGS__)
16#define ApupExitOnWin32Error(e, x, s, ...) ExitOnWin32ErrorSource(DUTIL_SOURCE_APUPUTIL, e, x, s, __VA_ARGS__)
17#define ApupExitOnGdipFailure(g, x, s, ...) ExitOnGdipFailureSource(DUTIL_SOURCE_APUPUTIL, g, x, s, __VA_ARGS__)
18
19// prototypes
20static HRESULT ProcessEntry(
21 __in ATOM_ENTRY* pAtomEntry,
22 __in LPCWSTR wzDefaultAppId,
23 __inout APPLICATION_UPDATE_ENTRY* pApupEntry
24 );
25static HRESULT ParseEnclosure(
26 __in ATOM_LINK* pLink,
27 __in APPLICATION_UPDATE_ENCLOSURE* pEnclosure
28 );
29static __callback int __cdecl CompareEntries(
30 void* pvContext,
31 const void* pvLeft,
32 const void* pvRight
33 );
34static HRESULT FilterEntries(
35 __in APPLICATION_UPDATE_ENTRY* rgEntries,
36 __in DWORD cEntries,
37 __in VERUTIL_VERSION* pCurrentVersion,
38 __inout APPLICATION_UPDATE_ENTRY** prgFilteredEntries,
39 __inout DWORD* pcFilteredEntries
40 );
41static HRESULT CopyEntry(
42 __in const APPLICATION_UPDATE_ENTRY* pSrc,
43 __in APPLICATION_UPDATE_ENTRY* pDest
44 );
45static HRESULT CopyEnclosure(
46 __in const APPLICATION_UPDATE_ENCLOSURE* pSrc,
47 __in APPLICATION_UPDATE_ENCLOSURE* pDest
48 );
49static void FreeEntry(
50 __in APPLICATION_UPDATE_ENTRY* pApupEntry
51 );
52static void FreeEnclosure(
53 __in APPLICATION_UPDATE_ENCLOSURE* pEnclosure
54 );
55
56
57//
58// ApupCalculateChainFromAtom - returns the chain of application updates found in an ATOM feed.
59//
60extern "C" HRESULT DAPI ApupAllocChainFromAtom(
61 __in ATOM_FEED* pFeed,
62 __out APPLICATION_UPDATE_CHAIN** ppChain
63 )
64{
65 HRESULT hr = S_OK;
66 APPLICATION_UPDATE_CHAIN* pChain = NULL;
67
68 pChain = static_cast<APPLICATION_UPDATE_CHAIN*>(MemAlloc(sizeof(APPLICATION_UPDATE_CHAIN), TRUE));
69
70 // First search the ATOM feed's custom elements to try and find the default application identity.
71 for (ATOM_UNKNOWN_ELEMENT* pElement = pFeed->pUnknownElements; pElement; pElement = pElement->pNext)
72 {
73 if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, pElement->wzNamespace, -1, APPLICATION_SYNDICATION_NAMESPACE, -1))
74 {
75 if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, pElement->wzElement, -1, L"application", -1))
76 {
77 hr = StrAllocString(&pChain->wzDefaultApplicationId, pElement->wzValue, 0);
78 ApupExitOnFailure(hr, "Failed to allocate default application id.");
79
80 for (ATOM_UNKNOWN_ATTRIBUTE* pAttribute = pElement->pAttributes; pAttribute; pAttribute = pAttribute->pNext)
81 {
82 if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, pAttribute->wzAttribute, -1, L"type", -1))
83 {
84 hr = StrAllocString(&pChain->wzDefaultApplicationType, pAttribute->wzValue, 0);
85 ApupExitOnFailure(hr, "Failed to allocate default application type.");
86 }
87 }
88 }
89 }
90 }
91
92 // Assume there will be as many application updates entries as their are feed entries.
93 if (pFeed->cEntries)
94 {
95 pChain->rgEntries = static_cast<APPLICATION_UPDATE_ENTRY*>(MemAlloc(sizeof(APPLICATION_UPDATE_ENTRY) * pFeed->cEntries, TRUE));
96 ApupExitOnNull(pChain->rgEntries, hr, E_OUTOFMEMORY, "Failed to allocate memory for update entries.");
97
98 // Process each entry, building up the chain.
99 for (DWORD i = 0; i < pFeed->cEntries; ++i)
100 {
101 hr = ProcessEntry(pFeed->rgEntries + i, pChain->wzDefaultApplicationId, pChain->rgEntries + pChain->cEntries);
102 ApupExitOnFailure(hr, "Failed to process ATOM entry.");
103
104 if (S_FALSE != hr)
105 {
106 ++pChain->cEntries;
107 }
108 }
109
110 // Sort the chain by descending version and ascending total size.
111 qsort_s(pChain->rgEntries, pChain->cEntries, sizeof(APPLICATION_UPDATE_ENTRY), CompareEntries, NULL);
112 }
113
114 // Trim the unused entries from the end, if any of the entries failed to parse or validate
115 if (pChain->cEntries != pFeed->cEntries)
116 {
117 if (pChain->cEntries > 0)
118 {
119 pChain->rgEntries = static_cast<APPLICATION_UPDATE_ENTRY*>(MemReAlloc(pChain->rgEntries, sizeof(APPLICATION_UPDATE_ENTRY) * pChain->cEntries, FALSE));
120 ApupExitOnNull(pChain->rgEntries, hr, E_OUTOFMEMORY, "Failed to reallocate memory for update entries.");
121 }
122 else
123 {
124 ReleaseNullMem(pChain->rgEntries);
125 }
126 }
127
128 *ppChain = pChain;
129 pChain = NULL;
130
131LExit:
132 ReleaseApupChain(pChain);
133
134 return hr;
135}
136
137
138//
139// ApupFilterChain - remove the unneeded update elements from the chain.
140//
141HRESULT DAPI ApupFilterChain(
142 __in APPLICATION_UPDATE_CHAIN* pChain,
143 __in VERUTIL_VERSION* pVersion,
144 __out APPLICATION_UPDATE_CHAIN** ppFilteredChain
145 )
146{
147 HRESULT hr = S_OK;
148 APPLICATION_UPDATE_CHAIN* pNewChain = NULL;
149 APPLICATION_UPDATE_ENTRY* prgEntries = NULL;
150 DWORD cEntries = NULL;
151
152 pNewChain = static_cast<APPLICATION_UPDATE_CHAIN*>(MemAlloc(sizeof(APPLICATION_UPDATE_CHAIN), TRUE));
153 ApupExitOnNull(pNewChain, hr, E_OUTOFMEMORY, "Failed to allocate filtered chain.");
154
155 hr = FilterEntries(pChain->rgEntries, pChain->cEntries, pVersion, &prgEntries, &cEntries);
156 ApupExitOnFailure(hr, "Failed to filter entries by version.");
157
158 if (pChain->wzDefaultApplicationId)
159 {
160 hr = StrAllocString(&pNewChain->wzDefaultApplicationId, pChain->wzDefaultApplicationId, 0);
161 ApupExitOnFailure(hr, "Failed to copy default application id.");
162 }
163
164 if (pChain->wzDefaultApplicationType)
165 {
166 hr = StrAllocString(&pNewChain->wzDefaultApplicationType, pChain->wzDefaultApplicationType, 0);
167 ApupExitOnFailure(hr, "Failed to copy default application type.");
168 }
169
170 pNewChain->rgEntries = prgEntries;
171 pNewChain->cEntries = cEntries;
172
173 *ppFilteredChain = pNewChain;
174 pNewChain = NULL;
175
176LExit:
177 ReleaseApupChain(pNewChain);
178 return hr;
179}
180
181
182//
183// ApupFreeChain - frees a previously allocated application update chain.
184//
185extern "C" void DAPI ApupFreeChain(
186 __in APPLICATION_UPDATE_CHAIN* pChain
187 )
188{
189 if (pChain)
190 {
191 for (DWORD i = 0; i < pChain->cEntries; ++i)
192 {
193 FreeEntry(pChain->rgEntries + i);
194 }
195
196 ReleaseMem(pChain->rgEntries);
197 ReleaseStr(pChain->wzDefaultApplicationType);
198 ReleaseStr(pChain->wzDefaultApplicationId);
199 ReleaseMem(pChain);
200 }
201}
202
203
204static HRESULT ProcessEntry(
205 __in ATOM_ENTRY* pAtomEntry,
206 __in LPCWSTR wzDefaultAppId,
207 __inout APPLICATION_UPDATE_ENTRY* pApupEntry
208 )
209{
210 HRESULT hr = S_OK;
211 int nCompareResult = 0;
212
213 // First search the ATOM entry's custom elements to try and find the application update information.
214 for (ATOM_UNKNOWN_ELEMENT* pElement = pAtomEntry->pUnknownElements; pElement; pElement = pElement->pNext)
215 {
216 if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, pElement->wzNamespace, -1, APPLICATION_SYNDICATION_NAMESPACE, -1))
217 {
218 if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, pElement->wzElement, -1, L"application", -1))
219 {
220 hr = StrAllocString(&pApupEntry->wzApplicationId, pElement->wzValue, 0);
221 ApupExitOnFailure(hr, "Failed to allocate application identity.");
222
223 for (ATOM_UNKNOWN_ATTRIBUTE* pAttribute = pElement->pAttributes; pAttribute; pAttribute = pAttribute->pNext)
224 {
225 if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, pAttribute->wzAttribute, -1, L"type", -1))
226 {
227 hr = StrAllocString(&pApupEntry->wzApplicationType, pAttribute->wzValue, 0);
228 ApupExitOnFailure(hr, "Failed to allocate application type.");
229 }
230 }
231 }
232 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, pElement->wzElement, -1, L"upgrade", -1))
233 {
234 hr = StrAllocString(&pApupEntry->wzUpgradeId, pElement->wzValue, 0);
235 ApupExitOnFailure(hr, "Failed to allocate upgrade id.");
236
237 for (ATOM_UNKNOWN_ATTRIBUTE* pAttribute = pElement->pAttributes; pAttribute; pAttribute = pAttribute->pNext)
238 {
239 if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, pAttribute->wzAttribute, -1, L"version", -1))
240 {
241 hr = VerParseVersion(pAttribute->wzValue, 0, FALSE, &pApupEntry->pUpgradeVersion);
242 ApupExitOnFailure(hr, "Failed to parse upgrade version string '%ls' from ATOM entry.", pAttribute->wzValue);
243 }
244 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, pAttribute->wzAttribute, -1, L"exclusive", -1))
245 {
246 if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, pAttribute->wzValue, -1, L"true", -1))
247 {
248 pApupEntry->fUpgradeExclusive = TRUE;
249 }
250 }
251 }
252 }
253 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, pElement->wzElement, -1, L"version", -1))
254 {
255 hr = VerParseVersion(pElement->wzValue, 0, FALSE, &pApupEntry->pVersion);
256 ApupExitOnFailure(hr, "Failed to parse version string '%ls' from ATOM entry.", pElement->wzValue);
257 }
258 }
259 }
260
261 // If there is no application identity or no version, skip the whole thing.
262 if ((!pApupEntry->wzApplicationId && !wzDefaultAppId) || !pApupEntry->pVersion)
263 {
264 ExitFunction1(hr = S_FALSE); // skip this update since it has no application id or version.
265 }
266
267 if (pApupEntry->pUpgradeVersion)
268 {
269 hr = VerCompareParsedVersions(pApupEntry->pUpgradeVersion, pApupEntry->pVersion, &nCompareResult);
270 ApupExitOnFailure(hr, "Failed to compare version to upgrade version.");
271
272 if (nCompareResult >= 0)
273 {
274 hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
275 ApupExitOnRootFailure(hr, "Upgrade version is greater than or equal to application version.");
276 }
277 }
278
279 if (pAtomEntry->wzTitle)
280 {
281 hr = StrAllocString(&pApupEntry->wzTitle, pAtomEntry->wzTitle, 0);
282 ApupExitOnFailure(hr, "Failed to allocate application title.");
283 }
284
285 if (pAtomEntry->wzSummary)
286 {
287 hr = StrAllocString(&pApupEntry->wzSummary, pAtomEntry->wzSummary, 0);
288 ApupExitOnFailure(hr, "Failed to allocate application summary.");
289 }
290
291 if (pAtomEntry->pContent)
292 {
293 if (pAtomEntry->pContent->wzType)
294 {
295 hr = StrAllocString(&pApupEntry->wzContentType, pAtomEntry->pContent->wzType, 0);
296 ApupExitOnFailure(hr, "Failed to allocate content type.");
297 }
298
299 if (pAtomEntry->pContent->wzValue)
300 {
301 hr = StrAllocString(&pApupEntry->wzContent, pAtomEntry->pContent->wzValue, 0);
302 ApupExitOnFailure(hr, "Failed to allocate content.");
303 }
304 }
305 // Now process the enclosures. Assume every link in the ATOM entry is an enclosure.
306 pApupEntry->rgEnclosures = static_cast<APPLICATION_UPDATE_ENCLOSURE*>(MemAlloc(sizeof(APPLICATION_UPDATE_ENCLOSURE) * pAtomEntry->cLinks, TRUE));
307 ApupExitOnNull(pApupEntry->rgEnclosures, hr, E_OUTOFMEMORY, "Failed to allocate enclosures for application update entry.");
308
309 for (DWORD i = 0; i < pAtomEntry->cLinks; ++i)
310 {
311 ATOM_LINK* pLink = pAtomEntry->rgLinks + i;
312 if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, pLink->wzRel, -1, L"enclosure", -1))
313 {
314 hr = ParseEnclosure(pLink, pApupEntry->rgEnclosures + pApupEntry->cEnclosures);
315 ApupExitOnFailure(hr, "Failed to parse enclosure.");
316
317 pApupEntry->dw64TotalSize += pApupEntry->rgEnclosures[pApupEntry->cEnclosures].dw64Size; // total up the size of the enclosures
318
319 ++pApupEntry->cEnclosures;
320 }
321 }
322
323LExit:
324 if (S_OK != hr) // if anything went wrong, free the entry.
325 {
326 FreeEntry(pApupEntry);
327 memset(pApupEntry, 0, sizeof(APPLICATION_UPDATE_ENTRY));
328 }
329
330 return hr;
331}
332
333
334static HRESULT ParseEnclosure(
335 __in ATOM_LINK* pLink,
336 __in APPLICATION_UPDATE_ENCLOSURE* pEnclosure
337 )
338{
339 HRESULT hr = S_OK;
340 DWORD dwDigestLength = 0;
341 DWORD dwDigestStringLength = 0;
342 size_t cchDigestString = 0;
343
344 // First search the ATOM link's custom elements to try and find the application update enclosure information.
345 for (ATOM_UNKNOWN_ELEMENT* pElement = pLink->pUnknownElements; pElement; pElement = pElement->pNext)
346 {
347 if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, pElement->wzNamespace, -1, APPLICATION_SYNDICATION_NAMESPACE, -1))
348 {
349 if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, L"digest", -1, pElement->wzElement, -1))
350 {
351 // Find the digest[@algorithm] which is required. Everything else is ignored.
352 for (ATOM_UNKNOWN_ATTRIBUTE* pAttribute = pElement->pAttributes; pAttribute; pAttribute = pAttribute->pNext)
353 {
354 dwDigestLength = 0;
355 if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, L"algorithm", -1, pAttribute->wzAttribute, -1))
356 {
357 if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, L"md5", -1, pAttribute->wzValue, -1))
358 {
359 pEnclosure->digestAlgorithm = APUP_HASH_ALGORITHM_MD5;
360 dwDigestLength = MD5_HASH_LEN;
361 }
362 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, L"sha1", -1, pAttribute->wzValue, -1))
363 {
364 pEnclosure->digestAlgorithm = APUP_HASH_ALGORITHM_SHA1;
365 dwDigestLength = SHA1_HASH_LEN;
366 }
367 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, L"sha256", -1, pAttribute->wzValue, -1))
368 {
369 pEnclosure->digestAlgorithm = APUP_HASH_ALGORITHM_SHA256;
370 dwDigestLength = SHA256_HASH_LEN;
371 }
372 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, L"sha512", -1, pAttribute->wzValue, -1))
373 {
374 pEnclosure->digestAlgorithm = APUP_HASH_ALGORITHM_SHA512;
375 dwDigestLength = SHA512_HASH_LEN;
376 }
377 break;
378 }
379 }
380
381 if (dwDigestLength)
382 {
383 dwDigestStringLength = 2 * dwDigestLength;
384
385 hr = ::StringCchLengthW(pElement->wzValue, STRSAFE_MAX_CCH, &cchDigestString);
386 ApupExitOnFailure(hr, "Failed to get string length of digest value.");
387
388 if (dwDigestStringLength != cchDigestString)
389 {
390 hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
391 ApupExitOnRootFailure(hr, "Invalid digest length (%Iu) for digest algorithm (%u).", cchDigestString, dwDigestStringLength);
392 }
393
394 pEnclosure->cbDigest = sizeof(BYTE) * dwDigestLength;
395 pEnclosure->rgbDigest = static_cast<BYTE*>(MemAlloc(pEnclosure->cbDigest, TRUE));
396 ApupExitOnNull(pEnclosure->rgbDigest, hr, E_OUTOFMEMORY, "Failed to allocate memory for digest.");
397
398 hr = StrHexDecode(pElement->wzValue, pEnclosure->rgbDigest, pEnclosure->cbDigest);
399 ApupExitOnFailure(hr, "Failed to decode digest value.");
400 }
401 else
402 {
403 hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
404 ApupExitOnRootFailure(hr, "Unknown algorithm type for digest.");
405 }
406
407 break;
408 }
409 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, L"name", -1, pElement->wzElement, -1))
410 {
411 hr = StrAllocString(&pEnclosure->wzLocalName, pElement->wzValue, 0);
412 ApupExitOnFailure(hr, "Failed to copy local name.");
413 }
414 }
415 }
416
417 pEnclosure->dw64Size = pLink->dw64Length;
418
419 hr = StrAllocString(&pEnclosure->wzUrl, pLink->wzUrl, 0);
420 ApupExitOnFailure(hr, "Failed to allocate enclosure URL.");
421
422 pEnclosure->fInstaller = FALSE;
423 pEnclosure->wzLocalName = NULL;
424
425LExit:
426 return hr;
427}
428
429
430static __callback int __cdecl CompareEntries(
431 void* /*pvContext*/,
432 const void* pvLeft,
433 const void* pvRight
434 )
435{
436 int ret = 0;
437 const APPLICATION_UPDATE_ENTRY* pEntryLeft = static_cast<const APPLICATION_UPDATE_ENTRY*>(pvLeft);
438 const APPLICATION_UPDATE_ENTRY* pEntryRight = static_cast<const APPLICATION_UPDATE_ENTRY*>(pvRight);
439
440 VerCompareParsedVersions(pEntryLeft->pVersion, pEntryRight->pVersion, &ret);
441 if (0 == ret)
442 {
443 VerCompareParsedVersions(pEntryLeft->pUpgradeVersion, pEntryRight->pUpgradeVersion, &ret);
444 if (0 == ret)
445 {
446 ret = (pEntryLeft->dw64TotalSize < pEntryRight->dw64TotalSize) ? -1 :
447 (pEntryLeft->dw64TotalSize > pEntryRight->dw64TotalSize) ? 1 : 0;
448 }
449 }
450
451 // Sort descending.
452 ret = -ret;
453
454 return ret;
455}
456
457
458static HRESULT FilterEntries(
459 __in APPLICATION_UPDATE_ENTRY* rgEntries,
460 __in DWORD cEntries,
461 __in VERUTIL_VERSION* pCurrentVersion,
462 __inout APPLICATION_UPDATE_ENTRY** prgFilteredEntries,
463 __inout DWORD* pcFilteredEntries
464 )
465{
466 HRESULT hr = S_OK;
467 int nCompareResult = 0;
468 size_t cbAllocSize = 0;
469 const APPLICATION_UPDATE_ENTRY* pRequired = NULL;;
470 LPVOID pv = NULL;
471
472 if (cEntries)
473 {
474 for (DWORD i = 0; i < cEntries; ++i)
475 {
476 const APPLICATION_UPDATE_ENTRY* pEntry = rgEntries + i;
477
478 hr = VerCompareParsedVersions(pCurrentVersion, pEntry->pVersion, &nCompareResult);
479 ApupExitOnFailure(hr, "Failed to compare versions.");
480
481 if (nCompareResult >= 0)
482 {
483 continue;
484 }
485
486 hr = VerCompareParsedVersions(pCurrentVersion, pEntry->pUpgradeVersion, &nCompareResult);
487 ApupExitOnFailure(hr, "Failed to compare upgrade versions.");
488
489 if (nCompareResult > 0 || (!pEntry->fUpgradeExclusive && nCompareResult == 0))
490 {
491 pRequired = pEntry;
492 break;
493 }
494 }
495
496 if (pRequired)
497 {
498 DWORD cNewFilteredEntries = *pcFilteredEntries + 1;
499
500 hr = ::SizeTMult(sizeof(APPLICATION_UPDATE_ENTRY), cNewFilteredEntries, &cbAllocSize);
501 ApupExitOnFailure(hr, "Overflow while calculating alloc size for more entries - number of entries: %u", cNewFilteredEntries);
502
503 if (*prgFilteredEntries)
504 {
505 pv = MemReAlloc(*prgFilteredEntries, cbAllocSize, FALSE);
506 ApupExitOnNull(pv, hr, E_OUTOFMEMORY, "Failed to reallocate memory for more entries.");
507 }
508 else
509 {
510 pv = MemAlloc(cbAllocSize, TRUE);
511 ApupExitOnNull(pv, hr, E_OUTOFMEMORY, "Failed to allocate memory for entries.");
512 }
513
514 *pcFilteredEntries = cNewFilteredEntries;
515 *prgFilteredEntries = static_cast<APPLICATION_UPDATE_ENTRY*>(pv);
516 pv = NULL;
517
518 hr = CopyEntry(pRequired, *prgFilteredEntries + *pcFilteredEntries - 1);
519 ApupExitOnFailure(hr, "Failed to deep copy entry.");
520
521 hr = VerCompareParsedVersions(pRequired->pVersion, rgEntries[0].pVersion, &nCompareResult);
522 ApupExitOnFailure(hr, "Failed to compare required version.");
523
524 if (nCompareResult < 0)
525 {
526 FilterEntries(rgEntries, cEntries, pRequired->pVersion, prgFilteredEntries, pcFilteredEntries);
527 }
528 }
529 }
530
531LExit:
532 ReleaseMem(pv);
533 return hr;
534}
535
536
537static HRESULT CopyEntry(
538 __in const APPLICATION_UPDATE_ENTRY* pSrc,
539 __in APPLICATION_UPDATE_ENTRY* pDest
540 )
541{
542 HRESULT hr = S_OK;
543 size_t cbAllocSize = 0;
544
545 memset(pDest, 0, sizeof(APPLICATION_UPDATE_ENTRY));
546
547 if (pSrc->wzApplicationId)
548 {
549 hr = StrAllocString(&pDest->wzApplicationId, pSrc->wzApplicationId, 0);
550 ApupExitOnFailure(hr, "Failed to copy application id.");
551 }
552
553 if (pSrc->wzApplicationType)
554 {
555 hr = StrAllocString(&pDest->wzApplicationType, pSrc->wzApplicationType, 0);
556 ApupExitOnFailure(hr, "Failed to copy application type.");
557 }
558
559 if (pSrc->wzUpgradeId)
560 {
561 hr = StrAllocString(&pDest->wzUpgradeId, pSrc->wzUpgradeId, 0);
562 ApupExitOnFailure(hr, "Failed to copy upgrade id.");
563 }
564
565 if (pSrc->wzTitle)
566 {
567 hr = StrAllocString(&pDest->wzTitle, pSrc->wzTitle, 0);
568 ApupExitOnFailure(hr, "Failed to copy title.");
569 }
570
571 if (pSrc->wzSummary)
572 {
573 hr = StrAllocString(&pDest->wzSummary, pSrc->wzSummary, 0);
574 ApupExitOnFailure(hr, "Failed to copy summary.");
575 }
576
577 if (pSrc->wzContentType)
578 {
579 hr = StrAllocString(&pDest->wzContentType, pSrc->wzContentType, 0);
580 ApupExitOnFailure(hr, "Failed to copy content type.");
581 }
582
583 if (pSrc->wzContent)
584 {
585 hr = StrAllocString(&pDest->wzContent, pSrc->wzContent, 0);
586 ApupExitOnFailure(hr, "Failed to copy content.");
587 }
588
589 pDest->dw64TotalSize = pSrc->dw64TotalSize;
590
591 hr = VerCopyVersion(pSrc->pUpgradeVersion, &pDest->pUpgradeVersion);
592 ApupExitOnFailure(hr, "Failed to copy upgrade version.");
593
594 hr = VerCopyVersion(pSrc->pVersion, &pDest->pVersion);
595 ApupExitOnFailure(hr, "Failed to copy version.");
596
597 pDest->fUpgradeExclusive = pSrc->fUpgradeExclusive;
598
599 hr = ::SizeTMult(sizeof(APPLICATION_UPDATE_ENCLOSURE), pSrc->cEnclosures, &cbAllocSize);
600 ApupExitOnRootFailure(hr, "Overflow while calculating memory allocation size");
601
602 pDest->rgEnclosures = static_cast<APPLICATION_UPDATE_ENCLOSURE*>(MemAlloc(cbAllocSize, TRUE));
603 ApupExitOnNull(pDest->rgEnclosures, hr, E_OUTOFMEMORY, "Failed to allocate copy of enclosures.");
604
605 pDest->cEnclosures = pSrc->cEnclosures;
606
607 for (DWORD i = 0; i < pDest->cEnclosures; ++i)
608 {
609 hr = CopyEnclosure(pSrc->rgEnclosures + i, pDest->rgEnclosures + i);
610 ApupExitOnFailure(hr, "Failed to copy enclosure.");
611 }
612
613LExit:
614 if (FAILED(hr))
615 {
616 FreeEntry(pDest);
617 }
618
619 return hr;
620}
621
622
623static HRESULT CopyEnclosure(
624 __in const APPLICATION_UPDATE_ENCLOSURE* pSrc,
625 __in APPLICATION_UPDATE_ENCLOSURE* pDest
626 )
627{
628 HRESULT hr = S_OK;
629
630 memset(pDest, 0, sizeof(APPLICATION_UPDATE_ENCLOSURE));
631
632 if (pSrc->wzUrl)
633 {
634 hr = StrAllocString(&pDest->wzUrl, pSrc->wzUrl, 0);
635 ApupExitOnFailure(hr, "Failed copy url.");
636 }
637
638 if (pSrc->wzLocalName)
639 {
640 hr = StrAllocString(&pDest->wzLocalName, pSrc->wzLocalName, 0);
641 ApupExitOnFailure(hr, "Failed copy url.");
642 }
643
644 pDest->rgbDigest = static_cast<BYTE*>(MemAlloc(sizeof(BYTE) * pSrc->cbDigest, FALSE));
645 ApupExitOnNull(pDest->rgbDigest, hr, E_OUTOFMEMORY, "Failed to allocate memory for copy of digest.");
646
647 pDest->cbDigest = pSrc->cbDigest;
648
649 memcpy_s(pDest->rgbDigest, sizeof(BYTE) * pDest->cbDigest, pSrc->rgbDigest, sizeof(BYTE) * pSrc->cbDigest);
650
651 pDest->digestAlgorithm = pSrc->digestAlgorithm;
652
653 pDest->dw64Size = pSrc->dw64Size;
654 pDest->fInstaller = pSrc->fInstaller;
655
656LExit:
657 if (FAILED(hr))
658 {
659 FreeEnclosure(pDest);
660 }
661
662 return hr;
663}
664
665
666static void FreeEntry(
667 __in APPLICATION_UPDATE_ENTRY* pEntry
668 )
669{
670 if (pEntry)
671 {
672 for (DWORD i = 0; i < pEntry->cEnclosures; ++i)
673 {
674 FreeEnclosure(pEntry->rgEnclosures + i);
675 }
676
677 ReleaseStr(pEntry->wzUpgradeId);
678 ReleaseStr(pEntry->wzApplicationType);
679 ReleaseStr(pEntry->wzApplicationId);
680 ReleaseStr(pEntry->wzTitle);
681 ReleaseStr(pEntry->wzSummary);
682 ReleaseStr(pEntry->wzContentType);
683 ReleaseStr(pEntry->wzContent);
684 ReleaseVerutilVersion(pEntry->pVersion);
685 ReleaseVerutilVersion(pEntry->pUpgradeVersion);
686 }
687}
688
689
690static void FreeEnclosure(
691 __in APPLICATION_UPDATE_ENCLOSURE* pEnclosure
692 )
693{
694 if (pEnclosure)
695 {
696 ReleaseMem(pEnclosure->rgbDigest);
697 ReleaseStr(pEnclosure->wzLocalName);
698 ReleaseStr(pEnclosure->wzUrl);
699 }
700}