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