Sync with trunk r63192.
[reactos.git] / lib / rtl / version.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS system libraries
4 * PURPOSE: Runtime code
5 * FILE: lib/rtl/version.c
6 * PROGRAMERS: Filip Navara
7 * Hermes Belusca-Maito (hermes.belusca@sfr.fr)
8 */
9
10 /* INCLUDES *****************************************************************/
11
12 #include <rtl.h>
13
14 #define NDEBUG
15 #include <debug.h>
16
17 /* GLOBALS ******************************************************************/
18
19 NTSTATUS
20 NTAPI
21 RtlGetVersion(OUT PRTL_OSVERSIONINFOW lpVersionInformation);
22
23 /* FUNCTIONS ****************************************************************/
24
25 static BYTE
26 RtlpVerGetCondition(IN ULONGLONG dwlConditionMask,
27 IN DWORD dwTypeBitMask);
28
29 static BOOLEAN
30 RtlpVerCompare(ULONG left, ULONG right, UCHAR condition)
31 {
32 switch (condition)
33 {
34 case VER_EQUAL:
35 return (left == right);
36 case VER_GREATER:
37 return (left > right);
38 case VER_GREATER_EQUAL:
39 return (left >= right);
40 case VER_LESS:
41 return (left < right);
42 case VER_LESS_EQUAL:
43 return (left <= right);
44 default:
45 break;
46 }
47 return FALSE;
48 }
49
50 /*
51 * @implemented
52 */
53 NTSTATUS
54 NTAPI
55 RtlVerifyVersionInfo(IN PRTL_OSVERSIONINFOEXW VersionInfo,
56 IN ULONG TypeMask,
57 IN ULONGLONG ConditionMask)
58 {
59 RTL_OSVERSIONINFOEXW ver;
60 NTSTATUS status;
61 BOOLEAN comparison;
62
63 /* FIXME:
64 - Check the following special case on Windows (various versions):
65 o lp->wSuiteMask == 0 and ver.wSuiteMask != 0 and VER_AND/VER_OR
66 o lp->dwOSVersionInfoSize != sizeof(OSVERSIONINFOEXW)
67 - MSDN talks about some tests being impossible. Check what really happens.
68 */
69
70 ver.dwOSVersionInfoSize = sizeof(ver);
71 status = RtlGetVersion((PRTL_OSVERSIONINFOW)&ver);
72 if (status != STATUS_SUCCESS) return status;
73
74 if (!TypeMask || !ConditionMask) return STATUS_INVALID_PARAMETER;
75
76 if (TypeMask & VER_PRODUCT_TYPE)
77 {
78 comparison = RtlpVerCompare(ver.wProductType,
79 VersionInfo->wProductType,
80 RtlpVerGetCondition(ConditionMask, VER_PRODUCT_TYPE));
81 if (!comparison)
82 return STATUS_REVISION_MISMATCH;
83 }
84
85 if (TypeMask & VER_SUITENAME)
86 {
87 switch (RtlpVerGetCondition(ConditionMask, VER_SUITENAME))
88 {
89 case VER_AND:
90 if ((VersionInfo->wSuiteMask & ver.wSuiteMask) != VersionInfo->wSuiteMask)
91 {
92 return STATUS_REVISION_MISMATCH;
93 }
94 break;
95 case VER_OR:
96 if (!(VersionInfo->wSuiteMask & ver.wSuiteMask) && VersionInfo->wSuiteMask)
97 {
98 return STATUS_REVISION_MISMATCH;
99 }
100 break;
101 default:
102 return STATUS_INVALID_PARAMETER;
103 }
104 }
105
106 if (TypeMask & VER_PLATFORMID)
107 {
108 comparison = RtlpVerCompare(ver.dwPlatformId,
109 VersionInfo->dwPlatformId,
110 RtlpVerGetCondition(ConditionMask, VER_PLATFORMID));
111 if (!comparison)
112 return STATUS_REVISION_MISMATCH;
113 }
114
115 if (TypeMask & VER_BUILDNUMBER)
116 {
117 comparison = RtlpVerCompare(ver.dwBuildNumber,
118 VersionInfo->dwBuildNumber,
119 RtlpVerGetCondition(ConditionMask, VER_BUILDNUMBER));
120 if (!comparison)
121 return STATUS_REVISION_MISMATCH;
122 }
123
124 TypeMask &= VER_MAJORVERSION|VER_MINORVERSION|VER_SERVICEPACKMAJOR|VER_SERVICEPACKMINOR;
125 if (TypeMask)
126 {
127 BOOLEAN do_next_check = TRUE;
128 /*
129 * Select the leading comparison operator (for example, the comparison
130 * operator for VER_MAJORVERSION supersedes the others for VER_MINORVERSION,
131 * VER_SERVICEPACKMAJOR and VER_SERVICEPACKMINOR).
132 */
133 BYTE condition = RtlpVerGetCondition(ConditionMask, TypeMask);
134
135 comparison = TRUE;
136 if (TypeMask & VER_MAJORVERSION)
137 {
138 comparison = RtlpVerCompare(ver.dwMajorVersion,
139 VersionInfo->dwMajorVersion,
140 condition);
141 do_next_check = (ver.dwMajorVersion == VersionInfo->dwMajorVersion) &&
142 ((condition != VER_EQUAL) || comparison);
143 }
144 if ((TypeMask & VER_MINORVERSION) && do_next_check)
145 {
146 comparison = RtlpVerCompare(ver.dwMinorVersion,
147 VersionInfo->dwMinorVersion,
148 condition);
149 do_next_check = (ver.dwMinorVersion == VersionInfo->dwMinorVersion) &&
150 ((condition != VER_EQUAL) || comparison);
151 }
152 if ((TypeMask & VER_SERVICEPACKMAJOR) && do_next_check)
153 {
154 comparison = RtlpVerCompare(ver.wServicePackMajor,
155 VersionInfo->wServicePackMajor,
156 condition);
157 do_next_check = (ver.wServicePackMajor == VersionInfo->wServicePackMajor) &&
158 ((condition != VER_EQUAL) || comparison);
159 }
160 if ((TypeMask & VER_SERVICEPACKMINOR) && do_next_check)
161 {
162 comparison = RtlpVerCompare(ver.wServicePackMinor,
163 VersionInfo->wServicePackMinor,
164 condition);
165 }
166
167 if (!comparison)
168 return STATUS_REVISION_MISMATCH;
169 }
170
171 return STATUS_SUCCESS;
172 }
173
174 static BYTE
175 RtlpVerGetCondition(IN ULONGLONG dwlConditionMask,
176 IN DWORD dwTypeBitMask)
177 {
178 BYTE bConditionMask = 0;
179
180 if (dwTypeBitMask & VER_PRODUCT_TYPE)
181 bConditionMask |= dwlConditionMask >> (7 * VER_NUM_BITS_PER_CONDITION_MASK);
182 else if (dwTypeBitMask & VER_SUITENAME)
183 bConditionMask |= dwlConditionMask >> (6 * VER_NUM_BITS_PER_CONDITION_MASK);
184 else if (dwTypeBitMask & VER_PLATFORMID)
185 bConditionMask |= dwlConditionMask >> (3 * VER_NUM_BITS_PER_CONDITION_MASK);
186 else if (dwTypeBitMask & VER_BUILDNUMBER)
187 bConditionMask |= dwlConditionMask >> (2 * VER_NUM_BITS_PER_CONDITION_MASK);
188 /*
189 * We choose here the lexicographical order on the 4D space
190 * {(Major ; Minor ; SP Major ; SP Minor)} to select the
191 * appropriate comparison operator.
192 * Therefore the following 'else if' instructions must be in this order.
193 */
194 else if (dwTypeBitMask & VER_MAJORVERSION)
195 bConditionMask |= dwlConditionMask >> (1 * VER_NUM_BITS_PER_CONDITION_MASK);
196 else if (dwTypeBitMask & VER_MINORVERSION)
197 bConditionMask |= dwlConditionMask >> (0 * VER_NUM_BITS_PER_CONDITION_MASK);
198 else if (dwTypeBitMask & VER_SERVICEPACKMAJOR)
199 bConditionMask |= dwlConditionMask >> (5 * VER_NUM_BITS_PER_CONDITION_MASK);
200 else if (dwTypeBitMask & VER_SERVICEPACKMINOR)
201 bConditionMask |= dwlConditionMask >> (4 * VER_NUM_BITS_PER_CONDITION_MASK);
202
203 bConditionMask &= VER_CONDITION_MASK;
204
205 return bConditionMask;
206 }
207
208 /*
209 * @implemented
210 */
211 ULONGLONG
212 NTAPI
213 VerSetConditionMask(IN ULONGLONG dwlConditionMask,
214 IN DWORD dwTypeBitMask,
215 IN BYTE bConditionMask)
216 {
217 ULONGLONG ullCondMask;
218
219 if (dwTypeBitMask == 0)
220 return dwlConditionMask;
221
222 bConditionMask &= VER_CONDITION_MASK;
223
224 if (bConditionMask == 0)
225 return dwlConditionMask;
226
227 ullCondMask = bConditionMask;
228 if (dwTypeBitMask & VER_PRODUCT_TYPE)
229 dwlConditionMask |= ullCondMask << (7 * VER_NUM_BITS_PER_CONDITION_MASK);
230 else if (dwTypeBitMask & VER_SUITENAME)
231 dwlConditionMask |= ullCondMask << (6 * VER_NUM_BITS_PER_CONDITION_MASK);
232 else if (dwTypeBitMask & VER_SERVICEPACKMAJOR)
233 dwlConditionMask |= ullCondMask << (5 * VER_NUM_BITS_PER_CONDITION_MASK);
234 else if (dwTypeBitMask & VER_SERVICEPACKMINOR)
235 dwlConditionMask |= ullCondMask << (4 * VER_NUM_BITS_PER_CONDITION_MASK);
236 else if (dwTypeBitMask & VER_PLATFORMID)
237 dwlConditionMask |= ullCondMask << (3 * VER_NUM_BITS_PER_CONDITION_MASK);
238 else if (dwTypeBitMask & VER_BUILDNUMBER)
239 dwlConditionMask |= ullCondMask << (2 * VER_NUM_BITS_PER_CONDITION_MASK);
240 else if (dwTypeBitMask & VER_MAJORVERSION)
241 dwlConditionMask |= ullCondMask << (1 * VER_NUM_BITS_PER_CONDITION_MASK);
242 else if (dwTypeBitMask & VER_MINORVERSION)
243 dwlConditionMask |= ullCondMask << (0 * VER_NUM_BITS_PER_CONDITION_MASK);
244
245 return dwlConditionMask;
246 }
247
248 /* EOF */