4 * Copyright (C) 1996-1998 Marcus Meissner
5 * Copyright (C) 2000 Alexandre Julliard
16 #include "wine/unicode.h"
17 #include "debugtools.h"
19 DEFAULT_DEBUG_CHANNEL(ntdll);
21 UINT NlsAnsiCodePage = 1252;
22 BYTE NlsMbCodePageTag = 0;
23 BYTE NlsMbOemCodePageTag = 0;
25 static const union cptable *ansi_table;
26 static const union cptable *oem_table;
28 inline static const union cptable *get_ansi_table(void)
30 if (!ansi_table) ansi_table = cp_get_table( 1252 );
34 inline static const union cptable *get_oem_table(void)
36 if (!oem_table) oem_table = cp_get_table( 437 );
41 /**************************************************************************
42 * __wine_init_codepages (NTDLL.@)
44 * Set the code page once kernel32 is loaded. Should be done differently.
46 void __wine_init_codepages( const union cptable *ansi, const union cptable *oem )
50 NlsAnsiCodePage = ansi->info.codepage;
54 /**************************************************************************
55 * RtlInitAnsiString (NTDLL.@)
57 void WINAPI RtlInitAnsiString( PSTRING target, LPCSTR source)
59 if ((target->Buffer = (LPSTR)source))
61 target->Length = strlen(source);
62 target->MaximumLength = target->Length + 1;
64 else target->Length = target->MaximumLength = 0;
68 /**************************************************************************
69 * RtlInitString (NTDLL.@)
71 void WINAPI RtlInitString( PSTRING target, LPCSTR source )
73 return RtlInitAnsiString( target, source );
77 /**************************************************************************
78 * RtlFreeAnsiString (NTDLL.@)
80 void WINAPI RtlFreeAnsiString( PSTRING str )
82 if (str->Buffer) RtlFreeHeap( GetProcessHeap(), 0, str->Buffer );
86 /**************************************************************************
87 * RtlFreeOemString (NTDLL.@)
89 void WINAPI RtlFreeOemString( PSTRING str )
91 RtlFreeAnsiString( str );
95 /**************************************************************************
96 * RtlCopyString (NTDLL.@)
98 void WINAPI RtlCopyString( STRING *dst, const STRING *src )
102 unsigned int len = min( src->Length, dst->MaximumLength );
103 memcpy( dst->Buffer, src->Buffer, len );
106 else dst->Length = 0;
110 /**************************************************************************
111 * RtlInitUnicodeString (NTDLL.@)
113 void WINAPI RtlInitUnicodeString( PUNICODE_STRING target, LPCWSTR source )
115 if ((target->Buffer = (LPWSTR)source))
117 target->Length = strlenW(source) * sizeof(WCHAR);
118 target->MaximumLength = target->Length + sizeof(WCHAR);
120 else target->Length = target->MaximumLength = 0;
124 /**************************************************************************
125 * RtlCreateUnicodeString (NTDLL.@)
127 BOOLEAN WINAPI RtlCreateUnicodeString( PUNICODE_STRING target, LPCWSTR src )
129 int len = (strlenW(src) + 1) * sizeof(WCHAR);
130 if (!(target->Buffer = RtlAllocateHeap( GetProcessHeap(), 0, len ))) return FALSE;
131 memcpy( target->Buffer, src, len );
132 target->MaximumLength = len;
133 target->Length = len - 2;
138 /**************************************************************************
139 * RtlCreateUnicodeStringFromAsciiz (NTDLL.@)
141 BOOLEAN WINAPI RtlCreateUnicodeStringFromAsciiz( PUNICODE_STRING target, LPCSTR src )
144 RtlInitAnsiString( &ansi, src );
145 return !RtlAnsiStringToUnicodeString( target, &ansi, TRUE );
149 /**************************************************************************
150 * RtlFreeUnicodeString (NTDLL.@)
152 void WINAPI RtlFreeUnicodeString( PUNICODE_STRING str )
154 if (str->Buffer) RtlFreeHeap( GetProcessHeap(), 0, str->Buffer );
158 /**************************************************************************
159 * RtlCopyUnicodeString (NTDLL.@)
161 void WINAPI RtlCopyUnicodeString( UNICODE_STRING *dst, const UNICODE_STRING *src )
165 unsigned int len = min( src->Length, dst->MaximumLength );
166 memcpy( dst->Buffer, src->Buffer, len );
168 /* append terminating NULL if enough space */
169 if (len < dst->MaximumLength) dst->Buffer[len / sizeof(WCHAR)] = 0;
171 else dst->Length = 0;
175 /**************************************************************************
176 * RtlEraseUnicodeString (NTDLL.@)
178 void WINAPI RtlEraseUnicodeString( UNICODE_STRING *str )
182 memset( str->Buffer, 0, str->MaximumLength );
191 /******************************************************************************
192 * RtlCompareString (NTDLL.@)
194 LONG WINAPI RtlCompareString( const STRING *s1, const STRING *s2, BOOLEAN CaseInsensitive )
200 len = min(s1->Length, s2->Length);
206 while (!ret && len--) ret = toupper(*p1++) - toupper(*p2++);
210 while (!ret && len--) ret = *p1++ - *p2++;
212 if (!ret) ret = s1->Length - s2->Length;
217 /******************************************************************************
218 * RtlCompareUnicodeString (NTDLL.@)
220 LONG WINAPI RtlCompareUnicodeString( const UNICODE_STRING *s1, const UNICODE_STRING *s2,
221 BOOLEAN CaseInsensitive )
227 len = min(s1->Length, s2->Length) / sizeof(WCHAR);
233 while (!ret && len--) ret = toupperW(*p1++) - toupperW(*p2++);
237 while (!ret && len--) ret = *p1++ - *p2++;
239 if (!ret) ret = s1->Length - s2->Length;
244 /**************************************************************************
245 * RtlEqualString (NTDLL.@)
247 BOOLEAN WINAPI RtlEqualString( const STRING *s1, const STRING *s2, BOOLEAN CaseInsensitive )
249 if (s1->Length != s2->Length) return FALSE;
250 return !RtlCompareString( s1, s2, CaseInsensitive );
254 /**************************************************************************
255 * RtlEqualUnicodeString (NTDLL.@)
257 BOOLEAN WINAPI RtlEqualUnicodeString( const UNICODE_STRING *s1, const UNICODE_STRING *s2,
258 BOOLEAN CaseInsensitive )
260 if (s1->Length != s2->Length) return FALSE;
261 return !RtlCompareUnicodeString( s1, s2, CaseInsensitive );
265 /**************************************************************************
266 * RtlPrefixString (NTDLL.@)
268 * Test if s1 is a prefix in s2
270 BOOLEAN WINAPI RtlPrefixString( const STRING *s1, const STRING *s2, BOOLEAN ignore_case )
274 if (s1->Length > s2->Length) return FALSE;
277 for (i = 0; i < s1->Length; i++)
278 if (toupper(s1->Buffer[i]) != toupper(s2->Buffer[i])) return FALSE;
282 for (i = 0; i < s1->Length; i++)
283 if (s1->Buffer[i] != s2->Buffer[i]) return FALSE;
289 /**************************************************************************
290 * RtlPrefixUnicodeString (NTDLL.@)
292 * Test if s1 is a prefix in s2
294 BOOLEAN WINAPI RtlPrefixUnicodeString( const UNICODE_STRING *s1,
295 const UNICODE_STRING *s2,
296 BOOLEAN ignore_case )
300 if (s1->Length > s2->Length) return FALSE;
303 for (i = 0; i < s1->Length / sizeof(WCHAR); i++)
304 if (toupper(s1->Buffer[i]) != toupper(s2->Buffer[i])) return FALSE;
308 for (i = 0; i < s1->Length / sizeof(WCHAR); i++)
309 if (s1->Buffer[i] != s2->Buffer[i]) return FALSE;
316 COPY BETWEEN ANSI_STRING or UNICODE_STRING
317 there is no parameter checking, it just crashes
321 /**************************************************************************
322 * RtlAnsiStringToUnicodeString (NTDLL.@)
325 * writes terminating 0
327 NTSTATUS WINAPI RtlAnsiStringToUnicodeString( UNICODE_STRING *uni,
331 DWORD total = RtlAnsiStringToUnicodeSize( ansi );
333 if (total > 0xffff) return STATUS_INVALID_PARAMETER_2;
334 uni->Length = total - sizeof(WCHAR);
337 uni->MaximumLength = total;
338 if (!(uni->Buffer = RtlAllocateHeap( GetProcessHeap(), 0, total ))) return STATUS_NO_MEMORY;
340 else if (total > uni->MaximumLength) return STATUS_BUFFER_OVERFLOW;
342 RtlMultiByteToUnicodeN( uni->Buffer, uni->Length, NULL, ansi->Buffer, ansi->Length );
343 uni->Buffer[uni->Length / sizeof(WCHAR)] = 0;
344 return STATUS_SUCCESS;
348 /**************************************************************************
349 * RtlOemStringToUnicodeString (NTDLL.@)
352 * writes terminating 0
353 * if resulting length > 0xffff it returns STATUS_INVALID_PARAMETER_2
355 NTSTATUS WINAPI RtlOemStringToUnicodeString( UNICODE_STRING *uni,
359 DWORD total = RtlOemStringToUnicodeSize( oem );
361 if (total > 0xffff) return STATUS_INVALID_PARAMETER_2;
362 uni->Length = total - sizeof(WCHAR);
365 uni->MaximumLength = total;
366 if (!(uni->Buffer = RtlAllocateHeap( GetProcessHeap(), 0, total ))) return STATUS_NO_MEMORY;
368 else if (total > uni->MaximumLength) return STATUS_BUFFER_OVERFLOW;
370 RtlOemToUnicodeN( uni->Buffer, uni->Length, NULL, oem->Buffer, oem->Length );
371 uni->Buffer[uni->Length / sizeof(WCHAR)] = 0;
372 return STATUS_SUCCESS;
376 /**************************************************************************
377 * RtlUnicodeStringToAnsiString (NTDLL.@)
380 * writes terminating 0
381 * copies a part if the buffer is too small
383 NTSTATUS WINAPI RtlUnicodeStringToAnsiString( STRING *ansi,
384 const UNICODE_STRING *uni,
387 NTSTATUS ret = STATUS_SUCCESS;
388 DWORD len = RtlUnicodeStringToAnsiSize( uni );
393 ansi->MaximumLength = len + 1;
394 if (!(ansi->Buffer = RtlAllocateHeap( GetProcessHeap(), 0, len + 1 ))) return STATUS_NO_MEMORY;
396 else if (ansi->MaximumLength <= len)
398 if (!ansi->MaximumLength) return STATUS_BUFFER_OVERFLOW;
399 ansi->Length = ansi->MaximumLength - 1;
400 ret = STATUS_BUFFER_OVERFLOW;
403 RtlUnicodeToMultiByteN( ansi->Buffer, ansi->Length, NULL, uni->Buffer, uni->Length );
404 ansi->Buffer[ansi->Length] = 0;
409 /**************************************************************************
410 * RtlUnicodeStringToOemString (NTDLL.@)
413 * allocates uni->Length+1
414 * writes terminating 0
416 NTSTATUS WINAPI RtlUnicodeStringToOemString( STRING *oem,
417 const UNICODE_STRING *uni,
420 NTSTATUS ret = STATUS_SUCCESS;
421 DWORD len = RtlUnicodeStringToOemSize( uni );
426 oem->MaximumLength = len + 1;
427 if (!(oem->Buffer = RtlAllocateHeap( GetProcessHeap(), 0, len + 1 ))) return STATUS_NO_MEMORY;
429 else if (oem->MaximumLength <= len)
431 if (!oem->MaximumLength) return STATUS_BUFFER_OVERFLOW;
432 oem->Length = oem->MaximumLength - 1;
433 ret = STATUS_BUFFER_OVERFLOW;
436 RtlUnicodeToOemN( oem->Buffer, oem->Length, NULL, uni->Buffer, uni->Length );
437 oem->Buffer[oem->Length] = 0;
442 /**************************************************************************
443 * RtlMultiByteToUnicodeN (NTDLL.@)
446 * if unistr is too small a part is copied
448 NTSTATUS WINAPI RtlMultiByteToUnicodeN( LPWSTR dst, DWORD dstlen, LPDWORD reslen,
449 LPCSTR src, DWORD srclen )
452 int ret = cp_mbstowcs( get_ansi_table(), 0, src, srclen, dst, dstlen/sizeof(WCHAR) );
454 *reslen = (ret >= 0) ? ret*sizeof(WCHAR) : dstlen; /* overflow -> we filled up to dstlen */
455 return STATUS_SUCCESS;
459 /**************************************************************************
460 * RtlOemToUnicodeN (NTDLL.@)
462 NTSTATUS WINAPI RtlOemToUnicodeN( LPWSTR dst, DWORD dstlen, LPDWORD reslen,
463 LPCSTR src, DWORD srclen )
465 int ret = cp_mbstowcs( get_oem_table(), 0, src, srclen, dst, dstlen/sizeof(WCHAR) );
467 *reslen = (ret >= 0) ? ret*sizeof(WCHAR) : dstlen; /* overflow -> we filled up to dstlen */
468 return STATUS_SUCCESS;
472 /**************************************************************************
473 * RtlUnicodeToMultiByteN (NTDLL.@)
475 NTSTATUS WINAPI RtlUnicodeToMultiByteN( LPSTR dst, DWORD dstlen, LPDWORD reslen,
476 LPCWSTR src, DWORD srclen )
478 int ret = cp_wcstombs( get_ansi_table(), 0, src, srclen / sizeof(WCHAR),
479 dst, dstlen, NULL, NULL );
481 *reslen = (ret >= 0) ? ret : dstlen; /* overflow -> we filled up to dstlen */
482 return STATUS_SUCCESS;
486 /**************************************************************************
487 * RtlUnicodeToOemN (NTDLL.@)
489 NTSTATUS WINAPI RtlUnicodeToOemN( LPSTR dst, DWORD dstlen, LPDWORD reslen,
490 LPCWSTR src, DWORD srclen )
492 int ret = cp_wcstombs( get_oem_table(), 0, src, srclen / sizeof(WCHAR),
493 dst, dstlen, NULL, NULL );
495 *reslen = (ret >= 0) ? ret : dstlen; /* overflow -> we filled up to dstlen */
496 return STATUS_SUCCESS;
504 /**************************************************************************
505 * RtlUpperString (NTDLL.@)
507 void WINAPI RtlUpperString( STRING *dst, const STRING *src )
509 unsigned int i, len = min(src->Length, dst->MaximumLength);
511 for (i = 0; i < len; i++) dst->Buffer[i] = toupper(src->Buffer[i]);
516 /**************************************************************************
517 * RtlUpcaseUnicodeString (NTDLL.@)
520 * destination string is never 0-terminated because dest can be equal to src
521 * and src might be not 0-terminated
522 * dest.Length only set when success
524 NTSTATUS WINAPI RtlUpcaseUnicodeString( UNICODE_STRING *dest,
525 const UNICODE_STRING *src,
528 DWORD i, len = src->Length;
532 dest->MaximumLength = len;
533 if (!(dest->Buffer = RtlAllocateHeap( GetProcessHeap(), 0, len ))) return STATUS_NO_MEMORY;
535 else if (len > dest->MaximumLength) return STATUS_BUFFER_OVERFLOW;
537 for (i = 0; i < len/sizeof(WCHAR); i++) dest->Buffer[i] = toupperW(src->Buffer[i]);
539 return STATUS_SUCCESS;
543 /**************************************************************************
544 * RtlUpcaseUnicodeStringToAnsiString (NTDLL.@)
547 * writes terminating 0
549 NTSTATUS WINAPI RtlUpcaseUnicodeStringToAnsiString( STRING *dst,
550 const UNICODE_STRING *src,
554 UNICODE_STRING upcase;
556 if (!(ret = RtlUpcaseUnicodeString( &upcase, src, TRUE )))
558 ret = RtlUnicodeStringToAnsiString( dst, &upcase, doalloc );
559 RtlFreeUnicodeString( &upcase );
565 /**************************************************************************
566 * RtlUpcaseUnicodeStringToOemString (NTDLL.@)
569 * writes terminating 0
571 NTSTATUS WINAPI RtlUpcaseUnicodeStringToOemString( STRING *dst,
572 const UNICODE_STRING *src,
576 UNICODE_STRING upcase;
578 if (!(ret = RtlUpcaseUnicodeString( &upcase, src, TRUE )))
580 ret = RtlUnicodeStringToOemString( dst, &upcase, doalloc );
581 RtlFreeUnicodeString( &upcase );
587 /**************************************************************************
588 * RtlUpcaseUnicodeToMultiByteN (NTDLL.@)
590 NTSTATUS WINAPI RtlUpcaseUnicodeToMultiByteN( LPSTR dst, DWORD dstlen, LPDWORD reslen,
591 LPCWSTR src, DWORD srclen )
597 if (!(upcase = RtlAllocateHeap( GetProcessHeap(), 0, srclen ))) return STATUS_NO_MEMORY;
598 for (i = 0; i < srclen/sizeof(WCHAR); i++) upcase[i] = toupperW(src[i]);
599 ret = RtlUnicodeToMultiByteN( dst, dstlen, reslen, upcase, srclen );
600 RtlFreeHeap( GetProcessHeap(), 0, upcase );
605 /**************************************************************************
606 * RtlUpcaseUnicodeToOemN (NTDLL.@)
608 NTSTATUS WINAPI RtlUpcaseUnicodeToOemN( LPSTR dst, DWORD dstlen, LPDWORD reslen,
609 LPCWSTR src, DWORD srclen )
615 if (!(upcase = RtlAllocateHeap( GetProcessHeap(), 0, srclen ))) return STATUS_NO_MEMORY;
616 for (i = 0; i < srclen/sizeof(WCHAR); i++) upcase[i] = toupperW(src[i]);
617 ret = RtlUnicodeToOemN( dst, dstlen, reslen, upcase, srclen );
618 RtlFreeHeap( GetProcessHeap(), 0, upcase );
627 /**************************************************************************
628 * RtlOemStringToUnicodeSize (NTDLL.@)
629 * RtlxOemStringToUnicodeSize (NTDLL.@)
631 * Return the size in bytes necessary for the Unicode conversion of 'str',
632 * including the terminating NULL.
634 UINT WINAPI RtlOemStringToUnicodeSize( const STRING *str )
636 int ret = cp_mbstowcs( get_oem_table(), 0, str->Buffer, str->Length, NULL, 0 );
637 return (ret + 1) * sizeof(WCHAR);
641 /**************************************************************************
642 * RtlAnsiStringToUnicodeSize (NTDLL.@)
643 * RtlxAnsiStringToUnicodeSize (NTDLL.@)
645 * Return the size in bytes necessary for the Unicode conversion of 'str',
646 * including the terminating NULL.
648 DWORD WINAPI RtlAnsiStringToUnicodeSize( const STRING *str )
651 RtlMultiByteToUnicodeSize( &ret, str->Buffer, str->Length );
652 return ret + sizeof(WCHAR);
656 /**************************************************************************
657 * RtlMultiByteToUnicodeSize (NTDLL.@)
659 * Compute the size in bytes necessary for the Unicode conversion of 'str',
660 * without the terminating NULL.
662 NTSTATUS WINAPI RtlMultiByteToUnicodeSize( DWORD *size, LPCSTR str, UINT len )
664 *size = cp_mbstowcs( get_ansi_table(), 0, str, len, NULL, 0 ) * sizeof(WCHAR);
665 return STATUS_SUCCESS;
669 /**************************************************************************
670 * RtlUnicodeToMultiByteSize (NTDLL.@)
672 * Compute the size necessary for the multibyte conversion of 'str',
673 * without the terminating NULL.
675 NTSTATUS WINAPI RtlUnicodeToMultiByteSize( DWORD *size, LPCWSTR str, UINT len )
677 *size = cp_wcstombs( get_ansi_table(), 0, str, len / sizeof(WCHAR), NULL, 0, NULL, NULL );
678 return STATUS_SUCCESS;
682 /**************************************************************************
683 * RtlUnicodeStringToAnsiSize (NTDLL.@)
684 * RtlxUnicodeStringToAnsiSize (NTDLL.@)
686 * Return the size in bytes necessary for the Ansi conversion of 'str',
687 * including the terminating NULL.
689 DWORD WINAPI RtlUnicodeStringToAnsiSize( const UNICODE_STRING *str )
692 RtlUnicodeToMultiByteSize( &ret, str->Buffer, str->Length );
697 /**************************************************************************
698 * RtlUnicodeStringToOemSize (NTDLL.@)
699 * RtlxUnicodeStringToOemSize (NTDLL.@)
701 * Return the size in bytes necessary for the OEM conversion of 'str',
702 * including the terminating NULL.
704 DWORD WINAPI RtlUnicodeStringToOemSize( const UNICODE_STRING *str )
706 return cp_wcstombs( get_oem_table(), 0, str->Buffer, str->Length / sizeof(WCHAR),
707 NULL, 0, NULL, NULL ) + 1;
711 /**************************************************************************
712 * RtlAppendStringToString (NTDLL.@)
714 NTSTATUS WINAPI RtlAppendStringToString( STRING *dst, const STRING *src )
716 unsigned int len = src->Length + dst->Length;
717 if (len > dst->MaximumLength) return STATUS_BUFFER_TOO_SMALL;
718 memcpy( dst->Buffer + dst->Length, src->Buffer, src->Length );
720 return STATUS_SUCCESS;
724 /**************************************************************************
725 * RtlAppendAsciizToString (NTDLL.@)
727 NTSTATUS WINAPI RtlAppendAsciizToString( STRING *dst, LPCSTR src )
731 unsigned int srclen = strlen(src);
732 unsigned int total = srclen + dst->Length;
733 if (total > dst->MaximumLength) return STATUS_BUFFER_TOO_SMALL;
734 memcpy( dst->Buffer + dst->Length, src, srclen );
737 return STATUS_SUCCESS;
741 /**************************************************************************
742 * RtlAppendUnicodeToString (NTDLL.@)
744 NTSTATUS WINAPI RtlAppendUnicodeToString( UNICODE_STRING *dst, LPCWSTR src )
748 unsigned int srclen = strlenW(src) * sizeof(WCHAR);
749 unsigned int total = srclen + dst->Length;
750 if (total > dst->MaximumLength) return STATUS_BUFFER_TOO_SMALL;
751 memcpy( dst->Buffer + dst->Length/sizeof(WCHAR), src, srclen );
753 /* append terminating NULL if enough space */
754 if (total < dst->MaximumLength) dst->Buffer[total / sizeof(WCHAR)] = 0;
756 return STATUS_SUCCESS;
760 /**************************************************************************
761 * RtlAppendUnicodeStringToString (NTDLL.@)
763 NTSTATUS WINAPI RtlAppendUnicodeStringToString( UNICODE_STRING *dst, const UNICODE_STRING *src )
765 unsigned int len = src->Length + dst->Length;
766 if (len > dst->MaximumLength) return STATUS_BUFFER_TOO_SMALL;
767 memcpy( dst->Buffer + dst->Length/sizeof(WCHAR), src->Buffer, src->Length );
769 /* append terminating NULL if enough space */
770 if (len < dst->MaximumLength) dst->Buffer[len / sizeof(WCHAR)] = 0;
771 return STATUS_SUCCESS;
779 /**************************************************************************
780 * RtlIsTextUnicode (NTDLL.@)
782 * Apply various feeble heuristics to guess whether
783 * the text buffer contains Unicode.
784 * FIXME: should implement more tests.
786 DWORD WINAPI RtlIsTextUnicode(
792 DWORD flags = -1, out_flags = 0;
799 * Apply various tests to the text string. According to the
800 * docs, each test "passed" sets the corresponding flag in
801 * the output flags. But some of the tests are mutually
802 * exclusive, so I don't see how you could pass all tests ...
805 /* Check for an odd length ... pass if even. */
807 out_flags |= IS_TEXT_UNICODE_ODD_LENGTH;
809 /* Check for the special unicode marker byte. */
811 out_flags |= IS_TEXT_UNICODE_SIGNATURE;
814 * Check whether the string passed all of the tests.
816 flags &= ITU_IMPLEMENTED_TESTS;
817 if ((out_flags & flags) != flags)