1 23 24 package org.jivesoftware.stringprep; 25 26 class Punycode 27 { 28 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 44 public static String encode(String input) 45 throws PunycodeException 46 { 47 int n = INITIAL_N; 48 int delta = 0; 49 int bias = INITIAL_BIAS; 50 StringBuilder output = new StringBuilder (); 51 52 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 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 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 132 public static String decode(String input) 133 throws PunycodeException 134 { 135 int n = INITIAL_N; 136 int i = 0; 137 int bias = INITIAL_BIAS; 138 StringBuilder output = new StringBuilder (); 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 return d + 'a'; 229 } else if (d < 36) { 230 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 return c - '0' + 26; 243 } else if (c - 'a' < 26) { 244 return c - 'a'; 246 } else { 247 throw new PunycodeException(PunycodeException.BAD_INPUT); 248 } 249 } 250 } | Popular Tags |