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
*
Show replies by date