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