]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/ndb/idn.c
webfs: remove idn.c
[plan9front.git] / sys / src / cmd / ndb / idn.c
1 #include <u.h>
2 #include <libc.h>
3 #include <ip.h>
4 #include "dns.h"
5
6 enum {
7         base = 36,
8         tmin = 1,
9         tmax = 26,
10         skew = 38,
11         damp = 700,
12         initial_bias = 72,
13         initial_n = 0x80,
14 };
15
16 static uint maxint = ~0;
17
18 static uint
19 decode_digit(uint cp)
20 {
21         if((cp - '0') < 10)
22                 return cp - ('0' - 26);
23         if((cp - 'A') < 26)
24                 return cp - 'A';
25         if((cp - 'a') < 26)
26                 return cp - 'a';
27         return base;
28 }
29
30 static char
31 encode_digit(uint d, int flag)
32 {
33         if(d < 26)
34                 return d + (flag ? 'A' : 'a');
35         return d + ('0' - 26);
36 }
37
38 static uint
39 adapt(uint delta, uint numpoints, int firsttime)
40 {
41         uint k;
42
43         delta = firsttime ? delta / damp : delta >> 1;
44         delta += delta / numpoints;
45         for (k = 0; delta > ((base - tmin) * tmax) / 2; k += base)
46                 delta /= base - tmin;
47         return k + (base - tmin + 1) * delta / (delta + skew);
48 }
49
50 static int
51 punyencode(uint input_length, Rune input[], uint max_out, char output[])
52 {
53         uint n, delta, h, b, out, bias, j, m, q, k, t;
54
55         n = initial_n;
56         delta = out = 0;
57         bias = initial_bias;
58
59         for (j = 0;  j < input_length;  ++j) {
60                 if ((uint)input[j] < 0x80) {
61                         if (max_out - out < 2)
62                                 return -1;
63                         output[out++] = input[j];
64                 }
65         }
66
67         h = b = out;
68
69         if (b > 0)
70                 output[out++] = '-';
71
72         while (h < input_length) {
73                 for (m = maxint, j = 0; j < input_length; ++j) {
74                         if (input[j] >= n && input[j] < m)
75                                 m = input[j];
76                 }
77
78                 if (m - n > (maxint - delta) / (h + 1))
79                         return -1;
80
81                 delta += (m - n) * (h + 1);
82                 n = m;
83
84                 for (j = 0;  j < input_length;  ++j) {
85                         if (input[j] < n) {
86                                 if (++delta == 0)
87                                         return -1;
88                         }
89
90                         if (input[j] == n) {
91                                 for (q = delta, k = base;; k += base) {
92                                         if (out >= max_out)
93                                                 return -1;
94                                         if (k <= bias)
95                                                 t = tmin;
96                                         else if (k >= bias + tmax)
97                                                 t = tmax;
98                                         else
99                                                 t = k - bias;
100                                         if (q < t)
101                                                 break;
102                                         output[out++] = encode_digit(t + (q - t) % (base - t), 0);
103                                         q = (q - t) / (base - t);
104                                 }
105                                 output[out++] = encode_digit(q, isupperrune(input[j]));
106                                 bias = adapt(delta, h + 1, h == b);
107                                 delta = 0;
108                                 ++h;
109                         }
110                 }
111
112                 ++delta, ++n;
113         }
114
115         return (int)out;
116 }
117
118 static int
119 punydecode(uint input_length, char input[], uint max_out, Rune output[])
120 {
121         uint n, out, i, bias, b, j, in, oldi, w, k, digit, t;
122
123         n = initial_n;
124         out = i = 0;
125         bias = initial_bias;
126
127         for (b = j = 0; j < input_length; ++j)
128                 if (input[j] == '-')
129                         b = j;
130
131         if (b > max_out)
132                 return -1;
133
134         for (j = 0;  j < b;  ++j) {
135                 if (input[j] & 0x80)
136                         return -1;
137                 output[out++] = input[j];
138         }
139
140         for (in = b > 0 ? b + 1 : 0; in < input_length; ++out) {
141                 for (oldi = i, w = 1, k = base;; k += base) {
142                         if (in >= input_length)
143                                 return -1;
144                         digit = decode_digit(input[in++]);
145                         if (digit >= base)
146                                 return -1;
147                         if (digit > (maxint - i) / w)
148                                 return -1;
149                         i += digit * w;
150                         if (k <= bias)
151                                 t = tmin;
152                         else if (k >= bias + tmax)
153                                 t = tmax;
154                         else
155                                 t = k - bias;
156                         if (digit < t)
157                                 break;
158                         if (w > maxint / (base - t))
159                                 return -1;
160                         w *= (base - t);
161                 }
162
163                 bias = adapt(i - oldi, out + 1, oldi == 0);
164
165                 if (i / (out + 1) > maxint - n)
166                         return -1;
167                 n += i / (out + 1);
168                 i %= (out + 1);
169
170                 if (out >= max_out)
171                         return -1;
172
173                 memmove(output + i + 1, output + i, (out - i) * sizeof *output);
174                 if(((uint)input[in-1] - 'A') < 26)
175                         output[i++] = toupperrune(n);
176                 else
177                         output[i++] = tolowerrune(n);
178         }
179
180         return (int)out;
181 }
182
183 /*
184  * convert punycode encoded internationalized
185  * domain name to unicode string
186  */
187 char*
188 idn2utf(char *name, char *buf, int nbuf)
189 {
190         char *dp, *de, *cp;
191         Rune rb[Domlen], r;
192         int nc, nr, n;
193
194         cp = name;
195         dp = buf;
196         de = dp+nbuf-1;
197         for(;;){
198                 nc = nr = 0;
199                 while(cp[nc] != 0){
200                         n = chartorune(&r, cp+nc);
201                         if(r == '.')
202                                 break;
203                         rb[nr++] = r;
204                         nc += n;
205                 }
206                 if(cistrncmp(cp, "xn--", 4) == 0)
207                         if((nr = punydecode(nc-4, cp+4, nelem(rb), rb)) < 0)
208                                 return nil;
209                 dp = seprint(dp, de, "%.*S", nr, rb);
210                 if(dp >= de)
211                         return nil;
212                 if(cp[nc] == 0)
213                         break;
214                 *dp++ = '.';
215                 cp += nc+1;
216         }
217         *dp = 0;
218         return buf;
219 }
220
221 /*
222  * convert unicode string to punycode
223  * encoded internationalized domain name
224  */
225 char*
226 utf2idn(char *name, char *buf, int nbuf)
227 {
228         char *dp, *de, *cp;
229         Rune rb[Domlen], r;
230         int nc, nr, n;
231
232         dp = buf;
233         de = dp+nbuf-1;
234         cp = name;
235         for(;;){
236                 nc = nr = 0;
237                 while(cp[nc] != 0 && nr < nelem(rb)){
238                         n = chartorune(&r, cp+nc);
239                         if(r == '.')
240                                 break;
241                         rb[nr++] = r;
242                         nc += n;
243                 }
244                 if(nc == nr)
245                         dp = seprint(dp, de, "%.*s", nc, cp);
246                 else {
247                         dp = seprint(dp, de, "xn--");
248                         if((n = punyencode(nr, rb, de - dp, dp)) < 0)
249                                 return nil;
250                         dp += n;
251                 }
252                 if(dp >= de)
253                         return nil;
254                 if(cp[nc] == 0)
255                         break;
256                 *dp++ = '.';
257                 cp += nc+1;
258         }
259         *dp = 0;
260         return buf;
261 }
262