Move some fields (refCount, tls_index and module) from WINE_MODREF to
[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 = 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 = 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 void WINAPI RtlInitAnsiString( PSTRING target, LPCSTR source)
74 {
75     if ((target->Buffer = (LPSTR)source))
76     {
77         target->Length = strlen(source);
78         target->MaximumLength = target->Length + 1;
79     }
80     else target->Length = target->MaximumLength = 0;
81 }
82
83
84 /**************************************************************************
85  *      RtlInitString   (NTDLL.@)
86  */
87 void WINAPI RtlInitString( PSTRING target, LPCSTR source )
88 {
89     RtlInitAnsiString( target, source );
90 }
91
92
93 /**************************************************************************
94  *      RtlFreeAnsiString   (NTDLL.@)
95  */
96 void WINAPI RtlFreeAnsiString( PSTRING str )
97 {
98     if (str->Buffer) RtlFreeHeap( ntdll_get_process_heap(), 0, str->Buffer );
99 }
100
101
102 /**************************************************************************
103  *      RtlFreeOemString   (NTDLL.@)
104  */
105 void WINAPI RtlFreeOemString( PSTRING str )
106 {
107     RtlFreeAnsiString( str );
108 }
109
110
111 /**************************************************************************
112  *      RtlCopyString   (NTDLL.@)
113  */
114 void WINAPI RtlCopyString( STRING *dst, const STRING *src )
115 {
116     if (src)
117     {
118         unsigned int len = min( src->Length, dst->MaximumLength );
119         memcpy( dst->Buffer, src->Buffer, len );
120         dst->Length = len;
121     }
122     else dst->Length = 0;
123 }
124
125
126 /**************************************************************************
127  *      RtlInitUnicodeString   (NTDLL.@)
128  */
129 void WINAPI RtlInitUnicodeString( PUNICODE_STRING target, LPCWSTR source )
130 {
131     if ((target->Buffer = (LPWSTR)source))
132     {
133         target->Length = strlenW(source) * sizeof(WCHAR);
134         target->MaximumLength = target->Length + sizeof(WCHAR);
135     }
136     else target->Length = target->MaximumLength = 0;
137 }
138
139
140 /**************************************************************************
141  *      RtlCreateUnicodeString   (NTDLL.@)
142  */
143 BOOLEAN WINAPI RtlCreateUnicodeString( PUNICODE_STRING target, LPCWSTR src )
144 {
145     int len = (strlenW(src) + 1) * sizeof(WCHAR);
146     if (!(target->Buffer = RtlAllocateHeap( ntdll_get_process_heap(), 0, len ))) return FALSE;
147     memcpy( target->Buffer, src, len );
148     target->MaximumLength = len;
149     target->Length = len - sizeof(WCHAR);
150     return TRUE;
151 }
152
153
154 /**************************************************************************
155  *      RtlCreateUnicodeStringFromAsciiz   (NTDLL.@)
156  */
157 BOOLEAN WINAPI RtlCreateUnicodeStringFromAsciiz( PUNICODE_STRING target, LPCSTR src )
158 {
159     STRING ansi;
160     RtlInitAnsiString( &ansi, src );
161     return !RtlAnsiStringToUnicodeString( target, &ansi, TRUE );
162 }
163
164
165 /**************************************************************************
166  *      RtlFreeUnicodeString   (NTDLL.@)
167  */
168 void WINAPI RtlFreeUnicodeString( PUNICODE_STRING str )
169 {
170     if (str->Buffer) RtlFreeHeap( ntdll_get_process_heap(), 0, str->Buffer );
171 }
172
173
174 /**************************************************************************
175  *      RtlCopyUnicodeString   (NTDLL.@)
176  */
177 void WINAPI RtlCopyUnicodeString( UNICODE_STRING *dst, const UNICODE_STRING *src )
178 {
179     if (src)
180     {
181         unsigned int len = min( src->Length, dst->MaximumLength );
182         memcpy( dst->Buffer, src->Buffer, len );
183         dst->Length = len;
184         /* append terminating NULL if enough space */
185         if (len < dst->MaximumLength) dst->Buffer[len / sizeof(WCHAR)] = 0;
186     }
187     else dst->Length = 0;
188 }
189
190
191 /**************************************************************************
192  *      RtlEraseUnicodeString   (NTDLL.@)
193  */
194 void WINAPI RtlEraseUnicodeString( UNICODE_STRING *str )
195 {
196     if (str->Buffer)
197     {
198         memset( str->Buffer, 0, str->MaximumLength );
199         str->Length = 0;
200     }
201 }
202
203
204 /*
205     COMPARISON FUNCTIONS
206 */
207
208
209 /******************************************************************************
210  *      RtlCompareString   (NTDLL.@)
211  */
212 LONG WINAPI RtlCompareString( const STRING *s1, const STRING *s2, BOOLEAN CaseInsensitive )
213 {
214     unsigned int len;
215     LONG ret = 0;
216     LPCSTR p1, p2;
217
218     len = min(s1->Length, s2->Length);
219     p1 = s1->Buffer;
220     p2 = s2->Buffer;
221
222     if (CaseInsensitive)
223     {
224         while (!ret && len--) ret = toupper(*p1++) - toupper(*p2++);
225     }
226     else
227     {
228         while (!ret && len--) ret = *p1++ - *p2++;
229     }
230     if (!ret) ret = s1->Length - s2->Length;
231     return ret;
232 }
233
234
235 /******************************************************************************
236  *      RtlCompareUnicodeString   (NTDLL.@)
237  */
238 LONG WINAPI RtlCompareUnicodeString( const UNICODE_STRING *s1, const UNICODE_STRING *s2,
239                                      BOOLEAN CaseInsensitive )
240 {
241     unsigned int len;
242     LONG ret = 0;
243     LPCWSTR p1, p2;
244
245     len = min(s1->Length, s2->Length) / sizeof(WCHAR);
246     p1 = s1->Buffer;
247     p2 = s2->Buffer;
248
249     if (CaseInsensitive)
250     {
251         while (!ret && len--) ret = toupperW(*p1++) - toupperW(*p2++);
252     }
253     else
254     {
255         while (!ret && len--) ret = *p1++ - *p2++;
256     }
257     if (!ret) ret = s1->Length - s2->Length;
258     return ret;
259 }
260
261
262 /**************************************************************************
263  *      RtlEqualString   (NTDLL.@)
264  *
265  * Determine if two strings are equal.
266  *
267  * PARAMS
268  *  s1              [I] Source string
269  *  s2              [I] String to compare to s1
270  *  CaseInsensitive [I] TRUE = Case insensitive, FALSE = Case sensitive
271  *
272  * RETURNS
273  *  Non-zero if s1 is equal to s2, 0 otherwise.
274  */
275 BOOLEAN WINAPI RtlEqualString( const STRING *s1, const STRING *s2, BOOLEAN CaseInsensitive )
276 {
277     if (s1->Length != s2->Length) return FALSE;
278     return !RtlCompareString( s1, s2, CaseInsensitive );
279 }
280
281
282 /**************************************************************************
283  *      RtlEqualUnicodeString   (NTDLL.@)
284  *
285  * Unicode version of RtlEqualString.
286  */
287 BOOLEAN WINAPI RtlEqualUnicodeString( const UNICODE_STRING *s1, const UNICODE_STRING *s2,
288                                       BOOLEAN CaseInsensitive )
289 {
290     if (s1->Length != s2->Length) return FALSE;
291     return !RtlCompareUnicodeString( s1, s2, CaseInsensitive );
292 }
293
294
295 /**************************************************************************
296  *      RtlPrefixString   (NTDLL.@)
297  *
298  * Determine if one string is a prefix of another.
299  *
300  * PARAMS
301  *  s1          [I] Prefix to look for in s2
302  *  s2          [I] String that may contain s1 as a prefix
303  *  ignore_case [I] TRUE = Case insensitive, FALSE = Case sensitive
304  *
305  * RETURNS
306  *  TRUE if s2 contains s1 as a prefix, FALSE otherwise.
307  */
308 BOOLEAN WINAPI RtlPrefixString( const STRING *s1, const STRING *s2, BOOLEAN ignore_case )
309 {
310     unsigned int i;
311
312     if (s1->Length > s2->Length) return FALSE;
313     if (ignore_case)
314     {
315         for (i = 0; i < s1->Length; i++)
316             if (toupper(s1->Buffer[i]) != toupper(s2->Buffer[i])) return FALSE;
317     }
318     else
319     {
320         for (i = 0; i < s1->Length; i++)
321             if (s1->Buffer[i] != s2->Buffer[i]) return FALSE;
322     }
323     return TRUE;
324 }
325
326
327 /**************************************************************************
328  *      RtlPrefixUnicodeString   (NTDLL.@)
329  *
330  * Unicode version of RtlPrefixString.
331  */
332 BOOLEAN WINAPI RtlPrefixUnicodeString( const UNICODE_STRING *s1,
333                                        const UNICODE_STRING *s2,
334                                        BOOLEAN ignore_case )
335 {
336     unsigned int i;
337
338     if (s1->Length > s2->Length) return FALSE;
339     if (ignore_case)
340     {
341         for (i = 0; i < s1->Length / sizeof(WCHAR); i++)
342             if (toupperW(s1->Buffer[i]) != toupperW(s2->Buffer[i])) return FALSE;
343     }
344     else
345     {
346         for (i = 0; i < s1->Length / sizeof(WCHAR); i++)
347             if (s1->Buffer[i] != s2->Buffer[i]) return FALSE;
348     }
349     return TRUE;
350 }
351
352
353 /**************************************************************************
354  *      RtlEqualComputerName   (NTDLL.@)
355  *
356  * Determine if two computer names are the same.
357  *
358  * PARAMS
359  *  left  [I] First computer name
360  *  right [I] Second computer name
361  *
362  * RETURNS
363  *  0 if the names are equal, non-zero otherwise.
364  *
365  * NOTES
366  *  The comparason is case insensitive.
367  */
368 NTSTATUS WINAPI RtlEqualComputerName(const UNICODE_STRING *left,
369                                      const UNICODE_STRING *right)
370 {
371     NTSTATUS ret;
372     STRING upLeft, upRight;
373
374     if (!(ret = RtlUpcaseUnicodeStringToOemString( &upLeft, left, TRUE )))
375     {
376        if (!(ret = RtlUpcaseUnicodeStringToOemString( &upRight, right, TRUE )))
377        {
378          ret = RtlEqualString( &upLeft, &upRight, FALSE );
379          RtlFreeOemString( &upRight );
380        }
381        RtlFreeOemString( &upLeft );
382     }
383     return ret;
384 }
385
386 /**************************************************************************
387  *      RtlEqualDomainName   (NTDLL.@)
388  *
389  * Determine if two domain names are the same.
390  *
391  * PARAMS
392  *  left  [I] First domain name
393  *  right [I] Second domain name
394  *
395  * RETURNS
396  *  0 if the names are equal, non-zero otherwise.
397  *
398  * NOTES
399  *  The comparason is case insensitive.
400  */
401 NTSTATUS WINAPI RtlEqualDomainName(const UNICODE_STRING *left,
402                                    const UNICODE_STRING *right)
403 {
404     return RtlEqualComputerName(left, right);
405 }
406
407 /*
408         COPY BETWEEN ANSI_STRING or UNICODE_STRING
409         there is no parameter checking, it just crashes
410 */
411
412
413 /**************************************************************************
414  *      RtlAnsiStringToUnicodeString   (NTDLL.@)
415  *
416  * NOTES
417  *  This function always writes a terminating NUL.
418  */
419 NTSTATUS WINAPI RtlAnsiStringToUnicodeString( PUNICODE_STRING uni,
420                                               PCANSI_STRING ansi,
421                                               BOOLEAN doalloc )
422 {
423     DWORD total = RtlAnsiStringToUnicodeSize( ansi );
424
425     if (total > 0xffff) return STATUS_INVALID_PARAMETER_2;
426     uni->Length = total - sizeof(WCHAR);
427     if (doalloc)
428     {
429         uni->MaximumLength = total;
430         if (!(uni->Buffer = RtlAllocateHeap( ntdll_get_process_heap(), 0, total )))
431             return STATUS_NO_MEMORY;
432     }
433     else if (total > uni->MaximumLength) return STATUS_BUFFER_OVERFLOW;
434
435     RtlMultiByteToUnicodeN( uni->Buffer, uni->Length, NULL, ansi->Buffer, ansi->Length );
436     uni->Buffer[uni->Length / sizeof(WCHAR)] = 0;
437     return STATUS_SUCCESS;
438 }
439
440
441 /**************************************************************************
442  *      RtlOemStringToUnicodeString   (NTDLL.@)
443  *
444  * NOTES
445  *  This function always writes a terminating NUL.
446  *  If the resulting length > 0xffff it returns STATUS_INVALID_PARAMETER_2
447  */
448 NTSTATUS WINAPI RtlOemStringToUnicodeString( UNICODE_STRING *uni,
449                                              const STRING *oem,
450                                              BOOLEAN doalloc )
451 {
452     DWORD total = RtlOemStringToUnicodeSize( oem );
453
454     if (total > 0xffff) return STATUS_INVALID_PARAMETER_2;
455     uni->Length = total - sizeof(WCHAR);
456     if (doalloc)
457     {
458         uni->MaximumLength = total;
459         if (!(uni->Buffer = RtlAllocateHeap( ntdll_get_process_heap(), 0, total )))
460             return STATUS_NO_MEMORY;
461     }
462     else if (total > uni->MaximumLength) return STATUS_BUFFER_OVERFLOW;
463
464     RtlOemToUnicodeN( uni->Buffer, uni->Length, NULL, oem->Buffer, oem->Length );
465     uni->Buffer[uni->Length / sizeof(WCHAR)] = 0;
466     return STATUS_SUCCESS;
467 }
468
469
470 /**************************************************************************
471  *      RtlUnicodeStringToAnsiString   (NTDLL.@)
472  *
473  * NOTES
474  *  This function always writes a terminating NUL.
475  *  Performs a partial copy if ansi is too small.
476  */
477 NTSTATUS WINAPI RtlUnicodeStringToAnsiString( STRING *ansi,
478                                               const UNICODE_STRING *uni,
479                                               BOOLEAN doalloc )
480 {
481     NTSTATUS ret = STATUS_SUCCESS;
482     DWORD len = RtlUnicodeStringToAnsiSize( uni );
483
484     ansi->Length = len - 1;
485     if (doalloc)
486     {
487         ansi->MaximumLength = len;
488         if (!(ansi->Buffer = RtlAllocateHeap( ntdll_get_process_heap(), 0, len )))
489             return STATUS_NO_MEMORY;
490     }
491     else if (ansi->MaximumLength < len)
492     {
493         if (!ansi->MaximumLength) return STATUS_BUFFER_OVERFLOW;
494         ansi->Length = ansi->MaximumLength - 1;
495         ret = STATUS_BUFFER_OVERFLOW;
496     }
497
498     RtlUnicodeToMultiByteN( ansi->Buffer, ansi->Length, NULL, uni->Buffer, uni->Length );
499     ansi->Buffer[ansi->Length] = 0;
500     return ret;
501 }
502
503
504 /**************************************************************************
505  *      RtlUnicodeStringToOemString   (NTDLL.@)
506  *
507  * Convert a Rtl Unicode string to an OEM string.
508  *
509  * PARAMS
510  *  oem     [O] Destination for OEM string
511  *  uni     [I] Source Unicode string
512  *  doalloc [I] TRUE=Allocate new buffer for oem,FALSE=Use existing buffer
513  *
514  * RETURNS
515  *  Success: STATUS_SUCCESS. oem contains the converted string
516  *  Failure: STATUS_BUFFER_OVERFLOW if doalloc is FALSE and oem is too small.
517  *           STATUS_NO_MEMORY if doalloc is TRUE and allocation fails.
518  *
519  * NOTES
520  *   If doalloc is TRUE, the length allocated is uni->Length + 1.
521  *   This function always NUL terminates the string returned.
522  */
523 NTSTATUS WINAPI RtlUnicodeStringToOemString( STRING *oem,
524                                              const UNICODE_STRING *uni,
525                                              BOOLEAN doalloc )
526 {
527     NTSTATUS ret = STATUS_SUCCESS;
528     DWORD len = RtlUnicodeStringToOemSize( uni );
529
530     oem->Length = len - 1;
531     if (doalloc)
532     {
533         oem->MaximumLength = len;
534         if (!(oem->Buffer = RtlAllocateHeap( ntdll_get_process_heap(), 0, len )))
535             return STATUS_NO_MEMORY;
536     }
537     else if (oem->MaximumLength < len)
538     {
539         if (!oem->MaximumLength) return STATUS_BUFFER_OVERFLOW;
540         oem->Length = oem->MaximumLength - 1;
541         ret = STATUS_BUFFER_OVERFLOW;
542     }
543
544     RtlUnicodeToOemN( oem->Buffer, oem->Length, NULL, uni->Buffer, uni->Length );
545     oem->Buffer[oem->Length] = 0;
546     return ret;
547 }
548
549
550 /**************************************************************************
551  *      RtlMultiByteToUnicodeN   (NTDLL.@)
552  *
553  * NOTES
554  *  Performs a partial copy if dst is too small.
555  */
556 NTSTATUS WINAPI RtlMultiByteToUnicodeN( LPWSTR dst, DWORD dstlen, LPDWORD reslen,
557                                         LPCSTR src, DWORD srclen )
558 {
559
560     int ret = cp_mbstowcs( get_ansi_table(), 0, src, srclen, dst, dstlen/sizeof(WCHAR) );
561     if (reslen)
562         *reslen = (ret >= 0) ? ret*sizeof(WCHAR) : dstlen; /* overflow -> we filled up to dstlen */
563     return STATUS_SUCCESS;
564 }
565
566
567 /**************************************************************************
568  *      RtlOemToUnicodeN   (NTDLL.@)
569  */
570 NTSTATUS WINAPI RtlOemToUnicodeN( LPWSTR dst, DWORD dstlen, LPDWORD reslen,
571                                   LPCSTR src, DWORD srclen )
572 {
573     int ret = cp_mbstowcs( get_oem_table(), 0, src, srclen, dst, dstlen/sizeof(WCHAR) );
574     if (reslen)
575         *reslen = (ret >= 0) ? ret*sizeof(WCHAR) : dstlen; /* overflow -> we filled up to dstlen */
576     return STATUS_SUCCESS;
577 }
578
579
580 /**************************************************************************
581  *      RtlUnicodeToMultiByteN   (NTDLL.@)
582  */
583 NTSTATUS WINAPI RtlUnicodeToMultiByteN( LPSTR dst, DWORD dstlen, LPDWORD reslen,
584                                         LPCWSTR src, DWORD srclen )
585 {
586     int ret = cp_wcstombs( get_ansi_table(), 0, src, srclen / sizeof(WCHAR),
587                            dst, dstlen, NULL, NULL );
588     if (reslen)
589         *reslen = (ret >= 0) ? ret : dstlen; /* overflow -> we filled up to dstlen */
590     return STATUS_SUCCESS;
591 }
592
593
594 /**************************************************************************
595  *      RtlUnicodeToOemN   (NTDLL.@)
596  */
597 NTSTATUS WINAPI RtlUnicodeToOemN( LPSTR dst, DWORD dstlen, LPDWORD reslen,
598                                   LPCWSTR src, DWORD srclen )
599 {
600     int ret = cp_wcstombs( get_oem_table(), 0, src, srclen / sizeof(WCHAR),
601                            dst, dstlen, NULL, NULL );
602     if (reslen)
603         *reslen = (ret >= 0) ? ret : dstlen; /* overflow -> we filled up to dstlen */
604     return STATUS_SUCCESS;
605 }
606
607
608 /*
609      CASE CONVERSIONS
610 */
611
612
613 /**************************************************************************
614  *      RtlUpperChar   (NTDLL.@)
615  *
616  * Convert an Ascii character to uppercase.
617  *
618  * PARAMS
619  *  ch [I] Character to convert
620  *
621  * RETURNS
622  *  The uppercase character value.
623  */
624 CHAR WINAPI RtlUpperChar( CHAR ch )
625 {
626     if (ch >= 'a' && ch <= 'z') {
627         return ch - 'a' + 'A';
628     } else {
629         return ch;
630     }
631 }
632
633
634 /**************************************************************************
635  *      RtlUpperString   (NTDLL.@)
636  *
637  * Convert an Ascii string to uppercase.
638  *
639  * PARAMS
640  *  dst [O] Destination for converted string
641  *  src [I] Source string to convert
642  *
643  * RETURNS
644  *  Nothing.
645  */
646 void WINAPI RtlUpperString( STRING *dst, const STRING *src )
647 {
648     unsigned int i, len = min(src->Length, dst->MaximumLength);
649
650     for (i = 0; i < len; i++) dst->Buffer[i] = RtlUpperChar(src->Buffer[i]);
651     dst->Length = len;
652 }
653
654
655 /**************************************************************************
656  *      RtlUpcaseUnicodeChar   (NTDLL.@)
657  *
658  * Unicode version of of RtlUpperChar.
659  */
660 WCHAR WINAPI RtlUpcaseUnicodeChar( WCHAR wch )
661 {
662     return toupperW(wch);
663 }
664
665 /**************************************************************************
666  *      RtlDowncaseUnicodeChar   (NTDLL.@)
667  *
668  * Convert a Unicode character to lowercase.
669  *
670  * PARAMS
671  *  wch [I] Character to convert
672  *
673  * RETURNS
674  *  The lowercase character value.
675  */
676 WCHAR WINAPI RtlDowncaseUnicodeChar(WCHAR wch)
677 {
678     return tolowerW(wch);
679 }
680
681 /**************************************************************************
682  *      RtlUpcaseUnicodeString   (NTDLL.@)
683  *
684  * Convert a Unicode string to uppercase.
685  *
686  * PARAMS
687  *  dest    [O] Destination for converted string
688  *  src     [I] Source string to convert
689  *  doalloc [I] TRUE=Allocate a buffer for dest if it doesn't have one
690  *
691  * RETURNS
692  *  Success: STATUS_SUCCESS. dest contains the converted string.
693  *  Failure: STATUS_NO_MEMORY, if doalloc is TRUE and memory allocation fails, or
694  *           STATUS_BUFFER_OVERFLOW, if doalloc is FALSE and dest is too small.
695  *
696  * NOTES
697  *  dest is never NUL terminated because it may be equal to src, and src
698  *  might not be NUL terminated. dest->Length is only set upon success.
699  */
700 NTSTATUS WINAPI RtlUpcaseUnicodeString( UNICODE_STRING *dest,
701                                         const UNICODE_STRING *src,
702                                         BOOLEAN doalloc )
703 {
704     DWORD i, len = src->Length;
705
706     if (doalloc)
707     {
708         dest->MaximumLength = len;
709         if (!(dest->Buffer = RtlAllocateHeap( ntdll_get_process_heap(), 0, len )))
710             return STATUS_NO_MEMORY;
711     }
712     else if (len > dest->MaximumLength) return STATUS_BUFFER_OVERFLOW;
713
714     for (i = 0; i < len/sizeof(WCHAR); i++) dest->Buffer[i] = toupperW(src->Buffer[i]);
715     dest->Length = len;
716     return STATUS_SUCCESS;
717 }
718
719
720 /**************************************************************************
721  *      RtlUpcaseUnicodeStringToAnsiString   (NTDLL.@)
722  *
723  * NOTES
724  *  writes terminating 0
725  */
726 NTSTATUS WINAPI RtlUpcaseUnicodeStringToAnsiString( STRING *dst,
727                                                     const UNICODE_STRING *src,
728                                                     BOOLEAN doalloc )
729 {
730     NTSTATUS ret;
731     UNICODE_STRING upcase;
732
733     if (!(ret = RtlUpcaseUnicodeString( &upcase, src, TRUE )))
734     {
735         ret = RtlUnicodeStringToAnsiString( dst, &upcase, doalloc );
736         RtlFreeUnicodeString( &upcase );
737     }
738     return ret;
739 }
740
741
742 /**************************************************************************
743  *      RtlUpcaseUnicodeStringToOemString   (NTDLL.@)
744  *
745  * NOTES
746  *  writes terminating 0
747  */
748 NTSTATUS WINAPI RtlUpcaseUnicodeStringToOemString( STRING *dst,
749                                                    const UNICODE_STRING *src,
750                                                    BOOLEAN doalloc )
751 {
752     NTSTATUS ret;
753     UNICODE_STRING upcase;
754
755     if (!(ret = RtlUpcaseUnicodeString( &upcase, src, TRUE )))
756     {
757         ret = RtlUnicodeStringToOemString( dst, &upcase, doalloc );
758         RtlFreeUnicodeString( &upcase );
759     }
760     return ret;
761 }
762
763
764 /**************************************************************************
765  *      RtlUpcaseUnicodeToMultiByteN   (NTDLL.@)
766  */
767 NTSTATUS WINAPI RtlUpcaseUnicodeToMultiByteN( LPSTR dst, DWORD dstlen, LPDWORD reslen,
768                                               LPCWSTR src, DWORD srclen )
769 {
770     NTSTATUS ret;
771     LPWSTR upcase;
772     DWORD i;
773
774     if (!(upcase = RtlAllocateHeap( ntdll_get_process_heap(), 0, srclen ))) return STATUS_NO_MEMORY;
775     for (i = 0; i < srclen/sizeof(WCHAR); i++) upcase[i] = toupperW(src[i]);
776     ret = RtlUnicodeToMultiByteN( dst, dstlen, reslen, upcase, srclen );
777     RtlFreeHeap( ntdll_get_process_heap(), 0, upcase );
778     return ret;
779 }
780
781
782 /**************************************************************************
783  *      RtlUpcaseUnicodeToOemN   (NTDLL.@)
784  */
785 NTSTATUS WINAPI RtlUpcaseUnicodeToOemN( LPSTR dst, DWORD dstlen, LPDWORD reslen,
786                                         LPCWSTR src, DWORD srclen )
787 {
788     NTSTATUS ret;
789     LPWSTR upcase;
790     DWORD i;
791
792     if (!(upcase = RtlAllocateHeap( ntdll_get_process_heap(), 0, srclen ))) return STATUS_NO_MEMORY;
793     for (i = 0; i < srclen/sizeof(WCHAR); i++) upcase[i] = toupperW(src[i]);
794     ret = RtlUnicodeToOemN( dst, dstlen, reslen, upcase, srclen );
795     RtlFreeHeap( ntdll_get_process_heap(), 0, upcase );
796     return ret;
797 }
798
799
800 /*
801         STRING SIZE
802 */
803
804
805 /**************************************************************************
806  *      RtlOemStringToUnicodeSize   (NTDLL.@)
807  *      RtlxOemStringToUnicodeSize  (NTDLL.@)
808  *
809  * Calculate the size in bytes necessary for the Unicode conversion of str,
810  * including the terminating NUL.
811  *
812  * PARAMS
813  *  str [I] String to calculate the size of
814  *
815  * RETURNS
816  *  The calculated size.
817  */
818 UINT WINAPI RtlOemStringToUnicodeSize( const STRING *str )
819 {
820     int ret = cp_mbstowcs( get_oem_table(), 0, str->Buffer, str->Length, NULL, 0 );
821     return (ret + 1) * sizeof(WCHAR);
822 }
823
824
825 /**************************************************************************
826  *      RtlAnsiStringToUnicodeSize   (NTDLL.@)
827  *      RtlxAnsiStringToUnicodeSize  (NTDLL.@)
828  *
829  * Calculate the size in bytes necessary for the Unicode conversion of str,
830  * including the terminating NUL.
831  *
832  * PARAMS
833  *  str [I] String to calculate the size of
834  *
835  * RETURNS
836  *  The calculated size.
837  */
838 DWORD WINAPI RtlAnsiStringToUnicodeSize( const STRING *str )
839 {
840     DWORD ret;
841     RtlMultiByteToUnicodeSize( &ret, str->Buffer, str->Length );
842     return ret + sizeof(WCHAR);
843 }
844
845
846 /**************************************************************************
847  *      RtlMultiByteToUnicodeSize   (NTDLL.@)
848  *
849  * Compute the size in bytes necessary for the Unicode conversion of str,
850  * without the terminating NUL.
851  *
852  * PARAMS
853  *  size [O] Destination for size
854  *  str  [I] String to calculate the size of
855  *  len  [I] Length of str
856  *
857  * RETURNS
858  *  STATUS_SUCCESS.
859  */
860 NTSTATUS WINAPI RtlMultiByteToUnicodeSize( DWORD *size, LPCSTR str, UINT len )
861 {
862     *size = cp_mbstowcs( get_ansi_table(), 0, str, len, NULL, 0 ) * sizeof(WCHAR);
863     return STATUS_SUCCESS;
864 }
865
866
867 /**************************************************************************
868  *      RtlUnicodeToMultiByteSize   (NTDLL.@)
869  *
870  * Calculate the size necessary for the multibyte conversion of str,
871  * without the terminating NULL.
872  *
873  * PARAMS
874  *  size [O] Destination for size
875  *  str  [I] String to calculate the size of
876  *  len  [I] Length of str
877  *
878  * RETURNS
879  *  STATUS_SUCCESS.
880  */
881 NTSTATUS WINAPI RtlUnicodeToMultiByteSize( PULONG size, LPCWSTR str, ULONG len )
882 {
883     *size = cp_wcstombs( get_ansi_table(), 0, str, len / sizeof(WCHAR), NULL, 0, NULL, NULL );
884     return STATUS_SUCCESS;
885 }
886
887
888 /**************************************************************************
889  *      RtlUnicodeStringToAnsiSize   (NTDLL.@)
890  *      RtlxUnicodeStringToAnsiSize  (NTDLL.@)
891  *
892  * Calculate the size in bytes necessary for the Ansi conversion of str,
893  * including the terminating NUL.
894  *
895  * PARAMS
896  *  str [I] String to calculate the size of
897  *
898  * RETURNS
899  *  The calculated size.
900  */
901 DWORD WINAPI RtlUnicodeStringToAnsiSize( const UNICODE_STRING *str )
902 {
903     DWORD ret;
904     RtlUnicodeToMultiByteSize( &ret, str->Buffer, str->Length );
905     return ret + 1;
906 }
907
908
909 /**************************************************************************
910  *      RtlUnicodeStringToOemSize   (NTDLL.@)
911  *      RtlxUnicodeStringToOemSize  (NTDLL.@)
912  *
913  * Calculate the size in bytes necessary for the OEM conversion of str,
914  * including the terminating NUL.
915  *
916  * PARAMS
917  *  str [I] String to calculate the size of
918  *
919  * RETURNS
920  *  The calculated size.
921  */
922 DWORD WINAPI RtlUnicodeStringToOemSize( const UNICODE_STRING *str )
923 {
924     return cp_wcstombs( get_oem_table(), 0, str->Buffer, str->Length / sizeof(WCHAR),
925                         NULL, 0, NULL, NULL ) + 1;
926 }
927
928
929 /**************************************************************************
930  *      RtlAppendStringToString   (NTDLL.@)
931  */
932 NTSTATUS WINAPI RtlAppendStringToString( STRING *dst, const STRING *src )
933 {
934     unsigned int len = src->Length + dst->Length;
935     if (len > dst->MaximumLength) return STATUS_BUFFER_TOO_SMALL;
936     memcpy( dst->Buffer + dst->Length, src->Buffer, src->Length );
937     dst->Length = len;
938     return STATUS_SUCCESS;
939 }
940
941
942 /**************************************************************************
943  *      RtlAppendAsciizToString   (NTDLL.@)
944  */
945 NTSTATUS WINAPI RtlAppendAsciizToString( STRING *dst, LPCSTR src )
946 {
947     if (src)
948     {
949         unsigned int srclen = strlen(src);
950         unsigned int total  = srclen + dst->Length;
951         if (total > dst->MaximumLength) return STATUS_BUFFER_TOO_SMALL;
952         memcpy( dst->Buffer + dst->Length, src, srclen );
953         dst->Length = total;
954     }
955     return STATUS_SUCCESS;
956 }
957
958
959 /**************************************************************************
960  *      RtlAppendUnicodeToString   (NTDLL.@)
961  */
962 NTSTATUS WINAPI RtlAppendUnicodeToString( UNICODE_STRING *dst, LPCWSTR src )
963 {
964     if (src)
965     {
966         unsigned int srclen = strlenW(src) * sizeof(WCHAR);
967         unsigned int total  = srclen + dst->Length;
968         if (total > dst->MaximumLength) return STATUS_BUFFER_TOO_SMALL;
969         memcpy( dst->Buffer + dst->Length/sizeof(WCHAR), src, srclen );
970         dst->Length = total;
971         /* append terminating NULL if enough space */
972         if (total < dst->MaximumLength) dst->Buffer[total / sizeof(WCHAR)] = 0;
973     }
974     return STATUS_SUCCESS;
975 }
976
977
978 /**************************************************************************
979  *      RtlAppendUnicodeStringToString   (NTDLL.@)
980  */
981 NTSTATUS WINAPI RtlAppendUnicodeStringToString( UNICODE_STRING *dst, const UNICODE_STRING *src )
982 {
983     unsigned int len = src->Length + dst->Length;
984     if (len > dst->MaximumLength) return STATUS_BUFFER_TOO_SMALL;
985     memcpy( dst->Buffer + dst->Length/sizeof(WCHAR), src->Buffer, src->Length );
986     dst->Length = len;
987     /* append terminating NULL if enough space */
988     if (len < dst->MaximumLength) dst->Buffer[len / sizeof(WCHAR)] = 0;
989     return STATUS_SUCCESS;
990 }
991
992
993 /*
994         MISC
995 */
996
997 /**************************************************************************
998  *      RtlIsTextUnicode (NTDLL.@)
999  *
1000  * Attempt to guess whether a text buffer is Unicode.
1001  *
1002  * PARAMS
1003  *  buf [I] Text buffer to test
1004  *  len [I] Length of buf
1005  *  pf  [O] Destination for test results
1006  *
1007  * RETURNS
1008  *  The length of the string if all tests were passed, 0 otherwise.
1009  *
1010  * FIXME
1011  *  Should implement more tests.
1012  */
1013 DWORD WINAPI RtlIsTextUnicode(
1014         LPVOID buf,
1015         DWORD len,
1016         DWORD *pf)
1017 {
1018         LPWSTR s = buf;
1019         DWORD flags = -1, out_flags = 0;
1020
1021         if (!len)
1022                 goto out;
1023         if (pf)
1024                 flags = *pf;
1025         /*
1026          * Apply various tests to the text string. According to the
1027          * docs, each test "passed" sets the corresponding flag in
1028          * the output flags. But some of the tests are mutually
1029          * exclusive, so I don't see how you could pass all tests ...
1030          */
1031
1032         /* Check for an odd length ... pass if even. */
1033         if (!(len & 1))
1034                 out_flags |= IS_TEXT_UNICODE_ODD_LENGTH;
1035
1036         /* Check for the special unicode marker byte. */
1037         if (*s == 0xFEFF)
1038                 out_flags |= IS_TEXT_UNICODE_SIGNATURE;
1039
1040         /*
1041          * Check whether the string passed all of the tests.
1042          */
1043         flags &= ITU_IMPLEMENTED_TESTS;
1044         if ((out_flags & flags) != flags)
1045                 len = 0;
1046 out:
1047         if (pf)
1048                 *pf = out_flags;
1049         return len;
1050 }
1051
1052
1053 /**************************************************************************
1054  *      RtlCharToInteger   (NTDLL.@)
1055  *
1056  * Convert a character string into its integer equivalent.
1057  *
1058  * On success assign an integer value and return STATUS_SUCCESS.
1059  * For base 0 accept: {whitespace} [+|-] [0[x|o|b]] {digits}
1060  * For bases 2, 8, 10 and 16 accept: {whitespace} [+|-] {digits}
1061  * For other bases return STATUS_INVALID_PARAMETER.
1062  * For value == NULL return STATUS_ACCESS_VIOLATION.
1063  * No check of value overflow: Just assign lower 32 bits (as native DLL).
1064  * Do not check for str != NULL (as native DLL).
1065  *
1066  * Difference:
1067  * - Do not read garbage behind '\0' as native DLL does.
1068  */
1069 NTSTATUS WINAPI RtlCharToInteger(
1070         PCSZ str,
1071         ULONG base,
1072         ULONG *value)
1073 {
1074     CHAR chCurrent;
1075     int digit;
1076     ULONG RunningTotal = 0;
1077     char bMinus = 0;
1078
1079     while (*str != '\0' && *str <= ' ') {
1080         str++;
1081     } /* while */
1082
1083     if (*str == '+') {
1084         str++;
1085     } else if (*str == '-') {
1086         bMinus = 1;
1087         str++;
1088     } /* if */
1089
1090     if (base == 0) {
1091         base = 10;
1092         if (str[0] == '0') {
1093             if (str[1] == 'b') {
1094                 str += 2;
1095                 base = 2;
1096             } else if (str[1] == 'o') {
1097                 str += 2;
1098                 base = 8;
1099             } else if (str[1] == 'x') {
1100                 str += 2;
1101                 base = 16;
1102             } /* if */
1103         } /* if */
1104     } else if (base != 2 && base != 8 && base != 10 && base != 16) {
1105         return STATUS_INVALID_PARAMETER;
1106     } /* if */
1107
1108     if (value == NULL) {
1109         return STATUS_ACCESS_VIOLATION;
1110     } /* if */
1111
1112     while (*str != '\0') {
1113         chCurrent = *str;
1114         if (chCurrent >= '0' && chCurrent <= '9') {
1115             digit = chCurrent - '0';
1116         } else if (chCurrent >= 'A' && chCurrent <= 'Z') {
1117             digit = chCurrent - 'A' + 10;
1118         } else if (chCurrent >= 'a' && chCurrent <= 'z') {
1119             digit = chCurrent - 'a' + 10;
1120         } else {
1121             digit = -1;
1122         } /* if */
1123         if (digit < 0 || digit >= base) {
1124             *value = bMinus ? -RunningTotal : RunningTotal;
1125             return STATUS_SUCCESS;
1126         } /* if */
1127
1128         RunningTotal = RunningTotal * base + digit;
1129         str++;
1130     } /* while */
1131
1132     *value = bMinus ? -RunningTotal : RunningTotal;
1133     return STATUS_SUCCESS;
1134 }
1135
1136
1137 /**************************************************************************
1138  *      RtlIntegerToChar   (NTDLL.@)
1139  *
1140  * Convert an unsigned integer to a character string.
1141  *
1142  * NOTES
1143  * On success assign a string and return STATUS_SUCCESS.
1144  * If base is not 0 (=10), 2, 8, 10 or 16 return STATUS_INVALID_PARAMETER
1145  * Writes at most length characters to the string str.
1146  * Str is '\0' terminated when length allowes it.
1147  * When str fits exactly in length characters the '\0' is ommitted.
1148  * When str would be larger than length: return STATUS_BUFFER_OVERFLOW
1149  * For str == NULL return STATUS_ACCESS_VIOLATION.
1150  */
1151 NTSTATUS WINAPI RtlIntegerToChar(
1152         ULONG value,
1153         ULONG base,
1154         ULONG length,
1155         PCHAR str)
1156 {
1157     CHAR buffer[33];
1158     PCHAR pos;
1159     CHAR digit;
1160     ULONG len;
1161
1162     if (base == 0) {
1163         base = 10;
1164     } else if (base != 2 && base != 8 && base != 10 && base != 16) {
1165         return STATUS_INVALID_PARAMETER;
1166     } /* if */
1167
1168     pos = &buffer[32];
1169     *pos = '\0';
1170
1171     do {
1172         pos--;
1173         digit = value % base;
1174         value = value / base;
1175         if (digit < 10) {
1176             *pos = '0' + digit;
1177         } else {
1178             *pos = 'A' + digit - 10;
1179         } /* if */
1180     } while (value != 0L);
1181
1182     len = &buffer[32] - pos;
1183     if (len > length) {
1184         return STATUS_BUFFER_OVERFLOW;
1185     } else if (str == NULL) {
1186         return STATUS_ACCESS_VIOLATION;
1187     } else if (len == length) {
1188         memcpy(str, pos, len);
1189     } else {
1190         memcpy(str, pos, len + 1);
1191     } /* if */
1192     return STATUS_SUCCESS;
1193 }
1194
1195
1196 /**************************************************************************
1197  *      RtlUnicodeStringToInteger (NTDLL.@)
1198  *
1199  * Convert an unicode string into its integer equivalent.
1200  *
1201  * NOTES
1202  * On success assign an integer value and return STATUS_SUCCESS.
1203  * For base 0 accept: {whitespace} [+|-] [0[x|o|b]] {digits}
1204  * For bases 2, 8, 10 and 16 accept: {whitespace} [+|-] {digits}
1205  * For other bases return STATUS_INVALID_PARAMETER.
1206  * For value == NULL return STATUS_ACCESS_VIOLATION.
1207  * No check of value overflow: Just assign lower 32 bits (as native DLL).
1208  * Do not check for str != NULL (as native DLL).
1209  *
1210  * Difference:
1211  * - Do not read garbage on string length 0 as native DLL does.
1212  */
1213 NTSTATUS WINAPI RtlUnicodeStringToInteger(
1214         const UNICODE_STRING *str,
1215         ULONG base,
1216         ULONG *value)
1217 {
1218     LPWSTR lpwstr = str->Buffer;
1219     USHORT CharsRemaining = str->Length / sizeof(WCHAR);
1220     WCHAR wchCurrent;
1221     int digit;
1222     ULONG RunningTotal = 0;
1223     char bMinus = 0;
1224
1225     while (CharsRemaining >= 1 && *lpwstr <= ' ') {
1226         lpwstr++;
1227         CharsRemaining--;
1228     } /* while */
1229
1230     if (CharsRemaining >= 1) {
1231         if (*lpwstr == '+') {
1232             lpwstr++;
1233             CharsRemaining--;
1234         } else if (*lpwstr == '-') {
1235             bMinus = 1;
1236             lpwstr++;
1237             CharsRemaining--;
1238         } /* if */
1239     } /* if */
1240
1241     if (base == 0) {
1242         base = 10;
1243         if (CharsRemaining >= 2 && lpwstr[0] == '0') {
1244             if (lpwstr[1] == 'b') {
1245                 lpwstr += 2;
1246                 CharsRemaining -= 2;
1247                 base = 2;
1248             } else if (lpwstr[1] == 'o') {
1249                 lpwstr += 2;
1250                 CharsRemaining -= 2;
1251                 base = 8;
1252             } else if (lpwstr[1] == 'x') {
1253                 lpwstr += 2;
1254                 CharsRemaining -= 2;
1255                 base = 16;
1256             } /* if */
1257         } /* if */
1258     } else if (base != 2 && base != 8 && base != 10 && base != 16) {
1259         return STATUS_INVALID_PARAMETER;
1260     } /* if */
1261
1262     if (value == NULL) {
1263         return STATUS_ACCESS_VIOLATION;
1264     } /* if */
1265
1266     while (CharsRemaining >= 1) {
1267         wchCurrent = *lpwstr;
1268         if (wchCurrent >= '0' && wchCurrent <= '9') {
1269             digit = wchCurrent - '0';
1270         } else if (wchCurrent >= 'A' && wchCurrent <= 'Z') {
1271             digit = wchCurrent - 'A' + 10;
1272         } else if (wchCurrent >= 'a' && wchCurrent <= 'z') {
1273             digit = wchCurrent - 'a' + 10;
1274         } else {
1275             digit = -1;
1276         } /* if */
1277         if (digit < 0 || digit >= base) {
1278             *value = bMinus ? -RunningTotal : RunningTotal;
1279             return STATUS_SUCCESS;
1280         } /* if */
1281
1282         RunningTotal = RunningTotal * base + digit;
1283         lpwstr++;
1284         CharsRemaining--;
1285     } /* while */
1286
1287     *value = bMinus ? -RunningTotal : RunningTotal;
1288     return STATUS_SUCCESS;
1289 }
1290
1291
1292 /**************************************************************************
1293  *      RtlIntegerToUnicodeString (NTDLL.@)
1294  *
1295  * Convert an unsigned integer to a NULL terminated unicode string.
1296  *
1297  * NOTES
1298  * On success assign a NULL terminated string and return STATUS_SUCCESS.
1299  * If base is not 0 (=10), 2, 8, 10 or 16 return STATUS_INVALID_PARAMETER.
1300  * If str is too small to hold the string (with the NULL termination):
1301  * Set str->Length to the length the string would have (which can be
1302  * larger than the MaximumLength) and return STATUS_BUFFER_OVERFLOW.
1303  * Do not check for str != NULL (as native DLL).
1304  *
1305  * Difference:
1306  * - Do not return STATUS_BUFFER_OVERFLOW when the string is long enough.
1307  *   The native DLL does this when the string would be longer than 16
1308  *   characters even when the string parameter is long enough.
1309  */
1310 NTSTATUS WINAPI RtlIntegerToUnicodeString(
1311         ULONG value,
1312         ULONG base,
1313         UNICODE_STRING *str)
1314 {
1315     WCHAR buffer[33];
1316     PWCHAR pos;
1317     WCHAR digit;
1318
1319     if (base == 0) {
1320         base = 10;
1321     } else if (base != 2 && base != 8 && base != 10 && base != 16) {
1322         return STATUS_INVALID_PARAMETER;
1323     } /* if */
1324
1325     pos = &buffer[32];
1326     *pos = '\0';
1327
1328     do {
1329         pos--;
1330         digit = value % base;
1331         value = value / base;
1332         if (digit < 10) {
1333             *pos = '0' + digit;
1334         } else {
1335             *pos = 'A' + digit - 10;
1336         } /* if */
1337     } while (value != 0L);
1338
1339     str->Length = (&buffer[32] - pos) * sizeof(WCHAR);
1340     if (str->Length >= str->MaximumLength) {
1341         return STATUS_BUFFER_OVERFLOW;
1342     } else {
1343         memcpy(str->Buffer, pos, str->Length + 1);
1344     } /* if */
1345     return STATUS_SUCCESS;
1346 }