Fireball patch for fixing RtlUnicodeStringToInteger and RtlCharToInteger
<Fireball> Imported WINE's RtlUnicodeStringToInteger and RtlCharToInteger - they were seriously broken in our revision. Thanks to GreatLord for his help pointing out this bug with me :)
Modified: trunk/reactos/lib/rtl/unicode.c

Modified: trunk/reactos/lib/rtl/unicode.c
--- trunk/reactos/lib/rtl/unicode.c	2005-05-07 21:24:31 UTC (rev 15091)
+++ trunk/reactos/lib/rtl/unicode.c	2005-05-07 22:17:03 UTC (rev 15092)
@@ -154,50 +154,95 @@
 }
 
 
-/*
+/**************************************************************************
+ *      RtlCharToInteger   (NTDLL.@)
  * @implemented
+ * Converts a character string into its integer equivalent.
+ *
+ * RETURNS
+ *  Success: STATUS_SUCCESS. value contains the converted number
+ *  Failure: STATUS_INVALID_PARAMETER, if base is not 0, 2, 8, 10 or 16.
+ *           STATUS_ACCESS_VIOLATION, if value is NULL.
+ *
+ * NOTES
+ *  For base 0 it uses 10 as base and the string should be in the format
+ *      "{whitespace} [+|-] [0[x|o|b]] {digits}".
+ *  For other bases the string should be in the format
+ *      "{whitespace} [+|-] {digits}".
+ *  No check is made for value overflow, only the lower 32 bits are assigned.
+ *  If str is NULL it crashes, as the native function does.
+ *
+ * DIFFERENCES
+ *  This function does not read garbage behind '\0' as the native version does.
  */
 NTSTATUS
 STDCALL
 RtlCharToInteger(
-   IN PCSZ String,
-   IN ULONG Base,
-   IN OUT PULONG Value)
+    PCSZ str,      /* [I] '\0' terminated single-byte string containing a number */
+    ULONG base,    /* [I] Number base for conversion (allowed 0, 2, 8, 10 or 16) */
+    PULONG value)  /* [O] Destination for the converted value */
 {
-   ULONG Val;
+    CHAR chCurrent;
+    int digit;
+    ULONG RunningTotal = 0;
+    char bMinus = 0;
 
-   *Value = 0;
+    while (*str != '\0' && *str <= ' ') {
+	str++;
+    } /* while */
 
-   if (Base == 0)
-   {
-      Base = 10;
-      if (*String == '0')
-      {
-         Base = 8;
-         String++;
-         if ((*String == 'x') && isxdigit (String[1]))
-         {
-            String++;
-            Base = 16;
-         }
-      }
-   }
+    if (*str == '+') {
+	str++;
+    } else if (*str == '-') {
+	bMinus = 1;
+	str++;
+    } /* if */
 
-   if (!isxdigit (*String))
-      return STATUS_INVALID_PARAMETER;
+    if (base == 0) {
+	base = 10;
+	if (str[0] == '0') {
+	    if (str[1] == 'b') {
+		str += 2;
+		base = 2;
+	    } else if (str[1] == 'o') {
+		str += 2;
+		base = 8;
+	    } else if (str[1] == 'x') {
+		str += 2;
+		base = 16;
+	    } /* if */
+	} /* if */
+    } else if (base != 2 && base != 8 && base != 10 && base != 16) {
+	return STATUS_INVALID_PARAMETER;
+    } /* if */
 
-   while (isxdigit (*String) &&
-          (Val = isdigit (*String) ? * String - '0' : (islower (*String)
-                 ? toupper (*String) : *String) - 'A' + 10) < Base)
-   {
-      *Value = *Value * Base + Val;
-      String++;
-   }
+    if (value == NULL) {
+	return STATUS_ACCESS_VIOLATION;
+    } /* if */
 
-   return STATUS_SUCCESS;
-}
+    while (*str != '\0') {
+	chCurrent = *str;
+	if (chCurrent >= '0' && chCurrent <= '9') {
+	    digit = chCurrent - '0';
+	} else if (chCurrent >= 'A' && chCurrent <= 'Z') {
+	    digit = chCurrent - 'A' + 10;
+	} else if (chCurrent >= 'a' && chCurrent <= 'z') {
+	    digit = chCurrent - 'a' + 10;
+	} else {
+	    digit = -1;
+	} /* if */
+	if (digit < 0 || digit >= base) {
+	    *value = bMinus ? -RunningTotal : RunningTotal;
+	    return STATUS_SUCCESS;
+	} /* if */
 
+	RunningTotal = RunningTotal * base + digit;
+	str++;
+    } /* while */
 
+    *value = bMinus ? -RunningTotal : RunningTotal;
+    return STATUS_SUCCESS;
+}
 
 /*
  * @implemented
@@ -807,113 +852,113 @@
    return FALSE;
 }
 
-
-
-/*
+/**************************************************************************
+ *      RtlUnicodeStringToInteger (NTDLL.@)
  * @implemented
+ * Converts an unicode string into its integer equivalent.
  *
- * Note that regardless of success or failure status, we should leave the
- * partial value in Value.  An error is never returned based on the chars
- * in the string.
+ * RETURNS
+ *  Success: STATUS_SUCCESS. value contains the converted number
+ *  Failure: STATUS_INVALID_PARAMETER, if base is not 0, 2, 8, 10 or 16.
+ *           STATUS_ACCESS_VIOLATION, if value is NULL.
  *
- * This function does check the base.  Only 2, 8, 10, 16 are permitted,
- * else STATUS_INVALID_PARAMETER is returned.
+ * NOTES
+ *  For base 0 it uses 10 as base and the string should be in the format
+ *      "{whitespace} [+|-] [0[x|o|b]] {digits}".
+ *  For other bases the string should be in the format
+ *      "{whitespace} [+|-] {digits}".
+ *  No check is made for value overflow, only the lower 32 bits are assigned.
+ *  If str is NULL it crashes, as the native function does.
+ *
+ *  Note that regardless of success or failure status, we should leave the
+ *  partial value in Value.  An error is never returned based on the chars
+ *  in the string.
+ *
+ * DIFFERENCES
+ *  This function does not read garbage on string length 0 as the native
+ *  version does.
  */
 NTSTATUS
 STDCALL
 RtlUnicodeStringToInteger(
-   IN PUNICODE_STRING String,
-   IN ULONG  Base,
-   OUT PULONG  Value)
+    PUNICODE_STRING str, /* [I] Unicode string to be converted */
+    ULONG base,                /* [I] Number base for conversion (allowed 0, 2, 8, 10 or 16) */
+    PULONG value)              /* [O] Destination for the converted value */
 {
-   PWCHAR Str;
-   ULONG lenmin = 0;
-   ULONG i;
-   ULONG Val;
-   BOOLEAN addneg = FALSE;
-   NTSTATUS Status = STATUS_SUCCESS;
+    LPWSTR lpwstr = str->Buffer;
+    USHORT CharsRemaining = str->Length / sizeof(WCHAR);
+    WCHAR wchCurrent;
+    int digit;
+    ULONG RunningTotal = 0;
+    char bMinus = 0;
 
-   *Value = 0;
-   Str = String->Buffer;
+    while (CharsRemaining >= 1 && *lpwstr <= ' ') {
+	lpwstr++;
+	CharsRemaining--;
+    } /* while */
 
-   if( Base && Base != 2 && Base != 8 && Base != 10 && Base != 16 )
-       return STATUS_INVALID_PARAMETER;
+    if (CharsRemaining >= 1) {
+	if (*lpwstr == '+') {
+	    lpwstr++;
+	    CharsRemaining--;
+	} else if (*lpwstr == '-') {
+	    bMinus = 1;
+	    lpwstr++;
+	    CharsRemaining--;
+	} /* if */
+    } /* if */
 
-   for (i = 0; i < String->Length / sizeof(WCHAR); i++)
-   {
-      if (*Str == L'b')
-      {
-         Base = 2;
-         lenmin++;
-      }
-      else if (*Str == L'o')
-      {
-         Base = 8;
-         lenmin++;
-      }
-      else if (*Str == L'd')
-      {
-         Base = 10;
-         lenmin++;
-      }
-      else if (*Str == L'x')
-      {
-         Base = 16;
-         lenmin++;
-      }
-      else if (*Str == L'+')
-      {
-         lenmin++;
-      }
-      else if (*Str == L'-')
-      {
-         addneg = TRUE;
-         lenmin++;
-      }
-      else if ((*Str > L'1') && (Base == 2))
-      {
-	  break;
-      }
-      else if (((*Str > L'7') || (*Str < L'0')) && (Base == 8))
-      {
-	  break;
-      }
-      else if (((*Str > L'9') || (*Str < L'0')) && (Base == 10))
-      {
-	  break;
-      }
-      else if (  ((*Str > L'9') || (*Str < L'0')) &&
-                 ((towupper (*Str) > L'F') || (towupper (*Str) < L'A')) &&
-                 (Base == 16))
-      {
-	  break;
-      }
-      Str++;
-   }
+    if (base == 0) {
+	base = 10;
+	if (CharsRemaining >= 2 && lpwstr[0] == '0') {
+	    if (lpwstr[1] == 'b') {
+		lpwstr += 2;
+		CharsRemaining -= 2;
+		base = 2;
+	    } else if (lpwstr[1] == 'o') {
+		lpwstr += 2;
+		CharsRemaining -= 2;
+		base = 8;
+	    } else if (lpwstr[1] == 'x') {
+		lpwstr += 2;
+		CharsRemaining -= 2;
+		base = 16;
+	    } /* if */
+	} /* if */
+    } else if (base != 2 && base != 8 && base != 10 && base != 16) {
+	return STATUS_INVALID_PARAMETER;
+    } /* if */
 
-   Str = String->Buffer + lenmin;
+    if (value == NULL) {
+	return STATUS_ACCESS_VIOLATION;
+    } /* if */
 
-   if (Base == 0)
-      Base = 10;
+    while (CharsRemaining >= 1) {
+	wchCurrent = *lpwstr;
+	if (wchCurrent >= '0' && wchCurrent <= '9') {
+	    digit = wchCurrent - '0';
+	} else if (wchCurrent >= 'A' && wchCurrent <= 'Z') {
+	    digit = wchCurrent - 'A' + 10;
+	} else if (wchCurrent >= 'a' && wchCurrent <= 'z') {
+	    digit = wchCurrent - 'a' + 10;
+	} else {
+	    digit = -1;
+	} /* if */
+	if (digit < 0 || digit >= base) {
+	    *value = bMinus ? -RunningTotal : RunningTotal;
+	    return STATUS_SUCCESS;
+	} /* if */
 
-   while (iswxdigit (*Str) &&
-          (Val = 
-	   iswdigit (*Str) ? 
-	   *Str - L'0' : 
-	   (towupper (*Str) - L'A' + 10)) < Base)
-   {
-      *Value = *Value * Base + Val;
-      Str++;
-   }
+	RunningTotal = RunningTotal * base + digit;
+	lpwstr++;
+	CharsRemaining--;
+    } /* while */
 
-   if (addneg == TRUE)
-      *Value *= -1;
-
-   return Status;
+    *value = bMinus ? -RunningTotal : RunningTotal;
+    return STATUS_SUCCESS;
 }
 
 
-
 /*
  * @implemented
  *