org.xlightweb.ComposedByteBuffer Maven / Gradle / Ivy
/*
* Copyright (c) xlightweb.org, 2008. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Please refer to the LGPL license at: http://www.gnu.org/copyleft/lesser.txt
* The latest copy of this software may be found on http://www.xlightweb.org/
*/
package org.xlightweb;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
import org.xsocket.DataConverter;
import static org.xlightweb.HttpUtils.*;
/**
* Composed ByteBuffer
*
* @author [email protected]
*/
final class ComposedByteBuffer {
private ArrayList buffers = new ArrayList();
private int bufferIdx;
private ByteBuffer currentBuffer = null;
private int remainingCurrentBuffer;
private int remainingTotal;
/**
* appends data
* @param bufs the data to append
*/
void append(ByteBuffer[] bufs) {
if (bufs == null) {
return;
}
for (ByteBuffer byteBuffer : bufs) {
if ((byteBuffer != null) && (byteBuffer.hasRemaining())) {
remainingTotal += byteBuffer.remaining();
if (buffers.size() == 0) {
currentBuffer = bufs[0];
remainingCurrentBuffer = currentBuffer.remaining();
}
buffers.add(byteBuffer);
}
}
}
/**
* add data to the first position
* @param data the data to add
*/
void addFirst(byte[] data) {
List buffers = drain();
clear();
append(new ByteBuffer[] { ByteBuffer.wrap(data) });
append(buffers.toArray(new ByteBuffer[buffers.size()]));
}
/**
* read data by length
*
* @param length the numbers of bytes to read
* @param bufferSink the data sink to write the data
* @throws IOException if an exception occurs
*/
void readByteBufferByLength(int length, IBufferSink bufferSink) throws IOException {
// current buffer is empty?
if (remainingCurrentBuffer == 0) {
bufferIdx++;
currentBuffer = buffers.get(bufferIdx);
remainingCurrentBuffer = currentBuffer.remaining();
}
if (remainingCurrentBuffer == length) {
bufferSink.add(currentBuffer);
remainingTotal -= remainingCurrentBuffer;
remainingCurrentBuffer = 0;
} else if (remainingCurrentBuffer < length) {
int remainingRequired = length - remainingCurrentBuffer;
bufferSink.add(currentBuffer);
remainingTotal -= remainingCurrentBuffer;
remainingCurrentBuffer = 0;
readByteBufferByLength(remainingRequired, bufferSink); // recursive call
} else { // remainingCurrentBuffer > length
int savedLimit = currentBuffer.limit();
currentBuffer.limit(currentBuffer.position() + length);
ByteBuffer sliced = currentBuffer.slice();
bufferSink.add(sliced);
currentBuffer.position(currentBuffer.limit());
currentBuffer.limit(savedLimit);
remainingCurrentBuffer = currentBuffer.remaining();
remainingTotal -= length;
}
}
boolean readByteBufferByBoundaryDelimiter(String delimiter, IBufferSink bufferSink) throws IOException {
byte[] delimiterBytes = delimiter.getBytes("US-ASCII");
int length = indexOfBoundaryDelimiter(delimiterBytes);
if (length > 0) {
readByteBufferByLength(length, bufferSink);
return true;
} else {
if (remaining() > delimiterBytes.length) {
readByteBufferByLength(remaining() - delimiterBytes.length, bufferSink);
}
}
return false;
}
int indexOfBoundaryDelimiter(byte[] delimiter) {
int state = 1;
int pos = 0;
int length = 0;
for (int i = bufferIdx; i <= buffers.size(); i++) {
ByteBuffer buf = buffers.get(bufferIdx).duplicate();
while (buf.hasRemaining()) {
byte b = buf.get();
length++;
switch (state) {
case 1:
if (b == delimiter[pos]) {
pos++;
if (pos == delimiter.length) {
state = 2;
}
} else {
pos = 0;
}
break;
case 2:
if ((b == HTAB) || (b == SPACE)) {
break;
}
if (b == CR) {
state = 3;
} else {
pos = 0;
state = 1;
}
break;
case 3:
if ((b == HTAB) || (b == SPACE)) {
break;
}
if (b == LF) {
return length;
} else {
pos = 0;
state = 1;
}
break;
default:
break;
}
}
}
return 0;
}
/**
* return true if is empty
* @return true if is empty
*/
boolean isEmpty() {
return (remainingTotal == 0);
}
/**
* returns the number of remaining bytes
* @return the number of remaining bytes
*/
int remaining() {
return remainingTotal;
}
/**
* drains the buffer
*
* @return the data
*/
List drain() {
ArrayList result = null;
if (bufferIdx == 0) {
result = buffers;
buffers = new ArrayList();
} else {
result = new ArrayList();
for (int i = bufferIdx; i < buffers.size(); i++) {
result.add(buffers.get(i));
}
buffers = new ArrayList();
}
clear();
return result;
}
/**
* drains the buffer
*
* @param bufferSink the data sink to write the data
* @return the number of transfered bytes
* @throws IOException if an exctpion occurs
*/
int drain(IBufferSink bufferSink) throws IOException {
int read = 0;
for (int i = bufferIdx; i < buffers.size(); i++) {
ByteBuffer buffer = buffers.get(i);
read += buffer.remaining();
bufferSink.add(buffer);
}
clear();
return read;
}
/**
* returns the number of available bytes
* @return the number of available bytes
*/
int available() {
return remainingTotal;
}
/**
* return the next byte
* @return the next byte
*/
byte getByte() {
if (remainingCurrentBuffer > 0) {
assert (currentBuffer == buffers.get(bufferIdx));
// dec remaining
remainingTotal--;
remainingCurrentBuffer--;
// return byte
return currentBuffer.get();
} else {
bufferIdx++;
currentBuffer = buffers.get(bufferIdx);
remainingCurrentBuffer = currentBuffer.remaining();
return getByte();
}
}
/**
* clears the buffer
*/
void clear() {
buffers.clear();
bufferIdx = 0;
currentBuffer = null;
remainingCurrentBuffer = 0;
remainingTotal = 0;
}
/**
* {@inheritDoc}
*/
@Override
public String toString() {
List bufferCopy = new ArrayList();
for (int i = bufferIdx; i < buffers.size(); i++) {
bufferCopy.add(buffers.get(i).duplicate());
}
try {
return DataConverter.toString(bufferCopy, "US-ASCII");
} catch (UnsupportedEncodingException use) {
return DataConverter.toHexString(bufferCopy, Integer.MAX_VALUE);
}
}
/**
* buffer sink definition
* @author grro
*/
static interface IBufferSink {
/**
* add data
*
* @param buffer data
* @throws IOException if an exception occurs
*/
void add(ByteBuffer buffer) throws IOException;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy