2008-08-08 02:37:18 +02:00
|
|
|
/*
|
2009-08-28 09:15:49 +02:00
|
|
|
* Copyright 2009 Red Hat, Inc.
|
2008-08-08 02:37:18 +02:00
|
|
|
*
|
2009-08-28 09:15:49 +02:00
|
|
|
* Red Hat 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:
|
2008-08-08 02:37:18 +02:00
|
|
|
*
|
2009-08-28 09:15:49 +02:00
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
2008-08-08 03:27:24 +02:00
|
|
|
*
|
2009-08-28 09:15:49 +02:00
|
|
|
* 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.
|
2008-08-08 02:37:18 +02:00
|
|
|
*/
|
2008-08-08 03:40:10 +02:00
|
|
|
package org.jboss.netty.buffer;
|
2008-08-08 02:37:18 +02:00
|
|
|
|
|
|
|
import java.io.IOException;
|
|
|
|
import java.io.InputStream;
|
|
|
|
import java.io.OutputStream;
|
|
|
|
import java.nio.ByteBuffer;
|
|
|
|
import java.nio.ByteOrder;
|
|
|
|
import java.nio.channels.GatheringByteChannel;
|
|
|
|
import java.nio.channels.ScatteringByteChannel;
|
|
|
|
import java.util.ArrayList;
|
2009-10-13 10:03:05 +02:00
|
|
|
import java.util.Collections;
|
2008-08-08 02:37:18 +02:00
|
|
|
import java.util.List;
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
2008-09-02 09:13:20 +02:00
|
|
|
* A virtual buffer which shows multiple buffers as a single merged buffer. It
|
|
|
|
* is recommended to use {@link ChannelBuffers#wrappedBuffer(ChannelBuffer...)}
|
|
|
|
* instead of calling the constructor explicitly.
|
2008-08-10 07:52:36 +02:00
|
|
|
*
|
2010-01-26 10:04:19 +01:00
|
|
|
* @author <a href="http://www.jboss.org/netty/">The Netty Project</a>
|
|
|
|
* @author <a href="http://gleamynode.net/">Trustin Lee</a>
|
2009-10-14 07:35:03 +02:00
|
|
|
* @author Frederic Bregier (fredbregier@free.fr)
|
2008-08-08 02:37:18 +02:00
|
|
|
*/
|
|
|
|
public class CompositeChannelBuffer extends AbstractChannelBuffer {
|
|
|
|
|
2008-08-27 14:21:04 +02:00
|
|
|
private final ByteOrder order;
|
2009-10-13 10:35:22 +02:00
|
|
|
private ChannelBuffer[] components;
|
2009-10-13 09:54:18 +02:00
|
|
|
private int[] indices;
|
2009-10-13 10:35:22 +02:00
|
|
|
private int lastAccessedComponentId;
|
2008-08-08 02:37:18 +02:00
|
|
|
|
2009-11-03 03:34:54 +01:00
|
|
|
public CompositeChannelBuffer(ByteOrder endianness, List<ChannelBuffer> buffers) {
|
|
|
|
order = endianness;
|
|
|
|
setComponents(buffers);
|
2009-10-13 09:54:18 +02:00
|
|
|
}
|
|
|
|
|
2009-12-30 04:14:50 +01:00
|
|
|
/**
|
|
|
|
* Same with {@link #slice(int, int)} except that this method returns a list.
|
|
|
|
*/
|
|
|
|
public List<ChannelBuffer> decompose(int index, int length) {
|
|
|
|
if (length == 0) {
|
|
|
|
return Collections.emptyList();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (index + length > capacity()) {
|
|
|
|
throw new IndexOutOfBoundsException();
|
|
|
|
}
|
|
|
|
|
|
|
|
int componentId = componentId(index);
|
|
|
|
List<ChannelBuffer> slice = new ArrayList<ChannelBuffer>(components.length);
|
|
|
|
|
|
|
|
// The first component
|
|
|
|
ChannelBuffer first = components[componentId].duplicate();
|
|
|
|
first.readerIndex(index - indices[componentId]);
|
|
|
|
|
|
|
|
ChannelBuffer buf = first;
|
|
|
|
int bytesToSlice = length;
|
|
|
|
do {
|
|
|
|
int readableBytes = buf.readableBytes();
|
|
|
|
if (bytesToSlice <= readableBytes) {
|
|
|
|
// Last component
|
|
|
|
buf.writerIndex(buf.readerIndex() + bytesToSlice);
|
|
|
|
slice.add(buf);
|
|
|
|
break;
|
|
|
|
} else {
|
|
|
|
// Not the last component
|
|
|
|
slice.add(buf);
|
|
|
|
bytesToSlice -= readableBytes;
|
|
|
|
componentId ++;
|
|
|
|
|
|
|
|
// Fetch the next component.
|
|
|
|
buf = components[componentId].duplicate();
|
|
|
|
}
|
|
|
|
} while (bytesToSlice > 0);
|
|
|
|
|
|
|
|
// Slice all components because only readable bytes are interesting.
|
|
|
|
for (int i = 0; i < slice.size(); i ++) {
|
|
|
|
slice.set(i, slice.get(i).slice());
|
|
|
|
}
|
|
|
|
|
|
|
|
return slice;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Setup this ChannelBuffer from the list
|
|
|
|
*/
|
|
|
|
private void setComponents(List<ChannelBuffer> newComponents) {
|
|
|
|
assert !newComponents.isEmpty();
|
|
|
|
|
|
|
|
// Clear the cache.
|
|
|
|
lastAccessedComponentId = 0;
|
|
|
|
|
|
|
|
// Build the component array.
|
|
|
|
components = new ChannelBuffer[newComponents.size()];
|
|
|
|
for (int i = 0; i < components.length; i ++) {
|
|
|
|
ChannelBuffer c = newComponents.get(i);
|
|
|
|
if (c.order() != order()) {
|
|
|
|
throw new IllegalArgumentException(
|
|
|
|
"All buffers must have the same endianness.");
|
|
|
|
}
|
|
|
|
|
|
|
|
assert c.readerIndex() == 0;
|
|
|
|
assert c.writerIndex() == c.capacity();
|
|
|
|
|
|
|
|
components[i] = c;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Build the component lookup table.
|
2009-12-30 04:20:22 +01:00
|
|
|
indices = new int[components.length + 1];
|
2009-12-30 04:14:50 +01:00
|
|
|
indices[0] = 0;
|
|
|
|
for (int i = 1; i <= components.length; i ++) {
|
|
|
|
indices[i] = indices[i - 1] + components[i - 1].capacity();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Reset the indexes.
|
|
|
|
setIndex(0, capacity());
|
|
|
|
}
|
2008-08-08 02:37:18 +02:00
|
|
|
|
|
|
|
private CompositeChannelBuffer(CompositeChannelBuffer buffer) {
|
2008-08-27 14:21:04 +02:00
|
|
|
order = buffer.order;
|
2009-10-13 10:35:22 +02:00
|
|
|
components = buffer.components.clone();
|
2008-08-08 02:37:18 +02:00
|
|
|
indices = buffer.indices.clone();
|
|
|
|
setIndex(buffer.readerIndex(), buffer.writerIndex());
|
|
|
|
}
|
|
|
|
|
2010-11-12 01:45:39 +01:00
|
|
|
@Override
|
2008-12-08 09:20:34 +01:00
|
|
|
public ChannelBufferFactory factory() {
|
|
|
|
return HeapChannelBufferFactory.getInstance(order());
|
|
|
|
}
|
|
|
|
|
2010-11-12 01:45:39 +01:00
|
|
|
@Override
|
2008-08-08 02:37:18 +02:00
|
|
|
public ByteOrder order() {
|
2008-08-27 14:21:04 +02:00
|
|
|
return order;
|
2008-08-08 02:37:18 +02:00
|
|
|
}
|
|
|
|
|
2010-11-12 01:45:39 +01:00
|
|
|
@Override
|
2010-01-27 06:07:32 +01:00
|
|
|
public boolean isDirect() {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2010-11-12 01:45:39 +01:00
|
|
|
@Override
|
2009-11-25 08:08:52 +01:00
|
|
|
public boolean hasArray() {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2010-11-12 01:45:39 +01:00
|
|
|
@Override
|
2009-11-25 08:08:52 +01:00
|
|
|
public byte[] array() {
|
|
|
|
throw new UnsupportedOperationException();
|
|
|
|
}
|
|
|
|
|
2010-11-12 01:45:39 +01:00
|
|
|
@Override
|
2009-11-25 08:08:52 +01:00
|
|
|
public int arrayOffset() {
|
|
|
|
throw new UnsupportedOperationException();
|
|
|
|
}
|
|
|
|
|
2010-11-12 01:45:39 +01:00
|
|
|
@Override
|
2008-08-08 02:37:18 +02:00
|
|
|
public int capacity() {
|
2009-10-13 10:35:22 +02:00
|
|
|
return indices[components.length];
|
2008-08-08 02:37:18 +02:00
|
|
|
}
|
|
|
|
|
2010-11-12 01:45:39 +01:00
|
|
|
@Override
|
2008-08-08 02:37:18 +02:00
|
|
|
public byte getByte(int index) {
|
2009-10-13 10:35:22 +02:00
|
|
|
int componentId = componentId(index);
|
|
|
|
return components[componentId].getByte(index - indices[componentId]);
|
2008-08-08 02:37:18 +02:00
|
|
|
}
|
|
|
|
|
2010-11-12 01:45:39 +01:00
|
|
|
@Override
|
2008-08-08 02:37:18 +02:00
|
|
|
public short getShort(int index) {
|
2009-10-13 10:35:22 +02:00
|
|
|
int componentId = componentId(index);
|
|
|
|
if (index + 2 <= indices[componentId + 1]) {
|
|
|
|
return components[componentId].getShort(index - indices[componentId]);
|
2008-08-08 02:37:18 +02:00
|
|
|
} else if (order() == ByteOrder.BIG_ENDIAN) {
|
|
|
|
return (short) ((getByte(index) & 0xff) << 8 | getByte(index + 1) & 0xff);
|
|
|
|
} else {
|
|
|
|
return (short) (getByte(index) & 0xff | (getByte(index + 1) & 0xff) << 8);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-11-12 01:45:39 +01:00
|
|
|
@Override
|
2008-08-10 02:52:59 +02:00
|
|
|
public int getUnsignedMedium(int index) {
|
2009-10-13 10:35:22 +02:00
|
|
|
int componentId = componentId(index);
|
|
|
|
if (index + 3 <= indices[componentId + 1]) {
|
|
|
|
return components[componentId].getUnsignedMedium(index - indices[componentId]);
|
2008-08-08 02:37:18 +02:00
|
|
|
} else if (order() == ByteOrder.BIG_ENDIAN) {
|
|
|
|
return (getShort(index) & 0xffff) << 8 | getByte(index + 2) & 0xff;
|
|
|
|
} else {
|
|
|
|
return getShort(index) & 0xFFFF | (getByte(index + 2) & 0xFF) << 16;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-11-12 01:45:39 +01:00
|
|
|
@Override
|
2008-08-08 02:37:18 +02:00
|
|
|
public int getInt(int index) {
|
2009-10-13 10:35:22 +02:00
|
|
|
int componentId = componentId(index);
|
|
|
|
if (index + 4 <= indices[componentId + 1]) {
|
|
|
|
return components[componentId].getInt(index - indices[componentId]);
|
2008-08-08 02:37:18 +02:00
|
|
|
} else if (order() == ByteOrder.BIG_ENDIAN) {
|
|
|
|
return (getShort(index) & 0xffff) << 16 | getShort(index + 2) & 0xffff;
|
|
|
|
} else {
|
|
|
|
return getShort(index) & 0xFFFF | (getShort(index + 2) & 0xFFFF) << 16;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-11-12 01:45:39 +01:00
|
|
|
@Override
|
2008-08-08 02:37:18 +02:00
|
|
|
public long getLong(int index) {
|
2009-10-13 10:35:22 +02:00
|
|
|
int componentId = componentId(index);
|
|
|
|
if (index + 8 <= indices[componentId + 1]) {
|
|
|
|
return components[componentId].getLong(index - indices[componentId]);
|
2008-08-08 02:37:18 +02:00
|
|
|
} else if (order() == ByteOrder.BIG_ENDIAN) {
|
|
|
|
return (getInt(index) & 0xffffffffL) << 32 | getInt(index + 4) & 0xffffffffL;
|
|
|
|
} else {
|
|
|
|
return getInt(index) & 0xFFFFFFFFL | (getInt(index + 4) & 0xFFFFFFFFL) << 32;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-11-12 01:45:39 +01:00
|
|
|
@Override
|
2008-08-08 02:37:18 +02:00
|
|
|
public void getBytes(int index, byte[] dst, int dstIndex, int length) {
|
2009-10-13 10:35:22 +02:00
|
|
|
int componentId = componentId(index);
|
2008-08-26 09:30:41 +02:00
|
|
|
if (index > capacity() - length || dstIndex > dst.length - length) {
|
2008-08-08 02:37:18 +02:00
|
|
|
throw new IndexOutOfBoundsException();
|
|
|
|
}
|
|
|
|
|
2009-10-13 10:35:22 +02:00
|
|
|
int i = componentId;
|
2008-08-08 02:37:18 +02:00
|
|
|
while (length > 0) {
|
2009-10-13 10:35:22 +02:00
|
|
|
ChannelBuffer s = components[i];
|
2008-08-08 02:37:18 +02:00
|
|
|
int adjustment = indices[i];
|
|
|
|
int localLength = Math.min(length, s.capacity() - (index - adjustment));
|
|
|
|
s.getBytes(index - adjustment, dst, dstIndex, localLength);
|
|
|
|
index += localLength;
|
|
|
|
dstIndex += localLength;
|
|
|
|
length -= localLength;
|
|
|
|
i ++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-11-12 01:45:39 +01:00
|
|
|
@Override
|
2008-08-08 02:37:18 +02:00
|
|
|
public void getBytes(int index, ByteBuffer dst) {
|
2009-10-13 10:35:22 +02:00
|
|
|
int componentId = componentId(index);
|
2008-08-08 02:37:18 +02:00
|
|
|
int limit = dst.limit();
|
|
|
|
int length = dst.remaining();
|
2008-08-26 09:30:41 +02:00
|
|
|
if (index > capacity() - length) {
|
2008-08-08 02:37:18 +02:00
|
|
|
throw new IndexOutOfBoundsException();
|
|
|
|
}
|
|
|
|
|
2009-10-13 10:35:22 +02:00
|
|
|
int i = componentId;
|
2008-08-08 02:37:18 +02:00
|
|
|
try {
|
|
|
|
while (length > 0) {
|
2009-10-13 10:35:22 +02:00
|
|
|
ChannelBuffer s = components[i];
|
2008-08-08 02:37:18 +02:00
|
|
|
int adjustment = indices[i];
|
|
|
|
int localLength = Math.min(length, s.capacity() - (index - adjustment));
|
|
|
|
dst.limit(dst.position() + localLength);
|
|
|
|
s.getBytes(index - adjustment, dst);
|
|
|
|
index += localLength;
|
|
|
|
length -= localLength;
|
|
|
|
i ++;
|
|
|
|
}
|
|
|
|
} finally {
|
|
|
|
dst.limit(limit);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-11-12 01:45:39 +01:00
|
|
|
@Override
|
2008-08-08 02:37:18 +02:00
|
|
|
public void getBytes(int index, ChannelBuffer dst, int dstIndex, int length) {
|
2009-10-13 10:35:22 +02:00
|
|
|
int componentId = componentId(index);
|
2008-08-26 09:30:41 +02:00
|
|
|
if (index > capacity() - length || dstIndex > dst.capacity() - length) {
|
2008-08-08 02:37:18 +02:00
|
|
|
throw new IndexOutOfBoundsException();
|
|
|
|
}
|
|
|
|
|
2009-10-13 10:35:22 +02:00
|
|
|
int i = componentId;
|
2008-08-08 02:37:18 +02:00
|
|
|
while (length > 0) {
|
2009-10-13 10:35:22 +02:00
|
|
|
ChannelBuffer s = components[i];
|
2008-08-08 02:37:18 +02:00
|
|
|
int adjustment = indices[i];
|
|
|
|
int localLength = Math.min(length, s.capacity() - (index - adjustment));
|
|
|
|
s.getBytes(index - adjustment, dst, dstIndex, localLength);
|
|
|
|
index += localLength;
|
|
|
|
dstIndex += localLength;
|
|
|
|
length -= localLength;
|
|
|
|
i ++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-11-12 01:45:39 +01:00
|
|
|
@Override
|
2008-08-08 02:37:18 +02:00
|
|
|
public int getBytes(int index, GatheringByteChannel out, int length)
|
|
|
|
throws IOException {
|
|
|
|
// XXX Gathering write is not supported because of a known issue.
|
|
|
|
// See http://bugs.sun.com/view_bug.do?bug_id=6210541
|
2009-03-12 10:21:45 +01:00
|
|
|
// This issue appeared in 2004 and is still unresolved!?
|
2009-03-04 14:43:56 +01:00
|
|
|
return out.write(toByteBuffer(index, length));
|
2008-08-08 02:37:18 +02:00
|
|
|
}
|
|
|
|
|
2010-11-12 01:45:39 +01:00
|
|
|
@Override
|
2008-08-08 02:37:18 +02:00
|
|
|
public void getBytes(int index, OutputStream out, int length)
|
|
|
|
throws IOException {
|
2009-10-13 10:35:22 +02:00
|
|
|
int componentId = componentId(index);
|
2008-08-26 09:30:41 +02:00
|
|
|
if (index > capacity() - length) {
|
2008-08-08 02:37:18 +02:00
|
|
|
throw new IndexOutOfBoundsException();
|
|
|
|
}
|
|
|
|
|
2009-10-13 10:35:22 +02:00
|
|
|
int i = componentId;
|
2008-08-08 02:37:18 +02:00
|
|
|
while (length > 0) {
|
2009-10-13 10:35:22 +02:00
|
|
|
ChannelBuffer s = components[i];
|
2008-08-08 02:37:18 +02:00
|
|
|
int adjustment = indices[i];
|
|
|
|
int localLength = Math.min(length, s.capacity() - (index - adjustment));
|
|
|
|
s.getBytes(index - adjustment, out, localLength);
|
|
|
|
index += localLength;
|
|
|
|
length -= localLength;
|
|
|
|
i ++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-11-12 01:45:39 +01:00
|
|
|
@Override
|
2010-03-03 06:35:01 +01:00
|
|
|
public void setByte(int index, int value) {
|
2009-10-13 10:35:22 +02:00
|
|
|
int componentId = componentId(index);
|
|
|
|
components[componentId].setByte(index - indices[componentId], value);
|
2008-08-08 02:37:18 +02:00
|
|
|
}
|
|
|
|
|
2010-11-12 01:45:39 +01:00
|
|
|
@Override
|
2010-03-03 06:35:01 +01:00
|
|
|
public void setShort(int index, int value) {
|
2009-10-13 10:35:22 +02:00
|
|
|
int componentId = componentId(index);
|
|
|
|
if (index + 2 <= indices[componentId + 1]) {
|
|
|
|
components[componentId].setShort(index - indices[componentId], value);
|
2008-08-08 02:37:18 +02:00
|
|
|
} else if (order() == ByteOrder.BIG_ENDIAN) {
|
|
|
|
setByte(index, (byte) (value >>> 8));
|
|
|
|
setByte(index + 1, (byte) value);
|
|
|
|
} else {
|
|
|
|
setByte(index , (byte) value);
|
|
|
|
setByte(index + 1, (byte) (value >>> 8));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-11-12 01:45:39 +01:00
|
|
|
@Override
|
2008-08-08 02:37:18 +02:00
|
|
|
public void setMedium(int index, int value) {
|
2009-10-13 10:35:22 +02:00
|
|
|
int componentId = componentId(index);
|
|
|
|
if (index + 3 <= indices[componentId + 1]) {
|
|
|
|
components[componentId].setMedium(index - indices[componentId], value);
|
2008-08-08 02:37:18 +02:00
|
|
|
} else if (order() == ByteOrder.BIG_ENDIAN) {
|
2008-11-07 03:08:36 +01:00
|
|
|
setShort(index, (short) (value >> 8));
|
2008-08-08 02:37:18 +02:00
|
|
|
setByte(index + 2, (byte) value);
|
|
|
|
} else {
|
|
|
|
setShort(index , (short) value);
|
|
|
|
setByte (index + 2, (byte) (value >>> 16));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-11-12 01:45:39 +01:00
|
|
|
@Override
|
2008-08-08 02:37:18 +02:00
|
|
|
public void setInt(int index, int value) {
|
2009-10-13 10:35:22 +02:00
|
|
|
int componentId = componentId(index);
|
|
|
|
if (index + 4 <= indices[componentId + 1]) {
|
|
|
|
components[componentId].setInt(index - indices[componentId], value);
|
2008-08-08 02:37:18 +02:00
|
|
|
} else if (order() == ByteOrder.BIG_ENDIAN) {
|
|
|
|
setShort(index, (short) (value >>> 16));
|
|
|
|
setShort(index + 2, (short) value);
|
|
|
|
} else {
|
|
|
|
setShort(index , (short) value);
|
|
|
|
setShort(index + 2, (short) (value >>> 16));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-11-12 01:45:39 +01:00
|
|
|
@Override
|
2008-08-08 02:37:18 +02:00
|
|
|
public void setLong(int index, long value) {
|
2009-10-13 10:35:22 +02:00
|
|
|
int componentId = componentId(index);
|
|
|
|
if (index + 8 <= indices[componentId + 1]) {
|
|
|
|
components[componentId].setLong(index - indices[componentId], value);
|
2008-08-08 02:37:18 +02:00
|
|
|
} else if (order() == ByteOrder.BIG_ENDIAN) {
|
|
|
|
setInt(index, (int) (value >>> 32));
|
|
|
|
setInt(index + 4, (int) value);
|
|
|
|
} else {
|
|
|
|
setInt(index , (int) value);
|
|
|
|
setInt(index + 4, (int) (value >>> 32));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-11-12 01:45:39 +01:00
|
|
|
@Override
|
2008-08-08 02:37:18 +02:00
|
|
|
public void setBytes(int index, byte[] src, int srcIndex, int length) {
|
2009-10-13 10:35:22 +02:00
|
|
|
int componentId = componentId(index);
|
2008-08-26 09:30:41 +02:00
|
|
|
if (index > capacity() - length || srcIndex > src.length - length) {
|
2008-08-08 02:37:18 +02:00
|
|
|
throw new IndexOutOfBoundsException();
|
|
|
|
}
|
|
|
|
|
2009-10-13 10:35:22 +02:00
|
|
|
int i = componentId;
|
2008-08-08 02:37:18 +02:00
|
|
|
while (length > 0) {
|
2009-10-13 10:35:22 +02:00
|
|
|
ChannelBuffer s = components[i];
|
2008-08-08 02:37:18 +02:00
|
|
|
int adjustment = indices[i];
|
|
|
|
int localLength = Math.min(length, s.capacity() - (index - adjustment));
|
|
|
|
s.setBytes(index - adjustment, src, srcIndex, localLength);
|
|
|
|
index += localLength;
|
|
|
|
srcIndex += localLength;
|
|
|
|
length -= localLength;
|
|
|
|
i ++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-11-12 01:45:39 +01:00
|
|
|
@Override
|
2008-08-08 02:37:18 +02:00
|
|
|
public void setBytes(int index, ByteBuffer src) {
|
2009-10-13 10:35:22 +02:00
|
|
|
int componentId = componentId(index);
|
2008-08-08 02:37:18 +02:00
|
|
|
int limit = src.limit();
|
|
|
|
int length = src.remaining();
|
2008-08-26 09:30:41 +02:00
|
|
|
if (index > capacity() - length) {
|
2008-08-08 02:37:18 +02:00
|
|
|
throw new IndexOutOfBoundsException();
|
|
|
|
}
|
|
|
|
|
2009-10-13 10:35:22 +02:00
|
|
|
int i = componentId;
|
2008-08-08 02:37:18 +02:00
|
|
|
try {
|
|
|
|
while (length > 0) {
|
2009-10-13 10:35:22 +02:00
|
|
|
ChannelBuffer s = components[i];
|
2008-08-08 02:37:18 +02:00
|
|
|
int adjustment = indices[i];
|
|
|
|
int localLength = Math.min(length, s.capacity() - (index - adjustment));
|
|
|
|
src.limit(src.position() + localLength);
|
|
|
|
s.setBytes(index - adjustment, src);
|
|
|
|
index += localLength;
|
|
|
|
length -= localLength;
|
|
|
|
i ++;
|
|
|
|
}
|
|
|
|
} finally {
|
|
|
|
src.limit(limit);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-11-12 01:45:39 +01:00
|
|
|
@Override
|
2008-08-08 02:37:18 +02:00
|
|
|
public void setBytes(int index, ChannelBuffer src, int srcIndex, int length) {
|
2009-10-13 10:35:22 +02:00
|
|
|
int componentId = componentId(index);
|
2008-08-26 09:30:41 +02:00
|
|
|
if (index > capacity() - length || srcIndex > src.capacity() - length) {
|
2008-08-08 02:37:18 +02:00
|
|
|
throw new IndexOutOfBoundsException();
|
|
|
|
}
|
|
|
|
|
2009-10-13 10:35:22 +02:00
|
|
|
int i = componentId;
|
2008-08-08 02:37:18 +02:00
|
|
|
while (length > 0) {
|
2009-10-13 10:35:22 +02:00
|
|
|
ChannelBuffer s = components[i];
|
2008-08-08 02:37:18 +02:00
|
|
|
int adjustment = indices[i];
|
|
|
|
int localLength = Math.min(length, s.capacity() - (index - adjustment));
|
|
|
|
s.setBytes(index - adjustment, src, srcIndex, localLength);
|
|
|
|
index += localLength;
|
|
|
|
srcIndex += localLength;
|
|
|
|
length -= localLength;
|
|
|
|
i ++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-11-12 01:45:39 +01:00
|
|
|
@Override
|
2008-08-20 05:09:23 +02:00
|
|
|
public int setBytes(int index, InputStream in, int length)
|
2008-08-08 02:37:18 +02:00
|
|
|
throws IOException {
|
2009-10-13 10:35:22 +02:00
|
|
|
int componentId = componentId(index);
|
2008-08-26 09:30:41 +02:00
|
|
|
if (index > capacity() - length) {
|
2008-08-08 02:37:18 +02:00
|
|
|
throw new IndexOutOfBoundsException();
|
|
|
|
}
|
|
|
|
|
2009-10-13 10:35:22 +02:00
|
|
|
int i = componentId;
|
2008-08-20 05:09:23 +02:00
|
|
|
int readBytes = 0;
|
|
|
|
|
2008-08-26 09:12:04 +02:00
|
|
|
do {
|
2009-10-13 10:35:22 +02:00
|
|
|
ChannelBuffer s = components[i];
|
2008-08-08 02:37:18 +02:00
|
|
|
int adjustment = indices[i];
|
|
|
|
int localLength = Math.min(length, s.capacity() - (index - adjustment));
|
2008-08-20 05:09:23 +02:00
|
|
|
int localReadBytes = s.setBytes(index - adjustment, in, localLength);
|
|
|
|
if (localReadBytes < 0) {
|
|
|
|
if (readBytes == 0) {
|
|
|
|
return -1;
|
|
|
|
} else {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2008-08-26 09:12:04 +02:00
|
|
|
|
|
|
|
if (localReadBytes == localLength) {
|
|
|
|
index += localLength;
|
|
|
|
length -= localLength;
|
|
|
|
readBytes += localLength;
|
|
|
|
i ++;
|
|
|
|
} else {
|
|
|
|
index += localReadBytes;
|
|
|
|
length -= localReadBytes;
|
|
|
|
readBytes += localReadBytes;
|
|
|
|
}
|
|
|
|
} while (length > 0);
|
2008-08-20 05:09:23 +02:00
|
|
|
|
|
|
|
return readBytes;
|
2008-08-08 02:37:18 +02:00
|
|
|
}
|
|
|
|
|
2010-11-12 01:45:39 +01:00
|
|
|
@Override
|
2008-08-08 02:37:18 +02:00
|
|
|
public int setBytes(int index, ScatteringByteChannel in, int length)
|
|
|
|
throws IOException {
|
2009-10-13 10:35:22 +02:00
|
|
|
int componentId = componentId(index);
|
2008-08-26 09:30:41 +02:00
|
|
|
if (index > capacity() - length) {
|
2008-08-08 02:37:18 +02:00
|
|
|
throw new IndexOutOfBoundsException();
|
|
|
|
}
|
|
|
|
|
2009-10-13 10:35:22 +02:00
|
|
|
int i = componentId;
|
2008-08-26 09:12:04 +02:00
|
|
|
int readBytes = 0;
|
|
|
|
do {
|
2009-10-13 10:35:22 +02:00
|
|
|
ChannelBuffer s = components[i];
|
2008-08-08 02:37:18 +02:00
|
|
|
int adjustment = indices[i];
|
|
|
|
int localLength = Math.min(length, s.capacity() - (index - adjustment));
|
2008-08-26 09:12:04 +02:00
|
|
|
int localReadBytes = s.setBytes(index - adjustment, in, localLength);
|
|
|
|
|
|
|
|
if (localReadBytes == localLength) {
|
|
|
|
index += localLength;
|
|
|
|
length -= localLength;
|
|
|
|
readBytes += localLength;
|
|
|
|
i ++;
|
|
|
|
} else {
|
|
|
|
index += localReadBytes;
|
|
|
|
length -= localReadBytes;
|
|
|
|
readBytes += localReadBytes;
|
2008-08-08 02:37:18 +02:00
|
|
|
}
|
2008-08-26 09:12:04 +02:00
|
|
|
} while (length > 0);
|
2008-08-08 02:37:18 +02:00
|
|
|
|
2008-08-26 09:12:04 +02:00
|
|
|
return readBytes;
|
2008-08-08 02:37:18 +02:00
|
|
|
}
|
|
|
|
|
2010-11-12 01:45:39 +01:00
|
|
|
@Override
|
2008-08-08 02:37:18 +02:00
|
|
|
public ChannelBuffer duplicate() {
|
2008-08-26 13:08:55 +02:00
|
|
|
ChannelBuffer duplicate = new CompositeChannelBuffer(this);
|
|
|
|
duplicate.setIndex(readerIndex(), writerIndex());
|
|
|
|
return duplicate;
|
2008-08-08 02:37:18 +02:00
|
|
|
}
|
|
|
|
|
2010-11-12 01:45:39 +01:00
|
|
|
@Override
|
2008-08-08 02:37:18 +02:00
|
|
|
public ChannelBuffer copy(int index, int length) {
|
2009-10-13 10:35:22 +02:00
|
|
|
int componentId = componentId(index);
|
2008-08-26 09:30:41 +02:00
|
|
|
if (index > capacity() - length) {
|
2008-08-08 02:37:18 +02:00
|
|
|
throw new IndexOutOfBoundsException();
|
|
|
|
}
|
|
|
|
|
2008-12-08 09:20:34 +01:00
|
|
|
ChannelBuffer dst = factory().getBuffer(order(), length);
|
2009-10-13 10:35:22 +02:00
|
|
|
copyTo(index, length, componentId, dst);
|
2008-12-08 09:20:34 +01:00
|
|
|
return dst;
|
|
|
|
}
|
|
|
|
|
2009-10-13 10:35:22 +02:00
|
|
|
private void copyTo(int index, int length, int componentId, ChannelBuffer dst) {
|
2008-08-08 02:37:18 +02:00
|
|
|
int dstIndex = 0;
|
2009-10-13 10:35:22 +02:00
|
|
|
int i = componentId;
|
2008-08-08 02:37:18 +02:00
|
|
|
|
|
|
|
while (length > 0) {
|
2009-10-13 10:35:22 +02:00
|
|
|
ChannelBuffer s = components[i];
|
2008-08-08 02:37:18 +02:00
|
|
|
int adjustment = indices[i];
|
|
|
|
int localLength = Math.min(length, s.capacity() - (index - adjustment));
|
|
|
|
s.getBytes(index - adjustment, dst, dstIndex, localLength);
|
|
|
|
index += localLength;
|
|
|
|
dstIndex += localLength;
|
|
|
|
length -= localLength;
|
|
|
|
i ++;
|
|
|
|
}
|
|
|
|
|
|
|
|
dst.writerIndex(dst.capacity());
|
|
|
|
}
|
|
|
|
|
2010-11-12 01:45:39 +01:00
|
|
|
@Override
|
2008-08-08 02:37:18 +02:00
|
|
|
public ChannelBuffer slice(int index, int length) {
|
2008-08-27 14:21:04 +02:00
|
|
|
if (index == 0) {
|
|
|
|
if (length == 0) {
|
|
|
|
return ChannelBuffers.EMPTY_BUFFER;
|
|
|
|
}
|
|
|
|
} else if (index < 0 || index > capacity() - length) {
|
|
|
|
throw new IndexOutOfBoundsException();
|
|
|
|
} else if (length == 0) {
|
2008-08-26 17:37:08 +02:00
|
|
|
return ChannelBuffers.EMPTY_BUFFER;
|
|
|
|
}
|
2009-10-13 09:54:18 +02:00
|
|
|
|
2009-11-03 03:34:54 +01:00
|
|
|
List<ChannelBuffer> components = decompose(index, length);
|
|
|
|
switch (components.size()) {
|
|
|
|
case 0:
|
|
|
|
return ChannelBuffers.EMPTY_BUFFER;
|
|
|
|
case 1:
|
|
|
|
return components.get(0);
|
|
|
|
default:
|
|
|
|
return new CompositeChannelBuffer(order(), components);
|
|
|
|
}
|
2008-08-08 02:37:18 +02:00
|
|
|
}
|
|
|
|
|
2010-11-12 01:45:39 +01:00
|
|
|
@Override
|
2008-08-08 02:37:18 +02:00
|
|
|
public ByteBuffer toByteBuffer(int index, int length) {
|
2009-10-13 10:35:22 +02:00
|
|
|
if (components.length == 1) {
|
|
|
|
return components[0].toByteBuffer(index, length);
|
2008-08-08 12:17:26 +02:00
|
|
|
}
|
|
|
|
|
2008-08-08 02:37:18 +02:00
|
|
|
ByteBuffer[] buffers = toByteBuffers(index, length);
|
2009-06-15 08:13:50 +02:00
|
|
|
ByteBuffer merged = ByteBuffer.allocate(length).order(order());
|
2008-08-08 02:37:18 +02:00
|
|
|
for (ByteBuffer b: buffers) {
|
|
|
|
merged.put(b);
|
|
|
|
}
|
|
|
|
merged.flip();
|
|
|
|
return merged;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public ByteBuffer[] toByteBuffers(int index, int length) {
|
2009-10-13 10:35:22 +02:00
|
|
|
int componentId = componentId(index);
|
2008-08-08 02:37:18 +02:00
|
|
|
if (index + length > capacity()) {
|
|
|
|
throw new IndexOutOfBoundsException();
|
|
|
|
}
|
|
|
|
|
2009-10-13 10:35:22 +02:00
|
|
|
List<ByteBuffer> buffers = new ArrayList<ByteBuffer>(components.length);
|
2008-08-08 02:37:18 +02:00
|
|
|
|
2009-10-13 10:35:22 +02:00
|
|
|
int i = componentId;
|
2008-08-08 02:37:18 +02:00
|
|
|
while (length > 0) {
|
2009-10-13 10:35:22 +02:00
|
|
|
ChannelBuffer s = components[i];
|
2008-08-08 02:37:18 +02:00
|
|
|
int adjustment = indices[i];
|
|
|
|
int localLength = Math.min(length, s.capacity() - (index - adjustment));
|
|
|
|
buffers.add(s.toByteBuffer(index - adjustment, localLength));
|
|
|
|
index += localLength;
|
|
|
|
length -= localLength;
|
|
|
|
i ++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return buffers.toArray(new ByteBuffer[buffers.size()]);
|
|
|
|
}
|
|
|
|
|
2009-10-13 10:35:22 +02:00
|
|
|
private int componentId(int index) {
|
|
|
|
int lastComponentId = lastAccessedComponentId;
|
|
|
|
if (index >= indices[lastComponentId]) {
|
|
|
|
if (index < indices[lastComponentId + 1]) {
|
|
|
|
return lastComponentId;
|
2008-08-08 02:37:18 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Search right
|
2009-10-13 10:35:22 +02:00
|
|
|
for (int i = lastComponentId + 1; i < components.length; i ++) {
|
2008-08-08 02:37:18 +02:00
|
|
|
if (index < indices[i + 1]) {
|
2009-10-13 10:35:22 +02:00
|
|
|
lastAccessedComponentId = i;
|
2008-08-08 02:37:18 +02:00
|
|
|
return i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// Search left
|
2009-10-13 10:35:22 +02:00
|
|
|
for (int i = lastComponentId - 1; i >= 0; i --) {
|
2008-08-08 02:37:18 +02:00
|
|
|
if (index >= indices[i]) {
|
2009-10-13 10:35:22 +02:00
|
|
|
lastAccessedComponentId = i;
|
2008-08-08 02:37:18 +02:00
|
|
|
return i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
throw new IndexOutOfBoundsException();
|
|
|
|
}
|
2009-10-13 09:54:18 +02:00
|
|
|
|
|
|
|
@Override
|
|
|
|
public void discardReadBytes() {
|
|
|
|
// Only the bytes between readerIndex and writerIndex will be kept.
|
|
|
|
// New readerIndex and writerIndex will become 0 and
|
|
|
|
// (previous writerIndex - previous readerIndex) respectively.
|
|
|
|
|
|
|
|
final int localReaderIndex = this.readerIndex();
|
|
|
|
if (localReaderIndex == 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
int localWriterIndex = this.writerIndex();
|
|
|
|
|
|
|
|
final int bytesToMove = capacity() - localReaderIndex;
|
2009-11-03 03:34:54 +01:00
|
|
|
List<ChannelBuffer> list = decompose(localReaderIndex, bytesToMove);
|
2009-10-13 09:54:18 +02:00
|
|
|
|
|
|
|
// Add a new buffer so that the capacity of this composite buffer does
|
|
|
|
// not decrease due to the discarded components.
|
2009-10-13 10:35:22 +02:00
|
|
|
// XXX Might create too many components if discarded by small amount.
|
2009-10-13 10:51:25 +02:00
|
|
|
final ChannelBuffer padding = ChannelBuffers.buffer(order(), localReaderIndex);
|
|
|
|
padding.writerIndex(localReaderIndex);
|
|
|
|
list.add(padding);
|
2009-10-13 09:54:18 +02:00
|
|
|
|
|
|
|
// Reset the index markers to get the index marker values.
|
|
|
|
int localMarkedReaderIndex = localReaderIndex;
|
|
|
|
try {
|
|
|
|
resetReaderIndex();
|
|
|
|
localMarkedReaderIndex = this.readerIndex();
|
|
|
|
} catch (IndexOutOfBoundsException e) {
|
|
|
|
// ignore
|
|
|
|
}
|
|
|
|
int localMarkedWriterIndex = localWriterIndex;
|
|
|
|
try {
|
|
|
|
resetWriterIndex();
|
|
|
|
localMarkedWriterIndex = this.writerIndex();
|
|
|
|
} catch (IndexOutOfBoundsException e) {
|
|
|
|
// ignore
|
|
|
|
}
|
|
|
|
|
2009-10-13 10:46:41 +02:00
|
|
|
setComponents(list);
|
2009-10-13 09:54:18 +02:00
|
|
|
|
|
|
|
// reset marked Indexes
|
|
|
|
localMarkedReaderIndex = Math.max(localMarkedReaderIndex - localReaderIndex, 0);
|
|
|
|
localMarkedWriterIndex = Math.max(localMarkedWriterIndex - localReaderIndex, 0);
|
|
|
|
setIndex(localMarkedReaderIndex, localMarkedWriterIndex);
|
|
|
|
markReaderIndex();
|
|
|
|
markWriterIndex();
|
|
|
|
// reset real indexes
|
|
|
|
localWriterIndex = Math.max(localWriterIndex - localReaderIndex, 0);
|
|
|
|
setIndex(0, localWriterIndex);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public String toString() {
|
|
|
|
String result = super.toString();
|
|
|
|
result = result.substring(0, result.length() - 1);
|
2009-10-13 10:35:22 +02:00
|
|
|
return result + ", components=" + components.length + ")";
|
2009-10-13 09:54:18 +02:00
|
|
|
}
|
2008-08-08 02:37:18 +02:00
|
|
|
}
|