source: trunk/src/NTDLL/rtlstr.c@ 10367

Last change on this file since 10367 was 9986, checked in by sandervl, 22 years ago

PF: NTDLL update for GCC 3.2.1 + resync with Wine

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