/*
* Copyright 2012 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.
ByteProcessor;
import io.netty.util.
CharsetUtil;
import io.netty.util.
IllegalReferenceCountException;
import io.netty.util.
ResourceLeakDetector;
import io.netty.util.
ResourceLeakDetectorFactory;
import io.netty.util.internal.
PlatformDependent;
import io.netty.util.internal.
StringUtil;
import io.netty.util.internal.
SystemPropertyUtil;
import io.netty.util.internal.logging.
InternalLogger;
import io.netty.util.internal.logging.
InternalLoggerFactory;
import java.io.
IOException;
import java.io.
InputStream;
import java.io.
OutputStream;
import java.nio.
ByteBuffer;
import java.nio.
ByteOrder;
import java.nio.channels.
FileChannel;
import java.nio.channels.
GatheringByteChannel;
import java.nio.channels.
ScatteringByteChannel;
import java.nio.charset.
Charset;
import static io.netty.util.internal.
MathUtil.isOutOfBounds;
/**
* A skeletal implementation of a buffer.
*/
public abstract class
AbstractByteBuf extends
ByteBuf {
private static final
InternalLogger logger =
InternalLoggerFactory.
getInstance(
AbstractByteBuf.class);
private static final
String PROP_MODE = "io.netty.buffer.bytebuf.checkAccessible";
private static final boolean
checkAccessible;
static {
checkAccessible =
SystemPropertyUtil.
getBoolean(
PROP_MODE, true);
if (
logger.
isDebugEnabled()) {
logger.
debug("-D{}: {}",
PROP_MODE,
checkAccessible);
}
}
static final
ResourceLeakDetector<
ByteBuf>
leakDetector =
ResourceLeakDetectorFactory.
instance().
newResourceLeakDetector(
ByteBuf.class);
int
readerIndex;
int
writerIndex;
private int
markedReaderIndex;
private int
markedWriterIndex;
private int
maxCapacity;
protected
AbstractByteBuf(int
maxCapacity) {
if (
maxCapacity < 0) {
throw new
IllegalArgumentException("maxCapacity: " +
maxCapacity + " (expected: >= 0)");
}
this.
maxCapacity =
maxCapacity;
}
@
Override
public boolean
isReadOnly() {
return false;
}
@
SuppressWarnings("deprecation")
@
Override
public
ByteBuf asReadOnly() {
if (
isReadOnly()) {
return this;
}
return
Unpooled.
unmodifiableBuffer(this);
}
@
Override
public int
maxCapacity() {
return
maxCapacity;
}
protected final void
maxCapacity(int
maxCapacity) {
this.
maxCapacity =
maxCapacity;
}
@
Override
public int
readerIndex() {
return
readerIndex;
}
@
Override
public
ByteBuf readerIndex(int
readerIndex) {
if (
readerIndex < 0 ||
readerIndex >
writerIndex) {
throw new
IndexOutOfBoundsException(
String.
format(
"readerIndex: %d (expected: 0 <= readerIndex <= writerIndex(%d))",
readerIndex,
writerIndex));
}
this.
readerIndex =
readerIndex;
return this;
}
@
Override
public int
writerIndex() {
return
writerIndex;
}
@
Override
public
ByteBuf writerIndex(int
writerIndex) {
if (
writerIndex <
readerIndex ||
writerIndex >
capacity()) {
throw new
IndexOutOfBoundsException(
String.
format(
"writerIndex: %d (expected: readerIndex(%d) <= writerIndex <= capacity(%d))",
writerIndex,
readerIndex,
capacity()));
}
this.
writerIndex =
writerIndex;
return this;
}
@
Override
public
ByteBuf setIndex(int
readerIndex, int
writerIndex) {
if (
readerIndex < 0 ||
readerIndex >
writerIndex ||
writerIndex >
capacity()) {
throw new
IndexOutOfBoundsException(
String.
format(
"readerIndex: %d, writerIndex: %d (expected: 0 <= readerIndex <= writerIndex <= capacity(%d))",
readerIndex,
writerIndex,
capacity()));
}
setIndex0(
readerIndex,
writerIndex);
return this;
}
@
Override
public
ByteBuf clear() {
readerIndex =
writerIndex = 0;
return this;
}
@
Override
public boolean
isReadable() {
return
writerIndex >
readerIndex;
}
@
Override
public boolean
isReadable(int
numBytes) {
return
writerIndex -
readerIndex >=
numBytes;
}
@
Override
public boolean
isWritable() {
return
capacity() >
writerIndex;
}
@
Override
public boolean
isWritable(int
numBytes) {
return
capacity() -
writerIndex >=
numBytes;
}
@
Override
public int
readableBytes() {
return
writerIndex -
readerIndex;
}
@
Override
public int
writableBytes() {
return
capacity() -
writerIndex;
}
@
Override
public int
maxWritableBytes() {
return
maxCapacity() -
writerIndex;
}
@
Override
public
ByteBuf markReaderIndex() {
markedReaderIndex =
readerIndex;
return this;
}
@
Override
public
ByteBuf resetReaderIndex() {
readerIndex(
markedReaderIndex);
return this;
}
@
Override
public
ByteBuf markWriterIndex() {
markedWriterIndex =
writerIndex;
return this;
}
@
Override
public
ByteBuf resetWriterIndex() {
writerIndex(
markedWriterIndex);
return this;
}
@
Override
public
ByteBuf discardReadBytes() {
ensureAccessible();
if (
readerIndex == 0) {
return this;
}
if (
readerIndex !=
writerIndex) {
setBytes(0, this,
readerIndex,
writerIndex -
readerIndex);
writerIndex -=
readerIndex;
adjustMarkers(
readerIndex);
readerIndex = 0;
} else {
adjustMarkers(
readerIndex);
writerIndex =
readerIndex = 0;
}
return this;
}
@
Override
public
ByteBuf discardSomeReadBytes() {
ensureAccessible();
if (
readerIndex == 0) {
return this;
}
if (
readerIndex ==
writerIndex) {
adjustMarkers(
readerIndex);
writerIndex =
readerIndex = 0;
return this;
}
if (
readerIndex >=
capacity() >>> 1) {
setBytes(0, this,
readerIndex,
writerIndex -
readerIndex);
writerIndex -=
readerIndex;
adjustMarkers(
readerIndex);
readerIndex = 0;
}
return this;
}
protected final void
adjustMarkers(int
decrement) {
int
markedReaderIndex = this.
markedReaderIndex;
if (
markedReaderIndex <=
decrement) {
this.
markedReaderIndex = 0;
int
markedWriterIndex = this.
markedWriterIndex;
if (
markedWriterIndex <=
decrement) {
this.
markedWriterIndex = 0;
} else {
this.
markedWriterIndex =
markedWriterIndex -
decrement;
}
} else {
this.
markedReaderIndex =
markedReaderIndex -
decrement;
markedWriterIndex -=
decrement;
}
}
@
Override
public
ByteBuf ensureWritable(int
minWritableBytes) {
if (
minWritableBytes < 0) {
throw new
IllegalArgumentException(
String.
format(
"minWritableBytes: %d (expected: >= 0)",
minWritableBytes));
}
ensureWritable0(
minWritableBytes);
return this;
}
final void
ensureWritable0(int
minWritableBytes) {
ensureAccessible();
if (
minWritableBytes <=
writableBytes()) {
return;
}
if (
minWritableBytes >
maxCapacity -
writerIndex) {
throw new
IndexOutOfBoundsException(
String.
format(
"writerIndex(%d) + minWritableBytes(%d) exceeds maxCapacity(%d): %s",
writerIndex,
minWritableBytes,
maxCapacity, this));
}
// Normalize the current capacity to the power of 2.
int
newCapacity =
alloc().
calculateNewCapacity(
writerIndex +
minWritableBytes,
maxCapacity);
// Adjust to the new capacity.
capacity(
newCapacity);
}
@
Override
public int
ensureWritable(int
minWritableBytes, boolean
force) {
ensureAccessible();
if (
minWritableBytes < 0) {
throw new
IllegalArgumentException(
String.
format(
"minWritableBytes: %d (expected: >= 0)",
minWritableBytes));
}
if (
minWritableBytes <=
writableBytes()) {
return 0;
}
final int
maxCapacity =
maxCapacity();
final int
writerIndex =
writerIndex();
if (
minWritableBytes >
maxCapacity -
writerIndex) {
if (!
force ||
capacity() ==
maxCapacity) {
return 1;
}
capacity(
maxCapacity);
return 3;
}
// Normalize the current capacity to the power of 2.
int
newCapacity =
alloc().
calculateNewCapacity(
writerIndex +
minWritableBytes,
maxCapacity);
// Adjust to the new capacity.
capacity(
newCapacity);
return 2;
}
@
Override
public
ByteBuf order(
ByteOrder endianness) {
if (
endianness == null) {
throw new
NullPointerException("endianness");
}
if (
endianness ==
order()) {
return this;
}
return
newSwappedByteBuf();
}
/**
* Creates a new {@link SwappedByteBuf} for this {@link ByteBuf} instance.
*/
protected
SwappedByteBuf newSwappedByteBuf() {
return new
SwappedByteBuf(this);
}
@
Override
public byte
getByte(int
index) {
checkIndex(
index);
return
_getByte(
index);
}
protected abstract byte
_getByte(int
index);
@
Override
public boolean
getBoolean(int
index) {
return
getByte(
index) != 0;
}
@
Override
public short
getUnsignedByte(int
index) {
return (short) (
getByte(
index) & 0xFF);
}
@
Override
public short
getShort(int
index) {
checkIndex(
index, 2);
return
_getShort(
index);
}
protected abstract short
_getShort(int
index);
@
Override
public short
getShortLE(int
index) {
checkIndex(
index, 2);
return
_getShortLE(
index);
}
protected abstract short
_getShortLE(int
index);
@
Override
public int
getUnsignedShort(int
index) {
return
getShort(
index) & 0xFFFF;
}
@
Override
public int
getUnsignedShortLE(int
index) {
return
getShortLE(
index) & 0xFFFF;
}
@
Override
public int
getUnsignedMedium(int
index) {
checkIndex(
index, 3);
return
_getUnsignedMedium(
index);
}
protected abstract int
_getUnsignedMedium(int
index);
@
Override
public int
getUnsignedMediumLE(int
index) {
checkIndex(
index, 3);
return
_getUnsignedMediumLE(
index);
}
protected abstract int
_getUnsignedMediumLE(int
index);
@
Override
public int
getMedium(int
index) {
int
value =
getUnsignedMedium(
index);
if ((
value & 0x800000) != 0) {
value |= 0xff000000;
}
return
value;
}
@
Override
public int
getMediumLE(int
index) {
int
value =
getUnsignedMediumLE(
index);
if ((
value & 0x800000) != 0) {
value |= 0xff000000;
}
return
value;
}
@
Override
public int
getInt(int
index) {
checkIndex(
index, 4);
return
_getInt(
index);
}
protected abstract int
_getInt(int
index);
@
Override
public int
getIntLE(int
index) {
checkIndex(
index, 4);
return
_getIntLE(
index);
}
protected abstract int
_getIntLE(int
index);
@
Override
public long
getUnsignedInt(int
index) {
return
getInt(
index) & 0xFFFFFFFFL;
}
@
Override
public long
getUnsignedIntLE(int
index) {
return
getIntLE(
index) & 0xFFFFFFFFL;
}
@
Override
public long
getLong(int
index) {
checkIndex(
index, 8);
return
_getLong(
index);
}
protected abstract long
_getLong(int
index);
@
Override
public long
getLongLE(int
index) {
checkIndex(
index, 8);
return
_getLongLE(
index);
}
protected abstract long
_getLongLE(int
index);
@
Override
public char
getChar(int
index) {
return (char)
getShort(
index);
}
@
Override
public float
getFloat(int
index) {
return
Float.
intBitsToFloat(
getInt(
index));
}
@
Override
public double
getDouble(int
index) {
return
Double.
longBitsToDouble(
getLong(
index));
}
@
Override
public
ByteBuf getBytes(int
index, byte[]
dst) {
getBytes(
index,
dst, 0,
dst.length);
return this;
}
@
Override
public
ByteBuf getBytes(int
index,
ByteBuf dst) {
getBytes(
index,
dst,
dst.
writableBytes());
return this;
}
@
Override
public
ByteBuf getBytes(int
index,
ByteBuf dst, int
length) {
getBytes(
index,
dst,
dst.
writerIndex(),
length);
dst.
writerIndex(
dst.
writerIndex() +
length);
return this;
}
@
Override
public
CharSequence getCharSequence(int
index, int
length,
Charset charset) {
// TODO: We could optimize this for UTF8 and US_ASCII
return
toString(
index,
length,
charset);
}
@
Override
public
CharSequence readCharSequence(int
length,
Charset charset) {
CharSequence sequence =
getCharSequence(
readerIndex,
length,
charset);
readerIndex +=
length;
return
sequence;
}
@
Override
public
ByteBuf setByte(int
index, int
value) {
checkIndex(
index);
_setByte(
index,
value);
return this;
}
protected abstract void
_setByte(int
index, int
value);
@
Override
public
ByteBuf setBoolean(int
index, boolean
value) {
setByte(
index,
value? 1 : 0);
return this;
}
@
Override
public
ByteBuf setShort(int
index, int
value) {
checkIndex(
index, 2);
_setShort(
index,
value);
return this;
}
protected abstract void
_setShort(int
index, int
value);
@
Override
public
ByteBuf setShortLE(int
index, int
value) {
checkIndex(
index, 2);
_setShortLE(
index,
value);
return this;
}
protected abstract void
_setShortLE(int
index, int
value);
@
Override
public
ByteBuf setChar(int
index, int
value) {
setShort(
index,
value);
return this;
}
@
Override
public
ByteBuf setMedium(int
index, int
value) {
checkIndex(
index, 3);
_setMedium(
index,
value);
return this;
}
protected abstract void
_setMedium(int
index, int
value);
@
Override
public
ByteBuf setMediumLE(int
index, int
value) {
checkIndex(
index, 3);
_setMediumLE(
index,
value);
return this;
}
protected abstract void
_setMediumLE(int
index, int
value);
@
Override
public
ByteBuf setInt(int
index, int
value) {
checkIndex(
index, 4);
_setInt(
index,
value);
return this;
}
protected abstract void
_setInt(int
index, int
value);
@
Override
public
ByteBuf setIntLE(int
index, int
value) {
checkIndex(
index, 4);
_setIntLE(
index,
value);
return this;
}
protected abstract void
_setIntLE(int
index, int
value);
@
Override
public
ByteBuf setFloat(int
index, float
value) {
setInt(
index,
Float.
floatToRawIntBits(
value));
return this;
}
@
Override
public
ByteBuf setLong(int
index, long
value) {
checkIndex(
index, 8);
_setLong(
index,
value);
return this;
}
protected abstract void
_setLong(int
index, long
value);
@
Override
public
ByteBuf setLongLE(int
index, long
value) {
checkIndex(
index, 8);
_setLongLE(
index,
value);
return this;
}
protected abstract void
_setLongLE(int
index, long
value);
@
Override
public
ByteBuf setDouble(int
index, double
value) {
setLong(
index,
Double.
doubleToRawLongBits(
value));
return this;
}
@
Override
public
ByteBuf setBytes(int
index, byte[]
src) {
setBytes(
index,
src, 0,
src.length);
return this;
}
@
Override
public
ByteBuf setBytes(int
index,
ByteBuf src) {
setBytes(
index,
src,
src.
readableBytes());
return this;
}
@
Override
public
ByteBuf setBytes(int
index,
ByteBuf src, int
length) {
checkIndex(
index,
length);
if (
src == null) {
throw new
NullPointerException("src");
}
if (
length >
src.
readableBytes()) {
throw new
IndexOutOfBoundsException(
String.
format(
"length(%d) exceeds src.readableBytes(%d) where src is: %s",
length,
src.
readableBytes(),
src));
}
setBytes(
index,
src,
src.
readerIndex(),
length);
src.
readerIndex(
src.
readerIndex() +
length);
return this;
}
@
Override
public
ByteBuf setZero(int
index, int
length) {
if (
length == 0) {
return this;
}
checkIndex(
index,
length);
int
nLong =
length >>> 3;
int
nBytes =
length & 7;
for (int
i =
nLong;
i > 0;
i --) {
_setLong(
index, 0);
index += 8;
}
if (
nBytes == 4) {
_setInt(
index, 0);
// Not need to update the index as we not will use it after this.
} else if (
nBytes < 4) {
for (int
i =
nBytes;
i > 0;
i --) {
_setByte(
index, (byte) 0);
index ++;
}
} else {
_setInt(
index, 0);
index += 4;
for (int
i =
nBytes - 4;
i > 0;
i --) {
_setByte(
index, (byte) 0);
index ++;
}
}
return this;
}
@
Override
public int
setCharSequence(int
index,
CharSequence sequence,
Charset charset) {
return
setCharSequence0(
index,
sequence,
charset, false);
}
private int
setCharSequence0(int
index,
CharSequence sequence,
Charset charset, boolean
expand) {
if (
charset.
equals(
CharsetUtil.
UTF_8)) {
int
length =
ByteBufUtil.
utf8MaxBytes(
sequence);
if (
expand) {
ensureWritable0(
length);
checkIndex0(
index,
length);
} else {
checkIndex(
index,
length);
}
return
ByteBufUtil.
writeUtf8(this,
index,
sequence,
sequence.
length());
}
if (
charset.
equals(
CharsetUtil.
US_ASCII) ||
charset.
equals(
CharsetUtil.
ISO_8859_1)) {
int
length =
sequence.
length();
if (
expand) {
ensureWritable0(
length);
checkIndex0(
index,
length);
} else {
checkIndex(
index,
length);
}
return
ByteBufUtil.
writeAscii(this,
index,
sequence,
length);
}
byte[]
bytes =
sequence.
toString().
getBytes(
charset);
if (
expand) {
ensureWritable0(
bytes.length);
// setBytes(...) will take care of checking the indices.
}
setBytes(
index,
bytes);
return
bytes.length;
}
@
Override
public byte
readByte() {
checkReadableBytes0(1);
int
i =
readerIndex;
byte
b =
_getByte(
i);
readerIndex =
i + 1;
return
b;
}
@
Override
public boolean
readBoolean() {
return
readByte() != 0;
}
@
Override
public short
readUnsignedByte() {
return (short) (
readByte() & 0xFF);
}
@
Override
public short
readShort() {
checkReadableBytes0(2);
short
v =
_getShort(
readerIndex);
readerIndex += 2;
return
v;
}
@
Override
public short
readShortLE() {
checkReadableBytes0(2);
short
v =
_getShortLE(
readerIndex);
readerIndex += 2;
return
v;
}
@
Override
public int
readUnsignedShort() {
return
readShort() & 0xFFFF;
}
@
Override
public int
readUnsignedShortLE() {
return
readShortLE() & 0xFFFF;
}
@
Override
public int
readMedium() {
int
value =
readUnsignedMedium();
if ((
value & 0x800000) != 0) {
value |= 0xff000000;
}
return
value;
}
@
Override
public int
readMediumLE() {
int
value =
readUnsignedMediumLE();
if ((
value & 0x800000) != 0) {
value |= 0xff000000;
}
return
value;
}
@
Override
public int
readUnsignedMedium() {
checkReadableBytes0(3);
int
v =
_getUnsignedMedium(
readerIndex);
readerIndex += 3;
return
v;
}
@
Override
public int
readUnsignedMediumLE() {
checkReadableBytes0(3);
int
v =
_getUnsignedMediumLE(
readerIndex);
readerIndex += 3;
return
v;
}
@
Override
public int
readInt() {
checkReadableBytes0(4);
int
v =
_getInt(
readerIndex);
readerIndex += 4;
return
v;
}
@
Override
public int
readIntLE() {
checkReadableBytes0(4);
int
v =
_getIntLE(
readerIndex);
readerIndex += 4;
return
v;
}
@
Override
public long
readUnsignedInt() {
return
readInt() & 0xFFFFFFFFL;
}
@
Override
public long
readUnsignedIntLE() {
return
readIntLE() & 0xFFFFFFFFL;
}
@
Override
public long
readLong() {
checkReadableBytes0(8);
long
v =
_getLong(
readerIndex);
readerIndex += 8;
return
v;
}
@
Override
public long
readLongLE() {
checkReadableBytes0(8);
long
v =
_getLongLE(
readerIndex);
readerIndex += 8;
return
v;
}
@
Override
public char
readChar() {
return (char)
readShort();
}
@
Override
public float
readFloat() {
return
Float.
intBitsToFloat(
readInt());
}
@
Override
public double
readDouble() {
return
Double.
longBitsToDouble(
readLong());
}
@
Override
public
ByteBuf readBytes(int
length) {
checkReadableBytes(
length);
if (
length == 0) {
return
Unpooled.
EMPTY_BUFFER;
}
ByteBuf buf =
alloc().
buffer(
length,
maxCapacity);
buf.
writeBytes(this,
readerIndex,
length);
readerIndex +=
length;
return
buf;
}
@
Override
public
ByteBuf readSlice(int
length) {
checkReadableBytes(
length);
ByteBuf slice =
slice(
readerIndex,
length);
readerIndex +=
length;
return
slice;
}
@
Override
public
ByteBuf readRetainedSlice(int
length) {
checkReadableBytes(
length);
ByteBuf slice =
retainedSlice(
readerIndex,
length);
readerIndex +=
length;
return
slice;
}
@
Override
public
ByteBuf readBytes(byte[]
dst, int
dstIndex, int
length) {
checkReadableBytes(
length);
getBytes(
readerIndex,
dst,
dstIndex,
length);
readerIndex +=
length;
return this;
}
@
Override
public
ByteBuf readBytes(byte[]
dst) {
readBytes(
dst, 0,
dst.length);
return this;
}
@
Override
public
ByteBuf readBytes(
ByteBuf dst) {
readBytes(
dst,
dst.
writableBytes());
return this;
}
@
Override
public
ByteBuf readBytes(
ByteBuf dst, int
length) {
if (
length >
dst.
writableBytes()) {
throw new
IndexOutOfBoundsException(
String.
format(
"length(%d) exceeds dst.writableBytes(%d) where dst is: %s",
length,
dst.
writableBytes(),
dst));
}
readBytes(
dst,
dst.
writerIndex(),
length);
dst.
writerIndex(
dst.
writerIndex() +
length);
return this;
}
@
Override
public
ByteBuf readBytes(
ByteBuf dst, int
dstIndex, int
length) {
checkReadableBytes(
length);
getBytes(
readerIndex,
dst,
dstIndex,
length);
readerIndex +=
length;
return this;
}
@
Override
public
ByteBuf readBytes(
ByteBuffer dst) {
int
length =
dst.
remaining();
checkReadableBytes(
length);
getBytes(
readerIndex,
dst);
readerIndex +=
length;
return this;
}
@
Override
public int
readBytes(
GatheringByteChannel out, int
length)
throws
IOException {
checkReadableBytes(
length);
int
readBytes =
getBytes(
readerIndex,
out,
length);
readerIndex +=
readBytes;
return
readBytes;
}
@
Override
public int
readBytes(
FileChannel out, long
position, int
length)
throws
IOException {
checkReadableBytes(
length);
int
readBytes =
getBytes(
readerIndex,
out,
position,
length);
readerIndex +=
readBytes;
return
readBytes;
}
@
Override
public
ByteBuf readBytes(
OutputStream out, int
length) throws
IOException {
checkReadableBytes(
length);
getBytes(
readerIndex,
out,
length);
readerIndex +=
length;
return this;
}
@
Override
public
ByteBuf skipBytes(int
length) {
checkReadableBytes(
length);
readerIndex +=
length;
return this;
}
@
Override
public
ByteBuf writeBoolean(boolean
value) {
writeByte(
value ? 1 : 0);
return this;
}
@
Override
public
ByteBuf writeByte(int
value) {
ensureWritable0(1);
_setByte(
writerIndex++,
value);
return this;
}
@
Override
public
ByteBuf writeShort(int
value) {
ensureWritable0(2);
_setShort(
writerIndex,
value);
writerIndex += 2;
return this;
}
@
Override
public
ByteBuf writeShortLE(int
value) {
ensureWritable0(2);
_setShortLE(
writerIndex,
value);
writerIndex += 2;
return this;
}
@
Override
public
ByteBuf writeMedium(int
value) {
ensureWritable0(3);
_setMedium(
writerIndex,
value);
writerIndex += 3;
return this;
}
@
Override
public
ByteBuf writeMediumLE(int
value) {
ensureWritable0(3);
_setMediumLE(
writerIndex,
value);
writerIndex += 3;
return this;
}
@
Override
public
ByteBuf writeInt(int
value) {
ensureWritable0(4);
_setInt(
writerIndex,
value);
writerIndex += 4;
return this;
}
@
Override
public
ByteBuf writeIntLE(int
value) {
ensureWritable0(4);
_setIntLE(
writerIndex,
value);
writerIndex += 4;
return this;
}
@
Override
public
ByteBuf writeLong(long
value) {
ensureWritable0(8);
_setLong(
writerIndex,
value);
writerIndex += 8;
return this;
}
@
Override
public
ByteBuf writeLongLE(long
value) {
ensureWritable0(8);
_setLongLE(
writerIndex,
value);
writerIndex += 8;
return this;
}
@
Override
public
ByteBuf writeChar(int
value) {
writeShort(
value);
return this;
}
@
Override
public
ByteBuf writeFloat(float
value) {
writeInt(
Float.
floatToRawIntBits(
value));
return this;
}
@
Override
public
ByteBuf writeDouble(double
value) {
writeLong(
Double.
doubleToRawLongBits(
value));
return this;
}
@
Override
public
ByteBuf writeBytes(byte[]
src, int
srcIndex, int
length) {
ensureWritable(
length);
setBytes(
writerIndex,
src,
srcIndex,
length);
writerIndex +=
length;
return this;
}
@
Override
public
ByteBuf writeBytes(byte[]
src) {
writeBytes(
src, 0,
src.length);
return this;
}
@
Override
public
ByteBuf writeBytes(
ByteBuf src) {
writeBytes(
src,
src.
readableBytes());
return this;
}
@
Override
public
ByteBuf writeBytes(
ByteBuf src, int
length) {
if (
length >
src.
readableBytes()) {
throw new
IndexOutOfBoundsException(
String.
format(
"length(%d) exceeds src.readableBytes(%d) where src is: %s",
length,
src.
readableBytes(),
src));
}
writeBytes(
src,
src.
readerIndex(),
length);
src.
readerIndex(
src.
readerIndex() +
length);
return this;
}
@
Override
public
ByteBuf writeBytes(
ByteBuf src, int
srcIndex, int
length) {
ensureWritable(
length);
setBytes(
writerIndex,
src,
srcIndex,
length);
writerIndex +=
length;
return this;
}
@
Override
public
ByteBuf writeBytes(
ByteBuffer src) {
int
length =
src.
remaining();
ensureWritable0(
length);
setBytes(
writerIndex,
src);
writerIndex +=
length;
return this;
}
@
Override
public int
writeBytes(
InputStream in, int
length)
throws
IOException {
ensureWritable(
length);
int
writtenBytes =
setBytes(
writerIndex,
in,
length);
if (
writtenBytes > 0) {
writerIndex +=
writtenBytes;
}
return
writtenBytes;
}
@
Override
public int
writeBytes(
ScatteringByteChannel in, int
length) throws
IOException {
ensureWritable(
length);
int
writtenBytes =
setBytes(
writerIndex,
in,
length);
if (
writtenBytes > 0) {
writerIndex +=
writtenBytes;
}
return
writtenBytes;
}
@
Override
public int
writeBytes(
FileChannel in, long
position, int
length) throws
IOException {
ensureWritable(
length);
int
writtenBytes =
setBytes(
writerIndex,
in,
position,
length);
if (
writtenBytes > 0) {
writerIndex +=
writtenBytes;
}
return
writtenBytes;
}
@
Override
public
ByteBuf writeZero(int
length) {
if (
length == 0) {
return this;
}
ensureWritable(
length);
int
wIndex =
writerIndex;
checkIndex0(
wIndex,
length);
int
nLong =
length >>> 3;
int
nBytes =
length & 7;
for (int
i =
nLong;
i > 0;
i --) {
_setLong(
wIndex, 0);
wIndex += 8;
}
if (
nBytes == 4) {
_setInt(
wIndex, 0);
wIndex += 4;
} else if (
nBytes < 4) {
for (int
i =
nBytes;
i > 0;
i --) {
_setByte(
wIndex, (byte) 0);
wIndex++;
}
} else {
_setInt(
wIndex, 0);
wIndex += 4;
for (int
i =
nBytes - 4;
i > 0;
i --) {
_setByte(
wIndex, (byte) 0);
wIndex++;
}
}
writerIndex =
wIndex;
return this;
}
@
Override
public int
writeCharSequence(
CharSequence sequence,
Charset charset) {
int
written =
setCharSequence0(
writerIndex,
sequence,
charset, true);
writerIndex +=
written;
return
written;
}
@
Override
public
ByteBuf copy() {
return
copy(
readerIndex,
readableBytes());
}
@
Override
public
ByteBuf duplicate() {
ensureAccessible();
return new
UnpooledDuplicatedByteBuf(this);
}
@
Override
public
ByteBuf retainedDuplicate() {
return
duplicate().
retain();
}
@
Override
public
ByteBuf slice() {
return
slice(
readerIndex,
readableBytes());
}
@
Override
public
ByteBuf retainedSlice() {
return
slice().
retain();
}
@
Override
public
ByteBuf slice(int
index, int
length) {
ensureAccessible();
return new
UnpooledSlicedByteBuf(this,
index,
length);
}
@
Override
public
ByteBuf retainedSlice(int
index, int
length) {
return
slice(
index,
length).
retain();
}
@
Override
public
ByteBuffer nioBuffer() {
return
nioBuffer(
readerIndex,
readableBytes());
}
@
Override
public
ByteBuffer[]
nioBuffers() {
return
nioBuffers(
readerIndex,
readableBytes());
}
@
Override
public
String toString(
Charset charset) {
return
toString(
readerIndex,
readableBytes(),
charset);
}
@
Override
public
String toString(int
index, int
length,
Charset charset) {
return
ByteBufUtil.
decodeString(this,
index,
length,
charset);
}
@
Override
public int
indexOf(int
fromIndex, int
toIndex, byte
value) {
return
ByteBufUtil.
indexOf(this,
fromIndex,
toIndex,
value);
}
@
Override
public int
bytesBefore(byte
value) {
return
bytesBefore(
readerIndex(),
readableBytes(),
value);
}
@
Override
public int
bytesBefore(int
length, byte
value) {
checkReadableBytes(
length);
return
bytesBefore(
readerIndex(),
length,
value);
}
@
Override
public int
bytesBefore(int
index, int
length, byte
value) {
int
endIndex =
indexOf(
index,
index +
length,
value);
if (
endIndex < 0) {
return -1;
}
return
endIndex -
index;
}
@
Override
public int
forEachByte(
ByteProcessor processor) {
ensureAccessible();
try {
return
forEachByteAsc0(
readerIndex,
writerIndex,
processor);
} catch (
Exception e) {
PlatformDependent.
throwException(
e);
return -1;
}
}
@
Override
public int
forEachByte(int
index, int
length,
ByteProcessor processor) {
checkIndex(
index,
length);
try {
return
forEachByteAsc0(
index,
index +
length,
processor);
} catch (
Exception e) {
PlatformDependent.
throwException(
e);
return -1;
}
}
private int
forEachByteAsc0(int
start, int
end,
ByteProcessor processor) throws
Exception {
for (;
start <
end; ++
start) {
if (!
processor.
process(
_getByte(
start))) {
return
start;
}
}
return -1;
}
@
Override
public int
forEachByteDesc(
ByteProcessor processor) {
ensureAccessible();
try {
return
forEachByteDesc0(
writerIndex - 1,
readerIndex,
processor);
} catch (
Exception e) {
PlatformDependent.
throwException(
e);
return -1;
}
}
@
Override
public int
forEachByteDesc(int
index, int
length,
ByteProcessor processor) {
checkIndex(
index,
length);
try {
return
forEachByteDesc0(
index +
length - 1,
index,
processor);
} catch (
Exception e) {
PlatformDependent.
throwException(
e);
return -1;
}
}
private int
forEachByteDesc0(int
rStart, final int
rEnd,
ByteProcessor processor) throws
Exception {
for (;
rStart >=
rEnd; --
rStart) {
if (!
processor.
process(
_getByte(
rStart))) {
return
rStart;
}
}
return -1;
}
@
Override
public int
hashCode() {
return
ByteBufUtil.
hashCode(this);
}
@
Override
public boolean
equals(
Object o) {
return this ==
o || (
o instanceof
ByteBuf &&
ByteBufUtil.
equals(this, (
ByteBuf)
o));
}
@
Override
public int
compareTo(
ByteBuf that) {
return
ByteBufUtil.
compare(this,
that);
}
@
Override
public
String toString() {
if (
refCnt() == 0) {
return
StringUtil.
simpleClassName(this) + "(freed)";
}
StringBuilder buf = new
StringBuilder()
.
append(
StringUtil.
simpleClassName(this))
.
append("(ridx: ").
append(
readerIndex)
.
append(", widx: ").
append(
writerIndex)
.
append(", cap: ").
append(
capacity());
if (
maxCapacity !=
Integer.
MAX_VALUE) {
buf.
append('/').
append(
maxCapacity);
}
ByteBuf unwrapped =
unwrap();
if (
unwrapped != null) {
buf.
append(", unwrapped: ").
append(
unwrapped);
}
buf.
append(')');
return
buf.
toString();
}
protected final void
checkIndex(int
index) {
checkIndex(
index, 1);
}
protected final void
checkIndex(int
index, int
fieldLength) {
ensureAccessible();
checkIndex0(
index,
fieldLength);
}
final void
checkIndex0(int
index, int
fieldLength) {
if (
isOutOfBounds(
index,
fieldLength,
capacity())) {
throw new
IndexOutOfBoundsException(
String.
format(
"index: %d, length: %d (expected: range(0, %d))",
index,
fieldLength,
capacity()));
}
}
protected final void
checkSrcIndex(int
index, int
length, int
srcIndex, int
srcCapacity) {
checkIndex(
index,
length);
if (
isOutOfBounds(
srcIndex,
length,
srcCapacity)) {
throw new
IndexOutOfBoundsException(
String.
format(
"srcIndex: %d, length: %d (expected: range(0, %d))",
srcIndex,
length,
srcCapacity));
}
}
protected final void
checkDstIndex(int
index, int
length, int
dstIndex, int
dstCapacity) {
checkIndex(
index,
length);
if (
isOutOfBounds(
dstIndex,
length,
dstCapacity)) {
throw new
IndexOutOfBoundsException(
String.
format(
"dstIndex: %d, length: %d (expected: range(0, %d))",
dstIndex,
length,
dstCapacity));
}
}
/**
* Throws an {@link IndexOutOfBoundsException} if the current
* {@linkplain #readableBytes() readable bytes} of this buffer is less
* than the specified value.
*/
protected final void
checkReadableBytes(int
minimumReadableBytes) {
if (
minimumReadableBytes < 0) {
throw new
IllegalArgumentException("minimumReadableBytes: " +
minimumReadableBytes + " (expected: >= 0)");
}
checkReadableBytes0(
minimumReadableBytes);
}
protected final void
checkNewCapacity(int
newCapacity) {
ensureAccessible();
if (
newCapacity < 0 ||
newCapacity >
maxCapacity()) {
throw new
IllegalArgumentException("newCapacity: " +
newCapacity + " (expected: 0-" +
maxCapacity() + ')');
}
}
private void
checkReadableBytes0(int
minimumReadableBytes) {
ensureAccessible();
if (
readerIndex >
writerIndex -
minimumReadableBytes) {
throw new
IndexOutOfBoundsException(
String.
format(
"readerIndex(%d) + length(%d) exceeds writerIndex(%d): %s",
readerIndex,
minimumReadableBytes,
writerIndex, this));
}
}
/**
* Should be called by every method that tries to access the buffers content to check
* if the buffer was released before.
*/
protected final void
ensureAccessible() {
if (
checkAccessible &&
refCnt() == 0) {
throw new
IllegalReferenceCountException(0);
}
}
final void
setIndex0(int
readerIndex, int
writerIndex) {
this.
readerIndex =
readerIndex;
this.
writerIndex =
writerIndex;
}
final void
discardMarks() {
markedReaderIndex =
markedWriterIndex = 0;
}
}