Fixed MsiDatabaseImportA, MsiDatabaseImportW, and
[wine] / dlls / ntdll / wcstring.c
1 /*
2  * NTDLL wide-char functions
3  *
4  * Copyright 2000 Alexandre Julliard
5  * Copyright 2000 Jon Griffiths
6  * Copyright 2003 Thomas Mertes
7  *
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.
12  *
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.
17  *
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  */
22
23 #include "config.h"
24
25 #include <ctype.h>
26 #include <limits.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <stdarg.h>
30 #include <stdio.h>
31
32 #include "windef.h"
33 #include "winbase.h"
34 #include "winreg.h"
35 #include "winternl.h"
36 #include "wine/unicode.h"
37 #include "wine/debug.h"
38
39 WINE_DEFAULT_DEBUG_CHANNEL(ntdll);
40
41
42 /*********************************************************************
43  *           _wcsicmp    (NTDLL.@)
44  */
45 INT __cdecl NTDLL__wcsicmp( LPCWSTR str1, LPCWSTR str2 )
46 {
47     return strcmpiW( str1, str2 );
48 }
49
50
51 /*********************************************************************
52  *           _wcslwr    (NTDLL.@)
53  */
54 LPWSTR __cdecl NTDLL__wcslwr( LPWSTR str )
55 {
56     return strlwrW( str );
57 }
58
59
60 /*********************************************************************
61  *           _wcsnicmp    (NTDLL.@)
62  */
63 INT __cdecl NTDLL__wcsnicmp( LPCWSTR str1, LPCWSTR str2, INT n )
64 {
65     return strncmpiW( str1, str2, n );
66 }
67
68
69 /*********************************************************************
70  *           _wcsupr    (NTDLL.@)
71  */
72 LPWSTR __cdecl NTDLL__wcsupr( LPWSTR str )
73 {
74     return struprW( str );
75 }
76
77
78 /*********************************************************************
79  *           towlower    (NTDLL.@)
80  */
81 WCHAR __cdecl NTDLL_towlower( WCHAR ch )
82 {
83     return tolowerW(ch);
84 }
85
86
87 /*********************************************************************
88  *           towupper    (NTDLL.@)
89  */
90 WCHAR __cdecl NTDLL_towupper( WCHAR ch )
91 {
92     return toupperW(ch);
93 }
94
95
96 /***********************************************************************
97  *           wcscat    (NTDLL.@)
98  */
99 LPWSTR __cdecl NTDLL_wcscat( LPWSTR dst, LPCWSTR src )
100 {
101     return strcatW( dst, src );
102 }
103
104
105 /*********************************************************************
106  *           wcschr    (NTDLL.@)
107  */
108 LPWSTR __cdecl NTDLL_wcschr( LPCWSTR str, WCHAR ch )
109 {
110     return strchrW( str, ch );
111 }
112
113
114 /*********************************************************************
115  *           wcscmp    (NTDLL.@)
116  */
117 INT __cdecl NTDLL_wcscmp( LPCWSTR str1, LPCWSTR str2 )
118 {
119     return strcmpW( str1, str2 );
120 }
121
122
123 /***********************************************************************
124  *           wcscpy    (NTDLL.@)
125  */
126 LPWSTR __cdecl NTDLL_wcscpy( LPWSTR dst, LPCWSTR src )
127 {
128     return strcpyW( dst, src );
129 }
130
131
132 /*********************************************************************
133  *           wcscspn    (NTDLL.@)
134  */
135 INT __cdecl NTDLL_wcscspn( LPCWSTR str, LPCWSTR reject )
136 {
137     LPCWSTR start = str;
138     while (*str)
139     {
140         LPCWSTR p = reject;
141         while (*p && (*p != *str)) p++;
142         if (*p) break;
143         str++;
144     }
145     return str - start;
146 }
147
148
149 /***********************************************************************
150  *           wcslen    (NTDLL.@)
151  */
152 INT __cdecl NTDLL_wcslen( LPCWSTR str )
153 {
154     return strlenW( str );
155 }
156
157
158 /*********************************************************************
159  *           wcsncat    (NTDLL.@)
160  */
161 LPWSTR __cdecl NTDLL_wcsncat( LPWSTR s1, LPCWSTR s2, INT n )
162 {
163     LPWSTR ret = s1;
164     while (*s1) s1++;
165     while (n-- > 0) if (!(*s1++ = *s2++)) return ret;
166     *s1 = 0;
167     return ret;
168 }
169
170
171 /*********************************************************************
172  *           wcsncmp    (NTDLL.@)
173  */
174 INT __cdecl NTDLL_wcsncmp( LPCWSTR str1, LPCWSTR str2, INT n )
175 {
176     return strncmpW( str1, str2, n );
177 }
178
179
180 /*********************************************************************
181  *           wcsncpy    (NTDLL.@)
182  */
183 LPWSTR __cdecl NTDLL_wcsncpy( LPWSTR s1, LPCWSTR s2, INT n )
184 {
185     return strncpyW( s1, s2, n );
186 }
187
188
189 /*********************************************************************
190  *           wcspbrk    (NTDLL.@)
191  */
192 LPWSTR __cdecl NTDLL_wcspbrk( LPCWSTR str, LPCWSTR accept )
193 {
194     LPCWSTR p;
195     while (*str)
196     {
197         for (p = accept; *p; p++) if (*p == *str) return (LPWSTR)str;
198         str++;
199     }
200     return NULL;
201 }
202
203
204 /*********************************************************************
205  *           wcsrchr    (NTDLL.@)
206  */
207 LPWSTR __cdecl NTDLL_wcsrchr( LPWSTR str, WCHAR ch )
208 {
209     LPWSTR last = NULL;
210     while (*str)
211     {
212         if (*str == ch) last = str;
213         str++;
214     }
215     return last;
216 }
217
218
219 /*********************************************************************
220  *           wcsspn    (NTDLL.@)
221  */
222 INT __cdecl NTDLL_wcsspn( LPCWSTR str, LPCWSTR accept )
223 {
224     LPCWSTR start = str;
225     while (*str)
226     {
227         LPCWSTR p = accept;
228         while (*p && (*p != *str)) p++;
229         if (!*p) break;
230         str++;
231     }
232     return str - start;
233 }
234
235
236 /*********************************************************************
237  *           wcsstr    (NTDLL.@)
238  */
239 LPWSTR __cdecl NTDLL_wcsstr( LPCWSTR str, LPCWSTR sub )
240 {
241     return strstrW( str, sub );
242 }
243
244
245 /*********************************************************************
246  *           wcstok    (NTDLL.@)
247  */
248 LPWSTR __cdecl NTDLL_wcstok( LPWSTR str, LPCWSTR delim )
249 {
250     static LPWSTR next = NULL;
251     LPWSTR ret;
252
253     if (!str)
254         if (!(str = next)) return NULL;
255
256     while (*str && NTDLL_wcschr( delim, *str )) str++;
257     if (!*str) return NULL;
258     ret = str++;
259     while (*str && !NTDLL_wcschr( delim, *str )) str++;
260     if (*str) *str++ = 0;
261     next = str;
262     return ret;
263 }
264
265
266 /*********************************************************************
267  *           wcstombs    (NTDLL.@)
268  */
269 INT __cdecl NTDLL_wcstombs( LPSTR dst, LPCWSTR src, INT n )
270 {
271     DWORD len;
272
273     if (!dst)
274     {
275         RtlUnicodeToMultiByteSize( &len, src, strlenW(src)*sizeof(WCHAR) );
276         return len;
277     }
278     else
279     {
280         if (n <= 0) return 0;
281         RtlUnicodeToMultiByteN( dst, n, &len, src, strlenW(src)*sizeof(WCHAR) );
282         if (len < n) dst[len] = 0;
283     }
284     return len;
285 }
286
287
288 /*********************************************************************
289  *           mbstowcs    (NTDLL.@)
290  */
291 INT __cdecl NTDLL_mbstowcs( LPWSTR dst, LPCSTR src, INT n )
292 {
293     DWORD len;
294
295     if (!dst)
296     {
297         RtlMultiByteToUnicodeSize( &len, src, strlen(src) );
298     }
299     else
300     {
301         if (n <= 0) return 0;
302         RtlMultiByteToUnicodeN( dst, n*sizeof(WCHAR), &len, src, strlen(src) );
303         if (len / sizeof(WCHAR) < n) dst[len / sizeof(WCHAR)] = 0;
304     }
305     return len / sizeof(WCHAR);
306 }
307
308
309 /*********************************************************************
310  *                  wcstol  (NTDLL.@)
311  */
312 long __cdecl NTDLL_wcstol(LPCWSTR s,LPWSTR *end,INT base)
313 {
314     return strtolW( s, end, base );
315 }
316
317
318 /*********************************************************************
319  *                  wcstoul  (NTDLL.@)
320  */
321 unsigned long __cdecl NTDLL_wcstoul(LPCWSTR s,LPWSTR *end,INT base)
322 {
323     return strtoulW( s, end, base );
324 }
325
326
327 /*********************************************************************
328  *           iswctype    (NTDLL.@)
329  */
330 INT __cdecl NTDLL_iswctype( WCHAR wc, WCHAR wct )
331 {
332     return (get_char_typeW(wc) & 0xfff) & wct;
333 }
334
335
336 /*********************************************************************
337  *           iswalpha    (NTDLL.@)
338  *
339  * Checks if an unicode char wc is a letter
340  *
341  * RETURNS
342  *  TRUE: The unicode char wc is a letter.
343  *  FALSE: Otherwise
344  */
345 INT __cdecl NTDLL_iswalpha( WCHAR wc )
346 {
347     return isalphaW(wc);
348 }
349
350
351 /*********************************************************************
352  *              iswdigit (NTDLL.@)
353  *
354  * Checks if an unicode char wc is a digit
355  *
356  * RETURNS
357  *  TRUE: The unicode char wc is a digit.
358  *  FALSE: Otherwise
359  */
360 INT __cdecl NTDLL_iswdigit( WCHAR wc )
361 {
362     return isdigitW(wc);
363 }
364
365
366 /*********************************************************************
367  *              iswlower (NTDLL.@)
368  *
369  * Checks if an unicode char wc is a lower case letter
370  *
371  * RETURNS
372  *  TRUE: The unicode char wc is a lower case letter.
373  *  FALSE: Otherwise
374  */
375 INT __cdecl NTDLL_iswlower( WCHAR wc )
376 {
377     return islowerW(wc);
378 }
379
380
381 /*********************************************************************
382  *              iswspace (NTDLL.@)
383  *
384  * Checks if an unicode char wc is a white space character
385  *
386  * RETURNS
387  *  TRUE: The unicode char wc is a white space character.
388  *  FALSE: Otherwise
389  */
390 INT __cdecl NTDLL_iswspace( WCHAR wc )
391 {
392     return isspaceW(wc);
393 }
394
395
396 /*********************************************************************
397  *              iswxdigit (NTDLL.@)
398  *
399  * Checks if an unicode char wc is an extended digit
400  *
401  * RETURNS
402  *  TRUE: The unicode char wc is an extended digit.
403  *  FALSE: Otherwise
404  */
405 INT __cdecl NTDLL_iswxdigit( WCHAR wc )
406 {
407     return isxdigitW(wc);
408 }
409
410
411 /*********************************************************************
412  *      _ultow   (NTDLL.@)
413  *
414  * Converts an unsigned long integer to an unicode string.
415  *
416  * RETURNS
417  *  Always returns str.
418  *
419  * NOTES
420  *  Converts value to a '\0' terminated wstring which is copied to str.
421  *  The maximum length of the copied str is 33 bytes.
422  *  Does not check if radix is in the range of 2 to 36.
423  *  If str is NULL it just returns NULL.
424  */
425 LPWSTR __cdecl _ultow(
426     unsigned long value, /* [I] Value to be converted */
427     LPWSTR str,          /* [O] Destination for the converted value */
428     INT radix)           /* [I] Number base for conversion */
429 {
430     WCHAR buffer[33];
431     PWCHAR pos;
432     WCHAR digit;
433
434     pos = &buffer[32];
435     *pos = '\0';
436
437     do {
438         digit = value % radix;
439         value = value / radix;
440         if (digit < 10) {
441             *--pos = '0' + digit;
442         } else {
443             *--pos = 'a' + digit - 10;
444         } /* if */
445     } while (value != 0L);
446
447     if (str != NULL) {
448         memcpy(str, pos, (&buffer[32] - pos + 1) * sizeof(WCHAR));
449     } /* if */
450     return str;
451 }
452
453
454 /*********************************************************************
455  *      _ltow   (NTDLL.@)
456  *
457  * Converts a long integer to an unicode string.
458  *
459  * RETURNS
460  *  Always returns str.
461  *
462  * NOTES
463  *  Converts value to a '\0' terminated wstring which is copied to str.
464  *  The maximum length of the copied str is 33 bytes. If radix
465  *  is 10 and value is negative, the value is converted with sign.
466  *  Does not check if radix is in the range of 2 to 36.
467  *  If str is NULL it just returns NULL.
468  */
469 LPWSTR __cdecl _ltow(
470     long value, /* [I] Value to be converted */
471     LPWSTR str, /* [O] Destination for the converted value */
472     INT radix)  /* [I] Number base for conversion */
473 {
474     unsigned long val;
475     int negative;
476     WCHAR buffer[33];
477     PWCHAR pos;
478     WCHAR digit;
479
480     if (value < 0 && radix == 10) {
481         negative = 1;
482         val = -value;
483     } else {
484         negative = 0;
485         val = value;
486     } /* if */
487
488     pos = &buffer[32];
489     *pos = '\0';
490
491     do {
492         digit = val % radix;
493         val = val / radix;
494         if (digit < 10) {
495             *--pos = '0' + digit;
496         } else {
497             *--pos = 'a' + digit - 10;
498         } /* if */
499     } while (val != 0L);
500
501     if (negative) {
502         *--pos = '-';
503     } /* if */
504
505     if (str != NULL) {
506         memcpy(str, pos, (&buffer[32] - pos + 1) * sizeof(WCHAR));
507     } /* if */
508     return str;
509 }
510
511
512 /*********************************************************************
513  *      _itow    (NTDLL.@)
514  *
515  * Converts an integer to an unicode string.
516  *
517  * RETURNS
518  *  Always returns str.
519  *
520  * NOTES
521  *  Converts value to a '\0' terminated wstring which is copied to str.
522  *  The maximum length of the copied str is 33 bytes. If radix
523  *  is 10 and value is negative, the value is converted with sign.
524  *  Does not check if radix is in the range of 2 to 36.
525  *  If str is NULL it just returns NULL.
526  *
527  * DIFFERENCES
528  * - The native function crashes when the string is longer than 19 chars.
529  *   This function does not have this bug.
530  */
531 LPWSTR __cdecl _itow(
532     int value,  /* [I] Value to be converted */
533     LPWSTR str, /* [O] Destination for the converted value */
534     INT radix)  /* [I] Number base for conversion */
535 {
536     return _ltow(value, str, radix);
537 }
538
539
540 /*********************************************************************
541  *      _ui64tow   (NTDLL.@)
542  *
543  * Converts a large unsigned integer to an unicode string.
544  *
545  * RETURNS
546  *  Always returns str.
547  *
548  * NOTES
549  *  Converts value to a '\0' terminated wstring which is copied to str.
550  *  The maximum length of the copied str is 33 bytes.
551  *  Does not check if radix is in the range of 2 to 36.
552  *  If str is NULL it just returns NULL.
553  *
554  * DIFFERENCES
555  * - This function does not exist in the native DLL (but in msvcrt).
556  *   But since the maintenance of all these functions is better done
557  *   in one place we implement it here.
558  */
559 LPWSTR __cdecl _ui64tow(
560     ULONGLONG value, /* [I] Value to be converted */
561     LPWSTR str,      /* [O] Destination for the converted value */
562     INT radix)       /* [I] Number base for conversion */
563 {
564     WCHAR buffer[65];
565     PWCHAR pos;
566     WCHAR digit;
567
568     pos = &buffer[64];
569     *pos = '\0';
570
571     do {
572         digit = value % radix;
573         value = value / radix;
574         if (digit < 10) {
575             *--pos = '0' + digit;
576         } else {
577             *--pos = 'a' + digit - 10;
578         } /* if */
579     } while (value != 0L);
580
581     if (str != NULL) {
582         memcpy(str, pos, (&buffer[64] - pos + 1) * sizeof(WCHAR));
583     } /* if */
584     return str;
585 }
586
587
588 /*********************************************************************
589  *      _i64tow   (NTDLL.@)
590  *
591  * Converts a large integer to an unicode string.
592  *
593  * RETURNS
594  *  Always returns str.
595  *
596  * NOTES
597  *  Converts value to a '\0' terminated wstring which is copied to str.
598  *  The maximum length of the copied str is 33 bytes. If radix
599  *  is 10 and value is negative, the value is converted with sign.
600  *  Does not check if radix is in the range of 2 to 36.
601  *  If str is NULL it just returns NULL.
602  *
603  * DIFFERENCES
604  * - The native DLL converts negative values (for base 10) wrong:
605  *                     -1 is converted to -18446744073709551615
606  *                     -2 is converted to -18446744073709551614
607  *   -9223372036854775807 is converted to  -9223372036854775809
608  *   -9223372036854775808 is converted to  -9223372036854775808
609  *   The native msvcrt _i64tow function and our ntdll function do
610  *   not have this bug.
611  */
612 LPWSTR __cdecl _i64tow(
613     LONGLONG value, /* [I] Value to be converted */
614     LPWSTR str,     /* [O] Destination for the converted value */
615     INT radix)      /* [I] Number base for conversion */
616 {
617     ULONGLONG val;
618     int negative;
619     WCHAR buffer[65];
620     PWCHAR pos;
621     WCHAR digit;
622
623     if (value < 0 && radix == 10) {
624         negative = 1;
625         val = -value;
626     } else {
627         negative = 0;
628         val = value;
629     } /* if */
630
631     pos = &buffer[64];
632     *pos = '\0';
633
634     do {
635         digit = val % radix;
636         val = val / radix;
637         if (digit < 10) {
638             *--pos = '0' + digit;
639         } else {
640             *--pos = 'a' + digit - 10;
641         } /* if */
642     } while (val != 0L);
643
644     if (negative) {
645         *--pos = '-';
646     } /* if */
647
648     if (str != NULL) {
649         memcpy(str, pos, (&buffer[64] - pos + 1) * sizeof(WCHAR));
650     } /* if */
651     return str;
652 }
653
654
655 /*********************************************************************
656  *      _wtol    (NTDLL.@)
657  *
658  * Converts an unicode string to a long integer.
659  *
660  * PARAMS
661  *  str [I] Wstring to be converted
662  *
663  * RETURNS
664  *  On success it returns the integer value otherwise it returns 0.
665  *
666  * NOTES
667  *  Accepts: {whitespace} [+|-] {digits}
668  *  No check is made for value overflow, only the lower 32 bits are assigned.
669  *  If str is NULL it crashes, as the native function does.
670  */
671 LONG __cdecl _wtol( LPCWSTR str )
672 {
673     ULONG RunningTotal = 0;
674     char bMinus = 0;
675
676     while (isspaceW(*str)) {
677         str++;
678     } /* while */
679
680     if (*str == '+') {
681         str++;
682     } else if (*str == '-') {
683         bMinus = 1;
684         str++;
685     } /* if */
686
687     while (*str >= '0' && *str <= '9') {
688         RunningTotal = RunningTotal * 10 + *str - '0';
689         str++;
690     } /* while */
691
692     return bMinus ? -RunningTotal : RunningTotal;
693 }
694
695
696 /*********************************************************************
697  *      _wtoi    (NTDLL.@)
698  *
699  * Converts an unicode string to an integer.
700  *
701  * PARAMS
702  *  str [I] Wstring to be converted
703  *
704  * RETURNS
705  *  On success it returns the integer value otherwise it returns 0.
706  *
707  * NOTES
708  *  Accepts: {whitespace} [+|-] {digits}
709  *  No check is made for value overflow, only the lower 32 bits are assigned.
710  *  If str is NULL it crashes, as the native function does.
711  */
712 int __cdecl _wtoi( LPCWSTR str )
713 {
714     return _wtol(str);
715 }
716
717
718 /*********************************************************************
719  *      _wtoi64   (NTDLL.@)
720  *
721  * Converts an unicode string to a large integer.
722  *
723  * PARAMS
724  *  str [I] Wstring to be converted
725  *
726  * RETURNS
727  *  On success it returns the integer value otherwise it returns 0.
728  *
729  * NOTES
730  *  Accepts: {whitespace} [+|-] {digits}
731  *  No check is made for value overflow, only the lower 64 bits are assigned.
732  *  If str is NULL it crashes, as the native function does.
733  */
734 LONGLONG  __cdecl _wtoi64( LPCWSTR str )
735 {
736     ULONGLONG RunningTotal = 0;
737     char bMinus = 0;
738
739     while (isspaceW(*str)) {
740         str++;
741     } /* while */
742
743     if (*str == '+') {
744         str++;
745     } else if (*str == '-') {
746         bMinus = 1;
747         str++;
748     } /* if */
749
750     while (*str >= '0' && *str <= '9') {
751         RunningTotal = RunningTotal * 10 + *str - '0';
752         str++;
753     } /* while */
754
755     return bMinus ? -RunningTotal : RunningTotal;
756 }
757
758
759 /***********************************************************************
760  *        _snwprintf (NTDLL.@)
761  */
762 int __cdecl _snwprintf(WCHAR *str, unsigned int len, const WCHAR *format, ...)
763 {
764   int retval;
765   va_list valist;
766   va_start(valist, format);
767   retval = vsnprintfW(str, len, format, valist);
768   va_end(valist);
769   return retval;
770 }
771
772
773 /***********************************************************************
774  *        swprintf (NTDLL.@)
775  */
776 int __cdecl NTDLL_swprintf(WCHAR *str, const WCHAR *format, ...)
777 {
778   int retval;
779   va_list valist;
780   va_start(valist, format);
781   retval = vsnprintfW(str, INT_MAX, format, valist);
782   va_end(valist);
783   return retval;
784 }