2015-04-09 16:02:48 +00:00
|
|
|
|
|
|
|
#define WIN32_NO_STATUS
|
|
|
|
#include <wine/unicode.h>
|
2015-04-26 06:10:03 +00:00
|
|
|
|
|
|
|
#define NDEBUG
|
2015-04-09 16:02:48 +00:00
|
|
|
#include <debug.h>
|
|
|
|
|
|
|
|
/* Taken from Wine kernel32/locale.c */
|
|
|
|
|
|
|
|
enum {
|
|
|
|
BASE = 36,
|
|
|
|
TMIN = 1,
|
|
|
|
TMAX = 26,
|
|
|
|
SKEW = 38,
|
|
|
|
DAMP = 700,
|
|
|
|
INIT_BIAS = 72,
|
|
|
|
INIT_N = 128
|
|
|
|
};
|
|
|
|
|
|
|
|
static inline INT adapt(INT delta, INT numpoints, BOOL firsttime)
|
|
|
|
{
|
|
|
|
INT k;
|
|
|
|
|
|
|
|
delta /= (firsttime ? DAMP : 2);
|
|
|
|
delta += delta/numpoints;
|
|
|
|
|
|
|
|
for(k=0; delta>((BASE-TMIN)*TMAX)/2; k+=BASE)
|
|
|
|
delta /= BASE-TMIN;
|
|
|
|
return k+((BASE-TMIN+1)*delta)/(delta+SKEW);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline unsigned short get_table_entry( const unsigned short *table, WCHAR ch )
|
|
|
|
{
|
|
|
|
return table[table[table[ch >> 8] + ((ch >> 4) & 0x0f)] + (ch & 0xf)];
|
|
|
|
}
|
|
|
|
|
|
|
|
INT WINAPI IdnToUnicode(DWORD dwFlags, LPCWSTR lpASCIICharStr, INT cchASCIIChar,
|
|
|
|
LPWSTR lpUnicodeCharStr, INT cchUnicodeChar)
|
|
|
|
{
|
|
|
|
extern const unsigned short nameprep_char_type[];
|
|
|
|
|
|
|
|
INT i, label_start, label_end, out_label, out = 0;
|
|
|
|
WCHAR ch;
|
|
|
|
|
|
|
|
DPRINT("%x %p %d %p %d\n", dwFlags, lpASCIICharStr, cchASCIIChar,
|
|
|
|
lpUnicodeCharStr, cchUnicodeChar);
|
|
|
|
|
|
|
|
for(label_start=0; label_start<cchASCIIChar;) {
|
|
|
|
INT n = INIT_N, pos = 0, old_pos, w, k, bias = INIT_BIAS, delim=0, digit, t;
|
|
|
|
|
|
|
|
out_label = out;
|
|
|
|
for(i=label_start; i<cchASCIIChar; i++) {
|
|
|
|
ch = lpASCIICharStr[i];
|
|
|
|
|
|
|
|
if(ch>0x7f || (i!=cchASCIIChar-1 && !ch)) {
|
|
|
|
SetLastError(ERROR_INVALID_NAME);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!ch || ch=='.')
|
|
|
|
break;
|
|
|
|
if(ch == '-')
|
|
|
|
delim = i;
|
|
|
|
|
|
|
|
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) && (lpASCIICharStr[label_start]=='-' ||
|
|
|
|
lpASCIICharStr[label_end-1]=='-')) {
|
|
|
|
SetLastError(ERROR_INVALID_NAME);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
if(label_end-label_start > 63) {
|
|
|
|
SetLastError(ERROR_INVALID_NAME);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(label_end-label_start<4 ||
|
|
|
|
tolowerW(lpASCIICharStr[label_start])!='x' ||
|
|
|
|
tolowerW(lpASCIICharStr[label_start+1])!='n' ||
|
|
|
|
lpASCIICharStr[label_start+2]!='-' || lpASCIICharStr[label_start+3]!='-') {
|
|
|
|
if(label_end < cchASCIIChar)
|
|
|
|
label_end++;
|
|
|
|
|
|
|
|
if(!lpUnicodeCharStr) {
|
|
|
|
out += label_end-label_start;
|
|
|
|
}else if(out+label_end-label_start <= cchUnicodeChar) {
|
|
|
|
memcpy(lpUnicodeCharStr+out, lpASCIICharStr+label_start,
|
|
|
|
(label_end-label_start)*sizeof(WCHAR));
|
|
|
|
out += label_end-label_start;
|
|
|
|
}else {
|
|
|
|
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
label_start = label_end;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(delim == label_start+3)
|
|
|
|
delim++;
|
|
|
|
if(!lpUnicodeCharStr) {
|
|
|
|
out += delim-label_start-4;
|
|
|
|
}else if(out+delim-label_start-4 <= cchUnicodeChar) {
|
|
|
|
memcpy(lpUnicodeCharStr+out, lpASCIICharStr+label_start+4,
|
|
|
|
(delim-label_start-4)*sizeof(WCHAR));
|
|
|
|
out += delim-label_start-4;
|
|
|
|
}else {
|
|
|
|
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
if(out != out_label)
|
|
|
|
delim++;
|
|
|
|
|
|
|
|
for(i=delim; i<label_end;) {
|
|
|
|
old_pos = pos;
|
|
|
|
w = 1;
|
|
|
|
for(k=BASE; ; k+=BASE) {
|
|
|
|
ch = i<label_end ? tolowerW(lpASCIICharStr[i++]) : 0;
|
|
|
|
if((ch<'a' || ch>'z') && (ch<'0' || ch>'9')) {
|
|
|
|
SetLastError(ERROR_INVALID_NAME);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
digit = ch<='9' ? ch-'0'+'z'-'a'+1 : ch-'a';
|
|
|
|
pos += digit*w;
|
|
|
|
t = k<=bias ? TMIN : k>=bias+TMAX ? TMAX : k-bias;
|
|
|
|
if(digit < t)
|
|
|
|
break;
|
|
|
|
w *= BASE-t;
|
|
|
|
}
|
|
|
|
bias = adapt(pos-old_pos, out-out_label+1, old_pos==0);
|
|
|
|
n += pos/(out-out_label+1);
|
|
|
|
pos %= out-out_label+1;
|
|
|
|
|
|
|
|
if((dwFlags&IDN_ALLOW_UNASSIGNED)==0 &&
|
|
|
|
get_table_entry(nameprep_char_type, n)==1/*UNASSIGNED*/) {
|
|
|
|
SetLastError(ERROR_INVALID_NAME);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
if(!lpUnicodeCharStr) {
|
|
|
|
out++;
|
|
|
|
}else if(out+1 <= cchASCIIChar) {
|
|
|
|
memmove(lpUnicodeCharStr+out_label+pos+1,
|
|
|
|
lpUnicodeCharStr+out_label+pos,
|
|
|
|
(out-out_label-pos)*sizeof(WCHAR));
|
|
|
|
lpUnicodeCharStr[out_label+pos] = n;
|
|
|
|
out++;
|
|
|
|
}else {
|
|
|
|
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
pos++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(out-out_label > 63) {
|
|
|
|
SetLastError(ERROR_INVALID_NAME);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(label_end < cchASCIIChar) {
|
|
|
|
if(!lpUnicodeCharStr) {
|
|
|
|
out++;
|
|
|
|
}else if(out+1 <= cchUnicodeChar) {
|
|
|
|
lpUnicodeCharStr[out++] = lpASCIICharStr[label_end];
|
|
|
|
}else {
|
|
|
|
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
label_start = label_end+1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return out;
|
|
|
|
}
|