#define WIN32_NO_STATUS #include #define NDEBUG #include /* 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_start0x7f || (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'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; }