- DDRAW_SYSTEMMEMORY is handled like OFFSCREENPLAIN for now
[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  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21
22 #include "config.h"
23
24 #include <assert.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <ctype.h>
28
29 #include "ntddk.h"
30 #include "wine/unicode.h"
31 #include "wine/debug.h"
32
33 WINE_DEFAULT_DEBUG_CHANNEL(ntdll);
34
35 UINT NlsAnsiCodePage = 1252;
36 BYTE NlsMbCodePageTag = 0;
37 BYTE NlsMbOemCodePageTag = 0;
38
39 static const union cptable *ansi_table;
40 static const union cptable *oem_table;
41
42 inline static const union cptable *get_ansi_table(void)
43 {
44     if (!ansi_table) ansi_table = cp_get_table( 1252 );
45     return ansi_table;
46 }
47
48 inline static const union cptable *get_oem_table(void)
49 {
50     if (!oem_table) oem_table = cp_get_table( 437 );
51     return oem_table;
52 }
53
54
55 /**************************************************************************
56  *      __wine_init_codepages   (NTDLL.@)
57  *
58  * Set the code page once kernel32 is loaded. Should be done differently.
59  */
60 void __wine_init_codepages( const union cptable *ansi, const union cptable *oem )
61 {
62     ansi_table = ansi;
63     oem_table = oem;
64     NlsAnsiCodePage = ansi->info.codepage;
65 }
66
67
68 /**************************************************************************
69  *      RtlInitAnsiString   (NTDLL.@)
70  */
71 void WINAPI RtlInitAnsiString( PSTRING target, LPCSTR source)
72 {
73     if ((target->Buffer = (LPSTR)source))
74     {
75         target->Length = strlen(source);
76         target->MaximumLength = target->Length + 1;
77     }
78     else target->Length = target->MaximumLength = 0;
79 }
80
81
82 /**************************************************************************
83  *      RtlInitString   (NTDLL.@)
84  */
85 void WINAPI RtlInitString( PSTRING target, LPCSTR source )
86 {
87     RtlInitAnsiString( target, source );
88 }
89
90
91 /**************************************************************************
92  *      RtlFreeAnsiString   (NTDLL.@)
93  */
94 void WINAPI RtlFreeAnsiString( PSTRING str )
95 {
96     if (str->Buffer) RtlFreeHeap( GetProcessHeap(), 0, str->Buffer );
97 }
98
99
100 /**************************************************************************
101  *      RtlFreeOemString   (NTDLL.@)
102  */
103 void WINAPI RtlFreeOemString( PSTRING str )
104 {
105     RtlFreeAnsiString( str );
106 }
107
108
109 /**************************************************************************
110  *      RtlCopyString   (NTDLL.@)
111  */
112 void WINAPI RtlCopyString( STRING *dst, const STRING *src )
113 {
114     if (src)
115     {
116         unsigned int len = min( src->Length, dst->MaximumLength );
117         memcpy( dst->Buffer, src->Buffer, len );
118         dst->Length = len;
119     }
120     else dst->Length = 0;
121 }
122
123
124 /**************************************************************************
125  *      RtlInitUnicodeString   (NTDLL.@)
126  */
127 void WINAPI RtlInitUnicodeString( PUNICODE_STRING target, LPCWSTR source )
128 {
129     if ((target->Buffer = (LPWSTR)source))
130     {
131         target->Length = strlenW(source) * sizeof(WCHAR);
132         target->MaximumLength = target->Length + sizeof(WCHAR);
133     }
134     else target->Length = target->MaximumLength = 0;
135 }
136
137
138 /**************************************************************************
139  *      RtlCreateUnicodeString   (NTDLL.@)
140  */
141 BOOLEAN WINAPI RtlCreateUnicodeString( PUNICODE_STRING target, LPCWSTR src )
142 {
143     int len = (strlenW(src) + 1) * sizeof(WCHAR);
144     if (!(target->Buffer = RtlAllocateHeap( GetProcessHeap(), 0, len ))) return FALSE;
145     memcpy( target->Buffer, src, len );
146     target->MaximumLength = len;
147     target->Length = len - 2;
148     return TRUE;
149 }
150
151
152 /**************************************************************************
153  *      RtlCreateUnicodeStringFromAsciiz   (NTDLL.@)
154  */
155 BOOLEAN WINAPI RtlCreateUnicodeStringFromAsciiz( PUNICODE_STRING target, LPCSTR src )
156 {
157     STRING ansi;
158     RtlInitAnsiString( &ansi, src );
159     return !RtlAnsiStringToUnicodeString( target, &ansi, TRUE );
160 }
161
162
163 /**************************************************************************
164  *      RtlFreeUnicodeString   (NTDLL.@)
165  */
166 void WINAPI RtlFreeUnicodeString( PUNICODE_STRING str )
167 {
168     if (str->Buffer) RtlFreeHeap( GetProcessHeap(), 0, str->Buffer );
169 }
170
171
172 /**************************************************************************
173  *      RtlCopyUnicodeString   (NTDLL.@)
174  */
175 void WINAPI RtlCopyUnicodeString( UNICODE_STRING *dst, const UNICODE_STRING *src )
176 {
177     if (src)
178     {
179         unsigned int len = min( src->Length, dst->MaximumLength );
180         memcpy( dst->Buffer, src->Buffer, len );
181         dst->Length = len;
182         /* append terminating NULL if enough space */
183         if (len < dst->MaximumLength) dst->Buffer[len / sizeof(WCHAR)] = 0;
184     }
185     else dst->Length = 0;
186 }
187
188
189 /**************************************************************************
190  *      RtlEraseUnicodeString   (NTDLL.@)
191  */
192 void WINAPI RtlEraseUnicodeString( UNICODE_STRING *str )
193 {
194     if (str->Buffer)
195     {
196         memset( str->Buffer, 0, str->MaximumLength );
197         str->Length = 0;
198     }
199 }
200
201 /*
202     COMPARISON FUNCTIONS
203 */
204
205 /******************************************************************************
206  *      RtlCompareString   (NTDLL.@)
207  */
208 LONG WINAPI RtlCompareString( const STRING *s1, const STRING *s2, BOOLEAN CaseInsensitive )
209 {
210     unsigned int len;
211     LONG ret = 0;
212     LPCSTR p1, p2;
213
214     len = min(s1->Length, s2->Length);
215     p1 = s1->Buffer;
216     p2 = s2->Buffer;
217
218     if (CaseInsensitive)
219     {
220         while (!ret && len--) ret = toupper(*p1++) - toupper(*p2++);
221     }
222     else
223     {
224         while (!ret && len--) ret = *p1++ - *p2++;
225     }
226     if (!ret) ret = s1->Length - s2->Length;
227     return ret;
228 }
229
230
231 /******************************************************************************
232  *      RtlCompareUnicodeString   (NTDLL.@)
233  */
234 LONG WINAPI RtlCompareUnicodeString( const UNICODE_STRING *s1, const UNICODE_STRING *s2,
235                                      BOOLEAN CaseInsensitive )
236 {
237     unsigned int len;
238     LONG ret = 0;
239     LPCWSTR p1, p2;
240
241     len = min(s1->Length, s2->Length) / sizeof(WCHAR);
242     p1 = s1->Buffer;
243     p2 = s2->Buffer;
244
245     if (CaseInsensitive)
246     {
247         while (!ret && len--) ret = toupperW(*p1++) - toupperW(*p2++);
248     }
249     else
250     {
251         while (!ret && len--) ret = *p1++ - *p2++;
252     }
253     if (!ret) ret = s1->Length - s2->Length;
254     return ret;
255 }
256
257
258 /**************************************************************************
259  *      RtlEqualString   (NTDLL.@)
260  */
261 BOOLEAN WINAPI RtlEqualString( const STRING *s1, const STRING *s2, BOOLEAN CaseInsensitive )
262 {
263     if (s1->Length != s2->Length) return FALSE;
264     return !RtlCompareString( s1, s2, CaseInsensitive );
265 }
266
267
268 /**************************************************************************
269  *      RtlEqualUnicodeString   (NTDLL.@)
270  */
271 BOOLEAN WINAPI RtlEqualUnicodeString( const UNICODE_STRING *s1, const UNICODE_STRING *s2,
272                                       BOOLEAN CaseInsensitive )
273 {
274     if (s1->Length != s2->Length) return FALSE;
275     return !RtlCompareUnicodeString( s1, s2, CaseInsensitive );
276 }
277
278
279 /**************************************************************************
280  *      RtlPrefixString   (NTDLL.@)
281  *
282  * Test if s1 is a prefix in s2
283  */
284 BOOLEAN WINAPI RtlPrefixString( const STRING *s1, const STRING *s2, BOOLEAN ignore_case )
285 {
286     unsigned int i;
287
288     if (s1->Length > s2->Length) return FALSE;
289     if (ignore_case)
290     {
291         for (i = 0; i < s1->Length; i++)
292             if (toupper(s1->Buffer[i]) != toupper(s2->Buffer[i])) return FALSE;
293     }
294     else
295     {
296         for (i = 0; i < s1->Length; i++)
297             if (s1->Buffer[i] != s2->Buffer[i]) return FALSE;
298     }
299     return TRUE;
300 }
301
302
303 /**************************************************************************
304  *      RtlPrefixUnicodeString   (NTDLL.@)
305  *
306  * Test if s1 is a prefix in s2
307  */
308 BOOLEAN WINAPI RtlPrefixUnicodeString( const UNICODE_STRING *s1,
309                                        const UNICODE_STRING *s2,
310                                        BOOLEAN ignore_case )
311 {
312     unsigned int i;
313
314     if (s1->Length > s2->Length) return FALSE;
315     if (ignore_case)
316     {
317         for (i = 0; i < s1->Length / sizeof(WCHAR); i++)
318             if (toupper(s1->Buffer[i]) != toupper(s2->Buffer[i])) return FALSE;
319     }
320     else
321     {
322         for (i = 0; i < s1->Length / sizeof(WCHAR); i++)
323             if (s1->Buffer[i] != s2->Buffer[i]) return FALSE;
324     }
325     return TRUE;
326 }
327
328
329 /*
330         COPY BETWEEN ANSI_STRING or UNICODE_STRING
331         there is no parameter checking, it just crashes
332 */
333
334
335 /**************************************************************************
336  *      RtlAnsiStringToUnicodeString   (NTDLL.@)
337  *
338  * NOTES:
339  *  writes terminating 0
340  */
341 NTSTATUS WINAPI RtlAnsiStringToUnicodeString( UNICODE_STRING *uni,
342                                               const STRING *ansi,
343                                               BOOLEAN doalloc )
344 {
345     DWORD total = RtlAnsiStringToUnicodeSize( ansi );
346
347     if (total > 0xffff) return STATUS_INVALID_PARAMETER_2;
348     uni->Length = total - sizeof(WCHAR);
349     if (doalloc)
350     {
351         uni->MaximumLength = total;
352         if (!(uni->Buffer = RtlAllocateHeap( GetProcessHeap(), 0, total ))) return STATUS_NO_MEMORY;
353     }
354     else if (total > uni->MaximumLength) return STATUS_BUFFER_OVERFLOW;
355
356     RtlMultiByteToUnicodeN( uni->Buffer, uni->Length, NULL, ansi->Buffer, ansi->Length );
357     uni->Buffer[uni->Length / sizeof(WCHAR)] = 0;
358     return STATUS_SUCCESS;
359 }
360
361
362 /**************************************************************************
363  *      RtlOemStringToUnicodeString   (NTDLL.@)
364  *
365  * NOTES
366  *  writes terminating 0
367  *  if resulting length > 0xffff it returns STATUS_INVALID_PARAMETER_2
368  */
369 NTSTATUS WINAPI RtlOemStringToUnicodeString( UNICODE_STRING *uni,
370                                              const STRING *oem,
371                                              BOOLEAN doalloc )
372 {
373     DWORD total = RtlOemStringToUnicodeSize( oem );
374
375     if (total > 0xffff) return STATUS_INVALID_PARAMETER_2;
376     uni->Length = total - sizeof(WCHAR);
377     if (doalloc)
378     {
379         uni->MaximumLength = total;
380         if (!(uni->Buffer = RtlAllocateHeap( GetProcessHeap(), 0, total ))) return STATUS_NO_MEMORY;
381     }
382     else if (total > uni->MaximumLength) return STATUS_BUFFER_OVERFLOW;
383
384     RtlOemToUnicodeN( uni->Buffer, uni->Length, NULL, oem->Buffer, oem->Length );
385     uni->Buffer[uni->Length / sizeof(WCHAR)] = 0;
386     return STATUS_SUCCESS;
387 }
388
389
390 /**************************************************************************
391  *      RtlUnicodeStringToAnsiString   (NTDLL.@)
392  *
393  * NOTES
394  *  writes terminating 0
395  *  copies a part if the buffer is too small
396  */
397 NTSTATUS WINAPI RtlUnicodeStringToAnsiString( STRING *ansi,
398                                               const UNICODE_STRING *uni,
399                                               BOOLEAN doalloc )
400 {
401     NTSTATUS ret = STATUS_SUCCESS;
402     DWORD len = RtlUnicodeStringToAnsiSize( uni );
403
404     ansi->Length = len - 1;
405     if (doalloc)
406     {
407         ansi->MaximumLength = len;
408         if (!(ansi->Buffer = RtlAllocateHeap( GetProcessHeap(), 0, len ))) return STATUS_NO_MEMORY;
409     }
410     else if (ansi->MaximumLength < len)
411     {
412         if (!ansi->MaximumLength) return STATUS_BUFFER_OVERFLOW;
413         ansi->Length = ansi->MaximumLength - 1;
414         ret = STATUS_BUFFER_OVERFLOW;
415     }
416
417     RtlUnicodeToMultiByteN( ansi->Buffer, ansi->Length, NULL, uni->Buffer, uni->Length );
418     ansi->Buffer[ansi->Length] = 0;
419     return ret;
420 }
421
422
423 /**************************************************************************
424  *      RtlUnicodeStringToOemString   (NTDLL.@)
425  *
426  * NOTES
427  *   allocates uni->Length+1
428  *   writes terminating 0
429  */
430 NTSTATUS WINAPI RtlUnicodeStringToOemString( STRING *oem,
431                                              const UNICODE_STRING *uni,
432                                              BOOLEAN doalloc )
433 {
434     NTSTATUS ret = STATUS_SUCCESS;
435     DWORD len = RtlUnicodeStringToOemSize( uni );
436
437     oem->Length = len - 1;
438     if (doalloc)
439     {
440         oem->MaximumLength = len;
441         if (!(oem->Buffer = RtlAllocateHeap( GetProcessHeap(), 0, len ))) return STATUS_NO_MEMORY;
442     }
443     else if (oem->MaximumLength < len)
444     {
445         if (!oem->MaximumLength) return STATUS_BUFFER_OVERFLOW;
446         oem->Length = oem->MaximumLength - 1;
447         ret = STATUS_BUFFER_OVERFLOW;
448     }
449
450     RtlUnicodeToOemN( oem->Buffer, oem->Length, NULL, uni->Buffer, uni->Length );
451     oem->Buffer[oem->Length] = 0;
452     return ret;
453 }
454
455
456 /**************************************************************************
457  *      RtlMultiByteToUnicodeN   (NTDLL.@)
458  *
459  * NOTES
460  *  if unistr is too small a part is copied
461  */
462 NTSTATUS WINAPI RtlMultiByteToUnicodeN( LPWSTR dst, DWORD dstlen, LPDWORD reslen,
463                                         LPCSTR src, DWORD srclen )
464 {
465
466     int ret = cp_mbstowcs( get_ansi_table(), 0, src, srclen, dst, dstlen/sizeof(WCHAR) );
467     if (reslen)
468         *reslen = (ret >= 0) ? ret*sizeof(WCHAR) : dstlen; /* overflow -> we filled up to dstlen */
469     return STATUS_SUCCESS;
470 }
471
472
473 /**************************************************************************
474  *      RtlOemToUnicodeN   (NTDLL.@)
475  */
476 NTSTATUS WINAPI RtlOemToUnicodeN( LPWSTR dst, DWORD dstlen, LPDWORD reslen,
477                                   LPCSTR src, DWORD srclen )
478 {
479     int ret = cp_mbstowcs( get_oem_table(), 0, src, srclen, dst, dstlen/sizeof(WCHAR) );
480     if (reslen)
481         *reslen = (ret >= 0) ? ret*sizeof(WCHAR) : dstlen; /* overflow -> we filled up to dstlen */
482     return STATUS_SUCCESS;
483 }
484
485
486 /**************************************************************************
487  *      RtlUnicodeToMultiByteN   (NTDLL.@)
488  */
489 NTSTATUS WINAPI RtlUnicodeToMultiByteN( LPSTR dst, DWORD dstlen, LPDWORD reslen,
490                                         LPCWSTR src, DWORD srclen )
491 {
492     int ret = cp_wcstombs( get_ansi_table(), 0, src, srclen / sizeof(WCHAR),
493                            dst, dstlen, NULL, NULL );
494     if (reslen)
495         *reslen = (ret >= 0) ? ret : dstlen; /* overflow -> we filled up to dstlen */
496     return STATUS_SUCCESS;
497 }
498
499
500 /**************************************************************************
501  *      RtlUnicodeToOemN   (NTDLL.@)
502  */
503 NTSTATUS WINAPI RtlUnicodeToOemN( LPSTR dst, DWORD dstlen, LPDWORD reslen,
504                                   LPCWSTR src, DWORD srclen )
505 {
506     int ret = cp_wcstombs( get_oem_table(), 0, src, srclen / sizeof(WCHAR),
507                            dst, dstlen, NULL, NULL );
508     if (reslen)
509         *reslen = (ret >= 0) ? ret : dstlen; /* overflow -> we filled up to dstlen */
510     return STATUS_SUCCESS;
511 }
512
513
514 /*
515      CASE CONVERSIONS
516 */
517
518 /**************************************************************************
519  *      RtlUpperString   (NTDLL.@)
520  */
521 void WINAPI RtlUpperString( STRING *dst, const STRING *src )
522 {
523     unsigned int i, len = min(src->Length, dst->MaximumLength);
524
525     for (i = 0; i < len; i++) dst->Buffer[i] = toupper(src->Buffer[i]);
526     dst->Length = len;
527 }
528
529
530 /**************************************************************************
531  *      RtlUpcaseUnicodeString   (NTDLL.@)
532  *
533  * NOTES:
534  *  destination string is never 0-terminated because dest can be equal to src
535  *  and src might be not 0-terminated
536  *  dest.Length only set when success
537  */
538 NTSTATUS WINAPI RtlUpcaseUnicodeString( UNICODE_STRING *dest,
539                                         const UNICODE_STRING *src,
540                                         BOOLEAN doalloc )
541 {
542     DWORD i, len = src->Length;
543
544     if (doalloc)
545     {
546         dest->MaximumLength = len;
547         if (!(dest->Buffer = RtlAllocateHeap( GetProcessHeap(), 0, len ))) return STATUS_NO_MEMORY;
548     }
549     else if (len > dest->MaximumLength) return STATUS_BUFFER_OVERFLOW;
550
551     for (i = 0; i < len/sizeof(WCHAR); i++) dest->Buffer[i] = toupperW(src->Buffer[i]);
552     dest->Length = len;
553     return STATUS_SUCCESS;
554 }
555
556
557 /**************************************************************************
558  *      RtlUpcaseUnicodeStringToAnsiString   (NTDLL.@)
559  *
560  * NOTES
561  *  writes terminating 0
562  */
563 NTSTATUS WINAPI RtlUpcaseUnicodeStringToAnsiString( STRING *dst,
564                                                     const UNICODE_STRING *src,
565                                                     BOOLEAN doalloc )
566 {
567     NTSTATUS ret;
568     UNICODE_STRING upcase;
569
570     if (!(ret = RtlUpcaseUnicodeString( &upcase, src, TRUE )))
571     {
572         ret = RtlUnicodeStringToAnsiString( dst, &upcase, doalloc );
573         RtlFreeUnicodeString( &upcase );
574     }
575     return ret;
576 }
577
578
579 /**************************************************************************
580  *      RtlUpcaseUnicodeStringToOemString   (NTDLL.@)
581  *
582  * NOTES
583  *  writes terminating 0
584  */
585 NTSTATUS WINAPI RtlUpcaseUnicodeStringToOemString( STRING *dst,
586                                                    const UNICODE_STRING *src,
587                                                    BOOLEAN doalloc )
588 {
589     NTSTATUS ret;
590     UNICODE_STRING upcase;
591
592     if (!(ret = RtlUpcaseUnicodeString( &upcase, src, TRUE )))
593     {
594         ret = RtlUnicodeStringToOemString( dst, &upcase, doalloc );
595         RtlFreeUnicodeString( &upcase );
596     }
597     return ret;
598 }
599
600
601 /**************************************************************************
602  *      RtlUpcaseUnicodeToMultiByteN   (NTDLL.@)
603  */
604 NTSTATUS WINAPI RtlUpcaseUnicodeToMultiByteN( LPSTR dst, DWORD dstlen, LPDWORD reslen,
605                                               LPCWSTR src, DWORD srclen )
606 {
607     NTSTATUS ret;
608     LPWSTR upcase;
609     DWORD i;
610
611     if (!(upcase = RtlAllocateHeap( GetProcessHeap(), 0, srclen ))) return STATUS_NO_MEMORY;
612     for (i = 0; i < srclen/sizeof(WCHAR); i++) upcase[i] = toupperW(src[i]);
613     ret = RtlUnicodeToMultiByteN( dst, dstlen, reslen, upcase, srclen );
614     RtlFreeHeap( GetProcessHeap(), 0, upcase );
615     return ret;
616 }
617
618
619 /**************************************************************************
620  *      RtlUpcaseUnicodeToOemN   (NTDLL.@)
621  */
622 NTSTATUS WINAPI RtlUpcaseUnicodeToOemN( LPSTR dst, DWORD dstlen, LPDWORD reslen,
623                                         LPCWSTR src, DWORD srclen )
624 {
625     NTSTATUS ret;
626     LPWSTR upcase;
627     DWORD i;
628
629     if (!(upcase = RtlAllocateHeap( GetProcessHeap(), 0, srclen ))) return STATUS_NO_MEMORY;
630     for (i = 0; i < srclen/sizeof(WCHAR); i++) upcase[i] = toupperW(src[i]);
631     ret = RtlUnicodeToOemN( dst, dstlen, reslen, upcase, srclen );
632     RtlFreeHeap( GetProcessHeap(), 0, upcase );
633     return ret;
634 }
635
636
637 /*
638         STRING SIZE
639 */
640
641 /**************************************************************************
642  *      RtlOemStringToUnicodeSize   (NTDLL.@)
643  *      RtlxOemStringToUnicodeSize  (NTDLL.@)
644  *
645  * Return the size in bytes necessary for the Unicode conversion of 'str',
646  * including the terminating NULL.
647  */
648 UINT WINAPI RtlOemStringToUnicodeSize( const STRING *str )
649 {
650     int ret = cp_mbstowcs( get_oem_table(), 0, str->Buffer, str->Length, NULL, 0 );
651     return (ret + 1) * sizeof(WCHAR);
652 }
653
654
655 /**************************************************************************
656  *      RtlAnsiStringToUnicodeSize   (NTDLL.@)
657  *      RtlxAnsiStringToUnicodeSize  (NTDLL.@)
658  *
659  * Return the size in bytes necessary for the Unicode conversion of 'str',
660  * including the terminating NULL.
661  */
662 DWORD WINAPI RtlAnsiStringToUnicodeSize( const STRING *str )
663 {
664     DWORD ret;
665     RtlMultiByteToUnicodeSize( &ret, str->Buffer, str->Length );
666     return ret + sizeof(WCHAR);
667 }
668
669
670 /**************************************************************************
671  *      RtlMultiByteToUnicodeSize   (NTDLL.@)
672  *
673  * Compute the size in bytes necessary for the Unicode conversion of 'str',
674  * without the terminating NULL.
675  */
676 NTSTATUS WINAPI RtlMultiByteToUnicodeSize( DWORD *size, LPCSTR str, UINT len )
677 {
678     *size = cp_mbstowcs( get_ansi_table(), 0, str, len, NULL, 0 ) * sizeof(WCHAR);
679     return STATUS_SUCCESS;
680 }
681
682
683 /**************************************************************************
684  *      RtlUnicodeToMultiByteSize   (NTDLL.@)
685  *
686  * Compute the size necessary for the multibyte conversion of 'str',
687  * without the terminating NULL.
688  */
689 NTSTATUS WINAPI RtlUnicodeToMultiByteSize( DWORD *size, LPCWSTR str, UINT len )
690 {
691     *size = cp_wcstombs( get_ansi_table(), 0, str, len / sizeof(WCHAR), NULL, 0, NULL, NULL );
692     return STATUS_SUCCESS;
693 }
694
695
696 /**************************************************************************
697  *      RtlUnicodeStringToAnsiSize   (NTDLL.@)
698  *      RtlxUnicodeStringToAnsiSize  (NTDLL.@)
699  *
700  * Return the size in bytes necessary for the Ansi conversion of 'str',
701  * including the terminating NULL.
702  */
703 DWORD WINAPI RtlUnicodeStringToAnsiSize( const UNICODE_STRING *str )
704 {
705     DWORD ret;
706     RtlUnicodeToMultiByteSize( &ret, str->Buffer, str->Length );
707     return ret + 1;
708 }
709
710
711 /**************************************************************************
712  *      RtlUnicodeStringToOemSize   (NTDLL.@)
713  *      RtlxUnicodeStringToOemSize  (NTDLL.@)
714  *
715  * Return the size in bytes necessary for the OEM conversion of 'str',
716  * including the terminating NULL.
717  */
718 DWORD WINAPI RtlUnicodeStringToOemSize( const UNICODE_STRING *str )
719 {
720     return cp_wcstombs( get_oem_table(), 0, str->Buffer, str->Length / sizeof(WCHAR),
721                         NULL, 0, NULL, NULL ) + 1;
722 }
723
724
725 /**************************************************************************
726  *      RtlAppendStringToString   (NTDLL.@)
727  */
728 NTSTATUS WINAPI RtlAppendStringToString( STRING *dst, const STRING *src )
729 {
730     unsigned int len = src->Length + dst->Length;
731     if (len > dst->MaximumLength) return STATUS_BUFFER_TOO_SMALL;
732     memcpy( dst->Buffer + dst->Length, src->Buffer, src->Length );
733     dst->Length = len;
734     return STATUS_SUCCESS;
735 }
736
737
738 /**************************************************************************
739  *      RtlAppendAsciizToString   (NTDLL.@)
740  */
741 NTSTATUS WINAPI RtlAppendAsciizToString( STRING *dst, LPCSTR src )
742 {
743     if (src)
744     {
745         unsigned int srclen = strlen(src);
746         unsigned int total  = srclen + dst->Length;
747         if (total > dst->MaximumLength) return STATUS_BUFFER_TOO_SMALL;
748         memcpy( dst->Buffer + dst->Length, src, srclen );
749         dst->Length = total;
750     }
751     return STATUS_SUCCESS;
752 }
753
754
755 /**************************************************************************
756  *      RtlAppendUnicodeToString   (NTDLL.@)
757  */
758 NTSTATUS WINAPI RtlAppendUnicodeToString( UNICODE_STRING *dst, LPCWSTR src )
759 {
760     if (src)
761     {
762         unsigned int srclen = strlenW(src) * sizeof(WCHAR);
763         unsigned int total  = srclen + dst->Length;
764         if (total > dst->MaximumLength) return STATUS_BUFFER_TOO_SMALL;
765         memcpy( dst->Buffer + dst->Length/sizeof(WCHAR), src, srclen );
766         dst->Length = total;
767         /* append terminating NULL if enough space */
768         if (total < dst->MaximumLength) dst->Buffer[total / sizeof(WCHAR)] = 0;
769     }
770     return STATUS_SUCCESS;
771 }
772
773
774 /**************************************************************************
775  *      RtlAppendUnicodeStringToString   (NTDLL.@)
776  */
777 NTSTATUS WINAPI RtlAppendUnicodeStringToString( UNICODE_STRING *dst, const UNICODE_STRING *src )
778 {
779     unsigned int len = src->Length + dst->Length;
780     if (len > dst->MaximumLength) return STATUS_BUFFER_TOO_SMALL;
781     memcpy( dst->Buffer + dst->Length/sizeof(WCHAR), src->Buffer, src->Length );
782     dst->Length = len;
783     /* append terminating NULL if enough space */
784     if (len < dst->MaximumLength) dst->Buffer[len / sizeof(WCHAR)] = 0;
785     return STATUS_SUCCESS;
786 }
787
788
789 /*
790         MISC
791 */
792
793 /**************************************************************************
794  *      RtlIsTextUnicode (NTDLL.@)
795  *
796  *      Apply various feeble heuristics to guess whether
797  *      the text buffer contains Unicode.
798  *      FIXME: should implement more tests.
799  */
800 DWORD WINAPI RtlIsTextUnicode(
801         LPVOID buf,
802         DWORD len,
803         DWORD *pf)
804 {
805         LPWSTR s = buf;
806         DWORD flags = -1, out_flags = 0;
807
808         if (!len)
809                 goto out;
810         if (pf)
811                 flags = *pf;
812         /*
813          * Apply various tests to the text string. According to the
814          * docs, each test "passed" sets the corresponding flag in
815          * the output flags. But some of the tests are mutually
816          * exclusive, so I don't see how you could pass all tests ...
817          */
818
819         /* Check for an odd length ... pass if even. */
820         if (!(len & 1))
821                 out_flags |= IS_TEXT_UNICODE_ODD_LENGTH;
822
823         /* Check for the special unicode marker byte. */
824         if (*s == 0xFEFF)
825                 out_flags |= IS_TEXT_UNICODE_SIGNATURE;
826
827         /*
828          * Check whether the string passed all of the tests.
829          */
830         flags &= ITU_IMPLEMENTED_TESTS;
831         if ((out_flags & flags) != flags)
832                 len = 0;
833 out:
834         if (pf)
835                 *pf = out_flags;
836         return len;
837 }