All Downloads are FREE. Search and download functionalities are using the official Maven repository.

java.net.IDN Maven / Gradle / Ivy

There is a newer version: 1.0.6
Show newest version
package java.net;

import java.util.Locale;

public class IDN {
  /* Punycode parameters */
  private static final int TMIN = 1;
  private static final int TMAX = 26;
  private static final int BASE = 36;
  private static final int INITIAL_N = 128;
  private static final int INITIAL_BIAS = 72;
  private static final int DAMP = 700;
  private static final int SKEW = 38;
  private static final char DELIMITER = '-';
  private static final String ACE_PREFIX = "xn--";

  public static String toASCII(final String input) {
    if (isOnlyASCII(input)) {
      return input;
    }
    if (input == null) {
      throw new IllegalArgumentException("input can not be null!");
    }
    return encodeDomain(input.toLowerCase(Locale.ENGLISH));
  }


  /**
   * Punycodes a unicode string.
   *
   * @param input Unicode string.
   * @return Punycoded string.
   */
  private static String encodeDomain(final String input) {
    final StringBuffer resultBuffer = new StringBuffer();
    final String[] domainParts = input.split("[\\.\\u3002\\uFF0E\\uFF61]");
    for (final String part : domainParts) {
      if (resultBuffer.length() > 0) {
        resultBuffer.append('.');
      }
      if (isOnlyASCII(part)) {
        resultBuffer.append(part);
      } else {
        final String encodedPart = encode(part);
        resultBuffer.append(ACE_PREFIX);
        resultBuffer.append(encodedPart);
      }
    }
    return resultBuffer.toString();
  }

  /**
   * Punycodes a unicode string.
   *
   * @param input Unicode string.
   * @return Punycoded string.
   */
  public static String encode(final String input) throws IllegalArgumentException {
    int n = INITIAL_N;
    int delta = 0;
    int bias = INITIAL_BIAS;
    final StringBuffer output = new StringBuffer();

    // Copy all basic code points to the output
    int b = 0;
    for (int i = 0; i < input.length(); i++) {
      final char c = input.charAt(i);
      final int charAsInt = c;
      if (charAsInt <= 0x9F && (charAsInt >= 0x7F || charAsInt >>> 5 == 0) || charAsInt > 55296) {
        throw new IllegalArgumentException("Bad input");
      } else if (isBasic(c)) {
        output.append(c);
        b++;
      }
    }

    // Append delimiter
    if (b > 0) {
      output.append(DELIMITER);
    }

    int h = b;
    while (h < input.length()) {
      int m = Integer.MAX_VALUE;

      // Find the minimum code point >= n
      for (int i = 0; i < input.length(); i++) {
        final int c = input.charAt(i);
        if (c >= n && c < m) {
          m = c;
        }
      }

      if (m - n > (Integer.MAX_VALUE - delta) / (h + 1)) {
        throw new IllegalArgumentException("overflow");
      }
      delta = delta + (m - n) * (h + 1);
      n = m;

      for (int j = 0; j < input.length(); j++) {
        final int c = input.charAt(j);
        if (c < n) {
          delta++;
          if (0 == delta) {
            throw new IllegalArgumentException("overflow");
          }
        }
        if (c == n) {
          int q = delta;

          for (int k = BASE;; k += BASE) {
            int t;
            if (k <= bias) {
              t = TMIN;
            } else if (k >= bias + TMAX) {
              t = TMAX;
            } else {
              t = k - bias;
            }
            if (q < t) {
              break;
            }
            output.append((char) digit2codepoint(t + (q - t) % (BASE - t)));
            q = (q - t) / (BASE - t);
          }

          output.append((char) digit2codepoint(q));
          bias = adapt(delta, h + 1, h == b);
          delta = 0;
          h++;
        }
      }

      delta++;
      n++;
    }

    return output.toString();
  }

  public final static int adapt(int delta, final int numpoints, final boolean first) {
    if (first) {
      delta = delta / DAMP;
    } else {
      delta = delta / 2;
    }

    delta = delta + delta / numpoints;

    int k = 0;
    while (delta > (BASE - TMIN) * TMAX / 2) {
      delta = delta / (BASE - TMIN);
      k = k + BASE;
    }

    return k + (BASE - TMIN + 1) * delta / (delta + SKEW);
  }

  private final static boolean isBasic(final char c) {
    return c < 0x80;
  }

  private final static int digit2codepoint(final int d) throws IllegalArgumentException {
    if (d < 26) {
      // 0..25 : 'a'..'z'
      return d + 'a';
    } else if (d < 36) {
      // 26..35 : '0'..'9';
      return d - 26 + '0';
    } else {
      throw new IllegalArgumentException("bad input");
    }
  }

  /*
   * Check if input contains only ASCII Treats null as all ASCII
   */
  private static boolean isOnlyASCII(final String input) {
    if (input == null) {
      return true;
    }
    for (int i = 0; i < input.length(); i++) {
      if (input.charAt(i) > 0x7F) {
        return false;
      }
    }
    return true;
  }

  public static String toUnicode(final String line) {
    return line;
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy