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