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