Create the AHCI branch for Aman's work
[reactos.git] / 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 NTSTATUS Status;
60 RTL_OSVERSIONINFOEXW ver;
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 UCHAR 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 UCHAR
175 RtlpVerGetCondition(IN ULONGLONG ConditionMask,
176 IN ULONG TypeMask)
177 {
178 UCHAR Condition = 0;
179
180 if (TypeMask & VER_PRODUCT_TYPE)
181 Condition |= ConditionMask >> (7 * VER_NUM_BITS_PER_CONDITION_MASK);
182 else if (TypeMask & VER_SUITENAME)
183 Condition |= ConditionMask >> (6 * VER_NUM_BITS_PER_CONDITION_MASK);
184 else if (TypeMask & VER_PLATFORMID)
185 Condition |= ConditionMask >> (3 * VER_NUM_BITS_PER_CONDITION_MASK);
186 else if (TypeMask & VER_BUILDNUMBER)
187 Condition |= ConditionMask >> (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 (TypeMask & VER_MAJORVERSION)
195 Condition |= ConditionMask >> (1 * VER_NUM_BITS_PER_CONDITION_MASK);
196 else if (TypeMask & VER_MINORVERSION)
197 Condition |= ConditionMask >> (0 * VER_NUM_BITS_PER_CONDITION_MASK);
198 else if (TypeMask & VER_SERVICEPACKMAJOR)
199 Condition |= ConditionMask >> (5 * VER_NUM_BITS_PER_CONDITION_MASK);
200 else if (TypeMask & VER_SERVICEPACKMINOR)
201 Condition |= ConditionMask >> (4 * VER_NUM_BITS_PER_CONDITION_MASK);
202
203 Condition &= VER_CONDITION_MASK;
204
205 return Condition;
206 }
207
208 /*
209 * @implemented
210 */
211 ULONGLONG
212 NTAPI
213 VerSetConditionMask(IN ULONGLONG ConditionMask,
214 IN ULONG TypeMask,
215 IN UCHAR Condition)
216 {
217 ULONGLONG ullCondMask;
218
219 if (TypeMask == 0)
220 return ConditionMask;
221
222 Condition &= VER_CONDITION_MASK;
223
224 if (Condition == 0)
225 return ConditionMask;
226
227 ullCondMask = Condition;
228 if (TypeMask & VER_PRODUCT_TYPE)
229 ConditionMask |= ullCondMask << (7 * VER_NUM_BITS_PER_CONDITION_MASK);
230 else if (TypeMask & VER_SUITENAME)
231 ConditionMask |= ullCondMask << (6 * VER_NUM_BITS_PER_CONDITION_MASK);
232 else if (TypeMask & VER_SERVICEPACKMAJOR)
233 ConditionMask |= ullCondMask << (5 * VER_NUM_BITS_PER_CONDITION_MASK);
234 else if (TypeMask & VER_SERVICEPACKMINOR)
235 ConditionMask |= ullCondMask << (4 * VER_NUM_BITS_PER_CONDITION_MASK);
236 else if (TypeMask & VER_PLATFORMID)
237 ConditionMask |= ullCondMask << (3 * VER_NUM_BITS_PER_CONDITION_MASK);
238 else if (TypeMask & VER_BUILDNUMBER)
239 ConditionMask |= ullCondMask << (2 * VER_NUM_BITS_PER_CONDITION_MASK);
240 else if (TypeMask & VER_MAJORVERSION)
241 ConditionMask |= ullCondMask << (1 * VER_NUM_BITS_PER_CONDITION_MASK);
242 else if (TypeMask & VER_MINORVERSION)
243 ConditionMask |= ullCondMask << (0 * VER_NUM_BITS_PER_CONDITION_MASK);
244
245 return ConditionMask;
246 }
247
248 /* EOF */