2 #define WIN32_NO_STATUS
3 #include <wine/unicode.h>
8 /* Taken from Wine kernel32/locale.c */
20 static inline INT
adapt(INT delta
, INT numpoints
, BOOL firsttime
)
24 delta
/= (firsttime
? DAMP
: 2);
25 delta
+= delta
/numpoints
;
27 for(k
=0; delta
>((BASE
-TMIN
)*TMAX
)/2; k
+=BASE
)
29 return k
+((BASE
-TMIN
+1)*delta
)/(delta
+SKEW
);
32 static inline unsigned short get_table_entry( const unsigned short *table
, WCHAR ch
)
34 return table
[table
[table
[ch
>> 8] + ((ch
>> 4) & 0x0f)] + (ch
& 0xf)];
37 INT WINAPI
IdnToNameprepUnicode(DWORD dwFlags
, LPCWSTR lpUnicodeCharStr
, INT cchUnicodeChar
,
38 LPWSTR lpNameprepCharStr
, INT cchNameprepChar
)
47 extern const unsigned short nameprep_char_type
[];
48 extern const WCHAR nameprep_mapping
[];
51 WCHAR buf
[64], *map_str
, norm_str
[64], ch
;
52 DWORD i
, map_len
, norm_len
, mask
, label_start
, label_end
, out
= 0;
53 BOOL have_bidi_ral
, prohibit_bidi_ral
, ascii_only
;
55 DPRINT("%x %p %d %p %d\n", dwFlags
, lpUnicodeCharStr
, cchUnicodeChar
,
56 lpNameprepCharStr
, cchNameprepChar
);
58 if(dwFlags
& ~(IDN_ALLOW_UNASSIGNED
|IDN_USE_STD3_ASCII_RULES
)) {
59 SetLastError(ERROR_INVALID_FLAGS
);
63 if(!lpUnicodeCharStr
|| cchUnicodeChar
<-1) {
64 SetLastError(ERROR_INVALID_PARAMETER
);
68 if(cchUnicodeChar
== -1)
69 cchUnicodeChar
= (UINT
)strlenW(lpUnicodeCharStr
)+1;
70 if(!cchUnicodeChar
|| (cchUnicodeChar
==1 && lpUnicodeCharStr
[0]==0)) {
71 SetLastError(ERROR_INVALID_NAME
);
75 for(label_start
=0; label_start
<(UINT
)cchUnicodeChar
;) {
77 for(i
=label_start
; i
<(UINT
)cchUnicodeChar
; i
++) {
78 ch
= lpUnicodeCharStr
[i
];
80 if(i
!=cchUnicodeChar
-1 && !ch
) {
81 SetLastError(ERROR_INVALID_NAME
);
84 /* check if ch is one of label separators defined in RFC3490 */
85 if(!ch
|| ch
=='.' || ch
==0x3002 || ch
==0xff0e || ch
==0xff61)
93 if((dwFlags
&IDN_USE_STD3_ASCII_RULES
) == 0)
95 if((ch
>='a' && ch
<='z') || (ch
>='A' && ch
<='Z')
96 || (ch
>='0' && ch
<='9') || ch
=='-')
99 SetLastError(ERROR_INVALID_NAME
);
103 /* last label may be empty */
104 if(label_start
==label_end
&& ch
) {
105 SetLastError(ERROR_INVALID_NAME
);
109 if((dwFlags
&IDN_USE_STD3_ASCII_RULES
) && (lpUnicodeCharStr
[label_start
]=='-' ||
110 lpUnicodeCharStr
[label_end
-1]=='-')) {
111 SetLastError(ERROR_INVALID_NAME
);
116 /* maximal label length is 63 characters */
117 if(label_end
-label_start
> 63) {
118 SetLastError(ERROR_INVALID_NAME
);
121 if(label_end
< (UINT
)cchUnicodeChar
)
124 if(!lpNameprepCharStr
) {
125 out
+= label_end
-label_start
;
126 }else if(out
+label_end
-label_start
<= (UINT
)cchNameprepChar
) {
127 memcpy(lpNameprepCharStr
+out
, lpUnicodeCharStr
+label_start
,
128 (label_end
-label_start
)*sizeof(WCHAR
));
129 if(lpUnicodeCharStr
[label_end
-1] > 0x7f)
130 lpNameprepCharStr
[out
+label_end
-label_start
-1] = '.';
131 out
+= label_end
-label_start
;
133 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
137 label_start
= label_end
;
142 for(i
=label_start
; i
<label_end
; i
++) {
143 ch
= lpUnicodeCharStr
[i
];
144 ptr
= nameprep_mapping
+ nameprep_mapping
[ch
>>8];
145 ptr
= nameprep_mapping
+ ptr
[(ch
>>4)&0x0f] + 3*(ch
&0x0f);
147 if(!ptr
[0]) map_len
++;
148 else if(!ptr
[1]) map_len
++;
149 else if(!ptr
[2]) map_len
+= 2;
150 else if(ptr
[0]!=0xffff || ptr
[1]!=0xffff || ptr
[2]!=0xffff) map_len
+= 3;
152 if(map_len
*sizeof(WCHAR
) > sizeof(buf
)) {
153 map_str
= HeapAlloc(GetProcessHeap(), 0, map_len
*sizeof(WCHAR
));
155 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
162 for(i
=label_start
; i
<label_end
; i
++) {
163 ch
= lpUnicodeCharStr
[i
];
164 ptr
= nameprep_mapping
+ nameprep_mapping
[ch
>>8];
165 ptr
= nameprep_mapping
+ ptr
[(ch
>>4)&0x0f] + 3*(ch
&0x0f);
168 map_str
[map_len
++] = ch
;
170 map_str
[map_len
++] = ptr
[0];
172 map_str
[map_len
++] = ptr
[0];
173 map_str
[map_len
++] = ptr
[1];
174 }else if(ptr
[0]!=0xffff || ptr
[1]!=0xffff || ptr
[2]!=0xffff) {
175 map_str
[map_len
++] = ptr
[0];
176 map_str
[map_len
++] = ptr
[1];
177 map_str
[map_len
++] = ptr
[2];
181 norm_len
= FoldStringW(MAP_FOLDCZONE
, map_str
, map_len
,
182 norm_str
, sizeof(norm_str
)/sizeof(WCHAR
)-1);
184 HeapFree(GetProcessHeap(), 0, map_str
);
186 if(GetLastError() == ERROR_INSUFFICIENT_BUFFER
)
187 SetLastError(ERROR_INVALID_NAME
);
191 if(label_end
< (UINT
)cchUnicodeChar
) {
192 norm_str
[norm_len
++] = lpUnicodeCharStr
[label_end
] ? '.' : 0;
196 if(!lpNameprepCharStr
) {
198 }else if(out
+norm_len
<= (UINT
)cchNameprepChar
) {
199 memcpy(lpNameprepCharStr
+out
, norm_str
, norm_len
*sizeof(WCHAR
));
202 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
206 have_bidi_ral
= prohibit_bidi_ral
= FALSE
;
208 if((dwFlags
&IDN_ALLOW_UNASSIGNED
) == 0)
210 for(i
=0; i
<norm_len
; i
++) {
212 flags
= get_table_entry( nameprep_char_type
, ch
);
215 SetLastError((flags
& PROHIBITED
) ? ERROR_INVALID_NAME
216 : ERROR_NO_UNICODE_TRANSLATION
);
221 have_bidi_ral
= TRUE
;
223 prohibit_bidi_ral
= TRUE
;
228 flags
= get_table_entry( nameprep_char_type
, ch
);
229 if((flags
& BIDI_RAL
) == 0)
230 prohibit_bidi_ral
= TRUE
;
232 ch
= norm_str
[norm_len
-1];
233 flags
= get_table_entry( nameprep_char_type
, ch
);
234 if((flags
& BIDI_RAL
) == 0)
235 prohibit_bidi_ral
= TRUE
;
238 if(have_bidi_ral
&& prohibit_bidi_ral
) {
239 SetLastError(ERROR_INVALID_NAME
);
243 label_start
= label_end
;
249 INT WINAPI
IdnToAscii(DWORD dwFlags
, LPCWSTR lpUnicodeCharStr
, INT cchUnicodeChar
,
250 LPWSTR lpASCIICharStr
, INT cchASCIIChar
)
252 static const WCHAR prefixW
[] = {'x','n','-','-'};
255 INT i
, label_start
, label_end
, norm_len
, out_label
, out
= 0;
257 DPRINT("%x %p %d %p %d\n", dwFlags
, lpUnicodeCharStr
, cchUnicodeChar
,
258 lpASCIICharStr
, cchASCIIChar
);
260 norm_len
= IdnToNameprepUnicode(dwFlags
, lpUnicodeCharStr
, cchUnicodeChar
, NULL
, 0);
263 norm_str
= HeapAlloc(GetProcessHeap(), 0, norm_len
*sizeof(WCHAR
));
265 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
268 norm_len
= IdnToNameprepUnicode(dwFlags
, lpUnicodeCharStr
,
269 cchUnicodeChar
, norm_str
, norm_len
);
271 HeapFree(GetProcessHeap(), 0, norm_str
);
275 for(label_start
=0; label_start
<norm_len
;) {
276 INT n
= INIT_N
, bias
= INIT_BIAS
;
277 INT delta
= 0, b
= 0, h
;
280 for(i
=label_start
; i
<norm_len
&& norm_str
[i
]!='.' &&
281 norm_str
[i
]!=0x3002 && norm_str
[i
]!='\0'; i
++)
282 if(norm_str
[i
] < 0x80)
286 if(b
== label_end
-label_start
) {
287 if(label_end
< norm_len
)
289 if(!lpASCIICharStr
) {
291 }else if(out
+b
<= cchASCIIChar
) {
292 memcpy(lpASCIICharStr
+out
, norm_str
+label_start
, b
*sizeof(WCHAR
));
295 HeapFree(GetProcessHeap(), 0, norm_str
);
296 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
299 label_start
= label_end
+1;
303 if(!lpASCIICharStr
) {
304 out
+= 5+b
; /* strlen(xn--...-) */
305 }else if(out
+5+b
<= cchASCIIChar
) {
306 memcpy(lpASCIICharStr
+out
, prefixW
, sizeof(prefixW
));
308 for(i
=label_start
; i
<label_end
; i
++)
309 if(norm_str
[i
] < 0x80)
310 lpASCIICharStr
[out
++] = norm_str
[i
];
311 lpASCIICharStr
[out
++] = '-';
313 HeapFree(GetProcessHeap(), 0, norm_str
);
314 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
320 for(h
=b
; h
<label_end
-label_start
;) {
321 INT m
= 0xffff, q
, k
;
323 for(i
=label_start
; i
<label_end
; i
++) {
324 if(norm_str
[i
]>=n
&& m
>norm_str
[i
])
327 delta
+= (m
-n
)*(h
+1);
330 for(i
=label_start
; i
<label_end
; i
++) {
331 if(norm_str
[i
] < n
) {
333 }else if(norm_str
[i
] == n
) {
334 for(q
=delta
, k
=BASE
; ; k
+=BASE
) {
335 INT t
= k
<=bias
? TMIN
: k
>=bias
+TMAX
? TMAX
: k
-bias
;
336 INT disp
= q
<t
? q
: t
+(q
-t
)%(BASE
-t
);
337 if(!lpASCIICharStr
) {
339 }else if(out
+1 <= cchASCIIChar
) {
340 lpASCIICharStr
[out
++] = disp
<='z'-'a' ?
341 'a'+disp
: '0'+disp
-'z'+'a'-1;
343 HeapFree(GetProcessHeap(), 0, norm_str
);
344 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
351 bias
= adapt(delta
, h
+1, h
==b
);
360 if(out
-out_label
> 63) {
361 HeapFree(GetProcessHeap(), 0, norm_str
);
362 SetLastError(ERROR_INVALID_NAME
);
366 if(label_end
< norm_len
) {
367 if(!lpASCIICharStr
) {
369 }else if(out
+1 <= cchASCIIChar
) {
370 lpASCIICharStr
[out
++] = norm_str
[label_end
] ? '.' : 0;
372 HeapFree(GetProcessHeap(), 0, norm_str
);
373 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
377 label_start
= label_end
+1;
380 HeapFree(GetProcessHeap(), 0, norm_str
);