ntdll: Reimplement IdnToAscii() using the normalization table and the ntdll helpers.
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
cd13557f48
commit
01237d0896
|
@ -568,141 +568,12 @@ static inline INT adapt(INT delta, INT numpoints, BOOL firsttime)
|
|||
|
||||
/******************************************************************************
|
||||
* IdnToAscii (KERNEL32.@)
|
||||
* Implementation of Punycode based on RFC 3492.
|
||||
*/
|
||||
INT WINAPI IdnToAscii(DWORD dwFlags, LPCWSTR lpUnicodeCharStr, INT cchUnicodeChar,
|
||||
LPWSTR lpASCIICharStr, INT cchASCIIChar)
|
||||
INT WINAPI IdnToAscii( DWORD flags, const WCHAR *src, INT srclen, WCHAR *dst, INT dstlen )
|
||||
{
|
||||
static const WCHAR prefixW[] = {'x','n','-','-'};
|
||||
|
||||
WCHAR *norm_str;
|
||||
INT i, label_start, label_end, norm_len, out_label, out = 0;
|
||||
|
||||
TRACE("%x %p %d %p %d\n", dwFlags, lpUnicodeCharStr, cchUnicodeChar,
|
||||
lpASCIICharStr, cchASCIIChar);
|
||||
|
||||
norm_len = IdnToNameprepUnicode(dwFlags, lpUnicodeCharStr, cchUnicodeChar, NULL, 0);
|
||||
if(!norm_len)
|
||||
return 0;
|
||||
norm_str = HeapAlloc(GetProcessHeap(), 0, norm_len*sizeof(WCHAR));
|
||||
if(!norm_str) {
|
||||
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
||||
return 0;
|
||||
}
|
||||
norm_len = IdnToNameprepUnicode(dwFlags, lpUnicodeCharStr,
|
||||
cchUnicodeChar, norm_str, norm_len);
|
||||
if(!norm_len) {
|
||||
HeapFree(GetProcessHeap(), 0, norm_str);
|
||||
return 0;
|
||||
}
|
||||
|
||||
for(label_start=0; label_start<norm_len;) {
|
||||
INT n = INIT_N, bias = INIT_BIAS;
|
||||
INT delta = 0, b = 0, h;
|
||||
|
||||
out_label = out;
|
||||
for(i=label_start; i<norm_len && norm_str[i]!='.' &&
|
||||
norm_str[i]!=0x3002 && norm_str[i]!='\0'; i++)
|
||||
if(norm_str[i] < 0x80)
|
||||
b++;
|
||||
label_end = i;
|
||||
|
||||
if(b == label_end-label_start) {
|
||||
if(label_end < norm_len)
|
||||
b++;
|
||||
if(!lpASCIICharStr) {
|
||||
out += b;
|
||||
}else if(out+b <= cchASCIIChar) {
|
||||
memcpy(lpASCIICharStr+out, norm_str+label_start, b*sizeof(WCHAR));
|
||||
out += b;
|
||||
}else {
|
||||
HeapFree(GetProcessHeap(), 0, norm_str);
|
||||
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
||||
return 0;
|
||||
}
|
||||
label_start = label_end+1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(!lpASCIICharStr) {
|
||||
out += 5+b; /* strlen(xn--...-) */
|
||||
}else if(out+5+b <= cchASCIIChar) {
|
||||
memcpy(lpASCIICharStr+out, prefixW, sizeof(prefixW));
|
||||
out += 4;
|
||||
for(i=label_start; i<label_end; i++)
|
||||
if(norm_str[i] < 0x80)
|
||||
lpASCIICharStr[out++] = norm_str[i];
|
||||
lpASCIICharStr[out++] = '-';
|
||||
}else {
|
||||
HeapFree(GetProcessHeap(), 0, norm_str);
|
||||
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
||||
return 0;
|
||||
}
|
||||
if(!b)
|
||||
out--;
|
||||
|
||||
for(h=b; h<label_end-label_start;) {
|
||||
INT m = 0xffff, q, k;
|
||||
|
||||
for(i=label_start; i<label_end; i++) {
|
||||
if(norm_str[i]>=n && m>norm_str[i])
|
||||
m = norm_str[i];
|
||||
}
|
||||
delta += (m-n)*(h+1);
|
||||
n = m;
|
||||
|
||||
for(i=label_start; i<label_end; i++) {
|
||||
if(norm_str[i] < n) {
|
||||
delta++;
|
||||
}else if(norm_str[i] == n) {
|
||||
for(q=delta, k=BASE; ; k+=BASE) {
|
||||
INT t = k<=bias ? TMIN : k>=bias+TMAX ? TMAX : k-bias;
|
||||
INT disp = q<t ? q : t+(q-t)%(BASE-t);
|
||||
if(!lpASCIICharStr) {
|
||||
out++;
|
||||
}else if(out+1 <= cchASCIIChar) {
|
||||
lpASCIICharStr[out++] = disp<='z'-'a' ?
|
||||
'a'+disp : '0'+disp-'z'+'a'-1;
|
||||
}else {
|
||||
HeapFree(GetProcessHeap(), 0, norm_str);
|
||||
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
||||
return 0;
|
||||
}
|
||||
if(q < t)
|
||||
break;
|
||||
q = (q-t)/(BASE-t);
|
||||
}
|
||||
bias = adapt(delta, h+1, h==b);
|
||||
delta = 0;
|
||||
h++;
|
||||
}
|
||||
}
|
||||
delta++;
|
||||
n++;
|
||||
}
|
||||
|
||||
if(out-out_label > 63) {
|
||||
HeapFree(GetProcessHeap(), 0, norm_str);
|
||||
SetLastError(ERROR_INVALID_NAME);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(label_end < norm_len) {
|
||||
if(!lpASCIICharStr) {
|
||||
out++;
|
||||
}else if(out+1 <= cchASCIIChar) {
|
||||
lpASCIICharStr[out++] = norm_str[label_end] ? '.' : 0;
|
||||
}else {
|
||||
HeapFree(GetProcessHeap(), 0, norm_str);
|
||||
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
label_start = label_end+1;
|
||||
}
|
||||
|
||||
HeapFree(GetProcessHeap(), 0, norm_str);
|
||||
return out;
|
||||
NTSTATUS status = RtlIdnToAscii( flags, src, srclen, dst, &dstlen );
|
||||
if (!set_ntstatus( status )) return 0;
|
||||
return dstlen;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
|
|
|
@ -4572,10 +4572,8 @@ 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 == 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);
|
||||
todo_wine_if (i == 10)
|
||||
ok(!wcsnicmp(test_data[i].out, buf, ret), "%d: buf = %s\n", i, wine_dbgstr_wn(buf, ret));
|
||||
}
|
||||
}
|
||||
|
@ -4691,10 +4689,16 @@ static void test_Idn(void)
|
|||
ret = pIdnToAscii( 0, columns[0], -1, dst, ARRAY_SIZE(dst) );
|
||||
if (!is_idn_error( error ))
|
||||
{
|
||||
ok( ret, "line %u: toAscii failed for %s\n", line, debugstr_w(columns[0]) );
|
||||
ok( ret, "line %u: toAscii failed for %s expected %s\n", line,
|
||||
debugstr_w(columns[0]), debugstr_w(expect) );
|
||||
if (ret) ok( !wcscmp( dst, expect ), "line %u: got %s expected %s\n",
|
||||
line, debugstr_w(dst), debugstr_w(expect) );
|
||||
}
|
||||
else
|
||||
{
|
||||
ok( !ret, "line %u: toAscii didn't fail for %s got %s expected error %s\n",
|
||||
line, debugstr_w(columns[0]), debugstr_w(dst), debugstr_w(error) );
|
||||
}
|
||||
|
||||
expect = columns[1];
|
||||
if (!*expect) expect = columns[0];
|
||||
|
|
|
@ -2018,6 +2018,154 @@ NTSTATUS WINAPI RtlNormalizeString( ULONG form, const WCHAR *src, INT src_len, W
|
|||
}
|
||||
|
||||
|
||||
/* Punycode parameters */
|
||||
enum { BASE = 36, TMIN = 1, TMAX = 26, SKEW = 38, DAMP = 700 };
|
||||
|
||||
static BOOL check_invalid_chars( const struct norm_table *info, DWORD flags,
|
||||
const unsigned int *buffer, int len )
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
switch (buffer[i])
|
||||
{
|
||||
case 0x200c: /* zero-width non-joiner */
|
||||
case 0x200d: /* zero-width joiner */
|
||||
if (!i || get_combining_class( info, buffer[i - 1] ) != 9) return TRUE;
|
||||
break;
|
||||
case 0x2260: /* not equal to */
|
||||
case 0x226e: /* not less than */
|
||||
case 0x226f: /* not greater than */
|
||||
if (flags & IDN_USE_STD3_ASCII_RULES) return TRUE;
|
||||
break;
|
||||
}
|
||||
switch (get_char_props( info, buffer[i] ))
|
||||
{
|
||||
case 0xbf:
|
||||
return TRUE;
|
||||
case 0xff:
|
||||
if (buffer[i] >= HANGUL_SBASE && buffer[i] < HANGUL_SBASE + 0x2c00) break;
|
||||
return TRUE;
|
||||
case 0x7f:
|
||||
if (!(flags & IDN_ALLOW_UNASSIGNED)) return TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ((flags & IDN_USE_STD3_ASCII_RULES) && len && (buffer[0] == '-' || buffer[len - 1] == '-'))
|
||||
return TRUE;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* RtlIdnToAscii (NTDLL.@)
|
||||
*/
|
||||
NTSTATUS WINAPI RtlIdnToAscii( DWORD flags, const WCHAR *src, INT srclen, WCHAR *dst, INT *dstlen )
|
||||
{
|
||||
static const WCHAR prefixW[] = {'x','n','-','-'};
|
||||
const struct norm_table *info;
|
||||
NTSTATUS status;
|
||||
WCHAR normstr[256], res[256];
|
||||
unsigned int ch, buffer[64];
|
||||
int i, len, start, end, out_label, out = 0, normlen = ARRAY_SIZE(normstr);
|
||||
|
||||
TRACE( "%x %s %p %d\n", flags, debugstr_wn(src, srclen), dst, *dstlen );
|
||||
|
||||
if ((status = load_norm_table( 13, &info ))) return status;
|
||||
|
||||
if ((status = RtlIdnToNameprepUnicode( flags, src, srclen, normstr, &normlen ))) return status;
|
||||
|
||||
/* implementation of Punycode based on RFC 3492 */
|
||||
|
||||
for (start = 0; start < normlen; start = end + 1)
|
||||
{
|
||||
int n = 0x80, bias = 72, delta = 0, b = 0, h, buflen = 0;
|
||||
|
||||
out_label = out;
|
||||
for (i = start; i < normlen; i += len)
|
||||
{
|
||||
if (!(len = get_utf16( normstr + i, normlen - i, &ch ))) break;
|
||||
if (!ch || ch == '.') break;
|
||||
if (ch < 0x80) b++;
|
||||
buffer[buflen++] = ch;
|
||||
}
|
||||
end = i;
|
||||
|
||||
if (b == end - start)
|
||||
{
|
||||
if (end < normlen) b++;
|
||||
if (out + b > ARRAY_SIZE(res)) return STATUS_INVALID_IDN_NORMALIZATION;
|
||||
memcpy( res + out, normstr + start, b * sizeof(WCHAR) );
|
||||
out += b;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (buflen >= 4 && buffer[2] == '-' && buffer[3] == '-') return STATUS_INVALID_IDN_NORMALIZATION;
|
||||
if (check_invalid_chars( info, flags, buffer, buflen )) return STATUS_INVALID_IDN_NORMALIZATION;
|
||||
|
||||
if (out + 5 + b > ARRAY_SIZE(res)) return STATUS_INVALID_IDN_NORMALIZATION;
|
||||
memcpy( res + out, prefixW, sizeof(prefixW) );
|
||||
out += ARRAY_SIZE(prefixW);
|
||||
if (b)
|
||||
{
|
||||
for (i = start; i < end; i++) if (normstr[i] < 0x80) res[out++] = normstr[i];
|
||||
res[out++] = '-';
|
||||
}
|
||||
|
||||
for (h = b; h < buflen; delta++, n++)
|
||||
{
|
||||
int m = 0x10ffff, q, k;
|
||||
|
||||
for (i = 0; i < buflen; i++) if (buffer[i] >= n && m > buffer[i]) m = buffer[i];
|
||||
delta += (m - n) * (h + 1);
|
||||
n = m;
|
||||
|
||||
for (i = 0; i < buflen; i++)
|
||||
{
|
||||
if (buffer[i] == n)
|
||||
{
|
||||
for (q = delta, k = BASE; ; k += BASE)
|
||||
{
|
||||
int t = k <= bias ? TMIN : k >= bias + TMAX ? TMAX : k - bias;
|
||||
int disp = q < t ? q : t + (q - t) % (BASE - t);
|
||||
if (out + 1 > ARRAY_SIZE(res)) return STATUS_INVALID_IDN_NORMALIZATION;
|
||||
res[out++] = disp <= 25 ? 'a' + disp : '0' + disp - 26;
|
||||
if (q < t) break;
|
||||
q = (q - t) / (BASE - t);
|
||||
}
|
||||
delta /= (h == b ? DAMP : 2);
|
||||
delta += delta / (h + 1);
|
||||
for (k = 0; delta > ((BASE - TMIN) * TMAX) / 2; k += BASE) delta /= BASE - TMIN;
|
||||
bias = k + ((BASE - TMIN + 1) * delta) / (delta + SKEW);
|
||||
delta = 0;
|
||||
h++;
|
||||
}
|
||||
else if (buffer[i] < n) delta++;
|
||||
}
|
||||
}
|
||||
|
||||
if (out - out_label > 63) return STATUS_INVALID_IDN_NORMALIZATION;
|
||||
|
||||
if (end < normlen)
|
||||
{
|
||||
if (out + 1 > ARRAY_SIZE(res)) return STATUS_INVALID_IDN_NORMALIZATION;
|
||||
res[out++] = normstr[end];
|
||||
}
|
||||
}
|
||||
|
||||
if (*dstlen)
|
||||
{
|
||||
if (out <= *dstlen) memcpy( dst, res, out * sizeof(WCHAR) );
|
||||
else status = STATUS_BUFFER_TOO_SMALL;
|
||||
}
|
||||
*dstlen = out;
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* RtlIdnToNameprepUnicode (NTDLL.@)
|
||||
*/
|
||||
|
|
|
@ -722,6 +722,7 @@
|
|||
@ stub RtlGuidToPropertySetName
|
||||
@ stdcall RtlHashUnicodeString(ptr long long ptr)
|
||||
@ stdcall RtlIdentifierAuthoritySid(ptr)
|
||||
@ stdcall RtlIdnToAscii(long wstr long ptr ptr)
|
||||
@ stdcall RtlIdnToNameprepUnicode(long wstr long ptr ptr)
|
||||
@ stdcall RtlImageDirectoryEntryToData(long long long ptr)
|
||||
@ stdcall RtlImageNtHeader(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 RtlIdnToAscii(DWORD,const WCHAR*,INT,WCHAR*,INT*);
|
||||
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);
|
||||
|
|
Loading…
Reference in New Issue