1 2 #define WIN32_NO_STATUS 3 #include <wine/unicode.h> 4 5 #define NDEBUG 6 #include <debug.h> 7 8 /* Taken from Wine kernel32/locale.c */ 9 10 enum { 11 BASE = 36, 12 TMIN = 1, 13 TMAX = 26, 14 SKEW = 38, 15 DAMP = 700, 16 INIT_BIAS = 72, 17 INIT_N = 128 18 }; 19 20 static inline INT adapt(INT delta, INT numpoints, BOOL firsttime) 21 { 22 INT k; 23 24 delta /= (firsttime ? DAMP : 2); 25 delta += delta/numpoints; 26 27 for(k=0; delta>((BASE-TMIN)*TMAX)/2; k+=BASE) 28 delta /= BASE-TMIN; 29 return k+((BASE-TMIN+1)*delta)/(delta+SKEW); 30 } 31 32 static inline unsigned short get_table_entry( const unsigned short *table, WCHAR ch ) 33 { 34 return table[table[table[ch >> 8] + ((ch >> 4) & 0x0f)] + (ch & 0xf)]; 35 } 36 37 INT WINAPI IdnToUnicode(DWORD dwFlags, LPCWSTR lpASCIICharStr, INT cchASCIIChar, 38 LPWSTR lpUnicodeCharStr, INT cchUnicodeChar) 39 { 40 extern const unsigned short nameprep_char_type[]; 41 42 INT i, label_start, label_end, out_label, out = 0; 43 WCHAR ch; 44 45 DPRINT("%x %p %d %p %d\n", dwFlags, lpASCIICharStr, cchASCIIChar, 46 lpUnicodeCharStr, cchUnicodeChar); 47 48 for(label_start=0; label_start<cchASCIIChar;) { 49 INT n = INIT_N, pos = 0, old_pos, w, k, bias = INIT_BIAS, delim=0, digit, t; 50 51 out_label = out; 52 for(i=label_start; i<cchASCIIChar; i++) { 53 ch = lpASCIICharStr[i]; 54 55 if(ch>0x7f || (i!=cchASCIIChar-1 && !ch)) { 56 SetLastError(ERROR_INVALID_NAME); 57 return 0; 58 } 59 60 if(!ch || ch=='.') 61 break; 62 if(ch == '-') 63 delim = i; 64 65 if((dwFlags&IDN_USE_STD3_ASCII_RULES) == 0) 66 continue; 67 if((ch>='a' && ch<='z') || (ch>='A' && ch<='Z') 68 || (ch>='0' && ch<='9') || ch=='-') 69 continue; 70 71 SetLastError(ERROR_INVALID_NAME); 72 return 0; 73 } 74 label_end = i; 75 /* last label may be empty */ 76 if(label_start==label_end && ch) { 77 SetLastError(ERROR_INVALID_NAME); 78 return 0; 79 } 80 81 if((dwFlags&IDN_USE_STD3_ASCII_RULES) && (lpASCIICharStr[label_start]=='-' || 82 lpASCIICharStr[label_end-1]=='-')) { 83 SetLastError(ERROR_INVALID_NAME); 84 return 0; 85 } 86 if(label_end-label_start > 63) { 87 SetLastError(ERROR_INVALID_NAME); 88 return 0; 89 } 90 91 if(label_end-label_start<4 || 92 tolowerW(lpASCIICharStr[label_start])!='x' || 93 tolowerW(lpASCIICharStr[label_start+1])!='n' || 94 lpASCIICharStr[label_start+2]!='-' || lpASCIICharStr[label_start+3]!='-') { 95 if(label_end < cchASCIIChar) 96 label_end++; 97 98 if(!lpUnicodeCharStr) { 99 out += label_end-label_start; 100 }else if(out+label_end-label_start <= cchUnicodeChar) { 101 memcpy(lpUnicodeCharStr+out, lpASCIICharStr+label_start, 102 (label_end-label_start)*sizeof(WCHAR)); 103 out += label_end-label_start; 104 }else { 105 SetLastError(ERROR_INSUFFICIENT_BUFFER); 106 return 0; 107 } 108 109 label_start = label_end; 110 continue; 111 } 112 113 if(delim == label_start+3) 114 delim++; 115 if(!lpUnicodeCharStr) { 116 out += delim-label_start-4; 117 }else if(out+delim-label_start-4 <= cchUnicodeChar) { 118 memcpy(lpUnicodeCharStr+out, lpASCIICharStr+label_start+4, 119 (delim-label_start-4)*sizeof(WCHAR)); 120 out += delim-label_start-4; 121 }else { 122 SetLastError(ERROR_INSUFFICIENT_BUFFER); 123 return 0; 124 } 125 if(out != out_label) 126 delim++; 127 128 for(i=delim; i<label_end;) { 129 old_pos = pos; 130 w = 1; 131 for(k=BASE; ; k+=BASE) { 132 ch = i<label_end ? tolowerW(lpASCIICharStr[i++]) : 0; 133 if((ch<'a' || ch>'z') && (ch<'0' || ch>'9')) { 134 SetLastError(ERROR_INVALID_NAME); 135 return 0; 136 } 137 digit = ch<='9' ? ch-'0'+'z'-'a'+1 : ch-'a'; 138 pos += digit*w; 139 t = k<=bias ? TMIN : k>=bias+TMAX ? TMAX : k-bias; 140 if(digit < t) 141 break; 142 w *= BASE-t; 143 } 144 bias = adapt(pos-old_pos, out-out_label+1, old_pos==0); 145 n += pos/(out-out_label+1); 146 pos %= out-out_label+1; 147 148 if((dwFlags&IDN_ALLOW_UNASSIGNED)==0 && 149 get_table_entry(nameprep_char_type, n)==1/*UNASSIGNED*/) { 150 SetLastError(ERROR_INVALID_NAME); 151 return 0; 152 } 153 if(!lpUnicodeCharStr) { 154 out++; 155 }else if(out+1 <= cchASCIIChar) { 156 memmove(lpUnicodeCharStr+out_label+pos+1, 157 lpUnicodeCharStr+out_label+pos, 158 (out-out_label-pos)*sizeof(WCHAR)); 159 lpUnicodeCharStr[out_label+pos] = n; 160 out++; 161 }else { 162 SetLastError(ERROR_INSUFFICIENT_BUFFER); 163 return 0; 164 } 165 pos++; 166 } 167 168 if(out-out_label > 63) { 169 SetLastError(ERROR_INVALID_NAME); 170 return 0; 171 } 172 173 if(label_end < cchASCIIChar) { 174 if(!lpUnicodeCharStr) { 175 out++; 176 }else if(out+1 <= cchUnicodeChar) { 177 lpUnicodeCharStr[out++] = lpASCIICharStr[label_end]; 178 }else { 179 SetLastError(ERROR_INSUFFICIENT_BUFFER); 180 return 0; 181 } 182 } 183 label_start = label_end+1; 184 } 185 186 return out; 187 } 188