From a4ebdd0eca8dfca3d9eaaeae9dded473cd1542c5 Mon Sep 17 00:00:00 2001 From: Janecek Jakub Date: Mon, 16 Nov 2015 17:01:36 +0100 Subject: [PATCH] Fix setBytes on read-only ByteBuffer Motivation: The method setBytes did not work correctly because read-only ByteBuffer does not allow access to its underlying array. Modifications: New case was added for ByteBuffer's that are not direct and do not have an array. These must be handled by copying the data into a temporary array. Unit test was added to test this case. Result: It is now possible to use read-only ByteBuffer as the source for the setBytes method. --- .../io/netty/buffer/UnsafeByteBufUtil.java | 14 +++++- .../netty/buffer/UnsafeByteBufUtilTest.java | 48 +++++++++++++++++++ 2 files changed, 60 insertions(+), 2 deletions(-) create mode 100644 buffer/src/test/java/io/netty/buffer/UnsafeByteBufUtilTest.java diff --git a/buffer/src/main/java/io/netty/buffer/UnsafeByteBufUtil.java b/buffer/src/main/java/io/netty/buffer/UnsafeByteBufUtil.java index 6186a610bf..b074c1f08b 100644 --- a/buffer/src/main/java/io/netty/buffer/UnsafeByteBufUtil.java +++ b/buffer/src/main/java/io/netty/buffer/UnsafeByteBufUtil.java @@ -362,11 +362,21 @@ final class UnsafeByteBufUtil { // Copy from direct memory long srcAddress = PlatformDependent.directBufferAddress(src); PlatformDependent.copyMemory(srcAddress + src.position(), addr, src.remaining()); - } else { + src.position(src.position() + length); + } else if (src.hasArray()) { // Copy from array PlatformDependent.copyMemory(src.array(), src.arrayOffset() + src.position(), addr, length); + src.position(src.position() + length); + } else { + ByteBuf tmpBuf = buf.alloc().heapBuffer(length); + try { + byte[] tmp = tmpBuf.array(); + src.get(tmp, tmpBuf.arrayOffset(), length); // moves the src position too + PlatformDependent.copyMemory(tmp, 0, addr, length); + } finally { + tmpBuf.release(); + } } - src.position(src.position() + length); } static void getBytes(AbstractByteBuf buf, long addr, int index, OutputStream out, int length) throws IOException { diff --git a/buffer/src/test/java/io/netty/buffer/UnsafeByteBufUtilTest.java b/buffer/src/test/java/io/netty/buffer/UnsafeByteBufUtilTest.java new file mode 100644 index 0000000000..679a661c1d --- /dev/null +++ b/buffer/src/test/java/io/netty/buffer/UnsafeByteBufUtilTest.java @@ -0,0 +1,48 @@ +/* + * Copyright 2015 The Netty Project + * + * The Netty Project 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 io.netty.buffer; + +import org.junit.Test; + +import java.nio.ByteBuffer; + +import static io.netty.util.internal.PlatformDependent.directBufferAddress; +import static org.junit.Assert.assertArrayEquals; + +public class UnsafeByteBufUtilTest { + + @Test + public void testSetBytesOnReadOnlyByteBuffer() throws Exception { + byte[] testData = new byte[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; + int length = testData.length; + + ByteBuffer readOnlyBuffer = ByteBuffer.wrap(testData).asReadOnlyBuffer(); + + UnpooledByteBufAllocator alloc = new UnpooledByteBufAllocator(true); + UnpooledDirectByteBuf targetBuffer = new UnpooledDirectByteBuf(alloc, length, length); + + try { + UnsafeByteBufUtil.setBytes(targetBuffer, directBufferAddress(targetBuffer.nioBuffer()), 0, readOnlyBuffer); + + byte[] check = new byte[length]; + targetBuffer.getBytes(0, check, 0, length); + + assertArrayEquals("The byte array's copy does not equal the original", testData, check); + } finally { + targetBuffer.release(); + } + } +}