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
IdnToUnicode(DWORD dwFlags
, LPCWSTR lpASCIICharStr
, INT cchASCIIChar
,
36 LPWSTR lpUnicodeCharStr
, INT cchUnicodeChar
)
38 extern const unsigned short nameprep_char_type
[];
40 INT i
, label_start
, label_end
, out_label
, out
= 0;
43 DPRINT("%x %p %d %p %d\n", dwFlags
, lpASCIICharStr
, cchASCIIChar
,
44 lpUnicodeCharStr
, cchUnicodeChar
);
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
;
50 for(i
=label_start
; i
<cchASCIIChar
; i
++) {
51 ch
= lpASCIICharStr
[i
];
53 if(ch
>0x7f || (i
!=cchASCIIChar
-1 && !ch
)) {
54 SetLastError(ERROR_INVALID_NAME
);
63 if((dwFlags
&IDN_USE_STD3_ASCII_RULES
) == 0)
65 if((ch
>='a' && ch
<='z') || (ch
>='A' && ch
<='Z')
66 || (ch
>='0' && ch
<='9') || ch
=='-')
69 SetLastError(ERROR_INVALID_NAME
);
73 /* last label may be empty */
74 if(label_start
==label_end
&& ch
) {
75 SetLastError(ERROR_INVALID_NAME
);
79 if((dwFlags
&IDN_USE_STD3_ASCII_RULES
) && (lpASCIICharStr
[label_start
]=='-' ||
80 lpASCIICharStr
[label_end
-1]=='-')) {
81 SetLastError(ERROR_INVALID_NAME
);
84 if(label_end
-label_start
> 63) {
85 SetLastError(ERROR_INVALID_NAME
);
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
)
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
;
103 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
107 label_start
= label_end
;
111 if(delim
== label_start
+3)
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;
120 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
126 for(i
=delim
; i
<label_end
;) {
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
);
135 digit
= ch
<='9' ? ch
-'0'+'z'-'a'+1 : ch
-'a';
137 t
= k
<=bias
? TMIN
: k
>=bias
+TMAX
? TMAX
: k
-bias
;
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;
146 if((dwFlags
&IDN_ALLOW_UNASSIGNED
)==0 &&
147 get_table_entry(nameprep_char_type
, n
)==1/*UNASSIGNED*/) {
148 SetLastError(ERROR_INVALID_NAME
);
151 if(!lpUnicodeCharStr
) {
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
;
160 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
166 if(out
-out_label
> 63) {
167 SetLastError(ERROR_INVALID_NAME
);
171 if(label_end
< cchASCIIChar
) {
172 if(!lpUnicodeCharStr
) {
174 }else if(out
+1 <= cchUnicodeChar
) {
175 lpUnicodeCharStr
[out
++] = lpASCIICharStr
[label_end
];
177 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
181 label_start
= label_end
+1;