1 /* 2 * ==================================================================== 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * ==================================================================== 20 * 21 * This software consists of voluntary contributions made by many 22 * individuals on behalf of the Apache Software Foundation. For more 23 * information on the Apache Software Foundation, please see 24 * <http://www.apache.org/>. 25 * 26 */ 27 package ch.boye.httpclientandroidlib.client.utils; 28 29 import java.util.StringTokenizer; 30 31 import ch.boye.httpclientandroidlib.annotation.Immutable; 32 33 /** 34 * Implementation from pseudo code in RFC 3492. 35 * 36 * @since 4.0 37 */ 38 @Immutable 39 public class Rfc3492Idn implements Idn { 40 private static final int base = 36; 41 private static final int tmin = 1; 42 private static final int tmax = 26; 43 private static final int skew = 38; 44 private static final int damp = 700; 45 private static final int initial_bias = 72; 46 private static final int initial_n = 128; 47 private static final char delimiter = '-'; 48 private static final String ACE_PREFIX = "xn--"; 49 adapt(final int delta, final int numpoints, final boolean firsttime)50 private int adapt(final int delta, final int numpoints, final boolean firsttime) { 51 int d = delta; 52 if (firsttime) { 53 d = d / damp; 54 } else { 55 d = d / 2; 56 } 57 d = d + (d / numpoints); 58 int k = 0; 59 while (d > ((base - tmin) * tmax) / 2) { 60 d = d / (base - tmin); 61 k = k + base; 62 } 63 return k + (((base - tmin + 1) * d) / (d + skew)); 64 } 65 digit(final char c)66 private int digit(final char c) { 67 if ((c >= 'A') && (c <= 'Z')) { 68 return (c - 'A'); 69 } 70 if ((c >= 'a') && (c <= 'z')) { 71 return (c - 'a'); 72 } 73 if ((c >= '0') && (c <= '9')) { 74 return (c - '0') + 26; 75 } 76 throw new IllegalArgumentException("illegal digit: "+ c); 77 } 78 toUnicode(final String punycode)79 public String toUnicode(final String punycode) { 80 final StringBuilder unicode = new StringBuilder(punycode.length()); 81 final StringTokenizer tok = new StringTokenizer(punycode, "."); 82 while (tok.hasMoreTokens()) { 83 String t = tok.nextToken(); 84 if (unicode.length() > 0) { 85 unicode.append('.'); 86 } 87 if (t.startsWith(ACE_PREFIX)) { 88 t = decode(t.substring(4)); 89 } 90 unicode.append(t); 91 } 92 return unicode.toString(); 93 } 94 decode(final String s)95 protected String decode(final String s) { 96 String input = s; 97 int n = initial_n; 98 int i = 0; 99 int bias = initial_bias; 100 final StringBuilder output = new StringBuilder(input.length()); 101 final int lastdelim = input.lastIndexOf(delimiter); 102 if (lastdelim != -1) { 103 output.append(input.subSequence(0, lastdelim)); 104 input = input.substring(lastdelim + 1); 105 } 106 107 while (input.length() > 0) { 108 final int oldi = i; 109 int w = 1; 110 for (int k = base;; k += base) { 111 if (input.length() == 0) { 112 break; 113 } 114 final char c = input.charAt(0); 115 input = input.substring(1); 116 final int digit = digit(c); 117 i = i + digit * w; // FIXME fail on overflow 118 final int t; 119 if (k <= bias + tmin) { 120 t = tmin; 121 } else if (k >= bias + tmax) { 122 t = tmax; 123 } else { 124 t = k - bias; 125 } 126 if (digit < t) { 127 break; 128 } 129 w = w * (base - t); // FIXME fail on overflow 130 } 131 bias = adapt(i - oldi, output.length() + 1, (oldi == 0)); 132 n = n + i / (output.length() + 1); // FIXME fail on overflow 133 i = i % (output.length() + 1); 134 // {if n is a basic code point then fail} 135 output.insert(i, (char) n); 136 i++; 137 } 138 return output.toString(); 139 } 140 141 } 142