summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorElliott Hughes <enh@google.com>2010-04-01 11:15:14 -0700
committerAndroid (Google) Code Review <android-gerrit@google.com>2010-04-01 11:15:14 -0700
commitf072c0384c0b12f081fb99bc365d284ae6381379 (patch)
tree80bb4f4c1bb7b1410b4e1479f427620999e2690e
parentde816ccf0d96c9fd9a042f4f8beaafee86ca02e7 (diff)
parent79179d5284bdc6854d1366226d26eec8b766d1ac (diff)
downloadlibcore-f072c0384c0b12f081fb99bc365d284ae6381379.zip
libcore-f072c0384c0b12f081fb99bc365d284ae6381379.tar.gz
libcore-f072c0384c0b12f081fb99bc365d284ae6381379.tar.bz2
Merge "Add Java 6's java.net.IDN." into dalvik-dev
-rw-r--r--icu/src/main/java/com/ibm/icu4jni/text/NativeIDN.java44
-rw-r--r--icu/src/main/native/NativeIDN.cpp64
-rw-r--r--icu/src/main/native/NativeNormalizer.cpp2
-rw-r--r--icu/src/main/native/sub.mk1
-rw-r--r--luni/src/main/java/java/net/IDN.java105
-rw-r--r--luni/src/test/java/java/net/AllTests.java1
-rw-r--r--luni/src/test/java/java/net/IDNTest.java40
-rw-r--r--luni/src/test/java/tests/api/java/net/AllTests.java3
-rw-r--r--luni/src/test/java/tests/api/java/net/IDNTest.java160
9 files changed, 418 insertions, 2 deletions
diff --git a/icu/src/main/java/com/ibm/icu4jni/text/NativeIDN.java b/icu/src/main/java/com/ibm/icu4jni/text/NativeIDN.java
new file mode 100644
index 0000000..b973131
--- /dev/null
+++ b/icu/src/main/java/com/ibm/icu4jni/text/NativeIDN.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.ibm.icu4jni.text;
+
+public class NativeIDN {
+ public static String toASCII(String s, int flags) {
+ return convert(s, flags, true);
+ }
+
+ public static String toUnicode(String s, int flags) {
+ try {
+ return convert(s, flags, false);
+ } catch (IllegalArgumentException ex) {
+ // The RI documentation explicitly states that this method can't fail.
+ // ICU4C disagrees, as does the RI in practice.
+ // The RI just returns the input string if it can't
+ return s;
+ }
+ }
+
+ private static String convert(String s, int flags, boolean toAscii) {
+ if (s == null) {
+ throw new NullPointerException();
+ }
+ return convertImpl(s, flags, toAscii);
+ }
+ private static native String convertImpl(String s, int flags, boolean toAscii);
+
+ private NativeIDN() {}
+}
diff --git a/icu/src/main/native/NativeIDN.cpp b/icu/src/main/native/NativeIDN.cpp
new file mode 100644
index 0000000..5ce3e94
--- /dev/null
+++ b/icu/src/main/native/NativeIDN.cpp
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ErrorCode.h"
+#include "JNIHelp.h"
+#include "ScopedJavaUnicodeString.h"
+#include "unicode/uidna.h"
+
+static bool isLabelSeparator(const UChar ch) {
+ switch (ch) {
+ case 0x3002: // ideographic full stop
+ case 0xff0e: // fullwidth full stop
+ case 0xff61: // halfwidth ideographic full stop
+ return true;
+ default:
+ return false;
+ }
+}
+
+static jstring convertImpl(JNIEnv* env, jclass, jstring s, jint flags, jboolean toAscii) {
+ ScopedJavaUnicodeString sus(env, s);
+ const UChar* src = sus.unicodeString().getBuffer();
+ const size_t srcLength = sus.unicodeString().length();
+ UChar dst[256];
+ UErrorCode status = U_ZERO_ERROR;
+ int32_t resultLength = toAscii
+ ? uidna_IDNToASCII(src, srcLength, &dst[0], sizeof(dst), flags, NULL, &status)
+ : uidna_IDNToUnicode(src, srcLength, &dst[0], sizeof(dst), flags, NULL, &status);
+ if (U_FAILURE(status)) {
+ jniThrowException(env, "java/lang/IllegalArgumentException", u_errorName(status));
+ return NULL;
+ }
+ if (!toAscii) {
+ // ICU only translates separators to ASCII for toASCII.
+ // Java expects the translation for toUnicode too.
+ // We may as well do this here, while the string is still mutable.
+ for (size_t i = 0; i < resultLength; ++i) {
+ if (isLabelSeparator(dst[i])) {
+ dst[i] = '.';
+ }
+ }
+ }
+ return env->NewString(&dst[0], resultLength);
+}
+
+static JNINativeMethod gMethods[] = {
+ {"convertImpl", "(Ljava/lang/String;IZ)Ljava/lang/String;", (void*) convertImpl},
+};
+extern "C" int register_com_ibm_icu4jni_text_NativeIDN(JNIEnv* env) {
+ return jniRegisterNativeMethods(env, "com/ibm/icu4jni/text/NativeIDN", gMethods, NELEM(gMethods));
+}
diff --git a/icu/src/main/native/NativeNormalizer.cpp b/icu/src/main/native/NativeNormalizer.cpp
index b09b26e..0aa7d29 100644
--- a/icu/src/main/native/NativeNormalizer.cpp
+++ b/icu/src/main/native/NativeNormalizer.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2006 The Android Open Source Project
+ * Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/icu/src/main/native/sub.mk b/icu/src/main/native/sub.mk
index b101531..f72db1b 100644
--- a/icu/src/main/native/sub.mk
+++ b/icu/src/main/native/sub.mk
@@ -9,6 +9,7 @@ LOCAL_SRC_FILES := \
NativeCollation.cpp \
NativeConverter.cpp \
NativeDecimalFormat.cpp \
+ NativeIDN.cpp \
NativeNormalizer.cpp \
NativeRegEx.cpp \
Resources.cpp \
diff --git a/luni/src/main/java/java/net/IDN.java b/luni/src/main/java/java/net/IDN.java
new file mode 100644
index 0000000..51cebeb
--- /dev/null
+++ b/luni/src/main/java/java/net/IDN.java
@@ -0,0 +1,105 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package java.net;
+
+import com.ibm.icu4jni.text.NativeIDN;
+
+/**
+ * Converts internationalized domain names between Unicode and the ASCII Compatible Encoding
+ * (ACE) representation.
+ *
+ * <p>See <a href="http://www.ietf.org/rfc/rfc3490.txt">RFC 3490</a> for full details.
+ *
+ * @since 1.6
+ * @hide
+ */
+public final class IDN {
+ /**
+ * When set, allows IDN to process unassigned unicode points.
+ */
+ public static final int ALLOW_UNASSIGNED = 1;
+
+ /**
+ * When set, ASCII strings are checked against RFC 1122 & RFC 1123.
+ */
+ public static final int USE_STD3_ASCII_RULES = 2;
+
+ private IDN() {
+ }
+
+ /**
+ * Transform a Unicode String to ASCII Compatible Encoding String according
+ * to the algorithm defined in RFC 3490.
+ *
+ * <p>If the transformation fails (because the input is not a valid IDN), an
+ * exception will be thrown.
+ *
+ * <p>This method can handle either an individual label or an entire domain name.
+ * In the latter case, the separators are: U+002E (full stop), U+3002 (ideographic full stop),
+ * U+FF0E (fullwidth full stop), and U+FF61 (halfwidth ideographic full stop).
+ * All of these will become U+002E (full stop) in the result.
+ *
+ * @param input the Unicode name
+ * @param flags 0, {@code ALLOW_UNASSIGNED}, {@code USE_STD3_ASCII_RULES},
+ * or {@code ALLOW_UNASSIGNED | USE_STD3_ASCII_RULES}
+ * @return the ACE name
+ * @throws IllegalArgumentException if {@code input} does not conform to RFC 3490
+ */
+ public static String toASCII(String input, int flags) {
+ return NativeIDN.toASCII(input, flags);
+ }
+
+ /**
+ * Equivalent to {@code toASCII(input, 0)}.
+ *
+ * @param input the Unicode name
+ * @return the ACE name
+ * @throws IllegalArgumentException if {@code input} does not conform to RFC 3490
+ */
+ public static String toASCII(String input) {
+ return toASCII(input, 0);
+ }
+
+ /**
+ * Translates a string from ASCII Compatible Encoding (ACE) to Unicode
+ * according to the algorithm defined in RFC 3490.
+ *
+ * <p>Unlike {@code toASCII}, this transformation cannot fail.
+ *
+ * <p>This method can handle either an individual label or an entire domain name.
+ * In the latter case, the separators are: U+002E (full stop), U+3002 (ideographic full stop),
+ * U+FF0E (fullwidth full stop), and U+FF61 (halfwidth ideographic full stop).
+ *
+ * @param input the ACE name
+ * @return the Unicode name
+ * @param flags 0, {@code ALLOW_UNASSIGNED}, {@code USE_STD3_ASCII_RULES},
+ * or {@code ALLOW_UNASSIGNED | USE_STD3_ASCII_RULES}
+ */
+ public static String toUnicode(String input, int flags) {
+ return NativeIDN.toUnicode(input, flags);
+ }
+
+ /**
+ * Equivalent to {@code toUnicode(input, 0)}.
+ *
+ * @param input the ACE name
+ * @return the Unicode name
+ */
+ public static String toUnicode(String input) {
+ return NativeIDN.toUnicode(input, 0);
+ }
+}
diff --git a/luni/src/test/java/java/net/AllTests.java b/luni/src/test/java/java/net/AllTests.java
index 664d755..dbfb3e4 100644
--- a/luni/src/test/java/java/net/AllTests.java
+++ b/luni/src/test/java/java/net/AllTests.java
@@ -22,6 +22,7 @@ import junit.framework.TestSuite;
public class AllTests {
public static final Test suite() {
TestSuite suite = new TestSuite();
+ suite.addTestSuite(java.net.IDNTest.class);
suite.addTestSuite(java.net.SocketTest.class);
suite.addTestSuite(java.net.URLConnectionTest.class);
return suite;
diff --git a/luni/src/test/java/java/net/IDNTest.java b/luni/src/test/java/java/net/IDNTest.java
new file mode 100644
index 0000000..5a9bf8a
--- /dev/null
+++ b/luni/src/test/java/java/net/IDNTest.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package java.net;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+public class IDNTest extends junit.framework.TestCase {
+ private static String makePunyString(int xCount) {
+ StringBuilder s = new StringBuilder();
+ s.append("xn--bcher");
+ for (int i = 0; i < xCount; ++i) {
+ s.append('x');
+ }
+ s.append("-kva");
+ return s.toString();
+ }
+
+ public void test_toUnicode_failures() {
+ // This is short enough to work...
+ assertEquals("b\u00fccher", IDN.toUnicode(makePunyString(0)));
+ // This is too long, and the RI just returns the input string...
+ String longInput = makePunyString(512);
+ assertEquals(longInput, IDN.toUnicode(longInput));
+ }
+}
diff --git a/luni/src/test/java/tests/api/java/net/AllTests.java b/luni/src/test/java/tests/api/java/net/AllTests.java
index 2d9921d..257a166 100644
--- a/luni/src/test/java/tests/api/java/net/AllTests.java
+++ b/luni/src/test/java/tests/api/java/net/AllTests.java
@@ -41,7 +41,8 @@ public class AllTests {
suite.addTestSuite(DatagramSocketTest.class);
suite.addTestSuite(ExcludedProxyTest.class);
suite.addTestSuite(FileNameMapTest.class);
- suite.addTestSuite(HttpRetryExceptionTest.class);
+ suite.addTestSuite(HttpRetryExceptionTest.class);
+ suite.addTestSuite(IDNTest.class);
suite.addTestSuite(JarURLConnectionTest.class);
suite.addTestSuite(MalformedURLExceptionTest.class);
suite.addTestSuite(MulticastSocketTest.class);
diff --git a/luni/src/test/java/tests/api/java/net/IDNTest.java b/luni/src/test/java/tests/api/java/net/IDNTest.java
new file mode 100644
index 0000000..7ea209c
--- /dev/null
+++ b/luni/src/test/java/tests/api/java/net/IDNTest.java
@@ -0,0 +1,160 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package tests.api.java.net;
+
+import java.net.IDN;
+
+import junit.framework.TestCase;
+
+public class IDNTest extends TestCase {
+
+ /**
+ * @tests {@link java.net.IDN#toASCII(String)}
+ *
+ * @since 1.6
+ */
+ public void test_ToASCII_LString() {
+ try {
+ IDN.toASCII(null);
+ fail("should throw NullPointerException");
+ } catch (NullPointerException e) {
+ // expected
+ }
+
+ try {
+ IDN.toASCII("www.m\uE400kitorppa.edu");
+ fail("should throw IllegalArgumentException");
+ } catch (IllegalArgumentException e) {
+ // expected
+ }
+
+ try {
+ IDN.toASCII("www.\u672C\uFE73\uFFFF.jp");
+ fail("should throw IllegalArgumentException");
+ } catch (IllegalArgumentException e) {
+ // expected
+ }
+
+ assertEquals("www.xn--gwtq9nb2a.jp", IDN
+ .toASCII("www.\u65E5\u672C\u5E73.jp"));
+ assertEquals(
+ "www.xn--vckk7bxa0eza9ezc9d.com",
+ IDN
+ .toASCII("www.\u30CF\u30F3\u30C9\u30DC\u30FC\u30EB\u30B5\u30E0\u30BA.com"));
+ assertEquals("www.xn--frgbolaget-q5a.nu", IDN
+ .toASCII("www.f\u00E4rgbolaget.nu"));
+ assertEquals("www.xn--bcher-kva.de", IDN.toASCII("www.b\u00FCcher.de"));
+ assertEquals("www.xn--brndendekrlighed-vobh.com", IDN
+ .toASCII("www.br\u00E6ndendek\u00E6rlighed.com"));
+ assertEquals("www.xn--rksmrgs-5wao1o.se", IDN
+ .toASCII("www.r\u00E4ksm\u00F6rg\u00E5s.se"));
+ assertEquals("www.xn--9d0bm53a3xbzui.com", IDN
+ .toASCII("www.\uC608\uBE44\uAD50\uC0AC.com"));
+ assertEquals("xn--lck1c3crb1723bpq4a.com", IDN
+ .toASCII("\u7406\u5BB9\u30CA\u30AB\u30E0\u30E9.com"));
+ assertEquals("xn--l8je6s7a45b.org", IDN
+ .toASCII("\u3042\u30FC\u308B\u3044\u3093.org"));
+ assertEquals("www.xn--frjestadsbk-l8a.net", IDN
+ .toASCII("www.f\u00E4rjestadsbk.net"));
+ assertEquals("www.xn--mkitorppa-v2a.edu", IDN
+ .toASCII("www.m\u00E4kitorppa.edu"));
+ }
+
+ /**
+ * @tests {@link java.net.IDN#toASCII(String, int)}
+ *
+ * @since 1.6
+ */
+ public void test_ToASCII_LString_I() {
+ try {
+ IDN.toASCII("www.br\u00E6ndendek\u00E6rlighed.com",
+ IDN.USE_STD3_ASCII_RULES);
+ } catch (IllegalArgumentException e) {
+ // expected
+ }
+
+ try {
+ IDN.toASCII("www.r\u00E4ksm\u00F6rg\u00E5s.se",
+ IDN.USE_STD3_ASCII_RULES);
+ } catch (IllegalArgumentException e) {
+ // expected
+ }
+
+ try {
+ IDN.toASCII("www.f\u00E4rjestadsbk.net", IDN.ALLOW_UNASSIGNED
+ | IDN.USE_STD3_ASCII_RULES);
+ } catch (IllegalArgumentException e) {
+ // expected
+ }
+
+ assertEquals("www.xn--gwtq9nb2a.jp", IDN.toASCII(
+ "www.\u65E5\u672C\u5E73.jp", 0));
+ assertEquals(
+ "www.xn--vckk7bxa0eza9ezc9d.com",
+ IDN
+ .toASCII(
+ "www.\u30CF\u30F3\u30C9\u30DC\u30FC\u30EB\u30B5\u30E0\u30BA.com",
+ 0));
+ assertEquals("www.xn--frgbolaget-q5a.nu", IDN.toASCII(
+ "www.f\u00E4rgbolaget.nu", IDN.ALLOW_UNASSIGNED));
+ assertEquals("www.xn--bcher-kva.de", IDN.toASCII("www.b\u00FCcher.de",
+ IDN.ALLOW_UNASSIGNED));
+ assertEquals("www.google.com", IDN.toASCII("www.google\u002Ecom",
+ IDN.USE_STD3_ASCII_RULES));
+ }
+
+ /**
+ * @tests {@link java.net.IDN#toUnicode(String)}
+ *
+ * @since 1.6
+ */
+ public void test_ToUnicode_LString() {
+ try {
+ IDN.toUnicode(null);
+ fail("should throw NullPointerException");
+ } catch (NullPointerException e) {
+ // expected
+ }
+
+ assertEquals("", IDN.toUnicode(""));
+ assertEquals("www.bcher.de", IDN.toUnicode("www.bcher.de"));
+ assertEquals("www.b\u00FCcher.de", IDN.toUnicode("www.b\u00FCcher.de"));
+ assertEquals("www.\u65E5\u672C\u5E73.jp", IDN
+ .toUnicode("www.\u65E5\u672C\u5E73.jp"));
+ assertEquals("www.\u65E5\u672C\u5E73.jp", IDN.toUnicode("www\uFF0Exn--gwtq9nb2a\uFF61jp"));
+ assertEquals("www.\u65E5\u672C\u5E73.jp", IDN.toUnicode("www.xn--gwtq9nb2a.jp"));
+ }
+
+ /**
+ * @tests {@link java.net.IDN#toUnicode(String, int)}
+ *
+ * @since 1.6
+ */
+ public void test_ToUnicode_LString_I() {
+ assertEquals("", IDN.toUnicode("", IDN.ALLOW_UNASSIGNED));
+ assertEquals("www.f\u00E4rgbolaget.nu", IDN.toUnicode(
+ "www.f\u00E4rgbolaget.nu", IDN.USE_STD3_ASCII_RULES));
+ assertEquals("www.r\u00E4ksm\u00F6rg\u00E5s.nu", IDN.toUnicode(
+ "www.r\u00E4ksm\u00F6rg\u00E5s\u3002nu",
+ IDN.USE_STD3_ASCII_RULES));
+ // RI bug. It cannot parse "www.xn--gwtq9nb2a.jp" when
+ // USE_STD3_ASCII_RULES is set.
+ assertEquals("www.\u65E5\u672C\u5E73.jp", IDN.toUnicode(
+ "www\uFF0Exn--gwtq9nb2a\uFF61jp", IDN.USE_STD3_ASCII_RULES));
+
+ }
+}