Don't use free'd pointer in status control - found by Valgrind.
[wine] / dlls / ntdll / rtlstr.c
1 /*
2  * Rtl string functions
3  *
4  * Copyright (C) 1996-1998 Marcus Meissner
5  * Copyright (C) 2000      Alexandre Julliard
6  * Copyright (C) 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 <assert.h>
26 #include <stdarg.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <ctype.h>
30
31 #include "windef.h"
32 #include "winbase.h"
33 #include "winreg.h"
34 #include "winternl.h"
35 #include "wine/unicode.h"
36 #include "wine/debug.h"
37 #include "ntdll_misc.h"
38
39 WINE_DEFAULT_DEBUG_CHANNEL(ntdll);
40
41 UINT NlsAnsiCodePage = 1252;
42 BYTE NlsMbCodePageTag = 0;
43 BYTE NlsMbOemCodePageTag = 0;
44
45 static const union cptable *ansi_table;
46 static const union cptable *oem_table;
47
48 inline static const union cptable *get_ansi_table(void)
49 {
50     if (!ansi_table) ansi_table = wine_cp_get_table( 1252 );
51     return ansi_table;
52 }
53
54 inline static const union cptable *get_oem_table(void)
55 {
56     if (!oem_table) oem_table = wine_cp_get_table( 437 );
57     return oem_table;
58 }
59
60
61 /**************************************************************************
62  *      __wine_init_codepages   (NTDLL.@)
63  *
64  * Set the code page once kernel32 is loaded. Should be done differently.
65  */
66 void __wine_init_codepages( const union cptable *ansi, const union cptable *oem )
67 {
68     ansi_table = ansi;
69     oem_table = oem;
70     NlsAnsiCodePage = ansi->info.codepage;
71 }
72
73
74 /**************************************************************************
75  *      RtlInitAnsiString   (NTDLL.@)
76  *
77  * Initializes a buffered ansi string.
78  *
79  * RETURNS
80  *  Nothing.
81  *
82  * NOTES
83  *  Assigns source to target->Buffer. The length of source is assigned to
84  *  target->Length and target->MaximumLength. If source is NULL the length
85  *  of source is assumed to be 0.
86  */
87 void WINAPI RtlInitAnsiString(
88     PANSI_STRING target, /* [I/O] Buffered ansi string to be initialized */
89     PCSZ source)         /* [I]   '\0' terminated string used to initialize target */
90 {
91     if ((target->Buffer = (PCHAR) source))
92     {
93         target->Length = strlen(source);
94         target->MaximumLength = target->Length + 1;
95     }
96     else target->Length = target->MaximumLength = 0;
97 }
98
99
100 /**************************************************************************
101  *      RtlInitString   (NTDLL.@)
102  *
103  * Initializes a buffered string.
104  *
105  * RETURNS
106  *  Nothing.
107  *
108  * NOTES
109  *  Assigns source to target->Buffer. The length of source is assigned to
110  *  target->Length and target->MaximumLength. If source is NULL the length
111  *  of source is assumed to be 0.
112  */
113 void WINAPI RtlInitString(
114     PSTRING target, /* [I/O] Buffered string to be initialized */
115     PCSZ source)    /* [I]   '\0' terminated string used to initialize target */
116 {
117     RtlInitAnsiString( target, source );
118 }
119
120
121 /**************************************************************************
122  *      RtlFreeAnsiString   (NTDLL.@)
123  */
124 void WINAPI RtlFreeAnsiString( PSTRING str )
125 {
126     if (str->Buffer) RtlFreeHeap( ntdll_get_process_heap(), 0, str->Buffer );
127 }
128
129
130 /**************************************************************************
131  *      RtlFreeOemString   (NTDLL.@)
132  */
133 void WINAPI RtlFreeOemString( PSTRING str )
134 {
135     RtlFreeAnsiString( str );
136 }
137
138
139 /**************************************************************************
140  *      RtlCopyString   (NTDLL.@)
141  */
142 void WINAPI RtlCopyString( STRING *dst, const STRING *src )
143 {
144     if (src)
145     {
146         unsigned int len = min( src->Length, dst->MaximumLength );
147         memcpy( dst->Buffer, src->Buffer, len );
148         dst->Length = len;
149     }
150     else dst->Length = 0;
151 }
152
153
154 /**************************************************************************
155  *      RtlInitUnicodeString   (NTDLL.@)
156  *
157  * Initializes a buffered unicode string.
158  *
159  * RETURNS
160  *  Nothing.
161  *
162  * NOTES
163  *  Assigns source to target->Buffer. The length of source is assigned to
164  *  target->Length and target->MaximumLength. If source is NULL the length
165  *  of source is assumed to be 0.
166  */
167 void WINAPI RtlInitUnicodeString(
168     PUNICODE_STRING target, /* [I/O] Buffered unicode string to be initialized */
169     PCWSTR source)          /* [I]   '\0' terminated unicode string used to initialize target */
170 {
171     if ((target->Buffer = (PWSTR) source))
172     {
173         target->Length = strlenW(source) * sizeof(WCHAR);
174         target->MaximumLength = target->Length + sizeof(WCHAR);
175     }
176     else target->Length = target->MaximumLength = 0;
177 }
178
179
180 /**************************************************************************
181  *      RtlInitUnicodeStringEx   (NTDLL.@)
182  *
183  * Initializes a buffered unicode string.
184  *
185  * RETURNS
186  *  Success: STATUS_SUCCESS. target is initialized.
187  *  Failure: STATUS_NAME_TOO_LONG, if the source string is larger than 65532 bytes.
188  *
189  * NOTES
190  *  Assigns source to target->Buffer. The length of source is assigned to
191  *  target->Length and target->MaximumLength. If source is NULL the length
192  *  of source is assumed to be 0.
193  */
194 NTSTATUS WINAPI RtlInitUnicodeStringEx(
195     PUNICODE_STRING target, /* [I/O] Buffered unicode string to be initialized */
196     PCWSTR source)          /* [I]   '\0' terminated unicode string used to initialize target */
197 {
198     if (source != NULL) {
199         unsigned int len = strlenW(source) * sizeof(WCHAR);
200
201         if (len > 0xFFFC) {
202             return STATUS_NAME_TOO_LONG;
203         } else {
204             target->Length = len;
205             target->MaximumLength = len + sizeof(WCHAR);
206             target->Buffer = (PWSTR) source;
207         } /* if */
208     } else {
209         target->Length = 0;
210         target->MaximumLength = 0;
211         target->Buffer = NULL;
212     } /* if */
213     return STATUS_SUCCESS;
214 }
215
216
217 /**************************************************************************
218  *      RtlCreateUnicodeString   (NTDLL.@)
219  */
220 BOOLEAN WINAPI RtlCreateUnicodeString( PUNICODE_STRING target, LPCWSTR src )
221 {
222     int len = (strlenW(src) + 1) * sizeof(WCHAR);
223     if (!(target->Buffer = RtlAllocateHeap( ntdll_get_process_heap(), 0, len ))) return FALSE;
224     memcpy( target->Buffer, src, len );
225     target->MaximumLength = len;
226     target->Length = len - sizeof(WCHAR);
227     return TRUE;
228 }
229
230
231 /**************************************************************************
232  *      RtlCreateUnicodeStringFromAsciiz   (NTDLL.@)
233  */
234 BOOLEAN WINAPI RtlCreateUnicodeStringFromAsciiz( PUNICODE_STRING target, LPCSTR src )
235 {
236     STRING ansi;
237     RtlInitAnsiString( &ansi, src );
238     return !RtlAnsiStringToUnicodeString( target, &ansi, TRUE );
239 }
240
241
242 /**************************************************************************
243  *      RtlFreeUnicodeString   (NTDLL.@)
244  */
245 void WINAPI RtlFreeUnicodeString( PUNICODE_STRING str )
246 {
247     if (str->Buffer) RtlFreeHeap( ntdll_get_process_heap(), 0, str->Buffer );
248 }
249
250
251 /**************************************************************************
252  *      RtlCopyUnicodeString   (NTDLL.@)
253  */
254 void WINAPI RtlCopyUnicodeString( UNICODE_STRING *dst, const UNICODE_STRING *src )
255 {
256     if (src)
257     {
258         unsigned int len = min( src->Length, dst->MaximumLength );
259         memcpy( dst->Buffer, src->Buffer, len );
260         dst->Length = len;
261         /* append terminating '\0' if enough space */
262         if (len < dst->MaximumLength) dst->Buffer[len / sizeof(WCHAR)] = 0;
263     }
264     else dst->Length = 0;
265 }
266
267
268 /**************************************************************************
269  *      RtlDuplicateUnicodeString   (NTDLL.@)
270  *
271  * Duplicates an unicode string.
272  *
273  * RETURNS
274  *  Success: STATUS_SUCCESS. destination contains the duplicated unicode string.
275  *  Failure: STATUS_INVALID_PARAMETER, if one of the parameters is illegal.
276  *           STATUS_NO_MEMORY, if the allocation fails.
277  *
278  * NOTES
279  *  For add_nul there are several possible values:
280  *  0 = destination will not be '\0' terminated,
281  *  1 = destination will be '\0' terminated,
282  *  3 = like 1 but for an empty source string produce '\0' terminated empty
283  *     Buffer instead of assigning NULL to the Buffer.
284  *  Other add_nul values are invalid.
285  */
286 NTSTATUS WINAPI RtlDuplicateUnicodeString(
287     int add_nul,                  /* [I] flag */
288     const UNICODE_STRING *source, /* [I] Unicode string to be duplicated */
289     UNICODE_STRING *destination)  /* [O] destination for the duplicated unicode string */
290 {
291     if (source == NULL || destination == NULL ||
292         source->Length > source->MaximumLength ||
293         (source->Length == 0 && source->MaximumLength > 0 && source->Buffer == NULL) ||
294         add_nul == 2 || add_nul >= 4 || add_nul < 0) {
295         return STATUS_INVALID_PARAMETER;
296     } else {
297         if (source->Length == 0 && add_nul != 3) {
298             destination->Length = 0;
299             destination->MaximumLength = 0;
300             destination->Buffer = NULL;
301         } else {
302             unsigned int destination_max_len = source->Length;
303
304             if (add_nul) {
305                 destination_max_len += sizeof(WCHAR);
306             } /* if */
307             destination->Buffer = RtlAllocateHeap(ntdll_get_process_heap(), 0, destination_max_len);
308             if (destination->Buffer == NULL) {
309                 return STATUS_NO_MEMORY;
310             } else {
311                 memcpy(destination->Buffer, source->Buffer, source->Length);
312                 destination->Length = source->Length;
313                 destination->MaximumLength = source->Length;
314                 /* append terminating '\0' if enough space */
315                 if (add_nul) {
316                     destination->MaximumLength = destination_max_len;
317                     destination->Buffer[destination->Length / sizeof(WCHAR)] = 0;
318                 } /* if */
319             } /* if */
320         } /* if */
321     } /* if */
322     return STATUS_SUCCESS;
323 }
324
325
326 /**************************************************************************
327  *      RtlEraseUnicodeString   (NTDLL.@)
328  */
329 void WINAPI RtlEraseUnicodeString( UNICODE_STRING *str )
330 {
331     if (str->Buffer)
332     {
333         memset( str->Buffer, 0, str->MaximumLength );
334         str->Length = 0;
335     }
336 }
337
338
339 /*
340     COMPARISON FUNCTIONS
341 */
342
343
344 /******************************************************************************
345  *      RtlCompareString   (NTDLL.@)
346  */
347 LONG WINAPI RtlCompareString( const STRING *s1, const STRING *s2, BOOLEAN CaseInsensitive )
348 {
349     unsigned int len;
350     LONG ret = 0;
351     LPCSTR p1, p2;
352
353     len = min(s1->Length, s2->Length);
354     p1 = s1->Buffer;
355     p2 = s2->Buffer;
356
357     if (CaseInsensitive)
358     {
359         while (!ret && len--) ret = toupper(*p1++) - toupper(*p2++);
360     }
361     else
362     {
363         while (!ret && len--) ret = *p1++ - *p2++;
364     }
365     if (!ret) ret = s1->Length - s2->Length;
366     return ret;
367 }
368
369
370 /******************************************************************************
371  *      RtlCompareUnicodeString   (NTDLL.@)
372  */
373 LONG WINAPI RtlCompareUnicodeString( const UNICODE_STRING *s1, const UNICODE_STRING *s2,
374                                      BOOLEAN CaseInsensitive )
375 {
376     unsigned int len;
377     LONG ret = 0;
378     LPCWSTR p1, p2;
379
380     len = min(s1->Length, s2->Length) / sizeof(WCHAR);
381     p1 = s1->Buffer;
382     p2 = s2->Buffer;
383
384     if (CaseInsensitive)
385     {
386         while (!ret && len--) ret = toupperW(*p1++) - toupperW(*p2++);
387     }
388     else
389     {
390         while (!ret && len--) ret = *p1++ - *p2++;
391     }
392     if (!ret) ret = s1->Length - s2->Length;
393     return ret;
394 }
395
396
397 /**************************************************************************
398  *      RtlEqualString   (NTDLL.@)
399  *
400  * Determine if two strings are equal.
401  *
402  * PARAMS
403  *  s1              [I] Source string
404  *  s2              [I] String to compare to s1
405  *  CaseInsensitive [I] TRUE = Case insensitive, FALSE = Case sensitive
406  *
407  * RETURNS
408  *  Non-zero if s1 is equal to s2, 0 otherwise.
409  */
410 BOOLEAN WINAPI RtlEqualString( const STRING *s1, const STRING *s2, BOOLEAN CaseInsensitive )
411 {
412     if (s1->Length != s2->Length) return FALSE;
413     return !RtlCompareString( s1, s2, CaseInsensitive );
414 }
415
416
417 /**************************************************************************
418  *      RtlEqualUnicodeString   (NTDLL.@)
419  *
420  * Unicode version of RtlEqualString.
421  */
422 BOOLEAN WINAPI RtlEqualUnicodeString( const UNICODE_STRING *s1, const UNICODE_STRING *s2,
423                                       BOOLEAN CaseInsensitive )
424 {
425     if (s1->Length != s2->Length) return FALSE;
426     return !RtlCompareUnicodeString( s1, s2, CaseInsensitive );
427 }
428
429
430 /**************************************************************************
431  *      RtlPrefixString   (NTDLL.@)
432  *
433  * Determine if one string is a prefix of another.
434  *
435  * PARAMS
436  *  s1          [I] Prefix to look for in s2
437  *  s2          [I] String that may contain s1 as a prefix
438  *  ignore_case [I] TRUE = Case insensitive, FALSE = Case sensitive
439  *
440  * RETURNS
441  *  TRUE if s2 contains s1 as a prefix, FALSE otherwise.
442  */
443 BOOLEAN WINAPI RtlPrefixString( const STRING *s1, const STRING *s2, BOOLEAN ignore_case )
444 {
445     unsigned int i;
446
447     if (s1->Length > s2->Length) return FALSE;
448     if (ignore_case)
449     {
450         for (i = 0; i < s1->Length; i++)
451             if (toupper(s1->Buffer[i]) != toupper(s2->Buffer[i])) return FALSE;
452     }
453     else
454     {
455         for (i = 0; i < s1->Length; i++)
456             if (s1->Buffer[i] != s2->Buffer[i]) return FALSE;
457     }
458     return TRUE;
459 }
460
461
462 /**************************************************************************
463  *      RtlPrefixUnicodeString   (NTDLL.@)
464  *
465  * Unicode version of RtlPrefixString.
466  */
467 BOOLEAN WINAPI RtlPrefixUnicodeString( const UNICODE_STRING *s1,
468                                        const UNICODE_STRING *s2,
469                                        BOOLEAN ignore_case )
470 {
471     unsigned int i;
472
473     if (s1->Length > s2->Length) return FALSE;
474     if (ignore_case)
475     {
476         for (i = 0; i < s1->Length / sizeof(WCHAR); i++)
477             if (toupperW(s1->Buffer[i]) != toupperW(s2->Buffer[i])) return FALSE;
478     }
479     else
480     {
481         for (i = 0; i < s1->Length / sizeof(WCHAR); i++)
482             if (s1->Buffer[i] != s2->Buffer[i]) return FALSE;
483     }
484     return TRUE;
485 }
486
487
488 /**************************************************************************
489  *      RtlEqualComputerName   (NTDLL.@)
490  *
491  * Determine if two computer names are the same.
492  *
493  * PARAMS
494  *  left  [I] First computer name
495  *  right [I] Second computer name
496  *
497  * RETURNS
498  *  0 if the names are equal, non-zero otherwise.
499  *
500  * NOTES
501  *  The comparason is case insensitive.
502  */
503 NTSTATUS WINAPI RtlEqualComputerName(const UNICODE_STRING *left,
504                                      const UNICODE_STRING *right)
505 {
506     NTSTATUS ret;
507     STRING upLeft, upRight;
508
509     if (!(ret = RtlUpcaseUnicodeStringToOemString( &upLeft, left, TRUE )))
510     {
511        if (!(ret = RtlUpcaseUnicodeStringToOemString( &upRight, right, TRUE )))
512        {
513          ret = RtlEqualString( &upLeft, &upRight, FALSE );
514          RtlFreeOemString( &upRight );
515        }
516        RtlFreeOemString( &upLeft );
517     }
518     return ret;
519 }
520
521
522 /**************************************************************************
523  *      RtlEqualDomainName   (NTDLL.@)
524  *
525  * Determine if two domain names are the same.
526  *
527  * PARAMS
528  *  left  [I] First domain name
529  *  right [I] Second domain name
530  *
531  * RETURNS
532  *  0 if the names are equal, non-zero otherwise.
533  *
534  * NOTES
535  *  The comparason is case insensitive.
536  */
537 NTSTATUS WINAPI RtlEqualDomainName(const UNICODE_STRING *left,
538                                    const UNICODE_STRING *right)
539 {
540     return RtlEqualComputerName(left, right);
541 }
542
543
544 /*
545         COPY BETWEEN ANSI_STRING or UNICODE_STRING
546         there is no parameter checking, it just crashes
547 */
548
549
550 /**************************************************************************
551  *      RtlAnsiStringToUnicodeString   (NTDLL.@)
552  *
553  * Converts an ansi string to an unicode string.
554  *
555  * RETURNS
556  *  Success: STATUS_SUCCESS. uni contains the converted string
557  *  Failure: STATUS_BUFFER_OVERFLOW, if doalloc is FALSE and ansi is too small.
558  *           STATUS_NO_MEMORY, if doalloc is TRUE and the allocation fails.
559  *           STATUS_INVALID_PARAMETER_2, if the unicode string would be larger than 65535.
560  *
561  * NOTES
562  *  This function always writes a terminating '\0'.
563  */
564 NTSTATUS WINAPI RtlAnsiStringToUnicodeString(
565     PUNICODE_STRING uni, /* [I/O] Destination for the unicode string */
566     PCANSI_STRING ansi,  /* [I]   Ansi string to be converted */
567     BOOLEAN doalloc)     /* [I]   TRUE=Allocate new buffer for uni, FALSE=Use existing buffer */
568 {
569     DWORD total = RtlAnsiStringToUnicodeSize( ansi );
570
571     if (total > 0xffff) return STATUS_INVALID_PARAMETER_2;
572     uni->Length = total - sizeof(WCHAR);
573     if (doalloc)
574     {
575         uni->MaximumLength = total;
576         if (!(uni->Buffer = RtlAllocateHeap( ntdll_get_process_heap(), 0, total )))
577             return STATUS_NO_MEMORY;
578     }
579     else if (total > uni->MaximumLength) return STATUS_BUFFER_OVERFLOW;
580
581     RtlMultiByteToUnicodeN( uni->Buffer, uni->Length, NULL, ansi->Buffer, ansi->Length );
582     uni->Buffer[uni->Length / sizeof(WCHAR)] = 0;
583     return STATUS_SUCCESS;
584 }
585
586
587 /**************************************************************************
588  *      RtlOemStringToUnicodeString   (NTDLL.@)
589  *
590  * Converts an oem string to an unicode string.
591  *
592  * RETURNS
593  *  Success: STATUS_SUCCESS. uni contains the converted string
594  *  Failure: STATUS_BUFFER_OVERFLOW, if doalloc is FALSE and oem is too small.
595  *           STATUS_NO_MEMORY, if doalloc is TRUE and the allocation fails.
596  *           STATUS_INVALID_PARAMETER_2, if the unicode string would be larger than 65535.
597  *
598  * NOTES
599  *  This function always writes a terminating '\0'.
600  */
601 NTSTATUS WINAPI RtlOemStringToUnicodeString(
602     UNICODE_STRING *uni, /* [I/O] Destination for the unicode string */
603     const STRING *oem,   /* [I]   Oem string to be converted */
604     BOOLEAN doalloc)     /* [I]   TRUE=Allocate new buffer for uni, FALSE=Use existing buffer */
605 {
606     DWORD total = RtlOemStringToUnicodeSize( oem );
607
608     if (total > 0xffff) return STATUS_INVALID_PARAMETER_2;
609     uni->Length = total - sizeof(WCHAR);
610     if (doalloc)
611     {
612         uni->MaximumLength = total;
613         if (!(uni->Buffer = RtlAllocateHeap( ntdll_get_process_heap(), 0, total )))
614             return STATUS_NO_MEMORY;
615     }
616     else if (total > uni->MaximumLength) return STATUS_BUFFER_OVERFLOW;
617
618     RtlOemToUnicodeN( uni->Buffer, uni->Length, NULL, oem->Buffer, oem->Length );
619     uni->Buffer[uni->Length / sizeof(WCHAR)] = 0;
620     return STATUS_SUCCESS;
621 }
622
623
624 /**************************************************************************
625  *      RtlUnicodeStringToAnsiString   (NTDLL.@)
626  *
627  * Converts an unicode string to an ansi string.
628  *
629  * RETURNS
630  *  Success: STATUS_SUCCESS. ansi contains the converted string
631  *  Failure: STATUS_BUFFER_OVERFLOW, if doalloc is FALSE and ansi is too small.
632  *           STATUS_NO_MEMORY, if doalloc is TRUE and the allocation fails.
633  *
634  * NOTES
635  *  This function always writes a terminating '\0'.
636  *  It performs a partial copy if ansi is too small.
637  */
638 NTSTATUS WINAPI RtlUnicodeStringToAnsiString(
639     STRING *ansi,              /* [I/O] Destination for the ansi string */
640     const UNICODE_STRING *uni, /* [I]   Unicode string to be converted */
641     BOOLEAN doalloc)           /* [I]   TRUE=Allocate new buffer for ansi, FALSE=Use existing buffer */
642 {
643     NTSTATUS ret = STATUS_SUCCESS;
644     DWORD len = RtlUnicodeStringToAnsiSize( uni );
645
646     ansi->Length = len - 1;
647     if (doalloc)
648     {
649         ansi->MaximumLength = len;
650         if (!(ansi->Buffer = RtlAllocateHeap( ntdll_get_process_heap(), 0, len )))
651             return STATUS_NO_MEMORY;
652     }
653     else if (ansi->MaximumLength < len)
654     {
655         if (!ansi->MaximumLength) return STATUS_BUFFER_OVERFLOW;
656         ansi->Length = ansi->MaximumLength - 1;
657         ret = STATUS_BUFFER_OVERFLOW;
658     }
659
660     RtlUnicodeToMultiByteN( ansi->Buffer, ansi->Length, NULL, uni->Buffer, uni->Length );
661     ansi->Buffer[ansi->Length] = 0;
662     return ret;
663 }
664
665
666 /**************************************************************************
667  *      RtlUnicodeStringToOemString   (NTDLL.@)
668  *
669  * Converts a Rtl Unicode string to an OEM string.
670  *
671  * PARAMS
672  *  oem     [O] Destination for OEM string
673  *  uni     [I] Source Unicode string
674  *  doalloc [I] TRUE=Allocate new buffer for oem,FALSE=Use existing buffer
675  *
676  * RETURNS
677  *  Success: STATUS_SUCCESS. oem contains the converted string
678  *  Failure: STATUS_BUFFER_OVERFLOW, if doalloc is FALSE and oem is too small.
679  *           STATUS_NO_MEMORY, if doalloc is TRUE and allocation fails.
680  *
681  * NOTES
682  *   If doalloc is TRUE, the length allocated is uni->Length + 1.
683  *   This function always '\0' terminates the string returned.
684  */
685 NTSTATUS WINAPI RtlUnicodeStringToOemString( STRING *oem,
686                                              const UNICODE_STRING *uni,
687                                              BOOLEAN doalloc )
688 {
689     NTSTATUS ret = STATUS_SUCCESS;
690     DWORD len = RtlUnicodeStringToOemSize( uni );
691
692     oem->Length = len - 1;
693     if (doalloc)
694     {
695         oem->MaximumLength = len;
696         if (!(oem->Buffer = RtlAllocateHeap( ntdll_get_process_heap(), 0, len )))
697             return STATUS_NO_MEMORY;
698     }
699     else if (oem->MaximumLength < len)
700     {
701         if (!oem->MaximumLength) return STATUS_BUFFER_OVERFLOW;
702         oem->Length = oem->MaximumLength - 1;
703         ret = STATUS_BUFFER_OVERFLOW;
704     }
705
706     RtlUnicodeToOemN( oem->Buffer, oem->Length, NULL, uni->Buffer, uni->Length );
707     oem->Buffer[oem->Length] = 0;
708     return ret;
709 }
710
711
712 /**************************************************************************
713  *      RtlMultiByteToUnicodeN   (NTDLL.@)
714  *
715  * NOTES
716  *  Performs a partial copy if dst is too small.
717  */
718 NTSTATUS WINAPI RtlMultiByteToUnicodeN( LPWSTR dst, DWORD dstlen, LPDWORD reslen,
719                                         LPCSTR src, DWORD srclen )
720 {
721
722     int ret = wine_cp_mbstowcs( get_ansi_table(), 0, src, srclen, dst, dstlen/sizeof(WCHAR) );
723     if (reslen)
724         *reslen = (ret >= 0) ? ret*sizeof(WCHAR) : dstlen; /* overflow -> we filled up to dstlen */
725     return STATUS_SUCCESS;
726 }
727
728
729 /**************************************************************************
730  *      RtlOemToUnicodeN   (NTDLL.@)
731  */
732 NTSTATUS WINAPI RtlOemToUnicodeN( LPWSTR dst, DWORD dstlen, LPDWORD reslen,
733                                   LPCSTR src, DWORD srclen )
734 {
735     int ret = wine_cp_mbstowcs( get_oem_table(), 0, src, srclen, dst, dstlen/sizeof(WCHAR) );
736     if (reslen)
737         *reslen = (ret >= 0) ? ret*sizeof(WCHAR) : dstlen; /* overflow -> we filled up to dstlen */
738     return STATUS_SUCCESS;
739 }
740
741
742 /**************************************************************************
743  *      RtlUnicodeToMultiByteN   (NTDLL.@)
744  */
745 NTSTATUS WINAPI RtlUnicodeToMultiByteN( LPSTR dst, DWORD dstlen, LPDWORD reslen,
746                                         LPCWSTR src, DWORD srclen )
747 {
748     int ret = wine_cp_wcstombs( get_ansi_table(), 0, src, srclen / sizeof(WCHAR),
749                                 dst, dstlen, NULL, NULL );
750     if (reslen)
751         *reslen = (ret >= 0) ? ret : dstlen; /* overflow -> we filled up to dstlen */
752     return STATUS_SUCCESS;
753 }
754
755
756 /**************************************************************************
757  *      RtlUnicodeToOemN   (NTDLL.@)
758  */
759 NTSTATUS WINAPI RtlUnicodeToOemN( LPSTR dst, DWORD dstlen, LPDWORD reslen,
760                                   LPCWSTR src, DWORD srclen )
761 {
762     int ret = wine_cp_wcstombs( get_oem_table(), 0, src, srclen / sizeof(WCHAR),
763                                 dst, dstlen, NULL, NULL );
764     if (reslen)
765         *reslen = (ret >= 0) ? ret : dstlen; /* overflow -> we filled up to dstlen */
766     return STATUS_SUCCESS;
767 }
768
769
770 /*
771      CASE CONVERSIONS
772 */
773
774
775 /**************************************************************************
776  *      RtlUpperChar   (NTDLL.@)
777  *
778  * Converts an Ascii character to uppercase.
779  *
780  * PARAMS
781  *  ch [I] Character to convert
782  *
783  * RETURNS
784  *  The uppercase character value.
785  *
786  * NOTES
787  *  For the input characters from 'a' .. 'z' it returns 'A' .. 'Z'.
788  *  All other input characters are returned unchanged. The locale and
789  *  multibyte characters are not taken into account (as native DLL).
790  */
791 CHAR WINAPI RtlUpperChar( CHAR ch )
792 {
793     if (ch >= 'a' && ch <= 'z') {
794         return ch - 'a' + 'A';
795     } else {
796         return ch;
797     } /* if */
798 }
799
800
801 /**************************************************************************
802  *      RtlUpperString   (NTDLL.@)
803  *
804  * Converts an Ascii string to uppercase.
805  *
806  * PARAMS
807  *  dst [O] Destination for converted string
808  *  src [I] Source string to convert
809  *
810  * RETURNS
811  *  Nothing.
812  *
813  * NOTES
814  *  For the src characters from 'a' .. 'z' it assigns 'A' .. 'Z' to dst.
815  *  All other src characters are copied unchanged to dst. The locale and
816  *  multibyte characters are not taken into account (as native DLL).
817  *  The number of character copied is the minimum of src->Length and
818  *  the dst->MaximumLength.
819  */
820 void WINAPI RtlUpperString( STRING *dst, const STRING *src )
821 {
822     unsigned int i, len = min(src->Length, dst->MaximumLength);
823
824     for (i = 0; i < len; i++) dst->Buffer[i] = RtlUpperChar(src->Buffer[i]);
825     dst->Length = len;
826 }
827
828
829 /**************************************************************************
830  *      RtlUpcaseUnicodeChar   (NTDLL.@)
831  *
832  * Converts an Unicode character to uppercase.
833  *
834  * PARAMS
835  *  wch [I] Character to convert
836  *
837  * RETURNS
838  *  The uppercase character value.
839  */
840 WCHAR WINAPI RtlUpcaseUnicodeChar( WCHAR wch )
841 {
842     return toupperW(wch);
843 }
844
845
846 /**************************************************************************
847  *      RtlDowncaseUnicodeChar   (NTDLL.@)
848  *
849  * Converts an Unicode character to lowercase.
850  *
851  * PARAMS
852  *  wch [I] Character to convert
853  *
854  * RETURNS
855  *  The lowercase character value.
856  */
857 WCHAR WINAPI RtlDowncaseUnicodeChar(WCHAR wch)
858 {
859     return tolowerW(wch);
860 }
861
862
863 /**************************************************************************
864  *      RtlUpcaseUnicodeString   (NTDLL.@)
865  *
866  * Converts an Unicode string to uppercase.
867  *
868  * PARAMS
869  *  dest    [O] Destination for converted string
870  *  src     [I] Source string to convert
871  *  doalloc [I] TRUE=Allocate a buffer for dest if it doesn't have one
872  *
873  * RETURNS
874  *  Success: STATUS_SUCCESS. dest contains the converted string.
875  *  Failure: STATUS_NO_MEMORY, if doalloc is TRUE and memory allocation fails, or
876  *           STATUS_BUFFER_OVERFLOW, if doalloc is FALSE and dest is too small.
877  *
878  * NOTES
879  *  dest is never '\0' terminated because it may be equal to src, and src
880  *  might not be '\0' terminated. dest->Length is only set upon success.
881  */
882 NTSTATUS WINAPI RtlUpcaseUnicodeString( UNICODE_STRING *dest,
883                                         const UNICODE_STRING *src,
884                                         BOOLEAN doalloc)
885 {
886     DWORD i, len = src->Length;
887
888     if (doalloc)
889     {
890         dest->MaximumLength = len;
891         if (!(dest->Buffer = RtlAllocateHeap( ntdll_get_process_heap(), 0, len )))
892             return STATUS_NO_MEMORY;
893     }
894     else if (len > dest->MaximumLength) return STATUS_BUFFER_OVERFLOW;
895
896     for (i = 0; i < len/sizeof(WCHAR); i++) dest->Buffer[i] = toupperW(src->Buffer[i]);
897     dest->Length = len;
898     return STATUS_SUCCESS;
899 }
900
901
902 /**************************************************************************
903  *      RtlDowncaseUnicodeString   (NTDLL.@)
904  *
905  * Converts an Unicode string to lowercase.
906  *
907  * PARAMS
908  *  dest    [O] Destination for converted string
909  *  src     [I] Source string to convert
910  *  doalloc [I] TRUE=Allocate a buffer for dest if it doesn't have one
911  *
912  * RETURNS
913  *  Success: STATUS_SUCCESS. dest contains the converted string.
914  *  Failure: STATUS_NO_MEMORY, if doalloc is TRUE and memory allocation fails, or
915  *           STATUS_BUFFER_OVERFLOW, if doalloc is FALSE and dest is too small.
916  *
917  * NOTES
918  *  dest is never '\0' terminated because it may be equal to src, and src
919  *  might not be '\0' terminated. dest->Length is only set upon success.
920  */
921 NTSTATUS WINAPI RtlDowncaseUnicodeString(
922     UNICODE_STRING *dest,
923     const UNICODE_STRING *src,
924     BOOLEAN doalloc)
925 {
926     DWORD i;
927     DWORD len = src->Length;
928
929     if (doalloc) {
930         dest->MaximumLength = len;
931         if (!(dest->Buffer = RtlAllocateHeap( ntdll_get_process_heap(), 0, len ))) {
932             return STATUS_NO_MEMORY;
933         } /* if */
934     } else if (len > dest->MaximumLength) {
935         return STATUS_BUFFER_OVERFLOW;
936     } /* if */
937
938     for (i = 0; i < len/sizeof(WCHAR); i++) {
939         dest->Buffer[i] = tolowerW(src->Buffer[i]);
940     } /* for */
941     dest->Length = len;
942     return STATUS_SUCCESS;
943 }
944
945
946 /**************************************************************************
947  *      RtlUpcaseUnicodeStringToAnsiString   (NTDLL.@)
948  *
949  * NOTES
950  *  writes terminating 0
951  */
952 NTSTATUS WINAPI RtlUpcaseUnicodeStringToAnsiString( STRING *dst,
953                                                     const UNICODE_STRING *src,
954                                                     BOOLEAN doalloc )
955 {
956     NTSTATUS ret;
957     UNICODE_STRING upcase;
958
959     if (!(ret = RtlUpcaseUnicodeString( &upcase, src, TRUE )))
960     {
961         ret = RtlUnicodeStringToAnsiString( dst, &upcase, doalloc );
962         RtlFreeUnicodeString( &upcase );
963     }
964     return ret;
965 }
966
967
968 /**************************************************************************
969  *      RtlUpcaseUnicodeStringToOemString   (NTDLL.@)
970  *
971  * NOTES
972  *  writes terminating 0
973  */
974 NTSTATUS WINAPI RtlUpcaseUnicodeStringToOemString( STRING *dst,
975                                                    const UNICODE_STRING *src,
976                                                    BOOLEAN doalloc )
977 {
978     NTSTATUS ret;
979     UNICODE_STRING upcase;
980
981     if (!(ret = RtlUpcaseUnicodeString( &upcase, src, TRUE )))
982     {
983         ret = RtlUnicodeStringToOemString( dst, &upcase, doalloc );
984         RtlFreeUnicodeString( &upcase );
985     }
986     return ret;
987 }
988
989
990 /**************************************************************************
991  *      RtlUpcaseUnicodeStringToCountedOemString   (NTDLL.@)
992  *
993  * NOTES
994  *  Same as RtlUpcaseUnicodeStringToOemString but doesn't write terminating null
995  */
996 NTSTATUS WINAPI RtlUpcaseUnicodeStringToCountedOemString( STRING *oem,
997                                                           const UNICODE_STRING *uni,
998                                                           BOOLEAN doalloc )
999 {
1000     NTSTATUS ret;
1001     UNICODE_STRING upcase;
1002
1003     if (!(ret = RtlUpcaseUnicodeString( &upcase, uni, TRUE )))
1004     {
1005         DWORD len = RtlUnicodeStringToOemSize( &upcase ) - 1;
1006         oem->Length = len;
1007         if (doalloc)
1008         {
1009             oem->MaximumLength = len;
1010             if (!(oem->Buffer = RtlAllocateHeap( ntdll_get_process_heap(), 0, len )))
1011             {
1012                 ret = STATUS_NO_MEMORY;
1013                 goto done;
1014             }
1015         }
1016         else if (oem->MaximumLength < len)
1017         {
1018             ret = STATUS_BUFFER_OVERFLOW;
1019             oem->Length = oem->MaximumLength;
1020             if (!oem->MaximumLength) goto done;
1021         }
1022         RtlUnicodeToOemN( oem->Buffer, oem->Length, NULL, upcase.Buffer, upcase.Length );
1023     done:
1024         RtlFreeUnicodeString( &upcase );
1025     }
1026     return ret;
1027 }
1028
1029
1030 /**************************************************************************
1031  *      RtlUpcaseUnicodeToMultiByteN   (NTDLL.@)
1032  */
1033 NTSTATUS WINAPI RtlUpcaseUnicodeToMultiByteN( LPSTR dst, DWORD dstlen, LPDWORD reslen,
1034                                               LPCWSTR src, DWORD srclen )
1035 {
1036     NTSTATUS ret;
1037     LPWSTR upcase;
1038     DWORD i;
1039
1040     if (!(upcase = RtlAllocateHeap( ntdll_get_process_heap(), 0, srclen ))) return STATUS_NO_MEMORY;
1041     for (i = 0; i < srclen/sizeof(WCHAR); i++) upcase[i] = toupperW(src[i]);
1042     ret = RtlUnicodeToMultiByteN( dst, dstlen, reslen, upcase, srclen );
1043     RtlFreeHeap( ntdll_get_process_heap(), 0, upcase );
1044     return ret;
1045 }
1046
1047
1048 /**************************************************************************
1049  *      RtlUpcaseUnicodeToOemN   (NTDLL.@)
1050  */
1051 NTSTATUS WINAPI RtlUpcaseUnicodeToOemN( LPSTR dst, DWORD dstlen, LPDWORD reslen,
1052                                         LPCWSTR src, DWORD srclen )
1053 {
1054     NTSTATUS ret;
1055     LPWSTR upcase;
1056     DWORD i;
1057
1058     if (!(upcase = RtlAllocateHeap( ntdll_get_process_heap(), 0, srclen ))) return STATUS_NO_MEMORY;
1059     for (i = 0; i < srclen/sizeof(WCHAR); i++) upcase[i] = toupperW(src[i]);
1060     ret = RtlUnicodeToOemN( dst, dstlen, reslen, upcase, srclen );
1061     RtlFreeHeap( ntdll_get_process_heap(), 0, upcase );
1062     return ret;
1063 }
1064
1065
1066 /*
1067         STRING SIZE
1068 */
1069
1070
1071 /**************************************************************************
1072  *      RtlOemStringToUnicodeSize   (NTDLL.@)
1073  *      RtlxOemStringToUnicodeSize  (NTDLL.@)
1074  *
1075  * Calculate the size in bytes necessary for the Unicode conversion of str,
1076  * including the terminating '\0'.
1077  *
1078  * PARAMS
1079  *  str [I] String to calculate the size of
1080  *
1081  * RETURNS
1082  *  The calculated size.
1083  */
1084 UINT WINAPI RtlOemStringToUnicodeSize( const STRING *str )
1085 {
1086     int ret = wine_cp_mbstowcs( get_oem_table(), 0, str->Buffer, str->Length, NULL, 0 );
1087     return (ret + 1) * sizeof(WCHAR);
1088 }
1089
1090
1091 /**************************************************************************
1092  *      RtlAnsiStringToUnicodeSize   (NTDLL.@)
1093  *      RtlxAnsiStringToUnicodeSize  (NTDLL.@)
1094  *
1095  * Calculate the size in bytes necessary for the Unicode conversion of str,
1096  * including the terminating '\0'.
1097  *
1098  * PARAMS
1099  *  str [I] String to calculate the size of
1100  *
1101  * RETURNS
1102  *  The calculated size.
1103  */
1104 DWORD WINAPI RtlAnsiStringToUnicodeSize( const STRING *str )
1105 {
1106     DWORD ret;
1107     RtlMultiByteToUnicodeSize( &ret, str->Buffer, str->Length );
1108     return ret + sizeof(WCHAR);
1109 }
1110
1111
1112 /**************************************************************************
1113  *      RtlMultiByteToUnicodeSize   (NTDLL.@)
1114  *
1115  * Compute the size in bytes necessary for the Unicode conversion of str,
1116  * without the terminating '\0'.
1117  *
1118  * PARAMS
1119  *  size [O] Destination for size
1120  *  str  [I] String to calculate the size of
1121  *  len  [I] Length of str
1122  *
1123  * RETURNS
1124  *  STATUS_SUCCESS.
1125  */
1126 NTSTATUS WINAPI RtlMultiByteToUnicodeSize( DWORD *size, LPCSTR str, UINT len )
1127 {
1128     *size = wine_cp_mbstowcs( get_ansi_table(), 0, str, len, NULL, 0 ) * sizeof(WCHAR);
1129     return STATUS_SUCCESS;
1130 }
1131
1132
1133 /**************************************************************************
1134  *      RtlUnicodeToMultiByteSize   (NTDLL.@)
1135  *
1136  * Calculate the size in bytes necessary for the multibyte conversion of str,
1137  * without the terminating '\0'.
1138  *
1139  * PARAMS
1140  *  size [O] Destination for size
1141  *  str  [I] String to calculate the size of
1142  *  len  [I] Length of str
1143  *
1144  * RETURNS
1145  *  STATUS_SUCCESS.
1146  */
1147 NTSTATUS WINAPI RtlUnicodeToMultiByteSize( PULONG size, LPCWSTR str, ULONG len )
1148 {
1149     *size = wine_cp_wcstombs( get_ansi_table(), 0, str, len / sizeof(WCHAR), NULL, 0, NULL, NULL );
1150     return STATUS_SUCCESS;
1151 }
1152
1153
1154 /**************************************************************************
1155  *      RtlUnicodeStringToAnsiSize   (NTDLL.@)
1156  *      RtlxUnicodeStringToAnsiSize  (NTDLL.@)
1157  *
1158  * Calculate the size in bytes necessary for the Ansi conversion of str,
1159  * including the terminating '\0'.
1160  *
1161  * PARAMS
1162  *  str [I] String to calculate the size of
1163  *
1164  * RETURNS
1165  *  The calculated size.
1166  */
1167 DWORD WINAPI RtlUnicodeStringToAnsiSize( const UNICODE_STRING *str )
1168 {
1169     DWORD ret;
1170     RtlUnicodeToMultiByteSize( &ret, str->Buffer, str->Length );
1171     return ret + 1;
1172 }
1173
1174
1175 /**************************************************************************
1176  *      RtlUnicodeStringToOemSize   (NTDLL.@)
1177  *      RtlxUnicodeStringToOemSize  (NTDLL.@)
1178  *
1179  * Calculate the size in bytes necessary for the OEM conversion of str,
1180  * including the terminating '\0'.
1181  *
1182  * PARAMS
1183  *  str [I] String to calculate the size of
1184  *
1185  * RETURNS
1186  *  The calculated size.
1187  */
1188 DWORD WINAPI RtlUnicodeStringToOemSize( const UNICODE_STRING *str )
1189 {
1190     return wine_cp_wcstombs( get_oem_table(), 0, str->Buffer, str->Length / sizeof(WCHAR),
1191                              NULL, 0, NULL, NULL ) + 1;
1192 }
1193
1194
1195 /**************************************************************************
1196  *      RtlAppendAsciizToString   (NTDLL.@)
1197  *
1198  * Concatenates a buffered character string and a '\0' terminated character
1199  * string
1200  *
1201  * RETURNS
1202  *  Success: STATUS_SUCCESS. src is appended to dest.
1203  *  Failure: STATUS_BUFFER_TOO_SMALL, if the buffer of dest is to small
1204  *                  to hold the concatenated string.
1205  *
1206  * NOTES
1207  *  if src is NULL dest is unchanged.
1208  *  dest is never '\0' terminated.
1209  */
1210 NTSTATUS WINAPI RtlAppendAsciizToString(
1211     STRING *dest, /* [I/O] Buffered character string to which src is concatenated */
1212     LPCSTR src)   /* [I]   '\0' terminated character string to be concatenated */
1213 {
1214     if (src != NULL) {
1215         unsigned int src_len = strlen(src);
1216         unsigned int dest_len  = src_len + dest->Length;
1217
1218         if (dest_len > dest->MaximumLength) return STATUS_BUFFER_TOO_SMALL;
1219         memcpy(dest->Buffer + dest->Length, src, src_len);
1220         dest->Length = dest_len;
1221     } /* if */
1222     return STATUS_SUCCESS;
1223 }
1224
1225
1226 /**************************************************************************
1227  *      RtlAppendStringToString   (NTDLL.@)
1228  *
1229  * Concatenates two buffered character strings
1230  *
1231  * RETURNS
1232  *  Success: STATUS_SUCCESS. src is appended to dest.
1233  *  Failure: STATUS_BUFFER_TOO_SMALL, if the buffer of dest is to small
1234  *                  to hold the concatenated string.
1235  *
1236  * NOTES
1237  *  if src->length is zero dest is unchanged.
1238  *  dest is never '\0' terminated.
1239  */
1240 NTSTATUS WINAPI RtlAppendStringToString(
1241     STRING *dest,       /* [I/O] Buffered character string to which src is concatenated */
1242     const STRING *src)  /* [I]   Buffered character string to be concatenated */
1243 {
1244     if (src->Length != 0) {
1245         unsigned int dest_len = src->Length + dest->Length;
1246
1247         if (dest_len > dest->MaximumLength) return STATUS_BUFFER_TOO_SMALL;
1248         memcpy(dest->Buffer + dest->Length, src->Buffer, src->Length);
1249         dest->Length = dest_len;
1250     } /* if */
1251     return STATUS_SUCCESS;
1252 }
1253
1254
1255 /**************************************************************************
1256  *      RtlAppendUnicodeToString   (NTDLL.@)
1257  *
1258  * Concatenates an buffered unicode string and a '\0' terminated unicode 
1259  * string
1260  *
1261  * RETURNS
1262  *  Success: STATUS_SUCCESS. src is appended to dest.
1263  *  Failure: STATUS_BUFFER_TOO_SMALL, if the buffer of dest is to small
1264  *                  to hold the concatenated string.
1265  *
1266  * NOTES
1267  *  if src is NULL dest is unchanged.
1268  *  dest is '\0' terminated when the MaximumLength allowes it.
1269  *  When dest fits exactly in MaximumLength characters the '\0' is ommitted.
1270  *
1271  * DIFFERENCES
1272  *  Does not write in the src->Buffer beyond MaximumLength when
1273  *  MaximumLength is odd as the native function does.
1274  */
1275 NTSTATUS WINAPI RtlAppendUnicodeToString(
1276     UNICODE_STRING *dest, /* [I/O] Buffered unicode string to which src is concatenated */
1277     LPCWSTR src)          /* [I]   '\0' terminated unicode string to be concatenated */
1278 {
1279     if (src != NULL) {
1280         unsigned int src_len = strlenW(src) * sizeof(WCHAR);
1281         unsigned int dest_len  = src_len + dest->Length;
1282
1283         if (dest_len > dest->MaximumLength) return STATUS_BUFFER_TOO_SMALL;
1284         memcpy(dest->Buffer + dest->Length/sizeof(WCHAR), src, src_len);
1285         dest->Length = dest_len;
1286         /* append terminating '\0' if enough space */
1287         if (dest_len + sizeof(WCHAR) <= dest->MaximumLength) {
1288             dest->Buffer[dest_len / sizeof(WCHAR)] = 0;
1289         } /* if */
1290     } /* if */
1291     return STATUS_SUCCESS;
1292 }
1293
1294
1295 /**************************************************************************
1296  *      RtlAppendUnicodeStringToString   (NTDLL.@)
1297  *
1298  * Concatenates two buffered unicode strings
1299  *
1300  * RETURNS
1301  *  Success: STATUS_SUCCESS. src is appended to dest.
1302  *  Failure: STATUS_BUFFER_TOO_SMALL, if the buffer of dest is to small
1303  *                  to hold the concatenated string.
1304  *
1305  * NOTES
1306  *  if src->length is zero dest is unchanged.
1307  *  dest is '\0' terminated when the MaximumLength allowes it.
1308  *  When dest fits exactly in MaximumLength characters the '\0' is ommitted.
1309  *
1310  * DIFFERENCES
1311  *  Does not write in the src->Buffer beyond MaximumLength when
1312  *  MaximumLength is odd as the native function does.
1313  */
1314 NTSTATUS WINAPI RtlAppendUnicodeStringToString(
1315     UNICODE_STRING *dest,      /* [I/O] Buffered unicode string to which src is concatenated */
1316     const UNICODE_STRING *src) /* [I]   Buffered unicode string to be concatenated */
1317 {
1318     if (src->Length != 0) {
1319         unsigned int dest_len = src->Length + dest->Length;
1320
1321         if (dest_len > dest->MaximumLength) return STATUS_BUFFER_TOO_SMALL;
1322         memcpy(dest->Buffer + dest->Length/sizeof(WCHAR), src->Buffer, src->Length);
1323         dest->Length = dest_len;
1324         /* append terminating '\0' if enough space */
1325         if (dest_len + sizeof(WCHAR) <= dest->MaximumLength) {
1326             dest->Buffer[dest_len / sizeof(WCHAR)] = 0;
1327         } /* if */
1328     } /* if */
1329     return STATUS_SUCCESS;
1330 }
1331
1332
1333 /**************************************************************************
1334  *      RtlFindCharInUnicodeString   (NTDLL.@)
1335  *
1336  * Searches for one of several unicode characters in an unicode string.
1337  *
1338  * RETURNS
1339  *  Success: STATUS_SUCCESS. pos contains the position after the character found.
1340  *  Failure: STATUS_NOT_FOUND, if none of the search_chars are in main_str.
1341  */
1342 NTSTATUS WINAPI RtlFindCharInUnicodeString(
1343     int flags,                          /* [I] Flags */
1344     const UNICODE_STRING *main_str,     /* [I] Unicode string in which one or more characters are searched */
1345     const UNICODE_STRING *search_chars, /* [I] Unicode string which contains the characters to search for */
1346     USHORT *pos)                        /* [O] Position of the first character found + 2 */
1347 {
1348     int main_idx;
1349     unsigned int search_idx;
1350
1351     switch (flags) {
1352         case 0:
1353             for (main_idx = 0; main_idx < main_str->Length / sizeof(WCHAR); main_idx++) {
1354                 for (search_idx = 0; search_idx < search_chars->Length / sizeof(WCHAR); search_idx++) {
1355                     if (main_str->Buffer[main_idx] == search_chars->Buffer[search_idx]) {
1356                         *pos = (main_idx + 1) * sizeof(WCHAR);
1357                         return STATUS_SUCCESS;
1358                     }
1359                 }
1360             }
1361             *pos = 0;
1362             return STATUS_NOT_FOUND;
1363         case 1:
1364             for (main_idx = main_str->Length / sizeof(WCHAR) - 1; main_idx >= 0; main_idx--) {
1365                 for (search_idx = 0; search_idx < search_chars->Length / sizeof(WCHAR); search_idx++) {
1366                     if (main_str->Buffer[main_idx] == search_chars->Buffer[search_idx]) {
1367                         *pos = main_idx * sizeof(WCHAR);
1368                         return STATUS_SUCCESS;
1369                     }
1370                 }
1371             }
1372             *pos = 0;
1373             return STATUS_NOT_FOUND;
1374         case 2:
1375             for (main_idx = 0; main_idx < main_str->Length / sizeof(WCHAR); main_idx++) {
1376                 search_idx = 0;
1377                 while (search_idx < search_chars->Length / sizeof(WCHAR) &&
1378                          main_str->Buffer[main_idx] != search_chars->Buffer[search_idx]) {
1379                     search_idx++;
1380                 }
1381                 if (search_idx >= search_chars->Length / sizeof(WCHAR)) {
1382                     *pos = (main_idx + 1) * sizeof(WCHAR);
1383                     return STATUS_SUCCESS;
1384                 }
1385             }
1386             *pos = 0;
1387             return STATUS_NOT_FOUND;
1388         case 3:
1389             for (main_idx = main_str->Length / sizeof(WCHAR) - 1; main_idx >= 0; main_idx--) {
1390                 search_idx = 0;
1391                 while (search_idx < search_chars->Length / sizeof(WCHAR) &&
1392                          main_str->Buffer[main_idx] != search_chars->Buffer[search_idx]) {
1393                     search_idx++;
1394                 }
1395                 if (search_idx >= search_chars->Length / sizeof(WCHAR)) {
1396                     *pos = main_idx * sizeof(WCHAR);
1397                     return STATUS_SUCCESS;
1398                 }
1399             }
1400             *pos = 0;
1401             return STATUS_NOT_FOUND;
1402     } /* switch */
1403     return STATUS_NOT_FOUND;
1404 }
1405
1406
1407 /*
1408         MISC
1409 */
1410 /* Tests that we currently implement */
1411 #define ITU_IMPLEMENTED_TESTS \
1412     (IS_TEXT_UNICODE_SIGNATURE | \
1413      IS_TEXT_UNICODE_REVERSE_SIGNATURE | \
1414      IS_TEXT_UNICODE_ODD_LENGTH | \
1415      IS_TEXT_UNICODE_STATISTICS | \
1416      IS_TEXT_UNICODE_NULL_BYTES)
1417
1418 /**************************************************************************
1419  *      RtlIsTextUnicode (NTDLL.@)
1420  *
1421  * Attempt to guess whether a text buffer is Unicode.
1422  *
1423  * PARAMS
1424  *  buf [I] Text buffer to test
1425  *  len [I] Length of buf
1426  *  pf  [O] Destination for test results
1427  *
1428  * RETURNS
1429  *  The length of the string if all tests were passed, 0 otherwise.
1430  *
1431  * FIXME
1432  *  Should implement more tests.
1433  */
1434 DWORD WINAPI RtlIsTextUnicode(
1435         LPVOID buf,
1436         DWORD len,
1437         DWORD *pf)
1438 {
1439         LPWSTR s = buf;
1440         DWORD flags = -1, out_flags = 0;
1441
1442         if (!len)
1443                 goto out;
1444         if (pf)
1445                 flags = *pf;
1446         /*
1447          * Apply various tests to the text string. According to the
1448          * docs, each test "passed" sets the corresponding flag in
1449          * the output flags. But some of the tests are mutually
1450          * exclusive, so I don't see how you could pass all tests ...
1451          */
1452
1453         /* Check for an odd length ... pass if even. */
1454         if ((flags & IS_TEXT_UNICODE_ODD_LENGTH) && (len & 1))
1455                 out_flags |= IS_TEXT_UNICODE_ODD_LENGTH;
1456
1457         /* Check for the special byte order unicode marks. */
1458         if ((flags & IS_TEXT_UNICODE_SIGNATURE) && *s == 0xFEFF)
1459                 out_flags |= IS_TEXT_UNICODE_SIGNATURE;
1460
1461     if ((flags & IS_TEXT_UNICODE_REVERSE_SIGNATURE) && *s == 0xFFFE)
1462         out_flags |= IS_TEXT_UNICODE_REVERSE_SIGNATURE;
1463
1464     /* apply some statistical analysis */
1465     if (flags & IS_TEXT_UNICODE_STATISTICS)
1466     {
1467         DWORD i, stats = 0;
1468         /* FIXME: checks only for ASCII characters in the unicode stream */
1469         for (i = 0; i < len / sizeof(WCHAR); i++)
1470         {
1471             if (s[i] <= 255) stats++;
1472         }
1473         if (stats > len / sizeof(WCHAR) / 2)
1474             out_flags |= IS_TEXT_UNICODE_STATISTICS;
1475     }
1476
1477     /* Check for unicode NULL chars */
1478     if (flags & IS_TEXT_UNICODE_NULL_BYTES)
1479     {
1480         DWORD i;
1481         for (i = 0; i < len / sizeof(WCHAR); i++)
1482         {
1483             if (!s[i])
1484             {
1485                 out_flags |= IS_TEXT_UNICODE_NULL_BYTES;
1486                 break;
1487             }
1488         }
1489     }
1490
1491         /*
1492          * Check whether the string passed all of the tests.
1493          */
1494         flags &= ITU_IMPLEMENTED_TESTS;
1495         if ((out_flags & flags) != flags)
1496                 len = 0;
1497 out:
1498         if (pf)
1499                 *pf = out_flags;
1500         return len;
1501 }
1502
1503
1504 /**************************************************************************
1505  *      RtlCharToInteger   (NTDLL.@)
1506  *
1507  * Converts a character string into its integer equivalent.
1508  *
1509  * RETURNS
1510  *  Success: STATUS_SUCCESS. value contains the converted number
1511  *  Failure: STATUS_INVALID_PARAMETER, if base is not 0, 2, 8, 10 or 16.
1512  *           STATUS_ACCESS_VIOLATION, if value is NULL.
1513  *
1514  * NOTES
1515  *  For base 0 it uses 10 as base and the string should be in the format
1516  *      "{whitespace} [+|-] [0[x|o|b]] {digits}".
1517  *  For other bases the string should be in the format
1518  *      "{whitespace} [+|-] {digits}".
1519  *  No check is made for value overflow, only the lower 32 bits are assigned.
1520  *  If str is NULL it crashes, as the native function does.
1521  *
1522  * DIFFERENCES
1523  *  This function does not read garbage behind '\0' as the native version does.
1524  */
1525 NTSTATUS WINAPI RtlCharToInteger(
1526     PCSZ str,      /* [I] '\0' terminated single-byte string containing a number */
1527     ULONG base,    /* [I] Number base for conversion (allowed 0, 2, 8, 10 or 16) */
1528     ULONG *value)  /* [O] Destination for the converted value */
1529 {
1530     CHAR chCurrent;
1531     int digit;
1532     ULONG RunningTotal = 0;
1533     char bMinus = 0;
1534
1535     while (*str != '\0' && *str <= ' ') {
1536         str++;
1537     } /* while */
1538
1539     if (*str == '+') {
1540         str++;
1541     } else if (*str == '-') {
1542         bMinus = 1;
1543         str++;
1544     } /* if */
1545
1546     if (base == 0) {
1547         base = 10;
1548         if (str[0] == '0') {
1549             if (str[1] == 'b') {
1550                 str += 2;
1551                 base = 2;
1552             } else if (str[1] == 'o') {
1553                 str += 2;
1554                 base = 8;
1555             } else if (str[1] == 'x') {
1556                 str += 2;
1557                 base = 16;
1558             } /* if */
1559         } /* if */
1560     } else if (base != 2 && base != 8 && base != 10 && base != 16) {
1561         return STATUS_INVALID_PARAMETER;
1562     } /* if */
1563
1564     if (value == NULL) {
1565         return STATUS_ACCESS_VIOLATION;
1566     } /* if */
1567
1568     while (*str != '\0') {
1569         chCurrent = *str;
1570         if (chCurrent >= '0' && chCurrent <= '9') {
1571             digit = chCurrent - '0';
1572         } else if (chCurrent >= 'A' && chCurrent <= 'Z') {
1573             digit = chCurrent - 'A' + 10;
1574         } else if (chCurrent >= 'a' && chCurrent <= 'z') {
1575             digit = chCurrent - 'a' + 10;
1576         } else {
1577             digit = -1;
1578         } /* if */
1579         if (digit < 0 || digit >= base) {
1580             *value = bMinus ? -RunningTotal : RunningTotal;
1581             return STATUS_SUCCESS;
1582         } /* if */
1583
1584         RunningTotal = RunningTotal * base + digit;
1585         str++;
1586     } /* while */
1587
1588     *value = bMinus ? -RunningTotal : RunningTotal;
1589     return STATUS_SUCCESS;
1590 }
1591
1592
1593 /**************************************************************************
1594  *      RtlIntegerToChar   (NTDLL.@)
1595  *
1596  * Converts an unsigned integer to a character string.
1597  *
1598  * RETURNS
1599  *  Success: STATUS_SUCCESS. str contains the converted number
1600  *  Failure: STATUS_INVALID_PARAMETER, if base is not 0, 2, 8, 10 or 16.
1601  *           STATUS_BUFFER_OVERFLOW, if str would be larger than length.
1602  *           STATUS_ACCESS_VIOLATION, if str is NULL.
1603  *
1604  * NOTES
1605  *  Instead of base 0 it uses 10 as base.
1606  *  Writes at most length characters to the string str.
1607  *  Str is '\0' terminated when length allowes it.
1608  *  When str fits exactly in length characters the '\0' is ommitted.
1609  */
1610 NTSTATUS WINAPI RtlIntegerToChar(
1611     ULONG value,   /* [I] Value to be converted */
1612     ULONG base,    /* [I] Number base for conversion (allowed 0, 2, 8, 10 or 16) */
1613     ULONG length,  /* [I] Length of the str buffer in bytes */
1614     PCHAR str)     /* [O] Destination for the converted value */
1615 {
1616     CHAR buffer[33];
1617     PCHAR pos;
1618     CHAR digit;
1619     ULONG len;
1620
1621     if (base == 0) {
1622         base = 10;
1623     } else if (base != 2 && base != 8 && base != 10 && base != 16) {
1624         return STATUS_INVALID_PARAMETER;
1625     } /* if */
1626
1627     pos = &buffer[32];
1628     *pos = '\0';
1629
1630     do {
1631         pos--;
1632         digit = value % base;
1633         value = value / base;
1634         if (digit < 10) {
1635             *pos = '0' + digit;
1636         } else {
1637             *pos = 'A' + digit - 10;
1638         } /* if */
1639     } while (value != 0L);
1640
1641     len = &buffer[32] - pos;
1642     if (len > length) {
1643         return STATUS_BUFFER_OVERFLOW;
1644     } else if (str == NULL) {
1645         return STATUS_ACCESS_VIOLATION;
1646     } else if (len == length) {
1647         memcpy(str, pos, len);
1648     } else {
1649         memcpy(str, pos, len + 1);
1650     } /* if */
1651     return STATUS_SUCCESS;
1652 }
1653
1654
1655 /**************************************************************************
1656  *      RtlUnicodeStringToInteger (NTDLL.@)
1657  *
1658  * Converts an unicode string into its integer equivalent.
1659  *
1660  * RETURNS
1661  *  Success: STATUS_SUCCESS. value contains the converted number
1662  *  Failure: STATUS_INVALID_PARAMETER, if base is not 0, 2, 8, 10 or 16.
1663  *           STATUS_ACCESS_VIOLATION, if value is NULL.
1664  *
1665  * NOTES
1666  *  For base 0 it uses 10 as base and the string should be in the format
1667  *      "{whitespace} [+|-] [0[x|o|b]] {digits}".
1668  *  For other bases the string should be in the format
1669  *      "{whitespace} [+|-] {digits}".
1670  *  No check is made for value overflow, only the lower 32 bits are assigned.
1671  *  If str is NULL it crashes, as the native function does.
1672  *
1673  * DIFFERENCES
1674  *  This function does not read garbage on string length 0 as the native
1675  *  version does.
1676  */
1677 NTSTATUS WINAPI RtlUnicodeStringToInteger(
1678     const UNICODE_STRING *str, /* [I] Unicode string to be converted */
1679     ULONG base,                /* [I] Number base for conversion (allowed 0, 2, 8, 10 or 16) */
1680     ULONG *value)              /* [O] Destination for the converted value */
1681 {
1682     LPWSTR lpwstr = str->Buffer;
1683     USHORT CharsRemaining = str->Length / sizeof(WCHAR);
1684     WCHAR wchCurrent;
1685     int digit;
1686     ULONG RunningTotal = 0;
1687     char bMinus = 0;
1688
1689     while (CharsRemaining >= 1 && *lpwstr <= ' ') {
1690         lpwstr++;
1691         CharsRemaining--;
1692     } /* while */
1693
1694     if (CharsRemaining >= 1) {
1695         if (*lpwstr == '+') {
1696             lpwstr++;
1697             CharsRemaining--;
1698         } else if (*lpwstr == '-') {
1699             bMinus = 1;
1700             lpwstr++;
1701             CharsRemaining--;
1702         } /* if */
1703     } /* if */
1704
1705     if (base == 0) {
1706         base = 10;
1707         if (CharsRemaining >= 2 && lpwstr[0] == '0') {
1708             if (lpwstr[1] == 'b') {
1709                 lpwstr += 2;
1710                 CharsRemaining -= 2;
1711                 base = 2;
1712             } else if (lpwstr[1] == 'o') {
1713                 lpwstr += 2;
1714                 CharsRemaining -= 2;
1715                 base = 8;
1716             } else if (lpwstr[1] == 'x') {
1717                 lpwstr += 2;
1718                 CharsRemaining -= 2;
1719                 base = 16;
1720             } /* if */
1721         } /* if */
1722     } else if (base != 2 && base != 8 && base != 10 && base != 16) {
1723         return STATUS_INVALID_PARAMETER;
1724     } /* if */
1725
1726     if (value == NULL) {
1727         return STATUS_ACCESS_VIOLATION;
1728     } /* if */
1729
1730     while (CharsRemaining >= 1) {
1731         wchCurrent = *lpwstr;
1732         if (wchCurrent >= '0' && wchCurrent <= '9') {
1733             digit = wchCurrent - '0';
1734         } else if (wchCurrent >= 'A' && wchCurrent <= 'Z') {
1735             digit = wchCurrent - 'A' + 10;
1736         } else if (wchCurrent >= 'a' && wchCurrent <= 'z') {
1737             digit = wchCurrent - 'a' + 10;
1738         } else {
1739             digit = -1;
1740         } /* if */
1741         if (digit < 0 || digit >= base) {
1742             *value = bMinus ? -RunningTotal : RunningTotal;
1743             return STATUS_SUCCESS;
1744         } /* if */
1745
1746         RunningTotal = RunningTotal * base + digit;
1747         lpwstr++;
1748         CharsRemaining--;
1749     } /* while */
1750
1751     *value = bMinus ? -RunningTotal : RunningTotal;
1752     return STATUS_SUCCESS;
1753 }
1754
1755
1756 /**************************************************************************
1757  *      RtlIntegerToUnicodeString (NTDLL.@)
1758  *
1759  * Converts an unsigned integer to a '\0' terminated unicode string.
1760  *
1761  * RETURNS
1762  *  Success: STATUS_SUCCESS. str contains the converted number
1763  *  Failure: STATUS_INVALID_PARAMETER, if base is not 0, 2, 8, 10 or 16.
1764  *           STATUS_BUFFER_OVERFLOW, if str is too small to hold the string
1765  *                  (with the '\0' termination). In this case str->Length
1766  *                  is set to the length, the string would have (which can
1767  *                  be larger than the MaximumLength).
1768  *
1769  * NOTES
1770  *  Instead of base 0 it uses 10 as base.
1771  *  If str is NULL it crashes, as the native function does.
1772  *
1773  * DIFFERENCES
1774  *  Do not return STATUS_BUFFER_OVERFLOW when the string is long enough.
1775  *  The native function does this when the string would be longer than 16
1776  *  characters even when the string parameter is long enough.
1777  */
1778 NTSTATUS WINAPI RtlIntegerToUnicodeString(
1779     ULONG value,         /* [I] Value to be converted */
1780     ULONG base,          /* [I] Number base for conversion (allowed 0, 2, 8, 10 or 16) */
1781     UNICODE_STRING *str) /* [O] Destination for the converted value */
1782 {
1783     WCHAR buffer[33];
1784     PWCHAR pos;
1785     WCHAR digit;
1786
1787     if (base == 0) {
1788         base = 10;
1789     } else if (base != 2 && base != 8 && base != 10 && base != 16) {
1790         return STATUS_INVALID_PARAMETER;
1791     } /* if */
1792
1793     pos = &buffer[32];
1794     *pos = '\0';
1795
1796     do {
1797         pos--;
1798         digit = value % base;
1799         value = value / base;
1800         if (digit < 10) {
1801             *pos = '0' + digit;
1802         } else {
1803             *pos = 'A' + digit - 10;
1804         } /* if */
1805     } while (value != 0L);
1806
1807     str->Length = (&buffer[32] - pos) * sizeof(WCHAR);
1808     if (str->Length >= str->MaximumLength) {
1809         return STATUS_BUFFER_OVERFLOW;
1810     } else {
1811         memcpy(str->Buffer, pos, str->Length + sizeof(WCHAR));
1812     } /* if */
1813     return STATUS_SUCCESS;
1814 }