[RTL]
[reactos.git] / reactos / lib / rtl / version.c
index 0be7352..d340380 100644 (file)
@@ -1,8 +1,10 @@
-/* COPYRIGHT:       See COPYING in the top level directory
+/*
+ * COPYRIGHT:       See COPYING in the top level directory
  * PROJECT:         ReactOS system libraries
  * PURPOSE:         Runtime code
  * FILE:            lib/rtl/version.c
- * PROGRAMER:       Filip Navara
+ * PROGRAMERS:      Filip Navara
+ *                  Hermes Belusca-Maito (hermes.belusca@sfr.fr)
  */
 
 /* INCLUDES *****************************************************************/
 
 NTSTATUS
 NTAPI
-RtlGetVersion(
-    OUT PRTL_OSVERSIONINFOW lpVersionInformation
-    );
+RtlGetVersion(OUT PRTL_OSVERSIONINFOW lpVersionInformation);
 
 /* FUNCTIONS ****************************************************************/
 
-static inline NTSTATUS version_compare_values(ULONG left, ULONG right, UCHAR condition)
+static BYTE
+RtlpVerGetCondition(IN ULONGLONG dwlConditionMask,
+                    IN DWORD dwTypeBitMask);
+
+static BOOLEAN
+RtlpVerCompare(ULONG left, ULONG right, UCHAR condition)
 {
-    switch (condition) {
+    switch (condition)
+    {
         case VER_EQUAL:
-            if (left != right) return STATUS_REVISION_MISMATCH;
-            break;
+            return (left == right);
         case VER_GREATER:
-            if (left <= right) return STATUS_REVISION_MISMATCH;
-            break;
+            return (left > right);
         case VER_GREATER_EQUAL:
-            if (left < right) return STATUS_REVISION_MISMATCH;
-            break;
+            return (left >= right);
         case VER_LESS:
-            if (left >= right) return STATUS_REVISION_MISMATCH;
-            break;
+            return (left < right);
         case VER_LESS_EQUAL:
-            if (left > right) return STATUS_REVISION_MISMATCH;
-            break;
+            return (left <= right);
         default:
-            return STATUS_REVISION_MISMATCH;
+            break;
     }
-    return STATUS_SUCCESS;
+    return FALSE;
 }
 
 /*
@@ -51,14 +52,13 @@ static inline NTSTATUS version_compare_values(ULONG left, ULONG right, UCHAR con
 */
 NTSTATUS
 NTAPI
-RtlVerifyVersionInfo(
-    IN PRTL_OSVERSIONINFOEXW VersionInfo,
-    IN ULONG TypeMask,
-    IN ULONGLONG ConditionMask
-    )
+RtlVerifyVersionInfo(IN PRTL_OSVERSIONINFOEXW VersionInfo,
+                     IN ULONG TypeMask,
+                     IN ULONGLONG ConditionMask)
 {
     RTL_OSVERSIONINFOEXW ver;
     NTSTATUS status;
+    BOOLEAN comparison;
 
     /* FIXME:
         - Check the following special case on Windows (various versions):
@@ -68,123 +68,181 @@ RtlVerifyVersionInfo(
      */
 
     ver.dwOSVersionInfoSize = sizeof(ver);
-    status = RtlGetVersion( (PRTL_OSVERSIONINFOW)&ver );
+    status = RtlGetVersion((PRTL_OSVERSIONINFOW)&ver);
     if (status != STATUS_SUCCESS) return status;
 
-    if(!(TypeMask && ConditionMask)) return STATUS_INVALID_PARAMETER;
+    if (!TypeMask || !ConditionMask) return STATUS_INVALID_PARAMETER;
 
-    if(TypeMask & VER_PRODUCT_TYPE)
+    if (TypeMask & VER_PRODUCT_TYPE)
     {
-        status = version_compare_values(ver.wProductType, VersionInfo->wProductType, ConditionMask >> 7 * VER_NUM_BITS_PER_CONDITION_MASK & VER_CONDITION_MASK);
-        if (status != STATUS_SUCCESS)
-            return status;
+        comparison = RtlpVerCompare(ver.wProductType,
+                                    VersionInfo->wProductType,
+                                    RtlpVerGetCondition(ConditionMask, VER_PRODUCT_TYPE));
+        if (!comparison)
+            return STATUS_REVISION_MISMATCH;
     }
-    if(TypeMask & VER_SUITENAME)
+
+    if (TypeMask & VER_SUITENAME)
     {
-        switch(ConditionMask >> 6 * VER_NUM_BITS_PER_CONDITION_MASK & VER_CONDITION_MASK)
+        switch (RtlpVerGetCondition(ConditionMask, VER_SUITENAME))
         {
             case VER_AND:
-                if((VersionInfo->wSuiteMask & ver.wSuiteMask) != VersionInfo->wSuiteMask)
+                if ((VersionInfo->wSuiteMask & ver.wSuiteMask) != VersionInfo->wSuiteMask)
+                {
                     return STATUS_REVISION_MISMATCH;
+                }
                 break;
             case VER_OR:
-                if(!(VersionInfo->wSuiteMask & ver.wSuiteMask) && VersionInfo->wSuiteMask)
+                if (!(VersionInfo->wSuiteMask & ver.wSuiteMask) && VersionInfo->wSuiteMask)
+                {
                     return STATUS_REVISION_MISMATCH;
+                }
                 break;
             default:
                 return STATUS_INVALID_PARAMETER;
         }
     }
-    if(TypeMask & VER_PLATFORMID)
+
+    if (TypeMask & VER_PLATFORMID)
     {
-        status = version_compare_values(ver.dwPlatformId, VersionInfo->dwPlatformId, ConditionMask >> 3 * VER_NUM_BITS_PER_CONDITION_MASK & VER_CONDITION_MASK);
-        if (status != STATUS_SUCCESS)
-            return status;
+        comparison = RtlpVerCompare(ver.dwPlatformId,
+                                    VersionInfo->dwPlatformId,
+                                    RtlpVerGetCondition(ConditionMask, VER_PLATFORMID));
+        if (!comparison)
+            return STATUS_REVISION_MISMATCH;
     }
-    if(TypeMask & VER_BUILDNUMBER)
+
+    if (TypeMask & VER_BUILDNUMBER)
     {
-        status = version_compare_values(ver.dwBuildNumber, VersionInfo->dwBuildNumber, ConditionMask >> 2 * VER_NUM_BITS_PER_CONDITION_MASK & VER_CONDITION_MASK);
-        if (status != STATUS_SUCCESS)
-            return status;
+        comparison = RtlpVerCompare(ver.dwBuildNumber,
+                                    VersionInfo->dwBuildNumber,
+                                    RtlpVerGetCondition(ConditionMask, VER_BUILDNUMBER));
+        if (!comparison)
+            return STATUS_REVISION_MISMATCH;
     }
-    if(TypeMask & (VER_MAJORVERSION|VER_MINORVERSION|VER_SERVICEPACKMAJOR|VER_SERVICEPACKMINOR))
+
+    TypeMask &= VER_MAJORVERSION|VER_MINORVERSION|VER_SERVICEPACKMAJOR|VER_SERVICEPACKMINOR;
+    if (TypeMask)
     {
-        unsigned char condition = 0;
         BOOLEAN do_next_check = TRUE;
-
-        if(TypeMask & VER_MAJORVERSION)
-            condition = ConditionMask >> 1 * VER_NUM_BITS_PER_CONDITION_MASK & VER_CONDITION_MASK;
-        else if(TypeMask & VER_MINORVERSION)
-            condition = ConditionMask >> 0 * VER_NUM_BITS_PER_CONDITION_MASK & VER_CONDITION_MASK;
-        else if(TypeMask & VER_SERVICEPACKMAJOR)
-            condition = ConditionMask >> 5 * VER_NUM_BITS_PER_CONDITION_MASK & VER_CONDITION_MASK;
-        else if(TypeMask & VER_SERVICEPACKMINOR)
-            condition = ConditionMask >> 4 * VER_NUM_BITS_PER_CONDITION_MASK & VER_CONDITION_MASK;
-
-        if(TypeMask & VER_MAJORVERSION)
+        /*
+         * Select the leading comparison operator (for example, the comparison
+         * operator for VER_MAJORVERSION supersedes the others for VER_MINORVERSION,
+         * VER_SERVICEPACKMAJOR and VER_SERVICEPACKMINOR).
+         */
+        BYTE condition = RtlpVerGetCondition(ConditionMask, TypeMask);
+
+        comparison = TRUE;
+        if (TypeMask & VER_MAJORVERSION)
         {
-            status = version_compare_values(ver.dwMajorVersion, VersionInfo->dwMajorVersion, condition);
+            comparison = RtlpVerCompare(ver.dwMajorVersion,
+                                        VersionInfo->dwMajorVersion,
+                                        condition);
             do_next_check = (ver.dwMajorVersion == VersionInfo->dwMajorVersion) &&
-                ((condition != VER_EQUAL) || (status == STATUS_SUCCESS));
+                ((condition != VER_EQUAL) || comparison);
         }
-        if((TypeMask & VER_MINORVERSION) && do_next_check)
+        if ((TypeMask & VER_MINORVERSION) && do_next_check)
         {
-            status = version_compare_values(ver.dwMinorVersion, VersionInfo->dwMinorVersion, condition);
+            comparison = RtlpVerCompare(ver.dwMinorVersion,
+                                        VersionInfo->dwMinorVersion,
+                                        condition);
             do_next_check = (ver.dwMinorVersion == VersionInfo->dwMinorVersion) &&
-                ((condition != VER_EQUAL) || (status == STATUS_SUCCESS));
+                ((condition != VER_EQUAL) || comparison);
         }
-        if((TypeMask & VER_SERVICEPACKMAJOR) && do_next_check)
+        if ((TypeMask & VER_SERVICEPACKMAJOR) && do_next_check)
         {
-            status = version_compare_values(ver.wServicePackMajor, VersionInfo->wServicePackMajor, condition);
+            comparison = RtlpVerCompare(ver.wServicePackMajor,
+                                        VersionInfo->wServicePackMajor,
+                                        condition);
             do_next_check = (ver.wServicePackMajor == VersionInfo->wServicePackMajor) &&
-                ((condition != VER_EQUAL) || (status == STATUS_SUCCESS));
+                ((condition != VER_EQUAL) || comparison);
         }
-        if((TypeMask & VER_SERVICEPACKMINOR) && do_next_check)
+        if ((TypeMask & VER_SERVICEPACKMINOR) && do_next_check)
         {
-            status = version_compare_values(ver.wServicePackMinor, VersionInfo->wServicePackMinor, condition);
+            comparison = RtlpVerCompare(ver.wServicePackMinor,
+                                        VersionInfo->wServicePackMinor,
+                                        condition);
         }
 
-        if (status != STATUS_SUCCESS)
-            return status;
+        if (!comparison)
+            return STATUS_REVISION_MISMATCH;
     }
 
     return STATUS_SUCCESS;
 }
 
+static BYTE
+RtlpVerGetCondition(IN ULONGLONG dwlConditionMask,
+                    IN DWORD dwTypeBitMask)
+{
+    BYTE bConditionMask = 0;
+
+    if (dwTypeBitMask & VER_PRODUCT_TYPE)
+        bConditionMask |= dwlConditionMask >> 7 * VER_NUM_BITS_PER_CONDITION_MASK;
+    else if (dwTypeBitMask & VER_SUITENAME)
+        bConditionMask |= dwlConditionMask >> 6 * VER_NUM_BITS_PER_CONDITION_MASK;
+    else if (dwTypeBitMask & VER_PLATFORMID)
+        bConditionMask |= dwlConditionMask >> 3 * VER_NUM_BITS_PER_CONDITION_MASK;
+    else if (dwTypeBitMask & VER_BUILDNUMBER)
+        bConditionMask |= dwlConditionMask >> 2 * VER_NUM_BITS_PER_CONDITION_MASK;
+    /*
+     * We choose here the lexicographical order on the 4D space
+     * {(Major ; Minor ; SP Major ; SP Minor)} to select the
+     * appropriate comparison operator.
+     * Therefore the following 'else if' instructions must be in this order.
+     */
+    else if (dwTypeBitMask & VER_MAJORVERSION)
+        bConditionMask |= dwlConditionMask >> 1 * VER_NUM_BITS_PER_CONDITION_MASK;
+    else if (dwTypeBitMask & VER_MINORVERSION)
+        bConditionMask |= dwlConditionMask >> 0 * VER_NUM_BITS_PER_CONDITION_MASK;
+    else if (dwTypeBitMask & VER_SERVICEPACKMAJOR)
+        bConditionMask |= dwlConditionMask >> 5 * VER_NUM_BITS_PER_CONDITION_MASK;
+    else if (dwTypeBitMask & VER_SERVICEPACKMINOR)
+        bConditionMask |= dwlConditionMask >> 4 * VER_NUM_BITS_PER_CONDITION_MASK;
+
+    bConditionMask &= VER_CONDITION_MASK;
+
+    return bConditionMask;
+}
+
 /*
  * @implemented
  */
-ULONGLONG NTAPI
+ULONGLONG
+NTAPI
 VerSetConditionMask(IN ULONGLONG dwlConditionMask,
                     IN DWORD dwTypeBitMask,
-                    IN BYTE dwConditionMask)
+                    IN BYTE bConditionMask)
 {
-  if(dwTypeBitMask == 0)
-    return dwlConditionMask;
-
-  dwConditionMask &= VER_CONDITION_MASK;
+    ULONGLONG ullCondMask;
+
+    if (dwTypeBitMask == 0)
+        return dwlConditionMask;
+
+    bConditionMask &= VER_CONDITION_MASK;
+
+    if (bConditionMask == 0)
+        return dwlConditionMask;
+
+    ullCondMask = bConditionMask;
+    if (dwTypeBitMask & VER_PRODUCT_TYPE)
+        dwlConditionMask |= ullCondMask << (7 * VER_NUM_BITS_PER_CONDITION_MASK);
+    else if (dwTypeBitMask & VER_SUITENAME)
+        dwlConditionMask |= ullCondMask << (6 * VER_NUM_BITS_PER_CONDITION_MASK);
+    else if (dwTypeBitMask & VER_SERVICEPACKMAJOR)
+        dwlConditionMask |= ullCondMask << (5 * VER_NUM_BITS_PER_CONDITION_MASK);
+    else if (dwTypeBitMask & VER_SERVICEPACKMINOR)
+        dwlConditionMask |= ullCondMask << (4 * VER_NUM_BITS_PER_CONDITION_MASK);
+    else if (dwTypeBitMask & VER_PLATFORMID)
+        dwlConditionMask |= ullCondMask << (3 * VER_NUM_BITS_PER_CONDITION_MASK);
+    else if (dwTypeBitMask & VER_BUILDNUMBER)
+        dwlConditionMask |= ullCondMask << (2 * VER_NUM_BITS_PER_CONDITION_MASK);
+    else if (dwTypeBitMask & VER_MAJORVERSION)
+        dwlConditionMask |= ullCondMask << (1 * VER_NUM_BITS_PER_CONDITION_MASK);
+    else if (dwTypeBitMask & VER_MINORVERSION)
+        dwlConditionMask |= ullCondMask << (0 * VER_NUM_BITS_PER_CONDITION_MASK);
 
-  if(dwConditionMask == 0)
     return dwlConditionMask;
-
-  if(dwTypeBitMask & VER_PRODUCT_TYPE)
-    dwlConditionMask |= dwConditionMask << 7 * VER_NUM_BITS_PER_CONDITION_MASK;
-  else if(dwTypeBitMask & VER_SUITENAME)
-    dwlConditionMask |= dwConditionMask << 6 * VER_NUM_BITS_PER_CONDITION_MASK;
-  else if(dwTypeBitMask & VER_SERVICEPACKMAJOR)
-    dwlConditionMask |= dwConditionMask << 5 * VER_NUM_BITS_PER_CONDITION_MASK;
-  else if(dwTypeBitMask & VER_SERVICEPACKMINOR)
-    dwlConditionMask |= dwConditionMask << 4 * VER_NUM_BITS_PER_CONDITION_MASK;
-  else if(dwTypeBitMask & VER_PLATFORMID)
-    dwlConditionMask |= dwConditionMask << 3 * VER_NUM_BITS_PER_CONDITION_MASK;
-  else if(dwTypeBitMask & VER_BUILDNUMBER)
-    dwlConditionMask |= dwConditionMask << 2 * VER_NUM_BITS_PER_CONDITION_MASK;
-  else if(dwTypeBitMask & VER_MAJORVERSION)
-    dwlConditionMask |= dwConditionMask << 1 * VER_NUM_BITS_PER_CONDITION_MASK;
-  else if(dwTypeBitMask & VER_MINORVERSION)
-    dwlConditionMask |= dwConditionMask << 0 * VER_NUM_BITS_PER_CONDITION_MASK;
-
-  return dwlConditionMask;
 }
 
 /* EOF */