diff options
author | Elliott Hughes <enh@google.com> | 2010-04-01 11:15:14 -0700 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2010-04-01 11:15:14 -0700 |
commit | f072c0384c0b12f081fb99bc365d284ae6381379 (patch) | |
tree | 80bb4f4c1bb7b1410b4e1479f427620999e2690e | |
parent | de816ccf0d96c9fd9a042f4f8beaafee86ca02e7 (diff) | |
parent | 79179d5284bdc6854d1366226d26eec8b766d1ac (diff) | |
download | libcore-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.java | 44 | ||||
-rw-r--r-- | icu/src/main/native/NativeIDN.cpp | 64 | ||||
-rw-r--r-- | icu/src/main/native/NativeNormalizer.cpp | 2 | ||||
-rw-r--r-- | icu/src/main/native/sub.mk | 1 | ||||
-rw-r--r-- | luni/src/main/java/java/net/IDN.java | 105 | ||||
-rw-r--r-- | luni/src/test/java/java/net/AllTests.java | 1 | ||||
-rw-r--r-- | luni/src/test/java/java/net/IDNTest.java | 40 | ||||
-rw-r--r-- | luni/src/test/java/tests/api/java/net/AllTests.java | 3 | ||||
-rw-r--r-- | luni/src/test/java/tests/api/java/net/IDNTest.java | 160 |
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)); + + } +} |