blob: 1a4f0072d6681642db253f2ab06a8d00f6a89961 [file] [log] [blame]
/*
*
* 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.
*
*/
using System;
using System.Text;
namespace Qpid.Buffer
{
public enum ByteOrder { BigEndian, LittleEndian }
// /// <summary>
// /// A buffer that manages an underlying byte oriented stream, and writes and reads to and from it in
// /// BIG ENDIAN order.
// /// </summary>
// public abstract class ByteBuffer
// {
// protected const int MINIMUM_CAPACITY = 1;
//
// protected static Stack _containerStack = new Stack();
//
// protected static Stack[] _heapBufferStacks = new Stack[]
// {
// new Stack(), new Stack(), new Stack(), new Stack(),
// new Stack(), new Stack(), new Stack(), new Stack(),
// new Stack(), new Stack(), new Stack(), new Stack(),
// new Stack(), new Stack(), new Stack(), new Stack(),
// new Stack(), new Stack(), new Stack(), new Stack(),
// new Stack(), new Stack(), new Stack(), new Stack(),
// new Stack(), new Stack(), new Stack(), new Stack(),
// new Stack(), new Stack(), new Stack(), new Stack()
// };
//
// /// <summary>
// /// Returns the direct or heap buffer which is capable of the specified size.
// /// Currently does not support direct buffers but this will be an option in future.
// /// </summary>
// /// <param name="capacity">The capacity.</param>
// /// <returns></returns>
// public static ByteBuffer Allocate(int capacity)
// {
// // for now, just allocate a heap buffer but in future could do an optimised "direct" buffer
// // that is implemented natively
// return Allocate(capacity, false);
// }
//
// public static ByteBuffer Allocate(int capacity, bool direct)
// {
// ByteBuffer buffer = Allocate0(capacity, direct);
// RefCountingByteBuffer buf = AllocateContainer();
// buf.Init(buffer);
// return buf;
// }
//
// private static RefCountingByteBuffer AllocateContainer()
// {
// RefCountingByteBuffer buf = null;
// lock (_containerStack)
// {
// if (_containerStack.Count > 0)
// {
// buf = (RefCountingByteBuffer) _containerStack.Pop();
// }
// }
//
// if (buf == null)
// {
// buf = new RefCountingByteBuffer();
// }
// return buf;
// }
//
// protected static ByteBuffer Allocate0(int capacity, bool direct)
// {
// if (direct)
// {
// throw new NotSupportedException("Direct buffers not currently implemented");
// }
// int idx = GetBufferStackIndex(_heapBufferStacks, capacity);
// Stack stack = _heapBufferStacks[idx];
// ByteBuffer buf = null;
// lock (stack)
// {
// if (stack.Count > 0)
// {
// buf = (ByteBuffer) stack.Pop();
// }
// }
//
// if (buf == null)
// {
// buf = new HeapByteBuffer(MINIMUM_CAPACITY << idx);
// }
//
// return buf;
// }
//
// protected static void Release0(ByteBuffer buf)
// {
// Stack stack = _heapBufferStacks[GetBufferStackIndex(_heapBufferStacks, buf.Capacity)];
// lock (stack)
// {
// stack.Push(buf);
// }
// }
//
// private static int GetBufferStackIndex(Stack[] bufferStacks, int size)
// {
// int targetSize = MINIMUM_CAPACITY;
// int stackIdx = 0;
// // each bucket contains buffers that are double the size of the previous bucket
// while (size > targetSize)
// {
// targetSize <<= 1;
// stackIdx++;
// if (stackIdx >= bufferStacks.Length)
// {
// throw new ArgumentOutOfRangeException("size", "Buffer size is too big: " + size);
// }
// }
// return stackIdx;
// }
//
// /// <summary>
// /// Increases the internal reference count of this buffer to defer automatic release. You have
// /// to invoke release() as many times as you invoked this method to release this buffer.
// /// </summary>
// public abstract void Acquire();
//
// /// <summary>
// /// Releases the specified buffer to the buffer pool.
// /// </summary>
// public abstract void Release();
//
// public abstract int Capacity
// {
// get;
// }
//
// public abstract bool IsAutoExpand
// {
// get;
// set;
// }
//
// /// <summary>
// /// Changes the capacity and limit of this buffer sot his buffer gets the specified
// /// expectedRemaining room from the current position. This method works even if you didn't set
// /// autoExpand to true.
// /// </summary>
// /// <param name="expectedRemaining">Room you want from the current position</param>
// public abstract void Expand(int expectedRemaining);
//
// /// <summary>
// /// Changes the capacity and limit of this buffer sot his buffer gets the specified
// /// expectedRemaining room from the specified position.
// /// </summary>
// /// <param name="pos">The pos you want the room to be available from.</param>
// /// <param name="expectedRemaining">The expected room you want available.</param>
// public abstract void Expand(int pos, int expectedRemaining);
//
// /// <summary>
// /// Returns true if and only if this buffer is returned back to the buffer pool when released.
// /// </summary>
// /// <value><c>true</c> if pooled; otherwise, <c>false</c>.</value>
// public abstract bool Pooled
// {
// get;
// set;
// }
//
// public abstract int Position
// {
// get;
// set;
// }
//
// public abstract int Limit
// {
// get;
// set;
// }
//
// //public abstract void Mark();
//
// //public abstract void Reset();
//
// public abstract void Clear();
//
// /// <summary>
// /// Clears this buffer and fills its content with NULL. The position is set to zero, the limit is set to
// /// capacity and the mark is discarded.
// /// </summary>
// public void Sweep()
// {
// Clear();
// FillAndReset(Remaining);
// }
//
// public void Sweep(byte value)
// {
// Clear();
// FillAndReset(value, Remaining);
// }
//
// public abstract void Flip();
//
// public abstract void Rewind();
//
// public abstract int Remaining
// {
// get;
// }
//
// public bool HasRemaining()
// {
// return Remaining > 0;
// }
//
// public abstract byte Get();
//
// public abstract byte Get(int index);
//
// public abstract void Get(byte[] destination);
//
// public abstract ushort GetUnsignedShort();
//
// public abstract uint GetUnsignedInt();
//
// public abstract ulong GetUnsignedLong();
//
// public abstract string GetString(uint length, Encoding encoder);
//
// public abstract void Put(byte data);
//
// public abstract void Put(byte[] data);
// public abstract void Put(byte[] data, int offset, int size);
//
// public abstract void Put(ushort data);
//
// public abstract void Put(uint data);
//
// public abstract void Put(ulong data);
//
// public abstract void Put(ByteBuffer buf);
//
// public abstract void Compact();
//
// public abstract byte[] ToByteArray();
//
// public override string ToString()
// {
// StringBuilder buf = new StringBuilder();
// buf.Append("HeapBuffer");
// buf.AppendFormat("[pos={0} lim={1} cap={2} : {3}]", Position, Limit, Capacity, HexDump);
// return buf.ToString();
// }
//
// public override int GetHashCode()
// {
// int h = 1;
// int p = Position;
// for (int i = Limit - 1; i >= p; i--)
// {
// h = 31 * h + Get(i);
// }
//
// return h;
// }
//
// public override bool Equals(object obj)
// {
// if (!(obj is ByteBuffer))
// {
// return false;
// }
// ByteBuffer that = (ByteBuffer) obj;
//
// if (Remaining != that.Remaining)
// {
// return false;
// }
// int p = Position;
// for (int i = 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;
// }
//
// public string HexDump
// {
// get
// {
// return ByteBufferHexDumper.GetHexDump(this);
// }
// }
//
// /// <summary>
// /// Fills the buffer with the specified specified value. This method moves the buffer position forward.
// /// </summary>
// /// <param name="value">The value.</param>
// /// <param name="size">The size.</param>
// public void 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 |= (ushort)intValue;
//
// for (int i = q; i > 0; i--)
// {
// Put((ulong)longValue);
// }
// }
//
// q = r >> 2;
// r = r & 3;
//
// if (q > 0)
// {
// int intValue = value | (value << 8) | (value << 16) | (value << 24);
// Put((uint)intValue);
// }
//
// q = r >> 1;
// r = r & 1;
//
// if (q > 0)
// {
// short shortValue = (short) (value | (value << 8));
// Put((ushort) shortValue);
// }
// if (r > 0)
// {
// Put(value);
// }
// }
//
// public void FillAndReset(byte value, int size)
// {
// AutoExpand(size);
// int pos = Position;
// try
// {
// Fill(value, size);
// }
// finally
// {
// Position = pos;
// }
// }
//
// public void Fill(int size)
// {
// AutoExpand(size);
// int q = size >> 3;
// int r = size & 7;
//
// for (int i = q; i > 0; i--)
// {
// Put(0L);
// }
//
// q = r >> 2;
// r = r & 3;
//
// if (q > 0)
// {
// Put(0);
// }
//
// q = r >> 1;
// r = r & 1;
//
// if(q > 0)
// {
// Put((ushort) 0);
// }
//
// if (r > 0)
// {
// Put((byte) 0);
// }
// }
//
// public void FillAndReset(int size)
// {
// AutoExpand(size);
// int pos = Position;
// try
// {
// Fill(size);
// }
// finally
// {
// Position = pos;
// }
// }
//
// public void Skip(int size)
// {
// AutoExpand(size);
// Position = Position + size;
// }
//
// protected void AutoExpand(int expectedRemaining)
// {
// if (IsAutoExpand)
// {
// Expand(expectedRemaining);
// }
// }
//
// protected void AutoExpand(int pos, int expectedRemaining)
// {
// if (IsAutoExpand)
// {
// Expand(pos, expectedRemaining);
// }
// }
// }
/*
* 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 org.apache.mina.common;
//
//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.nio.BufferOverflowException;
//import java.nio.BufferUnderflowException;
//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 org.apache.mina.common.support.ByteBufferHexDumper;
//import org.apache.mina.filter.codec.ProtocolEncoderOutput;
/**
* A byte buffer used by MINA applications.
* <p>
* This is a replacement for {@link FixedByteBuffer}. Please refer to
* {@link FixedByteBuffer} and {@link java.nio.Buffer} documentation for
* usage. MINA does not use NIO {@link FixedByteBuffer} directly for two
* reasons:
* <ul>
* <li>It doesn't provide useful getters and putters such as
* <code>fill</code>, <code>get/putString</code>, and
* <code>get/putAsciiInt()</code> enough.</li>
* <li>It is hard to distinguish if the buffer is created from MINA buffer
* pool or not. MINA have to return used buffers back to pool.</li>
* <li>It is difficult to write variable-length data due to its fixed
* capacity</li>
* </ul>
* </p>
*
* <h2>Allocation</h2>
* <p>
* You can get a heap buffer from buffer pool:
* <pre>
* ByteBuffer buf = ByteBuffer.allocate(1024, false);
* </pre>
* you can also get a direct buffer from buffer pool:
* <pre>
* ByteBuffer buf = ByteBuffer.allocate(1024, true);
* </pre>
* or you can let MINA choose:
* <pre>
* ByteBuffer buf = ByteBuffer.allocate(1024);
* </pre>
* </p>
*
* <h2>Acquire/Release</h2>
* <p>
* <b>Please note that you never need to release the allocated buffer</b>
* because MINA will release it automatically when:
* <ul>
* <li>You pass the buffer by calling {@link IoSession#write(Object)}.</li>
* <li>You pass the buffer by calling {@link IoFilter.NextFilter#filterWrite(IoSession,IoFilter.WriteRequest)}.</li>
* <li>You pass the buffer by calling {@link ProtocolEncoderOutput#write(ByteBuffer)}.</li>
* </ul>
* And, you don't need to release any {@link ByteBuffer} which is passed as a parameter
* of {@link IoHandler#messageReceived(IoSession, Object)} method. They are released
* automatically when the method returns.
* <p>
* You have to release buffers manually by calling {@link #release()} when:
* <ul>
* <li>You allocated a buffer, but didn't pass the buffer to any of two methods above.</li>
* <li>You called {@link #acquire()} to prevent the buffer from being released.</li>
* </ul>
* </p>
*
* <h2>Wrapping existing NIO buffers and arrays</h2>
* <p>
* This class provides a few <tt>wrap(...)</tt> methods that wraps
* any NIO buffers and byte arrays. Wrapped MINA buffers are not returned
* to the buffer pool by default to prevent unexpected memory leakage by default.
* In case you want to make it pooled, you can call {@link #setPooled(bool)}
* with <tt>true</tt> flag to enable pooling.
*
* <h2>AutoExpand</h2>
* <p>
* Writing variable-length data using NIO <tt>ByteBuffers</tt> is not really
* easy, and it is because its size is fixed. MINA <tt>ByteBuffer</tt>
* introduces <tt>autoExpand</tt> property. If <tt>autoExpand</tt> property
* is true, you never get {@link BufferOverflowException} or
* {@link IndexOutOfBoundsException} (except when index is negative).
* It automatically expands its capacity and limit value. For example:
* <pre>
* String greeting = messageBundle.getMessage( "hello" );
* ByteBuffer buf = ByteBuffer.allocate( 16 );
* // Turn on autoExpand (it is off by default)
* buf.setAutoExpand( true );
* buf.putString( greeting, utf8encoder );
* </pre>
* NIO <tt>ByteBuffer</tt> is reallocated by MINA <tt>ByteBuffer</tt> behind
* the scene if the encoded data is larger than 16 bytes. Its capacity will
* increase by two times, and its limit will increase to the last position
* the string is written.
* </p>
*
* <h2>Derived Buffers</h2>
* <p>
* Derived buffers are the buffers which were created by
* {@link #duplicate()}, {@link #slice()}, or {@link #asReadOnlyBuffer()}.
* They are useful especially when you broadcast the same messages to
* multiple {@link IoSession}s. Please note that the derived buffers are
* neither pooled nor auto-expandable. Trying to expand a derived buffer will
* raise {@link IllegalStateException}.
* </p>
*
* <h2>Changing Buffer Allocation and Management Policy</h2>
* <p>
* MINA provides a {@link ByteBufferAllocator} interface to let you override
* the default buffer management behavior. There are two allocators provided
* out-of-the-box:
* <ul>
* <li>{@link PooledByteBufferAllocator} (Default)</li>
* <li>{@link SimpleByteBufferAllocator}</li>
* </ul>
* You can change the allocator by calling {@link #setAllocator(ByteBufferAllocator)}.
* </p>
*
* @author The Apache Directory Project (mina-dev@directory.apache.org)
* @version $Rev: 451854 $, $Date: 2006-10-02 11:30:11 +0900 (ì›”, 02 10ì›” 2006) $
* @noinspection StaticNonFinalField
* @see ByteBufferAllocator
*/
public abstract class ByteBuffer : IComparable
{
//private static ByteBufferAllocator allocator = new PooledByteBufferAllocator();
private static IByteBufferAllocator allocator = new SimpleByteBufferAllocator();
private static bool _useDirectBuffers = false;
public string HexDump
{
get
{
return ByteBufferHexDumper.GetHexDump(this);
}
}
/**
* Returns the current allocator which manages the allocated buffers.
*/
public static IByteBufferAllocator getAllocator()
{
return allocator;
}
/**
* Changes the current allocator with the specified one to manage
* the allocated buffers from now.
*/
public static void setAllocator( IByteBufferAllocator newAllocator )
{
if( newAllocator == null )
{
throw new NullReferenceException("allocator cannot be null");
}
IByteBufferAllocator oldAllocator = allocator;
allocator = newAllocator;
if( null != oldAllocator )
{
oldAllocator.Dispose();
}
}
public static bool isUseDirectBuffers()
{
return _useDirectBuffers;
}
public static void setUseDirectBuffers( bool useDirectBuffers )
{
_useDirectBuffers = useDirectBuffers;
}
/**
* Returns the direct or heap buffer which is capable of the specified
* size. This method tries to allocate direct buffer first, and then
* tries heap buffer if direct buffer memory is exhausted. Please use
* {@link #allocate(int, bool)} to allocate buffers of specific type.
*
* @param capacity the capacity of the buffer
*/
public static ByteBuffer allocate( int capacity )
{
if( _useDirectBuffers )
{
try
{
// first try to allocate direct buffer
return allocate( capacity, true );
}
catch (OutOfMemoryException)
{
// fall through to heap buffer
}
}
return allocate( capacity, false );
}
/**
* Returns the buffer which is capable of the specified size.
*
* @param capacity the capacity of the buffer
* @param direct <tt>true</tt> to get a direct buffer,
* <tt>false</tt> to get a heap buffer.
*/
public static ByteBuffer allocate( int capacity, bool direct )
{
return allocator.Allocate( capacity, direct );
}
/**
* Wraps the specified NIO {@link FixedByteBuffer} into MINA buffer.
*/
public static ByteBuffer wrap( FixedByteBuffer nioBuffer )
{
return allocator.Wrap( nioBuffer );
}
/**
* Wraps the specified byte array into MINA heap buffer.
*/
public static ByteBuffer wrap( byte[] byteArray )
{
return wrap( FixedByteBuffer.wrap( byteArray ) );
}
/**
* Wraps the specified byte array into MINA heap buffer.
* Please note that MINA buffers are going to be pooled, and
* therefore there can be waste of memory if you wrap
* your byte array specifying <tt>offset</tt> and <tt>length</tt>.
*/
public static ByteBuffer wrap( byte[] byteArray, int offset, int length )
{
return wrap( FixedByteBuffer.wrap( byteArray, offset, length ) );
}
protected ByteBuffer()
{
}
/**
* Increases the internal reference count of this buffer to defer
* automatic release. You have to invoke {@link #release()} as many
* as you invoked this method to release this buffer.
*
* @throws IllegalStateException if you attempt to acquire already
* released buffer.
*/
public abstract void acquire();
/**
* Releases the specified buffer to buffer pool.
*
* @throws IllegalStateException if you attempt to release already
* released buffer.
*/
public abstract void release();
/**
* Returns the underlying NIO buffer instance.
*/
public abstract FixedByteBuffer buf();
/**
* @see FixedByteBuffer#isDirect()
*/
public abstract bool isDirect();
/**
* @see FixedByteBuffer#isReadOnly()
*/
public abstract bool isReadOnly();
/**
* @see FixedByteBuffer#capacity()
*/
public abstract int capacity();
/**
* Changes the capacity of this buffer.
*/
public abstract ByteBuffer capacity( int newCapacity );
/**
* Returns <tt>true</tt> if and only if <tt>autoExpand</tt> is turned on.
*/
public abstract bool isAutoExpand();
/**
* Turns on or off <tt>autoExpand</tt>.
*/
public abstract ByteBuffer setAutoExpand( bool autoExpand );
/**
* Changes the capacity and limit of this buffer so this buffer get
* the specified <tt>expectedRemaining</tt> room from the current position.
* This method works even if you didn't set <tt>autoExpand</tt> to
* <tt>true</tt>.
*/
public ByteBuffer expand( int expectedRemaining )
{
return expand( position(), expectedRemaining );
}
/**
* Changes the capacity and limit of this buffer so this buffer get
* the specified <tt>expectedRemaining</tt> room from the specified
* <tt>pos</tt>.
* This method works even if you didn't set <tt>autoExpand</tt> to
* <tt>true</tt>.
*/
public abstract ByteBuffer expand( int pos, int expectedRemaining );
/**
* Returns <tt>true</tt> if and only if this buffer is returned back
* to the buffer pool when released.
* <p>
* The default value of this property is <tt>true</tt> if and only if you
* allocated this buffer using {@link #allocate(int)} or {@link #allocate(int, bool)},
* or <tt>false</tt> otherwise. (i.e. {@link #wrap(byte[])}, {@link #wrap(byte[], int, int)},
* and {@link #wrap(FixedByteBuffer)})
*/
public abstract bool isPooled();
/**
* Sets whether this buffer is returned back to the buffer pool when released.
* <p>
* The default value of this property is <tt>true</tt> if and only if you
* allocated this buffer using {@link #allocate(int)} or {@link #allocate(int, bool)},
* or <tt>false</tt> otherwise. (i.e. {@link #wrap(byte[])}, {@link #wrap(byte[], int, int)},
* and {@link #wrap(FixedByteBuffer)})
*/
public abstract void setPooled( bool pooled );
/**
* @see java.nio.Buffer#position()
*/
public abstract int position();
/**
* @see java.nio.Buffer#position(int)
*/
public abstract ByteBuffer position( int newPosition );
/**
* @see java.nio.Buffer#limit()
*/
public abstract int limit();
/**
* @see java.nio.Buffer#limit(int)
*/
public abstract ByteBuffer limit( int newLimit );
/**
* @see java.nio.Buffer#mark()
*/
public abstract ByteBuffer mark();
/**
* Returns the position of the current mark. This method returns <tt>-1</tt> if no
* mark is set.
*/
public abstract int markValue();
/**
* @see java.nio.Buffer#reset()
*/
public abstract ByteBuffer reset();
/**
* @see java.nio.Buffer#clear()
*/
public abstract ByteBuffer clear();
/**
* Clears this buffer and fills its content with <tt>NUL</tt>.
* The position is set to zero, the limit is set to the capacity,
* and the mark is discarded.
*/
// public ByteBuffer sweep()
// {
// clear();
// return fillAndReset( remaining() );
// }
/**
* Clears this buffer and fills its content with <tt>value</tt>.
* The position is set to zero, the limit is set to the capacity,
* and the mark is discarded.
*/
// public ByteBuffer sweep( byte value )
// {
// clear();
// return fillAndReset( value, remaining() );
// }
/**
* @see java.nio.Buffer#flip()
*/
public abstract ByteBuffer flip();
/**
* @see java.nio.Buffer#rewind()
*/
public abstract ByteBuffer rewind();
/**
* @see java.nio.Buffer#remaining()
*/
public int remaining()
{
return limit() - position();
}
/**
* @see java.nio.Buffer#hasRemaining()
*/
public bool hasRemaining()
{
return remaining() > 0;
}
/**
* @see FixedByteBuffer#duplicate()
*/
public abstract ByteBuffer duplicate();
/**
* @see FixedByteBuffer#slice()
*/
public abstract ByteBuffer slice();
/**
* @see FixedByteBuffer#asReadOnlyBuffer()
*/
public abstract ByteBuffer asReadOnlyBuffer();
/**
* @see FixedByteBuffer#array()
*/
public abstract byte[] array();
/**
* @see FixedByteBuffer#arrayOffset()
*/
public abstract int arrayOffset();
/**
* @see FixedByteBuffer#get()
*/
public abstract byte get();
/**
* Reads one unsigned byte as a short integer.
*/
public short getUnsigned()
{
return (short)( get() & 0xff );
}
/**
* @see FixedByteBuffer#put(byte)
*/
public abstract ByteBuffer put( byte b );
/**
* @see FixedByteBuffer#get(int)
*/
public abstract byte get( int index );
/**
* Reads one byte as an unsigned short integer.
*/
public short getUnsigned( int index )
{
return (short)( get( index ) & 0xff );
}
/**
* @see FixedByteBuffer#put(int, byte)
*/
public abstract ByteBuffer put( int index, byte b );
/**
* @see FixedByteBuffer#get(byte[], int, int)
*/
public abstract ByteBuffer get( byte[] dst, int offset, int length );
/**
* @see FixedByteBuffer#get(byte[])
*/
public abstract ByteBuffer get(byte[] dst);
// {
// return get( dst, 0, dst.Length );
// }
/**
* Writes the content of the specified <tt>src</tt> into this buffer.
*/
public abstract ByteBuffer put( FixedByteBuffer src );
/**
* Writes the content of the specified <tt>src</tt> into this buffer.
*/
public ByteBuffer put( ByteBuffer src )
{
return put( src.buf() );
}
/**
* @see FixedByteBuffer#put(byte[], int, int)
*/
public abstract ByteBuffer put( byte[] src, int offset, int length );
/**
* @see FixedByteBuffer#put(byte[])
*/
public abstract ByteBuffer put(byte[] src);
// {
// return put(src);
//// return put( src, 0, src.Length );
// }
/**
* @see FixedByteBuffer#compact()
*/
public abstract ByteBuffer compact();
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() );
buf.Append( ']' );
return buf.ToString();
}
public int hashCode()
{
int h = 1;
int p = position();
for( int i = limit() - 1; i >= p; i -- )
{
h = 31 * h + get( i );
}
return h;
}
public bool equals( Object o )
{
if( !( o is ByteBuffer ) )
{
return false;
}
ByteBuffer that = (ByteBuffer)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;
}
public int CompareTo( Object o )
{
ByteBuffer that = (ByteBuffer)o;
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();
}
/**
* @see FixedByteBuffer#order()
*/
public abstract ByteOrder order();
/**
* @see FixedByteBuffer#order(ByteOrder)
*/
public abstract ByteBuffer order( ByteOrder bo );
/**
* @see FixedByteBuffer#getChar()
*/
public abstract char getChar();
/**
* @see FixedByteBuffer#putChar(char)
*/
public abstract ByteBuffer putChar( char value );
/**
* @see FixedByteBuffer#getChar(int)
*/
public abstract char getChar( int index );
/**
* @see FixedByteBuffer#putChar(int, char)
*/
public abstract ByteBuffer putChar( int index, char value );
/**
* @see FixedByteBuffer#asCharBuffer()
*/
// public abstract CharBuffer asCharBuffer();
/**
* @see FixedByteBuffer#getShort()
*/
public abstract short getShort();
/**
* Reads two bytes unsigned integer.
*/
public int getUnsignedShort()
{
return getShort() & 0xffff;
}
/**
* @see FixedByteBuffer#putShort(short)
*/
public abstract ByteBuffer putShort( short value );
/**
* @see FixedByteBuffer#getShort()
*/
public abstract short getShort( int index );
/**
* Reads two bytes unsigned integer.
*/
public int getUnsignedShort( int index )
{
return getShort( index ) & 0xffff;
}
/**
* @see FixedByteBuffer#putShort(int, short)
*/
public abstract ByteBuffer putShort( int index, short value );
/**
* @see FixedByteBuffer#asShortBuffer()
*/
// public abstract ShortBuffer asShortBuffer();
/**
* @see FixedByteBuffer#getInt()
*/
public abstract int getInt();
/**
* Reads four bytes unsigned integer.
*/
public uint getUnsignedInt()
{
// return getInt() & 0xffffffffL;
//CheckSpaceForReading(4);
byte b1 = get();
byte b2 = get();
byte b3 = get();
byte b4 = get();
return (uint)((b1 << 24) + (b2 << 16) + (b3 << 8) + b4);
}
/**
* @see FixedByteBuffer#putInt(int)
*/
public abstract ByteBuffer putInt( int value );
/**
* @see FixedByteBuffer#getInt(int)
*/
public abstract int getInt( int index );
/**
* Reads four bytes unsigned integer.
*/
public long getUnsignedInt( int index )
{
return getInt( index ) & 0xffffffffL;
}
/**
* @see FixedByteBuffer#putInt(int, int)
*/
public abstract ByteBuffer putInt( int index, int value );
/**
* @see FixedByteBuffer#asIntBuffer()
*/
// public abstract IntBuffer asIntBuffer();
/**
* @see FixedByteBuffer#getLong()
*/
public abstract long getLong();
/**
* @see FixedByteBuffer#putLong(int, long)
*/
public abstract ByteBuffer putLong( long value );
/**
* @see FixedByteBuffer#getLong(int)
*/
public abstract long getLong( int index );
/**
* @see FixedByteBuffer#putLong(int, long)
*/
public abstract ByteBuffer putLong( int index, long value );
/**
* @see FixedByteBuffer#asLongBuffer()
*/
// public abstract LongBuffer asLongBuffer();
/**
* @see FixedByteBuffer#getFloat()
*/
public abstract float getFloat();
/**
* @see FixedByteBuffer#putFloat(float)
*/
public abstract ByteBuffer putFloat( float value );
/**
* @see FixedByteBuffer#getFloat(int)
*/
public abstract float getFloat( int index );
/**
* @see FixedByteBuffer#putFloat(int, float)
*/
public abstract ByteBuffer putFloat( int index, float value );
/**
* @see FixedByteBuffer#asFloatBuffer()
*/
// public abstract FloatBuffer asFloatBuffer();
/**
* @see FixedByteBuffer#getDouble()
*/
public abstract double getDouble();
/**
* @see FixedByteBuffer#putDouble(double)
*/
public abstract ByteBuffer putDouble( double value );
/**
* @see FixedByteBuffer#getDouble(int)
*/
public abstract double getDouble( int index );
/**
* @see FixedByteBuffer#putDouble(int, double)
*/
public abstract ByteBuffer putDouble( int index, double value );
/**
* @see FixedByteBuffer#asDoubleBuffer()
*/
// public abstract DoubleBuffer asDoubleBuffer();
/**
* Returns an {@link InputStream} that reads the data from this buffer.
* {@link InputStream#read()} returns <tt>-1</tt> if the buffer position
* reaches to the limit.
*/
// public InputStream asInputStream()
// {
// // XXX: Use System.IO.Stream here?
// return new InputStream()
// {
// public int available()
// {
// return ByteBuffer.this.remaining();
// }
//
// public synchronized void mark( int readlimit )
// {
// ByteBuffer.this.mark();
// }
//
// public bool markSupported()
// {
// return true;
// }
//
// public int read()
// {
// if( ByteBuffer.this.hasRemaining() )
// {
// return ByteBuffer.this.get() & 0xff;
// }
// else
// {
// return -1;
// }
// }
//
// public int read( byte[] b, int off, int len )
// {
// int remaining = ByteBuffer.this.remaining();
// if( remaining > 0 )
// {
// int readBytes = Math.min( remaining, len );
// ByteBuffer.this.get( b, off, readBytes );
// return readBytes;
// }
// else
// {
// return -1;
// }
// }
//
// public synchronized void reset()
// {
// ByteBuffer.this.reset();
// }
//
// public long skip( long n )
// {
// int bytes;
// if( n > Integer.MAX_VALUE )
// {
// bytes = ByteBuffer.this.remaining();
// }
// else
// {
// bytes = Math.min( ByteBuffer.this.remaining(), (int)n );
// }
// ByteBuffer.this.skip( bytes );
// return bytes;
// }
// };
// }
/**
* Returns an {@link OutputStream} that Appends the data into this buffer.
* Please note that the {@link OutputStream#write(int)} will throw a
* {@link BufferOverflowException} instead of an {@link IOException}
* in case of buffer overflow. Please set <tt>autoExpand</tt> property by
* calling {@link #setAutoExpand(bool)} to prevent the unexpected runtime
* exception.
*/
// public OutputStream asOutputStream()
// {
// return new OutputStream()
// {
// public void write( byte[] b, int off, int len )
// {
// ByteBuffer.this.put( b, off, len );
// }
//
// public void write( int b )
// {
// ByteBuffer.this.put( (byte)b );
// }
// };
// }
/**
* Returns hexdump of this buffer.
*/
public String getHexDump()
{
return ByteBufferHexDumper.GetHexDump(this);
}
////////////////////////////////
// String getters and putters //
////////////////////////////////
/**
* Reads a <code>NUL</code>-terminated string from this buffer using the
* specified <code>decoder</code> and returns it. This method reads
* until the limit of this buffer if no <tt>NUL</tt> is found.
*/
// public String getString( Encoding decoder )
// {
// if( !hasRemaining() )
// {
// return "";
// }
//
// decoder.
// bool utf16 = decoder.charset().name().startsWith( "UTF-16" );
//
// int oldPos = position();
// int oldLimit = limit();
// int end;
//
// if( !utf16 )
// {
// while( hasRemaining() )
// {
// if( get() == 0 )
// {
// break;
// }
// }
//
// end = position();
// if( end == oldLimit && get( end - 1 ) != 0 )
// {
// limit( end );
// }
// else
// {
// limit( end - 1 );
// }
// }
// else
// {
// while( remaining() >= 2 )
// {
// if( ( get() == 0 ) && ( get() == 0 ) )
// {
// break;
// }
// }
//
// end = position();
// if( end == oldLimit || end == oldLimit - 1 )
// {
// limit( end );
// }
// else
// {
// limit( end - 2 );
// }
// }
//
// position( oldPos );
// 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;
// }
//
// cr.throwException();
// }
//
// limit( oldLimit );
// position( end );
// return out.flip().toString();
// }
/**
* Reads a <code>NUL</code>-terminated string from this buffer using the
* specified <code>decoder</code> and returns it.
*
* @param fieldSize the maximum number of bytes to read
*/
// public String getString( int fieldSize, CharsetDecoder decoder ) throws CharacterCodingException
// {
// checkFieldSize( fieldSize );
//
// if( fieldSize == 0 )
// {
// return "";
// }
//
// if( !hasRemaining() )
// {
// return "";
// }
//
// bool 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 = position() + fieldSize;
//
// if( oldLimit < end )
// {
// throw new BufferUnderflowException();
// }
//
// int i;
//
// if( !utf16 )
// {
// for( i = 0; i < fieldSize; i ++ )
// {
// if( get() == 0 )
// {
// break;
// }
// }
//
// if( i == fieldSize )
// {
// limit( end );
// }
// else
// {
// limit( position() - 1 );
// }
// }
// else
// {
// for( i = 0; i < fieldSize; i += 2 )
// {
// if( ( get() == 0 ) && ( get() == 0 ) )
// {
// break;
// }
// }
//
// if( i == fieldSize )
// {
// limit( end );
// }
// else
// {
// limit( position() - 2 );
// }
// }
//
// position( oldPos );
// 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;
// }
//
// cr.throwException();
// }
//
// limit( oldLimit );
// position( end );
// return out.flip().toString();
// }
/**
* Writes the content of <code>in</code> into this buffer using the
* specified <code>encoder</code>. This method doesn't terminate
* string with <tt>NUL</tt>. You have to do it by yourself.
*
* @throws BufferOverflowException if the specified string doesn't fit
*/
// public ByteBuffer 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;
// }
/**
* Writes the content of <code>in</code> into this buffer as a
* <code>NUL</code>-terminated string using the specified
* <code>encoder</code>.
* <p>
* If the charset name of the encoder is UTF-16, you cannot specify
* odd <code>fieldSize</code>, and this method will Append two
* <code>NUL</code>s as a terminator.
* <p>
* Please note that this method doesn't terminate with <code>NUL</code>
* if the input string is longer than <tt>fieldSize</tt>.
*
* @param fieldSize the maximum number of bytes to write
*/
// public ByteBuffer putString(
// CharSequence val, int fieldSize, CharsetEncoder encoder ) throws CharacterCodingException
// {
// checkFieldSize( fieldSize );
//
// if( fieldSize == 0 )
// return this;
//
// autoExpand( fieldSize );
//
// bool 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;
// }
/**
* Reads a string which has a 16-bit length field before the actual
* encoded string, using the specified <code>decoder</code> and returns it.
* This method is a shortcut for <tt>getPrefixedString(2, decoder)</tt>.
*/
// 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)
*/
// 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 "";
// }
//
// bool 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();
// }
/**
* Writes the content of <code>in</code> into this buffer as a
* string which has a 16-bit length field before the actual
* encoded string, using the specified <code>encoder</code>.
* This method is a shortcut for <tt>putPrefixedString(in, 2, 0, encoder)</tt>.
*
* @throws BufferOverflowException if the specified string doesn't fit
*/
// public ByteBuffer putPrefixedString( CharSequence in, CharsetEncoder encoder ) throws CharacterCodingException
// {
// return putPrefixedString( in, 2, 0, encoder );
// }
/**
* Writes the content of <code>in</code> into this buffer as a
* string which has a 16-bit length field before the actual
* encoded string, using the specified <code>encoder</code>.
* This method is a shortcut for <tt>putPrefixedString(in, prefixLength, 0, encoder)</tt>.
*
* @param prefixLength the length of the length field (1, 2, or 4)
*
* @throws BufferOverflowException if the specified string doesn't fit
*/
// public ByteBuffer putPrefixedString( CharSequence in, int prefixLength, CharsetEncoder encoder )
// throws CharacterCodingException
// {
// return putPrefixedString( in, prefixLength, 0, encoder );
// }
/**
* Writes the content of <code>in</code> into this buffer as a
* string which has a 16-bit length field before the actual
* encoded string, using the specified <code>encoder</code>.
* This method is a shortcut for <tt>putPrefixedString(in, prefixLength, padding, ( byte ) 0, encoder)</tt>.
*
* @param prefixLength the length of the length field (1, 2, or 4)
* @param padding the number of padded <tt>NUL</tt>s (1 (or 0), 2, or 4)
*
* @throws BufferOverflowException if the specified string doesn't fit
*/
// public ByteBuffer putPrefixedString( CharSequence in, int prefixLength, int padding, CharsetEncoder encoder )
// throws CharacterCodingException
// {
// return putPrefixedString( in, prefixLength, padding, (byte)0, encoder );
// }
/**
* Writes the content of <code>in</code> into this buffer as a
* string which has a 16-bit length field before the actual
* encoded string, using the specified <code>encoder</code>.
*
* @param prefixLength the length of the length field (1, 2, or 4)
* @param padding the number of padded bytes (1 (or 0), 2, or 4)
* @param padValue the value of padded bytes
*
* @throws BufferOverflowException if the specified string doesn't fit
*/
// public ByteBuffer 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 );
// int expectedLength = (int)( in.remaining() * encoder.averageBytesPerChar() ) + 1;
//
// skip( prefixLength ); // make a room for the length field
// int oldPos = position();
// encoder.reset();
//
// 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() && isAutoExpand() )
// {
// autoExpand( expectedLength );
// continue;
// }
// 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;
// }
/**
* Reads a Java object from the buffer using the context {@link ClassLoader}
* of the current thread.
*/
// public Object getObject() throws ClassNotFoundException
// {
// return getObject( Thread.currentThread().getContextClassLoader() );
// }
/**
* Reads a Java object from the buffer using the specified <tt>classLoader</tt>.
*/
// 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() )
// {
// protected ObjectStreamClass readClassDescriptor() throws IOException, ClassNotFoundException
// {
// String className = readUTF();
// Class clazz = Class.forName( className, true, classLoader );
// return ObjectStreamClass.lookup( clazz );
// }
// };
// return in.readObject();
// }
// catch( IOException e )
// {
// throw new BufferDataException( e );
// }
// finally
// {
// limit( oldLimit );
// }
// }
/**
* Writes the specified Java object to the buffer.
*/
// public ByteBuffer putObject( Object o )
// {
// int oldPos = position();
// skip( 4 ); // Make a room for the length field.
// try
// {
// ObjectOutputStream out = new ObjectOutputStream( asOutputStream() )
// {
// protected void writeClassDescriptor( ObjectStreamClass desc ) throws IOException
// {
// 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;
// }
/**
* Returns <tt>true</tt> if this buffer contains a data which has a data
* length as a prefix and the buffer has remaining data as enough as
* specified in the data length field. This method is identical with
* <tt>prefixedDataAvailable( prefixLength, Integer.MAX_VALUE )</tt>.
* Please not that using this method can allow DoS (Denial of Service)
* attack in case the remote peer sends too big data length value.
* It is recommended to use {@link #prefixedDataAvailable(int, int)}
* instead.
*
* @param prefixLength the length of the prefix field (1, 2, or 4)
*
* @throws IllegalArgumentException if prefixLength is wrong
* @throws BufferDataException if data length is negative
*/
public bool prefixedDataAvailable( int prefixLength )
{
return prefixedDataAvailable( prefixLength, int.MaxValue);
}
/**
* Returns <tt>true</tt> if this buffer contains a data which has a data
* length as a prefix and the buffer has remaining data as enough as
* specified in the data length field.
*
* @param prefixLength the length of the prefix field (1, 2, or 4)
* @param maxDataLength the allowed maximum of the read data length
*
* @throws IllegalArgumentException if prefixLength is wrong
* @throws BufferDataException if data length is negative or greater then <tt>maxDataLength</tt>
*/
public bool 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 ArgumentException("prefixLength: " + prefixLength);
}
if( dataLength < 0 || dataLength > maxDataLength )
{
throw new BufferDataException( "dataLength: " + dataLength );
}
return remaining() - prefixLength >= dataLength;
}
//////////////////////////
// Skip or fill methods //
//////////////////////////
/**
* Forwards the position of this buffer as the specified <code>size</code>
* bytes.
*/
public ByteBuffer skip( int size )
{
autoExpand( size );
return position( position() + size );
}
/**
* Fills this buffer with the specified value.
* This method moves buffer position forward.
*/
// public ByteBuffer 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;
// }
/**
* Fills this buffer with the specified value.
* This method does not change buffer position.
*/
// public ByteBuffer fillAndReset( byte value, int size )
// {
// autoExpand( size );
// int pos = position();
// try
// {
// fill( value, size );
// }
// finally
// {
// position( pos );
// }
// return this;
// }
/**
* Fills this buffer with <code>NUL (0x00)</code>.
* This method moves buffer position forward.
*/
// public ByteBuffer 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;
// }
/**
* Fills this buffer with <code>NUL (0x00)</code>.
* This method does not change buffer position.
*/
// public ByteBuffer fillAndReset( int size )
// {
// autoExpand( size );
// int pos = position();
// try
// {
// fill( size );
// }
// finally
// {
// position( pos );
// }
//
// return this;
// }
/**
* This method forwards the call to {@link #expand(int)} only when
* <tt>autoExpand</tt> property is <tt>true</tt>.
*/
protected ByteBuffer autoExpand( int expectedRemaining )
{
if( isAutoExpand() )
{
expand( expectedRemaining );
}
return this;
}
/**
* This method forwards the call to {@link #expand(int)} only when
* <tt>autoExpand</tt> property is <tt>true</tt>.
*/
protected ByteBuffer autoExpand( int pos, int expectedRemaining )
{
if( isAutoExpand() )
{
expand( pos, expectedRemaining );
}
return this;
}
public abstract void put(ushort value);
public abstract ushort GetUnsignedShort();
public abstract uint GetUnsignedInt();
public abstract void put(uint max);
public abstract void put(ulong tag);
public abstract ulong GetUnsignedLong();
}
}