2 * NTDLL wide-char functions
4 * Copyright 2000 Alexandre Julliard
5 * Copyright 2000 Jon Griffiths
6 * Copyright 2003 Thomas Mertes
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
35 #include "ntdll_misc.h"
37 static const unsigned short wctypes
[256] =
40 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
41 0x0020, 0x0068, 0x0028, 0x0028, 0x0028, 0x0028, 0x0020, 0x0020,
43 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
44 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
46 0x0048, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010,
47 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010,
49 0x0084, 0x0084, 0x0084, 0x0084, 0x0084, 0x0084, 0x0084, 0x0084,
50 0x0084, 0x0084, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010,
52 0x0010, 0x0181, 0x0181, 0x0181, 0x0181, 0x0181, 0x0181, 0x0101,
53 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101,
55 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101,
56 0x0101, 0x0101, 0x0101, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010,
58 0x0010, 0x0182, 0x0182, 0x0182, 0x0182, 0x0182, 0x0182, 0x0102,
59 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102,
61 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102,
62 0x0102, 0x0102, 0x0102, 0x0010, 0x0010, 0x0010, 0x0010, 0x0020,
64 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
65 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
67 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
68 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
70 0x0048, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010,
71 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010,
73 0x0010, 0x0010, 0x0014, 0x0014, 0x0010, 0x0010, 0x0010, 0x0010,
74 0x0010, 0x0014, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010,
76 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101,
77 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101,
79 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0010,
80 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0102,
82 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102,
83 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102,
85 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0010,
86 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102
90 /*********************************************************************
93 int __cdecl
NTDLL__wcsicmp( LPCWSTR str1
, LPCWSTR str2
)
97 WCHAR ch1
= (*str1
>= 'A' && *str1
<= 'Z') ? *str1
+ 32 : *str1
;
98 WCHAR ch2
= (*str2
>= 'A' && *str2
<= 'Z') ? *str2
+ 32 : *str2
;
99 if (ch1
!= ch2
|| !*str1
) return ch1
- ch2
;
106 /*********************************************************************
109 LPWSTR __cdecl
NTDLL__wcslwr( LPWSTR str
)
116 if (ch
>= 'A' && ch
<= 'Z') ch
+= 32;
123 /*********************************************************************
124 * _wcsnicmp (NTDLL.@)
126 int __cdecl
NTDLL__wcsnicmp( LPCWSTR str1
, LPCWSTR str2
, size_t n
)
129 for ( ; n
> 0; n
--, str1
++, str2
++)
131 WCHAR ch1
= (*str1
>= 'A' && *str1
<= 'Z') ? *str1
+ 32 : *str1
;
132 WCHAR ch2
= (*str2
>= 'A' && *str2
<= 'Z') ? *str2
+ 32 : *str2
;
133 if ((ret
= ch1
- ch2
) || !*str1
) break;
139 /*********************************************************************
142 LPWSTR __cdecl
NTDLL__wcsupr( LPWSTR str
)
149 if (ch
>= 'a' && ch
<= 'z') ch
-= 32;
156 /***********************************************************************
159 LPWSTR __cdecl
NTDLL_wcscpy( LPWSTR dst
, LPCWSTR src
)
162 while ((*p
++ = *src
++));
167 /***********************************************************************
170 size_t __cdecl
NTDLL_wcslen( LPCWSTR str
)
172 const WCHAR
*s
= str
;
178 /***********************************************************************
181 LPWSTR __cdecl
NTDLL_wcscat( LPWSTR dst
, LPCWSTR src
)
183 NTDLL_wcscpy( dst
+ NTDLL_wcslen(dst
), src
);
188 /*********************************************************************
191 LPWSTR __cdecl
NTDLL_wcschr( LPCWSTR str
, WCHAR ch
)
193 do { if (*str
== ch
) return (WCHAR
*)(ULONG_PTR
)str
; } while (*str
++);
198 /*********************************************************************
201 int __cdecl
NTDLL_wcscmp( LPCWSTR str1
, LPCWSTR str2
)
203 while (*str1
&& (*str1
== *str2
)) { str1
++; str2
++; }
204 return *str1
- *str2
;
208 /*********************************************************************
211 size_t __cdecl
NTDLL_wcscspn( LPCWSTR str
, LPCWSTR reject
)
214 for (ptr
= str
; *ptr
; ptr
++) if (NTDLL_wcschr( reject
, *ptr
)) break;
219 /*********************************************************************
222 LPWSTR __cdecl
NTDLL_wcsncat( LPWSTR s1
, LPCWSTR s2
, size_t n
)
226 while (n
-- > 0) if (!(*s1
++ = *s2
++)) return ret
;
232 /*********************************************************************
235 int __cdecl
NTDLL_wcsncmp( LPCWSTR str1
, LPCWSTR str2
, size_t n
)
237 if (n
<= 0) return 0;
238 while ((--n
> 0) && *str1
&& (*str1
== *str2
)) { str1
++; str2
++; }
239 return *str1
- *str2
;
243 /*********************************************************************
246 LPWSTR __cdecl
NTDLL_wcsncpy( LPWSTR s1
, LPCWSTR s2
, size_t n
)
249 while (n
-- > 0) if (!(*s1
++ = *s2
++)) break;
250 while (n
-- > 0) *s1
++ = 0;
255 /*********************************************************************
258 LPWSTR __cdecl
NTDLL_wcspbrk( LPCWSTR str
, LPCWSTR accept
)
260 for ( ; *str
; str
++) if (NTDLL_wcschr( accept
, *str
)) return (WCHAR
*)(ULONG_PTR
)str
;
265 /*********************************************************************
268 LPWSTR __cdecl
NTDLL_wcsrchr( LPCWSTR str
, WCHAR ch
)
271 do { if (*str
== ch
) ret
= (WCHAR
*)(ULONG_PTR
)str
; } while (*str
++);
276 /*********************************************************************
279 size_t __cdecl
NTDLL_wcsspn( LPCWSTR str
, LPCWSTR accept
)
282 for (ptr
= str
; *ptr
; ptr
++) if (!NTDLL_wcschr( accept
, *ptr
)) break;
287 /*********************************************************************
290 LPWSTR __cdecl
NTDLL_wcsstr( LPCWSTR str
, LPCWSTR sub
)
294 const WCHAR
*p1
= str
, *p2
= sub
;
295 while (*p1
&& *p2
&& *p1
== *p2
) { p1
++; p2
++; }
296 if (!*p2
) return (WCHAR
*)str
;
303 /*********************************************************************
306 LPWSTR __cdecl
NTDLL_wcstok( LPWSTR str
, LPCWSTR delim
)
308 static LPWSTR next
= NULL
;
312 if (!(str
= next
)) return NULL
;
314 while (*str
&& NTDLL_wcschr( delim
, *str
)) str
++;
315 if (!*str
) return NULL
;
317 while (*str
&& !NTDLL_wcschr( delim
, *str
)) str
++;
318 if (*str
) *str
++ = 0;
324 /*********************************************************************
327 INT __cdecl
NTDLL_wcstombs( LPSTR dst
, LPCWSTR src
, INT n
)
333 RtlUnicodeToMultiByteSize( &len
, src
, NTDLL_wcslen(src
) * sizeof(WCHAR
) );
338 if (n
<= 0) return 0;
339 RtlUnicodeToMultiByteN( dst
, n
, &len
, src
, NTDLL_wcslen(src
) * sizeof(WCHAR
) );
340 if (len
< n
) dst
[len
] = 0;
346 /*********************************************************************
349 INT __cdecl
NTDLL_mbstowcs( LPWSTR dst
, LPCSTR src
, INT n
)
355 RtlMultiByteToUnicodeSize( &len
, src
, strlen(src
) );
359 if (n
<= 0) return 0;
360 RtlMultiByteToUnicodeN( dst
, n
*sizeof(WCHAR
), &len
, src
, strlen(src
) );
361 if (len
/ sizeof(WCHAR
) < n
) dst
[len
/ sizeof(WCHAR
)] = 0;
363 return len
/ sizeof(WCHAR
);
367 /*********************************************************************
370 INT __cdecl
NTDLL_iswctype( WCHAR wc
, unsigned short type
)
372 if (wc
>= 256) return 0;
373 return wctypes
[wc
] & type
;
377 /*********************************************************************
380 INT __cdecl
NTDLL_iswalpha( WCHAR wc
)
382 if (wc
>= 256) return 0;
383 return wctypes
[wc
] & (C1_ALPHA
| C1_UPPER
| C1_LOWER
);
387 /*********************************************************************
390 * Checks if a unicode char wc is a digit
393 * TRUE: The unicode char wc is a digit.
396 INT __cdecl
NTDLL_iswdigit( WCHAR wc
)
398 if (wc
>= 256) return 0;
399 return wctypes
[wc
] & C1_DIGIT
;
403 /*********************************************************************
406 * Checks if a unicode char wc is a lower case letter
409 * TRUE: The unicode char wc is a lower case letter.
412 INT __cdecl
NTDLL_iswlower( WCHAR wc
)
414 if (wc
>= 256) return 0;
415 return wctypes
[wc
] & C1_LOWER
;
419 /*********************************************************************
422 * Checks if a unicode char wc is a white space character
425 * TRUE: The unicode char wc is a white space character.
428 INT __cdecl
NTDLL_iswspace( WCHAR wc
)
430 if (wc
>= 256) return 0;
431 return wctypes
[wc
] & C1_SPACE
;
435 /*********************************************************************
436 * iswxdigit (NTDLL.@)
438 * Checks if a unicode char wc is an extended digit
441 * TRUE: The unicode char wc is an extended digit.
444 INT __cdecl
NTDLL_iswxdigit( WCHAR wc
)
446 if (wc
>= 256) return 0;
447 return wctypes
[wc
] & C1_XDIGIT
;
451 static int wctoint( WCHAR c
)
453 /* NOTE: MAP_FOLDDIGITS supports too many things. */
454 /* Unicode points that contain digits 0-9; keep this sorted! */
455 static const WCHAR zeros
[] =
457 0x0660, 0x06f0, 0x0966, 0x09e6, 0x0a66, 0x0ae6, 0x0b66, 0x0c66, 0x0ce6,
458 0x0d66, 0x0e50, 0x0ed0, 0x0f20, 0x1040, 0x17e0, 0x1810, 0xff10
462 if ('0' <= c
&& c
<= '9') return c
- '0';
463 if ('A' <= c
&& c
<= 'Z') return c
- 'A' + 10;
464 if ('a' <= c
&& c
<= 'z') return c
- 'a' + 10;
465 for (i
= 0; i
< ARRAY_SIZE(zeros
) && c
>= zeros
[i
]; i
++)
466 if (zeros
[i
] <= c
&& c
<= zeros
[i
] + 9) return c
- zeros
[i
];
471 /*********************************************************************
474 LONG __cdecl
NTDLL_wcstol(LPCWSTR s
, LPWSTR
*end
, INT base
)
476 BOOL negative
= FALSE
, empty
= TRUE
;
479 if (base
< 0 || base
== 1 || base
> 36) return 0;
480 if (end
) *end
= (WCHAR
*)s
;
481 while (NTDLL_iswspace(*s
)) s
++;
488 else if (*s
== '+') s
++;
490 if ((base
== 0 || base
== 16) && !wctoint( *s
) && (s
[1] == 'x' || s
[1] == 'X'))
495 if (base
== 0) base
= wctoint( *s
) ? 10 : 8;
499 int v
= wctoint( *s
);
500 if (v
< 0 || v
>= base
) break;
501 if (negative
) v
= -v
;
505 if (!negative
&& (ret
> MAXLONG
/ base
|| ret
* base
> MAXLONG
- v
))
507 else if (negative
&& (ret
< (LONG
)MINLONG
/ base
|| ret
* base
< (LONG
)(MINLONG
- v
)))
510 ret
= ret
* base
+ v
;
513 if (end
&& !empty
) *end
= (WCHAR
*)s
;
518 /*********************************************************************
521 ULONG __cdecl
NTDLL_wcstoul(LPCWSTR s
, LPWSTR
*end
, INT base
)
523 BOOL negative
= FALSE
, empty
= TRUE
;
526 if (base
< 0 || base
== 1 || base
> 36) return 0;
527 if (end
) *end
= (WCHAR
*)s
;
528 while (NTDLL_iswspace(*s
)) s
++;
535 else if (*s
== '+') s
++;
537 if ((base
== 0 || base
== 16) && !wctoint( *s
) && (s
[1] == 'x' || s
[1] == 'X'))
542 if (base
== 0) base
= wctoint( *s
) ? 10 : 8;
546 int v
= wctoint( *s
);
547 if (v
< 0 || v
>= base
) break;
551 if (ret
> MAXDWORD
/ base
|| ret
* base
> MAXDWORD
- v
)
554 ret
= ret
* base
+ v
;
557 if (end
&& !empty
) *end
= (WCHAR
*)s
;
558 return negative
? -ret
: ret
;
562 /*********************************************************************
565 * Converts an unsigned long integer to a unicode string.
568 * Always returns str.
571 * Converts value to a '\0' terminated wstring which is copied to str.
572 * The maximum length of the copied str is 33 bytes.
573 * Does not check if radix is in the range of 2 to 36.
574 * If str is NULL it just returns NULL.
576 LPWSTR __cdecl
_ultow(
577 ULONG value
, /* [I] Value to be converted */
578 LPWSTR str
, /* [O] Destination for the converted value */
579 INT radix
) /* [I] Number base for conversion */
589 digit
= value
% radix
;
590 value
= value
/ radix
;
592 *--pos
= '0' + digit
;
594 *--pos
= 'a' + digit
- 10;
596 } while (value
!= 0L);
599 memcpy(str
, pos
, (&buffer
[32] - pos
+ 1) * sizeof(WCHAR
));
605 /*********************************************************************
608 * Converts a long integer to a unicode string.
611 * Always returns str.
614 * Converts value to a '\0' terminated wstring which is copied to str.
615 * The maximum length of the copied str is 33 bytes. If radix
616 * is 10 and value is negative, the value is converted with sign.
617 * Does not check if radix is in the range of 2 to 36.
618 * If str is NULL it just returns NULL.
620 LPWSTR __cdecl
_ltow(
621 LONG value
, /* [I] Value to be converted */
622 LPWSTR str
, /* [O] Destination for the converted value */
623 INT radix
) /* [I] Number base for conversion */
631 if (value
< 0 && radix
== 10) {
646 *--pos
= '0' + digit
;
648 *--pos
= 'a' + digit
- 10;
657 memcpy(str
, pos
, (&buffer
[32] - pos
+ 1) * sizeof(WCHAR
));
663 /*********************************************************************
666 * Converts an integer to a unicode string.
669 * Always returns str.
672 * Converts value to a '\0' terminated wstring which is copied to str.
673 * The maximum length of the copied str is 33 bytes. If radix
674 * is 10 and value is negative, the value is converted with sign.
675 * Does not check if radix is in the range of 2 to 36.
676 * If str is NULL it just returns NULL.
679 * - The native function crashes when the string is longer than 19 chars.
680 * This function does not have this bug.
682 LPWSTR __cdecl
_itow(
683 int value
, /* [I] Value to be converted */
684 LPWSTR str
, /* [O] Destination for the converted value */
685 INT radix
) /* [I] Number base for conversion */
687 return _ltow(value
, str
, radix
);
691 /*********************************************************************
694 * Converts a large unsigned integer to a unicode string.
697 * Always returns str.
700 * Converts value to a '\0' terminated wstring which is copied to str.
701 * The maximum length of the copied str is 33 bytes.
702 * Does not check if radix is in the range of 2 to 36.
703 * If str is NULL it just returns NULL.
706 * - This function does not exist in the native DLL (but in msvcrt).
707 * But since the maintenance of all these functions is better done
708 * in one place we implement it here.
710 LPWSTR __cdecl
_ui64tow(
711 ULONGLONG value
, /* [I] Value to be converted */
712 LPWSTR str
, /* [O] Destination for the converted value */
713 INT radix
) /* [I] Number base for conversion */
723 digit
= value
% radix
;
724 value
= value
/ radix
;
726 *--pos
= '0' + digit
;
728 *--pos
= 'a' + digit
- 10;
730 } while (value
!= 0L);
733 memcpy(str
, pos
, (&buffer
[64] - pos
+ 1) * sizeof(WCHAR
));
739 /*********************************************************************
742 * Converts a large integer to a unicode string.
745 * Always returns str.
748 * Converts value to a '\0' terminated wstring which is copied to str.
749 * The maximum length of the copied str is 33 bytes. If radix
750 * is 10 and value is negative, the value is converted with sign.
751 * Does not check if radix is in the range of 2 to 36.
752 * If str is NULL it just returns NULL.
755 * - The native DLL converts negative values (for base 10) wrong:
756 * -1 is converted to -18446744073709551615
757 * -2 is converted to -18446744073709551614
758 * -9223372036854775807 is converted to -9223372036854775809
759 * -9223372036854775808 is converted to -9223372036854775808
760 * The native msvcrt _i64tow function and our ntdll function do
763 LPWSTR __cdecl
_i64tow(
764 LONGLONG value
, /* [I] Value to be converted */
765 LPWSTR str
, /* [O] Destination for the converted value */
766 INT radix
) /* [I] Number base for conversion */
774 if (value
< 0 && radix
== 10) {
789 *--pos
= '0' + digit
;
791 *--pos
= 'a' + digit
- 10;
800 memcpy(str
, pos
, (&buffer
[64] - pos
+ 1) * sizeof(WCHAR
));
806 /*********************************************************************
809 * Converts a unicode string to a long integer.
812 * str [I] Wstring to be converted
815 * On success it returns the integer value otherwise it returns 0.
818 * Accepts: {whitespace} [+|-] {digits}
819 * No check is made for value overflow, only the lower 32 bits are assigned.
820 * If str is NULL it crashes, as the native function does.
822 LONG __cdecl
_wtol( LPCWSTR str
)
824 ULONG RunningTotal
= 0;
827 while (NTDLL_iswspace(*str
)) str
++;
831 } else if (*str
== '-') {
836 while (*str
>= '0' && *str
<= '9') {
837 RunningTotal
= RunningTotal
* 10 + *str
- '0';
841 return bMinus
? -RunningTotal
: RunningTotal
;
845 /*********************************************************************
848 * Converts a unicode string to an integer.
851 * str [I] Wstring to be converted
854 * On success it returns the integer value otherwise it returns 0.
857 * Accepts: {whitespace} [+|-] {digits}
858 * No check is made for value overflow, only the lower 32 bits are assigned.
859 * If str is NULL it crashes, as the native function does.
861 int __cdecl
_wtoi( LPCWSTR str
)
867 /*********************************************************************
870 * Converts a unicode string to a large integer.
873 * str [I] Wstring to be converted
876 * On success it returns the integer value otherwise it returns 0.
879 * Accepts: {whitespace} [+|-] {digits}
880 * No check is made for value overflow, only the lower 64 bits are assigned.
881 * If str is NULL it crashes, as the native function does.
883 LONGLONG __cdecl
_wtoi64( LPCWSTR str
)
885 ULONGLONG RunningTotal
= 0;
888 while (NTDLL_iswspace(*str
)) str
++;
892 } else if (*str
== '-') {
897 while (*str
>= '0' && *str
<= '9') {
898 RunningTotal
= RunningTotal
* 10 + *str
- '0';
902 return bMinus
? -RunningTotal
: RunningTotal
;