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