xref: /reactos/sdk/lib/rtl/version.c (revision 40462c92)
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(Version.wServicePackMinor,
209                                             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 */
298