org.bouncycastle.jsse.provider.IDNUtil Maven / Gradle / Ivy
The newest version!
package org.bouncycastle.jsse.provider;
import java.lang.reflect.Method;
public class IDNUtil
{
public static final int ALLOW_UNASSIGNED;
public static final int USE_STD3_ASCII_RULES;
private static final Method toASCIIMethod;
private static final Method toUnicodeMethod;
private static final String IDN_CLASSNAME = "java.net.IDN";
// private static final String ACE_PREFIX = "xn--";
private static final int MAX_LABEL_LENGTH = 63;
static
{
ALLOW_UNASSIGNED = ReflectionUtil.getStaticIntOrDefault(IDN_CLASSNAME, "ALLOW_UNASSIGNED", 0x01);
USE_STD3_ASCII_RULES = ReflectionUtil.getStaticIntOrDefault(IDN_CLASSNAME, "USE_STD3_ASCII_RULES", 0x02);
toASCIIMethod = ReflectionUtil.getMethod(IDN_CLASSNAME, "toASCII", String.class, int.class);
toUnicodeMethod = ReflectionUtil.getMethod(IDN_CLASSNAME, "toUnicode", String.class, int.class);
}
public static String toASCII(String input, int flag)
{
if (null != toASCIIMethod)
{
return (String)ReflectionUtil.invokeMethod(null, toASCIIMethod, input, flag);
}
if (isRoot(input))
{
return ".";
}
StringBuilder result = new StringBuilder();
int len = input.length(), pos = 0, sepPos;
while (pos < len)
{
sepPos = findSeparator(input, pos);
String label = input.substring(pos, sepPos);
String asciiLabel = toAsciiLabel(label, flag);
result.append(asciiLabel);
if (sepPos < input.length())
{
result.append('.');
}
pos = sepPos + 1;
}
return result.toString();
}
public static String toUnicode(String input, int flag)
{
// NOTE: toUnicode should never fail; it is best effort
if (null != toUnicodeMethod)
{
return (String)ReflectionUtil.invokeMethod(null, toUnicodeMethod, input, flag);
}
if (isRoot(input))
{
return ".";
}
StringBuilder result = new StringBuilder();
int len = input.length(), pos = 0, sepPos;
while (pos < len)
{
sepPos = findSeparator(input, pos);
String label = input.substring(pos, sepPos);
String unicodeLabel = toUnicodeLabel(label, flag);
result.append(unicodeLabel);
if (sepPos < input.length())
{
result.append('.');
}
pos = sepPos + 1;
}
return result.toString();
}
private static int findSeparator(String s, int pos)
{
while (pos < s.length())
{
if (isSeparator(s.charAt(pos)))
{
break;
}
++pos;
}
return pos;
}
private static boolean isAllAscii(CharSequence s)
{
for (int i = 0; i < s.length(); ++i)
{
int c = s.charAt(i);
if (c >= 0x80)
{
return false;
}
}
return true;
}
private static boolean hasAnyNonLDHAscii(CharSequence s)
{
for (int i = 0; i < s.length(); ++i)
{
int ch = s.charAt(i);
if ((0x0000 <= ch && ch <= 0x002C) ||
(0x002E <= ch && ch <= 0x002F) ||
(0x003A <= ch && ch <= 0x0040) ||
(0x005B <= ch && ch <= 0x0060) ||
(0x007B <= ch && ch <= 0x007F))
{
return true;
}
}
return false;
}
private static boolean isRoot(String s)
{
return s.length() == 1 && isSeparator(s.charAt(0));
}
private static boolean isSeparator(char c)
{
switch (c)
{
case '.':
case '\u3002':
case '\uFF0E':
case '\uFF61':
return true;
default:
return false;
}
}
// private static boolean startsWithACEPrefix(CharSequence s)
// {
// int len = ACE_PREFIX.length();
// if (s.length() < len)
// {
// return false;
// }
// for (int i = 0; i < len; ++i)
// {
// char c = s.charAt(i);
// if (ACE_PREFIX.charAt(i) != toAsciiLower(c))
// {
// return false;
// }
// }
// return true;
// }
private static String toAsciiLabel(String s, int flag)
{
if (s.length() < 1)
{
throw new IllegalArgumentException("Domain name label cannot be empty");
}
boolean allAscii = isAllAscii(s);
if (!allAscii)
{
// TODO[jsse] Implement Nameprep and Punycode?
throw new UnsupportedOperationException("IDN support incomplete");
}
boolean useSTD3ASCIIRules = ((flag & USE_STD3_ASCII_RULES) != 0);
if (useSTD3ASCIIRules)
{
if (hasAnyNonLDHAscii(s))
{
throw new IllegalArgumentException("Domain name label cannot contain non-LDH characters");
}
if ('-' == s.charAt(0) || '-' == s.charAt(s.length() - 1))
{
throw new IllegalArgumentException("Domain name label cannot begin or end with a hyphen");
}
}
if (MAX_LABEL_LENGTH < s.length())
{
throw new IllegalArgumentException("Domain name label length cannot be more than " + MAX_LABEL_LENGTH);
}
return s;
}
// private static char toAsciiLower(char c)
// {
// if (c < 'A' || 'Z' < c)
// {
// return c;
// }
//
// return (char)(c - 'A' + 'a');
// }
// private static void toAsciiLower(CharSequence s, StringBuilder output)
// {
// int len = s.length();
// for (int i = 0; i < len; ++i)
// {
// char c = s.charAt(i);
// output.append(toAsciiLower(c));
// }
// }
private static String toUnicodeLabel(String s, int flag)
{
// TODO[jsse] Implement Nameprep and Punycode?
return s;
}
}