ntdll: The FileMailslotSetInformation and FileCompletionInformation cases of NtSetInf...
[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( flags, 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     if (((char *)buf)[len - 1] == 0)
1614         len--;  /* Windows seems to do something like that to avoid e.g. false IS_TEXT_UNICODE_NULL_BYTES  */
1615
1616     len /= sizeof(WCHAR);
1617     /* Windows only checks the first 256 characters */
1618     if (len > 256) len = 256;
1619
1620     /* Check for the special byte order unicode marks. */
1621     if (*s == 0xFEFF) out_flags |= IS_TEXT_UNICODE_SIGNATURE;
1622     if (*s == 0xFFFE) out_flags |= IS_TEXT_UNICODE_REVERSE_SIGNATURE;
1623
1624     /* apply some statistical analysis */
1625     if (flags & IS_TEXT_UNICODE_STATISTICS)
1626     {
1627         int stats = 0;
1628         /* FIXME: checks only for ASCII characters in the unicode stream */
1629         for (i = 0; i < len; i++)
1630         {
1631             if (s[i] <= 255) stats++;
1632         }
1633         if (stats > len / 2)
1634             out_flags |= IS_TEXT_UNICODE_STATISTICS;
1635     }
1636
1637     /* Check for unicode NULL chars */
1638     if (flags & IS_TEXT_UNICODE_NULL_BYTES)
1639     {
1640         for (i = 0; i < len; i++)
1641         {
1642             if (!(s[i] & 0xff) || !(s[i] >> 8))
1643             {
1644                 out_flags |= IS_TEXT_UNICODE_NULL_BYTES;
1645                 break;
1646             }
1647         }
1648     }
1649
1650     if (pf)
1651     {
1652         out_flags &= *pf;
1653         *pf = out_flags;
1654     }
1655     /* check for flags that indicate it's definitely not valid Unicode */
1656     if (out_flags & (IS_TEXT_UNICODE_REVERSE_MASK | IS_TEXT_UNICODE_NOT_UNICODE_MASK)) return FALSE;
1657     /* now check for invalid ASCII, and assume Unicode if so */
1658     if (out_flags & IS_TEXT_UNICODE_NOT_ASCII_MASK) return TRUE;
1659     /* now check for Unicode flags */
1660     if (out_flags & IS_TEXT_UNICODE_UNICODE_MASK) return TRUE;
1661     /* no flags set */
1662     return FALSE;
1663 }
1664
1665
1666 /**************************************************************************
1667  *      RtlCharToInteger   (NTDLL.@)
1668  *
1669  * Converts a character string into its integer equivalent.
1670  *
1671  * RETURNS
1672  *  Success: STATUS_SUCCESS. value contains the converted number
1673  *  Failure: STATUS_INVALID_PARAMETER, if base is not 0, 2, 8, 10 or 16.
1674  *           STATUS_ACCESS_VIOLATION, if value is NULL.
1675  *
1676  * NOTES
1677  *  For base 0 it uses 10 as base and the string should be in the format
1678  *      "{whitespace} [+|-] [0[x|o|b]] {digits}".
1679  *  For other bases the string should be in the format
1680  *      "{whitespace} [+|-] {digits}".
1681  *  No check is made for value overflow, only the lower 32 bits are assigned.
1682  *  If str is NULL it crashes, as the native function does.
1683  *
1684  * DIFFERENCES
1685  *  This function does not read garbage behind '\0' as the native version does.
1686  */
1687 NTSTATUS WINAPI RtlCharToInteger(
1688     PCSZ str,      /* [I] '\0' terminated single-byte string containing a number */
1689     ULONG base,    /* [I] Number base for conversion (allowed 0, 2, 8, 10 or 16) */
1690     ULONG *value)  /* [O] Destination for the converted value */
1691 {
1692     CHAR chCurrent;
1693     int digit;
1694     ULONG RunningTotal = 0;
1695     char bMinus = 0;
1696
1697     while (*str != '\0' && *str <= ' ') {
1698         str++;
1699     } /* while */
1700
1701     if (*str == '+') {
1702         str++;
1703     } else if (*str == '-') {
1704         bMinus = 1;
1705         str++;
1706     } /* if */
1707
1708     if (base == 0) {
1709         base = 10;
1710         if (str[0] == '0') {
1711             if (str[1] == 'b') {
1712                 str += 2;
1713                 base = 2;
1714             } else if (str[1] == 'o') {
1715                 str += 2;
1716                 base = 8;
1717             } else if (str[1] == 'x') {
1718                 str += 2;
1719                 base = 16;
1720             } /* if */
1721         } /* if */
1722     } else if (base != 2 && base != 8 && base != 10 && base != 16) {
1723         return STATUS_INVALID_PARAMETER;
1724     } /* if */
1725
1726     if (value == NULL) {
1727         return STATUS_ACCESS_VIOLATION;
1728     } /* if */
1729
1730     while (*str != '\0') {
1731         chCurrent = *str;
1732         if (chCurrent >= '0' && chCurrent <= '9') {
1733             digit = chCurrent - '0';
1734         } else if (chCurrent >= 'A' && chCurrent <= 'Z') {
1735             digit = chCurrent - 'A' + 10;
1736         } else if (chCurrent >= 'a' && chCurrent <= 'z') {
1737             digit = chCurrent - 'a' + 10;
1738         } else {
1739             digit = -1;
1740         } /* if */
1741         if (digit < 0 || digit >= base) {
1742             *value = bMinus ? -RunningTotal : RunningTotal;
1743             return STATUS_SUCCESS;
1744         } /* if */
1745
1746         RunningTotal = RunningTotal * base + digit;
1747         str++;
1748     } /* while */
1749
1750     *value = bMinus ? -RunningTotal : RunningTotal;
1751     return STATUS_SUCCESS;
1752 }
1753
1754
1755 /**************************************************************************
1756  *      RtlIntegerToChar   (NTDLL.@)
1757  *
1758  * Converts an unsigned integer to a character string.
1759  *
1760  * RETURNS
1761  *  Success: STATUS_SUCCESS. str contains the converted number
1762  *  Failure: STATUS_INVALID_PARAMETER, if base is not 0, 2, 8, 10 or 16.
1763  *           STATUS_BUFFER_OVERFLOW, if str would be larger than length.
1764  *           STATUS_ACCESS_VIOLATION, if str is NULL.
1765  *
1766  * NOTES
1767  *  Instead of base 0 it uses 10 as base.
1768  *  Writes at most length characters to the string str.
1769  *  Str is '\0' terminated when length allows it.
1770  *  When str fits exactly in length characters the '\0' is omitted.
1771  */
1772 NTSTATUS WINAPI RtlIntegerToChar(
1773     ULONG value,   /* [I] Value to be converted */
1774     ULONG base,    /* [I] Number base for conversion (allowed 0, 2, 8, 10 or 16) */
1775     ULONG length,  /* [I] Length of the str buffer in bytes */
1776     PCHAR str)     /* [O] Destination for the converted value */
1777 {
1778     CHAR buffer[33];
1779     PCHAR pos;
1780     CHAR digit;
1781     ULONG len;
1782
1783     if (base == 0) {
1784         base = 10;
1785     } else if (base != 2 && base != 8 && base != 10 && base != 16) {
1786         return STATUS_INVALID_PARAMETER;
1787     } /* if */
1788
1789     pos = &buffer[32];
1790     *pos = '\0';
1791
1792     do {
1793         pos--;
1794         digit = value % base;
1795         value = value / base;
1796         if (digit < 10) {
1797             *pos = '0' + digit;
1798         } else {
1799             *pos = 'A' + digit - 10;
1800         } /* if */
1801     } while (value != 0L);
1802
1803     len = &buffer[32] - pos;
1804     if (len > length) {
1805         return STATUS_BUFFER_OVERFLOW;
1806     } else if (str == NULL) {
1807         return STATUS_ACCESS_VIOLATION;
1808     } else if (len == length) {
1809         memcpy(str, pos, len);
1810     } else {
1811         memcpy(str, pos, len + 1);
1812     } /* if */
1813     return STATUS_SUCCESS;
1814 }
1815
1816
1817 /**************************************************************************
1818  *      RtlUnicodeStringToInteger (NTDLL.@)
1819  *
1820  * Converts an unicode string into its integer equivalent.
1821  *
1822  * RETURNS
1823  *  Success: STATUS_SUCCESS. value contains the converted number
1824  *  Failure: STATUS_INVALID_PARAMETER, if base is not 0, 2, 8, 10 or 16.
1825  *           STATUS_ACCESS_VIOLATION, if value is NULL.
1826  *
1827  * NOTES
1828  *  For base 0 it uses 10 as base and the string should be in the format
1829  *      "{whitespace} [+|-] [0[x|o|b]] {digits}".
1830  *  For other bases the string should be in the format
1831  *      "{whitespace} [+|-] {digits}".
1832  *  No check is made for value overflow, only the lower 32 bits are assigned.
1833  *  If str is NULL it crashes, as the native function does.
1834  *
1835  * DIFFERENCES
1836  *  This function does not read garbage on string length 0 as the native
1837  *  version does.
1838  */
1839 NTSTATUS WINAPI RtlUnicodeStringToInteger(
1840     const UNICODE_STRING *str, /* [I] Unicode string to be converted */
1841     ULONG base,                /* [I] Number base for conversion (allowed 0, 2, 8, 10 or 16) */
1842     ULONG *value)              /* [O] Destination for the converted value */
1843 {
1844     LPWSTR lpwstr = str->Buffer;
1845     USHORT CharsRemaining = str->Length / sizeof(WCHAR);
1846     WCHAR wchCurrent;
1847     int digit;
1848     ULONG RunningTotal = 0;
1849     char bMinus = 0;
1850
1851     while (CharsRemaining >= 1 && *lpwstr <= ' ') {
1852         lpwstr++;
1853         CharsRemaining--;
1854     } /* while */
1855
1856     if (CharsRemaining >= 1) {
1857         if (*lpwstr == '+') {
1858             lpwstr++;
1859             CharsRemaining--;
1860         } else if (*lpwstr == '-') {
1861             bMinus = 1;
1862             lpwstr++;
1863             CharsRemaining--;
1864         } /* if */
1865     } /* if */
1866
1867     if (base == 0) {
1868         base = 10;
1869         if (CharsRemaining >= 2 && lpwstr[0] == '0') {
1870             if (lpwstr[1] == 'b') {
1871                 lpwstr += 2;
1872                 CharsRemaining -= 2;
1873                 base = 2;
1874             } else if (lpwstr[1] == 'o') {
1875                 lpwstr += 2;
1876                 CharsRemaining -= 2;
1877                 base = 8;
1878             } else if (lpwstr[1] == 'x') {
1879                 lpwstr += 2;
1880                 CharsRemaining -= 2;
1881                 base = 16;
1882             } /* if */
1883         } /* if */
1884     } else if (base != 2 && base != 8 && base != 10 && base != 16) {
1885         return STATUS_INVALID_PARAMETER;
1886     } /* if */
1887
1888     if (value == NULL) {
1889         return STATUS_ACCESS_VIOLATION;
1890     } /* if */
1891
1892     while (CharsRemaining >= 1) {
1893         wchCurrent = *lpwstr;
1894         if (wchCurrent >= '0' && wchCurrent <= '9') {
1895             digit = wchCurrent - '0';
1896         } else if (wchCurrent >= 'A' && wchCurrent <= 'Z') {
1897             digit = wchCurrent - 'A' + 10;
1898         } else if (wchCurrent >= 'a' && wchCurrent <= 'z') {
1899             digit = wchCurrent - 'a' + 10;
1900         } else {
1901             digit = -1;
1902         } /* if */
1903         if (digit < 0 || digit >= base) {
1904             *value = bMinus ? -RunningTotal : RunningTotal;
1905             return STATUS_SUCCESS;
1906         } /* if */
1907
1908         RunningTotal = RunningTotal * base + digit;
1909         lpwstr++;
1910         CharsRemaining--;
1911     } /* while */
1912
1913     *value = bMinus ? -RunningTotal : RunningTotal;
1914     return STATUS_SUCCESS;
1915 }
1916
1917
1918 /**************************************************************************
1919  *      RtlIntegerToUnicodeString (NTDLL.@)
1920  *
1921  * Converts an unsigned integer to a '\0' terminated unicode string.
1922  *
1923  * RETURNS
1924  *  Success: STATUS_SUCCESS. str contains the converted number
1925  *  Failure: STATUS_INVALID_PARAMETER, if base is not 0, 2, 8, 10 or 16.
1926  *           STATUS_BUFFER_OVERFLOW, if str is too small to hold the string
1927  *                  (with the '\0' termination). In this case str->Length
1928  *                  is set to the length, the string would have (which can
1929  *                  be larger than the MaximumLength).
1930  *
1931  * NOTES
1932  *  Instead of base 0 it uses 10 as base.
1933  *  If str is NULL it crashes, as the native function does.
1934  *
1935  * DIFFERENCES
1936  *  Do not return STATUS_BUFFER_OVERFLOW when the string is long enough.
1937  *  The native function does this when the string would be longer than 16
1938  *  characters even when the string parameter is long enough.
1939  */
1940 NTSTATUS WINAPI RtlIntegerToUnicodeString(
1941     ULONG value,         /* [I] Value to be converted */
1942     ULONG base,          /* [I] Number base for conversion (allowed 0, 2, 8, 10 or 16) */
1943     UNICODE_STRING *str) /* [O] Destination for the converted value */
1944 {
1945     WCHAR buffer[33];
1946     PWCHAR pos;
1947     WCHAR digit;
1948
1949     if (base == 0) {
1950         base = 10;
1951     } else if (base != 2 && base != 8 && base != 10 && base != 16) {
1952         return STATUS_INVALID_PARAMETER;
1953     } /* if */
1954
1955     pos = &buffer[32];
1956     *pos = '\0';
1957
1958     do {
1959         pos--;
1960         digit = value % base;
1961         value = value / base;
1962         if (digit < 10) {
1963             *pos = '0' + digit;
1964         } else {
1965             *pos = 'A' + digit - 10;
1966         } /* if */
1967     } while (value != 0L);
1968
1969     str->Length = (&buffer[32] - pos) * sizeof(WCHAR);
1970     if (str->Length >= str->MaximumLength) {
1971         return STATUS_BUFFER_OVERFLOW;
1972     } else {
1973         memcpy(str->Buffer, pos, str->Length + sizeof(WCHAR));
1974     } /* if */
1975     return STATUS_SUCCESS;
1976 }
1977
1978
1979 /*************************************************************************
1980  * RtlGUIDFromString (NTDLL.@)
1981  *
1982  * Convert a string representation of a GUID into a GUID.
1983  *
1984  * PARAMS
1985  *  str  [I] String representation in the format "{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}"
1986  *  guid [O] Destination for the converted GUID
1987  *
1988  * RETURNS
1989  *  Success: STATUS_SUCCESS. guid contains the converted value.
1990  *  Failure: STATUS_INVALID_PARAMETER, if str is not in the expected format.
1991  *
1992  * SEE ALSO
1993  *  See RtlStringFromGUID.
1994  */
1995 NTSTATUS WINAPI RtlGUIDFromString(PUNICODE_STRING str, GUID* guid)
1996 {
1997   int i = 0;
1998   const WCHAR *lpszCLSID = str->Buffer;
1999   BYTE* lpOut = (BYTE*)guid;
2000
2001   TRACE("(%s,%p)\n", debugstr_us(str), guid);
2002
2003   /* Convert string: {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}
2004    * to memory:       DWORD... WORD WORD BYTES............
2005    */
2006   while (i <= 37)
2007   {
2008     switch (i)
2009     {
2010     case 0:
2011       if (*lpszCLSID != '{')
2012         return STATUS_INVALID_PARAMETER;
2013       break;
2014
2015     case 9: case 14: case 19: case 24:
2016       if (*lpszCLSID != '-')
2017         return STATUS_INVALID_PARAMETER;
2018       break;
2019
2020     case 37:
2021       if (*lpszCLSID != '}')
2022         return STATUS_INVALID_PARAMETER;
2023       break;
2024
2025     default:
2026       {
2027         WCHAR ch = *lpszCLSID, ch2 = lpszCLSID[1];
2028         unsigned char byte;
2029
2030         /* Read two hex digits as a byte value */
2031         if      (ch >= '0' && ch <= '9') ch = ch - '0';
2032         else if (ch >= 'a' && ch <= 'f') ch = ch - 'a' + 10;
2033         else if (ch >= 'A' && ch <= 'F') ch = ch - 'A' + 10;
2034         else return STATUS_INVALID_PARAMETER;
2035
2036         if      (ch2 >= '0' && ch2 <= '9') ch2 = ch2 - '0';
2037         else if (ch2 >= 'a' && ch2 <= 'f') ch2 = ch2 - 'a' + 10;
2038         else if (ch2 >= 'A' && ch2 <= 'F') ch2 = ch2 - 'A' + 10;
2039         else return STATUS_INVALID_PARAMETER;
2040
2041         byte = ch << 4 | ch2;
2042
2043         switch (i)
2044         {
2045 #ifndef WORDS_BIGENDIAN
2046         /* For Big Endian machines, we store the data such that the
2047          * dword/word members can be read as DWORDS and WORDS correctly. */
2048         /* Dword */
2049         case 1:  lpOut[3] = byte; break;
2050         case 3:  lpOut[2] = byte; break;
2051         case 5:  lpOut[1] = byte; break;
2052         case 7:  lpOut[0] = byte; lpOut += 4;  break;
2053         /* Word */
2054         case 10: case 15: lpOut[1] = byte; break;
2055         case 12: case 17: lpOut[0] = byte; lpOut += 2; break;
2056 #endif
2057         /* Byte */
2058         default: lpOut[0] = byte; lpOut++; break;
2059         }
2060         lpszCLSID++; /* Skip 2nd character of byte */
2061         i++;
2062       }
2063     }
2064     lpszCLSID++;
2065     i++;
2066   }
2067
2068   return STATUS_SUCCESS;
2069 }
2070
2071 /*************************************************************************
2072  * RtlStringFromGUID (NTDLL.@)
2073  *
2074  * Convert a GUID into a string representation of a GUID.
2075  *
2076  * PARAMS
2077  *  guid [I] GUID to convert
2078  *  str  [O] Destination for the converted string
2079  *
2080  * RETURNS
2081  *  Success: STATUS_SUCCESS. str contains the converted value.
2082  *  Failure: STATUS_NO_MEMORY, if memory for str cannot be allocated.
2083  *
2084  * SEE ALSO
2085  *  See RtlGUIDFromString.
2086  */
2087 NTSTATUS WINAPI RtlStringFromGUID(const GUID* guid, UNICODE_STRING *str)
2088 {
2089   static const WCHAR szFormat[] = { '{','%','0','8','l','X','-',
2090     '%','0','4','X','-',  '%','0','4','X','-','%','0','2','X','%','0','2','X',
2091     '-',   '%','0','2','X','%','0','2','X','%','0','2','X','%','0','2','X',
2092     '%','0','2','X','%','0','2','X','}','\0' };
2093
2094   TRACE("(%p,%p)\n", guid, str);
2095
2096   str->Length = GUID_STRING_LENGTH * sizeof(WCHAR);
2097   str->MaximumLength = str->Length + sizeof(WCHAR);
2098   str->Buffer = (WCHAR*)RtlAllocateHeap(GetProcessHeap(), 0, str->MaximumLength);
2099   if (!str->Buffer)
2100   {
2101     str->Length = str->MaximumLength = 0;
2102     return STATUS_NO_MEMORY;
2103   }
2104   sprintfW(str->Buffer, szFormat, guid->Data1, guid->Data2, guid->Data3,
2105           guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3],
2106           guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7]);
2107
2108   return STATUS_SUCCESS;
2109 }