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