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