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