source: trunk/src/ntdll/rtlstr.c@ 21916

Last change on this file since 21916 was 21916, checked in by dmik, 14 years ago

Merge branch gcc-kmk to trunk.

File size: 37.7 KB
Line 
1/*
2 * Rtl string functions
3 *
4 * Copyright (C) 1996-1998 Marcus Meissner
5 * Copyright (C) 2000 Alexandre Julliard
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21
22#include "config.h"
23
24#include <assert.h>
25#include <stdlib.h>
26#include <string.h>
27#include <ctype.h>
28
29#include "ntddk.h"
30#include "wine/unicode.h"
31#include "wine/debug.h"
32#include "winnt.h"
33
34WINE_DEFAULT_DEBUG_CHANNEL(ntdll);
35
36#ifdef __WIN32OS2__
37#define RtlAllocateHeap HeapAlloc
38#define RtlFreeHeap HeapFree
39#endif
40
41
42UINT NlsAnsiCodePage = 1252;
43BYTE NlsMbCodePageTag = 0;
44BYTE NlsMbOemCodePageTag = 0;
45
46static const union cptable *ansi_table;
47static const union cptable *oem_table;
48
49inline static const union cptable *get_ansi_table(void)
50{
51 if (!ansi_table) ansi_table = cp_get_table( 1252 );
52 return ansi_table;
53}
54
55inline static const union cptable *get_oem_table(void)
56{
57 if (!oem_table) oem_table = cp_get_table( 437 );
58 return oem_table;
59}
60
61
62/**************************************************************************
63 * __wine_init_codepages (NTDLL.@)
64 *
65 * Set the code page once kernel32 is loaded. Should be done differently.
66 */
67void __wine_init_codepages( const union cptable *ansi, const union cptable *oem )
68{
69 ansi_table = ansi;
70 oem_table = oem;
71 NlsAnsiCodePage = ansi->info.codepage;
72}
73
74
75/**************************************************************************
76 * RtlInitAnsiString (NTDLL.@)
77 */
78void WINAPI RtlInitAnsiString( PSTRING target, LPCSTR source)
79{
80 if ((target->Buffer = (LPSTR)source))
81 {
82 target->Length = strlen(source);
83 target->MaximumLength = target->Length + 1;
84 }
85 else target->Length = target->MaximumLength = 0;
86}
87
88
89/**************************************************************************
90 * RtlInitString (NTDLL.@)
91 */
92void WINAPI RtlInitString( PSTRING target, LPCSTR source )
93{
94 return RtlInitAnsiString( target, source );
95}
96
97
98/**************************************************************************
99 * RtlFreeAnsiString (NTDLL.@)
100 */
101void WINAPI RtlFreeAnsiString( PSTRING str )
102{
103 if (str->Buffer) RtlFreeHeap( GetProcessHeap(), 0, str->Buffer );
104}
105
106
107/**************************************************************************
108 * RtlFreeOemString (NTDLL.@)
109 */
110void WINAPI RtlFreeOemString( PSTRING str )
111{
112 RtlFreeAnsiString( str );
113}
114
115
116/**************************************************************************
117 * RtlCopyString (NTDLL.@)
118 */
119void WINAPI RtlCopyString( STRING *dst, const STRING *src )
120{
121 if (src)
122 {
123 unsigned int len = min( src->Length, dst->MaximumLength );
124 memcpy( dst->Buffer, src->Buffer, len );
125 dst->Length = len;
126 }
127 else dst->Length = 0;
128}
129
130
131/**************************************************************************
132 * RtlInitUnicodeString (NTDLL.@)
133 */
134void WINAPI RtlInitUnicodeString( PUNICODE_STRING target, LPCWSTR source )
135{
136 if ((target->Buffer = (LPWSTR)source))
137 {
138 target->Length = strlenW(source) * sizeof(WCHAR);
139 target->MaximumLength = target->Length + sizeof(WCHAR);
140 }
141 else target->Length = target->MaximumLength = 0;
142}
143
144
145/**************************************************************************
146 * RtlCreateUnicodeString (NTDLL.@)
147 */
148BOOLEAN WINAPI RtlCreateUnicodeString( PUNICODE_STRING target, LPCWSTR src )
149{
150 int len = (strlenW(src) + 1) * sizeof(WCHAR);
151 if (!(target->Buffer = RtlAllocateHeap( GetProcessHeap(), 0, len ))) return FALSE;
152 memcpy( target->Buffer, src, len );
153 target->MaximumLength = len;
154 target->Length = len - sizeof(WCHAR);
155 return TRUE;
156}
157
158
159/**************************************************************************
160 * RtlCreateUnicodeStringFromAsciiz (NTDLL.@)
161 */
162BOOLEAN WINAPI RtlCreateUnicodeStringFromAsciiz( PUNICODE_STRING target, LPCSTR src )
163{
164 STRING ansi;
165 RtlInitAnsiString( &ansi, src );
166 return !RtlAnsiStringToUnicodeString( target, &ansi, TRUE );
167}
168
169
170/**************************************************************************
171 * RtlFreeUnicodeString (NTDLL.@)
172 */
173void WINAPI RtlFreeUnicodeString( PUNICODE_STRING str )
174{
175 if (str->Buffer) RtlFreeHeap( GetProcessHeap(), 0, str->Buffer );
176}
177
178
179/**************************************************************************
180 * RtlCopyUnicodeString (NTDLL.@)
181 */
182void WINAPI RtlCopyUnicodeString( UNICODE_STRING *dst, const UNICODE_STRING *src )
183{
184 if (src)
185 {
186 unsigned int len = min( src->Length, dst->MaximumLength );
187 memcpy( dst->Buffer, src->Buffer, len );
188 dst->Length = len;
189 /* append terminating NULL if enough space */
190 if (len < dst->MaximumLength) dst->Buffer[len / sizeof(WCHAR)] = 0;
191 }
192 else dst->Length = 0;
193}
194
195
196/**************************************************************************
197 * RtlEraseUnicodeString (NTDLL.@)
198 */
199void WINAPI RtlEraseUnicodeString( UNICODE_STRING *str )
200{
201 if (str->Buffer)
202 {
203 memset( str->Buffer, 0, str->MaximumLength );
204 str->Length = 0;
205 }
206}
207
208/*
209 COMPARISON FUNCTIONS
210*/
211
212/******************************************************************************
213 * RtlCompareString (NTDLL.@)
214 */
215LONG WINAPI RtlCompareString( const STRING *s1, const STRING *s2, BOOLEAN CaseInsensitive )
216{
217 unsigned int len;
218 LONG ret = 0;
219 LPCSTR p1, p2;
220
221 len = min(s1->Length, s2->Length);
222 p1 = s1->Buffer;
223 p2 = s2->Buffer;
224
225 if (CaseInsensitive)
226 {
227 while (!ret && len--) ret = toupper(*p1++) - toupper(*p2++);
228 }
229 else
230 {
231 while (!ret && len--) ret = *p1++ - *p2++;
232 }
233 if (!ret) ret = s1->Length - s2->Length;
234 return ret;
235}
236
237
238/******************************************************************************
239 * RtlCompareUnicodeString (NTDLL.@)
240 */
241LONG WINAPI RtlCompareUnicodeString( const UNICODE_STRING *s1, const UNICODE_STRING *s2,
242 BOOLEAN CaseInsensitive )
243{
244 unsigned int len;
245 LONG ret = 0;
246 LPCWSTR p1, p2;
247
248 len = min(s1->Length, s2->Length) / sizeof(WCHAR);
249 p1 = s1->Buffer;
250 p2 = s2->Buffer;
251
252 if (CaseInsensitive)
253 {
254 while (!ret && len--) ret = toupperW(*p1++) - toupperW(*p2++);
255 }
256 else
257 {
258 while (!ret && len--) ret = *p1++ - *p2++;
259 }
260 if (!ret) ret = s1->Length - s2->Length;
261 return ret;
262}
263
264
265/**************************************************************************
266 * RtlEqualString (NTDLL.@)
267 */
268BOOLEAN WINAPI RtlEqualString( const STRING *s1, const STRING *s2, BOOLEAN CaseInsensitive )
269{
270 if (s1->Length != s2->Length) return FALSE;
271 return !RtlCompareString( s1, s2, CaseInsensitive );
272}
273
274
275/**************************************************************************
276 * RtlEqualUnicodeString (NTDLL.@)
277 */
278BOOLEAN WINAPI RtlEqualUnicodeString( const UNICODE_STRING *s1, const UNICODE_STRING *s2,
279 BOOLEAN CaseInsensitive )
280{
281 if (s1->Length != s2->Length) return FALSE;
282 return !RtlCompareUnicodeString( s1, s2, CaseInsensitive );
283}
284
285
286/**************************************************************************
287 * RtlPrefixString (NTDLL.@)
288 *
289 * Test if s1 is a prefix in s2
290 */
291BOOLEAN WINAPI RtlPrefixString( const STRING *s1, const STRING *s2, BOOLEAN ignore_case )
292{
293 unsigned int i;
294
295 if (s1->Length > s2->Length) return FALSE;
296 if (ignore_case)
297 {
298 for (i = 0; i < s1->Length; i++)
299 if (toupper(s1->Buffer[i]) != toupper(s2->Buffer[i])) return FALSE;
300 }
301 else
302 {
303 for (i = 0; i < s1->Length; i++)
304 if (s1->Buffer[i] != s2->Buffer[i]) return FALSE;
305 }
306 return TRUE;
307}
308
309
310/**************************************************************************
311 * RtlPrefixUnicodeString (NTDLL.@)
312 *
313 * Test if s1 is a prefix in s2
314 */
315BOOLEAN WINAPI RtlPrefixUnicodeString( const UNICODE_STRING *s1,
316 const UNICODE_STRING *s2,
317 BOOLEAN ignore_case )
318{
319 unsigned int i;
320
321 if (s1->Length > s2->Length) return FALSE;
322 if (ignore_case)
323 {
324 for (i = 0; i < s1->Length / sizeof(WCHAR); i++)
325 if (toupper(s1->Buffer[i]) != toupper(s2->Buffer[i])) return FALSE;
326 }
327 else
328 {
329 for (i = 0; i < s1->Length / sizeof(WCHAR); i++)
330 if (s1->Buffer[i] != s2->Buffer[i]) return FALSE;
331 }
332 return TRUE;
333}
334
335/**************************************************************************
336 * RtlEqualComputerName (NTDLL.@)
337 *
338 * Determine if two computer names are the same.
339 *
340 * PARAMS
341 * left [I] First computer name
342 * right [I] Second computer name
343 *
344 * RETURNS
345 * 0 if the names are equal, non-zero otherwise.
346 *
347 * NOTES
348 * The comparason is case insensitive.
349 */
350NTSTATUS WINAPI RtlEqualComputerName(const UNICODE_STRING *left,
351 const UNICODE_STRING *right)
352{
353 NTSTATUS ret;
354 STRING upLeft, upRight;
355
356 if (!(ret = RtlUpcaseUnicodeStringToOemString( &upLeft, left, TRUE )))
357 {
358 if (!(ret = RtlUpcaseUnicodeStringToOemString( &upRight, right, TRUE )))
359 {
360 ret = RtlEqualString( &upLeft, &upRight, FALSE );
361 RtlFreeOemString( &upRight );
362 }
363 RtlFreeOemString( &upLeft );
364 }
365 return ret;
366}
367
368/**************************************************************************
369 * RtlEqualDomainName (NTDLL.@)
370 *
371 * Determine if two domain names are the same.
372 *
373 * PARAMS
374 * left [I] First domain name
375 * right [I] Second domain name
376 *
377 * RETURNS
378 * 0 if the names are equal, non-zero otherwise.
379 *
380 * NOTES
381 * The comparason is case insensitive.
382 */
383NTSTATUS WINAPI RtlEqualDomainName(const UNICODE_STRING *left,
384 const UNICODE_STRING *right)
385{
386 return RtlEqualComputerName(left, right);
387}
388
389
390/*
391 COPY BETWEEN ANSI_STRING or UNICODE_STRING
392 there is no parameter checking, it just crashes
393*/
394
395
396/**************************************************************************
397 * RtlAnsiStringToUnicodeString (NTDLL.@)
398 *
399 * NOTES:
400 * writes terminating 0
401 */
402NTSTATUS WINAPI RtlAnsiStringToUnicodeString( UNICODE_STRING *uni,
403 const STRING *ansi,
404 BOOLEAN doalloc )
405{
406 DWORD total = RtlAnsiStringToUnicodeSize( ansi );
407
408 if (total > 0xffff) return STATUS_INVALID_PARAMETER_2;
409 uni->Length = total - sizeof(WCHAR);
410 if (doalloc)
411 {
412 uni->MaximumLength = total;
413 if (!(uni->Buffer = RtlAllocateHeap( GetProcessHeap(), 0, total ))) return STATUS_NO_MEMORY;
414 }
415 else if (total > uni->MaximumLength) return STATUS_BUFFER_OVERFLOW;
416
417 RtlMultiByteToUnicodeN( uni->Buffer, uni->Length, NULL, ansi->Buffer, ansi->Length );
418 uni->Buffer[uni->Length / sizeof(WCHAR)] = 0;
419 return STATUS_SUCCESS;
420}
421
422
423/**************************************************************************
424 * RtlOemStringToUnicodeString (NTDLL.@)
425 *
426 * NOTES
427 * writes terminating 0
428 * if resulting length > 0xffff it returns STATUS_INVALID_PARAMETER_2
429 */
430NTSTATUS WINAPI RtlOemStringToUnicodeString( UNICODE_STRING *uni,
431 const STRING *oem,
432 BOOLEAN doalloc )
433{
434 DWORD total = RtlOemStringToUnicodeSize( oem );
435
436 if (total > 0xffff) return STATUS_INVALID_PARAMETER_2;
437 uni->Length = total - sizeof(WCHAR);
438 if (doalloc)
439 {
440 uni->MaximumLength = total;
441 if (!(uni->Buffer = RtlAllocateHeap( GetProcessHeap(), 0, total ))) return STATUS_NO_MEMORY;
442 }
443 else if (total > uni->MaximumLength) return STATUS_BUFFER_OVERFLOW;
444
445 RtlOemToUnicodeN( uni->Buffer, uni->Length, NULL, oem->Buffer, oem->Length );
446 uni->Buffer[uni->Length / sizeof(WCHAR)] = 0;
447 return STATUS_SUCCESS;
448}
449
450
451/**************************************************************************
452 * RtlUnicodeStringToAnsiString (NTDLL.@)
453 *
454 * NOTES
455 * writes terminating 0
456 * copies a part if the buffer is too small
457 */
458NTSTATUS WINAPI RtlUnicodeStringToAnsiString( STRING *ansi,
459 const UNICODE_STRING *uni,
460 BOOLEAN doalloc )
461{
462 NTSTATUS ret = STATUS_SUCCESS;
463 DWORD len = RtlUnicodeStringToAnsiSize( uni );
464
465 ansi->Length = len - 1;
466 if (doalloc)
467 {
468 ansi->MaximumLength = len;
469 if (!(ansi->Buffer = RtlAllocateHeap( GetProcessHeap(), 0, len ))) return STATUS_NO_MEMORY;
470 }
471 else if (ansi->MaximumLength < len)
472 {
473 if (!ansi->MaximumLength) return STATUS_BUFFER_OVERFLOW;
474 ansi->Length = ansi->MaximumLength - 1;
475 ret = STATUS_BUFFER_OVERFLOW;
476 }
477
478 RtlUnicodeToMultiByteN( ansi->Buffer, ansi->Length, NULL, uni->Buffer, uni->Length );
479 ansi->Buffer[ansi->Length] = 0;
480 return ret;
481}
482
483
484/**************************************************************************
485 * RtlUnicodeStringToOemString (NTDLL.@)
486 *
487 * NOTES
488 * allocates uni->Length+1
489 * writes terminating 0
490 */
491NTSTATUS WINAPI RtlUnicodeStringToOemString( STRING *oem,
492 const UNICODE_STRING *uni,
493 BOOLEAN doalloc )
494{
495 NTSTATUS ret = STATUS_SUCCESS;
496 DWORD len = RtlUnicodeStringToOemSize( uni );
497
498 oem->Length = len - 1;
499 if (doalloc)
500 {
501 oem->MaximumLength = len;
502 if (!(oem->Buffer = RtlAllocateHeap( GetProcessHeap(), 0, len ))) return STATUS_NO_MEMORY;
503 }
504 else if (oem->MaximumLength < len)
505 {
506 if (!oem->MaximumLength) return STATUS_BUFFER_OVERFLOW;
507 oem->Length = oem->MaximumLength - 1;
508 ret = STATUS_BUFFER_OVERFLOW;
509 }
510
511 RtlUnicodeToOemN( oem->Buffer, oem->Length, NULL, uni->Buffer, uni->Length );
512 oem->Buffer[oem->Length] = 0;
513 return ret;
514}
515
516
517/**************************************************************************
518 * RtlMultiByteToUnicodeN (NTDLL.@)
519 *
520 * NOTES
521 * if unistr is too small a part is copied
522 */
523NTSTATUS WINAPI RtlMultiByteToUnicodeN( LPWSTR dst, DWORD dstlen, LPDWORD reslen,
524 LPCSTR src, DWORD srclen )
525{
526
527 int ret = cp_mbstowcs( get_ansi_table(), 0, src, srclen, dst, dstlen/sizeof(WCHAR) );
528 if (reslen)
529 *reslen = (ret >= 0) ? ret*sizeof(WCHAR) : dstlen; /* overflow -> we filled up to dstlen */
530 return STATUS_SUCCESS;
531}
532
533
534/**************************************************************************
535 * RtlOemToUnicodeN (NTDLL.@)
536 */
537NTSTATUS WINAPI RtlOemToUnicodeN( LPWSTR dst, DWORD dstlen, LPDWORD reslen,
538 LPCSTR src, DWORD srclen )
539{
540 int ret = cp_mbstowcs( get_oem_table(), 0, src, srclen, dst, dstlen/sizeof(WCHAR) );
541 if (reslen)
542 *reslen = (ret >= 0) ? ret*sizeof(WCHAR) : dstlen; /* overflow -> we filled up to dstlen */
543 return STATUS_SUCCESS;
544}
545
546
547/**************************************************************************
548 * RtlUnicodeToMultiByteN (NTDLL.@)
549 */
550NTSTATUS WINAPI RtlUnicodeToMultiByteN( LPSTR dst, DWORD dstlen, LPDWORD reslen,
551 LPCWSTR src, DWORD srclen )
552{
553 int ret = cp_wcstombs( get_ansi_table(), 0, src, srclen / sizeof(WCHAR),
554 dst, dstlen, NULL, NULL );
555 if (reslen)
556 *reslen = (ret >= 0) ? ret : dstlen; /* overflow -> we filled up to dstlen */
557 return STATUS_SUCCESS;
558}
559
560
561/**************************************************************************
562 * RtlUnicodeToOemN (NTDLL.@)
563 */
564NTSTATUS WINAPI RtlUnicodeToOemN( LPSTR dst, DWORD dstlen, LPDWORD reslen,
565 LPCWSTR src, DWORD srclen )
566{
567 int ret = cp_wcstombs( get_oem_table(), 0, src, srclen / sizeof(WCHAR),
568 dst, dstlen, NULL, NULL );
569 if (reslen)
570 *reslen = (ret >= 0) ? ret : dstlen; /* overflow -> we filled up to dstlen */
571 return STATUS_SUCCESS;
572}
573
574
575/*
576 CASE CONVERSIONS
577*/
578
579/**************************************************************************
580 * RtlUpperChar (NTDLL.@)
581 *
582 * Converts an Ascii character to uppercase.
583 *
584 * PARAMS
585 * ch [I] Character to convert
586 *
587 * RETURNS
588 * The uppercase character value.
589 *
590 * NOTES
591 * For the input characters from 'a' .. 'z' it returns 'A' .. 'Z'.
592 * All other input characters are returned unchanged. The locale and
593 * multibyte characters are not taken into account (as native DLL).
594 */
595CHAR WINAPI RtlUpperChar( CHAR ch )
596{
597 if (ch >= 'a' && ch <= 'z') {
598 return ch - 'a' + 'A';
599 } else {
600 return ch;
601 } /* if */
602}
603
604/**************************************************************************
605 * RtlUpperString (NTDLL.@)
606 *
607 * Converts an Ascii string to uppercase.
608 *
609 * PARAMS
610 * dst [O] Destination for converted string
611 * src [I] Source string to convert
612 *
613 * RETURNS
614 * Nothing.
615 *
616 * NOTES
617 * For the src characters from 'a' .. 'z' it assigns 'A' .. 'Z' to dst.
618 * All other src characters are copied unchanged to dst. The locale and
619 * multibyte characters are not taken into account (as native DLL).
620 * The number of character copied is the minimum of src->Length and
621 * the dst->MaximumLength.
622 */
623void WINAPI RtlUpperString( STRING *dst, const STRING *src )
624{
625 unsigned int i, len = min(src->Length, dst->MaximumLength);
626
627 for (i = 0; i < len; i++) dst->Buffer[i] = RtlUpperChar(src->Buffer[i]);
628 dst->Length = len;
629}
630
631
632/**************************************************************************
633 * RtlUpcaseUnicodeChar (NTDLL.@)
634 *
635 * Converts an Unicode character to uppercase.
636 *
637 * PARAMS
638 * wch [I] Character to convert
639 *
640 * RETURNS
641 * The uppercase character value.
642 */
643WCHAR WINAPI RtlUpcaseUnicodeChar( WCHAR wch )
644{
645 return toupperW(wch);
646}
647
648/**************************************************************************
649 * RtlDowncaseUnicodeChar (NTDLL.@)
650 *
651 * Converts an Unicode character to lowercase.
652 *
653 * PARAMS
654 * wch [I] Character to convert
655 *
656 * RETURNS
657 * The lowercase character value.
658 */
659WCHAR WINAPI RtlDowncaseUnicodeChar(WCHAR wch)
660{
661 return tolowerW(wch);
662}
663
664/**************************************************************************
665 * RtlUpcaseUnicodeString (NTDLL.@)
666 *
667 * NOTES:
668 * destination string is never 0-terminated because dest can be equal to src
669 * and src might be not 0-terminated
670 * dest.Length only set when success
671 */
672NTSTATUS WINAPI RtlUpcaseUnicodeString( UNICODE_STRING *dest,
673 const UNICODE_STRING *src,
674 BOOLEAN doalloc )
675{
676 DWORD i, len = src->Length;
677
678 if (doalloc)
679 {
680 dest->MaximumLength = len;
681 if (!(dest->Buffer = RtlAllocateHeap( GetProcessHeap(), 0, len ))) return STATUS_NO_MEMORY;
682 }
683 else if (len > dest->MaximumLength) return STATUS_BUFFER_OVERFLOW;
684
685 for (i = 0; i < len/sizeof(WCHAR); i++) dest->Buffer[i] = toupperW(src->Buffer[i]);
686 dest->Length = len;
687 return STATUS_SUCCESS;
688}
689
690
691/**************************************************************************
692 * RtlDowncaseUnicodeString (NTDLL.@)
693 *
694 * Converts an Unicode string to lowercase.
695 *
696 * PARAMS
697 * dest [O] Destination for converted string
698 * src [I] Source string to convert
699 * doalloc [I] TRUE=Allocate a buffer for dest if it doesn't have one
700 *
701 * RETURNS
702 * Success: STATUS_SUCCESS. dest contains the converted string.
703 * Failure: STATUS_NO_MEMORY, if doalloc is TRUE and memory allocation fails, or
704 * STATUS_BUFFER_OVERFLOW, if doalloc is FALSE and dest is too small.
705 *
706 * NOTES
707 * dest is never NUL terminated because it may be equal to src, and src
708 * might not be NUL terminated. dest->Length is only set upon success.
709 */
710NTSTATUS WINAPI RtlDowncaseUnicodeString(
711 UNICODE_STRING *dest,
712 const UNICODE_STRING *src,
713 BOOLEAN doalloc)
714{
715 DWORD i;
716 DWORD len = src->Length;
717
718 if (doalloc) {
719 dest->MaximumLength = len;
720 if (!(dest->Buffer = RtlAllocateHeap( GetProcessHeap(), 0, len ))) {
721 return STATUS_NO_MEMORY;
722 } /* if */
723 } else if (len > dest->MaximumLength) {
724 return STATUS_BUFFER_OVERFLOW;
725 } /* if */
726
727 for (i = 0; i < len/sizeof(WCHAR); i++) {
728 dest->Buffer[i] = tolowerW(src->Buffer[i]);
729 } /* for */
730 dest->Length = len;
731 return STATUS_SUCCESS;
732}
733
734/**************************************************************************
735 * RtlUpcaseUnicodeStringToAnsiString (NTDLL.@)
736 *
737 * NOTES
738 * writes terminating 0
739 */
740NTSTATUS WINAPI RtlUpcaseUnicodeStringToAnsiString( STRING *dst,
741 const UNICODE_STRING *src,
742 BOOLEAN doalloc )
743{
744 NTSTATUS ret;
745 UNICODE_STRING upcase;
746
747 if (!(ret = RtlUpcaseUnicodeString( &upcase, src, TRUE )))
748 {
749 ret = RtlUnicodeStringToAnsiString( dst, &upcase, doalloc );
750 RtlFreeUnicodeString( &upcase );
751 }
752 return ret;
753}
754
755
756/**************************************************************************
757 * RtlUpcaseUnicodeStringToOemString (NTDLL.@)
758 *
759 * NOTES
760 * writes terminating 0
761 */
762NTSTATUS WINAPI RtlUpcaseUnicodeStringToOemString( STRING *dst,
763 const UNICODE_STRING *src,
764 BOOLEAN doalloc )
765{
766 NTSTATUS ret;
767 UNICODE_STRING upcase;
768
769 if (!(ret = RtlUpcaseUnicodeString( &upcase, src, TRUE )))
770 {
771 ret = RtlUnicodeStringToOemString( dst, &upcase, doalloc );
772 RtlFreeUnicodeString( &upcase );
773 }
774 return ret;
775}
776
777
778/**************************************************************************
779 * RtlUpcaseUnicodeToMultiByteN (NTDLL.@)
780 */
781NTSTATUS WINAPI RtlUpcaseUnicodeToMultiByteN( LPSTR dst, DWORD dstlen, LPDWORD reslen,
782 LPCWSTR src, DWORD srclen )
783{
784 NTSTATUS ret;
785 LPWSTR upcase;
786 DWORD i;
787
788 if (!(upcase = RtlAllocateHeap( GetProcessHeap(), 0, srclen ))) return STATUS_NO_MEMORY;
789 for (i = 0; i < srclen/sizeof(WCHAR); i++) upcase[i] = toupperW(src[i]);
790 ret = RtlUnicodeToMultiByteN( dst, dstlen, reslen, upcase, srclen );
791 RtlFreeHeap( GetProcessHeap(), 0, upcase );
792 return ret;
793}
794
795
796/**************************************************************************
797 * RtlUpcaseUnicodeToOemN (NTDLL.@)
798 */
799NTSTATUS WINAPI RtlUpcaseUnicodeToOemN( LPSTR dst, DWORD dstlen, LPDWORD reslen,
800 LPCWSTR src, DWORD srclen )
801{
802 NTSTATUS ret;
803 LPWSTR upcase;
804 DWORD i;
805
806 if (!(upcase = RtlAllocateHeap( GetProcessHeap(), 0, srclen ))) return STATUS_NO_MEMORY;
807 for (i = 0; i < srclen/sizeof(WCHAR); i++) upcase[i] = toupperW(src[i]);
808 ret = RtlUnicodeToOemN( dst, dstlen, reslen, upcase, srclen );
809 RtlFreeHeap( GetProcessHeap(), 0, upcase );
810 return ret;
811}
812
813
814/*
815 STRING SIZE
816*/
817
818/**************************************************************************
819 * RtlOemStringToUnicodeSize (NTDLL.@)
820 * RtlxOemStringToUnicodeSize (NTDLL.@)
821 *
822 * Return the size in bytes necessary for the Unicode conversion of 'str',
823 * including the terminating NULL.
824 */
825UINT WINAPI RtlOemStringToUnicodeSize( const STRING *str )
826{
827 int ret = cp_mbstowcs( get_oem_table(), 0, str->Buffer, str->Length, NULL, 0 );
828 return (ret + 1) * sizeof(WCHAR);
829}
830
831
832/**************************************************************************
833 * RtlAnsiStringToUnicodeSize (NTDLL.@)
834 * RtlxAnsiStringToUnicodeSize (NTDLL.@)
835 *
836 * Return the size in bytes necessary for the Unicode conversion of 'str',
837 * including the terminating NULL.
838 */
839DWORD WINAPI RtlAnsiStringToUnicodeSize( const STRING *str )
840{
841 DWORD ret;
842 RtlMultiByteToUnicodeSize( &ret, str->Buffer, str->Length );
843 return ret + sizeof(WCHAR);
844}
845
846
847/**************************************************************************
848 * RtlMultiByteToUnicodeSize (NTDLL.@)
849 *
850 * Compute the size in bytes necessary for the Unicode conversion of 'str',
851 * without the terminating NULL.
852 */
853NTSTATUS WINAPI RtlMultiByteToUnicodeSize( DWORD *size, LPCSTR str, UINT len )
854{
855 *size = cp_mbstowcs( get_ansi_table(), 0, str, len, NULL, 0 ) * sizeof(WCHAR);
856 return STATUS_SUCCESS;
857}
858
859
860/**************************************************************************
861 * RtlUnicodeToMultiByteSize (NTDLL.@)
862 *
863 * Compute the size necessary for the multibyte conversion of 'str',
864 * without the terminating NULL.
865 */
866NTSTATUS WINAPI RtlUnicodeToMultiByteSize( DWORD *size, LPCWSTR str, UINT len )
867{
868 *size = cp_wcstombs( get_ansi_table(), 0, str, len / sizeof(WCHAR), NULL, 0, NULL, NULL );
869 return STATUS_SUCCESS;
870}
871
872
873/**************************************************************************
874 * RtlUnicodeStringToAnsiSize (NTDLL.@)
875 * RtlxUnicodeStringToAnsiSize (NTDLL.@)
876 *
877 * Return the size in bytes necessary for the Ansi conversion of 'str',
878 * including the terminating NULL.
879 */
880DWORD WINAPI RtlUnicodeStringToAnsiSize( const UNICODE_STRING *str )
881{
882 DWORD ret;
883 RtlUnicodeToMultiByteSize( &ret, str->Buffer, str->Length );
884 return ret + 1;
885}
886
887
888/**************************************************************************
889 * RtlUnicodeStringToOemSize (NTDLL.@)
890 * RtlxUnicodeStringToOemSize (NTDLL.@)
891 *
892 * Return the size in bytes necessary for the OEM conversion of 'str',
893 * including the terminating NULL.
894 */
895DWORD WINAPI RtlUnicodeStringToOemSize( const UNICODE_STRING *str )
896{
897 return cp_wcstombs( get_oem_table(), 0, str->Buffer, str->Length / sizeof(WCHAR),
898 NULL, 0, NULL, NULL ) + 1;
899}
900
901
902/**************************************************************************
903 * RtlAppendStringToString (NTDLL.@)
904 */
905NTSTATUS WINAPI RtlAppendStringToString( STRING *dst, const STRING *src )
906{
907 unsigned int len = src->Length + dst->Length;
908 if (len > dst->MaximumLength) return STATUS_BUFFER_TOO_SMALL;
909 memcpy( dst->Buffer + dst->Length, src->Buffer, src->Length );
910 dst->Length = len;
911 return STATUS_SUCCESS;
912}
913
914
915/**************************************************************************
916 * RtlAppendAsciizToString (NTDLL.@)
917 */
918NTSTATUS WINAPI RtlAppendAsciizToString( STRING *dst, LPCSTR src )
919{
920 if (src)
921 {
922 unsigned int srclen = strlen(src);
923 unsigned int total = srclen + dst->Length;
924 if (total > dst->MaximumLength) return STATUS_BUFFER_TOO_SMALL;
925 memcpy( dst->Buffer + dst->Length, src, srclen );
926 dst->Length = total;
927 }
928 return STATUS_SUCCESS;
929}
930
931
932/**************************************************************************
933 * RtlAppendUnicodeToString (NTDLL.@)
934 */
935NTSTATUS WINAPI RtlAppendUnicodeToString( UNICODE_STRING *dst, LPCWSTR src )
936{
937 if (src)
938 {
939 unsigned int srclen = strlenW(src) * sizeof(WCHAR);
940 unsigned int total = srclen + dst->Length;
941 if (total > dst->MaximumLength) return STATUS_BUFFER_TOO_SMALL;
942 memcpy( dst->Buffer + dst->Length/sizeof(WCHAR), src, srclen );
943 dst->Length = total;
944 /* append terminating NULL if enough space */
945 if (total < dst->MaximumLength) dst->Buffer[total / sizeof(WCHAR)] = 0;
946 }
947 return STATUS_SUCCESS;
948}
949
950
951/**************************************************************************
952 * RtlAppendUnicodeStringToString (NTDLL.@)
953 */
954NTSTATUS WINAPI RtlAppendUnicodeStringToString( UNICODE_STRING *dst, const UNICODE_STRING *src )
955{
956 unsigned int len = src->Length + dst->Length;
957 if (src->Length == 0) return STATUS_SUCCESS;
958 if (len > dst->MaximumLength) return STATUS_BUFFER_TOO_SMALL;
959 memcpy( dst->Buffer + dst->Length/sizeof(WCHAR), src->Buffer, src->Length );
960 dst->Length = len;
961 /* append terminating NULL if enough space */
962 if (len < dst->MaximumLength) dst->Buffer[len / sizeof(WCHAR)] = 0;
963 return STATUS_SUCCESS;
964}
965
966
967/*
968 MISC
969*/
970
971/**************************************************************************
972 * RtlIsTextUnicode (NTDLL.@)
973 *
974 * Apply various feeble heuristics to guess whether
975 * the text buffer contains Unicode.
976 * FIXME: should implement more tests.
977 */
978DWORD WINAPI RtlIsTextUnicode(
979 LPVOID buf,
980 DWORD len,
981 DWORD *pf)
982{
983 LPWSTR s = buf;
984 DWORD flags = -1, out_flags = 0;
985
986 if (!len)
987 goto out;
988 if (pf)
989 flags = *pf;
990 /*
991 * Apply various tests to the text string. According to the
992 * docs, each test "passed" sets the corresponding flag in
993 * the output flags. But some of the tests are mutually
994 * exclusive, so I don't see how you could pass all tests ...
995 */
996
997 /* Check for an odd length ... pass if even. */
998 if (!(len & 1))
999 out_flags |= IS_TEXT_UNICODE_ODD_LENGTH;
1000
1001 /* Check for the special unicode marker byte. */
1002 if (*s == 0xFEFF)
1003 out_flags |= IS_TEXT_UNICODE_SIGNATURE;
1004
1005 /*
1006 * Check whether the string passed all of the tests.
1007 */
1008 flags &= ITU_IMPLEMENTED_TESTS;
1009 if ((out_flags & flags) != flags)
1010 len = 0;
1011out:
1012 if (pf)
1013 *pf = out_flags;
1014 return len;
1015}
1016
1017/**************************************************************************
1018 * RtlCharToInteger (NTDLL.@)
1019 *
1020 * Converts a character string into its integer equivalent.
1021 *
1022 * RETURNS
1023 * Success: STATUS_SUCCESS. value contains the converted number
1024 * Failure: STATUS_INVALID_PARAMETER, if base is not 0, 2, 8, 10 or 16.
1025 * STATUS_ACCESS_VIOLATION, if value is NULL.
1026 *
1027 * NOTES
1028 * For base 0 it uses 10 as base and the string should be in the format
1029 * "{whitespace} [+|-] [0[x|o|b]] {digits}".
1030 * For other bases the string should be in the format
1031 * "{whitespace} [+|-] {digits}".
1032 * No check is made for value overflow, only the lower 32 bits are assigned.
1033 * If str is NULL it crashes, as the native function does.
1034 *
1035 * DIFFERENCES
1036 * This function does not read garbage behind '\0' as the native version does.
1037 */
1038NTSTATUS WINAPI RtlCharToInteger(
1039 PCSZ str, /* [I] '\0' terminated single-byte string containing a number */
1040 ULONG base, /* [I] Number base for conversion (allowed 0, 2, 8, 10 or 16) */
1041 ULONG *value) /* [O] Destination for the converted value */
1042{
1043 CHAR chCurrent;
1044 int digit;
1045 ULONG RunningTotal = 0;
1046 char bMinus = 0;
1047
1048 while (*str != '\0' && *str <= ' ') {
1049 str++;
1050 } /* while */
1051
1052 if (*str == '+') {
1053 str++;
1054 } else if (*str == '-') {
1055 bMinus = 1;
1056 str++;
1057 } /* if */
1058
1059 if (base == 0) {
1060 base = 10;
1061 if (str[0] == '0') {
1062 if (str[1] == 'b') {
1063 str += 2;
1064 base = 2;
1065 } else if (str[1] == 'o') {
1066 str += 2;
1067 base = 8;
1068 } else if (str[1] == 'x') {
1069 str += 2;
1070 base = 16;
1071 } /* if */
1072 } /* if */
1073 } else if (base != 2 && base != 8 && base != 10 && base != 16) {
1074 return STATUS_INVALID_PARAMETER;
1075 } /* if */
1076
1077 if (value == NULL) {
1078 return STATUS_ACCESS_VIOLATION;
1079 } /* if */
1080
1081 while (*str != '\0') {
1082 chCurrent = *str;
1083 if (chCurrent >= '0' && chCurrent <= '9') {
1084 digit = chCurrent - '0';
1085 } else if (chCurrent >= 'A' && chCurrent <= 'Z') {
1086 digit = chCurrent - 'A' + 10;
1087 } else if (chCurrent >= 'a' && chCurrent <= 'z') {
1088 digit = chCurrent - 'a' + 10;
1089 } else {
1090 digit = -1;
1091 } /* if */
1092 if (digit < 0 || digit >= base) {
1093 *value = bMinus ? -RunningTotal : RunningTotal;
1094 return STATUS_SUCCESS;
1095 } /* if */
1096
1097 RunningTotal = RunningTotal * base + digit;
1098 str++;
1099 } /* while */
1100
1101 *value = bMinus ? -RunningTotal : RunningTotal;
1102 return STATUS_SUCCESS;
1103}
1104
1105/**************************************************************************
1106 * RtlIntegerToChar (NTDLL.@)
1107 *
1108 * Converts an unsigned integer to a character string.
1109 *
1110 * RETURNS
1111 * Success: STATUS_SUCCESS. str contains the converted number
1112 * Failure: STATUS_INVALID_PARAMETER, if base is not 0, 2, 8, 10 or 16.
1113 * STATUS_BUFFER_OVERFLOW, if str would be larger than length.
1114 * STATUS_ACCESS_VIOLATION, if str is NULL.
1115 *
1116 * NOTES
1117 * Instead of base 0 it uses 10 as base.
1118 * Writes at most length characters to the string str.
1119 * Str is '\0' terminated when length allowes it.
1120 * When str fits exactly in length characters the '\0' is ommitted.
1121 */
1122NTSTATUS WINAPI RtlIntegerToChar(
1123 ULONG value, /* [I] Value to be converted */
1124 ULONG base, /* [I] Number base for conversion (allowed 0, 2, 8, 10 or 16) */
1125 ULONG length, /* [I] Length of the str buffer in bytes */
1126 PCHAR str) /* [O] Destination for the converted value */
1127{
1128 CHAR buffer[33];
1129 PCHAR pos;
1130 CHAR digit;
1131 ULONG len;
1132
1133 if (base == 0) {
1134 base = 10;
1135 } else if (base != 2 && base != 8 && base != 10 && base != 16) {
1136 return STATUS_INVALID_PARAMETER;
1137 } /* if */
1138
1139 pos = &buffer[32];
1140 *pos = '\0';
1141
1142 do {
1143 pos--;
1144 digit = value % base;
1145 value = value / base;
1146 if (digit < 10) {
1147 *pos = '0' + digit;
1148 } else {
1149 *pos = 'A' + digit - 10;
1150 } /* if */
1151 } while (value != 0L);
1152
1153 len = &buffer[32] - pos;
1154 if (len > length) {
1155 return STATUS_BUFFER_OVERFLOW;
1156 } else if (str == NULL) {
1157 return STATUS_ACCESS_VIOLATION;
1158 } else if (len == length) {
1159 memcpy(str, pos, len);
1160 } else {
1161 memcpy(str, pos, len + 1);
1162 } /* if */
1163 return STATUS_SUCCESS;
1164}
1165
1166/**************************************************************************
1167 * RtlUnicodeStringToInteger (NTDLL.@)
1168 *
1169 * Converts an unicode string into its integer equivalent.
1170 *
1171 * RETURNS
1172 * Success: STATUS_SUCCESS. value contains the converted number
1173 * Failure: STATUS_INVALID_PARAMETER, if base is not 0, 2, 8, 10 or 16.
1174 * STATUS_ACCESS_VIOLATION, if value is NULL.
1175 *
1176 * NOTES
1177 * For base 0 it uses 10 as base and the string should be in the format
1178 * "{whitespace} [+|-] [0[x|o|b]] {digits}".
1179 * For other bases the string should be in the format
1180 * "{whitespace} [+|-] {digits}".
1181 * No check is made for value overflow, only the lower 32 bits are assigned.
1182 * If str is NULL it crashes, as the native function does.
1183 *
1184 * DIFFERENCES
1185 * This function does not read garbage on string length 0 as the native
1186 * version does.
1187 */
1188NTSTATUS WINAPI RtlUnicodeStringToInteger(
1189 const UNICODE_STRING *str, /* [I] Unicode string to be converted */
1190 ULONG base, /* [I] Number base for conversion (allowed 0, 2, 8, 10 or 16) */
1191 ULONG *value) /* [O] Destination for the converted value */
1192{
1193 LPWSTR lpwstr = str->Buffer;
1194 USHORT CharsRemaining = str->Length / sizeof(WCHAR);
1195 WCHAR wchCurrent;
1196 int digit;
1197 ULONG RunningTotal = 0;
1198 char bMinus = 0;
1199
1200 while (CharsRemaining >= 1 && *lpwstr <= ' ') {
1201 lpwstr++;
1202 CharsRemaining--;
1203 } /* while */
1204
1205 if (CharsRemaining >= 1) {
1206 if (*lpwstr == '+') {
1207 lpwstr++;
1208 CharsRemaining--;
1209 } else if (*lpwstr == '-') {
1210 bMinus = 1;
1211 lpwstr++;
1212 CharsRemaining--;
1213 } /* if */
1214 } /* if */
1215
1216 if (base == 0) {
1217 base = 10;
1218 if (CharsRemaining >= 2 && lpwstr[0] == '0') {
1219 if (lpwstr[1] == 'b') {
1220 lpwstr += 2;
1221 CharsRemaining -= 2;
1222 base = 2;
1223 } else if (lpwstr[1] == 'o') {
1224 lpwstr += 2;
1225 CharsRemaining -= 2;
1226 base = 8;
1227 } else if (lpwstr[1] == 'x') {
1228 lpwstr += 2;
1229 CharsRemaining -= 2;
1230 base = 16;
1231 } /* if */
1232 } /* if */
1233 } else if (base != 2 && base != 8 && base != 10 && base != 16) {
1234 return STATUS_INVALID_PARAMETER;
1235 } /* if */
1236
1237 if (value == NULL) {
1238 return STATUS_ACCESS_VIOLATION;
1239 } /* if */
1240
1241 while (CharsRemaining >= 1) {
1242 wchCurrent = *lpwstr;
1243 if (wchCurrent >= '0' && wchCurrent <= '9') {
1244 digit = wchCurrent - '0';
1245 } else if (wchCurrent >= 'A' && wchCurrent <= 'Z') {
1246 digit = wchCurrent - 'A' + 10;
1247 } else if (wchCurrent >= 'a' && wchCurrent <= 'z') {
1248 digit = wchCurrent - 'a' + 10;
1249 } else {
1250 digit = -1;
1251 } /* if */
1252 if (digit < 0 || digit >= base) {
1253 *value = bMinus ? -RunningTotal : RunningTotal;
1254 return STATUS_SUCCESS;
1255 } /* if */
1256
1257 RunningTotal = RunningTotal * base + digit;
1258 lpwstr++;
1259 CharsRemaining--;
1260 } /* while */
1261
1262 *value = bMinus ? -RunningTotal : RunningTotal;
1263 return STATUS_SUCCESS;
1264}
1265
1266/**************************************************************************
1267 * RtlIntegerToUnicodeString (NTDLL.@)
1268 *
1269 * Converts an unsigned integer to a '\0' terminated unicode string.
1270 *
1271 * RETURNS
1272 * Success: STATUS_SUCCESS. str contains the converted number
1273 * Failure: STATUS_INVALID_PARAMETER, if base is not 0, 2, 8, 10 or 16.
1274 * STATUS_BUFFER_OVERFLOW, if str is too small to hold the string
1275 * (with the '\0' termination). In this case str->Length
1276 * is set to the length, the string would have (which can
1277 * be larger than the MaximumLength).
1278 *
1279 * NOTES
1280 * Instead of base 0 it uses 10 as base.
1281 * If str is NULL it crashes, as the native function does.
1282 *
1283 * DIFFERENCES
1284 * Do not return STATUS_BUFFER_OVERFLOW when the string is long enough.
1285 * The native function does this when the string would be longer than 16
1286 * characters even when the string parameter is long enough.
1287 */
1288NTSTATUS WINAPI RtlIntegerToUnicodeString(
1289 ULONG value, /* [I] Value to be converted */
1290 ULONG base, /* [I] Number base for conversion (allowed 0, 2, 8, 10 or 16) */
1291 UNICODE_STRING *str) /* [O] Destination for the converted value */
1292{
1293 WCHAR buffer[33];
1294 PWCHAR pos;
1295 WCHAR digit;
1296
1297 if (base == 0) {
1298 base = 10;
1299 } else if (base != 2 && base != 8 && base != 10 && base != 16) {
1300 return STATUS_INVALID_PARAMETER;
1301 } /* if */
1302
1303 pos = &buffer[32];
1304 *pos = '\0';
1305
1306 do {
1307 pos--;
1308 digit = value % base;
1309 value = value / base;
1310 if (digit < 10) {
1311 *pos = '0' + digit;
1312 } else {
1313 *pos = 'A' + digit - 10;
1314 } /* if */
1315 } while (value != 0L);
1316
1317 str->Length = (&buffer[32] - pos) * sizeof(WCHAR);
1318 if (str->Length >= str->MaximumLength) {
1319 return STATUS_BUFFER_OVERFLOW;
1320 } else {
1321 memcpy(str->Buffer, pos, str->Length + sizeof(WCHAR));
1322 } /* if */
1323 return STATUS_SUCCESS;
1324}
Note: See TracBrowser for help on using the repository browser.