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