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