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