KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jivesoftware > stringprep > Punycode


1 /**
2  * Copyright (C) 2004 Free Software Foundation, Inc.
3  *
4  * Author: Oliver Hitz
5  *
6  * This file is part of GNU Libidn.
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public License
10  * as published by the Free Software Foundation; either version 2.1 of
11  * the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful, but
14  * WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
21  * USA
22  */

23
24 package org.jivesoftware.stringprep;
25
26 class Punycode
27 {
28   /* Punycode parameters */
29   final static int TMIN = 1;
30   final static int TMAX = 26;
31   final static int BASE = 36;
32   final static int INITIAL_N = 128;
33   final static int INITIAL_BIAS = 72;
34   final static int DAMP = 700;
35   final static int SKEW = 38;
36   final static char DELIMITER = '-';
37
38   /**
39    * Punycodes a unicode string.
40    *
41    * @param input Unicode string.
42    * @return Punycoded string.
43    */

44   public static String JavaDoc encode(String JavaDoc input)
45     throws PunycodeException
46   {
47     int n = INITIAL_N;
48     int delta = 0;
49     int bias = INITIAL_BIAS;
50     StringBuilder JavaDoc output = new StringBuilder JavaDoc();
51
52     // Copy all basic code points to the output
53
int b = 0;
54     for (int i = 0; i < input.length(); i++) {
55       char c = input.charAt(i);
56       if (isBasic(c)) {
57     output.append(c);
58     b++;
59       }
60     }
61
62     // Append delimiter
63
if (b > 0) {
64       output.append(DELIMITER);
65     }
66
67     int h = b;
68     while (h < input.length()) {
69       int m = Integer.MAX_VALUE;
70
71       // Find the minimum code point >= n
72
for (int i = 0; i < input.length(); i++) {
73     int c = input.charAt(i);
74     if (c >= n && c < m) {
75       m = c;
76     }
77       }
78
79       if (m - n > (Integer.MAX_VALUE - delta) / (h + 1)) {
80     throw new PunycodeException(PunycodeException.OVERFLOW);
81       }
82       delta = delta + (m - n) * (h + 1);
83       n = m;
84
85       for (int j = 0; j < input.length(); j++) {
86     int c = input.charAt(j);
87     if (c < n) {
88       delta++;
89       if (0 == delta) {
90         throw new PunycodeException(PunycodeException.OVERFLOW);
91       }
92     }
93     if (c == n) {
94       int q = delta;
95
96       for (int k = BASE;; k += BASE) {
97         int t;
98         if (k <= bias) {
99           t = TMIN;
100         } else if (k >= bias + TMAX) {
101           t = TMAX;
102         } else {
103           t = k - bias;
104         }
105         if (q < t) {
106           break;
107         }
108         output.append((char) digit2codepoint(t + (q - t) % (BASE - t)));
109         q = (q - t) / (BASE - t);
110       }
111
112       output.append((char) digit2codepoint(q));
113       bias = adapt(delta, h + 1, h == b);
114       delta = 0;
115       h++;
116     }
117       }
118
119       delta++;
120       n++;
121     }
122
123     return output.toString();
124   }
125
126   /**
127    * Decode a punycoded string.
128    *
129    * @param input Punycode string
130    * @return Unicode string.
131    */

132   public static String JavaDoc decode(String JavaDoc input)
133     throws PunycodeException
134   {
135     int n = INITIAL_N;
136     int i = 0;
137     int bias = INITIAL_BIAS;
138     StringBuilder JavaDoc output = new StringBuilder JavaDoc();
139
140     int d = input.lastIndexOf(DELIMITER);
141     if (d > 0) {
142       for (int j = 0; j < d; j++) {
143     char c = input.charAt(j);
144     if (!isBasic(c)) {
145       throw new PunycodeException(PunycodeException.BAD_INPUT);
146     }
147     output.append(c);
148       }
149       d++;
150     } else {
151       d = 0;
152     }
153
154     while (d < input.length()) {
155       int oldi = i;
156       int w = 1;
157
158       for (int k = BASE; ; k += BASE) {
159     if (d == input.length()) {
160       throw new PunycodeException(PunycodeException.BAD_INPUT);
161     }
162     int c = input.charAt(d++);
163     int digit = codepoint2digit(c);
164     if (digit > (Integer.MAX_VALUE - i) / w) {
165       throw new PunycodeException(PunycodeException.OVERFLOW);
166     }
167
168     i = i + digit * w;
169
170     int t;
171     if (k <= bias) {
172       t = TMIN;
173     } else if (k >= bias + TMAX) {
174       t = TMAX;
175     } else {
176       t = k - bias;
177     }
178     if (digit < t) {
179       break;
180     }
181     w = w * (BASE - t);
182       }
183
184       bias = adapt(i - oldi, output.length()+1, oldi == 0);
185
186       if (i / (output.length() + 1) > Integer.MAX_VALUE - n) {
187     throw new PunycodeException(PunycodeException.OVERFLOW);
188       }
189
190       n = n + i / (output.length() + 1);
191       i = i % (output.length() + 1);
192       output.insert(i, (char) n);
193       i++;
194     }
195
196     return output.toString();
197   }
198
199   public final static int adapt(int delta, int numpoints, boolean first)
200   {
201     if (first) {
202       delta = delta / DAMP;
203     } else {
204       delta = delta / 2;
205     }
206
207     delta = delta + (delta / numpoints);
208
209     int k = 0;
210     while (delta > ((BASE - TMIN) * TMAX) / 2) {
211       delta = delta / (BASE - TMIN);
212       k = k + BASE;
213     }
214
215     return k + ((BASE - TMIN + 1) * delta) / (delta + SKEW);
216   }
217
218   public final static boolean isBasic(char c)
219   {
220     return c < 0x80;
221   }
222
223   public final static int digit2codepoint(int d)
224     throws PunycodeException
225   {
226     if (d < 26) {
227       // 0..25 : 'a'..'z'
228
return d + 'a';
229     } else if (d < 36) {
230       // 26..35 : '0'..'9';
231
return d - 26 + '0';
232     } else {
233       throw new PunycodeException(PunycodeException.BAD_INPUT);
234     }
235   }
236
237   public final static int codepoint2digit(int c)
238     throws PunycodeException
239   {
240     if (c - '0' < 10) {
241       // '0'..'9' : 26..35
242
return c - '0' + 26;
243     } else if (c - 'a' < 26) {
244       // 'a'..'z' : 0..25
245
return c - 'a';
246     } else {
247       throw new PunycodeException(PunycodeException.BAD_INPUT);
248     }
249   }
250 }
Popular Tags