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