2 #define WIN32_NO_STATUS
3 #include <wine/unicode.h>
6 /* Taken from Wine kernel32/locale.c */
18 static inline INT
adapt(INT delta
, INT numpoints
, BOOL firsttime
)
22 delta
/= (firsttime
? DAMP
: 2);
23 delta
+= delta
/numpoints
;
25 for(k
=0; delta
>((BASE
-TMIN
)*TMAX
)/2; k
+=BASE
)
27 return k
+((BASE
-TMIN
+1)*delta
)/(delta
+SKEW
);
30 static inline unsigned short get_table_entry( const unsigned short *table
, WCHAR ch
)
32 return table
[table
[table
[ch
>> 8] + ((ch
>> 4) & 0x0f)] + (ch
& 0xf)];
35 INT WINAPI
IdnToNameprepUnicode(DWORD dwFlags
, LPCWSTR lpUnicodeCharStr
, INT cchUnicodeChar
,
36 LPWSTR lpNameprepCharStr
, INT cchNameprepChar
)
45 extern const unsigned short nameprep_char_type
[];
46 extern const WCHAR nameprep_mapping
[];
49 WCHAR buf
[64], *map_str
, norm_str
[64], ch
;
50 DWORD i
, map_len
, norm_len
, mask
, label_start
, label_end
, out
= 0;
51 BOOL have_bidi_ral
, prohibit_bidi_ral
, ascii_only
;
53 DPRINT("%x %p %d %p %d\n", dwFlags
, lpUnicodeCharStr
, cchUnicodeChar
,
54 lpNameprepCharStr
, cchNameprepChar
);
56 if(dwFlags
& ~(IDN_ALLOW_UNASSIGNED
|IDN_USE_STD3_ASCII_RULES
)) {
57 SetLastError(ERROR_INVALID_FLAGS
);
61 if(!lpUnicodeCharStr
|| cchUnicodeChar
<-1) {
62 SetLastError(ERROR_INVALID_PARAMETER
);
66 if(cchUnicodeChar
== -1)
67 cchUnicodeChar
= (UINT
)strlenW(lpUnicodeCharStr
)+1;
68 if(!cchUnicodeChar
|| (cchUnicodeChar
==1 && lpUnicodeCharStr
[0]==0)) {
69 SetLastError(ERROR_INVALID_NAME
);
73 for(label_start
=0; label_start
<(UINT
)cchUnicodeChar
;) {
75 for(i
=label_start
; i
<(UINT
)cchUnicodeChar
; i
++) {
76 ch
= lpUnicodeCharStr
[i
];
78 if(i
!=cchUnicodeChar
-1 && !ch
) {
79 SetLastError(ERROR_INVALID_NAME
);
82 /* check if ch is one of label separators defined in RFC3490 */
83 if(!ch
|| ch
=='.' || ch
==0x3002 || ch
==0xff0e || ch
==0xff61)
91 if((dwFlags
&IDN_USE_STD3_ASCII_RULES
) == 0)
93 if((ch
>='a' && ch
<='z') || (ch
>='A' && ch
<='Z')
94 || (ch
>='0' && ch
<='9') || ch
=='-')
97 SetLastError(ERROR_INVALID_NAME
);
101 /* last label may be empty */
102 if(label_start
==label_end
&& ch
) {
103 SetLastError(ERROR_INVALID_NAME
);
107 if((dwFlags
&IDN_USE_STD3_ASCII_RULES
) && (lpUnicodeCharStr
[label_start
]=='-' ||
108 lpUnicodeCharStr
[label_end
-1]=='-')) {
109 SetLastError(ERROR_INVALID_NAME
);
114 /* maximal label length is 63 characters */
115 if(label_end
-label_start
> 63) {
116 SetLastError(ERROR_INVALID_NAME
);
119 if(label_end
< (UINT
)cchUnicodeChar
)
122 if(!lpNameprepCharStr
) {
123 out
+= label_end
-label_start
;
124 }else if(out
+label_end
-label_start
<= (UINT
)cchNameprepChar
) {
125 memcpy(lpNameprepCharStr
+out
, lpUnicodeCharStr
+label_start
,
126 (label_end
-label_start
)*sizeof(WCHAR
));
127 if(lpUnicodeCharStr
[label_end
-1] > 0x7f)
128 lpNameprepCharStr
[out
+label_end
-label_start
-1] = '.';
129 out
+= label_end
-label_start
;
131 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
135 label_start
= label_end
;
140 for(i
=label_start
; i
<label_end
; i
++) {
141 ch
= lpUnicodeCharStr
[i
];
142 ptr
= nameprep_mapping
+ nameprep_mapping
[ch
>>8];
143 ptr
= nameprep_mapping
+ ptr
[(ch
>>4)&0x0f] + 3*(ch
&0x0f);
145 if(!ptr
[0]) map_len
++;
146 else if(!ptr
[1]) map_len
++;
147 else if(!ptr
[2]) map_len
+= 2;
148 else if(ptr
[0]!=0xffff || ptr
[1]!=0xffff || ptr
[2]!=0xffff) map_len
+= 3;
150 if(map_len
*sizeof(WCHAR
) > sizeof(buf
)) {
151 map_str
= HeapAlloc(GetProcessHeap(), 0, map_len
*sizeof(WCHAR
));
153 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
160 for(i
=label_start
; i
<label_end
; i
++) {
161 ch
= lpUnicodeCharStr
[i
];
162 ptr
= nameprep_mapping
+ nameprep_mapping
[ch
>>8];
163 ptr
= nameprep_mapping
+ ptr
[(ch
>>4)&0x0f] + 3*(ch
&0x0f);
166 map_str
[map_len
++] = ch
;
168 map_str
[map_len
++] = ptr
[0];
170 map_str
[map_len
++] = ptr
[0];
171 map_str
[map_len
++] = ptr
[1];
172 }else if(ptr
[0]!=0xffff || ptr
[1]!=0xffff || ptr
[2]!=0xffff) {
173 map_str
[map_len
++] = ptr
[0];
174 map_str
[map_len
++] = ptr
[1];
175 map_str
[map_len
++] = ptr
[2];
179 norm_len
= FoldStringW(MAP_FOLDCZONE
, map_str
, map_len
,
180 norm_str
, sizeof(norm_str
)/sizeof(WCHAR
)-1);
182 HeapFree(GetProcessHeap(), 0, map_str
);
184 if(GetLastError() == ERROR_INSUFFICIENT_BUFFER
)
185 SetLastError(ERROR_INVALID_NAME
);
189 if(label_end
< (UINT
)cchUnicodeChar
) {
190 norm_str
[norm_len
++] = lpUnicodeCharStr
[label_end
] ? '.' : 0;
194 if(!lpNameprepCharStr
) {
196 }else if(out
+norm_len
<= (UINT
)cchNameprepChar
) {
197 memcpy(lpNameprepCharStr
+out
, norm_str
, norm_len
*sizeof(WCHAR
));
200 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
204 have_bidi_ral
= prohibit_bidi_ral
= FALSE
;
206 if((dwFlags
&IDN_ALLOW_UNASSIGNED
) == 0)
208 for(i
=0; i
<norm_len
; i
++) {
210 flags
= get_table_entry( nameprep_char_type
, ch
);
213 SetLastError((flags
& PROHIBITED
) ? ERROR_INVALID_NAME
214 : ERROR_NO_UNICODE_TRANSLATION
);
219 have_bidi_ral
= TRUE
;
221 prohibit_bidi_ral
= TRUE
;
226 flags
= get_table_entry( nameprep_char_type
, ch
);
227 if((flags
& BIDI_RAL
) == 0)
228 prohibit_bidi_ral
= TRUE
;
230 ch
= norm_str
[norm_len
-1];
231 flags
= get_table_entry( nameprep_char_type
, ch
);
232 if((flags
& BIDI_RAL
) == 0)
233 prohibit_bidi_ral
= TRUE
;
236 if(have_bidi_ral
&& prohibit_bidi_ral
) {
237 SetLastError(ERROR_INVALID_NAME
);
241 label_start
= label_end
;
247 INT WINAPI
IdnToAscii(DWORD dwFlags
, LPCWSTR lpUnicodeCharStr
, INT cchUnicodeChar
,
248 LPWSTR lpASCIICharStr
, INT cchASCIIChar
)
250 static const WCHAR prefixW
[] = {'x','n','-','-'};
253 INT i
, label_start
, label_end
, norm_len
, out_label
, out
= 0;
255 DPRINT("%x %p %d %p %d\n", dwFlags
, lpUnicodeCharStr
, cchUnicodeChar
,
256 lpASCIICharStr
, cchASCIIChar
);
258 norm_len
= IdnToNameprepUnicode(dwFlags
, lpUnicodeCharStr
, cchUnicodeChar
, NULL
, 0);
261 norm_str
= HeapAlloc(GetProcessHeap(), 0, norm_len
*sizeof(WCHAR
));
263 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
266 norm_len
= IdnToNameprepUnicode(dwFlags
, lpUnicodeCharStr
,
267 cchUnicodeChar
, norm_str
, norm_len
);
269 HeapFree(GetProcessHeap(), 0, norm_str
);
273 for(label_start
=0; label_start
<norm_len
;) {
274 INT n
= INIT_N
, bias
= INIT_BIAS
;
275 INT delta
= 0, b
= 0, h
;
278 for(i
=label_start
; i
<norm_len
&& norm_str
[i
]!='.' &&
279 norm_str
[i
]!=0x3002 && norm_str
[i
]!='\0'; i
++)
280 if(norm_str
[i
] < 0x80)
284 if(b
== label_end
-label_start
) {
285 if(label_end
< norm_len
)
287 if(!lpASCIICharStr
) {
289 }else if(out
+b
<= cchASCIIChar
) {
290 memcpy(lpASCIICharStr
+out
, norm_str
+label_start
, b
*sizeof(WCHAR
));
293 HeapFree(GetProcessHeap(), 0, norm_str
);
294 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
297 label_start
= label_end
+1;
301 if(!lpASCIICharStr
) {
302 out
+= 5+b
; /* strlen(xn--...-) */
303 }else if(out
+5+b
<= cchASCIIChar
) {
304 memcpy(lpASCIICharStr
+out
, prefixW
, sizeof(prefixW
));
306 for(i
=label_start
; i
<label_end
; i
++)
307 if(norm_str
[i
] < 0x80)
308 lpASCIICharStr
[out
++] = norm_str
[i
];
309 lpASCIICharStr
[out
++] = '-';
311 HeapFree(GetProcessHeap(), 0, norm_str
);
312 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
318 for(h
=b
; h
<label_end
-label_start
;) {
319 INT m
= 0xffff, q
, k
;
321 for(i
=label_start
; i
<label_end
; i
++) {
322 if(norm_str
[i
]>=n
&& m
>norm_str
[i
])
325 delta
+= (m
-n
)*(h
+1);
328 for(i
=label_start
; i
<label_end
; i
++) {
329 if(norm_str
[i
] < n
) {
331 }else if(norm_str
[i
] == n
) {
332 for(q
=delta
, k
=BASE
; ; k
+=BASE
) {
333 INT t
= k
<=bias
? TMIN
: k
>=bias
+TMAX
? TMAX
: k
-bias
;
334 INT disp
= q
<t
? q
: t
+(q
-t
)%(BASE
-t
);
335 if(!lpASCIICharStr
) {
337 }else if(out
+1 <= cchASCIIChar
) {
338 lpASCIICharStr
[out
++] = disp
<='z'-'a' ?
339 'a'+disp
: '0'+disp
-'z'+'a'-1;
341 HeapFree(GetProcessHeap(), 0, norm_str
);
342 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
349 bias
= adapt(delta
, h
+1, h
==b
);
358 if(out
-out_label
> 63) {
359 HeapFree(GetProcessHeap(), 0, norm_str
);
360 SetLastError(ERROR_INVALID_NAME
);
364 if(label_end
< norm_len
) {
365 if(!lpASCIICharStr
) {
367 }else if(out
+1 <= cchASCIIChar
) {
368 lpASCIICharStr
[out
++] = norm_str
[label_end
] ? '.' : 0;
370 HeapFree(GetProcessHeap(), 0, norm_str
);
371 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
375 label_start
= label_end
+1;
378 HeapFree(GetProcessHeap(), 0, norm_str
);