ntdll: Reimplement IdnToNameprepUnicode() using the NLS normalization table.
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
35c223850e
commit
cd13557f48
|
@ -708,213 +708,11 @@ INT WINAPI IdnToAscii(DWORD dwFlags, LPCWSTR lpUnicodeCharStr, INT cchUnicodeCha
|
|||
/******************************************************************************
|
||||
* IdnToNameprepUnicode (KERNEL32.@)
|
||||
*/
|
||||
INT WINAPI IdnToNameprepUnicode(DWORD dwFlags, LPCWSTR lpUnicodeCharStr, INT cchUnicodeChar,
|
||||
LPWSTR lpNameprepCharStr, INT cchNameprepChar)
|
||||
INT WINAPI IdnToNameprepUnicode( DWORD flags, const WCHAR *src, INT srclen, WCHAR *dst, INT dstlen )
|
||||
{
|
||||
enum {
|
||||
UNASSIGNED = 0x1,
|
||||
PROHIBITED = 0x2,
|
||||
BIDI_RAL = 0x4,
|
||||
BIDI_L = 0x8
|
||||
};
|
||||
|
||||
const WCHAR *ptr;
|
||||
WORD flags;
|
||||
WCHAR buf[64], *map_str, norm_str[64], ch;
|
||||
DWORD i, map_len, norm_len, mask, label_start, label_end, out = 0;
|
||||
BOOL have_bidi_ral, prohibit_bidi_ral, ascii_only;
|
||||
|
||||
TRACE("%x %p %d %p %d\n", dwFlags, lpUnicodeCharStr, cchUnicodeChar,
|
||||
lpNameprepCharStr, cchNameprepChar);
|
||||
|
||||
if(dwFlags & ~(IDN_ALLOW_UNASSIGNED|IDN_USE_STD3_ASCII_RULES)) {
|
||||
SetLastError(ERROR_INVALID_FLAGS);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(!lpUnicodeCharStr || cchUnicodeChar<-1) {
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(cchUnicodeChar == -1)
|
||||
cchUnicodeChar = strlenW(lpUnicodeCharStr)+1;
|
||||
if(!cchUnicodeChar || (cchUnicodeChar==1 && lpUnicodeCharStr[0]==0)) {
|
||||
SetLastError(ERROR_INVALID_NAME);
|
||||
return 0;
|
||||
}
|
||||
|
||||
for(label_start=0; label_start<cchUnicodeChar;) {
|
||||
ascii_only = TRUE;
|
||||
for(i=label_start; i<cchUnicodeChar; i++) {
|
||||
ch = lpUnicodeCharStr[i];
|
||||
|
||||
if(i!=cchUnicodeChar-1 && !ch) {
|
||||
SetLastError(ERROR_INVALID_NAME);
|
||||
return 0;
|
||||
}
|
||||
/* check if ch is one of label separators defined in RFC3490 */
|
||||
if(!ch || ch=='.' || ch==0x3002 || ch==0xff0e || ch==0xff61)
|
||||
break;
|
||||
|
||||
if(ch > 0x7f) {
|
||||
ascii_only = FALSE;
|
||||
continue;
|
||||
}
|
||||
|
||||
if((dwFlags&IDN_USE_STD3_ASCII_RULES) == 0)
|
||||
continue;
|
||||
if((ch>='a' && ch<='z') || (ch>='A' && ch<='Z')
|
||||
|| (ch>='0' && ch<='9') || ch=='-')
|
||||
continue;
|
||||
|
||||
SetLastError(ERROR_INVALID_NAME);
|
||||
return 0;
|
||||
}
|
||||
label_end = i;
|
||||
/* last label may be empty */
|
||||
if(label_start==label_end && ch) {
|
||||
SetLastError(ERROR_INVALID_NAME);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if((dwFlags&IDN_USE_STD3_ASCII_RULES) && (lpUnicodeCharStr[label_start]=='-' ||
|
||||
lpUnicodeCharStr[label_end-1]=='-')) {
|
||||
SetLastError(ERROR_INVALID_NAME);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(ascii_only) {
|
||||
/* maximal label length is 63 characters */
|
||||
if(label_end-label_start > 63) {
|
||||
SetLastError(ERROR_INVALID_NAME);
|
||||
return 0;
|
||||
}
|
||||
if(label_end < cchUnicodeChar)
|
||||
label_end++;
|
||||
|
||||
if(!lpNameprepCharStr) {
|
||||
out += label_end-label_start;
|
||||
}else if(out+label_end-label_start <= cchNameprepChar) {
|
||||
memcpy(lpNameprepCharStr+out, lpUnicodeCharStr+label_start,
|
||||
(label_end-label_start)*sizeof(WCHAR));
|
||||
if(lpUnicodeCharStr[label_end-1] > 0x7f)
|
||||
lpNameprepCharStr[out+label_end-label_start-1] = '.';
|
||||
out += label_end-label_start;
|
||||
}else {
|
||||
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
||||
return 0;
|
||||
}
|
||||
|
||||
label_start = label_end;
|
||||
continue;
|
||||
}
|
||||
|
||||
map_len = 0;
|
||||
for(i=label_start; i<label_end; i++) {
|
||||
ch = lpUnicodeCharStr[i];
|
||||
ptr = nameprep_mapping + nameprep_mapping[ch>>8];
|
||||
ptr = nameprep_mapping + ptr[(ch>>4)&0x0f] + 3*(ch&0x0f);
|
||||
|
||||
if(!ptr[0]) map_len++;
|
||||
else if(!ptr[1]) map_len++;
|
||||
else if(!ptr[2]) map_len += 2;
|
||||
else if(ptr[0]!=0xffff || ptr[1]!=0xffff || ptr[2]!=0xffff) map_len += 3;
|
||||
}
|
||||
if(map_len*sizeof(WCHAR) > sizeof(buf)) {
|
||||
map_str = HeapAlloc(GetProcessHeap(), 0, map_len*sizeof(WCHAR));
|
||||
if(!map_str) {
|
||||
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
||||
return 0;
|
||||
}
|
||||
}else {
|
||||
map_str = buf;
|
||||
}
|
||||
map_len = 0;
|
||||
for(i=label_start; i<label_end; i++) {
|
||||
ch = lpUnicodeCharStr[i];
|
||||
ptr = nameprep_mapping + nameprep_mapping[ch>>8];
|
||||
ptr = nameprep_mapping + ptr[(ch>>4)&0x0f] + 3*(ch&0x0f);
|
||||
|
||||
if(!ptr[0]) {
|
||||
map_str[map_len++] = ch;
|
||||
}else if(!ptr[1]) {
|
||||
map_str[map_len++] = ptr[0];
|
||||
}else if(!ptr[2]) {
|
||||
map_str[map_len++] = ptr[0];
|
||||
map_str[map_len++] = ptr[1];
|
||||
}else if(ptr[0]!=0xffff || ptr[1]!=0xffff || ptr[2]!=0xffff) {
|
||||
map_str[map_len++] = ptr[0];
|
||||
map_str[map_len++] = ptr[1];
|
||||
map_str[map_len++] = ptr[2];
|
||||
}
|
||||
}
|
||||
|
||||
norm_len = FoldStringW(MAP_FOLDCZONE, map_str, map_len, norm_str, ARRAY_SIZE(norm_str)-1);
|
||||
if(map_str != buf)
|
||||
HeapFree(GetProcessHeap(), 0, map_str);
|
||||
if(!norm_len) {
|
||||
if(GetLastError() == ERROR_INSUFFICIENT_BUFFER)
|
||||
SetLastError(ERROR_INVALID_NAME);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(label_end < cchUnicodeChar) {
|
||||
norm_str[norm_len++] = lpUnicodeCharStr[label_end] ? '.' : 0;
|
||||
label_end++;
|
||||
}
|
||||
|
||||
if(!lpNameprepCharStr) {
|
||||
out += norm_len;
|
||||
}else if(out+norm_len <= cchNameprepChar) {
|
||||
memcpy(lpNameprepCharStr+out, norm_str, norm_len*sizeof(WCHAR));
|
||||
out += norm_len;
|
||||
}else {
|
||||
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
||||
return 0;
|
||||
}
|
||||
|
||||
have_bidi_ral = prohibit_bidi_ral = FALSE;
|
||||
mask = PROHIBITED;
|
||||
if((dwFlags&IDN_ALLOW_UNASSIGNED) == 0)
|
||||
mask |= UNASSIGNED;
|
||||
for(i=0; i<norm_len; i++) {
|
||||
ch = norm_str[i];
|
||||
flags = get_table_entry( nameprep_char_type, ch );
|
||||
|
||||
if(flags & mask) {
|
||||
SetLastError((flags & PROHIBITED) ? ERROR_INVALID_NAME
|
||||
: ERROR_NO_UNICODE_TRANSLATION);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(flags & BIDI_RAL)
|
||||
have_bidi_ral = TRUE;
|
||||
if(flags & BIDI_L)
|
||||
prohibit_bidi_ral = TRUE;
|
||||
}
|
||||
|
||||
if(have_bidi_ral) {
|
||||
ch = norm_str[0];
|
||||
flags = get_table_entry( nameprep_char_type, ch );
|
||||
if((flags & BIDI_RAL) == 0)
|
||||
prohibit_bidi_ral = TRUE;
|
||||
|
||||
ch = norm_str[norm_len-1];
|
||||
flags = get_table_entry( nameprep_char_type, ch );
|
||||
if((flags & BIDI_RAL) == 0)
|
||||
prohibit_bidi_ral = TRUE;
|
||||
}
|
||||
|
||||
if(have_bidi_ral && prohibit_bidi_ral) {
|
||||
SetLastError(ERROR_INVALID_NAME);
|
||||
return 0;
|
||||
}
|
||||
|
||||
label_start = label_end;
|
||||
}
|
||||
|
||||
return out;
|
||||
NTSTATUS status = RtlIdnToNameprepUnicode( flags, src, srclen, dst, &dstlen );
|
||||
if (!set_ntstatus( status )) return 0;
|
||||
return dstlen;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
|
|
|
@ -4431,14 +4431,14 @@ static void test_IdnToNameprepUnicode(void)
|
|||
{ 5, L"test", 0, 5, 5, L"test" },
|
||||
{ 3, L"a\xe111z", 0, 0, 0, L"a\xe111z", 0, STATUS_NO_UNICODE_TRANSLATION },
|
||||
{ 4, L"t\0e", 0, 0, 0, {0}, STATUS_NO_UNICODE_TRANSLATION, STATUS_NO_UNICODE_TRANSLATION },
|
||||
{ 1, L"T", 0, 1, 1, L"t" },
|
||||
{ 1, L"T", 0, 1, 1, L"T" },
|
||||
{ 1, {0}, 0, 0 },
|
||||
/* 5 */
|
||||
{ 6, L" -/[]", 0, 6, 6, L" -/[]" },
|
||||
{ 3, L"a-a", IDN_USE_STD3_ASCII_RULES, 3, 3, L"a-a" },
|
||||
{ 3, L"aa-", IDN_USE_STD3_ASCII_RULES, 0, 0, L"aa-" },
|
||||
{ -1, L"T\xdf\x130\x143\x37a\x6a\x30c \xaa", 0, 12, 12, L"tssi\x307\x144 \x3b9\x1f0 a" },
|
||||
{ 11, L"t\xad\x34f\x1806\x180b\x180c\x180d\x200b\x200c\x200d", 0, 2, 0, L"t",
|
||||
{ 11, L"t\xad\x34f\x1806\x180b\x180c\x180d\x200b\x200c\x200d", 0, 0, 2, L"t",
|
||||
STATUS_NO_UNICODE_TRANSLATION },
|
||||
/* 10 */
|
||||
{ 2, {0x3b0}, 0, 2, 2, {0x3b0} },
|
||||
|
@ -4447,6 +4447,9 @@ static void test_IdnToNameprepUnicode(void)
|
|||
{ 5, L"a..a", 0, 0, 0, L"a..a" },
|
||||
{ 3, L"a.", 0, 3, 3, L"a." },
|
||||
/* 15 */
|
||||
{ 5, L"T.\x105.A", 0, 5, 5, L"t.\x105.a" },
|
||||
{ 5, L"T.*.A", 0, 5, 5, L"T.*.A" },
|
||||
{ 5, L"X\xff0e.Z", 0, 0, 0, L"x..z" },
|
||||
{ 63, L"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", 0,
|
||||
63, 63, L"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" },
|
||||
{ 64, L"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", 0,
|
||||
|
@ -4515,7 +4518,7 @@ static void test_IdnToNameprepUnicode(void)
|
|||
if (ret == test_data[i].ret)
|
||||
{
|
||||
ok(err == ret ? 0xdeadbeef : ERROR_INVALID_NAME, "%d: err = %d\n", i, err);
|
||||
ok(!wcsnicmp(test_data[i].out, buf, ret), "%d: buf = %s\n", i, wine_dbgstr_wn(buf, ret));
|
||||
ok(!wcsncmp(test_data[i].out, buf, ret), "%d: buf = %s\n", i, wine_dbgstr_wn(buf, ret));
|
||||
}
|
||||
if (pRtlNormalizeString)
|
||||
{
|
||||
|
@ -4525,7 +4528,7 @@ static void test_IdnToNameprepUnicode(void)
|
|||
status = pRtlNormalizeString( 13, test_data[i].in, test_data[i].in_len, buf, &len );
|
||||
ok( status == test_data[i].status || broken(status == test_data[i].broken_status),
|
||||
"%d: failed %x\n", i, status );
|
||||
if (!status) ok( !wcsncmp(test_data[i].out, buf, len), "%d: buf = %s\n", i, wine_dbgstr_wn(buf, len));
|
||||
if (!status) ok( !wcsnicmp(test_data[i].out, buf, len), "%d: buf = %s\n", i, wine_dbgstr_wn(buf, len));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4569,10 +4572,11 @@ static void test_IdnToAscii(void)
|
|||
SetLastError(0xdeadbeef);
|
||||
ret = pIdnToAscii(test_data[i].flags, test_data[i].in, test_data[i].in_len, buf, ARRAY_SIZE(buf));
|
||||
err = GetLastError();
|
||||
todo_wine_if (i > 9)
|
||||
todo_wine_if (i == 10)
|
||||
ok(ret == test_data[i].ret || broken(ret == test_data[i].broken_ret), "%d: ret = %d\n", i, ret);
|
||||
ok(err == ret ? 0xdeadbeef : ERROR_INVALID_NAME, "%d: err = %d\n", i, err);
|
||||
ok(!wcsncmp(test_data[i].out, buf, ret), "%d: buf = %s\n", i, wine_dbgstr_wn(buf, ret));
|
||||
todo_wine_if (i == 10)
|
||||
ok(!wcsnicmp(test_data[i].out, buf, ret), "%d: buf = %s\n", i, wine_dbgstr_wn(buf, ret));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2016,3 +2016,77 @@ NTSTATUS WINAPI RtlNormalizeString( ULONG form, const WCHAR *src, INT src_len, W
|
|||
*dst_len = buf_len;
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* RtlIdnToNameprepUnicode (NTDLL.@)
|
||||
*/
|
||||
NTSTATUS WINAPI RtlIdnToNameprepUnicode( DWORD flags, const WCHAR *src, INT srclen,
|
||||
WCHAR *dst, INT *dstlen )
|
||||
{
|
||||
const struct norm_table *info;
|
||||
unsigned int ch;
|
||||
NTSTATUS status;
|
||||
WCHAR buf[256];
|
||||
int i, start, len, buflen = ARRAY_SIZE(buf);
|
||||
|
||||
if (flags & ~(IDN_ALLOW_UNASSIGNED | IDN_USE_STD3_ASCII_RULES)) return STATUS_INVALID_PARAMETER;
|
||||
if (!src || srclen < -1) return STATUS_INVALID_PARAMETER;
|
||||
|
||||
TRACE( "%x %s %p %d\n", flags, debugstr_wn(src, srclen), dst, *dstlen );
|
||||
|
||||
if ((status = load_norm_table( 13, &info ))) return status;
|
||||
|
||||
if (srclen == -1) srclen = strlenW(src) + 1;
|
||||
|
||||
for (i = 0; i < srclen; i++) if (src[i] < 0x20 || src[i] >= 0x7f) break;
|
||||
|
||||
if (i == srclen || (i == srclen - 1 && !src[i])) /* ascii only */
|
||||
{
|
||||
if (srclen > buflen) return STATUS_INVALID_IDN_NORMALIZATION;
|
||||
memcpy( buf, src, srclen * sizeof(WCHAR) );
|
||||
buflen = srclen;
|
||||
}
|
||||
else if ((status = RtlNormalizeString( 13, src, srclen, buf, &buflen )))
|
||||
{
|
||||
if (status == STATUS_NO_UNICODE_TRANSLATION) status = STATUS_INVALID_IDN_NORMALIZATION;
|
||||
return status;
|
||||
}
|
||||
|
||||
for (i = start = 0; i < buflen; i += len)
|
||||
{
|
||||
if (!(len = get_utf16( buf + i, buflen - i, &ch ))) break;
|
||||
if (!ch) break;
|
||||
if (ch == '.')
|
||||
{
|
||||
if (start == i) return STATUS_INVALID_IDN_NORMALIZATION;
|
||||
/* maximal label length is 63 characters */
|
||||
if (i - start > 63) return STATUS_INVALID_IDN_NORMALIZATION;
|
||||
if ((flags & IDN_USE_STD3_ASCII_RULES) && (buf[start] == '-' || buf[i-1] == '-'))
|
||||
return STATUS_INVALID_IDN_NORMALIZATION;
|
||||
start = i + 1;
|
||||
continue;
|
||||
}
|
||||
if (flags & IDN_USE_STD3_ASCII_RULES)
|
||||
{
|
||||
if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') ||
|
||||
(ch >= '0' && ch <= '9') || ch == '-') continue;
|
||||
return STATUS_INVALID_IDN_NORMALIZATION;
|
||||
}
|
||||
if (!(flags & IDN_ALLOW_UNASSIGNED))
|
||||
{
|
||||
if (get_char_props( info, ch ) == 0x7f) return STATUS_INVALID_IDN_NORMALIZATION;
|
||||
}
|
||||
}
|
||||
if (!i || i - start > 63) return STATUS_INVALID_IDN_NORMALIZATION;
|
||||
if ((flags & IDN_USE_STD3_ASCII_RULES) && (buf[start] == '-' || buf[i-1] == '-'))
|
||||
return STATUS_INVALID_IDN_NORMALIZATION;
|
||||
|
||||
if (*dstlen)
|
||||
{
|
||||
if (buflen <= *dstlen) memcpy( dst, buf, buflen * sizeof(WCHAR) );
|
||||
else status = STATUS_BUFFER_TOO_SMALL;
|
||||
}
|
||||
*dstlen = buflen;
|
||||
return status;
|
||||
}
|
||||
|
|
|
@ -722,6 +722,7 @@
|
|||
@ stub RtlGuidToPropertySetName
|
||||
@ stdcall RtlHashUnicodeString(ptr long long ptr)
|
||||
@ stdcall RtlIdentifierAuthoritySid(ptr)
|
||||
@ stdcall RtlIdnToNameprepUnicode(long wstr long ptr ptr)
|
||||
@ stdcall RtlImageDirectoryEntryToData(long long long ptr)
|
||||
@ stdcall RtlImageNtHeader(long)
|
||||
@ stdcall RtlImageRvaToSection(ptr long long)
|
||||
|
|
|
@ -2797,6 +2797,7 @@ NTSYSAPI DWORD WINAPI RtlGetThreadErrorMode(void);
|
|||
NTSYSAPI NTSTATUS WINAPI RtlGetVersion(RTL_OSVERSIONINFOEXW*);
|
||||
NTSYSAPI NTSTATUS WINAPI RtlGUIDFromString(PUNICODE_STRING,GUID*);
|
||||
NTSYSAPI PSID_IDENTIFIER_AUTHORITY WINAPI RtlIdentifierAuthoritySid(PSID);
|
||||
NTSYSAPI NTSTATUS WINAPI RtlIdnToNameprepUnicode(DWORD,const WCHAR*,INT,WCHAR*,INT*);
|
||||
NTSYSAPI PVOID WINAPI RtlImageDirectoryEntryToData(HMODULE,BOOL,WORD,ULONG *);
|
||||
NTSYSAPI PIMAGE_NT_HEADERS WINAPI RtlImageNtHeader(HMODULE);
|
||||
NTSYSAPI PIMAGE_SECTION_HEADER WINAPI RtlImageRvaToSection(const IMAGE_NT_HEADERS *,HMODULE,DWORD);
|
||||
|
|
Loading…
Reference in New Issue