No longer directly accessing debuggee memory.
[wine] / dlls / ntdll / rtlstr.c
1 /*
2  *      Rtl string functions
3  *
4  *      Copyright 1996-1998 Marcus Meissner
5  */
6
7 #include "config.h"
8
9 #include <stdlib.h>
10 #include <string.h>
11 #include <ctype.h>
12 #ifdef HAVE_WCTYPE_H
13 # include <wctype.h>
14 #endif
15 #include "wine/winestring.h"
16 #include "crtdll.h"
17 #include "heap.h"
18 #include "winnls.h"
19 #include "debugtools.h"
20 #include "ntdll_misc.h"
21 #include "ntddk.h"
22
23 DEFAULT_DEBUG_CHANNEL(ntdll)
24
25 /*      STRING FUNCTIONS        */
26
27 /**************************************************************************
28  *      RtlInitString
29  */
30 VOID WINAPI RtlInitString(PSTRING target,LPCSTR source)
31 {
32         TRACE("%p %p(%s)\n", target, source, debugstr_a(source));
33
34         target->Buffer = (LPSTR)source;
35         if (source)
36         {
37           target->Length = lstrlenA(source);
38           target->MaximumLength = target->Length+1;
39         }
40         else
41         {
42           target->Length = target->MaximumLength = 0;
43         }
44 }
45
46
47
48 /*      ANSI FUNCTIONS  */
49
50 /**************************************************************************
51  *      RtlInitAnsiString
52  */
53 VOID WINAPI RtlInitAnsiString(
54         PANSI_STRING target,
55         LPCSTR source)
56 {
57         TRACE("%p %p(%s)\n", target, source, debugstr_a(source));
58
59         target->Buffer = (LPSTR)source;
60         if (source)
61         {
62           target->Length = lstrlenA(source);
63           target->MaximumLength = target->Length+1;
64         }
65         else
66         {
67           target->Length = target->MaximumLength = 0;
68         }
69 }
70
71 /**************************************************************************
72  *      RtlFreeAnsiString
73  */
74 VOID WINAPI RtlFreeAnsiString(
75         PANSI_STRING AnsiString)
76 {
77         TRACE("%p\n", AnsiString);
78         dump_AnsiString(AnsiString, TRUE);
79
80         if( AnsiString->Buffer )
81           HeapFree( GetProcessHeap(),0,AnsiString->Buffer );
82 }
83
84
85
86 /*      UNICODE FUNCTIONS       */
87
88 /**************************************************************************
89  *      RtlInitUnicodeString                    [NTDLL.403]
90  */
91 VOID WINAPI RtlInitUnicodeString(
92         PUNICODE_STRING target,
93         LPCWSTR source)
94 {
95         TRACE("%p %p(%s)\n", target, source, debugstr_w(source));
96         
97         target->Buffer = (LPWSTR)source;
98         if (source)
99         {
100           target->Length = lstrlenW(source)*2;
101           target->MaximumLength = target->Length + 2;
102         }
103         else
104         {
105           target->Length = target->MaximumLength = 0;
106         }
107 }
108
109 /**************************************************************************
110  *      RtlFreeUnicodeString                    [NTDLL.377]
111  */
112 VOID WINAPI RtlFreeUnicodeString(
113         PUNICODE_STRING UnicodeString)
114 {
115         TRACE("%p\n", UnicodeString);
116         dump_UnicodeString(UnicodeString, TRUE);
117
118         if (UnicodeString->Buffer)
119           HeapFree(GetProcessHeap(),0,UnicodeString->Buffer);
120 }
121
122 /*
123          COMPARE FUNCTIONS
124 */
125
126 /**************************************************************************
127  *      RtlEqualUnicodeString
128  */
129 BOOLEAN WINAPI RtlEqualUnicodeString(
130         IN PUNICODE_STRING s1,
131         IN PUNICODE_STRING s2,
132         IN BOOLEAN CaseInsensitive) 
133 {
134         BOOLEAN ret;
135         TRACE("(%p,%p,%x)\n",s1,s2,CaseInsensitive);
136         dump_UnicodeString(s1, TRUE);
137         dump_UnicodeString(s2, TRUE);
138
139         if(!s1 || !s2 || !s1->Buffer || !s2->Buffer) return FALSE;
140         if (s1->Length != s2->Length) return FALSE;
141
142         if (CaseInsensitive)
143           ret = !CRTDLL__wcsnicmp(s1->Buffer,s2->Buffer,s1->Length/sizeof(WCHAR));
144         else    
145           ret = !CRTDLL_wcsncmp(s1->Buffer,s2->Buffer,s1->Length/sizeof(WCHAR));
146         return ret;
147 }
148
149 /******************************************************************************
150  *      RtlCompareUnicodeString
151  */
152 LONG WINAPI RtlCompareUnicodeString(
153         PUNICODE_STRING s1,
154         PUNICODE_STRING s2,
155         BOOLEAN CaseInsensitive) 
156 {
157         LONG ret;
158
159         TRACE("(%p,%p,%x)\n",s1,s2,CaseInsensitive);
160         dump_UnicodeString(s1, TRUE);
161         dump_UnicodeString(s2, TRUE);
162
163         if(!s1 || !s2 || !s1->Buffer || !s2->Buffer) return FALSE;
164         
165         if (s1->Length != s2->Length) return (s1->Length - s2->Length);
166
167         if (CaseInsensitive)
168           ret = CRTDLL__wcsnicmp(s1->Buffer,s2->Buffer,s1->Length/sizeof(WCHAR));
169         else    
170           ret = CRTDLL_wcsncmp(s1->Buffer,s2->Buffer,s1->Length/sizeof(WCHAR));
171         return ret;
172 }
173
174 /*
175         COPY BETWEEN ANSI_STRING or UNICODE_STRING
176         there is no parameter checking, it just crashes
177 */
178
179 /**************************************************************************
180  *      RtlAnsiStringToUnicodeString
181  *
182  * NOTES:
183  *  writes terminating 0
184  */
185 NTSTATUS
186 WINAPI RtlAnsiStringToUnicodeString(
187         PUNICODE_STRING uni,
188         PANSI_STRING ansi,
189         BOOLEAN doalloc)
190 {
191         int len = ansi->Length * sizeof(WCHAR);
192
193         TRACE("%p %p %u\n",uni, ansi, doalloc);
194         dump_AnsiString(ansi, TRUE);
195         dump_UnicodeString(uni, FALSE);
196
197         if (len>0xfffe) return STATUS_INVALID_PARAMETER_2;
198         uni->Length = len;
199         if (doalloc) 
200         {
201           uni->MaximumLength = len + sizeof(WCHAR);
202           uni->Buffer = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,uni->MaximumLength);
203           if (!uni->Buffer) return STATUS_NO_MEMORY;
204         }
205         else if (len+sizeof(WCHAR) > uni->MaximumLength)
206         {
207           return STATUS_BUFFER_OVERFLOW;
208         }
209         lstrcpynAtoW(uni->Buffer,ansi->Buffer,ansi->Length+1);
210         return STATUS_SUCCESS;
211 }
212
213 /**************************************************************************
214  *      RtlUpcaseUnicodeString
215  *
216  * NOTES:
217  *  destination string is never 0-terminated because dest can be equal to src
218  *  and src might be not 0-terminated
219  *  dest.Length only set when success
220  */
221 DWORD WINAPI RtlUpcaseUnicodeString(
222         PUNICODE_STRING dest,
223         PUNICODE_STRING src,
224         BOOLEAN doalloc)
225 {
226         int i, len = src->Length;
227
228         TRACE("(%p,%p,%x)\n",dest, src, doalloc);
229         dump_UnicodeString(dest, FALSE);
230         dump_UnicodeString(src, TRUE);
231
232         if (doalloc)
233         {
234           dest->Buffer = (LPWSTR)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len);
235           if (!dest->Buffer) return STATUS_NO_MEMORY;
236           dest->MaximumLength = len; 
237         }
238         else if (len > dest->MaximumLength)
239         {
240           return STATUS_BUFFER_OVERFLOW;
241         }
242
243         for (i=0; i < len/sizeof(WCHAR); i++)
244         {
245           dest->Buffer[i] = towupper(src->Buffer[i]);
246         }
247         dest->Length = len;
248         return STATUS_SUCCESS;
249 }
250
251 /**************************************************************************
252  *      RtlOemStringToUnicodeString
253  *
254  * NOTES
255  *  writes terminating 0
256  *  buffer must be bigger than (ansi->Length+1)*2
257  *  if astr.Length > 0x7ffe it returns STATUS_INVALID_PARAMETER_2
258  *
259  * FIXME
260  *  OEM to unicode
261  */
262 NTSTATUS
263 WINAPI RtlOemStringToUnicodeString(
264         PUNICODE_STRING uni,
265         PSTRING ansi,
266         BOOLEAN doalloc)
267 {
268         int len = ansi->Length * sizeof(WCHAR);
269
270         if (len > 0xfffe) return STATUS_INVALID_PARAMETER_2;
271
272         uni->Length = len;
273         if (doalloc) 
274         {
275           uni->Buffer = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, len + sizeof(WCHAR));
276           if (!uni->Buffer) return STATUS_NO_MEMORY;
277           uni->MaximumLength = len + sizeof(WCHAR);
278         }
279         else if (len+1 > uni->MaximumLength )
280         {
281           return STATUS_BUFFER_OVERFLOW;
282         }
283         lstrcpynAtoW(uni->Buffer,ansi->Buffer,ansi->Length+1);
284         return STATUS_SUCCESS;
285 }
286
287 /**************************************************************************
288  *      RtlUnicodeStringToOemString
289  *
290  * NOTES
291  *   allocates uni->Length+1
292  *   writes terminating 0
293  */
294 NTSTATUS
295 WINAPI RtlUnicodeStringToOemString(
296         PANSI_STRING oem,
297         PUNICODE_STRING uni,
298         BOOLEAN doalloc)
299 {
300         int len = uni->Length/sizeof(WCHAR);
301
302         TRACE("%p %s %i\n", oem, debugstr_us(uni), doalloc);
303
304         oem->Length = len;
305         if (doalloc)
306         {
307           oem->Buffer = (LPSTR)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len+1);
308           if (! oem->Buffer) return STATUS_NO_MEMORY;
309           oem->MaximumLength = len + 1;
310         }
311         else if (oem->MaximumLength <= len)
312         {
313           return STATUS_BUFFER_OVERFLOW;
314         }
315         lstrcpynWtoA(oem->Buffer, uni->Buffer, len+1);
316         return STATUS_SUCCESS;
317 }
318
319 /**************************************************************************
320  *      RtlUpcaseUnicodeStringToOemString
321  *
322  * NOTES
323  *  writes terminating 0
324  */
325 NTSTATUS
326 WINAPI RtlUpcaseUnicodeStringToOemString(
327         PANSI_STRING oem,
328         PUNICODE_STRING uni,
329         BOOLEAN doalloc)
330 {
331         int i, len = uni->Length/sizeof(WCHAR);
332
333         TRACE("%p %s %i\n", oem, debugstr_us(uni), doalloc);
334
335         oem->Length = len;
336         if (doalloc)
337         {
338           oem->Buffer = (LPSTR)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len+1);
339           if (! oem->Buffer) return STATUS_NO_MEMORY;
340           oem->MaximumLength = len + 1;
341         }
342         else if (oem->MaximumLength <= len)
343         {
344           return STATUS_BUFFER_OVERFLOW;
345         }
346
347         for (i=0; i < len; i++)
348         {
349           oem->Buffer[i] = towupper((char)(uni->Buffer[i]));
350         }
351         oem->Buffer[i] = 0;
352         return STATUS_SUCCESS;
353 }
354
355 /**************************************************************************
356  *      RtlUnicodeStringToAnsiString
357  *
358  * NOTES
359  *  writes terminating 0
360  *  copys a part if the buffer is to small
361  */
362 NTSTATUS
363 WINAPI RtlUnicodeStringToAnsiString(
364         PANSI_STRING ansi,
365         PUNICODE_STRING uni,
366         BOOLEAN doalloc)
367 {
368         int len = uni->Length/sizeof(WCHAR);
369         NTSTATUS ret = STATUS_SUCCESS;
370
371         TRACE("%p %s %i\n", ansi, debugstr_us(uni), doalloc);
372
373         ansi->Length = len;
374         if (doalloc)
375         {
376           ansi->Buffer = (LPSTR)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len+1);
377           if (! ansi->Buffer) return STATUS_NO_MEMORY;
378           ansi->MaximumLength = len + 1;
379         }
380         else if (ansi->MaximumLength <= len)
381         {
382           ansi->Length = ansi->MaximumLength - 1;
383           ret = STATUS_BUFFER_OVERFLOW;
384         }
385         lstrcpynWtoA(ansi->Buffer, uni->Buffer, ansi->Length+1);
386         return ret;
387 }
388
389 /*
390         COPY BETWEEN ANSI/UNICODE_STRING AND MULTIBYTE STRINGS
391 */
392 /**************************************************************************
393  *      RtlMultiByteToUnicodeN
394  *
395  * NOTES
396  *  dest can be equal to src
397  *  if unistr is to small a part is copyed
398  *
399  * FIXME
400  *  multibyte support
401  */
402 NTSTATUS
403 WINAPI RtlMultiByteToUnicodeN(
404         LPWSTR unistr,
405         DWORD unilen,
406         LPDWORD reslen,
407         LPSTR oemstr,
408         DWORD oemlen)
409 {
410         UINT len;
411         int i;
412
413         TRACE("%p %lu, %p, %s, %lu\n", oemstr, oemlen, reslen, debugstr_w(unistr), unilen);
414
415         len = (unilen/sizeof(WCHAR) < oemlen) ? unilen/sizeof(WCHAR) : oemlen;
416
417         for (i = len-1; i>=0; i--)
418           unistr[i] = (WCHAR)oemstr[i];
419
420         if (reslen) *reslen = len * 2;
421         return 0;
422 }
423
424 /**************************************************************************
425  *      RtlOemToUnicodeN
426  */
427 NTSTATUS
428 WINAPI RtlOemToUnicodeN(
429         LPWSTR unistr,
430         DWORD unilen,
431         LPDWORD reslen,
432         LPSTR oemstr,
433         DWORD oemlen)
434 {
435         UINT len;
436         int i;
437
438         TRACE("%p %lu, %p, %s, %lu\n", oemstr, oemlen, reslen, debugstr_w(unistr), unilen);
439
440         len = (unilen/sizeof(WCHAR) < oemlen) ? unilen/sizeof(WCHAR) : oemlen;
441
442         for (i = len-1; i>=0; i--)
443           unistr[i] = (WCHAR)oemstr[i];
444
445         if (reslen) *reslen = len * 2;
446         return 0;
447 }
448
449
450 /**************************************************************************
451  *      RtlUnicodeToOemN
452  */
453 NTSTATUS
454 WINAPI RtlUnicodeToOemN(
455         LPSTR oemstr,
456         DWORD oemlen,
457         LPDWORD reslen,
458         LPWSTR unistr,
459         DWORD unilen)
460 {
461         UINT len;
462         int i;
463
464         TRACE("%p %lu, %p, %s, %lu\n", oemstr, oemlen, reslen, debugstr_w(unistr), unilen);
465
466         len = (oemlen < unilen/sizeof(WCHAR)) ? unilen/sizeof(WCHAR) : oemlen;
467
468         for (i = len-1; i>=0; i--)
469           oemstr[i] = (CHAR)unistr[i];
470
471         if (reslen) *reslen = len * 2;
472         return 0;
473 }
474
475 /**************************************************************************
476  *      RtlUpcaseUnicodeToOemN
477  */
478 NTSTATUS
479 WINAPI RtlUpcaseUnicodeToOemN(
480         LPSTR oemstr,
481         DWORD oemlen,
482         LPDWORD reslen,
483         LPWSTR unistr,
484         DWORD unilen)
485 {
486         UINT len;
487         int i;
488
489         TRACE("%p %lu, %p, %s, %lu\n", oemstr, oemlen, reslen, debugstr_w(unistr), unilen);
490
491         len = (oemlen < unilen/sizeof(WCHAR)) ? unilen/sizeof(WCHAR) : oemlen;
492
493         for (i = len-1; i>=0; i--)
494           oemstr[i] = toupper((CHAR)unistr[i]);
495
496         if (reslen) *reslen = len * 2;
497         return 0;
498 }
499
500 /**************************************************************************
501  *      RtlUnicodeToMultiByteN
502  */
503 NTSTATUS WINAPI RtlUnicodeToMultiByteN(
504         PCHAR  MbString,
505         ULONG  MbSize,
506         PULONG ResultSize,
507         PWCHAR UnicodeString,
508         ULONG  UnicodeSize)
509 {
510         int Size = 0, i;
511
512         TRACE("(%p,%lu,%p,%p(%s),%lu)\n",
513         MbString, MbSize, ResultSize, UnicodeString, debugstr_w(UnicodeString), UnicodeSize);
514
515         Size = (UnicodeSize > (MbSize*sizeof(WCHAR))) ? MbSize: UnicodeSize/sizeof(WCHAR);
516
517         if (ResultSize != NULL) *ResultSize = Size;
518
519         for(i = 0; i < Size; i++)
520         {
521           *(MbString++) = *(UnicodeString++);
522         }
523         return STATUS_SUCCESS;      
524 }
525
526 /*
527         STRING SIZE
528
529         Rtlx* supports multibyte
530 */
531
532 /**************************************************************************
533  *      RtlxOemStringToUnicodeSize
534  */
535 UINT WINAPI RtlxOemStringToUnicodeSize(PSTRING str)
536 {
537         return str->Length*2+2;
538 }
539
540 /**************************************************************************
541  *      RtlxAnsiStringToUnicodeSize
542  */
543 UINT WINAPI RtlxAnsiStringToUnicodeSize(PANSI_STRING str)
544 {
545         return str->Length*2+2;
546 }
547
548 /**************************************************************************
549  *      RtlxUnicodeStringToOemSize
550  *
551  */
552 UINT WINAPI RtlxUnicodeStringToOemSize(PUNICODE_STRING str)
553 {
554         return str->Length+1;
555 }
556
557 /*
558         MISC
559 */
560
561 /**************************************************************************
562  *      RtlIsTextUnicode
563  *
564  *      Apply various feeble heuristics to guess whether
565  *      the text buffer contains Unicode.
566  *      FIXME: should implement more tests.
567  */
568 DWORD WINAPI RtlIsTextUnicode(
569         LPVOID buf,
570         DWORD len,
571         DWORD *pf)
572 {
573         LPWSTR s = buf;
574         DWORD flags = -1, out_flags = 0;
575
576         if (!len)
577                 goto out;
578         if (pf)
579                 flags = *pf;
580         /*
581          * Apply various tests to the text string. According to the
582          * docs, each test "passed" sets the corresponding flag in
583          * the output flags. But some of the tests are mutually
584          * exclusive, so I don't see how you could pass all tests ...
585          */
586
587         /* Check for an odd length ... pass if even. */
588         if (!(len & 1))
589                 out_flags |= IS_TEXT_UNICODE_ODD_LENGTH;
590
591         /* Check for the special unicode marker byte. */
592         if (*s == 0xFEFF)
593                 out_flags |= IS_TEXT_UNICODE_SIGNATURE;
594
595         /*
596          * Check whether the string passed all of the tests.
597          */
598         flags &= ITU_IMPLEMENTED_TESTS;
599         if ((out_flags & flags) != flags)
600                 len = 0;
601 out:
602         if (pf)
603                 *pf = out_flags;
604         return len;
605 }
606
607 /**************************************************************************
608  *      RtlPrefixUnicodeString
609  */
610 NTSTATUS WINAPI RtlPrefixUnicodeString(
611         PUNICODE_STRING a,
612         PUNICODE_STRING b,
613         DWORD x)
614 {
615         TRACE("(%s,%s,%lx)\n",debugstr_us(a),debugstr_us(b),x);
616         return STATUS_SUCCESS;
617 }
618