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