/*
* Copyright 2013 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 io.netty.util.internal.
StringUtil;
import java.io.
IOException;
import java.io.
InputStream;
import java.io.
OutputStream;
import java.nio.
ByteBuffer;
import java.nio.
ByteOrder;
import java.nio.
ReadOnlyBufferException;
import java.nio.channels.
FileChannel;
import java.nio.channels.
GatheringByteChannel;
import java.nio.channels.
ScatteringByteChannel;
/**
* Read-only ByteBuf which wraps a read-only ByteBuffer.
*/
class
ReadOnlyByteBufferBuf extends
AbstractReferenceCountedByteBuf {
protected final
ByteBuffer buffer;
private final
ByteBufAllocator allocator;
private
ByteBuffer tmpNioBuf;
ReadOnlyByteBufferBuf(
ByteBufAllocator allocator,
ByteBuffer buffer) {
super(
buffer.
remaining());
if (!
buffer.
isReadOnly()) {
throw new
IllegalArgumentException("must be a readonly buffer: " +
StringUtil.
simpleClassName(
buffer));
}
this.
allocator =
allocator;
this.
buffer =
buffer.
slice().
order(
ByteOrder.
BIG_ENDIAN);
writerIndex(this.
buffer.
limit());
}
@
Override
protected void
deallocate() { }
@
Override
public boolean
isWritable() {
return false;
}
@
Override
public boolean
isWritable(int
numBytes) {
return false;
}
@
Override
public
ByteBuf ensureWritable(int
minWritableBytes) {
throw new
ReadOnlyBufferException();
}
@
Override
public int
ensureWritable(int
minWritableBytes, boolean
force) {
return 1;
}
@
Override
public byte
getByte(int
index) {
ensureAccessible();
return
_getByte(
index);
}
@
Override
protected byte
_getByte(int
index) {
return
buffer.
get(
index);
}
@
Override
public short
getShort(int
index) {
ensureAccessible();
return
_getShort(
index);
}
@
Override
protected short
_getShort(int
index) {
return
buffer.
getShort(
index);
}
@
Override
public short
getShortLE(int
index) {
ensureAccessible();
return
_getShortLE(
index);
}
@
Override
protected short
_getShortLE(int
index) {
return
ByteBufUtil.
swapShort(
buffer.
getShort(
index));
}
@
Override
public int
getUnsignedMedium(int
index) {
ensureAccessible();
return
_getUnsignedMedium(
index);
}
@
Override
protected int
_getUnsignedMedium(int
index) {
return (
getByte(
index) & 0xff) << 16 |
(
getByte(
index + 1) & 0xff) << 8 |
getByte(
index + 2) & 0xff;
}
@
Override
public int
getUnsignedMediumLE(int
index) {
ensureAccessible();
return
_getUnsignedMediumLE(
index);
}
@
Override
protected int
_getUnsignedMediumLE(int
index) {
return
getByte(
index) & 0xff |
(
getByte(
index + 1) & 0xff) << 8 |
(
getByte(
index + 2) & 0xff) << 16;
}
@
Override
public int
getInt(int
index) {
ensureAccessible();
return
_getInt(
index);
}
@
Override
protected int
_getInt(int
index) {
return
buffer.
getInt(
index);
}
@
Override
public int
getIntLE(int
index) {
ensureAccessible();
return
_getIntLE(
index);
}
@
Override
protected int
_getIntLE(int
index) {
return
ByteBufUtil.
swapInt(
buffer.
getInt(
index));
}
@
Override
public long
getLong(int
index) {
ensureAccessible();
return
_getLong(
index);
}
@
Override
protected long
_getLong(int
index) {
return
buffer.
getLong(
index);
}
@
Override
public long
getLongLE(int
index) {
ensureAccessible();
return
_getLongLE(
index);
}
@
Override
protected long
_getLongLE(int
index) {
return
ByteBufUtil.
swapLong(
buffer.
getLong(
index));
}
@
Override
public
ByteBuf getBytes(int
index,
ByteBuf dst, int
dstIndex, int
length) {
checkDstIndex(
index,
length,
dstIndex,
dst.
capacity());
if (
dst.
hasArray()) {
getBytes(
index,
dst.
array(),
dst.
arrayOffset() +
dstIndex,
length);
} else if (
dst.
nioBufferCount() > 0) {
for (
ByteBuffer bb:
dst.
nioBuffers(
dstIndex,
length)) {
int
bbLen =
bb.
remaining();
getBytes(
index,
bb);
index +=
bbLen;
}
} else {
dst.
setBytes(
dstIndex, this,
index,
length);
}
return this;
}
@
Override
public
ByteBuf getBytes(int
index, byte[]
dst, int
dstIndex, int
length) {
checkDstIndex(
index,
length,
dstIndex,
dst.length);
if (
dstIndex < 0 ||
dstIndex >
dst.length -
length) {
throw new
IndexOutOfBoundsException(
String.
format(
"dstIndex: %d, length: %d (expected: range(0, %d))",
dstIndex,
length,
dst.length));
}
ByteBuffer tmpBuf =
internalNioBuffer();
tmpBuf.
clear().
position(
index).
limit(
index +
length);
tmpBuf.
get(
dst,
dstIndex,
length);
return this;
}
@
Override
public
ByteBuf getBytes(int
index,
ByteBuffer dst) {
checkIndex(
index);
if (
dst == null) {
throw new
NullPointerException("dst");
}
int
bytesToCopy =
Math.
min(
capacity() -
index,
dst.
remaining());
ByteBuffer tmpBuf =
internalNioBuffer();
tmpBuf.
clear().
position(
index).
limit(
index +
bytesToCopy);
dst.
put(
tmpBuf);
return this;
}
@
Override
public
ByteBuf setByte(int
index, int
value) {
throw new
ReadOnlyBufferException();
}
@
Override
protected void
_setByte(int
index, int
value) {
throw new
ReadOnlyBufferException();
}
@
Override
public
ByteBuf setShort(int
index, int
value) {
throw new
ReadOnlyBufferException();
}
@
Override
protected void
_setShort(int
index, int
value) {
throw new
ReadOnlyBufferException();
}
@
Override
public
ByteBuf setShortLE(int
index, int
value) {
throw new
ReadOnlyBufferException();
}
@
Override
protected void
_setShortLE(int
index, int
value) {
throw new
ReadOnlyBufferException();
}
@
Override
public
ByteBuf setMedium(int
index, int
value) {
throw new
ReadOnlyBufferException();
}
@
Override
protected void
_setMedium(int
index, int
value) {
throw new
ReadOnlyBufferException();
}
@
Override
public
ByteBuf setMediumLE(int
index, int
value) {
throw new
ReadOnlyBufferException();
}
@
Override
protected void
_setMediumLE(int
index, int
value) {
throw new
ReadOnlyBufferException();
}
@
Override
public
ByteBuf setInt(int
index, int
value) {
throw new
ReadOnlyBufferException();
}
@
Override
protected void
_setInt(int
index, int
value) {
throw new
ReadOnlyBufferException();
}
@
Override
public
ByteBuf setIntLE(int
index, int
value) {
throw new
ReadOnlyBufferException();
}
@
Override
protected void
_setIntLE(int
index, int
value) {
throw new
ReadOnlyBufferException();
}
@
Override
public
ByteBuf setLong(int
index, long
value) {
throw new
ReadOnlyBufferException();
}
@
Override
protected void
_setLong(int
index, long
value) {
throw new
ReadOnlyBufferException();
}
@
Override
public
ByteBuf setLongLE(int
index, long
value) {
throw new
ReadOnlyBufferException();
}
@
Override
protected void
_setLongLE(int
index, long
value) {
throw new
ReadOnlyBufferException();
}
@
Override
public int
capacity() {
return
maxCapacity();
}
@
Override
public
ByteBuf capacity(int
newCapacity) {
throw new
ReadOnlyBufferException();
}
@
Override
public
ByteBufAllocator alloc() {
return
allocator;
}
@
Override
public
ByteOrder order() {
return
ByteOrder.
BIG_ENDIAN;
}
@
Override
public
ByteBuf unwrap() {
return null;
}
@
Override
public boolean
isReadOnly() {
return
buffer.
isReadOnly();
}
@
Override
public boolean
isDirect() {
return
buffer.
isDirect();
}
@
Override
public
ByteBuf getBytes(int
index,
OutputStream out, int
length) throws
IOException {
ensureAccessible();
if (
length == 0) {
return this;
}
if (
buffer.
hasArray()) {
out.
write(
buffer.
array(),
index +
buffer.
arrayOffset(),
length);
} else {
byte[]
tmp = new byte[
length];
ByteBuffer tmpBuf =
internalNioBuffer();
tmpBuf.
clear().
position(
index);
tmpBuf.
get(
tmp);
out.
write(
tmp);
}
return this;
}
@
Override
public int
getBytes(int
index,
GatheringByteChannel out, int
length) throws
IOException {
ensureAccessible();
if (
length == 0) {
return 0;
}
ByteBuffer tmpBuf =
internalNioBuffer();
tmpBuf.
clear().
position(
index).
limit(
index +
length);
return
out.
write(
tmpBuf);
}
@
Override
public int
getBytes(int
index,
FileChannel out, long
position, int
length) throws
IOException {
ensureAccessible();
if (
length == 0) {
return 0;
}
ByteBuffer tmpBuf =
internalNioBuffer();
tmpBuf.
clear().
position(
index).
limit(
index +
length);
return
out.
write(
tmpBuf,
position);
}
@
Override
public
ByteBuf setBytes(int
index,
ByteBuf src, int
srcIndex, int
length) {
throw new
ReadOnlyBufferException();
}
@
Override
public
ByteBuf setBytes(int
index, byte[]
src, int
srcIndex, int
length) {
throw new
ReadOnlyBufferException();
}
@
Override
public
ByteBuf setBytes(int
index,
ByteBuffer src) {
throw new
ReadOnlyBufferException();
}
@
Override
public int
setBytes(int
index,
InputStream in, int
length) throws
IOException {
throw new
ReadOnlyBufferException();
}
@
Override
public int
setBytes(int
index,
ScatteringByteChannel in, int
length) throws
IOException {
throw new
ReadOnlyBufferException();
}
@
Override
public int
setBytes(int
index,
FileChannel in, long
position, int
length) throws
IOException {
throw new
ReadOnlyBufferException();
}
protected final
ByteBuffer internalNioBuffer() {
ByteBuffer tmpNioBuf = this.
tmpNioBuf;
if (
tmpNioBuf == null) {
this.
tmpNioBuf =
tmpNioBuf =
buffer.
duplicate();
}
return
tmpNioBuf;
}
@
Override
public
ByteBuf copy(int
index, int
length) {
ensureAccessible();
ByteBuffer src;
try {
src = (
ByteBuffer)
internalNioBuffer().
clear().
position(
index).
limit(
index +
length);
} catch (
IllegalArgumentException ignored) {
throw new
IndexOutOfBoundsException("Too many bytes to read - Need " + (
index +
length));
}
ByteBuf dst =
src.
isDirect() ?
alloc().
directBuffer(
length) :
alloc().
heapBuffer(
length);
dst.
writeBytes(
src);
return
dst;
}
@
Override
public int
nioBufferCount() {
return 1;
}
@
Override
public
ByteBuffer[]
nioBuffers(int
index, int
length) {
return new
ByteBuffer[] {
nioBuffer(
index,
length) };
}
@
Override
public
ByteBuffer nioBuffer(int
index, int
length) {
return (
ByteBuffer)
buffer.
duplicate().
position(
index).
limit(
index +
length);
}
@
Override
public
ByteBuffer internalNioBuffer(int
index, int
length) {
ensureAccessible();
return (
ByteBuffer)
internalNioBuffer().
clear().
position(
index).
limit(
index +
length);
}
@
Override
public boolean
hasArray() {
return
buffer.
hasArray();
}
@
Override
public byte[]
array() {
return
buffer.
array();
}
@
Override
public int
arrayOffset() {
return
buffer.
arrayOffset();
}
@
Override
public boolean
hasMemoryAddress() {
return false;
}
@
Override
public long
memoryAddress() {
throw new
UnsupportedOperationException();
}
}