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