/* * 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 libcore.java.nio.charset; import java.nio.ByteBuffer; import java.nio.CharBuffer; import java.nio.charset.Charset; import java.nio.charset.CharsetDecoder; import java.nio.charset.CharsetEncoder; import junit.framework.TestCase; /* See bug http://b/1844104. * Checks for ICU encoder/decoder buffer corruption. */ public class OldCharsetEncoderDecoderBufferTest extends TestCase { /* Checks for a buffer corruption that happens in ICU * (CharsetDecoderICU) when a decode operation * is done first with an out-buffer with hasArray()==true, and next with an out-buffer with * hasArray()==false. In that situation ICU may overwrite the first out-buffer. */ public void testDecoderOutputBuffer() { CharsetDecoder decoder = Charset.forName("UTF-8").newDecoder(); char[] cBuf = new char[10]; CharBuffer out = CharBuffer.wrap(cBuf); assertTrue(out.hasArray()); decoder.decode(ByteBuffer.wrap(new byte[]{(byte)'a', (byte)'b', (byte)'c', (byte)'d'}), out, false); assertEquals("abcd", new String(cBuf, 0, 4)); assertEquals(0, cBuf[4]); assertEquals(0, cBuf[5]); byte[] bBuf = new byte[10]; out = ByteBuffer.wrap(bBuf).asCharBuffer(); assertFalse(out.hasArray()); decoder.decode(ByteBuffer.wrap(new byte[]{(byte)'x'}), out, true); assertEquals('x', bBuf[1]); assertEquals(0, bBuf[3]); // check if the first buffer was corrupted by the second decode assertEquals("abcd", new String(cBuf, 0, 4)); assertEquals(0, cBuf[4]); assertEquals(0, cBuf[5]); } /* Checks for a buffer corruption that happens in ICU * (CharsetDecoderICU) when a decode operation * is done first with an in-buffer with hasArray()==true, and next with an in-buffer with * hasArray()==false. In that situation ICU may overwrite the array of the first in-buffer. */ public void testDecoderInputBuffer() { CharsetDecoder decoder = Charset.forName("UTF-8").newDecoder(); CharBuffer out = CharBuffer.wrap(new char[10]); byte[] inArray = {(byte)'a', (byte)'b'}; ByteBuffer inWithArray = ByteBuffer.wrap(inArray); assertTrue(inWithArray.hasArray()); decoder.decode(inWithArray, out, false); assertEquals('a', inArray[0]); assertEquals('b', inArray[1]); // A read-only ByteBuffer must not expose its array. ByteBuffer inWithoutArray = ByteBuffer.wrap(new byte[] { (byte) 'x' }).asReadOnlyBuffer(); assertFalse(inWithoutArray.hasArray()); decoder.decode(inWithoutArray, out, true); // check whether the first buffer was corrupted by the second decode assertEquals('a', inArray[0]); assertEquals('b', inArray[1]); } /* Checks for a buffer corruption that happens in ICU * (CharsetEncoderICU) when an encode operation * is done first with an out-buffer with hasArray()==true, and next with an out-buffer with * hasArray()==false. In that situation ICU may overwrite the first out-buffer. */ public void testEncoderOutputBuffer() { CharsetEncoder encoder = Charset.forName("UTF-8").newEncoder(); byte[] buffer = new byte[10]; ByteBuffer out = ByteBuffer.wrap(buffer); assertTrue(out.hasArray()); encoder.encode(CharBuffer.wrap("ab"), out, false); assertEquals('a', buffer[0]); assertEquals('b', buffer[1]); assertEquals(0, buffer[2]); out = ByteBuffer.allocateDirect(10); // It's no longer possible to get a byte buffer without a backing byte[] on Android. // This test is useless on Android, unless that changes again. (You can't even // subclass ByteBuffer because -- although it's non-final -- both the RI and Android // have [different] package-private abstract methods you'd need to implement but can't.) //assertFalse(out.hasArray()); encoder.encode(CharBuffer.wrap("x"), out, true); // check whether the second decode corrupted the first buffer assertEquals('a', buffer[0]); assertEquals('b', buffer[1]); assertEquals(0, buffer[2]); } /* Checks for a buffer corruption that happens in ICU * (CharsetEncoderICU) when an encode operation * is done first with an in-buffer with hasArray()==true, and next with an in-buffer with * hasArray()==false. In that situation ICU may overwrite the array of the first in-buffer. */ public void testEncoderInputBuffer() { CharsetEncoder encoder = Charset.forName("UTF-8").newEncoder(); ByteBuffer out = ByteBuffer.wrap(new byte[10]); char[] inArray = {'a', 'b'}; CharBuffer inWithArray = CharBuffer.wrap(inArray); assertTrue(inWithArray.hasArray()); encoder.encode(inWithArray, out, false); assertEquals('a', inArray[0]); assertEquals('b', inArray[1]); CharBuffer inWithoutArray = CharBuffer.wrap("x"); assertFalse(inWithoutArray.hasArray()); encoder.encode(inWithoutArray, out, true); // check whether the second decode corrupted the first buffer assertEquals('a', inArray[0]); assertEquals('b', inArray[1]); } }