From 29368a0dd8aa2b173a26cb65288fae0152947ddc Mon Sep 17 00:00:00 2001 From: Aiken Harris Date: Fri, 15 May 2026 15:02:22 +0200 Subject: [PATCH] Implement string to number conversion functions --- sdk/xtdk/xtstatus.h | 2 + xtoskrnl/includes/rtl/string.hh | 3 + xtoskrnl/includes/rtl/widestr.hh | 3 + xtoskrnl/rtl/string.cc | 186 +++++++++++++++++++++++++++++++ xtoskrnl/rtl/widestr.cc | 186 +++++++++++++++++++++++++++++++ 5 files changed, 380 insertions(+) diff --git a/sdk/xtdk/xtstatus.h b/sdk/xtdk/xtstatus.h index 169f507..0803ba2 100644 --- a/sdk/xtdk/xtstatus.h +++ b/sdk/xtdk/xtstatus.h @@ -61,6 +61,8 @@ #define STATUS_NO_MEMORY ((XTSTATUS) 0xC0000017L) #define STATUS_PORT_DISCONNECTED ((XTSTATUS) 0xC0000037L) #define STATUS_CRC_ERROR ((XTSTATUS) 0xC000003FL) +#define STATUS_FLOAT_OVERFLOW ((XTSTATUS) 0xC0000091L) +#define STATUS_INTEGER_OVERFLOW ((XTSTATUS) 0xC0000095L) #define STATUS_INSUFFICIENT_RESOURCES ((XTSTATUS) 0xC000009AL) #define STATUS_DEVICE_NOT_READY ((XTSTATUS) 0xC00000A3L) #define STATUS_NOT_SUPPORTED ((XTSTATUS) 0xC00000BBL) diff --git a/xtoskrnl/includes/rtl/string.hh b/xtoskrnl/includes/rtl/string.hh index 8d1ca18..f6feec4 100644 --- a/xtoskrnl/includes/rtl/string.hh +++ b/xtoskrnl/includes/rtl/string.hh @@ -38,6 +38,9 @@ namespace RTL IN ULONG Length); STATIC XTAPI SIZE_T StringLength(IN PCSTR String, IN SIZE_T MaxLength); + STATIC XTAPI XTSTATUS StringToNumber(IN PCSTR String, + IN ULONG Base, + OUT PULONG Value); STATIC XTAPI SIZE_T StringToWideString(OUT PWCHAR Destination, IN PCSTR *Source, IN SIZE_T Length); diff --git a/xtoskrnl/includes/rtl/widestr.hh b/xtoskrnl/includes/rtl/widestr.hh index 66175fe..8b4b459 100644 --- a/xtoskrnl/includes/rtl/widestr.hh +++ b/xtoskrnl/includes/rtl/widestr.hh @@ -49,6 +49,9 @@ namespace RTL STATIC XTAPI PWCHAR TrimWideString(IN PWCHAR String); STATIC XTAPI SIZE_T WideStringLength(IN PCWSTR String, IN SIZE_T MaxLength); + STATIC XTAPI XTSTATUS WideStringToNumber(IN PCWSTR String, + IN ULONG Base, + OUT PULONG Value); private: STATIC XTAPI XTSTATUS FormatArgumentSpecifier(IN PRTL_PRINT_CONTEXT Context, diff --git a/xtoskrnl/rtl/string.cc b/xtoskrnl/rtl/string.cc index df0812a..12b5182 100644 --- a/xtoskrnl/rtl/string.cc +++ b/xtoskrnl/rtl/string.cc @@ -427,6 +427,192 @@ RTL::String::StringLength(IN PCSTR String, return Length; } +/** + * Converts a string to a number. + * + * @param String + * Supplies a pointer to the NULL-terminated string to convert. + * + * @param Base + * Supplies the optional numerical base for the conversion (2, 8, 10, or 16). + * + * @param Value + * Supplies a pointer to a variable that receives the converted numeric value. + * + * @return This routine returns a status code. + * + * @since XT 1.0 + */ +XTAPI +XTSTATUS +RTL::String::StringToNumber(IN PCSTR String, + IN ULONG Base, + OUT PULONG Value) +{ + BOOLEAN NegativeValue; + ULONG Digit, Result; + + /* Validate input parameters */ + if(!String || !Value) + { + /* Invalid input parameters, return error code */ + return STATUS_INVALID_PARAMETER; + } + + /* Initialize local variables */ + NegativeValue = FALSE; + Result = 0; + + /* Skip leading whitespaces and control characters */ + while(*String != '\0' && *String <= ' ') + { + /* Advance to the next character */ + String++; + } + + /* Consume and record sign */ + if(*String == '-') + { + /* Set negative value flag and advance to the next character */ + NegativeValue = TRUE; + String++; + } + else if(*String == '+') + { + /* Advance to the next character */ + String++; + } + + /* Autodetect and validate the base */ + if(Base == 0) + { + /* Autodetect base based on prefix */ + if(String[0] == '0') + { + /* Validate prefix */ + if(String[1] == 'x' || String[1] == 'X') + { + /* Hexadecimal base */ + Base = 16; + String += 2; + } + else if(String[1] == 'o' || String[1] == 'O') + { + /* Octal base */ + Base = 8; + String += 2; + } + else if(String[1] == 'b' || String[1] == 'B') + { + /* Binary base */ + Base = 2; + String += 2; + } + else + { + /* Starts with 0 but no known prefix, treat as decimal */ + Base = 10; + } + } + else + { + /* Default to decimal base */ + Base = 10; + } + } + else + { + /* Validate explicitly provided base */ + if(Base != 2 && Base != 8 && Base != 10 && Base != 16) + { + /* Invalid base, return error code */ + return STATUS_INVALID_PARAMETER; + } + + /* Check if number starts with 0 */ + if(String[0] == '0') + { + /* Check for prefix */ + if(Base == 16 && (String[1] == 'x' || String[1] == 'X')) + { + /* Skip hexadecimal prefix */ + String += 2; + } + else if(Base == 8 && (String[1] == 'o' || String[1] == 'O')) + { + /* Skip octal prefix */ + String += 2; + } + else if(Base == 2 && (String[1] == 'b' || String[1] == 'B')) + { + /* Skip binary prefix */ + String += 2; + } + } + } + + /* Parse string character by character */ + while(*String != '\0') + { + /* Convert character to numeric digit */ + if(*String >= '0' && *String <= '9') + { + /* Convert decimal digit */ + Digit = *String - '0'; + } + else if(*String >= 'A' && *String <= 'F') + { + /* Convert hexadecimal digit */ + Digit = *String - 'A' + 10; + } + else if(*String >= 'a' && *String <= 'f') + { + /* Convert hexadecimal digit */ + Digit = *String - 'a' + 10; + } + else + { + /* Invalid character for a number encountered, stop parsing */ + break; + } + + /* Check if digit is valid for the current base */ + if(Digit >= Base) + { + /* Digit out of range for this base, stop parsing */ + break; + } + + /* Check for integer overflow */ + if((Result > (MAXULONG / Base)) || ((Result * Base) > (MAXULONG - Digit))) + { + /* Integer overflow, return error code */ + return STATUS_INTEGER_OVERFLOW; + } + + /* Accumulate result */ + Result = (Result * Base) + Digit; + + /* Advance to the next character */ + String++; + } + + /* Check for negative value */ + if(NegativeValue) + { + /* Apply sign and return the result */ + *Value = (ULONG)(-(LONG)Result); + } + else + { + /* Return the result */ + *Value = Result; + } + + /* Return success */ + return STATUS_SUCCESS; +} + /** * Converts a multibyte character string to its wide character representation. * diff --git a/xtoskrnl/rtl/widestr.cc b/xtoskrnl/rtl/widestr.cc index dc8dbec..aed6c05 100644 --- a/xtoskrnl/rtl/widestr.cc +++ b/xtoskrnl/rtl/widestr.cc @@ -1524,6 +1524,192 @@ RTL::WideString::WideStringLength(IN PCWSTR String, return Length; } +/** + * Converts a wide string to a number. + * + * @param String + * Supplies a pointer to the NULL-terminated wide string to convert. + * + * @param Base + * Supplies the optional numerical base for the conversion (2, 8, 10, or 16). + * + * @param Value + * Supplies a pointer to a variable that receives the converted numeric value. + * + * @return This routine returns a status code. + * + * @since XT 1.0 + */ +XTAPI +XTSTATUS +RTL::WideString::WideStringToNumber(IN PCWSTR String, + IN ULONG Base, + OUT PULONG Value) +{ + BOOLEAN NegativeValue; + ULONG Digit, Result; + + /* Validate input parameters */ + if(!String || !Value) + { + /* Invalid input parameters, return error code */ + return STATUS_INVALID_PARAMETER; + } + + /* Initialize local variables */ + NegativeValue = FALSE; + Result = 0; + + /* Skip leading whitespaces and control characters */ + while(*String != L'\0' && *String <= L' ') + { + /* Advance to the next character */ + String++; + } + + /* Consume and record sign */ + if(*String == L'-') + { + /* Set negative value flag and advance to the next character */ + NegativeValue = TRUE; + String++; + } + else if(*String == L'+') + { + /* Advance to the next character */ + String++; + } + + /* Autodetect and validate the base */ + if(Base == 0) + { + /* Autodetect base based on prefix */ + if(String[0] == L'0') + { + /* Validate prefix */ + if(String[1] == L'x' || String[1] == L'X') + { + /* Hexadecimal base */ + Base = 16; + String += 2; + } + else if(String[1] == L'o' || String[1] == L'O') + { + /* Octal base */ + Base = 8; + String += 2; + } + else if(String[1] == L'b' || String[1] == L'B') + { + /* Binary base */ + Base = 2; + String += 2; + } + else + { + /* Starts with 0 but no known prefix, treat as decimal */ + Base = 10; + } + } + else + { + /* Default to decimal base */ + Base = 10; + } + } + else + { + /* Validate explicitly provided base */ + if(Base != 2 && Base != 8 && Base != 10 && Base != 16) + { + /* Invalid base, return error code */ + return STATUS_INVALID_PARAMETER; + } + + /* Check if number starts with 0 */ + if(String[0] == L'0') + { + /* Check for prefix */ + if(Base == 16 && (String[1] == L'x' || String[1] == L'X')) + { + /* Skip hexadecimal prefix */ + String += 2; + } + else if(Base == 8 && (String[1] == L'o' || String[1] == L'O')) + { + /* Skip octal prefix */ + String += 2; + } + else if(Base == 2 && (String[1] == L'b' || String[1] == L'B')) + { + /* Skip binary prefix */ + String += 2; + } + } + } + + /* Parse string character by character */ + while(*String != L'\0') + { + /* Convert wide character to numeric digit */ + if(*String >= L'0' && *String <= L'9') + { + /* Convert decimal digit */ + Digit = *String - L'0'; + } + else if(*String >= L'A' && *String <= L'F') + { + /* Convert hexadecimal digit */ + Digit = *String - L'A' + 10; + } + else if(*String >= L'a' && *String <= L'f') + { + /* Convert hexadecimal digit */ + Digit = *String - L'a' + 10; + } + else + { + /* Invalid character for a number encountered, stop parsing */ + break; + } + + /* Check if digit is valid for the current base */ + if(Digit >= Base) + { + /* Digit out of range for this base, stop parsing */ + break; + } + + /* Check for integer overflow */ + if((Result > (MAXULONG / Base)) || ((Result * Base) > (MAXULONG - Digit))) + { + /* Integer overflow, return error code */ + return STATUS_INTEGER_OVERFLOW; + } + + /* Accumulate result */ + Result = (Result * Base) + Digit; + + /* Advance to the next character */ + String++; + } + + /* Check for negative value */ + if(NegativeValue) + { + /* Apply sign and return the result */ + *Value = (ULONG)(-(LONG)Result); + } + else + { + /* Return the result */ + *Value = Result; + } + + /* Return success */ + return STATUS_SUCCESS; +} + /** * Writes a wide character to the destination provided by the print context. *