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