summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorElliott Hughes <enh@google.com>2009-11-03 15:52:10 -0800
committerElliott Hughes <enh@google.com>2009-11-03 15:52:10 -0800
commitb7bfb47e9720ecc6e10f43878f27e40542a9c800 (patch)
tree27e5dbbe6c2d4aa95b4d5a3e17b5d68200c309ec
parent538eac4977156a74e8a055d793097256efa0fba4 (diff)
downloadlibcore-b7bfb47e9720ecc6e10f43878f27e40542a9c800.zip
libcore-b7bfb47e9720ecc6e10f43878f27e40542a9c800.tar.gz
libcore-b7bfb47e9720ecc6e10f43878f27e40542a9c800.tar.bz2
CharsetDecoderICU/CharsetEncoderICU should take arrayOffset into account.
CharsetDecoderICU and CharsetEncoderICU special-case array-backed ByteBuffers and CharBuffers for performance reasons, but they shouldn't assume that the backing array always has offset 0. An external user hit this while using the jAudioTagger library. Test cases from user submission: http://code.google.com/p/android/issues/detail?id=4237 See also: 2234697
-rw-r--r--icu/src/main/java/com/ibm/icu4jni/charset/CharsetDecoderICU.java16
-rw-r--r--icu/src/main/java/com/ibm/icu4jni/charset/CharsetEncoderICU.java16
-rw-r--r--luni/src/test/java/java/nio/charset/AllTests.java28
-rw-r--r--luni/src/test/java/java/nio/charset/CharsetDecoderTest.java85
-rw-r--r--luni/src/test/java/tests/AllTests.java1
5 files changed, 136 insertions, 10 deletions
diff --git a/icu/src/main/java/com/ibm/icu4jni/charset/CharsetDecoderICU.java b/icu/src/main/java/com/ibm/icu4jni/charset/CharsetDecoderICU.java
index 919d865..9c74d68 100644
--- a/icu/src/main/java/com/ibm/icu4jni/charset/CharsetDecoderICU.java
+++ b/icu/src/main/java/com/ibm/icu4jni/charset/CharsetDecoderICU.java
@@ -286,9 +286,11 @@ public final class CharsetDecoderICU extends CharsetDecoder{
private final int getArray(CharBuffer out){
if(out.hasArray()){
+ // BEGIN android-changed: take arrayOffset into account
output = out.array();
- outEnd = out.limit();
- return out.position();
+ outEnd = out.arrayOffset() + out.limit();
+ return out.arrayOffset() + out.position();
+ // END android-changed
}else{
outEnd = out.remaining();
// BEGIN android-added
@@ -306,9 +308,11 @@ public final class CharsetDecoderICU extends CharsetDecoder{
}
private final int getArray(ByteBuffer in){
if(in.hasArray()){
+ // BEGIN android-changed: take arrayOffset into account
input = in.array();
- inEnd = in.limit();
- return in.position()+savedInputHeldLen;/*exclude the number fo bytes held in previous conversion*/
+ inEnd = in.arrayOffset() + in.limit();
+ return in.arrayOffset() + in.position() + savedInputHeldLen;/*exclude the number fo bytes held in previous conversion*/
+ // END android-changed
}else{
inEnd = in.remaining();
// BEGIN android-added
@@ -331,7 +335,9 @@ public final class CharsetDecoderICU extends CharsetDecoder{
}
private final void setPosition(CharBuffer out){
if(out.hasArray()){
- out.position(out.position() + data[OUTPUT_OFFSET]);
+ // BEGIN android-changed: take arrayOffset into account
+ out.position(out.position() + data[OUTPUT_OFFSET] - out.arrayOffset());
+ // END android-changed
}else{
out.put(output,0,data[OUTPUT_OFFSET]);
}
diff --git a/icu/src/main/java/com/ibm/icu4jni/charset/CharsetEncoderICU.java b/icu/src/main/java/com/ibm/icu4jni/charset/CharsetEncoderICU.java
index ec169f4..eada080 100644
--- a/icu/src/main/java/com/ibm/icu4jni/charset/CharsetEncoderICU.java
+++ b/icu/src/main/java/com/ibm/icu4jni/charset/CharsetEncoderICU.java
@@ -328,9 +328,11 @@ public final class CharsetEncoderICU extends CharsetEncoder {
//------------------------------------------
private final int getArray(ByteBuffer out) {
if(out.hasArray()){
+ // BEGIN android-changed: take arrayOffset into account
output = out.array();
- outEnd = out.limit();
- return out.position();
+ outEnd = out.arrayOffset() + out.limit();
+ return out.arrayOffset() + out.position();
+ // END android-changed
}else{
outEnd = out.remaining();
// BEGIN android-added
@@ -348,9 +350,11 @@ public final class CharsetEncoderICU extends CharsetEncoder {
private final int getArray(CharBuffer in) {
if(in.hasArray()){
+ // BEGIN android-changed: take arrayOffset into account
input = in.array();
- inEnd = in.limit();
- return in.position()+savedInputHeldLen;/*exclude the number fo bytes held in previous conversion*/
+ inEnd = in.arrayOffset() + in.limit();
+ return in.arrayOffset() + in.position() + savedInputHeldLen;/*exclude the number fo bytes held in previous conversion*/
+ // END android-changed
}else{
inEnd = in.remaining();
// BEGIN android-added
@@ -378,7 +382,9 @@ public final class CharsetEncoderICU extends CharsetEncoder {
// array backing the buffer directly and wrote to
// it, so just just set the position and return.
// This is done to avoid the creation of temp array.
- out.position(out.position() + data[OUTPUT_OFFSET] );
+ // BEGIN android-changed: take arrayOffset into account
+ out.position(out.position() + data[OUTPUT_OFFSET] - out.arrayOffset());
+ // END android-changed
} else {
out.put(output, 0, data[OUTPUT_OFFSET]);
}
diff --git a/luni/src/test/java/java/nio/charset/AllTests.java b/luni/src/test/java/java/nio/charset/AllTests.java
new file mode 100644
index 0000000..6f45162
--- /dev/null
+++ b/luni/src/test/java/java/nio/charset/AllTests.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2009 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.nio.charset;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+public class AllTests {
+ public static final Test suite() {
+ TestSuite suite = tests.TestSuiteFactory.createTestSuite();
+ suite.addTestSuite(java.nio.charset.CharsetDecoderTest.class);
+ return suite;
+ }
+}
diff --git a/luni/src/test/java/java/nio/charset/CharsetDecoderTest.java b/luni/src/test/java/java/nio/charset/CharsetDecoderTest.java
new file mode 100644
index 0000000..23184dd
--- /dev/null
+++ b/luni/src/test/java/java/nio/charset/CharsetDecoderTest.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2009 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.nio.charset;
+
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+public class CharsetDecoderTest extends junit.framework.TestCase {
+ private static final String CHARSET = "UTF-16";
+
+ private static final String SAMPLE_STRING = "Android";
+
+ // http://code.google.com/p/android/issues/detail?id=4237
+ public void test_ByteArray_decode_no_offset() throws Exception {
+ CharsetDecoder decoder = getCharsetDecoderUnderTest();
+ byte[] arr = getEncodedByteArrayFixture();
+ ByteBuffer inBuffer = ByteBuffer.wrap(arr, 0, arr.length).slice();
+ CharBuffer outBuffer = CharBuffer.allocate(arr.length);
+ decoder.reset();
+ CoderResult coderResult = decoder.decode(inBuffer, outBuffer, true);
+ assertFalse(coderResult.toString(), coderResult.isError());
+ decoder.flush(outBuffer);
+ outBuffer.flip();
+ assertEquals(SAMPLE_STRING, outBuffer.toString().trim());
+ }
+
+ // http://code.google.com/p/android/issues/detail?id=4237
+ public void test_ByteArray_decode_with_offset() throws Exception {
+ CharsetDecoder decoder = getCharsetDecoderUnderTest();
+ byte[] arr = getEncodedByteArrayFixture();
+ arr = prependByteToByteArray(arr, new Integer(1).byteValue());
+ int offset = 1;
+ ByteBuffer inBuffer = ByteBuffer.wrap(arr, offset, arr.length - offset).slice();
+ CharBuffer outBuffer = CharBuffer.allocate(arr.length - offset);
+ decoder.reset();
+ CoderResult coderResult = decoder.decode(inBuffer, outBuffer, true);
+ assertFalse(coderResult.toString(), coderResult.isError());
+ decoder.flush(outBuffer);
+ outBuffer.flip();
+ assertEquals(SAMPLE_STRING, outBuffer.toString().trim());
+ }
+
+ // http://code.google.com/p/android/issues/detail?id=4237
+ public void test_ByteArray_decode_with_offset_using_facade_method() throws Exception {
+ CharsetDecoder decoder = getCharsetDecoderUnderTest();
+ byte[] arr = getEncodedByteArrayFixture();
+ arr = prependByteToByteArray(arr, new Integer(1).byteValue());
+ int offset = 1;
+ CharBuffer outBuffer = decoder.decode(ByteBuffer.wrap(arr, offset, arr.length - offset));
+ assertEquals(SAMPLE_STRING, outBuffer.toString().trim());
+ }
+
+ private static byte[] prependByteToByteArray(byte[] arr, byte b) {
+ byte[] result = new byte[arr.length + 1];
+ result[0] = b;
+ System.arraycopy(arr, 0, result, 1, arr.length);
+ return result;
+ }
+
+ private static CharsetDecoder getCharsetDecoderUnderTest() {
+ return Charset.forName(CHARSET).newDecoder();
+ }
+
+ private byte[] getEncodedByteArrayFixture() throws CharacterCodingException {
+ CharsetEncoder encoder = Charset.forName(CHARSET).newEncoder();
+ return encoder.encode(CharBuffer.wrap(SAMPLE_STRING)).array();
+ }
+}
diff --git a/luni/src/test/java/tests/AllTests.java b/luni/src/test/java/tests/AllTests.java
index d2799ec..c54d388 100644
--- a/luni/src/test/java/tests/AllTests.java
+++ b/luni/src/test/java/tests/AllTests.java
@@ -60,6 +60,7 @@ public class AllTests
suite.addTest(java.lang.AllTests.suite());
suite.addTest(java.lang.reflect.AllTests.suite());
suite.addTest(java.net.AllTests.suite());
+ suite.addTest(java.nio.charset.AllTests.suite());
suite.addTest(org.apache.harmony.luni.platform.AllTests.suite());
suite.addTest(tests.api.org.apache.harmony.kernel.dalvik.AllTests.suite());