vbscript: Handle index read access to array properties.
[wine.git] / dlls / ntdll / locale.c
blob105de1feec4ee7c6c1fbf3c04ca96df89acd9db4
1 /*
2 * Locale functions
4 * Copyright 2004, 2019 Alexandre Julliard
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #define NONAMELESSUNION
23 #include <stdarg.h>
24 #include <string.h>
25 #include <stdlib.h>
27 #include "ntstatus.h"
28 #define WIN32_NO_STATUS
29 #include "windef.h"
30 #include "winbase.h"
31 #include "winnls.h"
32 #include "ntdll_misc.h"
33 #include "locale_private.h"
34 #include "wine/debug.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(nls);
38 UINT NlsAnsiCodePage = 0;
39 BYTE NlsMbCodePageTag = 0;
40 BYTE NlsMbOemCodePageTag = 0;
42 static LCID user_resource_lcid;
43 static LCID user_resource_neutral_lcid;
44 static LCID system_lcid;
45 static NLSTABLEINFO nls_info = { { CP_UTF8 }, { CP_UTF8 } };
46 static struct norm_table *norm_tables[16];
47 static const NLS_LOCALE_HEADER *locale_table;
48 static const WCHAR *locale_strings;
51 static WCHAR casemap( USHORT *table, WCHAR ch )
53 return ch + table[table[table[ch >> 8] + ((ch >> 4) & 0x0f)] + (ch & 0x0f)];
57 static NTSTATUS load_norm_table( ULONG form, const struct norm_table **info )
59 unsigned int i;
60 USHORT *data, *tables;
61 SIZE_T size;
62 NTSTATUS status;
64 if (!form) return STATUS_INVALID_PARAMETER;
65 if (form >= ARRAY_SIZE(norm_tables)) return STATUS_OBJECT_NAME_NOT_FOUND;
67 if (!norm_tables[form])
69 if ((status = NtGetNlsSectionPtr( NLS_SECTION_NORMALIZE, form, NULL, (void **)&data, &size )))
70 return status;
72 /* sanity checks */
74 if (size <= 0x44) goto invalid;
75 if (data[0x14] != form) goto invalid;
76 tables = data + 0x1a;
77 for (i = 0; i < 8; i++)
79 if (tables[i] > size / sizeof(USHORT)) goto invalid;
80 if (i && tables[i] < tables[i-1]) goto invalid;
83 if (InterlockedCompareExchangePointer( (void **)&norm_tables[form], data, NULL ))
84 NtUnmapViewOfSection( GetCurrentProcess(), data );
86 *info = norm_tables[form];
87 return STATUS_SUCCESS;
89 invalid:
90 NtUnmapViewOfSection( GetCurrentProcess(), data );
91 return STATUS_INVALID_PARAMETER;
95 void locale_init(void)
97 USHORT utf8[2] = { 0, CP_UTF8 };
98 WCHAR locale[LOCALE_NAME_MAX_LENGTH];
99 LARGE_INTEGER unused;
100 SIZE_T size;
101 UINT ansi_cp = 1252, oem_cp = 437;
102 void *ansi_ptr = utf8, *oem_ptr = utf8, *case_ptr;
103 NTSTATUS status;
104 const struct locale_nls_header *header;
106 status = RtlGetLocaleFileMappingAddress( (void **)&header, &system_lcid, &unused );
107 if (status)
109 ERR( "locale init failed %x\n", status );
110 return;
112 locale_table = (const NLS_LOCALE_HEADER *)((char *)header + header->locales);
113 locale_strings = (const WCHAR *)((char *)locale_table + locale_table->strings_offset);
115 if (system_lcid == LOCALE_CUSTOM_UNSPECIFIED)
117 ansi_cp = oem_cp = CP_UTF8;
119 else
121 const NLS_LOCALE_LCID_INDEX *entry = find_lcid_entry( locale_table, system_lcid );
122 ansi_cp = get_locale_data( locale_table, entry->idx )->idefaultansicodepage;
123 oem_cp = get_locale_data( locale_table, entry->idx )->idefaultcodepage;
126 NtQueryDefaultLocale( TRUE, &user_resource_lcid );
127 user_resource_neutral_lcid = PRIMARYLANGID( user_resource_lcid );
128 if (user_resource_lcid == LOCALE_CUSTOM_UNSPECIFIED)
130 const NLS_LOCALE_LCNAME_INDEX *entry;
131 const WCHAR *parent;
132 WCHAR bufferW[LOCALE_NAME_MAX_LENGTH];
133 SIZE_T len;
135 if (!RtlQueryEnvironmentVariable( NULL, L"WINEUSERLOCALE", 14, bufferW, ARRAY_SIZE(bufferW), &len )
136 && (entry = find_lcname_entry( locale_table, bufferW )))
138 user_resource_lcid = get_locale_data( locale_table, entry->idx )->unique_lcid;
139 parent = locale_strings + get_locale_data( locale_table, entry->idx )->sparent;
140 if (*parent && (entry = find_lcname_entry( locale_table, parent + 1 )))
141 user_resource_neutral_lcid = get_locale_data( locale_table, entry->idx )->unique_lcid;
144 TRACE( "resources: %04x/%04x/%04x\n", user_resource_lcid, user_resource_neutral_lcid, system_lcid );
146 if (!RtlQueryActivationContextApplicationSettings( 0, NULL, L"http://schemas.microsoft.com/SMI/2019/WindowsSettings",
147 L"activeCodePage", locale, ARRAY_SIZE(locale), NULL ))
149 const NLS_LOCALE_LCNAME_INDEX *entry = find_lcname_entry( locale_table, locale );
151 if (!wcsicmp( locale, L"utf-8" ))
153 ansi_cp = oem_cp = CP_UTF8;
155 else if (!wcsicmp( locale, L"legacy" ))
157 if (ansi_cp == CP_UTF8) ansi_cp = 1252;
158 if (oem_cp == CP_UTF8) oem_cp = 437;
160 else if ((entry = find_lcname_entry( locale_table, locale )))
162 ansi_cp = get_locale_data( locale_table, entry->idx )->idefaultansicodepage;
163 oem_cp = get_locale_data( locale_table, entry->idx )->idefaultcodepage;
167 NtGetNlsSectionPtr( 10, 0, NULL, &case_ptr, &size );
168 NtCurrentTeb()->Peb->UnicodeCaseTableData = case_ptr;
169 if (ansi_cp != CP_UTF8)
171 NtGetNlsSectionPtr( 11, ansi_cp, NULL, &ansi_ptr, &size );
172 NtCurrentTeb()->Peb->AnsiCodePageData = ansi_ptr;
174 if (oem_cp != CP_UTF8)
176 NtGetNlsSectionPtr( 11, oem_cp, NULL, &oem_ptr, &size );
177 NtCurrentTeb()->Peb->OemCodePageData = oem_ptr;
179 RtlInitNlsTables( ansi_ptr, oem_ptr, case_ptr, &nls_info );
180 NlsAnsiCodePage = nls_info.AnsiTableInfo.CodePage;
181 NlsMbCodePageTag = nls_info.AnsiTableInfo.DBCSCodePage;
182 NlsMbOemCodePageTag = nls_info.OemTableInfo.DBCSCodePage;
186 /* return LCIDs to use for resource lookup */
187 void get_resource_lcids( LANGID *user, LANGID *user_neutral, LANGID *system )
189 *user = LANGIDFROMLCID( user_resource_lcid );
190 *user_neutral = LANGIDFROMLCID( user_resource_neutral_lcid );
191 *system = LANGIDFROMLCID( system_lcid );
195 static NTSTATUS get_dummy_preferred_ui_language( DWORD flags, LANGID lang, ULONG *count,
196 WCHAR *buffer, ULONG *size )
198 WCHAR name[LOCALE_NAME_MAX_LENGTH + 2];
199 NTSTATUS status;
200 ULONG len;
202 FIXME("(0x%x %p %p %p) returning a dummy value (current locale)\n", flags, count, buffer, size);
204 if (flags & MUI_LANGUAGE_ID) swprintf( name, ARRAY_SIZE(name), L"%04lX", lang );
205 else
207 UNICODE_STRING str;
209 str.Buffer = name;
210 str.MaximumLength = sizeof(name);
211 status = RtlLcidToLocaleName( lang, &str, 0, FALSE );
212 if (status) return status;
215 len = wcslen( name ) + 2;
216 name[len - 1] = 0;
217 if (buffer)
219 if (len > *size)
221 *size = len;
222 return STATUS_BUFFER_TOO_SMALL;
224 memcpy( buffer, name, len * sizeof(WCHAR) );
226 *size = len;
227 *count = 1;
228 TRACE("returned variable content: %d, \"%s\", %d\n", *count, debugstr_w(buffer), *size);
229 return STATUS_SUCCESS;
233 /**************************************************************************
234 * RtlGetProcessPreferredUILanguages (NTDLL.@)
236 NTSTATUS WINAPI RtlGetProcessPreferredUILanguages( DWORD flags, ULONG *count, WCHAR *buffer, ULONG *size )
238 LANGID ui_language;
240 FIXME( "%08x, %p, %p %p\n", flags, count, buffer, size );
242 NtQueryDefaultUILanguage( &ui_language );
243 return get_dummy_preferred_ui_language( flags, ui_language, count, buffer, size );
247 /**************************************************************************
248 * RtlGetSystemPreferredUILanguages (NTDLL.@)
250 NTSTATUS WINAPI RtlGetSystemPreferredUILanguages( DWORD flags, ULONG unknown, ULONG *count,
251 WCHAR *buffer, ULONG *size )
253 LANGID ui_language;
255 if (flags & ~(MUI_LANGUAGE_NAME | MUI_LANGUAGE_ID | MUI_MACHINE_LANGUAGE_SETTINGS)) return STATUS_INVALID_PARAMETER;
256 if ((flags & MUI_LANGUAGE_NAME) && (flags & MUI_LANGUAGE_ID)) return STATUS_INVALID_PARAMETER;
257 if (*size && !buffer) return STATUS_INVALID_PARAMETER;
259 NtQueryInstallUILanguage( &ui_language );
260 return get_dummy_preferred_ui_language( flags, ui_language, count, buffer, size );
264 /**************************************************************************
265 * RtlGetThreadPreferredUILanguages (NTDLL.@)
267 NTSTATUS WINAPI RtlGetThreadPreferredUILanguages( DWORD flags, ULONG *count, WCHAR *buffer, ULONG *size )
269 LANGID ui_language;
271 FIXME( "%08x, %p, %p %p\n", flags, count, buffer, size );
273 NtQueryDefaultUILanguage( &ui_language );
274 return get_dummy_preferred_ui_language( flags, ui_language, count, buffer, size );
278 /**************************************************************************
279 * RtlGetUserPreferredUILanguages (NTDLL.@)
281 NTSTATUS WINAPI RtlGetUserPreferredUILanguages( DWORD flags, ULONG unknown, ULONG *count,
282 WCHAR *buffer, ULONG *size )
284 LANGID ui_language;
286 if (flags & ~(MUI_LANGUAGE_NAME | MUI_LANGUAGE_ID)) return STATUS_INVALID_PARAMETER;
287 if ((flags & MUI_LANGUAGE_NAME) && (flags & MUI_LANGUAGE_ID)) return STATUS_INVALID_PARAMETER;
288 if (*size && !buffer) return STATUS_INVALID_PARAMETER;
290 NtQueryDefaultUILanguage( &ui_language );
291 return get_dummy_preferred_ui_language( flags, ui_language, count, buffer, size );
295 /**************************************************************************
296 * RtlSetProcessPreferredUILanguages (NTDLL.@)
298 NTSTATUS WINAPI RtlSetProcessPreferredUILanguages( DWORD flags, PCZZWSTR buffer, ULONG *count )
300 FIXME( "%u, %p, %p\n", flags, buffer, count );
301 return STATUS_SUCCESS;
305 /**************************************************************************
306 * RtlSetThreadPreferredUILanguages (NTDLL.@)
308 NTSTATUS WINAPI RtlSetThreadPreferredUILanguages( DWORD flags, PCZZWSTR buffer, ULONG *count )
310 FIXME( "%u, %p, %p\n", flags, buffer, count );
311 return STATUS_SUCCESS;
315 /******************************************************************
316 * RtlInitCodePageTable (NTDLL.@)
318 void WINAPI RtlInitCodePageTable( USHORT *ptr, CPTABLEINFO *info )
320 static const CPTABLEINFO utf8_cpinfo = { CP_UTF8, 4, '?', 0xfffd, '?', '?' };
322 if (ptr[1] == CP_UTF8) *info = utf8_cpinfo;
323 else init_codepage_table( ptr, info );
327 /**************************************************************************
328 * RtlInitNlsTables (NTDLL.@)
330 void WINAPI RtlInitNlsTables( USHORT *ansi, USHORT *oem, USHORT *casetable, NLSTABLEINFO *info )
332 RtlInitCodePageTable( ansi, &info->AnsiTableInfo );
333 RtlInitCodePageTable( oem, &info->OemTableInfo );
334 info->UpperCaseTable = casetable + 2;
335 info->LowerCaseTable = casetable + casetable[1] + 2;
339 /**************************************************************************
340 * RtlResetRtlTranslations (NTDLL.@)
342 void WINAPI RtlResetRtlTranslations( const NLSTABLEINFO *info )
344 NlsAnsiCodePage = info->AnsiTableInfo.CodePage;
345 NlsMbCodePageTag = info->AnsiTableInfo.DBCSCodePage;
346 NlsMbOemCodePageTag = info->OemTableInfo.DBCSCodePage;
347 nls_info = *info;
351 /**************************************************************************
352 * RtlGetLocaleFileMappingAddress (NTDLL.@)
354 NTSTATUS WINAPI RtlGetLocaleFileMappingAddress( void **ptr, LCID *lcid, LARGE_INTEGER *size )
356 static void *cached_ptr;
357 static LCID cached_lcid;
359 if (!cached_ptr)
361 void *addr;
362 NTSTATUS status = NtInitializeNlsFiles( &addr, &cached_lcid, size );
364 if (status) return status;
365 if (InterlockedCompareExchangePointer( &cached_ptr, addr, NULL ))
366 NtUnmapViewOfSection( GetCurrentProcess(), addr );
368 *ptr = cached_ptr;
369 *lcid = cached_lcid;
370 return STATUS_SUCCESS;
374 /**************************************************************************
375 * RtlAnsiCharToUnicodeChar (NTDLL.@)
377 WCHAR WINAPI RtlAnsiCharToUnicodeChar( char **ansi )
379 unsigned char ch = *(*ansi)++;
381 if (nls_info.AnsiTableInfo.CodePage == CP_UTF8)
383 unsigned int res;
385 if (ch < 0x80) return ch;
386 if ((res = decode_utf8_char( ch, (const char **)ansi, *ansi + 3 )) > 0x10ffff) res = 0xfffd;
387 return res;
389 if (nls_info.AnsiTableInfo.DBCSOffsets)
391 USHORT off = nls_info.AnsiTableInfo.DBCSOffsets[ch];
392 if (off) return nls_info.AnsiTableInfo.DBCSOffsets[off + (unsigned char)*(*ansi)++];
394 return nls_info.AnsiTableInfo.MultiByteTable[ch];
398 /******************************************************************************
399 * RtlCompareUnicodeStrings (NTDLL.@)
401 LONG WINAPI RtlCompareUnicodeStrings( const WCHAR *s1, SIZE_T len1, const WCHAR *s2, SIZE_T len2,
402 BOOLEAN case_insensitive )
404 LONG ret = 0;
405 SIZE_T len = min( len1, len2 );
407 if (case_insensitive)
409 if (nls_info.UpperCaseTable)
411 while (!ret && len--) ret = casemap( nls_info.UpperCaseTable, *s1++ ) -
412 casemap( nls_info.UpperCaseTable, *s2++ );
414 else /* locale not setup yet */
416 while (!ret && len--) ret = casemap_ascii( *s1++ ) - casemap_ascii( *s2++ );
419 else
421 while (!ret && len--) ret = *s1++ - *s2++;
423 if (!ret) ret = len1 - len2;
424 return ret;
428 /**************************************************************************
429 * RtlPrefixUnicodeString (NTDLL.@)
431 BOOLEAN WINAPI RtlPrefixUnicodeString( const UNICODE_STRING *s1, const UNICODE_STRING *s2,
432 BOOLEAN ignore_case )
434 unsigned int i;
436 if (s1->Length > s2->Length) return FALSE;
437 if (ignore_case)
439 for (i = 0; i < s1->Length / sizeof(WCHAR); i++)
440 if (casemap( nls_info.UpperCaseTable, s1->Buffer[i] ) !=
441 casemap( nls_info.UpperCaseTable, s2->Buffer[i] )) return FALSE;
443 else
445 for (i = 0; i < s1->Length / sizeof(WCHAR); i++)
446 if (s1->Buffer[i] != s2->Buffer[i]) return FALSE;
448 return TRUE;
453 /******************************************************************************
454 * RtlHashUnicodeString (NTDLL.@)
456 NTSTATUS WINAPI RtlHashUnicodeString( const UNICODE_STRING *string, BOOLEAN case_insensitive,
457 ULONG alg, ULONG *hash )
459 unsigned int i;
461 if (!string || !hash) return STATUS_INVALID_PARAMETER;
463 switch (alg)
465 case HASH_STRING_ALGORITHM_DEFAULT:
466 case HASH_STRING_ALGORITHM_X65599:
467 break;
468 default:
469 return STATUS_INVALID_PARAMETER;
472 *hash = 0;
473 if (!case_insensitive)
474 for (i = 0; i < string->Length / sizeof(WCHAR); i++)
475 *hash = *hash * 65599 + string->Buffer[i];
476 else if (nls_info.UpperCaseTable)
477 for (i = 0; i < string->Length / sizeof(WCHAR); i++)
478 *hash = *hash * 65599 + casemap( nls_info.UpperCaseTable, string->Buffer[i] );
479 else /* locale not setup yet */
480 for (i = 0; i < string->Length / sizeof(WCHAR); i++)
481 *hash = *hash * 65599 + casemap_ascii( string->Buffer[i] );
482 return STATUS_SUCCESS;
486 /**************************************************************************
487 * RtlCustomCPToUnicodeN (NTDLL.@)
489 NTSTATUS WINAPI RtlCustomCPToUnicodeN( CPTABLEINFO *info, WCHAR *dst, DWORD dstlen, DWORD *reslen,
490 const char *src, DWORD srclen )
492 unsigned int ret = cp_mbstowcs( info, dst, dstlen / sizeof(WCHAR), src, srclen );
493 if (reslen) *reslen = ret * sizeof(WCHAR);
494 return STATUS_SUCCESS;
498 /**************************************************************************
499 * RtlUnicodeToCustomCPN (NTDLL.@)
501 NTSTATUS WINAPI RtlUnicodeToCustomCPN( CPTABLEINFO *info, char *dst, DWORD dstlen, DWORD *reslen,
502 const WCHAR *src, DWORD srclen )
504 unsigned int ret = cp_wcstombs( info, dst, dstlen, src, srclen / sizeof(WCHAR) );
505 if (reslen) *reslen = ret;
506 return STATUS_SUCCESS;
510 /**************************************************************************
511 * RtlMultiByteToUnicodeN (NTDLL.@)
513 NTSTATUS WINAPI RtlMultiByteToUnicodeN( WCHAR *dst, DWORD dstlen, DWORD *reslen,
514 const char *src, DWORD srclen )
516 unsigned int ret;
518 if (nls_info.AnsiTableInfo.CodePage != CP_UTF8)
519 ret = cp_mbstowcs( &nls_info.AnsiTableInfo, dst, dstlen / sizeof(WCHAR), src, srclen );
520 else
521 utf8_mbstowcs( dst, dstlen / sizeof(WCHAR), &ret, src, srclen );
523 if (reslen) *reslen = ret * sizeof(WCHAR);
524 return STATUS_SUCCESS;
528 /**************************************************************************
529 * RtlMultiByteToUnicodeSize (NTDLL.@)
531 NTSTATUS WINAPI RtlMultiByteToUnicodeSize( DWORD *size, const char *str, DWORD len )
533 unsigned int ret;
535 if (nls_info.AnsiTableInfo.CodePage != CP_UTF8)
536 ret = cp_mbstowcs_size( &nls_info.AnsiTableInfo, str, len );
537 else
538 utf8_mbstowcs_size( str, len, &ret );
540 *size = ret * sizeof(WCHAR);
541 return STATUS_SUCCESS;
545 /**************************************************************************
546 * RtlOemToUnicodeN (NTDLL.@)
548 NTSTATUS WINAPI RtlOemToUnicodeN( WCHAR *dst, DWORD dstlen, DWORD *reslen,
549 const char *src, DWORD srclen )
551 unsigned int ret;
553 if (nls_info.OemTableInfo.CodePage != CP_UTF8)
554 ret = cp_mbstowcs( &nls_info.OemTableInfo, dst, dstlen / sizeof(WCHAR), src, srclen );
555 else
556 utf8_mbstowcs( dst, dstlen / sizeof(WCHAR), &ret, src, srclen );
558 if (reslen) *reslen = ret * sizeof(WCHAR);
559 return STATUS_SUCCESS;
563 /**************************************************************************
564 * RtlOemStringToUnicodeSize (NTDLL.@)
565 * RtlxOemStringToUnicodeSize (NTDLL.@)
567 DWORD WINAPI RtlOemStringToUnicodeSize( const STRING *str )
569 unsigned int ret;
571 if (nls_info.OemTableInfo.CodePage != CP_UTF8)
572 ret = cp_mbstowcs_size( &nls_info.OemTableInfo, str->Buffer, str->Length );
573 else
574 utf8_mbstowcs_size( str->Buffer, str->Length, &ret );
576 return (ret + 1) * sizeof(WCHAR);
580 /**************************************************************************
581 * RtlUnicodeStringToOemSize (NTDLL.@)
582 * RtlxUnicodeStringToOemSize (NTDLL.@)
584 DWORD WINAPI RtlUnicodeStringToOemSize( const UNICODE_STRING *str )
586 unsigned int ret;
588 if (nls_info.OemTableInfo.CodePage != CP_UTF8)
589 ret = cp_wcstombs_size( &nls_info.OemTableInfo, str->Buffer, str->Length / sizeof(WCHAR) );
590 else
591 utf8_wcstombs_size( str->Buffer, str->Length / sizeof(WCHAR), &ret );
593 return ret + 1;
597 /**************************************************************************
598 * RtlUnicodeToMultiByteN (NTDLL.@)
600 NTSTATUS WINAPI RtlUnicodeToMultiByteN( char *dst, DWORD dstlen, DWORD *reslen,
601 const WCHAR *src, DWORD srclen )
603 unsigned int ret;
605 if (nls_info.AnsiTableInfo.CodePage != CP_UTF8)
606 ret = cp_wcstombs( &nls_info.AnsiTableInfo, dst, dstlen, src, srclen / sizeof(WCHAR) );
607 else
608 utf8_wcstombs( dst, dstlen, &ret, src, srclen / sizeof(WCHAR) );
610 if (reslen) *reslen = ret;
611 return STATUS_SUCCESS;
615 /**************************************************************************
616 * RtlUnicodeToMultiByteSize (NTDLL.@)
618 NTSTATUS WINAPI RtlUnicodeToMultiByteSize( DWORD *size, const WCHAR *str, DWORD len )
620 unsigned int ret;
622 if (nls_info.AnsiTableInfo.CodePage != CP_UTF8)
623 ret = cp_wcstombs_size( &nls_info.AnsiTableInfo, str, len / sizeof(WCHAR) );
624 else
625 utf8_wcstombs_size( str, len / sizeof(WCHAR), &ret );
627 *size = ret;
628 return STATUS_SUCCESS;
632 /**************************************************************************
633 * RtlUnicodeToOemN (NTDLL.@)
635 NTSTATUS WINAPI RtlUnicodeToOemN( char *dst, DWORD dstlen, DWORD *reslen,
636 const WCHAR *src, DWORD srclen )
638 unsigned int ret;
640 if (nls_info.OemTableInfo.CodePage != CP_UTF8)
641 ret = cp_wcstombs( &nls_info.OemTableInfo, dst, dstlen, src, srclen / sizeof(WCHAR) );
642 else
643 utf8_wcstombs( dst, dstlen, &ret, src, srclen / sizeof(WCHAR) );
645 if (reslen) *reslen = ret;
646 return STATUS_SUCCESS;
650 /**************************************************************************
651 * RtlDowncaseUnicodeChar (NTDLL.@)
653 WCHAR WINAPI RtlDowncaseUnicodeChar( WCHAR wch )
655 if (nls_info.LowerCaseTable) return casemap( nls_info.LowerCaseTable, wch );
656 if (wch >= 'A' && wch <= 'Z') wch += 'a' - 'A';
657 return wch;
661 /**************************************************************************
662 * RtlDowncaseUnicodeString (NTDLL.@)
664 NTSTATUS WINAPI RtlDowncaseUnicodeString( UNICODE_STRING *dest, const UNICODE_STRING *src,
665 BOOLEAN alloc )
667 DWORD i, len = src->Length;
669 if (alloc)
671 dest->MaximumLength = len;
672 if (!(dest->Buffer = RtlAllocateHeap( GetProcessHeap(), 0, len ))) return STATUS_NO_MEMORY;
674 else if (len > dest->MaximumLength) return STATUS_BUFFER_OVERFLOW;
676 for (i = 0; i < len / sizeof(WCHAR); i++)
677 dest->Buffer[i] = casemap( nls_info.LowerCaseTable, src->Buffer[i] );
678 dest->Length = len;
679 return STATUS_SUCCESS;
683 /**************************************************************************
684 * RtlUpcaseUnicodeChar (NTDLL.@)
686 WCHAR WINAPI RtlUpcaseUnicodeChar( WCHAR wch )
688 return casemap( nls_info.UpperCaseTable, wch );
692 /**************************************************************************
693 * RtlUpcaseUnicodeString (NTDLL.@)
695 NTSTATUS WINAPI RtlUpcaseUnicodeString( UNICODE_STRING *dest, const UNICODE_STRING *src,
696 BOOLEAN alloc )
698 DWORD i, len = src->Length;
700 if (alloc)
702 dest->MaximumLength = len;
703 if (!(dest->Buffer = RtlAllocateHeap( GetProcessHeap(), 0, len ))) return STATUS_NO_MEMORY;
705 else if (len > dest->MaximumLength) return STATUS_BUFFER_OVERFLOW;
707 for (i = 0; i < len / sizeof(WCHAR); i++)
708 dest->Buffer[i] = casemap( nls_info.UpperCaseTable, src->Buffer[i] );
709 dest->Length = len;
710 return STATUS_SUCCESS;
714 /**************************************************************************
715 * RtlUpcaseUnicodeToCustomCPN (NTDLL.@)
717 NTSTATUS WINAPI RtlUpcaseUnicodeToCustomCPN( CPTABLEINFO *info, char *dst, DWORD dstlen, DWORD *reslen,
718 const WCHAR *src, DWORD srclen )
720 DWORD i, ret;
722 srclen /= sizeof(WCHAR);
723 if (info->DBCSCodePage)
725 WCHAR *uni2cp = info->WideCharTable;
727 for (i = dstlen; srclen && i; i--, srclen--, src++)
729 WCHAR ch = casemap( nls_info.UpperCaseTable, *src );
730 if (uni2cp[ch] & 0xff00)
732 if (i == 1) break; /* do not output a partial char */
733 i--;
734 *dst++ = uni2cp[ch] >> 8;
736 *dst++ = (char)uni2cp[ch];
738 ret = dstlen - i;
740 else
742 char *uni2cp = info->WideCharTable;
743 ret = min( srclen, dstlen );
744 for (i = 0; i < ret; i++) dst[i] = uni2cp[casemap( nls_info.UpperCaseTable, src[i] )];
746 if (reslen) *reslen = ret;
747 return STATUS_SUCCESS;
751 static NTSTATUS upcase_unicode_to_utf8( char *dst, DWORD dstlen, DWORD *reslen,
752 const WCHAR *src, DWORD srclen )
754 char *end;
755 unsigned int val;
756 NTSTATUS status = STATUS_SUCCESS;
758 srclen /= sizeof(WCHAR);
760 for (end = dst + dstlen; srclen; srclen--, src++)
762 WCHAR ch = casemap( nls_info.UpperCaseTable, *src );
764 if (ch < 0x80) /* 0x00-0x7f: 1 byte */
766 if (dst > end - 1) break;
767 *dst++ = ch;
768 continue;
770 if (ch < 0x800) /* 0x80-0x7ff: 2 bytes */
772 if (dst > end - 2) break;
773 dst[1] = 0x80 | (ch & 0x3f);
774 ch >>= 6;
775 dst[0] = 0xc0 | ch;
776 dst += 2;
777 continue;
779 if (!get_utf16( src, srclen, &val ))
781 val = 0xfffd;
782 status = STATUS_SOME_NOT_MAPPED;
784 if (val < 0x10000) /* 0x800-0xffff: 3 bytes */
786 if (dst > end - 3) break;
787 dst[2] = 0x80 | (val & 0x3f);
788 val >>= 6;
789 dst[1] = 0x80 | (val & 0x3f);
790 val >>= 6;
791 dst[0] = 0xe0 | val;
792 dst += 3;
794 else /* 0x10000-0x10ffff: 4 bytes */
796 if (dst > end - 4) break;
797 dst[3] = 0x80 | (val & 0x3f);
798 val >>= 6;
799 dst[2] = 0x80 | (val & 0x3f);
800 val >>= 6;
801 dst[1] = 0x80 | (val & 0x3f);
802 val >>= 6;
803 dst[0] = 0xf0 | val;
804 dst += 4;
805 src++;
806 srclen--;
809 if (srclen) status = STATUS_BUFFER_TOO_SMALL;
810 if (reslen) *reslen = dstlen - (end - dst);
811 return status;
814 /**************************************************************************
815 * RtlUpcaseUnicodeToMultiByteN (NTDLL.@)
817 NTSTATUS WINAPI RtlUpcaseUnicodeToMultiByteN( char *dst, DWORD dstlen, DWORD *reslen,
818 const WCHAR *src, DWORD srclen )
820 if (nls_info.AnsiTableInfo.CodePage == CP_UTF8)
821 return upcase_unicode_to_utf8( dst, dstlen, reslen, src, srclen );
822 return RtlUpcaseUnicodeToCustomCPN( &nls_info.AnsiTableInfo, dst, dstlen, reslen, src, srclen );
826 /**************************************************************************
827 * RtlUpcaseUnicodeToOemN (NTDLL.@)
829 NTSTATUS WINAPI RtlUpcaseUnicodeToOemN( char *dst, DWORD dstlen, DWORD *reslen,
830 const WCHAR *src, DWORD srclen )
832 if (nls_info.OemTableInfo.CodePage == CP_UTF8)
833 return upcase_unicode_to_utf8( dst, dstlen, reslen, src, srclen );
834 return RtlUpcaseUnicodeToCustomCPN( &nls_info.OemTableInfo, dst, dstlen, reslen, src, srclen );
838 /*********************************************************************
839 * towlower (NTDLL.@)
841 WCHAR __cdecl towlower( WCHAR ch )
843 if (ch >= 0x100) return ch;
844 return casemap( nls_info.LowerCaseTable, ch );
848 /*********************************************************************
849 * towupper (NTDLL.@)
851 WCHAR __cdecl towupper( WCHAR ch )
853 if (nls_info.UpperCaseTable) return casemap( nls_info.UpperCaseTable, ch );
854 return casemap_ascii( ch );
858 /******************************************************************
859 * RtlIsValidLocaleName (NTDLL.@)
861 BOOLEAN WINAPI RtlIsValidLocaleName( const WCHAR *name, ULONG flags )
863 const NLS_LOCALE_LCNAME_INDEX *entry = find_lcname_entry( locale_table, name );
865 if (!entry) return FALSE;
866 /* reject neutral locale unless flag 2 is set */
867 if (!(flags & 2) && !get_locale_data( locale_table, entry->idx )->inotneutral) return FALSE;
868 return TRUE;
872 /******************************************************************
873 * RtlLcidToLocaleName (NTDLL.@)
875 NTSTATUS WINAPI RtlLcidToLocaleName( LCID lcid, UNICODE_STRING *str, ULONG flags, BOOLEAN alloc )
877 const NLS_LOCALE_LCID_INDEX *entry;
878 const WCHAR *name;
879 ULONG len;
881 if (!str) return STATUS_INVALID_PARAMETER_2;
883 switch (lcid)
885 case LOCALE_USER_DEFAULT:
886 NtQueryDefaultLocale( TRUE, &lcid );
887 break;
888 case LOCALE_SYSTEM_DEFAULT:
889 case LOCALE_CUSTOM_DEFAULT:
890 lcid = system_lcid;
891 break;
892 case LOCALE_CUSTOM_UI_DEFAULT:
893 return STATUS_UNSUCCESSFUL;
894 case LOCALE_CUSTOM_UNSPECIFIED:
895 return STATUS_INVALID_PARAMETER_1;
898 if (!(entry = find_lcid_entry( locale_table, lcid ))) return STATUS_INVALID_PARAMETER_1;
899 /* reject neutral locale unless flag 2 is set */
900 if (!(flags & 2) && !get_locale_data( locale_table, entry->idx )->inotneutral)
901 return STATUS_INVALID_PARAMETER_1;
903 name = locale_strings + entry->name;
904 len = *name++;
906 if (alloc)
908 if (!(str->Buffer = RtlAllocateHeap( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) )))
909 return STATUS_NO_MEMORY;
910 str->MaximumLength = (len + 1) * sizeof(WCHAR);
912 else if (str->MaximumLength < (len + 1) * sizeof(WCHAR)) return STATUS_BUFFER_TOO_SMALL;
914 wcscpy( str->Buffer, name );
915 str->Length = len * sizeof(WCHAR);
916 TRACE( "%04x -> %s\n", lcid, debugstr_us(str) );
917 return STATUS_SUCCESS;
921 /******************************************************************
922 * RtlLocaleNameToLcid (NTDLL.@)
924 NTSTATUS WINAPI RtlLocaleNameToLcid( const WCHAR *name, LCID *lcid, ULONG flags )
926 const NLS_LOCALE_LCNAME_INDEX *entry = find_lcname_entry( locale_table, name );
928 if (!entry) return STATUS_INVALID_PARAMETER_1;
929 /* reject neutral locale unless flag 2 is set */
930 if (!(flags & 2) && !get_locale_data( locale_table, entry->idx )->inotneutral)
931 return STATUS_INVALID_PARAMETER_1;
932 *lcid = entry->id;
933 TRACE( "%s -> %04x\n", debugstr_w(name), *lcid );
934 return STATUS_SUCCESS;
938 /**************************************************************************
939 * RtlUTF8ToUnicodeN (NTDLL.@)
941 NTSTATUS WINAPI RtlUTF8ToUnicodeN( WCHAR *dst, DWORD dstlen, DWORD *reslen, const char *src, DWORD srclen )
943 unsigned int ret;
944 NTSTATUS status;
946 if (!src) return STATUS_INVALID_PARAMETER_4;
947 if (!reslen) return STATUS_INVALID_PARAMETER;
949 if (!dst)
950 status = utf8_mbstowcs_size( src, srclen, &ret );
951 else
952 status = utf8_mbstowcs( dst, dstlen / sizeof(WCHAR), &ret, src, srclen );
954 *reslen = ret * sizeof(WCHAR);
955 return status;
959 /**************************************************************************
960 * RtlUnicodeToUTF8N (NTDLL.@)
962 NTSTATUS WINAPI RtlUnicodeToUTF8N( char *dst, DWORD dstlen, DWORD *reslen, const WCHAR *src, DWORD srclen )
964 unsigned int ret;
965 NTSTATUS status;
967 if (!src) return STATUS_INVALID_PARAMETER_4;
968 if (!reslen) return STATUS_INVALID_PARAMETER;
969 if (dst && (srclen & 1)) return STATUS_INVALID_PARAMETER_5;
971 if (!dst)
972 status = utf8_wcstombs_size( src, srclen / sizeof(WCHAR), &ret );
973 else
974 status = utf8_wcstombs( dst, dstlen, &ret, src, srclen / sizeof(WCHAR) );
976 *reslen = ret;
977 return status;
981 /******************************************************************************
982 * RtlIsNormalizedString (NTDLL.@)
984 NTSTATUS WINAPI RtlIsNormalizedString( ULONG form, const WCHAR *str, INT len, BOOLEAN *res )
986 const struct norm_table *info;
987 NTSTATUS status;
988 BYTE props, class, last_class = 0;
989 unsigned int ch;
990 int i, r, result = 1;
992 if ((status = load_norm_table( form, &info ))) return status;
994 if (len == -1) len = wcslen( str );
996 for (i = 0; i < len && result; i += r)
998 if (!(r = get_utf16( str + i, len - i, &ch ))) return STATUS_NO_UNICODE_TRANSLATION;
999 if (info->comp_size)
1001 if ((ch >= HANGUL_VBASE && ch < HANGUL_VBASE + HANGUL_VCOUNT) ||
1002 (ch >= HANGUL_TBASE && ch < HANGUL_TBASE + HANGUL_TCOUNT))
1004 result = -1; /* QC=Maybe */
1005 continue;
1008 else if (ch >= HANGUL_SBASE && ch < HANGUL_SBASE + HANGUL_SCOUNT)
1010 result = 0; /* QC=No */
1011 break;
1013 props = get_char_props( info, ch );
1014 class = props & 0x3f;
1015 if (class == 0x3f)
1017 last_class = 0;
1018 if (props == 0xbf) result = 0; /* QC=No */
1019 else if (props == 0xff)
1021 /* ignore other chars in Hangul range */
1022 if (ch >= HANGUL_LBASE && ch < HANGUL_LBASE + 0x100) continue;
1023 if (ch >= HANGUL_SBASE && ch < HANGUL_SBASE + 0x2c00) continue;
1024 /* allow final null */
1025 if (!ch && i == len - 1) continue;
1026 return STATUS_NO_UNICODE_TRANSLATION;
1029 else if (props & 0x80)
1031 if ((props & 0xc0) == 0xc0) result = -1; /* QC=Maybe */
1032 if (class && class < last_class) result = 0; /* QC=No */
1033 last_class = class;
1035 else last_class = 0;
1038 if (result == -1)
1040 int dstlen = len * 4;
1041 NTSTATUS status;
1042 WCHAR *buffer = RtlAllocateHeap( GetProcessHeap(), 0, dstlen * sizeof(WCHAR) );
1043 if (!buffer) return STATUS_NO_MEMORY;
1044 status = RtlNormalizeString( form, str, len, buffer, &dstlen );
1045 result = !status && (dstlen == len) && !wcsncmp( buffer, str, len );
1046 RtlFreeHeap( GetProcessHeap(), 0, buffer );
1048 *res = result;
1049 return STATUS_SUCCESS;
1053 /******************************************************************************
1054 * RtlNormalizeString (NTDLL.@)
1056 NTSTATUS WINAPI RtlNormalizeString( ULONG form, const WCHAR *src, INT src_len, WCHAR *dst, INT *dst_len )
1058 int buf_len;
1059 WCHAR *buf = NULL;
1060 const struct norm_table *info;
1061 NTSTATUS status = STATUS_SUCCESS;
1063 TRACE( "%x %s %d %p %d\n", form, debugstr_wn(src, src_len), src_len, dst, *dst_len );
1065 if ((status = load_norm_table( form, &info ))) return status;
1067 if (src_len == -1) src_len = wcslen(src) + 1;
1069 if (!*dst_len)
1071 *dst_len = src_len * info->len_factor;
1072 if (*dst_len > 64) *dst_len = max( 64, src_len + src_len / 8 );
1073 return STATUS_SUCCESS;
1075 if (!src_len)
1077 *dst_len = 0;
1078 return STATUS_SUCCESS;
1081 if (!info->comp_size) return decompose_string( info, src, src_len, dst, dst_len );
1083 buf_len = src_len * 4;
1084 for (;;)
1086 buf = RtlAllocateHeap( GetProcessHeap(), 0, buf_len * sizeof(WCHAR) );
1087 if (!buf) return STATUS_NO_MEMORY;
1088 status = decompose_string( info, src, src_len, buf, &buf_len );
1089 if (status != STATUS_BUFFER_TOO_SMALL) break;
1090 RtlFreeHeap( GetProcessHeap(), 0, buf );
1092 if (!status)
1094 buf_len = compose_string( info, buf, buf_len );
1095 if (*dst_len >= buf_len) memcpy( dst, buf, buf_len * sizeof(WCHAR) );
1096 else status = STATUS_BUFFER_TOO_SMALL;
1098 RtlFreeHeap( GetProcessHeap(), 0, buf );
1099 *dst_len = buf_len;
1100 return status;
1104 /* Punycode parameters */
1105 enum { BASE = 36, TMIN = 1, TMAX = 26, SKEW = 38, DAMP = 700 };
1107 static BOOL check_invalid_chars( const struct norm_table *info, DWORD flags,
1108 const unsigned int *buffer, int len )
1110 int i;
1112 for (i = 0; i < len; i++)
1114 switch (buffer[i])
1116 case 0x200c: /* zero-width non-joiner */
1117 case 0x200d: /* zero-width joiner */
1118 if (!i || get_combining_class( info, buffer[i - 1] ) != 9) return TRUE;
1119 break;
1120 case 0x2260: /* not equal to */
1121 case 0x226e: /* not less than */
1122 case 0x226f: /* not greater than */
1123 if (flags & IDN_USE_STD3_ASCII_RULES) return TRUE;
1124 break;
1126 switch (get_char_props( info, buffer[i] ))
1128 case 0xbf:
1129 return TRUE;
1130 case 0xff:
1131 if (buffer[i] >= HANGUL_SBASE && buffer[i] < HANGUL_SBASE + 0x2c00) break;
1132 return TRUE;
1133 case 0x7f:
1134 if (!(flags & IDN_ALLOW_UNASSIGNED)) return TRUE;
1135 break;
1139 if ((flags & IDN_USE_STD3_ASCII_RULES) && len && (buffer[0] == '-' || buffer[len - 1] == '-'))
1140 return TRUE;
1142 return FALSE;
1146 /******************************************************************************
1147 * RtlIdnToAscii (NTDLL.@)
1149 NTSTATUS WINAPI RtlIdnToAscii( DWORD flags, const WCHAR *src, INT srclen, WCHAR *dst, INT *dstlen )
1151 static const WCHAR prefixW[] = {'x','n','-','-'};
1152 const struct norm_table *info;
1153 NTSTATUS status;
1154 WCHAR normstr[256], res[256];
1155 unsigned int ch, buffer[64];
1156 int i, len, start, end, out_label, out = 0, normlen = ARRAY_SIZE(normstr);
1158 TRACE( "%x %s %p %d\n", flags, debugstr_wn(src, srclen), dst, *dstlen );
1160 if ((status = load_norm_table( 13, &info ))) return status;
1162 if ((status = RtlIdnToNameprepUnicode( flags, src, srclen, normstr, &normlen ))) return status;
1164 /* implementation of Punycode based on RFC 3492 */
1166 for (start = 0; start < normlen; start = end + 1)
1168 int n = 0x80, bias = 72, delta = 0, b = 0, h, buflen = 0;
1170 out_label = out;
1171 for (i = start; i < normlen; i += len)
1173 if (!(len = get_utf16( normstr + i, normlen - i, &ch ))) break;
1174 if (!ch || ch == '.') break;
1175 if (ch < 0x80) b++;
1176 buffer[buflen++] = ch;
1178 end = i;
1180 if (b == end - start)
1182 if (end < normlen) b++;
1183 if (out + b > ARRAY_SIZE(res)) return STATUS_INVALID_IDN_NORMALIZATION;
1184 memcpy( res + out, normstr + start, b * sizeof(WCHAR) );
1185 out += b;
1186 continue;
1189 if (buflen >= 4 && buffer[2] == '-' && buffer[3] == '-') return STATUS_INVALID_IDN_NORMALIZATION;
1190 if (check_invalid_chars( info, flags, buffer, buflen )) return STATUS_INVALID_IDN_NORMALIZATION;
1192 if (out + 5 + b > ARRAY_SIZE(res)) return STATUS_INVALID_IDN_NORMALIZATION;
1193 memcpy( res + out, prefixW, sizeof(prefixW) );
1194 out += ARRAY_SIZE(prefixW);
1195 if (b)
1197 for (i = start; i < end; i++) if (normstr[i] < 0x80) res[out++] = normstr[i];
1198 res[out++] = '-';
1201 for (h = b; h < buflen; delta++, n++)
1203 int m = 0x10ffff, q, k;
1205 for (i = 0; i < buflen; i++) if (buffer[i] >= n && m > buffer[i]) m = buffer[i];
1206 delta += (m - n) * (h + 1);
1207 n = m;
1209 for (i = 0; i < buflen; i++)
1211 if (buffer[i] == n)
1213 for (q = delta, k = BASE; ; k += BASE)
1215 int t = k <= bias ? TMIN : k >= bias + TMAX ? TMAX : k - bias;
1216 int disp = q < t ? q : t + (q - t) % (BASE - t);
1217 if (out + 1 > ARRAY_SIZE(res)) return STATUS_INVALID_IDN_NORMALIZATION;
1218 res[out++] = disp <= 25 ? 'a' + disp : '0' + disp - 26;
1219 if (q < t) break;
1220 q = (q - t) / (BASE - t);
1222 delta /= (h == b ? DAMP : 2);
1223 delta += delta / (h + 1);
1224 for (k = 0; delta > ((BASE - TMIN) * TMAX) / 2; k += BASE) delta /= BASE - TMIN;
1225 bias = k + ((BASE - TMIN + 1) * delta) / (delta + SKEW);
1226 delta = 0;
1227 h++;
1229 else if (buffer[i] < n) delta++;
1233 if (out - out_label > 63) return STATUS_INVALID_IDN_NORMALIZATION;
1235 if (end < normlen)
1237 if (out + 1 > ARRAY_SIZE(res)) return STATUS_INVALID_IDN_NORMALIZATION;
1238 res[out++] = normstr[end];
1242 if (*dstlen)
1244 if (out <= *dstlen) memcpy( dst, res, out * sizeof(WCHAR) );
1245 else status = STATUS_BUFFER_TOO_SMALL;
1247 *dstlen = out;
1248 return status;
1252 /******************************************************************************
1253 * RtlIdnToNameprepUnicode (NTDLL.@)
1255 NTSTATUS WINAPI RtlIdnToNameprepUnicode( DWORD flags, const WCHAR *src, INT srclen,
1256 WCHAR *dst, INT *dstlen )
1258 const struct norm_table *info;
1259 unsigned int ch;
1260 NTSTATUS status;
1261 WCHAR buf[256];
1262 int i, start, len, buflen = ARRAY_SIZE(buf);
1264 if (flags & ~(IDN_ALLOW_UNASSIGNED | IDN_USE_STD3_ASCII_RULES)) return STATUS_INVALID_PARAMETER;
1265 if (!src || srclen < -1) return STATUS_INVALID_PARAMETER;
1267 TRACE( "%x %s %p %d\n", flags, debugstr_wn(src, srclen), dst, *dstlen );
1269 if ((status = load_norm_table( 13, &info ))) return status;
1271 if (srclen == -1) srclen = wcslen(src) + 1;
1273 for (i = 0; i < srclen; i++) if (src[i] < 0x20 || src[i] >= 0x7f) break;
1275 if (i == srclen || (i == srclen - 1 && !src[i])) /* ascii only */
1277 if (srclen > buflen) return STATUS_INVALID_IDN_NORMALIZATION;
1278 memcpy( buf, src, srclen * sizeof(WCHAR) );
1279 buflen = srclen;
1281 else if ((status = RtlNormalizeString( 13, src, srclen, buf, &buflen )))
1283 if (status == STATUS_NO_UNICODE_TRANSLATION) status = STATUS_INVALID_IDN_NORMALIZATION;
1284 return status;
1287 for (i = start = 0; i < buflen; i += len)
1289 if (!(len = get_utf16( buf + i, buflen - i, &ch ))) break;
1290 if (!ch) break;
1291 if (ch == '.')
1293 if (start == i) return STATUS_INVALID_IDN_NORMALIZATION;
1294 /* maximal label length is 63 characters */
1295 if (i - start > 63) return STATUS_INVALID_IDN_NORMALIZATION;
1296 if ((flags & IDN_USE_STD3_ASCII_RULES) && (buf[start] == '-' || buf[i-1] == '-'))
1297 return STATUS_INVALID_IDN_NORMALIZATION;
1298 start = i + 1;
1299 continue;
1301 if (flags & IDN_USE_STD3_ASCII_RULES)
1303 if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') ||
1304 (ch >= '0' && ch <= '9') || ch == '-') continue;
1305 return STATUS_INVALID_IDN_NORMALIZATION;
1307 if (!(flags & IDN_ALLOW_UNASSIGNED))
1309 if (get_char_props( info, ch ) == 0x7f) return STATUS_INVALID_IDN_NORMALIZATION;
1312 if (!i || i - start > 63) return STATUS_INVALID_IDN_NORMALIZATION;
1313 if ((flags & IDN_USE_STD3_ASCII_RULES) && (buf[start] == '-' || buf[i-1] == '-'))
1314 return STATUS_INVALID_IDN_NORMALIZATION;
1316 if (*dstlen)
1318 if (buflen <= *dstlen) memcpy( dst, buf, buflen * sizeof(WCHAR) );
1319 else status = STATUS_BUFFER_TOO_SMALL;
1321 *dstlen = buflen;
1322 return status;
1326 /******************************************************************************
1327 * RtlIdnToUnicode (NTDLL.@)
1329 NTSTATUS WINAPI RtlIdnToUnicode( DWORD flags, const WCHAR *src, INT srclen, WCHAR *dst, INT *dstlen )
1331 const struct norm_table *info;
1332 int i, buflen, start, end, out_label, out = 0;
1333 NTSTATUS status;
1334 UINT buffer[64];
1335 WCHAR ch;
1337 if (!src || srclen < -1) return STATUS_INVALID_PARAMETER;
1338 if (srclen == -1) srclen = wcslen( src ) + 1;
1340 TRACE( "%x %s %p %d\n", flags, debugstr_wn(src, srclen), dst, *dstlen );
1342 if ((status = load_norm_table( 13, &info ))) return status;
1344 for (start = 0; start < srclen; )
1346 int n = 0x80, bias = 72, pos = 0, old_pos, w, k, t, delim = 0, digit, delta;
1348 out_label = out;
1349 for (i = start; i < srclen; i++)
1351 ch = src[i];
1352 if (ch > 0x7f || (i != srclen - 1 && !ch)) return STATUS_INVALID_IDN_NORMALIZATION;
1353 if (!ch || ch == '.') break;
1354 if (ch == '-') delim = i;
1356 if (!(flags & IDN_USE_STD3_ASCII_RULES)) continue;
1357 if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') ||
1358 (ch >= '0' && ch <= '9') || ch == '-')
1359 continue;
1360 return STATUS_INVALID_IDN_NORMALIZATION;
1362 end = i;
1364 /* last label may be empty */
1365 if (start == end && ch) return STATUS_INVALID_IDN_NORMALIZATION;
1367 if (end - start < 4 ||
1368 (src[start] != 'x' && src[start] != 'X') ||
1369 (src[start + 1] != 'n' && src[start + 1] != 'N') ||
1370 src[start + 2] != '-' || src[start + 3] != '-')
1372 if (end - start > 63) return STATUS_INVALID_IDN_NORMALIZATION;
1374 if ((flags & IDN_USE_STD3_ASCII_RULES) && (src[start] == '-' || src[end - 1] == '-'))
1375 return STATUS_INVALID_IDN_NORMALIZATION;
1377 if (end < srclen) end++;
1378 if (*dstlen)
1380 if (out + end - start <= *dstlen)
1381 memcpy( dst + out, src + start, (end - start) * sizeof(WCHAR));
1382 else return STATUS_BUFFER_TOO_SMALL;
1384 out += end - start;
1385 start = end;
1386 continue;
1389 if (delim == start + 3) delim++;
1390 buflen = 0;
1391 for (i = start + 4; i < delim && buflen < ARRAY_SIZE(buffer); i++) buffer[buflen++] = src[i];
1392 if (buflen) i++;
1393 while (i < end)
1395 old_pos = pos;
1396 w = 1;
1397 for (k = BASE; ; k += BASE)
1399 if (i >= end) return STATUS_INVALID_IDN_NORMALIZATION;
1400 ch = src[i++];
1401 if (ch >= 'a' && ch <= 'z') digit = ch - 'a';
1402 else if (ch >= 'A' && ch <= 'Z') digit = ch - 'A';
1403 else if (ch >= '0' && ch <= '9') digit = ch - '0' + 26;
1404 else return STATUS_INVALID_IDN_NORMALIZATION;
1405 pos += digit * w;
1406 t = k <= bias ? TMIN : k >= bias + TMAX ? TMAX : k - bias;
1407 if (digit < t) break;
1408 w *= BASE - t;
1411 delta = (pos - old_pos) / (!old_pos ? DAMP : 2);
1412 delta += delta / (buflen + 1);
1413 for (k = 0; delta > ((BASE - TMIN) * TMAX) / 2; k += BASE) delta /= BASE - TMIN;
1414 bias = k + ((BASE - TMIN + 1) * delta) / (delta + SKEW);
1415 n += pos / (buflen + 1);
1416 pos %= buflen + 1;
1418 if (buflen >= ARRAY_SIZE(buffer) - 1) return STATUS_INVALID_IDN_NORMALIZATION;
1419 memmove( buffer + pos + 1, buffer + pos, (buflen - pos) * sizeof(*buffer) );
1420 buffer[pos++] = n;
1421 buflen++;
1424 if (check_invalid_chars( info, flags, buffer, buflen )) return STATUS_INVALID_IDN_NORMALIZATION;
1426 for (i = 0; i < buflen; i++)
1428 int len = 1 + (buffer[i] >= 0x10000);
1429 if (*dstlen)
1431 if (out + len <= *dstlen) put_utf16( dst + out, buffer[i] );
1432 else return STATUS_BUFFER_TOO_SMALL;
1434 out += len;
1437 if (out - out_label > 63) return STATUS_INVALID_IDN_NORMALIZATION;
1439 if (end < srclen)
1441 if (*dstlen)
1443 if (out + 1 <= *dstlen) dst[out] = src[end];
1444 else return STATUS_BUFFER_TOO_SMALL;
1446 out++;
1448 start = end + 1;
1450 *dstlen = out;
1451 return STATUS_SUCCESS;