From f6b87bd3206122fdc30cf970bc0741c5ff568b29 Mon Sep 17 00:00:00 2001 From: Magnus Olsen Date: Sat, 7 May 2005 22:17:03 +0000 Subject: [PATCH] Fireball patch for fixing RtlUnicodeStringToInteger and RtlCharToInteger 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 :) svn path=/trunk/; revision=15092 --- reactos/lib/rtl/unicode.c | 287 ++++++++++++++++++++++---------------- 1 file changed, 166 insertions(+), 121 deletions(-) diff --git a/reactos/lib/rtl/unicode.c b/reactos/lib/rtl/unicode.c index ee485f609f5..483a5793dc9 100644 --- a/reactos/lib/rtl/unicode.c +++ b/reactos/lib/rtl/unicode.c @@ -154,51 +154,96 @@ RtlAppendUnicodeStringToString( } -/* +/************************************************************************** + * 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 @@ RtlPrefixUnicodeString( 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 *