2495 lines
52 KiB
Java
2495 lines
52 KiB
Java
/*
|
|
* Licensed to the Apache Software Foundation (ASF) under one or more contributor license
|
|
* agreements. See the NOTICE file distributed with this work for additional information regarding
|
|
* copyright ownership. The ASF 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 com.google.code.yanf4j.buffer;
|
|
|
|
import java.io.EOFException;
|
|
import java.io.IOException;
|
|
import java.io.InputStream;
|
|
import java.io.ObjectInputStream;
|
|
import java.io.ObjectOutputStream;
|
|
import java.io.ObjectStreamClass;
|
|
import java.io.OutputStream;
|
|
import java.io.StreamCorruptedException;
|
|
import java.nio.BufferOverflowException;
|
|
import java.nio.BufferUnderflowException;
|
|
import java.nio.ByteBuffer;
|
|
import java.nio.ByteOrder;
|
|
import java.nio.CharBuffer;
|
|
import java.nio.DoubleBuffer;
|
|
import java.nio.FloatBuffer;
|
|
import java.nio.IntBuffer;
|
|
import java.nio.LongBuffer;
|
|
import java.nio.ShortBuffer;
|
|
import java.nio.charset.CharacterCodingException;
|
|
import java.nio.charset.CharsetDecoder;
|
|
import java.nio.charset.CharsetEncoder;
|
|
import java.nio.charset.CoderResult;
|
|
import java.util.EnumSet;
|
|
import java.util.Set;
|
|
|
|
/**
|
|
* A base implementation of {@link IoBuffer}. This implementation assumes that
|
|
* {@link IoBuffer#buf()} always returns a correct NIO {@link ByteBuffer} instance. Most
|
|
* implementations could extend this class and implement their own buffer management mechanism.
|
|
*
|
|
* @author The Apache MINA Project (dev@mina.apache.org)
|
|
* @version $Rev: 748210 $, $Date: 2009-02-26 18:05:40 +0100 (Thu, 26 Feb 2009) $
|
|
* @see IoBufferAllocator
|
|
*/
|
|
public abstract class AbstractIoBuffer extends IoBuffer {
|
|
/** Tells if a buffer has been created from an existing buffer */
|
|
private final boolean derived;
|
|
|
|
/** A flag set to true if the buffer can extend automatically */
|
|
private boolean autoExpand;
|
|
|
|
/** A flag set to true if the buffer can shrink automatically */
|
|
private boolean autoShrink;
|
|
|
|
/** Tells if a buffer can be expanded */
|
|
private boolean recapacityAllowed = true;
|
|
|
|
/** The minimum number of bytes the IoBuffer can hold */
|
|
private int minimumCapacity;
|
|
|
|
/** A mask for a byte */
|
|
private static final long BYTE_MASK = 0xFFL;
|
|
|
|
/** A mask for a short */
|
|
private static final long SHORT_MASK = 0xFFFFL;
|
|
|
|
/** A mask for an int */
|
|
private static final long INT_MASK = 0xFFFFFFFFL;
|
|
|
|
/**
|
|
* We don't have any access to Buffer.markValue(), so we need to track it down, which will cause
|
|
* small extra overhead.
|
|
*/
|
|
private int mark = -1;
|
|
|
|
/**
|
|
* Creates a new parent buffer.
|
|
*
|
|
* @param allocator The allocator to use to create new buffers
|
|
* @param initialCapacity The initial buffer capacity when created
|
|
*/
|
|
protected AbstractIoBuffer(IoBufferAllocator allocator, int initialCapacity) {
|
|
setAllocator(allocator);
|
|
this.recapacityAllowed = true;
|
|
this.derived = false;
|
|
this.minimumCapacity = initialCapacity;
|
|
}
|
|
|
|
/**
|
|
* Creates a new derived buffer. A derived buffer uses an existing buffer properties - the
|
|
* allocator and capacity -.
|
|
*
|
|
* @param parent The buffer we get the properties from
|
|
*/
|
|
protected AbstractIoBuffer(AbstractIoBuffer parent) {
|
|
setAllocator(parent.getAllocator());
|
|
this.recapacityAllowed = false;
|
|
this.derived = true;
|
|
this.minimumCapacity = parent.minimumCapacity;
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public final boolean isDirect() {
|
|
return buf().isDirect();
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public final boolean isReadOnly() {
|
|
return buf().isReadOnly();
|
|
}
|
|
|
|
/**
|
|
* Sets the underlying NIO buffer instance.
|
|
*
|
|
* @param newBuf The buffer to store within this IoBuffer
|
|
*/
|
|
protected abstract void buf(ByteBuffer newBuf);
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public final int minimumCapacity() {
|
|
return minimumCapacity;
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public final IoBuffer minimumCapacity(int minimumCapacity) {
|
|
if (minimumCapacity < 0) {
|
|
throw new IllegalArgumentException("minimumCapacity: " + minimumCapacity);
|
|
}
|
|
this.minimumCapacity = minimumCapacity;
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public final int capacity() {
|
|
return buf().capacity();
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public final IoBuffer capacity(int newCapacity) {
|
|
if (!recapacityAllowed) {
|
|
throw new IllegalStateException("Derived buffers and their parent can't be expanded.");
|
|
}
|
|
|
|
// Allocate a new buffer and transfer all settings to it.
|
|
if (newCapacity > capacity()) {
|
|
// Expand:
|
|
// // Save the state.
|
|
int pos = position();
|
|
int limit = limit();
|
|
ByteOrder bo = order();
|
|
|
|
// // Reallocate.
|
|
ByteBuffer oldBuf = buf();
|
|
ByteBuffer newBuf = getAllocator().allocateNioBuffer(newCapacity, isDirect());
|
|
oldBuf.clear();
|
|
newBuf.put(oldBuf);
|
|
buf(newBuf);
|
|
|
|
// // Restore the state.
|
|
buf().limit(limit);
|
|
if (mark >= 0) {
|
|
buf().position(mark);
|
|
buf().mark();
|
|
}
|
|
buf().position(pos);
|
|
buf().order(bo);
|
|
}
|
|
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public final boolean isAutoExpand() {
|
|
return autoExpand && recapacityAllowed;
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public final boolean isAutoShrink() {
|
|
return autoShrink && recapacityAllowed;
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public final boolean isDerived() {
|
|
return derived;
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public final IoBuffer setAutoExpand(boolean autoExpand) {
|
|
if (!recapacityAllowed) {
|
|
throw new IllegalStateException("Derived buffers and their parent can't be expanded.");
|
|
}
|
|
this.autoExpand = autoExpand;
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public final IoBuffer setAutoShrink(boolean autoShrink) {
|
|
if (!recapacityAllowed) {
|
|
throw new IllegalStateException("Derived buffers and their parent can't be shrinked.");
|
|
}
|
|
this.autoShrink = autoShrink;
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public final IoBuffer expand(int expectedRemaining) {
|
|
return expand(position(), expectedRemaining, false);
|
|
}
|
|
|
|
private IoBuffer expand(int expectedRemaining, boolean autoExpand) {
|
|
return expand(position(), expectedRemaining, autoExpand);
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public final IoBuffer expand(int pos, int expectedRemaining) {
|
|
return expand(pos, expectedRemaining, false);
|
|
}
|
|
|
|
private IoBuffer expand(int pos, int expectedRemaining, boolean autoExpand) {
|
|
if (!recapacityAllowed) {
|
|
throw new IllegalStateException("Derived buffers and their parent can't be expanded.");
|
|
}
|
|
|
|
int end = pos + expectedRemaining;
|
|
int newCapacity;
|
|
if (autoExpand) {
|
|
newCapacity = IoBuffer.normalizeCapacity(end);
|
|
} else {
|
|
newCapacity = end;
|
|
}
|
|
if (newCapacity > capacity()) {
|
|
// The buffer needs expansion.
|
|
capacity(newCapacity);
|
|
}
|
|
|
|
if (end > limit()) {
|
|
// We call limit() directly to prevent StackOverflowError
|
|
buf().limit(end);
|
|
}
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public final IoBuffer shrink() {
|
|
|
|
if (!recapacityAllowed) {
|
|
throw new IllegalStateException("Derived buffers and their parent can't be expanded.");
|
|
}
|
|
|
|
int position = position();
|
|
int capacity = capacity();
|
|
int limit = limit();
|
|
if (capacity == limit) {
|
|
return this;
|
|
}
|
|
|
|
int newCapacity = capacity;
|
|
int minCapacity = Math.max(minimumCapacity, limit);
|
|
for (;;) {
|
|
if (newCapacity >>> 1 < minCapacity) {
|
|
break;
|
|
}
|
|
newCapacity >>>= 1;
|
|
}
|
|
|
|
newCapacity = Math.max(minCapacity, newCapacity);
|
|
|
|
if (newCapacity == capacity) {
|
|
return this;
|
|
}
|
|
|
|
// Shrink and compact:
|
|
// // Save the state.
|
|
ByteOrder bo = order();
|
|
|
|
// // Reallocate.
|
|
ByteBuffer oldBuf = buf();
|
|
ByteBuffer newBuf = getAllocator().allocateNioBuffer(newCapacity, isDirect());
|
|
oldBuf.position(0);
|
|
oldBuf.limit(limit);
|
|
newBuf.put(oldBuf);
|
|
buf(newBuf);
|
|
|
|
// // Restore the state.
|
|
buf().position(position);
|
|
buf().limit(limit);
|
|
buf().order(bo);
|
|
mark = -1;
|
|
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public final int position() {
|
|
return buf().position();
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public final IoBuffer position(int newPosition) {
|
|
autoExpand(newPosition, 0);
|
|
buf().position(newPosition);
|
|
if (mark > newPosition) {
|
|
mark = -1;
|
|
}
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public final int limit() {
|
|
return buf().limit();
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public final IoBuffer limit(int newLimit) {
|
|
autoExpand(newLimit, 0);
|
|
buf().limit(newLimit);
|
|
if (mark > newLimit) {
|
|
mark = -1;
|
|
}
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public final IoBuffer mark() {
|
|
buf().mark();
|
|
mark = position();
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public final int markValue() {
|
|
return mark;
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public final IoBuffer reset() {
|
|
buf().reset();
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public final IoBuffer clear() {
|
|
buf().clear();
|
|
mark = -1;
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public final IoBuffer sweep() {
|
|
clear();
|
|
return fillAndReset(remaining());
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public final IoBuffer sweep(byte value) {
|
|
clear();
|
|
return fillAndReset(value, remaining());
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public final IoBuffer flip() {
|
|
buf().flip();
|
|
mark = -1;
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public final IoBuffer rewind() {
|
|
buf().rewind();
|
|
mark = -1;
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public final int remaining() {
|
|
return limit() - position();
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public final boolean hasRemaining() {
|
|
return limit() > position();
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public final byte get() {
|
|
return buf().get();
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public final short getUnsigned() {
|
|
return (short) (get() & 0xff);
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public final IoBuffer put(byte b) {
|
|
autoExpand(1);
|
|
buf().put(b);
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public final byte get(int index) {
|
|
return buf().get(index);
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public final short getUnsigned(int index) {
|
|
return (short) (get(index) & 0xff);
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public final IoBuffer put(int index, byte b) {
|
|
autoExpand(index, 1);
|
|
buf().put(index, b);
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public final IoBuffer get(byte[] dst, int offset, int length) {
|
|
buf().get(dst, offset, length);
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public final IoBuffer put(ByteBuffer src) {
|
|
autoExpand(src.remaining());
|
|
buf().put(src);
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public final IoBuffer put(byte[] src, int offset, int length) {
|
|
autoExpand(length);
|
|
buf().put(src, offset, length);
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public final IoBuffer compact() {
|
|
int remaining = remaining();
|
|
int capacity = capacity();
|
|
|
|
if (capacity == 0) {
|
|
return this;
|
|
}
|
|
|
|
if (isAutoShrink() && remaining <= capacity >>> 2 && capacity > minimumCapacity) {
|
|
int newCapacity = capacity;
|
|
int minCapacity = Math.max(minimumCapacity, remaining << 1);
|
|
for (;;) {
|
|
if (newCapacity >>> 1 < minCapacity) {
|
|
break;
|
|
}
|
|
newCapacity >>>= 1;
|
|
}
|
|
|
|
newCapacity = Math.max(minCapacity, newCapacity);
|
|
|
|
if (newCapacity == capacity) {
|
|
return this;
|
|
}
|
|
|
|
// Shrink and compact:
|
|
// // Save the state.
|
|
ByteOrder bo = order();
|
|
|
|
// // Sanity check.
|
|
if (remaining > newCapacity) {
|
|
throw new IllegalStateException(
|
|
"The amount of the remaining bytes is greater than " + "the new capacity.");
|
|
}
|
|
|
|
// // Reallocate.
|
|
ByteBuffer oldBuf = buf();
|
|
ByteBuffer newBuf = getAllocator().allocateNioBuffer(newCapacity, isDirect());
|
|
newBuf.put(oldBuf);
|
|
buf(newBuf);
|
|
|
|
// // Restore the state.
|
|
buf().order(bo);
|
|
} else {
|
|
buf().compact();
|
|
}
|
|
mark = -1;
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public final ByteOrder order() {
|
|
return buf().order();
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public final IoBuffer order(ByteOrder bo) {
|
|
buf().order(bo);
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public final char getChar() {
|
|
return buf().getChar();
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public final IoBuffer putChar(char value) {
|
|
autoExpand(2);
|
|
buf().putChar(value);
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public final char getChar(int index) {
|
|
return buf().getChar(index);
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public final IoBuffer putChar(int index, char value) {
|
|
autoExpand(index, 2);
|
|
buf().putChar(index, value);
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public final CharBuffer asCharBuffer() {
|
|
return buf().asCharBuffer();
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public final short getShort() {
|
|
return buf().getShort();
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public final IoBuffer putShort(short value) {
|
|
autoExpand(2);
|
|
buf().putShort(value);
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public final short getShort(int index) {
|
|
return buf().getShort(index);
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public final IoBuffer putShort(int index, short value) {
|
|
autoExpand(index, 2);
|
|
buf().putShort(index, value);
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public final ShortBuffer asShortBuffer() {
|
|
return buf().asShortBuffer();
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public final int getInt() {
|
|
return buf().getInt();
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public final IoBuffer putInt(int value) {
|
|
autoExpand(4);
|
|
buf().putInt(value);
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public final int getInt(int index) {
|
|
return buf().getInt(index);
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public final IoBuffer putInt(int index, int value) {
|
|
autoExpand(index, 4);
|
|
buf().putInt(index, value);
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public final IntBuffer asIntBuffer() {
|
|
return buf().asIntBuffer();
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public final long getLong() {
|
|
return buf().getLong();
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public final IoBuffer putLong(long value) {
|
|
autoExpand(8);
|
|
buf().putLong(value);
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public final long getLong(int index) {
|
|
return buf().getLong(index);
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public final IoBuffer putLong(int index, long value) {
|
|
autoExpand(index, 8);
|
|
buf().putLong(index, value);
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public final LongBuffer asLongBuffer() {
|
|
return buf().asLongBuffer();
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public final float getFloat() {
|
|
return buf().getFloat();
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public final IoBuffer putFloat(float value) {
|
|
autoExpand(4);
|
|
buf().putFloat(value);
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public final float getFloat(int index) {
|
|
return buf().getFloat(index);
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public final IoBuffer putFloat(int index, float value) {
|
|
autoExpand(index, 4);
|
|
buf().putFloat(index, value);
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public final FloatBuffer asFloatBuffer() {
|
|
return buf().asFloatBuffer();
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public final double getDouble() {
|
|
return buf().getDouble();
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public final IoBuffer putDouble(double value) {
|
|
autoExpand(8);
|
|
buf().putDouble(value);
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public final double getDouble(int index) {
|
|
return buf().getDouble(index);
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public final IoBuffer putDouble(int index, double value) {
|
|
autoExpand(index, 8);
|
|
buf().putDouble(index, value);
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public final DoubleBuffer asDoubleBuffer() {
|
|
return buf().asDoubleBuffer();
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public final IoBuffer asReadOnlyBuffer() {
|
|
recapacityAllowed = false;
|
|
return asReadOnlyBuffer0();
|
|
}
|
|
|
|
/**
|
|
* Implement this method to return the unexpandable read only version of this buffer.
|
|
*/
|
|
protected abstract IoBuffer asReadOnlyBuffer0();
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public final IoBuffer duplicate() {
|
|
recapacityAllowed = false;
|
|
return duplicate0();
|
|
}
|
|
|
|
/**
|
|
* Implement this method to return the unexpandable duplicate of this buffer.
|
|
*/
|
|
protected abstract IoBuffer duplicate0();
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public final IoBuffer slice() {
|
|
recapacityAllowed = false;
|
|
return slice0();
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public final IoBuffer getSlice(int index, int length) {
|
|
if (length < 0) {
|
|
throw new IllegalArgumentException("length: " + length);
|
|
}
|
|
|
|
int limit = limit();
|
|
|
|
if (index > limit) {
|
|
throw new IllegalArgumentException("index: " + index);
|
|
}
|
|
|
|
int endIndex = index + length;
|
|
|
|
if (capacity() < endIndex) {
|
|
throw new IndexOutOfBoundsException(
|
|
"index + length (" + endIndex + ") is greater " + "than capacity (" + capacity() + ").");
|
|
}
|
|
|
|
clear();
|
|
position(index);
|
|
limit(endIndex);
|
|
|
|
IoBuffer slice = slice();
|
|
position(index);
|
|
limit(limit);
|
|
return slice;
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public final IoBuffer getSlice(int length) {
|
|
if (length < 0) {
|
|
throw new IllegalArgumentException("length: " + length);
|
|
}
|
|
int pos = position();
|
|
int limit = limit();
|
|
int nextPos = pos + length;
|
|
if (limit < nextPos) {
|
|
throw new IndexOutOfBoundsException(
|
|
"position + length (" + nextPos + ") is greater " + "than limit (" + limit + ").");
|
|
}
|
|
|
|
limit(pos + length);
|
|
IoBuffer slice = slice();
|
|
position(nextPos);
|
|
limit(limit);
|
|
return slice;
|
|
}
|
|
|
|
/**
|
|
* Implement this method to return the unexpandable slice of this buffer.
|
|
*/
|
|
protected abstract IoBuffer slice0();
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public int hashCode() {
|
|
int h = 1;
|
|
int p = position();
|
|
for (int i = limit() - 1; i >= p; i--) {
|
|
h = 31 * h + get(i);
|
|
}
|
|
return h;
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public boolean equals(Object o) {
|
|
if (!(o instanceof IoBuffer)) {
|
|
return false;
|
|
}
|
|
|
|
IoBuffer that = (IoBuffer) o;
|
|
if (this.remaining() != that.remaining()) {
|
|
return false;
|
|
}
|
|
|
|
int p = this.position();
|
|
for (int i = this.limit() - 1, j = that.limit() - 1; i >= p; i--, j--) {
|
|
byte v1 = this.get(i);
|
|
byte v2 = that.get(j);
|
|
if (v1 != v2) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
public int compareTo(IoBuffer that) {
|
|
int n = this.position() + Math.min(this.remaining(), that.remaining());
|
|
for (int i = this.position(), j = that.position(); i < n; i++, j++) {
|
|
byte v1 = this.get(i);
|
|
byte v2 = that.get(j);
|
|
if (v1 == v2) {
|
|
continue;
|
|
}
|
|
if (v1 < v2) {
|
|
return -1;
|
|
}
|
|
|
|
return +1;
|
|
}
|
|
return this.remaining() - that.remaining();
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public String toString() {
|
|
StringBuilder buf = new StringBuilder();
|
|
if (isDirect()) {
|
|
buf.append("DirectBuffer");
|
|
} else {
|
|
buf.append("HeapBuffer");
|
|
}
|
|
buf.append("[pos=");
|
|
buf.append(position());
|
|
buf.append(" lim=");
|
|
buf.append(limit());
|
|
buf.append(" cap=");
|
|
buf.append(capacity());
|
|
buf.append(": ");
|
|
buf.append(getHexDump(16));
|
|
buf.append(']');
|
|
return buf.toString();
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public IoBuffer get(byte[] dst) {
|
|
return get(dst, 0, dst.length);
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public IoBuffer put(IoBuffer src) {
|
|
return put(src.buf());
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public IoBuffer put(byte[] src) {
|
|
return put(src, 0, src.length);
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public int getUnsignedShort() {
|
|
return getShort() & 0xffff;
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public int getUnsignedShort(int index) {
|
|
return getShort(index) & 0xffff;
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public long getUnsignedInt() {
|
|
return getInt() & 0xffffffffL;
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public int getMediumInt() {
|
|
byte b1 = get();
|
|
byte b2 = get();
|
|
byte b3 = get();
|
|
if (ByteOrder.BIG_ENDIAN.equals(order())) {
|
|
return getMediumInt(b1, b2, b3);
|
|
} else {
|
|
return getMediumInt(b3, b2, b1);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public int getUnsignedMediumInt() {
|
|
int b1 = getUnsigned();
|
|
int b2 = getUnsigned();
|
|
int b3 = getUnsigned();
|
|
if (ByteOrder.BIG_ENDIAN.equals(order())) {
|
|
return b1 << 16 | b2 << 8 | b3;
|
|
} else {
|
|
return b3 << 16 | b2 << 8 | b1;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public int getMediumInt(int index) {
|
|
byte b1 = get(index);
|
|
byte b2 = get(index + 1);
|
|
byte b3 = get(index + 2);
|
|
if (ByteOrder.BIG_ENDIAN.equals(order())) {
|
|
return getMediumInt(b1, b2, b3);
|
|
} else {
|
|
return getMediumInt(b3, b2, b1);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public int getUnsignedMediumInt(int index) {
|
|
int b1 = getUnsigned(index);
|
|
int b2 = getUnsigned(index + 1);
|
|
int b3 = getUnsigned(index + 2);
|
|
if (ByteOrder.BIG_ENDIAN.equals(order())) {
|
|
return b1 << 16 | b2 << 8 | b3;
|
|
} else {
|
|
return b3 << 16 | b2 << 8 | b1;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
private int getMediumInt(byte b1, byte b2, byte b3) {
|
|
int ret = b1 << 16 & 0xff0000 | b2 << 8 & 0xff00 | b3 & 0xff;
|
|
// Check to see if the medium int is negative (high bit in b1 set)
|
|
if ((b1 & 0x80) == 0x80) {
|
|
// Make the the whole int negative
|
|
ret |= 0xff000000;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public IoBuffer putMediumInt(int value) {
|
|
byte b1 = (byte) (value >> 16);
|
|
byte b2 = (byte) (value >> 8);
|
|
byte b3 = (byte) value;
|
|
|
|
if (ByteOrder.BIG_ENDIAN.equals(order())) {
|
|
put(b1).put(b2).put(b3);
|
|
} else {
|
|
put(b3).put(b2).put(b1);
|
|
}
|
|
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public IoBuffer putMediumInt(int index, int value) {
|
|
byte b1 = (byte) (value >> 16);
|
|
byte b2 = (byte) (value >> 8);
|
|
byte b3 = (byte) value;
|
|
|
|
if (ByteOrder.BIG_ENDIAN.equals(order())) {
|
|
put(index, b1).put(index + 1, b2).put(index + 2, b3);
|
|
} else {
|
|
put(index, b3).put(index + 1, b2).put(index + 2, b1);
|
|
}
|
|
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public long getUnsignedInt(int index) {
|
|
return getInt(index) & 0xffffffffL;
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public InputStream asInputStream() {
|
|
return new InputStream() {
|
|
@Override
|
|
public int available() {
|
|
return AbstractIoBuffer.this.remaining();
|
|
}
|
|
|
|
@Override
|
|
public synchronized void mark(int readlimit) {
|
|
AbstractIoBuffer.this.mark();
|
|
}
|
|
|
|
@Override
|
|
public boolean markSupported() {
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
public int read() {
|
|
if (AbstractIoBuffer.this.hasRemaining()) {
|
|
return AbstractIoBuffer.this.get() & 0xff;
|
|
} else {
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public int read(byte[] b, int off, int len) {
|
|
int remaining = AbstractIoBuffer.this.remaining();
|
|
if (remaining > 0) {
|
|
int readBytes = Math.min(remaining, len);
|
|
AbstractIoBuffer.this.get(b, off, readBytes);
|
|
return readBytes;
|
|
} else {
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public synchronized void reset() {
|
|
AbstractIoBuffer.this.reset();
|
|
}
|
|
|
|
@Override
|
|
public long skip(long n) {
|
|
int bytes;
|
|
if (n > Integer.MAX_VALUE) {
|
|
bytes = AbstractIoBuffer.this.remaining();
|
|
} else {
|
|
bytes = Math.min(AbstractIoBuffer.this.remaining(), (int) n);
|
|
}
|
|
AbstractIoBuffer.this.skip(bytes);
|
|
return bytes;
|
|
}
|
|
};
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public OutputStream asOutputStream() {
|
|
return new OutputStream() {
|
|
@Override
|
|
public void write(byte[] b, int off, int len) {
|
|
AbstractIoBuffer.this.put(b, off, len);
|
|
}
|
|
|
|
@Override
|
|
public void write(int b) {
|
|
AbstractIoBuffer.this.put((byte) b);
|
|
}
|
|
};
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public String getHexDump() {
|
|
return this.getHexDump(Integer.MAX_VALUE);
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public String getHexDump(int lengthLimit) {
|
|
return IoBufferHexDumper.getHexdump(this, lengthLimit);
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public String getString(CharsetDecoder decoder) throws CharacterCodingException {
|
|
if (!hasRemaining()) {
|
|
return "";
|
|
}
|
|
|
|
boolean utf16 = decoder.charset().name().startsWith("UTF-16");
|
|
|
|
int oldPos = position();
|
|
int oldLimit = limit();
|
|
int end = -1;
|
|
int newPos;
|
|
|
|
if (!utf16) {
|
|
end = indexOf((byte) 0x00);
|
|
if (end < 0) {
|
|
newPos = end = oldLimit;
|
|
} else {
|
|
newPos = end + 1;
|
|
}
|
|
} else {
|
|
int i = oldPos;
|
|
for (;;) {
|
|
boolean wasZero = get(i) == 0;
|
|
i++;
|
|
|
|
if (i >= oldLimit) {
|
|
break;
|
|
}
|
|
|
|
if (get(i) != 0) {
|
|
i++;
|
|
if (i >= oldLimit) {
|
|
break;
|
|
} else {
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if (wasZero) {
|
|
end = i - 1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (end < 0) {
|
|
newPos = end = oldPos + (oldLimit - oldPos & 0xFFFFFFFE);
|
|
} else {
|
|
if (end + 2 <= oldLimit) {
|
|
newPos = end + 2;
|
|
} else {
|
|
newPos = end;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (oldPos == end) {
|
|
position(newPos);
|
|
return "";
|
|
}
|
|
|
|
limit(end);
|
|
decoder.reset();
|
|
|
|
int expectedLength = (int) (remaining() * decoder.averageCharsPerByte()) + 1;
|
|
CharBuffer out = CharBuffer.allocate(expectedLength);
|
|
for (;;) {
|
|
CoderResult cr;
|
|
if (hasRemaining()) {
|
|
cr = decoder.decode(buf(), out, true);
|
|
} else {
|
|
cr = decoder.flush(out);
|
|
}
|
|
|
|
if (cr.isUnderflow()) {
|
|
break;
|
|
}
|
|
|
|
if (cr.isOverflow()) {
|
|
CharBuffer o = CharBuffer.allocate(out.capacity() + expectedLength);
|
|
out.flip();
|
|
o.put(out);
|
|
out = o;
|
|
continue;
|
|
}
|
|
|
|
if (cr.isError()) {
|
|
// Revert the buffer back to the previous state.
|
|
limit(oldLimit);
|
|
position(oldPos);
|
|
cr.throwException();
|
|
}
|
|
}
|
|
|
|
limit(oldLimit);
|
|
position(newPos);
|
|
return out.flip().toString();
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public String getString(int fieldSize, CharsetDecoder decoder) throws CharacterCodingException {
|
|
checkFieldSize(fieldSize);
|
|
|
|
if (fieldSize == 0) {
|
|
return "";
|
|
}
|
|
|
|
if (!hasRemaining()) {
|
|
return "";
|
|
}
|
|
|
|
boolean utf16 = decoder.charset().name().startsWith("UTF-16");
|
|
|
|
if (utf16 && (fieldSize & 1) != 0) {
|
|
throw new IllegalArgumentException("fieldSize is not even.");
|
|
}
|
|
|
|
int oldPos = position();
|
|
int oldLimit = limit();
|
|
int end = oldPos + fieldSize;
|
|
|
|
if (oldLimit < end) {
|
|
throw new BufferUnderflowException();
|
|
}
|
|
|
|
int i;
|
|
|
|
if (!utf16) {
|
|
for (i = oldPos; i < end; i++) {
|
|
if (get(i) == 0) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (i == end) {
|
|
limit(end);
|
|
} else {
|
|
limit(i);
|
|
}
|
|
} else {
|
|
for (i = oldPos; i < end; i += 2) {
|
|
if (get(i) == 0 && get(i + 1) == 0) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (i == end) {
|
|
limit(end);
|
|
} else {
|
|
limit(i);
|
|
}
|
|
}
|
|
|
|
if (!hasRemaining()) {
|
|
limit(oldLimit);
|
|
position(end);
|
|
return "";
|
|
}
|
|
decoder.reset();
|
|
|
|
int expectedLength = (int) (remaining() * decoder.averageCharsPerByte()) + 1;
|
|
CharBuffer out = CharBuffer.allocate(expectedLength);
|
|
for (;;) {
|
|
CoderResult cr;
|
|
if (hasRemaining()) {
|
|
cr = decoder.decode(buf(), out, true);
|
|
} else {
|
|
cr = decoder.flush(out);
|
|
}
|
|
|
|
if (cr.isUnderflow()) {
|
|
break;
|
|
}
|
|
|
|
if (cr.isOverflow()) {
|
|
CharBuffer o = CharBuffer.allocate(out.capacity() + expectedLength);
|
|
out.flip();
|
|
o.put(out);
|
|
out = o;
|
|
continue;
|
|
}
|
|
|
|
if (cr.isError()) {
|
|
// Revert the buffer back to the previous state.
|
|
limit(oldLimit);
|
|
position(oldPos);
|
|
cr.throwException();
|
|
}
|
|
}
|
|
|
|
limit(oldLimit);
|
|
position(end);
|
|
return out.flip().toString();
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public IoBuffer putString(CharSequence val, CharsetEncoder encoder)
|
|
throws CharacterCodingException {
|
|
if (val.length() == 0) {
|
|
return this;
|
|
}
|
|
|
|
CharBuffer in = CharBuffer.wrap(val);
|
|
encoder.reset();
|
|
|
|
int expandedState = 0;
|
|
|
|
for (;;) {
|
|
CoderResult cr;
|
|
if (in.hasRemaining()) {
|
|
cr = encoder.encode(in, buf(), true);
|
|
} else {
|
|
cr = encoder.flush(buf());
|
|
}
|
|
|
|
if (cr.isUnderflow()) {
|
|
break;
|
|
}
|
|
if (cr.isOverflow()) {
|
|
if (isAutoExpand()) {
|
|
switch (expandedState) {
|
|
case 0:
|
|
autoExpand((int) Math.ceil(in.remaining() * encoder.averageBytesPerChar()));
|
|
expandedState++;
|
|
break;
|
|
case 1:
|
|
autoExpand((int) Math.ceil(in.remaining() * encoder.maxBytesPerChar()));
|
|
expandedState++;
|
|
break;
|
|
default:
|
|
throw new RuntimeException(
|
|
"Expanded by " + (int) Math.ceil(in.remaining() * encoder.maxBytesPerChar())
|
|
+ " but that wasn't enough for '" + val + "'");
|
|
}
|
|
continue;
|
|
}
|
|
} else {
|
|
expandedState = 0;
|
|
}
|
|
cr.throwException();
|
|
}
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public IoBuffer putString(CharSequence val, int fieldSize, CharsetEncoder encoder)
|
|
throws CharacterCodingException {
|
|
checkFieldSize(fieldSize);
|
|
|
|
if (fieldSize == 0) {
|
|
return this;
|
|
}
|
|
|
|
autoExpand(fieldSize);
|
|
|
|
boolean utf16 = encoder.charset().name().startsWith("UTF-16");
|
|
|
|
if (utf16 && (fieldSize & 1) != 0) {
|
|
throw new IllegalArgumentException("fieldSize is not even.");
|
|
}
|
|
|
|
int oldLimit = limit();
|
|
int end = position() + fieldSize;
|
|
|
|
if (oldLimit < end) {
|
|
throw new BufferOverflowException();
|
|
}
|
|
|
|
if (val.length() == 0) {
|
|
if (!utf16) {
|
|
put((byte) 0x00);
|
|
} else {
|
|
put((byte) 0x00);
|
|
put((byte) 0x00);
|
|
}
|
|
position(end);
|
|
return this;
|
|
}
|
|
|
|
CharBuffer in = CharBuffer.wrap(val);
|
|
limit(end);
|
|
encoder.reset();
|
|
|
|
for (;;) {
|
|
CoderResult cr;
|
|
if (in.hasRemaining()) {
|
|
cr = encoder.encode(in, buf(), true);
|
|
} else {
|
|
cr = encoder.flush(buf());
|
|
}
|
|
|
|
if (cr.isUnderflow() || cr.isOverflow()) {
|
|
break;
|
|
}
|
|
cr.throwException();
|
|
}
|
|
|
|
limit(oldLimit);
|
|
|
|
if (position() < end) {
|
|
if (!utf16) {
|
|
put((byte) 0x00);
|
|
} else {
|
|
put((byte) 0x00);
|
|
put((byte) 0x00);
|
|
}
|
|
}
|
|
|
|
position(end);
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public String getPrefixedString(CharsetDecoder decoder) throws CharacterCodingException {
|
|
return getPrefixedString(2, decoder);
|
|
}
|
|
|
|
/**
|
|
* Reads a string which has a length field before the actual encoded string, using the specified
|
|
* <code>decoder</code> and returns it.
|
|
*
|
|
* @param prefixLength the length of the length field (1, 2, or 4)
|
|
* @param decoder the decoder to use for decoding the string
|
|
* @return the prefixed string
|
|
* @throws CharacterCodingException when decoding fails
|
|
* @throws BufferUnderflowException when there is not enough data available
|
|
*/
|
|
@Override
|
|
public String getPrefixedString(int prefixLength, CharsetDecoder decoder)
|
|
throws CharacterCodingException {
|
|
if (!prefixedDataAvailable(prefixLength)) {
|
|
throw new BufferUnderflowException();
|
|
}
|
|
|
|
int fieldSize = 0;
|
|
|
|
switch (prefixLength) {
|
|
case 1:
|
|
fieldSize = getUnsigned();
|
|
break;
|
|
case 2:
|
|
fieldSize = getUnsignedShort();
|
|
break;
|
|
case 4:
|
|
fieldSize = getInt();
|
|
break;
|
|
}
|
|
|
|
if (fieldSize == 0) {
|
|
return "";
|
|
}
|
|
|
|
boolean utf16 = decoder.charset().name().startsWith("UTF-16");
|
|
|
|
if (utf16 && (fieldSize & 1) != 0) {
|
|
throw new BufferDataException("fieldSize is not even for a UTF-16 string.");
|
|
}
|
|
|
|
int oldLimit = limit();
|
|
int end = position() + fieldSize;
|
|
|
|
if (oldLimit < end) {
|
|
throw new BufferUnderflowException();
|
|
}
|
|
|
|
limit(end);
|
|
decoder.reset();
|
|
|
|
int expectedLength = (int) (remaining() * decoder.averageCharsPerByte()) + 1;
|
|
CharBuffer out = CharBuffer.allocate(expectedLength);
|
|
for (;;) {
|
|
CoderResult cr;
|
|
if (hasRemaining()) {
|
|
cr = decoder.decode(buf(), out, true);
|
|
} else {
|
|
cr = decoder.flush(out);
|
|
}
|
|
|
|
if (cr.isUnderflow()) {
|
|
break;
|
|
}
|
|
|
|
if (cr.isOverflow()) {
|
|
CharBuffer o = CharBuffer.allocate(out.capacity() + expectedLength);
|
|
out.flip();
|
|
o.put(out);
|
|
out = o;
|
|
continue;
|
|
}
|
|
|
|
cr.throwException();
|
|
}
|
|
|
|
limit(oldLimit);
|
|
position(end);
|
|
return out.flip().toString();
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public IoBuffer putPrefixedString(CharSequence in, CharsetEncoder encoder)
|
|
throws CharacterCodingException {
|
|
return putPrefixedString(in, 2, 0, encoder);
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public IoBuffer putPrefixedString(CharSequence in, int prefixLength, CharsetEncoder encoder)
|
|
throws CharacterCodingException {
|
|
return putPrefixedString(in, prefixLength, 0, encoder);
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public IoBuffer putPrefixedString(CharSequence in, int prefixLength, int padding,
|
|
CharsetEncoder encoder) throws CharacterCodingException {
|
|
return putPrefixedString(in, prefixLength, padding, (byte) 0, encoder);
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public IoBuffer putPrefixedString(CharSequence val, int prefixLength, int padding, byte padValue,
|
|
CharsetEncoder encoder) throws CharacterCodingException {
|
|
int maxLength;
|
|
switch (prefixLength) {
|
|
case 1:
|
|
maxLength = 255;
|
|
break;
|
|
case 2:
|
|
maxLength = 65535;
|
|
break;
|
|
case 4:
|
|
maxLength = Integer.MAX_VALUE;
|
|
break;
|
|
default:
|
|
throw new IllegalArgumentException("prefixLength: " + prefixLength);
|
|
}
|
|
|
|
if (val.length() > maxLength) {
|
|
throw new IllegalArgumentException("The specified string is too long.");
|
|
}
|
|
if (val.length() == 0) {
|
|
switch (prefixLength) {
|
|
case 1:
|
|
put((byte) 0);
|
|
break;
|
|
case 2:
|
|
putShort((short) 0);
|
|
break;
|
|
case 4:
|
|
putInt(0);
|
|
break;
|
|
}
|
|
return this;
|
|
}
|
|
|
|
int padMask;
|
|
switch (padding) {
|
|
case 0:
|
|
case 1:
|
|
padMask = 0;
|
|
break;
|
|
case 2:
|
|
padMask = 1;
|
|
break;
|
|
case 4:
|
|
padMask = 3;
|
|
break;
|
|
default:
|
|
throw new IllegalArgumentException("padding: " + padding);
|
|
}
|
|
|
|
CharBuffer in = CharBuffer.wrap(val);
|
|
skip(prefixLength); // make a room for the length field
|
|
int oldPos = position();
|
|
encoder.reset();
|
|
|
|
int expandedState = 0;
|
|
|
|
for (;;) {
|
|
CoderResult cr;
|
|
if (in.hasRemaining()) {
|
|
cr = encoder.encode(in, buf(), true);
|
|
} else {
|
|
cr = encoder.flush(buf());
|
|
}
|
|
|
|
if (position() - oldPos > maxLength) {
|
|
throw new IllegalArgumentException("The specified string is too long.");
|
|
}
|
|
|
|
if (cr.isUnderflow()) {
|
|
break;
|
|
}
|
|
if (cr.isOverflow()) {
|
|
if (isAutoExpand()) {
|
|
switch (expandedState) {
|
|
case 0:
|
|
autoExpand((int) Math.ceil(in.remaining() * encoder.averageBytesPerChar()));
|
|
expandedState++;
|
|
break;
|
|
case 1:
|
|
autoExpand((int) Math.ceil(in.remaining() * encoder.maxBytesPerChar()));
|
|
expandedState++;
|
|
break;
|
|
default:
|
|
throw new RuntimeException(
|
|
"Expanded by " + (int) Math.ceil(in.remaining() * encoder.maxBytesPerChar())
|
|
+ " but that wasn't enough for '" + val + "'");
|
|
}
|
|
continue;
|
|
}
|
|
} else {
|
|
expandedState = 0;
|
|
}
|
|
cr.throwException();
|
|
}
|
|
|
|
// Write the length field
|
|
fill(padValue, padding - (position() - oldPos & padMask));
|
|
int length = position() - oldPos;
|
|
switch (prefixLength) {
|
|
case 1:
|
|
put(oldPos - 1, (byte) length);
|
|
break;
|
|
case 2:
|
|
putShort(oldPos - 2, (short) length);
|
|
break;
|
|
case 4:
|
|
putInt(oldPos - 4, length);
|
|
break;
|
|
}
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public Object getObject() throws ClassNotFoundException {
|
|
return getObject(Thread.currentThread().getContextClassLoader());
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public Object getObject(final ClassLoader classLoader) throws ClassNotFoundException {
|
|
if (!prefixedDataAvailable(4)) {
|
|
throw new BufferUnderflowException();
|
|
}
|
|
|
|
int length = getInt();
|
|
if (length <= 4) {
|
|
throw new BufferDataException("Object length should be greater than 4: " + length);
|
|
}
|
|
|
|
int oldLimit = limit();
|
|
limit(position() + length);
|
|
try {
|
|
ObjectInputStream in = new ObjectInputStream(asInputStream()) {
|
|
@Override
|
|
protected ObjectStreamClass readClassDescriptor()
|
|
throws IOException, ClassNotFoundException {
|
|
int type = read();
|
|
if (type < 0) {
|
|
throw new EOFException();
|
|
}
|
|
switch (type) {
|
|
case 0: // Primitive types
|
|
return super.readClassDescriptor();
|
|
case 1: // Non-primitive types
|
|
String className = readUTF();
|
|
Class<?> clazz = Class.forName(className, true, classLoader);
|
|
return ObjectStreamClass.lookup(clazz);
|
|
default:
|
|
throw new StreamCorruptedException("Unexpected class descriptor type: " + type);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
protected Class<?> resolveClass(ObjectStreamClass desc)
|
|
throws IOException, ClassNotFoundException {
|
|
String name = desc.getName();
|
|
try {
|
|
return Class.forName(name, false, classLoader);
|
|
} catch (ClassNotFoundException ex) {
|
|
return super.resolveClass(desc);
|
|
}
|
|
}
|
|
};
|
|
return in.readObject();
|
|
} catch (IOException e) {
|
|
throw new BufferDataException(e);
|
|
} finally {
|
|
limit(oldLimit);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public IoBuffer putObject(Object o) {
|
|
int oldPos = position();
|
|
skip(4); // Make a room for the length field.
|
|
try {
|
|
ObjectOutputStream out = new ObjectOutputStream(asOutputStream()) {
|
|
@Override
|
|
protected void writeClassDescriptor(ObjectStreamClass desc) throws IOException {
|
|
if (desc.forClass().isPrimitive()) {
|
|
write(0);
|
|
super.writeClassDescriptor(desc);
|
|
} else {
|
|
write(1);
|
|
writeUTF(desc.getName());
|
|
}
|
|
}
|
|
};
|
|
out.writeObject(o);
|
|
out.flush();
|
|
} catch (IOException e) {
|
|
throw new BufferDataException(e);
|
|
}
|
|
|
|
// Fill the length field
|
|
int newPos = position();
|
|
position(oldPos);
|
|
putInt(newPos - oldPos - 4);
|
|
position(newPos);
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public boolean prefixedDataAvailable(int prefixLength) {
|
|
return prefixedDataAvailable(prefixLength, Integer.MAX_VALUE);
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public boolean prefixedDataAvailable(int prefixLength, int maxDataLength) {
|
|
if (remaining() < prefixLength) {
|
|
return false;
|
|
}
|
|
|
|
int dataLength;
|
|
switch (prefixLength) {
|
|
case 1:
|
|
dataLength = getUnsigned(position());
|
|
break;
|
|
case 2:
|
|
dataLength = getUnsignedShort(position());
|
|
break;
|
|
case 4:
|
|
dataLength = getInt(position());
|
|
break;
|
|
default:
|
|
throw new IllegalArgumentException("prefixLength: " + prefixLength);
|
|
}
|
|
|
|
if (dataLength < 0 || dataLength > maxDataLength) {
|
|
throw new BufferDataException("dataLength: " + dataLength);
|
|
}
|
|
|
|
return remaining() - prefixLength >= dataLength;
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public int indexOf(byte b) {
|
|
if (hasArray()) {
|
|
int arrayOffset = arrayOffset();
|
|
int beginPos = arrayOffset + position();
|
|
int limit = arrayOffset + limit();
|
|
byte[] array = array();
|
|
|
|
for (int i = beginPos; i < limit; i++) {
|
|
if (array[i] == b) {
|
|
return i - arrayOffset;
|
|
}
|
|
}
|
|
} else {
|
|
int beginPos = position();
|
|
int limit = limit();
|
|
|
|
for (int i = beginPos; i < limit; i++) {
|
|
if (get(i) == b) {
|
|
return i;
|
|
}
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public IoBuffer skip(int size) {
|
|
autoExpand(size);
|
|
return position(position() + size);
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public IoBuffer fill(byte value, int size) {
|
|
autoExpand(size);
|
|
int q = size >>> 3;
|
|
int r = size & 7;
|
|
|
|
if (q > 0) {
|
|
int intValue = value | value << 8 | value << 16 | value << 24;
|
|
long longValue = intValue;
|
|
longValue <<= 32;
|
|
longValue |= intValue;
|
|
|
|
for (int i = q; i > 0; i--) {
|
|
putLong(longValue);
|
|
}
|
|
}
|
|
|
|
q = r >>> 2;
|
|
r = r & 3;
|
|
|
|
if (q > 0) {
|
|
int intValue = value | value << 8 | value << 16 | value << 24;
|
|
putInt(intValue);
|
|
}
|
|
|
|
q = r >> 1;
|
|
r = r & 1;
|
|
|
|
if (q > 0) {
|
|
short shortValue = (short) (value | value << 8);
|
|
putShort(shortValue);
|
|
}
|
|
|
|
if (r > 0) {
|
|
put(value);
|
|
}
|
|
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public IoBuffer fillAndReset(byte value, int size) {
|
|
autoExpand(size);
|
|
int pos = position();
|
|
try {
|
|
fill(value, size);
|
|
} finally {
|
|
position(pos);
|
|
}
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public IoBuffer fill(int size) {
|
|
autoExpand(size);
|
|
int q = size >>> 3;
|
|
int r = size & 7;
|
|
|
|
for (int i = q; i > 0; i--) {
|
|
putLong(0L);
|
|
}
|
|
|
|
q = r >>> 2;
|
|
r = r & 3;
|
|
|
|
if (q > 0) {
|
|
putInt(0);
|
|
}
|
|
|
|
q = r >> 1;
|
|
r = r & 1;
|
|
|
|
if (q > 0) {
|
|
putShort((short) 0);
|
|
}
|
|
|
|
if (r > 0) {
|
|
put((byte) 0);
|
|
}
|
|
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public IoBuffer fillAndReset(int size) {
|
|
autoExpand(size);
|
|
int pos = position();
|
|
try {
|
|
fill(size);
|
|
} finally {
|
|
position(pos);
|
|
}
|
|
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public <E extends Enum<E>> E getEnum(Class<E> enumClass) {
|
|
return toEnum(enumClass, getUnsigned());
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public <E extends Enum<E>> E getEnum(int index, Class<E> enumClass) {
|
|
return toEnum(enumClass, getUnsigned(index));
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public <E extends Enum<E>> E getEnumShort(Class<E> enumClass) {
|
|
return toEnum(enumClass, getUnsignedShort());
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public <E extends Enum<E>> E getEnumShort(int index, Class<E> enumClass) {
|
|
return toEnum(enumClass, getUnsignedShort(index));
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public <E extends Enum<E>> E getEnumInt(Class<E> enumClass) {
|
|
return toEnum(enumClass, getInt());
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public <E extends Enum<E>> E getEnumInt(int index, Class<E> enumClass) {
|
|
return toEnum(enumClass, getInt(index));
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public IoBuffer putEnum(Enum<?> e) {
|
|
if (e.ordinal() > BYTE_MASK) {
|
|
throw new IllegalArgumentException(enumConversionErrorMessage(e, "byte"));
|
|
}
|
|
return put((byte) e.ordinal());
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public IoBuffer putEnum(int index, Enum<?> e) {
|
|
if (e.ordinal() > BYTE_MASK) {
|
|
throw new IllegalArgumentException(enumConversionErrorMessage(e, "byte"));
|
|
}
|
|
return put(index, (byte) e.ordinal());
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public IoBuffer putEnumShort(Enum<?> e) {
|
|
if (e.ordinal() > SHORT_MASK) {
|
|
throw new IllegalArgumentException(enumConversionErrorMessage(e, "short"));
|
|
}
|
|
return putShort((short) e.ordinal());
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public IoBuffer putEnumShort(int index, Enum<?> e) {
|
|
if (e.ordinal() > SHORT_MASK) {
|
|
throw new IllegalArgumentException(enumConversionErrorMessage(e, "short"));
|
|
}
|
|
return putShort(index, (short) e.ordinal());
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public IoBuffer putEnumInt(Enum<?> e) {
|
|
return putInt(e.ordinal());
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public IoBuffer putEnumInt(int index, Enum<?> e) {
|
|
return putInt(index, e.ordinal());
|
|
}
|
|
|
|
private <E> E toEnum(Class<E> enumClass, int i) {
|
|
E[] enumConstants = enumClass.getEnumConstants();
|
|
if (i > enumConstants.length) {
|
|
throw new IndexOutOfBoundsException(String.format(
|
|
"%d is too large of an ordinal to convert to the enum %s", i, enumClass.getName()));
|
|
}
|
|
return enumConstants[i];
|
|
}
|
|
|
|
private String enumConversionErrorMessage(Enum<?> e, String type) {
|
|
return String.format("%s.%s has an ordinal value too large for a %s", e.getClass().getName(),
|
|
e.name(), type);
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public <E extends Enum<E>> EnumSet<E> getEnumSet(Class<E> enumClass) {
|
|
return toEnumSet(enumClass, get() & BYTE_MASK);
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public <E extends Enum<E>> EnumSet<E> getEnumSet(int index, Class<E> enumClass) {
|
|
return toEnumSet(enumClass, get(index) & BYTE_MASK);
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public <E extends Enum<E>> EnumSet<E> getEnumSetShort(Class<E> enumClass) {
|
|
return toEnumSet(enumClass, getShort() & SHORT_MASK);
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public <E extends Enum<E>> EnumSet<E> getEnumSetShort(int index, Class<E> enumClass) {
|
|
return toEnumSet(enumClass, getShort(index) & SHORT_MASK);
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public <E extends Enum<E>> EnumSet<E> getEnumSetInt(Class<E> enumClass) {
|
|
return toEnumSet(enumClass, getInt() & INT_MASK);
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public <E extends Enum<E>> EnumSet<E> getEnumSetInt(int index, Class<E> enumClass) {
|
|
return toEnumSet(enumClass, getInt(index) & INT_MASK);
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public <E extends Enum<E>> EnumSet<E> getEnumSetLong(Class<E> enumClass) {
|
|
return toEnumSet(enumClass, getLong());
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public <E extends Enum<E>> EnumSet<E> getEnumSetLong(int index, Class<E> enumClass) {
|
|
return toEnumSet(enumClass, getLong(index));
|
|
}
|
|
|
|
private <E extends Enum<E>> EnumSet<E> toEnumSet(Class<E> clazz, long vector) {
|
|
EnumSet<E> set = EnumSet.noneOf(clazz);
|
|
long mask = 1;
|
|
for (E e : clazz.getEnumConstants()) {
|
|
if ((mask & vector) == mask) {
|
|
set.add(e);
|
|
}
|
|
mask <<= 1;
|
|
}
|
|
return set;
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public <E extends Enum<E>> IoBuffer putEnumSet(Set<E> set) {
|
|
long vector = toLong(set);
|
|
if ((vector & ~BYTE_MASK) != 0) {
|
|
throw new IllegalArgumentException("The enum set is too large to fit in a byte: " + set);
|
|
}
|
|
return put((byte) vector);
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public <E extends Enum<E>> IoBuffer putEnumSet(int index, Set<E> set) {
|
|
long vector = toLong(set);
|
|
if ((vector & ~BYTE_MASK) != 0) {
|
|
throw new IllegalArgumentException("The enum set is too large to fit in a byte: " + set);
|
|
}
|
|
return put(index, (byte) vector);
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public <E extends Enum<E>> IoBuffer putEnumSetShort(Set<E> set) {
|
|
long vector = toLong(set);
|
|
if ((vector & ~SHORT_MASK) != 0) {
|
|
throw new IllegalArgumentException("The enum set is too large to fit in a short: " + set);
|
|
}
|
|
return putShort((short) vector);
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public <E extends Enum<E>> IoBuffer putEnumSetShort(int index, Set<E> set) {
|
|
long vector = toLong(set);
|
|
if ((vector & ~SHORT_MASK) != 0) {
|
|
throw new IllegalArgumentException("The enum set is too large to fit in a short: " + set);
|
|
}
|
|
return putShort(index, (short) vector);
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public <E extends Enum<E>> IoBuffer putEnumSetInt(Set<E> set) {
|
|
long vector = toLong(set);
|
|
if ((vector & ~INT_MASK) != 0) {
|
|
throw new IllegalArgumentException("The enum set is too large to fit in an int: " + set);
|
|
}
|
|
return putInt((int) vector);
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public <E extends Enum<E>> IoBuffer putEnumSetInt(int index, Set<E> set) {
|
|
long vector = toLong(set);
|
|
if ((vector & ~INT_MASK) != 0) {
|
|
throw new IllegalArgumentException("The enum set is too large to fit in an int: " + set);
|
|
}
|
|
return putInt(index, (int) vector);
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public <E extends Enum<E>> IoBuffer putEnumSetLong(Set<E> set) {
|
|
return putLong(toLong(set));
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
@Override
|
|
public <E extends Enum<E>> IoBuffer putEnumSetLong(int index, Set<E> set) {
|
|
return putLong(index, toLong(set));
|
|
}
|
|
|
|
private <E extends Enum<E>> long toLong(Set<E> set) {
|
|
long vector = 0;
|
|
for (E e : set) {
|
|
if (e.ordinal() >= Long.SIZE) {
|
|
throw new IllegalArgumentException(
|
|
"The enum set is too large to fit in a bit vector: " + set);
|
|
}
|
|
vector |= 1L << e.ordinal();
|
|
}
|
|
return vector;
|
|
}
|
|
|
|
/**
|
|
* This method forwards the call to {@link #expand(int)} only when <code>autoExpand</code> property is
|
|
* <code>true</code>.
|
|
*/
|
|
private IoBuffer autoExpand(int expectedRemaining) {
|
|
if (isAutoExpand()) {
|
|
expand(expectedRemaining, true);
|
|
}
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* This method forwards the call to {@link #expand(int)} only when <code>autoExpand</code> property is
|
|
* <code>true</code>.
|
|
*/
|
|
private IoBuffer autoExpand(int pos, int expectedRemaining) {
|
|
if (isAutoExpand()) {
|
|
expand(pos, expectedRemaining, true);
|
|
}
|
|
return this;
|
|
}
|
|
|
|
private static void checkFieldSize(int fieldSize) {
|
|
if (fieldSize < 0) {
|
|
throw new IllegalArgumentException("fieldSize cannot be negative: " + fieldSize);
|
|
}
|
|
}
|
|
}
|