Bump versions.
[libidn.git] / csharp / Punycode.cs
blob9b213dafc479aab1690d3220f75d16abfd4cb6db
1 /// <summary>
2 /// Copyright (C) 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
3 /// *
4 /// Author: Alexander Gnauck AG-Software
5 /// *
6 /// This file is part of GNU Libidn.
7 /// *
8 /// This program is free software; you can redistribute it and/or
9 /// modify it under the terms of the GNU General Public License as
10 /// published by the Free Software Foundation; either version 2 of the
11 /// License, or (at your option) any later version.
12 /// *
13 /// This program is distributed in the hope that it will be useful,
14 /// but WITHOUT ANY WARRANTY; without even the implied warranty of
15 /// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 /// General Public License for more details.
17 /// *
18 /// You should have received a copy of the GNU General Public License
19 /// along with this program; if not, write to the Free Software
20 /// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
21 /// 02111-1307 USA.
22 /// </summary>
24 using System;
26 namespace gnu.inet.encoding
29 public class Punycode
31 /* Punycode parameters */
32 internal const int TMIN = 1;
33 internal const int TMAX = 26;
34 internal const int BASE = 36;
35 internal const int INITIAL_N = 128;
36 internal const int INITIAL_BIAS = 72;
37 internal const int DAMP = 700;
38 internal const int SKEW = 38;
39 internal const char DELIMITER = '-';
41 /// <summary> Punycodes a unicode string.
42 /// *
43 /// </summary>
44 /// <param name="input">Unicode string.
45 /// </param>
46 /// <returns> Punycoded string.
47 ///
48 /// </returns>
49 public static System.String encode(System.String input)
51 int n = INITIAL_N;
52 int delta = 0;
53 int bias = INITIAL_BIAS;
54 System.Text.StringBuilder output = new System.Text.StringBuilder();
56 // Copy all basic code points to the output
57 int b = 0;
58 for (int i = 0; i < input.Length; i++)
60 char c = input[i];
61 if (isBasic(c))
63 output.Append(c);
64 b++;
68 // Append delimiter
69 if (b > 0)
71 output.Append(DELIMITER);
74 int h = b;
75 while (h < input.Length)
77 int m = System.Int32.MaxValue;
79 // Find the minimum code point >= n
80 for (int i = 0; i < input.Length; i++)
82 int c = input[i];
83 if (c >= n && c < m)
85 m = c;
89 if (m - n > (System.Int32.MaxValue - delta) / (h + 1))
91 throw new PunycodeException(PunycodeException.OVERFLOW);
93 delta = delta + (m - n) * (h + 1);
94 n = m;
96 for (int j = 0; j < input.Length; j++)
98 int c = input[j];
99 if (c < n)
101 delta++;
102 if (0 == delta)
104 throw new PunycodeException(PunycodeException.OVERFLOW);
107 if (c == n)
109 int q = delta;
111 for (int k = BASE; ; k += BASE)
113 int t;
114 if (k <= bias)
116 t = TMIN;
118 else if (k >= bias + TMAX)
120 t = TMAX;
122 else
124 t = k - bias;
126 if (q < t)
128 break;
130 output.Append((char) digit2codepoint(t + (q - t) % (BASE - t)));
131 q = (q - t) / (BASE - t);
134 output.Append((char) digit2codepoint(q));
135 bias = adapt(delta, h + 1, h == b);
136 delta = 0;
137 h++;
141 delta++;
142 n++;
145 return output.ToString();
148 /// <summary> Decode a punycoded string.
149 /// *
150 /// </summary>
151 /// <param name="input">Punycode string
152 /// </param>
153 /// <returns> Unicode string.
154 ///
155 /// </returns>
156 public static System.String decode(System.String input)
158 int n = INITIAL_N;
159 int i = 0;
160 int bias = INITIAL_BIAS;
161 System.Text.StringBuilder output = new System.Text.StringBuilder();
163 int d = input.LastIndexOf((System.Char) DELIMITER);
164 if (d > 0)
166 for (int j = 0; j < d; j++)
168 char c = input[j];
169 if (!isBasic(c))
171 throw new PunycodeException(PunycodeException.BAD_INPUT);
173 output.Append(c);
175 d++;
177 else
179 d = 0;
182 while (d < input.Length)
184 int oldi = i;
185 int w = 1;
187 for (int k = BASE; ; k += BASE)
189 if (d == input.Length)
191 throw new PunycodeException(PunycodeException.BAD_INPUT);
193 int c = input[d++];
194 int digit = codepoint2digit(c);
195 if (digit > (System.Int32.MaxValue - i) / w)
197 throw new PunycodeException(PunycodeException.OVERFLOW);
200 i = i + digit * w;
202 int t;
203 if (k <= bias)
205 t = TMIN;
207 else if (k >= bias + TMAX)
209 t = TMAX;
211 else
213 t = k - bias;
215 if (digit < t)
217 break;
219 w = w * (BASE - t);
222 bias = adapt(i - oldi, output.Length + 1, oldi == 0);
224 if (i / (output.Length + 1) > System.Int32.MaxValue - n)
226 throw new PunycodeException(PunycodeException.OVERFLOW);
229 n = n + i / (output.Length + 1);
230 i = i % (output.Length + 1);
231 // following overload is not supported on CF
232 //output.Insert(i,(char) n);
233 output.Insert(i, new char[1] { (char) n });
234 i++;
237 return output.ToString();
240 public static int adapt(int delta, int numpoints, bool first)
242 if (first)
244 delta = delta / DAMP;
246 else
248 delta = delta / 2;
251 delta = delta + (delta / numpoints);
253 int k = 0;
254 while (delta > ((BASE - TMIN) * TMAX) / 2)
256 delta = delta / (BASE - TMIN);
257 k = k + BASE;
260 return k + ((BASE - TMIN + 1) * delta) / (delta + SKEW);
263 public static bool isBasic(char c)
265 return c < 0x80;
268 public static int digit2codepoint(int d)
270 if (d < 26)
272 // 0..25 : 'a'..'z'
273 return d + 'a';
275 else if (d < 36)
277 // 26..35 : '0'..'9';
278 return d - 26 + '0';
280 else
282 throw new PunycodeException(PunycodeException.BAD_INPUT);
286 public static int codepoint2digit(int c)
288 if (c - '0' < 10)
290 // '0'..'9' : 26..35
291 return c - '0' + 26;
293 else if (c - 'a' < 26)
295 // 'a'..'z' : 0..25
296 return c - 'a';
298 else
300 throw new PunycodeException(PunycodeException.BAD_INPUT);