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