f553ca9ae89e88fafcf3e6254142aa3a07b85ae5
[reactos.git] / reactos / sdk / 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 UCHAR
26 RtlpVerGetCondition(IN ULONGLONG ConditionMask,
27 IN ULONG TypeMask);
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 Version;
60 BOOLEAN Comparison;
61 BOOLEAN DoNextCheck;
62 NTSTATUS Status;
63 UCHAR Condition;
64
65 /* FIXME:
66 - Check the following special case on Windows (various versions):
67 o lp->wSuiteMask == 0 and ver.wSuiteMask != 0 and VER_AND/VER_OR
68 o lp->dwOSVersionInfoSize != sizeof(OSVERSIONINFOEXW)
69 - MSDN talks about some tests being impossible. Check what really happens.
70 */
71
72 Version.dwOSVersionInfoSize = sizeof(Version);
73
74 Status = RtlGetVersion((PRTL_OSVERSIONINFOW)&Version);
75 if (Status != STATUS_SUCCESS)
76 {
77 return Status;
78 }
79
80 if (!TypeMask || !ConditionMask)
81 {
82 return STATUS_INVALID_PARAMETER;
83 }
84
85 if (TypeMask & VER_PRODUCT_TYPE)
86 {
87 Comparison = RtlpVerCompare(Version.wProductType,
88 VersionInfo->wProductType,
89 RtlpVerGetCondition(ConditionMask, VER_PRODUCT_TYPE));
90 if (!Comparison)
91 {
92 return STATUS_REVISION_MISMATCH;
93 }
94 }
95
96 if (TypeMask & VER_SUITENAME)
97 {
98 switch (RtlpVerGetCondition(ConditionMask, VER_SUITENAME))
99 {
100 case VER_AND:
101 {
102 if ((VersionInfo->wSuiteMask & Version.wSuiteMask) != VersionInfo->wSuiteMask)
103 {
104 return STATUS_REVISION_MISMATCH;
105 }
106 }
107 break;
108
109 case VER_OR:
110 {
111 if (!(VersionInfo->wSuiteMask & Version.wSuiteMask) && VersionInfo->wSuiteMask)
112 {
113 return STATUS_REVISION_MISMATCH;
114 }
115 break;
116 }
117
118 default:
119 {
120 return STATUS_INVALID_PARAMETER;
121 }
122 }
123 }
124
125 if (TypeMask & VER_PLATFORMID)
126 {
127 Comparison = RtlpVerCompare(Version.dwPlatformId,
128 VersionInfo->dwPlatformId,
129 RtlpVerGetCondition(ConditionMask, VER_PLATFORMID));
130 if (!Comparison)
131 {
132 return STATUS_REVISION_MISMATCH;
133 }
134 }
135
136 if (TypeMask & VER_BUILDNUMBER)
137 {
138 Comparison = RtlpVerCompare(Version.dwBuildNumber,
139 VersionInfo->dwBuildNumber,
140 RtlpVerGetCondition(ConditionMask, VER_BUILDNUMBER));
141 if (!Comparison)
142 {
143 return STATUS_REVISION_MISMATCH;
144 }
145 }
146
147 DoNextCheck = TRUE;
148 Condition = VER_EQUAL;
149
150 if (TypeMask & VER_MAJORVERSION)
151 {
152 Condition = RtlpVerGetCondition(ConditionMask, VER_MAJORVERSION);
153 DoNextCheck = (VersionInfo->dwMajorVersion == Version.dwMajorVersion);
154 Comparison = RtlpVerCompare(Version.dwMajorVersion,
155 VersionInfo->dwMajorVersion,
156 Condition);
157
158 if (!Comparison && !DoNextCheck)
159 {
160 return STATUS_REVISION_MISMATCH;
161 }
162 }
163
164 if (DoNextCheck)
165 {
166 if (TypeMask & VER_MINORVERSION)
167 {
168 if (Condition == VER_EQUAL)
169 {
170 Condition = RtlpVerGetCondition(ConditionMask, VER_MINORVERSION);
171 }
172
173 DoNextCheck = (VersionInfo->dwMinorVersion == Version.dwMinorVersion);
174 Comparison = RtlpVerCompare(Version.dwMinorVersion,
175 VersionInfo->dwMinorVersion,
176 Condition);
177
178 if (!Comparison && !DoNextCheck)
179 {
180 return STATUS_REVISION_MISMATCH;
181 }
182 }
183
184 if (DoNextCheck && (TypeMask & VER_SERVICEPACKMAJOR))
185 {
186 if (Condition == VER_EQUAL)
187 {
188 Condition = RtlpVerGetCondition(ConditionMask, VER_SERVICEPACKMAJOR);
189 }
190
191 DoNextCheck = (VersionInfo->wServicePackMajor == Version.wServicePackMajor);
192 Comparison = RtlpVerCompare(Version.wServicePackMajor,
193 VersionInfo->wServicePackMajor,
194 Condition);
195
196 if (!Comparison && !DoNextCheck)
197 {
198 return STATUS_REVISION_MISMATCH;
199 }
200
201 if (DoNextCheck && (TypeMask & VER_SERVICEPACKMINOR))
202 {
203 if (Condition == VER_EQUAL)
204 {
205 Condition = RtlpVerGetCondition(ConditionMask, VER_SERVICEPACKMINOR);
206 }
207
208 Comparison = RtlpVerCompare((ULONG)Version.wServicePackMinor,
209 (ULONG)VersionInfo->wServicePackMinor,
210 Condition);
211
212 if (!Comparison)
213 {
214 return STATUS_REVISION_MISMATCH;
215 }
216 }
217 }
218 }
219
220 return STATUS_SUCCESS;
221 }
222
223 static UCHAR
224 RtlpVerGetCondition(IN ULONGLONG ConditionMask,
225 IN ULONG TypeMask)
226 {
227 UCHAR Condition = 0;
228
229 if (TypeMask & VER_PRODUCT_TYPE)
230 Condition |= ConditionMask >> (7 * VER_NUM_BITS_PER_CONDITION_MASK);
231 else if (TypeMask & VER_SUITENAME)
232 Condition |= ConditionMask >> (6 * VER_NUM_BITS_PER_CONDITION_MASK);
233 else if (TypeMask & VER_PLATFORMID)
234 Condition |= ConditionMask >> (3 * VER_NUM_BITS_PER_CONDITION_MASK);
235 else if (TypeMask & VER_BUILDNUMBER)
236 Condition |= ConditionMask >> (2 * VER_NUM_BITS_PER_CONDITION_MASK);
237 /*
238 * We choose here the lexicographical order on the 4D space
239 * {(Major ; Minor ; SP Major ; SP Minor)} to select the
240 * appropriate comparison operator.
241 * Therefore the following 'else if' instructions must be in this order.
242 */
243 else if (TypeMask & VER_MAJORVERSION)
244 Condition |= ConditionMask >> (1 * VER_NUM_BITS_PER_CONDITION_MASK);
245 else if (TypeMask & VER_MINORVERSION)
246 Condition |= ConditionMask >> (0 * VER_NUM_BITS_PER_CONDITION_MASK);
247 else if (TypeMask & VER_SERVICEPACKMAJOR)
248 Condition |= ConditionMask >> (5 * VER_NUM_BITS_PER_CONDITION_MASK);
249 else if (TypeMask & VER_SERVICEPACKMINOR)
250 Condition |= ConditionMask >> (4 * VER_NUM_BITS_PER_CONDITION_MASK);
251
252 Condition &= VER_CONDITION_MASK;
253
254 return Condition;
255 }
256
257 /*
258 * @implemented
259 */
260 ULONGLONG
261 NTAPI
262 VerSetConditionMask(IN ULONGLONG ConditionMask,
263 IN ULONG TypeMask,
264 IN UCHAR Condition)
265 {
266 ULONGLONG ullCondMask;
267
268 if (TypeMask == 0)
269 return ConditionMask;
270
271 Condition &= VER_CONDITION_MASK;
272
273 if (Condition == 0)
274 return ConditionMask;
275
276 ullCondMask = Condition;
277 if (TypeMask & VER_PRODUCT_TYPE)
278 ConditionMask |= ullCondMask << (7 * VER_NUM_BITS_PER_CONDITION_MASK);
279 else if (TypeMask & VER_SUITENAME)
280 ConditionMask |= ullCondMask << (6 * VER_NUM_BITS_PER_CONDITION_MASK);
281 else if (TypeMask & VER_SERVICEPACKMAJOR)
282 ConditionMask |= ullCondMask << (5 * VER_NUM_BITS_PER_CONDITION_MASK);
283 else if (TypeMask & VER_SERVICEPACKMINOR)
284 ConditionMask |= ullCondMask << (4 * VER_NUM_BITS_PER_CONDITION_MASK);
285 else if (TypeMask & VER_PLATFORMID)
286 ConditionMask |= ullCondMask << (3 * VER_NUM_BITS_PER_CONDITION_MASK);
287 else if (TypeMask & VER_BUILDNUMBER)
288 ConditionMask |= ullCondMask << (2 * VER_NUM_BITS_PER_CONDITION_MASK);
289 else if (TypeMask & VER_MAJORVERSION)
290 ConditionMask |= ullCondMask << (1 * VER_NUM_BITS_PER_CONDITION_MASK);
291 else if (TypeMask & VER_MINORVERSION)
292 ConditionMask |= ullCondMask << (0 * VER_NUM_BITS_PER_CONDITION_MASK);
293
294 return ConditionMask;
295 }
296
297 /* EOF */