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
IdnToUnicode(DWORD dwFlags
, LPCWSTR lpASCIICharStr
, INT cchASCIIChar
,
38 LPWSTR lpUnicodeCharStr
, INT cchUnicodeChar
)
40 extern const unsigned short nameprep_char_type
[];
42 INT i
, label_start
, label_end
, out_label
, out
= 0;
45 DPRINT("%x %p %d %p %d\n", dwFlags
, lpASCIICharStr
, cchASCIIChar
,
46 lpUnicodeCharStr
, cchUnicodeChar
);
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
;
52 for(i
=label_start
; i
<cchASCIIChar
; i
++) {
53 ch
= lpASCIICharStr
[i
];
55 if(ch
>0x7f || (i
!=cchASCIIChar
-1 && !ch
)) {
56 SetLastError(ERROR_INVALID_NAME
);
65 if((dwFlags
&IDN_USE_STD3_ASCII_RULES
) == 0)
67 if((ch
>='a' && ch
<='z') || (ch
>='A' && ch
<='Z')
68 || (ch
>='0' && ch
<='9') || ch
=='-')
71 SetLastError(ERROR_INVALID_NAME
);
75 /* last label may be empty */
76 if(label_start
==label_end
&& ch
) {
77 SetLastError(ERROR_INVALID_NAME
);
81 if((dwFlags
&IDN_USE_STD3_ASCII_RULES
) && (lpASCIICharStr
[label_start
]=='-' ||
82 lpASCIICharStr
[label_end
-1]=='-')) {
83 SetLastError(ERROR_INVALID_NAME
);
86 if(label_end
-label_start
> 63) {
87 SetLastError(ERROR_INVALID_NAME
);
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
)
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
;
105 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
109 label_start
= label_end
;
113 if(delim
== label_start
+3)
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;
122 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
128 for(i
=delim
; i
<label_end
;) {
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
);
137 digit
= ch
<='9' ? ch
-'0'+'z'-'a'+1 : ch
-'a';
139 t
= k
<=bias
? TMIN
: k
>=bias
+TMAX
? TMAX
: k
-bias
;
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;
148 if((dwFlags
&IDN_ALLOW_UNASSIGNED
)==0 &&
149 get_table_entry(nameprep_char_type
, n
)==1/*UNASSIGNED*/) {
150 SetLastError(ERROR_INVALID_NAME
);
153 if(!lpUnicodeCharStr
) {
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
;
162 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
168 if(out
-out_label
> 63) {
169 SetLastError(ERROR_INVALID_NAME
);
173 if(label_end
< cchASCIIChar
) {
174 if(!lpUnicodeCharStr
) {
176 }else if(out
+1 <= cchUnicodeChar
) {
177 lpUnicodeCharStr
[out
++] = lpASCIICharStr
[label_end
];
179 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
183 label_start
= label_end
+1;