Module: wine Branch: master Commit: e2f0463963c45e06789454e1bebc0a71800fe48a URL: http://source.winehq.org/git/wine.git/?a=commit;h=e2f0463963c45e06789454e1be...
Author: Piotr Caban piotr@codeweavers.com Date: Mon Apr 30 17:28:08 2012 +0200
kernel32: Added IdnToUnicode implementation.
---
dlls/kernel32/locale.c | 149 +++++++++++++++++++++++++++++++++++++++++++++++- 1 files changed, 146 insertions(+), 3 deletions(-)
diff --git a/dlls/kernel32/locale.c b/dlls/kernel32/locale.c index fbc3ae2..b506f15 100644 --- a/dlls/kernel32/locale.c +++ b/dlls/kernel32/locale.c @@ -4263,8 +4263,151 @@ INT WINAPI IdnToNameprepUnicode(DWORD dwFlags, LPCWSTR lpUnicodeCharStr, INT cch INT WINAPI IdnToUnicode(DWORD dwFlags, LPCWSTR lpASCIICharStr, INT cchASCIIChar, LPWSTR lpUnicodeCharStr, INT cchUnicodeChar) { - FIXME("%x %p %d %p %d\n", dwFlags, lpASCIICharStr, cchASCIIChar, + extern const unsigned short nameprep_char_type[]; + + INT i, label_start, label_end, out_label, out = 0; + WCHAR ch; + + TRACE("%x %p %d %p %d\n", dwFlags, lpASCIICharStr, cchASCIIChar, lpUnicodeCharStr, cchUnicodeChar); - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return 0; + + 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) && (lpUnicodeCharStr[label_start]=='-' || + lpUnicodeCharStr[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 < cchUnicodeChar) + 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; }