diff options
author | Elliott Hughes <enh@google.com> | 2009-11-03 15:52:10 -0800 |
---|---|---|
committer | Elliott Hughes <enh@google.com> | 2009-11-03 15:52:10 -0800 |
commit | b7bfb47e9720ecc6e10f43878f27e40542a9c800 (patch) | |
tree | 27e5dbbe6c2d4aa95b4d5a3e17b5d68200c309ec | |
parent | 538eac4977156a74e8a055d793097256efa0fba4 (diff) | |
download | libcore-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
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()); |