Signed-off-by: Daniel Lehman dlehman25@gmail.com --- include/wine/unicode.h | 1 + libs/port/string.c | 113 +++++++++++++++++++++++++++++++++++++++++ libs/wine/wine.map | 1 + 3 files changed, 115 insertions(+)
diff --git a/include/wine/unicode.h b/include/wine/unicode.h index ff6f6568a5..5ee53e74a5 100644 --- a/include/wine/unicode.h +++ b/include/wine/unicode.h @@ -108,6 +108,7 @@ extern int memicmpW( const WCHAR *str1, const WCHAR *str2, int n ); extern WCHAR *strstrW( const WCHAR *str, const WCHAR *sub ); extern long int strtolW( const WCHAR *nptr, WCHAR **endptr, int base ); extern unsigned long int strtoulW( const WCHAR *nptr, WCHAR **endptr, int base ); +extern unsigned long long strtoullW( const WCHAR *nptr, WCHAR **endptr, int base ); extern int sprintfW( WCHAR *str, const WCHAR *format, ... ); extern int snprintfW( WCHAR *str, size_t len, const WCHAR *format, ... ); extern int vsprintfW( WCHAR *str, const WCHAR *format, va_list valist ); diff --git a/libs/port/string.c b/libs/port/string.c index c3388bcc7d..0ff4700664 100644 --- a/libs/port/string.c +++ b/libs/port/string.c @@ -301,6 +301,119 @@ noconv: }
+unsigned long long strtoullW( const WCHAR *nptr, WCHAR **endptr, int base ) +{ + int negative; + register unsigned long long cutoff; + register unsigned int cutlim; + register unsigned long long i; + register const WCHAR *s; + register WCHAR c; + const WCHAR *save, *end; + int overflow; + + if (base < 0 || base == 1 || base > 36) return 0; + + save = s = nptr; + + /* Skip white space. */ + while (isspaceW (*s)) + ++s; + if (!*s) goto noconv; + + /* Check for a sign. */ + negative = 0; + if (*s == '-') + { + negative = 1; + ++s; + } + else if (*s == '+') + ++s; + + /* Recognize number prefix and if BASE is zero, figure it out ourselves. */ + if (*s == '0') + { + if ((base == 0 || base == 16) && toupperW(s[1]) == 'X') + { + s += 2; + base = 16; + } + else if (base == 0) + base = 8; + } + else if (base == 0) + base = 10; + + /* Save the pointer so we can check later if anything happened. */ + save = s; + end = NULL; + + cutoff = ULLONG_MAX / (unsigned long long) base; + cutlim = ULLONG_MAX % (unsigned long long) base; + + overflow = 0; + i = 0; + c = *s; + for (;c != '\0'; c = *++s) + { + if (s == end) + break; + if (c >= '0' && c <= '9') + c -= '0'; + else if (isalphaW (c)) + c = toupperW (c) - 'A' + 10; + else + break; + if ((int) c >= base) + break; + /* Check for overflow. */ + if (i > cutoff || (i == cutoff && c > cutlim)) + overflow = 1; + else + { + i *= (unsigned long long) base; + i += c; + } + } + + /* Check if anything actually happened. */ + if (s == save) + goto noconv; + + /* Store in ENDPTR the address of one character + past the last character we converted. */ + if (endptr != NULL) + *endptr = (WCHAR *)s; + + if (overflow) + { + errno = ERANGE; + return ULLONG_MAX; + } + + /* Return the result of the appropriate sign. */ + return negative ? -i : i; + +noconv: + /* We must handle a special case here: the base is 0 or 16 and the + first two characters are '0' and 'x', but the rest are not + hexadecimal digits. This is no error case. We return 0 and + ENDPTR points to the `x`. */ + if (endptr != NULL) + { + if (save - nptr >= 2 && toupperW (save[-1]) == 'X' + && save[-2] == '0') + *endptr = (WCHAR *)&save[-1]; + else + /* There was no number to convert. */ + *endptr = (WCHAR *)nptr; + } + + return 0; +} + + /* format a WCHAR string according to a printf format; helper for vsnprintfW */ static size_t format_string( WCHAR *buffer, size_t len, const char *format, const WCHAR *str, int str_len ) { diff --git a/libs/wine/wine.map b/libs/wine/wine.map index 2159fac852..741ae759de 100644 --- a/libs/wine/wine.map +++ b/libs/wine/wine.map @@ -44,6 +44,7 @@ WINE_1.0 strstrW; strtolW; strtoulW; + strtoullW; struprW; tolowerW; toupperW;