All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.xlightweb.ComposedByteBuffer Maven / Gradle / Ivy

Go to download

xLightweb is a lightweight, high performance, scalable web network library

There is a newer version: 2.13.2
Show newest version
/*
 *  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