diff options
Diffstat (limited to 'src/libs/dutil/WixToolset.DUtil/verutil.cpp')
-rw-r--r-- | src/libs/dutil/WixToolset.DUtil/verutil.cpp | 647 |
1 files changed, 647 insertions, 0 deletions
diff --git a/src/libs/dutil/WixToolset.DUtil/verutil.cpp b/src/libs/dutil/WixToolset.DUtil/verutil.cpp new file mode 100644 index 00000000..21626f94 --- /dev/null +++ b/src/libs/dutil/WixToolset.DUtil/verutil.cpp | |||
@@ -0,0 +1,647 @@ | |||
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 VerExitOnLastError(x, s, ...) ExitOnLastErrorSource(DUTIL_SOURCE_VERUTIL, x, s, __VA_ARGS__) | ||
7 | #define VerExitOnLastErrorDebugTrace(x, s, ...) ExitOnLastErrorDebugTraceSource(DUTIL_SOURCE_VERUTIL, x, s, __VA_ARGS__) | ||
8 | #define VerExitWithLastError(x, s, ...) ExitWithLastErrorSource(DUTIL_SOURCE_VERUTIL, x, s, __VA_ARGS__) | ||
9 | #define VerExitOnFailure(x, s, ...) ExitOnFailureSource(DUTIL_SOURCE_VERUTIL, x, s, __VA_ARGS__) | ||
10 | #define VerExitOnRootFailure(x, s, ...) ExitOnRootFailureSource(DUTIL_SOURCE_VERUTIL, x, s, __VA_ARGS__) | ||
11 | #define VerExitOnFailureDebugTrace(x, s, ...) ExitOnFailureDebugTraceSource(DUTIL_SOURCE_VERUTIL, x, s, __VA_ARGS__) | ||
12 | #define VerExitOnNull(p, x, e, s, ...) ExitOnNullSource(DUTIL_SOURCE_VERUTIL, p, x, e, s, __VA_ARGS__) | ||
13 | #define VerExitOnNullWithLastError(p, x, s, ...) ExitOnNullWithLastErrorSource(DUTIL_SOURCE_VERUTIL, p, x, s, __VA_ARGS__) | ||
14 | #define VerExitOnNullDebugTrace(p, x, e, s, ...) ExitOnNullDebugTraceSource(DUTIL_SOURCE_VERUTIL, p, x, e, s, __VA_ARGS__) | ||
15 | #define VerExitOnInvalidHandleWithLastError(p, x, s, ...) ExitOnInvalidHandleWithLastErrorSource(DUTIL_SOURCE_VERUTIL, p, x, s, __VA_ARGS__) | ||
16 | #define VerExitOnWin32Error(e, x, s, ...) ExitOnWin32ErrorSource(DUTIL_SOURCE_VERUTIL, e, x, s, __VA_ARGS__) | ||
17 | |||
18 | // constants | ||
19 | const DWORD GROW_RELEASE_LABELS = 3; | ||
20 | |||
21 | // Forward declarations. | ||
22 | static int CompareDword( | ||
23 | __in const DWORD& dw1, | ||
24 | __in const DWORD& dw2 | ||
25 | ); | ||
26 | static HRESULT CompareReleaseLabel( | ||
27 | __in const VERUTIL_VERSION_RELEASE_LABEL* p1, | ||
28 | __in LPCWSTR wzVersion1, | ||
29 | __in const VERUTIL_VERSION_RELEASE_LABEL* p2, | ||
30 | __in LPCWSTR wzVersion2, | ||
31 | __out int* pnResult | ||
32 | ); | ||
33 | static HRESULT CompareVersionSubstring( | ||
34 | __in LPCWSTR wzString1, | ||
35 | __in int cchCount1, | ||
36 | __in LPCWSTR wzString2, | ||
37 | __in int cchCount2, | ||
38 | __out int* pnResult | ||
39 | ); | ||
40 | |||
41 | |||
42 | DAPI_(HRESULT) VerCompareParsedVersions( | ||
43 | __in_opt VERUTIL_VERSION* pVersion1, | ||
44 | __in_opt VERUTIL_VERSION* pVersion2, | ||
45 | __out int* pnResult | ||
46 | ) | ||
47 | { | ||
48 | HRESULT hr = S_OK; | ||
49 | int nResult = 0; | ||
50 | DWORD cMaxReleaseLabels = 0; | ||
51 | BOOL fCompareMetadata = FALSE; | ||
52 | |||
53 | if (pVersion1 && !pVersion1->sczVersion || | ||
54 | pVersion2 && !pVersion2->sczVersion) | ||
55 | { | ||
56 | ExitFunction1(hr = E_INVALIDARG); | ||
57 | } | ||
58 | |||
59 | if (pVersion1 == pVersion2) | ||
60 | { | ||
61 | ExitFunction1(nResult = 0); | ||
62 | } | ||
63 | else if (pVersion1 && !pVersion2) | ||
64 | { | ||
65 | ExitFunction1(nResult = 1); | ||
66 | } | ||
67 | else if (!pVersion1 && pVersion2) | ||
68 | { | ||
69 | ExitFunction1(nResult = -1); | ||
70 | } | ||
71 | |||
72 | nResult = CompareDword(pVersion1->dwMajor, pVersion2->dwMajor); | ||
73 | if (0 != nResult) | ||
74 | { | ||
75 | ExitFunction(); | ||
76 | } | ||
77 | |||
78 | nResult = CompareDword(pVersion1->dwMinor, pVersion2->dwMinor); | ||
79 | if (0 != nResult) | ||
80 | { | ||
81 | ExitFunction(); | ||
82 | } | ||
83 | |||
84 | nResult = CompareDword(pVersion1->dwPatch, pVersion2->dwPatch); | ||
85 | if (0 != nResult) | ||
86 | { | ||
87 | ExitFunction(); | ||
88 | } | ||
89 | |||
90 | nResult = CompareDword(pVersion1->dwRevision, pVersion2->dwRevision); | ||
91 | if (0 != nResult) | ||
92 | { | ||
93 | ExitFunction(); | ||
94 | } | ||
95 | |||
96 | if (pVersion1->cReleaseLabels) | ||
97 | { | ||
98 | if (pVersion2->cReleaseLabels) | ||
99 | { | ||
100 | cMaxReleaseLabels = max(pVersion1->cReleaseLabels, pVersion2->cReleaseLabels); | ||
101 | } | ||
102 | else | ||
103 | { | ||
104 | ExitFunction1(nResult = -1); | ||
105 | } | ||
106 | } | ||
107 | else if (pVersion2->cReleaseLabels) | ||
108 | { | ||
109 | ExitFunction1(nResult = 1); | ||
110 | } | ||
111 | |||
112 | if (cMaxReleaseLabels) | ||
113 | { | ||
114 | for (DWORD i = 0; i < cMaxReleaseLabels; ++i) | ||
115 | { | ||
116 | VERUTIL_VERSION_RELEASE_LABEL* pReleaseLabel1 = pVersion1->cReleaseLabels > i ? pVersion1->rgReleaseLabels + i : NULL; | ||
117 | VERUTIL_VERSION_RELEASE_LABEL* pReleaseLabel2 = pVersion2->cReleaseLabels > i ? pVersion2->rgReleaseLabels + i : NULL; | ||
118 | |||
119 | hr = CompareReleaseLabel(pReleaseLabel1, pVersion1->sczVersion, pReleaseLabel2, pVersion2->sczVersion, &nResult); | ||
120 | if (FAILED(hr) || 0 != nResult) | ||
121 | { | ||
122 | ExitFunction(); | ||
123 | } | ||
124 | } | ||
125 | } | ||
126 | |||
127 | if (pVersion1->fInvalid) | ||
128 | { | ||
129 | if (!pVersion2->fInvalid) | ||
130 | { | ||
131 | ExitFunction1(nResult = -1); | ||
132 | } | ||
133 | else | ||
134 | { | ||
135 | fCompareMetadata = TRUE; | ||
136 | } | ||
137 | } | ||
138 | else if (pVersion2->fInvalid) | ||
139 | { | ||
140 | ExitFunction1(nResult = 1); | ||
141 | } | ||
142 | |||
143 | if (fCompareMetadata) | ||
144 | { | ||
145 | hr = CompareVersionSubstring(pVersion1->sczVersion + pVersion1->cchMetadataOffset, -1, pVersion2->sczVersion + pVersion2->cchMetadataOffset, -1, &nResult); | ||
146 | } | ||
147 | |||
148 | LExit: | ||
149 | *pnResult = nResult; | ||
150 | return hr; | ||
151 | } | ||
152 | |||
153 | DAPI_(HRESULT) VerCompareStringVersions( | ||
154 | __in_z LPCWSTR wzVersion1, | ||
155 | __in_z LPCWSTR wzVersion2, | ||
156 | __in BOOL fStrict, | ||
157 | __out int* pnResult | ||
158 | ) | ||
159 | { | ||
160 | HRESULT hr = S_OK; | ||
161 | VERUTIL_VERSION* pVersion1 = NULL; | ||
162 | VERUTIL_VERSION* pVersion2 = NULL; | ||
163 | int nResult = 0; | ||
164 | |||
165 | hr = VerParseVersion(wzVersion1, 0, fStrict, &pVersion1); | ||
166 | VerExitOnFailure(hr, "Failed to parse Verutil version '%ls'", wzVersion1); | ||
167 | |||
168 | hr = VerParseVersion(wzVersion2, 0, fStrict, &pVersion2); | ||
169 | VerExitOnFailure(hr, "Failed to parse Verutil version '%ls'", wzVersion2); | ||
170 | |||
171 | hr = VerCompareParsedVersions(pVersion1, pVersion2, &nResult); | ||
172 | VerExitOnFailure(hr, "Failed to compare parsed Verutil versions '%ls' and '%ls'.", wzVersion1, wzVersion2); | ||
173 | |||
174 | LExit: | ||
175 | *pnResult = nResult; | ||
176 | |||
177 | ReleaseVerutilVersion(pVersion1); | ||
178 | ReleaseVerutilVersion(pVersion2); | ||
179 | |||
180 | return hr; | ||
181 | } | ||
182 | |||
183 | DAPI_(HRESULT) VerCopyVersion( | ||
184 | __in VERUTIL_VERSION* pSource, | ||
185 | __out VERUTIL_VERSION** ppVersion | ||
186 | ) | ||
187 | { | ||
188 | HRESULT hr = S_OK; | ||
189 | VERUTIL_VERSION* pCopy = NULL; | ||
190 | |||
191 | pCopy = reinterpret_cast<VERUTIL_VERSION*>(MemAlloc(sizeof(VERUTIL_VERSION), TRUE)); | ||
192 | VerExitOnNull(pCopy, hr, E_OUTOFMEMORY, "Failed to allocate memory for Verutil version copy."); | ||
193 | |||
194 | hr = StrAllocString(&pCopy->sczVersion, pSource->sczVersion, 0); | ||
195 | VerExitOnFailure(hr, "Failed to copy Verutil version string '%ls'.", pSource->sczVersion); | ||
196 | |||
197 | pCopy->dwMajor = pSource->dwMajor; | ||
198 | pCopy->dwMinor = pSource->dwMinor; | ||
199 | pCopy->dwPatch = pSource->dwPatch; | ||
200 | pCopy->dwRevision = pSource->dwRevision; | ||
201 | |||
202 | if (pSource->cReleaseLabels) | ||
203 | { | ||
204 | hr = MemEnsureArraySize(reinterpret_cast<LPVOID*>(&pCopy->rgReleaseLabels), 0, sizeof(VERUTIL_VERSION_RELEASE_LABEL), pSource->cReleaseLabels); | ||
205 | VerExitOnFailure(hr, "Failed to allocate memory for Verutil version release labels copies."); | ||
206 | |||
207 | pCopy->cReleaseLabels = pSource->cReleaseLabels; | ||
208 | |||
209 | for (DWORD i = 0; i < pCopy->cReleaseLabels; ++i) | ||
210 | { | ||
211 | VERUTIL_VERSION_RELEASE_LABEL* pSourceLabel = pSource->rgReleaseLabels + i; | ||
212 | VERUTIL_VERSION_RELEASE_LABEL* pCopyLabel = pCopy->rgReleaseLabels + i; | ||
213 | |||
214 | pCopyLabel->cchLabelOffset = pSourceLabel->cchLabelOffset; | ||
215 | pCopyLabel->cchLabel = pSourceLabel->cchLabel; | ||
216 | pCopyLabel->fNumeric = pSourceLabel->fNumeric; | ||
217 | pCopyLabel->dwValue = pSourceLabel->dwValue; | ||
218 | } | ||
219 | } | ||
220 | |||
221 | pCopy->cchMetadataOffset = pSource->cchMetadataOffset; | ||
222 | pCopy->fInvalid = pSource->fInvalid; | ||
223 | |||
224 | *ppVersion = pCopy; | ||
225 | pCopy = NULL; | ||
226 | |||
227 | LExit: | ||
228 | ReleaseVerutilVersion(pCopy); | ||
229 | |||
230 | return hr; | ||
231 | } | ||
232 | |||
233 | DAPI_(void) VerFreeVersion( | ||
234 | __in VERUTIL_VERSION* pVersion | ||
235 | ) | ||
236 | { | ||
237 | if (pVersion) | ||
238 | { | ||
239 | ReleaseStr(pVersion->sczVersion); | ||
240 | ReleaseMem(pVersion->rgReleaseLabels); | ||
241 | ReleaseMem(pVersion); | ||
242 | } | ||
243 | } | ||
244 | |||
245 | DAPI_(HRESULT) VerParseVersion( | ||
246 | __in_z LPCWSTR wzVersion, | ||
247 | __in SIZE_T cchVersion, | ||
248 | __in BOOL fStrict, | ||
249 | __out VERUTIL_VERSION** ppVersion | ||
250 | ) | ||
251 | { | ||
252 | HRESULT hr = S_OK; | ||
253 | VERUTIL_VERSION* pVersion = NULL; | ||
254 | LPCWSTR wzEnd = NULL; | ||
255 | LPCWSTR wzPartBegin = NULL; | ||
256 | LPCWSTR wzPartEnd = NULL; | ||
257 | BOOL fInvalid = FALSE; | ||
258 | BOOL fLastPart = FALSE; | ||
259 | BOOL fTrailingDot = FALSE; | ||
260 | BOOL fParsedVersionNumber = FALSE; | ||
261 | BOOL fExpectedReleaseLabels = FALSE; | ||
262 | DWORD iPart = 0; | ||
263 | |||
264 | if (!wzVersion || !ppVersion) | ||
265 | { | ||
266 | ExitFunction1(hr = E_INVALIDARG); | ||
267 | } | ||
268 | |||
269 | // Get string length if not provided. | ||
270 | if (!cchVersion) | ||
271 | { | ||
272 | hr = ::StringCchLengthW(wzVersion, STRSAFE_MAX_CCH, reinterpret_cast<size_t*>(&cchVersion)); | ||
273 | VerExitOnRootFailure(hr, "Failed to get length of version string: %ls", wzVersion); | ||
274 | } | ||
275 | else if (INT_MAX < cchVersion) | ||
276 | { | ||
277 | VerExitOnRootFailure(hr = E_INVALIDARG, "Version string is too long: %Iu", cchVersion); | ||
278 | } | ||
279 | |||
280 | if (L'v' == *wzVersion || L'V' == *wzVersion) | ||
281 | { | ||
282 | ++wzVersion; | ||
283 | --cchVersion; | ||
284 | } | ||
285 | |||
286 | pVersion = reinterpret_cast<VERUTIL_VERSION*>(MemAlloc(sizeof(VERUTIL_VERSION), TRUE)); | ||
287 | VerExitOnNull(pVersion, hr, E_OUTOFMEMORY, "Failed to allocate memory for Verutil version '%ls'.", wzVersion); | ||
288 | |||
289 | hr = StrAllocString(&pVersion->sczVersion, wzVersion, cchVersion); | ||
290 | VerExitOnFailure(hr, "Failed to copy Verutil version string '%ls'.", wzVersion); | ||
291 | |||
292 | wzVersion = wzPartBegin = wzPartEnd = pVersion->sczVersion; | ||
293 | |||
294 | // Save end pointer. | ||
295 | wzEnd = wzVersion + cchVersion; | ||
296 | |||
297 | // Parse version number | ||
298 | while (wzPartBegin < wzEnd) | ||
299 | { | ||
300 | fTrailingDot = FALSE; | ||
301 | |||
302 | // Find end of part. | ||
303 | for (;;) | ||
304 | { | ||
305 | if (wzPartEnd >= wzEnd) | ||
306 | { | ||
307 | fLastPart = TRUE; | ||
308 | break; | ||
309 | } | ||
310 | |||
311 | switch (*wzPartEnd) | ||
312 | { | ||
313 | case L'0': | ||
314 | case L'1': | ||
315 | case L'2': | ||
316 | case L'3': | ||
317 | case L'4': | ||
318 | case L'5': | ||
319 | case L'6': | ||
320 | case L'7': | ||
321 | case L'8': | ||
322 | case L'9': | ||
323 | ++wzPartEnd; | ||
324 | continue; | ||
325 | case L'.': | ||
326 | fTrailingDot = TRUE; | ||
327 | break; | ||
328 | case L'-': | ||
329 | case L'+': | ||
330 | fLastPart = TRUE; | ||
331 | break; | ||
332 | default: | ||
333 | fInvalid = TRUE; | ||
334 | break; | ||
335 | } | ||
336 | |||
337 | break; | ||
338 | } | ||
339 | |||
340 | if (wzPartBegin == wzPartEnd) | ||
341 | { | ||
342 | fInvalid = TRUE; | ||
343 | } | ||
344 | |||
345 | if (fInvalid) | ||
346 | { | ||
347 | break; | ||
348 | } | ||
349 | |||
350 | DWORD cchPart = 0; | ||
351 | hr = ::PtrdiffTToDWord(wzPartEnd - wzPartBegin, &cchPart); | ||
352 | if (FAILED(hr)) | ||
353 | { | ||
354 | fInvalid = TRUE; | ||
355 | break; | ||
356 | } | ||
357 | |||
358 | // Parse version part. | ||
359 | UINT uPart = 0; | ||
360 | hr = StrStringToUInt32(wzPartBegin, cchPart, &uPart); | ||
361 | if (FAILED(hr)) | ||
362 | { | ||
363 | fInvalid = TRUE; | ||
364 | break; | ||
365 | } | ||
366 | |||
367 | switch (iPart) | ||
368 | { | ||
369 | case 0: | ||
370 | pVersion->dwMajor = uPart; | ||
371 | break; | ||
372 | case 1: | ||
373 | pVersion->dwMinor = uPart; | ||
374 | break; | ||
375 | case 2: | ||
376 | pVersion->dwPatch = uPart; | ||
377 | break; | ||
378 | case 3: | ||
379 | pVersion->dwRevision = uPart; | ||
380 | break; | ||
381 | } | ||
382 | |||
383 | if (fTrailingDot) | ||
384 | { | ||
385 | ++wzPartEnd; | ||
386 | } | ||
387 | wzPartBegin = wzPartEnd; | ||
388 | ++iPart; | ||
389 | |||
390 | if (4 <= iPart || fLastPart) | ||
391 | { | ||
392 | fParsedVersionNumber = TRUE; | ||
393 | break; | ||
394 | } | ||
395 | } | ||
396 | |||
397 | fInvalid |= !fParsedVersionNumber || fTrailingDot; | ||
398 | |||
399 | if (!fInvalid && wzPartBegin < wzEnd && *wzPartBegin == L'-') | ||
400 | { | ||
401 | wzPartBegin = wzPartEnd = wzPartBegin + 1; | ||
402 | fExpectedReleaseLabels = TRUE; | ||
403 | fLastPart = FALSE; | ||
404 | } | ||
405 | |||
406 | while (fExpectedReleaseLabels && wzPartBegin < wzEnd) | ||
407 | { | ||
408 | fTrailingDot = FALSE; | ||
409 | |||
410 | // Find end of part. | ||
411 | for (;;) | ||
412 | { | ||
413 | if (wzPartEnd >= wzEnd) | ||
414 | { | ||
415 | fLastPart = TRUE; | ||
416 | break; | ||
417 | } | ||
418 | |||
419 | if (*wzPartEnd >= L'0' && *wzPartEnd <= L'9' || | ||
420 | *wzPartEnd >= L'A' && *wzPartEnd <= L'Z' || | ||
421 | *wzPartEnd >= L'a' && *wzPartEnd <= L'z' || | ||
422 | *wzPartEnd == L'-') | ||
423 | { | ||
424 | ++wzPartEnd; | ||
425 | continue; | ||
426 | } | ||
427 | else if (*wzPartEnd == L'+') | ||
428 | { | ||
429 | fLastPart = TRUE; | ||
430 | } | ||
431 | else if (*wzPartEnd == L'.') | ||
432 | { | ||
433 | fTrailingDot = TRUE; | ||
434 | } | ||
435 | else | ||
436 | { | ||
437 | fInvalid = TRUE; | ||
438 | } | ||
439 | |||
440 | break; | ||
441 | } | ||
442 | |||
443 | if (wzPartBegin == wzPartEnd) | ||
444 | { | ||
445 | fInvalid = TRUE; | ||
446 | } | ||
447 | |||
448 | if (fInvalid) | ||
449 | { | ||
450 | break; | ||
451 | } | ||
452 | |||
453 | int cchLabel = 0; | ||
454 | hr = ::PtrdiffTToInt32(wzPartEnd - wzPartBegin, &cchLabel); | ||
455 | if (FAILED(hr) || 0 > cchLabel) | ||
456 | { | ||
457 | fInvalid = TRUE; | ||
458 | break; | ||
459 | } | ||
460 | |||
461 | hr = MemReAllocArray(reinterpret_cast<LPVOID*>(&pVersion->rgReleaseLabels), pVersion->cReleaseLabels, sizeof(VERUTIL_VERSION_RELEASE_LABEL), GROW_RELEASE_LABELS - (pVersion->cReleaseLabels % GROW_RELEASE_LABELS)); | ||
462 | VerExitOnFailure(hr, "Failed to allocate memory for Verutil version release labels '%ls'", wzVersion); | ||
463 | |||
464 | VERUTIL_VERSION_RELEASE_LABEL* pReleaseLabel = pVersion->rgReleaseLabels + pVersion->cReleaseLabels; | ||
465 | ++pVersion->cReleaseLabels; | ||
466 | |||
467 | // Try to parse as number. | ||
468 | UINT uLabel = 0; | ||
469 | hr = StrStringToUInt32(wzPartBegin, cchLabel, &uLabel); | ||
470 | if (SUCCEEDED(hr)) | ||
471 | { | ||
472 | pReleaseLabel->fNumeric = TRUE; | ||
473 | pReleaseLabel->dwValue = uLabel; | ||
474 | } | ||
475 | |||
476 | pReleaseLabel->cchLabelOffset = wzPartBegin - pVersion->sczVersion; | ||
477 | pReleaseLabel->cchLabel = cchLabel; | ||
478 | |||
479 | if (fTrailingDot) | ||
480 | { | ||
481 | ++wzPartEnd; | ||
482 | } | ||
483 | wzPartBegin = wzPartEnd; | ||
484 | |||
485 | if (fLastPart) | ||
486 | { | ||
487 | break; | ||
488 | } | ||
489 | } | ||
490 | |||
491 | fInvalid |= fExpectedReleaseLabels && (!pVersion->cReleaseLabels || fTrailingDot); | ||
492 | |||
493 | if (!fInvalid && wzPartBegin < wzEnd) | ||
494 | { | ||
495 | if (*wzPartBegin == L'+') | ||
496 | { | ||
497 | wzPartBegin = wzPartEnd = wzPartBegin + 1; | ||
498 | } | ||
499 | else | ||
500 | { | ||
501 | fInvalid = TRUE; | ||
502 | } | ||
503 | } | ||
504 | |||
505 | if (fInvalid && fStrict) | ||
506 | { | ||
507 | ExitFunction1(hr = E_INVALIDARG); | ||
508 | } | ||
509 | |||
510 | pVersion->cchMetadataOffset = min(wzPartBegin, wzEnd) - pVersion->sczVersion; | ||
511 | pVersion->fInvalid = fInvalid; | ||
512 | |||
513 | *ppVersion = pVersion; | ||
514 | pVersion = NULL; | ||
515 | hr = S_OK; | ||
516 | |||
517 | LExit: | ||
518 | ReleaseVerutilVersion(pVersion); | ||
519 | |||
520 | return hr; | ||
521 | } | ||
522 | |||
523 | DAPI_(HRESULT) VerVersionFromQword( | ||
524 | __in DWORD64 qwVersion, | ||
525 | __out VERUTIL_VERSION** ppVersion | ||
526 | ) | ||
527 | { | ||
528 | HRESULT hr = S_OK; | ||
529 | VERUTIL_VERSION* pVersion = NULL; | ||
530 | |||
531 | pVersion = reinterpret_cast<VERUTIL_VERSION*>(MemAlloc(sizeof(VERUTIL_VERSION), TRUE)); | ||
532 | VerExitOnNull(pVersion, hr, E_OUTOFMEMORY, "Failed to allocate memory for Verutil version from QWORD."); | ||
533 | |||
534 | pVersion->dwMajor = (WORD)(qwVersion >> 48 & 0xffff); | ||
535 | pVersion->dwMinor = (WORD)(qwVersion >> 32 & 0xffff); | ||
536 | pVersion->dwPatch = (WORD)(qwVersion >> 16 & 0xffff); | ||
537 | pVersion->dwRevision = (WORD)(qwVersion & 0xffff); | ||
538 | |||
539 | hr = StrAllocFormatted(&pVersion->sczVersion, L"%lu.%lu.%lu.%lu", pVersion->dwMajor, pVersion->dwMinor, pVersion->dwPatch, pVersion->dwRevision); | ||
540 | ExitOnFailure(hr, "Failed to allocate and format the version string."); | ||
541 | |||
542 | pVersion->cchMetadataOffset = lstrlenW(pVersion->sczVersion); | ||
543 | |||
544 | *ppVersion = pVersion; | ||
545 | pVersion = NULL; | ||
546 | |||
547 | LExit: | ||
548 | ReleaseVerutilVersion(pVersion); | ||
549 | |||
550 | return hr; | ||
551 | } | ||
552 | |||
553 | |||
554 | static int CompareDword( | ||
555 | __in const DWORD& dw1, | ||
556 | __in const DWORD& dw2 | ||
557 | ) | ||
558 | { | ||
559 | int nResult = 0; | ||
560 | |||
561 | if (dw1 > dw2) | ||
562 | { | ||
563 | nResult = 1; | ||
564 | } | ||
565 | else if (dw1 < dw2) | ||
566 | { | ||
567 | nResult = -1; | ||
568 | } | ||
569 | |||
570 | return nResult; | ||
571 | } | ||
572 | |||
573 | static HRESULT CompareReleaseLabel( | ||
574 | __in const VERUTIL_VERSION_RELEASE_LABEL* p1, | ||
575 | __in LPCWSTR wzVersion1, | ||
576 | __in const VERUTIL_VERSION_RELEASE_LABEL* p2, | ||
577 | __in LPCWSTR wzVersion2, | ||
578 | __out int* pnResult | ||
579 | ) | ||
580 | { | ||
581 | HRESULT hr = S_OK; | ||
582 | int nResult = 0; | ||
583 | |||
584 | if (p1 == p2) | ||
585 | { | ||
586 | ExitFunction(); | ||
587 | } | ||
588 | else if (p1 && !p2) | ||
589 | { | ||
590 | ExitFunction1(nResult = 1); | ||
591 | } | ||
592 | else if (!p1 && p2) | ||
593 | { | ||
594 | ExitFunction1(nResult = -1); | ||
595 | } | ||
596 | |||
597 | if (p1->fNumeric) | ||
598 | { | ||
599 | if (p2->fNumeric) | ||
600 | { | ||
601 | nResult = CompareDword(p1->dwValue, p2->dwValue); | ||
602 | } | ||
603 | else | ||
604 | { | ||
605 | nResult = -1; | ||
606 | } | ||
607 | } | ||
608 | else | ||
609 | { | ||
610 | if (p2->fNumeric) | ||
611 | { | ||
612 | nResult = 1; | ||
613 | } | ||
614 | else | ||
615 | { | ||
616 | hr = CompareVersionSubstring(wzVersion1 + p1->cchLabelOffset, p1->cchLabel, wzVersion2 + p2->cchLabelOffset, p2->cchLabel, &nResult); | ||
617 | } | ||
618 | } | ||
619 | |||
620 | LExit: | ||
621 | *pnResult = nResult; | ||
622 | |||
623 | return hr; | ||
624 | } | ||
625 | |||
626 | static HRESULT CompareVersionSubstring( | ||
627 | __in LPCWSTR wzString1, | ||
628 | __in int cchCount1, | ||
629 | __in LPCWSTR wzString2, | ||
630 | __in int cchCount2, | ||
631 | __out int* pnResult | ||
632 | ) | ||
633 | { | ||
634 | HRESULT hr = S_OK; | ||
635 | int nResult = 0; | ||
636 | |||
637 | nResult = ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, wzString1, cchCount1, wzString2, cchCount2); | ||
638 | if (!nResult) | ||
639 | { | ||
640 | VerExitOnLastError(hr, "Failed to compare version substrings"); | ||
641 | } | ||
642 | |||
643 | LExit: | ||
644 | *pnResult = nResult - 2; | ||
645 | |||
646 | return hr; | ||
647 | } | ||